Example Camera
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
const e = Entity.create();
|
||||
const pos = e.add(Component.POSITION);
|
||||
pos.localPosition = new Vec3(-1, 0, 1);
|
||||
Console.print('Entity ID: ' + e.toString());
|
||||
const cam = Entity.create();
|
||||
const pos = cam.add(Component.POSITION);
|
||||
cam.add(Component.CAMERA);
|
||||
|
||||
pos.localPosition = new Vec3(3, 3, 3);
|
||||
pos.lookAt(new Vec3(0, 0, 0));
|
||||
|
||||
Console.print('Camera entity ID: ' + cam.toString());
|
||||
|
||||
@@ -9,29 +9,27 @@
|
||||
#include "console/console.h"
|
||||
#include "scene/scene.h"
|
||||
#include "script/script.h"
|
||||
#include "time/time.h"
|
||||
#include "ui/uiloading.h"
|
||||
#include "entity/entitymanager.h"
|
||||
#include "entity/entity.h"
|
||||
#include "entity/component/display/entityposition.h"
|
||||
#include "entity/component/display/entityrenderable.h"
|
||||
|
||||
void initialSceneInit(void) {
|
||||
consolePrint("Initial scene initialized");
|
||||
|
||||
// Cube entity — RENDERABLE init defaults to a white unit cube at origin
|
||||
entityid_t cubeId = entityManagerAdd();
|
||||
SCENE.data.initial.cubeEntityId = cubeId;
|
||||
entityAddComponent(cubeId, COMPONENT_TYPE_POSITION);
|
||||
entityAddComponent(cubeId, COMPONENT_TYPE_RENDERABLE);
|
||||
|
||||
errorCatch(errorPrint(scriptExecFile("testentity.js")));
|
||||
// SCENE.data.initial.timer = 0.0f;
|
||||
// SCENE.data.initial.hiding = false;
|
||||
// uiLoadingShow(NULL, NULL);
|
||||
}
|
||||
|
||||
errorret_t initialSceneUpdate(void) {
|
||||
// initialscene_t *scene = &SCENE.data.initial;
|
||||
// if(scene->hiding) errorOk();
|
||||
|
||||
// scene->timer += TIME.delta;
|
||||
// if(scene->timer >= INITIAL_SCENE_WAIT) {
|
||||
// scene->hiding = true;
|
||||
// uiLoadingHide(NULL, NULL);
|
||||
// }
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void initialSceneDispose(void) {
|
||||
entityDispose(SCENE.data.initial.cubeEntityId);
|
||||
}
|
||||
|
||||
@@ -7,12 +7,10 @@
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
|
||||
#define INITIAL_SCENE_WAIT 2.0f
|
||||
#include "entity/entitybase.h"
|
||||
|
||||
typedef struct {
|
||||
float_t timer;
|
||||
bool_t hiding;
|
||||
entityid_t cubeEntityId;
|
||||
} initialscene_t;
|
||||
|
||||
void initialSceneInit(void);
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* 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"
|
||||
#include "script/scriptproto.h"
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "entity/component/display/entitycamera.h"
|
||||
|
||||
static scriptproto_t MODULE_CAMERA_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleCameraCtor) {
|
||||
(void)callInfo; (void)args; (void)argc;
|
||||
return moduleBaseThrow("Camera cannot be instantiated with new");
|
||||
}
|
||||
|
||||
static inline jscomponent_t *moduleCameraSelf(
|
||||
const jerry_call_info_t *callInfo
|
||||
) {
|
||||
return (jscomponent_t *)scriptProtoGetValue(
|
||||
&MODULE_CAMERA_PROTO, callInfo->this_value
|
||||
);
|
||||
}
|
||||
|
||||
static inline entitycamera_t *moduleCameraData(const jscomponent_t *c) {
|
||||
return (entitycamera_t *)componentGetData(
|
||||
c->entityId, c->componentId, COMPONENT_TYPE_CAMERA
|
||||
);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraGetEntity) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->entityId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraGetId) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
return jerry_number((double)c->componentId);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraGetFov) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
return jerry_number((double)cam->perspective.fov);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraSetFov) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
cam->perspective.fov = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraGetNearClip) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
return jerry_number((double)cam->nearClip);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraSetNearClip) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
cam->nearClip = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraGetFarClip) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
return jerry_number((double)cam->farClip);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraSetFarClip) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
cam->farClip = moduleBaseArgFloat(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraGetProjType) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
return jerry_number((double)cam->projType);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraSetProjType) {
|
||||
moduleBaseRequireArgs(1);
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
entitycamera_t *cam = moduleCameraData(c);
|
||||
if(!cam) return jerry_undefined();
|
||||
cam->projType = (entitycameraprojectiontype_t)moduleBaseArgInt(0);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleCameraToString) {
|
||||
jscomponent_t *c = moduleCameraSelf(callInfo);
|
||||
if(!c) return jerry_string_sz("Camera:invalid");
|
||||
char_t buf[32];
|
||||
snprintf(buf, sizeof(buf), "Camera(%u)", (unsigned)c->componentId);
|
||||
return jerry_string_sz(buf);
|
||||
}
|
||||
|
||||
static void moduleCameraInit(void) {
|
||||
scriptProtoInit(
|
||||
&MODULE_CAMERA_PROTO, "Camera",
|
||||
sizeof(jscomponent_t), moduleCameraCtor
|
||||
);
|
||||
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "entity", moduleCameraGetEntity, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "id", moduleCameraGetId, NULL
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "fov", moduleCameraGetFov, moduleCameraSetFov
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "nearClip",
|
||||
moduleCameraGetNearClip, moduleCameraSetNearClip
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "farClip",
|
||||
moduleCameraGetFarClip, moduleCameraSetFarClip
|
||||
);
|
||||
scriptProtoDefineProp(
|
||||
&MODULE_CAMERA_PROTO, "projType",
|
||||
moduleCameraGetProjType, moduleCameraSetProjType
|
||||
);
|
||||
scriptProtoDefineToString(&MODULE_CAMERA_PROTO, moduleCameraToString);
|
||||
|
||||
/* Camera.PERSPECTIVE, Camera.PERSPECTIVE_FLIPPED, Camera.ORTHOGRAPHIC */
|
||||
jerry_value_t ctor = MODULE_CAMERA_PROTO.constructor;
|
||||
struct { const char_t *name; int val; } projtypes[] = {
|
||||
{ "PERSPECTIVE", ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE },
|
||||
{ "PERSPECTIVE_FLIPPED", ENTITY_CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED },
|
||||
{ "ORTHOGRAPHIC", ENTITY_CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC },
|
||||
};
|
||||
for(int i = 0; i < 3; i++) {
|
||||
jerry_value_t k = jerry_string_sz(projtypes[i].name);
|
||||
jerry_value_t v = jerry_number((double)projtypes[i].val);
|
||||
jerry_object_set(ctor, k, v);
|
||||
jerry_value_free(v);
|
||||
jerry_value_free(k);
|
||||
}
|
||||
}
|
||||
|
||||
static void moduleCameraDispose(void) {
|
||||
scriptProtoDispose(&MODULE_CAMERA_PROTO);
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "script/module/entity/modulecomponent.h"
|
||||
#include "camera/modulecamera.h"
|
||||
#include "position/moduleposition.h"
|
||||
|
||||
/**
|
||||
@@ -20,6 +21,8 @@ static jerry_value_t moduleComponentListCreateInstance(
|
||||
switch(type) {
|
||||
case COMPONENT_TYPE_POSITION:
|
||||
return scriptProtoCreateValue(&MODULE_POSITION_PROTO, comp);
|
||||
case COMPONENT_TYPE_CAMERA:
|
||||
return scriptProtoCreateValue(&MODULE_CAMERA_PROTO, comp);
|
||||
default:
|
||||
return scriptProtoCreateValue(&MODULE_COMPONENT_PROTO, comp);
|
||||
}
|
||||
@@ -27,8 +30,10 @@ static jerry_value_t moduleComponentListCreateInstance(
|
||||
|
||||
static void moduleComponentListInit(void) {
|
||||
modulePositionInit();
|
||||
moduleCameraInit();
|
||||
}
|
||||
|
||||
static void moduleComponentListDispose(void) {
|
||||
moduleCameraDispose();
|
||||
modulePositionDispose();
|
||||
}
|
||||
|
||||
@@ -147,6 +147,26 @@ moduleBaseFunction(modulePositionSetWorldScale) {
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionLookAt) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
moduleBaseRequireArgs(1);
|
||||
float_t *target = moduleVec3From(args[0]);
|
||||
if(!target) return moduleBaseThrow("Position.lookAt: expected Vec3 target");
|
||||
|
||||
vec3 eye;
|
||||
entityPositionGetLocalPosition(c->entityId, c->componentId, eye);
|
||||
|
||||
vec3 up = { 0.0f, 1.0f, 0.0f };
|
||||
if(argc >= 2) {
|
||||
float_t *upArg = moduleVec3From(args[1]);
|
||||
if(upArg) glm_vec3_copy(upArg, up);
|
||||
}
|
||||
|
||||
entityPositionLookAt(c->entityId, c->componentId, eye, target, up);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
moduleBaseFunction(modulePositionSetParent) {
|
||||
jscomponent_t *c = modulePositionSelf(callInfo);
|
||||
if(!c) return jerry_undefined();
|
||||
@@ -214,6 +234,9 @@ static void modulePositionInit(void) {
|
||||
&MODULE_POSITION_PROTO, "worldScale",
|
||||
modulePositionGetWorldScale, modulePositionSetWorldScale
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_POSITION_PROTO, "lookAt", modulePositionLookAt
|
||||
);
|
||||
scriptProtoDefineFunc(
|
||||
&MODULE_POSITION_PROTO, "setParent", modulePositionSetParent
|
||||
);
|
||||
|
||||
@@ -12,8 +12,43 @@
|
||||
|
||||
static scriptproto_t MODULE_SCENE_PROTO;
|
||||
|
||||
moduleBaseFunction(moduleSceneGetCurrent) {
|
||||
return jerry_number((double)SCENE.type);
|
||||
}
|
||||
|
||||
moduleBaseFunction(moduleSceneSet) {
|
||||
moduleBaseRequireArgs(1);
|
||||
moduleBaseRequireNumber(0);
|
||||
const scenetype_t type = (scenetype_t)moduleBaseArgInt(0);
|
||||
if(type <= SCENE_TYPE_NULL || type >= SCENE_TYPE_COUNT) {
|
||||
return moduleBaseThrow("Scene.set: invalid scene type");
|
||||
}
|
||||
sceneSet(type);
|
||||
return jerry_undefined();
|
||||
}
|
||||
|
||||
static void moduleSceneInit(void) {
|
||||
scriptProtoInit(&MODULE_SCENE_PROTO, "Scene", sizeof(uint8_t), NULL);
|
||||
|
||||
scriptProtoDefineStaticProp(
|
||||
&MODULE_SCENE_PROTO, "current", moduleSceneGetCurrent, NULL
|
||||
);
|
||||
scriptProtoDefineStaticFunc(
|
||||
&MODULE_SCENE_PROTO, "set", moduleSceneSet
|
||||
);
|
||||
|
||||
/* Scene.INITIAL, Scene.TEST, Scene.OVERWORLD, ... */
|
||||
jerry_value_t global = MODULE_SCENE_PROTO.prototype;
|
||||
#define X(structName, varName, varNameUpper, initFunc, updateFunc, disposeFunc) \
|
||||
do { \
|
||||
jerry_value_t _key = jerry_string_sz(#varNameUpper); \
|
||||
jerry_value_t _val = jerry_number((double)SCENE_TYPE_##varNameUpper); \
|
||||
jerry_object_set(global, _key, _val); \
|
||||
jerry_value_free(_val); \
|
||||
jerry_value_free(_key); \
|
||||
} while(0);
|
||||
#include "scene/scenelist.h"
|
||||
#undef X
|
||||
}
|
||||
|
||||
static void moduleSceneDispose(void) {
|
||||
|
||||
Vendored
+129
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Component (generic base returned by entity.add() for untyped components)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Base component returned by entity.add() for component types without a specific module. */
|
||||
interface Component {
|
||||
/** Entity ID this component belongs to. */
|
||||
readonly entity: number;
|
||||
/** Component slot ID. */
|
||||
readonly id: number;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface ComponentConstructor {
|
||||
/** Sentinel value for an invalid component ID. */
|
||||
readonly INVALID: number;
|
||||
|
||||
// Component type constants (generated from componentlist.h)
|
||||
readonly POSITION: number;
|
||||
readonly CAMERA: number;
|
||||
readonly RENDERABLE: number;
|
||||
readonly PHYSICS: number;
|
||||
readonly TRIGGER: number;
|
||||
readonly OVERWORLD: number;
|
||||
readonly PLAYER: number;
|
||||
readonly INTERACTABLE: number;
|
||||
readonly OVERWORLD_CAMERA: number;
|
||||
readonly OVERWORLD_TRIGGER: number;
|
||||
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var Component: ComponentConstructor;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Position
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Position/rotation/scale transform component with optional parent hierarchy. */
|
||||
interface Position extends Component {
|
||||
/**
|
||||
* Local-space position. Assigning a Vec3 writes to the C transform and
|
||||
* marks the world transform dirty. Reading returns a fresh Vec3 copy.
|
||||
*/
|
||||
localPosition: Vec3;
|
||||
/** World-space position (accounts for all parent transforms). */
|
||||
worldPosition: Vec3;
|
||||
/** Local-space euler rotation in radians (XYZ). */
|
||||
localRotation: Vec3;
|
||||
/** World-space euler rotation in radians. */
|
||||
worldRotation: Vec3;
|
||||
/** Local-space scale. */
|
||||
localScale: Vec3;
|
||||
/** World-space scale. */
|
||||
worldScale: Vec3;
|
||||
/**
|
||||
* Orients the transform to look at a world-space target point.
|
||||
* Uses the current local position as the eye. Optionally specify an up
|
||||
* vector (defaults to Y-up).
|
||||
*/
|
||||
lookAt(target: Vec3, up?: Vec3): void;
|
||||
/**
|
||||
* Sets this component's parent in the transform hierarchy.
|
||||
* Pass `null` or `undefined` to detach.
|
||||
*/
|
||||
setParent(parent: Position | null | undefined): void;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface PositionConstructor {
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var Position: PositionConstructor;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Camera
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Camera projection component. */
|
||||
interface Camera extends Component {
|
||||
/** Field of view in radians (perspective projections only). */
|
||||
fov: number;
|
||||
/** Near clip plane distance. */
|
||||
nearClip: number;
|
||||
/** Far clip plane distance. */
|
||||
farClip: number;
|
||||
/** Projection type — one of the Camera.PERSPECTIVE / Camera.ORTHOGRAPHIC constants. */
|
||||
projType: number;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface CameraConstructor {
|
||||
readonly PERSPECTIVE: number;
|
||||
readonly PERSPECTIVE_FLIPPED: number;
|
||||
readonly ORTHOGRAPHIC: number;
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var Camera: CameraConstructor;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Entity
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
interface Entity {
|
||||
/** Add a component of the given type and return a typed instance. */
|
||||
add(type: CameraConstructor["PERSPECTIVE"] | number): Component;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface EntityConstructor {
|
||||
/** Sentinel value for an invalid entity ID. */
|
||||
readonly INVALID: number;
|
||||
/** Creates a new entity and returns it. Returns Entity.INVALID slot if the pool is full. */
|
||||
create(): Entity;
|
||||
/** Disposes the entity and all its components. */
|
||||
dispose(entity: Entity): void;
|
||||
new(): never;
|
||||
}
|
||||
|
||||
declare var Entity: EntityConstructor;
|
||||
Vendored
+3
@@ -19,3 +19,6 @@
|
||||
/// <reference path="./engine.d.ts" />
|
||||
/// <reference path="./input.d.ts" />
|
||||
/// <reference path="./system.d.ts" />
|
||||
/// <reference path="./vec3.d.ts" />
|
||||
/// <reference path="./entity.d.ts" />
|
||||
/// <reference path="./scene.d.ts" />
|
||||
|
||||
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** Scene management — request scene transitions and query the active scene. */
|
||||
interface SceneNamespace {
|
||||
/** The type constant of the currently active scene, or 0 if none. */
|
||||
readonly current: number;
|
||||
|
||||
/**
|
||||
* Requests a scene transition. The change takes effect at the start of the
|
||||
* next safe update tick (current scene is disposed, new scene is initialized).
|
||||
*
|
||||
* @param type - A `Scene.*` scene type constant.
|
||||
*
|
||||
* @example
|
||||
* Scene.set(Scene.OVERWORLD);
|
||||
*/
|
||||
set(type: number): void;
|
||||
|
||||
// Scene type constants (generated from scenelist.h)
|
||||
readonly INITIAL: number;
|
||||
readonly TEST: number;
|
||||
readonly OVERWORLD: number;
|
||||
}
|
||||
|
||||
declare var Scene: SceneNamespace;
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/** A three-component float vector (x, y, z). */
|
||||
declare class Vec3 {
|
||||
constructor(x?: number, y?: number, z?: number);
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
toString(): string;
|
||||
}
|
||||
Reference in New Issue
Block a user