More cleanup
This commit is contained in:
+18
-31
@@ -1,35 +1,22 @@
|
||||
var Cube = {
|
||||
create: function() {
|
||||
var e = Entity.create();
|
||||
e.add(COMPONENT_TYPE_POSITION);
|
||||
e.position.x = 0;
|
||||
e.position.y = 0;
|
||||
e.position.z = 0;
|
||||
e.add(COMPONENT_TYPE_MESH);
|
||||
e.add(COMPONENT_TYPE_MATERIAL);
|
||||
// e.material.setColor(Color.black());
|
||||
function CubeEntity() {
|
||||
Entity.call(this);
|
||||
this.add(POSITION);
|
||||
this.position.x = 0;
|
||||
this.position.y = 0;
|
||||
this.position.z = 0;
|
||||
this.add(MESH);
|
||||
this.add(MATERIAL);
|
||||
}
|
||||
|
||||
print(Color);
|
||||
print(Color.prototype);
|
||||
Object.assign(CubeEntity.prototype, Entity.prototype);
|
||||
|
||||
return {
|
||||
_e: e,
|
||||
update: Cube.update,
|
||||
dispose: Cube.dispose
|
||||
};
|
||||
},
|
||||
|
||||
update: function() {
|
||||
var speed = 3.0;
|
||||
var dx = inputAxis(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT);
|
||||
var dz = inputAxis(INPUT_ACTION_UP, INPUT_ACTION_DOWN);
|
||||
this._e.position.x += dx * speed * TIME.delta;
|
||||
this._e.position.z += dz * speed * TIME.delta;
|
||||
},
|
||||
|
||||
dispose: function() {
|
||||
this._e.dispose();
|
||||
}
|
||||
CubeEntity.prototype.update = function() {
|
||||
var speed = 3.0;
|
||||
var dx = inputAxis(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT);
|
||||
var dz = inputAxis(INPUT_ACTION_UP, INPUT_ACTION_DOWN);
|
||||
this.position.x += dx * speed * TIME.delta;
|
||||
this.position.z += dz * speed * TIME.delta;
|
||||
this.material.setColor(Color.rainbow());
|
||||
};
|
||||
|
||||
Cube;
|
||||
module = CubeEntity;
|
||||
+19
-21
@@ -1,28 +1,26 @@
|
||||
var Cube = include('entities/cube.js');
|
||||
|
||||
var cam;
|
||||
var cube;
|
||||
function CubeScene() {
|
||||
this.cam = new Entity();
|
||||
this.cam.add(POSITION);
|
||||
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);
|
||||
|
||||
var SceneCube = {
|
||||
init: function() {
|
||||
cam = Entity.create();
|
||||
cam.add(COMPONENT_TYPE_POSITION);
|
||||
cam.position.x = 3;
|
||||
cam.position.y = 3;
|
||||
cam.position.z = 3;
|
||||
cam.position.lookAt(0, 0, 0);
|
||||
cam.add(COMPONENT_TYPE_CAMERA);
|
||||
cube = Cube.create();
|
||||
},
|
||||
this.cube = new Cube();
|
||||
}
|
||||
|
||||
update: function() {
|
||||
cube.update();
|
||||
},
|
||||
Object.assign(CubeScene, Scene.prototype);
|
||||
|
||||
dispose: function() {
|
||||
cam.dispose();
|
||||
cube.dispose();
|
||||
}
|
||||
CubeScene.prototype.update = function() {
|
||||
this.cube.update();
|
||||
};
|
||||
|
||||
SceneCube;
|
||||
CubeScene.prototype.dispose = function() {
|
||||
this.cam.dispose();
|
||||
this.cube.dispose();
|
||||
};
|
||||
|
||||
module = CubeScene;
|
||||
|
||||
@@ -13,7 +13,7 @@ componentdefinition_t COMPONENT_DEFINITIONS[] = {
|
||||
[COMPONENT_TYPE_NULL] = { 0 },
|
||||
|
||||
#define X(enumName, type, field, iMethod, dMethod) \
|
||||
[COMPONENT_TYPE_##enumName] = { .init = iMethod, .dispose = dMethod },
|
||||
[COMPONENT_TYPE_##enumName] = { .name = #field, .init = iMethod, .dispose = dMethod },
|
||||
#include "componentlist.h"
|
||||
#undef X
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ typedef union {
|
||||
} componentdata_t;
|
||||
|
||||
typedef struct {
|
||||
const char_t *name;
|
||||
void (*init)(const entityid_t, const componentid_t);
|
||||
void (*dispose)(const entityid_t, const componentid_t);
|
||||
} componentdefinition_t;
|
||||
|
||||
+15
-7
@@ -167,19 +167,27 @@ errorret_t sceneSetImmediate(const char_t *scene) {
|
||||
);
|
||||
|
||||
if(scene != NULL) {
|
||||
jerry_value_t sceneObj = SCENE_SCRIPT_REF_NONE;
|
||||
jerry_value_t sceneClass = SCENE_SCRIPT_REF_NONE;
|
||||
errorChain(scriptContextExecFile(
|
||||
&SCRIPT_MANAGER.mainContext, scene, &sceneObj
|
||||
&SCRIPT_MANAGER.mainContext, scene, &sceneClass
|
||||
));
|
||||
|
||||
if(!jerry_value_is_object(sceneObj)) {
|
||||
if(sceneObj != SCENE_SCRIPT_REF_NONE) jerry_value_free(sceneObj);
|
||||
errorThrow("Scene '%s' must return an object", scene);
|
||||
if(!jerry_value_is_function(sceneClass)) {
|
||||
if(sceneClass != SCENE_SCRIPT_REF_NONE) jerry_value_free(sceneClass);
|
||||
errorThrow("Scene '%s' must export a constructor function", scene);
|
||||
}
|
||||
|
||||
jerry_value_t sceneObj = jerry_construct(sceneClass, NULL, 0);
|
||||
jerry_value_free(sceneClass);
|
||||
|
||||
if(jerry_value_is_exception(sceneObj)) {
|
||||
char_t errMsg[512];
|
||||
moduleBaseExceptionMessage(sceneObj, errMsg, sizeof(errMsg));
|
||||
jerry_value_free(sceneObj);
|
||||
errorThrow("Scene '%s' constructor threw: %s", scene, errMsg);
|
||||
}
|
||||
|
||||
SCENE.scriptRef = sceneObj;
|
||||
|
||||
errorChain(moduleSceneCall("init"));
|
||||
SCENE.sceneActive = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "script/scriptproto.h"
|
||||
|
||||
// Define the prototype.
|
||||
scriptproto_t MODULE_COLOR_PROTO;
|
||||
static scriptproto_t MODULE_COLOR_PROTO;
|
||||
|
||||
// Getters
|
||||
moduleBaseFunction(moduleColorGetR) {
|
||||
@@ -88,12 +88,25 @@ moduleBaseFunction(moduleColorSetA) {
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorToString) {
|
||||
color_t *color = (color_t*)scriptProtoGetValue(
|
||||
&MODULE_COLOR_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!color) return jerry_undefined();
|
||||
char_t buf[32];
|
||||
stringFormat(buf, sizeof(buf), "[ %d, %d, %d, %d ]",
|
||||
(int32_t)color->r, (int32_t)color->g,
|
||||
(int32_t)color->b, (int32_t)color->a
|
||||
);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
// Constructor
|
||||
static jerry_value_t moduleColorMakeObject(color_t color) {
|
||||
return scriptProtoCreateValue(&MODULE_COLOR_PROTO, &color);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleColorRGBA) {
|
||||
moduleBaseFunction(moduleColorConstructor) {
|
||||
color_t c;
|
||||
|
||||
if(argc > 0) {
|
||||
@@ -158,21 +171,22 @@ moduleBaseFunction(moduleColorRainbow) {
|
||||
|
||||
// Root Module
|
||||
static void moduleColor(void) {
|
||||
scriptProtoInit(&MODULE_COLOR_PROTO, sizeof(color_t));
|
||||
scriptProtoInit(
|
||||
&MODULE_COLOR_PROTO,
|
||||
"Color",
|
||||
sizeof(color_t),
|
||||
moduleColorConstructor
|
||||
);
|
||||
|
||||
#define X(x, g, s) \
|
||||
scriptProtoDefineProperty(&MODULE_COLOR_PROTO, #x, g, s);
|
||||
scriptProtoDefineProp(&MODULE_COLOR_PROTO, #x, g, s);
|
||||
X(r, moduleColorGetR, moduleColorSetR);
|
||||
X(g, moduleColorGetG, moduleColorSetG);
|
||||
X(b, moduleColorGetB, moduleColorSetB);
|
||||
X(a, moduleColorGetA, moduleColorSetA);
|
||||
#undef X
|
||||
|
||||
scriptProtoDefineMethod(&MODULE_COLOR_PROTO, "rgba", moduleColorRGBA);
|
||||
scriptProtoDefineMethod(
|
||||
&MODULE_COLOR_PROTO,"rainbow", moduleColorRainbow
|
||||
);
|
||||
|
||||
scriptProtoCreateGlobal(&MODULE_COLOR_PROTO, "Color");
|
||||
moduleBaseEval("Color.prototype.black = function() { print('test'); };");
|
||||
scriptProtoDefineStaticFunc(&MODULE_COLOR_PROTO, "rainbow", moduleColorRainbow);
|
||||
scriptProtoDefineToString(&MODULE_COLOR_PROTO, moduleColorToString);
|
||||
moduleBaseEval(COLOR_SCRIPT);
|
||||
}
|
||||
|
||||
@@ -45,21 +45,14 @@ moduleBaseFunction(moduleScreenSetBackground) {
|
||||
}
|
||||
|
||||
static void moduleScreen(void) {
|
||||
// Define the prototype
|
||||
scriptProtoInit(&MODULE_SCREEN_PROTO, sizeof(screen_t));
|
||||
scriptProtoInit(&MODULE_SCREEN_PROTO, "Screen", sizeof(screen_t), NULL);
|
||||
|
||||
#define X(x, g, s) \
|
||||
scriptProtoDefineProperty(&MODULE_SCREEN_PROTO, #x, g, s);
|
||||
|
||||
// Setup the getters and setters
|
||||
scriptProtoDefineProp(&MODULE_SCREEN_PROTO, #x, g, s);
|
||||
X(width, moduleScreenGetWidth, NULL)
|
||||
X(height, moduleScreenGetHeight, NULL)
|
||||
X(aspect, moduleScreenGetAspect, NULL)
|
||||
X(background, moduleScreenGetBackground, moduleScreenSetBackground)
|
||||
|
||||
#undef X
|
||||
|
||||
// Create global Screen object
|
||||
scriptProtoCreateGlobal(&MODULE_SCREEN_PROTO, "Screen");
|
||||
}
|
||||
|
||||
@@ -7,81 +7,89 @@
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "entity/entity.h"
|
||||
#include "entity/entitymanager.h"
|
||||
|
||||
#include "component/moduleentityposition.h"
|
||||
#include "component/moduleentitycamera.h"
|
||||
#include "component/moduleentitymesh.h"
|
||||
#include "component/moduleentitymaterial.h"
|
||||
#include "component/moduleentityphysics.h"
|
||||
|
||||
// ---- component type constants script ----
|
||||
typedef struct {
|
||||
entityid_t id;
|
||||
} entityscript_t;
|
||||
|
||||
#define X(enumName, type, field, init, dispose) \
|
||||
"var COMPONENT_TYPE_" #enumName " = \"" #field "\";\n"
|
||||
static const char_t *COMPONENT_TYPE_SCRIPT =
|
||||
#include "entity/componentlist.h"
|
||||
;
|
||||
#undef X
|
||||
static scriptproto_t MODULE_ENTITY_PROTO;
|
||||
|
||||
// ---- Entity base class script ----
|
||||
|
||||
static const char_t *ENTITY_SCRIPT =
|
||||
"var Entity = {};\n"
|
||||
"Entity.POSITION = COMPONENT_TYPE_POSITION;\n"
|
||||
"Entity.CAMERA = COMPONENT_TYPE_CAMERA;\n"
|
||||
"Entity.MESH = COMPONENT_TYPE_MESH;\n"
|
||||
"Entity.MATERIAL = COMPONENT_TYPE_MATERIAL;\n"
|
||||
"Entity.PHYSICS = COMPONENT_TYPE_PHYSICS;\n"
|
||||
"\n"
|
||||
"var _addFns = {};\n"
|
||||
"_addFns[COMPONENT_TYPE_POSITION] = entityPositionAdd;\n"
|
||||
"_addFns[COMPONENT_TYPE_CAMERA] = entityCameraAdd;\n"
|
||||
"_addFns[COMPONENT_TYPE_MESH] = entityMeshAdd;\n"
|
||||
"_addFns[COMPONENT_TYPE_MATERIAL] = entityMaterialAdd;\n"
|
||||
"_addFns[COMPONENT_TYPE_PHYSICS] = entityPhysicsAdd;\n"
|
||||
"\n"
|
||||
"Entity.create = function() {\n"
|
||||
" var self = Object.create(Entity);\n"
|
||||
" self.id = entityAdd();\n"
|
||||
" return self;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"Entity.add = function(componentType) {\n"
|
||||
" var fn = _addFns[componentType];\n"
|
||||
" if(!fn) throw new Error('unknown component type: ' + String(componentType));\n"
|
||||
" this[componentType] = fn(this.id);\n"
|
||||
" return this[componentType];\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"Entity.dispose = function() {\n"
|
||||
" entityRemove(this.id);\n"
|
||||
"};\n"
|
||||
;
|
||||
|
||||
// ---- module functions ----
|
||||
|
||||
/**
|
||||
* Allocates a new entity and returns its id as a JS number.
|
||||
*/
|
||||
moduleBaseFunction(moduleEntityAdd) {
|
||||
return jerry_number((double)entityManagerAdd());
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the entity with the given id.
|
||||
* Arg 0: entity id (number).
|
||||
*/
|
||||
moduleBaseFunction(moduleEntityRemove) {
|
||||
moduleBaseRequireArgs(1); moduleBaseRequireNumber(0);
|
||||
entityDispose((entityid_t)jerry_value_as_number(args[0]));
|
||||
moduleBaseFunction(moduleEntityConstructor) {
|
||||
entityscript_t *inst = (entityscript_t*)memoryAllocate(sizeof(entityscript_t));
|
||||
inst->id = entityManagerAdd();
|
||||
jerry_object_set_native_ptr(callInfo->this_value, &MODULE_ENTITY_PROTO.info, inst);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
jerry_value_t nameKey = jerry_string_sz("name");
|
||||
jerry_value_t nameJsVal = jerry_object_get(args[0], nameKey);
|
||||
jerry_value_free(nameKey);
|
||||
|
||||
if(!jerry_value_is_string(nameJsVal)) {
|
||||
jerry_value_free(nameJsVal);
|
||||
return moduleBaseThrow("Entity.add: component type must have a .name property");
|
||||
}
|
||||
|
||||
char_t nameStr[64];
|
||||
moduleBaseToString(nameJsVal, nameStr, sizeof(nameStr));
|
||||
jerry_value_free(nameJsVal);
|
||||
|
||||
jerry_external_handler_t addFn = NULL;
|
||||
const char_t *propName = NULL;
|
||||
|
||||
if(stringCompare(nameStr, "POSITION") == 0) {
|
||||
addFn = moduleEntityPositionAdd; propName = "position";
|
||||
} else if(stringCompare(nameStr, "CAMERA") == 0) {
|
||||
addFn = moduleEntityCameraAdd; propName = "camera";
|
||||
} else if(stringCompare(nameStr, "MESH") == 0) {
|
||||
addFn = moduleEntityMeshAdd; propName = "mesh";
|
||||
} else if(stringCompare(nameStr, "MATERIAL") == 0) {
|
||||
addFn = moduleEntityMaterialAdd; propName = "material";
|
||||
} else if(stringCompare(nameStr, "PHYSICS") == 0) {
|
||||
addFn = moduleEntityPhysicsAdd; propName = "physics";
|
||||
}
|
||||
|
||||
if(!addFn) return moduleBaseThrow("Entity.add: unknown component type");
|
||||
|
||||
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(propName);
|
||||
jerry_object_set(callInfo->this_value, propKey, handle);
|
||||
jerry_value_free(propKey);
|
||||
return handle;
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleEntityDisposeMethod) {
|
||||
entityscript_t *inst = (entityscript_t*)scriptProtoGetValue(
|
||||
&MODULE_ENTITY_PROTO, callInfo->this_value
|
||||
);
|
||||
if(!inst) return jerry_undefined();
|
||||
entityDispose(inst->id);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers all entity and component modules, component type constants, and
|
||||
* the Entity base object into the JS realm.
|
||||
*/
|
||||
static void moduleEntity(void) {
|
||||
moduleEntityPosition();
|
||||
moduleEntityCamera();
|
||||
@@ -89,9 +97,35 @@ static void moduleEntity(void) {
|
||||
moduleEntityMaterial();
|
||||
moduleEntityPhysics();
|
||||
|
||||
moduleBaseFunctionRegister("entityAdd", moduleEntityAdd);
|
||||
moduleBaseFunctionRegister("entityRemove", moduleEntityRemove);
|
||||
scriptProtoInit(
|
||||
&MODULE_ENTITY_PROTO,
|
||||
"Entity",
|
||||
sizeof(entityscript_t),
|
||||
moduleEntityConstructor
|
||||
);
|
||||
|
||||
moduleBaseEval(COMPONENT_TYPE_SCRIPT);
|
||||
moduleBaseEval(ENTITY_SCRIPT);
|
||||
scriptProtoDefineFunc(&MODULE_ENTITY_PROTO, "add", moduleEntityAddComponent);
|
||||
scriptProtoDefineFunc(&MODULE_ENTITY_PROTO, "dispose", moduleEntityDisposeMethod);
|
||||
|
||||
// Register component type objects as globals and as Entity.POSITION etc.
|
||||
// Each object has a .name property with the uppercase enum name, e.g. "POSITION".
|
||||
jerry_value_t global = jerry_current_realm();
|
||||
#define X(enumName, type, field, init, dispose) { \
|
||||
jerry_value_t ctObj = jerry_object(); \
|
||||
jerry_value_t nk = jerry_string_sz("name"); \
|
||||
jerry_value_t nv = jerry_string_sz(#enumName); \
|
||||
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); \
|
||||
}
|
||||
#include "entity/componentlist.h"
|
||||
#undef X
|
||||
jerry_value_free(global);
|
||||
}
|
||||
|
||||
@@ -7,20 +7,40 @@
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/scriptproto.h"
|
||||
#include "scene/scene.h"
|
||||
|
||||
static scriptproto_t MODULE_SCENE_PROTO;
|
||||
|
||||
// Default no-op lifecycle methods — JS scene instances override these.
|
||||
moduleBaseFunction(moduleSceneDefaultUpdate) {
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleSceneDefaultDispose) {
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
// Constructor — returns undefined so JerryScript uses `this`, which already
|
||||
// has Scene.prototype set. Scenes carry no C struct; all state lives in JS.
|
||||
moduleBaseFunction(moduleSceneConstructor) {
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
// Static: Scene.set(name)
|
||||
moduleBaseFunction(moduleSceneSet) {
|
||||
moduleBaseRequireArgs(1);
|
||||
moduleBaseRequireString(0);
|
||||
|
||||
char_t name[ASSET_FILE_PATH_MAX];
|
||||
moduleBaseToString(args[0], name, sizeof(name));
|
||||
if(name[0] == '\0') return moduleBaseThrow("Scene.set: Scene name cannot be empty");
|
||||
if(name[0] == '\0') return moduleBaseThrow("Scene.set: name cannot be empty");
|
||||
|
||||
sceneSet(name);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
// Static: Scene.current (getter)
|
||||
moduleBaseFunction(moduleSceneGetCurrent) {
|
||||
if(SCENE.sceneCurrent[0] == '\0') return jerry_undefined();
|
||||
return jerry_string_sz(SCENE.sceneCurrent);
|
||||
@@ -32,13 +52,15 @@ static void moduleSceneReset(void) {
|
||||
SCENE.scriptRef = SCENE_SCRIPT_REF_NONE;
|
||||
}
|
||||
|
||||
jerry_value_t obj = jerry_object();
|
||||
|
||||
moduleBaseDefineMethod(obj, "set", moduleSceneSet);
|
||||
moduleBaseDefineProperty(obj, "current", moduleSceneGetCurrent, NULL);
|
||||
|
||||
moduleBaseSetValue("Scene", obj);
|
||||
jerry_value_free(obj);
|
||||
// Drop the 'module' global reference to the scene class so JerryScript's
|
||||
// GC can collect it and all associated closures.
|
||||
jerry_value_t global = jerry_current_realm();
|
||||
jerry_value_t key = jerry_string_sz("module");
|
||||
jerry_value_t undef = jerry_undefined();
|
||||
jerry_object_set(global, key, undef);
|
||||
jerry_value_free(undef);
|
||||
jerry_value_free(key);
|
||||
jerry_value_free(global);
|
||||
}
|
||||
|
||||
static errorret_t moduleSceneCall(const char_t *method) {
|
||||
@@ -72,5 +94,18 @@ static errorret_t moduleSceneCall(const char_t *method) {
|
||||
}
|
||||
|
||||
static void moduleScene(void) {
|
||||
moduleSceneReset();
|
||||
scriptProtoInit(
|
||||
&MODULE_SCENE_PROTO,
|
||||
"Scene",
|
||||
sizeof(uint8_t),
|
||||
moduleSceneConstructor
|
||||
);
|
||||
|
||||
scriptProtoDefineFunc(&MODULE_SCENE_PROTO, "update", moduleSceneDefaultUpdate);
|
||||
scriptProtoDefineFunc(&MODULE_SCENE_PROTO, "dispose", moduleSceneDefaultDispose);
|
||||
|
||||
scriptProtoDefineStaticFunc(&MODULE_SCENE_PROTO, "set", moduleSceneSet);
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_SCENE_PROTO, "current", moduleSceneGetCurrent, NULL
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
|
||||
moduleBaseFunction(moduleInclude) {
|
||||
if(argc < 1 || !jerry_value_is_string(args[0])) {
|
||||
return moduleBaseThrow("Expected string filename");
|
||||
}
|
||||
|
||||
char_t filename[1024];
|
||||
moduleBaseToString(args[0], filename, sizeof(filename));
|
||||
|
||||
if(filename[0] == '\0') {
|
||||
return moduleBaseThrow("Filename cannot be empty");
|
||||
}
|
||||
|
||||
size_t len = strlen(filename);
|
||||
if(len < 3 || stringCompare(&filename[len - 3], ".js") != 0) {
|
||||
return moduleBaseThrow("include: filename must end with .js");
|
||||
}
|
||||
|
||||
char_t buffer[1024];
|
||||
stringCopy(buffer, filename, sizeof(buffer));
|
||||
|
||||
// Save and reset 'export' so the included module gets a clean undefined
|
||||
// default. Saving lets nested includes each have their own export scope.
|
||||
jerry_value_t global = jerry_current_realm();
|
||||
jerry_value_t moduleKey = jerry_string_sz("module");
|
||||
jerry_value_t prevModule = jerry_object_get(global, moduleKey);
|
||||
jerry_value_t undef = jerry_undefined();
|
||||
jerry_object_set(global, moduleKey, undef);
|
||||
jerry_value_free(undef);
|
||||
|
||||
jerry_value_t result = 0;
|
||||
errorret_t err = scriptContextExecFile(scriptContextCurrent, buffer, &result);
|
||||
if(result != 0) jerry_value_free(result);
|
||||
|
||||
// Capture whatever the module assigned to 'module', then restore the
|
||||
// caller's value so nested includes don't clobber each other.
|
||||
jerry_value_t moduleVal = jerry_object_get(global, moduleKey);
|
||||
jerry_object_set(global, moduleKey, prevModule);
|
||||
jerry_value_free(prevModule);
|
||||
jerry_value_free(moduleKey);
|
||||
jerry_value_free(global);
|
||||
|
||||
if(err.code != ERROR_OK) {
|
||||
jerry_value_free(moduleVal);
|
||||
errorCatch(errorPrint(err));
|
||||
return moduleBaseThrow("Failed to include script file");
|
||||
}
|
||||
|
||||
return moduleVal;
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "script/module/modulebase.h"
|
||||
#include "script/module/script/moduleinclude.h"
|
||||
#include "console/console.h"
|
||||
|
||||
moduleBaseFunction(moduleScriptPrint) {
|
||||
@@ -35,42 +36,7 @@ moduleBaseFunction(moduleScriptPrint) {
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleScriptInclude) {
|
||||
if(argc < 1 || !jerry_value_is_string(args[0])) {
|
||||
return moduleBaseThrow("Expected string filename");
|
||||
}
|
||||
|
||||
char_t filename[1024];
|
||||
moduleBaseToString(args[0], filename, sizeof(filename));
|
||||
|
||||
if(filename[0] == '\0') {
|
||||
return moduleBaseThrow("Filename cannot be empty");
|
||||
}
|
||||
|
||||
char_t buffer[1024];
|
||||
stringCopy(buffer, filename, sizeof(buffer));
|
||||
|
||||
size_t len = strlen(buffer);
|
||||
if(len < 3 || stringCompare(&buffer[len - 3], ".js") != 0) {
|
||||
if(len + 3 >= sizeof(buffer)) {
|
||||
return moduleBaseThrow("Filename too long to append .js");
|
||||
}
|
||||
stringCopy(&buffer[len], ".js", 4);
|
||||
}
|
||||
|
||||
jerry_value_t result = 0;
|
||||
errorret_t err = scriptContextExecFile(scriptContextCurrent, buffer, &result);
|
||||
if(err.code != ERROR_OK) {
|
||||
if(result != 0) jerry_value_free(result);
|
||||
errorCatch(errorPrint(err));
|
||||
return moduleBaseThrow("Failed to include script file");
|
||||
}
|
||||
|
||||
if(result == 0) return jerry_undefined();
|
||||
return result;
|
||||
}
|
||||
|
||||
static void moduleScript(void) {
|
||||
moduleBaseFunctionRegister("print", moduleScriptPrint);
|
||||
moduleBaseFunctionRegister("include", moduleScriptInclude);
|
||||
moduleBaseFunctionRegister("include", moduleInclude);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,12 @@
|
||||
#include "util/memory.h"
|
||||
#include "script/module/modulebase.h"
|
||||
|
||||
void scriptProtoInit(scriptproto_t *proto, const size_t size) {
|
||||
void scriptProtoInit(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
const size_t size,
|
||||
jerry_external_handler_t constructor
|
||||
) {
|
||||
assertNotNull(proto, "Script prototype struct must not be null");
|
||||
memoryZero(proto, sizeof(scriptproto_t));
|
||||
|
||||
@@ -19,13 +24,35 @@ void scriptProtoInit(scriptproto_t *proto, const size_t size) {
|
||||
.number_of_references = 0,
|
||||
.offset_of_references = 0
|
||||
};
|
||||
|
||||
proto->prototype = jerry_object();
|
||||
|
||||
proto->size = size;
|
||||
|
||||
if(constructor != NULL) {
|
||||
proto->constructor = jerry_function_external(constructor);
|
||||
jerry_value_t protoKey = jerry_string_sz("prototype");
|
||||
jerry_object_set(proto->constructor, protoKey, proto->prototype);
|
||||
jerry_value_free(protoKey);
|
||||
jerry_value_t ctorKey = jerry_string_sz("constructor");
|
||||
jerry_object_set(proto->prototype, ctorKey, proto->constructor);
|
||||
jerry_value_free(ctorKey);
|
||||
}
|
||||
|
||||
if(name != NULL) {
|
||||
jerry_value_t global = jerry_current_realm();
|
||||
jerry_value_t key = jerry_string_sz(name);
|
||||
jerry_value_t val;
|
||||
if(proto->constructor) {
|
||||
val = proto->constructor;
|
||||
} else {
|
||||
val = proto->prototype;
|
||||
}
|
||||
jerry_object_set(global, key, val);
|
||||
jerry_value_free(key);
|
||||
jerry_value_free(global);
|
||||
}
|
||||
}
|
||||
|
||||
void scriptProtoDefineProperty(
|
||||
void scriptProtoDefineProp(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t getter,
|
||||
@@ -51,16 +78,14 @@ void scriptProtoDefineProperty(
|
||||
}
|
||||
|
||||
jerry_value_t key = jerry_string_sz(name);
|
||||
jerry_value_t result = jerry_object_define_own_prop(
|
||||
proto->prototype, key, &desc
|
||||
);
|
||||
jerry_value_t result = jerry_object_define_own_prop(proto->prototype, key, &desc);
|
||||
jerry_value_free(result);
|
||||
jerry_value_free(key);
|
||||
jerry_value_free(desc.getter);
|
||||
if(setter != NULL) jerry_value_free(desc.setter);
|
||||
}
|
||||
|
||||
void scriptProtoDefineMethod(
|
||||
void scriptProtoDefineFunc(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t fn
|
||||
@@ -76,24 +101,56 @@ void scriptProtoDefineMethod(
|
||||
jerry_value_free(key);
|
||||
}
|
||||
|
||||
void scriptProtoCreateGlobal(
|
||||
void scriptProtoDefineStaticProp(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name
|
||||
const char_t *name,
|
||||
jerry_external_handler_t getter,
|
||||
jerry_external_handler_t setter
|
||||
) {
|
||||
assertNotNull(proto, "Script prototype struct must not be null");
|
||||
assertStrLenMin(name, 1, "Global object name must not be empty");
|
||||
assertStrLenMin(name, 1, "Property name must not be empty");
|
||||
assertNotNull(getter, "Getter must not be null");
|
||||
|
||||
jerry_value_t target = proto->constructor ? proto->constructor : proto->prototype;
|
||||
|
||||
jerry_property_descriptor_t desc;
|
||||
memoryZero(&desc, sizeof(desc));
|
||||
desc.flags = (uint16_t)(
|
||||
JERRY_PROP_IS_GET_DEFINED |
|
||||
JERRY_PROP_IS_ENUMERABLE_DEFINED | JERRY_PROP_IS_ENUMERABLE |
|
||||
JERRY_PROP_IS_CONFIGURABLE_DEFINED | JERRY_PROP_IS_CONFIGURABLE
|
||||
);
|
||||
|
||||
desc.getter = jerry_function_external(getter);
|
||||
|
||||
if(setter != NULL) {
|
||||
desc.flags |= JERRY_PROP_IS_SET_DEFINED;
|
||||
desc.setter = jerry_function_external(setter);
|
||||
}
|
||||
|
||||
jerry_value_t global = jerry_current_realm();
|
||||
jerry_value_t key = jerry_string_sz(name);
|
||||
jerry_object_set(global, key, proto->prototype);
|
||||
jerry_value_t result = jerry_object_define_own_prop(target, key, &desc);
|
||||
jerry_value_free(result);
|
||||
jerry_value_free(key);
|
||||
jerry_value_free(global);
|
||||
jerry_value_free(desc.getter);
|
||||
if(setter != NULL) jerry_value_free(desc.setter);
|
||||
}
|
||||
|
||||
void * scriptProtoGetValue(const scriptproto_t *proto, const jerry_value_t obj){
|
||||
void scriptProtoDefineStaticFunc(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t fn
|
||||
) {
|
||||
assertNotNull(proto, "Script prototype struct must not be null");
|
||||
if(!jerry_value_is_object(obj)) return NULL;
|
||||
return jerry_object_get_native_ptr(obj, &proto->info);
|
||||
assertStrLenMin(name, 1, "Method name must not be empty");
|
||||
assertNotNull(fn, "Function handler must not be null");
|
||||
|
||||
jerry_value_t target = proto->constructor ? proto->constructor : proto->prototype;
|
||||
jerry_value_t key = jerry_string_sz(name);
|
||||
jerry_value_t func = jerry_function_external(fn);
|
||||
jerry_object_set(target, key, func);
|
||||
jerry_value_free(func);
|
||||
jerry_value_free(key);
|
||||
}
|
||||
|
||||
jerry_value_t scriptProtoCreateValue(
|
||||
@@ -106,12 +163,29 @@ jerry_value_t scriptProtoCreateValue(
|
||||
void *ptr = memoryAllocate(proto->size);
|
||||
memoryCopy(ptr, value, proto->size);
|
||||
jerry_value_t obj = jerry_object();
|
||||
jerry_object_set_native_ptr(obj, ptr, &proto->info);
|
||||
jerry_object_set_native_ptr(obj, &proto->info, ptr);
|
||||
jerry_object_set_proto(obj, proto->prototype);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void *scriptProtoGetValue(
|
||||
const scriptproto_t *proto,
|
||||
const jerry_value_t obj
|
||||
) {
|
||||
assertNotNull(proto, "Script prototype struct must not be null");
|
||||
if(!jerry_value_is_object(obj)) return NULL;
|
||||
return jerry_object_get_native_ptr(obj, &proto->info);
|
||||
}
|
||||
|
||||
void scriptProtoDefineToString(
|
||||
scriptproto_t *proto,
|
||||
jerry_external_handler_t fn
|
||||
) {
|
||||
scriptProtoDefineFunc(proto, "toString", fn);
|
||||
}
|
||||
|
||||
void scriptProtoDispose(scriptproto_t *proto) {
|
||||
assertNotNull(proto, "Script prototype struct must not be null");
|
||||
jerry_value_free(proto->prototype);
|
||||
if(proto->constructor) jerry_value_free(proto->constructor);
|
||||
}
|
||||
|
||||
@@ -12,26 +12,38 @@
|
||||
typedef struct {
|
||||
jerry_object_native_info_t info;
|
||||
jerry_value_t prototype;
|
||||
jerry_value_t constructor;
|
||||
size_t size;
|
||||
} scriptproto_t;
|
||||
|
||||
/**
|
||||
* Initialize a script prototype struct.
|
||||
* Initialize a JS class prototype.
|
||||
*
|
||||
* @param proto The script prototype struct to initialize.
|
||||
* @param size Size of the struct that this proto represents.
|
||||
* If name is non-NULL the class is registered as a global. When ctor is also
|
||||
* non-NULL the global is the constructor function (enabling `new Name(...)`);
|
||||
* otherwise the prototype object itself becomes the global.
|
||||
*
|
||||
* @param proto The struct to initialize.
|
||||
* @param name JS global name, or NULL to skip global registration.
|
||||
* @param size sizeof the C struct this class wraps.
|
||||
* @param ctor Constructor handler, or NULL if the class has no constructor.
|
||||
*/
|
||||
void scriptProtoInit(scriptproto_t *proto, const size_t size);
|
||||
void scriptProtoInit(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
const size_t size,
|
||||
jerry_external_handler_t ctor
|
||||
);
|
||||
|
||||
/**
|
||||
* Define a property on a prototype with the provided getter and setter.
|
||||
* Define an instance property with a getter and optional setter.
|
||||
*
|
||||
* @param proto The prototype to define the property on.
|
||||
* @param name The name of the property.
|
||||
* @param getter Function to call for getting.
|
||||
* @param setter Function to call for setting (or NULL for read-only).
|
||||
* @param proto The class prototype.
|
||||
* @param name Property name.
|
||||
* @param getter Getter handler (must not be NULL).
|
||||
* @param setter Setter handler, or NULL for a read-only property.
|
||||
*/
|
||||
void scriptProtoDefineProperty(
|
||||
void scriptProtoDefineProp(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t getter,
|
||||
@@ -39,35 +51,58 @@ void scriptProtoDefineProperty(
|
||||
);
|
||||
|
||||
/**
|
||||
* Define a method on a prototype.
|
||||
* Define an instance method on the class prototype.
|
||||
*
|
||||
* @param proto The prototype to define the method on.
|
||||
* @param name The name of the method.
|
||||
* @param fn The C function to call when the method is invoked in JS.
|
||||
* @param proto The class prototype.
|
||||
* @param name Method name.
|
||||
* @param fn C handler called when the method is invoked.
|
||||
*/
|
||||
void scriptProtoDefineMethod(
|
||||
void scriptProtoDefineFunc(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t fn
|
||||
);
|
||||
|
||||
/**
|
||||
* Defines a global object with the provided name and prototype.
|
||||
* Define a static property on the class (e.g. Scene.current).
|
||||
*
|
||||
* @param proto The prototype struct to use for the global object.
|
||||
* @param name The name of the global object to create.
|
||||
* Attaches to the constructor function when one exists, otherwise attaches
|
||||
* directly to the prototype object (which is the global in that case).
|
||||
*
|
||||
* @param proto The class prototype.
|
||||
* @param name Property name.
|
||||
* @param getter Getter handler (must not be NULL).
|
||||
* @param setter Setter handler, or NULL for a read-only property.
|
||||
*/
|
||||
void scriptProtoCreateGlobal(
|
||||
void scriptProtoDefineStaticProp(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name
|
||||
const char_t *name,
|
||||
jerry_external_handler_t getter,
|
||||
jerry_external_handler_t setter
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a JS object based on a C value using the provided prototype.
|
||||
* Define a static method on the class (e.g. Color.fromRGBA).
|
||||
*
|
||||
* @param proto The prototype.
|
||||
* @param value The pointer to the C value to create a JS object for.
|
||||
* @return A JS object wrapping the provided C value.
|
||||
* Attaches to the constructor function when one exists, otherwise attaches
|
||||
* directly to the prototype object (which is the global in that case).
|
||||
*
|
||||
* @param proto The class prototype.
|
||||
* @param name Method name.
|
||||
* @param fn C handler called when the static method is invoked.
|
||||
*/
|
||||
void scriptProtoDefineStaticFunc(
|
||||
scriptproto_t *proto,
|
||||
const char_t *name,
|
||||
jerry_external_handler_t fn
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a JS instance wrapping a copy of a C value.
|
||||
*
|
||||
* @param proto The class prototype.
|
||||
* @param value Pointer to the C value to copy into the new JS object.
|
||||
* @return A new JS object with the class prototype and native pointer set.
|
||||
*/
|
||||
jerry_value_t scriptProtoCreateValue(
|
||||
const scriptproto_t *proto,
|
||||
@@ -75,9 +110,31 @@ jerry_value_t scriptProtoCreateValue(
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the native C struct pointer from a JS object using the prototype info.
|
||||
* Unwrap the native C pointer from a JS object.
|
||||
*
|
||||
* @param proto The prototype struct containing the native info.
|
||||
* @param obj The JS object to get the native value from.
|
||||
* @param proto The class prototype.
|
||||
* @param obj The JS object to inspect.
|
||||
* @return Pointer to the wrapped C value, or NULL if not an instance.
|
||||
*/
|
||||
void * scriptProtoGetValue(const scriptproto_t *proto, const jerry_value_t obj);
|
||||
void *scriptProtoGetValue(
|
||||
const scriptproto_t *proto,
|
||||
const jerry_value_t obj
|
||||
);
|
||||
|
||||
/**
|
||||
* Define the toString() method on the class prototype.
|
||||
*
|
||||
* @param proto The class prototype.
|
||||
* @param fn C handler called when toString() is invoked on an instance.
|
||||
*/
|
||||
void scriptProtoDefineToString(
|
||||
scriptproto_t *proto,
|
||||
jerry_external_handler_t fn
|
||||
);
|
||||
|
||||
/**
|
||||
* Release all JerryScript resources held by the prototype.
|
||||
*
|
||||
* @param proto The class prototype to dispose.
|
||||
*/
|
||||
void scriptProtoDispose(scriptproto_t *proto);
|
||||
|
||||
@@ -62,7 +62,7 @@ for name, (r, g, b, a) in colors.items():
|
||||
]
|
||||
js += [
|
||||
f"Color.{name.lower()} = function() {{",
|
||||
f" return Color.rgba({r8}, {g8}, {b8}, {a8});",
|
||||
f" return new Color({r8}, {g8}, {b8}, {a8});",
|
||||
"};",
|
||||
"",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user