Bring the entity-component system online: rendering, scene manager, scripting
entityRenderAll() (src/dusk/entity/entityrender.c) ports ac2's scene.c:sceneRender() camera/view-matrix/draw-loop logic as a standalone function - find the active camera, bind SHADER_UNLIT with its projection/ view, draw every COMPONENT_TYPE_RENDERABLE entity. display.c calls it each frame between the screen clear and screenUnbind(), the same spot the old sceneRender() used to sit. A single-scene scene manager (src/dusk/scene/, ported from ac2 minus its prefab system and physics/trigger stepping - that module hasn't been ported yet) sits alongside this but isn't wired into the engine loop yet; only one scene can ever exist (no SCENE_COUNT_MAX array). entitymanager.c/h removed entirely: its three arrays (entities/components/ entitiesWithComponent) are now plain globals in entity.h/.c (ENTITIES/COMPONENTS/ENTITIES_WITH_COMPONENT), and every entity/component function across the whole ECS (entity, component, position, camera, renderable, physics, trigger, animation) drops its entitymanager_t *mgr parameter to operate on them directly - there was only ever one instance of that struct in the whole engine, so the indirection bought nothing. New duskscript bindings (src/dusk/script/native/entity/) expose entityAdd, entityAddComponent/entityGetComponent, entitySetName/entityGetName/ entityFindByName, entityDispose/entityDisposeDeep, entityPositionSetLocalPosition/entityPositionLookAt, entityRenderableSetMesh (by name - cube/plane/sphere/capsule/triprism/quad), and COMPONENT_TYPE_*/ENTITY_ID_INVALID/COMPONENT_ID_INVALID constants. assets/init.ds uses them to spawn a camera (via LookAt from (3,3,3) at the origin), a cube and a plane as the engine's first real content on the new ECS. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
1 parent
fdfdfa3a66
commit
9a24b3d7db
43 files changed
+1084
-605
No files matched your search
+19
-1
@@ -1,2 +1,20 @@
|
||||
// Entry point, run once by the engine after every other system is ready.
|
||||
consolePrint("Test");
|
||||
|
||||
var camera = entityAdd();
|
||||
var cameraPosition = entityAddComponent(camera, COMPONENT_TYPE_POSITION);
|
||||
entityAddComponent(camera, COMPONENT_TYPE_CAMERA);
|
||||
entityPositionLookAt(camera, cameraPosition, 3, 3, 3, 0, 0, 0);
|
||||
|
||||
var cube = entityAdd();
|
||||
var cubePosition = entityAddComponent(cube, COMPONENT_TYPE_POSITION);
|
||||
var cubeRenderable = entityAddComponent(cube, COMPONENT_TYPE_RENDERABLE);
|
||||
entityRenderableSetMesh(cube, cubeRenderable, "cube");
|
||||
entityPositionSetLocalPosition(cube, cubePosition, 0, 0, 0);
|
||||
|
||||
var plane = entityAdd();
|
||||
var planePosition = entityAddComponent(plane, COMPONENT_TYPE_POSITION);
|
||||
var planeRenderable = entityAddComponent(plane, COMPONENT_TYPE_RENDERABLE);
|
||||
entityRenderableSetMesh(plane, planeRenderable, "plane");
|
||||
entityPositionSetLocalPosition(plane, planePosition, 0, 0, 0);
|
||||
|
||||
consolePrint("Camera, cube and plane created");
|
||||
@@ -82,12 +82,10 @@ add_subdirectory(error)
|
||||
add_subdirectory(input)
|
||||
add_subdirectory(locale)
|
||||
add_subdirectory(perf)
|
||||
add_subdirectory(rpg)
|
||||
add_subdirectory(script)
|
||||
add_subdirectory(scene)
|
||||
add_subdirectory(script)
|
||||
add_subdirectory(system)
|
||||
add_subdirectory(time)
|
||||
add_subdirectory(ui)
|
||||
add_subdirectory(save)
|
||||
add_subdirectory(util)
|
||||
add_subdirectory(thread)
|
||||
@@ -7,7 +7,8 @@
|
||||
|
||||
#include "display/display.h"
|
||||
#include "display/framebuffer/framebuffer.h"
|
||||
#include "scene/scene.h"
|
||||
#include "entity/entity.h"
|
||||
#include "entity/entityrender.h"
|
||||
#include "display/spritebatch/spritebatch.h"
|
||||
#include "display/mesh/quad.h"
|
||||
#include "display/mesh/cube.h"
|
||||
@@ -16,7 +17,6 @@
|
||||
#include "display/mesh/capsule.h"
|
||||
#include "display/mesh/triprism.h"
|
||||
#include "display/screen/screen.h"
|
||||
#include "ui/ui.h"
|
||||
#include "display/text/text.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
@@ -76,14 +76,14 @@ errorret_t displayUpdate(void) {
|
||||
spriteBatchClear();
|
||||
errorChain(frameBufferBind(NULL));
|
||||
|
||||
// Bind screen and render scene
|
||||
// Bind screen and render the entity world
|
||||
errorChain(screenBind());
|
||||
frameBufferClear(
|
||||
FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH,
|
||||
SCREEN.background
|
||||
);
|
||||
|
||||
errorChain(sceneRender());
|
||||
errorChain(entityRenderAll());
|
||||
|
||||
// Finish up
|
||||
screenUnbind();
|
||||
|
||||
@@ -11,11 +11,9 @@
|
||||
#include "time/time.h"
|
||||
#include "input/input.h"
|
||||
#include "locale/localemanager.h"
|
||||
#include "rpg/rpg.h"
|
||||
#include "display/display.h"
|
||||
#include "scene/scene.h"
|
||||
#include "entity/entity.h"
|
||||
#include "asset/asset.h"
|
||||
#include "ui/ui.h"
|
||||
#include "assert/assert.h"
|
||||
#ifdef DUSK_NETWORK
|
||||
#include "network/network.h"
|
||||
@@ -48,13 +46,11 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
errorChain(localeManagerInit());
|
||||
errorChain(displayInit());
|
||||
errorChain(audioInit());
|
||||
errorChain(rpgInit());
|
||||
errorChain(uiInit());
|
||||
entityManagerInit();
|
||||
#ifdef DUSK_NETWORK
|
||||
errorChain(networkInit());
|
||||
#endif
|
||||
errorChain(scriptInit());
|
||||
errorChain(sceneInit());
|
||||
|
||||
// Runs once every other system is ready, so init.ds can use any of them.
|
||||
scripterror_t scriptInitError;
|
||||
@@ -70,8 +66,6 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
consolePrint("Assertions real");
|
||||
#endif
|
||||
|
||||
sceneSet(SCENE_TYPE_INITIAL);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -85,10 +79,8 @@ errorret_t engineUpdate(void) {
|
||||
inputUpdate();
|
||||
consoleUpdate();
|
||||
errorChain(audioUpdateEarly());
|
||||
errorChain(rpgUpdate());
|
||||
errorChain(sceneUpdate());
|
||||
errorChain(assetUpdate());
|
||||
errorChain(uiUpdate());
|
||||
entityManagerUpdate();
|
||||
|
||||
// Render
|
||||
errorChain(displayUpdate());
|
||||
@@ -102,14 +94,12 @@ void engineExit(void) {
|
||||
}
|
||||
|
||||
errorret_t engineDispose(void) {
|
||||
errorChain(sceneDispose());
|
||||
errorChain(scriptDispose());
|
||||
entityManagerDispose();
|
||||
#ifdef DUSK_NETWORK
|
||||
errorChain(networkDispose());
|
||||
#endif
|
||||
errorChain(rpgDispose());
|
||||
localeManagerDispose();
|
||||
errorChain(uiDispose());
|
||||
errorChain(audioDispose());
|
||||
consoleDispose();
|
||||
errorChain(displayDispose());
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
entity.c
|
||||
entitymanager.c
|
||||
entityrender.c
|
||||
component.c
|
||||
)
|
||||
|
||||
|
||||
+13
-22
@@ -5,7 +5,7 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entitymanager.h"
|
||||
#include "entity.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
@@ -28,41 +28,37 @@ componentdefinition_t COMPONENT_DEFINITIONS[] = {
|
||||
};
|
||||
|
||||
void componentInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const componenttype_t type
|
||||
) {
|
||||
assertNotNull(mgr, "Entity manager cannot be null");
|
||||
assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB");
|
||||
assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB");
|
||||
assertTrue(type < COMPONENT_TYPE_COUNT, "Component type OOB");
|
||||
assertTrue(type != COMPONENT_TYPE_NULL, "Cannot initialize null component");
|
||||
|
||||
componentindex_t index = componentGetIndex(entityId, componentId);
|
||||
component_t *cmp = &mgr->components[index];
|
||||
component_t *cmp = &COMPONENTS[index];
|
||||
memoryZero(cmp, sizeof(component_t));
|
||||
|
||||
cmp->type = type;
|
||||
if(COMPONENT_DEFINITIONS[type].init) {
|
||||
COMPONENT_DEFINITIONS[type].init(mgr, entityId, componentId);
|
||||
COMPONENT_DEFINITIONS[type].init(entityId, componentId);
|
||||
}
|
||||
}
|
||||
|
||||
void * componentGetData(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const componenttype_t type
|
||||
) {
|
||||
assertNotNull(mgr, "Entity manager cannot be null");
|
||||
assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB");
|
||||
assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB");
|
||||
assertTrue(type < COMPONENT_TYPE_COUNT, "Component type OOB");
|
||||
assertTrue(type != COMPONENT_TYPE_NULL, "Cannot get data of null component");
|
||||
|
||||
componentindex_t index = componentGetIndex(entityId, componentId);
|
||||
component_t *cmp = &mgr->components[index];
|
||||
component_t *cmp = &COMPONENTS[index];
|
||||
assertTrue(cmp->type == type, "Component type mismatch");
|
||||
|
||||
return &cmp->data;
|
||||
@@ -78,12 +74,10 @@ componentindex_t componentGetIndex(
|
||||
}
|
||||
|
||||
entityid_t componentGetEntitiesWithComponent(
|
||||
entitymanager_t *mgr,
|
||||
const componenttype_t type,
|
||||
entityid_t outEntities[ENTITY_COUNT_MAX],
|
||||
componentid_t outComponents[ENTITY_COUNT_MAX]
|
||||
) {
|
||||
assertNotNull(mgr, "Entity manager cannot be null");
|
||||
assertTrue(type < COMPONENT_TYPE_COUNT, "Component type OOB");
|
||||
assertTrue(type != COMPONENT_TYPE_NULL, "Cannot check NULL type");
|
||||
assertNotNull(outEntities, "Output entities array cannot be null");
|
||||
@@ -91,16 +85,16 @@ entityid_t componentGetEntitiesWithComponent(
|
||||
|
||||
entityid_t written = 0;
|
||||
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
|
||||
componentid_t used = mgr->entitiesWithComponent[
|
||||
componentid_t used = ENTITIES_WITH_COMPONENT[
|
||||
type * ENTITY_COUNT_MAX + i
|
||||
];
|
||||
if(used == COMPONENT_ID_INVALID) continue;
|
||||
assertTrue(
|
||||
mgr->components[componentGetIndex(i, used)].type == type,
|
||||
COMPONENTS[componentGetIndex(i, used)].type == type,
|
||||
"Component type mismatch in entitiesWithComponent lookup"
|
||||
);
|
||||
assertTrue(
|
||||
(mgr->entities[i].state & ENTITY_STATE_ACTIVE) != 0,
|
||||
(ENTITIES[i].state & ENTITY_STATE_ACTIVE) != 0,
|
||||
"Inactive entity in entitiesWithComponent lookup"
|
||||
);
|
||||
assertTrue(
|
||||
@@ -117,35 +111,32 @@ entityid_t componentGetEntitiesWithComponent(
|
||||
return written;
|
||||
}
|
||||
|
||||
errorret_t componentRenderAll(entitymanager_t *mgr) {
|
||||
assertNotNull(mgr, "Entity manager cannot be null");
|
||||
errorret_t componentRenderAll(void) {
|
||||
for(entityid_t eid = 0; eid < ENTITY_COUNT_MAX; eid++) {
|
||||
if(!(mgr->entities[eid].state & ENTITY_STATE_ACTIVE)) continue;
|
||||
if(!(ENTITIES[eid].state & ENTITY_STATE_ACTIVE)) continue;
|
||||
for(componentid_t cid = 0; cid < ENTITY_COMPONENT_COUNT_MAX; cid++) {
|
||||
component_t *cmp = &mgr->components[componentGetIndex(eid, cid)];
|
||||
component_t *cmp = &COMPONENTS[componentGetIndex(eid, cid)];
|
||||
if(cmp->type == COMPONENT_TYPE_NULL) continue;
|
||||
if(!COMPONENT_DEFINITIONS[cmp->type].render) continue;
|
||||
errorChain(COMPONENT_DEFINITIONS[cmp->type].render(mgr, eid, cid));
|
||||
errorChain(COMPONENT_DEFINITIONS[cmp->type].render(eid, cid));
|
||||
}
|
||||
}
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void componentDispose(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
assertNotNull(mgr, "Entity manager cannot be null");
|
||||
assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB");
|
||||
assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB");
|
||||
|
||||
componentindex_t index = componentGetIndex(entityId, componentId);
|
||||
component_t *cmp = &mgr->components[index];
|
||||
component_t *cmp = &COMPONENTS[index];
|
||||
if(cmp->type == COMPONENT_TYPE_NULL) return;
|
||||
|
||||
if(COMPONENT_DEFINITIONS[cmp->type].dispose) {
|
||||
COMPONENT_DEFINITIONS[cmp->type].dispose(mgr, entityId, componentId);
|
||||
COMPONENT_DEFINITIONS[cmp->type].dispose(entityId, componentId);
|
||||
}
|
||||
|
||||
cmp->type = COMPONENT_TYPE_NULL;
|
||||
|
||||
@@ -23,12 +23,10 @@ typedef union {
|
||||
/**
|
||||
* Callback signature for a component's init/dispose hooks.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
*/
|
||||
typedef void (*componentcallback_t)(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -36,13 +34,11 @@ typedef void (*componentcallback_t)(
|
||||
/**
|
||||
* Callback signature for a component's render hook.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return Error state.
|
||||
*/
|
||||
typedef errorret_t (*componentcallbackerror_t)(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -76,13 +72,11 @@ extern componentdefinition_t COMPONENT_DEFINITIONS[];
|
||||
/**
|
||||
* Initializes a component of the given type for the entity with component ID.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param type The type of the component to initialize.
|
||||
*/
|
||||
void componentInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const componenttype_t type
|
||||
@@ -91,14 +85,12 @@ void componentInit(
|
||||
/**
|
||||
* Gets the pointer to the data of a component for the entity with component ID.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param type The type of the component to get, only used for assertion.
|
||||
* @return A pointer to the component data.
|
||||
*/
|
||||
void * componentGetData(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const componenttype_t type
|
||||
@@ -119,7 +111,6 @@ componentindex_t componentGetIndex(
|
||||
/**
|
||||
* Gets the entity IDs of all entities with a component of the given type.
|
||||
*
|
||||
* @param mgr The entity manager to search.
|
||||
* @param type The type of the component to get entities for.
|
||||
* @param outEntities An array to write the entity IDs to, must be at least
|
||||
* ENTITY_COUNT_MAX in size.
|
||||
@@ -127,7 +118,6 @@ componentindex_t componentGetIndex(
|
||||
* @return The number of entity IDs written to outEntities.
|
||||
*/
|
||||
entityid_t componentGetEntitiesWithComponent(
|
||||
entitymanager_t *mgr,
|
||||
const componenttype_t type,
|
||||
entityid_t outEntities[ENTITY_COUNT_MAX],
|
||||
componentid_t outComponents[ENTITY_COUNT_MAX]
|
||||
@@ -136,12 +126,10 @@ entityid_t componentGetEntitiesWithComponent(
|
||||
/**
|
||||
* Disposes of a component for the entity with component ID.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
*/
|
||||
void componentDispose(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -151,7 +139,6 @@ void componentDispose(
|
||||
* Iterates all active entities and all their component slots. No-op for
|
||||
* components whose definition has render == NULL.
|
||||
*
|
||||
* @param mgr The entity manager to render.
|
||||
* @return Error state.
|
||||
*/
|
||||
errorret_t componentRenderAll(entitymanager_t *mgr);
|
||||
errorret_t componentRenderAll(void);
|
||||
@@ -6,53 +6,49 @@
|
||||
*/
|
||||
|
||||
#include "entityanimation.h"
|
||||
#include "entity/entitymanager.h"
|
||||
#include "entity/entity.h"
|
||||
#include "util/memory.h"
|
||||
#include "time/time.h"
|
||||
|
||||
void entityAnimationInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
|
||||
|
||||
memoryZero(animComp, sizeof(entityanimation_t));
|
||||
animComp->speed = 1.0f;
|
||||
|
||||
entityUpdateAdd(mgr, entityId, entityAnimationUpdate, componentId, NULL);
|
||||
entityUpdateAdd(entityId, entityAnimationUpdate, componentId, NULL);
|
||||
}
|
||||
|
||||
entityanimation_t *entityAnimationGet(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
return componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_ANIMATION
|
||||
entityId, componentId, COMPONENT_TYPE_ANIMATION
|
||||
);
|
||||
}
|
||||
|
||||
void entityAnimationSetKeyframes(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
keyframe_t *keyframes,
|
||||
uint16_t *keyframeCounts,
|
||||
const uint16_t layerCount
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
|
||||
animationInit(&animComp->anim, keyframes, keyframeCounts, layerCount);
|
||||
animComp->speed = 1.0f;
|
||||
animComp->playing = false;
|
||||
}
|
||||
|
||||
void entityAnimationPlay(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
|
||||
animComp->anim.time = 0.0f;
|
||||
// Clear the internal completed latch so a previously-finished
|
||||
// (non-looping) animation can actually advance again.
|
||||
@@ -61,61 +57,55 @@ void entityAnimationPlay(
|
||||
}
|
||||
|
||||
void entityAnimationStop(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
|
||||
animComp->playing = false;
|
||||
}
|
||||
|
||||
bool_t entityAnimationIsPlaying(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
|
||||
return animComp->playing;
|
||||
}
|
||||
|
||||
void entityAnimationSetLoop(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const bool_t loop
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
|
||||
if(loop) animComp->anim.flags |= ANIMATION_FLAG_LOOP;
|
||||
else animComp->anim.flags &= ~ANIMATION_FLAG_LOOP;
|
||||
}
|
||||
|
||||
void entityAnimationSetSpeed(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const float_t speed
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
|
||||
animComp->speed = speed;
|
||||
}
|
||||
|
||||
float_t entityAnimationGetValue(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const uint16_t channelIndex
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
|
||||
return animationGetLayerValue(&animComp->anim, channelIndex);
|
||||
}
|
||||
|
||||
void entityAnimationUpdate(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
) {
|
||||
entityanimation_t *animComp = entityAnimationGet(mgr, entityId, componentId);
|
||||
entityanimation_t *animComp = entityAnimationGet(entityId, componentId);
|
||||
if(!animComp->playing) return;
|
||||
animationUpdate(&animComp->anim, TIME.delta * animComp->speed);
|
||||
}
|
||||
@@ -34,12 +34,10 @@ typedef struct {
|
||||
* entityAnimationUpdate as an update callback. Call
|
||||
* entityAnimationSetKeyframes() before entityAnimationPlay().
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
*/
|
||||
void entityAnimationInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -48,14 +46,12 @@ void entityAnimationInit(
|
||||
* Gets the underlying animation structure (temporarily) for the given
|
||||
* entity. Prefer the dedicated getters/setters where possible.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return The animation component data for the given entity and
|
||||
* component ID.
|
||||
*/
|
||||
entityanimation_t *entityAnimationGet(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -66,7 +62,6 @@ entityanimation_t *entityAnimationGet(
|
||||
* they point to are not copied, and must outlive this component (e.g.
|
||||
* static/const arrays owned by the caller).
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param keyframes Flat array of keyframe_t, one contiguous run per layer
|
||||
@@ -76,7 +71,6 @@ entityanimation_t *entityAnimationGet(
|
||||
* @param layerCount The number of layers/channels.
|
||||
*/
|
||||
void entityAnimationSetKeyframes(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
keyframe_t *keyframes,
|
||||
@@ -87,12 +81,10 @@ void entityAnimationSetKeyframes(
|
||||
/**
|
||||
* Starts (or restarts) playback from time 0.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
*/
|
||||
void entityAnimationPlay(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -100,12 +92,10 @@ void entityAnimationPlay(
|
||||
/**
|
||||
* Stops playback without resetting the current time.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
*/
|
||||
void entityAnimationStop(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -113,13 +103,11 @@ void entityAnimationStop(
|
||||
/**
|
||||
* Checks whether the animation is currently playing.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return True if playing.
|
||||
*/
|
||||
bool_t entityAnimationIsPlaying(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -128,13 +116,11 @@ bool_t entityAnimationIsPlaying(
|
||||
* Sets whether the animation loops on reaching its final keyframe, rather
|
||||
* than stopping there.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param loop True to loop, false to stop at the end.
|
||||
*/
|
||||
void entityAnimationSetLoop(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const bool_t loop
|
||||
@@ -143,13 +129,11 @@ void entityAnimationSetLoop(
|
||||
/**
|
||||
* Sets the animation's playback rate multiplier.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param speed The new playback rate; 1.0 = normal speed.
|
||||
*/
|
||||
void entityAnimationSetSpeed(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const float_t speed
|
||||
@@ -159,7 +143,6 @@ void entityAnimationSetSpeed(
|
||||
* Evaluates one of the animation's channels at its current playback
|
||||
* time, regardless of whether it's currently playing.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param channelIndex The channel to evaluate, in [0, channelCount) as
|
||||
@@ -167,7 +150,6 @@ void entityAnimationSetSpeed(
|
||||
* @return That channel's value at the current time.
|
||||
*/
|
||||
float_t entityAnimationGetValue(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const uint16_t channelIndex
|
||||
@@ -178,13 +160,11 @@ float_t entityAnimationGetValue(
|
||||
* (a no-op if not playing). Registered automatically as an update
|
||||
* callback by entityAnimationInit.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param user Unused.
|
||||
*/
|
||||
void entityAnimationUpdate(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
|
||||
@@ -5,18 +5,16 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entity/entitymanager.h"
|
||||
#include "entity/entity.h"
|
||||
#include "entity/component/display/entityposition.h"
|
||||
#include "display/screen/screen.h"
|
||||
|
||||
void entityCameraInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entitycamera_t *cam = (entitycamera_t *)componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_CAMERA
|
||||
entityId, componentId, COMPONENT_TYPE_CAMERA
|
||||
);
|
||||
cam->nearClip = 0.1f;
|
||||
cam->farClip = 5000.0f;
|
||||
@@ -25,13 +23,12 @@ void entityCameraInit(
|
||||
}
|
||||
|
||||
void entityCameraGetProjection(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
mat4 out
|
||||
) {
|
||||
entitycamera_t *cam = (entitycamera_t *)componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_CAMERA
|
||||
entityId, componentId, COMPONENT_TYPE_CAMERA
|
||||
);
|
||||
|
||||
if(
|
||||
@@ -64,26 +61,25 @@ void entityCameraGetProjection(
|
||||
}
|
||||
}
|
||||
|
||||
entityid_t entityCameraGetCurrent(entitymanager_t *mgr) {
|
||||
entityid_t entityCameraGetCurrent(void) {
|
||||
entityid_t camEnts[ENTITY_COUNT_MAX];
|
||||
componentid_t camComps[ENTITY_COUNT_MAX];
|
||||
entityid_t count = componentGetEntitiesWithComponent(
|
||||
mgr, COMPONENT_TYPE_CAMERA, camEnts, camComps
|
||||
COMPONENT_TYPE_CAMERA, camEnts, camComps
|
||||
);
|
||||
if(count == 0) return ENTITY_ID_INVALID;
|
||||
return camEnts[0];
|
||||
}
|
||||
|
||||
void entityCameraGetForward(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
vec2 out
|
||||
) {
|
||||
componentid_t posComp = entityGetComponent(
|
||||
mgr, entityId, COMPONENT_TYPE_POSITION
|
||||
entityId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
mat4 transform;
|
||||
entityPositionGetTransform(mgr, entityId, posComp, transform);
|
||||
entityPositionGetTransform(entityId, posComp, transform);
|
||||
// transform is an object->world matrix; column 2 is the entity's local Z
|
||||
// axis expressed in world space. Cameras look down their local -Z.
|
||||
float_t fx = -transform[2][0];
|
||||
@@ -95,15 +91,14 @@ void entityCameraGetForward(
|
||||
}
|
||||
|
||||
void entityCameraGetRight(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
vec2 out
|
||||
) {
|
||||
componentid_t posComp = entityGetComponent(
|
||||
mgr, entityId, COMPONENT_TYPE_POSITION
|
||||
entityId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
mat4 transform;
|
||||
entityPositionGetTransform(mgr, entityId, posComp, transform);
|
||||
entityPositionGetTransform(entityId, posComp, transform);
|
||||
// transform is an object->world matrix; column 0 is the entity's local X
|
||||
// (right) axis expressed in world space.
|
||||
float_t rx = transform[0][0];
|
||||
@@ -115,7 +110,6 @@ void entityCameraGetRight(
|
||||
}
|
||||
|
||||
void entityCameraLookAtPixelPerfect(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t ent,
|
||||
const componentid_t posComp,
|
||||
const componentid_t camComp,
|
||||
@@ -124,7 +118,7 @@ void entityCameraLookAtPixelPerfect(
|
||||
const float_t scale
|
||||
) {
|
||||
entitycamera_t *cam = (entitycamera_t *)componentGetData(
|
||||
mgr, ent, camComp, COMPONENT_TYPE_CAMERA
|
||||
ent, camComp, COMPONENT_TYPE_CAMERA
|
||||
);
|
||||
float_t dist = (
|
||||
(float_t)SCREEN.height / (2.0f * scale * tanf(cam->perspective.fov * 0.5f))
|
||||
@@ -136,5 +130,5 @@ void entityCameraLookAtPixelPerfect(
|
||||
point[2] + eyeOffset[2]
|
||||
};
|
||||
vec3 up = { 0.0f, 0.0f, -1.0f };
|
||||
entityPositionLookAt(mgr, ent, posComp, eye, (float_t *)point, up);
|
||||
entityPositionLookAt(ent, posComp, eye, (float_t *)point, up);
|
||||
}
|
||||
@@ -37,12 +37,10 @@ typedef struct {
|
||||
/**
|
||||
* Initializes an entity camera component.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
*/
|
||||
void entityCameraInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -50,13 +48,11 @@ void entityCameraInit(
|
||||
/**
|
||||
* Renders out the projection matrix for the given camera.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param out The output projection matrix.
|
||||
*/
|
||||
void entityCameraGetProjection(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
mat4 out
|
||||
@@ -66,21 +62,18 @@ void entityCameraGetProjection(
|
||||
* Returns the entity ID of the first active camera, or ENTITY_ID_INVALID if
|
||||
* none are active.
|
||||
*
|
||||
* @param mgr The entity manager to search.
|
||||
*/
|
||||
entityid_t entityCameraGetCurrent(entitymanager_t *mgr);
|
||||
entityid_t entityCameraGetCurrent(void);
|
||||
|
||||
/**
|
||||
* Gets the camera's horizontal forward direction (XZ plane) from its
|
||||
* position component. Automatically finds the position component on the
|
||||
* entity.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The camera entity ID.
|
||||
* @param out Output vec2: {forwardX, forwardZ} normalized.
|
||||
*/
|
||||
void entityCameraGetForward(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
vec2 out
|
||||
);
|
||||
@@ -89,12 +82,10 @@ void entityCameraGetForward(
|
||||
* Gets the camera's horizontal right direction (XZ plane) from its position
|
||||
* component. Automatically finds the position component on the entity.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The camera entity ID.
|
||||
* @param out Output vec2: {rightX, rightZ} normalized.
|
||||
*/
|
||||
void entityCameraGetRight(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
vec2 out
|
||||
);
|
||||
@@ -103,7 +94,6 @@ void entityCameraGetRight(
|
||||
* Positions the camera to look at a 3D point at a pixel-perfect distance
|
||||
* derived from the camera's FOV and screen height.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param ent The camera entity ID.
|
||||
* @param posComp The position component ID.
|
||||
* @param camComp The camera component ID.
|
||||
@@ -112,7 +102,6 @@ void entityCameraGetRight(
|
||||
* @param scale Pixels per world unit. 1.0 = pixel perfect, 2.0 = 2px per unit.
|
||||
*/
|
||||
void entityCameraLookAtPixelPerfect(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t ent,
|
||||
const componentid_t posComp,
|
||||
const componentid_t camComp,
|
||||
|
||||
@@ -5,16 +5,15 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entity/entitymanager.h"
|
||||
#include "entity/entity.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
void entityPositionInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
|
||||
pos->flags = 0;
|
||||
@@ -29,7 +28,6 @@ void entityPositionInit(
|
||||
}
|
||||
|
||||
void entityPositionLookAt(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 eye,
|
||||
@@ -37,7 +35,7 @@ void entityPositionLookAt(
|
||||
vec3 up
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
// glm_lookat() produces a view matrix (world -> eye space). Every other
|
||||
// setter treats localTransform as this entity's placement in world space
|
||||
@@ -50,19 +48,18 @@ void entityPositionLookAt(
|
||||
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_PRS_DIRTY)
|
||||
& ~(ENTITY_POSITION_FLAG_ROTATION_DIRTY |
|
||||
ENTITY_POSITION_FLAG_POSITION_DIRTY);
|
||||
entityPositionMarkDirty(mgr, pos);
|
||||
entityPositionMarkDirty(pos);
|
||||
}
|
||||
|
||||
void entityPositionGetTransform(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
mat4 dest
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityPositionEnsureWorld(mgr, pos);
|
||||
entityPositionEnsureWorld(pos);
|
||||
glm_mat4_copy(
|
||||
pos->parentEntityId == ENTITY_ID_INVALID
|
||||
? pos->localTransform : pos->worldTransform,
|
||||
@@ -71,71 +68,67 @@ void entityPositionGetTransform(
|
||||
}
|
||||
|
||||
void entityPositionGetLocalTransform(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
mat4 dest
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityPositionEnsureLocal(pos);
|
||||
glm_mat4_copy(pos->localTransform, dest);
|
||||
}
|
||||
|
||||
void entityPositionGetLocalPosition(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 dest
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityPositionEnsurePRS(pos);
|
||||
glm_vec3_copy(pos->position, dest);
|
||||
}
|
||||
|
||||
void entityPositionGetWorldPosition(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 dest
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
if(pos->parentEntityId == ENTITY_ID_INVALID) {
|
||||
entityPositionEnsurePRS(pos);
|
||||
glm_vec3_copy(pos->position, dest);
|
||||
return;
|
||||
}
|
||||
entityPositionEnsureWorld(mgr, pos);
|
||||
entityPositionEnsureWorld(pos);
|
||||
dest[0] = pos->worldTransform[3][0];
|
||||
dest[1] = pos->worldTransform[3][1];
|
||||
dest[2] = pos->worldTransform[3][2];
|
||||
}
|
||||
|
||||
void entityPositionSetWorldPosition(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 position
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
if(pos->parentEntityId == ENTITY_ID_INVALID) {
|
||||
glm_vec3_copy(position, pos->position);
|
||||
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_POSITION_DIRTY)
|
||||
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
|
||||
entityPositionMarkDirty(mgr, pos);
|
||||
entityPositionMarkDirty(pos);
|
||||
return;
|
||||
}
|
||||
entityposition_t *parent = componentGetData(
|
||||
mgr, pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
|
||||
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityPositionEnsureWorld(mgr, parent);
|
||||
entityPositionEnsureWorld(parent);
|
||||
mat4 invParent;
|
||||
glm_mat4_inv(parent->worldTransform, invParent);
|
||||
vec3 localPos;
|
||||
@@ -143,52 +136,49 @@ void entityPositionSetWorldPosition(
|
||||
glm_vec3_copy(localPos, pos->position);
|
||||
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_POSITION_DIRTY)
|
||||
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
|
||||
entityPositionMarkDirty(mgr, pos);
|
||||
entityPositionMarkDirty(pos);
|
||||
}
|
||||
|
||||
void entityPositionSetLocalPosition(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 position
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
glm_vec3_copy(position, pos->position);
|
||||
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_POSITION_DIRTY)
|
||||
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
|
||||
entityPositionMarkDirty(mgr, pos);
|
||||
entityPositionMarkDirty(pos);
|
||||
}
|
||||
|
||||
void entityPositionGetLocalRotation(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 dest
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityPositionEnsurePRS(pos);
|
||||
glm_vec3_copy(pos->rotation, dest);
|
||||
}
|
||||
|
||||
void entityPositionGetWorldRotation(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 dest
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
if(pos->parentEntityId == ENTITY_ID_INVALID) {
|
||||
entityPositionEnsurePRS(pos);
|
||||
glm_vec3_copy(pos->rotation, dest);
|
||||
return;
|
||||
}
|
||||
entityPositionEnsureWorld(mgr, pos);
|
||||
entityPositionEnsureWorld(pos);
|
||||
const float_t (*wt)[4] = pos->worldTransform;
|
||||
const float_t sx = sqrtf(
|
||||
wt[0][0]*wt[0][0] + wt[0][1]*wt[0][1] + wt[0][2]*wt[0][2]
|
||||
@@ -219,40 +209,38 @@ void entityPositionGetWorldRotation(
|
||||
}
|
||||
|
||||
void entityPositionSetLocalRotation(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 rotation
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
glm_vec3_copy(rotation, pos->rotation);
|
||||
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
|
||||
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
|
||||
entityPositionMarkDirty(mgr, pos);
|
||||
entityPositionMarkDirty(pos);
|
||||
}
|
||||
|
||||
void entityPositionSetWorldRotation(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 rotation
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
if(pos->parentEntityId == ENTITY_ID_INVALID) {
|
||||
glm_vec3_copy(rotation, pos->rotation);
|
||||
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
|
||||
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
|
||||
entityPositionMarkDirty(mgr, pos);
|
||||
entityPositionMarkDirty(pos);
|
||||
return;
|
||||
}
|
||||
entityposition_t *parent = componentGetData(
|
||||
mgr, pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
|
||||
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityPositionEnsureWorld(mgr, parent);
|
||||
entityPositionEnsureWorld(parent);
|
||||
|
||||
// Build target world rotation matrix (unit scale) from XYZ euler.
|
||||
const float_t c0 = cosf(rotation[0]), s0 = sinf(rotation[0]);
|
||||
@@ -319,37 +307,35 @@ void entityPositionSetWorldRotation(
|
||||
}
|
||||
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
|
||||
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
|
||||
entityPositionMarkDirty(mgr, pos);
|
||||
entityPositionMarkDirty(pos);
|
||||
}
|
||||
|
||||
void entityPositionGetLocalScale(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 dest
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityPositionEnsurePRS(pos);
|
||||
glm_vec3_copy(pos->scale, dest);
|
||||
}
|
||||
|
||||
void entityPositionGetWorldScale(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 dest
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
if(pos->parentEntityId == ENTITY_ID_INVALID) {
|
||||
entityPositionEnsurePRS(pos);
|
||||
glm_vec3_copy(pos->scale, dest);
|
||||
return;
|
||||
}
|
||||
entityPositionEnsureWorld(mgr, pos);
|
||||
entityPositionEnsureWorld(pos);
|
||||
const float_t (*wt)[4] = pos->worldTransform;
|
||||
dest[0] = sqrtf(wt[0][0]*wt[0][0] + wt[0][1]*wt[0][1] + wt[0][2]*wt[0][2]);
|
||||
dest[1] = sqrtf(wt[1][0]*wt[1][0] + wt[1][1]*wt[1][1] + wt[1][2]*wt[1][2]);
|
||||
@@ -357,40 +343,38 @@ void entityPositionGetWorldScale(
|
||||
}
|
||||
|
||||
void entityPositionSetLocalScale(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 scale
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
glm_vec3_copy(scale, pos->scale);
|
||||
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
|
||||
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
|
||||
entityPositionMarkDirty(mgr, pos);
|
||||
entityPositionMarkDirty(pos);
|
||||
}
|
||||
|
||||
void entityPositionSetWorldScale(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 scale
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
if(pos->parentEntityId == ENTITY_ID_INVALID) {
|
||||
glm_vec3_copy(scale, pos->scale);
|
||||
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
|
||||
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
|
||||
entityPositionMarkDirty(mgr, pos);
|
||||
entityPositionMarkDirty(pos);
|
||||
return;
|
||||
}
|
||||
entityposition_t *parent = componentGetData(
|
||||
mgr, pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
|
||||
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityPositionEnsureWorld(mgr, parent);
|
||||
entityPositionEnsureWorld(parent);
|
||||
const float_t (*pt)[4] = parent->worldTransform;
|
||||
const float_t psx = sqrtf(
|
||||
pt[0][0]*pt[0][0] + pt[0][1]*pt[0][1] + pt[0][2]*pt[0][2]
|
||||
@@ -406,24 +390,23 @@ void entityPositionSetWorldScale(
|
||||
pos->scale[2] = psz > 0.0f ? scale[2] / psz : scale[2];
|
||||
pos->flags = (pos->flags | ENTITY_POSITION_FLAG_ROTATION_DIRTY)
|
||||
& ~ENTITY_POSITION_FLAG_PRS_DIRTY;
|
||||
entityPositionMarkDirty(mgr, pos);
|
||||
entityPositionMarkDirty(pos);
|
||||
}
|
||||
|
||||
void entityPositionSetParent(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const entityid_t parentEntityId,
|
||||
const componentid_t parentComponentId
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
|
||||
// Remove from old parent's child list.
|
||||
if(pos->parentEntityId != ENTITY_ID_INVALID) {
|
||||
entityposition_t *oldParent = componentGetData(
|
||||
mgr, pos->parentEntityId, pos->parentComponentId,
|
||||
pos->parentEntityId, pos->parentComponentId,
|
||||
COMPONENT_TYPE_POSITION
|
||||
);
|
||||
for(uint8_t i = 0; i < oldParent->childCount; i++) {
|
||||
@@ -447,7 +430,7 @@ void entityPositionSetParent(
|
||||
// Register with new parent.
|
||||
if(parentEntityId != ENTITY_ID_INVALID) {
|
||||
entityposition_t *parent = componentGetData(
|
||||
mgr, parentEntityId, parentComponentId, COMPONENT_TYPE_POSITION
|
||||
parentEntityId, parentComponentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
if(parent->childCount < ENTITY_POSITION_CHILDREN_MAX) {
|
||||
parent->childEntityIds[parent->childCount] = entityId;
|
||||
@@ -456,62 +439,59 @@ void entityPositionSetParent(
|
||||
}
|
||||
}
|
||||
|
||||
entityPositionMarkDirty(mgr, pos);
|
||||
entityPositionMarkDirty(pos);
|
||||
}
|
||||
|
||||
entityid_t entityPositionGetParent(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
return pos->parentEntityId;
|
||||
}
|
||||
|
||||
entityposition_t *entityPositionGet(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
return componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
entityId, componentId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
}
|
||||
|
||||
void entityPositionRebuild(entitymanager_t *mgr, entityposition_t *pos) {
|
||||
void entityPositionRebuild(entityposition_t *pos) {
|
||||
pos->flags = (
|
||||
pos->flags |
|
||||
ENTITY_POSITION_FLAG_ROTATION_DIRTY |
|
||||
ENTITY_POSITION_FLAG_POSITION_DIRTY
|
||||
) & ~ENTITY_POSITION_FLAG_PRS_DIRTY;
|
||||
entityPositionMarkDirty(mgr, pos);
|
||||
entityPositionMarkDirty(pos);
|
||||
}
|
||||
|
||||
void entityPositionMarkDirty(entitymanager_t *mgr, entityposition_t *pos) {
|
||||
void entityPositionMarkDirty(entityposition_t *pos) {
|
||||
if(pos->flags & ENTITY_POSITION_FLAG_WORLD_DIRTY) return;
|
||||
pos->flags |= ENTITY_POSITION_FLAG_WORLD_DIRTY;
|
||||
for(uint8_t i = 0; i < pos->childCount; i++) {
|
||||
entityposition_t *child = componentGetData(
|
||||
mgr, pos->childEntityIds[i], pos->childComponentIds[i],
|
||||
pos->childEntityIds[i], pos->childComponentIds[i],
|
||||
COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityPositionMarkDirty(mgr, child);
|
||||
entityPositionMarkDirty(child);
|
||||
}
|
||||
}
|
||||
|
||||
void entityPositionDisposeDeep(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityposition_t *pos = entityPositionGet(mgr, entityId, componentId);
|
||||
entityposition_t *pos = entityPositionGet(entityId, componentId);
|
||||
|
||||
// Detach from parent so the parent's child list stays consistent.
|
||||
if(pos->parentEntityId != ENTITY_ID_INVALID) {
|
||||
entityPositionSetParent(
|
||||
mgr, entityId, componentId, ENTITY_ID_INVALID, COMPONENT_ID_INVALID
|
||||
entityId, componentId, ENTITY_ID_INVALID, COMPONENT_ID_INVALID
|
||||
);
|
||||
}
|
||||
|
||||
@@ -526,16 +506,16 @@ void entityPositionDisposeDeep(
|
||||
// Sever child's parent link so it won't try to modify our disposed
|
||||
// data.
|
||||
entityposition_t *child = entityPositionGet(
|
||||
mgr, childEntityIds[i], childComponentIds[i]
|
||||
childEntityIds[i], childComponentIds[i]
|
||||
);
|
||||
child->parentEntityId = ENTITY_ID_INVALID;
|
||||
child->parentComponentId = COMPONENT_ID_INVALID;
|
||||
}
|
||||
|
||||
entityDispose(mgr, entityId);
|
||||
entityDispose(entityId);
|
||||
|
||||
for(uint8_t i = 0; i < childCount; i++) {
|
||||
entityPositionDisposeDeep(mgr, childEntityIds[i], childComponentIds[i]);
|
||||
entityPositionDisposeDeep(childEntityIds[i], childComponentIds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,7 +622,7 @@ void entityPositionEnsureLocal(entityposition_t *pos) {
|
||||
);
|
||||
}
|
||||
|
||||
void entityPositionEnsureWorld(entitymanager_t *mgr, entityposition_t *pos) {
|
||||
void entityPositionEnsureWorld(entityposition_t *pos) {
|
||||
if(!(pos->flags & ENTITY_POSITION_FLAG_WORLD_DIRTY)) return;
|
||||
entityPositionEnsureLocal(pos);
|
||||
|
||||
@@ -650,10 +630,10 @@ void entityPositionEnsureWorld(entitymanager_t *mgr, entityposition_t *pos) {
|
||||
// Parented: world = parent.world x local. worldTransform must be
|
||||
// written because children (and this node's getters) read it.
|
||||
entityposition_t *parent = componentGetData(
|
||||
mgr, pos->parentEntityId, pos->parentComponentId,
|
||||
pos->parentEntityId, pos->parentComponentId,
|
||||
COMPONENT_TYPE_POSITION
|
||||
);
|
||||
entityPositionEnsureWorld(mgr, parent);
|
||||
entityPositionEnsureWorld(parent);
|
||||
glm_mat4_mul(
|
||||
parent->worldTransform, pos->localTransform, pos->worldTransform
|
||||
);
|
||||
|
||||
@@ -83,12 +83,10 @@ typedef struct {
|
||||
* Initializes the entity position component, setting identity transforms and
|
||||
* zeroing all parent/child state.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
*/
|
||||
void entityPositionInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -99,7 +97,6 @@ void entityPositionInit(
|
||||
* setter), not as a view matrix -- invert entityPositionGetTransform()'s
|
||||
* result to get a view matrix for rendering.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param eye The eye/camera position.
|
||||
@@ -107,7 +104,6 @@ void entityPositionInit(
|
||||
* @param up The up vector.
|
||||
*/
|
||||
void entityPositionLookAt(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 eye,
|
||||
@@ -118,13 +114,11 @@ void entityPositionLookAt(
|
||||
/**
|
||||
* Gets the world-space transform matrix, recomputing it lazily if dirty.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param dest Destination matrix.
|
||||
*/
|
||||
void entityPositionGetTransform(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
mat4 dest
|
||||
@@ -133,13 +127,11 @@ void entityPositionGetTransform(
|
||||
/**
|
||||
* Gets the local transform matrix (does not include parent transforms).
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param dest Destination matrix.
|
||||
*/
|
||||
void entityPositionGetLocalTransform(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
mat4 dest
|
||||
@@ -150,13 +142,11 @@ void entityPositionGetLocalTransform(
|
||||
* first if ENTITY_POSITION_FLAG_PRS_DIRTY is set; never triggers a matrix
|
||||
* rebuild or world-transform update.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param dest Destination vector.
|
||||
*/
|
||||
void entityPositionGetLocalPosition(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 dest
|
||||
@@ -166,13 +156,11 @@ void entityPositionGetLocalPosition(
|
||||
* Gets the world-space position. For parentless entities this is the same as
|
||||
* the local position.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param dest Destination vector.
|
||||
*/
|
||||
void entityPositionGetWorldPosition(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 dest
|
||||
@@ -183,13 +171,11 @@ void entityPositionGetWorldPosition(
|
||||
* to entityPositionSetLocalPosition. For parented entities the position is
|
||||
* converted to local space via the inverted parent world transform.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param position The desired world-space position.
|
||||
*/
|
||||
void entityPositionSetWorldPosition(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 position
|
||||
@@ -199,13 +185,11 @@ void entityPositionSetWorldPosition(
|
||||
* Sets the local position, marks localTransform and worldTransform (self +
|
||||
* descendants) dirty.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param position The new local position.
|
||||
*/
|
||||
void entityPositionSetLocalPosition(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 position
|
||||
@@ -215,13 +199,11 @@ void entityPositionSetLocalPosition(
|
||||
* Gets the cached local euler rotation (XYZ, radians). Decomposes
|
||||
* localTransform first if ENTITY_POSITION_FLAG_PRS_DIRTY is set.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param dest Destination vector.
|
||||
*/
|
||||
void entityPositionGetLocalRotation(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 dest
|
||||
@@ -232,13 +214,11 @@ void entityPositionGetLocalRotation(
|
||||
* world transform. For parentless entities this is the same as local
|
||||
* rotation.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param dest Destination vector.
|
||||
*/
|
||||
void entityPositionGetWorldRotation(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 dest
|
||||
@@ -247,13 +227,11 @@ void entityPositionGetWorldRotation(
|
||||
/**
|
||||
* Sets the local euler rotation (XYZ, radians) and marks transforms dirty.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param rotation The new local rotation.
|
||||
*/
|
||||
void entityPositionSetLocalRotation(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 rotation
|
||||
@@ -265,13 +243,11 @@ void entityPositionSetLocalRotation(
|
||||
* parented entities the rotation is converted to local space by removing
|
||||
* the parent world rotation.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param rotation The desired world-space euler rotation.
|
||||
*/
|
||||
void entityPositionSetWorldRotation(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 rotation
|
||||
@@ -281,13 +257,11 @@ void entityPositionSetWorldRotation(
|
||||
* Gets the cached local scale. Decomposes localTransform first if
|
||||
* ENTITY_POSITION_FLAG_PRS_DIRTY is set.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param dest Destination vector.
|
||||
*/
|
||||
void entityPositionGetLocalScale(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 dest
|
||||
@@ -297,13 +271,11 @@ void entityPositionGetLocalScale(
|
||||
* Gets the world-space scale by extracting column lengths from the world
|
||||
* transform. For parentless entities this is the same as local scale.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param dest Destination vector.
|
||||
*/
|
||||
void entityPositionGetWorldScale(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 dest
|
||||
@@ -312,13 +284,11 @@ void entityPositionGetWorldScale(
|
||||
/**
|
||||
* Sets the local scale and marks transforms dirty.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param scale The new local scale.
|
||||
*/
|
||||
void entityPositionSetLocalScale(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 scale
|
||||
@@ -329,13 +299,11 @@ void entityPositionSetLocalScale(
|
||||
* entityPositionSetLocalScale. For parented entities the scale is converted
|
||||
* to local space by dividing by the parent world scale (assumes no shear).
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param scale The desired world-space scale.
|
||||
*/
|
||||
void entityPositionSetWorldScale(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 scale
|
||||
@@ -345,14 +313,12 @@ void entityPositionSetWorldScale(
|
||||
* Sets the parent of this entity's position component.
|
||||
* Pass ENTITY_ID_INVALID / COMPONENT_ID_INVALID to detach from any parent.
|
||||
*
|
||||
* @param mgr The entity manager that owns both entities.
|
||||
* @param entityId The child entity ID.
|
||||
* @param componentId The child component ID.
|
||||
* @param parentEntityId The parent entity ID.
|
||||
* @param parentComponentId The parent component ID.
|
||||
*/
|
||||
void entityPositionSetParent(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const entityid_t parentEntityId,
|
||||
@@ -362,13 +328,11 @@ void entityPositionSetParent(
|
||||
/**
|
||||
* Gets the entity ID of this position component's parent.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return The parent entity ID, or ENTITY_ID_INVALID if unparented.
|
||||
*/
|
||||
entityid_t entityPositionGetParent(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -379,13 +343,11 @@ entityid_t entityPositionGetParent(
|
||||
* set ENTITY_POSITION_FLAG_WORLD_DIRTY on self and descendants. After
|
||||
* modifying PRS directly, call entityPositionRebuild() instead.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return Pointer to the component data.
|
||||
*/
|
||||
entityposition_t *entityPositionGet(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -397,31 +359,27 @@ entityposition_t *entityPositionGet(
|
||||
* ENTITY_POSITION_FLAG_PRS_DIRTY, propagates ENTITY_POSITION_FLAG_WORLD_DIRTY
|
||||
* to self and all descendants.
|
||||
*
|
||||
* @param mgr The entity manager that owns pos and its descendants.
|
||||
* @param pos The position component whose PRS was modified.
|
||||
*/
|
||||
void entityPositionRebuild(entitymanager_t *mgr, entityposition_t *pos);
|
||||
void entityPositionRebuild(entityposition_t *pos);
|
||||
|
||||
/**
|
||||
* Sets ENTITY_POSITION_FLAG_WORLD_DIRTY on this node and all descendants,
|
||||
* indicating that worldTransform must be recomputed before it is read.
|
||||
* Call this after modifying localTransform directly.
|
||||
*
|
||||
* @param mgr The entity manager that owns pos and its descendants.
|
||||
* @param pos The position component to mark dirty.
|
||||
*/
|
||||
void entityPositionMarkDirty(entitymanager_t *mgr, entityposition_t *pos);
|
||||
void entityPositionMarkDirty(entityposition_t *pos);
|
||||
|
||||
/**
|
||||
* Disposes this entity and all of its position-component descendants
|
||||
* recursively. Detaches from any parent before destroying.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The root entity ID.
|
||||
* @param componentId The root position component ID.
|
||||
*/
|
||||
void entityPositionDisposeDeep(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -454,7 +412,6 @@ void entityPositionEnsureLocal(entityposition_t *pos);
|
||||
* Internal. Recomputes worldTransform from the parent chain if
|
||||
* ENTITY_POSITION_FLAG_WORLD_DIRTY is set.
|
||||
*
|
||||
* @param mgr The entity manager that owns pos and its ancestors.
|
||||
* @param pos The position component to update.
|
||||
*/
|
||||
void entityPositionEnsureWorld(entitymanager_t *mgr, entityposition_t *pos);
|
||||
void entityPositionEnsureWorld(entityposition_t *pos);
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "entityrenderable.h"
|
||||
#include "entity/entitymanager.h"
|
||||
#include "entity/entity.h"
|
||||
#include "display/shader/shadermaterial.h"
|
||||
#include "display/shader/shaderunlit.h"
|
||||
#include "display/display.h"
|
||||
@@ -15,12 +15,11 @@
|
||||
#include "assert/assert.h"
|
||||
|
||||
void entityRenderableInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
memoryZero(r, sizeof(entityrenderable_t));
|
||||
r->type = ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL;
|
||||
@@ -34,44 +33,40 @@ void entityRenderableInit(
|
||||
}
|
||||
|
||||
void entityRenderableDispose(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
}
|
||||
|
||||
void entityRenderableSetType(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const entityrenderabletype_t type
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
r->type = type;
|
||||
}
|
||||
|
||||
void entityRenderableSetPriority(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const int8_t priority
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
r->priority = priority;
|
||||
}
|
||||
|
||||
void entityRenderableSetColor(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const color_t color
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
assertTrue(
|
||||
r->type == ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL,
|
||||
@@ -81,7 +76,6 @@ void entityRenderableSetColor(
|
||||
}
|
||||
|
||||
void entityRenderableSetMesh(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const uint8_t slot,
|
||||
@@ -91,7 +85,7 @@ void entityRenderableSetMesh(
|
||||
assertTrue(slot < ENTITY_RENDERABLE_MESHES_MAX, "Mesh slot out of bounds");
|
||||
|
||||
entityrenderable_t *r = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
assertTrue(
|
||||
r->type == ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL,
|
||||
@@ -107,11 +101,9 @@ void entityRenderableSetMesh(
|
||||
}
|
||||
|
||||
void entityRenderableSetDraw(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
errorret_t (*draw)(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
@@ -120,7 +112,7 @@ void entityRenderableSetDraw(
|
||||
) {
|
||||
assertNotNull(draw, "Draw callback cannot be null");
|
||||
entityrenderable_t *r = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
r->type = ENTITY_RENDERABLE_TYPE_CUSTOM;
|
||||
r->data.custom.draw = draw;
|
||||
@@ -128,12 +120,11 @@ void entityRenderableSetDraw(
|
||||
}
|
||||
|
||||
errorret_t entityRenderableDraw(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityrenderable_t *r = componentGetData(
|
||||
mgr, entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||
);
|
||||
switch(r->type) {
|
||||
case ENTITY_RENDERABLE_TYPE_SPRITEBATCH:
|
||||
@@ -142,7 +133,7 @@ errorret_t entityRenderableDraw(
|
||||
return entityRenderableDrawMaterial(&r->data.material);
|
||||
case ENTITY_RENDERABLE_TYPE_CUSTOM:
|
||||
return entityRenderableDrawCustom(
|
||||
mgr, entityId, componentId, &r->data.custom
|
||||
entityId, componentId, &r->data.custom
|
||||
);
|
||||
default:
|
||||
assertUnreachable("Invalid renderable type");
|
||||
@@ -183,10 +174,9 @@ errorret_t entityRenderableDrawMaterial(const entityrenderablematerial_t *m) {
|
||||
}
|
||||
|
||||
errorret_t entityRenderableDrawCustom(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const entityrenderablecustom_t *custom
|
||||
) {
|
||||
return custom->draw(mgr, entityId, componentId, custom->drawUser);
|
||||
return custom->draw(entityId, componentId, custom->drawUser);
|
||||
}
|
||||
@@ -40,7 +40,6 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
errorret_t (*draw)(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
@@ -70,12 +69,10 @@ typedef struct {
|
||||
* ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL with the unlit shader, a white
|
||||
* cube, and depth-test enabled.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity to initialize the component for.
|
||||
* @param componentId The renderable component of the entity.
|
||||
*/
|
||||
void entityRenderableInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -83,12 +80,10 @@ void entityRenderableInit(
|
||||
/**
|
||||
* Disposes the entity renderable component.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity to dispose the component for.
|
||||
* @param componentId The renderable component of the entity.
|
||||
*/
|
||||
void entityRenderableDispose(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -97,13 +92,11 @@ void entityRenderableDispose(
|
||||
* Sets the rendering type for the renderable component. Resets
|
||||
* type-specific data to zero.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity to configure.
|
||||
* @param componentId The renderable component.
|
||||
* @param type The rendering type to use.
|
||||
*/
|
||||
void entityRenderableSetType(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const entityrenderabletype_t type
|
||||
@@ -113,13 +106,11 @@ void entityRenderableSetType(
|
||||
* Sets the render priority. 0 = auto (derived from type/flags). Higher
|
||||
* values render later (on top). Use non-zero to force ordering.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity to configure.
|
||||
* @param componentId The renderable component.
|
||||
* @param priority The priority value, or 0 for auto.
|
||||
*/
|
||||
void entityRenderableSetPriority(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const int8_t priority
|
||||
@@ -130,13 +121,11 @@ void entityRenderableSetPriority(
|
||||
* (or defaults to) ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL -- asserts
|
||||
* otherwise.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity to configure.
|
||||
* @param componentId The renderable component.
|
||||
* @param color The color to tint the material with.
|
||||
*/
|
||||
void entityRenderableSetColor(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const color_t color
|
||||
@@ -147,7 +136,6 @@ void entityRenderableSetColor(
|
||||
* count override). Only meaningful when the renderable is (or defaults
|
||||
* to) ENTITY_RENDERABLE_TYPE_SHADER_MATERIAL -- asserts otherwise.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity to configure.
|
||||
* @param componentId The renderable component.
|
||||
* @param slot Index into the material's meshes array (0 to
|
||||
@@ -155,7 +143,6 @@ void entityRenderableSetColor(
|
||||
* @param mesh The mesh to draw in that slot.
|
||||
*/
|
||||
void entityRenderableSetMesh(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const uint8_t slot,
|
||||
@@ -166,18 +153,15 @@ void entityRenderableSetMesh(
|
||||
* Sets the draw callback, switching the type to
|
||||
* ENTITY_RENDERABLE_TYPE_CUSTOM.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity to configure.
|
||||
* @param componentId The renderable component of the entity.
|
||||
* @param draw The draw callback to assign.
|
||||
* @param user Userdata passed to the callback.
|
||||
*/
|
||||
void entityRenderableSetDraw(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
errorret_t (*draw)(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
@@ -188,13 +172,11 @@ void entityRenderableSetDraw(
|
||||
/**
|
||||
* Draws the entity using its renderable component data.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity to draw.
|
||||
* @param componentId The renderable component of the entity.
|
||||
* @return Any error state that happened.
|
||||
*/
|
||||
errorret_t entityRenderableDraw(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -220,14 +202,12 @@ errorret_t entityRenderableDrawMaterial(const entityrenderablematerial_t *m);
|
||||
/**
|
||||
* Internal. Invokes a custom-type renderable's draw callback.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity being drawn.
|
||||
* @param componentId The renderable component of the entity.
|
||||
* @param custom The custom draw data.
|
||||
* @return Error state.
|
||||
*/
|
||||
errorret_t entityRenderableDrawCustom(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const entityrenderablecustom_t *custom
|
||||
|
||||
@@ -6,15 +6,14 @@
|
||||
*/
|
||||
|
||||
#include "entityphysics.h"
|
||||
#include "entity/entitymanager.h"
|
||||
#include "entity/entity.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
void entityPhysicsInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
|
||||
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
|
||||
|
||||
memoryZero(phys, sizeof(entityphysics_t));
|
||||
|
||||
@@ -30,106 +29,95 @@ void entityPhysicsInit(
|
||||
}
|
||||
|
||||
entityphysics_t *entityPhysicsGet(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
return componentGetData(mgr, entityId, componentId, COMPONENT_TYPE_PHYSICS);
|
||||
return componentGetData(entityId, componentId, COMPONENT_TYPE_PHYSICS);
|
||||
}
|
||||
|
||||
void entityPhysicsSetShape(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const physicsshape_t shape
|
||||
) {
|
||||
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
|
||||
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
|
||||
phys->shape = shape;
|
||||
}
|
||||
|
||||
physicsshape_t entityPhysicsGetShape(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
|
||||
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
|
||||
return phys->shape;
|
||||
}
|
||||
|
||||
void entityPhysicsGetVelocity(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 dest
|
||||
) {
|
||||
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
|
||||
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
|
||||
glm_vec3_copy(phys->velocity, dest);
|
||||
}
|
||||
|
||||
void entityPhysicsSetVelocity(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 velocity
|
||||
) {
|
||||
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
|
||||
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
|
||||
glm_vec3_copy(velocity, phys->velocity);
|
||||
}
|
||||
|
||||
void entityPhysicsApplyImpulse(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 impulse
|
||||
) {
|
||||
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
|
||||
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
|
||||
if(phys->type == PHYSICS_BODY_STATIC) return;
|
||||
glm_vec3_add(phys->velocity, impulse, phys->velocity);
|
||||
}
|
||||
|
||||
bool_t entityPhysicsIsOnGround(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
|
||||
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
|
||||
return phys->onGround;
|
||||
}
|
||||
|
||||
void entityPhysicsSetBodyType(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const physicsbodytype_t type
|
||||
) {
|
||||
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
|
||||
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
|
||||
phys->type = type;
|
||||
}
|
||||
|
||||
physicsbodytype_t entityPhysicsGetBodyType(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
|
||||
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
|
||||
return phys->type;
|
||||
}
|
||||
|
||||
void entityPhysicsSetCollideMask(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const uint32_t mask
|
||||
) {
|
||||
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
|
||||
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
|
||||
phys->collideMask = mask;
|
||||
}
|
||||
|
||||
uint32_t entityPhysicsGetCollideMask(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityphysics_t *phys = entityPhysicsGet(mgr, entityId, componentId);
|
||||
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
|
||||
return phys->collideMask;
|
||||
}
|
||||
@@ -31,12 +31,10 @@ typedef struct {
|
||||
* Initializes the physics component: defaults to a dynamic 1x1x1 cube
|
||||
* body, zero velocity, unit gravity scale, and onGround false.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
*/
|
||||
void entityPhysicsInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -46,13 +44,11 @@ void entityPhysicsInit(
|
||||
* This is really just intended for doing operations faster than using the
|
||||
* getters and setters, but it is preferred that you use those.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return The physics component data for the given entity and component ID.
|
||||
*/
|
||||
entityphysics_t *entityPhysicsGet(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -62,13 +58,11 @@ entityphysics_t *entityPhysicsGet(
|
||||
* state, so if you change from a cube to a sphere, it will keep the same
|
||||
* velocity and onGround state.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param shape The new shape to set on the physics body.
|
||||
*/
|
||||
void entityPhysicsSetShape(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const physicsshape_t shape
|
||||
@@ -77,13 +71,11 @@ void entityPhysicsSetShape(
|
||||
/**
|
||||
* Gets the shape of the entity's physics body.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return The shape of the physics body.
|
||||
*/
|
||||
physicsshape_t entityPhysicsGetShape(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -91,13 +83,11 @@ physicsshape_t entityPhysicsGetShape(
|
||||
/**
|
||||
* Gets the velocity of the entity's physics body.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param dest The destination vec3 to write the velocity to.
|
||||
*/
|
||||
void entityPhysicsGetVelocity(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 dest
|
||||
@@ -107,13 +97,11 @@ void entityPhysicsGetVelocity(
|
||||
* Sets the velocity of the entity's physics body. This is not an impulse, so
|
||||
* it will be affected by mass and drag.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param velocity The new velocity to set on the physics body.
|
||||
*/
|
||||
void entityPhysicsSetVelocity(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 velocity
|
||||
@@ -124,13 +112,11 @@ void entityPhysicsSetVelocity(
|
||||
* velocity change that is not affected by mass or drag. No-op on STATIC
|
||||
* bodies.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param impulse The impulse to apply to the physics body.
|
||||
*/
|
||||
void entityPhysicsApplyImpulse(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
vec3 impulse
|
||||
@@ -140,13 +126,11 @@ void entityPhysicsApplyImpulse(
|
||||
* Returns true if the entity's physics body rested on a surface during the
|
||||
* last physicsWorldStep.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return True if the body is on the ground, false otherwise.
|
||||
*/
|
||||
bool_t entityPhysicsIsOnGround(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -154,13 +138,11 @@ bool_t entityPhysicsIsOnGround(
|
||||
/**
|
||||
* Sets the body type of the entity's physics body.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param type The body type to set.
|
||||
*/
|
||||
void entityPhysicsSetBodyType(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const physicsbodytype_t type
|
||||
@@ -169,13 +151,11 @@ void entityPhysicsSetBodyType(
|
||||
/**
|
||||
* Gets the body type of the entity's physics body.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return The body type of the physics body.
|
||||
*/
|
||||
physicsbodytype_t entityPhysicsGetBodyType(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -184,13 +164,11 @@ physicsbodytype_t entityPhysicsGetBodyType(
|
||||
* Sets the collision mask of the entity's physics body. Two bodies only
|
||||
* collide if their masks share at least one set bit.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param mask The new collision mask to set on the physics body.
|
||||
*/
|
||||
void entityPhysicsSetCollideMask(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const uint32_t mask
|
||||
@@ -199,13 +177,11 @@ void entityPhysicsSetCollideMask(
|
||||
/**
|
||||
* Gets the collision mask of the entity's physics body.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return The collision mask of the physics body.
|
||||
*/
|
||||
uint32_t entityPhysicsGetCollideMask(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -6,15 +6,14 @@
|
||||
*/
|
||||
|
||||
#include "entitytrigger.h"
|
||||
#include "entity/entitymanager.h"
|
||||
#include "entity/entity.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
void entityTriggerInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
|
||||
memoryZero(trig, sizeof(entitytrigger_t));
|
||||
|
||||
@@ -26,78 +25,70 @@ void entityTriggerInit(
|
||||
}
|
||||
|
||||
entitytrigger_t *entityTriggerGet(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
return componentGetData(mgr, entityId, componentId, COMPONENT_TYPE_TRIGGER);
|
||||
return componentGetData(entityId, componentId, COMPONENT_TYPE_TRIGGER);
|
||||
}
|
||||
|
||||
void entityTriggerSetShape(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const physicsshape_t shape
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
trig->shape = shape;
|
||||
}
|
||||
|
||||
physicsshape_t entityTriggerGetShape(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
return trig->shape;
|
||||
}
|
||||
|
||||
void entityTriggerSetCollideMask(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const uint32_t mask
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
trig->collideMask = mask;
|
||||
}
|
||||
|
||||
uint32_t entityTriggerGetCollideMask(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
return trig->collideMask;
|
||||
}
|
||||
|
||||
uint8_t entityTriggerGetOccupantCount(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
return trig->occupantCount;
|
||||
}
|
||||
|
||||
entityid_t entityTriggerGetOccupantEntityId(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const uint8_t index
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
if(index >= trig->occupantCount) return ENTITY_ID_INVALID;
|
||||
return trig->occupants[index].entityId;
|
||||
}
|
||||
|
||||
bool_t entityTriggerIsOccupyingEntity(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const entityid_t otherEntityId
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
for(uint8_t i = 0; i < trig->occupantCount; i++) {
|
||||
if(trig->occupants[i].entityId == otherEntityId) return true;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
* Callback invoked for a trigger's onEnter/onActive/onMove/onLeave events.
|
||||
* See entityTriggerOnEnterAdd() and its onActive/onMove/onLeave siblings.
|
||||
*
|
||||
* @param mgr The entity manager that owns both entities.
|
||||
* @param triggerEntityId The entity ID of the trigger volume.
|
||||
* @param triggerComponentId The TRIGGER component ID.
|
||||
* @param otherEntityId The entity ID that entered/is inside/left the
|
||||
@@ -29,7 +28,6 @@
|
||||
* @param user The user pointer passed to the matching *Add() call.
|
||||
*/
|
||||
typedef void (*triggercallback_t)(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t triggerEntityId,
|
||||
const componentid_t triggerComponentId,
|
||||
const entityid_t otherEntityId,
|
||||
@@ -93,12 +91,10 @@ typedef struct {
|
||||
* Initializes the trigger component: defaults to a 1x1x1 cube volume, no
|
||||
* tracked occupants, and no event subscribers.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
*/
|
||||
void entityTriggerInit(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -107,13 +103,11 @@ void entityTriggerInit(
|
||||
* Gets the underlying trigger structure (temporarily) for the given
|
||||
* entity. Prefer the dedicated getters/setters where possible.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return The trigger component data for the given entity and component ID.
|
||||
*/
|
||||
entitytrigger_t *entityTriggerGet(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -121,13 +115,11 @@ entitytrigger_t *entityTriggerGet(
|
||||
/**
|
||||
* Sets the shape of the trigger volume.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param shape The new shape to set on the trigger volume.
|
||||
*/
|
||||
void entityTriggerSetShape(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const physicsshape_t shape
|
||||
@@ -136,13 +128,11 @@ void entityTriggerSetShape(
|
||||
/**
|
||||
* Gets the shape of the trigger volume.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return The shape of the trigger volume.
|
||||
*/
|
||||
physicsshape_t entityTriggerGetShape(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -151,13 +141,11 @@ physicsshape_t entityTriggerGetShape(
|
||||
* Sets the collision mask of the trigger volume. An entity's PHYSICS body
|
||||
* is only detected if their masks share at least one set bit.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param mask The new collision mask to set on the trigger volume.
|
||||
*/
|
||||
void entityTriggerSetCollideMask(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const uint32_t mask
|
||||
@@ -166,13 +154,11 @@ void entityTriggerSetCollideMask(
|
||||
/**
|
||||
* Gets the collision mask of the trigger volume.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return The collision mask of the trigger volume.
|
||||
*/
|
||||
uint32_t entityTriggerGetCollideMask(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -180,13 +166,11 @@ uint32_t entityTriggerGetCollideMask(
|
||||
/**
|
||||
* Gets the number of entities currently overlapping this trigger.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return The number of currently tracked occupants.
|
||||
*/
|
||||
uint8_t entityTriggerGetOccupantCount(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -195,7 +179,6 @@ uint8_t entityTriggerGetOccupantCount(
|
||||
* Gets the entity ID of the occupant at the given index, in [0,
|
||||
* entityTriggerGetOccupantCount()). Order is not stable across steps.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param index The occupant index.
|
||||
@@ -203,7 +186,6 @@ uint8_t entityTriggerGetOccupantCount(
|
||||
* of range.
|
||||
*/
|
||||
entityid_t entityTriggerGetOccupantEntityId(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const uint8_t index
|
||||
@@ -212,14 +194,12 @@ entityid_t entityTriggerGetOccupantEntityId(
|
||||
/**
|
||||
* Checks whether a specific entity is currently overlapping this trigger.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param otherEntityId The entity ID to check for.
|
||||
* @return True if otherEntityId is a currently tracked occupant.
|
||||
*/
|
||||
bool_t entityTriggerIsOccupyingEntity(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const entityid_t otherEntityId
|
||||
|
||||
@@ -9,13 +9,12 @@
|
||||
#include "assert/assert.h"
|
||||
|
||||
void entityTriggerOnEnterAdd(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback,
|
||||
void *user
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
assertTrue(
|
||||
trig->onEnterCount < ENTITY_TRIGGER_CALLBACK_COUNT_MAX,
|
||||
"Trigger onEnter callback slots full"
|
||||
@@ -26,12 +25,11 @@ void entityTriggerOnEnterAdd(
|
||||
}
|
||||
|
||||
void entityTriggerOnEnterRemove(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
for(uint8_t i = 0; i < trig->onEnterCount; i++) {
|
||||
if(trig->onEnter[i] != callback) continue;
|
||||
trig->onEnterCount--;
|
||||
@@ -44,13 +42,12 @@ void entityTriggerOnEnterRemove(
|
||||
}
|
||||
|
||||
void entityTriggerOnActiveAdd(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback,
|
||||
void *user
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
assertTrue(
|
||||
trig->onActiveCount < ENTITY_TRIGGER_CALLBACK_COUNT_MAX,
|
||||
"Trigger onActive callback slots full"
|
||||
@@ -61,12 +58,11 @@ void entityTriggerOnActiveAdd(
|
||||
}
|
||||
|
||||
void entityTriggerOnActiveRemove(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
for(uint8_t i = 0; i < trig->onActiveCount; i++) {
|
||||
if(trig->onActive[i] != callback) continue;
|
||||
trig->onActiveCount--;
|
||||
@@ -79,13 +75,12 @@ void entityTriggerOnActiveRemove(
|
||||
}
|
||||
|
||||
void entityTriggerOnMoveAdd(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback,
|
||||
void *user
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
assertTrue(
|
||||
trig->onMoveCount < ENTITY_TRIGGER_CALLBACK_COUNT_MAX,
|
||||
"Trigger onMove callback slots full"
|
||||
@@ -96,12 +91,11 @@ void entityTriggerOnMoveAdd(
|
||||
}
|
||||
|
||||
void entityTriggerOnMoveRemove(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
for(uint8_t i = 0; i < trig->onMoveCount; i++) {
|
||||
if(trig->onMove[i] != callback) continue;
|
||||
trig->onMoveCount--;
|
||||
@@ -114,13 +108,12 @@ void entityTriggerOnMoveRemove(
|
||||
}
|
||||
|
||||
void entityTriggerOnLeaveAdd(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback,
|
||||
void *user
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
assertTrue(
|
||||
trig->onLeaveCount < ENTITY_TRIGGER_CALLBACK_COUNT_MAX,
|
||||
"Trigger onLeave callback slots full"
|
||||
@@ -131,12 +124,11 @@ void entityTriggerOnLeaveAdd(
|
||||
}
|
||||
|
||||
void entityTriggerOnLeaveRemove(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(mgr, entityId, componentId);
|
||||
entitytrigger_t *trig = entityTriggerGet(entityId, componentId);
|
||||
for(uint8_t i = 0; i < trig->onLeaveCount; i++) {
|
||||
if(trig->onLeave[i] != callback) continue;
|
||||
trig->onLeaveCount--;
|
||||
@@ -149,72 +141,68 @@ void entityTriggerOnLeaveRemove(
|
||||
}
|
||||
|
||||
void entityTriggerFireEnter(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t triggerEntityId,
|
||||
const componentid_t triggerComponentId,
|
||||
const entityid_t otherEntityId,
|
||||
const componentid_t otherComponentId
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(
|
||||
mgr, triggerEntityId, triggerComponentId
|
||||
triggerEntityId, triggerComponentId
|
||||
);
|
||||
for(uint8_t i = 0; i < trig->onEnterCount; i++) {
|
||||
trig->onEnter[i](
|
||||
mgr, triggerEntityId, triggerComponentId,
|
||||
triggerEntityId, triggerComponentId,
|
||||
otherEntityId, otherComponentId, trig->onEnterUser[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void entityTriggerFireActive(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t triggerEntityId,
|
||||
const componentid_t triggerComponentId,
|
||||
const entityid_t otherEntityId,
|
||||
const componentid_t otherComponentId
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(
|
||||
mgr, triggerEntityId, triggerComponentId
|
||||
triggerEntityId, triggerComponentId
|
||||
);
|
||||
for(uint8_t i = 0; i < trig->onActiveCount; i++) {
|
||||
trig->onActive[i](
|
||||
mgr, triggerEntityId, triggerComponentId,
|
||||
triggerEntityId, triggerComponentId,
|
||||
otherEntityId, otherComponentId, trig->onActiveUser[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void entityTriggerFireMove(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t triggerEntityId,
|
||||
const componentid_t triggerComponentId,
|
||||
const entityid_t otherEntityId,
|
||||
const componentid_t otherComponentId
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(
|
||||
mgr, triggerEntityId, triggerComponentId
|
||||
triggerEntityId, triggerComponentId
|
||||
);
|
||||
for(uint8_t i = 0; i < trig->onMoveCount; i++) {
|
||||
trig->onMove[i](
|
||||
mgr, triggerEntityId, triggerComponentId,
|
||||
triggerEntityId, triggerComponentId,
|
||||
otherEntityId, otherComponentId, trig->onMoveUser[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void entityTriggerFireLeave(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t triggerEntityId,
|
||||
const componentid_t triggerComponentId,
|
||||
const entityid_t otherEntityId,
|
||||
const componentid_t otherComponentId
|
||||
) {
|
||||
entitytrigger_t *trig = entityTriggerGet(
|
||||
mgr, triggerEntityId, triggerComponentId
|
||||
triggerEntityId, triggerComponentId
|
||||
);
|
||||
for(uint8_t i = 0; i < trig->onLeaveCount; i++) {
|
||||
trig->onLeave[i](
|
||||
mgr, triggerEntityId, triggerComponentId,
|
||||
triggerEntityId, triggerComponentId,
|
||||
otherEntityId, otherComponentId, trig->onLeaveUser[i]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,14 +12,12 @@
|
||||
* Subscribes a callback to a trigger's onEnter event, fired the step an
|
||||
* entity begins overlapping the trigger volume.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param callback The callback to invoke.
|
||||
* @param user Arbitrary pointer forwarded to the callback unchanged.
|
||||
*/
|
||||
void entityTriggerOnEnterAdd(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback,
|
||||
@@ -30,13 +28,11 @@ void entityTriggerOnEnterAdd(
|
||||
* Unsubscribes a previously added onEnter callback. No-op if not
|
||||
* currently subscribed.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param callback The callback that was passed to entityTriggerOnEnterAdd().
|
||||
*/
|
||||
void entityTriggerOnEnterRemove(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback
|
||||
@@ -47,14 +43,12 @@ void entityTriggerOnEnterRemove(
|
||||
* entity continues overlapping the trigger volume (starting the step
|
||||
* after onEnter fired).
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param callback The callback to invoke.
|
||||
* @param user Arbitrary pointer forwarded to the callback unchanged.
|
||||
*/
|
||||
void entityTriggerOnActiveAdd(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback,
|
||||
@@ -65,13 +59,11 @@ void entityTriggerOnActiveAdd(
|
||||
* Unsubscribes a previously added onActive callback. No-op if not
|
||||
* currently subscribed.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param callback The callback that was passed to entityTriggerOnActiveAdd().
|
||||
*/
|
||||
void entityTriggerOnActiveRemove(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback
|
||||
@@ -82,14 +74,12 @@ void entityTriggerOnActiveRemove(
|
||||
* onActive on any step where the overlapping entity's position changed
|
||||
* since the previous step.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param callback The callback to invoke.
|
||||
* @param user Arbitrary pointer forwarded to the callback unchanged.
|
||||
*/
|
||||
void entityTriggerOnMoveAdd(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback,
|
||||
@@ -100,13 +90,11 @@ void entityTriggerOnMoveAdd(
|
||||
* Unsubscribes a previously added onMove callback. No-op if not currently
|
||||
* subscribed.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param callback The callback that was passed to entityTriggerOnMoveAdd().
|
||||
*/
|
||||
void entityTriggerOnMoveRemove(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback
|
||||
@@ -116,14 +104,12 @@ void entityTriggerOnMoveRemove(
|
||||
* Subscribes a callback to a trigger's onLeave event, fired the step an
|
||||
* entity stops overlapping the trigger volume.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param callback The callback to invoke.
|
||||
* @param user Arbitrary pointer forwarded to the callback unchanged.
|
||||
*/
|
||||
void entityTriggerOnLeaveAdd(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback,
|
||||
@@ -134,13 +120,11 @@ void entityTriggerOnLeaveAdd(
|
||||
* Unsubscribes a previously added onLeave callback. No-op if not
|
||||
* currently subscribed.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param callback The callback that was passed to entityTriggerOnLeaveAdd().
|
||||
*/
|
||||
void entityTriggerOnLeaveRemove(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const triggercallback_t callback
|
||||
@@ -150,14 +134,12 @@ void entityTriggerOnLeaveRemove(
|
||||
* Internal. Invokes every subscribed onEnter callback for a trigger.
|
||||
* Called by triggerSystemStep() when an entity begins overlapping.
|
||||
*
|
||||
* @param mgr The entity manager that owns both entities.
|
||||
* @param triggerEntityId The entity ID of the trigger volume.
|
||||
* @param triggerComponentId The TRIGGER component ID.
|
||||
* @param otherEntityId The entity ID that entered the trigger volume.
|
||||
* @param otherComponentId The other entity's POSITION component ID.
|
||||
*/
|
||||
void entityTriggerFireEnter(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t triggerEntityId,
|
||||
const componentid_t triggerComponentId,
|
||||
const entityid_t otherEntityId,
|
||||
@@ -168,14 +150,12 @@ void entityTriggerFireEnter(
|
||||
* Internal. Invokes every subscribed onActive callback for a trigger.
|
||||
* Called by triggerSystemStep() for every entity still overlapping.
|
||||
*
|
||||
* @param mgr The entity manager that owns both entities.
|
||||
* @param triggerEntityId The entity ID of the trigger volume.
|
||||
* @param triggerComponentId The TRIGGER component ID.
|
||||
* @param otherEntityId The entity ID still inside the trigger volume.
|
||||
* @param otherComponentId The other entity's POSITION component ID.
|
||||
*/
|
||||
void entityTriggerFireActive(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t triggerEntityId,
|
||||
const componentid_t triggerComponentId,
|
||||
const entityid_t otherEntityId,
|
||||
@@ -187,14 +167,12 @@ void entityTriggerFireActive(
|
||||
* Called by triggerSystemStep() when an overlapping entity's position
|
||||
* changed since the previous step.
|
||||
*
|
||||
* @param mgr The entity manager that owns both entities.
|
||||
* @param triggerEntityId The entity ID of the trigger volume.
|
||||
* @param triggerComponentId The TRIGGER component ID.
|
||||
* @param otherEntityId The entity ID that moved within the trigger volume.
|
||||
* @param otherComponentId The other entity's POSITION component ID.
|
||||
*/
|
||||
void entityTriggerFireMove(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t triggerEntityId,
|
||||
const componentid_t triggerComponentId,
|
||||
const entityid_t otherEntityId,
|
||||
@@ -205,14 +183,12 @@ void entityTriggerFireMove(
|
||||
* Internal. Invokes every subscribed onLeave callback for a trigger.
|
||||
* Called by triggerSystemStep() when an entity stops overlapping.
|
||||
*
|
||||
* @param mgr The entity manager that owns both entities.
|
||||
* @param triggerEntityId The entity ID of the trigger volume.
|
||||
* @param triggerComponentId The TRIGGER component ID.
|
||||
* @param otherEntityId The entity ID that left the trigger volume.
|
||||
* @param otherComponentId The other entity's POSITION component ID.
|
||||
*/
|
||||
void entityTriggerFireLeave(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t triggerEntityId,
|
||||
const componentid_t triggerComponentId,
|
||||
const entityid_t otherEntityId,
|
||||
|
||||
+80
-40
@@ -5,14 +5,63 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entitymanager.h"
|
||||
#include "entity.h"
|
||||
#include "component/display/entityposition.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
#include "assert/assert.h"
|
||||
#include "console/console.h"
|
||||
|
||||
void entityInit(entitymanager_t *mgr, const entityid_t entityId) {
|
||||
entity_t *ent = &mgr->entities[entityId];
|
||||
entity_t ENTITIES[ENTITY_COUNT_MAX];
|
||||
component_t COMPONENTS[ENTITY_COUNT_MAX * ENTITY_COMPONENT_COUNT_MAX];
|
||||
componentid_t ENTITIES_WITH_COMPONENT[COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX];
|
||||
|
||||
void entityManagerInit(void) {
|
||||
memoryZero(ENTITIES, sizeof(ENTITIES));
|
||||
memoryZero(COMPONENTS, sizeof(COMPONENTS));
|
||||
memorySet(
|
||||
ENTITIES_WITH_COMPONENT, COMPONENT_ID_INVALID,
|
||||
sizeof(ENTITIES_WITH_COMPONENT)
|
||||
);
|
||||
|
||||
size_t totalSize =
|
||||
sizeof(ENTITIES) + sizeof(COMPONENTS) + sizeof(ENTITIES_WITH_COMPONENT);
|
||||
consolePrint(
|
||||
"Entity manager size: %zu bytes (%.2f KB)",
|
||||
totalSize,
|
||||
totalSize / 1024.0f
|
||||
);
|
||||
}
|
||||
|
||||
entityid_t entityManagerAdd(void) {
|
||||
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
|
||||
if((ENTITIES[i].state & ENTITY_STATE_ACTIVE) != 0) continue;
|
||||
entityInit(i);
|
||||
return i;
|
||||
}
|
||||
assertUnreachable("No more entity IDs available");
|
||||
return ENTITY_ID_INVALID;
|
||||
}
|
||||
|
||||
void entityManagerUpdate(void) {
|
||||
entityid_t i = 0;
|
||||
while(i < ENTITY_COUNT_MAX) {
|
||||
if((ENTITIES[i].state & ENTITY_STATE_ACTIVE) != 0) {
|
||||
entityUpdate(i);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void entityManagerDispose(void) {
|
||||
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
|
||||
if((ENTITIES[i].state & ENTITY_STATE_ACTIVE) == 0) continue;
|
||||
entityDispose(i);
|
||||
}
|
||||
}
|
||||
|
||||
void entityInit(const entityid_t entityId) {
|
||||
entity_t *ent = &ENTITIES[entityId];
|
||||
|
||||
memoryZero(ent, sizeof(entity_t));
|
||||
|
||||
@@ -22,7 +71,7 @@ void entityInit(entitymanager_t *mgr, const entityid_t entityId) {
|
||||
compType < COMPONENT_TYPE_COUNT;
|
||||
compType++
|
||||
) {
|
||||
mgr->entitiesWithComponent[
|
||||
ENTITIES_WITH_COMPONENT[
|
||||
compType * ENTITY_COUNT_MAX + entityId
|
||||
] = COMPONENT_ID_INVALID;
|
||||
}
|
||||
@@ -31,7 +80,6 @@ void entityInit(entitymanager_t *mgr, const entityid_t entityId) {
|
||||
}
|
||||
|
||||
componentid_t entityAddComponent(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componenttype_t type
|
||||
) {
|
||||
@@ -39,15 +87,15 @@ componentid_t entityAddComponent(
|
||||
|
||||
for(componentid_t i = 0; i < ENTITY_COMPONENT_COUNT_MAX; i++) {
|
||||
compInd = componentGetIndex(entityId, i);
|
||||
if(mgr->components[compInd].type != COMPONENT_TYPE_NULL) {
|
||||
if(COMPONENTS[compInd].type != COMPONENT_TYPE_NULL) {
|
||||
assertTrue(
|
||||
mgr->components[compInd].type != type,
|
||||
COMPONENTS[compInd].type != type,
|
||||
"Entity already has component of this type"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
componentInit(mgr, entityId, i, type);
|
||||
mgr->entitiesWithComponent[
|
||||
componentInit(entityId, i, type);
|
||||
ENTITIES_WITH_COMPONENT[
|
||||
type * ENTITY_COUNT_MAX + entityId
|
||||
] = i;
|
||||
return i;
|
||||
@@ -58,98 +106,93 @@ componentid_t entityAddComponent(
|
||||
}
|
||||
|
||||
componentid_t entityGetComponent(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componenttype_t type
|
||||
) {
|
||||
componentid_t compId = mgr->entitiesWithComponent[
|
||||
componentid_t compId = ENTITIES_WITH_COMPONENT[
|
||||
type * ENTITY_COUNT_MAX + entityId
|
||||
];
|
||||
if(compId == COMPONENT_ID_INVALID) return compId;
|
||||
assertTrue(
|
||||
mgr->components[componentGetIndex(entityId, compId)].type == type,
|
||||
COMPONENTS[componentGetIndex(entityId, compId)].type == type,
|
||||
"Component type mismatch"
|
||||
);
|
||||
return compId;
|
||||
}
|
||||
|
||||
void entitySetName(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const char_t *name
|
||||
) {
|
||||
stringCopy(mgr->entities[entityId].name, name, ENTITY_NAME_MAX);
|
||||
stringCopy(ENTITIES[entityId].name, name, ENTITY_NAME_MAX);
|
||||
}
|
||||
|
||||
const char_t *entityGetName(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId
|
||||
) {
|
||||
return mgr->entities[entityId].name;
|
||||
return ENTITIES[entityId].name;
|
||||
}
|
||||
|
||||
entityid_t entityFindByName(
|
||||
entitymanager_t *mgr,
|
||||
const char_t *name
|
||||
) {
|
||||
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
|
||||
if(!(mgr->entities[i].state & ENTITY_STATE_ACTIVE)) continue;
|
||||
if(stringEquals(mgr->entities[i].name, name)) return i;
|
||||
if(!(ENTITIES[i].state & ENTITY_STATE_ACTIVE)) continue;
|
||||
if(stringEquals(ENTITIES[i].name, name)) return i;
|
||||
}
|
||||
return ENTITY_ID_INVALID;
|
||||
}
|
||||
|
||||
void entityDisposeDeep(entitymanager_t *mgr, const entityid_t entityId) {
|
||||
void entityDisposeDeep(const entityid_t entityId) {
|
||||
componentid_t posComp = entityGetComponent(
|
||||
mgr, entityId, COMPONENT_TYPE_POSITION
|
||||
entityId, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
if(posComp != COMPONENT_ID_INVALID) {
|
||||
entityPositionDisposeDeep(mgr, entityId, posComp);
|
||||
entityPositionDisposeDeep(entityId, posComp);
|
||||
} else {
|
||||
entityDispose(mgr, entityId);
|
||||
entityDispose(entityId);
|
||||
}
|
||||
}
|
||||
|
||||
void entityUpdate(entitymanager_t *mgr, const entityid_t entityId) {
|
||||
entity_t *ent = &mgr->entities[entityId];
|
||||
void entityUpdate(const entityid_t entityId) {
|
||||
entity_t *ent = &ENTITIES[entityId];
|
||||
for(uint8_t i = 0; i < ent->updateCount; i++) {
|
||||
ent->onUpdate[i](
|
||||
mgr, entityId, ent->updateComponentId[i], ent->updateUser[i]
|
||||
entityId, ent->updateComponentId[i], ent->updateUser[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void entityDispose(entitymanager_t *mgr, const entityid_t entityId) {
|
||||
void entityDispose(const entityid_t entityId) {
|
||||
componentindex_t compInd;
|
||||
entity_t *ent = &mgr->entities[entityId];
|
||||
entity_t *ent = &ENTITIES[entityId];
|
||||
|
||||
for(uint8_t i = 0; i < ent->disposeCount; i++) {
|
||||
ent->onDispose[i](
|
||||
mgr, entityId, ent->disposeComponentId[i], ent->disposeUser[i]
|
||||
entityId, ent->disposeComponentId[i], ent->disposeUser[i]
|
||||
);
|
||||
}
|
||||
|
||||
for(componentid_t i = 0; i < ENTITY_COMPONENT_COUNT_MAX; i++) {
|
||||
compInd = componentGetIndex(entityId, i);
|
||||
componenttype_t type = mgr->components[compInd].type;
|
||||
componenttype_t type = COMPONENTS[compInd].type;
|
||||
if(type == COMPONENT_TYPE_NULL) continue;
|
||||
mgr->entitiesWithComponent[
|
||||
ENTITIES_WITH_COMPONENT[
|
||||
type * ENTITY_COUNT_MAX + entityId
|
||||
] = COMPONENT_ID_INVALID;
|
||||
componentDispose(mgr, entityId, i);
|
||||
componentDispose(entityId, i);
|
||||
}
|
||||
|
||||
ent->state = 0;
|
||||
}
|
||||
|
||||
void entityUpdateAdd(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const entitycallback_t callback,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
) {
|
||||
entity_t *ent = &mgr->entities[entityId];
|
||||
entity_t *ent = &ENTITIES[entityId];
|
||||
assertTrue(
|
||||
ent->updateCount < ENTITY_UPDATE_CALLBACK_COUNT_MAX,
|
||||
"Entity update callback slots full"
|
||||
@@ -161,11 +204,10 @@ void entityUpdateAdd(
|
||||
}
|
||||
|
||||
void entityUpdateRemove(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const entitycallback_t callback
|
||||
) {
|
||||
entity_t *ent = &mgr->entities[entityId];
|
||||
entity_t *ent = &ENTITIES[entityId];
|
||||
for(uint8_t i = 0; i < ent->updateCount; i++) {
|
||||
if(ent->onUpdate[i] != callback) continue;
|
||||
ent->updateCount--;
|
||||
@@ -179,13 +221,12 @@ void entityUpdateRemove(
|
||||
}
|
||||
|
||||
void entityDisposeAdd(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const entitycallback_t callback,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
) {
|
||||
entity_t *ent = &mgr->entities[entityId];
|
||||
entity_t *ent = &ENTITIES[entityId];
|
||||
assertTrue(
|
||||
ent->disposeCount < ENTITY_DISPOSE_CALLBACK_COUNT_MAX,
|
||||
"Entity dispose callback slots full"
|
||||
@@ -197,11 +238,10 @@ void entityDisposeAdd(
|
||||
}
|
||||
|
||||
void entityDisposeRemove(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const entitycallback_t callback
|
||||
) {
|
||||
entity_t *ent = &mgr->entities[entityId];
|
||||
entity_t *ent = &ENTITIES[entityId];
|
||||
for(uint8_t i = 0; i < ent->disposeCount; i++) {
|
||||
if(ent->onDispose[i] != callback) continue;
|
||||
ent->disposeCount--;
|
||||
|
||||
+32
-27
@@ -16,7 +16,6 @@
|
||||
#define ENTITY_NAME_MAX 32
|
||||
|
||||
typedef void (*entitycallback_t)(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
void *user
|
||||
@@ -35,24 +34,49 @@ typedef struct {
|
||||
void *disposeUser[ENTITY_DISPOSE_CALLBACK_COUNT_MAX];
|
||||
} entity_t;
|
||||
|
||||
extern entity_t ENTITIES[ENTITY_COUNT_MAX];
|
||||
extern component_t COMPONENTS[ENTITY_COUNT_MAX * ENTITY_COMPONENT_COUNT_MAX];
|
||||
extern componentid_t ENTITIES_WITH_COMPONENT[COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX];
|
||||
|
||||
/**
|
||||
* Initializes the entity system, marking all entities and components as
|
||||
* unused.
|
||||
*/
|
||||
void entityManagerInit(void);
|
||||
|
||||
/**
|
||||
* Adds / Reserves a new entity ID.
|
||||
*
|
||||
* @return The new entity ID.
|
||||
*/
|
||||
entityid_t entityManagerAdd(void);
|
||||
|
||||
/**
|
||||
* Updates all active entities.
|
||||
*/
|
||||
void entityManagerUpdate(void);
|
||||
|
||||
/**
|
||||
* Disposes of the entity system, in turn freeing all entities and
|
||||
* components.
|
||||
*/
|
||||
void entityManagerDispose(void);
|
||||
|
||||
/**
|
||||
* Initializes an entity with the given ID.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The ID of the entity to initialize.
|
||||
*/
|
||||
void entityInit(entitymanager_t *mgr, const entityid_t entityId);
|
||||
void entityInit(const entityid_t entityId);
|
||||
|
||||
/**
|
||||
* Adds a component of the given type to the entity with the given ID.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The ID of the entity to add the component to.
|
||||
* @param type The type of the component to add.
|
||||
* @return The ID of the entity with component.
|
||||
*/
|
||||
componentid_t entityAddComponent(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componenttype_t type
|
||||
);
|
||||
@@ -61,13 +85,11 @@ componentid_t entityAddComponent(
|
||||
* Gets the ID of the component of the given type on the entity with the
|
||||
* given ID, or COMPONENT_ID_INVALID if the entity lacks the component.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The ID of the entity to get the component from.
|
||||
* @param type The type of the component to get.
|
||||
* @return The ID of the component.
|
||||
*/
|
||||
componentid_t entityGetComponent(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const componenttype_t type
|
||||
);
|
||||
@@ -78,13 +100,11 @@ componentid_t entityGetComponent(
|
||||
* entity referenceable by name, e.g. as a parent via
|
||||
* entityPositionSetParent().
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The ID of the entity to name.
|
||||
* @param name The name to give the entity. Must be shorter than
|
||||
* ENTITY_NAME_MAX.
|
||||
*/
|
||||
void entitySetName(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const char_t *name
|
||||
);
|
||||
@@ -92,65 +112,56 @@ void entitySetName(
|
||||
/**
|
||||
* Gets an entity's name, or an empty string if it has none.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The ID of the entity to get the name of.
|
||||
* @return The entity's name.
|
||||
*/
|
||||
const char_t *entityGetName(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId
|
||||
);
|
||||
|
||||
/**
|
||||
* Finds the first active entity with the given name.
|
||||
*
|
||||
* @param mgr The entity manager to search.
|
||||
* @param name The name to search for.
|
||||
* @return The entity ID, or ENTITY_ID_INVALID if no active entity matches.
|
||||
*/
|
||||
entityid_t entityFindByName(
|
||||
entitymanager_t *mgr,
|
||||
const char_t *name
|
||||
);
|
||||
|
||||
/**
|
||||
* Runs all registered update callbacks for the entity.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The ID of the entity to update.
|
||||
*/
|
||||
void entityUpdate(entitymanager_t *mgr, const entityid_t entityId);
|
||||
void entityUpdate(const entityid_t entityId);
|
||||
|
||||
/**
|
||||
* Disposes of an entity with the given ID. Fires all dispose callbacks
|
||||
* before cleaning up components and state.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The ID of the entity to dispose of.
|
||||
*/
|
||||
void entityDispose(entitymanager_t *mgr, const entityid_t entityId);
|
||||
void entityDispose(const entityid_t entityId);
|
||||
|
||||
/**
|
||||
* Disposes of an entity and all of its position-component descendants
|
||||
* recursively. If the entity has no position component, behaves like
|
||||
* entityDispose.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The root entity ID.
|
||||
*/
|
||||
void entityDisposeDeep(entitymanager_t *mgr, const entityid_t entityId);
|
||||
void entityDisposeDeep(const entityid_t entityId);
|
||||
|
||||
/**
|
||||
* Registers an update callback, invoked each time entityUpdate is called.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity to register on.
|
||||
* @param callback The function to call.
|
||||
* @param componentId The component ID passed back to the callback.
|
||||
* @param user Userdata passed back to the callback.
|
||||
*/
|
||||
void entityUpdateAdd(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const entitycallback_t callback,
|
||||
const componentid_t componentId,
|
||||
@@ -160,12 +171,10 @@ void entityUpdateAdd(
|
||||
/**
|
||||
* Removes a previously registered update callback.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity to remove from.
|
||||
* @param callback The function to remove.
|
||||
*/
|
||||
void entityUpdateRemove(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const entitycallback_t callback
|
||||
);
|
||||
@@ -174,14 +183,12 @@ void entityUpdateRemove(
|
||||
* Registers a dispose callback, invoked at the start of entityDispose
|
||||
* before any component or state cleanup.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity to register on.
|
||||
* @param callback The function to call.
|
||||
* @param componentId The component ID passed back to the callback.
|
||||
* @param user Userdata passed back to the callback.
|
||||
*/
|
||||
void entityDisposeAdd(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const entitycallback_t callback,
|
||||
const componentid_t componentId,
|
||||
@@ -191,12 +198,10 @@ void entityDisposeAdd(
|
||||
/**
|
||||
* Removes a previously registered dispose callback.
|
||||
*
|
||||
* @param mgr The entity manager that owns the entity.
|
||||
* @param entityId The entity to remove from.
|
||||
* @param callback The function to remove.
|
||||
*/
|
||||
void entityDisposeRemove(
|
||||
entitymanager_t *mgr,
|
||||
const entityid_t entityId,
|
||||
const entitycallback_t callback
|
||||
);
|
||||
@@ -17,8 +17,3 @@
|
||||
typedef uint8_t entityid_t;
|
||||
typedef uint8_t componentid_t;
|
||||
typedef uint16_t componentindex_t;
|
||||
|
||||
// Forward declared here (rather than in component.h) so every entity/
|
||||
// component header can reference entitymanager_t* regardless of include
|
||||
// order, without needing a full entitymanager.h include.
|
||||
typedef struct entitymanager_t entitymanager_t;
|
||||
@@ -1,56 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entitymanager.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "console/console.h"
|
||||
|
||||
void entityManagerInit(entitymanager_t *mgr) {
|
||||
assertNotNull(mgr, "Entity manager cannot be null");
|
||||
memoryZero(mgr, sizeof(entitymanager_t));
|
||||
memorySet(
|
||||
mgr->entitiesWithComponent, COMPONENT_ID_INVALID,
|
||||
sizeof(componentid_t) * COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX
|
||||
);
|
||||
|
||||
consolePrint(
|
||||
"Entity manager size: %zu bytes (%.2f KB)",
|
||||
sizeof(entitymanager_t),
|
||||
sizeof(entitymanager_t) / 1024.0f
|
||||
);
|
||||
}
|
||||
|
||||
entityid_t entityManagerAdd(entitymanager_t *mgr) {
|
||||
assertNotNull(mgr, "Entity manager cannot be null");
|
||||
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
|
||||
if((mgr->entities[i].state & ENTITY_STATE_ACTIVE) != 0) continue;
|
||||
entityInit(mgr, i);
|
||||
return i;
|
||||
}
|
||||
assertUnreachable("No more entity IDs available");
|
||||
return ENTITY_ID_INVALID;
|
||||
}
|
||||
|
||||
void entityManagerUpdate(entitymanager_t *mgr) {
|
||||
assertNotNull(mgr, "Entity manager cannot be null");
|
||||
entityid_t i = 0;
|
||||
while(i < ENTITY_COUNT_MAX) {
|
||||
if((mgr->entities[i].state & ENTITY_STATE_ACTIVE) != 0) {
|
||||
entityUpdate(mgr, i);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void entityManagerDispose(entitymanager_t *mgr) {
|
||||
assertNotNull(mgr, "Entity manager cannot be null");
|
||||
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
|
||||
if((mgr->entities[i].state & ENTITY_STATE_ACTIVE) == 0) continue;
|
||||
entityDispose(mgr, i);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entity.h"
|
||||
|
||||
typedef struct entitymanager_t {
|
||||
entity_t entities[ENTITY_COUNT_MAX];
|
||||
component_t components[ENTITY_COUNT_MAX * ENTITY_COMPONENT_COUNT_MAX];
|
||||
componentid_t entitiesWithComponent[COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX];
|
||||
} entitymanager_t;
|
||||
|
||||
/**
|
||||
* Initializes an entity manager, marking all entities and components as
|
||||
* unused.
|
||||
*
|
||||
* @param mgr The entity manager to initialize.
|
||||
*/
|
||||
void entityManagerInit(entitymanager_t *mgr);
|
||||
|
||||
/**
|
||||
* Adds / Reserves a new entity ID in the given manager.
|
||||
*
|
||||
* @param mgr The entity manager to allocate the entity in.
|
||||
* @return The new entity ID.
|
||||
*/
|
||||
entityid_t entityManagerAdd(entitymanager_t *mgr);
|
||||
|
||||
/**
|
||||
* Updates all active entities in the given manager.
|
||||
*
|
||||
* @param mgr The entity manager to update.
|
||||
*/
|
||||
void entityManagerUpdate(entitymanager_t *mgr);
|
||||
|
||||
/**
|
||||
* Disposes of the entity manager, in turn freeing all entities and
|
||||
* components.
|
||||
*
|
||||
* @param mgr The entity manager to dispose.
|
||||
*/
|
||||
void entityManagerDispose(entitymanager_t *mgr);
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entityrender.h"
|
||||
#include "component/display/entitycamera.h"
|
||||
#include "component/display/entityposition.h"
|
||||
#include "component/display/entityrenderable.h"
|
||||
#include "display/shader/shaderunlit.h"
|
||||
|
||||
errorret_t entityRenderAll(void) {
|
||||
entityid_t camEntity = entityCameraGetCurrent();
|
||||
if(camEntity == ENTITY_ID_INVALID) errorOk();
|
||||
|
||||
componentid_t camComp = entityGetComponent(
|
||||
camEntity, COMPONENT_TYPE_CAMERA
|
||||
);
|
||||
componentid_t camPosComp = entityGetComponent(
|
||||
camEntity, COMPONENT_TYPE_POSITION
|
||||
);
|
||||
|
||||
mat4 proj;
|
||||
entityCameraGetProjection(camEntity, camComp, proj);
|
||||
|
||||
mat4 view;
|
||||
glm_mat4_identity(view);
|
||||
if(camPosComp != COMPONENT_ID_INVALID) {
|
||||
mat4 camTransform;
|
||||
entityPositionGetTransform(camEntity, camPosComp, camTransform);
|
||||
// Position components always store world-space placement (eye ->
|
||||
// world), regardless of how they were set (SetPosition/Rotation or
|
||||
// LookAt) -- invert to get the view matrix (world -> eye).
|
||||
glm_mat4_inv(camTransform, view);
|
||||
}
|
||||
|
||||
errorChain(shaderBind(&SHADER_UNLIT));
|
||||
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_PROJECTION, proj));
|
||||
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_VIEW, view));
|
||||
|
||||
entityid_t renderEntities[ENTITY_COUNT_MAX];
|
||||
componentid_t renderComponents[ENTITY_COUNT_MAX];
|
||||
entityid_t renderCount = componentGetEntitiesWithComponent(
|
||||
COMPONENT_TYPE_RENDERABLE, renderEntities, renderComponents
|
||||
);
|
||||
|
||||
for(entityid_t i = 0; i < renderCount; i++) {
|
||||
mat4 model;
|
||||
componentid_t posComp = entityGetComponent(
|
||||
renderEntities[i], COMPONENT_TYPE_POSITION
|
||||
);
|
||||
if(posComp == COMPONENT_ID_INVALID) {
|
||||
glm_mat4_identity(model);
|
||||
} else {
|
||||
entityPositionGetTransform(renderEntities[i], posComp, model);
|
||||
}
|
||||
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_MODEL, model));
|
||||
errorChain(entityRenderableDraw(renderEntities[i], renderComponents[i]));
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entity.h"
|
||||
#include "error/error.h"
|
||||
|
||||
/**
|
||||
* Renders every COMPONENT_TYPE_RENDERABLE entity, from the view of its
|
||||
* first COMPONENT_TYPE_CAMERA entity. A no-op if there is no camera.
|
||||
*
|
||||
* @return Error state.
|
||||
*/
|
||||
errorret_t entityRenderAll(void);
|
||||
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
scene.c
|
||||
)
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "scene.h"
|
||||
#include "entity/entity.h"
|
||||
#include "entity/entityrender.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "time/time.h"
|
||||
|
||||
scenemanager_t SCENE_MANAGER;
|
||||
|
||||
errorret_t sceneInit(void) {
|
||||
memoryZero(&SCENE_MANAGER, sizeof(scenemanager_t));
|
||||
SCENE_MANAGER.active = SCENE_ID_INVALID;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
sceneid_t sceneCreate(void) {
|
||||
assertTrue(!SCENE_MANAGER.scene.used, "Scene is already in use");
|
||||
SCENE_MANAGER.scene.used = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceneDestroy(const sceneid_t id) {
|
||||
assertTrue(id == 0, "Scene ID OOB");
|
||||
if(!SCENE_MANAGER.scene.used) return;
|
||||
|
||||
SCENE_MANAGER.scene.used = false;
|
||||
|
||||
if(SCENE_MANAGER.active == id) SCENE_MANAGER.active = SCENE_ID_INVALID;
|
||||
}
|
||||
|
||||
void sceneSetActive(const sceneid_t id) {
|
||||
assertTrue(
|
||||
id == SCENE_ID_INVALID || id == 0, "Scene ID OOB"
|
||||
);
|
||||
SCENE_MANAGER.active = id;
|
||||
}
|
||||
|
||||
sceneid_t sceneGetActive(void) {
|
||||
return SCENE_MANAGER.active;
|
||||
}
|
||||
|
||||
errorret_t sceneUpdate(void) {
|
||||
#if DUSK_TIME_DYNAMIC
|
||||
if(TIME.dynamicUpdate) errorOk();
|
||||
#endif
|
||||
|
||||
errorChain(sceneFixedUpdate());
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t sceneFixedUpdate(void) {
|
||||
if(SCENE_MANAGER.active == SCENE_ID_INVALID) errorOk();
|
||||
|
||||
entityManagerUpdate();
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t sceneRender(void) {
|
||||
if(SCENE_MANAGER.active != SCENE_ID_INVALID) {
|
||||
errorChain(entityRenderAll());
|
||||
}
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t sceneDispose(void) {
|
||||
sceneDestroy(0);
|
||||
errorOk();
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "scenebase.h"
|
||||
#include "error/error.h"
|
||||
|
||||
typedef struct {
|
||||
bool_t used;
|
||||
} scene_t;
|
||||
|
||||
typedef struct {
|
||||
scene_t scene;
|
||||
sceneid_t active;
|
||||
} scenemanager_t;
|
||||
|
||||
extern scenemanager_t SCENE_MANAGER;
|
||||
|
||||
/**
|
||||
* Initialises the scene manager. No scenes are created or active until
|
||||
* sceneCreate()/sceneSetActive() are called.
|
||||
*
|
||||
* @return An error if the init failed, or errorOk() if it succeeded.
|
||||
*/
|
||||
errorret_t sceneInit(void);
|
||||
|
||||
/**
|
||||
* Creates the single scene. There is no per-scene entity pool -- entities
|
||||
* are global (see entity.h) -- so this just marks the scene as used. Not
|
||||
* made active automatically.
|
||||
*
|
||||
* @return The ID of the new scene (always 0).
|
||||
*/
|
||||
sceneid_t sceneCreate(void);
|
||||
|
||||
/**
|
||||
* Destroys the scene. Does not touch the global entity arrays -- entity
|
||||
* lifecycle is the engine's job (entityManagerInit()/entityManagerDispose()),
|
||||
* not scoped to scene create/destroy. If the scene was active, no scene is
|
||||
* active afterwards.
|
||||
*
|
||||
* @param id The ID of the scene to destroy. Must be 0.
|
||||
*/
|
||||
void sceneDestroy(const sceneid_t id);
|
||||
|
||||
/**
|
||||
* Sets which scene is active. Only the active scene is ticked and rendered
|
||||
* by sceneUpdate()/sceneRender(). Previously active scenes are left running
|
||||
* in the background (paused, not disposed) until sceneDestroy() is called.
|
||||
*
|
||||
* @param id The ID of the scene to make active, or SCENE_ID_INVALID to make
|
||||
* no scene active.
|
||||
*/
|
||||
void sceneSetActive(const sceneid_t id);
|
||||
|
||||
/**
|
||||
* Gets the ID of the currently active scene.
|
||||
*
|
||||
* @return The active scene ID, or SCENE_ID_INVALID if none is active.
|
||||
*/
|
||||
sceneid_t sceneGetActive(void);
|
||||
|
||||
/**
|
||||
* Called every frame (every call to engineUpdate). On a non-dynamic-time
|
||||
* platform (DUSK_TIME_DYNAMIC undefined) every frame is itself a fixed
|
||||
* timestep, so this calls sceneFixedUpdate() every time. On a
|
||||
* dynamic-time platform, most calls are sub-steps still accumulating
|
||||
* toward the next fixed timestep (TIME.dynamicUpdate is true) and do
|
||||
* nothing here; this calls sceneFixedUpdate() only on the one call where
|
||||
* TIME.dynamicUpdate is false, i.e. exactly once per fixed timestep.
|
||||
*
|
||||
* @return An error if the update failed, or errorOk() if it succeeded.
|
||||
*/
|
||||
errorret_t sceneUpdate(void);
|
||||
|
||||
/**
|
||||
* Ticks the active scene's entities (update callbacks) by one fixed
|
||||
* timestep (TIME.delta). Called by sceneUpdate() at the fixed-timestep
|
||||
* cadence described there -- never once per rendered frame on a
|
||||
* dynamic-time platform, so game logic stays frame-rate independent and
|
||||
* deterministic. Does not step physics or triggers yet -- physicsworld_t/
|
||||
* triggersystem_t haven't been ported from ac2 onto this branch, so a
|
||||
* scene's entities can't collide or trigger each other until that lands.
|
||||
*
|
||||
* @return An error if the update failed, or errorOk() if it succeeded.
|
||||
*/
|
||||
errorret_t sceneFixedUpdate(void);
|
||||
|
||||
/**
|
||||
* Renders the active scene's entities, from the view of its active
|
||||
* camera (see entityRenderAll).
|
||||
*
|
||||
* @return An error if the render failed, or errorOk() if it succeeded.
|
||||
*/
|
||||
errorret_t sceneRender(void);
|
||||
|
||||
/**
|
||||
* Destroys the scene.
|
||||
*
|
||||
* @return An error if the dispose failed, or errorOk() if it succeeded.
|
||||
*/
|
||||
errorret_t sceneDispose(void);
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
#define SCENE_ID_INVALID 0xFF
|
||||
|
||||
typedef uint8_t sceneid_t;
|
||||
@@ -7,3 +7,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
scriptnativeconsole.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(entity)
|
||||
@@ -0,0 +1,12 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
scriptnativeentity.c
|
||||
scriptnativeentitymanager.c
|
||||
scriptnativeentityposition.c
|
||||
scriptnativeentityrenderable.c
|
||||
)
|
||||
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "scriptnativeentity.h"
|
||||
#include "entity/entity.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
SCRIPT_NATIVE(scriptNativeEntityAddComponent) {
|
||||
entityid_t entityId;
|
||||
componenttype_t type;
|
||||
componentid_t componentId;
|
||||
|
||||
scriptArgCount(runtime, argc, 2, 2);
|
||||
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
|
||||
type = (componenttype_t)scriptArgInteger(runtime, args, argc, 1);
|
||||
|
||||
componentId = entityAddComponent(entityId, type);
|
||||
return scriptNumber((float)componentId);
|
||||
}
|
||||
|
||||
SCRIPT_NATIVE(scriptNativeEntityGetComponent) {
|
||||
entityid_t entityId;
|
||||
componenttype_t type;
|
||||
componentid_t componentId;
|
||||
|
||||
scriptArgCount(runtime, argc, 2, 2);
|
||||
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
|
||||
type = (componenttype_t)scriptArgInteger(runtime, args, argc, 1);
|
||||
|
||||
componentId = entityGetComponent(entityId, type);
|
||||
return scriptNumber((float)componentId);
|
||||
}
|
||||
|
||||
SCRIPT_NATIVE(scriptNativeEntitySetName) {
|
||||
entityid_t entityId;
|
||||
scriptstring_t *name;
|
||||
char_t buffer[ENTITY_NAME_MAX];
|
||||
uint16_t length;
|
||||
|
||||
scriptArgCount(runtime, argc, 2, 2);
|
||||
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
|
||||
name = scriptArgString(runtime, args, argc, 1);
|
||||
|
||||
// name->data isn't null terminated - entitySetName needs a C string.
|
||||
length = name->length;
|
||||
if(length > ENTITY_NAME_MAX - 1) length = ENTITY_NAME_MAX - 1;
|
||||
if(length) memoryCopy(buffer, name->data, length);
|
||||
buffer[length] = 0;
|
||||
|
||||
entitySetName(entityId, buffer);
|
||||
return scriptUndefined();
|
||||
}
|
||||
|
||||
SCRIPT_NATIVE(scriptNativeEntityGetName) {
|
||||
entityid_t entityId;
|
||||
|
||||
scriptArgCount(runtime, argc, 1, 1);
|
||||
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
|
||||
|
||||
return scriptStringFromC(
|
||||
runtime, entityGetName(entityId)
|
||||
);
|
||||
}
|
||||
|
||||
SCRIPT_NATIVE(scriptNativeEntityFindByName) {
|
||||
scriptstring_t *name;
|
||||
char_t buffer[ENTITY_NAME_MAX];
|
||||
uint16_t length;
|
||||
entityid_t entityId;
|
||||
|
||||
scriptArgCount(runtime, argc, 1, 1);
|
||||
name = scriptArgString(runtime, args, argc, 0);
|
||||
|
||||
length = name->length;
|
||||
if(length > ENTITY_NAME_MAX - 1) length = ENTITY_NAME_MAX - 1;
|
||||
if(length) memoryCopy(buffer, name->data, length);
|
||||
buffer[length] = 0;
|
||||
|
||||
entityId = entityFindByName(buffer);
|
||||
return scriptNumber((float)entityId);
|
||||
}
|
||||
|
||||
SCRIPT_NATIVE(scriptNativeEntityDispose) {
|
||||
entityid_t entityId;
|
||||
|
||||
scriptArgCount(runtime, argc, 1, 1);
|
||||
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
|
||||
|
||||
entityDispose(entityId);
|
||||
return scriptUndefined();
|
||||
}
|
||||
|
||||
SCRIPT_NATIVE(scriptNativeEntityDisposeDeep) {
|
||||
entityid_t entityId;
|
||||
|
||||
scriptArgCount(runtime, argc, 1, 1);
|
||||
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
|
||||
|
||||
entityDisposeDeep(entityId);
|
||||
return scriptUndefined();
|
||||
}
|
||||
|
||||
void scriptNativeEntityRegister(scriptruntime_t *runtime) {
|
||||
assertNotNull(runtime, "scriptNativeEntityRegister needs a runtime, not NULL");
|
||||
|
||||
scriptBuiltinAdd(runtime, "entityAddComponent", scriptNativeEntityAddComponent);
|
||||
scriptBuiltinAdd(runtime, "entityGetComponent", scriptNativeEntityGetComponent);
|
||||
scriptBuiltinAdd(runtime, "entitySetName", scriptNativeEntitySetName);
|
||||
scriptBuiltinAdd(runtime, "entityGetName", scriptNativeEntityGetName);
|
||||
scriptBuiltinAdd(runtime, "entityFindByName", scriptNativeEntityFindByName);
|
||||
scriptBuiltinAdd(runtime, "entityDispose", scriptNativeEntityDispose);
|
||||
scriptBuiltinAdd(runtime, "entityDisposeDeep", scriptNativeEntityDisposeDeep);
|
||||
|
||||
scriptBuiltinAddInt(runtime, "ENTITY_ID_INVALID", ENTITY_ID_INVALID);
|
||||
scriptBuiltinAddInt(runtime, "COMPONENT_ID_INVALID", COMPONENT_ID_INVALID);
|
||||
|
||||
#define X(enumName, type, field, init, dispose, render) \
|
||||
scriptBuiltinAddInt(runtime, "COMPONENT_TYPE_" #enumName, COMPONENT_TYPE_##enumName);
|
||||
#include "entity/componentlist.h"
|
||||
#undef X
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/script.h"
|
||||
#include "entity/entity.h"
|
||||
|
||||
/**
|
||||
* Registers the entity natives (entityAddComponent, entityGetComponent,
|
||||
* entitySetName, entityGetName, entityFindByName, entityDispose,
|
||||
* entityDisposeDeep) and the ENTITY_ID_INVALID/COMPONENT_ID_INVALID and
|
||||
* COMPONENT_TYPE_* constants they take, against the engine's global
|
||||
* entity/component arrays (entity.h). See scriptNativeEntityManagerRegister
|
||||
* for the entityAdd() native.
|
||||
*
|
||||
* @param runtime The runtime to add them to.
|
||||
*/
|
||||
void scriptNativeEntityRegister(scriptruntime_t *runtime);
|
||||
|
||||
/**
|
||||
* Native implementation of entityAddComponent(entityId, type): adds a
|
||||
* component of the given COMPONENT_TYPE_* to the entity.
|
||||
*
|
||||
* @param runtime The runtime.
|
||||
* @param args The arguments: an entity ID and a component type.
|
||||
* @param argc Number of arguments.
|
||||
* @param self The native function value.
|
||||
* @return The new component's ID.
|
||||
*/
|
||||
SCRIPT_NATIVE(scriptNativeEntityAddComponent);
|
||||
|
||||
/**
|
||||
* Native implementation of entityGetComponent(entityId, type): finds the
|
||||
* entity's component of the given COMPONENT_TYPE_*, or COMPONENT_ID_INVALID
|
||||
* if it has none.
|
||||
*
|
||||
* @param runtime The runtime.
|
||||
* @param args The arguments: an entity ID and a component type.
|
||||
* @param argc Number of arguments.
|
||||
* @param self The native function value.
|
||||
* @return The component's ID, or COMPONENT_ID_INVALID.
|
||||
*/
|
||||
SCRIPT_NATIVE(scriptNativeEntityGetComponent);
|
||||
|
||||
/**
|
||||
* Native implementation of entitySetName(entityId, name): names an entity,
|
||||
* making it referenceable by entityFindByName.
|
||||
*
|
||||
* @param runtime The runtime.
|
||||
* @param args The arguments: an entity ID and a name.
|
||||
* @param argc Number of arguments.
|
||||
* @param self The native function value.
|
||||
* @return undefined.
|
||||
*/
|
||||
SCRIPT_NATIVE(scriptNativeEntitySetName);
|
||||
|
||||
/**
|
||||
* Native implementation of entityGetName(entityId): gets an entity's name,
|
||||
* or an empty string if it has none.
|
||||
*
|
||||
* @param runtime The runtime.
|
||||
* @param args The arguments: an entity ID.
|
||||
* @param argc Number of arguments.
|
||||
* @param self The native function value.
|
||||
* @return The entity's name.
|
||||
*/
|
||||
SCRIPT_NATIVE(scriptNativeEntityGetName);
|
||||
|
||||
/**
|
||||
* Native implementation of entityFindByName(name): finds the first active
|
||||
* entity with the given name, or ENTITY_ID_INVALID if none matches.
|
||||
*
|
||||
* @param runtime The runtime.
|
||||
* @param args The arguments: a name.
|
||||
* @param argc Number of arguments.
|
||||
* @param self The native function value.
|
||||
* @return The entity's ID, or ENTITY_ID_INVALID.
|
||||
*/
|
||||
SCRIPT_NATIVE(scriptNativeEntityFindByName);
|
||||
|
||||
/**
|
||||
* Native implementation of entityDispose(entityId): disposes an entity and
|
||||
* its components.
|
||||
*
|
||||
* @param runtime The runtime.
|
||||
* @param args The arguments: an entity ID.
|
||||
* @param argc Number of arguments.
|
||||
* @param self The native function value.
|
||||
* @return undefined.
|
||||
*/
|
||||
SCRIPT_NATIVE(scriptNativeEntityDispose);
|
||||
|
||||
/**
|
||||
* Native implementation of entityDisposeDeep(entityId): disposes an entity
|
||||
* and, recursively, every position-component descendant of it.
|
||||
*
|
||||
* @param runtime The runtime.
|
||||
* @param args The arguments: an entity ID.
|
||||
* @param argc Number of arguments.
|
||||
* @param self The native function value.
|
||||
* @return undefined.
|
||||
*/
|
||||
SCRIPT_NATIVE(scriptNativeEntityDisposeDeep);
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "scriptnativeentitymanager.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
SCRIPT_NATIVE(scriptNativeEntityAdd) {
|
||||
scriptArgCount(runtime, argc, 0, 0);
|
||||
return scriptNumber((float)entityManagerAdd());
|
||||
}
|
||||
|
||||
void scriptNativeEntityManagerRegister(scriptruntime_t *runtime) {
|
||||
assertNotNull(runtime, "scriptNativeEntityManagerRegister needs a runtime, not NULL");
|
||||
|
||||
scriptBuiltinAdd(runtime, "entityAdd", scriptNativeEntityAdd);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/script.h"
|
||||
#include "entity/entity.h"
|
||||
|
||||
/**
|
||||
* Registers the entityAdd() native.
|
||||
*
|
||||
* @param runtime The runtime to add it to.
|
||||
*/
|
||||
void scriptNativeEntityManagerRegister(scriptruntime_t *runtime);
|
||||
|
||||
/**
|
||||
* Native implementation of entityAdd(): reserves a new entity ID.
|
||||
*
|
||||
* @param runtime The runtime.
|
||||
* @param args Unused, takes no arguments.
|
||||
* @param argc Number of arguments.
|
||||
* @param self The native function value.
|
||||
* @return The new entity's ID.
|
||||
*/
|
||||
SCRIPT_NATIVE(scriptNativeEntityAdd);
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "scriptnativeentityposition.h"
|
||||
#include "entity/entity.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
SCRIPT_NATIVE(scriptNativeEntityPositionSetLocalPosition) {
|
||||
entityid_t entityId;
|
||||
componentid_t componentId;
|
||||
vec3 position;
|
||||
|
||||
scriptArgCount(runtime, argc, 5, 5);
|
||||
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
|
||||
componentId = (componentid_t)scriptArgInteger(runtime, args, argc, 1);
|
||||
position[0] = scriptArgNumber(runtime, args, argc, 2).as.number;
|
||||
position[1] = scriptArgNumber(runtime, args, argc, 3).as.number;
|
||||
position[2] = scriptArgNumber(runtime, args, argc, 4).as.number;
|
||||
|
||||
entityPositionSetLocalPosition(
|
||||
entityId, componentId, position
|
||||
);
|
||||
return scriptUndefined();
|
||||
}
|
||||
|
||||
SCRIPT_NATIVE(scriptNativeEntityPositionLookAt) {
|
||||
entityid_t entityId;
|
||||
componentid_t componentId;
|
||||
vec3 eye;
|
||||
vec3 target;
|
||||
vec3 up = { 0.0f, 1.0f, 0.0f };
|
||||
|
||||
scriptArgCount(runtime, argc, 8, 8);
|
||||
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
|
||||
componentId = (componentid_t)scriptArgInteger(runtime, args, argc, 1);
|
||||
eye[0] = scriptArgNumber(runtime, args, argc, 2).as.number;
|
||||
eye[1] = scriptArgNumber(runtime, args, argc, 3).as.number;
|
||||
eye[2] = scriptArgNumber(runtime, args, argc, 4).as.number;
|
||||
target[0] = scriptArgNumber(runtime, args, argc, 5).as.number;
|
||||
target[1] = scriptArgNumber(runtime, args, argc, 6).as.number;
|
||||
target[2] = scriptArgNumber(runtime, args, argc, 7).as.number;
|
||||
|
||||
entityPositionLookAt(entityId, componentId, eye, target, up);
|
||||
return scriptUndefined();
|
||||
}
|
||||
|
||||
void scriptNativeEntityPositionRegister(scriptruntime_t *runtime) {
|
||||
assertNotNull(runtime, "scriptNativeEntityPositionRegister needs a runtime, not NULL");
|
||||
|
||||
scriptBuiltinAdd(
|
||||
runtime, "entityPositionSetLocalPosition",
|
||||
scriptNativeEntityPositionSetLocalPosition
|
||||
);
|
||||
scriptBuiltinAdd(
|
||||
runtime, "entityPositionLookAt", scriptNativeEntityPositionLookAt
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/script.h"
|
||||
#include "entity/component/display/entityposition.h"
|
||||
|
||||
/**
|
||||
* Registers the entityPositionSetLocalPosition and entityPositionLookAt
|
||||
* natives.
|
||||
*
|
||||
* @param runtime The runtime to add it to.
|
||||
*/
|
||||
void scriptNativeEntityPositionRegister(scriptruntime_t *runtime);
|
||||
|
||||
/**
|
||||
* Native implementation of
|
||||
* entityPositionSetLocalPosition(entityId, componentId, x, y, z).
|
||||
*
|
||||
* @param runtime The runtime.
|
||||
* @param args The arguments: an entity ID, a position component ID, and x/y/z.
|
||||
* @param argc Number of arguments.
|
||||
* @param self The native function value.
|
||||
* @return undefined.
|
||||
*/
|
||||
SCRIPT_NATIVE(scriptNativeEntityPositionSetLocalPosition);
|
||||
|
||||
/**
|
||||
* Native implementation of
|
||||
* entityPositionLookAt(entityId, componentId, eyeX, eyeY, eyeZ, targetX,
|
||||
* targetY, targetZ): places the entity at eye, facing target, with world
|
||||
* up (0, 1, 0) - SCRIPT_PARAMS_MAX leaves no room for an up argument too.
|
||||
*
|
||||
* @param runtime The runtime.
|
||||
* @param args The arguments: an entity ID, a position component ID, and the
|
||||
* eye and target points.
|
||||
* @param argc Number of arguments.
|
||||
* @param self The native function value.
|
||||
* @return undefined.
|
||||
*/
|
||||
SCRIPT_NATIVE(scriptNativeEntityPositionLookAt);
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "scriptnativeentityrenderable.h"
|
||||
#include "entity/entity.h"
|
||||
#include "error/scriptraise.h"
|
||||
#include "display/mesh/cube.h"
|
||||
#include "display/mesh/plane.h"
|
||||
#include "display/mesh/sphere.h"
|
||||
#include "display/mesh/capsule.h"
|
||||
#include "display/mesh/triprism.h"
|
||||
#include "display/mesh/quad.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
#define SCRIPT_NATIVE_ENTITY_RENDERABLE_MESH_NAME_MAX 16
|
||||
|
||||
// Scripts don't have mesh assets to point at yet, so this just names the
|
||||
// engine's built in primitive shapes.
|
||||
static mesh_t *scriptNativeEntityRenderableResolveMesh(const char_t *name) {
|
||||
if(stringEquals(name, "cube")) return &CUBE_MESH_SIMPLE;
|
||||
if(stringEquals(name, "plane")) return &PLANE_MESH_SIMPLE;
|
||||
if(stringEquals(name, "sphere")) return &SPHERE_MESH_SIMPLE;
|
||||
if(stringEquals(name, "capsule")) return &CAPSULE_MESH_SIMPLE;
|
||||
if(stringEquals(name, "triprism")) return &TRIPRISM_MESH_SIMPLE;
|
||||
if(stringEquals(name, "quad")) return &QUAD_MESH_SIMPLE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SCRIPT_NATIVE(scriptNativeEntityRenderableSetMesh) {
|
||||
entityid_t entityId;
|
||||
componentid_t componentId;
|
||||
scriptstring_t *nameArg;
|
||||
char_t name[SCRIPT_NATIVE_ENTITY_RENDERABLE_MESH_NAME_MAX];
|
||||
uint16_t length;
|
||||
mesh_t *mesh;
|
||||
|
||||
scriptArgCount(runtime, argc, 3, 3);
|
||||
entityId = (entityid_t)scriptArgInteger(runtime, args, argc, 0);
|
||||
componentId = (componentid_t)scriptArgInteger(runtime, args, argc, 1);
|
||||
nameArg = scriptArgString(runtime, args, argc, 2);
|
||||
|
||||
// nameArg->data isn't null terminated - need a C string to compare.
|
||||
length = nameArg->length;
|
||||
if(length > SCRIPT_NATIVE_ENTITY_RENDERABLE_MESH_NAME_MAX - 1) {
|
||||
length = SCRIPT_NATIVE_ENTITY_RENDERABLE_MESH_NAME_MAX - 1;
|
||||
}
|
||||
if(length) memoryCopy(name, nameArg->data, length);
|
||||
name[length] = 0;
|
||||
|
||||
mesh = scriptNativeEntityRenderableResolveMesh(name);
|
||||
if(!mesh) scriptRaise(runtime, "Unknown mesh '%s'", name);
|
||||
|
||||
entityRenderableSetMesh(
|
||||
entityId, componentId, 0, mesh
|
||||
);
|
||||
return scriptUndefined();
|
||||
}
|
||||
|
||||
void scriptNativeEntityRenderableRegister(scriptruntime_t *runtime) {
|
||||
assertNotNull(runtime, "scriptNativeEntityRenderableRegister needs a runtime, not NULL");
|
||||
|
||||
scriptBuiltinAdd(
|
||||
runtime, "entityRenderableSetMesh", scriptNativeEntityRenderableSetMesh
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/script.h"
|
||||
#include "entity/component/display/entityrenderable.h"
|
||||
|
||||
/**
|
||||
* Registers the entityRenderableSetMesh native.
|
||||
*
|
||||
* @param runtime The runtime to add it to.
|
||||
*/
|
||||
void scriptNativeEntityRenderableRegister(scriptruntime_t *runtime);
|
||||
|
||||
/**
|
||||
* Native implementation of
|
||||
* entityRenderableSetMesh(entityId, componentId, name): sets slot 0 of a
|
||||
* material renderable to one of the engine's built in primitive meshes, by
|
||||
* name - "cube", "plane", "sphere", "capsule", "triprism" or "quad".
|
||||
*
|
||||
* @param runtime The runtime.
|
||||
* @param args The arguments: an entity ID, a renderable component ID, and a
|
||||
* mesh name.
|
||||
* @param argc Number of arguments.
|
||||
* @param self The native function value.
|
||||
* @return undefined.
|
||||
*/
|
||||
SCRIPT_NATIVE(scriptNativeEntityRenderableSetMesh);
|
||||
@@ -7,6 +7,10 @@
|
||||
|
||||
#include "script.h"
|
||||
#include "native/scriptnativeconsole.h"
|
||||
#include "native/entity/scriptnativeentity.h"
|
||||
#include "native/entity/scriptnativeentitymanager.h"
|
||||
#include "native/entity/scriptnativeentityposition.h"
|
||||
#include "native/entity/scriptnativeentityrenderable.h"
|
||||
#include "builtin/scriptbuiltinregister.h"
|
||||
#include "console/console.h"
|
||||
#include "asset/asset.h"
|
||||
@@ -68,6 +72,10 @@ errorret_t scriptInit(void) {
|
||||
|
||||
scriptBuiltinsRegister(SCRIPT.runtime);
|
||||
scriptNativeConsoleRegister(SCRIPT.runtime);
|
||||
scriptNativeEntityManagerRegister(SCRIPT.runtime);
|
||||
scriptNativeEntityRegister(SCRIPT.runtime);
|
||||
scriptNativeEntityPositionRegister(SCRIPT.runtime);
|
||||
scriptNativeEntityRenderableRegister(SCRIPT.runtime);
|
||||
scriptVmAttach(SCRIPT.runtime);
|
||||
scriptRuntimeSetPrintHandler(SCRIPT.runtime, scriptPrintHandler);
|
||||
scriptRuntimeSetLoadHandler(SCRIPT.runtime, scriptLoadHandler);
|
||||
|
||||
Reference in new issue
Block a user