Just trying to fix things now
This commit is contained in:
@@ -53,6 +53,13 @@ All struct and enum types end in `_t` (`animation_t`, `errorret_t`, …).
|
|||||||
### Implementation files (`.c`)
|
### Implementation files (`.c`)
|
||||||
- Contain function bodies only; no declarations.
|
- Contain function bodies only; no declarations.
|
||||||
- Pull in whatever additional includes the implementation needs.
|
- Pull in whatever additional includes the implementation needs.
|
||||||
|
- Do not use `static` or `inline` on **functions**. Every function,
|
||||||
|
including internal helpers, must be declared in the matching `.h` and
|
||||||
|
defined in the `.c` file. Internal helpers belong near the bottom of
|
||||||
|
the `.c` file, not at the top with a `static` qualifier.
|
||||||
|
`static` and `inline` on functions are only appropriate when the
|
||||||
|
function body is written directly inside a `.h` file.
|
||||||
|
`static` on **variables** (file-scope state) is fine and expected.
|
||||||
|
|
||||||
### Formatting
|
### Formatting
|
||||||
- Hard-wrap all lines at **80 characters**.
|
- Hard-wrap all lines at **80 characters**.
|
||||||
@@ -398,10 +405,8 @@ const size_t size
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Comments in `.c` files
|
### Comments in `.c` files
|
||||||
- Block comments that describe a section use the divider style:
|
- Do not use section dividers (`/* ---- ... ---- */`). Just let the
|
||||||
```c
|
functions follow one another with a single blank line between them.
|
||||||
/* ---- Public API ---- */
|
|
||||||
```
|
|
||||||
- Multi-line explanatory comments inside function bodies use `//` lines:
|
- Multi-line explanatory comments inside function bodies use `//` lines:
|
||||||
```c
|
```c
|
||||||
// Script modules are freed; orphaned JS wrapper objects now get GC'd
|
// Script modules are freed; orphaned JS wrapper objects now get GC'd
|
||||||
|
|||||||
+18
-6
@@ -4,12 +4,24 @@
|
|||||||
// https://opensource.org/licenses/MIT
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
const PLAYER_SPEED = 5.0;
|
const PLAYER_SPEED = 5.0;
|
||||||
|
// 1 world unit = 16 pixels.
|
||||||
|
const PIXEL_SCALE = 1.0 / 16.0;
|
||||||
|
// Player sprite is 32x32 px (test.png dimensions).
|
||||||
|
const PLAYER_W = 32 * PIXEL_SCALE;
|
||||||
|
const PLAYER_H = 32 * PIXEL_SCALE;
|
||||||
|
|
||||||
var player = {};
|
var player = {};
|
||||||
|
|
||||||
var _entity, _position, _physics;
|
player.getAssets = () => {
|
||||||
|
return [
|
||||||
|
{ path: 'test.png', type: Asset.TYPE_TEXTURE, format: Texture.FORMAT_RGBA }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
player.init = function(scene) {
|
||||||
|
var texture = scene.assets.getAssetByPath('test.png');
|
||||||
|
Console.print('Player init: got texture ' + texture);
|
||||||
|
|
||||||
player.create = function(texEntry) {
|
|
||||||
_entity = Entity.create();
|
_entity = Entity.create();
|
||||||
_position = _entity.add(Component.POSITION);
|
_position = _entity.add(Component.POSITION);
|
||||||
_physics = _entity.add(Component.PHYSICS);
|
_physics = _entity.add(Component.PHYSICS);
|
||||||
@@ -19,13 +31,13 @@ player.create = function(texEntry) {
|
|||||||
_physics.gravityScale = 1.0;
|
_physics.gravityScale = 1.0;
|
||||||
|
|
||||||
var r = _entity.add(Component.RENDERABLE);
|
var r = _entity.add(Component.RENDERABLE);
|
||||||
r.texture = texEntry.texture;
|
r.texture = texture.texture;
|
||||||
r.type = Renderable.SPRITEBATCH;
|
r.type = Renderable.SPRITEBATCH;
|
||||||
r.color = new Color(220, 80, 80);
|
r.color = new Color(220, 80, 80);
|
||||||
// upright quad: (-0.5,0,0) -> (0.5,1,0) in XY plane
|
// Upright quad centered on X, bottom-aligned on Y.
|
||||||
r.sprites = [[-0.5, 0, 0, 0.5, 1, 0, 0, 1, 1, 0]];
|
r.sprites = [[-PLAYER_W/2, 0, 0, PLAYER_W/2, PLAYER_H, 0, 0, 1, 1, 0]];
|
||||||
|
|
||||||
_position.localPosition = new Vec3(0, 1, 0);
|
_position.localPosition = new Vec3(0, PLAYER_H, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
player.getPosition = function() {
|
player.getPosition = function() {
|
||||||
|
|||||||
+14
-47
@@ -4,11 +4,6 @@
|
|||||||
// https://opensource.org/licenses/MIT
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
var scene = {};
|
var scene = {};
|
||||||
var player = require('player.js');
|
|
||||||
|
|
||||||
var assets = AssetBatch([
|
|
||||||
{ path: 'test.png', type: Asset.TYPE_TEXTURE, format: Texture.FORMAT_RGBA }
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Pokemon DS-style camera: ~34 degrees elevation (atan(6/9)).
|
// Pokemon DS-style camera: ~34 degrees elevation (atan(6/9)).
|
||||||
// CAM_HEIGHT / CAM_DIST ratio controls the tilt - keep it under 0.7 for
|
// CAM_HEIGHT / CAM_DIST ratio controls the tilt - keep it under 0.7 for
|
||||||
@@ -16,58 +11,30 @@ var assets = AssetBatch([
|
|||||||
const CAM_HEIGHT = 6;
|
const CAM_HEIGHT = 6;
|
||||||
const CAM_DIST = 9;
|
const CAM_DIST = 9;
|
||||||
|
|
||||||
var cam, camPos;
|
|
||||||
var floorEntity;
|
|
||||||
|
|
||||||
function updateCamera() {
|
|
||||||
var pp = player.getPosition().worldPosition;
|
|
||||||
// Position is offset above and behind the player; lookAt the exact player
|
|
||||||
// world position so the player projects to the center pixel every frame.
|
|
||||||
camPos.localPosition = new Vec3(pp.x, pp.y + CAM_HEIGHT, pp.z + CAM_DIST);
|
|
||||||
camPos.lookAt(new Vec3(pp.x, pp.y, pp.z));
|
|
||||||
}
|
|
||||||
|
|
||||||
scene.init = async function() {
|
scene.init = async function() {
|
||||||
assets.lock();
|
|
||||||
await assets.loaded();
|
|
||||||
|
|
||||||
var texEntry = assets.entry(0);
|
|
||||||
|
|
||||||
// Camera
|
// Camera
|
||||||
cam = Entity.create();
|
scene.cam = Entity.create();
|
||||||
camPos = cam.add(Component.POSITION);
|
var camPos = scene.cam.add(Component.POSITION);
|
||||||
cam.add(Component.CAMERA);
|
var cam = scene.cam.add(Component.CAMERA);
|
||||||
|
camPos.localPosition = new Vec3(3, 3, 3);
|
||||||
|
camPos.lookAt(new Vec3(0, 0, 0));
|
||||||
|
|
||||||
// Floor - infinite static plane at Y=0. Rendered as a large flat blue
|
// Floor - large flat slab, no texture needed.
|
||||||
// slab using the default SHADER_MATERIAL (no texture needed).
|
scene.floor = Entity.create();
|
||||||
floorEntity = Entity.create();
|
var floorPos = scene.floor.add(Component.POSITION);
|
||||||
var floorPos = floorEntity.add(Component.POSITION);
|
var floorR = scene.floor.add(Component.RENDERABLE);
|
||||||
var floorPhysics = floorEntity.add(Component.PHYSICS);
|
floorR.type = Renderable.SHADER_MATERIAL;
|
||||||
floorPhysics.bodyType = Physics.STATIC;
|
|
||||||
floorPhysics.shape = Physics.SHAPE_PLANE;
|
|
||||||
|
|
||||||
var floorR = floorEntity.add(Component.RENDERABLE);
|
|
||||||
floorR.color = Color.BLUE;
|
floorR.color = Color.BLUE;
|
||||||
floorPos.localScale = new Vec3(16, 0.2, 16);
|
// floorPos.localScale = new Vec3(16, 0.2, 16);
|
||||||
floorPos.localPosition = new Vec3(0, -0.1, 0);
|
// floorPos.localPosition = new Vec3(0, -0.1, 0);
|
||||||
|
|
||||||
// Player - spawns 1 unit above the floor so physics drops it cleanly.
|
|
||||||
player.create(texEntry);
|
|
||||||
|
|
||||||
// Initialise camera at the correct angle from the player's spawn position.
|
|
||||||
updateCamera();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
scene.update = function() {
|
scene.update = function() {
|
||||||
player.update();
|
|
||||||
updateCamera();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
scene.dispose = function() {
|
scene.dispose = function() {
|
||||||
player.dispose();
|
Entity.dispose(scene.floor);
|
||||||
Entity.dispose(floorEntity);
|
Entity.dispose(scene.cam);
|
||||||
Entity.dispose(cam);
|
|
||||||
assets.unlock();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = scene;
|
module.exports = scene;
|
||||||
|
|||||||
+30
-34
@@ -11,38 +11,6 @@
|
|||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/* ---- Per-entry event trampolines ----------------------------------------- */
|
|
||||||
|
|
||||||
static void assetBatchEntryOnLoadedCb(void *params, void *user) {
|
|
||||||
assetentry_t *entry = (assetentry_t *)params;
|
|
||||||
assetbatch_t *batch = (assetbatch_t *)user;
|
|
||||||
|
|
||||||
batch->loadedCount++;
|
|
||||||
eventInvoke(&batch->onEntryLoaded, entry);
|
|
||||||
|
|
||||||
if((uint16_t)(batch->loadedCount + batch->errorCount) >= batch->count) {
|
|
||||||
if(batch->errorCount == 0) {
|
|
||||||
eventInvoke(&batch->onLoaded, batch);
|
|
||||||
} else {
|
|
||||||
eventInvoke(&batch->onError, batch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void assetBatchEntryOnErrorCb(void *params, void *user) {
|
|
||||||
assetentry_t *entry = (assetentry_t *)params;
|
|
||||||
assetbatch_t *batch = (assetbatch_t *)user;
|
|
||||||
|
|
||||||
batch->errorCount++;
|
|
||||||
eventInvoke(&batch->onEntryError, entry);
|
|
||||||
|
|
||||||
if((uint16_t)(batch->loadedCount + batch->errorCount) >= batch->count) {
|
|
||||||
eventInvoke(&batch->onError, batch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- Public API ---------------------------------------------------------- */
|
|
||||||
|
|
||||||
void assetBatchInit(
|
void assetBatchInit(
|
||||||
assetbatch_t *batch,
|
assetbatch_t *batch,
|
||||||
const uint16_t count,
|
const uint16_t count,
|
||||||
@@ -86,7 +54,7 @@ void assetBatchInit(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if(batch->entries[i]->state == ASSET_ENTRY_STATE_LOADED) {
|
if(batch->entries[i]->state == ASSET_ENTRY_STATE_LOADED) {
|
||||||
/* Already loaded (cached) - count it now, no subscription needed. */
|
// Already loaded (cached) - count it now, no subscription needed.
|
||||||
batch->loadedCount++;
|
batch->loadedCount++;
|
||||||
} else if(batch->entries[i]->state == ASSET_ENTRY_STATE_ERROR) {
|
} else if(batch->entries[i]->state == ASSET_ENTRY_STATE_ERROR) {
|
||||||
batch->errorCount++;
|
batch->errorCount++;
|
||||||
@@ -161,9 +129,37 @@ void assetBatchDispose(assetbatch_t *batch) {
|
|||||||
if(batch->entries[i]) {
|
if(batch->entries[i]) {
|
||||||
// Unsubscribe while we still hold a lock so the entry is live.
|
// Unsubscribe while we still hold a lock so the entry is live.
|
||||||
eventUnsubscribe(&batch->entries[i]->onLoaded, assetBatchEntryOnLoadedCb);
|
eventUnsubscribe(&batch->entries[i]->onLoaded, assetBatchEntryOnLoadedCb);
|
||||||
eventUnsubscribe(&batch->entries[i]->onError, assetBatchEntryOnErrorCb);
|
eventUnsubscribe(&batch->entries[i]->onError, assetBatchEntryOnErrorCb);
|
||||||
assetUnlockEntry(batch->entries[i]);
|
assetUnlockEntry(batch->entries[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memoryZero(batch, sizeof(assetbatch_t));
|
memoryZero(batch, sizeof(assetbatch_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void assetBatchEntryOnLoadedCb(void *params, void *user) {
|
||||||
|
assetentry_t *entry = (assetentry_t *)params;
|
||||||
|
assetbatch_t *batch = (assetbatch_t *)user;
|
||||||
|
|
||||||
|
batch->loadedCount++;
|
||||||
|
eventInvoke(&batch->onEntryLoaded, entry);
|
||||||
|
|
||||||
|
if((uint16_t)(batch->loadedCount + batch->errorCount) >= batch->count) {
|
||||||
|
if(batch->errorCount == 0) {
|
||||||
|
eventInvoke(&batch->onLoaded, batch);
|
||||||
|
} else {
|
||||||
|
eventInvoke(&batch->onError, batch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void assetBatchEntryOnErrorCb(void *params, void *user) {
|
||||||
|
assetentry_t *entry = (assetentry_t *)params;
|
||||||
|
assetbatch_t *batch = (assetbatch_t *)user;
|
||||||
|
|
||||||
|
batch->errorCount++;
|
||||||
|
eventInvoke(&batch->onEntryError, entry);
|
||||||
|
|
||||||
|
if((uint16_t)(batch->loadedCount + batch->errorCount) >= batch->count) {
|
||||||
|
eventInvoke(&batch->onError, batch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -104,3 +104,21 @@ errorret_t assetBatchRequireLoaded(assetbatch_t *batch);
|
|||||||
* @param batch Batch to dispose.
|
* @param batch Batch to dispose.
|
||||||
*/
|
*/
|
||||||
void assetBatchDispose(assetbatch_t *batch);
|
void assetBatchDispose(assetbatch_t *batch);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event trampoline invoked when a batch entry finishes loading.
|
||||||
|
* Increments the loaded counter and fires batch-level events.
|
||||||
|
*
|
||||||
|
* @param params The loaded assetentry_t pointer.
|
||||||
|
* @param user The owning assetbatch_t pointer.
|
||||||
|
*/
|
||||||
|
void assetBatchEntryOnLoadedCb(void *params, void *user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event trampoline invoked when a batch entry fails to load.
|
||||||
|
* Increments the error counter and fires batch-level events.
|
||||||
|
*
|
||||||
|
* @param params The errored assetentry_t pointer.
|
||||||
|
* @param user The owning assetbatch_t pointer.
|
||||||
|
*/
|
||||||
|
void assetBatchEntryOnErrorCb(void *params, void *user);
|
||||||
|
|||||||
@@ -7,9 +7,13 @@ var Scene = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Scene.update = () => {
|
Scene.update = () => {
|
||||||
|
if(!Scene.current || !Scene.current.update) return;
|
||||||
|
Scene.current.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
Scene.dynamicUpdate = () => {
|
Scene.dynamicUpdate = () => {
|
||||||
|
if(!Scene.current || !Scene.current.dynamicUpdate) return;
|
||||||
|
Scene.current.dynamicUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
Scene.set = (newScene) => {
|
Scene.set = (newScene) => {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "moduleassetbatch.h"
|
#include "moduleassetbatch.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
|
||||||
#define ASSET_BATCH_LOADED_MAX 8
|
#define ASSET_BATCH_LOADED_MAX 8
|
||||||
|
|
||||||
@@ -273,6 +274,30 @@ moduleBaseFunction(moduleAssetBatchEntry) {
|
|||||||
return scriptProtoCreateValue(&MODULE_ASSET_ENTRY_PROTO, &e);
|
return scriptProtoCreateValue(&MODULE_ASSET_ENTRY_PROTO, &e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
moduleBaseFunction(moduleAssetBatchGetAssetByPath) {
|
||||||
|
moduleBaseRequireArgs(1);
|
||||||
|
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||||
|
if(!b || !b->batch) return jerry_undefined();
|
||||||
|
if(!jerry_value_is_string(args[0])) return jerry_undefined();
|
||||||
|
|
||||||
|
char_t path[ASSET_FILE_NAME_MAX];
|
||||||
|
jerry_size_t pathLen = jerry_string_to_buffer(
|
||||||
|
args[0], JERRY_ENCODING_UTF8,
|
||||||
|
(jerry_char_t *)path, ASSET_FILE_NAME_MAX - 1
|
||||||
|
);
|
||||||
|
path[pathLen] = '\0';
|
||||||
|
|
||||||
|
for(uint16_t i = 0; i < b->batch->count; i++) {
|
||||||
|
assetentry_t *entry = b->batch->entries[i];
|
||||||
|
if(!entry) continue;
|
||||||
|
if(!stringEquals(entry->name, path)) continue;
|
||||||
|
assetEntryLock(entry);
|
||||||
|
jsassetentry_t e = { .entry = entry };
|
||||||
|
return scriptProtoCreateValue(&MODULE_ASSET_ENTRY_PROTO, &e);
|
||||||
|
}
|
||||||
|
return jerry_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
moduleBaseFunction(moduleAssetBatchGetOnLoaded) {
|
moduleBaseFunction(moduleAssetBatchGetOnLoaded) {
|
||||||
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
jsassetbatch_t *b = moduleAssetBatchSelf(callInfo);
|
||||||
if(!b || !b->batch) return jerry_undefined();
|
if(!b || !b->batch) return jerry_undefined();
|
||||||
@@ -349,6 +374,10 @@ void moduleAssetBatchInit(void) {
|
|||||||
scriptProtoDefineFunc(
|
scriptProtoDefineFunc(
|
||||||
&MODULE_ASSET_BATCH_PROTO, "entry", moduleAssetBatchEntry
|
&MODULE_ASSET_BATCH_PROTO, "entry", moduleAssetBatchEntry
|
||||||
);
|
);
|
||||||
|
scriptProtoDefineFunc(
|
||||||
|
&MODULE_ASSET_BATCH_PROTO, "getAssetByPath",
|
||||||
|
moduleAssetBatchGetAssetByPath
|
||||||
|
);
|
||||||
scriptProtoDefineProp(
|
scriptProtoDefineProp(
|
||||||
&MODULE_ASSET_BATCH_PROTO, "onLoaded",
|
&MODULE_ASSET_BATCH_PROTO, "onLoaded",
|
||||||
moduleAssetBatchGetOnLoaded, NULL
|
moduleAssetBatchGetOnLoaded, NULL
|
||||||
|
|||||||
@@ -89,6 +89,15 @@ moduleBaseFunction(moduleAssetBatchUnlock);
|
|||||||
*/
|
*/
|
||||||
moduleBaseFunction(moduleAssetBatchEntry);
|
moduleBaseFunction(moduleAssetBatchEntry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getAssetByPath(path) - finds the first entry whose name matches path
|
||||||
|
* and returns it as a locked AssetEntry, or undefined if not found.
|
||||||
|
* The returned entry must be unlocked separately when no longer needed.
|
||||||
|
* @param args[0] Path string to match against entry names.
|
||||||
|
* @return AssetEntry, or undefined if no entry matches.
|
||||||
|
*/
|
||||||
|
moduleBaseFunction(moduleAssetBatchGetAssetByPath);
|
||||||
|
|
||||||
/** @return The onLoaded Event (fires once when all entries load). */
|
/** @return The onLoaded Event (fires once when all entries load). */
|
||||||
moduleBaseFunction(moduleAssetBatchGetOnLoaded);
|
moduleBaseFunction(moduleAssetBatchGetOnLoaded);
|
||||||
|
|
||||||
|
|||||||
Vendored
+6
@@ -57,6 +57,12 @@ interface AssetBatch {
|
|||||||
* Returns `undefined` if `index` is out of range or the batch is disposed.
|
* Returns `undefined` if `index` is out of range or the batch is disposed.
|
||||||
*/
|
*/
|
||||||
entry(index: number): AssetEntry | undefined;
|
entry(index: number): AssetEntry | undefined;
|
||||||
|
/**
|
||||||
|
* Returns the first `AssetEntry` whose path matches, adding an
|
||||||
|
* independent lock. Returns `undefined` if no entry matches.
|
||||||
|
* The returned entry must be unlocked separately when no longer needed.
|
||||||
|
*/
|
||||||
|
getAssetByPath(path: string): AssetEntry | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fires once when every entry has loaded successfully.
|
* Fires once when every entry has loaded successfully.
|
||||||
|
|||||||
Reference in New Issue
Block a user