Optimized
This commit is contained in:
@@ -43,4 +43,5 @@ target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
|||||||
DUSK_INPUT_POINTER
|
DUSK_INPUT_POINTER
|
||||||
DUSK_INPUT_GAMEPAD
|
DUSK_INPUT_GAMEPAD
|
||||||
DUSK_TIME_DYNAMIC
|
DUSK_TIME_DYNAMIC
|
||||||
|
DUSK_THREAD_PTHREAD
|
||||||
)
|
)
|
||||||
@@ -75,6 +75,7 @@ target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
|||||||
DUSK_OPENGL_LEGACY
|
DUSK_OPENGL_LEGACY
|
||||||
DUSK_DISPLAY_WIDTH=960
|
DUSK_DISPLAY_WIDTH=960
|
||||||
DUSK_DISPLAY_HEIGHT=544
|
DUSK_DISPLAY_HEIGHT=544
|
||||||
|
DUSK_THREAD_PTHREAD
|
||||||
)
|
)
|
||||||
|
|
||||||
# Post-build: create SELF from the ELF binary (UNSAFE = homebrew, no signing)
|
# Post-build: create SELF from the ELF binary (UNSAFE = homebrew, no signing)
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include "easing.h"
|
#include "easing.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "util/math.h"
|
|
||||||
|
|
||||||
const easingfn_t EASING_FUNCTIONS[EASING_COUNT] = {
|
const easingfn_t EASING_FUNCTIONS[EASING_COUNT] = {
|
||||||
easingLinear,
|
easingLinear,
|
||||||
@@ -36,15 +35,15 @@ float_t easingLinear(const float_t t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float_t easingInSine(const float_t t) {
|
float_t easingInSine(const float_t t) {
|
||||||
return 1.0f - cosf(t * MATH_PI * 0.5f);
|
return 1.0f - cosf(t * EASING_PI * 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
float_t easingOutSine(const float_t t) {
|
float_t easingOutSine(const float_t t) {
|
||||||
return sinf(t * MATH_PI * 0.5f);
|
return sinf(t * EASING_PI * 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
float_t easingInOutSine(const float_t t) {
|
float_t easingInOutSine(const float_t t) {
|
||||||
return -(cosf(MATH_PI * t) - 1.0f) * 0.5f;
|
return -(cosf(EASING_PI * t) - 1.0f) * 0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float_t easingInQuad(const float_t t) {
|
float_t easingInQuad(const float_t t) {
|
||||||
|
|||||||
@@ -84,6 +84,25 @@ extern assetloadercallbacks_t ASSET_LOADER_CALLBACKS[ASSET_LOADER_TYPE_COUNT];
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like @ref assetLoaderErrorChain, but also frees `_ptr` (via memoryFree)
|
||||||
|
* before chaining the error if `_expr` failed. Use this for any loader step
|
||||||
|
* that runs after a buffer has already been allocated, so a later I/O
|
||||||
|
* failure doesn't leak it.
|
||||||
|
*
|
||||||
|
* @param loading The asset loading slot.
|
||||||
|
* @param _ptr A heap pointer to free if `_expr` fails.
|
||||||
|
* @param _expr The error return value to check and chain if it's an error.
|
||||||
|
*/
|
||||||
|
#define assetLoaderErrorChainFree(loading, _ptr, _expr) {\
|
||||||
|
errorret_t _alecf = (_expr); \
|
||||||
|
if(errorIsNotOk(_alecf)) { \
|
||||||
|
memoryFree(_ptr); \
|
||||||
|
(loading)->entry->state = ASSET_ENTRY_STATE_ERROR; \
|
||||||
|
errorChain(_alecf); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shorthand method to both throw an error (against the loader state) and to
|
* Shorthand method to both throw an error (against the loader state) and to
|
||||||
* set the asset entry state to error.
|
* set the asset entry state to error.
|
||||||
|
|||||||
@@ -27,11 +27,12 @@ errorret_t assetTilesetLoaderAsync(assetloading_t *loading) {
|
|||||||
assetFileInit(file, loading->entry->name, NULL, NULL)
|
assetFileInit(file, loading->entry->name, NULL, NULL)
|
||||||
);
|
);
|
||||||
|
|
||||||
uint8_t *data = memoryAllocate(file->size);
|
|
||||||
assetLoaderErrorChain(loading, assetFileOpen(file));
|
assetLoaderErrorChain(loading, assetFileOpen(file));
|
||||||
assetLoaderErrorChain(loading, assetFileRead(file, data, file->size));
|
|
||||||
assetLoaderErrorChain(loading, assetFileClose(file));
|
uint8_t *data = memoryAllocate(file->size);
|
||||||
assetLoaderErrorChain(loading, assetFileDispose(file));
|
assetLoaderErrorChainFree(loading, data, assetFileRead(file, data, file->size));
|
||||||
|
assetLoaderErrorChainFree(loading, data, assetFileClose(file));
|
||||||
|
assetLoaderErrorChainFree(loading, data, assetFileDispose(file));
|
||||||
assertTrue(
|
assertTrue(
|
||||||
file->lastRead == file->size,
|
file->lastRead == file->size,
|
||||||
"Failed to read entire tileset file."
|
"Failed to read entire tileset file."
|
||||||
@@ -102,6 +103,11 @@ errorret_t assetTilesetLoaderSync(assetloading_t *loading) {
|
|||||||
out->uv[0] = endianLittleToHostFloat(*(float *)(data + 16));
|
out->uv[0] = endianLittleToHostFloat(*(float *)(data + 16));
|
||||||
out->uv[1] = endianLittleToHostFloat(*(float *)(data + 20));
|
out->uv[1] = endianLittleToHostFloat(*(float *)(data + 20));
|
||||||
|
|
||||||
|
if(out->uv[0] < 0.0f || out->uv[0] > 1.0f) {
|
||||||
|
memoryFree(data);
|
||||||
|
assetLoaderErrorThrow(loading, "Invalid u0 value in tileset");
|
||||||
|
}
|
||||||
|
|
||||||
if(out->uv[1] < 0.0f || out->uv[1] > 1.0f) {
|
if(out->uv[1] < 0.0f || out->uv[1] > 1.0f) {
|
||||||
memoryFree(data);
|
memoryFree(data);
|
||||||
assetLoaderErrorThrow(loading, "Invalid v0 value in tileset");
|
assetLoaderErrorThrow(loading, "Invalid v0 value in tileset");
|
||||||
|
|||||||
@@ -27,11 +27,12 @@ errorret_t assetMeshLoaderAsync(assetloading_t *loading) {
|
|||||||
assetFileInit(file, loading->entry->name, NULL, NULL)
|
assetFileInit(file, loading->entry->name, NULL, NULL)
|
||||||
);
|
);
|
||||||
|
|
||||||
uint8_t *raw = memoryAllocate(file->size);
|
|
||||||
assetLoaderErrorChain(loading, assetFileOpen(file));
|
assetLoaderErrorChain(loading, assetFileOpen(file));
|
||||||
assetLoaderErrorChain(loading, assetFileRead(file, raw, file->size));
|
|
||||||
assetLoaderErrorChain(loading, assetFileClose(file));
|
uint8_t *raw = memoryAllocate(file->size);
|
||||||
assetLoaderErrorChain(loading, assetFileDispose(file));
|
assetLoaderErrorChainFree(loading, raw, assetFileRead(file, raw, file->size));
|
||||||
|
assetLoaderErrorChainFree(loading, raw, assetFileClose(file));
|
||||||
|
assetLoaderErrorChainFree(loading, raw, assetFileDispose(file));
|
||||||
assertTrue(file->lastRead == file->size, "Failed to read entire DMF file.");
|
assertTrue(file->lastRead == file->size, "Failed to read entire DMF file.");
|
||||||
|
|
||||||
if(raw[0] != 'D' || raw[1] != 'M' || raw[2] != 'F') {
|
if(raw[0] != 'D' || raw[1] != 'M' || raw[2] != 'F') {
|
||||||
|
|||||||
@@ -32,13 +32,14 @@ errorret_t assetJsonLoaderAsync(assetloading_t *loading) {
|
|||||||
assetLoaderErrorThrow(loading, "JSON exceeds maximum allowed size");
|
assetLoaderErrorThrow(loading, "JSON exceeds maximum allowed size");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assetLoaderErrorChain(loading, assetFileOpen(file));
|
||||||
|
|
||||||
size_t fileSize = (size_t)file->size;
|
size_t fileSize = (size_t)file->size;
|
||||||
uint8_t *buffer = memoryAllocate(fileSize);
|
uint8_t *buffer = memoryAllocate(fileSize);
|
||||||
assetLoaderErrorChain(loading, assetFileOpen(file));
|
assetLoaderErrorChainFree(loading, buffer, assetFileRead(file, buffer, fileSize));
|
||||||
assetLoaderErrorChain(loading, assetFileRead(file, buffer, fileSize));
|
|
||||||
assertTrue(file->lastRead == file->size, "Failed to read entire JSON file.");
|
assertTrue(file->lastRead == file->size, "Failed to read entire JSON file.");
|
||||||
assetLoaderErrorChain(loading, assetFileClose(file));
|
assetLoaderErrorChainFree(loading, buffer, assetFileClose(file));
|
||||||
assetLoaderErrorChain(loading, assetFileDispose(file));
|
assetLoaderErrorChainFree(loading, buffer, assetFileDispose(file));
|
||||||
|
|
||||||
loading->loading.json.buffer = buffer;
|
loading->loading.json.buffer = buffer;
|
||||||
loading->loading.json.size = fileSize;
|
loading->loading.json.size = fileSize;
|
||||||
|
|||||||
@@ -482,6 +482,24 @@ errorret_t assetLocaleGetString(
|
|||||||
assertTrue(pluralCount >= 0, "Plural index cannot be negative.");
|
assertTrue(pluralCount >= 0, "Plural index cannot be negative.");
|
||||||
assertNotNull(stringBuffer, "String buffer cannot be NULL.");
|
assertNotNull(stringBuffer, "String buffer cannot be NULL.");
|
||||||
assertTrue(stringBufferSize > 0, "String buffer size must be > 0");
|
assertTrue(stringBufferSize > 0, "String buffer size must be > 0");
|
||||||
|
|
||||||
|
// Check the cache before rewinding/rescanning the whole file.
|
||||||
|
for(uint8_t i = 0; i < ASSET_LOCALE_STRING_CACHE_SIZE; i++) {
|
||||||
|
assetlocalecacheentry_t *entry = &file->stringCache[i];
|
||||||
|
if(
|
||||||
|
!entry->valid ||
|
||||||
|
entry->pluralCount != pluralCount ||
|
||||||
|
stringCompare(messageId, entry->messageId) != 0
|
||||||
|
) continue;
|
||||||
|
|
||||||
|
size_t valueLen = strlen(entry->value);
|
||||||
|
if(valueLen >= stringBufferSize) {
|
||||||
|
errorThrow("String buffer overflow");
|
||||||
|
}
|
||||||
|
memoryCopy(stringBuffer, entry->value, valueLen + 1);
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
assetfilelinereader_t reader;
|
assetfilelinereader_t reader;
|
||||||
|
|
||||||
bool_t msgidFound = false, msgidPluralFound = false, msgstrFound = false;
|
bool_t msgidFound = false, msgidPluralFound = false, msgstrFound = false;
|
||||||
@@ -625,6 +643,20 @@ errorret_t assetLocaleGetString(
|
|||||||
errorThrow("Failed to find msgstr for message ID: %s", messageId);
|
errorThrow("Failed to find msgstr for message ID: %s", messageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cache the resolved string for future lookups, if it fits.
|
||||||
|
if(
|
||||||
|
strlen(messageId) < ASSET_LOCALE_CACHE_MESSAGE_ID_MAX &&
|
||||||
|
strlen(stringBuffer) < ASSET_LOCALE_CACHE_VALUE_MAX
|
||||||
|
) {
|
||||||
|
assetlocalecacheentry_t *entry = &file->stringCache[file->stringCacheNext];
|
||||||
|
stringCopy(entry->messageId, messageId, sizeof(entry->messageId) - 1);
|
||||||
|
stringCopy(entry->value, stringBuffer, sizeof(entry->value) - 1);
|
||||||
|
entry->pluralCount = pluralCount;
|
||||||
|
entry->valid = true;
|
||||||
|
file->stringCacheNext =
|
||||||
|
(file->stringCacheNext + 1) % ASSET_LOCALE_STRING_CACHE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,27 @@ typedef struct {
|
|||||||
/** Maximum number of distinct plural forms a locale file may declare. */
|
/** Maximum number of distinct plural forms a locale file may declare. */
|
||||||
#define ASSET_LOCALE_FILE_PLURAL_FORM_COUNT 6
|
#define ASSET_LOCALE_FILE_PLURAL_FORM_COUNT 6
|
||||||
|
|
||||||
|
/** Max distinct resolved strings cached per open locale file. */
|
||||||
|
#define ASSET_LOCALE_STRING_CACHE_SIZE 16
|
||||||
|
|
||||||
|
/** Max message ID length (incl. null terminator) storable in the cache. */
|
||||||
|
#define ASSET_LOCALE_CACHE_MESSAGE_ID_MAX 128
|
||||||
|
|
||||||
|
/** Max resolved string length (incl. null terminator) storable in the cache. */
|
||||||
|
#define ASSET_LOCALE_CACHE_VALUE_MAX 256
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single cached (messageId, pluralCount) -> resolved string lookup, used by
|
||||||
|
* @ref assetLocaleGetString to avoid rescanning the whole PO file for
|
||||||
|
* repeated lookups of the same message.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
bool_t valid;
|
||||||
|
char_t messageId[ASSET_LOCALE_CACHE_MESSAGE_ID_MAX];
|
||||||
|
int32_t pluralCount;
|
||||||
|
char_t value[ASSET_LOCALE_CACHE_VALUE_MAX];
|
||||||
|
} assetlocalecacheentry_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comparison operator used in a plural-form expression.
|
* Comparison operator used in a plural-form expression.
|
||||||
*
|
*
|
||||||
@@ -98,6 +119,12 @@ typedef struct {
|
|||||||
|
|
||||||
/** Form index used when no conditional clause matches. */
|
/** Form index used when no conditional clause matches. */
|
||||||
uint8_t pluralDefaultIndex;
|
uint8_t pluralDefaultIndex;
|
||||||
|
|
||||||
|
/** Ring buffer of recently resolved (messageId, pluralCount) lookups. */
|
||||||
|
assetlocalecacheentry_t stringCache[ASSET_LOCALE_STRING_CACHE_SIZE];
|
||||||
|
|
||||||
|
/** Next slot in @ref stringCache to overwrite. */
|
||||||
|
uint8_t stringCacheNext;
|
||||||
} assetlocalefile_t;
|
} assetlocalefile_t;
|
||||||
|
|
||||||
/** Convenience alias - the loaded output type of a locale asset entry. */
|
/** Convenience alias - the loaded output type of a locale asset entry. */
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ spritebatchsprite_t textGetSprite(
|
|||||||
tileIndex = ((int32_t)'@') - TEXT_CHAR_START;
|
tileIndex = ((int32_t)'@') - TEXT_CHAR_START;
|
||||||
}
|
}
|
||||||
assertTrue(
|
assertTrue(
|
||||||
tileIndex >= 0 && tileIndex <= font->tileset->tileCount,
|
tileIndex >= 0 && tileIndex < font->tileset->tileCount,
|
||||||
"Character is out of bounds for font tiles"
|
"Character is out of bounds for font tiles"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -105,10 +105,6 @@ entityid_t componentGetEntitiesWithComponent(
|
|||||||
componentGetIndex(i,used) < ENTITY_COUNT_MAX*ENTITY_COMPONENT_COUNT_MAX,
|
componentGetIndex(i,used) < ENTITY_COUNT_MAX*ENTITY_COMPONENT_COUNT_MAX,
|
||||||
"Component index OOB in entitiesWithComponent lookup"
|
"Component index OOB in entitiesWithComponent lookup"
|
||||||
);
|
);
|
||||||
assertTrue(
|
|
||||||
ENTITY_MANAGER.components[componentGetIndex(i,used)].type == type,
|
|
||||||
"Component type mismatch in entitiesWithComponent lookup"
|
|
||||||
);
|
|
||||||
outComponents[written] = used;
|
outComponents[written] = used;
|
||||||
outEntities[written++] = i;
|
outEntities[written++] = i;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -220,9 +220,15 @@ entityposition_t *entityPositionGet(
|
|||||||
void entityPositionRebuild(entityposition_t *pos) {
|
void entityPositionRebuild(entityposition_t *pos) {
|
||||||
glm_mat4_identity(pos->localTransform);
|
glm_mat4_identity(pos->localTransform);
|
||||||
glm_translate(pos->localTransform, pos->position);
|
glm_translate(pos->localTransform, pos->position);
|
||||||
glm_rotate_x(pos->localTransform, pos->rotation[0], pos->localTransform);
|
if(pos->rotation[0] != 0.0f) {
|
||||||
glm_rotate_y(pos->localTransform, pos->rotation[1], pos->localTransform);
|
glm_rotate_x(pos->localTransform, pos->rotation[0], pos->localTransform);
|
||||||
glm_rotate_z(pos->localTransform, pos->rotation[2], pos->localTransform);
|
}
|
||||||
|
if(pos->rotation[1] != 0.0f) {
|
||||||
|
glm_rotate_y(pos->localTransform, pos->rotation[1], pos->localTransform);
|
||||||
|
}
|
||||||
|
if(pos->rotation[2] != 0.0f) {
|
||||||
|
glm_rotate_z(pos->localTransform, pos->rotation[2], pos->localTransform);
|
||||||
|
}
|
||||||
glm_scale(pos->localTransform, pos->scale);
|
glm_scale(pos->localTransform, pos->scale);
|
||||||
entityPositionMarkDirty(pos);
|
entityPositionMarkDirty(pos);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,35 @@
|
|||||||
|
|
||||||
physicsworld_t PHYSICS_WORLD;
|
physicsworld_t PHYSICS_WORLD;
|
||||||
|
|
||||||
|
/** Below this squared speed, a grounded body is considered at rest. */
|
||||||
|
#define PHYSICS_REST_VELOCITY_EPSILON_SQ 0.0001f
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a conservative (never-too-small) AABB half-extent for a shape,
|
||||||
|
* used as a cheap broad-phase pre-filter before the full narrow-phase test.
|
||||||
|
* Returns false for unbounded shapes (planes), which skip the pre-filter.
|
||||||
|
*/
|
||||||
|
static bool_t physicsShapeBroadphaseExtents(
|
||||||
|
const physicsshape_t shape, vec3 outHalfExtents
|
||||||
|
) {
|
||||||
|
switch(shape.type) {
|
||||||
|
case PHYSICS_SHAPE_CUBE:
|
||||||
|
glm_vec3_copy((float_t *)shape.data.cube.halfExtents, outHalfExtents);
|
||||||
|
return true;
|
||||||
|
case PHYSICS_SHAPE_SPHERE:
|
||||||
|
outHalfExtents[0] = outHalfExtents[1] = outHalfExtents[2] =
|
||||||
|
shape.data.sphere.radius;
|
||||||
|
return true;
|
||||||
|
case PHYSICS_SHAPE_CAPSULE:
|
||||||
|
outHalfExtents[0] = outHalfExtents[2] = shape.data.capsule.radius;
|
||||||
|
outHalfExtents[1] =
|
||||||
|
shape.data.capsule.radius + shape.data.capsule.halfHeight;
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void physicsWorldInit() {
|
void physicsWorldInit() {
|
||||||
memoryZero(&PHYSICS_WORLD, sizeof(physicsworld_t));
|
memoryZero(&PHYSICS_WORLD, sizeof(physicsworld_t));
|
||||||
|
|
||||||
@@ -34,6 +63,8 @@ void physicsWorldStep(const float_t dt) {
|
|||||||
/* Pre-fetch all position and physics pointers once. */
|
/* Pre-fetch all position and physics pointers once. */
|
||||||
entityposition_t *positions[ENTITY_COUNT_MAX];
|
entityposition_t *positions[ENTITY_COUNT_MAX];
|
||||||
entityphysics_t *physBodies[ENTITY_COUNT_MAX];
|
entityphysics_t *physBodies[ENTITY_COUNT_MAX];
|
||||||
|
vec3 boundsHalfExtents[ENTITY_COUNT_MAX];
|
||||||
|
bool_t boundsValid[ENTITY_COUNT_MAX];
|
||||||
for(entityid_t i = 0; i < physCount; i++) {
|
for(entityid_t i = 0; i < physCount; i++) {
|
||||||
componentid_t posComp = entityGetComponent(
|
componentid_t posComp = entityGetComponent(
|
||||||
physEnts[i], COMPONENT_TYPE_POSITION
|
physEnts[i], COMPONENT_TYPE_POSITION
|
||||||
@@ -42,6 +73,9 @@ void physicsWorldStep(const float_t dt) {
|
|||||||
? entityPositionGet(physEnts[i], posComp)
|
? entityPositionGet(physEnts[i], posComp)
|
||||||
: NULL;
|
: NULL;
|
||||||
physBodies[i] = entityPhysicsGet(physEnts[i], physComps[i]);
|
physBodies[i] = entityPhysicsGet(physEnts[i], physComps[i]);
|
||||||
|
boundsValid[i] = physicsShapeBroadphaseExtents(
|
||||||
|
physBodies[i]->shape, boundsHalfExtents[i]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Phase 1: integrate dynamic bodies (gravity + velocity → position).
|
/* Phase 1: integrate dynamic bodies (gravity + velocity → position).
|
||||||
@@ -51,8 +85,16 @@ void physicsWorldStep(const float_t dt) {
|
|||||||
entityphysics_t *phys = physBodies[i];
|
entityphysics_t *phys = physBodies[i];
|
||||||
if(phys->type != PHYSICS_BODY_DYNAMIC) continue;
|
if(phys->type != PHYSICS_BODY_DYNAMIC) continue;
|
||||||
|
|
||||||
|
// A body resting from the previous tick skips gravity/velocity
|
||||||
|
// integration this tick, but still takes part in phases 2/3 below so it
|
||||||
|
// correctly notices being pushed or its support disappearing.
|
||||||
|
bool_t wasResting = phys->onGround &&
|
||||||
|
glm_vec3_norm2(phys->velocity) < PHYSICS_REST_VELOCITY_EPSILON_SQ;
|
||||||
|
|
||||||
phys->onGround = false;
|
phys->onGround = false;
|
||||||
|
|
||||||
|
if(wasResting) continue;
|
||||||
|
|
||||||
phys->velocity[0] += PHYSICS_WORLD.gravity[0] * phys->gravityScale * dt;
|
phys->velocity[0] += PHYSICS_WORLD.gravity[0] * phys->gravityScale * dt;
|
||||||
phys->velocity[1] += PHYSICS_WORLD.gravity[1] * phys->gravityScale * dt;
|
phys->velocity[1] += PHYSICS_WORLD.gravity[1] * phys->gravityScale * dt;
|
||||||
phys->velocity[2] += PHYSICS_WORLD.gravity[2] * phys->gravityScale * dt;
|
phys->velocity[2] += PHYSICS_WORLD.gravity[2] * phys->gravityScale * dt;
|
||||||
@@ -76,6 +118,15 @@ void physicsWorldStep(const float_t dt) {
|
|||||||
entityphysics_t *otherPhys = physBodies[j];
|
entityphysics_t *otherPhys = physBodies[j];
|
||||||
if(otherPhys->type == PHYSICS_BODY_DYNAMIC) continue;
|
if(otherPhys->type == PHYSICS_BODY_DYNAMIC) continue;
|
||||||
|
|
||||||
|
if(boundsValid[i] && boundsValid[j]) {
|
||||||
|
vec3 bpNormal; float_t bpDepth;
|
||||||
|
if(!physicsTestAabbVsAabb(
|
||||||
|
pos, boundsHalfExtents[i],
|
||||||
|
positions[j]->position, boundsHalfExtents[j],
|
||||||
|
bpNormal, &bpDepth
|
||||||
|
)) continue;
|
||||||
|
}
|
||||||
|
|
||||||
vec3 normal; float_t depth;
|
vec3 normal; float_t depth;
|
||||||
if(!physicsTestShapeVsShape(
|
if(!physicsTestShapeVsShape(
|
||||||
pos, phys->shape,
|
pos, phys->shape,
|
||||||
@@ -113,6 +164,15 @@ void physicsWorldStep(const float_t dt) {
|
|||||||
|
|
||||||
float_t *posB = positions[j]->position;
|
float_t *posB = positions[j]->position;
|
||||||
|
|
||||||
|
if(boundsValid[i] && boundsValid[j]) {
|
||||||
|
vec3 bpNormal; float_t bpDepth;
|
||||||
|
if(!physicsTestAabbVsAabb(
|
||||||
|
posA, boundsHalfExtents[i],
|
||||||
|
posB, boundsHalfExtents[j],
|
||||||
|
bpNormal, &bpDepth
|
||||||
|
)) continue;
|
||||||
|
}
|
||||||
|
|
||||||
vec3 normal; float_t depth;
|
vec3 normal; float_t depth;
|
||||||
if(!physicsTestShapeVsShape(
|
if(!physicsTestShapeVsShape(
|
||||||
posA, physA->shape, posB, physB->shape, normal, &depth
|
posA, physA->shape, posB, physB->shape, normal, &depth
|
||||||
|
|||||||
+28
-15
@@ -19,6 +19,16 @@ scene_t SCENE;
|
|||||||
|
|
||||||
errorret_t sceneInit(void) {
|
errorret_t sceneInit(void) {
|
||||||
memoryZero(&SCENE, sizeof(scene_t));
|
memoryZero(&SCENE, sizeof(scene_t));
|
||||||
|
|
||||||
|
// Fixed for the lifetime of the scene manager; computed once here.
|
||||||
|
glm_mat4_identity(SCENE.screenIdentity);
|
||||||
|
glm_lookat(
|
||||||
|
(vec3){ 0.0f, 0.0f, 1.0f },
|
||||||
|
(vec3){ 0.0f, 0.0f, 0.0f },
|
||||||
|
(vec3){ 0.0f, 1.0f, 0.0f },
|
||||||
|
SCENE.screenView
|
||||||
|
);
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,22 +68,25 @@ errorret_t sceneUpdate(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
errorret_t sceneRender(void) {
|
errorret_t sceneRender(void) {
|
||||||
// Setup screen matrices for 3D rendering.
|
// Recompute the UI ortho projection only when its inputs actually change.
|
||||||
glm_mat4_identity(SCENE.screenIdentity);
|
if(
|
||||||
|
!SCENE.screenProjValid ||
|
||||||
glm_ortho(
|
SCENE.cachedScreenWidth != SCREEN.width ||
|
||||||
0.0f, (float_t)(SCREEN.width / SCREEN.scaleUi),
|
SCENE.cachedScreenHeight != SCREEN.height ||
|
||||||
(float_t)(SCREEN.height / SCREEN.scaleUi), 0.0f,
|
SCENE.cachedScreenScaleUi != SCREEN.scaleUi
|
||||||
0.1f, 100.0f,
|
) {
|
||||||
SCENE.screenProj
|
glm_ortho(
|
||||||
);
|
0.0f, (float_t)(SCREEN.width / SCREEN.scaleUi),
|
||||||
|
(float_t)(SCREEN.height / SCREEN.scaleUi), 0.0f,
|
||||||
|
0.1f, 100.0f,
|
||||||
|
SCENE.screenProj
|
||||||
|
);
|
||||||
|
|
||||||
glm_lookat(
|
SCENE.cachedScreenWidth = SCREEN.width;
|
||||||
(vec3){ 0.0f, 0.0f, 1.0f },
|
SCENE.cachedScreenHeight = SCREEN.height;
|
||||||
(vec3){ 0.0f, 0.0f, 0.0f },
|
SCENE.cachedScreenScaleUi = SCREEN.scaleUi;
|
||||||
(vec3){ 0.0f, 1.0f, 0.0f },
|
SCENE.screenProjValid = true;
|
||||||
SCENE.screenView
|
}
|
||||||
);
|
|
||||||
|
|
||||||
// Scene rendering
|
// Scene rendering
|
||||||
if(
|
if(
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ typedef struct {
|
|||||||
mat4 screenProj;
|
mat4 screenProj;
|
||||||
mat4 screenView;
|
mat4 screenView;
|
||||||
mat4 screenIdentity;
|
mat4 screenIdentity;
|
||||||
|
int32_t cachedScreenWidth;
|
||||||
|
int32_t cachedScreenHeight;
|
||||||
|
int32_t cachedScreenScaleUi;
|
||||||
|
bool_t screenProjValid;
|
||||||
} scene_t;
|
} scene_t;
|
||||||
|
|
||||||
extern scene_t SCENE;
|
extern scene_t SCENE;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
|
#include "util/string.h"
|
||||||
#include "scriptproto.h"
|
#include "scriptproto.h"
|
||||||
#include "script/module/module.h"
|
#include "script/module/module.h"
|
||||||
|
|
||||||
@@ -120,13 +121,35 @@ static errorret_t scriptManagerFormatException(
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a cached jerry_value_t string key for a global function name,
|
||||||
|
* creating and caching it on first use. Avoids re-allocating a JS string
|
||||||
|
* every call for names looked up every frame/tick (e.g. "update").
|
||||||
|
*/
|
||||||
|
static jerry_value_t scriptManagerGetGlobalKey(const char_t *name) {
|
||||||
|
for(uint8_t i = 0; i < SCRIPT_MANAGER.globalKeyCacheCount; i++) {
|
||||||
|
if(stringCompare(name, SCRIPT_MANAGER.globalKeyCache[i].name) == 0) {
|
||||||
|
return SCRIPT_MANAGER.globalKeyCache[i].key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jerry_value_t key = jerry_string_sz(name);
|
||||||
|
assertTrue(
|
||||||
|
SCRIPT_MANAGER.globalKeyCacheCount < SCRIPT_MANAGER_MAX_CACHED_GLOBAL_KEYS,
|
||||||
|
"Global function key cache is full."
|
||||||
|
);
|
||||||
|
SCRIPT_MANAGER.globalKeyCache[SCRIPT_MANAGER.globalKeyCacheCount].name = name;
|
||||||
|
SCRIPT_MANAGER.globalKeyCache[SCRIPT_MANAGER.globalKeyCacheCount].key = key;
|
||||||
|
SCRIPT_MANAGER.globalKeyCacheCount++;
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
errorret_t scriptManagerCallGlobal(const char_t *name) {
|
errorret_t scriptManagerCallGlobal(const char_t *name) {
|
||||||
assertNotNull(name, "Function name cannot be NULL");
|
assertNotNull(name, "Function name cannot be NULL");
|
||||||
|
|
||||||
jerry_value_t global = jerry_current_realm();
|
jerry_value_t global = jerry_current_realm();
|
||||||
jerry_value_t key = jerry_string_sz(name);
|
jerry_value_t key = scriptManagerGetGlobalKey(name);
|
||||||
jerry_value_t fn = jerry_object_get(global, key);
|
jerry_value_t fn = jerry_object_get(global, key);
|
||||||
jerry_value_free(key);
|
|
||||||
jerry_value_free(global);
|
jerry_value_free(global);
|
||||||
|
|
||||||
if(!jerry_value_is_function(fn)) {
|
if(!jerry_value_is_function(fn)) {
|
||||||
@@ -176,6 +199,12 @@ errorret_t scriptManagerCallGlobal(const char_t *name) {
|
|||||||
|
|
||||||
errorret_t scriptManagerDispose(void) {
|
errorret_t scriptManagerDispose(void) {
|
||||||
scriptProtoDisposeAll();
|
scriptProtoDisposeAll();
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < SCRIPT_MANAGER.globalKeyCacheCount; i++) {
|
||||||
|
jerry_value_free(SCRIPT_MANAGER.globalKeyCache[i].key);
|
||||||
|
}
|
||||||
|
SCRIPT_MANAGER.globalKeyCacheCount = 0;
|
||||||
|
|
||||||
jerry_cleanup();
|
jerry_cleanup();
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,15 @@
|
|||||||
|
|
||||||
#define SCRIPT_MANAGER_MAX_EVENT_SUBSCRIPTIONS 64
|
#define SCRIPT_MANAGER_MAX_EVENT_SUBSCRIPTIONS 64
|
||||||
|
|
||||||
|
/** Max distinct global function names cached by @ref scriptManagerCallGlobal. */
|
||||||
|
#define SCRIPT_MANAGER_MAX_CACHED_GLOBAL_KEYS 8
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void* nothing;
|
struct {
|
||||||
|
const char_t *name;
|
||||||
|
jerry_value_t key;
|
||||||
|
} globalKeyCache[SCRIPT_MANAGER_MAX_CACHED_GLOBAL_KEYS];
|
||||||
|
uint8_t globalKeyCacheCount;
|
||||||
} scriptmanager_t;
|
} scriptmanager_t;
|
||||||
|
|
||||||
extern scriptmanager_t SCRIPT_MANAGER;
|
extern scriptmanager_t SCRIPT_MANAGER;
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ void threadMutexLock(threadmutex_t *lock) {
|
|||||||
bool_t threadMutexTryLock(threadmutex_t *lock) {
|
bool_t threadMutexTryLock(threadmutex_t *lock) {
|
||||||
#ifdef DUSK_THREAD_PTHREAD
|
#ifdef DUSK_THREAD_PTHREAD
|
||||||
return pthread_mutex_trylock(&lock->mutex) == 0;
|
return pthread_mutex_trylock(&lock->mutex) == 0;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,6 @@
|
|||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
|
|
||||||
#include "console/console.h"
|
|
||||||
|
|
||||||
dusktime_t TIME;
|
dusktime_t TIME;
|
||||||
|
|
||||||
void timeInit(void) {
|
void timeInit(void) {
|
||||||
@@ -48,12 +46,6 @@ void timeUpdate(void) {
|
|||||||
TIME.delta = DUSK_TIME_STEP;
|
TIME.delta = DUSK_TIME_STEP;
|
||||||
TIME.time += DUSK_TIME_STEP;
|
TIME.time += DUSK_TIME_STEP;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Print time in UTC style string
|
|
||||||
dusktimeepoch_t epoch = timeGetEpoch();
|
|
||||||
char_t buffer[256];
|
|
||||||
timeEpochFormat(epoch, "%Y-%m-%d %H:%M:%S", buffer, sizeof(buffer));
|
|
||||||
// consolePrint("Real Time: %s", buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dusktimeepoch_t timeGetEpoch(void) {
|
dusktimeepoch_t timeGetEpoch(void) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ errorret_t uiConsoleDraw(void) {
|
|||||||
|
|
||||||
float_t lineH = (float_t)FONT_DEFAULT.tileset->tileHeight;
|
float_t lineH = (float_t)FONT_DEFAULT.tileset->tileHeight;
|
||||||
for(uint32_t i = 0; i < CONSOLE_HISTORY_MAX; i++) {
|
for(uint32_t i = 0; i < CONSOLE_HISTORY_MAX; i++) {
|
||||||
|
if(CONSOLE.line[i][0] == '\0') continue;
|
||||||
errorChain(textDraw(
|
errorChain(textDraw(
|
||||||
(float_t)SCREEN.scanX,
|
(float_t)SCREEN.scanX,
|
||||||
(float_t)SCREEN.scanY + lineH * (float_t)i,
|
(float_t)SCREEN.scanY + lineH * (float_t)i,
|
||||||
|
|||||||
@@ -58,8 +58,11 @@ errorret_t uiFPSDraw() {
|
|||||||
));
|
));
|
||||||
errorChain(spriteBatchFlush());
|
errorChain(spriteBatchFlush());
|
||||||
|
|
||||||
int32_t versionWidth, versionHeight;
|
// ENGINE.version and FONT_DEFAULT never change after boot; measure once.
|
||||||
textMeasure(ENGINE.version, &FONT_DEFAULT, &versionWidth, &versionHeight);
|
static int32_t versionWidth = -1, versionHeight = 0;
|
||||||
|
if(versionWidth < 0) {
|
||||||
|
textMeasure(ENGINE.version, &FONT_DEFAULT, &versionWidth, &versionHeight);
|
||||||
|
}
|
||||||
errorChain(textDraw(
|
errorChain(textDraw(
|
||||||
(float_t)(SCREEN.scanX + SCREEN.scanWidth - versionWidth),
|
(float_t)(SCREEN.scanX + SCREEN.scanWidth - versionWidth),
|
||||||
(float_t)(SCREEN.scanY + SCREEN.scanHeight - versionHeight),
|
(float_t)(SCREEN.scanY + SCREEN.scanHeight - versionHeight),
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ void uiDropdownInit(
|
|||||||
dropdown->options = options;
|
dropdown->options = options;
|
||||||
dropdown->optionCount = optionCount;
|
dropdown->optionCount = optionCount;
|
||||||
dropdown->selectedIndex = selectedIndex < optionCount ? selectedIndex : 0;
|
dropdown->selectedIndex = selectedIndex < optionCount ? selectedIndex : 0;
|
||||||
|
textMeasure(
|
||||||
|
label, &FONT_DEFAULT, &dropdown->labelWidth, &dropdown->labelHeight
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t uiDropdownGetSelectedIndex(const uidropdown_t *dropdown) {
|
uint8_t uiDropdownGetSelectedIndex(const uidropdown_t *dropdown) {
|
||||||
@@ -83,9 +86,6 @@ errorret_t uiDropdownDraw(
|
|||||||
|
|
||||||
errorChain(textDraw(x, y, dropdown->label, color, &FONT_DEFAULT));
|
errorChain(textDraw(x, y, dropdown->label, color, &FONT_DEFAULT));
|
||||||
|
|
||||||
int32_t labelW, labelH;
|
|
||||||
textMeasure(dropdown->label, &FONT_DEFAULT, &labelW, &labelH);
|
|
||||||
|
|
||||||
char_t valueText[UI_DROPDOWN_VALUE_TEXT_MAX];
|
char_t valueText[UI_DROPDOWN_VALUE_TEXT_MAX];
|
||||||
stringFormat(
|
stringFormat(
|
||||||
valueText, UI_DROPDOWN_VALUE_TEXT_MAX - 1, "< %s >",
|
valueText, UI_DROPDOWN_VALUE_TEXT_MAX - 1, "< %s >",
|
||||||
@@ -93,7 +93,8 @@ errorret_t uiDropdownDraw(
|
|||||||
);
|
);
|
||||||
|
|
||||||
errorChain(textDraw(
|
errorChain(textDraw(
|
||||||
x + (float_t)labelW + UI_DROPDOWN_GAP, y, valueText, color, &FONT_DEFAULT
|
x + (float_t)dropdown->labelWidth + UI_DROPDOWN_GAP, y, valueText, color,
|
||||||
|
&FONT_DEFAULT
|
||||||
));
|
));
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ typedef struct {
|
|||||||
uint8_t optionCount;
|
uint8_t optionCount;
|
||||||
uint8_t selectedIndex;
|
uint8_t selectedIndex;
|
||||||
bool_t highlighted;
|
bool_t highlighted;
|
||||||
|
int32_t labelWidth;
|
||||||
|
int32_t labelHeight;
|
||||||
} uidropdown_t;
|
} uidropdown_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ void uiSliderInitFloat(
|
|||||||
slider->max.f = max;
|
slider->max.f = max;
|
||||||
slider->step.f = step;
|
slider->step.f = step;
|
||||||
slider->value.f = mathClamp(value, min, max);
|
slider->value.f = mathClamp(value, min, max);
|
||||||
|
textMeasure(label, &FONT_DEFAULT, &slider->labelWidth, &slider->labelHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiSliderInitInt(
|
void uiSliderInitInt(
|
||||||
@@ -58,6 +59,7 @@ void uiSliderInitInt(
|
|||||||
slider->max.i = max;
|
slider->max.i = max;
|
||||||
slider->step.i = step;
|
slider->step.i = step;
|
||||||
slider->value.i = mathClamp(value, min, max);
|
slider->value.i = mathClamp(value, min, max);
|
||||||
|
textMeasure(label, &FONT_DEFAULT, &slider->labelWidth, &slider->labelHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
float_t uiSliderGetFloat(const uislider_t *slider) {
|
float_t uiSliderGetFloat(const uislider_t *slider) {
|
||||||
@@ -151,11 +153,8 @@ errorret_t uiSliderDraw(
|
|||||||
|
|
||||||
errorChain(textDraw(x, y, slider->label, color, &FONT_DEFAULT));
|
errorChain(textDraw(x, y, slider->label, color, &FONT_DEFAULT));
|
||||||
|
|
||||||
int32_t labelW, labelH;
|
float_t trackX = x + (float_t)slider->labelWidth + UI_SLIDER_GAP;
|
||||||
textMeasure(slider->label, &FONT_DEFAULT, &labelW, &labelH);
|
float_t trackY = y + ((float_t)slider->labelHeight - UI_SLIDER_TRACK_HEIGHT) * 0.5f;
|
||||||
|
|
||||||
float_t trackX = x + (float_t)labelW + UI_SLIDER_GAP;
|
|
||||||
float_t trackY = y + ((float_t)labelH - UI_SLIDER_TRACK_HEIGHT) * 0.5f;
|
|
||||||
|
|
||||||
spritebatchsprite_t trackSprite = {
|
spritebatchsprite_t trackSprite = {
|
||||||
.min = { trackX, trackY, 0.0f },
|
.min = { trackX, trackY, 0.0f },
|
||||||
@@ -170,7 +169,6 @@ errorret_t uiSliderDraw(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
errorChain(spriteBatchBuffer(&trackSprite, 1, &SHADER_UNLIT, trackMaterial));
|
errorChain(spriteBatchBuffer(&trackSprite, 1, &SHADER_UNLIT, trackMaterial));
|
||||||
errorChain(spriteBatchFlush());
|
|
||||||
|
|
||||||
float_t fillWidth = UI_SLIDER_TRACK_WIDTH * uiSliderGetRatio(slider);
|
float_t fillWidth = UI_SLIDER_TRACK_WIDTH * uiSliderGetRatio(slider);
|
||||||
if(fillWidth > 0.0f) {
|
if(fillWidth > 0.0f) {
|
||||||
@@ -187,7 +185,6 @@ errorret_t uiSliderDraw(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
errorChain(spriteBatchBuffer(&fillSprite, 1, &SHADER_UNLIT, fillMaterial));
|
errorChain(spriteBatchBuffer(&fillSprite, 1, &SHADER_UNLIT, fillMaterial));
|
||||||
errorChain(spriteBatchFlush());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t stepCount = uiSliderGetStepCount(slider);
|
int32_t stepCount = uiSliderGetStepCount(slider);
|
||||||
@@ -218,7 +215,6 @@ errorret_t uiSliderDraw(
|
|||||||
errorChain(
|
errorChain(
|
||||||
spriteBatchBuffer(&markerSprite, 1, &SHADER_UNLIT, markerMaterial)
|
spriteBatchBuffer(&markerSprite, 1, &SHADER_UNLIT, markerMaterial)
|
||||||
);
|
);
|
||||||
errorChain(spriteBatchFlush());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ typedef struct {
|
|||||||
uislidervalue_t max;
|
uislidervalue_t max;
|
||||||
uislidervalue_t step;
|
uislidervalue_t step;
|
||||||
bool_t highlighted;
|
bool_t highlighted;
|
||||||
|
int32_t labelWidth;
|
||||||
|
int32_t labelHeight;
|
||||||
} uislider_t;
|
} uislider_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ void uiTabInit(uitab_t *tab, const char_t *label) {
|
|||||||
assertNotNull(label, "Label cannot be NULL");
|
assertNotNull(label, "Label cannot be NULL");
|
||||||
memoryZero(tab, sizeof(uitab_t));
|
memoryZero(tab, sizeof(uitab_t));
|
||||||
tab->label = label;
|
tab->label = label;
|
||||||
|
textMeasure(label, &FONT_DEFAULT, &tab->labelWidth, &tab->labelHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool_t uiTabIsActive(const uitab_t *tab) {
|
bool_t uiTabIsActive(const uitab_t *tab) {
|
||||||
@@ -38,12 +39,9 @@ errorret_t uiTabDraw(
|
|||||||
) {
|
) {
|
||||||
assertNotNull(tab, "Tab cannot be NULL");
|
assertNotNull(tab, "Tab cannot be NULL");
|
||||||
|
|
||||||
int32_t labelW, labelH;
|
|
||||||
textMeasure(tab->label, &FONT_DEFAULT, &labelW, &labelH);
|
|
||||||
|
|
||||||
spritebatchsprite_t sprite = {
|
spritebatchsprite_t sprite = {
|
||||||
.min = { x, y, 0.0f },
|
.min = { x, y, 0.0f },
|
||||||
.max = { x + (float_t)labelW, y + (float_t)labelH, 0.0f },
|
.max = { x + (float_t)tab->labelWidth, y + (float_t)tab->labelHeight, 0.0f },
|
||||||
.uvMin = { 0.0f, 0.0f },
|
.uvMin = { 0.0f, 0.0f },
|
||||||
.uvMax = { 1.0f, 1.0f }
|
.uvMax = { 1.0f, 1.0f }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
const char_t *label;
|
const char_t *label;
|
||||||
bool_t active;
|
bool_t active;
|
||||||
|
int32_t labelWidth;
|
||||||
|
int32_t labelHeight;
|
||||||
} uitab_t;
|
} uitab_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -28,9 +28,3 @@ void cryptCRC32Update(uint32_t *crc, const void *data, const size_t size) {
|
|||||||
uint32_t cryptCRC32End(const uint32_t crc) {
|
uint32_t cryptCRC32End(const uint32_t crc) {
|
||||||
return ~crc;
|
return ~crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t cryptCRC32(const void *data, const size_t size) {
|
|
||||||
uint32_t crc = cryptCRC32Begin();
|
|
||||||
cryptCRC32Update(&crc, data, size);
|
|
||||||
return cryptCRC32End(crc);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,15 +8,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "dusk.h"
|
#include "dusk.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes a CRC32 checksum over a block of data.
|
|
||||||
*
|
|
||||||
* @param data Pointer to the data to checksum.
|
|
||||||
* @param size Number of bytes to checksum.
|
|
||||||
* @return The CRC32 checksum.
|
|
||||||
*/
|
|
||||||
uint32_t cryptCRC32(const void *data, const size_t size);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the initial CRC32 accumulator value.
|
* Returns the initial CRC32 accumulator value.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -103,15 +103,6 @@ int_t memoryCompare(
|
|||||||
return memcmp(a, b, size);
|
return memcmp(a, b, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void memoryReallocate(void **ptr, const size_t size) {
|
|
||||||
assertNotNull(ptr, "Cannot reallocate NULL pointer.");
|
|
||||||
assertTrue(size > 0, "Cannot reallocate to 0 bytes of memory.");
|
|
||||||
void *newPointer = memoryAllocate(size);
|
|
||||||
assertNotNull(newPointer, "Memory reallocation failed.");
|
|
||||||
memoryFree(*ptr);
|
|
||||||
*ptr = newPointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void memoryCopyInterleaved(
|
void memoryCopyInterleaved(
|
||||||
void *dest,
|
void *dest,
|
||||||
const size_t destStride,
|
const size_t destStride,
|
||||||
|
|||||||
@@ -114,14 +114,6 @@ int_t memoryCompare(
|
|||||||
const size_t size
|
const size_t size
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* Reallocates memory.
|
|
||||||
*
|
|
||||||
* @param ptr The pointer to the memory to reallocate.
|
|
||||||
* @param size The new size of the memory.
|
|
||||||
*/
|
|
||||||
void memoryReallocate(void **ptr, const size_t size);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reallocates memory, but copies existing data to the new memory.
|
* Reallocates memory, but copies existing data to the new memory.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -6,12 +6,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
float_t randomFloat(const float_t min, const float_t max) {
|
float_t randomFloat(const float_t min, const float_t max) {
|
||||||
|
assertTrue(max > min, "randomFloat: max must be greater than min.");
|
||||||
return min + ((float_t)rand() / (float_t)RAND_MAX) * (max - min);
|
return min + ((float_t)rand() / (float_t)RAND_MAX) * (max - min);
|
||||||
}
|
}
|
||||||
|
|
||||||
int_t randomInt(const int_t min, const int_t max) {
|
int_t randomInt(const int_t min, const int_t max) {
|
||||||
|
assertTrue(max > min, "randomInt: max must be greater than min.");
|
||||||
return min + (rand() % (max - min));
|
return min + (rand() % (max - min));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,9 +21,7 @@ uint32_t frameBufferGLGetWidth(const framebuffer_t *framebuffer) {
|
|||||||
|
|
||||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
||||||
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
|
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
|
||||||
int32_t windowWidth, windowHeight;
|
return DISPLAY.cachedWidth;
|
||||||
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
|
|
||||||
return windowWidth;
|
|
||||||
#else
|
#else
|
||||||
return DUSK_DISPLAY_WIDTH;
|
return DUSK_DISPLAY_WIDTH;
|
||||||
#endif
|
#endif
|
||||||
@@ -39,9 +37,7 @@ uint32_t frameBufferGLGetHeight(const framebuffer_t *framebuffer) {
|
|||||||
|
|
||||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
||||||
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
|
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
|
||||||
int32_t windowWidth, windowHeight;
|
return DISPLAY.cachedHeight;
|
||||||
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
|
|
||||||
return windowHeight;
|
|
||||||
#else
|
#else
|
||||||
return DUSK_DISPLAY_HEIGHT;
|
return DUSK_DISPLAY_HEIGHT;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -93,13 +93,11 @@ errorret_t meshFlushGL(
|
|||||||
#else
|
#else
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId);
|
glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId);
|
||||||
errorChain(errorGLCheck());
|
errorChain(errorGLCheck());
|
||||||
glBufferData(
|
glBufferSubData(
|
||||||
GL_ARRAY_BUFFER,
|
GL_ARRAY_BUFFER,
|
||||||
mesh->vertexCount * sizeof(meshvertex_t),
|
vertOffset * sizeof(meshvertex_t),
|
||||||
mesh->vertices,
|
vertCount * sizeof(meshvertex_t),
|
||||||
// vertCount * sizeof(meshvertex_t),
|
&mesh->vertices[vertOffset]
|
||||||
// &mesh->vertices[vertOffset],
|
|
||||||
GL_DYNAMIC_DRAW
|
|
||||||
);
|
);
|
||||||
errorChain(errorGLCheck());
|
errorChain(errorGLCheck());
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -157,13 +157,28 @@ errorret_t shaderParamGetLocationGL(
|
|||||||
#ifdef DUSK_OPENGL_LEGACY
|
#ifdef DUSK_OPENGL_LEGACY
|
||||||
assertUnreachable("Cannot get uniform locations on legacy opengl.");
|
assertUnreachable("Cannot get uniform locations on legacy opengl.");
|
||||||
#else
|
#else
|
||||||
|
for(uint8_t i = 0; i < shader->uniformCacheCount; i++) {
|
||||||
|
if(stringCompare(name, shader->uniformCache[i].name) == 0) {
|
||||||
|
*location = shader->uniformCache[i].location;
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
*location = glGetUniformLocation(shader->shaderProgramId, name);
|
*location = glGetUniformLocation(shader->shaderProgramId, name);
|
||||||
errorChain(errorGLCheck());
|
errorChain(errorGLCheck());
|
||||||
if(*location == -1) {
|
if(*location == -1) {
|
||||||
errorThrow("Uniform '%s' not found in shader.", name);
|
errorThrow("Uniform '%s' not found in shader.", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
shader->uniformCacheCount < SHADERGL_MAX_CACHED_UNIFORMS,
|
||||||
|
"Uniform cache is full; increase SHADERGL_MAX_CACHED_UNIFORMS."
|
||||||
|
);
|
||||||
|
shader->uniformCache[shader->uniformCacheCount].name = name;
|
||||||
|
shader->uniformCache[shader->uniformCacheCount].location = *location;
|
||||||
|
shader->uniformCacheCount++;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ typedef struct {
|
|||||||
#endif
|
#endif
|
||||||
} shaderdefinitiongl_t;
|
} shaderdefinitiongl_t;
|
||||||
|
|
||||||
|
/** Number of distinct uniform names a single shader instance can cache. */
|
||||||
|
#define SHADERGL_MAX_CACHED_UNIFORMS 8
|
||||||
|
|
||||||
typedef struct shadergl_s {
|
typedef struct shadergl_s {
|
||||||
const shaderdefinitiongl_t *definition;
|
const shaderdefinitiongl_t *definition;
|
||||||
|
|
||||||
@@ -41,6 +44,12 @@ typedef struct shadergl_s {
|
|||||||
GLuint shaderProgramId;
|
GLuint shaderProgramId;
|
||||||
GLuint vertexShaderId;
|
GLuint vertexShaderId;
|
||||||
GLuint fragmentShaderId;
|
GLuint fragmentShaderId;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
const char_t *name;
|
||||||
|
GLint location;
|
||||||
|
} uniformCache[SHADERGL_MAX_CACHED_UNIFORMS];
|
||||||
|
uint8_t uniformCacheCount;
|
||||||
#endif
|
#endif
|
||||||
} shadergl_t;
|
} shadergl_t;
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,10 @@
|
|||||||
.setMaterial = shaderUnlitSetMaterial,
|
.setMaterial = shaderUnlitSetMaterial,
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
|
// Last-uploaded palette for the (single, global) unlit shader instance;
|
||||||
|
// skips rebuilding/re-uploading the color array when it hasn't changed.
|
||||||
|
static palette_t *SHADER_UNLIT_LAST_PALETTE = NULL;
|
||||||
|
|
||||||
errorret_t shaderUnlitSetTextureGL(
|
errorret_t shaderUnlitSetTextureGL(
|
||||||
shadergl_t *shader,
|
shadergl_t *shader,
|
||||||
const char_t *name,
|
const char_t *name,
|
||||||
@@ -52,23 +56,27 @@
|
|||||||
glUniform1i(locType, 2);
|
glUniform1i(locType, 2);
|
||||||
errorChain(errorGLCheck());
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
shaderParamGetLocationGL(shader, "u_ColorCount", &locColorCount);
|
if(texture->palette != SHADER_UNLIT_LAST_PALETTE) {
|
||||||
glUniform1i(locColorCount, texture->palette->count);
|
shaderParamGetLocationGL(shader, "u_ColorCount", &locColorCount);
|
||||||
errorChain(errorGLCheck());
|
glUniform1i(locColorCount, texture->palette->count);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
shaderParamGetLocationGL(shader, "u_Colors", &locColors);
|
shaderParamGetLocationGL(shader, "u_Colors", &locColors);
|
||||||
GLuint paletteData[texture->palette->count];
|
GLuint paletteData[texture->palette->count];
|
||||||
for(size_t i = 0; i < texture->palette->count; i++) {
|
for(size_t i = 0; i < texture->palette->count; i++) {
|
||||||
color_t color = texture->palette->colors[i];
|
color_t color = texture->palette->colors[i];
|
||||||
paletteData[i] = (
|
paletteData[i] = (
|
||||||
((uint32_t)color.r << 24) |
|
((uint32_t)color.r << 24) |
|
||||||
((uint32_t)color.g << 16) |
|
((uint32_t)color.g << 16) |
|
||||||
((uint32_t)color.b << 8) |
|
((uint32_t)color.b << 8) |
|
||||||
((uint32_t)color.a << 0)
|
((uint32_t)color.a << 0)
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
glUniform1uiv(locColors, texture->palette->count, paletteData);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
|
SHADER_UNLIT_LAST_PALETTE = texture->palette;
|
||||||
}
|
}
|
||||||
glUniform1uiv(locColors, texture->palette->count, paletteData);
|
|
||||||
errorChain(errorGLCheck());
|
|
||||||
} else {
|
} else {
|
||||||
glUniform1i(locType, 1);
|
glUniform1i(locType, 1);
|
||||||
errorChain(errorGLCheck());
|
errorChain(errorGLCheck());
|
||||||
|
|||||||
@@ -10,7 +10,12 @@
|
|||||||
#include "display/displaygl.h"
|
#include "display/displaygl.h"
|
||||||
#include "error/errorgl.h"
|
#include "error/errorgl.h"
|
||||||
|
|
||||||
|
static displaystate_t DISPLAY_STATE_CACHE = { 0 };
|
||||||
|
static bool_t DISPLAY_STATE_CACHE_VALID = false;
|
||||||
|
|
||||||
errorret_t displaySDL2Init(void) {
|
errorret_t displaySDL2Init(void) {
|
||||||
|
DISPLAY_STATE_CACHE_VALID = false;
|
||||||
|
|
||||||
uint32_t flags = SDL_INIT_VIDEO;
|
uint32_t flags = SDL_INIT_VIDEO;
|
||||||
#ifdef DUSK_INPUT_GAMEPAD
|
#ifdef DUSK_INPUT_GAMEPAD
|
||||||
flags |= SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK;
|
flags |= SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK;
|
||||||
@@ -57,7 +62,9 @@ errorret_t displaySDL2Init(void) {
|
|||||||
errorChain(errorGLCheck());
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
errorChain(displayOpenGLInit());
|
errorChain(displayOpenGLInit());
|
||||||
|
|
||||||
|
SDL_GetWindowSize(DISPLAY.window, &DISPLAY.cachedWidth, &DISPLAY.cachedHeight);
|
||||||
|
|
||||||
errorChain(errorGLCheck());
|
errorChain(errorGLCheck());
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
@@ -77,11 +84,19 @@ errorret_t displaySDL2Update(void) {
|
|||||||
ENGINE.running = false;
|
ENGINE.running = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SDL_WINDOWEVENT_RESIZED:
|
||||||
|
case SDL_WINDOWEVENT_SIZE_CHANGED: {
|
||||||
|
DISPLAY.cachedWidth = event.window.data1;
|
||||||
|
DISPLAY.cachedHeight = event.window.data2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
@@ -103,42 +118,57 @@ errorret_t displaySDL2Swap(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
errorret_t displaySDL2SetState(displaystate_t state) {
|
errorret_t displaySDL2SetState(displaystate_t state) {
|
||||||
if(state.flags & DISPLAY_STATE_FLAG_CULL) {
|
uint8_t changed = DISPLAY_STATE_CACHE_VALID
|
||||||
glEnable(GL_CULL_FACE);
|
? (state.flags ^ DISPLAY_STATE_CACHE.flags)
|
||||||
errorChain(errorGLCheck());
|
: 0xFF;
|
||||||
glCullFace(GL_BACK);
|
|
||||||
errorChain(errorGLCheck());
|
if(changed & DISPLAY_STATE_FLAG_CULL) {
|
||||||
} else {
|
if(state.flags & DISPLAY_STATE_FLAG_CULL) {
|
||||||
glDisable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
errorChain(errorGLCheck());
|
errorChain(errorGLCheck());
|
||||||
|
glCullFace(GL_BACK);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
} else {
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(state.flags & DISPLAY_STATE_FLAG_DEPTH_TEST) {
|
if(changed & DISPLAY_STATE_FLAG_DEPTH_TEST) {
|
||||||
glEnable(GL_DEPTH_TEST);
|
if(state.flags & DISPLAY_STATE_FLAG_DEPTH_TEST) {
|
||||||
errorChain(errorGLCheck());
|
glEnable(GL_DEPTH_TEST);
|
||||||
glDepthFunc(GL_LEQUAL);
|
errorChain(errorGLCheck());
|
||||||
errorChain(errorGLCheck());
|
glDepthFunc(GL_LEQUAL);
|
||||||
glClearDepth(1.0f);
|
errorChain(errorGLCheck());
|
||||||
errorChain(errorGLCheck());
|
glClearDepth(1.0f);
|
||||||
} else {
|
errorChain(errorGLCheck());
|
||||||
glDisable(GL_DEPTH_TEST);
|
} else {
|
||||||
errorChain(errorGLCheck());
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(state.flags & DISPLAY_STATE_FLAG_BLEND) {
|
if(changed & DISPLAY_STATE_FLAG_BLEND) {
|
||||||
glEnable(GL_BLEND);
|
if(state.flags & DISPLAY_STATE_FLAG_BLEND) {
|
||||||
errorChain(errorGLCheck());
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
errorChain(errorGLCheck());
|
||||||
errorChain(errorGLCheck());
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
} else {
|
errorChain(errorGLCheck());
|
||||||
glDisable(GL_BLEND);
|
} else {
|
||||||
errorChain(errorGLCheck());
|
glDisable(GL_BLEND);
|
||||||
|
errorChain(errorGLCheck());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DISPLAY_STATE_CACHE = state;
|
||||||
|
DISPLAY_STATE_CACHE_VALID = true;
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
void displaySDL2Dispose(void) {
|
void displaySDL2Dispose(void) {
|
||||||
|
DISPLAY_STATE_CACHE_VALID = false;
|
||||||
|
|
||||||
if(DISPLAY.glContext) {
|
if(DISPLAY.glContext) {
|
||||||
SDL_GL_DeleteContext(DISPLAY.glContext);
|
SDL_GL_DeleteContext(DISPLAY.glContext);
|
||||||
DISPLAY.glContext = NULL;
|
DISPLAY.glContext = NULL;
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ typedef struct {
|
|||||||
SDL_Window *window;
|
SDL_Window *window;
|
||||||
SDL_GLContext glContext;
|
SDL_GLContext glContext;
|
||||||
bool_t usingShaderedPalettes;
|
bool_t usingShaderedPalettes;
|
||||||
|
int32_t cachedWidth;
|
||||||
|
int32_t cachedHeight;
|
||||||
} displaysdl2_t;
|
} displaysdl2_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -326,39 +326,6 @@ static void test_memoryCompare(void **state) {
|
|||||||
assert_int_equal(memoryGetAllocatedCount(), 0);
|
assert_int_equal(memoryGetAllocatedCount(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_memoryReallocate(void **state) {
|
|
||||||
|
|
||||||
|
|
||||||
size_t initialSize = 16;
|
|
||||||
void *ptr = memoryAllocate(initialSize);
|
|
||||||
assert_non_null(ptr);
|
|
||||||
|
|
||||||
// Reallocate to a larger size
|
|
||||||
size_t newSize = 32;
|
|
||||||
memoryReallocate(&ptr, newSize);
|
|
||||||
assert_non_null(ptr);
|
|
||||||
|
|
||||||
// Reallocate to a smaller size
|
|
||||||
size_t smallerSize = 8;
|
|
||||||
memoryReallocate(&ptr, smallerSize);
|
|
||||||
assert_non_null(ptr);
|
|
||||||
|
|
||||||
// Cannot realloc to size 0
|
|
||||||
expect_assert_failure(memoryReallocate(&ptr, 0));
|
|
||||||
|
|
||||||
// Cannot realloc NULL pointer
|
|
||||||
expect_assert_failure(memoryReallocate(NULL, 16));
|
|
||||||
|
|
||||||
// Cannot reallocate more memory than possible
|
|
||||||
expect_assert_failure(memoryReallocate(&ptr, SIZE_MAX));
|
|
||||||
|
|
||||||
// All we really care about is that the pointer is valid after reallocations
|
|
||||||
memoryFree(ptr);
|
|
||||||
|
|
||||||
// Expect no leaks
|
|
||||||
assert_int_equal(memoryGetAllocatedCount(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_memoryResize(void **state) {
|
static void test_memoryResize(void **state) {
|
||||||
|
|
||||||
|
|
||||||
@@ -514,7 +481,6 @@ int main(int argc, char **argv) {
|
|||||||
cmocka_unit_test(test_memoryCopyRangeSafe),
|
cmocka_unit_test(test_memoryCopyRangeSafe),
|
||||||
cmocka_unit_test(test_memoryMove),
|
cmocka_unit_test(test_memoryMove),
|
||||||
cmocka_unit_test(test_memoryCompare),
|
cmocka_unit_test(test_memoryCompare),
|
||||||
cmocka_unit_test(test_memoryReallocate),
|
|
||||||
cmocka_unit_test(test_memoryResize),
|
cmocka_unit_test(test_memoryResize),
|
||||||
cmocka_unit_test(test_memoryCopyInterleaved),
|
cmocka_unit_test(test_memoryCopyInterleaved),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user