Minor README update and some git hassles

This commit is contained in:
Toasterbirb 2022-01-24 21:13:15 +02:00
parent 4431771af1
commit e11ea35c4c
9 changed files with 330 additions and 35 deletions

View File

@ -1,7 +1,7 @@
CC=g++
SRCDIR=./src
outputDir=./build
CFLAGS=-fPIC -O2
CFLAGS=-fPIC -O2 -g
WarningFlags=-Wpedantic -pedantic -Wall -Wextra
SDL_FLAGS=-lSDL2 -lSDL2main -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lSDL2_gfx
INCLUDES=-I./include
@ -9,6 +9,9 @@ LIBFILE=libbirb2d.so
all: test engine_lib
docs:
doxygen ./doxygen_config
test: tests.o logger.o renderwindow.o values.o timestep.o utils.o math.o
mkdir -p build
$(CC) $^ $(SDL_FLAGS) $(WarningFlags) -o $(outputDir)/test
@ -16,22 +19,24 @@ test: tests.o logger.o renderwindow.o values.o timestep.o utils.o math.o
run_tests: test
./build/test
engine_obj: audio.o entity.o logger.o math.o renderwindow.o physics.o timer.o timestep.o utils.o values.o
engine_lib: audio.o entity.o logger.o math.o renderwindow.o physics.o timer.o timestep.o ui.o utils.o values.o
mkdir -p build
ld -r $^ -o $(outputDir)/birb2d.o
g++ -shared -g $(SDL_FLAGS) -o $(outputDir)/$(LIBFILE) $^
engine_lib: audio.o entity.o logger.o math.o renderwindow.o physics.o timer.o timestep.o utils.o values.o
static_engine_lib: audio.o entity.o logger.o math.o renderwindow.o physics.o timer.o timestep.o ui.o utils.o values.o
mkdir -p build
g++ -shared $(SDL_FLAGS) -o $(outputDir)/$(LIBFILE) $^
g++ -static $(SDL_FLAGS) -o $(outputDir)/$(LIBFILE) $^
install: engine_lib
cp $(outputDir)/$(LIBFILE) /usr/lib/
mkdir -p /usr/local/include/birb2d
cp ./include/* /usr/local/include/birb2d/
ldconfig
uninstall:
rm -f /usr/lib/$(LIBFILE)
rm -rf /usr/local/include/birb2d
ldconfig
audio.o: $(SRCDIR)/audio.cpp
$(CC) -c $(CFLAGS) $(INCLUDES) $^ -o audio.o
@ -60,6 +65,9 @@ timer.o: $(SRCDIR)/timer.cpp
timestep.o: $(SRCDIR)/timestep.cpp
$(CC) -c $(CFLAGS) $(INCLUDES) $(WarningFlags) $^ -o timestep.o
ui.o: $(SRCDIR)/ui.cpp
$(CC) -c $(CFLAGS) $(INCLUDES) $(WarningFlags) $^ -o ui.o
utils.o: $(SRCDIR)/utils.cpp
$(CC) -c $(CFLAGS) $(INCLUDES) $(WarningFlags) $^ -o utils.o
@ -72,3 +80,4 @@ values.o: $(SRCDIR)/values.cpp
clean:
rm -f *.o log.txt
rm -rf $(outputDir)
rm -rf docs

View File

@ -63,6 +63,6 @@ make uninstall
- [ ] Resolution independent UI scaling
- [ ] Anchors
- [x] Sound
- [ ] Animation
- [x] Animation (sprite based animations supported)
- [ ] Physics
- [ ] To be continued...

View File

@ -1,21 +1,62 @@
#pragma once
#include <functional>
#include <string>
#include <vector>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include "Utils.hpp"
#include "Timer.hpp"
namespace Birb
{
/// TextComponent contains details needed to generate a sprite for the Entity in case the Entity is used to display text.
struct TextComponent
namespace EntityComponent
{
TextComponent();
TextComponent(std::string p_text, TTF_Font* font, SDL_Color* p_color);
std::string text;
TTF_Font* font;
SDL_Color* color; ///< Surface color of the text
};
/// TextComponent contains details needed to generate a sprite for the Entity in case the Entity is used to display text.
struct TextComponent
{
TextComponent();
TextComponent(std::string p_text, TTF_Font* font, SDL_Color* p_color);
TextComponent(std::string p_text, TTF_Font* font, SDL_Color* p_color, SDL_Color* p_bgColor);
std::string text;
TTF_Font* font;
SDL_Color* color; ///< Surface color of the text
SDL_Color* bgColor; ///< Background color for the text component
};
/// ClickComponent adds button functionality to the Entity
struct ClickComponent
{
ClickComponent();
ClickComponent(std::function<void()> p_onClick);
bool active;
std::function<void()> onClick;
};
/// AnimationComponent allows for texture atlas based sprite animations
struct AnimationComponent
{
AnimationComponent();
AnimationComponent(Vector2int p_spriteSize, int p_frameCount, int p_fps);
AnimationComponent(Vector2int p_spriteSize, int p_frameCount, int p_fps, bool p_loop);
int fps;
bool loop; ///< Start the animation over when it ends
int frameIndex; ///< Current visible frame
int frameCount; ///< Total amount of sprites in the atlas
Vector2int spriteSize; ///< The size of one sprite in the atlas. Used for cropping
Timer frameTimer;
bool animationQueued;
int lastFrame;
void StartAnimation();
void StartAnimation(int startFrame);
void StartAnimation(int startFrame, int endFrame);
void ResetAnimationAtlas();
};
}
/// Entities are objects that contain all of the information required to render stuff
@ -24,7 +65,7 @@ namespace Birb
{
Entity(); ///< Creates empty Entity object
Entity(std::string p_name, Rect p_rect, SDL_Texture* p_texture); ///< Creates an Entity with a SDL_Texture to render with custom scale
Entity(std::string p_name, Vector2int pos, TextComponent p_textComponent); ///< Creates a Text Entity using a TextComponent
Entity(std::string p_name, Vector2int pos, EntityComponent::TextComponent p_textComponent); ///< Creates a Text Entity using a TextComponent
Entity(std::string p_name, Vector2int pos, SDL_Texture* p_texture); ///< Creates an Entity with a SDL_Texture to render without specifying a scale
/* Make it possible to update the TextComponent */
@ -33,16 +74,24 @@ namespace Birb
void SetColor(SDL_Color* color); ///< Change the color in TextComponent and reload the sprite
std::string name; ///< Name of the entity. Used for debugging
/* Sprite handlings */
SDL_Texture* sprite; ///< Sprite to be rendered
float angle; ///< Sets the rotation of the entity when rendering it
Rect rect; ///< Sets the position and the dimensions of the entity
Vector2f localScale; ///< Scale modifier for the Entity rendering
TextComponent textComponent; ///< Having a TextComponent in an Entity enables the rendering of Text
EntityComponent::TextComponent textComponent; ///< Enables the rendering of Text
EntityComponent::ClickComponent clickComponent; ///< Enables button-like functionality
EntityComponent::AnimationComponent animationComponent; ///< Enables animations for sprite rendering
void LoadSprite(); ///< Create a sprite for the Entity using details found in the textComponent variable
void ReloadSprite(); ///< Destroy the old sprite and create a new one. Useful for refreshing text after editing the textComponent variable
void SetBaseEntityValues(); ///< Used to set some default value when they aren't provided during Entity initialization
/* Informational functions */
bool isHovering(); ///< Check if the cursor is hovering over this entity
Vector2int getAtlasPosition(int frame); ///< Get position in a texture atlas given the sprite index
};
}

