Basic animations

This commit is contained in:
2022-12-04 15:36:40 -08:00
parent ba9881e39d
commit b5d7c927c5
15 changed files with 314 additions and 28 deletions

View File

@ -31,6 +31,7 @@ extern "C" {
#include <stb_truetype.h>
#include <memory>
#include <algorithm>
#include <sstream>
// #include <iterator>
// #include <algorithm>
// #include <string>

View File

@ -11,5 +11,6 @@ target_sources(${DAWN_TARGET_NAME}
)
# Subdirs
add_subdirectory(animation)
add_subdirectory(font)
add_subdirectory(mesh)

View File

@ -0,0 +1,173 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "event/Event.hpp"
#include "Easing.hpp"
#include "util/mathutils.hpp"
namespace Dawn {
template<typename T>
struct Keyframe {
float_t time;
T value;
};
template<typename T>
struct TimelineItem {
T *modifies;
std::vector<struct Keyframe<T>> keyframes;
};
template<typename T>
struct Animation {
public:
bool_t loop = false;
bool_t finished = false;
float_t time = 0;
float_t duration = 0;
easefunction_t *easing = &easeLinear;
std::vector<struct TimelineItem<T>> timelineItems;
Event<> eventAnimationEnd;
/**
* Get an existing timeline item based on the value that will be modified.
*
* @param modifies Value that is intended to be modified for the timeline.
* @return The existing timeline item OR NULL if not found.
*/
struct TimelineItem<T> * getTimelineItem(T *modifies) {
assertNotNull(modifies);
auto it = this->timelineItems.begin();
while(it != this->timelineItems.end()) {
if(it->modifies == modifies) return &(*it);
++it;
}
return nullptr;
}
/**
* Add a timeline item to an animation.
*
* @param modifies Value that will be modified for the timeline item.
* @return The timeline item for that modified value.
*/
struct TimelineItem<T> * addTimelineItem(T *modifies) {
assertNotNull(modifies);
struct TimelineItem<T> item;
item.modifies = modifies;
this->timelineItems.push_back(item);
return &this->timelineItems.back();
}
/**
* Add a keyframe to the animation.
*
* @param modifies Pointer to the value that will be modified.
* @param time Time that the animation will occur at (gametime seconds).
* @param value Value for this keyframe
* @return The keyframe that was added.
*/
struct Keyframe<T> * addKeyframe(T *modifies, float_t time, T value) {
auto item = this->getTimelineItem(modifies);
if(item == nullptr) item = this->addTimelineItem(modifies);
struct Keyframe<T> keyframe;
keyframe.time = time;
keyframe.value = value;
this->duration = mathMax<float_t>(this->duration, time);
this->finished = false;
item->keyframes.push_back(keyframe);
return &item->keyframes.back();
}
/**
* Tick/Update the animation.
*
* @param delta Delta (in seconds) to update the animation by.
*/
void tick(float_t delta) {
if(this->finished) return;
float_t newTime = this->time + delta;
auto it = this->timelineItems.begin();
while(it != this->timelineItems.end()) {
struct Keyframe<T> *keyframeNext = nullptr;
struct Keyframe<T> *keyframeCurrent = nullptr;
// For each keyframe
auto itKey = it->keyframes.begin();
while(itKey != it->keyframes.end()) {
if(itKey->time > newTime) {
keyframeNext = &(*itKey);
break;
}
keyframeCurrent = &(*itKey);
++itKey;
}
// Skip when no keyframe
float_t oldTime;
T oldValue;
if(keyframeCurrent == nullptr) {
if(keyframeNext == nullptr) continue;
oldTime = this->time;
oldValue = *it->modifies;
} else if(keyframeNext == nullptr) {
*it->modifies = keyframeCurrent->value;
++it;
continue;
} else {
oldValue = keyframeCurrent->value;
oldTime = keyframeCurrent->time;
}
// Slerp between keyframes
float_t keyframeDelta = this->easing(
(newTime - oldTime) / (keyframeNext->time - oldTime)
);
*it->modifies = oldValue + (
(keyframeNext->value - oldValue) * keyframeDelta
);
++it;
}
// Update time.
this->time = newTime;
// Has the animation finished?
if(newTime < this->duration) return;
// Do we need to loop?
if(this->loop) {
this->time = 0;
return;
}
// Animation end.
this->finished = true;
this->eventAnimationEnd.invoke();
}
void restart() {
this->time = 0;
this->finished = false;
}
/**
* Clears an animaton of all its animation items and keyframes.
*/
void clear() {
this->timelineItems.clear();
this->duration = 0;
}
};
}

View File

@ -0,0 +1,10 @@
# Copyright (c) 2022 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
# target_sources(${DAWN_TARGET_NAME}
# PRIVATE
# Animation.cpp
# )

View File

@ -7,6 +7,7 @@
#pragma once
#include "dawnlibs.hpp"
typedef float_t easefunction_t(float_t t);
/**

View File

@ -25,7 +25,7 @@ void PokerGame::newGame() {
auto it = this->players.begin();
while(it != this->players.end()) {
auto player = *it;
player->chips = POKER_PLAYER_CHIPS_DEFAULT;
player->setChips(POKER_PLAYER_CHIPS_DEFAULT);
player->isOut = false;
++it;
}

View File

@ -24,6 +24,12 @@ void PokerPlayer::addChips(int32_t chips) {
this->chips += chips;
if(this->chips > 0) this->isOut = false;
eventChipsChanged.invoke();
}
void PokerPlayer::setChips(int32_t chips) {
this->chips = 0;
this->addChips(chips);
}
bool_t PokerPlayer::needsToBetThisRound() {
@ -39,7 +45,7 @@ void PokerPlayer::bet(struct PokerPot *pot, int32_t chips) {
assertTrue(chips >= 0);
assertTrue(!this->isFolded);
assertTrue(!this->isOut);
this->chips -= chips;
this->setChips(this->chips - chips);
this->currentBet += chips;
this->hasBetThisRound = true;
if(chips > 0) {

View File

@ -37,6 +37,8 @@ namespace Dawn {
bool_t isHuman = false;
std::vector<struct Card> hand;
Event<> eventChipsChanged;
/**
* Creates a PokerPlayer instance.
*
@ -54,6 +56,13 @@ namespace Dawn {
*/
void addChips(int32_t chips);
/**
* Sets the chips a player has.
*
* @param chips Chips to set to the player.
*/
void setChips(int32_t chips);
/**
* Returns true if the player still needs to bet this betting round.
*

View File

@ -96,6 +96,14 @@ float_t UIComponent::getHeight() {
return this->height;
}
float_t UIComponent::getContentWidth() {
return this->width;
}
float_t UIComponent::getContentHeight() {
return this->height;
}
float_t UIComponent::getRelativeX() {
return this->relativeX;
}
@ -104,6 +112,14 @@ float_t UIComponent::getRelativeY() {
return this->relativeY;
}
DawnGame * UIComponent::getGame() {
return this->canvas->getGame();
}
Scene * UIComponent::getScene() {
return this->canvas->getScene();
}
void UIComponent::setTransform(
UIComponentAlign xAlign,
UIComponentAlign yAlign,

View File

@ -68,14 +68,30 @@ namespace Dawn {
*
* @return Width of the component.
*/
float_t getWidth();
virtual float_t getWidth();
/**
* Returns the calculated height, based on the internal alignment values.
*
* @return Height of the component.
*/
float_t getHeight();
virtual float_t getHeight();
/**
* Returns the internal width of the content within this element, e.g.
* the content width.
*
* @return Content width.
*/
virtual float_t getContentWidth();
/**
* Returns the internal height of the content within this element, e.g.
* the content height.
*
* @return Content height.
*/
virtual float_t getContentHeight();
/**
* Returns the X position, relative to this components' parent.
@ -91,6 +107,20 @@ namespace Dawn {
*/
float_t getRelativeY();
/**
* Gets the game that this UI component belongs to.
*
* @return Game instance.
*/
DawnGame * getGame();
/**
* Gets the scene that thsi UI Component belongs to.
*
* @return Scene instance.
*/
Scene * getScene();
/**
* Updates the transformation for this component.
*

View File

@ -21,7 +21,7 @@ void UILabel::updateMesh() {
if(this->font == nullptr || !this->font->isReady()) return;
if(this->text.size() == 0) return;
float_t width = this->getWidth();
float_t width = this->width;
if(width == 0) width = -1;
this->font->buffer(
@ -54,6 +54,16 @@ void UILabel::setFontSize(float_t fontSize) {
this->needsRebuffering = true;
}
float_t UILabel::getContentWidth() {
this->updateMesh();
return this->measure.getWidth();
}
float_t UILabel::getContentHeight() {
this->updateMesh();
return this->measure.getHeight();
}
void UILabel::drawSelf(UIShader *shader, glm::mat4 selfTransform) {
if(this->font == nullptr || this->text.size() == 0) return;

View File

@ -29,6 +29,8 @@ namespace Dawn {
UILabel(UICanvas *canvas);
void drawSelf(UIShader *shader, glm::mat4 selfTransform) override;
virtual float_t getContentWidth() override;
virtual float_t getContentHeight() override;
void setTransform(
UIComponentAlign xAlign,
UIComponentAlign yAlign,