Cogs.Core
PickingBeamComponent.cpp
1#include "PickingBeamComponent.h"
2
3#include "Types.h"
4#include "Input/InputManager.h"
5#include "Resources/MaterialManager.h"
6
7#include "Components/Geometry/MeshGeneratorComponent.h"
8#include "Components/Core/MeshRenderComponent.h"
9
10#include "Scene/RayPick.h"
11#include "EntityStore.h"
12
13#include "Systems/Core/CameraSystem.h"
14#include "Systems/Core/TransformSystem.h"
15#include "Systems/Core/SceneSystem.h"
16
17#include "Foundation/Logging/Logger.h"
18#include "Foundation/Reflection/Method.h"
19
20#include <glm/gtx/matrix_decompose.hpp>
21
22#include <algorithm>
23
24namespace
25{
26 const Cogs::Logging::Log logger = Cogs::Logging::getLogger("PickingBeamComponent");
27}
28
29
30using namespace Cogs::Core;
31using namespace Cogs::Reflection;
32
33//static
34void Cogs::Core::PickingBeamComponent::registerType()
35{
36 Field fields[] = {
44 };
45 Method methods[] = {
46 Method(Name("initialize"), &PickingBeamComponent::initialize),
47 Method(Name("update"), &PickingBeamComponent::update),
48 };
49
50 DynamicComponent::registerDerivedType<PickingBeamComponent>().setMethods(methods).setFields(fields);
51}
52
53void Cogs::Core::PickingBeamComponent::initialize(Cogs::Core::Context * context)
54{
55 this->context = context;
56 beam = context->store->findEntity("aimBeam", getContainer());
57 if (!beam) {
58 beam = context->store->createChildEntity("Group", getContainer(), "aimBeam");
59 }
60 aimTransform = getComponentHandle<TransformComponent>();
61 EntityPtr beamGeometry = context->store->findEntity("aimCylinder", this->beam.get());
62 if (!beamGeometry) {
63 beamGeometry = context->store->createChildEntity("Cylinder", this->beam.get(), "aimCylinder");
64 }
65 beamGeometry->getComponent<MeshGeneratorComponent>()->shape = Cogs::Core::ShapeType::Cylinder;
66
67 MaterialHandle defaultMat = context->materialManager->getDefaultMaterial();
68 MaterialInstanceHandle materialInstance = context->materialInstanceManager->createMaterialInstance(defaultMat);
69 materialInstance->setOption("CullMode", "None");
70 materialInstance->setOption("Transparency", "On");
71 materialInstance->setOption("DepthTestEnabled", enableDepthTest ? "On" : "Off");
72
73 MeshRenderComponent *beamMeshRender = beamGeometry->getComponent<MeshRenderComponent>();
74 beamMeshRender->material = materialInstance;
76 beamMeshRender->setChanged();
77
78 RenderComponent *beamRender = beamGeometry->getComponent<RenderComponent>();
79 beamRender->drawOrder = transparencyLayer;
80 beamRender->setChanged();
81
82 this->beamGeometryTransform = beamGeometry->getComponentHandle<TransformComponent>();
83 TransformComponent *beamGeometryTrans = beamGeometryTransform.resolveComponent<TransformComponent>();
84 beamGeometryTrans->position = glm::vec3(0, 0, -2500);
85 beamGeometryTrans->scale = glm::vec3(0.002f, 0.002f, 2500);
86 beamGeometryTrans->setChanged();
87
88 TransformComponent *beamTransform = this->beam->getComponent<TransformComponent>();
89 beamTransform->position = beamOffset;
90 beamTransform->rotation = beamRotation;
91 beamTransform->setChanged();
92
93 SceneComponent *beamVisibility = beamGeometry->getComponent<SceneComponent>();
94 beamVisibility->visible = false;
95 beamVisibility->pickable = false;
96 beamVisibility->setChanged();
97
98 CameraComponent* beamCam = beam.get()->getComponent<CameraComponent>();
99 if (!beamCam) {
100 beamCam = context->store->addComponent<CameraComponent>(beam.get());
101 }
103 beamCam->fieldOfView = 0.01f;
105 beamCam->viewportSize = glm::vec2(3, 3);
106 beamCam->nearPlaneLimit = 0.1f;
107 beamCam->enableClippingPlaneAdjustment = true;
108 beamCam->setChanged();
109
110 beamCamera = beamCam->getComponentHandle<CameraComponent>();
111
112 beamScene = beamGeometry->getComponentHandle<SceneComponent>();
113
114 destinationMarker = context->store->findEntity("destinationMarker", getContainer());
115 if (!destinationMarker) {
116 destinationMarker = context->store->createChildEntity("Group", getContainer(), "destinationMarker");
117 }
118 EntityPtr destGeometry = context->store->findEntity("BasicMeshGeneratorEntity", destinationMarker.get());
119 if (!destGeometry) {
120 destGeometry = context->store->createChildEntity("BasicMeshGeneratorEntity", destinationMarker.get(), "destinationSphere");
121 }
122 destGeometry->getComponent<MeshGeneratorComponent>()->shape = Cogs::Core::ShapeType::Sphere;
123 destGeometry->getComponent<MeshGeneratorComponent>()->setChanged();
124
125 MeshRenderComponent *destMeshRender = destGeometry->getComponent<MeshRenderComponent>();
126 destMeshRender->material = materialInstance;
128 destMeshRender->setChanged();
129
130 RenderComponent *destRender = destGeometry->getComponent<RenderComponent>();
131 destRender->drawOrder = transparencyLayer;
132 destRender->setChanged();
133
134 TransformComponent *destTransform = destGeometry->getComponent<TransformComponent>();
135 destTransform->scale = glm::vec3(0.25f);
136 destTransform->setChanged();
137
138 destinationScene = destinationMarker->getComponentHandle<SceneComponent>();
139 destinationTransform = destinationMarker->getComponentHandle<TransformComponent>();
140
141 SceneComponent *destVis = destinationScene.resolveComponent<SceneComponent>();
142 destVis->pickable = false;
143 destVis->visible = false;
144 destVis->setChanged();
145
146 mainCamera = context->cameraSystem->getMainCamera()->getComponentHandle<CameraComponent>();
147}
148
149void Cogs::Core::PickingBeamComponent::update()
150{
151 auto beamVis = beamScene.resolveComponent<SceneComponent>();
152 auto destVis = destinationScene.resolveComponent<SceneComponent>();
153
154 if (active)
155 {
156 //FIXME: Store this as member variable or similar:
157 auto materialInstance = destinationMarker->getComponent<SceneComponent>()->children[0].get()->getComponent<MeshRenderComponent>()->material;
158 materialInstance->setProperty("diffuseColor", &diffuseColor, sizeof(glm::vec4));
159 materialInstance->setProperty("emissiveColor", &emissiveColor, sizeof(glm::vec3));
160
161 //FIXME: Make sure the picking cam has had its transform and frustum updated before picking:
162 context->transformSystem->update(context);
163 context->cameraSystem->update(context);
164
165 if (!wasActive)
166 {
167 beamVis->visible = true;
168 beamVis->setChanged();
169 context->sceneSystem->updateState(*beamVis);
170 }
171
172 auto destTrans = destinationTransform.resolveComponent<TransformComponent>();
173
174 auto beamCam = beamCamera.resolveComponent<CameraComponent>();
175 auto size = beamCam->viewportSize;
176
177 auto beamTrans = beamGeometryTransform.resolveComponent<TransformComponent>();
178 auto aimTrans = aimTransform.resolveComponent<TransformComponent>();
179
180 const glm::vec2 windowPosition(size.x / 2, size.y / 2);
181 std::vector<RayPicking::RayPickHit> hits;
182 context->rayPicking->pickCamera(context, *beamCam, windowPosition, std::numeric_limits<float>::max(), defaultPickingRadius, PickingFlags::None, PicksReturned::Closest, {}, hits);
183
184 float dist = 5000;
185 if (!hits.empty()) {
186 lastPickedEntity = hits.front().entity;
187 lastPickedPos = context->transformSystem->getOrigin() + glm::dvec3(hits.front().position);
188 //move the picked point into the aim entity (avatar) frame:
189 glm::vec3 scale, trans, skew;
190 glm::quat orient;
191 glm::vec4 persp;
192 glm::decompose(context->transformSystem->getLocalToWorld(aimTrans), scale, orient, trans, skew, persp);
193
194 dist = glm::distance(hits.front().position, trans);
195 dist /= scale.x;
196
197 destTrans->coordinates = lastPickedPos;
198 destTrans->setChanged();
199 context->transformSystem->updateTransformData(*destTrans);
200
201 if (!destVis->visible) {
202 destVis->visible = true;
203 destVis->setChanged();
204 context->sceneSystem->updateState(*destVis);
205 }
206 }
207 else {
208 lastPickedEntity = NoEntity;
209 lastPickedPos = glm::dvec3(0);
210 if (destVis->visible) {
211 destVis->visible = false;
212 destVis->setChanged();
213 context->sceneSystem->updateState(*destVis);
214 }
215 }
216
217 //adjust length of picking beam:
218 beamTrans->scale = glm::vec3(0.002f, 0.002f, dist / 2);
219 beamTrans->position = glm::vec3(0, 0, -dist / 2);
220 beamTrans->setChanged();
221 context->transformSystem->updateTransformData(*beamTrans);
222 }
223 else
224 {
225 //not active
226 if (wasActive) {
227 beamVis->visible = false;
228 beamVis->setChanged();
229 destVis->visible = false;
230 destVis->setChanged();
231 context->sceneSystem->updateState(*beamVis);
232 context->sceneSystem->updateState(*destVis);
233 }
234 }
235 wasActive = active;
236}
void setChanged()
Sets the component to the ComponentFlags::Changed state with carry.
Definition: Component.h:202
ComponentType * getComponent() const
Definition: Component.h:159
ComponentHandle getComponentHandle() const
Definition: Component.h:177
CameraFlags flags
Camera behavior flags.
float fieldOfView
Vertical field of view, given in radians.
bool enableClippingPlaneAdjustment
If automatic adjustment of the clipping planes should be performed to fit as much of the scene as pos...
glm::vec2 viewportSize
Size of the viewport covered by this instance, given in pixels.
ProjectionMode projectionMode
The projection mode to use for the camera.
float nearPlaneLimit
Smallest value allowed to adjust near plane to.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
class EntityStore * store
Entity store.
Definition: Context.h:231
std::unique_ptr< class RayPicking > rayPicking
RayPicking service instance.
Definition: Context.h:213
ComponentModel::Component * addComponent(ComponentModel::Entity *entity, Reflection::TypeId typeId)
Add a component of the given type to the entity.
EntityPtr createChildEntity(const StringView &type, ComponentModel::Entity *parent, const StringView &name=StringView())
Create a new Entity, parenting it to the given parent.
EntityPtr findEntity(const StringView &name, const ComponentModel::Entity *root=nullptr, EntityFind findOptions=EntityFind::Default) const
Finds an entity with the given name.
Renders the contents of a MeshComponent using the given materials.
MaterialInstanceHandle material
Material used to render the mesh.
glm::quat beamRotation
Rotation of the beam relative to the parent transform.
glm::dvec3 lastPickedPos
World coordinates of the last raypick hit.
bool active
whether the beam is active and should be visible and update the picked position each frame
glm::vec4 diffuseColor
diffuse color of the beam and marker
EntityId lastPickedEntity
Last entity picked.
glm::vec4 emissiveColor
emissive color of the beam and marker
glm::vec3 beamOffset
Offset of the beam starting point relative to the parent transform.
Base component for all rendering content.
int32_t drawOrder
Draw order within a render bucke.
constexpr void unsetRenderFlag(RenderFlags flag)
Unset the given flag.
Contains information on how the entity behaves in the scene.
bool visible
If the entity this component is a member of should be visible.
bool pickable
If the entity this component is a member of should be pickable.
Defines a 4x4 transformation matrix for the entity and a global offset for root entities.
glm::vec3 scale
Scale factor to apply to each of the axes.
glm::quat rotation
Rotation given as a quaternion.
glm::vec3 position
Local position relative to the global coordinates, or the parent coordinate system if the parent fiel...
glm::dvec3 getOrigin() const
Gets the Origin offset of the scene.
void update(class Context *context) override
Updates the transform system.
void updateTransformData(const TransformComponent &component)
Force an update of the transform data associated with the given component.
Log implementation class.
Definition: LogManager.h:140
Field definition describing a single data member of a data structure.
Definition: Field.h:70
Simple method definition.
Definition: Method.h:72
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
std::shared_ptr< ComponentModel::Entity > EntityPtr
Smart pointer for Entity access.
Definition: EntityPtr.h:12
@ Closest
Return just the closest hit.
@ CastShadows
Casts shadows.
@ EnablePicking
Supports picking.
@ None
No flags specified,.
@ Perspective
Perspective projection.
@ Cylinder
Generic cylinder shape.
@ Sphere
Generic sphere shape.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
Contains reflection support.
Definition: Component.h:11
void setChanged(Cogs::Core::Context *context, Cogs::ComponentModel::Component *component, Reflection::FieldId fieldId)
Must be Called after changing a Component field. Mark field changed. Request engine update.
Definition: FieldSetter.h:25
void setOption(const StringView &key, const StringView &value)
Sets the option with the given key to a value parsed from the value string.
Generates mesh data and assigns the generated mesh to a MeshComponent on the same entity.
Represents an unique name.
Definition: Name.h:70