Optimized
This commit is contained in:
@@ -43,4 +43,5 @@ target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DUSK_INPUT_POINTER
|
||||
DUSK_INPUT_GAMEPAD
|
||||
DUSK_TIME_DYNAMIC
|
||||
DUSK_THREAD_PTHREAD
|
||||
)
|
||||
@@ -75,6 +75,7 @@ target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DUSK_OPENGL_LEGACY
|
||||
DUSK_DISPLAY_WIDTH=960
|
||||
DUSK_DISPLAY_HEIGHT=544
|
||||
DUSK_THREAD_PTHREAD
|
||||
)
|
||||
|
||||
# Post-build: create SELF from the ELF binary (UNSAFE = homebrew, no signing)
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "easing.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/math.h"
|
||||
|
||||
const easingfn_t EASING_FUNCTIONS[EASING_COUNT] = {
|
||||
easingLinear,
|
||||
@@ -36,15 +35,15 @@ float_t easingLinear(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) {
|
||||
return sinf(t * MATH_PI * 0.5f);
|
||||
return sinf(t * EASING_PI * 0.5f);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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
|
||||
* set the asset entry state to error.
|
||||
|
||||
@@ -27,11 +27,12 @@ errorret_t assetTilesetLoaderAsync(assetloading_t *loading) {
|
||||
assetFileInit(file, loading->entry->name, NULL, NULL)
|
||||
);
|
||||
|
||||
uint8_t *data = memoryAllocate(file->size);
|
||||
assetLoaderErrorChain(loading, assetFileOpen(file));
|
||||
assetLoaderErrorChain(loading, assetFileRead(file, data, file->size));
|
||||
assetLoaderErrorChain(loading, assetFileClose(file));
|
||||
assetLoaderErrorChain(loading, assetFileDispose(file));
|
||||
|
||||
uint8_t *data = memoryAllocate(file->size);
|
||||
assetLoaderErrorChainFree(loading, data, assetFileRead(file, data, file->size));
|
||||
assetLoaderErrorChainFree(loading, data, assetFileClose(file));
|
||||
assetLoaderErrorChainFree(loading, data, assetFileDispose(file));
|
||||
assertTrue(
|
||||
file->lastRead == file->size,
|
||||
"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[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) {
|
||||
memoryFree(data);
|
||||
assetLoaderErrorThrow(loading, "Invalid v0 value in tileset");
|
||||
|
||||
@@ -27,11 +27,12 @@ errorret_t assetMeshLoaderAsync(assetloading_t *loading) {
|
||||
assetFileInit(file, loading->entry->name, NULL, NULL)
|
||||
);
|
||||
|
||||
uint8_t *raw = memoryAllocate(file->size);
|
||||
assetLoaderErrorChain(loading, assetFileOpen(file));
|
||||
assetLoaderErrorChain(loading, assetFileRead(file, raw, file->size));
|
||||
assetLoaderErrorChain(loading, assetFileClose(file));
|
||||
assetLoaderErrorChain(loading, assetFileDispose(file));
|
||||
|
||||
uint8_t *raw = memoryAllocate(file->size);
|
||||
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.");
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
assetLoaderErrorChain(loading, assetFileOpen(file));
|
||||
|
||||
size_t fileSize = (size_t)file->size;
|
||||
uint8_t *buffer = memoryAllocate(fileSize);
|
||||
assetLoaderErrorChain(loading, assetFileOpen(file));
|
||||
assetLoaderErrorChain(loading, assetFileRead(file, buffer, fileSize));
|
||||
assetLoaderErrorChainFree(loading, buffer, assetFileRead(file, buffer, fileSize));
|
||||
assertTrue(file->lastRead == file->size, "Failed to read entire JSON file.");
|
||||
assetLoaderErrorChain(loading, assetFileClose(file));
|
||||
assetLoaderErrorChain(loading, assetFileDispose(file));
|
||||
assetLoaderErrorChainFree(loading, buffer, assetFileClose(file));
|
||||
assetLoaderErrorChainFree(loading, buffer, assetFileDispose(file));
|
||||
|
||||
loading->loading.json.buffer = buffer;
|
||||
loading->loading.json.size = fileSize;
|
||||
|
||||
@@ -482,6 +482,24 @@ errorret_t assetLocaleGetString(
|
||||
assertTrue(pluralCount >= 0, "Plural index cannot be negative.");
|
||||
assertNotNull(stringBuffer, "String buffer cannot be NULL.");
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,27 @@ typedef struct {
|
||||
/** Maximum number of distinct plural forms a locale file may declare. */
|
||||
#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.
|
||||
*
|
||||
@@ -98,6 +119,12 @@ typedef struct {
|
||||
|
||||
/** Form index used when no conditional clause matches. */
|
||||
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;
|
||||
|
||||
/** Convenience alias - the loaded output type of a locale asset entry. */
|
||||
|
||||
@@ -51,7 +51,7 @@ spritebatchsprite_t textGetSprite(
|
||||
tileIndex = ((int32_t)'@') - TEXT_CHAR_START;
|
||||
}
|
||||
assertTrue(
|
||||
tileIndex >= 0 && tileIndex <= font->tileset->tileCount,
|
||||
tileIndex >= 0 && tileIndex < font->tileset->tileCount,
|
||||
"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,
|
||||
"Component index OOB in entitiesWithComponent lookup"
|
||||
);
|
||||
assertTrue(
|
||||
ENTITY_MANAGER.components[componentGetIndex(i,used)].type == type,
|
||||
"Component type mismatch in entitiesWithComponent lookup"
|
||||
);
|
||||
outComponents[written] = used;
|
||||
outEntities[written++] = i;
|
||||
}
|
||||
|
||||
@@ -220,9 +220,15 @@ entityposition_t *entityPositionGet(
|
||||
void entityPositionRebuild(entityposition_t *pos) {
|
||||
glm_mat4_identity(pos->localTransform);
|
||||
glm_translate(pos->localTransform, pos->position);
|
||||
glm_rotate_x(pos->localTransform, pos->rotation[0], pos->localTransform);
|
||||
glm_rotate_y(pos->localTransform, pos->rotation[1], pos->localTransform);
|
||||
glm_rotate_z(pos->localTransform, pos->rotation[2], pos->localTransform);
|
||||
if(pos->rotation[0] != 0.0f) {
|
||||
glm_rotate_x(pos->localTransform, pos->rotation[0], 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);
|
||||
entityPositionMarkDirty(pos);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,35 @@
|
||||
|
||||
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() {
|
||||
memoryZero(&PHYSICS_WORLD, sizeof(physicsworld_t));
|
||||
|
||||
@@ -34,6 +63,8 @@ void physicsWorldStep(const float_t dt) {
|
||||
/* Pre-fetch all position and physics pointers once. */
|
||||
entityposition_t *positions[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++) {
|
||||
componentid_t posComp = entityGetComponent(
|
||||
physEnts[i], COMPONENT_TYPE_POSITION
|
||||
@@ -42,6 +73,9 @@ void physicsWorldStep(const float_t dt) {
|
||||
? entityPositionGet(physEnts[i], posComp)
|
||||
: NULL;
|
||||
physBodies[i] = entityPhysicsGet(physEnts[i], physComps[i]);
|
||||
boundsValid[i] = physicsShapeBroadphaseExtents(
|
||||
physBodies[i]->shape, boundsHalfExtents[i]
|
||||
);
|
||||
}
|
||||
|
||||
/* Phase 1: integrate dynamic bodies (gravity + velocity → position).
|
||||
@@ -51,8 +85,16 @@ void physicsWorldStep(const float_t dt) {
|
||||
entityphysics_t *phys = physBodies[i];
|
||||
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;
|
||||
|
||||
if(wasResting) continue;
|
||||
|
||||
phys->velocity[0] += PHYSICS_WORLD.gravity[0] * phys->gravityScale * dt;
|
||||
phys->velocity[1] += PHYSICS_WORLD.gravity[1] * 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];
|
||||
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;
|
||||
if(!physicsTestShapeVsShape(
|
||||
pos, phys->shape,
|
||||
@@ -113,6 +164,15 @@ void physicsWorldStep(const float_t dt) {
|
||||
|
||||
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;
|
||||
if(!physicsTestShapeVsShape(
|
||||
posA, physA->shape, posB, physB->shape, normal, &depth
|
||||
|
||||
+28
-15
@@ -19,6 +19,16 @@ scene_t SCENE;
|
||||
|
||||
errorret_t sceneInit(void) {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -58,22 +68,25 @@ errorret_t sceneUpdate(void) {
|
||||
}
|
||||
|
||||
errorret_t sceneRender(void) {
|
||||
// Setup screen matrices for 3D rendering.
|
||||
glm_mat4_identity(SCENE.screenIdentity);
|
||||
|
||||
glm_ortho(
|
||||
0.0f, (float_t)(SCREEN.width / SCREEN.scaleUi),
|
||||
(float_t)(SCREEN.height / SCREEN.scaleUi), 0.0f,
|
||||
0.1f, 100.0f,
|
||||
SCENE.screenProj
|
||||
);
|
||||
// Recompute the UI ortho projection only when its inputs actually change.
|
||||
if(
|
||||
!SCENE.screenProjValid ||
|
||||
SCENE.cachedScreenWidth != SCREEN.width ||
|
||||
SCENE.cachedScreenHeight != SCREEN.height ||
|
||||
SCENE.cachedScreenScaleUi != SCREEN.scaleUi
|
||||
) {
|
||||
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(
|
||||
(vec3){ 0.0f, 0.0f, 1.0f },
|
||||
(vec3){ 0.0f, 0.0f, 0.0f },
|
||||
(vec3){ 0.0f, 1.0f, 0.0f },
|
||||
SCENE.screenView
|
||||
);
|
||||
SCENE.cachedScreenWidth = SCREEN.width;
|
||||
SCENE.cachedScreenHeight = SCREEN.height;
|
||||
SCENE.cachedScreenScaleUi = SCREEN.scaleUi;
|
||||
SCENE.screenProjValid = true;
|
||||
}
|
||||
|
||||
// Scene rendering
|
||||
if(
|
||||
|
||||
@@ -16,6 +16,10 @@ typedef struct {
|
||||
mat4 screenProj;
|
||||
mat4 screenView;
|
||||
mat4 screenIdentity;
|
||||
int32_t cachedScreenWidth;
|
||||
int32_t cachedScreenHeight;
|
||||
int32_t cachedScreenScaleUi;
|
||||
bool_t screenProjValid;
|
||||
} scene_t;
|
||||
|
||||
extern scene_t SCENE;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "assert/assert.h"
|
||||
#include "asset/asset.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
#include "scriptproto.h"
|
||||
#include "script/module/module.h"
|
||||
|
||||
@@ -120,13 +121,35 @@ static errorret_t scriptManagerFormatException(
|
||||
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) {
|
||||
assertNotNull(name, "Function name cannot be NULL");
|
||||
|
||||
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_free(key);
|
||||
jerry_value_free(global);
|
||||
|
||||
if(!jerry_value_is_function(fn)) {
|
||||
@@ -176,6 +199,12 @@ errorret_t scriptManagerCallGlobal(const char_t *name) {
|
||||
|
||||
errorret_t scriptManagerDispose(void) {
|
||||
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();
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -12,8 +12,15 @@
|
||||
|
||||
#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 {
|
||||
void* nothing;
|
||||
struct {
|
||||
const char_t *name;
|
||||
jerry_value_t key;
|
||||
} globalKeyCache[SCRIPT_MANAGER_MAX_CACHED_GLOBAL_KEYS];
|
||||
uint8_t globalKeyCacheCount;
|
||||
} scriptmanager_t;
|
||||
|
||||
extern scriptmanager_t SCRIPT_MANAGER;
|
||||
|
||||
@@ -23,6 +23,8 @@ void threadMutexLock(threadmutex_t *lock) {
|
||||
bool_t threadMutexTryLock(threadmutex_t *lock) {
|
||||
#ifdef DUSK_THREAD_PTHREAD
|
||||
return pthread_mutex_trylock(&lock->mutex) == 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
#include "console/console.h"
|
||||
|
||||
dusktime_t TIME;
|
||||
|
||||
void timeInit(void) {
|
||||
@@ -48,12 +46,6 @@ void timeUpdate(void) {
|
||||
TIME.delta = DUSK_TIME_STEP;
|
||||
TIME.time += DUSK_TIME_STEP;
|
||||
#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) {
|
||||
|
||||
@@ -16,6 +16,7 @@ errorret_t uiConsoleDraw(void) {
|
||||
|
||||
float_t lineH = (float_t)FONT_DEFAULT.tileset->tileHeight;
|
||||
for(uint32_t i = 0; i < CONSOLE_HISTORY_MAX; i++) {
|
||||
if(CONSOLE.line[i][0] == '\0') continue;
|
||||
errorChain(textDraw(
|
||||
(float_t)SCREEN.scanX,
|
||||
(float_t)SCREEN.scanY + lineH * (float_t)i,
|
||||
|
||||
@@ -58,8 +58,11 @@ errorret_t uiFPSDraw() {
|
||||
));
|
||||
errorChain(spriteBatchFlush());
|
||||
|
||||
int32_t versionWidth, versionHeight;
|
||||
textMeasure(ENGINE.version, &FONT_DEFAULT, &versionWidth, &versionHeight);
|
||||
// ENGINE.version and FONT_DEFAULT never change after boot; measure once.
|
||||
static int32_t versionWidth = -1, versionHeight = 0;
|
||||
if(versionWidth < 0) {
|
||||
textMeasure(ENGINE.version, &FONT_DEFAULT, &versionWidth, &versionHeight);
|
||||
}
|
||||
errorChain(textDraw(
|
||||
(float_t)(SCREEN.scanX + SCREEN.scanWidth - versionWidth),
|
||||
(float_t)(SCREEN.scanY + SCREEN.scanHeight - versionHeight),
|
||||
|
||||
@@ -29,6 +29,9 @@ void uiDropdownInit(
|
||||
dropdown->options = options;
|
||||
dropdown->optionCount = optionCount;
|
||||
dropdown->selectedIndex = selectedIndex < optionCount ? selectedIndex : 0;
|
||||
textMeasure(
|
||||
label, &FONT_DEFAULT, &dropdown->labelWidth, &dropdown->labelHeight
|
||||
);
|
||||
}
|
||||
|
||||
uint8_t uiDropdownGetSelectedIndex(const uidropdown_t *dropdown) {
|
||||
@@ -83,9 +86,6 @@ errorret_t uiDropdownDraw(
|
||||
|
||||
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];
|
||||
stringFormat(
|
||||
valueText, UI_DROPDOWN_VALUE_TEXT_MAX - 1, "< %s >",
|
||||
@@ -93,7 +93,8 @@ errorret_t uiDropdownDraw(
|
||||
);
|
||||
|
||||
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();
|
||||
|
||||
@@ -17,6 +17,8 @@ typedef struct {
|
||||
uint8_t optionCount;
|
||||
uint8_t selectedIndex;
|
||||
bool_t highlighted;
|
||||
int32_t labelWidth;
|
||||
int32_t labelHeight;
|
||||
} uidropdown_t;
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,6 +36,7 @@ void uiSliderInitFloat(
|
||||
slider->max.f = max;
|
||||
slider->step.f = step;
|
||||
slider->value.f = mathClamp(value, min, max);
|
||||
textMeasure(label, &FONT_DEFAULT, &slider->labelWidth, &slider->labelHeight);
|
||||
}
|
||||
|
||||
void uiSliderInitInt(
|
||||
@@ -58,6 +59,7 @@ void uiSliderInitInt(
|
||||
slider->max.i = max;
|
||||
slider->step.i = step;
|
||||
slider->value.i = mathClamp(value, min, max);
|
||||
textMeasure(label, &FONT_DEFAULT, &slider->labelWidth, &slider->labelHeight);
|
||||
}
|
||||
|
||||
float_t uiSliderGetFloat(const uislider_t *slider) {
|
||||
@@ -151,11 +153,8 @@ errorret_t uiSliderDraw(
|
||||
|
||||
errorChain(textDraw(x, y, slider->label, color, &FONT_DEFAULT));
|
||||
|
||||
int32_t labelW, labelH;
|
||||
textMeasure(slider->label, &FONT_DEFAULT, &labelW, &labelH);
|
||||
|
||||
float_t trackX = x + (float_t)labelW + UI_SLIDER_GAP;
|
||||
float_t trackY = y + ((float_t)labelH - UI_SLIDER_TRACK_HEIGHT) * 0.5f;
|
||||
float_t trackX = x + (float_t)slider->labelWidth + UI_SLIDER_GAP;
|
||||
float_t trackY = y + ((float_t)slider->labelHeight - UI_SLIDER_TRACK_HEIGHT) * 0.5f;
|
||||
|
||||
spritebatchsprite_t trackSprite = {
|
||||
.min = { trackX, trackY, 0.0f },
|
||||
@@ -170,7 +169,6 @@ errorret_t uiSliderDraw(
|
||||
}
|
||||
};
|
||||
errorChain(spriteBatchBuffer(&trackSprite, 1, &SHADER_UNLIT, trackMaterial));
|
||||
errorChain(spriteBatchFlush());
|
||||
|
||||
float_t fillWidth = UI_SLIDER_TRACK_WIDTH * uiSliderGetRatio(slider);
|
||||
if(fillWidth > 0.0f) {
|
||||
@@ -187,7 +185,6 @@ errorret_t uiSliderDraw(
|
||||
}
|
||||
};
|
||||
errorChain(spriteBatchBuffer(&fillSprite, 1, &SHADER_UNLIT, fillMaterial));
|
||||
errorChain(spriteBatchFlush());
|
||||
}
|
||||
|
||||
int32_t stepCount = uiSliderGetStepCount(slider);
|
||||
@@ -218,7 +215,6 @@ errorret_t uiSliderDraw(
|
||||
errorChain(
|
||||
spriteBatchBuffer(&markerSprite, 1, &SHADER_UNLIT, markerMaterial)
|
||||
);
|
||||
errorChain(spriteBatchFlush());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,8 @@ typedef struct {
|
||||
uislidervalue_t max;
|
||||
uislidervalue_t step;
|
||||
bool_t highlighted;
|
||||
int32_t labelWidth;
|
||||
int32_t labelHeight;
|
||||
} uislider_t;
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,7 @@ void uiTabInit(uitab_t *tab, const char_t *label) {
|
||||
assertNotNull(label, "Label cannot be NULL");
|
||||
memoryZero(tab, sizeof(uitab_t));
|
||||
tab->label = label;
|
||||
textMeasure(label, &FONT_DEFAULT, &tab->labelWidth, &tab->labelHeight);
|
||||
}
|
||||
|
||||
bool_t uiTabIsActive(const uitab_t *tab) {
|
||||
@@ -38,12 +39,9 @@ errorret_t uiTabDraw(
|
||||
) {
|
||||
assertNotNull(tab, "Tab cannot be NULL");
|
||||
|
||||
int32_t labelW, labelH;
|
||||
textMeasure(tab->label, &FONT_DEFAULT, &labelW, &labelH);
|
||||
|
||||
spritebatchsprite_t sprite = {
|
||||
.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 },
|
||||
.uvMax = { 1.0f, 1.0f }
|
||||
};
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
typedef struct {
|
||||
const char_t *label;
|
||||
bool_t active;
|
||||
int32_t labelWidth;
|
||||
int32_t labelHeight;
|
||||
} 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) {
|
||||
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
|
||||
#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.
|
||||
*
|
||||
|
||||
@@ -103,15 +103,6 @@ int_t memoryCompare(
|
||||
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 *dest,
|
||||
const size_t destStride,
|
||||
|
||||
@@ -114,14 +114,6 @@ int_t memoryCompare(
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -6,12 +6,15 @@
|
||||
*/
|
||||
|
||||
#include "random.h"
|
||||
#include "assert/assert.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -21,9 +21,7 @@ uint32_t frameBufferGLGetWidth(const framebuffer_t *framebuffer) {
|
||||
|
||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
||||
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
|
||||
int32_t windowWidth, windowHeight;
|
||||
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
|
||||
return windowWidth;
|
||||
return DISPLAY.cachedWidth;
|
||||
#else
|
||||
return DUSK_DISPLAY_WIDTH;
|
||||
#endif
|
||||
@@ -39,9 +37,7 @@ uint32_t frameBufferGLGetHeight(const framebuffer_t *framebuffer) {
|
||||
|
||||
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
|
||||
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
|
||||
int32_t windowWidth, windowHeight;
|
||||
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
|
||||
return windowHeight;
|
||||
return DISPLAY.cachedHeight;
|
||||
#else
|
||||
return DUSK_DISPLAY_HEIGHT;
|
||||
#endif
|
||||
|
||||
@@ -93,13 +93,11 @@ errorret_t meshFlushGL(
|
||||
#else
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId);
|
||||
errorChain(errorGLCheck());
|
||||
glBufferData(
|
||||
glBufferSubData(
|
||||
GL_ARRAY_BUFFER,
|
||||
mesh->vertexCount * sizeof(meshvertex_t),
|
||||
mesh->vertices,
|
||||
// vertCount * sizeof(meshvertex_t),
|
||||
// &mesh->vertices[vertOffset],
|
||||
GL_DYNAMIC_DRAW
|
||||
vertOffset * sizeof(meshvertex_t),
|
||||
vertCount * sizeof(meshvertex_t),
|
||||
&mesh->vertices[vertOffset]
|
||||
);
|
||||
errorChain(errorGLCheck());
|
||||
#endif
|
||||
|
||||
@@ -157,13 +157,28 @@ errorret_t shaderParamGetLocationGL(
|
||||
#ifdef DUSK_OPENGL_LEGACY
|
||||
assertUnreachable("Cannot get uniform locations on legacy opengl.");
|
||||
#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);
|
||||
errorChain(errorGLCheck());
|
||||
if(*location == -1) {
|
||||
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
|
||||
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,9 @@ typedef struct {
|
||||
#endif
|
||||
} shaderdefinitiongl_t;
|
||||
|
||||
/** Number of distinct uniform names a single shader instance can cache. */
|
||||
#define SHADERGL_MAX_CACHED_UNIFORMS 8
|
||||
|
||||
typedef struct shadergl_s {
|
||||
const shaderdefinitiongl_t *definition;
|
||||
|
||||
@@ -41,6 +44,12 @@ typedef struct shadergl_s {
|
||||
GLuint shaderProgramId;
|
||||
GLuint vertexShaderId;
|
||||
GLuint fragmentShaderId;
|
||||
|
||||
struct {
|
||||
const char_t *name;
|
||||
GLint location;
|
||||
} uniformCache[SHADERGL_MAX_CACHED_UNIFORMS];
|
||||
uint8_t uniformCacheCount;
|
||||
#endif
|
||||
} shadergl_t;
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
.setMaterial = shaderUnlitSetMaterial,
|
||||
};
|
||||
#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(
|
||||
shadergl_t *shader,
|
||||
const char_t *name,
|
||||
@@ -52,23 +56,27 @@
|
||||
glUniform1i(locType, 2);
|
||||
errorChain(errorGLCheck());
|
||||
|
||||
shaderParamGetLocationGL(shader, "u_ColorCount", &locColorCount);
|
||||
glUniform1i(locColorCount, texture->palette->count);
|
||||
errorChain(errorGLCheck());
|
||||
if(texture->palette != SHADER_UNLIT_LAST_PALETTE) {
|
||||
shaderParamGetLocationGL(shader, "u_ColorCount", &locColorCount);
|
||||
glUniform1i(locColorCount, texture->palette->count);
|
||||
errorChain(errorGLCheck());
|
||||
|
||||
shaderParamGetLocationGL(shader, "u_Colors", &locColors);
|
||||
GLuint paletteData[texture->palette->count];
|
||||
for(size_t i = 0; i < texture->palette->count; i++) {
|
||||
color_t color = texture->palette->colors[i];
|
||||
paletteData[i] = (
|
||||
((uint32_t)color.r << 24) |
|
||||
((uint32_t)color.g << 16) |
|
||||
((uint32_t)color.b << 8) |
|
||||
((uint32_t)color.a << 0)
|
||||
);
|
||||
shaderParamGetLocationGL(shader, "u_Colors", &locColors);
|
||||
GLuint paletteData[texture->palette->count];
|
||||
for(size_t i = 0; i < texture->palette->count; i++) {
|
||||
color_t color = texture->palette->colors[i];
|
||||
paletteData[i] = (
|
||||
((uint32_t)color.r << 24) |
|
||||
((uint32_t)color.g << 16) |
|
||||
((uint32_t)color.b << 8) |
|
||||
((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 {
|
||||
glUniform1i(locType, 1);
|
||||
errorChain(errorGLCheck());
|
||||
|
||||
@@ -10,7 +10,12 @@
|
||||
#include "display/displaygl.h"
|
||||
#include "error/errorgl.h"
|
||||
|
||||
static displaystate_t DISPLAY_STATE_CACHE = { 0 };
|
||||
static bool_t DISPLAY_STATE_CACHE_VALID = false;
|
||||
|
||||
errorret_t displaySDL2Init(void) {
|
||||
DISPLAY_STATE_CACHE_VALID = false;
|
||||
|
||||
uint32_t flags = SDL_INIT_VIDEO;
|
||||
#ifdef DUSK_INPUT_GAMEPAD
|
||||
flags |= SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK;
|
||||
@@ -57,7 +62,9 @@ errorret_t displaySDL2Init(void) {
|
||||
errorChain(errorGLCheck());
|
||||
|
||||
errorChain(displayOpenGLInit());
|
||||
|
||||
|
||||
SDL_GetWindowSize(DISPLAY.window, &DISPLAY.cachedWidth, &DISPLAY.cachedHeight);
|
||||
|
||||
errorChain(errorGLCheck());
|
||||
errorOk();
|
||||
}
|
||||
@@ -77,11 +84,19 @@ errorret_t displaySDL2Update(void) {
|
||||
ENGINE.running = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case SDL_WINDOWEVENT_RESIZED:
|
||||
case SDL_WINDOWEVENT_SIZE_CHANGED: {
|
||||
DISPLAY.cachedWidth = event.window.data1;
|
||||
DISPLAY.cachedHeight = event.window.data2;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
@@ -103,42 +118,57 @@ errorret_t displaySDL2Swap(void) {
|
||||
}
|
||||
|
||||
errorret_t displaySDL2SetState(displaystate_t state) {
|
||||
if(state.flags & DISPLAY_STATE_FLAG_CULL) {
|
||||
glEnable(GL_CULL_FACE);
|
||||
errorChain(errorGLCheck());
|
||||
glCullFace(GL_BACK);
|
||||
errorChain(errorGLCheck());
|
||||
} else {
|
||||
glDisable(GL_CULL_FACE);
|
||||
errorChain(errorGLCheck());
|
||||
uint8_t changed = DISPLAY_STATE_CACHE_VALID
|
||||
? (state.flags ^ DISPLAY_STATE_CACHE.flags)
|
||||
: 0xFF;
|
||||
|
||||
if(changed & DISPLAY_STATE_FLAG_CULL) {
|
||||
if(state.flags & DISPLAY_STATE_FLAG_CULL) {
|
||||
glEnable(GL_CULL_FACE);
|
||||
errorChain(errorGLCheck());
|
||||
glCullFace(GL_BACK);
|
||||
errorChain(errorGLCheck());
|
||||
} else {
|
||||
glDisable(GL_CULL_FACE);
|
||||
errorChain(errorGLCheck());
|
||||
}
|
||||
}
|
||||
|
||||
if(state.flags & DISPLAY_STATE_FLAG_DEPTH_TEST) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
errorChain(errorGLCheck());
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
errorChain(errorGLCheck());
|
||||
glClearDepth(1.0f);
|
||||
errorChain(errorGLCheck());
|
||||
} else {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
errorChain(errorGLCheck());
|
||||
if(changed & DISPLAY_STATE_FLAG_DEPTH_TEST) {
|
||||
if(state.flags & DISPLAY_STATE_FLAG_DEPTH_TEST) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
errorChain(errorGLCheck());
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
errorChain(errorGLCheck());
|
||||
glClearDepth(1.0f);
|
||||
errorChain(errorGLCheck());
|
||||
} else {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
errorChain(errorGLCheck());
|
||||
}
|
||||
}
|
||||
|
||||
if(state.flags & DISPLAY_STATE_FLAG_BLEND) {
|
||||
glEnable(GL_BLEND);
|
||||
errorChain(errorGLCheck());
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
errorChain(errorGLCheck());
|
||||
} else {
|
||||
glDisable(GL_BLEND);
|
||||
errorChain(errorGLCheck());
|
||||
if(changed & DISPLAY_STATE_FLAG_BLEND) {
|
||||
if(state.flags & DISPLAY_STATE_FLAG_BLEND) {
|
||||
glEnable(GL_BLEND);
|
||||
errorChain(errorGLCheck());
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
errorChain(errorGLCheck());
|
||||
} else {
|
||||
glDisable(GL_BLEND);
|
||||
errorChain(errorGLCheck());
|
||||
}
|
||||
}
|
||||
|
||||
DISPLAY_STATE_CACHE = state;
|
||||
DISPLAY_STATE_CACHE_VALID = true;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void displaySDL2Dispose(void) {
|
||||
DISPLAY_STATE_CACHE_VALID = false;
|
||||
|
||||
if(DISPLAY.glContext) {
|
||||
SDL_GL_DeleteContext(DISPLAY.glContext);
|
||||
DISPLAY.glContext = NULL;
|
||||
|
||||
@@ -13,6 +13,8 @@ typedef struct {
|
||||
SDL_Window *window;
|
||||
SDL_GLContext glContext;
|
||||
bool_t usingShaderedPalettes;
|
||||
int32_t cachedWidth;
|
||||
int32_t cachedHeight;
|
||||
} displaysdl2_t;
|
||||
|
||||
/**
|
||||
|
||||
@@ -326,39 +326,6 @@ static void test_memoryCompare(void **state) {
|
||||
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) {
|
||||
|
||||
|
||||
@@ -514,7 +481,6 @@ int main(int argc, char **argv) {
|
||||
cmocka_unit_test(test_memoryCopyRangeSafe),
|
||||
cmocka_unit_test(test_memoryMove),
|
||||
cmocka_unit_test(test_memoryCompare),
|
||||
cmocka_unit_test(test_memoryReallocate),
|
||||
cmocka_unit_test(test_memoryResize),
|
||||
cmocka_unit_test(test_memoryCopyInterleaved),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user