1#include "SceneFunctions.h"
3#include "Utilities/Math.h"
5#include "Scene/RayPick.h"
6#include "Scene/GetBounds.h"
7#include "Scene/GetDepth.h"
11#include "EntityStore.h"
12#include "ViewContext.h"
14#include "Systems/Core/TransformSystem.h"
15#include "Systems/Core/CameraSystem.h"
17#include "Utilities/CameraUtils.h"
19#include "Renderer/IRenderer.h"
21#include "Math/Projection.h"
33 inline glm::vec3* castToVec3(
float* input) {
34 return reinterpret_cast<glm::vec3*
>(input);
36 inline const glm::vec3* castToVec3(
const float* input) {
37 return reinterpret_cast<const glm::vec3*
>(input);
40 inline glm::dvec3* castToDVec3(
double* input) {
41 return reinterpret_cast<glm::dvec3*
>(input);
43 inline const glm::dvec3* castToDVec3(
const double* input) {
44 return reinterpret_cast<const glm::dvec3*
>(input);
47 inline const glm::quat* castToQuat(
const float* input) {
48 return reinterpret_cast<const glm::quat*
>(input);
52 template<
typename CoordType>
53 int copyPickResults(
const Context* context,
const std::vector<RayPicking::RayPickHit>& hits,
const int bufferSize,
54 EntityId* rootIds, EntityId* entityIds, CoordType* coordinates,
float* textureCoords)
56 size_t resultsLength = std::min(hits.size(),
static_cast<size_t>(bufferSize));
57 for (
size_t i = 0; i < resultsLength; i++) {
61 rootIds[i] = hit.
root;
67 if constexpr (std::is_same_v<CoordType, float>) {
68 coordinates[3 * i + 0] = hit.
position.x;
69 coordinates[3 * i + 1] = hit.
position.y;
70 coordinates[3 * i + 2] = hit.
position.z;
72 else if constexpr (std::is_same_v<CoordType, double>) {
73 const glm::dvec3 wc = context->transformSystem->worldFromEngineCoords(hit.
position);
74 coordinates[3 * i + 0] = wc.x;
75 coordinates[3 * i + 1] = wc.y;
76 coordinates[3 * i + 2] = wc.z;
87 return static_cast<int>(hits.size());
91void setOrigin(BridgeContext* ctx,
const double * origin)
95 context->transformSystem->
setOrigin(*castToDVec3(origin));
98void getOrigin(BridgeContext* ctx,
double* origin)
102 auto sceneOrigin = context->transformSystem->
getOrigin();
103 origin[0] = sceneOrigin.x;
104 origin[1] = sceneOrigin.y;
105 origin[2] = sceneOrigin.z;
108CogsBool getProjectedCoordinates(BridgeContext* ctx,
int x,
int y,
const float* normal,
const float* position,
float* coordinates) {
111 return view ? getProjectedCoordinatesInView(view, x, y, normal, position, coordinates) : false;
114CogsBool getProjectedCoordinatesWorld(BridgeContext* ctx,
float x,
float y,
const float* normal,
const double* worldPosition,
double* coordinates) {
117 return view ? getProjectedCoordinatesInViewWorld(view, x, y, normal, worldPosition, coordinates) : false;
120CogsBool getProjectedCoordinatesWorldUnit(BridgeContext* ctx,
float x,
float y,
const float* normal,
const double* worldPosition,
double* worldResult)
125 glm::vec3 enginePosition = context->transformSystem->engineFromWorldCoords(*castToDVec3(worldPosition));
126 glm::vec3 engineResult;
129 normal ? *castToVec3(normal) : glm::vec3(0.f),
133 *castToDVec3(worldResult) = context->transformSystem->worldFromEngineCoords(engineResult);
140CogsBool getProjectedCoordinatesInView(BridgeView* bv,
int x,
int y,
const float* normal,
const float* position,
float* coordinates) {
147 *castToVec3(position),
148 *castToVec3(coordinates));
151CogsBool getProjectedCoordinatesInViewWorld(BridgeView* bv,
float x,
float y,
const float* normal,
const double* worldPosition,
double* coordinates) {
155 glm::vec3 position = view->getContext()->transformSystem->engineFromWorldCoords(*castToDVec3(worldPosition));
156 bool result = getProjectedCoordinatesInView(bv,
int(x),
int(y), normal, &position[0], &coords[0]);
158 *castToDVec3(coordinates) = view->getContext()->transformSystem->worldFromEngineCoords(coords);
163int pickWithCameraRay(BridgeContext* ctx, EntityId cameraId,
float x,
float y,
164 float rayLength,
float rayRadius,
int pickingFlags,
int returnFlag,
int layerMask,
const char* entityType,
165 int bufferSize, EntityId* entityIds, EntityId* rootIds,
double* coordinates,
float* textureCoords)
169 assert(cameraEntity);
173 const size_t typeCode = entityType ==
nullptr ? RayPicking::NoPickEntityType :
Cogs::StringView(entityType).
hash();
174 std::vector<RayPicking::RayPickHit> hits;
177 context->
rayPicking->pickCamera(context, *cameraComp, glm::vec2(x, y), rayLength, rayRadius,
190 const CameraData& cameraData = context->cameraSystem->getData(cameraComp);
192 const glm::vec2 normPos = (2.f * (glm::vec2(x + 0.5f, y + 0.5f)) / cameraData.viewportSize) - glm::vec2(1.f);
193 const float sx = cameraData.viewportSize.x / rayRadius;
194 const float sy = cameraData.viewportSize.y / rayRadius;
195 const glm::mat4 worldPickMatrix = glm::mat4(sx, 0.f, 0.f, 0.f,
198 -normPos.x * sx, -normPos.y * sy, 0.f, 1.f) * cameraData.rawViewProjection;
199 const glm::vec3 a = euclidean(glm::inverse(worldPickMatrix) * glm::vec4(0.f, 0.f, 1.f, -1.f));
200 const glm::vec3 b = euclidean(glm::inverse(worldPickMatrix) * glm::vec4(0.f, 0.f, 1.f, 1.f));
201 const glm::vec3 c = euclidean(glm::inverse(worldPickMatrix) * glm::vec4(1.f, 1.f, 1.f, -1.f));
202 const float rayRadiusWorld = glm::distance(a, c);
203 const glm::quat rot = glm::quat(glm::vec3(0.f, 0.f, -1.f), glm::normalize(b - a));
205 context->
rayPicking->pickRay(context, a, rot, rayLength, rayRadiusWorld,
211 return copyPickResults(context, hits, bufferSize, rootIds, entityIds, coordinates, textureCoords);
214int pickWithCameraRayWorldUnit(BridgeContext* ctx, EntityId cameraId,
float x,
float y,
215 float rayLength,
float inRayRadius,
int pickingFlags,
int returnFlag,
int layerMask,
const char* entityType,
216 int bufferSize, EntityId* entityIds, EntityId* rootIds,
double* coordinates,
float* textureCoords)
220 assert(cameraEntity);
224 const CameraData& cameraData = context->cameraSystem->getData(cameraComp);
225 const glm::vec2 p = glm::vec2(x, 1.f - y) * cameraData.viewportSize;
227 const float screenRadius = std::max(1.f, inRayRadius * cameraData.viewportSize.y);
229 const size_t typeCode = entityType ==
nullptr ? RayPicking::NoPickEntityType :
Cogs::StringView(entityType).
hash();
230 std::vector<RayPicking::RayPickHit> hits;
231 context->
rayPicking->pickCamera(context, *cameraComp, p, rayLength, screenRadius,
235 return copyPickResults(context, hits, bufferSize, rootIds, entityIds, coordinates, textureCoords);
238int pickWithWorldRay(BridgeContext* ctx,
const double* worldPosition,
const float* orientation,
239 float rayLength,
float rayRadius,
int pickingFlags,
int returnFlag,
int layerMask,
const char* entityType,
240 int bufferSize, EntityId* entityIds, EntityId* rootIds,
double* coordinates,
float* textureCoords)
244 glm::vec3 pos = context->transformSystem->engineFromWorldCoords(*castToDVec3(worldPosition));
245 glm::quat rot = *castToQuat(orientation);
246 const size_t typeCode = entityType ==
nullptr ? RayPicking::NoPickEntityType :
Cogs::StringView(entityType).
hash();
247 std::vector<RayPicking::RayPickHit> hits;
248 context->
rayPicking->pickRay(context, pos, rot, rayLength, rayRadius,
252 return copyPickResults(context, hits, bufferSize, rootIds, entityIds, coordinates, textureCoords);
255EntityId getPickedEntity(BridgeContext* ctx,
int x,
int y,
float * coordinates)
257 return getPickedEntityFull2(ctx,
static_cast<float>(x),
static_cast<float>(y),
int(PickingFlags::None),
nullptr, coordinates,
nullptr);
260EntityId getPickedEntityFull2(BridgeContext* ctx,
float x,
float y,
int pickingFlags, EntityId* rootId,
float* coordinates,
float* textureCoords)
268 const glm::vec2 pickingRegionSize(std::max(1.0, context->
variables->get(
"scene.rayPick.size.x", 4.0)),
269 std::max(1.0, context->
variables->get(
"scene.rayPick.size.y", 4.0)));
271 std::vector<RayPicking::RayPickHit> hits;
272 const bool picked = context->
rayPicking->pickCamera(context, camera, glm::vec2(x, y), std::numeric_limits<float>::max(),
273 glm::length(pickingRegionSize), pickFlags, PicksReturned::Closest, {}, hits);
279 *castToVec3(coordinates) = hit.
position;
293int getAllPickedEntities2(BridgeContext* ctx,
const float x,
const float y,
const int pickingFlags,
const int bufferSize,
294 EntityId* rootIds, EntityId* entityIds,
float* coordinates,
float* textureCoords)
300 const glm::vec2 pickingRegionSize(std::max(1.0, context->
variables->get(
"scene.rayPick.size.x", 4.0)),
301 std::max(1.0, context->
variables->get(
"scene.rayPick.size.y", 4.0)));
303 std::vector<RayPicking::RayPickHit> hits;
304 context->
rayPicking->pickCamera(context, camera, glm::vec2(x, y), std::numeric_limits<float>::max(), glm::length(pickingRegionSize),
305 pickFlags, PicksReturned::AllSorted, {}, hits);
308 return copyPickResults(context, hits, bufferSize, rootIds, entityIds, coordinates, textureCoords);
311int getAllPickedEntitiesFromRay(BridgeContext* ctx,
const float* position,
const float* orientation,
312 const float rayLength,
const float radius,
int pickingFlags,
int bufferSize,
313 EntityId* rootIds, EntityId* entityIds,
float* coordinates,
float* textureCoords)
316 glm::vec3 pos = *castToVec3(position);
317 glm::quat rot = *castToQuat(orientation);
319 std::vector<RayPicking::RayPickHit> hits;
320 context->
rayPicking->pickRay(context, pos, rot, rayLength, radius, pickFlags, PicksReturned::AllSorted, {}, hits);
323 return copyPickResults(context, hits, bufferSize, rootIds, entityIds, coordinates, textureCoords);
326float getDepthWorld(BridgeContext* ctx, EntityId entityId,
const double* position)
329 const glm::dvec3 worldPos = *castToDVec3(position);
330 const glm::vec3 pos = context->transformSystem->engineFromWorldCoords(worldPos);
332 return Cogs::Core::getDepth(context, entityId, pos);
336float getDepth(BridgeContext* ctx, EntityId entityId,
const float * position)
339 return Cogs::Core::getDepth(context, entityId, *castToVec3(position));
342void calculateBoundingBoxWorld(BridgeContext* ctx, EntityId entityId,
double* values)
345 Cogs::Geometry::BoundingBox box;
346 calculateBoundingBox(ctx, entityId, box.data());
348 Cogs::Geometry::DBoundingBox dBox(context->transformSystem->worldFromEngineCoords(box.min),
349 context->transformSystem->worldFromEngineCoords(box.max));
350 dBox.toSpan(std::span<double, 6>(values, 6));
353void calculateBoundingBox(BridgeContext* ctx, EntityId entityId,
float * values)
356 Cogs::Geometry::BoundingBox box = Bounds::getBounds(context, entityId,
true);
357 box.toSpan(std::span<float, 6>(values, 6));
360void calculateBoundingBoxMultiWorld(BridgeContext* ctx, EntityId* entityIds,
int count,
double* values)
364 Cogs::Geometry::BoundingBox box;
365 calculateBoundingBoxMulti(ctx, entityIds, count, box.data());
367 Cogs::Geometry::DBoundingBox dBox(context->transformSystem->worldFromEngineCoords(box.min),
368 context->transformSystem->worldFromEngineCoords(box.max));
369 dBox.toSpan(std::span<double, 6>(values, 6));
372void calculateBoundingBoxMulti(BridgeContext* ctx, EntityId * entityIds,
int count,
float * values)
376 std::span<const EntityId> ids(entityIds, count);
377 Cogs::Geometry::BoundingBox box = Bounds::getBounds(context, ids,
true);
378 box.toSpan(std::span<float, 6>(values, 6));
381void calculateSceneBoundingBoxWorld(BridgeContext* ctx,
double* values)
384 Cogs::Geometry::BoundingBox box;
385 calculateSceneBoundingBox(ctx, box.data());
387 Cogs::Geometry::DBoundingBox dBox(context->transformSystem->worldFromEngineCoords(box.min),
388 context->transformSystem->worldFromEngineCoords(box.max));
389 dBox.toSpan(std::span<double, 6>(values, 6));
393void calculateSceneBoundingBox(BridgeContext* ctx,
float* values)
397 context->
bounds->getSceneBounds(context, values, RenderLayers::AllStandard & ~RenderLayers::Sky);
400void calculateSceneBoundingBoxWorld2(BridgeContext* ctx,
int layerMask,
double* values)
403 Cogs::Geometry::BoundingBox box;
406 context->
bounds->getSceneBounds(context, box.data(), layerMask_);
408 Cogs::Geometry::DBoundingBox dBox(context->transformSystem->worldFromEngineCoords(box.min),
409 context->transformSystem->worldFromEngineCoords(box.max));
410 dBox.toSpan(std::span<double, 6>(values, 6));
Container for components, providing composition of dynamic entities.
T * getComponent() const
Get a pointer to the first component implementing the given type in the entity.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
std::unique_ptr< class Bounds > bounds
Bounds service instance.
class EntityStore * store
Entity store.
std::unique_ptr< class RayPicking > rayPicking
RayPicking service instance.
std::unique_ptr< class Variables > variables
Variables service instance.
ComponentModel::Entity * getEntityPtr(const EntityId entityId)
Get a raw pointer to the entity with the given id.
CameraComponent * getCameraComponent() const
Utility to get the CameraComponent from.
Provides a weakly referenced view over the contents of a string.
constexpr size_t hash() const noexcept
Get the hash code of the string.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
PicksReturned
* Options for returning picking hits.
PickingFlags
Options for COGS picking.
RenderLayers
Contains common render layers.
bool getProjectedCoordinates(const glm::vec2 &coordinatesToProject, const CameraData &cameraData, const glm::vec3 &targetPlaneNormal, const glm::vec3 &targetPlanePosition, glm::vec3 &projectedCoordinates)
Project a screen coordinate onto a plane in 3d space.
Contains data describing a Camera instance and its derived data structured such as matrix data and vi...
glm::vec3 position
The picked position.
EntityId entity
The EntityId picked.