Cleanup animation

This commit is contained in:
2026-05-08 15:44:55 -05:00
parent 6d876bb767
commit 73e73d8772
20 changed files with 578 additions and 445 deletions
+1
View File
@@ -7,4 +7,5 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC PUBLIC
easing.c easing.c
animation.c animation.c
animationproperty.c
) )
+37 -54
View File
@@ -6,91 +6,74 @@
#include "animation.h" #include "animation.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "util/memory.h" #include "util/memory.h"
#include <math.h> #include "util/math.h"
void animationInit(animation_t *anim) { void animationInit(animation_t *anim) {
memoryZero(anim, sizeof(animation_t)); memoryZero(anim, sizeof(animation_t));
} }
animationproperty_t *animationAddProperty(animation_t *anim, float_t *target) { animationproperty_t *animationAddProperty(animation_t *anim) {
assertTrue( assertTrue(
anim->propertyCount < ANIMATION_PROPERTY_COUNT_MAX, anim->propertyCount < ANIMATION_PROPERTY_COUNT_MAX,
"Property count exceeds ANIMATION_PROPERTY_COUNT_MAX" "Property count exceeds ANIMATION_PROPERTY_COUNT_MAX"
); );
animationproperty_t *prop = &anim->properties[anim->propertyCount++]; animationproperty_t *prop = &anim->properties[anim->propertyCount++];
prop->target = target;
prop->keyframeCount = 0; prop->keyframeCount = 0;
return prop; return prop;
} }
void animationPropertyAddKeyframe(
animation_t *anim,
animationproperty_t *prop,
float_t time,
float_t value,
easingtype_t easing
) {
assertTrue(
prop->keyframeCount < ANIMATION_KEYFRAME_COUNT_MAX,
"Keyframe count exceeds ANIMATION_KEYFRAME_COUNT_MAX"
);
uint8_t i = prop->keyframeCount++;
prop->keyframes[i].time = time;
prop->keyframes[i].value = value;
prop->keyframes[i].easing = easing;
if(time > anim->duration) anim->duration = time;
}
static float_t animationPropertyGetValue(
const animationproperty_t *prop,
float_t time
) {
if(prop->keyframeCount == 0) return 0.0f;
uint8_t last = prop->keyframeCount - 1;
if(prop->keyframeCount == 1) return prop->keyframes[0].value;
if(time <= prop->keyframes[0].time) return prop->keyframes[0].value;
if(time >= prop->keyframes[last].time) return prop->keyframes[last].value;
for(uint8_t i = 0; i < last; i++) {
const keyframe_t *a = &prop->keyframes[i];
const keyframe_t *b = &prop->keyframes[i + 1];
if(time < a->time || time >= b->time) continue;
float_t t = (time - a->time) / (b->time - a->time);
t = easingApply(a->easing, t);
return a->value + (b->value - a->value) * t;
}
return prop->keyframes[last].value;
}
void animationUpdate(animation_t *anim, float_t delta) { void animationUpdate(animation_t *anim, float_t delta) {
assertNotNull(anim, "Animation cannot be null");
// Anim done?
if( if(
(anim->flags & ANIMATION_FLAG_FINISHED) && (anim->flags & ANIMATION_FLAG_FINISHED) &&
!(anim->flags & ANIMATION_FLAG_LOOP_ENABLED) !(anim->flags & ANIMATION_FLAG_LOOP_ENABLED)
) return; ) return;
// Start
anim->flags |= ANIMATION_FLAG_STARTED; anim->flags |= ANIMATION_FLAG_STARTED;
anim->time += delta; anim->time += delta;
if(anim->duration > 0.0f && anim->time >= anim->duration) { // Tick
float_t duration = animationGetDuration(anim);
if(anim->time >= duration) {
// Done/Loop
if(anim->flags & ANIMATION_FLAG_LOOP_ENABLED) { if(anim->flags & ANIMATION_FLAG_LOOP_ENABLED) {
anim->time = fmodf(anim->time, anim->duration); anim->time = mathModFloat(anim->time, duration);
} else { } else {
anim->time = anim->duration; anim->time = duration;
anim->flags |= ANIMATION_FLAG_FINISHED; anim->flags |= ANIMATION_FLAG_FINISHED;
} }
} }
for(uint8_t i = 0; i < anim->propertyCount; i++) {
animationproperty_t *prop = &anim->properties[i];
if(!prop->target) continue;
*prop->target = animationPropertyGetValue(prop, anim->time);
}
} }
void animationReset(animation_t *anim) { void animationReset(animation_t *anim) {
anim->time = 0.0f; anim->time = 0.0f;
anim->flags &= ~(ANIMATION_FLAG_FINISHED | ANIMATION_FLAG_STARTED); anim->flags &= ~(ANIMATION_FLAG_FINISHED | ANIMATION_FLAG_STARTED);
} }
bool_t animationIsFinished(const animation_t *anim) {
return (anim->flags & ANIMATION_FLAG_FINISHED) != 0;
}
bool_t animationIsStarted(const animation_t *anim) {
return (anim->flags & ANIMATION_FLAG_STARTED) != 0;
}
bool_t animationIsLooping(const animation_t *anim) {
return (anim->flags & ANIMATION_FLAG_LOOP_ENABLED) != 0;
}
float_t animationGetDuration(const animation_t *anim) {
float_t duration = 0.0f;
for(uint8_t i = 0; i < anim->propertyCount; i++) {
animationproperty_t *prop = &anim->properties[i];
if(prop->keyframeCount == 0) continue;
float_t lastKeyframeTime =
prop->keyframes[prop->keyframeCount - 1].time;
if(lastKeyframeTime > duration) duration = lastKeyframeTime;
}
return duration;
}
+48 -37
View File
@@ -4,72 +4,83 @@
// https://opensource.org/licenses/MIT // https://opensource.org/licenses/MIT
#pragma once #pragma once
#include "keyframe.h" #include "animationproperty.h"
#include "error/error.h"
#define ANIMATION_PROPERTY_COUNT_MAX 8 #define ANIMATION_PROPERTY_COUNT_MAX 8
typedef uint8_t animationflags_t; #define ANIMATION_FLAG_FINISHED (1 << 0)
#define ANIMATION_FLAG_FINISHED ((animationflags_t)(1 << 0)) #define ANIMATION_FLAG_STARTED (1 << 1)
#define ANIMATION_FLAG_STARTED ((animationflags_t)(1 << 1)) #define ANIMATION_FLAG_LOOP_ENABLED (1 << 2)
#define ANIMATION_FLAG_LOOP_ENABLED ((animationflags_t)(1 << 2))
typedef struct {
float_t *target;
keyframe_t keyframes[ANIMATION_KEYFRAME_COUNT_MAX];
uint8_t keyframeCount;
} animationproperty_t;
typedef struct { typedef struct {
animationproperty_t properties[ANIMATION_PROPERTY_COUNT_MAX]; animationproperty_t properties[ANIMATION_PROPERTY_COUNT_MAX];
uint8_t propertyCount; uint8_t propertyCount;
float_t time; float_t time;
float_t duration; uint8_t flags;
animationflags_t flags;
} animation_t; } animation_t;
/** /**
* Zeroes an animation struct. * Initializes an animation.
*
* @param anim The animation to initialize.
*/ */
void animationInit(animation_t *anim); void animationInit(animation_t *anim);
/** /**
* Adds a new animated property. The caller owns target and must keep it valid * Adds a new animated property. The caller owns target and must keep it valid
* for the lifetime of the animation. * for the lifetime of the animation.
*
* @param anim The animation to add the property to.
* @return A pointer to the new property.
*/ */
animationproperty_t *animationAddProperty(animation_t *anim, float_t *target); animationproperty_t *animationAddProperty(animation_t *anim);
/**
* Appends a keyframe to a property. Keyframes must be added in ascending time
* order. Updates the animation's duration.
*/
void animationPropertyAddKeyframe(
animation_t *anim,
animationproperty_t *prop,
float_t time,
float_t value,
easingtype_t easing
);
/** /**
* Advances the animation by delta seconds and writes interpolated values to * Advances the animation by delta seconds and writes interpolated values to
* each property's target pointer. * each property's target pointer.
*
* @param anim The animation to update.
* @param delta The time to advance the animation by, in seconds.
*/ */
void animationUpdate(animation_t *anim, float_t delta); void animationUpdate(animation_t *anim, float_t delta);
/** /**
* Resets the animation to the beginning, clearing Started and Finished flags. * Resets the animation to the beginning, clearing Started and Finished flags.
*
* @param anim The animation to reset.
*/ */
void animationReset(animation_t *anim); void animationReset(animation_t *anim);
static inline bool_t animationIsFinished(const animation_t *anim) { /**
return (anim->flags & ANIMATION_FLAG_FINISHED) != 0; * Returns true if the animation has finished (i.e. reached the end of its
} * duration and is not looping).
*
* @param anim The animation to check.
* @return true if the animation has finished, false otherwise.
*/
bool_t animationIsFinished(const animation_t *anim);
static inline bool_t animationIsStarted(const animation_t *anim) { /**
return (anim->flags & ANIMATION_FLAG_STARTED) != 0; * Returns true if the animation has been started (i.e. animationUpdate has
} * been called at least once).
*
* @param anim The animation to check.
* @return true if the animation has been started, false otherwise.
*/
bool_t animationIsStarted(const animation_t *anim);
static inline bool_t animationIsLooping(const animation_t *anim) { /**
return (anim->flags & ANIMATION_FLAG_LOOP_ENABLED) != 0; * Returns true if the animation is set to loop.
} *
* @param anim The animation to check.
* @return true if the animation is set to loop, false otherwise.
*/
bool_t animationIsLooping(const animation_t *anim);
/**
* Gets the total duration of the animation (based on the keyframes).
*
* @param anim The animation to get the duration of.
* @return The total duration of the animation, in seconds.
*/
float_t animationGetDuration(const animation_t *anim);
+55
View File
@@ -0,0 +1,55 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "animationproperty.h"
#include "assert/assert.h"
void animationPropertyAddKeyframe(
animationproperty_t *prop,
const float_t time,
const float_t value,
const easingtype_t easing
) {
assertNotNull(prop, "Property cannot be null");
assertTrue(
prop->keyframeCount < ANIMATION_PROPERTY_KEYFRAME_COUNT_MAX,
"Too many keyframes added to property"
);
assertTrue(time >= 0.0f, "Keyframe time cannot be negative");
keyframe_t *frame = &prop->keyframes[prop->keyframeCount++];
frame->time = time;
frame->value = value;
frame->easing = easing;
}
float_t animationPropertyGetValue(
const animationproperty_t *prop,
const float_t time
) {
assertNotNull(prop, "Property cannot be null");
assertTrue(time >= 0.0f, "Time cannot be negative");
if(prop->keyframeCount == 0) return 0.0f;
uint8_t last = prop->keyframeCount - 1;
if(prop->keyframeCount == 1) return prop->keyframes[0].value;
if(time <= prop->keyframes[0].time) return prop->keyframes[0].value;
if(time >= prop->keyframes[last].time) return prop->keyframes[last].value;
for(uint8_t i = 0; i < last; i++) {
const keyframe_t *a = &prop->keyframes[i];
const keyframe_t *b = &prop->keyframes[i + 1];
if(time < a->time || time >= b->time) continue;
float_t t = (time - a->time) / (b->time - a->time);
t = easingApply(a->easing, t);
return a->value + (b->value - a->value) * t;
}
return prop->keyframes[last].value;
}
+44
View File
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "keyframe.h"
#define ANIMATION_PROPERTY_KEYFRAME_COUNT_MAX 16
typedef struct {
keyframe_t keyframes[ANIMATION_PROPERTY_KEYFRAME_COUNT_MAX];
uint8_t keyframeCount;
} animationproperty_t;
/**
* Appends a keyframe to a property. Keyframes must be added in ascending time
* order. Updates the animation's duration.
*
* @param property The property to add the keyframe to.
* @param time The time of the keyframe, in seconds.
* @param value The value of the keyframe.
* @param easing The easing type to use when interpolating to the next keyframe.
*/
void animationPropertyAddKeyframe(
animationproperty_t *property,
const float_t time,
const float_t value,
const easingtype_t easing
);
/**
* Gets the property's value at a given time.
*
* @param prop The property to get the value from.
* @param time The time at which to get the value, in seconds.
* @return The value of the property at the given time.
*/
float_t animationPropertyGetValue(
const animationproperty_t *prop,
const float_t time
);
+39 -34
View File
@@ -7,82 +7,101 @@
#include "assert/assert.h" #include "assert/assert.h"
#include <math.h> #include <math.h>
#define EASING_PI 3.14159265358979323846f const easingfn_t EASING_FUNCTIONS[EASING_COUNT] = {
#define EASING_C1 1.70158f easingLinear,
#define EASING_C2 (EASING_C1 * 1.525f) easingInSine,
#define EASING_C3 (EASING_C1 + 1.0f) easingOutSine,
easingInOutSine,
easingInQuad,
easingOutQuad,
easingInOutQuad,
easingInCubic,
easingOutCubic,
easingInOutCubic,
easingInQuart,
easingOutQuart,
easingInOutQuart,
easingInBack,
easingOutBack,
easingInOutBack,
};
float_t easingLinear(float_t t) { float_t easingApply(const easingtype_t type, const float_t t) {
assertTrue(type < EASING_COUNT, "Invalid easing type");
return EASING_FUNCTIONS[type](t);
}
float_t easingLinear(const float_t t) {
return t; return t;
} }
float_t easingInSine(float_t t) { float_t easingInSine(const float_t t) {
return 1.0f - cosf(t * EASING_PI * 0.5f); return 1.0f - cosf(t * EASING_PI * 0.5f);
} }
float_t easingOutSine(float_t t) { float_t easingOutSine(const float_t t) {
return sinf(t * EASING_PI * 0.5f); return sinf(t * EASING_PI * 0.5f);
} }
float_t easingInOutSine(float_t t) { float_t easingInOutSine(const float_t t) {
return -(cosf(EASING_PI * t) - 1.0f) * 0.5f; return -(cosf(EASING_PI * t) - 1.0f) * 0.5f;
} }
float_t easingInQuad(float_t t) { float_t easingInQuad(const float_t t) {
return t * t; return t * t;
} }
float_t easingOutQuad(float_t t) { float_t easingOutQuad(const float_t t) {
float_t u = 1.0f - t; float_t u = 1.0f - t;
return 1.0f - u * u; return 1.0f - u * u;
} }
float_t easingInOutQuad(float_t t) { float_t easingInOutQuad(const float_t t) {
if(t < 0.5f) return 2.0f * t * t; if(t < 0.5f) return 2.0f * t * t;
float_t u = -2.0f * t + 2.0f; float_t u = -2.0f * t + 2.0f;
return 1.0f - u * u * 0.5f; return 1.0f - u * u * 0.5f;
} }
float_t easingInCubic(float_t t) { float_t easingInCubic(const float_t t) {
return t * t * t; return t * t * t;
} }
float_t easingOutCubic(float_t t) { float_t easingOutCubic(const float_t t) {
float_t u = 1.0f - t; float_t u = 1.0f - t;
return 1.0f - u * u * u; return 1.0f - u * u * u;
} }
float_t easingInOutCubic(float_t t) { float_t easingInOutCubic(const float_t t) {
if(t < 0.5f) return 4.0f * t * t * t; if(t < 0.5f) return 4.0f * t * t * t;
float_t u = -2.0f * t + 2.0f; float_t u = -2.0f * t + 2.0f;
return 1.0f - u * u * u * 0.5f; return 1.0f - u * u * u * 0.5f;
} }
float_t easingInQuart(float_t t) { float_t easingInQuart(const float_t t) {
return t * t * t * t; return t * t * t * t;
} }
float_t easingOutQuart(float_t t) { float_t easingOutQuart(const float_t t) {
float_t u = 1.0f - t; float_t u = 1.0f - t;
return 1.0f - u * u * u * u; return 1.0f - u * u * u * u;
} }
float_t easingInOutQuart(float_t t) { float_t easingInOutQuart(const float_t t) {
if(t < 0.5f) return 8.0f * t * t * t * t; if(t < 0.5f) return 8.0f * t * t * t * t;
float_t u = -2.0f * t + 2.0f; float_t u = -2.0f * t + 2.0f;
return 1.0f - u * u * u * u * 0.5f; return 1.0f - u * u * u * u * 0.5f;
} }
float_t easingInBack(float_t t) { float_t easingInBack(const float_t t) {
return EASING_C3 * t * t * t - EASING_C1 * t * t; return EASING_C3 * t * t * t - EASING_C1 * t * t;
} }
float_t easingOutBack(float_t t) { float_t easingOutBack(const float_t t) {
float_t u = t - 1.0f; float_t u = t - 1.0f;
return 1.0f + EASING_C3 * u * u * u + EASING_C1 * u * u; return 1.0f + EASING_C3 * u * u * u + EASING_C1 * u * u;
} }
float_t easingInOutBack(float_t t) { float_t easingInOutBack(const float_t t) {
if(t < 0.5f) { if(t < 0.5f) {
float_t u = 2.0f * t; float_t u = 2.0f * t;
return u * u * ((EASING_C2 + 1.0f) * u - EASING_C2) * 0.5f; return u * u * ((EASING_C2 + 1.0f) * u - EASING_C2) * 0.5f;
@@ -90,17 +109,3 @@ float_t easingInOutBack(float_t t) {
float_t u = 2.0f * t - 2.0f; float_t u = 2.0f * t - 2.0f;
return (u * u * ((EASING_C2 + 1.0f) * u + EASING_C2) + 2.0f) * 0.5f; return (u * u * ((EASING_C2 + 1.0f) * u + EASING_C2) + 2.0f) * 0.5f;
} }
const easingfn_t EASING_FUNCTIONS[EASING_COUNT] = {
easingLinear,
easingInSine, easingOutSine, easingInOutSine,
easingInQuad, easingOutQuad, easingInOutQuad,
easingInCubic, easingOutCubic, easingInOutCubic,
easingInQuart, easingOutQuart, easingInOutQuart,
easingInBack, easingOutBack, easingInOutBack,
};
float_t easingApply(easingtype_t type, float_t t) {
assertTrue(type < EASING_COUNT, "Invalid easing type");
return EASING_FUNCTIONS[type](t);
}
+50 -36
View File
@@ -6,44 +6,58 @@
#pragma once #pragma once
#include "dusk.h" #include "dusk.h"
#define EASING_LINEAR 0 #define EASING_PI 3.14159265358979323846f
#define EASING_IN_SINE 1 #define EASING_C1 1.70158f
#define EASING_OUT_SINE 2 #define EASING_C2 (EASING_C1 * 1.525f)
#define EASING_IN_OUT_SINE 3 #define EASING_C3 (EASING_C1 + 1.0f)
#define EASING_IN_QUAD 4
#define EASING_OUT_QUAD 5
#define EASING_IN_OUT_QUAD 6
#define EASING_IN_CUBIC 7
#define EASING_OUT_CUBIC 8
#define EASING_IN_OUT_CUBIC 9
#define EASING_IN_QUART 10
#define EASING_OUT_QUART 11
#define EASING_IN_OUT_QUART 12
#define EASING_IN_BACK 13
#define EASING_OUT_BACK 14
#define EASING_IN_OUT_BACK 15
#define EASING_COUNT 16
typedef uint8_t easingtype_t; typedef enum {
typedef float_t (*easingfn_t)(float_t t); EASING_LINEAR,
EASING_IN_SINE,
EASING_OUT_SINE,
EASING_IN_OUT_SINE,
EASING_IN_QUAD,
EASING_OUT_QUAD,
EASING_IN_OUT_QUAD,
EASING_IN_CUBIC,
EASING_OUT_CUBIC,
EASING_IN_OUT_CUBIC,
EASING_IN_QUART,
EASING_OUT_QUART,
EASING_IN_OUT_QUART,
EASING_IN_BACK,
EASING_OUT_BACK,
EASING_IN_OUT_BACK,
EASING_COUNT
} easingtype_t;
typedef float_t (*easingfn_t)(const float_t t);
extern const easingfn_t EASING_FUNCTIONS[EASING_COUNT]; extern const easingfn_t EASING_FUNCTIONS[EASING_COUNT];
float_t easingApply(easingtype_t type, float_t t); /**
* Applies the specified easing function to t.
*
* @param type The easing type to apply.
* @param t The input time, in the range [0, 1].
* @return The eased value, in the range [0, 1].
*/
float_t easingApply(const easingtype_t type, const float_t t);
float_t easingLinear(float_t t); float_t easingLinear(const float_t t);
float_t easingInSine(float_t t); float_t easingInSine(const float_t t);
float_t easingOutSine(float_t t); float_t easingOutSine(const float_t t);
float_t easingInOutSine(float_t t); float_t easingInOutSine(const float_t t);
float_t easingInQuad(float_t t); float_t easingInQuad(const float_t t);
float_t easingOutQuad(float_t t); float_t easingOutQuad(const float_t t);
float_t easingInOutQuad(float_t t); float_t easingInOutQuad(const float_t t);
float_t easingInCubic(float_t t); float_t easingInCubic(const float_t t);
float_t easingOutCubic(float_t t); float_t easingOutCubic(const float_t t);
float_t easingInOutCubic(float_t t); float_t easingInOutCubic(const float_t t);
float_t easingInQuart(float_t t); float_t easingInQuart(const float_t t);
float_t easingOutQuart(float_t t); float_t easingOutQuart(const float_t t);
float_t easingInOutQuart(float_t t); float_t easingInOutQuart(const float_t t);
float_t easingInBack(float_t t); float_t easingInBack(const float_t t);
float_t easingOutBack(float_t t); float_t easingOutBack(const float_t t);
float_t easingInOutBack(float_t t); float_t easingInOutBack(const float_t t);
-2
View File
@@ -6,8 +6,6 @@
#pragma once #pragma once
#include "easing.h" #include "easing.h"
#define ANIMATION_KEYFRAME_COUNT_MAX 16
typedef struct { typedef struct {
float_t time; float_t time;
float_t value; float_t value;
+2
View File
@@ -218,6 +218,8 @@
#endif #endif
// Static Assertions
#define assertStructSize(struct, size) \ #define assertStructSize(struct, size) \
_Static_assert(sizeof(struct) == size, "Size of " #struct " must be " #size) _Static_assert(sizeof(struct) == size, "Size of " #struct " must be " #size)
+2 -2
View File
@@ -25,7 +25,7 @@ errorret_t assetInit(void) {
} }
bool_t assetFileExists(const char_t *filename) { bool_t assetFileExists(const char_t *filename) {
assertStrLenMax(filename, ASSET_FILE_PATH_MAX, "Filename too long."); assertStrLenMax(filename, ASSET_FILE_NAME_MAX, "Filename too long.");
zip_int64_t idx = zip_name_locate(ASSET.zip, filename, 0); zip_int64_t idx = zip_name_locate(ASSET.zip, filename, 0);
if(idx < 0) return false; if(idx < 0) return false;
@@ -38,7 +38,7 @@ errorret_t assetLoad(
void *params, void *params,
void *output void *output
) { ) {
assertStrLenMax(filename, ASSET_FILE_PATH_MAX, "Filename too long."); assertStrLenMax(filename, ASSET_FILE_NAME_MAX, "Filename too long.");
assertNotNull(output, "Output pointer cannot be NULL."); assertNotNull(output, "Output pointer cannot be NULL.");
assertNotNull(loader, "Asset file loader cannot be NULL."); assertNotNull(loader, "Asset file loader cannot be NULL.");
+4 -2
View File
@@ -16,9 +16,11 @@ errorret_t assetFileInit(
void *params, void *params,
void *output void *output
) { ) {
memoryZero(file, sizeof(assetfile_t)); assertNotNull(file, "Asset file cannot be NULL.");
assertStrLenMax(filename, ASSET_FILE_NAME_MAX, "Filename too long.");
file->filename = filename; memoryZero(file, sizeof(assetfile_t));
memoryCopy(file->filename, filename, ASSET_FILE_NAME_MAX);
file->params = params; file->params = params;
file->output = output; file->output = output;
+2 -2
View File
@@ -9,14 +9,14 @@
#include "error/error.h" #include "error/error.h"
#include <zip.h> #include <zip.h>
#define ASSET_FILE_PATH_MAX FILENAME_MAX #define ASSET_FILE_NAME_MAX 48
typedef struct assetfile_s assetfile_t; typedef struct assetfile_s assetfile_t;
typedef errorret_t (*assetfileloader_t)(assetfile_t *file); typedef errorret_t (*assetfileloader_t)(assetfile_t *file);
typedef struct assetfile_s { typedef struct assetfile_s {
const char_t *filename; char_t filename[ASSET_FILE_NAME_MAX];
void *params; void *params;
void *output; void *output;
+3 -3
View File
@@ -168,7 +168,7 @@ errorret_t sceneSetImmediate(const char_t *scene) {
stringCopy( stringCopy(
SCENE.sceneNext, SCENE.sceneNext,
scene == NULL ? "" : scene, scene == NULL ? "" : scene,
ASSET_FILE_PATH_MAX ASSET_FILE_NAME_MAX
); );
} }
@@ -183,7 +183,7 @@ errorret_t sceneSetImmediate(const char_t *scene) {
stringCopy( stringCopy(
SCENE.sceneCurrent, SCENE.sceneCurrent,
scene == NULL ? "" : scene, scene == NULL ? "" : scene,
ASSET_FILE_PATH_MAX ASSET_FILE_NAME_MAX
); );
if(scene != NULL) { if(scene != NULL) {
@@ -216,7 +216,7 @@ void sceneSet(const char_t *scene) {
stringCopy( stringCopy(
SCENE.sceneNext, SCENE.sceneNext,
scene == NULL ? "" : scene, scene == NULL ? "" : scene,
ASSET_FILE_PATH_MAX ASSET_FILE_NAME_MAX
); );
} }
+2 -2
View File
@@ -14,8 +14,8 @@
typedef struct { typedef struct {
bool_t sceneActive; bool_t sceneActive;
jerry_value_t scriptRef; jerry_value_t scriptRef;
char_t sceneCurrent[ASSET_FILE_PATH_MAX]; char_t sceneCurrent[ASSET_FILE_NAME_MAX];
char_t sceneNext[ASSET_FILE_PATH_MAX]; char_t sceneNext[ASSET_FILE_NAME_MAX];
} scene_t; } scene_t;
extern scene_t SCENE; extern scene_t SCENE;
+257 -257
View File
@@ -9,307 +9,307 @@
#include "animation/animation.h" #include "animation/animation.h"
#include "util/memory.h" #include "util/memory.h"
static scriptproto_t MODULE_ANIMATION_PROTO; // static scriptproto_t MODULE_ANIMATION_PROTO;
// JS animation wraps a single-property animation; value is the managed target. // // JS animation wraps a single-property animation; value is the managed target.
typedef struct { // typedef struct {
animation_t anim; // animation_t anim;
float_t value; // float_t value;
} jsAnimation_t; // } jsAnimation_t;
static inline jsAnimation_t *moduleAnimationGetWrapper( // static inline jsAnimation_t *moduleAnimationGetWrapper(
const jerry_call_info_t *callInfo // const jerry_call_info_t *callInfo
) { // ) {
return (jsAnimation_t *)scriptProtoGetValue( // return (jsAnimation_t *)scriptProtoGetValue(
&MODULE_ANIMATION_PROTO, callInfo->this_value // &MODULE_ANIMATION_PROTO, callInfo->this_value
); // );
} // }
// Returns the animation_t pointer (first field of jsAnimation_t — same address). // // Returns the animation_t pointer (first field of jsAnimation_t — same address).
static inline animation_t *moduleAnimationGet( // static inline animation_t *moduleAnimationGet(
const jerry_call_info_t *callInfo // const jerry_call_info_t *callInfo
) { // ) {
return (animation_t *)moduleAnimationGetWrapper(callInfo); // return (animation_t *)moduleAnimationGetWrapper(callInfo);
} // }
// Extracts an easingtype_t from a JS value. Accepts either a plain number // // Extracts an easingtype_t from a JS value. Accepts either a plain number
// or an Easing.xxx function (which has a .type numeric property). // // or an Easing.xxx function (which has a .type numeric property).
static easingtype_t moduleAnimationReadEasing( // static easingtype_t moduleAnimationReadEasing(
const jerry_value_t val // const jerry_value_t val
) { // ) {
if(jerry_value_is_number(val)) { // if(jerry_value_is_number(val)) {
return (easingtype_t)(uint32_t)jerry_value_as_number(val); // return (easingtype_t)(uint32_t)jerry_value_as_number(val);
} // }
if(jerry_value_is_object(val) || jerry_value_is_function(val)) { // if(jerry_value_is_object(val) || jerry_value_is_function(val)) {
jerry_value_t key = jerry_string_sz("type"); // jerry_value_t key = jerry_string_sz("type");
jerry_value_t typeVal = jerry_object_get(val, key); // jerry_value_t typeVal = jerry_object_get(val, key);
jerry_value_free(key); // jerry_value_free(key);
easingtype_t result = EASING_LINEAR; // easingtype_t result = EASING_LINEAR;
if(jerry_value_is_number(typeVal)) { // if(jerry_value_is_number(typeVal)) {
result = (easingtype_t)(uint32_t)jerry_value_as_number(typeVal); // result = (easingtype_t)(uint32_t)jerry_value_as_number(typeVal);
} // }
jerry_value_free(typeVal); // jerry_value_free(typeVal);
return result; // return result;
} // }
return EASING_LINEAR; // return EASING_LINEAR;
} // }
// Fires onReach callbacks for any keyframes crossed between prevTime and // // Fires onReach callbacks for any keyframes crossed between prevTime and
// newTime. Returns an exception value on error, or jerry_undefined(). // // newTime. Returns an exception value on error, or jerry_undefined().
static jerry_value_t moduleAnimationFireKeyframes( // static jerry_value_t moduleAnimationFireKeyframes(
const jerry_value_t thisVal, // const jerry_value_t thisVal,
float_t prevTime, // float_t prevTime,
float_t newTime // float_t newTime
) { // ) {
jerry_value_t kfKey = jerry_string_sz("_keyframes"); // jerry_value_t kfKey = jerry_string_sz("_keyframes");
jerry_value_t kfArr = jerry_object_get(thisVal, kfKey); // jerry_value_t kfArr = jerry_object_get(thisVal, kfKey);
jerry_value_free(kfKey); // jerry_value_free(kfKey);
if(!jerry_value_is_array(kfArr)) { // if(!jerry_value_is_array(kfArr)) {
jerry_value_free(kfArr); // jerry_value_free(kfArr);
return jerry_undefined(); // return jerry_undefined();
} // }
jerry_length_t len = jerry_array_length(kfArr); // jerry_length_t len = jerry_array_length(kfArr);
for(jerry_length_t i = 0; i < len; i++) { // for(jerry_length_t i = 0; i < len; i++) {
jerry_value_t kfObj = jerry_object_get_index(kfArr, i); // jerry_value_t kfObj = jerry_object_get_index(kfArr, i);
jerry_value_t tKey = jerry_string_sz("time"); // jerry_value_t tKey = jerry_string_sz("time");
jerry_value_t tVal = jerry_object_get(kfObj, tKey); // jerry_value_t tVal = jerry_object_get(kfObj, tKey);
jerry_value_free(tKey); // jerry_value_free(tKey);
float_t kfTime = (float_t)jerry_value_as_number(tVal); // float_t kfTime = (float_t)jerry_value_as_number(tVal);
jerry_value_free(tVal); // jerry_value_free(tVal);
if(prevTime < kfTime && newTime >= kfTime) { // if(prevTime < kfTime && newTime >= kfTime) {
jerry_value_t cbKey = jerry_string_sz("onReach"); // jerry_value_t cbKey = jerry_string_sz("onReach");
jerry_value_t cb = jerry_object_get(kfObj, cbKey); // jerry_value_t cb = jerry_object_get(kfObj, cbKey);
jerry_value_free(cbKey); // jerry_value_free(cbKey);
if(jerry_value_is_function(cb)) { // if(jerry_value_is_function(cb)) {
jerry_value_t r = jerry_call(cb, thisVal, NULL, 0); // jerry_value_t r = jerry_call(cb, thisVal, NULL, 0);
jerry_value_free(cb); // jerry_value_free(cb);
if(jerry_value_is_exception(r)) { // if(jerry_value_is_exception(r)) {
jerry_value_free(kfObj); // jerry_value_free(kfObj);
jerry_value_free(kfArr); // jerry_value_free(kfArr);
return r; // return r;
} // }
jerry_value_free(r); // jerry_value_free(r);
} else { // } else {
jerry_value_free(cb); // jerry_value_free(cb);
} // }
} // }
jerry_value_free(kfObj); // jerry_value_free(kfObj);
} // }
jerry_value_free(kfArr); // jerry_value_free(kfArr);
return jerry_undefined(); // return jerry_undefined();
} // }
// Fires onComplete once. Returns an exception on error or jerry_undefined(). // // Fires onComplete once. Returns an exception on error or jerry_undefined().
static jerry_value_t moduleAnimationFireComplete( // static jerry_value_t moduleAnimationFireComplete(
const jerry_value_t thisVal // const jerry_value_t thisVal
) { // ) {
jerry_value_t firedKey = jerry_string_sz("_completeFired"); // jerry_value_t firedKey = jerry_string_sz("_completeFired");
jerry_value_t firedVal = jerry_object_get(thisVal, firedKey); // jerry_value_t firedVal = jerry_object_get(thisVal, firedKey);
bool_t alreadyFired = jerry_value_is_true(firedVal); // bool_t alreadyFired = jerry_value_is_true(firedVal);
jerry_value_free(firedVal); // jerry_value_free(firedVal);
if(alreadyFired) { // if(alreadyFired) {
jerry_value_free(firedKey); // jerry_value_free(firedKey);
return jerry_undefined(); // return jerry_undefined();
} // }
jerry_value_t trueVal = jerry_boolean(true); // jerry_value_t trueVal = jerry_boolean(true);
jerry_object_set(thisVal, firedKey, trueVal); // jerry_object_set(thisVal, firedKey, trueVal);
jerry_value_free(firedKey); // jerry_value_free(firedKey);
jerry_value_free(trueVal); // jerry_value_free(trueVal);
jerry_value_t cbKey = jerry_string_sz("onComplete"); // jerry_value_t cbKey = jerry_string_sz("onComplete");
jerry_value_t cb = jerry_object_get(thisVal, cbKey); // jerry_value_t cb = jerry_object_get(thisVal, cbKey);
jerry_value_free(cbKey); // jerry_value_free(cbKey);
if(jerry_value_is_function(cb)) { // if(jerry_value_is_function(cb)) {
jerry_value_t r = jerry_call(cb, thisVal, NULL, 0); // jerry_value_t r = jerry_call(cb, thisVal, NULL, 0);
jerry_value_free(cb); // jerry_value_free(cb);
if(jerry_value_is_exception(r)) return r; // if(jerry_value_is_exception(r)) return r;
jerry_value_free(r); // jerry_value_free(r);
} else { // } else {
jerry_value_free(cb); // jerry_value_free(cb);
} // }
return jerry_undefined(); // return jerry_undefined();
} // }
moduleBaseFunction(moduleAnimationConstructor) { // moduleBaseFunction(moduleAnimationConstructor) {
jsAnimation_t *janim = (jsAnimation_t *)memoryAllocate(sizeof(jsAnimation_t)); // jsAnimation_t *janim = (jsAnimation_t *)memoryAllocate(sizeof(jsAnimation_t));
animationInit(&janim->anim); // animationInit(&janim->anim);
janim->value = 0.0f; // janim->value = 0.0f;
if(argc > 0 && jerry_value_is_boolean(args[argc - 1])) { // if(argc > 0 && jerry_value_is_boolean(args[argc - 1])) {
if(jerry_value_is_true(args[argc - 1])) { // if(jerry_value_is_true(args[argc - 1])) {
janim->anim.flags |= ANIMATION_FLAG_LOOP_ENABLED; // janim->anim.flags |= ANIMATION_FLAG_LOOP_ENABLED;
} // }
} // }
animationproperty_t *prop = animationAddProperty(&janim->anim, &janim->value); // animationproperty_t *prop = animationAddProperty(&janim->anim, &janim->value);
if(argc > 0 && jerry_value_is_array(args[0])) { // if(argc > 0 && jerry_value_is_array(args[0])) {
jerry_length_t len = jerry_array_length(args[0]); // jerry_length_t len = jerry_array_length(args[0]);
for(jerry_length_t i = 0; i < len; i++) { // for(jerry_length_t i = 0; i < len; i++) {
jerry_value_t kf = jerry_object_get_index(args[0], i); // jerry_value_t kf = jerry_object_get_index(args[0], i);
jerry_value_t tKey = jerry_string_sz("time"); // jerry_value_t tKey = jerry_string_sz("time");
jerry_value_t vKey = jerry_string_sz("value"); // jerry_value_t vKey = jerry_string_sz("value");
jerry_value_t eKey = jerry_string_sz("easing"); // jerry_value_t eKey = jerry_string_sz("easing");
float_t t = (float_t)jerry_value_as_number( // float_t t = (float_t)jerry_value_as_number(
jerry_object_get(kf, tKey) // jerry_object_get(kf, tKey)
); // );
float_t v = (float_t)jerry_value_as_number( // float_t v = (float_t)jerry_value_as_number(
jerry_object_get(kf, vKey) // jerry_object_get(kf, vKey)
); // );
jerry_value_t eVal = jerry_object_get(kf, eKey); // jerry_value_t eVal = jerry_object_get(kf, eKey);
easingtype_t e = moduleAnimationReadEasing(eVal); // easingtype_t e = moduleAnimationReadEasing(eVal);
jerry_value_free(tKey); // jerry_value_free(tKey);
jerry_value_free(vKey); // jerry_value_free(vKey);
jerry_value_free(eKey); // jerry_value_free(eKey);
jerry_value_free(eVal); // jerry_value_free(eVal);
jerry_value_free(kf); // jerry_value_free(kf);
animationPropertyAddKeyframe(&janim->anim, prop, t, v, e); // animationPropertyAddKeyframe(&janim->anim, prop, t, v, e);
} // }
// Store the JS keyframes array for onReach callback detection. // // Store the JS keyframes array for onReach callback detection.
jerry_value_t kfKey = jerry_string_sz("_keyframes"); // jerry_value_t kfKey = jerry_string_sz("_keyframes");
jerry_object_set(callInfo->this_value, kfKey, args[0]); // jerry_object_set(callInfo->this_value, kfKey, args[0]);
jerry_value_free(kfKey); // jerry_value_free(kfKey);
} // }
jerry_value_t firedKey = jerry_string_sz("_completeFired"); // jerry_value_t firedKey = jerry_string_sz("_completeFired");
jerry_value_t falseVal = jerry_boolean(false); // jerry_value_t falseVal = jerry_boolean(false);
jerry_object_set(callInfo->this_value, firedKey, falseVal); // jerry_object_set(callInfo->this_value, firedKey, falseVal);
jerry_value_free(firedKey); // jerry_value_free(firedKey);
jerry_value_free(falseVal); // jerry_value_free(falseVal);
jerry_object_set_native_ptr( // jerry_object_set_native_ptr(
callInfo->this_value, &MODULE_ANIMATION_PROTO.info, janim // callInfo->this_value, &MODULE_ANIMATION_PROTO.info, janim
); // );
return jerry_undefined(); // return jerry_undefined();
} // }
moduleBaseFunction(moduleAnimationUpdate) { // moduleBaseFunction(moduleAnimationUpdate) {
jsAnimation_t *janim = moduleAnimationGetWrapper(callInfo); // jsAnimation_t *janim = moduleAnimationGetWrapper(callInfo);
if(!janim) return moduleBaseThrow("Invalid Animation instance"); // if(!janim) return moduleBaseThrow("Invalid Animation instance");
if(argc < 1 || !jerry_value_is_number(args[0])) { // if(argc < 1 || !jerry_value_is_number(args[0])) {
return moduleBaseThrow("update() expects a number delta"); // return moduleBaseThrow("update() expects a number delta");
} // }
float_t prevTime = janim->anim.time; // float_t prevTime = janim->anim.time;
float_t delta = (float_t)jerry_value_as_number(args[0]); // float_t delta = (float_t)jerry_value_as_number(args[0]);
animationUpdate(&janim->anim, delta); // animationUpdate(&janim->anim, delta);
jerry_value_t kfResult = moduleAnimationFireKeyframes( // jerry_value_t kfResult = moduleAnimationFireKeyframes(
callInfo->this_value, prevTime, janim->anim.time // callInfo->this_value, prevTime, janim->anim.time
); // );
if(jerry_value_is_exception(kfResult)) return kfResult; // if(jerry_value_is_exception(kfResult)) return kfResult;
jerry_value_free(kfResult); // jerry_value_free(kfResult);
if(animationIsFinished(&janim->anim)) { // if(animationIsFinished(&janim->anim)) {
jerry_value_t cResult = moduleAnimationFireComplete( // jerry_value_t cResult = moduleAnimationFireComplete(
callInfo->this_value // callInfo->this_value
); // );
if(jerry_value_is_exception(cResult)) return cResult; // if(jerry_value_is_exception(cResult)) return cResult;
jerry_value_free(cResult); // jerry_value_free(cResult);
} // }
return jerry_number((double)janim->value); // return jerry_number((double)janim->value);
} // }
moduleBaseFunction(moduleAnimationGetValue) { // moduleBaseFunction(moduleAnimationGetValue) {
jsAnimation_t *janim = moduleAnimationGetWrapper(callInfo); // jsAnimation_t *janim = moduleAnimationGetWrapper(callInfo);
if(!janim) return moduleBaseThrow("Invalid Animation instance"); // if(!janim) return moduleBaseThrow("Invalid Animation instance");
return jerry_number((double)janim->value); // return jerry_number((double)janim->value);
} // }
moduleBaseFunction(moduleAnimationReset) { // moduleBaseFunction(moduleAnimationReset) {
animation_t *anim = moduleAnimationGet(callInfo); // animation_t *anim = moduleAnimationGet(callInfo);
if(!anim) return moduleBaseThrow("Invalid Animation instance"); // if(!anim) return moduleBaseThrow("Invalid Animation instance");
animationReset(anim); // animationReset(anim);
jerry_value_t key = jerry_string_sz("_completeFired"); // jerry_value_t key = jerry_string_sz("_completeFired");
jerry_value_t falseVal = jerry_boolean(false); // jerry_value_t falseVal = jerry_boolean(false);
jerry_object_set(callInfo->this_value, key, falseVal); // jerry_object_set(callInfo->this_value, key, falseVal);
jerry_value_free(key); // jerry_value_free(key);
jerry_value_free(falseVal); // jerry_value_free(falseVal);
return jerry_undefined(); // return jerry_undefined();
} // }
moduleBaseFunction(moduleAnimationGetComplete) { // moduleBaseFunction(moduleAnimationGetComplete) {
animation_t *anim = moduleAnimationGet(callInfo); // animation_t *anim = moduleAnimationGet(callInfo);
return anim ? jerry_boolean(animationIsFinished(anim)) : jerry_boolean(false); // return anim ? jerry_boolean(animationIsFinished(anim)) : jerry_boolean(false);
} // }
moduleBaseFunction(moduleAnimationGetLoop) { // moduleBaseFunction(moduleAnimationGetLoop) {
animation_t *anim = moduleAnimationGet(callInfo); // animation_t *anim = moduleAnimationGet(callInfo);
return anim ? jerry_boolean(animationIsLooping(anim)) : jerry_boolean(false); // return anim ? jerry_boolean(animationIsLooping(anim)) : jerry_boolean(false);
} // }
moduleBaseFunction(moduleAnimationSetLoop) { // moduleBaseFunction(moduleAnimationSetLoop) {
animation_t *anim = moduleAnimationGet(callInfo); // animation_t *anim = moduleAnimationGet(callInfo);
if(!anim) return moduleBaseThrow("Invalid Animation instance"); // if(!anim) return moduleBaseThrow("Invalid Animation instance");
if(argc < 1) return moduleBaseThrow("Expected boolean"); // if(argc < 1) return moduleBaseThrow("Expected boolean");
if(jerry_value_is_true(args[0])) { // if(jerry_value_is_true(args[0])) {
anim->flags |= ANIMATION_FLAG_LOOP_ENABLED; // anim->flags |= ANIMATION_FLAG_LOOP_ENABLED;
} else { // } else {
anim->flags &= ~ANIMATION_FLAG_LOOP_ENABLED; // anim->flags &= ~ANIMATION_FLAG_LOOP_ENABLED;
} // }
return jerry_undefined(); // return jerry_undefined();
} // }
moduleBaseFunction(moduleAnimationGetTime) { // moduleBaseFunction(moduleAnimationGetTime) {
animation_t *anim = moduleAnimationGet(callInfo); // animation_t *anim = moduleAnimationGet(callInfo);
return anim ? jerry_number((double)anim->time) : jerry_number(0.0); // return anim ? jerry_number((double)anim->time) : jerry_number(0.0);
} // }
moduleBaseFunction(moduleAnimationGetDuration) { // moduleBaseFunction(moduleAnimationGetDuration) {
animation_t *anim = moduleAnimationGet(callInfo); // animation_t *anim = moduleAnimationGet(callInfo);
return anim ? jerry_number((double)anim->duration) : jerry_number(0.0); // return anim ? jerry_number((double)anim->duration) : jerry_number(0.0);
} // }
static void moduleAnimation(void) { static void moduleAnimation(void) {
scriptProtoInit( // scriptProtoInit(
&MODULE_ANIMATION_PROTO, // &MODULE_ANIMATION_PROTO,
"Animation", // "Animation",
sizeof(jsAnimation_t), // sizeof(jsAnimation_t),
moduleAnimationConstructor // moduleAnimationConstructor
); // );
scriptProtoDefineFunc( // scriptProtoDefineFunc(
&MODULE_ANIMATION_PROTO, "update", moduleAnimationUpdate // &MODULE_ANIMATION_PROTO, "update", moduleAnimationUpdate
); // );
scriptProtoDefineFunc( // scriptProtoDefineFunc(
&MODULE_ANIMATION_PROTO, "getValue", moduleAnimationGetValue // &MODULE_ANIMATION_PROTO, "getValue", moduleAnimationGetValue
); // );
scriptProtoDefineFunc( // scriptProtoDefineFunc(
&MODULE_ANIMATION_PROTO, "reset", moduleAnimationReset // &MODULE_ANIMATION_PROTO, "reset", moduleAnimationReset
); // );
scriptProtoDefineProp( // scriptProtoDefineProp(
&MODULE_ANIMATION_PROTO, "complete", // &MODULE_ANIMATION_PROTO, "complete",
moduleAnimationGetComplete, NULL // moduleAnimationGetComplete, NULL
); // );
scriptProtoDefineProp( // scriptProtoDefineProp(
&MODULE_ANIMATION_PROTO, "loop", // &MODULE_ANIMATION_PROTO, "loop",
moduleAnimationGetLoop, moduleAnimationSetLoop // moduleAnimationGetLoop, moduleAnimationSetLoop
); // );
scriptProtoDefineProp( // scriptProtoDefineProp(
&MODULE_ANIMATION_PROTO, "time", // &MODULE_ANIMATION_PROTO, "time",
moduleAnimationGetTime, NULL // moduleAnimationGetTime, NULL
); // );
scriptProtoDefineProp( // scriptProtoDefineProp(
&MODULE_ANIMATION_PROTO, "duration", // &MODULE_ANIMATION_PROTO, "duration",
moduleAnimationGetDuration, NULL // moduleAnimationGetDuration, NULL
); // );
} }
+1 -1
View File
@@ -28,7 +28,7 @@ moduleBaseFunction(moduleSceneSet) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); if(argc < 1) return moduleBaseThrow("Expected at least 1 argument");
moduleBaseRequireString(0); moduleBaseRequireString(0);
char_t name[ASSET_FILE_PATH_MAX]; char_t name[ASSET_FILE_NAME_MAX];
moduleBaseToString(args[0], name, sizeof(name)); moduleBaseToString(args[0], name, sizeof(name));
if(name[0] == '\0') return moduleBaseThrow("Scene.set: name cannot be empty"); if(name[0] == '\0') return moduleBaseThrow("Scene.set: name cannot be empty");
+6
View File
@@ -19,3 +19,9 @@ uint32_t mathNextPowTwo(uint32_t value) {
value |= value >> 16; value |= value >> 16;
return value + 1; return value + 1;
} }
float_t mathModFloat(float_t x, float_t y) {
float_t result = fmodf(x, y);
if(result < 0) result += y;
return result;
}
+10
View File
@@ -51,3 +51,13 @@ uint32_t mathNextPowTwo(uint32_t value);
* @return The absolute value of the number. * @return The absolute value of the number.
*/ */
#define mathAbs(amt) ((amt) < 0 ? -(amt) : (amt)) #define mathAbs(amt) ((amt) < 0 ? -(amt) : (amt))
/**
* Performs a modulus operation that always returns a non-negative result, even
* if the dividend is negative.
*
* @param x The dividend.
* @param y The divisor.
* @return The result of the modulus operation.
*/
float_t mathModFloat(float_t x, float_t y);
+11 -11
View File
@@ -14,12 +14,12 @@ errorret_t assetInitLinux(void) {
// Engine may have been provided the launch path // Engine may have been provided the launch path
if(ENGINE.argc > 0) { if(ENGINE.argc > 0) {
// Get the directory of the executable // Get the directory of the executable
char_t buffer[ASSET_FILE_PATH_MAX]; char_t buffer[ASSET_SYSTEM_PATH_MAX];
stringCopy(buffer, ENGINE.argv[0], ASSET_FILE_PATH_MAX); stringCopy(buffer, ENGINE.argv[0], ASSET_SYSTEM_PATH_MAX);
size_t len = strlen(buffer); size_t len = strlen(buffer);
// Normalize slashes // Normalize slashes
for(size_t i = 0; i < ASSET_FILE_PATH_MAX; i++) { for(size_t i = 0; i < ASSET_SYSTEM_PATH_MAX; i++) {
if(buffer[i] == '\0') break; if(buffer[i] == '\0') break;
if(buffer[i] == '\\') buffer[i] = '/'; if(buffer[i] == '\\') buffer[i] = '/';
} }
@@ -38,36 +38,36 @@ errorret_t assetInitLinux(void) {
// Did we find a slash? // Did we find a slash?
if(end != buffer) { if(end != buffer) {
// We found the directory, set as system path // We found the directory, set as system path
stringCopy(ASSET.platform.systemPath, buffer, ASSET_FILE_PATH_MAX); stringCopy(ASSET.platform.systemPath, buffer, ASSET_SYSTEM_PATH_MAX);
} }
} else { } else {
// Default system path, intended to be overridden by the platform // Default system path, intended to be overridden by the platform
stringCopy(ASSET.platform.systemPath, ".", ASSET_FILE_PATH_MAX); stringCopy(ASSET.platform.systemPath, ".", ASSET_SYSTEM_PATH_MAX);
} }
// Open zip file // Open zip file
char_t searchPath[ASSET_FILE_PATH_MAX]; char_t searchPath[ASSET_SYSTEM_PATH_MAX];
const char_t **path = ASSET_LINUX_SEARCH_PATHS; const char_t **path = ASSET_LINUX_SEARCH_PATHS;
int32_t error; int32_t error;
do { do {
char_t temp[ASSET_FILE_PATH_MAX]; char_t temp[ASSET_SYSTEM_PATH_MAX];
snprintf( snprintf(
temp, temp,
ASSET_FILE_PATH_MAX, ASSET_SYSTEM_PATH_MAX,
*path, *path,
ASSET_FILE_NAME ASSET_FILE_NAME
); );
// Ensure combined length does not exceed ASSET_FILE_PATH_MAX // Ensure combined length does not exceed ASSET_SYSTEM_PATH_MAX
size_t syslen = strlen(ASSET.platform.systemPath); size_t syslen = strlen(ASSET.platform.systemPath);
size_t slashlen = 1; // for '/' size_t slashlen = 1; // for '/'
size_t max_temp = ASSET_FILE_PATH_MAX - syslen - slashlen - 1; size_t max_temp = ASSET_SYSTEM_PATH_MAX - syslen - slashlen - 1;
if(strlen(temp) > max_temp) { if(strlen(temp) > max_temp) {
temp[max_temp] = '\0'; temp[max_temp] = '\0';
} }
snprintf( snprintf(
searchPath, searchPath,
ASSET_FILE_PATH_MAX, ASSET_SYSTEM_PATH_MAX,
"%s/%s", "%s/%s",
ASSET.platform.systemPath, ASSET.platform.systemPath,
temp temp
+3 -1
View File
@@ -9,6 +9,8 @@
#include "error/error.h" #include "error/error.h"
#include "asset/assetfile.h" #include "asset/assetfile.h"
#define ASSET_SYSTEM_PATH_MAX FILENAME_MAX
static const char_t *ASSET_LINUX_SEARCH_PATHS[] = { static const char_t *ASSET_LINUX_SEARCH_PATHS[] = {
"%s", "%s",
"../%s", "../%s",
@@ -19,7 +21,7 @@ static const char_t *ASSET_LINUX_SEARCH_PATHS[] = {
}; };
typedef struct { typedef struct {
char_t systemPath[ASSET_FILE_PATH_MAX]; char_t systemPath[ASSET_SYSTEM_PATH_MAX];
} assetlinux_t; } assetlinux_t;
/** /**