diff --git a/assets/entities/cube.js b/assets/entities/cube.js index c61df3d8..bea67795 100644 --- a/assets/entities/cube.js +++ b/assets/entities/cube.js @@ -1,14 +1,17 @@ function CubeEntity() { Entity.call(this); + this.add(POSITION); + this.add(MESH); + this.add(MATERIAL); + this.position.x = 0; this.position.y = 0; this.position.z = 0; - this.add(MESH); - this.add(MATERIAL); } -Object.assign(CubeEntity.prototype, Entity.prototype); +CubeEntity.prototype = Object.create(Entity.prototype); +CubeEntity.prototype.constructor = CubeEntity; CubeEntity.prototype.update = function() { var speed = 3.0; diff --git a/assets/scenes/cube.js b/assets/scenes/cube.js index f41b3d8c..f9359cfe 100644 --- a/assets/scenes/cube.js +++ b/assets/scenes/cube.js @@ -3,11 +3,12 @@ var Cube = include('entities/cube.js'); function CubeScene() { this.cam = new Entity(); this.cam.add(POSITION); + this.cam.add(CAMERA); + this.cam.position.x = 3; this.cam.position.y = 3; this.cam.position.z = 3; this.cam.position.lookAt(0, 0, 0); - this.cam.add(CAMERA); this.cube = new Cube(); } diff --git a/src/dusk/entity/component.c b/src/dusk/entity/component.c index 108c7c22..1538c371 100644 --- a/src/dusk/entity/component.c +++ b/src/dusk/entity/component.c @@ -12,8 +12,14 @@ componentdefinition_t COMPONENT_DEFINITIONS[] = { [COMPONENT_TYPE_NULL] = { 0 }, - #define X(enumName, type, field, iMethod, dMethod) \ - [COMPONENT_TYPE_##enumName] = { .name = #field, .init = iMethod, .dispose = dMethod }, + #define X(enm, type, field, iMethod, dMethod) \ + [COMPONENT_TYPE_##enm] = { \ + .enumName = #enm, \ + .name = #field, \ + .init = iMethod, \ + .dispose = dMethod \ + }, + #include "componentlist.h" #undef X diff --git a/src/dusk/entity/component.h b/src/dusk/entity/component.h index ab310786..6f86e60d 100644 --- a/src/dusk/entity/component.h +++ b/src/dusk/entity/component.h @@ -20,6 +20,7 @@ typedef union { } componentdata_t; typedef struct { + const char_t *enumName; const char_t *name; void (*init)(const entityid_t, const componentid_t); void (*dispose)(const entityid_t, const componentid_t); diff --git a/src/dusk/entity/componentlist.h b/src/dusk/entity/componentlist.h index 6fda2fea..0b9c09be 100644 --- a/src/dusk/entity/componentlist.h +++ b/src/dusk/entity/componentlist.h @@ -11,6 +11,12 @@ #include "entity/component/display/entitymaterial.h" #include "entity/component/physics/entityphysics.h" +// Name (Uppercase) +// Structure +// Field name (lowercase) +// Init function (optional) +// Dispose function (optional) + X(POSITION, entityposition_t, position, entityPositionInit, NULL) X(CAMERA, entitycamera_t, camera, entityCameraInit, NULL) X(MESH, entitymesh_t, mesh, entityMeshInit, entityMeshDispose) diff --git a/src/dusk/script/module/display/modulecolor.h b/src/dusk/script/module/display/modulecolor.h index 8fe2c44d..95136590 100644 --- a/src/dusk/script/module/display/modulecolor.h +++ b/src/dusk/script/module/display/modulecolor.h @@ -93,8 +93,10 @@ moduleBaseFunction(moduleColorToString) { &MODULE_COLOR_PROTO, callInfo->this_value ); if(!color) return jerry_undefined(); - char_t buf[32]; - stringFormat(buf, sizeof(buf), "[ %d, %d, %d, %d ]", + char_t buf[64]; + stringFormat( + buf, sizeof(buf), + "{ \"r\": %d, \"g\": %d, \"b\": %d, \"a\": %d }", (int32_t)color->r, (int32_t)color->g, (int32_t)color->b, (int32_t)color->a ); diff --git a/src/dusk/script/module/display/modulescreen.h b/src/dusk/script/module/display/modulescreen.h index 5eb3104b..0b77e318 100644 --- a/src/dusk/script/module/display/modulescreen.h +++ b/src/dusk/script/module/display/modulescreen.h @@ -44,6 +44,17 @@ moduleBaseFunction(moduleScreenSetBackground) { return jerry_undefined(); } +// Functions +moduleBaseFunction(moduleScreenToString) { + char_t buf[128]; + stringFormat( + buf, sizeof(buf), + "{ \"width\": %d, \"height\": %d, \"aspect\": %.2f }", + SCREEN.width, SCREEN.height, SCREEN.aspect + ); + return jerry_string_sz(buf); +} + static void moduleScreen(void) { scriptProtoInit(&MODULE_SCREEN_PROTO, "Screen", sizeof(screen_t), NULL); @@ -54,5 +65,6 @@ static void moduleScreen(void) { X(aspect, moduleScreenGetAspect, NULL) X(background, moduleScreenGetBackground, moduleScreenSetBackground) #undef X -} - \ No newline at end of file + + scriptProtoDefineToString(&MODULE_SCREEN_PROTO, moduleScreenToString); +} \ No newline at end of file diff --git a/src/dusk/script/module/entity/component/moduleentitycamera.h b/src/dusk/script/module/entity/component/moduleentitycamera.h index 50c9e75a..59800df6 100644 --- a/src/dusk/script/module/entity/component/moduleentitycamera.h +++ b/src/dusk/script/module/entity/component/moduleentitycamera.h @@ -61,7 +61,7 @@ moduleBaseFunction(moduleEntityCameraAdd) { return scriptProtoCreateValue(&MODULE_ENTITY_CAMERA_PROTO, &h); } -static void moduleEntityCamera(void) { +static void moduleEntityCAMERA(void) { scriptProtoInit( &MODULE_ENTITY_CAMERA_PROTO, NULL, sizeof(componenthandle_t), NULL ); diff --git a/src/dusk/script/module/entity/component/moduleentitymaterial.h b/src/dusk/script/module/entity/component/moduleentitymaterial.h index 38ffd8ab..3e745836 100644 --- a/src/dusk/script/module/entity/component/moduleentitymaterial.h +++ b/src/dusk/script/module/entity/component/moduleentitymaterial.h @@ -69,7 +69,7 @@ moduleBaseFunction(moduleEntityMaterialAdd) { return scriptProtoCreateValue(&MODULE_ENTITY_MATERIAL_PROTO, &h); } -static void moduleEntityMaterial(void) { +static void moduleEntityMATERIAL(void) { scriptProtoInit( &MODULE_ENTITY_MATERIAL_PROTO, NULL, diff --git a/src/dusk/script/module/entity/component/moduleentitymesh.h b/src/dusk/script/module/entity/component/moduleentitymesh.h index c824883b..38e2be7f 100644 --- a/src/dusk/script/module/entity/component/moduleentitymesh.h +++ b/src/dusk/script/module/entity/component/moduleentitymesh.h @@ -27,6 +27,6 @@ moduleBaseFunction(moduleEntityMeshAdd) { return scriptProtoCreateValue(&MODULE_ENTITY_MESH_PROTO, &h); } -static void moduleEntityMesh(void) { +static void moduleEntityMESH(void) { scriptProtoInit(&MODULE_ENTITY_MESH_PROTO, NULL, sizeof(componenthandle_t), NULL); } diff --git a/src/dusk/script/module/entity/component/moduleentityphysics.h b/src/dusk/script/module/entity/component/moduleentityphysics.h index ce5a45d6..94e44a2d 100644 --- a/src/dusk/script/module/entity/component/moduleentityphysics.h +++ b/src/dusk/script/module/entity/component/moduleentityphysics.h @@ -175,7 +175,7 @@ moduleBaseFunction(moduleEntityPhysicsAdd) { return scriptProtoCreateValue(&MODULE_ENTITY_PHYSICS_PROTO, &h); } -static void moduleEntityPhysics(void) { +static void moduleEntityPHYSICS(void) { scriptProtoInit(&MODULE_ENTITY_PHYSICS_PROTO, NULL, sizeof(componenthandle_t), NULL); scriptProtoDefineProp(&MODULE_ENTITY_PHYSICS_PROTO, "velX", moduleEntityPhysicsGetVelX, moduleEntityPhysicsSetVelX); diff --git a/src/dusk/script/module/entity/component/moduleentityposition.h b/src/dusk/script/module/entity/component/moduleentityposition.h index 051cf433..463e5341 100644 --- a/src/dusk/script/module/entity/component/moduleentityposition.h +++ b/src/dusk/script/module/entity/component/moduleentityposition.h @@ -232,7 +232,7 @@ moduleBaseFunction(moduleEntityPositionAdd) { return scriptProtoCreateValue(&MODULE_ENTITY_POSITION_PROTO, &h); } -static void moduleEntityPosition(void) { +static void moduleEntityPOSITION(void) { scriptProtoInit(&MODULE_ENTITY_POSITION_PROTO, NULL, sizeof(componenthandle_t), NULL); scriptProtoDefineProp(&MODULE_ENTITY_POSITION_PROTO, "x", moduleEntityPositionGetX, moduleEntityPositionSetX); diff --git a/src/dusk/script/module/entity/moduleentity.h b/src/dusk/script/module/entity/moduleentity.h index f9b560af..d41508ca 100644 --- a/src/dusk/script/module/entity/moduleentity.h +++ b/src/dusk/script/module/entity/moduleentity.h @@ -22,8 +22,58 @@ typedef struct { } entityscript_t; static scriptproto_t MODULE_ENTITY_PROTO; -static jerry_external_handler_t s_componentAddFns[COMPONENT_TYPE_COUNT]; +// Getters + +// Getter defined for each component type +static jerry_value_t moduleEntityGetComponent( + const jerry_call_info_t *callInfo, + const jerry_value_t args[], + const jerry_length_t argc, + const componenttype_t type, + scriptproto_t *proto +) { + assertNotNull(callInfo, "Call info must not be null"); + assertTrue(argc >= 0, "Argc must be non-negative"); + assertTrue( + type > COMPONENT_TYPE_NULL && type < COMPONENT_TYPE_COUNT, + "Invalid component type" + ); + + entityid_t entityId; + componentid_t compId; + + // Get the entity script data. + entityscript_t *inst = (entityscript_t*)scriptProtoGetValue( + &MODULE_ENTITY_PROTO, callInfo->this_value + ); + if(!inst) return jerry_undefined(); + entityId = inst->id; + + // Find the component ID of the requested type. + compId = entityGetComponent(entityId, type); + if(compId == 0xFF) { + return jerry_undefined(); + } + + componenthandle_t h = { .eid = entityId, .cid = compId }; + return scriptProtoCreateValue(proto, &h); +} + +#define X(enumName, type, field, init, dispose) \ + moduleBaseFunction(moduleEntityGet##enumName) { \ + return moduleEntityGetComponent( \ + callInfo, \ + args, \ + argc, \ + COMPONENT_TYPE_##enumName, \ + &MODULE_ENTITY_##enumName##_PROTO \ + ); \ + } +#include "entity/componentlist.h" +#undef X + +// Methods moduleBaseFunction(moduleEntityConstructor) { entityscript_t *inst = (entityscript_t*)memoryAllocate(sizeof(entityscript_t)); inst->id = entityManagerAdd(); @@ -32,43 +82,23 @@ moduleBaseFunction(moduleEntityConstructor) { } moduleBaseFunction(moduleEntityAddComponent) { - entityscript_t *inst = (entityscript_t*)scriptProtoGetValue( - &MODULE_ENTITY_PROTO, callInfo->this_value - ); - if(!inst) return moduleBaseThrow("Entity.add: invalid entity"); - moduleBaseRequireArgs(1); - - if(!jerry_value_is_object(args[0])) { - return moduleBaseThrow("Entity.add: expected a component type object"); + if(argc < 1 || !jerry_value_is_number(args[0])) { + return moduleBaseThrow("Entity.add: expected a valid component type"); } - jerry_value_t typeKey = jerry_string_sz("_type"); - jerry_value_t typeVal = jerry_object_get(args[0], typeKey); - jerry_value_free(typeKey); - - if(!jerry_value_is_number(typeVal)) { - jerry_value_free(typeVal); - return moduleBaseThrow("Entity.add: expected a component type object"); - } - - componenttype_t type = (componenttype_t)(int32_t)jerry_value_as_number(typeVal); - jerry_value_free(typeVal); - + componenttype_t type = (componenttype_t)jerry_value_as_number(args[0]); if(type <= COMPONENT_TYPE_NULL || type >= COMPONENT_TYPE_COUNT) { return moduleBaseThrow("Entity.add: invalid component type"); } - jerry_external_handler_t addFn = s_componentAddFns[type]; - if(!addFn) return moduleBaseThrow("Entity.add: no handler for this component type"); + // Get the entity script data. + entityscript_t *inst = (entityscript_t*)scriptProtoGetValue( + &MODULE_ENTITY_PROTO, callInfo->this_value + ); + if(!inst) return moduleBaseThrow("Entity.add: invalid entity"); - jerry_value_t idVal = jerry_number((double)inst->id); - jerry_value_t handle = addFn(callInfo, &idVal, 1); - jerry_value_free(idVal); - - jerry_value_t propKey = jerry_string_sz(COMPONENT_DEFINITIONS[type].name); - jerry_object_set(callInfo->this_value, propKey, handle); - jerry_value_free(propKey); - return handle; + componentid_t id = entityAddComponent(inst->id, type); + return jerry_number(id); } moduleBaseFunction(moduleEntityDisposeMethod) { @@ -81,12 +111,7 @@ moduleBaseFunction(moduleEntityDisposeMethod) { } static void moduleEntity(void) { - moduleEntityPosition(); - moduleEntityCamera(); - moduleEntityMesh(); - moduleEntityMaterial(); - moduleEntityPhysics(); - + // Init the entity prototype scriptProtoInit( &MODULE_ENTITY_PROTO, "Entity", @@ -94,40 +119,32 @@ static void moduleEntity(void) { moduleEntityConstructor ); - scriptProtoDefineFunc(&MODULE_ENTITY_PROTO, "add", moduleEntityAddComponent); - scriptProtoDefineFunc(&MODULE_ENTITY_PROTO, "dispose", moduleEntityDisposeMethod); + // Entity Methods + scriptProtoDefineFunc( + &MODULE_ENTITY_PROTO, "add", moduleEntityAddComponent + ); + scriptProtoDefineFunc( + &MODULE_ENTITY_PROTO, "dispose", moduleEntityDisposeMethod + ); - // Lookup table: componenttype_t → add handler. Indexed directly, O(1) dispatch. - memoryZero(s_componentAddFns, sizeof(s_componentAddFns)); - s_componentAddFns[COMPONENT_TYPE_POSITION] = moduleEntityPositionAdd; - s_componentAddFns[COMPONENT_TYPE_CAMERA] = moduleEntityCameraAdd; - s_componentAddFns[COMPONENT_TYPE_MESH] = moduleEntityMeshAdd; - s_componentAddFns[COMPONENT_TYPE_MATERIAL] = moduleEntityMaterialAdd; - s_componentAddFns[COMPONENT_TYPE_PHYSICS] = moduleEntityPhysicsAdd; + // Init component type modules. + char_t buffer[64]; - // Register component type objects as globals and as Entity.POSITION etc. - // Each object stores _type (numeric componenttype_t) for O(1) dispatch, - // and .name (lowercase field name) matching COMPONENT_DEFINITIONS. - jerry_value_t global = jerry_current_realm(); - #define X(enumName, type, field, init, dispose) { \ - jerry_value_t ctObj = jerry_object(); \ - jerry_value_t tk = jerry_string_sz("_type"); \ - jerry_value_t tv = jerry_number((double)COMPONENT_TYPE_##enumName); \ - jerry_object_set(ctObj, tk, tv); \ - jerry_value_free(tv); jerry_value_free(tk); \ - jerry_value_t nk = jerry_string_sz("name"); \ - jerry_value_t nv = jerry_string_sz(#field); \ - jerry_object_set(ctObj, nk, nv); \ - jerry_value_free(nv); jerry_value_free(nk); \ - jerry_value_t gk = jerry_string_sz(#enumName); \ - jerry_object_set(global, gk, ctObj); \ - jerry_value_free(gk); \ - jerry_value_t ek = jerry_string_sz(#enumName); \ - jerry_object_set(MODULE_ENTITY_PROTO.constructor, ek, ctObj); \ - jerry_value_free(ek); \ - jerry_value_free(ctObj); \ - } + #define X(enumName, type, field, iMethod, dMethod) \ + moduleEntity##enumName(); \ + scriptProtoDefineProp( \ + &MODULE_ENTITY_PROTO, \ + COMPONENT_DEFINITIONS[COMPONENT_TYPE_##enumName].name, \ + moduleEntityGet##enumName, \ + NULL \ + ); \ + snprintf( \ + buffer, sizeof(buffer), \ + "%s = %d\n", \ + #enumName, \ + COMPONENT_TYPE_##enumName \ + ); \ + moduleBaseEval(buffer); #include "entity/componentlist.h" #undef X - jerry_value_free(global); }