View File

@ -54,6 +54,7 @@ namespace Birb
{
static SDL_Texture* LoadTexture(std::string p_filePath);
static SDL_Texture* TextSprite(std::string text, TTF_Font* font, SDL_Color& color);
static SDL_Texture* TextSprite(std::string text, TTF_Font* font, SDL_Color& color, SDL_Color& bgColor);
static TTF_Font* LoadFont(std::string p_filePath, int p_fontSize);
};

16
include/UI.hpp Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <vector>
#include "Entity.hpp"
#include "Renderwindow.hpp"
namespace Birb
{
class UI
{
public:
UI();
std::vector<Entity> Buttons;
void AddButton(Entity buttonEntity);
void PollButtons(Window window);
};
}

View File

@ -4,16 +4,114 @@
namespace Birb
{
TextComponent::TextComponent()
namespace EntityComponent
{
text = "";
font = NULL;
color = NULL;
TextComponent::TextComponent()
{
text = "";
font = NULL;
color = NULL;
bgColor = NULL;
}
TextComponent::TextComponent(std::string p_text, TTF_Font* p_font, SDL_Color* p_color)
:text(p_text), font(p_font), color(p_color)
{
bgColor = NULL;
}
TextComponent::TextComponent(std::string p_text, TTF_Font* p_font, SDL_Color* p_color, SDL_Color* p_bgColor)
:text(p_text), font(p_font), color(p_color), bgColor(p_bgColor)
{}
void PlaceHolderClickEvent()
{
Debug::Log("This button is working");
}
ClickComponent::ClickComponent()
{
active = true;
onClick = PlaceHolderClickEvent;
}
ClickComponent::ClickComponent(std::function<void()> p_onClick)
:onClick(p_onClick)
{
active = true;
}
AnimationComponent::AnimationComponent()
{
fps = 24;
loop = false;
frameIndex = 0;
frameCount = 0;
spriteSize = { 16, 16 };
animationQueued = false;
}
AnimationComponent::AnimationComponent(Vector2int p_spriteSize, int p_frameCount, int p_fps)
:spriteSize(p_spriteSize), frameCount(p_frameCount), fps(p_fps), lastFrame(p_frameCount - 1)
{
frameIndex = 0;
loop = false;
animationQueued = false;
}
AnimationComponent::AnimationComponent(Vector2int p_spriteSize, int p_frameCount, int p_fps, bool p_loop)
:spriteSize(p_spriteSize), frameCount(p_frameCount), fps(p_fps), loop(p_loop), lastFrame(p_frameCount - 1)
{
frameIndex = 0;
animationQueued = false;
}
void AnimationComponent::ResetAnimationAtlas()
{
frameIndex = 0;
lastFrame = frameCount - 1;
}
void AnimationComponent::StartAnimation()
{
ResetAnimationAtlas();
animationQueued = true;
}
void AnimationComponent::StartAnimation(int p_startFrame)
{
frameIndex = p_startFrame;
lastFrame = frameCount - 1;
animationQueued = true;
}
void AnimationComponent::StartAnimation(int p_startFrame, int p_lastFrame)
{
frameIndex = p_startFrame;
lastFrame = p_lastFrame;
animationQueued = true;
}
}
TextComponent::TextComponent(std::string p_text, TTF_Font* p_font, SDL_Color* p_color)
:text(p_text), font(p_font), color(p_color)
{}
Vector2int Entity::getAtlasPosition(int frame)
{
Vector2int pos;
int index = frame;
int texWidth;
int texHeight;
SDL_QueryTexture(sprite, NULL, NULL, &texWidth, &texHeight);
int spritesPerRow = texWidth / animationComponent.spriteSize.x;
float fullRowCount = std::floor(index / spritesPerRow);
float leftOver = ((index / (float)spritesPerRow) - fullRowCount) * spritesPerRow;
pos.x = leftOver * animationComponent.spriteSize.x;
pos.y = fullRowCount * animationComponent.spriteSize.y;
return pos;
}
void Entity::SetText(std::string newText)
{
@ -59,7 +157,7 @@ namespace Birb
SetBaseEntityValues();
}
Entity::Entity(std::string p_name, Vector2int pos, TextComponent p_textComponent)
Entity::Entity(std::string p_name, Vector2int pos, EntityComponent::TextComponent p_textComponent)
:name(p_name)
{
/* Load the text sprite */
@ -91,8 +189,10 @@ namespace Birb
/* There's a text component. Let's generate a text sprite for it */
if (textComponent.text != "")
{
//Debug::Log("Loading a text sprite '" + name + "'");
sprite = Resources::TextSprite(textComponent.text, textComponent.font, *textComponent.color);
if (textComponent.bgColor == NULL)
sprite = Resources::TextSprite(textComponent.text, textComponent.font, *textComponent.color);
else
sprite = Resources::TextSprite(textComponent.text, textComponent.font, *textComponent.color, *textComponent.bgColor);
if (sprite == nullptr)
Debug::Log("Something went wrong while creating the text sprite for '" + name + "'", Debug::error);

View File

@ -102,6 +102,24 @@ namespace Birb
SDL_RenderPresent(Global::RenderVars::Renderer);
}
Vector2int Window::CursorPosition()
{
Vector2int pos;
SDL_GetMouseState(&pos.x, &pos.y);
return pos;
}
bool Window::CursorInRect(Rect rect)
{
Vector2int cursorPos = CursorPosition();
if (cursorPos.x > rect.x && cursorPos.x < rect.x + rect.w)
if (cursorPos.y > rect.y && cursorPos.y < rect.y + rect.h)
return true;
return false;
}
void Window::SetWindowSize(Vector2int dimensions)
{
SDL_SetWindowSize(win, dimensions.x, dimensions.y);
@ -180,6 +198,27 @@ namespace Birb
return texture;
}
SDL_Texture* Resources::TextSprite(std::string text, TTF_Font* font, SDL_Color& color, SDL_Color& bgColor)
{
/* Check if the arguments are valid */
if (font == nullptr)
{
Debug::Log("Tried to render text with invalid font!");
return NULL;
}
SDL_Surface* surface = TTF_RenderText_Shaded(font, text.c_str(), color, bgColor);
if (surface == nullptr)
Debug::Log("Error creating SDL_Surface. Text: " + (std::string)text + ". SDL Error: " + (std::string)SDL_GetError(), Debug::error);
SDL_Texture* texture = SDL_CreateTextureFromSurface(Global::RenderVars::Renderer, surface);
if (texture == nullptr)
Debug::Log("Error creating texture from surface: " + (std::string)SDL_GetError(), Debug::error);
SDL_FreeSurface(surface);
return texture;
}
void Render::DrawEntity(Entity& entity)
{
if (entity.sprite == nullptr)
@ -197,15 +236,65 @@ namespace Birb
int texHeight;
SDL_QueryTexture(entity.sprite, NULL, NULL, &texWidth, &texHeight);
src.x = 0;
src.y = 0;
src.w = texWidth;
src.h = texHeight;
if (entity.animationComponent.frameCount == 0)
{
src.x = 0;
src.y = 0;
src.w = texWidth;
src.h = texHeight;
dst.x = entity.rect.x;
dst.y = entity.rect.y;
dst.w = entity.rect.w * entity.localScale.x;
dst.h = entity.rect.h * entity.localScale.y;
dst.x = entity.rect.x;
dst.y = entity.rect.y;
dst.w = entity.rect.w * entity.localScale.x;
dst.h = entity.rect.h * entity.localScale.y;
}
else
{
/* Entity probably has an animation component */
//src.x = entity.animationComponent.curAtlasPosition.x;
//src.y = entity.animationComponent.curAtlasPosition.y;
Vector2int atlasPos = entity.getAtlasPosition(entity.animationComponent.frameIndex);
src.x = atlasPos.x;
src.y = atlasPos.y;
src.w = entity.animationComponent.spriteSize.x;
src.h = entity.animationComponent.spriteSize.y;
dst.x = entity.rect.x;
dst.y = entity.rect.y;
dst.w = src.w * entity.localScale.x;
dst.h = src.h * entity.localScale.y;
/* Set the current atlast position to the next frame */
if (entity.animationComponent.animationQueued || entity.animationComponent.loop)
{
if (entity.animationComponent.frameTimer.running && entity.animationComponent.frameTimer.ElapsedSeconds() >= (1.0 / entity.animationComponent.fps))
{
if (entity.animationComponent.frameIndex < entity.animationComponent.lastFrame)
{
entity.animationComponent.frameIndex++;
entity.animationComponent.frameTimer.Stop();
entity.animationComponent.frameTimer.Start();
}
}
else if (!entity.animationComponent.frameTimer.running)
{
/* Start the frame timer */
entity.animationComponent.frameTimer.Start();
}
if (entity.animationComponent.loop && entity.animationComponent.frameIndex >= entity.animationComponent.lastFrame)
{
entity.animationComponent.frameIndex = 0;
}
else if (entity.animationComponent.animationQueued && entity.animationComponent.frameIndex >= entity.animationComponent.lastFrame)
{
entity.animationComponent.frameIndex = entity.animationComponent.lastFrame;
entity.animationComponent.animationQueued = false;
}
}
}
centerPoint = Vector2int(entity.rect.w / 2, entity.rect.h / 2);
SDL_Point center = { centerPoint.x, centerPoint.y };

View File

@ -22,7 +22,7 @@ TEST_CASE("logging")
TEST_CASE("window and rendering functions")
{
Birb::Window window("Title", Birb::Vector2int(1280, 720), 60);
Birb::Window window("Title", Birb::Vector2int(1280, 720), 60, false);
SDL_Texture* texture = Birb::Resources::LoadTexture("/home/toasterbirb/git/birb2d/res/textures/giga_stretch.png");
TTF_Font* font = Birb::Resources::LoadFont("/home/toasterbirb/git/birb2d/res/fonts/freefont/FreeMonoBold.ttf", 32);

31
src/ui.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "UI.hpp"
namespace Birb
{
UI::UI() {}
void UI::AddButton(Entity buttonEntity)
{
Buttons.push_back(buttonEntity);
}
void UI::PollButtons(Window window)
{
for (int i = 0; i < Buttons.size(); i++)
{
/* Skip inactive buttons */
if (!Buttons[i].clickComponent.active)
continue;
/* Check if the cursor is on top of the button */
if (!window.CursorInRect(Buttons[i].rect))
continue;
/* Run the button click event */
Buttons[i].clickComponent.onClick();
/* You can really only click one button at once, so lets stop if we got this far */
break;
}
}
}