Moved a tonne of code around
This commit is contained in:
20
src/dawn/display/animation/animation.c
Normal file
20
src/dawn/display/animation/animation.c
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "animation.h"
|
||||
|
||||
float animForwardAndBackward(float t) {
|
||||
return (t < 0.5 ? t : 1 - t);
|
||||
}
|
||||
|
||||
float animForwardAndBackwardScaled(float t) {
|
||||
return animForwardAndBackward(t) * 2.0f;
|
||||
}
|
||||
|
||||
float animTimeScaleFromFrameTime(int32_t frames, float time) {
|
||||
return 1.0f / (float)frames / time;
|
||||
}
|
38
src/dawn/display/animation/animation.h
Normal file
38
src/dawn/display/animation/animation.h
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../../libs.h"
|
||||
|
||||
/**
|
||||
* Animation tool for converting 0-1 space into a 0-0.5 back to zero space. This
|
||||
* is intended to make a "Forward then backwards" effect for animation. This
|
||||
* method will not scale t.
|
||||
* @param t Time in space to back and fourth on between 0 and 1.
|
||||
* @returns Forward and backwards time. 0 to 0.5 are as such, 0.5 to 1 are from
|
||||
* 0.5 to 0.
|
||||
*/
|
||||
float animForwardAndBackward(float t);
|
||||
|
||||
/**
|
||||
* Animation tool for converting 0-1 space into a 0-1-0 space. Scaled version of
|
||||
* animForwardAndBackward().
|
||||
* @param t Time in space to back and fourth on between 0 and 1.
|
||||
* @returns Forward and backwards time.
|
||||
*/
|
||||
float animForwardAndBackwardScaled(float t);
|
||||
|
||||
/**
|
||||
* Returns the time scale (speed to multiply time range by) for a given frame
|
||||
* time and frame count. E.g. 3 frames at 0.5 time each would have a time scale
|
||||
* of 1.5.
|
||||
*
|
||||
* @param frames Frames to get the scale of.
|
||||
* @param time Time to get the scale of.
|
||||
* @return The time scale.
|
||||
*/
|
||||
float animTimeScaleFromFrameTime(int32_t frames, float time);
|
60
src/dawn/display/animation/easing.c
Normal file
60
src/dawn/display/animation/easing.c
Normal file
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "easing.h"
|
||||
|
||||
float easeLinear(float t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
float easeInQuad(float t) {
|
||||
return t * t;
|
||||
}
|
||||
|
||||
float easeOutQuad(float t) {
|
||||
return t * (2 - t);
|
||||
}
|
||||
|
||||
float easeInOutQuad(float t) {
|
||||
return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
||||
}
|
||||
|
||||
float easeInCubic(float t) {
|
||||
return t * t * t;
|
||||
}
|
||||
|
||||
float easeOutCubic(float t) {
|
||||
return (t - 1) * (t - 1) * (t - 1) + 1;
|
||||
}
|
||||
|
||||
float easeInOutCubic(float t) {
|
||||
return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
|
||||
}
|
||||
|
||||
float easeInQuart(float t) {
|
||||
return t * t * t * t;
|
||||
}
|
||||
|
||||
float easeOutQuart(float t) {
|
||||
return 1 - (t-1)*(t-1)*(t-1)*(t-1);
|
||||
}
|
||||
|
||||
float easeInOutQuart(float t) {
|
||||
return t < .5 ? 8*t*t*t*t : 1-8*(t-1)*(t-1)*(t-1)*(t-1);
|
||||
}
|
||||
|
||||
float easeInQuint(float t) {
|
||||
return t*t*t*t*t;
|
||||
}
|
||||
|
||||
float easeOutQuint(float t) {
|
||||
return 1 + (t-1)*(t-1)*(t-1)*(t-1)*(t-1);
|
||||
}
|
||||
|
||||
float easeInOutQuint(float t) {
|
||||
return t<.5 ? 16*t*t*t*t*t : 1+16*(t-1)*(t-1)*(t-1)*(t-1)*(t-1);
|
||||
}
|
32
src/dawn/display/animation/easing.h
Normal file
32
src/dawn/display/animation/easing.h
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
typedef float easefunction_t(float t);
|
||||
|
||||
/**
|
||||
* Returns the ease time for a given real time duration span.
|
||||
* @param start At what point in time the animation started
|
||||
* @param current The current point in time the animation is at.
|
||||
* @param duration The total duration on the animation.
|
||||
* @returns The easing time (0-1 time) that the animation is at.
|
||||
*/
|
||||
#define easeTimeToEase(start, current, duration) ((current-start)/duration)
|
||||
|
||||
float easeLinear(float t);
|
||||
float easeInQuad(float t);
|
||||
float easeOutQuad(float t);
|
||||
float easeInOutQuad(float t);
|
||||
float easeInCubic(float t);
|
||||
float easeOutCubic(float t);
|
||||
float easeInOutCubic(float t);
|
||||
float easeInQuart(float t);
|
||||
float easeOutQuart(float t);
|
||||
float easeInOutQuart(float t);
|
||||
float easeInQuint(float t);
|
||||
float easeOutQuint(float t);
|
||||
float easeInOutQuint(float t);
|
97
src/dawn/display/animation/queue.c
Normal file
97
src/dawn/display/animation/queue.c
Normal file
@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "queue.h"
|
||||
|
||||
void queueInit(queue_t *queue) {
|
||||
queue->timeline = 0;
|
||||
queue->count = 0;
|
||||
queue->current = ANIMATION_QUEUE_START;
|
||||
}
|
||||
|
||||
queueaction_t * queueNext(queue_t *queue) {
|
||||
queueaction_t *action;
|
||||
|
||||
// Is there a currently running action? If so, end it.
|
||||
if(queue->current != ANIMATION_QUEUE_START) {
|
||||
action = queue->items + queue->current;
|
||||
if(action->onEnd != NULL) action->onEnd(queue, action, queue->current);
|
||||
}
|
||||
|
||||
// Prepare to go to next action if there is a next action.
|
||||
queue->current++;
|
||||
queue->actionStarted = queue->timeline;
|
||||
if(queue->current >= queue->count) return NULL;
|
||||
|
||||
// Go to next action, start it.
|
||||
action = queue->items + queue->current;
|
||||
if(action->onStart != NULL) action->onStart(queue, action, queue->current);
|
||||
return action;
|
||||
}
|
||||
|
||||
queueaction_t * queueAdd(queue_t *queue) {
|
||||
queueaction_t *action;
|
||||
action = queue->items + queue->count;
|
||||
|
||||
action->index = queue->count;
|
||||
action->data = NULL;
|
||||
action->onStart = NULL;
|
||||
action->onUpdate = NULL;
|
||||
action->onEnd = NULL;
|
||||
|
||||
queue->count++;
|
||||
return action;
|
||||
}
|
||||
|
||||
void queueUpdate(queue_t *queue, float delta) {
|
||||
queueaction_t *action;
|
||||
queue->timeline += delta;
|
||||
if(queue->current >= queue->count) return;
|
||||
|
||||
action = queue->items + queue->current;
|
||||
if(action->onUpdate != NULL) {
|
||||
action->onUpdate(queue, action, queue->current);
|
||||
}
|
||||
}
|
||||
|
||||
void queueDispose(queue_t *queue) {
|
||||
queueaction_t *action;
|
||||
if(queue->current >= queue->count) return;
|
||||
action = queue->items + queue->current;
|
||||
if(action->onEnd != NULL) action->onEnd(queue, action, queue->current);
|
||||
}
|
||||
|
||||
void queueRestack(queue_t *queue) {
|
||||
uint8_t i;
|
||||
|
||||
// Rewind the array.
|
||||
arrayRewind(sizeof(queueaction_t), queue->items, ANIMATION_QUEUE_START,
|
||||
queue->current, queue->count
|
||||
);
|
||||
|
||||
// Now rewind the stack
|
||||
queue->count -= queue->current;
|
||||
queue->current = 0;
|
||||
|
||||
// Now fix indexes
|
||||
for(i = 0; i < queue->count; i++) {
|
||||
queue->items[i].index = i;
|
||||
}
|
||||
}
|
||||
|
||||
void _queueDelayUpdate(queue_t *queue, queueaction_t *action, uint8_t i) {
|
||||
float n = queue->timeline - queue->actionStarted;
|
||||
if(n < queue->delays[i]) return;
|
||||
queueNext(queue);
|
||||
}
|
||||
|
||||
queueaction_t * queueDelay(queue_t *queue, float delay) {
|
||||
queueaction_t *action = queueAdd(queue);
|
||||
queue->delays[action->index] = delay;
|
||||
action->onUpdate = &_queueDelayUpdate;
|
||||
return action;
|
||||
}
|
113
src/dawn/display/animation/queue.h
Normal file
113
src/dawn/display/animation/queue.h
Normal file
@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../../libs.h"
|
||||
#include "../../util/array.h"
|
||||
|
||||
#define ANIMATION_QUEUE_ITEM_MAX 128
|
||||
#define ANIMATION_QUEUE_START 0xFF
|
||||
|
||||
typedef struct _queueaction_t queueaction_t;
|
||||
typedef struct _queue_t queue_t;
|
||||
|
||||
/**
|
||||
* Callback for queue events.
|
||||
* @param conversation Conversation this text is attached to.
|
||||
* @param text Text item that is being used in the callback
|
||||
* @param i Index of the item in the queue.
|
||||
*/
|
||||
typedef void queuecallback_t(queue_t *queue, queueaction_t *action, uint8_t i);
|
||||
|
||||
typedef struct _queueaction_t {
|
||||
/** Index that the action is within the queue */
|
||||
uint8_t index;
|
||||
|
||||
/** Pointer to any custom user data */
|
||||
void *data;
|
||||
|
||||
/** Callback to fire the moment the action is active in the queue */
|
||||
queuecallback_t *onStart;
|
||||
|
||||
/** Callback to fire when this action has ended */
|
||||
queuecallback_t *onEnd;
|
||||
|
||||
/** Callback to fire every update of this queue while action is active. */
|
||||
queuecallback_t *onUpdate;
|
||||
} queueaction_t;
|
||||
|
||||
typedef struct _queue_t {
|
||||
/** Array of items within the queue. */
|
||||
queueaction_t items[ANIMATION_QUEUE_ITEM_MAX];
|
||||
uint8_t count;
|
||||
|
||||
/** Current index within the array of actions that is currently processing */
|
||||
uint8_t current;
|
||||
|
||||
/** Internal timeline tracking */
|
||||
float timeline;
|
||||
|
||||
/** Time that the current aciton started */
|
||||
float actionStarted;
|
||||
|
||||
/** Delay Queue Item Storage */
|
||||
float delays[ANIMATION_QUEUE_ITEM_MAX];
|
||||
} queue_t;
|
||||
|
||||
/**
|
||||
* Initialize the queue set.
|
||||
* @param queue Queue to initialize.
|
||||
*/
|
||||
void queueInit(queue_t *queue);
|
||||
|
||||
/**
|
||||
* Goes to the next action, or start the queue if this is the first action.
|
||||
* @param queue Queue to skip to the next action.
|
||||
* @returns Action that was just started.
|
||||
*/
|
||||
queueaction_t * queueNext(queue_t *queue);
|
||||
|
||||
/**
|
||||
* Add a queue action to the queue.
|
||||
* @param convo Queue to add to.
|
||||
* @return Pointer to the queue action that was added.
|
||||
*/
|
||||
queueaction_t * queueAdd(queue_t *queue);
|
||||
|
||||
/**
|
||||
* Updates the queue logic.
|
||||
* @param convo Queue to update.
|
||||
* @param delta Time delta to tick the queue by.
|
||||
*/
|
||||
void queueUpdate(queue_t *queue, float delta);
|
||||
|
||||
/**
|
||||
* Dispose the queue when finished.
|
||||
* @param queue Queue to dispose.
|
||||
*/
|
||||
void queueDispose(queue_t *queue);
|
||||
|
||||
/**
|
||||
* Restacks the queue. The restack process essentially rewinds the queue so that
|
||||
* the current items move back to position 0, and allows you to add more items
|
||||
* to the queue again. Because the memory does shift, and the indexes do change
|
||||
* a lot of your pointers will break, make sure you re-reference all your
|
||||
* pointers.
|
||||
*
|
||||
* @param queue Queue to restack.
|
||||
*/
|
||||
void queueRestack(queue_t *queue);
|
||||
|
||||
/** Callbacks for Queue Delay Action */
|
||||
void _queueDelayUpdate(queue_t *queue, queueaction_t *action, uint8_t i);
|
||||
/**
|
||||
* Adds a delay action to a queue.
|
||||
* @param queue Queue to add to.
|
||||
* @param delay Delay time (in seconds) to have.
|
||||
* @return Pointer to the action added to the queue.
|
||||
*/
|
||||
queueaction_t * queueDelay(queue_t *queue, float delay);
|
141
src/dawn/display/animation/timeline.c
Normal file
141
src/dawn/display/animation/timeline.c
Normal file
@ -0,0 +1,141 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "timeline.h"
|
||||
|
||||
void _timelineActionDeltaUpdateStart(
|
||||
timeline_t *timeline, timelineaction_t *action, uint8_t i
|
||||
) {
|
||||
if(action->data == NULL) return;
|
||||
*((float *)action->data) = timeline->initials[i];
|
||||
}
|
||||
|
||||
void _timelineActionDeltaUpdateDuration(
|
||||
timeline_t *timeline, timelineaction_t *action, uint8_t i
|
||||
) {
|
||||
float n;
|
||||
if(action->data == NULL) return;
|
||||
n = timeline->easings[i](
|
||||
timelineActionGetTimeRaw(timeline, action)
|
||||
);
|
||||
*((float *)action->data) = timeline->initials[i] + (timeline->deltas[i] * n);
|
||||
}
|
||||
|
||||
void _timelineActionDeltaUpdateEnd(
|
||||
timeline_t *timeline, timelineaction_t *action, uint8_t i
|
||||
) {
|
||||
if(action->data == NULL) return;
|
||||
*((float *)action->data) = timeline->initials[i] + timeline->deltas[i];
|
||||
}
|
||||
|
||||
|
||||
void timelineInit(timeline_t *timeline) {
|
||||
timeline->current = 0;
|
||||
timeline->diff = 0;
|
||||
timeline->previous = 0;
|
||||
timeline->user = 0;
|
||||
timeline->actionCount = 0;
|
||||
}
|
||||
|
||||
void timelineUpdate(timeline_t *timeline, float delta) {
|
||||
uint8_t i;
|
||||
timelineaction_t *action;
|
||||
float full;
|
||||
|
||||
timeline->diff = delta;
|
||||
timeline->previous = timeline->current;
|
||||
timeline->current = timeline->current + delta;
|
||||
|
||||
// Find all actions that would have started or ended in this timespan.
|
||||
for(i = 0; i < timeline->actionCount; i++) {
|
||||
action = timeline->actions +i;
|
||||
|
||||
// Has the action started yet?
|
||||
if(action->start > timeline->current) continue;
|
||||
|
||||
// Did we start this frame?
|
||||
if(action->start > timeline->previous && action->onStart != NULL) {
|
||||
action->onStart(timeline, action, i);
|
||||
}
|
||||
|
||||
// Durations of 0 only fire starts, never ends or durations.
|
||||
if(action->duration == 0) continue;
|
||||
|
||||
// Is the end still in the future? Durations in negatives go forever
|
||||
full = action->start+action->duration;
|
||||
if(action->duration < 0 || full > timeline->current) {
|
||||
if(action->onDuration != NULL) action->onDuration(timeline, action, i);
|
||||
} else if(full > timeline->previous) {// Did we end this frame?
|
||||
if(action->onEnd != NULL) action->onEnd(timeline, action, i);
|
||||
if(action->loop) action->start = timeline->current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool timelineIsFinished(timeline_t *timeline) {
|
||||
uint8_t i;
|
||||
timelineaction_t *action;
|
||||
|
||||
for(i = 0; i < timeline->actionCount; i++) {
|
||||
action = timeline->actions +i;
|
||||
if(action->start > timeline->current) return false;
|
||||
if(action->duration < 0) return false;
|
||||
if(action->duration == 0) continue;
|
||||
if(action->start+action->duration > timeline->current) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
timelineaction_t * timelineAddAction(timeline_t *timeline, float start,
|
||||
float duration
|
||||
) {
|
||||
timelineaction_t *action = timeline->actions + (timeline->actionCount++);
|
||||
action->loop = false;
|
||||
action->start = start, action->duration = duration;
|
||||
action->onStart = action->onEnd = action->onDuration = NULL;
|
||||
return action;
|
||||
}
|
||||
|
||||
timelineaction_t * timelineAddDeltaAction(timeline_t *timeline,
|
||||
float start, float duration, float initial, float delta,
|
||||
easefunction_t *easing, float *destination
|
||||
) {
|
||||
timelineaction_t *action;
|
||||
timeline->initials[timeline->actionCount] = initial;
|
||||
timeline->deltas[timeline->actionCount] = delta;
|
||||
timeline->easings[timeline->actionCount] = (
|
||||
easing == NULL ? &easeLinear : easing
|
||||
);
|
||||
action = timelineAddAction(timeline, start, duration);
|
||||
action->data = destination;
|
||||
action->onStart = &_timelineActionDeltaUpdateStart;
|
||||
action->onDuration = &_timelineActionDeltaUpdateDuration;
|
||||
action->onEnd = &_timelineActionDeltaUpdateEnd;
|
||||
return action;
|
||||
}
|
||||
|
||||
timelineaction_t * timelineAddDeltaActionTo(timeline_t *timeline,
|
||||
float start, float duration, float initial, float end,
|
||||
easefunction_t *easing, float *destination
|
||||
) {
|
||||
return timelineAddDeltaAction(
|
||||
timeline, start, duration, initial, end-initial, easing, destination
|
||||
);
|
||||
}
|
||||
|
||||
float timelineActionGetTimeRaw(timeline_t *timeline, timelineaction_t *action) {
|
||||
return (timeline->current - action->start) / action->duration;
|
||||
}
|
||||
|
||||
float timelineActionGetTime(timeline_t *tl, timelineaction_t *at) {
|
||||
return mathClamp(timelineActionGetTimeRaw(tl, at), 0, 1);
|
||||
}
|
||||
|
||||
void timelineClear(timeline_t *timeline) {
|
||||
timeline->actionCount = 0;
|
||||
}
|
187
src/dawn/display/animation/timeline.h
Normal file
187
src/dawn/display/animation/timeline.h
Normal file
@ -0,0 +1,187 @@
|
||||
// Copyright (c) 2021 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../../libs.h"
|
||||
#include "../../util/math.h"
|
||||
#include "easing.h"
|
||||
|
||||
/** Maximum number of actions a timeline can support, smaller than 0xFF */
|
||||
#define TIMELINE_ACTION_COUNT_MAX 128
|
||||
|
||||
/** Type forwarders */
|
||||
typedef struct _timeline_t timeline_t;
|
||||
typedef struct _timelineaction_t timelineaction_t;
|
||||
|
||||
/**
|
||||
* Callback for when a timeline event occurs
|
||||
* @param timeline The timeline that fired this callback.
|
||||
* @param action The action that this callback is attached to.
|
||||
* @param i The index that this action is within the timeline.
|
||||
*/
|
||||
typedef void timelinecallback_t(timeline_t *timeline, timelineaction_t *action,
|
||||
uint8_t i
|
||||
);
|
||||
|
||||
typedef struct _timelineaction_t {
|
||||
/** Pointer to any custom user data the timeline action wants to use. */
|
||||
void *data;
|
||||
|
||||
/**
|
||||
* The time that this action should occur within the timeline
|
||||
* set to 0 or less to start immediately.
|
||||
*/
|
||||
float start;
|
||||
|
||||
/**
|
||||
* The duration of the action, this will decide for how long onDuration will
|
||||
* be called for, and when onEnd should be called.
|
||||
* Set to a negative number to have this continue forever.
|
||||
* Set to 0 to only fire the onStart.
|
||||
* onStart can fire with either onDuration and onEnd on the same frame, but
|
||||
* onEnd and onDuration cannot fire the same frame.
|
||||
*/
|
||||
float duration;
|
||||
|
||||
/**
|
||||
* Enables animation looping. This works by forcing start to be equal to the
|
||||
* current time at the point in time that onEnd is called. This will also stop
|
||||
* onStart being called so ensure that your onStart and onEnd logic works.
|
||||
*/
|
||||
bool loop;
|
||||
|
||||
timelinecallback_t *onStart;
|
||||
|
||||
timelinecallback_t *onDuration;
|
||||
|
||||
timelinecallback_t *onEnd;
|
||||
} timelineaction_t;
|
||||
|
||||
typedef struct _timeline_t {
|
||||
/** The current time as far as the timeline is concerned */
|
||||
float current;
|
||||
|
||||
/** The time of the last "frame" as far as the timeline is concerned */
|
||||
float previous;
|
||||
|
||||
/** The frame time diff, essentially current = previous + diff */
|
||||
float diff;
|
||||
|
||||
/** User pointer, allows you to point to some other data */
|
||||
void *user;
|
||||
|
||||
/** Actions within the timeline */
|
||||
timelineaction_t actions[TIMELINE_ACTION_COUNT_MAX];
|
||||
|
||||
/** For delta actions, storage of the initial values */
|
||||
float initials[TIMELINE_ACTION_COUNT_MAX];
|
||||
/** For delta actions, storage of their deltas. */
|
||||
float deltas[TIMELINE_ACTION_COUNT_MAX];
|
||||
/** Easing functions to use for delta functions */
|
||||
easefunction_t *easings[TIMELINE_ACTION_COUNT_MAX];
|
||||
|
||||
uint8_t actionCount;
|
||||
} timeline_t;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes a timeline back to its default state.
|
||||
*
|
||||
* @param timeline Timeline to initialize.
|
||||
*/
|
||||
void timelineInit(timeline_t *timeline);
|
||||
|
||||
/**
|
||||
* Ticks the timeline. This can be done using any delta.
|
||||
*
|
||||
* @param timeline Timeline to tick
|
||||
* @param delta Delta to tick.
|
||||
*/
|
||||
void timelineUpdate(timeline_t *timeline, float delta);
|
||||
|
||||
/**
|
||||
* Returns true if every action in the timeline has finished.
|
||||
*
|
||||
* @param timeline Timeline to check
|
||||
* @return True if finished, otherwise false.
|
||||
*/
|
||||
bool timelineIsFinished(timeline_t *timeline);
|
||||
|
||||
/**
|
||||
* Adds an action to the timeline. This will initialize the action callbacks to
|
||||
* NULL, you will need to initialize your own callbacks.
|
||||
*
|
||||
* @param timeline Timeline to add to.
|
||||
* @param start Start time.
|
||||
* @param duration Duration time
|
||||
* @return Pointer to the timeline action or NULL if the list is full.
|
||||
*/
|
||||
timelineaction_t * timelineAddAction(timeline_t *timeline, float start,
|
||||
float duration
|
||||
);
|
||||
|
||||
/**
|
||||
* Add a special action kind that can treat delta style animations. These are
|
||||
* animations that have a start, and an end value, that will be tracked for you
|
||||
* and keep you up to date.
|
||||
*
|
||||
* @param timeline Timeline to add to.
|
||||
* @param start Starting time.
|
||||
* @param duration Animation duration.
|
||||
* @param initial Initial value for the animation.
|
||||
* @param delta Delta value for the animation.
|
||||
* @param easing Pointer to an easing function to use, set to NULL for linear.
|
||||
* @param destination A constant floating point to update.
|
||||
* @return The queued timeline action.
|
||||
*/
|
||||
timelineaction_t * timelineAddDeltaAction(timeline_t *timeline,
|
||||
float start, float duration, float initial, float delta,
|
||||
easefunction_t *easing, float *destination
|
||||
);
|
||||
|
||||
/**
|
||||
* Shorthand for timelineAddDeltaAction that will calculate the delta based on
|
||||
* and end position.
|
||||
*
|
||||
* @param timeline Timeline to add to.
|
||||
* @param start Starting time.
|
||||
* @param duration Animation duration.
|
||||
* @param initial Initial value for the animation.
|
||||
* @param end End value for the animation.
|
||||
* @param easing Pointer to an easing function to use, set to NULL for linear.
|
||||
* @param destination A constant floating point to update.
|
||||
* @return The queued timeline action.
|
||||
*/
|
||||
timelineaction_t * timelineAddDeltaActionTo(timeline_t *timeline,
|
||||
float start, float duration, float initial, float end,
|
||||
easefunction_t *easing, float *destination
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the timeline action's animation time. This is a representation of
|
||||
* 0 - 1 where 0 means the animation is at the start, and 1 meaning the
|
||||
* animation is at full completion. This is not clamped and may exceed 1.
|
||||
*
|
||||
* @param timeline Timeline the action belongs to.
|
||||
* @param action Action itself.
|
||||
* @return 0 - 1+, where 0 = start, 1 = duration, >1 is time since duration.
|
||||
*/
|
||||
float timelineActionGetTimeRaw(timeline_t *timeline, timelineaction_t *action);
|
||||
|
||||
/**
|
||||
* Gets the timeline action's animation time between 0 - 1, clamped.
|
||||
*
|
||||
* @param tl Timeline to get delta from.
|
||||
* @param at Timeline action.
|
||||
* @return 0 - 1, where 0 = start, 1 = duration.
|
||||
*/
|
||||
float timelineActionGetTime(timeline_t *tl, timelineaction_t *at);
|
||||
|
||||
/**
|
||||
* Removes all actions from the timeline.
|
||||
*
|
||||
* @param timeline Timeline to clear.
|
||||
*/
|
||||
void timelineClear(timeline_t *timeline);
|
120
src/dawn/display/bitmapfont.c
Normal file
120
src/dawn/display/bitmapfont.c
Normal file
@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "bitmapfont.h"
|
||||
|
||||
tilesetdiv_t * bitmapFontGetCharacterDivision(tileset_t *tileset,
|
||||
char character
|
||||
) {
|
||||
int32_t i = ((int32_t)character) - BITMAP_FONT_CHAR_START;
|
||||
return tileset->divisions + i;
|
||||
}
|
||||
|
||||
bitmapfontmeasure_t bitmapFontMeasure(char *string,
|
||||
float charWidth, float charHeight
|
||||
) {
|
||||
int32_t i;
|
||||
float x, y;
|
||||
char c;
|
||||
bitmapfontmeasure_t measure = {
|
||||
.height = 0, .lines = 1, .width = 0
|
||||
};
|
||||
|
||||
i = 0;
|
||||
y = 0;
|
||||
x = 0;
|
||||
|
||||
while(true) {
|
||||
c = string[i];
|
||||
if(c == '\0') break;
|
||||
i++;
|
||||
|
||||
if(c == '\n') {
|
||||
measure.width = mathMax(x, measure.width);
|
||||
x = 0;
|
||||
y += charHeight;
|
||||
measure.lines++;
|
||||
continue;
|
||||
} else if(c == ' ') {
|
||||
x += charWidth;
|
||||
continue;
|
||||
}
|
||||
|
||||
x += charWidth;
|
||||
}
|
||||
|
||||
measure.width = mathMax(x, measure.width);
|
||||
measure.height = y + charHeight;
|
||||
|
||||
return measure;
|
||||
}
|
||||
|
||||
bitmapfontmeasure_t bitmapFontSpriteBatchBuffer(
|
||||
spritebatch_t *batch, tileset_t *tileset,
|
||||
char *string, float x, float y, float z, float charWidth, float charHeight
|
||||
) {
|
||||
int32_t i;
|
||||
char c;
|
||||
tilesetdiv_t *div;
|
||||
float cx, cy;
|
||||
bitmapfontmeasure_t measure;
|
||||
|
||||
// Detect char dimensions
|
||||
if(charWidth == -1) charWidth = tileset->divX * (charHeight / tileset->divY);
|
||||
if(charHeight == -1) charHeight = tileset->divY * (charWidth / tileset->divX);
|
||||
|
||||
// Position the text.
|
||||
if(x == BITMAP_FONT_CENTER_X ||
|
||||
y == BITMAP_FONT_CENTER_Y ||
|
||||
x == BITMAP_FONT_RIGHT_X
|
||||
) {
|
||||
measure = bitmapFontMeasure(string, charWidth, charHeight);
|
||||
if(x == BITMAP_FONT_CENTER_X) {
|
||||
x = -(measure.width/2);
|
||||
} else if(x == BITMAP_FONT_RIGHT_X) {
|
||||
x = -measure.width;
|
||||
}
|
||||
if(y == BITMAP_FONT_CENTER_Y) y = -(measure.height/2);
|
||||
}
|
||||
|
||||
// Begin buffering the sprite batch
|
||||
measure.width = 0;
|
||||
measure.height = 0;
|
||||
measure.lines = 1;
|
||||
i = 0;
|
||||
cx = x, cy = y;
|
||||
|
||||
while(true) {
|
||||
c = string[i];
|
||||
if(c == '\0') break;
|
||||
i++;
|
||||
|
||||
// Special chars
|
||||
if(c == '\n') {
|
||||
measure.width = mathMax(cx-x, measure.width);
|
||||
cx = x;
|
||||
cy += charHeight;
|
||||
measure.lines++;
|
||||
continue;
|
||||
} else if(c == ' ') {
|
||||
cx += charWidth;
|
||||
continue;
|
||||
}
|
||||
|
||||
div = bitmapFontGetCharacterDivision(tileset, c);
|
||||
spriteBatchQuad(batch, -1,
|
||||
cx, cy, z, charWidth, charHeight,
|
||||
div->x0, div->y1, div->x1, div->y0
|
||||
);
|
||||
cx += charWidth;
|
||||
}
|
||||
|
||||
measure.width = mathMax(cx-x, measure.width);
|
||||
measure.height = cy-y + charHeight;
|
||||
|
||||
return measure;
|
||||
}
|
71
src/dawn/display/bitmapfont.h
Normal file
71
src/dawn/display/bitmapfont.h
Normal file
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "spritebatch.h"
|
||||
#include "tileset.h"
|
||||
#include "../util/math.h"
|
||||
|
||||
/** Which is the first character within the font tilemap */
|
||||
#define BITMAP_FONT_CHAR_START 33
|
||||
|
||||
/** Center a font along the X axis */
|
||||
#define BITMAP_FONT_CENTER_X 9876543
|
||||
|
||||
/** Center a font along the Y axis */
|
||||
#define BITMAP_FONT_CENTER_Y -BITMAP_FONT_CENTER_X
|
||||
|
||||
/** Align right edge of font to origin */
|
||||
#define BITMAP_FONT_RIGHT_X (BITMAP_FONT_CENTER_X-1)
|
||||
|
||||
typedef struct {
|
||||
float width, height;
|
||||
int32_t lines;
|
||||
} bitmapfontmeasure_t;
|
||||
|
||||
/**
|
||||
* Get the division for a given character.
|
||||
*
|
||||
* @param tileset Tileset to get the division from.
|
||||
* @param character Character to get the division for.
|
||||
* @return The division from the tileset for the character.
|
||||
*/
|
||||
tilesetdiv_t * bitmapFontGetCharacterDivision(tileset_t *tileset,
|
||||
char character
|
||||
);
|
||||
|
||||
/**
|
||||
* Measures a string's fully rendered size.
|
||||
*
|
||||
* @param string The string to measure
|
||||
* @param charWidth The width of each character.
|
||||
* @param charHeight The height of each character.
|
||||
* @return The measured string.
|
||||
*/
|
||||
bitmapfontmeasure_t bitmapFontMeasure(char *string,
|
||||
float charWidth, float charHeight
|
||||
);
|
||||
|
||||
/**
|
||||
* Renders a set of font characters to the sprite. Coordinates are anchored to
|
||||
* the top left (0,0) origin.
|
||||
*
|
||||
* @param batch Sprite Batch to render to.
|
||||
* @param tileset Tileset for the font.
|
||||
* @param string String to render.
|
||||
* @param x Position in X space.
|
||||
* @param y Position in Y space.
|
||||
* @param z Position in Z space.
|
||||
* @param charWidth Width of each character. Set to -1 to use the height ratio.
|
||||
* @param charHeight Height of each character. Set to -1 to be the width ratio.
|
||||
* @returns The string measurement.
|
||||
*/
|
||||
bitmapfontmeasure_t bitmapFontSpriteBatchBuffer(
|
||||
spritebatch_t *batch, tileset_t *tileset,
|
||||
char *string, float x, float y, float z, float charWidth, float charHeight
|
||||
);
|
55
src/dawn/display/camera.c
Normal file
55
src/dawn/display/camera.c
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Msters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "camera.h"
|
||||
|
||||
void cameraLookAt(camera_t *camera,
|
||||
float x, float y, float z,
|
||||
float targetX, float targetY, float targetZ
|
||||
) {
|
||||
matrixIdentity(&camera->view);
|
||||
matrixLookAt(&camera->view, x, y, z, targetX, targetY, targetZ, 0, 1, 0);
|
||||
}
|
||||
|
||||
void cameraLookAtStruct(camera_t *camera, cameralookat_t look) {
|
||||
cameraLookAt(camera,
|
||||
look.x, look.y, look.z, look.lookX, look.lookY, look.lookZ
|
||||
);
|
||||
}
|
||||
|
||||
void cameraLook(camera_t *camera,
|
||||
float x, float y, float z,
|
||||
float pitch, float yaw, float roll
|
||||
) {
|
||||
matrixIdentity(&camera->view);
|
||||
matrixLook(&camera->view, x, y, z, pitch, yaw, roll, 0, 1, 0);
|
||||
}
|
||||
|
||||
void cameraPerspective(camera_t *camera,
|
||||
float fov, float aspect, float camNear, float camFar
|
||||
) {
|
||||
matrixIdentity(&camera->projection);
|
||||
matrixPerspective(&camera->projection,mathDeg2Rad(fov),aspect,camNear,camFar);
|
||||
}
|
||||
|
||||
void cameraOrtho(camera_t *camera,
|
||||
float left, float right, float bottom, float top, float camNear, float camFar
|
||||
) {
|
||||
matrixIdentity(&camera->projection);
|
||||
matrixOrtho(&camera->projection, left, right, bottom, top, camNear, camFar);
|
||||
}
|
||||
|
||||
void cameraOrbit(camera_t *camera,
|
||||
float distance, float yaw, float pitch,
|
||||
float targetX, float targetY, float targetZ
|
||||
) {
|
||||
float cy = cosf(pitch);
|
||||
float x = distance * sinf(yaw) * cy;
|
||||
float y = distance * sinf(pitch);
|
||||
float z = distance * cosf(yaw) * cy;
|
||||
cameraLookAt(camera, x, y, z, targetX, targetY, targetZ);
|
||||
}
|
106
src/dawn/display/camera.h
Normal file
106
src/dawn/display/camera.h
Normal file
@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2021 Dominic Msters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/math.h"
|
||||
#include "matrix.h"
|
||||
|
||||
/** The math for the camera is stored here. */
|
||||
typedef struct {
|
||||
/** View Matrix (Where the camera looks) */
|
||||
matrix_t view;
|
||||
|
||||
/** Projection Matrix (How the camera looks) */
|
||||
matrix_t projection;
|
||||
} camera_t;
|
||||
|
||||
typedef struct {
|
||||
float x, y, z, lookX, lookY, lookZ;
|
||||
} cameralookat_t;
|
||||
|
||||
/**
|
||||
* Make a camera look at a position in world space while itself being positioned
|
||||
* within world space.
|
||||
*
|
||||
* @param camera The camera to position.
|
||||
* @param x The X position in world space of the camera.
|
||||
* @param y The Y position in world space of the camera.
|
||||
* @param z The Z position in world space of the camera.
|
||||
* @param targetX The Target X position in world space of the camera.
|
||||
* @param targetY The Target Y position in world space of the camera.
|
||||
* @param targetZ The Target Z position in world space of the camera.
|
||||
*/
|
||||
void cameraLookAt(camera_t *camera,
|
||||
float x, float y, float z,
|
||||
float targetX, float targetY, float targetZ
|
||||
);
|
||||
|
||||
/**
|
||||
* Shorthand for look at that uses the look struct.
|
||||
*
|
||||
* @param camera Camera to position.
|
||||
* @param look Look vectors.
|
||||
*/
|
||||
void cameraLookAtStruct(camera_t *camera, cameralookat_t look);
|
||||
|
||||
/**
|
||||
* Make a camera look in a direction based on a rotation direction.
|
||||
*
|
||||
* @param camera The camera to position.
|
||||
* @param x The X position in world space of the camera.
|
||||
* @param y The Y position in world space of the camera.
|
||||
* @param z The Z position in world space of the camera.
|
||||
* @param pitch The pitch of the camera.
|
||||
* @param yaw The yaw of the camera.
|
||||
* @param roll The roll of the camera.
|
||||
*/
|
||||
void cameraLook(camera_t *camera,
|
||||
float x, float y, float z,
|
||||
float pitch, float yaw, float roll
|
||||
);
|
||||
|
||||
/**
|
||||
* Make a camera's projection be a 3D Perspective view.
|
||||
*
|
||||
* @param camera The camera to project.
|
||||
* @param fov The field of view of the camera (in degrees).
|
||||
* @param aspect The aspect ratio of the camera (w / h)
|
||||
* @param camNear The near plane clip.
|
||||
* @param camFar the far plane clip.
|
||||
*/
|
||||
void cameraPerspective(camera_t *camera,
|
||||
float fov, float aspect, float camNear, float camFar
|
||||
);
|
||||
|
||||
/**
|
||||
* Defines an orthorgonal camera matrix.
|
||||
*
|
||||
* @param camera Camera to position.
|
||||
* @param left The left side of the viewport.
|
||||
* @param right The right side of the viewport.
|
||||
* @param bottom The bottom side of the viewport.
|
||||
* @param camNear The near plane clip.
|
||||
* @param camFar the far plane clip.
|
||||
*/
|
||||
void cameraOrtho(camera_t *camera,
|
||||
float left, float right, float bottom, float top, float camNear, float camFar
|
||||
);
|
||||
|
||||
/**
|
||||
* Update a camera to orbit around a point.
|
||||
*
|
||||
* @param camera Camera to update
|
||||
* @param distance Distance from the point
|
||||
* @param yaw Yaw (Y axis) rotation.
|
||||
* @param pitch Pitch (X/Z axis) rotation.
|
||||
* @param targetX X point to orbit around.
|
||||
* @param targetY Y point to orbit around.
|
||||
* @param targetZ Z point to orbit around.
|
||||
*/
|
||||
void cameraOrbit(camera_t *camera,
|
||||
float distance, float yaw, float pitch,
|
||||
float targetX, float targetY, float targetZ
|
||||
);
|
209
src/dawn/display/font.c
Normal file
209
src/dawn/display/font.c
Normal file
@ -0,0 +1,209 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "font.h"
|
||||
|
||||
// Due to some compiler bullshit, this is here.
|
||||
#ifndef STB_TRUETYPE_IMPLEMENTATION
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include <stb_truetype.h>
|
||||
#endif
|
||||
|
||||
void fontInit(font_t *font, char *data) {
|
||||
int32_t i, s;
|
||||
s = FONT_TEXTURE_WIDTH * FONT_TEXTURE_HEIGHT;
|
||||
|
||||
uint8_t *bitmapData = malloc(sizeof(uint8_t) * s);
|
||||
pixel_t *pixels = malloc(sizeof(pixel_t) * s);
|
||||
|
||||
// STBTT Loads fonts as single channel values only.
|
||||
stbtt_BakeFontBitmap(
|
||||
data, 0, FONT_TEXTURE_SIZE, bitmapData,
|
||||
FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT,
|
||||
FONT_FIRST_CHAR, FONT_NUM_CHARS,
|
||||
font->characterData
|
||||
);
|
||||
|
||||
for(i = 0; i < FONT_TEXTURE_WIDTH * FONT_TEXTURE_HEIGHT; i++) {
|
||||
pixels[i].r = 0xFF;
|
||||
pixels[i].g = 0xFF;
|
||||
pixels[i].b = 0xFF;
|
||||
pixels[i].a = bitmapData[i];
|
||||
}
|
||||
textureInit(&font->texture, FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT, pixels);
|
||||
|
||||
free(bitmapData);
|
||||
free(pixels);
|
||||
}
|
||||
|
||||
void fontDispose(font_t *font) {
|
||||
textureDispose(&font->texture);
|
||||
}
|
||||
|
||||
float fontGetScale(float fontSize) {
|
||||
return fontSize / FONT_SIZE_DEFAULT * FONT_GLOBAL_SCALE;
|
||||
}
|
||||
|
||||
bool _fontTextBufferAddLine(fonttextinfo_t *info, int32_t start, int32_t len) {
|
||||
info->lineCount++;
|
||||
|
||||
if(info->lineCount >= FONT_TEXT_INFO_LINES_MAX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
info->lines[info->lineCount].start = start;
|
||||
info->lines[info->lineCount].length = len;
|
||||
return true;
|
||||
}
|
||||
|
||||
void fontTextBuffer(
|
||||
font_t *font, primitive_t *primitive, fonttextinfo_t *info, char *text,
|
||||
float maxWidth, float fontSize
|
||||
) {
|
||||
int32_t i, j, wordStart;
|
||||
char c;
|
||||
float x, y, wordX, scale;
|
||||
stbtt_aligned_quad *quads;
|
||||
stbtt_aligned_quad *quad;
|
||||
|
||||
// Make some space
|
||||
quads = malloc(sizeof(stbtt_aligned_quad) * strlen(text));
|
||||
|
||||
// Get the font scale
|
||||
scale = fontGetScale(fontSize);
|
||||
|
||||
// Adjust the max width to match the scale, and allow "no max width".
|
||||
maxWidth = maxWidth == -1 ? 9999999 : maxWidth * (1 / scale);
|
||||
|
||||
/** Which index in the original text var is the current word from */
|
||||
wordStart = 0;
|
||||
|
||||
// Setup Scales
|
||||
info->length = 0;
|
||||
info->realLength = 0;
|
||||
info->lineCount = 0;
|
||||
|
||||
// Prepare the line counters
|
||||
info->lines[0].start = 0;
|
||||
info->lines[0].length = 0;
|
||||
|
||||
// Reset Dimensions
|
||||
info->width = 0, info->height = 0;
|
||||
|
||||
// Setup the initial loop state, and X/Y coords for the quad.
|
||||
i = 0;
|
||||
x = 0;
|
||||
y = FONT_INITIAL_LINE;
|
||||
wordX = 0;
|
||||
while(c = text[i++]) {
|
||||
if(info->lineCount >= FONT_TEXT_INFO_LINES_MAX) break;
|
||||
info->length++;
|
||||
|
||||
// When space, start of new word about to begin
|
||||
if(c == FONT_SPACE) {
|
||||
x += FONT_SPACE_SIZE * scale;
|
||||
|
||||
// Did this space cause a newline?
|
||||
if(x > maxWidth) {
|
||||
_fontTextBufferAddLine(info, info->realLength, 0);
|
||||
y += FONT_LINE_HEIGHT;
|
||||
x = 0;
|
||||
}
|
||||
wordX = x;
|
||||
wordStart = info->realLength;
|
||||
continue;
|
||||
}
|
||||
|
||||
// New line.
|
||||
if(c == FONT_NEWLINE) {
|
||||
_fontTextBufferAddLine(info, info->realLength, 0);
|
||||
wordStart = info->realLength;
|
||||
y += FONT_LINE_HEIGHT;
|
||||
x = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Generate the quad.
|
||||
quad = quads + info->realLength;
|
||||
stbtt_GetBakedQuad(font->characterData,
|
||||
FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT,
|
||||
((int32_t)c)-FONT_FIRST_CHAR, &x, &y, quad, FONT_FILL_MODE
|
||||
);
|
||||
|
||||
// Now measure the width of the line (take the right side of that quad)
|
||||
if(quad->x1 > maxWidth) {
|
||||
// We've exceeded the edge, go back to the start of the word and newline.
|
||||
x = quad->x1 - wordX;
|
||||
for(j = wordStart; j <= info->realLength; j++) {
|
||||
quad = quads + j;
|
||||
quad->x0 -= wordX;
|
||||
quad->x1 -= wordX;
|
||||
quad->y0 += FONT_LINE_HEIGHT;
|
||||
quad->y1 += FONT_LINE_HEIGHT;
|
||||
}
|
||||
|
||||
// Go back to the previous (still current) line and remove the chars
|
||||
info->lines[info->lineCount].length -= info->realLength - wordStart;
|
||||
|
||||
// Next line begins with this word
|
||||
y += FONT_LINE_HEIGHT;
|
||||
if(!_fontTextBufferAddLine(info, wordStart, info->realLength-wordStart)) {
|
||||
continue;
|
||||
}
|
||||
wordX = 0;
|
||||
}
|
||||
|
||||
info->lines[info->lineCount].length++;
|
||||
info->realLength++;
|
||||
}
|
||||
|
||||
info->lineCount++;
|
||||
|
||||
// Initialize primitive
|
||||
primitiveInit(primitive,
|
||||
QUAD_VERTICE_COUNT * info->realLength,
|
||||
QUAD_INDICE_COUNT * info->realLength
|
||||
);
|
||||
|
||||
for(j = 0; j < info->realLength; j++) {
|
||||
quad = quads + j;
|
||||
|
||||
// Scale the Quad
|
||||
if(scale != 1.0) {
|
||||
quad->x0 *= scale;
|
||||
quad->x1 *= scale;
|
||||
quad->y0 *= scale;
|
||||
quad->y1 *= scale;
|
||||
}
|
||||
|
||||
// Update the dimensions.
|
||||
info->width = mathMax(info->width, quad->x1);
|
||||
info->height = mathMax(info->height, quad->y1);
|
||||
|
||||
// Buffer the quad.
|
||||
quadBuffer(primitive, 0,
|
||||
quad->x0, quad->y0, quad->s0, quad->t0,
|
||||
quad->x1, quad->y1, quad->s1, quad->t1,
|
||||
j * QUAD_VERTICE_COUNT, j * QUAD_INDICE_COUNT
|
||||
);
|
||||
}
|
||||
|
||||
// Free up
|
||||
free(quads);
|
||||
}
|
||||
|
||||
int32_t fontGetLineCharCount(fonttextinfo_t *info,int32_t start,int32_t count) {
|
||||
int32_t charCount, i, m;
|
||||
m = mathMin(start+count, info->lineCount);
|
||||
|
||||
charCount = 0;
|
||||
for(i = start; i < m; i++) {
|
||||
charCount += info->lines[i].length;
|
||||
}
|
||||
|
||||
return charCount;
|
||||
}
|
138
src/dawn/display/font.h
Normal file
138
src/dawn/display/font.h
Normal file
@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "texture.h"
|
||||
#include "primitive/primitive.h"
|
||||
#include "primitive/quad.h"
|
||||
#include "../util/mem.h"
|
||||
#include "../util/math.h"
|
||||
|
||||
/** Which character (ASCII) to start the font from */
|
||||
#define FONT_FIRST_CHAR 32
|
||||
|
||||
/** How many characters (after the first char) to generate */
|
||||
#define FONT_NUM_CHARS 96
|
||||
|
||||
/** Width of the loaded font texture */
|
||||
#define FONT_TEXTURE_WIDTH 1024
|
||||
|
||||
/** Height of the loaded font texture */
|
||||
#define FONT_TEXTURE_HEIGHT FONT_TEXTURE_WIDTH
|
||||
|
||||
/** Refer to STBTT docs for OpenGL Fill Mode v d3d Fill Modes */
|
||||
#define FONT_FILL_MODE 1
|
||||
|
||||
/** Passed to STBTT for scaling the font, essentially the font resolution */
|
||||
#define FONT_TEXTURE_SIZE 64.0f
|
||||
|
||||
/** The global scale, just used to provide fine control of font sizes */
|
||||
#define FONT_GLOBAL_SCALE 0.5f;
|
||||
|
||||
/** Default Font Size (on which all font scales are based) */
|
||||
#define FONT_SIZE_DEFAULT 16.0f
|
||||
|
||||
// Chars
|
||||
#define FONT_NEWLINE '\n'
|
||||
#define FONT_SPACE ' '
|
||||
|
||||
// Heights
|
||||
#define FONT_LINE_HEIGHT FONT_TEXTURE_SIZE * 0.75f
|
||||
#define FONT_INITIAL_LINE FONT_LINE_HEIGHT * 0.75f
|
||||
#define FONT_SPACE_SIZE FONT_TEXTURE_SIZE * 0.45f
|
||||
|
||||
/** Maximum number of newlines that a font text info can hold. */
|
||||
#define FONT_TEXT_INFO_LINES_MAX 16
|
||||
|
||||
/** Representation of a font that can be used to render text */
|
||||
typedef struct {
|
||||
texture_t texture;
|
||||
stbtt_bakedchar characterData[FONT_NUM_CHARS];
|
||||
} font_t;
|
||||
|
||||
typedef struct {
|
||||
/** What (real character) index the line starts at */
|
||||
int32_t start;
|
||||
/** How many (real) characters the line is in length */
|
||||
int32_t length;
|
||||
} fonttextinfoline_t;
|
||||
|
||||
typedef struct {
|
||||
/** How many raw chars are in the string */
|
||||
int32_t length;
|
||||
|
||||
/** How many real characters (non whitespace) are in the string */
|
||||
int32_t realLength;
|
||||
|
||||
/** How many lines is the string? Trailing newlines will count */
|
||||
int32_t lineCount;
|
||||
|
||||
/** The real character info for each line */
|
||||
fonttextinfoline_t lines[FONT_TEXT_INFO_LINES_MAX];
|
||||
|
||||
/** Dimensions of the string */
|
||||
float width, height;
|
||||
} fonttextinfo_t;
|
||||
|
||||
/**
|
||||
* Initializes Font from raw TTF data.
|
||||
* @param font Font to initialize
|
||||
* @param data Data to intialize for.
|
||||
*/
|
||||
void fontInit(font_t *font, char *data);
|
||||
|
||||
/**
|
||||
* Clean up a previously loaded font
|
||||
* @param font Loaded font.
|
||||
*/
|
||||
void fontDispose(font_t *Font);
|
||||
|
||||
/**
|
||||
* Convert a Font's Size into a Font Scale. The scale is based on the font's
|
||||
* default size for the given texture size (Refer to FONT_SIZE_DEFAULT).
|
||||
*
|
||||
* @param fontSize Font size to convert.
|
||||
* @return The times scale that the font size is to the textured default.
|
||||
*/
|
||||
float fontGetScale(float fontSize);
|
||||
|
||||
/**
|
||||
* Internal method that adds a line to the text buffer process.
|
||||
*
|
||||
* @param info Info to add to.
|
||||
* @param start Start character index for the next line.
|
||||
* @param len Length of the next line.
|
||||
* @return True if added a line successfully, otherwise false.
|
||||
*/
|
||||
bool _fontTextBufferAddLine(fonttextinfo_t *info, int32_t start, int32_t len);
|
||||
|
||||
/**
|
||||
* Clamps text to a max width, inserting newlines where possible.
|
||||
*
|
||||
* @param font Font to use
|
||||
* @param primitive Primitive to buffer the text to.
|
||||
* @param info Font text info to clamp into.
|
||||
* @param text Text to clamp.
|
||||
* @param maxWidth Max width (pixels) to clamp the text to, -1 for no max width.
|
||||
* @param fontSize Font Size of the text.
|
||||
*/
|
||||
void fontTextBuffer(
|
||||
font_t *font, primitive_t *primitive, fonttextinfo_t *info, char *text,
|
||||
float maxWidth, float fontSize
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the number of real characters on the lines specified. Useful when
|
||||
* attempting to clamp to a set of lines.
|
||||
*
|
||||
* @param info Info to get the character counts from.
|
||||
* @param start Starting line index.
|
||||
* @param count Count of lines, this method will clamp to info's line length.
|
||||
* @returns The count of characters in those lines summed.
|
||||
*/
|
||||
int32_t fontGetLineCharCount(fonttextinfo_t *info, int32_t start,int32_t count);
|
76
src/dawn/display/framebuffer.c
Normal file
76
src/dawn/display/framebuffer.c
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "framebuffer.h"
|
||||
|
||||
void frameBufferInit(framebuffer_t *fb, int32_t w, int32_t h) {
|
||||
// At least one pixel
|
||||
if(w <= 0) w = 1;
|
||||
if(h <= 0) h = 1;
|
||||
|
||||
// Create Color Attachment texture.
|
||||
textureInit(&fb->texture, w, h, NULL);
|
||||
|
||||
// Create Frame Buffer
|
||||
glGenFramebuffers(1, &fb->fboId);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb->fboId);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, fb->texture.id, 0
|
||||
);
|
||||
|
||||
// Render Buffer
|
||||
glGenRenderbuffers(1, &fb->rboId);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, fb->rboId);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
|
||||
GL_RENDERBUFFER, fb->rboId
|
||||
);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
uint32_t error;
|
||||
error = 0;
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void frameBufferUse(framebuffer_t *frameBuffer, bool clear) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer->fboId);
|
||||
glViewport(0, 0, frameBuffer->texture.width, frameBuffer->texture.height);
|
||||
|
||||
if(clear) {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
void frameBufferResize(framebuffer_t *frameBuffer,int32_t width,int32_t height){
|
||||
if((
|
||||
frameBuffer->texture.width == width &&
|
||||
frameBuffer->texture.height == height
|
||||
)) return;
|
||||
|
||||
frameBufferDispose(frameBuffer);
|
||||
frameBufferInit(frameBuffer, width, height);
|
||||
}
|
||||
|
||||
void frameBufferUnbind(float viewWidth, float viewHeight, bool clear) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glViewport(0, 0, (GLsizei)viewWidth, (GLsizei)viewHeight);
|
||||
|
||||
if(clear) {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
void frameBufferDispose(framebuffer_t *frameBuffer) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
glDeleteRenderbuffers(1, &frameBuffer->rboId);
|
||||
glDeleteFramebuffers(1, &frameBuffer->fboId);
|
||||
textureDispose(&frameBuffer->texture);
|
||||
}
|
59
src/dawn/display/framebuffer.h
Normal file
59
src/dawn/display/framebuffer.h
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "texture.h"
|
||||
|
||||
typedef struct {
|
||||
GLuint fboId;
|
||||
GLuint rboId;
|
||||
texture_t texture;
|
||||
} framebuffer_t;
|
||||
|
||||
/**
|
||||
* Initializes frame buffer that can be rendered to.
|
||||
* @param frameBuffer Frame buffer to initialize.
|
||||
* @param width Width of the frame buffer (in pixels).
|
||||
* @param height Height of the frame buffer (in pixels).
|
||||
* @return A renderable frame buffer.
|
||||
*/
|
||||
void frameBufferInit(framebuffer_t *buffer, int32_t width, int32_t height);
|
||||
|
||||
/**
|
||||
* Use a given frame buffer as the current rendering context.
|
||||
*
|
||||
* @param frameBuffer Frame buffer to use.
|
||||
* @param clear Whether or not to clear the frame buffer prior to rendering.
|
||||
*/
|
||||
void frameBufferUse(framebuffer_t *frameBuffer, bool clear);
|
||||
|
||||
/**
|
||||
* Resize an existing frame buffer. This will do the check if resizing is even
|
||||
* necessary for you.
|
||||
*
|
||||
* @param frameBuffer Frame buffer to resize.
|
||||
* @param width New width of the frame buffer.
|
||||
* @param height New height of the frame buffer.
|
||||
*/
|
||||
void frameBufferResize(framebuffer_t *frameBuffer,int32_t width,int32_t height);
|
||||
|
||||
/**
|
||||
* Unbind the currently bound frame buffer.
|
||||
*
|
||||
* @param viewWidth Viewport width.
|
||||
* @param viewHeight Viewport height.
|
||||
* @param clear Whether or not to clear the back buffer.
|
||||
*/
|
||||
void frameBufferUnbind(float viewWidth, float viewHeight, bool clear);
|
||||
|
||||
/**
|
||||
* Dispose/cleanup a previously created frame buffer.
|
||||
*
|
||||
* @param frameBuffer Frame Buffer to clean.
|
||||
*/
|
||||
void frameBufferDispose(framebuffer_t *frameBuffer);
|
62
src/dawn/display/matrix.c
Normal file
62
src/dawn/display/matrix.c
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "matrix.h"
|
||||
|
||||
void matrixIdentity(matrix_t *matrix) {
|
||||
glm_mat4_identity(matrix->internalMatrix);
|
||||
}
|
||||
|
||||
void matrixLookAt(matrix_t *matrix,
|
||||
float x,float y,float z,
|
||||
float tx,float ty, float tz,
|
||||
float ux, float uy, float uz
|
||||
) {
|
||||
glm_lookat(
|
||||
(vec3){ x, y, z },
|
||||
(vec3){ tx, ty, tz },
|
||||
(vec3){ ux, uy, uz },
|
||||
matrix->internalMatrix
|
||||
);
|
||||
}
|
||||
|
||||
void matrixLook(matrix_t *matrix,
|
||||
float x, float y, float z,
|
||||
float pitch, float yaw, float roll,
|
||||
float ux, float uy, float uz
|
||||
) {
|
||||
glm_look(
|
||||
(vec3){ x, y, z },
|
||||
(vec3){ pitch, yaw, roll },
|
||||
(vec3){ ux, uy, uz },
|
||||
matrix->internalMatrix
|
||||
);
|
||||
}
|
||||
|
||||
void matrixPerspective(matrix_t *matrix,
|
||||
float fov, float aspect, float camNear, float camFar
|
||||
) {
|
||||
glm_perspective(fov, aspect, camNear, camFar, matrix->internalMatrix);
|
||||
}
|
||||
|
||||
void matrixOrtho(matrix_t *matrix,
|
||||
float left, float right, float bottom, float top, float camNear, float camFar
|
||||
) {
|
||||
glm_ortho(left, right, bottom, top, camNear, camFar, matrix->internalMatrix);
|
||||
}
|
||||
|
||||
void matrixTranslate(matrix_t *matrix, float x, float y, float z) {
|
||||
glm_translate(matrix->internalMatrix, (vec3){ x, y, z });
|
||||
}
|
||||
|
||||
void matrixRotate(matrix_t *matrix, float angle, float x, float y, float z) {
|
||||
glm_rotate(matrix->internalMatrix, angle, (vec3){ x, y, z });
|
||||
}
|
||||
|
||||
void matrixScale(matrix_t *matrix, float x, float y, float z) {
|
||||
glm_scale(matrix->internalMatrix, (vec3){ x, y, z });
|
||||
}
|
123
src/dawn/display/matrix.h
Normal file
123
src/dawn/display/matrix.h
Normal file
@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
|
||||
/**
|
||||
* Representation for a matrix. Used as a highlevel wrapper for the math
|
||||
* functions that sit underneath this API.
|
||||
*/
|
||||
typedef struct {
|
||||
/** Internal Matrix API */
|
||||
mat4 internalMatrix;
|
||||
} matrix_t;
|
||||
|
||||
/**
|
||||
* Makes matrix identity.
|
||||
* @param matrix Matrix to identify.
|
||||
*/
|
||||
void matrixIdentity(matrix_t *matrix);
|
||||
|
||||
/**
|
||||
* Applies a look at point vector to a matrix.
|
||||
*
|
||||
* @param matrix Matrix to apply to.
|
||||
* @param x Camera source X.
|
||||
* @param y Camera source Y.
|
||||
* @param z Camera source Z.
|
||||
* @param tx Camera target X.
|
||||
* @param ty Camera target Y.
|
||||
* @param tz Camera target Z.
|
||||
* @param ux Camera up vector X.
|
||||
* @param uy Camera up vector Y.
|
||||
* @param uz Camera up vector Z.
|
||||
*/
|
||||
void matrixLookAt(matrix_t *matrix,
|
||||
float x,float y,float z,
|
||||
float tx,float ty, float tz,
|
||||
float ux, float uy, float uz
|
||||
);
|
||||
|
||||
/**
|
||||
* Applies a look vector to a matrix.
|
||||
*
|
||||
* @param matrix Matrix to apply to.
|
||||
* @param x Camera source X.
|
||||
* @param y Camera source Y.
|
||||
* @param z Camera source Z.
|
||||
* @param pitch Camera pitch
|
||||
* @param yaw Camera yaw.
|
||||
* @param roll Camera roll.
|
||||
* @param ux Camera up vector X.
|
||||
* @param uy Camera up vector Y.
|
||||
* @param uz Camera up vector Z.
|
||||
*/
|
||||
void matrixLook(matrix_t *matrix,
|
||||
float x, float y, float z,
|
||||
float pitch, float yaw, float roll,
|
||||
float ux, float uy, float uz
|
||||
);
|
||||
|
||||
/**
|
||||
* Applies a perspective projection to a matrix.
|
||||
*
|
||||
* @param matrix Matrix to apply to.
|
||||
* @param fov Field of View (in radians) to use.
|
||||
* @param aspect Aspect ratio (w/h) of the viewport.
|
||||
* @param camNear Near vector, > 0.
|
||||
* @param camFar Far view vector.
|
||||
*/
|
||||
void matrixPerspective(matrix_t *matrix,
|
||||
float fov,float aspect, float camNear, float camFar
|
||||
);
|
||||
|
||||
/**
|
||||
* Applies an orthogonal projection to a matrix.
|
||||
*
|
||||
* @param matrix Matrix to apply to.
|
||||
* @param left Left view position.
|
||||
* @param right Right view position.
|
||||
* @param bottom Bottom view position.
|
||||
* @param top Top view position.
|
||||
* @param camNear Near vector, > 0.
|
||||
* @param camFar Far view vector.
|
||||
*/
|
||||
void matrixOrtho(matrix_t *matrix,
|
||||
float left, float right, float bottom, float top, float camNear, float camFar
|
||||
);
|
||||
|
||||
/**
|
||||
* Performs a matrix translation.
|
||||
*
|
||||
* @param matrix Matrix to translate.
|
||||
* @param x X coordinate to translate on.
|
||||
* @param y Y coordinate to translate on.
|
||||
* @param z Z coordinate to translate on.
|
||||
*/
|
||||
void matrixTranslate(matrix_t *matrix, float x, float y, float z);
|
||||
|
||||
/**
|
||||
* Applies a rotation vector to a matrix.
|
||||
*
|
||||
* @param matrix Matrix to rotate.
|
||||
* @param angle Angle (in radians) to rotate.
|
||||
* @param x X vector to rotate on.
|
||||
* @param y Y vector to rotate on.
|
||||
* @param z Z vector to rotate on.
|
||||
*/
|
||||
void matrixRotate(matrix_t *matrix, float angle, float x, float y, float z);
|
||||
|
||||
/**
|
||||
* Scales a matrix.
|
||||
*
|
||||
* @param matrix Matrix to scale
|
||||
* @param x X vector to scale.
|
||||
* @param y Y vector to scale.
|
||||
* @param z Z vector to scale.
|
||||
*/
|
||||
void matrixScale(matrix_t *matrix, float x, float y, float z);
|
111
src/dawn/display/primitive/cube.c
Normal file
111
src/dawn/display/primitive/cube.c
Normal file
@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cube.h"
|
||||
|
||||
void cubeBuffer(primitive_t *prim,
|
||||
float x, float y, float z,
|
||||
float w, float h, float d,
|
||||
int32_t verticeStart, int32_t indiceStart
|
||||
) {
|
||||
vertice_t *vertices = malloc(sizeof(vertice_t) * CUBE_VERTICE_COUNT);
|
||||
indice_t *indices = malloc(sizeof(indice_t) * CUBE_INDICE_COUNT);
|
||||
|
||||
vertices[0].x = x, vertices[0].y = y, vertices[0].z = z;
|
||||
vertices[0].u = 0, vertices[0].v = 0;
|
||||
|
||||
vertices[1].x = x+w, vertices[1].y = y, vertices[1].z = z;
|
||||
vertices[1].u = 1, vertices[1].v = 0;
|
||||
|
||||
vertices[2].x = x, vertices[2].y = y+h, vertices[2].z = z;
|
||||
vertices[2].u = 0, vertices[2].v = 1;
|
||||
|
||||
vertices[3].x = x+w, vertices[3].y = y+h, vertices[3].z = z;
|
||||
vertices[3].u = 1, vertices[3].v = 1;
|
||||
|
||||
vertices[4].x = x, vertices[4].y = y, vertices[4].z = z+d;
|
||||
vertices[4].u = 0, vertices[4].v = 0;
|
||||
|
||||
vertices[5].x = x+w, vertices[5].y = y, vertices[5].z = z+d;
|
||||
vertices[5].u = 1, vertices[5].v = 0;
|
||||
|
||||
vertices[6].x = x, vertices[6].y = y+h, vertices[6].z = z+d;
|
||||
vertices[6].u = 0, vertices[6].v = 1;
|
||||
|
||||
vertices[7].x = x+w, vertices[7].y = y+h, vertices[7].z = z+d;
|
||||
vertices[7].u = 1, vertices[7].v = 1;
|
||||
|
||||
// Back
|
||||
indices[ 0] = (indice_t)(verticeStart + 0);
|
||||
indices[ 1] = (indice_t)(verticeStart + 1);
|
||||
indices[ 2] = (indice_t)(verticeStart + 3);
|
||||
|
||||
indices[ 3] = (indice_t)(verticeStart + 0);
|
||||
indices[ 4] = (indice_t)(verticeStart + 2);
|
||||
indices[ 5] = (indice_t)(verticeStart + 3);
|
||||
|
||||
// Right
|
||||
indices[ 6] = (indice_t)(verticeStart + 1);
|
||||
indices[ 7] = (indice_t)(verticeStart + 5);
|
||||
indices[ 8] = (indice_t)(verticeStart + 7);
|
||||
|
||||
indices[ 9] = (indice_t)(verticeStart + 1);
|
||||
indices[10] = (indice_t)(verticeStart + 3);
|
||||
indices[11] = (indice_t)(verticeStart + 7);
|
||||
|
||||
// Left
|
||||
indices[12] = (indice_t)(verticeStart + 4);
|
||||
indices[13] = (indice_t)(verticeStart + 0);
|
||||
indices[14] = (indice_t)(verticeStart + 2);
|
||||
|
||||
indices[15] = (indice_t)(verticeStart + 4);
|
||||
indices[16] = (indice_t)(verticeStart + 6);
|
||||
indices[17] = (indice_t)(verticeStart + 2);
|
||||
|
||||
// Front
|
||||
indices[18] = (indice_t)(verticeStart + 5);
|
||||
indices[19] = (indice_t)(verticeStart + 4);
|
||||
indices[20] = (indice_t)(verticeStart + 6);
|
||||
|
||||
indices[21] = (indice_t)(verticeStart + 5);
|
||||
indices[22] = (indice_t)(verticeStart + 7);
|
||||
indices[23] = (indice_t)(verticeStart + 6);
|
||||
|
||||
// Top
|
||||
indices[24] = (indice_t)(verticeStart + 7);
|
||||
indices[25] = (indice_t)(verticeStart + 2);
|
||||
indices[26] = (indice_t)(verticeStart + 6);
|
||||
|
||||
indices[27] = (indice_t)(verticeStart + 7);
|
||||
indices[28] = (indice_t)(verticeStart + 3);
|
||||
indices[29] = (indice_t)(verticeStart + 2);
|
||||
|
||||
// Bottom
|
||||
indices[30] = (indice_t)(verticeStart + 1);
|
||||
indices[31] = (indice_t)(verticeStart + 0);
|
||||
indices[32] = (indice_t)(verticeStart + 4);
|
||||
|
||||
indices[33] = (indice_t)(verticeStart + 1);
|
||||
indices[34] = (indice_t)(verticeStart + 4);
|
||||
indices[35] = (indice_t)(verticeStart + 5);
|
||||
|
||||
|
||||
primitiveBufferVertices(prim, verticeStart, CUBE_VERTICE_COUNT, vertices);
|
||||
primitiveBufferIndices(prim, indiceStart, CUBE_INDICE_COUNT, indices);
|
||||
|
||||
free(vertices);
|
||||
free(indices);
|
||||
}
|
||||
|
||||
void cubeInit(primitive_t *primitive, float w, float h, float d) {
|
||||
primitiveInit(primitive, CUBE_VERTICE_COUNT, CUBE_INDICE_COUNT);
|
||||
cubeBuffer(primitive,
|
||||
-w/2, -h/2, -d/2,
|
||||
w, h, d,
|
||||
0, 0
|
||||
);
|
||||
}
|
38
src/dawn/display/primitive/cube.h
Normal file
38
src/dawn/display/primitive/cube.h
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2021 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../../libs.h"
|
||||
#include "primitive.h"
|
||||
|
||||
#define CUBE_VERTICE_COUNT 8
|
||||
#define CUBE_INDICE_COUNT 36
|
||||
|
||||
/**
|
||||
* Buffer the vertices and indices of a cube onto a primitive.
|
||||
* @param primitive Primitive to buffer to.
|
||||
* @param x X position of the cube.
|
||||
* @param y Y position of the cube.
|
||||
* @param z Z position of the cube.
|
||||
* @param w Width of cube.
|
||||
* @param h Height of cube.
|
||||
* @param d Depth of cube.
|
||||
* @param verticeStart The position of the vertex buffer to buffer into.
|
||||
* @param indiceStart The position of the index buffer to buffer into.
|
||||
*/
|
||||
void cubeBuffer(primitive_t *primitive,
|
||||
float x, float y, float z,
|
||||
float w, float h, float d,
|
||||
int32_t verticeStart, int32_t indiceStart
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates a cube primitive of given size.
|
||||
* @param primitive Primitive to create into a cube.
|
||||
* @param w Width of cube.
|
||||
* @param h Height of cube.
|
||||
* @param d Depth of cube.
|
||||
*/
|
||||
void cubeInit(primitive_t *primitive, float w, float h, float d);
|
132
src/dawn/display/primitive/primitive.c
Normal file
132
src/dawn/display/primitive/primitive.c
Normal file
@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "primitive.h"
|
||||
|
||||
void primitiveInit(primitive_t *primitive,
|
||||
int32_t verticeCount, int32_t indiceCount
|
||||
) {
|
||||
primitive->verticeCount = verticeCount;
|
||||
primitive->indiceCount = indiceCount;
|
||||
|
||||
// size_t sizeIndices = sizeof(uint32_t) * verticeCount;
|
||||
size_t sizePositions = sizeof(float) * verticeCount * PRIMITIVE_POSITIONS_PER_VERTICE;
|
||||
size_t sizeCoordinates = sizeof(float) * verticeCount * PRIMITIVE_COORDINATES_PER_VERTICE;
|
||||
size_t sizeIndices = sizeof(indice_t) * indiceCount;
|
||||
|
||||
// Create some buffers, one for the vertex data, one for the indices
|
||||
GLuint *buffer = malloc(sizeof(GLuint) * 2);
|
||||
glGenBuffers(2, buffer);
|
||||
|
||||
primitive->vertexBuffer = buffer[0];
|
||||
primitive->indexBuffer = buffer[1];
|
||||
free(buffer);
|
||||
|
||||
// Buffer an empty set of data then buffer each component
|
||||
glBindBuffer(GL_ARRAY_BUFFER, primitive->vertexBuffer);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, primitive->indexBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizePositions+sizeCoordinates, 0, GL_DYNAMIC_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeIndices, 0, GL_DYNAMIC_DRAW);
|
||||
|
||||
size_t offset = 0;
|
||||
|
||||
// Setup the attrib pointers
|
||||
glVertexAttribPointer(0, PRIMITIVE_POSITIONS_PER_VERTICE, GL_FLOAT,
|
||||
GL_FALSE, 0, (void *)offset
|
||||
);
|
||||
glEnableVertexAttribArray(0);
|
||||
offset += sizePositions;
|
||||
glVertexAttribPointer(1, PRIMITIVE_COORDINATES_PER_VERTICE, GL_FLOAT,
|
||||
GL_FALSE, 0, (void *)offset
|
||||
);
|
||||
glEnableVertexAttribArray(1);
|
||||
}
|
||||
|
||||
void primitiveBufferVertices(primitive_t *primitive,
|
||||
int32_t position, int32_t count, vertice_t *vertices
|
||||
) {
|
||||
// Memory
|
||||
size_t lengthPositions, lengthCoordinates, offsetPositions, offsetCoordinates;
|
||||
float *positions, *coordinates;
|
||||
int32_t i;
|
||||
|
||||
// Setup the size of the memory that the positions and coordinates will use
|
||||
lengthPositions = sizeof(float) * PRIMITIVE_POSITIONS_PER_VERTICE * count;
|
||||
offsetPositions = sizeof(float) * PRIMITIVE_POSITIONS_PER_VERTICE * position;
|
||||
|
||||
lengthCoordinates = sizeof(float) * PRIMITIVE_COORDINATES_PER_VERTICE * count;
|
||||
offsetCoordinates = (
|
||||
(sizeof(float) * PRIMITIVE_POSITIONS_PER_VERTICE * primitive->verticeCount)+
|
||||
(sizeof(float) * PRIMITIVE_COORDINATES_PER_VERTICE * position)
|
||||
);
|
||||
|
||||
// Create some memory
|
||||
positions = malloc(lengthPositions);
|
||||
coordinates = malloc(lengthCoordinates);
|
||||
|
||||
// Now copy the positions and coordinates from the vertices into the buffer
|
||||
for(i = 0; i < count; i++) {
|
||||
positions[i * PRIMITIVE_POSITIONS_PER_VERTICE] = vertices[i].x;
|
||||
positions[i * PRIMITIVE_POSITIONS_PER_VERTICE + 1] = vertices[i].y;
|
||||
positions[i * PRIMITIVE_POSITIONS_PER_VERTICE + 2] = vertices[i].z;
|
||||
|
||||
coordinates[i * PRIMITIVE_COORDINATES_PER_VERTICE] = vertices[i].u;
|
||||
coordinates[i * PRIMITIVE_COORDINATES_PER_VERTICE + 1] = vertices[i].v;
|
||||
}
|
||||
|
||||
// Buffer the data into the GPU
|
||||
glBindBuffer(GL_ARRAY_BUFFER, primitive->vertexBuffer);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, offsetPositions, lengthPositions, positions);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, offsetCoordinates, lengthCoordinates, coordinates);
|
||||
|
||||
// Free the vertices.
|
||||
free(positions);
|
||||
free(coordinates);
|
||||
}
|
||||
|
||||
void primitiveBufferIndices(primitive_t *primitive,
|
||||
int32_t position, int32_t count, indice_t *indices
|
||||
) {
|
||||
size_t length, offset;
|
||||
offset = position * sizeof(indice_t);
|
||||
length = count * sizeof(indice_t);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, primitive->indexBuffer);
|
||||
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, length, indices);
|
||||
}
|
||||
|
||||
void primitiveDraw(primitive_t *primitive, int32_t start, int32_t count) {
|
||||
if(count == -1) count = primitive->indiceCount;
|
||||
|
||||
// Re-Bind the buffers
|
||||
glBindBuffer(GL_ARRAY_BUFFER, primitive->vertexBuffer);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, primitive->indexBuffer);
|
||||
|
||||
// Re-Calculate the attrib pointers.
|
||||
size_t offset = 0;
|
||||
glVertexAttribPointer(0, PRIMITIVE_POSITIONS_PER_VERTICE, GL_FLOAT,
|
||||
GL_FALSE, 0, (void *)offset
|
||||
);
|
||||
glEnableVertexAttribArray(0);
|
||||
offset += sizeof(float) * primitive->verticeCount * PRIMITIVE_POSITIONS_PER_VERTICE;
|
||||
glVertexAttribPointer(1, PRIMITIVE_COORDINATES_PER_VERTICE, GL_FLOAT,
|
||||
GL_FALSE, 0, (void *)offset
|
||||
);
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
// Render the elements.
|
||||
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, (void *)(
|
||||
sizeof(indice_t)*start
|
||||
));
|
||||
}
|
||||
|
||||
void primitiveDispose(primitive_t *primitive) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glDeleteBuffers(1, &primitive->vertexBuffer);
|
||||
glDeleteBuffers(1, &primitive->indexBuffer);
|
||||
}
|
82
src/dawn/display/primitive/primitive.h
Normal file
82
src/dawn/display/primitive/primitive.h
Normal file
@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../../libs.h"
|
||||
|
||||
#define PRIMITIVE_POSITIONS_PER_VERTICE 3
|
||||
#define PRIMITIVE_COORDINATES_PER_VERTICE 2
|
||||
|
||||
/** Structure containing information about a primitive */
|
||||
typedef struct {
|
||||
/** How many vertices are in the primitive */
|
||||
int32_t verticeCount;
|
||||
/** How many indices are in the primitive */
|
||||
int32_t indiceCount;
|
||||
|
||||
/** Pointer to the vertex buffer on the GPU */
|
||||
GLuint vertexBuffer;
|
||||
/** Pointer to the index buffer on the GPU */
|
||||
GLuint indexBuffer;
|
||||
} primitive_t;
|
||||
|
||||
/** Structure containing vertice position information */
|
||||
typedef struct {
|
||||
/** Coordinates */
|
||||
float x, y, z;
|
||||
/** Texture UVs */
|
||||
float u, v;
|
||||
} vertice_t;
|
||||
|
||||
/** Indice that references a specific vertice */
|
||||
typedef unsigned int indice_t;
|
||||
|
||||
/**
|
||||
* Creates a new primitive.
|
||||
* @param primitive Primitive to initialize.
|
||||
* @param verticeCount How many vertices can the primitive hold.
|
||||
* @param indiceCount How many indices can the primitive hold.
|
||||
*/
|
||||
void primitiveInit(primitive_t *primitive,
|
||||
int32_t verticeCount, int32_t indiceCount
|
||||
);
|
||||
|
||||
/**
|
||||
* Buffer Vertices to a primitive for use in rendering.
|
||||
* @param primitive The primitive to buffer vertices into.
|
||||
* @param position The position (index) to overwrite the vertices of.
|
||||
* @param count The count of vertices to buffer.
|
||||
* @param vertices Array of vertices to buffer into the primitive.
|
||||
*/
|
||||
void primitiveBufferVertices(primitive_t *primitive,
|
||||
int32_t position, int32_t count, vertice_t *vertices
|
||||
);
|
||||
|
||||
/**
|
||||
* Buffer Indices to a primitive for use in rendering.
|
||||
* @param primitive The primitive to buffer indices into.
|
||||
* @param position The position (index) to overwrite the indices of.
|
||||
* @param count The count of indices to buffer.
|
||||
* @param indices Array of indices to buffer into the primitive.
|
||||
*/
|
||||
void primitiveBufferIndices(primitive_t *primitive,
|
||||
int32_t position, int32_t count, indice_t *indices
|
||||
);
|
||||
|
||||
/**
|
||||
* Draw a primitive. Primitives are drawn by their indices.
|
||||
* @param primitive Primitive to draw.
|
||||
* @param start Start indice (index) to draw.
|
||||
* @param count Count of indices to draw. Use -1 to draw all.
|
||||
*/
|
||||
void primitiveDraw(primitive_t *primitive, int32_t start, int32_t count);
|
||||
|
||||
/**
|
||||
* Cleanup a previously initialized primitive.
|
||||
* @param primitive Primitive to cleanup.
|
||||
*/
|
||||
void primitiveDispose(primitive_t *primitive);
|
56
src/dawn/display/primitive/quad.c
Normal file
56
src/dawn/display/primitive/quad.c
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "quad.h"
|
||||
|
||||
void quadBuffer(primitive_t *primitive, float z,
|
||||
float x0, float y0, float u0, float v0,
|
||||
float x1, float y1, float u1, float v1,
|
||||
int32_t verticeStart, int32_t indiceStart
|
||||
) {
|
||||
vertice_t *vertices = malloc(sizeof(vertice_t) * QUAD_VERTICE_COUNT);
|
||||
indice_t *indices = malloc(sizeof(indice_t) * QUAD_INDICE_COUNT);
|
||||
|
||||
vertices[0].x = x0, vertices[0].y = y0, vertices[0].z = z;
|
||||
vertices[0].u = u0, vertices[0].v = v0;
|
||||
|
||||
vertices[1].x = x1, vertices[1].y = y0, vertices[1].z = z;
|
||||
vertices[1].u = u1, vertices[1].v = v0;
|
||||
|
||||
vertices[2].x = x0, vertices[2].y = y1, vertices[2].z = z;
|
||||
vertices[2].u = u0, vertices[2].v = v1;
|
||||
|
||||
vertices[3].x = x1, vertices[3].y = y1, vertices[3].z = z;
|
||||
vertices[3].u = u1, vertices[3].v = v1;
|
||||
|
||||
indices[0] = (indice_t)(verticeStart + 0);
|
||||
indices[1] = (indice_t)(verticeStart + 1);
|
||||
indices[2] = (indice_t)(verticeStart + 2);
|
||||
|
||||
indices[3] = (indice_t)(verticeStart + 1);
|
||||
indices[4] = (indice_t)(verticeStart + 2);
|
||||
indices[5] = (indice_t)(verticeStart + 3);
|
||||
|
||||
primitiveBufferVertices(primitive,verticeStart,QUAD_VERTICE_COUNT,vertices);
|
||||
primitiveBufferIndices( primitive,indiceStart, QUAD_INDICE_COUNT, indices );
|
||||
|
||||
free(vertices);
|
||||
free(indices);
|
||||
}
|
||||
|
||||
void quadInit(primitive_t *primitive, float z,
|
||||
float x0, float y0, float u0, float v0,
|
||||
float x1, float y1, float u1, float v1
|
||||
) {
|
||||
primitiveInit(primitive, QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT);
|
||||
|
||||
quadBuffer(primitive, z,
|
||||
x0, y0, u0, v0,
|
||||
x1, y1, u1, v1,
|
||||
0, 0
|
||||
);
|
||||
}
|
53
src/dawn/display/primitive/quad.h
Normal file
53
src/dawn/display/primitive/quad.h
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2021 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../../libs.h"
|
||||
#include "primitive.h"
|
||||
|
||||
#define QUAD_VERTICE_COUNT 4
|
||||
#define QUAD_INDICE_COUNT 6
|
||||
#define QUAD_INDICE_PER_QUAD 2
|
||||
|
||||
/**
|
||||
* Buffers the vertices of a quad onto a primitive.
|
||||
*
|
||||
* @param primitive The primitive to buffer to.
|
||||
* @param z The Z axis coordinate of the quad.
|
||||
* @param x0 The X lower coordinate.
|
||||
* @param y0 The Y lower coordinate.
|
||||
* @param u0 The X lower texture coordinate.
|
||||
* @param v0 The Y lower texture coordinate.
|
||||
* @param x1 The X higher coordinate.
|
||||
* @param y1 The Y higher coordinate.
|
||||
* @param u1 The X higher texture coordinate.
|
||||
* @param v1 The Y higher texture coordinate.
|
||||
* @param verticeStart Start vertice to buffer to.
|
||||
* @param indiceStart Start indice to buffer to.
|
||||
*/
|
||||
void quadBuffer(primitive_t *primitive, float z,
|
||||
float x0, float y0, float u0, float v0,
|
||||
float x1, float y1, float u1, float v1,
|
||||
int32_t verticeStart, int32_t indiceStart
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates a new quad primitive.
|
||||
*
|
||||
* @param primitive Primitive to turn into a quad.
|
||||
* @param z The Z axis coordinate of the quad.
|
||||
* @param x0 The X lower coordinate.
|
||||
* @param y0 The Y lower coordinate.
|
||||
* @param u0 The X lower texture coordinate.
|
||||
* @param v0 The Y lower texture coordinate.
|
||||
* @param x1 The X higher coordinate.
|
||||
* @param y1 The Y higher coordinate.
|
||||
* @param u1 The X higher texture coordinate.
|
||||
* @param v1 The Y higher texture coordinate.
|
||||
*/
|
||||
void quadInit(primitive_t *primitive, float z,
|
||||
float x0, float y0, float u0, float v0,
|
||||
float x1, float y1, float u1, float v1
|
||||
);
|
58
src/dawn/display/primitive/skywall.c
Normal file
58
src/dawn/display/primitive/skywall.c
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "skywall.h"
|
||||
|
||||
void skywallInit(primitive_t *primitive) {
|
||||
primitiveInit(primitive, SKYWALL_VERTICE_COUNT, SKYWALL_INDICE_COUNT);
|
||||
|
||||
vertice_t vertices[SKYWALL_VERTICE_COUNT];
|
||||
indice_t indices[SKYWALL_INDICE_COUNT];
|
||||
int32_t n, i, j;
|
||||
float x, y, z, p, r;
|
||||
|
||||
// For each slice. We iterate slices+1 to do the wrapping mentioned below.
|
||||
for(i = 0; i < SKYWALL_SLICE_COUNT+1; i++) {
|
||||
// Get the "percentage" of the current slice, slice 0 is 0, slice n is 1
|
||||
p = (float)i/(float)SKYWALL_SLICE_COUNT;
|
||||
|
||||
// Because we we are to "seal the cylinder" we wrap around back to 0 on the
|
||||
// last slice to have the last vertice meet the first.
|
||||
if(SKYWALL_SLICE_COUNT == i) {
|
||||
r = 0;
|
||||
} else {
|
||||
r = p * MATH_PI * 2.0f;// Convert % to radians
|
||||
}
|
||||
|
||||
r += mathDeg2Rad(90);
|
||||
|
||||
// Determine the X/Z for the given radian
|
||||
x = SKYWALL_SIZE * (float)cos(r);
|
||||
z = SKYWALL_SIZE * (float)sin(r);
|
||||
y = SKYWALL_SIZE * 1;
|
||||
|
||||
// Get the start index for the ertices
|
||||
n = i * SKYWALL_VERTICES_PER_SLICE;
|
||||
vertices[n].x = x, vertices[n].y = -y, vertices[n].z = z;
|
||||
vertices[n].u = p, vertices[n].v = 1;
|
||||
vertices[n+1].x = x, vertices[n+1].y = y, vertices[n+1].z = z;
|
||||
vertices[n+1].u = p, vertices[n+1].v = 0;
|
||||
|
||||
if(i == SKYWALL_SLICE_COUNT) continue;
|
||||
j = i * SKYWALL_INDICES_PER_SLICE;
|
||||
indices[j] = (indice_t)n;
|
||||
indices[j+1] = (indice_t)n+1;
|
||||
indices[j+2] = (indice_t)n+2;
|
||||
|
||||
indices[j+3] = (indice_t)n+3;
|
||||
indices[j+4] = (indice_t)n+2;
|
||||
indices[j+5] = (indice_t)n+1;
|
||||
}
|
||||
|
||||
primitiveBufferVertices(primitive, 0, SKYWALL_VERTICE_COUNT, vertices);
|
||||
primitiveBufferIndices(primitive, 0, SKYWALL_INDICE_COUNT, indices);
|
||||
}
|
29
src/dawn/display/primitive/skywall.h
Normal file
29
src/dawn/display/primitive/skywall.h
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2021 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../../libs.h"
|
||||
#include "../../util/math.h"
|
||||
#include "primitive.h"
|
||||
|
||||
/** How many slices in each cylinder. */
|
||||
#define SKYWALL_SLICE_COUNT 40
|
||||
|
||||
/** How many vertices per slice */
|
||||
#define SKYWALL_VERTICES_PER_SLICE 2
|
||||
|
||||
/** How many indices per slice */
|
||||
#define SKYWALL_INDICES_PER_SLICE 6
|
||||
|
||||
/** How many vertices in the cylinder, +1 to have the cylinder "wrap" */
|
||||
#define SKYWALL_VERTICE_COUNT (SKYWALL_SLICE_COUNT+1)*SKYWALL_VERTICES_PER_SLICE
|
||||
|
||||
/** How many indices in the cylinder */
|
||||
#define SKYWALL_INDICE_COUNT SKYWALL_INDICES_PER_SLICE*SKYWALL_SLICE_COUNT
|
||||
|
||||
/** How big the skywall cylinder is */
|
||||
#define SKYWALL_SIZE 10
|
||||
|
||||
void skywallInit(primitive_t *primitive);
|
41
src/dawn/display/render.c
Normal file
41
src/dawn/display/render.c
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "render.h"
|
||||
|
||||
void renderInit() {
|
||||
// Enable GL things.
|
||||
glEnable(GL_BLEND);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
// Setup the alpha blend function.
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDepthMask(GL_TRUE);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
|
||||
glClearColor(0,0,0, 0.0);
|
||||
}
|
||||
|
||||
void renderFrameStart(render_t *render) {
|
||||
// Clear the frame buffer.
|
||||
renderResetFramebuffer(render);
|
||||
}
|
||||
|
||||
void renderDispose() {
|
||||
|
||||
}
|
||||
|
||||
void renderSetResolution(render_t *render, float width, float height) {
|
||||
render->width = width;
|
||||
render->height = height;
|
||||
}
|
||||
|
||||
void renderResetFramebuffer(render_t *render) {
|
||||
frameBufferUnbind(render->width, render->height, true);
|
||||
}
|
50
src/dawn/display/render.h
Normal file
50
src/dawn/display/render.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2021 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "framebuffer.h"
|
||||
|
||||
/**
|
||||
* Contains information about the current render state, can be used for querying
|
||||
* how the renderer is currently set up.
|
||||
*/
|
||||
typedef struct {
|
||||
/** Resolution (in pixels). Floats to allow subpixels in future. */
|
||||
float width, height;
|
||||
} render_t;
|
||||
|
||||
/**
|
||||
* Initialize the renderer.
|
||||
*/
|
||||
void renderInit();
|
||||
|
||||
/**
|
||||
* Render a single frame of the render loop. The renderer is not (currently)
|
||||
* responsible for render looping.
|
||||
* @param render The render manager
|
||||
*/
|
||||
void renderFrameStart(render_t *render);
|
||||
|
||||
/**
|
||||
* Cleanup a render context.
|
||||
*/
|
||||
void renderDispose();
|
||||
|
||||
/**
|
||||
* Sets the internal display resolution.
|
||||
*
|
||||
* @param render Render context to resize.
|
||||
* @param width Width of the display (in pixels).
|
||||
* @param height Height of the display (in pixels).
|
||||
*/
|
||||
void renderSetResolution(render_t *render, float width, float height);
|
||||
|
||||
/**
|
||||
* Reset the framebuffer back to the original backbuffer.
|
||||
*
|
||||
* @param render Render to reset the backbuffer to.
|
||||
*/
|
||||
void renderResetFramebuffer(render_t *render);
|
125
src/dawn/display/renderlist.c
Normal file
125
src/dawn/display/renderlist.c
Normal file
@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "renderlist.h"
|
||||
|
||||
void renderListInit(renderlist_t *list,int32_t width, int32_t height) {
|
||||
frameBufferInit(&list->frame, width, height);
|
||||
quadInit(&list->quad, 0, 0,0,0,0, 1,1,1,1);
|
||||
list->passCount = 0;
|
||||
}
|
||||
|
||||
renderpass_t * renderListGetPass(renderlist_t *list, uint8_t pass) {
|
||||
return list->passes + pass;
|
||||
}
|
||||
|
||||
uint8_t renderPassAdd(renderlist_t *list, shader_t *shader) {
|
||||
uint8_t i;
|
||||
renderpass_t *pass;
|
||||
|
||||
i = list->passCount++;
|
||||
pass = renderListGetPass(list, i);
|
||||
|
||||
pass->shader = shader;
|
||||
frameBufferInit(&pass->frame,
|
||||
list->frame.texture.width, list->frame.texture.height
|
||||
);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
renderpass_t * renderListRenderPass(
|
||||
renderlist_t *list, engine_t *engine, uint8_t pass
|
||||
) {
|
||||
renderpass_t *renderPass;
|
||||
|
||||
renderPass = renderListGetPass(list, pass);
|
||||
|
||||
// Bind the shader.
|
||||
frameBufferUse(&renderPass->frame, true);
|
||||
shaderUse(renderPass->shader);
|
||||
|
||||
return renderPass;
|
||||
}
|
||||
|
||||
void renderListRender(
|
||||
renderlist_t *list, shader_t *shader, shaderuniform_t *uniforms
|
||||
) {
|
||||
camera_t camera;
|
||||
int32_t i;
|
||||
renderpass_t *pass;
|
||||
|
||||
// Setup the camera
|
||||
cameraLookAt(&camera, 0,0,1, 0,0,0);
|
||||
cameraOrtho(&camera, 0,1, 0,1, 0.5f, 1.5f);
|
||||
|
||||
// Bind the framebuffer
|
||||
frameBufferUse(&list->frame, true);
|
||||
|
||||
// Set the shader
|
||||
shaderUse(shader);
|
||||
shaderUseCamera(shader, uniforms[0], uniforms[1], &camera);
|
||||
shaderUsePosition(shader, uniforms[2], 0,0,0, 0,0,0);
|
||||
|
||||
// Render each pass.
|
||||
for(i = 0; i < list->passCount; i++) {
|
||||
pass = renderListGetPass(list, i);
|
||||
shaderUseTexture(shader, uniforms[3+i], &pass->frame.texture);
|
||||
primitiveDraw(&list->quad, 0, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void renderListAsBackbuffer(
|
||||
renderlist_t *list, engine_t *engine, shader_t *shader,
|
||||
shaderuniform_t *uniforms
|
||||
) {
|
||||
camera_t camera;
|
||||
|
||||
// Reset to backbuffer
|
||||
renderResetFramebuffer(&engine->render);
|
||||
|
||||
// Setup camera to look right at teh quad.
|
||||
cameraLookAt(&camera, 0,0,1, 0,0,0);
|
||||
cameraOrtho(&camera, 0,1, 0,1, 0.5f, 1.5f);
|
||||
|
||||
// Set up the shader.
|
||||
shaderUse(shader);
|
||||
shaderUseCamera(shader, uniforms[0], uniforms[1], &camera);
|
||||
shaderUsePosition(shader, uniforms[2], 0,0,0, 0,0,0);
|
||||
shaderUseTexture(shader, uniforms[3], &list->frame.texture);
|
||||
|
||||
// Render the quad to the back buffer.
|
||||
primitiveDraw(&list->quad, 0, -1);
|
||||
}
|
||||
|
||||
void renderListResize(renderlist_t *list, int32_t width, int32_t height) {
|
||||
uint8_t i;
|
||||
|
||||
if(
|
||||
width == list->frame.texture.width &&
|
||||
height == list->frame.texture.height
|
||||
) return;
|
||||
|
||||
frameBufferDispose(&list->frame);
|
||||
frameBufferInit(&list->frame, width, height);
|
||||
|
||||
for(i = 0; i < list->passCount; i++) {
|
||||
frameBufferDispose(&list->passes[i].frame);
|
||||
frameBufferInit(&list->passes[i].frame, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void renderListDispose(renderlist_t *list) {
|
||||
uint8_t i;
|
||||
|
||||
for(i = 0; i < list->passCount; i++) {
|
||||
frameBufferDispose(&list->passes[i].frame);
|
||||
}
|
||||
|
||||
frameBufferDispose(&list->frame);
|
||||
primitiveDispose(&list->quad);
|
||||
}
|
126
src/dawn/display/renderlist.h
Normal file
126
src/dawn/display/renderlist.h
Normal file
@ -0,0 +1,126 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "framebuffer.h"
|
||||
#include "primitive/primitive.h"
|
||||
#include "shader.h"
|
||||
#include "camera.h"
|
||||
#include "../engine/engine.h"
|
||||
#include "primitive/quad.h"
|
||||
#include "../util/dynarray.h"
|
||||
#include "render.h"
|
||||
|
||||
#define RENDER_PASSES_MAX 8
|
||||
|
||||
typedef struct {
|
||||
framebuffer_t frame;
|
||||
shader_t *shader;
|
||||
} renderpass_t;
|
||||
|
||||
typedef struct {
|
||||
framebuffer_t frame;
|
||||
primitive_t quad;
|
||||
|
||||
renderpass_t passes[RENDER_PASSES_MAX];
|
||||
uint8_t passCount;
|
||||
} renderlist_t;
|
||||
|
||||
typedef struct {
|
||||
shader_t shader;
|
||||
shaderuniform_t uniformTexture;
|
||||
shaderuniform_t uniformView;
|
||||
shaderuniform_t uniformProjection;
|
||||
} renderlistbackbuffershader_t;
|
||||
|
||||
/**
|
||||
* Initialize a render pass list.
|
||||
*
|
||||
* @param list List to initialize.
|
||||
* @param width Width of the frame buffer(s).
|
||||
* @param height Height of the frame buffer(s).
|
||||
*/
|
||||
void renderListInit(renderlist_t *list, int32_t width, int32_t height);
|
||||
|
||||
/**
|
||||
* Retrieve the render pass at the given index.
|
||||
*
|
||||
* @param list List to get the pass from.
|
||||
* @param pass Render pass index to get.
|
||||
* @return The render pass at the given index.
|
||||
*/
|
||||
renderpass_t * renderListGetPass(renderlist_t *list, uint8_t pass);
|
||||
|
||||
/**
|
||||
* Adds a render pass to the render list.
|
||||
*
|
||||
* @param list Render list to add the pass to.
|
||||
* @param shader Shader to use for the render pass.
|
||||
* @return The render pass index.
|
||||
*/
|
||||
uint8_t renderPassAdd(renderlist_t *list, shader_t *shader);
|
||||
|
||||
/**
|
||||
* Prepare the rendering for a specific render pass. This will set up the
|
||||
* render pass framebuffer, shader and prepare it for rendering.
|
||||
*
|
||||
* @param list List to get the render pass from.
|
||||
* @param engine Game engine for the render pass.
|
||||
* @param pass Pass index to render.
|
||||
* @return The pointer to the render pass that is now active.
|
||||
*/
|
||||
renderpass_t * renderListRenderPass(
|
||||
renderlist_t *list, engine_t *engine, uint8_t pass
|
||||
);
|
||||
|
||||
/**
|
||||
* Render a render list. The render list will provide the sum of the textures to
|
||||
* the given shader as uniforms and then call a single render against a textured
|
||||
* quad. The given shader will need to decide how to multiply the provided
|
||||
* texture indexes.
|
||||
*
|
||||
* @param list List to render.
|
||||
* @param shader Shader to use while rendering.
|
||||
* @param uniforms Uniforms for the render list. [ view, proj, model, ...text ]
|
||||
*/
|
||||
void renderListRender(
|
||||
renderlist_t *list, shader_t *shader, shaderuniform_t *uniforms
|
||||
);
|
||||
|
||||
/**
|
||||
* Takes a previously rendered render list and renders it to the backbuffer.
|
||||
* You could do this manually, but this method makes the assumption that the
|
||||
* render list is the only thing to be rendered to the backbuffer (currently).
|
||||
*
|
||||
* @param list Render list to render to the backbuffer
|
||||
* @param engine Engine to use when rendering.
|
||||
* @param shader Shader to use to render to the backbuffer.
|
||||
* @param uniforms Uniforms for the back buffer. [ view, proj, model, text ]
|
||||
*/
|
||||
void renderListAsBackbuffer(
|
||||
renderlist_t *list, engine_t *engine, shader_t *shader,
|
||||
shaderuniform_t *uniforms
|
||||
);
|
||||
|
||||
/**
|
||||
* Resize an existing render list and all its render pass frame buffers. This
|
||||
* will dispose (and clear) the existing frame buffers for both the list and
|
||||
* each of the passes. Resizing to the same size won't cause an update to occur.
|
||||
*
|
||||
* @param list List to update.
|
||||
* @param width New render list width.
|
||||
* @param height New render list height.
|
||||
*/
|
||||
void renderListResize(renderlist_t *list, int32_t width, int32_t height);
|
||||
|
||||
/**
|
||||
* Dispose a render list entirely.
|
||||
*
|
||||
* @param list Render list to dispose.
|
||||
*/
|
||||
void renderListDispose(renderlist_t *list);
|
196
src/dawn/display/shader.c
Normal file
196
src/dawn/display/shader.c
Normal file
@ -0,0 +1,196 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Msters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "shader.h"
|
||||
|
||||
void shaderInit(shader_t *shader,
|
||||
char *vertexShaderSource, char* fragmentShaderSource
|
||||
) {
|
||||
int32_t isSuccess, maxLength, i, texture;
|
||||
char *error;
|
||||
GLuint shaderVertex, shaderFragment, shaderProgram;
|
||||
GLint size; // size of the variable
|
||||
GLsizei length; // name length
|
||||
|
||||
GLchar const* filesVertex[] = { vertexShaderSource };
|
||||
GLchar const* filesFragment[] = { fragmentShaderSource };
|
||||
|
||||
// Load the vertex shader first
|
||||
shaderVertex = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(shaderVertex, 1, filesVertex, 0);
|
||||
glCompileShader(shaderVertex);
|
||||
|
||||
// Validate
|
||||
glGetShaderiv(shaderVertex, GL_COMPILE_STATUS, &isSuccess);
|
||||
if(!isSuccess) {
|
||||
glGetShaderiv(shaderVertex, GL_INFO_LOG_LENGTH, &maxLength);
|
||||
error = malloc(maxLength);
|
||||
glGetShaderInfoLog(shaderVertex, maxLength, &maxLength, error);
|
||||
printf("Failed to compile vertex shader %s\n", error);
|
||||
free(error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Now load the Frag shader
|
||||
shaderFragment = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(shaderFragment, 1, filesFragment, 0);
|
||||
glCompileShader(shaderFragment);
|
||||
glGetShaderiv(shaderFragment, GL_COMPILE_STATUS, &isSuccess);
|
||||
if(!isSuccess) {
|
||||
glGetShaderiv(shaderFragment, GL_INFO_LOG_LENGTH, &maxLength);
|
||||
error = malloc(maxLength);
|
||||
glGetShaderInfoLog(shaderFragment, maxLength, &maxLength, error);
|
||||
printf("Failed to compile fragment shader %s\n", error);
|
||||
free(error);
|
||||
glDeleteShader(shaderVertex);
|
||||
return;
|
||||
}
|
||||
|
||||
// Now create the shader program.
|
||||
shaderProgram = glCreateProgram();
|
||||
glAttachShader(shaderProgram, shaderVertex);
|
||||
glAttachShader(shaderProgram, shaderFragment);
|
||||
|
||||
//Bind, Verify & Use the shader program
|
||||
glLinkProgram(shaderProgram);
|
||||
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &isSuccess);
|
||||
if(!isSuccess) {
|
||||
glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &maxLength);
|
||||
error = malloc(maxLength);
|
||||
glGetProgramInfoLog(shaderProgram, maxLength, &maxLength, error);
|
||||
printf("Failed to load shader program %s\n", error);
|
||||
free(error);
|
||||
glDeleteShader(shaderVertex);
|
||||
glDeleteShader(shaderFragment);
|
||||
return;
|
||||
}
|
||||
// Everything is okay, let's create the encapsulated shader.
|
||||
shader->shaderVertex = shaderVertex;
|
||||
shader->shaderFrag = shaderFragment;
|
||||
shader->shaderProgram = shaderProgram;
|
||||
|
||||
// Extract uniforms
|
||||
glGetProgramiv(shaderProgram, GL_ACTIVE_UNIFORMS, &shader->uniformCount);
|
||||
|
||||
texture = 0;
|
||||
for(i = 0; i < shader->uniformCount; i++) {
|
||||
shader->uniformNames[i] = (
|
||||
shader->uniformBuffer + (i * SHADER_UNIFORM_NAME_MAX)
|
||||
);
|
||||
|
||||
glGetActiveUniform(
|
||||
shaderProgram, (GLuint)i, SHADER_UNIFORM_NAME_MAX,
|
||||
&length, &size, shader->types + i, shader->uniformNames[i]
|
||||
);
|
||||
|
||||
// TODO: Reset uniforms to zero.
|
||||
if(shader->types[i] == GL_SAMPLER_2D) shader->textureSlots[i] = texture++;
|
||||
}
|
||||
|
||||
// Bind the shader
|
||||
shaderUse(shader);
|
||||
}
|
||||
|
||||
shaderuniform_t shaderGetUniform(shader_t *shader, char *name) {
|
||||
int32_t i;
|
||||
for(i = 0; i < shader->uniformCount; i++) {
|
||||
if(strcmp(shader->uniformNames[i], name) == 0) return i;
|
||||
}
|
||||
return (shaderuniform_t)0xFFFFFFFF;
|
||||
}
|
||||
|
||||
void shaderGetUniformArray(
|
||||
shader_t *shader, shaderuniform_t *uniformSet,
|
||||
char **uniforms, int32_t uniformCount
|
||||
) {
|
||||
int32_t i;
|
||||
for(i = 0; i < uniformCount; i++) {
|
||||
uniformSet[i] = shaderGetUniform(shader, uniforms[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void shaderDispose(shader_t *shader) {
|
||||
glDeleteProgram(shader->shaderProgram);
|
||||
glDeleteShader(shader->shaderVertex);
|
||||
glDeleteShader(shader->shaderFrag);
|
||||
}
|
||||
|
||||
void shaderUse(shader_t *shader) {
|
||||
glUseProgram(shader->shaderProgram);
|
||||
}
|
||||
|
||||
void shaderUseTexture(
|
||||
shader_t *shader, shaderuniform_t uniform, texture_t *texture
|
||||
) {
|
||||
int32_t i = shader->textureSlots[(int32_t)uniform];
|
||||
// TODO: I need to be able to get the texture ID
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glBindTexture(GL_TEXTURE_2D, texture->id);
|
||||
glUniform1i(uniform, i);
|
||||
}
|
||||
|
||||
void shaderUseMatrix(
|
||||
shader_t *shader, shaderuniform_t uniform, matrix_t *matrix
|
||||
) {
|
||||
glUniformMatrix4fv(uniform, 1, GL_FALSE, matrix->internalMatrix[0]);
|
||||
}
|
||||
|
||||
void shaderUseColor(shader_t *shader, shaderuniform_t uniform, pixel_t color) {
|
||||
glUniform4f(uniform,
|
||||
(float)color.r / 255.0f,
|
||||
(float)color.g / 255.0f,
|
||||
(float)color.b / 255.0f,
|
||||
(float)color.a / 255.0f
|
||||
);
|
||||
}
|
||||
|
||||
void shaderUsePosition(
|
||||
shader_t *shader, shaderuniform_t uniform,
|
||||
float x, float y, float z,
|
||||
float pitch, float yaw, float roll
|
||||
) {
|
||||
matrix_t matrix;
|
||||
|
||||
matrixIdentity(&matrix);
|
||||
matrixTranslate(&matrix, x, y, z);
|
||||
|
||||
// Rotation (YZX order)
|
||||
matrixRotate(&matrix, yaw, 0, 1, 0);
|
||||
matrixRotate(&matrix, roll, 0, 0, 1);
|
||||
matrixRotate(&matrix, pitch, 1, 0, 0);
|
||||
shaderUseMatrix(shader, uniform, &matrix);
|
||||
}
|
||||
|
||||
void shaderUsePositionAndScale(
|
||||
shader_t *shader, shaderuniform_t uniform,
|
||||
float x, float y, float z,
|
||||
float pitch, float yaw, float roll,
|
||||
float scaleX, float scaleY, float scaleZ
|
||||
) {
|
||||
matrix_t matrix;
|
||||
|
||||
matrixIdentity(&matrix);
|
||||
matrixTranslate(&matrix, x, y, z);
|
||||
|
||||
// Rotation (YZX order)
|
||||
matrixRotate(&matrix, yaw, 0, 1, 0);
|
||||
matrixRotate(&matrix, roll, 0, 0, 1);
|
||||
matrixRotate(&matrix, pitch, 1, 0, 0);
|
||||
|
||||
matrixScale(&matrix, scaleX, scaleY, scaleZ);
|
||||
|
||||
shaderUseMatrix(shader, uniform, &matrix);
|
||||
}
|
||||
|
||||
void shaderUseCamera(
|
||||
shader_t *shader,
|
||||
shaderuniform_t uniformView, shaderuniform_t uniformProjection,
|
||||
camera_t *camera
|
||||
) {
|
||||
shaderUseMatrix(shader, uniformView, &camera->view);
|
||||
shaderUseMatrix(shader, uniformProjection, &camera->projection);
|
||||
}
|
178
src/dawn/display/shader.h
Normal file
178
src/dawn/display/shader.h
Normal file
@ -0,0 +1,178 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Msters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <dawn/libs.h>
|
||||
#include "matrix.h"
|
||||
#include "camera.h"
|
||||
#include "texture.h"
|
||||
#include "../util/array.h"
|
||||
|
||||
#define SHADER_UNIFORM_NAME_MAX 24
|
||||
#define SHADER_UNIFORM_COUNT 16
|
||||
|
||||
/** Representation of a shader uniform */
|
||||
typedef GLuint shaderuniform_t;
|
||||
|
||||
/**
|
||||
* Structure containing information about an OpenGL Shader. For simplicity sake
|
||||
* we demand certain uninforms to be present on the shader target.
|
||||
*/
|
||||
typedef struct {
|
||||
/** Pointer to an uploaded vertex shader program */
|
||||
GLuint shaderVertex;
|
||||
|
||||
/** Pointer to an uploaded fragment shader program */
|
||||
GLuint shaderFrag;
|
||||
|
||||
/** Pointer to an uploaded shader program linked */
|
||||
GLuint shaderProgram;
|
||||
|
||||
/** Buffer of chars where we store the uniform names */
|
||||
char uniformBuffer[SHADER_UNIFORM_NAME_MAX * SHADER_UNIFORM_COUNT];
|
||||
|
||||
/** Array of strings (pointers to the above buffer) of the uniform names */
|
||||
char *uniformNames[SHADER_UNIFORM_COUNT];
|
||||
int32_t uniformCount;
|
||||
|
||||
/** Type of each uniform */
|
||||
GLenum types[SHADER_UNIFORM_COUNT];
|
||||
|
||||
/** Texture Slots (which texture slot for GL to use for each uniform) */
|
||||
uint8_t textureSlots[SHADER_UNIFORM_COUNT];
|
||||
} shader_t;
|
||||
|
||||
/**
|
||||
* Compiles a shader from vertex and fragment shader code.
|
||||
* @param shader Shader to compile into.
|
||||
* @param vertexShaderSource The raw vertex shader code.
|
||||
* @param fragmentShaderSource The raw fragment shader code.
|
||||
*/
|
||||
void shaderInit(shader_t *shader,
|
||||
char *vertexShaderSource, char* fragmentShaderSource
|
||||
);
|
||||
|
||||
/**
|
||||
* Return the shaderuniform_t for a given shader uniform name.
|
||||
*
|
||||
* @param shader Shader to get from
|
||||
* @param name Name to look for
|
||||
* @return The shader uniform, or -1 if not found.
|
||||
*/
|
||||
shaderuniform_t shaderGetUniform(shader_t *shader, char *name);
|
||||
|
||||
/**
|
||||
* Return an array of shaderuniform_t's into an array for a given string array.
|
||||
*
|
||||
* @param shader Shader to get the uniforms from.
|
||||
* @param uniformSet Uniform array to get.
|
||||
* @param uniforms Uniform strings to get.
|
||||
* @param uniformCount Count of uniforms you're getting.
|
||||
*/
|
||||
void shaderGetUniformArray(
|
||||
shader_t *shader, shaderuniform_t *uniformSet,
|
||||
char **uniforms, int32_t uniformCount
|
||||
);
|
||||
|
||||
/**
|
||||
* Cleanup and unload a previously loaded shader.
|
||||
* @param shader The shader to unload
|
||||
*/
|
||||
void shaderDispose(shader_t *shader);
|
||||
|
||||
/**
|
||||
* Attaches the supplied shader as the current shader.
|
||||
* @param shader The shader to attach
|
||||
*/
|
||||
void shaderUse(shader_t *shader);
|
||||
|
||||
/**
|
||||
* Attaches a texture to the shader.
|
||||
*
|
||||
* @param shader Shader to attach to.
|
||||
* @param uniform Uniform on the shader to set.
|
||||
* @param texture Texture to attach.
|
||||
*/
|
||||
void shaderUseTexture(
|
||||
shader_t *shader, shaderuniform_t uniform, texture_t *texture
|
||||
);
|
||||
|
||||
/**
|
||||
* Set's a specific shader uniform to a matrix.
|
||||
*
|
||||
* @param shader Shader to apply to.
|
||||
* @param uniform Uniform on the shader to set.
|
||||
* @param matrix Matrix to apply.
|
||||
*/
|
||||
void shaderUseMatrix(
|
||||
shader_t *shader, shaderuniform_t uniform, matrix_t *matrix
|
||||
);
|
||||
|
||||
/**
|
||||
* Set's a specific shader uniform to a color.
|
||||
*
|
||||
* @param shader Shader to apply to.
|
||||
* @param uniform Uniform on the shader to set.
|
||||
* @param color Color to set on to the uniform.
|
||||
*/
|
||||
void shaderUseColor(shader_t *shader, shaderuniform_t uniform, pixel_t color);
|
||||
|
||||
/**
|
||||
* Set's the current translation matrix onto the shader for the next
|
||||
* render to use. Rotation order is set to YZX.
|
||||
*
|
||||
* @param shader Shader to attach to.
|
||||
* @param uniform Uniform on the shader to set.
|
||||
* @param x X coordinate (world space).
|
||||
* @param y Y coordinate (world space).
|
||||
* @param z Z coordinate (world space).
|
||||
* @param pitch Pitch of the object (local space).
|
||||
* @param yaw Yaw of the object (local space).
|
||||
* @param roll Roll of the object (local space).
|
||||
*/
|
||||
void shaderUsePosition(
|
||||
shader_t *shader, shaderuniform_t uniform,
|
||||
float x, float y, float z,
|
||||
float pitch, float yaw, float roll
|
||||
);
|
||||
|
||||
/**
|
||||
* Set's the current translation matrix onto the shader for the next
|
||||
* render to use. Also provides scaling controls.
|
||||
*
|
||||
* @param shader Shader to attach to.
|
||||
* @param uniform Uniform on the shader to set.
|
||||
* @param x X coordinate (world space).
|
||||
* @param y Y coordinate (world space).
|
||||
* @param z Z coordinate (world space).
|
||||
* @param pitch Pitch of the object (local space).
|
||||
* @param yaw Yaw of the object (local space).
|
||||
* @param roll Roll of the object (local space).
|
||||
* @param scaleX X scale of model (1 being 100% scaled).
|
||||
* @param scaleY Y scale of model (1 being 100% scaled).
|
||||
* @param scaleZ Z scale of model (1 being 100% scaled).
|
||||
*/
|
||||
void shaderUsePositionAndScale(
|
||||
shader_t *shader, shaderuniform_t uniform,
|
||||
float x, float y, float z,
|
||||
float pitch, float yaw, float roll,
|
||||
float scaleX, float scaleY, float scaleZ
|
||||
);
|
||||
|
||||
/**
|
||||
* Attaches a camera to the shader.
|
||||
*
|
||||
* @param shader Shader to attach to.
|
||||
* @param uniformView Shader Uniform for the view matrix.
|
||||
* @param uniformProjection Shader Uniform for the view matrix.
|
||||
* @param camera Camera to attach.
|
||||
*/
|
||||
void shaderUseCamera(
|
||||
shader_t *shader,
|
||||
shaderuniform_t uniformView, shaderuniform_t uniformProjection,
|
||||
camera_t *camera
|
||||
);
|
49
src/dawn/display/spritebatch.c
Normal file
49
src/dawn/display/spritebatch.c
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "spritebatch.h"
|
||||
|
||||
void spriteBatchInit(spritebatch_t *batch, int32_t maxSprites) {
|
||||
batch->maxSprites = maxSprites;
|
||||
batch->currentSprite = 0;
|
||||
|
||||
primitiveInit(&batch->primitive,
|
||||
maxSprites*QUAD_VERTICE_COUNT, maxSprites*QUAD_INDICE_COUNT
|
||||
);
|
||||
}
|
||||
|
||||
void spriteBatchQuad(spritebatch_t *spriteBatch, int32_t index,
|
||||
float x, float y, float z, float width, float height,
|
||||
float u0, float v0, float u1, float v1
|
||||
) {
|
||||
if(index == -1) {
|
||||
index = spriteBatch->currentSprite++;
|
||||
} else {
|
||||
spriteBatch->currentSprite = mathMax(index, spriteBatch->currentSprite);
|
||||
}
|
||||
|
||||
quadBuffer(&spriteBatch->primitive, z,
|
||||
x, y, u0, v0,
|
||||
x+width, y+height, u1, v1,
|
||||
index*QUAD_VERTICE_COUNT, index*QUAD_INDICE_COUNT
|
||||
);
|
||||
}
|
||||
|
||||
void spriteBatchFlush(spritebatch_t *spriteBatch) {
|
||||
spriteBatch->currentSprite = 0;
|
||||
}
|
||||
|
||||
void spriteBatchDraw(spritebatch_t *spriteBatch, int32_t index, int32_t count) {
|
||||
if(count == -1) count = spriteBatch->currentSprite;
|
||||
primitiveDraw(&spriteBatch->primitive,
|
||||
index*QUAD_INDICE_COUNT, count*QUAD_INDICE_COUNT
|
||||
);
|
||||
}
|
||||
|
||||
void spriteBatchDispose(spritebatch_t *spriteBatch) {
|
||||
primitiveDispose(&spriteBatch->primitive);
|
||||
}
|
71
src/dawn/display/spritebatch.h
Normal file
71
src/dawn/display/spritebatch.h
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2021 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/math.h"
|
||||
#include "primitive/primitive.h"
|
||||
#include "primitive/quad.h"
|
||||
|
||||
/** Definition of a Sprite Batch. */
|
||||
typedef struct {
|
||||
/** Maximum sprites the batch can hold. */
|
||||
int32_t maxSprites;
|
||||
|
||||
/** The current/next sprite index. */
|
||||
int32_t currentSprite;
|
||||
|
||||
/** Internal primitive */
|
||||
primitive_t primitive;
|
||||
} spritebatch_t;
|
||||
|
||||
/**
|
||||
* Creates a new Sprite Batch made of standard quads.
|
||||
*
|
||||
* @param batch Sprite batch to init.
|
||||
* @param maxSprites The maxiumum number of sprites the batch can hold.
|
||||
*/
|
||||
void spriteBatchInit(spritebatch_t *batch, int32_t maxSprites);
|
||||
|
||||
/**
|
||||
* Renders a sprite onto a given Sprite Batch.
|
||||
*
|
||||
* @param spriteBatch The sprite batch to render to.
|
||||
* @param index The index within the sprite batch. Set to -1 to select "next".
|
||||
* @param x X coordinate of the sprite.
|
||||
* @param y Y coordinate of the sprite.
|
||||
* @param width Width of the sprite.
|
||||
* @param height Height of the sprite.
|
||||
* @param u0 Texture U coordinate (min).
|
||||
* @param v0 Texture V coordinate (min).
|
||||
* @param u1 Texture U coordinate (max).
|
||||
* @param v1 Texture V coordinate (max).
|
||||
*/
|
||||
void spriteBatchQuad(spritebatch_t *spriteBatch, int32_t index,
|
||||
float x, float y, float z, float width, float height,
|
||||
float u0, float v0, float u1, float v1
|
||||
);
|
||||
|
||||
/**
|
||||
* Flushes a sprite batch to reset the indexes.
|
||||
* @param spriteBatch The batch.
|
||||
*/
|
||||
void spriteBatchFlush(spritebatch_t *spriteBatch);
|
||||
|
||||
/**
|
||||
* Draws the Sprite Batch.
|
||||
*
|
||||
* @param spriteBatch The sprite batch to render.
|
||||
* @param start Start index to render from.
|
||||
* @param count Count of sprites to render. Set to -1 to render to the current.
|
||||
*/
|
||||
void spriteBatchDraw(spritebatch_t *spriteBatch, int32_t start, int32_t count);
|
||||
|
||||
/**
|
||||
* Disposes a previously created Sprite Batch.
|
||||
*
|
||||
* @param spriteBatch The sprite batch to dispose.
|
||||
*/
|
||||
void spriteBatchDispose(spritebatch_t *spriteBatch);
|
64
src/dawn/display/texture.c
Normal file
64
src/dawn/display/texture.c
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "texture.h"
|
||||
|
||||
// Due to some compiler bullshit, this is here.
|
||||
#ifndef STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
#endif
|
||||
|
||||
void textureInit(texture_t *texture, int32_t width, int32_t height,
|
||||
pixel_t *pixels
|
||||
) {
|
||||
texture->width = width;
|
||||
texture->height = height;
|
||||
|
||||
// Generate a texture ID and bind.
|
||||
glGenTextures(1, &texture->id);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture->id);
|
||||
|
||||
// Setup our preferred texture params
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// Start by buffering all transparent black pixels.
|
||||
if(pixels == NULL) {
|
||||
// TODO: I can optimize this, I think the GPU can default this somehow
|
||||
pixels = calloc(width * height, sizeof(pixel_t));
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, pixels
|
||||
);
|
||||
free(pixels);
|
||||
} else {
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, pixels
|
||||
);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
void textureBufferPixels(texture_t *texture,
|
||||
int32_t x, int32_t y, int32_t width, int32_t height, pixel_t *pixels
|
||||
) {
|
||||
glBindTexture(GL_TEXTURE_2D, texture->id);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0,
|
||||
x, y, width, height,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, pixels
|
||||
);
|
||||
}
|
||||
|
||||
void textureDispose(texture_t *texture) {
|
||||
glDeleteTextures(1, &texture->id);
|
||||
}
|
68
src/dawn/display/texture.h
Normal file
68
src/dawn/display/texture.h
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2021 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
|
||||
/**
|
||||
* Structure detailing information about a texture.
|
||||
* Because we plan to upload the pixels of a texture into the GPU, we don't
|
||||
* store the pixels in memory because we don't need to!
|
||||
*/
|
||||
typedef struct {
|
||||
/** Width (in pixels) of the texture */
|
||||
int32_t width;
|
||||
/** Height (in pixels) of the texture */
|
||||
int32_t height;
|
||||
/** Texture ID on the GPU */
|
||||
GLuint id;
|
||||
} texture_t;
|
||||
|
||||
/** Information about a single pixel. */
|
||||
typedef struct {
|
||||
/** RGBA Color values */
|
||||
uint8_t r, g, b, a;
|
||||
} pixel_t;
|
||||
|
||||
#define PIXEL_COLOR_WHITE ((pixel_t){ .r = 255, .g = 255, .b = 255, .a = 255 })
|
||||
#define PIXEL_COLOR_RED ((pixel_t){ .r = 255, .g = 0, .b = 0, .a = 255 })
|
||||
#define PIXEL_COLOR_GREEN ((pixel_t){ .r = 0, .g = 255, .b = 0, .a = 255 })
|
||||
#define PIXEL_COLOR_BLUE ((pixel_t){ .r = 0, .g = 0, .b = 255, .a = 255 })
|
||||
#define PIXEL_COLOR_BLACK ((pixel_t){ .r = 0, .g = 0, .b = 0, .a = 255 })
|
||||
#define PIXEL_COLOR_TRANSPARENT ((pixel_t){ .r = 0, .g = 0, .b = 0, .a = 0 })
|
||||
|
||||
/**
|
||||
* Initializes a texture that can be written in to.
|
||||
*
|
||||
* @param texture Texture to initialize.
|
||||
* @param width Width of the texture (in pixels).
|
||||
* @param height Height of the texture (in pixels).
|
||||
* @param pixels Default pixel array, set to NULL to set all pixel data to 0.
|
||||
*/
|
||||
void textureInit(texture_t *texture, int32_t width, int32_t height,
|
||||
pixel_t *pixels
|
||||
);
|
||||
|
||||
/**
|
||||
* Buffer pixel data onto the GPU. Pixel buffering is rather costly so avoid
|
||||
* doing this too often.
|
||||
*
|
||||
* @param texture Texture to buffer in to.
|
||||
* @param x X coordinate in texture space to render to.
|
||||
* @param y Y coordinate in texture space to render to.
|
||||
* @param width Width of the pixel region you're buffering.
|
||||
* @param height Height of the pixel region you're buffering.
|
||||
* @param pixels Array of pixels to buffer onto the GPU.
|
||||
*/
|
||||
void textureBufferPixels(texture_t *texture,
|
||||
int32_t x, int32_t y, int32_t width, int32_t height, pixel_t *pixels
|
||||
);
|
||||
|
||||
/**
|
||||
* Clean a previously created texture.
|
||||
*
|
||||
* @param texture Texture to clean up.
|
||||
*/
|
||||
void textureDispose(texture_t *texture);
|
29
src/dawn/display/texturescale.h
Normal file
29
src/dawn/display/texturescale.h
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "texture.h"
|
||||
|
||||
#define MANAGED_TEXTURE_SCALE_MAX 4
|
||||
|
||||
typedef struct {
|
||||
int16_t width;
|
||||
int16_t height;
|
||||
uint8_t scale;
|
||||
} texturescalescale_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t channels;
|
||||
char *file;
|
||||
char *path;
|
||||
int16_t baseWidth;
|
||||
int16_t baseHeight;
|
||||
|
||||
texturescalescale_t scales[MANAGED_TEXTURE_SCALE_MAX];
|
||||
uint8_t scaleCount;
|
||||
} texturescale_t;
|
62
src/dawn/display/tileset.c
Normal file
62
src/dawn/display/tileset.c
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "tileset.h"
|
||||
|
||||
void tilesetInit(tileset_t *tileset,
|
||||
int32_t columns, int32_t rows,
|
||||
int32_t width, int32_t height,
|
||||
int32_t gapX, int32_t gapY,
|
||||
int32_t borderX, int32_t borderY
|
||||
) {
|
||||
float tdivX, tdivY;
|
||||
int32_t x, y, i;
|
||||
|
||||
tileset->count = rows * columns;
|
||||
tileset->divisions = malloc(sizeof(tilesetdiv_t) * tileset->count);
|
||||
|
||||
tileset->columns = columns;
|
||||
tileset->rows = rows;
|
||||
|
||||
// Calculate division sizes (pixels)
|
||||
tileset->divX = (
|
||||
(float)width - ((float)borderX * 2.0f) - ((float)gapX * ((float)columns-1))
|
||||
) / columns;
|
||||
tileset->divY = (
|
||||
(float)height - ((float)borderY * 2.0f) - ((float)gapY * ((float)rows - 1))
|
||||
) / rows;
|
||||
|
||||
// Calculate the division sizes (units)
|
||||
tdivX = tileset->divX / width;
|
||||
tdivY = tileset->divY / height;
|
||||
|
||||
// Calculate the divisions (in units)
|
||||
i = -1;
|
||||
for(y = 0; y < rows; y++) {
|
||||
for(x = 0; x < columns; x++) {
|
||||
tileset->divisions[++i].x0 = (
|
||||
borderX + (tileset->divX * x) + (gapX * x)
|
||||
) / width;
|
||||
tileset->divisions[i].x1 = tileset->divisions[i].x0 + tdivX;
|
||||
|
||||
tileset->divisions[i].y0 = (
|
||||
borderY + (tileset->divY * y) + (gapY * y)
|
||||
) / height;
|
||||
tileset->divisions[i].y1 = tileset->divisions[i].y0 + tdivY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tilesetdiv_t tilesetGetDivision(tileset_t *tileset,int32_t column,int32_t row) {
|
||||
return tileset->divisions[
|
||||
(column % tileset->columns) + (row * tileset->columns)
|
||||
];
|
||||
}
|
||||
|
||||
void tilesetDispose(tileset_t *tileset) {
|
||||
free(tileset->divisions);
|
||||
}
|
64
src/dawn/display/tileset.h
Normal file
64
src/dawn/display/tileset.h
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2021 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
|
||||
/** Division of a texture */
|
||||
typedef struct {
|
||||
float x0, y0, x1, y1;
|
||||
} tilesetdiv_t;
|
||||
|
||||
/** Definition of a Tileset */
|
||||
typedef struct {
|
||||
/** Count of X/Y divisions */
|
||||
int32_t columns, rows;
|
||||
|
||||
/** Size of each divison (in pixels) */
|
||||
float divX, divY;
|
||||
|
||||
/** Count of divisions (unused) */
|
||||
int32_t count;
|
||||
|
||||
/** Division information */
|
||||
tilesetdiv_t *divisions;
|
||||
} tileset_t;
|
||||
|
||||
/**
|
||||
* Create a tileset. Tilesets will be pre-divided to save performance later.
|
||||
*
|
||||
* @param tileset Tileset to init into.
|
||||
* @param columns Count of columns.
|
||||
* @param rows Count of rows.
|
||||
* @param width Width of the tileset.
|
||||
* @param height Height of the tileset.
|
||||
* @param gapX Space between each column.
|
||||
* @param gapY Space between each row.
|
||||
* @param borderX Space around the edge of the tileset.
|
||||
* @param borderY Space around the edge of the tileset.
|
||||
*/
|
||||
void tilesetInit(tileset_t *tileset,
|
||||
int32_t columns, int32_t rows,
|
||||
int32_t width, int32_t height,
|
||||
int32_t gapX, int32_t gapY,
|
||||
int32_t borderX, int32_t borderY
|
||||
);
|
||||
|
||||
/**
|
||||
* Retreive the division for a given tileset coordinate.
|
||||
*
|
||||
* @param tileset Tileset to retreive from.
|
||||
* @param column X axis of the tileset.
|
||||
* @param row Y axis of the tileset.
|
||||
* @returns The Tileset division.
|
||||
*/
|
||||
tilesetdiv_t tilesetGetDivision(tileset_t *tileset,int32_t column, int32_t row);
|
||||
|
||||
/**
|
||||
* Cleans a previously created tileset
|
||||
*
|
||||
* @param tileset Cleanup the tileset.
|
||||
*/
|
||||
void tilesetDispose(tileset_t *tileset);
|
12
src/dawn/engine/client.c
Normal file
12
src/dawn/engine/client.c
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
|
||||
void clientInit(client_t *client) {
|
||||
client->setTitle = NULL;
|
||||
}
|
23
src/dawn/engine/client.h
Normal file
23
src/dawn/engine/client.h
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
|
||||
/** Callback to set the window title */
|
||||
typedef void clientsettitle_t(char *string);
|
||||
|
||||
typedef struct {
|
||||
clientsettitle_t *setTitle;
|
||||
} client_t;
|
||||
|
||||
/**
|
||||
* Initialize the client to its default state.
|
||||
*
|
||||
* @param client Client to initialize.
|
||||
*/
|
||||
void clientInit(client_t *client);
|
48
src/dawn/engine/engine.c
Normal file
48
src/dawn/engine/engine.c
Normal file
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "engine.h"
|
||||
|
||||
void engineInit(engine_t *engine) {
|
||||
randSeed(123);
|
||||
|
||||
#if defined(GAME_NAME)
|
||||
engine->name = GAME_NAME;
|
||||
#else
|
||||
engine->name = "Dawn";
|
||||
#endif
|
||||
|
||||
clientInit(&engine->client);
|
||||
epochInit(&engine->time);
|
||||
renderInit();
|
||||
inputInit(&engine->input);
|
||||
|
||||
assetManagerInit(&engine->assetManager);
|
||||
assetManagerStart(&engine->assetManager);
|
||||
}
|
||||
|
||||
void engineUpdateStart(engine_t *engine, float delta) {
|
||||
epochUpdate(&engine->time, delta);
|
||||
inputUpdate(&engine->input);
|
||||
assetManagerUpdate(&engine->assetManager);
|
||||
|
||||
renderFrameStart(&engine->render);
|
||||
}
|
||||
|
||||
bool engineUpdateEnd(engine_t *engine) {
|
||||
if(inputIsPressed(&engine->input, INPUT_NULL)) {
|
||||
printf("Game exit requested\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void engineDispose(engine_t *engine) {
|
||||
assetManagerDispose(&engine->assetManager);
|
||||
inputDispose(&engine->input);
|
||||
renderDispose();
|
||||
}
|
69
src/dawn/engine/engine.h
Normal file
69
src/dawn/engine/engine.h
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "client.h"
|
||||
#include "../util/rand.h"
|
||||
#include "../input/input.h"
|
||||
#include "../epoch/epoch.h"
|
||||
#include "../display/render.h"
|
||||
#include "../file/assetmanager.h"
|
||||
|
||||
// #if !defined(GAME_NAME)
|
||||
// #error You need to define the GAME_NAME string
|
||||
// #endif
|
||||
|
||||
typedef struct {
|
||||
/** Name of the game */
|
||||
char *name;
|
||||
|
||||
/** Time Manager for the game */
|
||||
epoch_t time;
|
||||
|
||||
/** Render Manager for the game */
|
||||
render_t render;
|
||||
|
||||
/** Asset Manager for the game */
|
||||
assetmanager_t assetManager;
|
||||
|
||||
/** Input Manager for the game */
|
||||
input_t input;
|
||||
|
||||
/** Game client information */
|
||||
client_t client;
|
||||
} engine_t;
|
||||
|
||||
/**
|
||||
* Initializes the provided engine. This will initialize all of the various
|
||||
* managers for the game to use.
|
||||
*
|
||||
* @param engine Engine to initialize.
|
||||
*/
|
||||
void engineInit(engine_t *engine);
|
||||
|
||||
/**
|
||||
* Updates the given engine at the start of a frame.
|
||||
*
|
||||
* @param engine Engine that is being updated
|
||||
* @param delta Delta tick provided by the game's platform.
|
||||
*/
|
||||
void engineUpdateStart(engine_t *engine, float delta);
|
||||
|
||||
/**
|
||||
* Updates the given engine at the end of a frame.
|
||||
*
|
||||
* @param engine Engine to update.
|
||||
*/
|
||||
bool engineUpdateEnd(engine_t *engine);
|
||||
|
||||
/**
|
||||
* Cleanup the engine context.
|
||||
*
|
||||
* @param engine Engine to clean up.
|
||||
*/
|
||||
void engineDispose(engine_t *engine);
|
45
src/dawn/engine/thread.c
Normal file
45
src/dawn/engine/thread.c
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "thread.h"
|
||||
|
||||
void threadInit(thread_t *thread, threadfunction_t *call) {
|
||||
thread->call = call;
|
||||
thread->user = NULL;
|
||||
thread->state = 0x00;
|
||||
}
|
||||
|
||||
void threadStart(thread_t *thread) {
|
||||
thread->state |= THREAD_FLAG_QUEUED;
|
||||
sysThreadCreate(&_threadWrappedCallback, thread->pt, thread);
|
||||
}
|
||||
|
||||
void threadJoin(thread_t *thread) {
|
||||
sysThreadJoin(thread->pt);
|
||||
}
|
||||
|
||||
void threadCancel(thread_t *thread) {
|
||||
sysThreadCancel(thread->pt, 1);
|
||||
}
|
||||
|
||||
void threadSleep(float time) {
|
||||
sleep((unsigned long)(time * 1000.0f));
|
||||
}
|
||||
|
||||
int32_t _threadWrappedCallback(thread_t *thread) {
|
||||
int32_t response;
|
||||
|
||||
flagOff(thread->state, THREAD_FLAG_QUEUED);
|
||||
thread->state |= THREAD_FLAG_RUNNING;
|
||||
|
||||
response = thread->call(thread);
|
||||
|
||||
thread->state |= THREAD_FLAG_HAS_RUN;
|
||||
flagOff(thread->state, THREAD_FLAG_RUNNING);
|
||||
|
||||
return response;
|
||||
}
|
72
src/dawn/engine/thread.h
Normal file
72
src/dawn/engine/thread.h
Normal file
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/flags.h"
|
||||
|
||||
typedef struct _thread_t thread_t;
|
||||
|
||||
#define THREAD_FLAG_RUNNING flagDefine(0)
|
||||
#define THREAD_FLAG_QUEUED flagDefine(1)
|
||||
#define THREAD_FLAG_HAS_RUN flagDefine(2)
|
||||
|
||||
/**
|
||||
* Thread function itself.
|
||||
*
|
||||
* @param thread Thread that was called.
|
||||
* @return The exit code, try to ensure only 0 is possible.
|
||||
*/
|
||||
typedef int32_t threadfunction_t(thread_t *thread);
|
||||
|
||||
typedef struct _thread_t {
|
||||
threadhandle_t pt;
|
||||
void *user;
|
||||
uint8_t state;
|
||||
threadfunction_t *call;
|
||||
} thread_t;
|
||||
|
||||
/**
|
||||
* Initialize a thread, prepare it to be started. You need to manually start it
|
||||
* yourself.
|
||||
*
|
||||
* @param thread Thread pointer to maintain.
|
||||
* @param call User callback to fire when the thread is started.
|
||||
*/
|
||||
void threadInit(thread_t *thread, threadfunction_t *call);
|
||||
|
||||
/**
|
||||
* Start a previously prepared thread.
|
||||
*
|
||||
* @param thread Thread to start.
|
||||
*/
|
||||
void threadStart(thread_t *thread);
|
||||
|
||||
/**
|
||||
* Wait for the given thread to finish execution.
|
||||
*
|
||||
* @param thread Thread to join.
|
||||
*/
|
||||
void threadJoin(thread_t *thread);
|
||||
|
||||
/**
|
||||
* Cancel a running thread, avoid using where possible incase of any undefined
|
||||
* behaviour.
|
||||
*
|
||||
* @param thread Thread to cancel.
|
||||
*/
|
||||
void threadCancel(thread_t *thread);
|
||||
|
||||
/**
|
||||
* Sleep the current thread.
|
||||
*
|
||||
* @param time Time in seconds to sleep for.
|
||||
*/
|
||||
void threadSleep(float time);
|
||||
|
||||
/** Managing function for thread to help update the state */
|
||||
int32_t _threadWrappedCallback(thread_t *thread);
|
23
src/dawn/epoch/epoch.c
Normal file
23
src/dawn/epoch/epoch.c
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "epoch.h"
|
||||
|
||||
void epochInit(epoch_t *epoch) {
|
||||
epoch->delta = EPOCH_FIXED_STEP;
|
||||
epoch->last = EPOCH_FIXED_STEP;
|
||||
epoch->current = EPOCH_FIXED_STEP + EPOCH_FIXED_STEP;
|
||||
}
|
||||
|
||||
void epochUpdate(epoch_t *epoch, float platformDelta) {
|
||||
platformDelta = mathClamp(platformDelta, 0, EPOCH_FIXED_STEP);
|
||||
|
||||
epoch->last = epoch->current;
|
||||
epoch->current = epoch->current + platformDelta;
|
||||
epoch->delta = epoch->current - epoch->last;
|
||||
epoch->fixedDelta = EPOCH_FIXED_STEP;
|
||||
}
|
58
src/dawn/epoch/epoch.h
Normal file
58
src/dawn/epoch/epoch.h
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/math.h"
|
||||
|
||||
#define EPOCH_FIXED_STEP 0.016f
|
||||
#define EPOCH_SMALLEST_STEP 0.001f
|
||||
|
||||
typedef struct {
|
||||
/**
|
||||
* Current time (as a float of seconds since game start).
|
||||
*
|
||||
* When time is initialized this will start at a fixed value of 2/60ths of a
|
||||
* second, regardless of what engine the game is running.
|
||||
*
|
||||
* This is to avoid any divide by zero errors.
|
||||
*/
|
||||
float current;
|
||||
|
||||
/**
|
||||
* Last Time (as a float of seconds since the game start).
|
||||
*
|
||||
* This value will start at 1/60th of a second regardless of engine the game
|
||||
* is running on to avoid divide by zero errors.
|
||||
*/
|
||||
float last;
|
||||
|
||||
/**
|
||||
* Varying timestep that occured since the last frame.
|
||||
*/
|
||||
float delta;
|
||||
|
||||
/**
|
||||
* Fixed timestep that is not affected by framerate but remains consistent.
|
||||
*/
|
||||
float fixedDelta;
|
||||
} epoch_t;
|
||||
|
||||
/**
|
||||
* Initializes the epoch time tracking.
|
||||
*
|
||||
* @param epoch Epoch to initialize.
|
||||
*/
|
||||
void epochInit(epoch_t *epoch);
|
||||
|
||||
/**
|
||||
* Ticks the current epoch time.
|
||||
*
|
||||
* @param epoch Epoch to update.
|
||||
* @param platformDelta The delta step between frames from the platform engine.
|
||||
*/
|
||||
void epochUpdate(epoch_t *epoch, float platformDelta);
|
104
src/dawn/file/asset.c
Normal file
104
src/dawn/file/asset.c
Normal file
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Msters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "asset.h"
|
||||
|
||||
size_t assetRawLoad(char *assetName, uint8_t *buffer) {
|
||||
assetbuffer_t *asset;
|
||||
size_t length, read;
|
||||
|
||||
// Open a buffer.
|
||||
asset = assetBufferOpen(assetName);
|
||||
if(asset == NULL) return 0;
|
||||
|
||||
// Read the count of bytes in the file
|
||||
assetBufferEnd(asset);
|
||||
length = assetBufferGetCurrentPosition(asset);// Get our current position (the end)
|
||||
|
||||
// Are we only reading the size?
|
||||
if(buffer == NULL) {
|
||||
assetBufferClose(asset);
|
||||
return length;
|
||||
}
|
||||
|
||||
// Reset to start
|
||||
assetBufferStart(asset);
|
||||
|
||||
// Read and seal the string.
|
||||
read = assetBufferRead(asset, buffer, length);
|
||||
assetBufferClose(asset); // Close the buffer.
|
||||
|
||||
// Did we read successfully?
|
||||
if(read < length) return 0;
|
||||
return read;
|
||||
}
|
||||
|
||||
char * assetStringLoad(char *assetName) {
|
||||
size_t length;
|
||||
char *string;
|
||||
|
||||
length = assetRawLoad(assetName, NULL);
|
||||
if(length == 0) return NULL;
|
||||
|
||||
string = malloc(length + 1);// +1 for null terminator
|
||||
if(string == NULL) return NULL;
|
||||
|
||||
length = assetRawLoad(assetName, string);
|
||||
if(length == 0) {
|
||||
free(string);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
string[length] = '\0';// Null terminate
|
||||
return string;
|
||||
}
|
||||
|
||||
assetbuffer_t * assetBufferOpen(char *assetName) {
|
||||
// Get the directory based on the raw input by creating a new string.
|
||||
FILE *fptr;
|
||||
char filename[512];
|
||||
|
||||
// Prep filename
|
||||
filename[0] = '\0';//Start at null
|
||||
strcat(filename, ASSET_PREFIX);//Add prefix
|
||||
strcat(filename, assetName);//Add body
|
||||
|
||||
printf("Opening up %s\n", filename);
|
||||
|
||||
// Open the file pointer now.
|
||||
fptr = fopen(filename, "rb");
|
||||
if(fptr == NULL) {
|
||||
printf("Error opening %s: %s\n", filename, strerror(errno));
|
||||
return NULL;// File available?
|
||||
}
|
||||
return (assetbuffer_t *)fptr;
|
||||
}
|
||||
|
||||
bool assetBufferClose(assetbuffer_t *buffer) {
|
||||
return fclose((FILE *)buffer);
|
||||
}
|
||||
|
||||
int32_t assetBufferRead(assetbuffer_t *buffer, char *data, size_t size) {
|
||||
return (int32_t)fread(data, 1, size, (FILE *)buffer);
|
||||
}
|
||||
|
||||
int32_t assetBufferEnd(assetbuffer_t *buffer) {
|
||||
// return feof((FILE *)buffer);
|
||||
return fseek((FILE *)buffer, 0, SEEK_END);// Seek to the end
|
||||
}
|
||||
|
||||
int32_t assetBufferStart(assetbuffer_t *buffer) {
|
||||
return fseek((FILE *)buffer, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
int32_t assetBufferSkip(assetbuffer_t *buffer, long n) {
|
||||
return fseek((FILE *)buffer, n, SEEK_CUR);
|
||||
}
|
||||
|
||||
size_t assetBufferGetCurrentPosition(assetbuffer_t *buffer) {
|
||||
return ftell((FILE *)buffer);
|
||||
}
|
90
src/dawn/file/asset.h
Normal file
90
src/dawn/file/asset.h
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Msters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../display/shader.h"
|
||||
#include "../display/texture.h"
|
||||
#include "../display/font.h"
|
||||
|
||||
#if !defined(ASSET_PREFIX)
|
||||
#error Asset Prefix has not been defined.
|
||||
#endif
|
||||
|
||||
/** Definition of an asset ready to be buffered */
|
||||
typedef FILE assetbuffer_t;
|
||||
|
||||
/**
|
||||
* Buffer an asset from the file system into memory.
|
||||
*
|
||||
* @param assetName Path to the asset to buffer.
|
||||
* @param buffer Place to buffer the data in to, or NULL to simply read the size
|
||||
* @return The length (in bytes) of the file.
|
||||
*/
|
||||
size_t assetRawLoad(char *assetName, uint8_t *buffer);
|
||||
|
||||
/**
|
||||
* Load a string from an asset into memory.
|
||||
*
|
||||
* @param assetName Asset to load
|
||||
* @return A newly loaded string (malloced into existance.)
|
||||
*/
|
||||
char * assetStringLoad(char *assetName);
|
||||
|
||||
/**
|
||||
* Platform-centric method to open a file buffer to an asset.
|
||||
* @param assetName The asset name to open a buffer for.
|
||||
* @return Pointer to a buffer, NULL if unsuccessfuil.
|
||||
*/
|
||||
assetbuffer_t * assetBufferOpen(char *assetName);
|
||||
|
||||
/**
|
||||
* Closes a previously opened asset buffer.
|
||||
* @param buffer Buffer to close.
|
||||
* @return True if successful, otherwise false.
|
||||
*/
|
||||
bool assetBufferClose(assetbuffer_t *buffer);
|
||||
|
||||
/**
|
||||
* Read bytes from buffer.
|
||||
* @param buffer The buffer pointing to an asset.
|
||||
* @param data Pointer to a ubyte array to buffer data into.
|
||||
* @param size Length of the data buffer. Represents how many bytes can be read.
|
||||
* @return The count of bytes read. Complete when less than data array size.
|
||||
*/
|
||||
int32_t assetBufferRead(assetbuffer_t *buffer, char *data, size_t size);
|
||||
|
||||
/**
|
||||
* Skip to the end of the buffer, useful to find the length of the buffer.
|
||||
* @param Buffer The buffer pointing to an asset.
|
||||
* @return How many bytes were skipped
|
||||
*/
|
||||
int32_t assetBufferEnd(assetbuffer_t *buffer);
|
||||
|
||||
/**
|
||||
* Rewinds an asset buffer to the start.
|
||||
*
|
||||
* @param buffer Buffer to rewind
|
||||
* @return 0 if successful, otherwise unsuccessful.
|
||||
*/
|
||||
int32_t assetBufferStart(assetbuffer_t *buffer);
|
||||
|
||||
/**
|
||||
* Method to skip n bytes in the buffer
|
||||
* @param buffer The buffer pointing to an asset.
|
||||
* @param n Count of bytes to skip.
|
||||
* @return 0 if successful, otherwise unsuccessful.
|
||||
*/
|
||||
int32_t assetBufferSkip(assetbuffer_t *buffer, long n);
|
||||
|
||||
/**
|
||||
* Retreive the current byte position within the asset that the head is at.
|
||||
*
|
||||
* @param buffer Buffer to get the position of.
|
||||
* @return Position (in bytes) that the current seek is at.
|
||||
*/
|
||||
size_t assetBufferGetCurrentPosition(assetbuffer_t *buffer);
|
240
src/dawn/file/assetmanager.c
Normal file
240
src/dawn/file/assetmanager.c
Normal file
@ -0,0 +1,240 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assetmanager.h"
|
||||
|
||||
assetmanagerloaderdefinition_t ASSET_MANAGER_LOADERS[] = {
|
||||
{
|
||||
&_assetManagerLoaderTextureAsync,
|
||||
&_assetManagerLoaderTextureSync,
|
||||
&_assetManagerLoaderTextureDispose
|
||||
},
|
||||
{
|
||||
&_assetManagerLoaderFontAsync,
|
||||
&_assetManagerLoaderFontSync,
|
||||
&_assetManagerLoaderFontDispose
|
||||
},
|
||||
{
|
||||
&_assetManagerLoaderShaderAsync,
|
||||
&_assetManagerLoaderShaderSync,
|
||||
&_assetManagerLoaderShaderDispose
|
||||
},
|
||||
{
|
||||
&_assetManagerLoaderScaledTextureAsync,
|
||||
&_assetManagerLoaderScaledTextureSync,
|
||||
&_assetManagerLoaderScaledTextureDispose
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void assetManagerInit(assetmanager_t *manager) {
|
||||
threadInit(&manager->thread, &_assetManagerThread);
|
||||
manager->thread.user = manager;
|
||||
manager->itemCount = 0;
|
||||
manager->finished = false;
|
||||
manager->holderCount = 0;
|
||||
manager->running = false;
|
||||
}
|
||||
|
||||
float assetManagerProgressGet(assetmanager_t *manager) {
|
||||
float done;
|
||||
uint8_t i;
|
||||
assetmanageritem_t *item;
|
||||
|
||||
done = 0.0f;
|
||||
for(i = 0; i < manager->itemCount; i++) {
|
||||
item = manager->items + i;
|
||||
done += assetManagerItemIsFinished(
|
||||
item, ASSET_MANAGER_LOADERS + item->type
|
||||
) ? 1 : 0;
|
||||
}
|
||||
return done / ((float)manager->itemCount);
|
||||
}
|
||||
|
||||
float assetManagerProgressGetForHolder(
|
||||
assetmanager_t *manager, assetmanagerowner_t hold
|
||||
) {
|
||||
float done;
|
||||
uint8_t i, j, c;
|
||||
assetmanageritem_t *item;
|
||||
done = 0.0f;
|
||||
c = 0x00;
|
||||
for(i = 0; i < manager->itemCount; i++) {
|
||||
//Is this held by this holder?
|
||||
item = manager->items + i;
|
||||
|
||||
for(j = 0; j < item->holderCount; j++) {
|
||||
if(item->holders[j] != hold) continue;
|
||||
c++;
|
||||
done += assetManagerItemIsFinished(
|
||||
item, ASSET_MANAGER_LOADERS + item->type
|
||||
) ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Is this thing even holding any assets to begin with?
|
||||
if(c == 0x00) return 1.0f;
|
||||
return done / (float)c;
|
||||
}
|
||||
|
||||
assetmanagerowner_t assetManagerHolderCreate(assetmanager_t *man) {
|
||||
uint8_t i;
|
||||
|
||||
// Find first available number.
|
||||
for(i = 0; i < 0xFF; i++) {
|
||||
if(arrayFind(
|
||||
sizeof(assetmanagerowner_t), man->holders, man->holderCount, &i
|
||||
) == -1) break;
|
||||
}
|
||||
|
||||
man->holders[man->holderCount++] = i;
|
||||
return i;// No slots left.
|
||||
}
|
||||
|
||||
void assetManagerHolderRelease(assetmanager_t *man, assetmanagerowner_t hold) {
|
||||
int32_t i;
|
||||
uint8_t j;
|
||||
assetmanageritem_t *item;
|
||||
size_t s;
|
||||
|
||||
s = sizeof(assetmanagerowner_t);
|
||||
i = arrayFind(s, man->holders,man->holderCount,&hold);
|
||||
if(i == -1) return;
|
||||
|
||||
arraySplice(sizeof(uint8_t), man->holders, i, 1, man->holderCount);
|
||||
man->holderCount--;
|
||||
|
||||
for(j = 0; j < man->itemCount; j++) {
|
||||
item = man->items + j;
|
||||
i = arrayFind(s, item->holders, item->holderCount, &hold);
|
||||
if(i == -1) continue;
|
||||
arraySplice(s, item->holders, i, 1, item->holderCount);
|
||||
item->holderCount--;
|
||||
}
|
||||
}
|
||||
|
||||
void assetManagerDisposeReleased(assetmanager_t *man) {
|
||||
uint8_t i;
|
||||
assetmanagerloader_t *disp;
|
||||
assetmanageritem_t *item;
|
||||
|
||||
for(i = 0; i < man->itemCount; i++) {
|
||||
item = man->items + i;
|
||||
disp = ASSET_MANAGER_LOADERS[item->type].dispose;
|
||||
if(item->holderCount > 0) continue;
|
||||
if(disp != NULL) disp(item);
|
||||
arraySplice(sizeof(assetmanageritem_t), man->items, i, 1, man->itemCount);
|
||||
man->itemCount--;
|
||||
}
|
||||
}
|
||||
|
||||
void assetManagerDispose(assetmanager_t *man) {
|
||||
uint8_t i;
|
||||
assetmanagerloader_t *disp;
|
||||
assetmanageritem_t *item;
|
||||
|
||||
for(i = 0; i < man->itemCount; i++) {
|
||||
item = man->items + i;
|
||||
disp = ASSET_MANAGER_LOADERS[item->type].dispose;
|
||||
if(item->holderCount > 0) continue;
|
||||
if(disp != NULL) disp(item);
|
||||
}
|
||||
|
||||
man->itemCount = 0;
|
||||
man->holderCount = 0;
|
||||
}
|
||||
|
||||
// Thread Management
|
||||
void assetManagerStart(assetmanager_t *manager) {
|
||||
if(manager->running) return;
|
||||
manager->running = true;
|
||||
threadStart(&manager->thread);
|
||||
}
|
||||
|
||||
int32_t _assetManagerThread(thread_t *thread) {
|
||||
// TODO: Can I allow multiple threads to run?
|
||||
uint8_t i;
|
||||
assetmanager_t *manager;
|
||||
assetmanageritem_t *item;
|
||||
assetmanagerloaderdefinition_t *definition;
|
||||
bool result;
|
||||
manager = thread->user;
|
||||
|
||||
for(i = 0; i < manager->itemCount; i++) {
|
||||
item = manager->items + i;
|
||||
definition = ASSET_MANAGER_LOADERS + item->type;
|
||||
|
||||
// Only bother with ASYNC items
|
||||
if(definition->loadAsync == NULL) continue;
|
||||
|
||||
// Are we already loading, not ready, or already tried to load?
|
||||
if(item->state != ASSET_MANAGER_STATE_PENDING) continue;
|
||||
|
||||
// Begin loading
|
||||
item->state = ASSET_MANAGER_STATE_ASYNC_LOADING;
|
||||
result = definition->loadAsync(item);
|
||||
|
||||
// Finish Loading
|
||||
if(!result) {
|
||||
item->state = ASSET_MANAGER_STATE_ASYNC_ERROR;
|
||||
} else {
|
||||
item->state = ASSET_MANAGER_STATE_ASYNC_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
manager->finished = assetManagerProgressGet(manager) >= 1.0f;
|
||||
manager->running = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void assetManagerUpdate(assetmanager_t *manager) {
|
||||
uint8_t i;
|
||||
assetmanageritem_t *item;
|
||||
assetmanagerloaderdefinition_t *definition;
|
||||
bool result;
|
||||
|
||||
// Autostart
|
||||
if(assetManagerProgressGet(manager) < 1.0f && !manager->running) {
|
||||
assetManagerStart(manager);
|
||||
}
|
||||
|
||||
for(i = 0; i < manager->itemCount; i++) {
|
||||
item = manager->items + i;
|
||||
definition = ASSET_MANAGER_LOADERS + item->type;
|
||||
|
||||
// Update not ready state (Synchronously)
|
||||
if(item->state == ASSET_MANAGER_STATE_NOT_READY) {
|
||||
item->state = ASSET_MANAGER_STATE_PENDING;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If requires ASYNC loading, then confirm it has finished loading.
|
||||
if(definition->loadAsync != NULL) {
|
||||
if(item->state != ASSET_MANAGER_STATE_ASYNC_DONE) continue;
|
||||
} else if(item->state != ASSET_MANAGER_STATE_PENDING) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(definition->loadSync == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Begin sync loading
|
||||
item->state = ASSET_MANAGER_STATE_SYNC_LOADING;
|
||||
result = definition->loadSync(item);
|
||||
|
||||
// Finish loading
|
||||
if(!result) {
|
||||
item->state = ASSET_MANAGER_STATE_SYNC_ERROR;
|
||||
} else {
|
||||
item->state = ASSET_MANAGER_STATE_SYNC_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
manager->finished = assetManagerProgressGet(manager) >= 1.0f;
|
||||
}
|
100
src/dawn/file/assetmanager.h
Normal file
100
src/dawn/file/assetmanager.h
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "types/common.h"
|
||||
#include "loaders/font.h"
|
||||
#include "loaders/scaledtexture.h"
|
||||
#include "loaders/shader.h"
|
||||
#include "loaders/texture.h"
|
||||
#include "asset.h"
|
||||
|
||||
// Constants
|
||||
extern assetmanagerloaderdefinition_t ASSET_MANAGER_LOADERS[];
|
||||
|
||||
/**
|
||||
* Initialize the asset manager
|
||||
*
|
||||
* @param manager Manager to initialize.
|
||||
*/
|
||||
void assetManagerInit(assetmanager_t *manager);
|
||||
|
||||
/**
|
||||
* Gets the progress of the asset manager as a representation of 0-1 as a % that
|
||||
* has loaded.
|
||||
*
|
||||
* @param manager Manager to check the state of.
|
||||
* @return The progress percent as a representation of 0-1
|
||||
*/
|
||||
float assetManagerProgressGet(assetmanager_t *manager);
|
||||
|
||||
/**
|
||||
* Gets the progress of the assets for only those held by a specific holder.
|
||||
*
|
||||
* @param manager Manager to get the progress from
|
||||
* @param hold Holder to get the items progress from.
|
||||
* @return The percentage (0-1) of the loaded assets.
|
||||
*/
|
||||
float assetManagerProgressGetForHolder(
|
||||
assetmanager_t *manager, assetmanagerowner_t hold
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates a holder for a given asset manager. Asset holders are kept track of
|
||||
* so that those who requests assets are responsible for those who free them. It
|
||||
* also ensures only the assets that are actually necessary are kept loaded in
|
||||
* memory at all times.
|
||||
*
|
||||
* @param man Asset manager in question
|
||||
* @return An asset manager owner ID.
|
||||
*/
|
||||
assetmanagerowner_t assetManagerHolderCreate(assetmanager_t *man);
|
||||
|
||||
/**
|
||||
* Release a previously reserved asset manager holder. This will (in turn) cause
|
||||
* all of the assets that manager was holding to also be released.
|
||||
*
|
||||
* @param man Asset manager holder to release for.
|
||||
* @param hold Holder to release.
|
||||
*/
|
||||
void assetManagerHolderRelease(assetmanager_t *man, assetmanagerowner_t hold);
|
||||
|
||||
/**
|
||||
* Disposes all assets that are not currently held (released assets). This can
|
||||
* only happen from the main thread due to synchronous assets such as Textures.
|
||||
*
|
||||
* @param man Manager to dispose.
|
||||
*/
|
||||
void assetManagerDisposeReleased(assetmanager_t *man);
|
||||
|
||||
/**
|
||||
* Completely dispose an asset manager. This will also completely dispose all
|
||||
* of the assets that this asset manager is holding.
|
||||
*
|
||||
* @param man Asset manager to dispose
|
||||
*/
|
||||
void assetManagerDispose(assetmanager_t *man);
|
||||
|
||||
/**
|
||||
* Begin asynchronously loading all of the assets
|
||||
*
|
||||
* @param manager Manager to begin async loading.
|
||||
*/
|
||||
void assetManagerStart(assetmanager_t *manager);
|
||||
|
||||
/** Private Thread that is executed asynchronously */
|
||||
int32_t _assetManagerThread(thread_t *thread);
|
||||
|
||||
/**
|
||||
* Synchronously tick the asset manager. Some assets require some form of sync
|
||||
* operations, such as buffering to the GPU, so make sure this is called at a
|
||||
* good time for that task, such as right at the end of a frame.
|
||||
*
|
||||
* @param manager Manager to synchronously tick.
|
||||
*/
|
||||
void assetManagerUpdate(assetmanager_t *manager);
|
223
src/dawn/file/csv.c
Normal file
223
src/dawn/file/csv.c
Normal file
@ -0,0 +1,223 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "csv.h"
|
||||
|
||||
csvbufferresult_t csvBuffer(
|
||||
assetbuffer_t *asset, csvbuffercallback_t *callback, void *user
|
||||
) {
|
||||
int32_t cellChar, read, i, currentColumnCount;
|
||||
char buffer[CSV_BUFFER_SIZE];
|
||||
char cell[CSV_CELL_SIZE_MAX];
|
||||
char c;
|
||||
bool callbackResponse;
|
||||
bool insideEncapsulation = false;
|
||||
csvbufferresult_t result = {
|
||||
.cellCount = 0,
|
||||
.rowCount = 0,
|
||||
.columnCount = 0
|
||||
};
|
||||
|
||||
// Init the cell Char Index.
|
||||
cellChar = 0;
|
||||
currentColumnCount = 0;
|
||||
|
||||
// Begin buffering.
|
||||
while(true) {
|
||||
// Read n bytes into our buffer
|
||||
read = assetBufferRead(asset, buffer, CSV_BUFFER_SIZE);
|
||||
|
||||
// Now read back those bytes.
|
||||
for(i = 0; i < read; i++) {
|
||||
c = buffer[i];
|
||||
|
||||
// Characters we flat out ignore
|
||||
if(c == '\r') continue;
|
||||
|
||||
// Handle quote marks.
|
||||
if(c == '"') {
|
||||
if(buffer[i+1] == '"') {// "" means a single quote (double-escaped)
|
||||
i++;
|
||||
cell[cellChar++] = c;
|
||||
} else if(insideEncapsulation) {
|
||||
insideEncapsulation = false;
|
||||
} else {
|
||||
insideEncapsulation = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Is the start of a new cell/row?
|
||||
if(c == '\0' || (!insideEncapsulation && (c == ',' || c == '\n'))) {
|
||||
cell[cellChar] = '\0';// Terminate Cell string
|
||||
|
||||
// Fire off the callback
|
||||
if(callback != NULL) {
|
||||
callbackResponse = callback(asset, user, result.rowCount, currentColumnCount, cell);
|
||||
if(!callbackResponse) return result;
|
||||
}
|
||||
|
||||
// Prepare for next row/cell
|
||||
currentColumnCount++;
|
||||
result.columnCount = mathMax(currentColumnCount, result.columnCount);
|
||||
if(c == '\n') {
|
||||
result.rowCount++;
|
||||
currentColumnCount = 0;
|
||||
}
|
||||
result.cellCount++;// Only count cells with
|
||||
cellChar = 0;
|
||||
continue;// Skip
|
||||
}
|
||||
|
||||
// Add character to the cell.
|
||||
cell[cellChar++] = c;
|
||||
}
|
||||
|
||||
if(read < CSV_BUFFER_SIZE) break;
|
||||
}
|
||||
|
||||
// If this is an empty row we don't count it, otherwise we do.
|
||||
if(currentColumnCount != 0) result.rowCount++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool _csvBufferRowParserCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, int32_t column, char *data
|
||||
) {
|
||||
csvbufferrowdata_t *rowData = (csvbufferrowdata_t *)user;
|
||||
|
||||
// Now did we change rows?
|
||||
if(row != rowData->row) {
|
||||
// Yes we did, let's buffer the previous row.
|
||||
if(rowData->callback != NULL) {
|
||||
if(!rowData->callback(
|
||||
asset, rowData->user, rowData->row, &rowData->rowCurrent
|
||||
)) return false;
|
||||
}
|
||||
// Begin next row
|
||||
rowData->row = row;
|
||||
rowData->rowCurrent.columnCount = 0;
|
||||
}
|
||||
|
||||
// Determine string info for the cell
|
||||
int32_t length = (int32_t)strlen(data);
|
||||
int32_t offset = (column * CSV_CELL_SIZE_MAX);
|
||||
|
||||
// Now copy the string data to the buffer
|
||||
arrayCopy(sizeof(char), data, length + 1, rowData->rowCurrent.data + offset);
|
||||
// Update the pointer to the string
|
||||
rowData->rowCurrent.columns[column] = rowData->rowCurrent.data + offset;
|
||||
rowData->rowCurrent.columnCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
csvbufferresult_t csvBufferRow(
|
||||
assetbuffer_t *asset, csvbufferrowcallback_t *callback, void *user
|
||||
) {
|
||||
csvbufferrowdata_t data;
|
||||
csvbufferresult_t result;
|
||||
data.row = 0;
|
||||
data.user = user;
|
||||
data.callback = callback;
|
||||
data.rowCurrent.columnCount = 0;
|
||||
|
||||
// Perform a per-cell buffer and run the parser callback.
|
||||
result = csvBuffer(asset, &_csvBufferRowParserCallback, &data);
|
||||
|
||||
// Because the buffer may not fire for the last row we handle it here.
|
||||
if(data.rowCurrent.columnCount > 0 && callback != NULL) {
|
||||
if(!callback(asset, user, data.row, &data.rowCurrent)) return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool _csvBufferRowWithHeadersCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *csv
|
||||
) {
|
||||
csvbufferrowwithheadersdata_t *data = (csvbufferrowwithheadersdata_t *)user;
|
||||
|
||||
// Take the headers for row 0
|
||||
if(row == 0) {
|
||||
csvRowPopulate(csv, &data->headerRow);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fire the callback
|
||||
return data->callback(asset, data->user, row, &data->headerRow, csv);
|
||||
}
|
||||
|
||||
csvbufferresult_t csvBufferRowWithHeaders(
|
||||
assetbuffer_t *asset, csvbufferrowwitheaderscallback_t *callback, void *user
|
||||
) {
|
||||
csvbufferrowwithheadersdata_t data;
|
||||
data.user = user;
|
||||
data.callback = callback;
|
||||
|
||||
return csvBufferRow(asset, &_csvBufferRowWithHeadersCallback, &data);
|
||||
}
|
||||
|
||||
void csvRowPopulate(csvrow_t *source, csvrow_t *dest) {
|
||||
int32_t i;
|
||||
|
||||
dest->columnCount = source->columnCount;
|
||||
|
||||
// Copy the raw characters from the source buffer.
|
||||
arrayCopy(sizeof(char), source->data, CSV_ROW_CHARACTERS_MAX, dest->data);
|
||||
|
||||
// Now update the destination pointers to reference the data buffer.
|
||||
for(i = 0; i < source->columnCount; i++) {
|
||||
dest->columns[i] = dest->data + (i * CSV_CELL_SIZE_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool _csvHeadersGetCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *current
|
||||
) {
|
||||
csvrow_t *rowData = (csvrow_t *)user;
|
||||
csvRowPopulate(current, rowData);
|
||||
return false;// False to break the loop
|
||||
}
|
||||
|
||||
csvbufferresult_t csvHeadersGet(assetbuffer_t *asset, csvrow_t *row) {
|
||||
return csvBufferRow(asset, &_csvHeadersGetCallback, row);
|
||||
}
|
||||
|
||||
int32_t csvColumnGetIndex(csvrow_t *row, char *key) {
|
||||
return arrayFindString(row->columns, row->columnCount, key);
|
||||
}
|
||||
|
||||
|
||||
bool _csvRowSearchCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *csv
|
||||
) {
|
||||
csvsearchdata_t *data = (csvsearchdata_t *)user;
|
||||
// Does the search match?
|
||||
if(strcmp(csv->columns[data->column], data->value) != 0) return true;
|
||||
// Matched, copy and end.
|
||||
csvRowPopulate(csv, data->row);
|
||||
data->rowIndex = row;
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t csvRowSearch(
|
||||
assetbuffer_t *asset, csvrow_t *row, int32_t column, char *value
|
||||
) {
|
||||
csvsearchdata_t data = {
|
||||
.column = column,
|
||||
.row = row,
|
||||
.rowIndex = -1,
|
||||
.value = value
|
||||
};
|
||||
csvBufferRow(asset, &_csvRowSearchCallback, &data);
|
||||
return data.rowIndex;
|
||||
}
|
191
src/dawn/file/csv.h
Normal file
191
src/dawn/file/csv.h
Normal file
@ -0,0 +1,191 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "asset.h"
|
||||
#include "../util/array.h"
|
||||
|
||||
/** Maximum characters that a cell can support */
|
||||
#define CSV_BUFFER_SIZE 32
|
||||
|
||||
/** Maximum characters in any given cell */
|
||||
#define CSV_CELL_SIZE_MAX 1024
|
||||
|
||||
/** Maximum number of columns/cells in a given row */
|
||||
#define CSV_ROW_COLUMNS_MAX 16
|
||||
|
||||
/** Count of characters maximum that a row can support */
|
||||
#define CSV_ROW_CHARACTERS_MAX CSV_CELL_SIZE_MAX * CSV_ROW_COLUMNS_MAX
|
||||
|
||||
/** Result of a CSV buffer operation. */
|
||||
typedef struct {
|
||||
/** How many rows within the CSV */
|
||||
int32_t rowCount;
|
||||
/** Count of columns in the CSV, this is the longest row in the CSV. */
|
||||
int32_t columnCount;
|
||||
/** How many cells within the CSV */
|
||||
int32_t cellCount;
|
||||
} csvbufferresult_t;
|
||||
|
||||
/** Callback to receive data for each cell in a CSV being buffered */
|
||||
typedef bool csvbuffercallback_t(
|
||||
assetbuffer_t *asset, void *user, int32_t row, int32_t column, char *data
|
||||
);
|
||||
|
||||
/** Representation of a CSV Row's complete data. */
|
||||
typedef struct {
|
||||
/** Characters within the row */
|
||||
char data[CSV_ROW_CHARACTERS_MAX];
|
||||
/** Pointer to the start of each string within the row */
|
||||
char *columns[CSV_ROW_COLUMNS_MAX];
|
||||
/** How many columns within the row */
|
||||
int32_t columnCount;
|
||||
} csvrow_t;
|
||||
|
||||
/** Callback to receive buffer data for a CSV row */
|
||||
typedef bool csvbufferrowcallback_t(
|
||||
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *csv
|
||||
);
|
||||
|
||||
/** Callback to receive buffer data for a CSV row, but includes CSV headers. */
|
||||
typedef bool csvbufferrowwitheaderscallback_t(
|
||||
assetbuffer_t *asset, void *user, int32_t row,
|
||||
csvrow_t *header, csvrow_t *current
|
||||
);
|
||||
|
||||
/** Data used by the cell callback for when the row buffering is progressing */
|
||||
typedef struct {
|
||||
/** Which row the current buffer is on */
|
||||
int32_t row;
|
||||
/** Information about the current row being parsed */
|
||||
csvrow_t rowCurrent;
|
||||
/** Pointer to custom user data */
|
||||
void *user;
|
||||
/** Pointer to custom user callback */
|
||||
csvbufferrowcallback_t *callback;
|
||||
} csvbufferrowdata_t;
|
||||
|
||||
/** Data used by the row callback for when the header row is parsed */
|
||||
typedef struct {
|
||||
/** Information about the header row */
|
||||
csvrow_t headerRow;
|
||||
/** Pointer to custom user data */
|
||||
void *user;
|
||||
/** Pointer to custom user callback */
|
||||
csvbufferrowwitheaderscallback_t *callback;
|
||||
} csvbufferrowwithheadersdata_t;
|
||||
|
||||
/** Data used while searching a CSV */
|
||||
typedef struct {
|
||||
/** Row to store the data in */
|
||||
csvrow_t *row;
|
||||
/** Row's index */
|
||||
int32_t rowIndex;
|
||||
/** Column to check */
|
||||
int32_t column;
|
||||
/** Value to check row */
|
||||
char *value;
|
||||
} csvsearchdata_t;
|
||||
|
||||
/**
|
||||
* Buffer each cell within a CSV Asset Buffer with a callback.
|
||||
*
|
||||
* @param asset Asset to buffer the CSV from.
|
||||
* @param callback Callback to fire for each cell parsed.
|
||||
* @param user Pointer to any custom user data.
|
||||
* @return The result of the CSV Buffer Operation.
|
||||
*/
|
||||
csvbufferresult_t csvBuffer(
|
||||
assetbuffer_t *asset, csvbuffercallback_t *callback, void *user
|
||||
);
|
||||
|
||||
/** Callback for when the CSV Row Buffer is parsing a row */
|
||||
bool _csvBufferRowParserCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, int32_t column, char *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Buffer each row within a CSV Asset Buffer with a callback.
|
||||
*
|
||||
* @param asset Asset to buffer the CSV from.
|
||||
* @param callback Callback to fire when a row is parsed.
|
||||
* @param user Pointer to any custom user data.
|
||||
* @return The result of the CSV Buffer Operation.
|
||||
*/
|
||||
csvbufferresult_t csvBufferRow(
|
||||
assetbuffer_t *asset, csvbufferrowcallback_t *callback, void *user
|
||||
);
|
||||
|
||||
|
||||
/** Parser that the header parser buffer uses. */
|
||||
bool _csvBufferRowWithHeadersCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *csv
|
||||
);
|
||||
|
||||
/**
|
||||
* Buffer each row within a CSV Asset Buffer with a callback. This will also
|
||||
* provide the callback with the header row (The first row), already parsed.
|
||||
*
|
||||
* @param asset
|
||||
* @param callback
|
||||
* @param user
|
||||
* @return csvbufferresult_t
|
||||
*/
|
||||
csvbufferresult_t csvBufferRowWithHeaders(
|
||||
assetbuffer_t *asset, csvbufferrowwitheaderscallback_t *callback, void *user
|
||||
);
|
||||
|
||||
/**
|
||||
* Essentially a CSV Row Cloner, copies data from one CSV row to another and
|
||||
* updates the char pointers for you.
|
||||
*
|
||||
* @param source The source CSV row to copy from.
|
||||
* @param dest The destination CSV row to copy to.
|
||||
*/
|
||||
void csvRowPopulate(csvrow_t *source, csvrow_t *dest);
|
||||
|
||||
/** Callback used to parse and get the headers row */
|
||||
bool _csvHeadersGetCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *current
|
||||
);
|
||||
/**
|
||||
* Parses just the headers row from a CSV and stores the output into the
|
||||
* provided buffers.
|
||||
*
|
||||
* @param asset Asset to get the headers from.
|
||||
* @param row The CSV Row to store the headers data in.
|
||||
* @return The result of the buffer operation.
|
||||
*/
|
||||
csvbufferresult_t csvHeadersGet(assetbuffer_t *asset, csvrow_t *row);
|
||||
|
||||
/**
|
||||
* Gets the column index within the CSV Row for the specific key.
|
||||
* @param row Row to get from.
|
||||
* @param key Key to search for
|
||||
* @return The column index for the key, or -1 if not found.
|
||||
*/
|
||||
int32_t csvColumnGetIndex(csvrow_t *row, char *key);
|
||||
|
||||
/** Callback to use while scanning the CSV to find the matching row */
|
||||
bool _csvRowSearchCallback(
|
||||
assetbuffer_t *asset, void *user, int32_t row, csvrow_t *csv
|
||||
);
|
||||
|
||||
/**
|
||||
* Search the CSV for a matching row. Will return data only if the given column
|
||||
* matches the given value.
|
||||
*
|
||||
* @param asset Asset buffer to search.
|
||||
* @param row Where the returned row will be stored.
|
||||
* @param column Column to check.
|
||||
* @param value Value to check in that column
|
||||
* @return The row index that the result was found on, or -1 if not found.
|
||||
*/
|
||||
int32_t csvRowSearch(
|
||||
assetbuffer_t *asset, csvrow_t *row, int32_t column, char *value
|
||||
);
|
39
src/dawn/file/loaders/font.c
Normal file
39
src/dawn/file/loaders/font.c
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "font.h"
|
||||
|
||||
assetmanageritem_t * assetManagerLoadFont(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner, char *fileName
|
||||
) {
|
||||
assetmanageritem_t *item;
|
||||
item = assetManagerItemGet(manager, fileName);
|
||||
if(item == NULL) {
|
||||
item = assetManagerItemAdd(manager, fileName);
|
||||
item->type = ASSET_MANAGER_TYPE_FONT;
|
||||
item->data.font.fileName = fileName;
|
||||
}
|
||||
assetManagerItemGetOrAddHolder(item, owner);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderFontAsync(assetmanageritem_t *item) {
|
||||
item->data.font.data = assetStringLoad(item->data.font.fileName);
|
||||
return item->data.font.data != NULL;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderFontSync(assetmanageritem_t *item) {
|
||||
fontInit(&item->data.font.font, item->data.font.data);
|
||||
free(item->data.font.data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderFontDispose(assetmanageritem_t *item) {
|
||||
fontDispose(&item->data.font.font);
|
||||
return true;
|
||||
}
|
27
src/dawn/file/loaders/font.h
Normal file
27
src/dawn/file/loaders/font.h
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "item.h"
|
||||
#include "../asset.h"
|
||||
|
||||
/**
|
||||
* Queue a font load onto the asset manager buffer.
|
||||
*
|
||||
* @param manager Manager to queue on to.
|
||||
* @param owner Owner ID requesting to load this resource.
|
||||
* @param font Font to push the result in to.
|
||||
* @param fileName Filename of the asset to load.
|
||||
* @return A pointer to the asset manager item for tracking.
|
||||
*/
|
||||
assetmanageritem_t * assetManagerLoadFont(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner, char *fileName
|
||||
);
|
||||
|
||||
bool _assetManagerLoaderFontAsync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderFontSync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderFontDispose(assetmanageritem_t *item);
|
57
src/dawn/file/loaders/item.c
Normal file
57
src/dawn/file/loaders/item.c
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "item.h"
|
||||
|
||||
assetmanageritem_t * assetManagerItemGet(assetmanager_t *man, char *key) {
|
||||
uint8_t i;
|
||||
assetmanageritem_t *item;
|
||||
|
||||
for(i = 0; i < man->itemCount; i++) {
|
||||
item = man->items + i;
|
||||
if(strcmp(item->key, key) == 0) return item;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assetmanageritem_t * assetManagerItemAdd(assetmanager_t *manager, char *key) {
|
||||
// Check if key already exists.
|
||||
assetmanageritem_t *item = manager->items + manager->itemCount++;
|
||||
item->state = ASSET_MANAGER_STATE_NOT_READY;
|
||||
memcpy(item->key, key, strlen(key) + 1);
|
||||
item->holderCount = 0x00;
|
||||
return item;
|
||||
}
|
||||
|
||||
uint8_t assetManagerItemGetOrAddHolder(
|
||||
assetmanageritem_t *item, assetmanagerowner_t owner
|
||||
) {
|
||||
uint8_t i, firstEmpty;
|
||||
firstEmpty = 0xFF;
|
||||
|
||||
for(i = 0; i < item->holderCount; i++) {
|
||||
if(item->holders[i] == owner) return i;
|
||||
if(firstEmpty == 0xFF && item->holders[i] == 0xFF) {
|
||||
firstEmpty = i;
|
||||
}
|
||||
}
|
||||
|
||||
if(firstEmpty == 0xFF) firstEmpty = item->holderCount++;
|
||||
item->holders[firstEmpty] = owner;
|
||||
return firstEmpty;
|
||||
}
|
||||
|
||||
bool assetManagerItemIsFinished(assetmanageritem_t *item, assetmanagerloaderdefinition_t *def) {
|
||||
// Sync done is always done
|
||||
if(item->state == ASSET_MANAGER_STATE_SYNC_DONE) return true;
|
||||
// Only check if ASYNC is done.
|
||||
if(item->state != ASSET_MANAGER_STATE_ASYNC_DONE) return false;
|
||||
// Does it need to still sync load?
|
||||
if(def->loadSync == NULL) return true;
|
||||
return false;
|
||||
}
|
49
src/dawn/file/loaders/item.h
Normal file
49
src/dawn/file/loaders/item.h
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../types/common.h"
|
||||
|
||||
/**
|
||||
* Retreive an exisitng asset manager item by its key.
|
||||
*
|
||||
* @param man Manager to get from
|
||||
* @param key Key to search for.
|
||||
* @return The matching asset manager item, or NULL if not found.
|
||||
*/
|
||||
assetmanageritem_t * assetManagerItemGet(assetmanager_t *man, char *key);
|
||||
|
||||
/**
|
||||
* Private method, simply adds an item to the manager and resets the state.
|
||||
*
|
||||
* @param manager Manager to add to.
|
||||
* @param key Key to use when adding.
|
||||
* @return The added and reset item.
|
||||
*/
|
||||
assetmanageritem_t * assetManagerItemAdd(assetmanager_t *manager, char *key);
|
||||
|
||||
/**
|
||||
* Add or get the index that a given holder has as a manager item.
|
||||
*
|
||||
* @param i Asset Item to check.
|
||||
* @param o Owner to get/add.
|
||||
* @return The index within the item that the owner is at.
|
||||
*/
|
||||
uint8_t assetManagerItemGetOrAddHolder(
|
||||
assetmanageritem_t *i, assetmanagerowner_t o
|
||||
);
|
||||
|
||||
/**
|
||||
* Checks if a given asset item is finished or not.
|
||||
*
|
||||
* @param item Item to check.
|
||||
* @param def Item type definition used for loading.
|
||||
* @return True if finished, otherwise false.
|
||||
*/
|
||||
bool assetManagerItemIsFinished(
|
||||
assetmanageritem_t *item, assetmanagerloaderdefinition_t *def
|
||||
);
|
123
src/dawn/file/loaders/scaledtexture.c
Normal file
123
src/dawn/file/loaders/scaledtexture.c
Normal file
@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "scaledtexture.h"
|
||||
|
||||
assetmanageritem_t * assetManagerLoadScaledTexture(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner,
|
||||
char *path, char *file, uint8_t scale
|
||||
) {
|
||||
assetmanageritem_t *item;
|
||||
texturescale_t *st;
|
||||
char buffer[ASSET_MANAGER_ITEM_NAME_MAX];
|
||||
|
||||
sprintf(buffer, "%s/%s_%u", path, file, scale);
|
||||
item = assetManagerItemGet(manager, buffer);
|
||||
|
||||
if(item == NULL) {
|
||||
item = assetManagerItemAdd(manager, buffer);
|
||||
item->type = ASSET_MANAGER_TYPE_SCALED_TEXTURE;
|
||||
item->data.scaledTexture.scale = scale;
|
||||
|
||||
st = &item->data.scaledTexture.textureScale;
|
||||
st->scaleCount = 0;
|
||||
st->baseWidth = 0;
|
||||
st->baseHeight = 0;
|
||||
st->path = path;
|
||||
st->file = file;
|
||||
}
|
||||
|
||||
assetManagerItemGetOrAddHolder(item, owner);
|
||||
return item;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderScaledTextureAsync(assetmanageritem_t *item) {
|
||||
char buffer[128];
|
||||
char *xmlData;
|
||||
xml_t xml;
|
||||
xml_t *child;
|
||||
int16_t i, j;
|
||||
texturescale_t *st;
|
||||
texturescalescale_t *sts;
|
||||
size_t length;
|
||||
|
||||
// TODO: This can be improved if we allow both asset dependencies and
|
||||
// dependency sibling adding
|
||||
|
||||
st = &item->data.scaledTexture.textureScale;
|
||||
|
||||
// Begin loading texture XML
|
||||
sprintf(buffer, "%s/%s.xml", st->path, st->file);
|
||||
|
||||
xmlData = assetStringLoad(buffer);
|
||||
if(xmlData == NULL) return false;
|
||||
xmlLoad(&xml, xmlData);
|
||||
free(xmlData);
|
||||
|
||||
// Parse root texture info
|
||||
i = xmlGetAttributeByName(&xml, "channels");
|
||||
st->channels = (uint8_t)atoi(xml.attributeDatas[i]);
|
||||
i = xmlGetAttributeByName(&xml, "width");
|
||||
st->baseWidth = (int16_t)atoi(xml.attributeDatas[i]);
|
||||
i = xmlGetAttributeByName(&xml, "height");
|
||||
st->baseHeight = (int16_t)atoi(xml.attributeDatas[i]);
|
||||
|
||||
for(j = 0; j < xml.childrenCount; j++) {
|
||||
child = xml.children + j;
|
||||
i = xmlGetAttributeByName(child, "scale");
|
||||
st->scales[st->scaleCount].scale = (uint8_t)atoi(child->attributeDatas[i]);
|
||||
i = xmlGetAttributeByName(child, "width");
|
||||
st->scales[st->scaleCount].width = (int16_t)atoi(child->attributeDatas[i]);
|
||||
i = xmlGetAttributeByName(child, "height");
|
||||
st->scales[st->scaleCount].height = (int16_t)atoi(child->attributeDatas[i]);
|
||||
st->scaleCount++;
|
||||
}
|
||||
|
||||
// Cleanup XML
|
||||
xmlDispose(&xml);
|
||||
|
||||
// Get the scale
|
||||
sts = st->scales + item->data.scaledTexture.scale;
|
||||
|
||||
// Get filename
|
||||
sprintf(buffer, "%s/%s_%i.texture", st->path, st->file, sts->scale);
|
||||
|
||||
// Create some space
|
||||
length = assetRawLoad(buffer, NULL);
|
||||
if(length == 0) return false;
|
||||
item->data.scaledTexture.data = malloc(sizeof(pixel_t) * length);
|
||||
|
||||
// Load
|
||||
length = assetRawLoad(buffer, (uint8_t *)item->data.scaledTexture.data);
|
||||
if(length == 0) {
|
||||
free(item->data.scaledTexture.data);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderScaledTextureSync(assetmanageritem_t *item) {
|
||||
texturescale_t *st;
|
||||
texturescalescale_t *sts;
|
||||
st = &item->data.scaledTexture.textureScale;
|
||||
sts = st->scales + item->data.scaledTexture.scale;
|
||||
|
||||
textureInit(
|
||||
&item->data.scaledTexture.texture,
|
||||
sts->width, sts->height,
|
||||
item->data.scaledTexture.data
|
||||
);
|
||||
|
||||
free(item->data.scaledTexture.data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderScaledTextureDispose(assetmanageritem_t *item) {
|
||||
textureDispose(&item->data.scaledTexture.texture);
|
||||
return true;
|
||||
}
|
30
src/dawn/file/loaders/scaledtexture.h
Normal file
30
src/dawn/file/loaders/scaledtexture.h
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "item.h"
|
||||
#include "../xml.h"
|
||||
#include "../asset.h"
|
||||
|
||||
/**
|
||||
* Load the given texture scale for a scaled texture.
|
||||
*
|
||||
* @param manager Manager to queue on to.
|
||||
* @param owner Owner ID requesting to load this resource.
|
||||
* @param path Path of the texture size sets
|
||||
* @param file Name of the texture that was generated.
|
||||
* @param scale Scale to load.
|
||||
* @return A pointer to the asset manager item for tracking.
|
||||
*/
|
||||
assetmanageritem_t * assetManagerLoadScaledTexture(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner,
|
||||
char *path, char *file, uint8_t scale
|
||||
);
|
||||
|
||||
bool _assetManagerLoaderScaledTextureAsync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderScaledTextureSync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderScaledTextureDispose(assetmanageritem_t *item);
|
55
src/dawn/file/loaders/shader.c
Normal file
55
src/dawn/file/loaders/shader.c
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "shader.h"
|
||||
|
||||
assetmanageritem_t * assetManagerLoadShader(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner,
|
||||
char *fileVert, char *fileFrag
|
||||
) {
|
||||
assetmanageritem_t *item;
|
||||
char buffer[ASSET_MANAGER_ITEM_NAME_MAX];
|
||||
sprintf(buffer, "%s/%s", fileVert, fileFrag);
|
||||
item = assetManagerItemGet(manager, buffer);
|
||||
if(item == NULL) {
|
||||
item = assetManagerItemAdd(manager, buffer);
|
||||
item->type = ASSET_MANAGER_TYPE_SHADER;
|
||||
item->data.shader.fileVert = fileVert;
|
||||
item->data.shader.fileFrag = fileFrag;
|
||||
}
|
||||
assetManagerItemGetOrAddHolder(item, owner);
|
||||
return item;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderShaderAsync(assetmanageritem_t *item) {
|
||||
item->data.shader.dataVert = assetStringLoad(item->data.shader.fileVert);
|
||||
if(item->data.shader.dataVert == NULL) return false;
|
||||
|
||||
item->data.shader.dataFrag = assetStringLoad(item->data.shader.fileFrag);
|
||||
if(item->data.shader.dataFrag == NULL) {
|
||||
free(item->data.shader.fileVert);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderShaderSync(assetmanageritem_t *item) {
|
||||
shaderInit(
|
||||
&item->data.shader.shader,
|
||||
item->data.shader.dataVert,
|
||||
item->data.shader.dataFrag
|
||||
);
|
||||
free(item->data.shader.dataFrag);
|
||||
free(item->data.shader.dataVert);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderShaderDispose(assetmanageritem_t *item) {
|
||||
shaderDispose(&item->data.shader.shader);
|
||||
return true;
|
||||
}
|
29
src/dawn/file/loaders/shader.h
Normal file
29
src/dawn/file/loaders/shader.h
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "item.h"
|
||||
#include "../asset.h"
|
||||
|
||||
/**
|
||||
* Queues a shader load onto the asset manager buffer.
|
||||
*
|
||||
* @param manager Manager to queue on to.
|
||||
* @param owner Owner ID requesting to load this resource.
|
||||
* @param shader Shader to push the result in to.
|
||||
* @param fileVert Vertex file in question to load.
|
||||
* @param fileFrag Fragment file in question to load.
|
||||
* @return A pointer to the asset manager item for tracking.
|
||||
*/
|
||||
assetmanageritem_t * assetManagerLoadShader(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner,
|
||||
char *fileVert, char *fileFrag
|
||||
);
|
||||
|
||||
bool _assetManagerLoaderShaderAsync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderShaderSync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderShaderDispose(assetmanageritem_t *item);
|
69
src/dawn/file/loaders/texture.c
Normal file
69
src/dawn/file/loaders/texture.c
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "texture.h"
|
||||
|
||||
assetmanageritem_t * assetManagerLoadTexture(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner, char *fileName
|
||||
) {
|
||||
assetmanageritem_t *item;
|
||||
item = assetManagerItemGet(manager, fileName);
|
||||
if(item == NULL) {
|
||||
item = assetManagerItemAdd(manager, fileName);
|
||||
item->type = ASSET_MANAGER_TYPE_TEXTURE;
|
||||
item->data.texture.fileName = fileName;
|
||||
}
|
||||
assetManagerItemGetOrAddHolder(item, owner);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderTextureAsync(assetmanageritem_t *item) {
|
||||
assetbuffer_t *buffer;
|
||||
int channels;
|
||||
stbi_io_callbacks OPENGL_STBI_CALLBACKS;
|
||||
|
||||
buffer = assetBufferOpen(item->data.texture.fileName);
|
||||
if(buffer == NULL) return false;
|
||||
|
||||
// Setup the interface for STBI
|
||||
OPENGL_STBI_CALLBACKS.read = &assetBufferRead;
|
||||
OPENGL_STBI_CALLBACKS.skip = &assetBufferSkip;
|
||||
OPENGL_STBI_CALLBACKS.eof = &assetBufferEnd;
|
||||
|
||||
// Buffer the image
|
||||
channels = 0;
|
||||
item->data.texture.data = (pixel_t *)stbi_load_from_callbacks(
|
||||
&OPENGL_STBI_CALLBACKS, buffer,
|
||||
&item->data.texture.width, &item->data.texture.height,
|
||||
&channels, STBI_rgb_alpha
|
||||
);
|
||||
|
||||
// Close the buffer
|
||||
assetBufferClose(buffer);
|
||||
if(item->data.texture.data == NULL) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderTextureSync(assetmanageritem_t *item) {
|
||||
// Turn into a texture.
|
||||
textureInit(
|
||||
&item->data.texture.texture,
|
||||
item->data.texture.width,
|
||||
item->data.texture.height,
|
||||
item->data.texture.data
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
stbi_image_free(item->data.texture.data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _assetManagerLoaderTextureDispose(assetmanageritem_t *item) {
|
||||
textureDispose(&item->data.texture.texture);
|
||||
return true;
|
||||
}
|
27
src/dawn/file/loaders/texture.h
Normal file
27
src/dawn/file/loaders/texture.h
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "item.h"
|
||||
#include "../asset.h"
|
||||
|
||||
/**
|
||||
* Queue a texture load onto the asset manager buffer.
|
||||
*
|
||||
* @param manager Manager to queue on to.
|
||||
* @param owner Owner ID requesting to load this resource.
|
||||
* @param texture Texture to push the result in to.
|
||||
* @param fileName Texture filename to load.
|
||||
* @return A pointer to the asset manager item for tracking.
|
||||
*/
|
||||
assetmanageritem_t * assetManagerLoadTexture(
|
||||
assetmanager_t *manager, assetmanagerowner_t owner, char *fileName
|
||||
);
|
||||
|
||||
bool _assetManagerLoaderTextureAsync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderTextureSync(assetmanageritem_t *item);
|
||||
bool _assetManagerLoaderTextureDispose(assetmanageritem_t *item);
|
80
src/dawn/file/types/common.h
Normal file
80
src/dawn/file/types/common.h
Normal file
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../../libs.h"
|
||||
#include "../../engine/thread.h"
|
||||
#include "texture.h"
|
||||
#include "font.h"
|
||||
#include "shader.h"
|
||||
#include "scaledtexture.h"
|
||||
|
||||
#define ASSET_MANAGER_ITEMS_MAX 64
|
||||
#define ASSET_MANAGER_ITEM_NAME_MAX 96
|
||||
#define ASSET_MANAGER_HOLDERS_MAX 8
|
||||
|
||||
/** States */
|
||||
#define ASSET_MANAGER_STATE_NOT_READY 0x00
|
||||
#define ASSET_MANAGER_STATE_PENDING 0x01
|
||||
#define ASSET_MANAGER_STATE_ASYNC_LOADING 0x02
|
||||
#define ASSET_MANAGER_STATE_ASYNC_ERROR 0x03
|
||||
#define ASSET_MANAGER_STATE_ASYNC_DONE 0x04
|
||||
#define ASSET_MANAGER_STATE_SYNC_LOADING 0x05
|
||||
#define ASSET_MANAGER_STATE_SYNC_ERROR 0x06
|
||||
#define ASSET_MANAGER_STATE_SYNC_DONE 0x07
|
||||
|
||||
/** Type IDs */
|
||||
#define ASSET_MANAGER_TYPE_TEXTURE 0x00
|
||||
#define ASSET_MANAGER_TYPE_FONT 0x01
|
||||
#define ASSET_MANAGER_TYPE_SHADER 0x02
|
||||
#define ASSET_MANAGER_TYPE_SCALED_TEXTURE 0x03
|
||||
|
||||
// Owner
|
||||
typedef uint8_t assetmanagerowner_t;
|
||||
|
||||
// Union of all the manager types
|
||||
typedef union {
|
||||
assetmanagertexture_t texture;
|
||||
assetmanagershader_t shader;
|
||||
assetmanagerfont_t font;
|
||||
assetmanagerscaledtexture_t scaledTexture;
|
||||
} assetmanagerassetdata_t;
|
||||
|
||||
// Item Type
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
uint8_t state;
|
||||
char key[ASSET_MANAGER_ITEM_NAME_MAX];
|
||||
assetmanagerassetdata_t data;
|
||||
assetmanagerowner_t holders[ASSET_MANAGER_HOLDERS_MAX];
|
||||
uint8_t holderCount;
|
||||
} assetmanageritem_t;
|
||||
|
||||
// Loader
|
||||
typedef bool assetmanagerloader_t(assetmanageritem_t *item);
|
||||
|
||||
// Loader Definition
|
||||
typedef struct {
|
||||
assetmanagerloader_t *loadAsync;
|
||||
assetmanagerloader_t *loadSync;
|
||||
assetmanagerloader_t *dispose;
|
||||
} assetmanagerloaderdefinition_t;
|
||||
|
||||
|
||||
|
||||
// Manager
|
||||
typedef struct {
|
||||
thread_t thread;
|
||||
bool finished;
|
||||
bool running;
|
||||
|
||||
assetmanageritem_t items[ASSET_MANAGER_ITEMS_MAX];
|
||||
uint8_t itemCount;
|
||||
|
||||
assetmanagerowner_t holders[ASSET_MANAGER_HOLDERS_MAX];
|
||||
uint8_t holderCount;
|
||||
} assetmanager_t;
|
15
src/dawn/file/types/font.h
Normal file
15
src/dawn/file/types/font.h
Normal file
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../../display/font.h"
|
||||
|
||||
typedef struct {
|
||||
font_t font;
|
||||
char *fileName;
|
||||
char *data;
|
||||
} assetmanagerfont_t;
|
18
src/dawn/file/types/scaledtexture.h
Normal file
18
src/dawn/file/types/scaledtexture.h
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../../libs.h"
|
||||
#include "../../display/texture.h"
|
||||
#include "../../display/texturescale.h"
|
||||
|
||||
typedef struct {
|
||||
texturescale_t textureScale;
|
||||
texture_t texture;
|
||||
uint8_t scale;
|
||||
pixel_t *data;
|
||||
} assetmanagerscaledtexture_t;
|
16
src/dawn/file/types/shader.h
Normal file
16
src/dawn/file/types/shader.h
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2021 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../../libs.h"
|
||||
#include "../../display/shader.h"
|
||||
|
||||
typedef struct {
|
||||
shader_t shader;
|
||||
char *fileVert;
|
||||
char *fileFrag;
|
||||
char *dataVert;
|
||||
char *dataFrag;
|
||||
} assetmanagershader_t;
|
15
src/dawn/file/types/texture.h
Normal file
15
src/dawn/file/types/texture.h
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2021 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../../libs.h"
|
||||
#include "../../display/texture.h"
|
||||
|
||||
typedef struct {
|
||||
texture_t texture;
|
||||
char *fileName;
|
||||
int32_t width, height;
|
||||
pixel_t *data;
|
||||
} assetmanagertexture_t;
|
210
src/dawn/file/xml.c
Normal file
210
src/dawn/file/xml.c
Normal file
@ -0,0 +1,210 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "xml.h"
|
||||
|
||||
int32_t xmlLoadChild(xml_t *xml, char *data, int32_t i) {
|
||||
char c;
|
||||
int32_t level = 0;
|
||||
uint8_t doing = XML_DOING_NOTHING;
|
||||
bool insideTag = false;
|
||||
char* buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
int32_t bufferLength = 0;
|
||||
|
||||
xml->value = NULL;
|
||||
xml->attributeCount = 0;
|
||||
|
||||
xml->children = malloc(sizeof(xml_t) * XML_CHILD_COUNT_MAX);
|
||||
xml->childrenCount = 0;
|
||||
|
||||
while(c = data[i++]) {
|
||||
switch(doing) {
|
||||
case XML_DOING_NOTHING:
|
||||
// Look for either an opening tag (<) or a word for a value.
|
||||
if(c == '>') continue;
|
||||
if(c == '<') {
|
||||
if(insideTag) {
|
||||
i = xmlLoadChild(xml->children + xml->childrenCount++, data, i-1);
|
||||
doing = XML_PARSING_CHILD;
|
||||
} else {
|
||||
doing = XML_PARSING_TAG_NAME;
|
||||
level++;
|
||||
insideTag = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(xmlIsWhitespace(c)) continue;
|
||||
doing = XML_PARSING_VALUE;
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_PARSING_TAG_NAME:
|
||||
// Just keep reading until we either hit a space (end of the tag name)
|
||||
// or a closing tag value, either / or >
|
||||
if(xmlIsWhitespace(c) || c == '>' || c == '/') {
|
||||
buffer[bufferLength] = '\0';
|
||||
xml->node = buffer;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
bufferLength = 0;
|
||||
if(c == '/') {
|
||||
level--;
|
||||
insideTag = false;
|
||||
doing = XML_PARSING_CLOSE;
|
||||
} else {
|
||||
doing = c == '>' ? XML_DOING_NOTHING : XML_LOOKING_FOR_ATTRIBUTE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_LOOKING_FOR_ATTRIBUTE:
|
||||
// Look until we hit either the end of a tag, or the attribute itself
|
||||
if(xmlIsWhitespace(c) || c == '>' || c == '/' || c == '=') {
|
||||
if(c == '>' || c == '/') {
|
||||
doing = XML_DOING_NOTHING;
|
||||
if(c == '/') {
|
||||
level--;
|
||||
insideTag = false;
|
||||
doing = XML_PARSING_CLOSE;
|
||||
}
|
||||
} else if(c == '=') {
|
||||
doing = XML_LOOKING_FOR_ATTRIBUTE_VALUE;
|
||||
} else {
|
||||
doing = XML_LOOKING_FOR_ATTRIBUTE;
|
||||
}
|
||||
|
||||
if(bufferLength > 0) {
|
||||
buffer[bufferLength] = '\0';
|
||||
xml->attributeNames[xml->attributeCount++] = buffer;
|
||||
xml->attributeDatas[xml->attributeCount] = NULL;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
bufferLength = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_LOOKING_FOR_ATTRIBUTE_VALUE:
|
||||
// Keep looking until we find a quote mark
|
||||
if(xmlIsWhitespace(c)) continue;
|
||||
if(c == '>' || c == '/') {
|
||||
doing = XML_DOING_NOTHING;
|
||||
insideTag = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c != '"') continue;
|
||||
doing = XML_PARSING_ATTRIBUTE_VALUE;
|
||||
break;
|
||||
|
||||
case XML_PARSING_ATTRIBUTE_VALUE:
|
||||
// Parse the attribute value until we find a quote mark.
|
||||
if(c == '"') {
|
||||
doing = XML_LOOKING_FOR_ATTRIBUTE;
|
||||
buffer[bufferLength] = '\0';
|
||||
xml->attributeDatas[xml->attributeCount - 1] = buffer;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
bufferLength = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_PARSING_VALUE:
|
||||
// Keep parsing child until we find a < for an opening/closing tag.
|
||||
if(c == '<') {
|
||||
// In HTML Spec there could be a child here but not in XML spec.
|
||||
doing = XML_PARSING_CLOSE;
|
||||
buffer[bufferLength] = '\0';
|
||||
bufferLength = 0;
|
||||
xml->value = buffer;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_PARSING_CHILD:
|
||||
if(c == '<') {
|
||||
// Read ahead and confirm this is a close or not
|
||||
if(data[i] == '/') {
|
||||
doing = XML_PARSING_CLOSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Likely another child.
|
||||
i = xmlLoadChild(xml->children + xml->childrenCount++, data, i-1);
|
||||
}
|
||||
|
||||
if(xmlIsWhitespace(c)) continue;
|
||||
|
||||
// In HTML Spec there's a chance for there to be a value here, but not
|
||||
// in the XML spec.
|
||||
break;
|
||||
|
||||
case XML_PARSING_CLOSE:
|
||||
// Just keep parsing until the tag closer finishes.
|
||||
if(c != '>') continue;
|
||||
doing = XML_DOING_NOTHING;
|
||||
|
||||
//TODO: Return index or something?
|
||||
free(buffer);
|
||||
return i;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
return i;
|
||||
}
|
||||
|
||||
void xmlLoad(xml_t *xml, char *data) {
|
||||
xmlLoadChild(xml, data, 0);
|
||||
}
|
||||
|
||||
void xmlDispose(xml_t *xml) {
|
||||
uint8_t i;
|
||||
|
||||
// Dispose children recursively
|
||||
for(i = 0; i < xml->childrenCount; i++) {
|
||||
xmlDispose(xml->children + i);
|
||||
}
|
||||
|
||||
// Free children array.
|
||||
free(xml->children);
|
||||
|
||||
// Dispose attributes
|
||||
for(i = 0; i < xml->attributeCount; i++) {
|
||||
free(xml->attributeNames[i]);
|
||||
if((xml->attributeDatas + i) != NULL) {
|
||||
free(xml->attributeDatas[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(xml->node);
|
||||
if(xml-> value != NULL) free(xml->value);
|
||||
}
|
||||
|
||||
int16_t xmlGetAttributeByName(xml_t *xml, char *name) {
|
||||
int16_t i;
|
||||
for(i = 0; i < xml->attributeCount; i++) {
|
||||
if(strcmp(xml->attributeNames[i], name) == 0) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool xmlIsWhitespace(char c) {
|
||||
return c == ' ' || c == '\r' || c == '\n' || c == '\t';
|
||||
}
|
66
src/dawn/file/xml.h
Normal file
66
src/dawn/file/xml.h
Normal file
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
|
||||
#define XML_DOING_NOTHING 0x00
|
||||
#define XML_PARSING_TAG_NAME 0x01
|
||||
#define XML_LOOKING_FOR_ATTRIBUTE 0x02
|
||||
#define XML_PARSING_ATTRIBUTE_NAME 0x03
|
||||
#define XML_LOOKING_FOR_ATTRIBUTE_VALUE 0x04
|
||||
#define XML_PARSING_ATTRIBUTE_VALUE 0x05
|
||||
#define XML_PARSING_VALUE 0x06
|
||||
#define XML_PARSING_CHILD 0x07
|
||||
#define XML_PARSING_CLOSE 0x08
|
||||
|
||||
#define XML_TEXT_BUFFER_MAX 256
|
||||
#define XML_CHILD_COUNT_MAX 16
|
||||
#define XML_ATTRIBUTE_MAX 16
|
||||
|
||||
typedef struct _xml_t xml_t;
|
||||
|
||||
typedef struct _xml_t {
|
||||
char *node;
|
||||
char *value;
|
||||
|
||||
char *attributeNames[XML_ATTRIBUTE_MAX];
|
||||
char *attributeDatas[XML_ATTRIBUTE_MAX];
|
||||
uint8_t attributeCount;
|
||||
|
||||
xml_t *children;
|
||||
uint8_t childrenCount;
|
||||
} xml_t;
|
||||
|
||||
/**
|
||||
* Load an XML child from a string buffer.
|
||||
*
|
||||
* @param xml XML to load.
|
||||
* @param data Data to parse
|
||||
* @param i Character index within the data
|
||||
* @return The index in the data string this XML node ends.
|
||||
*/
|
||||
int32_t xmlLoadChild(xml_t *xml, char *data, int32_t i);
|
||||
|
||||
/**
|
||||
* Load an XML String into an XML memory.
|
||||
*
|
||||
* @param xml XML to load into.
|
||||
* @param data XML string.
|
||||
*/
|
||||
void xmlLoad(xml_t *xml, char *data);
|
||||
|
||||
/**
|
||||
* Dispose a previously loaded XML.
|
||||
*
|
||||
* @param xml XML to dispose.
|
||||
*/
|
||||
void xmlDispose(xml_t *xml);
|
||||
|
||||
int16_t xmlGetAttributeByName(xml_t *xml, char *name);
|
||||
|
||||
bool xmlIsWhitespace(char c);
|
104
src/dawn/input/input.c
Normal file
104
src/dawn/input/input.c
Normal file
@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Msters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "input.h"
|
||||
|
||||
void inputInit(input_t *input) {
|
||||
int32_t i;
|
||||
|
||||
// Setup the bind lists
|
||||
for(i = 0; i < INPUT_BIND_COUNT; i++) {
|
||||
input->bindMap[i] = listCreate();
|
||||
}
|
||||
|
||||
input->current = input->inputsA;
|
||||
input->previous = input->inputsB;
|
||||
|
||||
// Create the buffer, zero all the values out.
|
||||
memset(input->buffer, 0, sizeof(inputval_t)*INPUT_SOURCE_COUNT);
|
||||
}
|
||||
|
||||
void inputUpdate(input_t *input) {
|
||||
int32_t i;
|
||||
listentry_t *item;
|
||||
inputval_t value;
|
||||
|
||||
// Flip the states to save memory.
|
||||
inputval_t *currentCurrent = input->current;
|
||||
input->current = input->previous;
|
||||
input->previous = currentCurrent;
|
||||
|
||||
// Now look at each bind...
|
||||
for(i = 0; i < INPUT_BIND_COUNT; i++) {
|
||||
// Now get the list of input sources bound to this input
|
||||
item = input->bindMap[i]->start;
|
||||
value = 0;
|
||||
|
||||
// For each input source, add the value from the buffer
|
||||
while(item != NULL) {
|
||||
value += input->buffer[(inputsource_t)item->data];
|
||||
item = item->next;
|
||||
}
|
||||
|
||||
// Set to the current state.
|
||||
input->current[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void inputDispose(input_t *input) {
|
||||
int32_t i;
|
||||
|
||||
// Free up the bind lists
|
||||
for(i = 0; i < INPUT_BIND_COUNT; i++) {
|
||||
listDispose(input->bindMap[i], false);
|
||||
}
|
||||
}
|
||||
|
||||
void inputBind(input_t *input, inputbind_t bind, inputsource_t source) {
|
||||
listAdd(input->bindMap[bind], (void *)source);
|
||||
}
|
||||
|
||||
void inputUnbind(input_t *input, inputbind_t bind, inputsource_t source) {
|
||||
listRemove(input->bindMap[bind], (void *)source);
|
||||
}
|
||||
|
||||
void inputStateSet(input_t *input, inputsource_t source, float value) {
|
||||
input->buffer[source] = value;
|
||||
}
|
||||
|
||||
bool inputIsDown(input_t *input, inputbind_t binding) {
|
||||
return input->current[binding] != 0;
|
||||
}
|
||||
|
||||
bool inputIsUp(input_t *input, inputbind_t binding) {
|
||||
return input->current[binding] == 0;
|
||||
}
|
||||
|
||||
bool inputIsPressed(input_t *input, inputbind_t binding) {
|
||||
return (
|
||||
input->previous[binding] == 0 &&
|
||||
input->current[binding] != 0
|
||||
);
|
||||
}
|
||||
|
||||
bool inputIsReleased(input_t *input, inputbind_t binding) {
|
||||
return input->current[binding]==0 && input->previous[binding] != 0;
|
||||
}
|
||||
|
||||
inputval_t inputGetAxis(input_t *input, inputbind_t binding) {
|
||||
return input->current[binding];
|
||||
}
|
||||
|
||||
float inputGetFullAxis(input_t *input, inputbind_t positive,
|
||||
inputbind_t negative
|
||||
) {
|
||||
return -input->current[negative] + input->current[positive];
|
||||
}
|
||||
|
||||
float inputGetAccuated(input_t *input, inputbind_t binding) {
|
||||
return input->times[binding];
|
||||
}
|
192
src/dawn/input/input.h
Normal file
192
src/dawn/input/input.h
Normal file
@ -0,0 +1,192 @@
|
||||
// Copyright (c) 2021 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/list.h"
|
||||
|
||||
/** Debug Inputs */
|
||||
#define INPUT_NULL (inputbind_t)0x00
|
||||
|
||||
/** Real Inputs (Starts at 32/0x20) */
|
||||
#define INPUT_UP (inputbind_t)0x20
|
||||
#define INPUT_DOWN (inputbind_t)0x21
|
||||
#define INPUT_LEFT (inputbind_t)0x22
|
||||
#define INPUT_RIGHT (inputbind_t)0x23
|
||||
#define INPUT_ACCEPT (inputbind_t)0x24
|
||||
|
||||
/** Additional sources */
|
||||
#define INPUT_MOUSE_X (inputsource_t)0x10
|
||||
#define INPUT_MOUSE_Y (inputsource_t)0x11
|
||||
|
||||
#define INPUT_BIND_COUNT 0x40
|
||||
#define INPUT_SOURCE_COUNT 0xFF
|
||||
|
||||
/**
|
||||
* Input Bind, a specific action bind reference for the game engine to use.
|
||||
* e.g. "Jump" or "Walk Forward".
|
||||
*/
|
||||
typedef uint8_t inputbind_t;
|
||||
|
||||
/**
|
||||
* Input source identifier. It's up to the platform itself to decide what the
|
||||
* hell this number refers to. For most platforms it will be an input, such as a
|
||||
* keyboard scancode or a (pad number * button count) + button.
|
||||
*/
|
||||
typedef uint8_t inputsource_t;
|
||||
|
||||
/**
|
||||
* Value that represents the state of an input. Defined as 0-1 where 0 is set
|
||||
* to be completely off / netural state, and 1 is completely on / full state.
|
||||
*/
|
||||
typedef float inputval_t;
|
||||
|
||||
/**
|
||||
* Structure for the entire input mapping.
|
||||
*/
|
||||
typedef struct {
|
||||
/** Float of the input between 0 and 1. */
|
||||
inputval_t inputsA[INPUT_BIND_COUNT];
|
||||
/** Float of the input between 0 and 1. */
|
||||
inputval_t inputsB[INPUT_BIND_COUNT];
|
||||
|
||||
/** Flippable state */
|
||||
inputval_t *current, *previous;
|
||||
|
||||
/**
|
||||
* Binding Map, Array of lists where index = binding and entry is a list of
|
||||
* input sources.
|
||||
*/
|
||||
list_t *bindMap[INPUT_BIND_COUNT];
|
||||
|
||||
/**
|
||||
* Input buffer array. Keeps track of raw values from the inputs.
|
||||
* The engine will read from the buffer when necessary.
|
||||
*/
|
||||
inputval_t buffer[INPUT_SOURCE_COUNT];
|
||||
|
||||
/** Float of the GameTime that the input was actuated last. */
|
||||
float times[INPUT_BIND_COUNT];
|
||||
} input_t;
|
||||
|
||||
/**
|
||||
* Initializes the input manager.
|
||||
*
|
||||
* @param input The input manager to initialize.
|
||||
*/
|
||||
void inputInit(input_t *input);
|
||||
|
||||
/**
|
||||
* Tick the input manager.
|
||||
*
|
||||
* @param input The input manager to update.
|
||||
*/
|
||||
void inputUpdate(input_t *input);
|
||||
|
||||
/**
|
||||
* Destroy the input manager and cleanup.
|
||||
*
|
||||
* @param input The input manager to dispose.
|
||||
*/
|
||||
void inputDispose(input_t *input);
|
||||
|
||||
/**
|
||||
* Binds the given input binding to the input source. Essentially allowing any
|
||||
* time we fetch the state of bind, we will read the value from source.
|
||||
*
|
||||
* @param input The input manager.
|
||||
* @param bind The binding to bind against.
|
||||
* @param source The source that is being bound.
|
||||
*/
|
||||
void inputBind(input_t *input, inputbind_t bind, inputsource_t source);
|
||||
|
||||
/**
|
||||
* Unbind a previously bound input source from a binding. This method is costly.
|
||||
*
|
||||
* @param input The input manager.
|
||||
* @param bind The binding to unbind from.
|
||||
* @param source The source that is being unbound.
|
||||
*/
|
||||
void inputUnbind(input_t *input, inputbind_t bind, inputsource_t source);
|
||||
|
||||
/**
|
||||
* Set the state of an input.
|
||||
*
|
||||
* @param input Input to set the state for.
|
||||
* @param source Source to set.
|
||||
* @param value Value to set.
|
||||
*/
|
||||
void inputStateSet(input_t *input, inputsource_t source, float value);
|
||||
|
||||
/**
|
||||
* Is the current input "down", being pressed, being moved, not in a state
|
||||
* of rest.
|
||||
*
|
||||
* @param input The input manager.
|
||||
* @param binding The previously bound input binding.
|
||||
* @return True if the input vector is non-zero.
|
||||
*/
|
||||
bool inputIsDown(input_t *input, inputbind_t binding);
|
||||
|
||||
/**
|
||||
* Is the current input "up", in a state of rest, not being actioned, moved.
|
||||
*
|
||||
* @param input The input manager.
|
||||
* @param binding The previously bound input binding.
|
||||
* @return True if input vector is zero
|
||||
*/
|
||||
bool inputIsUp(input_t *input, inputbind_t binding);
|
||||
|
||||
/**
|
||||
* Returns true on the first tick that an input was actioned/downed.
|
||||
*
|
||||
* @param input The input manager.
|
||||
* @param binding The previously bound input binding.
|
||||
* @return True if the input vector was non-zeroed this tick but not last.
|
||||
*/
|
||||
bool inputIsPressed(input_t *input, inputbind_t binding);
|
||||
|
||||
/**
|
||||
* Returns true on the first tick that an input was released/upped.
|
||||
*
|
||||
* @param input The input manager.
|
||||
* @param binding The previously bound input binding.
|
||||
* @return True if the input vector was zeroed this tick but not last.
|
||||
*/
|
||||
bool inputIsReleased(input_t *input, inputbind_t binding);
|
||||
|
||||
/**
|
||||
* Returns the raw input value as a float between 0 and 1. For digital (buttons)
|
||||
* this will typicall be 0 or 1 only. Other analogue inputs will have anywhere
|
||||
* within the range.
|
||||
*
|
||||
* @param input The input manager.
|
||||
* @param binding The previously bound input binding.
|
||||
* @return Input state of the axis.
|
||||
*/
|
||||
inputval_t inputGetAxis(input_t *input, inputbind_t binding);
|
||||
|
||||
/**
|
||||
* Returns a raw input value between -1 and 1 between two axis. This would be
|
||||
* indicitive of having an input with an axis that can be moved one direction
|
||||
* for a positive input and another for a negative input, typically a game
|
||||
* controller's analogue sticks.
|
||||
*
|
||||
* @param input The input manager.
|
||||
* @param postitive The positive axis binding.
|
||||
* @param negative The negative axis binding.
|
||||
* @return A float between -1 and 1 representing the result of both.
|
||||
*/
|
||||
float inputGetFullAxis(input_t *input, inputbind_t positive, inputbind_t negative);
|
||||
|
||||
/**
|
||||
* Returns the time that an input was actuated at. Actuate would count as a
|
||||
* non-zero input for analogue inputs.
|
||||
*
|
||||
* @param input The input manager.
|
||||
* @param binding The previously bound input binding.
|
||||
* @return Game Engine time that an input was non-zeroed
|
||||
*/
|
||||
float inputGetAccuated(input_t *input, inputbind_t binding);
|
44
src/dawn/libs.h
Normal file
44
src/dawn/libs.h
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2021 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
// Static Libs
|
||||
#include <glad/glad.h>
|
||||
#include <duktape.h>
|
||||
#include <cglm/cglm.h>
|
||||
#include <stb_image.h>
|
||||
#include <stb_truetype.h>
|
||||
|
||||
// Standard Libs
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
// Windows Fixes
|
||||
# define strtok_r strtok_s
|
||||
# define sleep(n) _sleep(n)
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
typedef HANDLE threadhandle_t;
|
||||
#define sysThreadCreate(mthd,otp,usr) otp=CreateThread(NULL,0,mthd,usr,0,NULL)
|
||||
#define sysThreadJoin(tp) WaitForSingleObject(tp, INFINITE)
|
||||
#define sysThreadCancel(tp,ec) TerminateThread(tp,ec)
|
||||
#else
|
||||
// Unix Fixes
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
typedef pthread_t threadhandle_t;
|
||||
#define sysThreadCreate(mthd,otp,usr) pthread_create(&otp,NULL,mthd,usr)
|
||||
#define sysThreadJoin(tp) pthread_join(tp, NULL)
|
||||
#define sysThreadCancel(tp,ec) pthread_cancel(tp)
|
||||
#endif
|
58
src/dawn/locale/language.c
Normal file
58
src/dawn/locale/language.c
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "language.h"
|
||||
|
||||
void languageInit(language_t *language, char *filename) {
|
||||
// Open the asset buffer
|
||||
language->asset = assetBufferOpen(filename);
|
||||
|
||||
// Get the headers
|
||||
csvHeadersGet(language->asset, &language->header);
|
||||
|
||||
// Get the row indexes
|
||||
language->headerIndexKey = csvColumnGetIndex(
|
||||
&language->header, LANGUAGE_HEADER_KEY
|
||||
);
|
||||
language->headerIndexValue = csvColumnGetIndex(
|
||||
&language->header, LANGUAGE_HEADER_VALUE
|
||||
);
|
||||
}
|
||||
|
||||
int32_t languageGet(
|
||||
language_t *language, char *key, char output[CSV_CELL_SIZE_MAX]
|
||||
) {
|
||||
csvrow_t row;
|
||||
// Reset the buffer
|
||||
assetBufferStart(language->asset);
|
||||
|
||||
// Search the CSV
|
||||
int32_t rowIndex = csvRowSearch(
|
||||
language->asset, &row, language->headerIndexKey, key
|
||||
);
|
||||
if(rowIndex == -1) return rowIndex;// Didn't find anything
|
||||
|
||||
// Copy the string
|
||||
arrayCopy(
|
||||
sizeof(char), row.columns[language->headerIndexValue],
|
||||
CSV_CELL_SIZE_MAX, output
|
||||
);
|
||||
return rowIndex;
|
||||
}
|
||||
|
||||
int32_t languageGetAndParse(language_t *language, char *key,
|
||||
stringhandlebarvariable_t *variables, int32_t variableCount, char *buffer
|
||||
) {
|
||||
char csvBuffer[CSV_CELL_SIZE_MAX];
|
||||
int32_t i = languageGet(language, key, csvBuffer);
|
||||
if(i == -1) return -1;
|
||||
return stringHandlebarsBuffer(csvBuffer, variables, variableCount, buffer);
|
||||
}
|
||||
|
||||
void languageDispose(language_t *language) {
|
||||
assetBufferClose(language->asset);
|
||||
}
|
74
src/dawn/locale/language.h
Normal file
74
src/dawn/locale/language.h
Normal file
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/string.h"
|
||||
#include "../file/asset.h"
|
||||
#include "../file/csv.h"
|
||||
|
||||
/** Column name for the KEY within the CSV */
|
||||
#define LANGUAGE_HEADER_KEY "Key"
|
||||
/** Column name for the VALUE within the CSV */
|
||||
#define LANGUAGE_HEADER_VALUE "Value"
|
||||
|
||||
/** Definition for a Language */
|
||||
typedef struct {
|
||||
/** The buffer to read the asset from. */
|
||||
assetbuffer_t *asset;
|
||||
/** CSV Row for the header */
|
||||
csvrow_t header;
|
||||
/** The index in the header row that the key column is in. */
|
||||
int32_t headerIndexKey;
|
||||
/** The index in the header row that the value column is in. */
|
||||
int32_t headerIndexValue;
|
||||
} language_t;
|
||||
|
||||
typedef struct {
|
||||
language_t *language;
|
||||
csvrow_t *row;
|
||||
char *key;
|
||||
} languagecsvget_t;
|
||||
|
||||
/**
|
||||
* Initializes a language.
|
||||
* @param language Language to initialize.
|
||||
* @param filename The filename of the asset that the language uses.
|
||||
*/
|
||||
void languageInit(language_t *language, char *filename);
|
||||
|
||||
/**
|
||||
* Get the value for a given key out of the language buffer.
|
||||
*
|
||||
* @param language Language to get from.
|
||||
* @param key Key to get.
|
||||
* @param output Output buffer to return.
|
||||
* @return Row within the CSV it was found, otherwise -1.
|
||||
*/
|
||||
int32_t languageGet(
|
||||
language_t *language, char *key, char output[CSV_CELL_SIZE_MAX]
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the parsed handlebars out of the language CSV.
|
||||
*
|
||||
* @param language Language to buffer from.
|
||||
* @param key Key to get out of the CSV.
|
||||
* @param variables Array of variables to parse the handlebars with.
|
||||
* @param variableCount Count of variables in the array.
|
||||
* @param buffer Buffer to store the output data in.
|
||||
* @return Forwarded result of stringHandlebarsBuffer.
|
||||
*/
|
||||
int32_t languageGetAndParse(language_t *language, char *key,
|
||||
stringhandlebarvariable_t *variables, int32_t variableCount, char *buffer
|
||||
);
|
||||
|
||||
/**
|
||||
* Cleanup a previously initialized language.
|
||||
* @param language Language to dispose.
|
||||
*/
|
||||
void languageDispose(language_t *language);
|
56
src/dawn/physics/aabb.c
Normal file
56
src/dawn/physics/aabb.c
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "aabb.h"
|
||||
|
||||
bool aabbPoint2D(
|
||||
float pointX, float pointY,
|
||||
float x, float y, float width, float height,
|
||||
aabbpointhit2d_t *hit
|
||||
) {
|
||||
|
||||
float dx, px, sx, halfWidth;
|
||||
float dy, py, sy, halfHeight;
|
||||
|
||||
if(hit == NULL) {
|
||||
// Check X Axis, are we outside the box
|
||||
if(pointX < x || pointY < y) return false;
|
||||
if(pointX > x+width || pointY > y+height) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
halfWidth = width / 2;
|
||||
halfHeight = height / 2;
|
||||
x += halfWidth;
|
||||
y += halfHeight;
|
||||
|
||||
dx = pointX - x;
|
||||
px = halfWidth - mathAbs(dx);
|
||||
if(px <= 0) return false;
|
||||
|
||||
dy = pointY - y;
|
||||
py = halfHeight - mathAbs(dy);
|
||||
if(py <= 0) return false;
|
||||
|
||||
if(px < py) {
|
||||
sx = mathSign(dx);
|
||||
// float deltaX = px *sx;
|
||||
hit->normalX = sx;
|
||||
hit->normalY = 0;
|
||||
hit->hitX = x + (halfWidth * sx);
|
||||
hit->hitY = pointY;
|
||||
} else {
|
||||
sy = mathSign(dy);
|
||||
// float deltaY = py * sy;
|
||||
hit->normalX = 0;
|
||||
hit->normalY = sy;
|
||||
hit->hitX = pointX;
|
||||
hit->hitY = x + (halfHeight * sy);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
48
src/dawn/physics/aabb.h
Normal file
48
src/dawn/physics/aabb.h
Normal file
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "sphere.h"
|
||||
#include "../input/input.h"
|
||||
#include "../util/math.h"
|
||||
|
||||
typedef struct {
|
||||
float hitX;
|
||||
float hitY;
|
||||
|
||||
float normalX;
|
||||
float normalY;
|
||||
} aabbpointhit2d_t;
|
||||
|
||||
typedef struct {
|
||||
float time;
|
||||
|
||||
float normalX;
|
||||
float normalY;
|
||||
|
||||
float hitX;
|
||||
float hitY;
|
||||
} aabbvectorhit2d_t;
|
||||
|
||||
/**
|
||||
* Perform a test against a point and an AABB.
|
||||
*
|
||||
* @param pointX Point X coordinate.
|
||||
* @param pointY Point Y coordinate.
|
||||
* @param x Box X coordinate.
|
||||
* @param y Box Y coordinate.
|
||||
* @param width Box width.
|
||||
* @param height Box height.
|
||||
* @param hit Pointer to hit information to store result in, or NULL for none.
|
||||
* @return True if a hit occured, otherwise false.
|
||||
*/
|
||||
bool aabbPoint2D(
|
||||
float pointX, float pointY,
|
||||
float x, float y, float width, float height,
|
||||
aabbpointhit2d_t *hit
|
||||
);
|
20
src/dawn/physics/sphere.c
Normal file
20
src/dawn/physics/sphere.c
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "sphere.h"
|
||||
|
||||
bool sphereDistance2D(float x0, float y0, float x1, float y1, float radius) {
|
||||
x0 = vectorDistance2D(x0, y0, x1, y1);
|
||||
return x0 <= radius;
|
||||
}
|
||||
|
||||
bool sphereDistance3D(
|
||||
float x0, float y0, float z0, float x1, float y1, float z1, float radius
|
||||
) {
|
||||
x0 = vectorDistance3D(x0, y0, z0, x1, y1, z1);
|
||||
return x0 <= radius;
|
||||
}
|
38
src/dawn/physics/sphere.h
Normal file
38
src/dawn/physics/sphere.h
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "vector.h"
|
||||
|
||||
/**
|
||||
* Checks whether a point is colliding with a circle.
|
||||
*
|
||||
* @param x0 X Position of the vector.
|
||||
* @param y0 Y position of the vector.
|
||||
* @param x1 Center point of the circle. X Coordinate.
|
||||
* @param y1 Center point of the circle. Y Coordinate.
|
||||
* @param radius Radius of the circle
|
||||
* @return True if the point is colliding, otherwise false.
|
||||
*/
|
||||
bool sphereDistance2D(float x0, float y0, float x1, float y1, float radius);
|
||||
|
||||
/**
|
||||
* Checks whether a point is colliding with a sphere.
|
||||
*
|
||||
* @param x0 X Position of the vector.
|
||||
* @param y0 Y Position of the vector.
|
||||
* @param z0 Z Position of the vector.
|
||||
* @param x1 Center point of the circle, X Coordinate.
|
||||
* @param y1 Center point of the circle, Y Coordinate.
|
||||
* @param z1 Center point of the circle, Z Coordinate.
|
||||
* @param radius Radius of the sphere.
|
||||
* @return True if the point is colliding with the sphere.
|
||||
*/
|
||||
bool sphereDistance3D(
|
||||
float x0, float y0, float z0, float x1, float y1, float z1, float radius
|
||||
);
|
24
src/dawn/physics/vector.c
Normal file
24
src/dawn/physics/vector.c
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "vector.h"
|
||||
|
||||
float vectorDistance2D(float x0, float y0, float x1, float y1) {
|
||||
x0 = x1 - x0;
|
||||
y0 = y1 - y0;
|
||||
return (float)sqrt(x0*x0 + y0*y0);
|
||||
}
|
||||
|
||||
|
||||
float vectorDistance3D(
|
||||
float x0, float y0, float z0, float x1, float y1, float z1
|
||||
) {
|
||||
x0 = x1 - x0;
|
||||
y0 = y1 - y0;
|
||||
z0 = z1 - z0;
|
||||
return (float)sqrt(x0*x0 + y0*y0 + z0*z0);
|
||||
}
|
35
src/dawn/physics/vector.h
Normal file
35
src/dawn/physics/vector.h
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
|
||||
/**
|
||||
* Calculate the distance between two points in 2D space.
|
||||
*
|
||||
* @param x0 First Position X Coordinate.
|
||||
* @param y0 First Position Y Coordinate.
|
||||
* @param x1 Second Position X Coordinate.
|
||||
* @param y1 Second Position Y Coordinate.
|
||||
* @return The distance measurement.
|
||||
*/
|
||||
float vectorDistance2D(float x0, float y0, float x1, float y1);
|
||||
|
||||
/**
|
||||
* Calculate the distance between two points in 3D space.
|
||||
*
|
||||
* @param x0 First Position X Coordinate.
|
||||
* @param y0 First Position Y Coordinate.
|
||||
* @param z0 First Position Z Coordinate.
|
||||
* @param x1 Second Position X Coordinate.
|
||||
* @param y1 Second Position Y Coordinate.
|
||||
* @param z1 Second Position Z Coordinate.
|
||||
* @return The distance measurement.
|
||||
*/
|
||||
float vectorDistance3D(
|
||||
float x0, float y0, float z0, float x1, float y1, float z1
|
||||
);
|
65
src/dawn/poker/bet.c
Normal file
65
src/dawn/poker/bet.c
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "bet.h"
|
||||
|
||||
uint8_t pokerBetGetNextPlayer(poker_t *poker) {
|
||||
uint8_t i, j;
|
||||
for(i = 0; i < poker->playerCount; i++) {
|
||||
j = (i + poker->better + 1) % poker->playerCount;
|
||||
if(pokerPlayerDoesNeedToBetThisRound(poker, j)) return j;
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
uint8_t pokerBetGetRemainingBetterCount(poker_t *poker) {
|
||||
uint8_t i, count;
|
||||
count = 0;
|
||||
for(i = 0; i < poker->playerCount; i++) {
|
||||
if(!pokerPlayerDoesNeedToBetThisRound(poker, i)) continue;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void pokerBet(
|
||||
poker_t *poker, pokerpot_t *pot, uint8_t playerIndex, int32_t chips
|
||||
) {
|
||||
pokerplayer_t *player;
|
||||
player = poker->players + playerIndex;
|
||||
|
||||
player->chips -= chips;
|
||||
player->currentBet += chips;
|
||||
|
||||
pot->chips += chips;
|
||||
pot->call = mathMax(pot->call, player->currentBet);
|
||||
pokerPotAddPlayer(pot, playerIndex);
|
||||
|
||||
player->state |= POKER_PLAYER_STATE_HAS_BET_THIS_ROUND;
|
||||
if(chips > 0) player->timesRaised++;
|
||||
}
|
||||
|
||||
void pokerBetForPlayer(poker_t *poker, uint8_t playerIndex, int32_t chips) {
|
||||
pokerBet(
|
||||
poker, poker->pots + (poker->potCount - 1), playerIndex, chips
|
||||
);
|
||||
}
|
||||
|
||||
int32_t pokerBetGetCurrentCallValue(poker_t *poker) {
|
||||
uint8_t i;
|
||||
int32_t call;
|
||||
call = 0;
|
||||
for(i = 0; i < poker->potCount; i++) {
|
||||
call = mathMax(call, poker->pots[i].call);
|
||||
}
|
||||
return call;
|
||||
}
|
||||
|
||||
//eh
|
||||
int32_t pokerPlayerGetCallBet(poker_t *poker, pokerplayer_t *player) {
|
||||
return pokerBetGetCurrentCallValue(poker) - player->currentBet;
|
||||
}
|
71
src/dawn/poker/bet.h
Normal file
71
src/dawn/poker/bet.h
Normal file
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/math.h"
|
||||
#include "common.h"
|
||||
#include "player.h"
|
||||
#include "pot.h"
|
||||
|
||||
/**
|
||||
* Returns the index of the first player that remains to bet for the current
|
||||
* round. This is based on whatever current better player index you provide.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param current Current better player index.
|
||||
* @return The player index of the next remaining player, otherwise 0xFF.
|
||||
*/
|
||||
uint8_t pokerBetGetNextPlayer(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Returns the count of players remaining to bet.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @return Count of players left to bet.
|
||||
*/
|
||||
uint8_t pokerBetGetRemainingBetterCount(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Let a player bet chips into the pot.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param pot Poker pot to bet in to.
|
||||
* @param playerIndex The players' index that is betting.
|
||||
* @param chips The amount of chips the player is betting.
|
||||
*/
|
||||
void pokerBet(
|
||||
poker_t *poker, pokerpot_t *pot, uint8_t playerIndex, int32_t chips
|
||||
);
|
||||
|
||||
/**
|
||||
* Let a player bet chips into the current pot.
|
||||
*
|
||||
* @param bet Poker game instance.
|
||||
* @param playerIndex The players' index that is betting.
|
||||
* @param chips The amount of chips the player is betting.
|
||||
*/
|
||||
void pokerBetForPlayer(poker_t *poker, uint8_t playerIndex, int32_t chips);
|
||||
|
||||
/**
|
||||
* Gets the amount of chips necessary to call the current bet.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @return Chips necessary to call the current bet.
|
||||
*/
|
||||
int32_t pokerBetGetCurrentCallValue(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Get the bet necessary for a specific player to make a call. This takes the
|
||||
* players current bet and the bet necessary to call into the pot and will
|
||||
* return the difference.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param player Player instance to get the call value for.
|
||||
* @return The count of chips needed to call into the current active pot.
|
||||
*/
|
||||
int32_t pokerPlayerGetCallBet(poker_t *poker, pokerplayer_t *player);
|
98
src/dawn/poker/card.c
Normal file
98
src/dawn/poker/card.c
Normal file
@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#include "card.h"
|
||||
|
||||
void cardDeal(
|
||||
card_t *source, uint8_t *sourceSize, card_t *dest, uint8_t *destSize
|
||||
) {
|
||||
card_t card;
|
||||
uint8_t i;
|
||||
|
||||
// Take Card
|
||||
i = *sourceSize - 1;
|
||||
card = source[i];
|
||||
*sourceSize = i;
|
||||
|
||||
// Put card
|
||||
i = *destSize;
|
||||
dest[i] = card;
|
||||
*destSize = i+1;
|
||||
}
|
||||
|
||||
void cardHandSort(card_t *cards, uint8_t length) {
|
||||
arraySort(sizeof(card_t), cards, (int32_t)length, (arraysort_t *)&_cardSorter);
|
||||
}
|
||||
|
||||
int32_t _cardSorter(const void* left, const void* right) {
|
||||
card_t cardL = *((card_t *)left);
|
||||
card_t cardR = *((card_t *)right);
|
||||
|
||||
uint8_t suitL = cardGetSuit(cardL);
|
||||
uint8_t suitR = cardGetSuit(cardR);
|
||||
if(suitL != suitR) return suitL - suitR;
|
||||
|
||||
uint8_t numberL = cardGetNumber(cardL);
|
||||
uint8_t numberR = cardGetNumber(cardR);
|
||||
|
||||
// Get the suit and the value of the card (reversed)
|
||||
return numberR - numberL;
|
||||
}
|
||||
|
||||
int32_t cardContains(card_t *hand, uint8_t length, card_t card) {
|
||||
return arrayFind(sizeof(card_t), hand, (int32_t)length, &card);
|
||||
}
|
||||
|
||||
int32_t cardContainsNumber(card_t *hand, uint8_t length, uint8_t number) {
|
||||
int32_t i;
|
||||
for(i = 0; i < length; i++) {
|
||||
if(cardGetNumber(hand[i]) == number) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t cardCountPairs(card_t *in, uint8_t inCount, uint8_t number,
|
||||
int32_t out[CARD_SUIT_COUNT]
|
||||
) {
|
||||
uint8_t i, count;
|
||||
|
||||
count = 0;
|
||||
for(i = 0; i < inCount; i++) {// "For each suit"
|
||||
if(cardGetNumber(in[i]) != number) continue;
|
||||
out[count++] = i;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void cardShuffle(card_t *hand, uint8_t length) {
|
||||
arrayShuffle(sizeof(card_t), hand, length);
|
||||
}
|
||||
|
||||
uint8_t cardWriteDeck(card_t *hand) {
|
||||
uint8_t i;
|
||||
for(i = 0; i < CARD_DECK_SIZE; i++) hand[i] = i;
|
||||
return CARD_DECK_SIZE;
|
||||
}
|
||||
|
||||
card_t cardGetHighest(card_t *cards, uint8_t cardCount) {
|
||||
uint8_t i, number, bestNumber;
|
||||
card_t card, bestCard;
|
||||
|
||||
bestNumber = 0xFF;
|
||||
|
||||
for(i = 0; i < cardCount; i++) {
|
||||
card = cards[i];
|
||||
number = cardGetNumber(card);
|
||||
if(number == CARD_ACE) return card;
|
||||
if(bestNumber != 0xFF && number <= bestNumber) continue;
|
||||
|
||||
bestCard = card;
|
||||
bestNumber = number;
|
||||
}
|
||||
|
||||
return bestCard;
|
||||
}
|
214
src/dawn/poker/card.h
Normal file
214
src/dawn/poker/card.h
Normal file
@ -0,0 +1,214 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/array.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Cards
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Aces
|
||||
#define CARD_CLUBS_TWO 0x00
|
||||
#define CARD_CLUBS_THREE 0x01
|
||||
#define CARD_CLUBS_FOUR 0x02
|
||||
#define CARD_CLUBS_FIVE 0x03
|
||||
#define CARD_CLUBS_SIX 0x04
|
||||
#define CARD_CLUBS_SEVEN 0x05
|
||||
#define CARD_CLUBS_EIGHT 0x06
|
||||
#define CARD_CLUBS_NINE 0x07
|
||||
#define CARD_CLUBS_TEN 0x08
|
||||
#define CARD_CLUBS_JACK 0x09
|
||||
#define CARD_CLUBS_QUEEN 0x0A
|
||||
#define CARD_CLUBS_KING 0x0B
|
||||
#define CARD_CLUBS_ACE 0x0C
|
||||
|
||||
// Diamonds
|
||||
#define CARD_DIAMONDS_TWO 0x0D
|
||||
#define CARD_DIAMONDS_THREE 0x0E
|
||||
#define CARD_DIAMONDS_FOUR 0x0F
|
||||
#define CARD_DIAMONDS_FIVE 0x10
|
||||
#define CARD_DIAMONDS_SIX 0x11
|
||||
#define CARD_DIAMONDS_SEVEN 0x12
|
||||
#define CARD_DIAMONDS_EIGHT 0x13
|
||||
#define CARD_DIAMONDS_NINE 0x14
|
||||
#define CARD_DIAMONDS_TEN 0x15
|
||||
#define CARD_DIAMONDS_JACK 0x16
|
||||
#define CARD_DIAMONDS_QUEEN 0x17
|
||||
#define CARD_DIAMONDS_KING 0x18
|
||||
#define CARD_DIAMONDS_ACE 0x19
|
||||
|
||||
// Hearts
|
||||
#define CARD_HEARTS_TWO 0x1A
|
||||
#define CARD_HEARTS_THREE 0x1B
|
||||
#define CARD_HEARTS_FOUR 0x1C
|
||||
#define CARD_HEARTS_FIVE 0x1D
|
||||
#define CARD_HEARTS_SIX 0x1E
|
||||
#define CARD_HEARTS_SEVEN 0x1F
|
||||
#define CARD_HEARTS_EIGHT 0x20
|
||||
#define CARD_HEARTS_NINE 0x21
|
||||
#define CARD_HEARTS_TEN 0x22
|
||||
#define CARD_HEARTS_JACK 0x23
|
||||
#define CARD_HEARTS_QUEEN 0x24
|
||||
#define CARD_HEARTS_KING 0x25
|
||||
#define CARD_HEARTS_ACE 0x26
|
||||
|
||||
// Spades
|
||||
#define CARD_SPADES_TWO 0x27
|
||||
#define CARD_SPADES_THREE 0x28
|
||||
#define CARD_SPADES_FOUR 0x29
|
||||
#define CARD_SPADES_FIVE 0x2A
|
||||
#define CARD_SPADES_SIX 0x2B
|
||||
#define CARD_SPADES_SEVEN 0x2C
|
||||
#define CARD_SPADES_EIGHT 0x2D
|
||||
#define CARD_SPADES_NINE 0x2E
|
||||
#define CARD_SPADES_TEN 0x2F
|
||||
#define CARD_SPADES_JACK 0x30
|
||||
#define CARD_SPADES_QUEEN 0x31
|
||||
#define CARD_SPADES_KING 0x32
|
||||
#define CARD_SPADES_ACE 0x33
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Suits
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define CARD_SUIT_CLUBS 0x00
|
||||
#define CARD_SUIT_DIAMONDS 0x01
|
||||
#define CARD_SUIT_HEARTS 0x02
|
||||
#define CARD_SUIT_SPADES 0x03
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Card numbers
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define CARD_TWO 0x00
|
||||
#define CARD_THREE 0x01
|
||||
#define CARD_FOUR 0x02
|
||||
#define CARD_FIVE 0x03
|
||||
#define CARD_SIX 0x04
|
||||
#define CARD_SEVEN 0x05
|
||||
#define CARD_EIGHT 0x06
|
||||
#define CARD_NINE 0x07
|
||||
#define CARD_TEN 0x08
|
||||
#define CARD_JACK 0x09
|
||||
#define CARD_QUEEN 0x0A
|
||||
#define CARD_KING 0x0B
|
||||
#define CARD_ACE 0x0C
|
||||
|
||||
/** Count of cards in each suit */
|
||||
#define CARD_COUNT_PER_SUIT 13
|
||||
|
||||
/** Count of suits */
|
||||
#define CARD_SUIT_COUNT 4
|
||||
|
||||
/** Standard Card Deck Size */
|
||||
#define CARD_DECK_SIZE 52
|
||||
|
||||
/** Type Representing a card's id */
|
||||
typedef uint8_t card_t;
|
||||
|
||||
/**
|
||||
* Returns the suit of a given card.
|
||||
* @param card to get the suit for.
|
||||
* @returns The suit.
|
||||
*/
|
||||
#define cardGetSuit(card) (card / CARD_COUNT_PER_SUIT)
|
||||
|
||||
/**
|
||||
* Returns the number of a given card.
|
||||
* @param card The card to get the number for.
|
||||
* @returns The card number.
|
||||
*/
|
||||
#define cardGetNumber(card) (card % CARD_COUNT_PER_SUIT)
|
||||
|
||||
/**
|
||||
* Returns the card number for a given suit.
|
||||
* @param number The number to get.
|
||||
* @param suit The suit to get.
|
||||
* @returns The card for this suit and number combo.
|
||||
*/
|
||||
#define cardGet(number, suit) ((suit * CARD_COUNT_PER_SUIT) + number)
|
||||
|
||||
/**
|
||||
* Deals a card from an array source to an array destination. Pointers to array
|
||||
* lengths will be updated.
|
||||
*
|
||||
* @param source Array source.
|
||||
* @param sourceSize Pointer to where the count of cards is being stored.
|
||||
* @param dest Array destination.
|
||||
* @param destSize Pointer to the size of the destination array.
|
||||
*/
|
||||
void cardDeal(
|
||||
card_t *source, uint8_t *sourceSize, card_t *dest, uint8_t *destSize
|
||||
);
|
||||
|
||||
/**
|
||||
* Sort a hand of cards. Cards are ordered in descending weight, aces are high.
|
||||
* Cards will be grouped by their suits, e.g. CARD_CLUBS_TWO will appear before
|
||||
* CARD_DIAMONDS_KING.
|
||||
*
|
||||
* @param cards Hand of cards to sort.
|
||||
* @param length Length of the array of cards.
|
||||
*/
|
||||
void cardHandSort(card_t *cards, uint8_t length);
|
||||
int32_t _cardSorter(const void* left, const void* right);
|
||||
|
||||
/**
|
||||
* Check if an array of cards contains a specific card.
|
||||
*
|
||||
* @param hand Hand/Array of cards to check.
|
||||
* @param length Length of the array of cards.
|
||||
* @param card Card to look for
|
||||
* @returns The index within the array that the card is. -1 if not found.
|
||||
*/
|
||||
int32_t cardContains(card_t *hand, uint8_t length, card_t card);
|
||||
|
||||
/**
|
||||
* Check if the array of cards contains a specific number.
|
||||
*
|
||||
* @param hand Array of cards to check
|
||||
* @param length Length of the array.
|
||||
* @param number The number to look for.
|
||||
* @returns The index within the array that the first card is. -1 if not found.
|
||||
*/
|
||||
int32_t cardContainsNumber(card_t *hand, uint8_t length, uint8_t number);
|
||||
|
||||
/**
|
||||
* Counts the amount of times a card's number appears within the given hand.
|
||||
*
|
||||
* @param in The hand to check
|
||||
* @param inCount How big the hand being checked is
|
||||
* @param number The number to look for.
|
||||
* @param out The indexes within the hand array for each card matching.
|
||||
* @return How many cards in the pair, e.g. 3 for Three of a kind, 4 for full.
|
||||
*/
|
||||
uint8_t cardCountPairs(
|
||||
card_t *in, uint8_t inCount, uint8_t number, int32_t out[4]
|
||||
);
|
||||
|
||||
/**
|
||||
* Shuffles a hand / deck
|
||||
*
|
||||
* @param hand Hand to shuffle.
|
||||
* @param length Length of the hand to shuffle.
|
||||
*/
|
||||
void cardShuffle(card_t *hand, uint8_t length);
|
||||
|
||||
/**
|
||||
* Write an entire deck of cards (in order) to a given hand.
|
||||
*
|
||||
* @param hand Hand to write the deck to.
|
||||
* @return The count of cards in the deck.
|
||||
*/
|
||||
uint8_t cardWriteDeck(card_t *hand);
|
||||
|
||||
/**
|
||||
* Get the highest card from a hand of cards.
|
||||
*
|
||||
* @param cards Array of cards.
|
||||
* @param cardCount Length of the array.
|
||||
* @return The highest card in the array.
|
||||
*/
|
||||
card_t cardGetHighest(card_t *cards, uint8_t cardCount);
|
184
src/dawn/poker/common.h
Normal file
184
src/dawn/poker/common.h
Normal file
@ -0,0 +1,184 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/flags.h"
|
||||
#include "card.h"
|
||||
|
||||
/** Maximum number of players that the game state can support */
|
||||
#define POKER_PLAYER_COUNT_MAX 5
|
||||
|
||||
/** Maximum cards a players' hand can hold */
|
||||
#define POKER_PLAYER_HAND_SIZE_MAX 2
|
||||
|
||||
/** Player States */
|
||||
#define POKER_PLAYER_STATE_FOLDED flagDefine(0)
|
||||
#define POKER_PLAYER_STATE_OUT flagDefine(1)
|
||||
#define POKER_PLAYER_STATE_HAS_BET_THIS_ROUND flagDefine(2)
|
||||
#define POKER_PLAYER_STATE_SHOWING flagDefine(3)
|
||||
|
||||
/** Maximum number of cards that the grave can hold */
|
||||
#define POKER_GRAVE_SIZE_MAX CARD_DECK_SIZE
|
||||
|
||||
/** Maximum number of community cards */
|
||||
#define POKER_COMMUNITY_SIZE_MAX 5
|
||||
|
||||
/** Maximum number of pots in the poker game. */
|
||||
#define POKER_POT_COUNT_MAX POKER_PLAYER_COUNT_MAX
|
||||
|
||||
/** Maximum number of cards a winning state can hold. */
|
||||
#define POKER_WINNING_FULL_SIZE (\
|
||||
POKER_PLAYER_HAND_SIZE_MAX + POKER_COMMUNITY_SIZE_MAX\
|
||||
)
|
||||
|
||||
/** How many cards in the winning set */
|
||||
#define POKER_WINNING_SET_SIZE 5
|
||||
|
||||
/** Winning Types */
|
||||
#define POKER_WINNING_TYPE_NULL 0x00
|
||||
#define POKER_WINNING_TYPE_ROYAL_FLUSH 0x01
|
||||
#define POKER_WINNING_TYPE_STRAIGHT_FLUSH 0x02
|
||||
#define POKER_WINNING_TYPE_FOUR_OF_A_KIND 0x03
|
||||
#define POKER_WINNING_TYPE_FULL_HOUSE 0x04
|
||||
#define POKER_WINNING_TYPE_FLUSH 0x05
|
||||
#define POKER_WINNING_TYPE_STRAIGHT 0x06
|
||||
#define POKER_WINNING_TYPE_THREE_OF_A_KIND 0x07
|
||||
#define POKER_WINNING_TYPE_TWO_PAIR 0x08
|
||||
#define POKER_WINNING_TYPE_PAIR 0x09
|
||||
#define POKER_WINNING_TYPE_HIGH_CARD 0x0A
|
||||
|
||||
#define POKER_WINNING_CONFIDENCE_ROYAL_FLUSH 1.0f
|
||||
#define POKER_WINNING_CONFIDENCE_STRAIGHT_FLUSH 0.99f
|
||||
#define POKER_WINNING_CONFIDENCE_FOUR_OF_A_KIND 0.9f
|
||||
#define POKER_WINNING_CONFIDENCE_FULL_HOUSE 0.85f
|
||||
#define POKER_WINNING_CONFIDENCE_FLUSH 0.8f
|
||||
#define POKER_WINNING_CONFIDENCE_STRAIGHT 0.7f
|
||||
#define POKER_WINNING_CONFIDENCE_THREE_OF_A_KIND 0.5f
|
||||
#define POKER_WINNING_CONFIDENCE_TWO_PAIR 0.4f
|
||||
#define POKER_WINNING_CONFIDENCE_PAIR 0.2f
|
||||
#define POKER_WINNING_CONFIDENCE_HIGH_CARD 0.1f
|
||||
|
||||
#define POKER_WORLD_DEALER_INDEX 0x02
|
||||
#define POKER_WORLD_HUMAN_INDEX 0x02
|
||||
|
||||
/** Turn Types */
|
||||
#define POKER_TURN_TYPE_OUT 0x00
|
||||
#define POKER_TURN_TYPE_FOLD 0x01
|
||||
#define POKER_TURN_TYPE_BET 0x02
|
||||
#define POKER_TURN_TYPE_CALL 0x03
|
||||
#define POKER_TURN_TYPE_ALL_IN 0x04
|
||||
#define POKER_TURN_TYPE_CALL_ALL_IN 0x04
|
||||
#define POKER_TURN_TYPE_CHECK 0x05
|
||||
|
||||
#define POKER_TURN_MAX_RAISES 0x02
|
||||
|
||||
/** How many chips each player has by defautl */
|
||||
#define POKER_BET_PLAYER_CHIPS_DEFAULT 1200
|
||||
/** The default blind cost for the big blind. */
|
||||
#define POKER_BET_BLIND_BIG_DEFAULT 600
|
||||
/** The default blind cost for the small blind. (Defaults half big blind) */
|
||||
#define POKER_BET_BLIND_SMALL_DEFAULT (POKER_BET_BLIND_BIG_DEFAULT/2)
|
||||
|
||||
/** How many cards are dealt for the flop, turn and river */
|
||||
#define POKER_FLOP_CARD_COUNT 3
|
||||
#define POKER_TURN_CARD_COUNT 1
|
||||
#define POKER_RIVER_CARD_COUNT 1
|
||||
|
||||
/** How many cards the dealer should burn before dealing the flop */
|
||||
#define POKER_FLOP_BURN_COUNT 1
|
||||
|
||||
typedef struct {
|
||||
/** Count of chips the player has */
|
||||
int32_t chips;
|
||||
|
||||
/** Cards in the players' hand */
|
||||
card_t cards[POKER_PLAYER_HAND_SIZE_MAX];
|
||||
uint8_t cardCount;
|
||||
|
||||
/** Players current state */
|
||||
uint8_t state;
|
||||
|
||||
/** Current bet that the player has done. */
|
||||
int32_t currentBet;
|
||||
|
||||
/** Count of times that the player has raised their bet */
|
||||
uint8_t timesRaised;
|
||||
} pokerplayer_t;
|
||||
|
||||
/** Holds information about a player's winning state */
|
||||
typedef struct {
|
||||
/** The full set of both the dealer and player's hand */
|
||||
card_t full[POKER_WINNING_FULL_SIZE];
|
||||
uint8_t fullSize;
|
||||
|
||||
/** Holds the winning set */
|
||||
card_t set[POKER_WINNING_SET_SIZE];
|
||||
uint8_t setSize;
|
||||
|
||||
/** Winning Type */
|
||||
uint8_t type;
|
||||
|
||||
/** If there was a kicker card it will be here, otherwise -1 for no kicker */
|
||||
card_t kicker;
|
||||
} pokerplayerwinning_t;
|
||||
|
||||
typedef struct {
|
||||
/** Current pot of chips */
|
||||
int32_t chips;
|
||||
/** Current call value for this pot */
|
||||
int32_t call;
|
||||
/** Players who are participating in the pot */
|
||||
uint8_t players[POKER_PLAYER_COUNT_MAX];
|
||||
uint8_t playerCount;
|
||||
} pokerpot_t;
|
||||
|
||||
typedef struct {
|
||||
/** What type of action the turn is */
|
||||
uint8_t type;
|
||||
/** How many chips they did in their turn (if applicable) */
|
||||
int32_t chips;
|
||||
/** How confident the AI is about their turn. 0 = none, 1 = full */
|
||||
float confidence;
|
||||
} pokerturn_t;
|
||||
|
||||
typedef struct {
|
||||
/** Current Card Deck (Dealer) */
|
||||
card_t deck[CARD_DECK_SIZE];
|
||||
uint8_t deckSize;
|
||||
|
||||
/** Card grave (where spent cards go when burned */
|
||||
card_t grave[POKER_GRAVE_SIZE_MAX];
|
||||
uint8_t graveSize;
|
||||
|
||||
/** Dealer Hand */
|
||||
card_t community[POKER_COMMUNITY_SIZE_MAX];
|
||||
uint8_t communitySize;
|
||||
|
||||
/** List of pots in the game (side pots) */
|
||||
pokerpot_t pots[POKER_POT_COUNT_MAX];
|
||||
uint8_t potCount;
|
||||
|
||||
/** Players within the game */
|
||||
pokerplayer_t players[POKER_PLAYER_COUNT_MAX];
|
||||
uint8_t playerCount;
|
||||
|
||||
/** Index of the dealer player */
|
||||
uint8_t playerDealer;
|
||||
/** Index of the small blind player */
|
||||
uint8_t playerSmallBlind;
|
||||
/** Index of the big blind player */
|
||||
uint8_t playerBigBlind;
|
||||
|
||||
/** Which player is the current active better ? */
|
||||
uint8_t better;
|
||||
|
||||
/** Size of the small blind */
|
||||
int32_t blindSmall;
|
||||
/** Size of the big blind */
|
||||
int32_t blindBig;
|
||||
} poker_t;
|
80
src/dawn/poker/dealer.c
Normal file
80
src/dawn/poker/dealer.c
Normal file
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "dealer.h"
|
||||
|
||||
void pokerDealerSet(poker_t *poker, uint8_t dealer) {
|
||||
uint8_t i, k;
|
||||
pokerplayer_t *player;
|
||||
bool foundDealer;
|
||||
bool foundSmall;
|
||||
|
||||
foundDealer = false;
|
||||
foundSmall = false;
|
||||
poker->playerDealer = dealer;
|
||||
|
||||
for(i = 0; i < poker->playerCount; i++) {
|
||||
k = (dealer + i) % poker->playerCount;
|
||||
player = poker->players + k;
|
||||
if(player->state & POKER_PLAYER_STATE_OUT) continue;
|
||||
if(!foundDealer) {
|
||||
poker->playerDealer = k;
|
||||
foundDealer = true;
|
||||
} else if(!foundSmall) {
|
||||
poker->playerSmallBlind = k;
|
||||
foundSmall = true;
|
||||
} else {
|
||||
poker->playerBigBlind = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pokerDealerNew(poker_t *poker) {
|
||||
pokerDealerSet(poker, poker->playerDealer + 1);
|
||||
}
|
||||
|
||||
void pokerDealerTurn(poker_t *poker, uint8_t count) {
|
||||
uint8_t i;
|
||||
for(i = 0; i < count; i++) {
|
||||
cardDeal(
|
||||
poker->deck, &poker->deckSize, poker->community, &poker->communitySize
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void pokerDealerBurn(poker_t *poker, uint8_t count) {
|
||||
uint8_t i;
|
||||
for(i = 0; i < count; i++) {
|
||||
cardDeal(poker->deck, &poker->deckSize, poker->grave, &poker->graveSize);
|
||||
}
|
||||
}
|
||||
|
||||
void pokerDeal(poker_t *poker, pokerplayer_t *player, uint8_t count) {
|
||||
uint8_t i;
|
||||
for(i = 0; i < count; i++) {
|
||||
cardDeal(poker->deck, &poker->deckSize, player->cards, &player->cardCount);
|
||||
}
|
||||
}
|
||||
|
||||
void pokerDealAllPlayers(poker_t *poker, uint8_t count) {
|
||||
uint8_t i, j;
|
||||
pokerplayer_t *player;
|
||||
|
||||
for(j = 0; j < count; j++) {
|
||||
for(i = 0; i < poker->playerCount; i++) {
|
||||
player = poker->players + i;
|
||||
|
||||
// Can't deal to a player who is folded or out
|
||||
if(player->state & (POKER_PLAYER_STATE_FOLDED|POKER_PLAYER_STATE_OUT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pokerDeal(poker, player, 1);
|
||||
}
|
||||
}
|
||||
}
|
62
src/dawn/poker/dealer.h
Normal file
62
src/dawn/poker/dealer.h
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "common.h"
|
||||
#include "card.h"
|
||||
|
||||
/**
|
||||
* Set a next dealer. This will also select the new small and big blind players.
|
||||
* This will automatically skip out players if you provide one.
|
||||
*
|
||||
* @param poker Poker game to select a new dealer for.
|
||||
* @param dealer Dealer to become the new dealer.
|
||||
*/
|
||||
void pokerDealerSet(poker_t *poker, uint8_t dealer);
|
||||
|
||||
/**
|
||||
* Cycles to the next dealer. This will also select the new small and big blind
|
||||
* players.
|
||||
*
|
||||
* @param poker Poker game to select a new dealer for.
|
||||
*/
|
||||
void pokerDealerNew(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Turns over cards from the deck onto the table (from the deck into the dealer
|
||||
* hand)
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param count Count of cards to deal.
|
||||
*/
|
||||
void pokerDealerTurn(poker_t *poker, uint8_t count);
|
||||
|
||||
/**
|
||||
* Burns a set of cards off the top of the deck into the graveyard.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param count Count of cards to burn.
|
||||
*/
|
||||
void pokerDealerBurn(poker_t *poker, uint8_t count);
|
||||
|
||||
/**
|
||||
* Deal a card to a player.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param player Poker player to deal to.
|
||||
* @param count Count of cards to deal to the player.
|
||||
*/
|
||||
void pokerDeal(poker_t *poker, pokerplayer_t *player, uint8_t count);
|
||||
|
||||
/**
|
||||
* Deal card(s) to every active player.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param count Count of cards to deal.
|
||||
*/
|
||||
void pokerDealAllPlayers(poker_t *poker, uint8_t count);
|
59
src/dawn/poker/player.c
Normal file
59
src/dawn/poker/player.c
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "player.h"
|
||||
|
||||
uint8_t pokerPlayerAdd(poker_t *poker) {
|
||||
pokerplayer_t *player;
|
||||
uint8_t i = poker->playerCount++;
|
||||
|
||||
player = poker->players + i;
|
||||
player->cardCount = 0;
|
||||
player->chips = 0;
|
||||
player->currentBet = 0;
|
||||
player->timesRaised = 0;
|
||||
player->state = POKER_PLAYER_STATE_OUT;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void pokerPlayerChipsAdd(pokerplayer_t *player, int32_t chips) {
|
||||
player->chips += chips;
|
||||
if(player->chips > 0) {
|
||||
player->state = flagOff(player->state, POKER_PLAYER_STATE_OUT);
|
||||
}
|
||||
}
|
||||
|
||||
bool pokerPlayerDoesNeedToBetThisRound(poker_t *poker, uint8_t playerIndex) {
|
||||
pokerplayer_t *player;
|
||||
player = poker->players + playerIndex;
|
||||
if(player->state & POKER_PLAYER_STATE_FOLDED) return false;
|
||||
if(player->chips <= 0) return false;
|
||||
if(!(player->state & POKER_PLAYER_STATE_HAS_BET_THIS_ROUND)) return true;
|
||||
if(player->currentBet < pokerBetGetCurrentCallValue(poker)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pokerPlayerCanCheck(poker_t *poker, pokerplayer_t *player) {
|
||||
return pokerBetGetCurrentCallValue(poker) <= player->currentBet;
|
||||
}
|
||||
|
||||
void pokerPlayerGetFullHand(
|
||||
poker_t *poker, pokerplayer_t *player, card_t *cards
|
||||
) {
|
||||
uint8_t i;
|
||||
|
||||
// Add the dealer hand
|
||||
for(i = 0; i < poker->communitySize; i++) {
|
||||
cards[i] = poker->community[i];
|
||||
}
|
||||
|
||||
// Add the player hand
|
||||
for(i = 0; i < player->cardCount; i++) {
|
||||
cards[i+poker->communitySize] = player->cards[i];
|
||||
}
|
||||
}
|
62
src/dawn/poker/player.h
Normal file
62
src/dawn/poker/player.h
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/flags.h"
|
||||
#include "common.h"
|
||||
#include "bet.h"
|
||||
|
||||
/**
|
||||
* Add a player to the game. The player starts in an out state (with no chips).
|
||||
*
|
||||
* @param poker Poker game instance to add to.
|
||||
* @return Player index.
|
||||
*/
|
||||
uint8_t pokerPlayerAdd(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Add chips to a player. This will also update their state if they were out
|
||||
* to ensure that they are no longer.
|
||||
*
|
||||
* @param player Player to add chips to.
|
||||
* @param chips Amount of chips to add.
|
||||
*/
|
||||
void pokerPlayerChipsAdd(pokerplayer_t *player, int32_t chips);
|
||||
|
||||
/**
|
||||
* Checks a players' state and decided whether or not the players still needs to
|
||||
* bet for the current round. This will check both whether the player has bet in
|
||||
* the current round yet, and whether or not they have met the call value of the
|
||||
* active pot.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param playerIndex Player index to check.
|
||||
* @return
|
||||
*/
|
||||
bool pokerPlayerDoesNeedToBetThisRound(poker_t *poker, uint8_t playerIndex);
|
||||
|
||||
/**
|
||||
* Determine whether or not a player CAN check, given the current max bet and
|
||||
* the players current bet.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param player Player to check.
|
||||
* @return True if the player can check, false if they need to call first.
|
||||
*/
|
||||
bool pokerPlayerCanCheck(poker_t *poker, pokerplayer_t *player);
|
||||
|
||||
/**
|
||||
* Returns the full hand for a given player including the cards on the bench.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param player Poker player to get the hand for.
|
||||
* @param cards Array to store the cards.
|
||||
*/
|
||||
void pokerPlayerGetFullHand(
|
||||
poker_t *poker, pokerplayer_t *player, card_t *cards
|
||||
);
|
96
src/dawn/poker/poker.c
Normal file
96
src/dawn/poker/poker.c
Normal file
@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "poker.h"
|
||||
|
||||
void pokerInit(poker_t *poker) {
|
||||
poker->playerCount = 0;
|
||||
poker->playerDealer = 0;
|
||||
poker->playerSmallBlind = 0;
|
||||
poker->playerBigBlind = 0;
|
||||
pokerResetRound(poker);
|
||||
pokerSetBlinds(poker, 0, 0);
|
||||
}
|
||||
|
||||
void pokerSetBlinds(poker_t *poker, int32_t blindSmall, int32_t blindBig) {
|
||||
poker->blindSmall = blindSmall;
|
||||
poker->blindBig = blindBig;
|
||||
}
|
||||
|
||||
void pokerResetRound(poker_t *poker) {
|
||||
uint8_t i;
|
||||
pokerplayer_t *player;
|
||||
|
||||
poker->deckSize = cardWriteDeck(poker->deck);
|
||||
poker->graveSize = 0;
|
||||
poker->communitySize = 0;
|
||||
poker->potCount = 0;
|
||||
pokerPotAdd(poker);
|
||||
|
||||
pokerResetBettingRound(poker);
|
||||
|
||||
for(i = 0; i < poker->playerCount; i++) {
|
||||
player = poker->players + i;
|
||||
player->cardCount = 0;
|
||||
player->currentBet = 0;
|
||||
player->timesRaised = 0;
|
||||
player->state &= ~(
|
||||
POKER_PLAYER_STATE_FOLDED |
|
||||
POKER_PLAYER_STATE_HAS_BET_THIS_ROUND |
|
||||
POKER_PLAYER_STATE_SHOWING
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void pokerResetBettingRound(poker_t *poker) {
|
||||
uint8_t i;
|
||||
pokerplayer_t *player;
|
||||
|
||||
// Reset the round betting state.
|
||||
for(i = 0; i < poker->playerCount; i++) {
|
||||
player = poker->players + i;
|
||||
player->state =flagOff(player->state,POKER_PLAYER_STATE_HAS_BET_THIS_ROUND);
|
||||
player->timesRaised = 0;
|
||||
}
|
||||
|
||||
// Now reset to the first player that needs to bet.
|
||||
if(poker->playerCount > 0) {
|
||||
poker->better = poker->playerBigBlind;
|
||||
} else {
|
||||
poker->better = 0x00;
|
||||
}
|
||||
|
||||
// Then we check who's remaining. We do this because the default better may
|
||||
// have folded already.
|
||||
poker->better = pokerBetGetNextPlayer(poker);
|
||||
}
|
||||
|
||||
void pokerTakeBlinds(poker_t *poker) {
|
||||
pokerplayer_t *player;
|
||||
pokerBetForPlayer(poker, poker->playerSmallBlind, poker->blindSmall);
|
||||
player = poker->players + poker->playerSmallBlind;
|
||||
player->state = flagOff(player->state, POKER_PLAYER_STATE_HAS_BET_THIS_ROUND);
|
||||
pokerBetForPlayer(poker, poker->playerBigBlind, poker->blindBig);
|
||||
player = poker->players + poker->playerBigBlind;
|
||||
player->state = flagOff(player->state, POKER_PLAYER_STATE_HAS_BET_THIS_ROUND);
|
||||
}
|
||||
|
||||
uint8_t pokerInRoundGetCount(poker_t *poker) {
|
||||
uint8_t i, count;
|
||||
pokerplayer_t *player;
|
||||
|
||||
count = 0;
|
||||
for(i = 0; i < poker->playerCount; i++) {
|
||||
player = poker->players + i;
|
||||
if(player->state & (POKER_PLAYER_STATE_FOLDED | POKER_PLAYER_STATE_OUT)) {
|
||||
continue;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
62
src/dawn/poker/poker.h
Normal file
62
src/dawn/poker/poker.h
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/flags.h"
|
||||
#include "common.h"
|
||||
#include "card.h"
|
||||
#include "pot.h"
|
||||
#include "bet.h"
|
||||
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Fucked if I know
|
||||
|
||||
/**
|
||||
* Initialize the poker game instance.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
*/
|
||||
void pokerInit(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Set the game's current blinds.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param blindSmall Small blind value.
|
||||
* @param blindBig Big blind value.
|
||||
*/
|
||||
void pokerSetBlinds(poker_t *poker, int32_t blindSmall, int32_t blindBig);
|
||||
|
||||
/**
|
||||
* Reset the poker game instance for the new round.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
*/
|
||||
void pokerResetRound(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Reset the poker betting round.
|
||||
*
|
||||
* @param poker Poker game instance to reset for.
|
||||
*/
|
||||
void pokerResetBettingRound(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Take the blinds from the blind players.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
*/
|
||||
void pokerTakeBlinds(poker_t *poker);
|
||||
|
||||
|
||||
/**
|
||||
* Gets the count of players still currently left in the round.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @return The count of players in the round.
|
||||
*/
|
||||
uint8_t pokerInRoundGetCount(poker_t *poker);
|
44
src/dawn/poker/pot.c
Normal file
44
src/dawn/poker/pot.c
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "pot.h"
|
||||
|
||||
uint8_t pokerPotAdd(poker_t *poker) {
|
||||
pokerpot_t *pot;
|
||||
uint8_t i = poker->potCount++;
|
||||
pot = poker->pots + i;
|
||||
pot->chips = 0;
|
||||
pot->playerCount = 0;
|
||||
pot->call = 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
bool pokerPotHasPlayer(pokerpot_t *pot, uint8_t playerIndex) {
|
||||
return arrayContains(
|
||||
sizeof(uint8_t), pot->players, pot->playerCount, &playerIndex
|
||||
);
|
||||
}
|
||||
|
||||
void pokerPotAddPlayer(pokerpot_t *pot, uint8_t playerIndex) {
|
||||
if(pokerPotHasPlayer(pot, playerIndex)) return;
|
||||
pot->players[pot->playerCount++] = playerIndex;
|
||||
}
|
||||
|
||||
int32_t pokerPotGetSumOfChipsForPlayer(poker_t *poker, uint8_t playerIndex) {
|
||||
int32_t count;
|
||||
uint8_t i;
|
||||
pokerpot_t *pot;
|
||||
|
||||
count = 0;
|
||||
for(i = 0; i < poker->potCount; i++) {
|
||||
pot = poker->pots + i;
|
||||
if(!pokerPotHasPlayer(pot, playerIndex)) continue;
|
||||
count += pot->chips;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
47
src/dawn/poker/pot.h
Normal file
47
src/dawn/poker/pot.h
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/array.h"
|
||||
#include "common.h"
|
||||
|
||||
/**
|
||||
* Adds a new pot to the poker game instance.
|
||||
*
|
||||
* @param poker Poker game instance to add a pot to.
|
||||
* @return The index of the pot within the array of pots.
|
||||
*/
|
||||
uint8_t pokerPotAdd(poker_t *poker);
|
||||
|
||||
/**
|
||||
* Check whether or not the given player is part of the given pot.
|
||||
*
|
||||
* @param pot Pot to check.
|
||||
* @param playerIndex Player index to see if within the pot or not.
|
||||
* @return True if in the pot, otherwise false.
|
||||
*/
|
||||
bool pokerPotHasPlayer(pokerpot_t *pot, uint8_t playerIndex);
|
||||
|
||||
/**
|
||||
* Add a player to a pot. This will not let you add the same player to the pot
|
||||
* twice.
|
||||
*
|
||||
* @param pot Pot to add to.
|
||||
* @param playerIndex Players' index to add to the pot.
|
||||
*/
|
||||
void pokerPotAddPlayer(pokerpot_t *pot, uint8_t playerIndex);
|
||||
|
||||
/**
|
||||
* Returns the sum of chips in the pot(s) that the specified player is in. This
|
||||
* does not consider the pot, player or hand, just the pure sum of chips.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param playerIndex Player Index to get the sum of chips from.
|
||||
* @return The sum of chips from the pots the player is within.
|
||||
*/
|
||||
int32_t pokerPotGetSumOfChipsForPlayer(poker_t *poker, uint8_t playerIndex);
|
221
src/dawn/poker/turn.c
Normal file
221
src/dawn/poker/turn.c
Normal file
@ -0,0 +1,221 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "turn.h"
|
||||
|
||||
pokerturn_t pokerTurnFold(poker_t *poker, uint8_t player) {
|
||||
return (pokerturn_t){
|
||||
.chips = 0,
|
||||
.confidence = 1,
|
||||
.type = POKER_TURN_TYPE_FOLD
|
||||
};
|
||||
}
|
||||
|
||||
pokerturn_t pokerTurnBet(poker_t *poker, uint8_t playerIndex, int32_t chips) {
|
||||
pokerturn_t turn;
|
||||
pokerplayer_t *player;
|
||||
int32_t i;
|
||||
player = poker->players + playerIndex;
|
||||
turn.confidence = 1;
|
||||
|
||||
if(chips == 0) {
|
||||
turn.type = POKER_TURN_TYPE_CHECK;
|
||||
turn.chips = 0;
|
||||
} else if(player->chips <= chips) {
|
||||
turn.chips = player->chips;
|
||||
turn.type = POKER_TURN_TYPE_ALL_IN;
|
||||
} else {
|
||||
turn.chips = chips;
|
||||
turn.type = POKER_TURN_TYPE_BET;
|
||||
i = pokerBetGetCurrentCallValue(poker);
|
||||
|
||||
if(chips == (i - player->currentBet)) {
|
||||
turn.type = POKER_TURN_TYPE_CALL;
|
||||
}
|
||||
}
|
||||
|
||||
return turn;
|
||||
}
|
||||
|
||||
pokerturn_t pokerTurnGetForPlayer(poker_t *poker, uint8_t playerIndex) {
|
||||
int32_t random, maxBet, bluffBet, callBet;
|
||||
float confidence, expectedGain, potOdds;
|
||||
bool isBluff;
|
||||
int32_t amount;
|
||||
pokerplayer_t *player;
|
||||
pokerplayerwinning_t winning;
|
||||
uint8_t i, cardNumber0, cardNumber1, suitNumber0, suitNumber1;
|
||||
pokerturn_t turn;
|
||||
|
||||
player = poker->players + playerIndex;
|
||||
|
||||
// Can the player do anything?
|
||||
if(player->state & (POKER_PLAYER_STATE_FOLDED | POKER_PLAYER_STATE_OUT)) {
|
||||
turn.type = POKER_TURN_TYPE_OUT;
|
||||
return turn;
|
||||
}
|
||||
|
||||
// The following logic is heavily inspired by;
|
||||
// https://github.com/gorel/C-Poker-AI/blob/master/src/common/pokerai.c
|
||||
// But with some changes and smarts added by me. The original source code will
|
||||
// essentially just run a crap tun of simulated games and get the times that
|
||||
// they are expected to win from those games, but I'm just going to use the
|
||||
// odds of the winning hand.
|
||||
|
||||
// Is this preflop?
|
||||
if(poker->communitySize == 0 && player->cardCount >= 2) {
|
||||
// Get the hand weight
|
||||
cardNumber0 = cardGetNumber(player->cards[0]);
|
||||
cardNumber1 = cardGetNumber(player->cards[1]);
|
||||
suitNumber0 = cardGetSuit(player->cards[0]);
|
||||
suitNumber1 = cardGetSuit(player->cards[1]);
|
||||
|
||||
// Get delta between cards
|
||||
i = mathAbs(cardNumber0 - cardNumber1);
|
||||
|
||||
// Get card weight
|
||||
confidence = (float)cardNumber0 + (float)cardNumber1;
|
||||
if(cardNumber0 == cardNumber1) {// Pairs
|
||||
confidence += 6;
|
||||
} else if(suitNumber0 == suitNumber1) {// Same suit
|
||||
confidence += 4;
|
||||
}
|
||||
|
||||
// Get difference from cards for guessing flush
|
||||
if(i > 4) {
|
||||
confidence -= 4;
|
||||
} else if(i > 2) {
|
||||
confidence -= i;
|
||||
}
|
||||
|
||||
// Get the confidence delta 0-1
|
||||
confidence = confidence / 30.0f;
|
||||
} else {
|
||||
// Simulate my hand being the winning hand, use that as the confidence
|
||||
pokerWinnerGetForPlayer(poker, player, &winning);
|
||||
confidence = pokerWinnerGetTypeConfidence(winning.type);
|
||||
}
|
||||
|
||||
// Now we know how confident the AI is, let's put a chip value to that weight
|
||||
// How many chips to call?
|
||||
callBet = pokerPlayerGetCallBet(poker, player);
|
||||
|
||||
// Do they need chips to call, or is it possible to check?
|
||||
if(callBet > 0) {
|
||||
potOdds = (float)callBet / (
|
||||
(float)callBet + (float)pokerPotGetSumOfChipsForPlayer(poker, playerIndex)
|
||||
);
|
||||
} else {
|
||||
potOdds = 1.0f / (float)pokerBetGetRemainingBetterCount(poker);
|
||||
}
|
||||
|
||||
// Now determine the expected ROI
|
||||
expectedGain = confidence / potOdds;
|
||||
|
||||
// Now get a random 0-100
|
||||
random = randInt32() % 100;
|
||||
|
||||
// Determine the max bet that the AI is willing to make
|
||||
maxBet = (int32_t)((float)player->chips / 1.75f) - (random / 2);
|
||||
maxBet -= callBet;
|
||||
|
||||
// Determine what's a good bluff bet.
|
||||
bluffBet = random * maxBet / 100 / 2;
|
||||
|
||||
// Now prep the output
|
||||
isBluff = false;
|
||||
amount = 0;
|
||||
|
||||
// Now the actual AI can happen. This is basically a weight to confidence
|
||||
// ratio. The higher the gains and the confidence then the more likely the AI
|
||||
// is to betting. There are also bluff chances within here.
|
||||
if(expectedGain < 0.8 && confidence < 0.8) {
|
||||
if(random < 95) {
|
||||
amount = 0;
|
||||
} else {
|
||||
amount = bluffBet;
|
||||
isBluff = true;
|
||||
}
|
||||
} else if ((expectedGain < 1.0 && confidence < 0.85) || confidence < 0.1) {
|
||||
if (random < 80) {
|
||||
amount = 0;
|
||||
} else if(random < 5) {
|
||||
amount = callBet;
|
||||
isBluff = true;
|
||||
} else {
|
||||
amount = bluffBet;
|
||||
isBluff = true;
|
||||
}
|
||||
} else if ((expectedGain < 1.3 && confidence < 0.9) || confidence < 0.5) {
|
||||
if (random < 60 || confidence < 0.5) {
|
||||
amount = callBet;
|
||||
} else {
|
||||
amount = maxBet;
|
||||
}
|
||||
} else if (confidence < 0.95 || poker->communitySize < 0x04) {
|
||||
if(random < 20) {
|
||||
amount = callBet;
|
||||
} else {
|
||||
amount = maxBet;
|
||||
}
|
||||
} else {
|
||||
amount = (player->chips - callBet) * 9 / 10;
|
||||
}
|
||||
|
||||
// If this is the first round... make it a lot less likely I'll bet
|
||||
if(poker->communitySize == 0x00 && amount > callBet) {
|
||||
if(random > 5) amount = callBet;
|
||||
}
|
||||
|
||||
// Did we actually bet?
|
||||
if(amount > 0) {
|
||||
printf("AI is betting %i chips, bluff: %i\n", amount, isBluff);
|
||||
|
||||
// Let's not get caught in a raising loop with AI.
|
||||
if(player->timesRaised >= POKER_TURN_MAX_RAISES) {
|
||||
amount = callBet;
|
||||
}
|
||||
|
||||
amount = mathMax(amount, callBet);
|
||||
turn = pokerTurnBet(poker, playerIndex, amount);
|
||||
turn.confidence = confidence;
|
||||
} else if(pokerPlayerCanCheck(poker, player)) {
|
||||
turn = pokerTurnBet(poker, playerIndex, 0);
|
||||
turn.confidence = 1;
|
||||
} else {
|
||||
turn = pokerTurnFold(poker, playerIndex);
|
||||
turn.confidence = 1 - confidence;
|
||||
}
|
||||
|
||||
return turn;
|
||||
}
|
||||
|
||||
void pokerTurnAction(poker_t *poker, uint8_t playerIndex, pokerturn_t turn) {
|
||||
pokerplayer_t *player;
|
||||
player = poker->players + playerIndex;
|
||||
|
||||
switch(turn.type) {
|
||||
case POKER_TURN_TYPE_BET:
|
||||
case POKER_TURN_TYPE_CALL:
|
||||
case POKER_TURN_TYPE_ALL_IN:
|
||||
pokerBetForPlayer(poker, playerIndex, turn.chips);
|
||||
player->timesRaised++;
|
||||
break;
|
||||
|
||||
case POKER_TURN_TYPE_CHECK:
|
||||
pokerBetForPlayer(poker, playerIndex, 0);
|
||||
player->timesRaised = 0;
|
||||
break;
|
||||
|
||||
case POKER_TURN_TYPE_FOLD:
|
||||
player->state |= POKER_PLAYER_STATE_FOLDED;
|
||||
player->timesRaised = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
player->state |= POKER_PLAYER_STATE_HAS_BET_THIS_ROUND;
|
||||
}
|
52
src/dawn/poker/turn.h
Normal file
52
src/dawn/poker/turn.h
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/math.h"
|
||||
#include "common.h"
|
||||
#include "bet.h"
|
||||
#include "card.h"
|
||||
#include "winner.h"
|
||||
#include "pot.h"
|
||||
|
||||
/**
|
||||
* Return a turn action for the given player to fold.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param player Player index.
|
||||
* @return A turn for a fold action.
|
||||
*/
|
||||
pokerturn_t pokerTurnFold(poker_t *poker, uint8_t player);
|
||||
|
||||
/**
|
||||
* Perform a turn action for betting as a player.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param playerIndex Player index who is betting.
|
||||
* @param chips Chips to raise by.
|
||||
* @return A turn for a bet action.
|
||||
*/
|
||||
pokerturn_t pokerTurnBet(poker_t *poker, uint8_t playerIndex, int32_t chips);
|
||||
|
||||
/**
|
||||
* Returns the AI result for a turn done by a non human player.
|
||||
*
|
||||
* @param poker Poker game instance to use.
|
||||
* @param playerIndex Player index to get the turn for.
|
||||
* @return Some information about the move the player is trying to perform.
|
||||
*/
|
||||
pokerturn_t pokerTurnGetForPlayer(poker_t *poker, uint8_t playerIndex);
|
||||
|
||||
/**
|
||||
* Perform the turn's action.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param playerIndex Player index.
|
||||
* @param turn Turn to action.
|
||||
*/
|
||||
void pokerTurnAction(poker_t *poker, uint8_t playerIndex, pokerturn_t turn);
|
401
src/dawn/poker/winner.c
Normal file
401
src/dawn/poker/winner.c
Normal file
@ -0,0 +1,401 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "winner.h"
|
||||
|
||||
void pokerWinnerFillRemaining(pokerplayerwinning_t *winning) {
|
||||
uint8_t i, highest, current;
|
||||
card_t highestCard, currentCard;
|
||||
|
||||
// Set the kicker
|
||||
winning->kicker = 0xFF;
|
||||
|
||||
// Fill the remaining cards
|
||||
while(winning->setSize < POKER_WINNING_SET_SIZE) {
|
||||
highest = 0xFF;
|
||||
|
||||
for(i = 0; i < winning->fullSize; i++) {
|
||||
currentCard = winning->full[i];
|
||||
if(cardContains(winning->set, winning->setSize, currentCard) != -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(highest == 0xFF) {
|
||||
highestCard = currentCard;
|
||||
highest = cardGetNumber(highestCard);
|
||||
} else {
|
||||
current = cardGetNumber(currentCard);
|
||||
if(current != CARD_ACE && current < highest) continue;
|
||||
highestCard = currentCard;
|
||||
highest = current;
|
||||
}
|
||||
}
|
||||
|
||||
if(highest == 0xFF) break;
|
||||
winning->set[winning->setSize++] = highestCard;
|
||||
}
|
||||
cardHandSort(winning->set, winning->setSize);
|
||||
}
|
||||
|
||||
void pokerWinnerGetForPlayer(
|
||||
poker_t *poker, pokerplayer_t *player, pokerplayerwinning_t *winning
|
||||
) {
|
||||
uint8_t i, j, l;
|
||||
int32_t index;
|
||||
card_t card;
|
||||
uint8_t number, suit, pairCount;
|
||||
int32_t pairs[CARD_SUIT_COUNT];
|
||||
|
||||
// Get the full poker hand (should be a 7 card hand, but MAY not be)
|
||||
winning->fullSize = poker->communitySize + player->cardCount;
|
||||
pokerPlayerGetFullHand(poker, player, winning->full);
|
||||
cardHandSort(winning->full, winning->fullSize);
|
||||
|
||||
// Reset the winning status.
|
||||
winning->setSize = 0;
|
||||
|
||||
//////////////////////// Now look for the winning set ////////////////////////
|
||||
|
||||
// Royal / Straight Flush
|
||||
for(i = 0; i < winning->fullSize; i++) {
|
||||
card = winning->full[i];
|
||||
number = cardGetNumber(card);
|
||||
if(number < CARD_FIVE) continue;
|
||||
|
||||
suit = cardGetSuit(card);
|
||||
winning->setSize = 1;
|
||||
|
||||
// Now look for the matching cards (Reverse order to order from A to 10)
|
||||
for(j = 1; j <= 4; j++) {
|
||||
l = number == CARD_FIVE && j == 4 ? CARD_ACE : number - j;//Ace low.
|
||||
index = cardContains(winning->full, winning->fullSize, cardGet(l, suit));
|
||||
if(index == -1) break;
|
||||
winning->set[j] = winning->full[index];
|
||||
winning->setSize++;
|
||||
}
|
||||
|
||||
// Check if has all necessary cards.
|
||||
if(winning->setSize < POKER_WINNING_SET_SIZE) continue;
|
||||
|
||||
// Add self to array
|
||||
winning->set[0] = winning->full[i];
|
||||
winning->type = (
|
||||
number == CARD_ACE ? POKER_WINNING_TYPE_ROYAL_FLUSH :
|
||||
POKER_WINNING_TYPE_STRAIGHT_FLUSH
|
||||
);
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Four of a kind.
|
||||
winning->setSize = 0;
|
||||
for(i = 0; i < winning->fullSize; i++) {
|
||||
card = winning->full[i];
|
||||
number = cardGetNumber(card);
|
||||
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
|
||||
if(pairCount < CARD_SUIT_COUNT) continue;
|
||||
|
||||
winning->setSize = pairCount;
|
||||
for(j = 0; j < pairCount; j++) winning->set[j] = winning->full[pairs[j]];
|
||||
winning->type = POKER_WINNING_TYPE_FOUR_OF_A_KIND;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Full House
|
||||
winning->setSize = 0;
|
||||
for(i = 0; i < winning->fullSize; i++) {
|
||||
// Check we haven't already added this card.
|
||||
card = winning->full[i];
|
||||
if(cardContains(winning->set, winning->setSize, card) != -1) continue;
|
||||
|
||||
number = cardGetNumber(card);
|
||||
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
|
||||
|
||||
// Did we find either two pair or three pair?
|
||||
if(pairCount != 2 && pairCount != 3) continue;
|
||||
if(winning->setSize == 3) pairCount = 2;//Clamp to 5 max.
|
||||
|
||||
// Copy found pairs.
|
||||
for(j = 0; j < pairCount; j++) {
|
||||
winning->set[winning->setSize + j] = winning->full[pairs[j]];
|
||||
}
|
||||
winning->setSize += pairCount;
|
||||
|
||||
// Winned?
|
||||
if(winning->setSize != POKER_WINNING_SET_SIZE) continue;
|
||||
winning->type = POKER_WINNING_TYPE_FULL_HOUSE;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Flush (5 same suit)
|
||||
for(i = 0; i < winning->fullSize; i++) {
|
||||
card = winning->full[i];
|
||||
suit = cardGetSuit(card);
|
||||
winning->setSize = 1;
|
||||
for(j = i+1; j < winning->fullSize; j++) {
|
||||
if(cardGetSuit(winning->full[j]) != suit) continue;
|
||||
winning->set[winning->setSize++] = winning->full[j];
|
||||
if(winning->setSize == POKER_WINNING_SET_SIZE) break;
|
||||
}
|
||||
if(winning->setSize < POKER_WINNING_SET_SIZE) continue;
|
||||
winning->set[0] = winning->full[i];
|
||||
winning->type = POKER_WINNING_TYPE_FLUSH;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Straight (sequence any suit)
|
||||
winning->setSize = 0;
|
||||
for(i = 0; i < winning->fullSize; i++) {
|
||||
card = winning->full[i];
|
||||
number = cardGetNumber(card);
|
||||
if(number < CARD_FIVE) continue;
|
||||
winning->setSize = 1;
|
||||
|
||||
for(j = 1; j <= 4; j++) {
|
||||
l = number == CARD_FIVE && j == 4 ? CARD_ACE : number - j;//Ace low.
|
||||
index = cardContainsNumber(winning->full, winning->fullSize, l);
|
||||
if(index == -1) break;
|
||||
winning->set[j] = winning->full[index];
|
||||
winning->setSize++;
|
||||
}
|
||||
|
||||
// Check if has all necessary cards.
|
||||
if(winning->setSize < POKER_WINNING_SET_SIZE) continue;
|
||||
winning->set[0] = winning->full[i];
|
||||
winning->type = POKER_WINNING_TYPE_STRAIGHT;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Three of a kind
|
||||
winning->setSize = 0;
|
||||
for(i = 0; i < winning->fullSize; i++) {
|
||||
card = winning->full[i];
|
||||
number = cardGetNumber(card);
|
||||
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
|
||||
if(pairCount != 3) continue;
|
||||
|
||||
winning->setSize = pairCount;
|
||||
for(j = 0; j < pairCount; j++) winning->set[j] = winning->full[pairs[j]];
|
||||
winning->type = POKER_WINNING_TYPE_THREE_OF_A_KIND;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Two Pair
|
||||
winning->setSize = 0;
|
||||
for(i = 0; i < winning->fullSize; i++) {
|
||||
card = winning->full[i];// Check we haven't already added this card.
|
||||
if(cardContains(winning->set, winning->setSize, card) != -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
number = cardGetNumber(card);
|
||||
pairCount = cardCountPairs(winning->full, winning->fullSize, number, pairs);
|
||||
if(pairCount != 2) continue;
|
||||
|
||||
for(j = 0; j < pairCount; j++) {
|
||||
winning->set[winning->setSize+j] = winning->full[pairs[j]];
|
||||
}
|
||||
winning->setSize += pairCount;
|
||||
if(winning->setSize != 4) continue;
|
||||
|
||||
winning->type = POKER_WINNING_TYPE_TWO_PAIR;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// Pair
|
||||
if(winning->setSize == 2) {
|
||||
winning->type = POKER_WINNING_TYPE_PAIR;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
return;
|
||||
}
|
||||
|
||||
// High card
|
||||
winning->setSize = 0;
|
||||
pokerWinnerFillRemaining(winning);
|
||||
winning->type = POKER_WINNING_TYPE_HIGH_CARD;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
card_t pokerWinnerCompare(
|
||||
pokerplayerwinning_t *left, pokerplayerwinning_t *right
|
||||
) {
|
||||
uint8_t i, number;
|
||||
card_t card;
|
||||
int32_t index;
|
||||
uint8_t countCardsSame;
|
||||
|
||||
card_t highCardLeft, highCardRight;
|
||||
uint8_t highNumberLeft, highNumberRight;
|
||||
|
||||
highNumberLeft = 0xFF;
|
||||
highNumberRight = 0xFF;
|
||||
countCardsSame = 0;
|
||||
|
||||
|
||||
for(i = 0; i < left->setSize; i++) {
|
||||
card = left->set[i];
|
||||
number = cardGetNumber(card);
|
||||
if(highNumberLeft != 0xFF && number < highNumberLeft) continue;//Quick check
|
||||
|
||||
// Check if this number is within the other hand or not
|
||||
index = cardContainsNumber(right->set, right->setSize, number);
|
||||
if(index != -1) {
|
||||
// This number IS within the other hand, let's check that the EXACT card
|
||||
// is a match/isn't a match.
|
||||
index = cardContains(right->set, right->setSize, card);
|
||||
|
||||
// Exact card match
|
||||
if(index != -1) {
|
||||
countCardsSame++;
|
||||
continue;
|
||||
}
|
||||
// Not exact card match.. ?
|
||||
}
|
||||
|
||||
if(highNumberLeft == 0xFF||number == CARD_ACE||highNumberLeft < number) {
|
||||
highNumberLeft = number;
|
||||
highCardLeft = card;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < right->setSize; i++) {
|
||||
card = right->set[i];
|
||||
number = cardGetNumber(card);
|
||||
if(highNumberRight != 0xFF && number < highNumberRight) continue;
|
||||
|
||||
index = cardContainsNumber(left->set, left->setSize, number);
|
||||
if(index != -1) {
|
||||
index = cardContains(left->set, left->setSize, card);
|
||||
if(index != -1) continue;
|
||||
}
|
||||
|
||||
if(highNumberRight == 0xFF||number == CARD_ACE||highNumberRight < number) {
|
||||
highNumberRight = number;
|
||||
highCardRight = card;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(countCardsSame == left->setSize) {
|
||||
for(i = 0; i < left->setSize; i++) {
|
||||
card = left->set[i];
|
||||
number = cardGetNumber(card);
|
||||
if(highNumberLeft == 0xFF||number == CARD_ACE||highNumberLeft < number) {
|
||||
highNumberLeft = number;
|
||||
highCardLeft = card;
|
||||
}
|
||||
}
|
||||
return highCardLeft;
|
||||
}
|
||||
|
||||
if(highCardLeft == 0xFF) return 0xFF;
|
||||
if(highNumberLeft < highNumberRight) return 0xFF;
|
||||
return highCardLeft;//Greater or Equal to.
|
||||
}
|
||||
|
||||
void pokerWinnerDetermineForPot(
|
||||
poker_t *poker,
|
||||
pokerpot_t *pot,
|
||||
pokerplayerwinning_t winners[POKER_PLAYER_COUNT_MAX],
|
||||
uint8_t winnerPlayers[POKER_PLAYER_COUNT_MAX],
|
||||
uint8_t *winnerCount,
|
||||
uint8_t participants[POKER_PLAYER_COUNT_MAX],
|
||||
uint8_t *participantCount
|
||||
) {
|
||||
uint8_t i, j, countPlayers, countWinners, number, highNumber;
|
||||
pokerplayerwinning_t *left, *right;
|
||||
pokerplayer_t *player;
|
||||
card_t card, highCard;
|
||||
bool isWinner;
|
||||
|
||||
countPlayers = 0;
|
||||
countWinners = 0;
|
||||
highCard = 0xFF;
|
||||
|
||||
// Get participating players and their hands.
|
||||
for(i = 0; i < pot->playerCount; i++) {
|
||||
player = poker->players + pot->players[i];
|
||||
if(player->state & (POKER_PLAYER_STATE_FOLDED|POKER_PLAYER_STATE_OUT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
participants[countPlayers] = pot->players[i];
|
||||
pokerWinnerGetForPlayer(poker, player, winners + countPlayers++);
|
||||
}
|
||||
|
||||
// Compare participating players
|
||||
for(i = 0; i < countPlayers; i++) {
|
||||
left = winners + i;
|
||||
isWinner = true;
|
||||
highNumber = 0xFF;
|
||||
|
||||
for(j = 0; j < countPlayers; j++) {
|
||||
if(i == j) continue;
|
||||
right = winners + j;
|
||||
|
||||
// Am I the better hand / Is it the better hand?
|
||||
if(left->type < right->type) continue;
|
||||
if(left->type > right->type) {
|
||||
isWinner = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Equal, compare hands.
|
||||
card = pokerWinnerCompare(left, right);
|
||||
if(card == 0xFF) {
|
||||
isWinner = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Determine high card.
|
||||
number = cardGetNumber(card);
|
||||
if(highNumber == 0xFF || number == CARD_ACE || number > highNumber) {
|
||||
highCard = card;
|
||||
highNumber = number;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isWinner) continue;
|
||||
left->kicker = highCard;
|
||||
winnerPlayers[countWinners++] = participants[i];
|
||||
}
|
||||
|
||||
*participantCount = countPlayers;
|
||||
*winnerCount = countWinners;
|
||||
}
|
||||
|
||||
float pokerWinnerGetTypeConfidence(uint8_t type) {
|
||||
switch(type) {
|
||||
case POKER_WINNING_TYPE_ROYAL_FLUSH:
|
||||
return POKER_WINNING_CONFIDENCE_ROYAL_FLUSH;
|
||||
case POKER_WINNING_TYPE_STRAIGHT_FLUSH:
|
||||
return POKER_WINNING_CONFIDENCE_STRAIGHT_FLUSH;
|
||||
case POKER_WINNING_TYPE_FOUR_OF_A_KIND:
|
||||
return POKER_WINNING_CONFIDENCE_FOUR_OF_A_KIND;
|
||||
case POKER_WINNING_TYPE_FULL_HOUSE:
|
||||
return POKER_WINNING_CONFIDENCE_FULL_HOUSE;
|
||||
case POKER_WINNING_TYPE_FLUSH:
|
||||
return POKER_WINNING_CONFIDENCE_FLUSH;
|
||||
case POKER_WINNING_TYPE_STRAIGHT:
|
||||
return POKER_WINNING_CONFIDENCE_STRAIGHT;
|
||||
case POKER_WINNING_TYPE_THREE_OF_A_KIND:
|
||||
return POKER_WINNING_CONFIDENCE_THREE_OF_A_KIND;
|
||||
case POKER_WINNING_TYPE_TWO_PAIR:
|
||||
return POKER_WINNING_CONFIDENCE_TWO_PAIR;
|
||||
case POKER_WINNING_TYPE_PAIR:
|
||||
return POKER_WINNING_CONFIDENCE_PAIR;
|
||||
default:
|
||||
return POKER_WINNING_CONFIDENCE_HIGH_CARD;
|
||||
}
|
||||
}
|
76
src/dawn/poker/winner.h
Normal file
76
src/dawn/poker/winner.h
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "card.h"
|
||||
#include "common.h"
|
||||
#include "player.h"
|
||||
|
||||
|
||||
/**
|
||||
* Fills the remaining cards for a given poker player winning hand. Essentially
|
||||
* this will just take the highest cards and slot them into the array. This also
|
||||
* sorts the cards.
|
||||
*
|
||||
* @param winning Pointer to the poker winning to fill out.
|
||||
*/
|
||||
void pokerWinnerFillRemaining(pokerplayerwinning_t *winning);
|
||||
|
||||
/**
|
||||
* Calculates and returns the winning state for a given player
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param player Player to get the state for.
|
||||
* @param winning Output winning state struct to push data in to.
|
||||
*/
|
||||
void pokerWinnerGetForPlayer(
|
||||
poker_t *poker, pokerplayer_t *player, pokerplayerwinning_t *winning
|
||||
);
|
||||
|
||||
/**
|
||||
* Compares two winning sets. The returned card is the kicker if the LEFT side
|
||||
* is the winner. If LEFT is not a winner then 0xFF will be returned.
|
||||
*
|
||||
* @param left Left winning set.
|
||||
* @param right Right winning set.
|
||||
* @return The kicker card from left's hand or 0xFF if left is not the winner.
|
||||
*/
|
||||
card_t pokerWinnerCompare(
|
||||
pokerplayerwinning_t *left, pokerplayerwinning_t *right
|
||||
);
|
||||
|
||||
/**
|
||||
* Determines the winning player for the given pot. The pot has participating
|
||||
* players, and from those participating players some will be winners. The
|
||||
* participants are only the players within the pot who haven't folded or out.
|
||||
*
|
||||
* @param poker Poker game instance.
|
||||
* @param pot Pot to get the winners for.
|
||||
* @param winners Array to store the winner state in.
|
||||
* @param winnerPlayers Array to store player indexes of each of the winners.
|
||||
* @param winnerCount Pointer to store the count of winners in.
|
||||
* @param participants Array to store player indexes of players who participate.
|
||||
* @param participantCount Pointer to store the count of participants in.
|
||||
*/
|
||||
void pokerWinnerDetermineForPot(
|
||||
poker_t *poker,
|
||||
pokerpot_t *pot,
|
||||
pokerplayerwinning_t winners[POKER_PLAYER_COUNT_MAX],
|
||||
uint8_t winnerPlayers[POKER_PLAYER_COUNT_MAX],
|
||||
uint8_t *winnerCount,
|
||||
uint8_t participants[POKER_PLAYER_COUNT_MAX],
|
||||
uint8_t *participantCount
|
||||
);
|
||||
|
||||
/**
|
||||
* Get the confidence of the bet for a given winning type.
|
||||
*
|
||||
* @param type Winning type type.
|
||||
* @return The confidence.
|
||||
*/
|
||||
float pokerWinnerGetTypeConfidence(uint8_t type);
|
72
src/dawn/save/save.c
Normal file
72
src/dawn/save/save.c
Normal file
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "save.h"
|
||||
|
||||
void saveManagerInit(savemanager_t *man) {
|
||||
man->count = 0;
|
||||
}
|
||||
|
||||
savevalue_t * saveManagerAddOrGet(savemanager_t *man, char *key) {
|
||||
uint8_t i, j;
|
||||
|
||||
j = saveManagerGetKey(man, key);
|
||||
|
||||
if(j != 0xFF) return man->values + j;
|
||||
|
||||
// Find empty key
|
||||
for(i = 0; i < man->count; i++) {
|
||||
if(man->keys[i] != NULL) continue;
|
||||
|
||||
man->keys[i] = key;
|
||||
return man->values + i;
|
||||
}
|
||||
|
||||
// No empty key
|
||||
man->keys[man->count] = key;
|
||||
return man->values + man->count++;
|
||||
}
|
||||
|
||||
uint8_t saveManagerGetKey(savemanager_t *man, char *key) {
|
||||
uint8_t i;
|
||||
for(i = 0; i < man->count; i++) {
|
||||
if(strcmp(man->keys + i, key) == 0) return i;
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void saveManagerRemove(savemanager_t *man, char *key) {
|
||||
uint8_t i;
|
||||
|
||||
i = saveManagerGetKey(man, key);
|
||||
if(i == 0xFF) return;
|
||||
|
||||
man->keys[i] = NULL;
|
||||
}
|
||||
|
||||
|
||||
// Setters
|
||||
savevalue_t * saveManagerSetBool(savemanager_t *man, char *key, bool val) {
|
||||
savevalue_t * v = saveManagerAddOrGet(man, key);
|
||||
v->b = val;
|
||||
return v;
|
||||
}
|
||||
|
||||
savevalue_t * saveManagerSetUint8(savemanager_t *man, char *key, uint8_t val) {
|
||||
savevalue_t * v = saveManagerAddOrGet(man, key);
|
||||
v->u8 = val;
|
||||
return v;
|
||||
}
|
||||
|
||||
// Getters
|
||||
bool saveManagerGetBool(savemanager_t *man, char *key) {
|
||||
return saveManagerAddOrGet(man, key)->b;
|
||||
}
|
||||
|
||||
uint8_t saveManagerGetUint8(savemanager_t *man, char *key) {
|
||||
return saveManagerAddOrGet(man, key)->u8;
|
||||
}
|
41
src/dawn/save/save.h
Normal file
41
src/dawn/save/save.h
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "../libs.h"
|
||||
#include "../util/array.h"
|
||||
|
||||
#define SAVE_VALUES_MAX 200
|
||||
|
||||
typedef union {
|
||||
// char *s;
|
||||
bool b;
|
||||
uint8_t u8;
|
||||
int8_t i8;
|
||||
int16_t i16;
|
||||
int32_t i32;
|
||||
} savevalue_t;
|
||||
|
||||
typedef struct {
|
||||
char *keys[SAVE_VALUES_MAX];
|
||||
savevalue_t values[SAVE_VALUES_MAX];
|
||||
uint8_t count;
|
||||
} savemanager_t;
|
||||
|
||||
void saveManagerInit(savemanager_t *man);
|
||||
|
||||
savevalue_t * saveManagerAddOrGet(savemanager_t *man, char *key);
|
||||
|
||||
uint8_t saveManagerGetKey(savemanager_t *man, char *key);
|
||||
|
||||
void saveManagerRemove(savemanager_t *man, char *key);
|
||||
|
||||
savevalue_t * saveManagerSetBool(savemanager_t *man, char *key, bool val);
|
||||
savevalue_t * saveManagerSetUint8(savemanager_t *man, char *key, uint8_t val);
|
||||
|
||||
bool saveManagerGetBool(savemanager_t *man, char *key);
|
||||
uint8_t saveManagerGetUint8(savemanager_t *man, char *key);
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user