Create project barebone

- Create makefile that compiles everything and xSDL as a shared library (.so)
- Create xSDL base library (not stable)
- Add vscode settings (include path)
- Default main.h
This commit is contained in:
Adrien Marquès 2019-11-05 21:45:41 +01:00
parent a01d9f0fc0
commit bbf5c25e8e
16 changed files with 1113 additions and 1 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/build/
/gitignore/

59
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,59 @@
{
"C_Cpp.default.includePath": [
"/usr/include/SDL2/"
],
"files.associations": {
"exception": "cpp",
"stdexcept": "cpp",
"string": "cpp",
"atomic": "cpp",
"*.tcc": "cpp",
"deque": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"fstream": "cpp",
"limits": "cpp",
"sstream": "cpp",
"system_error": "cpp",
"new": "cpp",
"array": "cpp",
"bit": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"condition_variable": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"string_view": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"initializer_list": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"mutex": "cpp",
"ostream": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp"
},
"C_Cpp.errorSquiggles": "Enabled"
}

View File

@ -1,2 +1,29 @@
# xmario ## xSDL
```yaml
package: xSDL
language: c++
version: 0.1.0
author: xdrm-brackets
```
xSDL is a simple 2D wrapper around the SDL2 to make your life easier.
### Documentation
The API aims to be straightforward as possible and tries to take advantage of patterns and principles to achieve its goal.
> xSDL can be compiled as a dynamic library (_e.g. lib.so_). The include header is located in _include/xSDL.h_. It can also be compiled directly within your application.
The class `xApplication` is a singleton representing your application, its window, renderer, etc. An `xApplication` features a `xController` that manages user input.
The interface `xElement` represents any graphical feature to be drawn on the screen. Any number of `xElement` can be pushed to or pulled from the application at any time in order to show them or not.
The class `xSprite` represents a sprite that can is a rectangle that can draw either as a single color, an image, or a copy of another sprite. It can be moved over time. Also, it allows you to set a custom clip if this is an image sprite.
The class `xSpriteAnimation` derives from an image sprite, which clip can change over time. These clips are called _frames_ and have to be set beforehand, when ready you can start or stop the animation with a specified delay between frames. Every `xSpriteAnimation` is scheduled on the same dedicated animation thread.
The concurrency model is led simple :
- the main loop schedules rendering and user input
- the animation loop schedules animation frame shifts

10
include/xSDL.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef DEF_XSDL_H
#define DEF_XSDL_H
#include "../xSDL/xApplication.h"
#include "../xSDL/xController.h"
#include "../xSDL/xElement.h"
#include "../xSDL/xSprite.h"
#include "../xSDL/xSpriteAnimation.h"
#endif

19
main.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef DEF_MAIN_H
#define DEF_MAIN_H
#include <iostream>
#include <ctime>
#include <thread>
#include <unistd.h>
#include "include/xSDL.h"
// #include "include/xMario.h"
using namespace std;
#define BLOC_WIDTH 32
#define BLOC_HEIGHT 20
#define FPS 40
#define BLOC_SIZE 32
#endif

41
makefile Normal file
View File

@ -0,0 +1,41 @@
.PHONY: build/exe
SDL_FLAGS=`pkg-config sdl2 SDL2_image --cflags --libs`
FLAGS=-pthread -std=c++11 $(SDL_FLAGS) -Wall -Wextra
CC=g++ $(FLAGS)
CC_STATIC=$(CC) -fPIC
CC_SHARED=g++ -shared
CUR_DIR=$(shell pwd)
# get list of '.o' files to be generated for 'build/include/libxsdl.so' target
XSDL_O_FILES=$(shell ls -l xSDL/*.cpp | awk '{print $$NF}' | sed 's/^xSDL\/\(.\+\)\.cpp$$/build\/static\/\1.o/g')
prepare:
test -d build/ || mkdir build/
test -d build/static || mkdir build/static
test -d build/include || mkdir build/include
clean:
test -d build/ && rm -r build/ || true
run:
LD_LIBRARY_PATH="$(CUR_DIR)/build/include/:$LD_LIBRARY_PATH" ./build/exe;
# build executable
build/exe: build/main.o build/include/libxsdl.so
$(CC) -L$(CUR_DIR)/build/include/ -o $@ $< -lxsdl
# xSDL lib static objects
build/static/%.o: xSDL/%.cpp
$(CC_STATIC) -c $^ -o $@
# xSDL shared (dynamic) library
build/include/libxsdl.so: $(XSDL_O_FILES)
$(CC_SHARED) -Wl,-soname,libxsdl.so -o $@ $^
# xMario lib
build/xMario.o: xMario/*.cpp
$(CC) -o $@ $^
# build main
build/main.o: main.cpp
$(CC) -o $@ -c $^

347
xSDL/xApplication.cpp Normal file
View File

@ -0,0 +1,347 @@
#include "xApplication.h"
xApplication* xApplication::_instance = nullptr;
/** Static singleton builder */
xApplication* xApplication::create(const char *t, int w, int h){
if( xApplication::_instance != nullptr ){
throw runtime_error("[xApplication] instance already created");
}
xApplication::_instance = new xApplication(t, w, h);
if( xApplication::_instance == nullptr ){
throw runtime_error("[xApplication] cannot instanciate");
}
return xApplication::_instance;
}
/** Static singleton getter */
xApplication* xApplication::get(){
if( xApplication::_instance == nullptr ){
throw runtime_error("[xApplication] instance not created yet");
}
return xApplication::_instance;
}
/** Private singleton constructor */
xApplication::xApplication(const char *t, int w, int h){
// default values
_lasttick = SDL_GetTicks();
_fpstime = 1000/60;
_window = NULL;
_renderer = NULL;
_texture = NULL;
// init SDL subsystems
SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER );
// create window
_window = SDL_CreateWindow(
t,
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
w,
h,
SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_BORDERLESS | SDL_WINDOW_OPENGL
);
if( _window == NULL ){
throw runtime_error("[xApplication] cannot create SDL window");
}
// store window dimensions
_winrect.x = 0; _winrect.y = 0;
_winrect.w = w; _winrect.h = h;
SDL_GetWindowSize(_window, &_winrect.w, &_winrect.h);
// create renderer
_renderer = SDL_CreateRenderer(
_window,
-1,
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
);
if( _renderer == NULL ){
throw runtime_error("[xApplication] cannot create SDL renderer");
}
}
/** clean resources */
xApplication::~xApplication(){
_sprites.clear();
SDL_DestroyTexture(_texture);
SDL_DestroyRenderer(_renderer);
SDL_DestroyWindow( _window );
SDL_Quit();
}
/** SDL getters */
SDL_Window* xApplication::window(){ return _window; }
SDL_Renderer* xApplication::renderer(){ return _renderer; }
/** Set rgba background */
void xApplication::setBackground(Uint8 r, Uint8 g, Uint8 b, Uint8 a){
SDL_SetRenderDrawColor( _renderer, r, g, b, a );
}
/** Sets image background */
bool xApplication::setImage(const char *url){
_texture = IMG_LoadTexture( _renderer, url );
return _texture != NULL;
}
/* [COLLIDE] Retourne si 2 objets sont en collision
=========================================================*/
// collisions <vector<bool>*>
// [0] -> VRAI si collision a droite
// [1] -> VRAI si collision a gauche
// [2] -> VRAI si collision en haut
// // [3] -> VRAI si collision en bas
// bool xApplication::collide(SDL_Rect a, SDL_Rect b, vector<bool>& cols){
// if( !this->status() ) return true;
// // Verification de collisions
// bool outLeft = (a.x >= b.x+b.w ); // Trop a droite
// bool outRight = (a.x+a.w <= b.x ); // Trop a gauche
// bool outUp = (a.y >= b.y+b.h ); // Trop en haut
// bool outDown = (a.y+a.h <= b.y ); // Trop en bas
// // Calcule du bord en question
// int distLeft = abs( (a.x+a.w) - b.x );
// int distRight = abs( a.x - (b.x+b.w) );
// int distBottom = abs( a.y - (b.y+b.h) );
// int distTop = abs( (a.y+a.h) - b.y );
// // Valeurs de retour pointeur
// cols[0] = !outRight && distRight <= 1; // plus proche de droite
// cols[1] = !outLeft && distLeft <= 2; // plus proche de gauche
// cols[2] = !outUp && distTop <= 2; // plus proche du haut
// cols[3] = !outDown && distBottom <= 1; // plus proche du bas
// // On retourne si il y a collision ou pas
// return !( outRight || outLeft || outUp || outDown );
// }
// /* [HIT] Retourne si une texture est en collision avec une autre
// =========================================================*/
// bool xApplication::hit(xSprite* current, int movex, int movey){
// if( !this->status() ) return true;
// // Anti conflit inter-thread
// _mutex_hit.try_lock();
// /* (1) On recupere le SDL_Rect destination du sprite courant */
// int xIndex = -1;
// for( int i = 0 ; i < _sprites.size() ; i++ )
// if( _sprites[i] == current ){
// xIndex = i;
// break;
// }
// if( xIndex == -1 ){
// _mutex_hit.unlock();
// return false;
// }
// SDL_Rect a = *current->dst();
// a.x += movex;
// a.y += movey;
// // Contiendra le sens de collision
// vector<bool> collideFrom(4, false);
// // Contiendra le sens de collision
// vector<bool> collideTo(4, false);
// /* (2) On regarde si en dehors de la fenetre */
// if( (a.x < _winrect.x ) // Inclus a droite
// || (a.x+a.w > _winrect.x+_winrect.w ) // Inclus a gauche
// || (a.y < _winrect.y ) // Inclus en haut
// || (a.y+a.h > _winrect.y+_winrect.h ) // Inclus en bas
// ){
// // Si on tombe, on meurt
// if( a.y+a.h > _winrect.y+_winrect.h )
// state = 2;
// cerr << _indexes[xIndex] << " collide with WINDOW" << endl;
// _mutex_hit.unlock();
// return true;
// }
// /* (3) On compare avec toutes les autres textures */
// for( int i = 0 ; i < _sprites.size() ; i++ ){
// // Si c'est pas le sprite courant
// if( _sprites[i] != current ){
// // On verifie que le sprite n'entre pas en collision
// if( this->collide(a, *(_sprites[i])->dst(), collideTo) ){
// // On recupere la surface en collision inverse
// collideFrom[0] = collideTo[1]; // On inverse Droite
// collideFrom[1] = collideTo[0]; // et Gauche
// collideFrom[2] = collideTo[3]; // On inverse Haut
// collideFrom[3] = collideTo[2]; // et Bas
// // On lance les listeners de collision
// _sprites[i]->onCollide(collideTo, current);
// current->onCollide(collideFrom, _sprites[i]);
// _debug = *(_sprites[i])->dst();
// _mutex_hit.unlock();
// return true;
// }
// }
// }
// // On debloque la ressource
// _mutex_hit.unlock();
// return false;
// }
// /* [HIT] Retourne si une texture est en collision avec une autre
// =========================================================*/
// bool xApplication::hit(string current, int movex, int movey){
// if( !this->status() ) return true;
// _mutex_hit.try_lock();
// /* (1) On recupere le SDL_Rect destination du sprite courant */
// xSprite *sprite = NULL;
// sprite = this->get(current);
// // Gestion erreur
// if( sprite == NULL ){
// _mutex_hit.unlock();
// return false;
// }
// // Retour du resultat
// _mutex_hit.unlock();
// return this->hit(sprite, movex, movey);
// }
/** adds new sprite to draw (with its identifier) */
void xApplication::push(string id, xElement* sprite){
_mutex_draw.try_lock();
_sprites[id] = sprite;
_mutex_draw.unlock();
}
/** removes a sprite to draw (from its identifier) */
void xApplication::pull(string id){
_mutex_draw.try_lock();
_sprites.erase(id);
_mutex_draw.unlock();
}
/** removes a sprite to draw (from its address) */
void xApplication::pull(xElement* sprite){
_mutex_draw.try_lock();
map<string, xElement*>::iterator it;
for( it = _sprites.begin() ; it != _sprites.end() ; it++ ){
if( sprite == it->second ){
_sprites.erase(it);
break;
}
}
_mutex_draw.unlock();
}
/** clears the scene */
void xApplication::clear(){
_mutex_draw.try_lock();
_sprites.clear();
_mutex_draw.unlock();
}
/** Update the scene */
void xApplication::render(){
_mutex_draw.try_lock();
/* 1. clear scene */
SDL_RenderClear(_renderer);
/* 2. apply background color */
SDL_RenderDrawRect(_renderer, &_winrect);
/* 3. add image texture if set */
if( _texture != NULL)
SDL_RenderCopy(_renderer, _texture, NULL, NULL);
/* 4. draw every sprite */
map<string, xElement*>::iterator it = _sprites.begin();
for( ; it != _sprites.end() ; it++ ){
xElement* sprite = it->second;
sprite->draw(_renderer);
}
/* 5. commit renderer */
SDL_RenderPresent(_renderer);
_mutex_draw.unlock();
}
/** Sets FPS */
void xApplication::setFps(const uint32_t fps){
_fps = fps;
}
/** schedules the main loop */
void xApplication::schedule(){
// poll events
SDL_Event event;
while( SDL_PollEvent(&event) != 0 )
this->_controller.handleEvent(&event);
// wait to satisfy FPS
this->syncFps(_fps);
// render
this->render();
}
/** synchronizes according to @fps
* to be used at the end of the UI loop */
void xApplication::syncFps(const int fps){
// set fps
if( fps != 0 )
_fpstime = 1000/fps;
if( _lasttick == 0 )
_lasttick = SDL_GetTicks()-_fpstime;
// wait if too fast
if( SDL_GetTicks()-_lasttick < _fpstime )
SDL_Delay( _fpstime - (SDL_GetTicks()-_lasttick) );
// store now
_lasttick = SDL_GetTicks();
}

89
xSDL/xApplication.h Normal file
View File

@ -0,0 +1,89 @@
#ifndef DEF_XENGINE_H
#define DEF_XENGINE_H
#include "SDL.h"
#include "SDL_image.h"
#include <vector>
#include <map>
#include <string>
#include <mutex>
#include <thread>
#include <stdexcept>
#include "xElement.h"
#include "xController.h"
using namespace std;
enum xAppState {
RUNNING,
STOPPING,
STOPPED
};
#define EventListener void(*)(SDL_Event*)
class xApplication{
public:
/** Singleton */
static xApplication* create(const char *t, int w, int h);
static xApplication* get();
~xApplication();
SDL_Window *window();
SDL_Renderer *renderer();
void setBackground(Uint8 r=0xff, Uint8 g=0xff, Uint8 b=0xff, Uint8 a=0xff);
bool setImage(const char *url);
// bool collide(SDL_Rect a, SDL_Rect b, vector<bool>& cols); // Collision entre 2 SDL_Rect
// bool hit(xSprite *current, int movex=0, int movey=0); // Gestion des collisions
// bool hit(string current, int movex=0, int movey=0); // Gestion des collisions
/** scene */
void push(string id, xElement* sprite);
void pull(string id);
void pull(xElement *sprite);
void clear();
void render();
// manage main loop and thread loops
void setFps(const uint32_t fps);
void schedule();
xAppState state;
private:
/** Singleton */
xApplication(const char *t, int w, int h);
static xApplication* _instance;
void syncFps(const int fps=0);
// fps management
uint32_t _fps = 60;
uint32_t _lasttick;
uint32_t _fpstime;
// event management
xController _controller;
// sdl objects
SDL_Window *_window;
SDL_Rect _winrect;
SDL_Renderer *_renderer;
SDL_Texture *_texture;
// sprites
map<string, xElement*> _sprites;
// shared threads
map<string, thread*> _pool;
// thread safety
mutex _mutex_draw;
};
#endif

40
xSDL/xController.cpp Normal file
View File

@ -0,0 +1,40 @@
#include "xController.h"
xController::xController():
_handlers()
{}
xController::~xController(){
_handlers.clear();
}
// called in scheduling
void xController::handleEvent(SDL_Event* event){
_mutex.lock();
map<SDL_EventType, EventListener>::iterator found = _handlers.find( (SDL_EventType) event->type );
// ignore no handler found
if( found == _handlers.end() ){
_mutex.unlock();
return;
}
(*found->second)(event);
_mutex.unlock();
}
// bind a new handler
void xController::attachEvent(SDL_EventType t, void(*handler)(SDL_Event*) ){
_mutex.lock();
_handlers[ t ] = handler;
_mutex.unlock();
}
// removes an existing handler
void xController::detachEvent(SDL_EventType t, void(*handler)(SDL_Event*) ){
_mutex.lock();
_handlers.erase(t);
_mutex.unlock();
}

32
xSDL/xController.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef DEF_XCONTROLLER_H
#define DEF_XCONTROLLER_H
#include "SDL.h"
#include <mutex>
#include <map>
using namespace std;
#define EventListener void(*)(SDL_Event*)
class xController{
public:
xController();
~xController();
// called in scheduling
void handleEvent(SDL_Event* event);
// manage handlers
void attachEvent(SDL_EventType t, void(*handler)(SDL_Event*) );
void detachEvent(SDL_EventType t, void(*handler)(SDL_Event*) );
private:
// event handlers
map<SDL_EventType, EventListener> _handlers;
// thread safety
mutex _mutex;
};
#endif

1
xSDL/xElement.cpp Normal file
View File

@ -0,0 +1 @@
#include "xElement.h"

10
xSDL/xElement.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef DEF_XELEMENT_H
#define DEF_XELEMENT_H
#include "SDL.h"
struct xElement {
virtual void draw(SDL_Renderer* renderer) = 0;
};
#endif

212
xSDL/xSprite.cpp Normal file
View File

@ -0,0 +1,212 @@
#include "xSprite.h"
/** clean SDL objects */
xSprite::~xSprite(){
_mutex.try_lock();
SDL_FreeSurface( _surface );
_mutex.unlock();
}
/** empty sprite */
xSprite::xSprite(){
_type = "basic";
}
/** color sprite */
xSprite::xSprite(const int rgba[]){
_type = "basic";
this->setSurface(rgba);
}
/** image sprite */
xSprite::xSprite(const char *url){
_type = "basic";
this->setSurface(url);
}
/** texture copy sprite */
xSprite::xSprite(SDL_Surface *s){
_type = "basic";
this->setSurface(s);
}
/** update sprite to rhb color */
void xSprite::setSurface(const int rgba[]){
_mutex.try_lock();
if( _surface != NULL ){
SDL_FreeSurface( _surface );
_surface = NULL;
}
_surface = SDL_CreateRGBSurface(0, 0, 0, 32, rgba[0], rgba[1], rgba[2], rgba[3]);
// On cree la texture a partir de la surface
// _surface = SDL_CreateTextureFromSurface(_manager->renderer(), surf);
if( _surface == NULL ) {
throw runtime_error("[xSprite] setSurface(rgba) -> NULL surface");
}
_mutex.unlock();
}
/** update sprite to image */
void xSprite::setSurface(const char *url){
_mutex.try_lock();
if( _surface != NULL ){
SDL_FreeSurface( _surface );
_surface = NULL;
}
_surface = IMG_Load(url);
if( _surface == NULL ) {
throw runtime_error("[xSprite] setSurface(url) -> NULL surface");
}
_mutex.unlock();
}
/* [SETTEXTURE] Modification de la texture texture
=========================================================*/
void xSprite::setSurface(SDL_Surface *s){
_mutex.try_lock();
if( _surface != NULL ){
SDL_FreeSurface( _surface );
_surface = NULL;
}
_surface = s;
if( _surface == NULL ) {
throw runtime_error("[xSprite] setSurface(surface) -> NULL surface");
}
_mutex.unlock();
}
/** move sprite with a (x,y) velocity
* - int[0]: new
* - int[1]: can move on y
*/
// bool* xSprite::move(double xSpeed, double ySpeed){
// _mutex.try_lock();
// bool result[2] = {false, false};
// /* logic variables */
// int incrx = x;
// int incry = y;
// bool moveFasterOnY = abs(x) <= abs(y);
// int signofx = (x==0) ? 0 : x / abs(x);
// int signofy = (y==0) ? 0 : y / abs(y);
// // while velocity not null
// while( incrx != 0 || incry != 0 ){
// result[0] = incrx;
// result[1] = incry;
// /* (3) Si on peut aller a la destination */
// // if( !_manager->hit(this, incrx, incry) ){
// // _dst.x += incrx;
// // _dst.y += incry;
// // // cerr << ">>> not locked <<<" << endl;
// // result[0] = incrx;
// // result[1] = incry;
// // _mutex.unlock();
// // return result;
// // }
// /* (4) Sinon, on decremente les deplacements 'alternativement' */
// if( moveFasterOnY ){ // Si on a plus de mouvement horizontal
// if( signofx != 0 && incrx != 0 ) // si la vel. sur x n'est pas nulle
// incrx -= signofx; // on diminue la vel. sur x
// else if( signofy != 0 && incry != 0 ) // sinon si vel. sur y n'est pas nulle
// incry -= signofy; // on diminue la vel. sur y
// else // sinon, velocite nulle
// return result; // On arrete de chercher
// }else{ // Si on a plus de mouvement vertical
// if( signofy != 0 && incry != 0 ) // si la vel. sur y n'est pas nulle
// incry -= signofy; // on diminue la vel. sur y
// else if( signofx != 0 && incrx != 0 ) // sinon si vel. sur x n'est pas nulle
// incrx -= signofx; // on diminue la vel. sur x
// else // sinon, velocite nulle
// return result; // On arrete de chercher
// }
// // if( !_manager->hit(this, 0, 1) ){
// // cerr << "locked from (" << _dst.x << ", " << _dst.y << ") to (" << incrx << ", " << incry << ")" << endl;
// // }
// }
// // retour
// _mutex.unlock();
// return result;
// }
/** get/set sprite type */
string xSprite::getType(){ return _type; }
void xSprite::setType(string newtype){ _type = newtype; }
/** set default dimensions */
void xSprite::dimensions(){
_mutex.try_lock();
/* extract surface lengths*/
int w = _surface->w;
int h = _surface->h;
_dst = (SDL_Rect){0, 0, w, h};
_src = (SDL_Rect){0, 0, w, h};
_mutex.unlock();
}
/** set surface dimensions */
void xSprite::dimensions(SDL_Rect r){
_mutex.try_lock();
/* extract surface lengths */
int w = _surface->w;
int h = _surface->h;
_src = (SDL_Rect){0, 0, w, h};
/* store destination dimensions */
_dst = (SDL_Rect){r.x, r.y, r.w, r.h};
_mutex.unlock();
}
/** set surface dimensions + clip */
void xSprite::dimensions(SDL_Rect r, SDL_Rect clip){
_mutex.try_lock();
_src = (SDL_Rect){clip.x, clip.y, clip.w, clip.h};
_dst = (SDL_Rect){r.x, r.y, r.w, r.h};
_mutex.unlock();
}
/** returns the surface */
SDL_Surface *xSprite::surface(){ return _surface; }
/** return destination dimensions */
SDL_Rect *xSprite::dst(){ return &_dst; }
/** return source dimensions */
SDL_Rect *xSprite::src(){ return &_src; }
/** draws to renderer */
void xSprite::draw(SDL_Renderer* renderer){
_mutex.try_lock();
SDL_RenderCopy(
renderer,
SDL_CreateTextureFromSurface(renderer, this->surface()),
this->src(),
this->dst()
);
_mutex.unlock();
}

60
xSDL/xSprite.h Normal file
View File

@ -0,0 +1,60 @@
#ifndef DEF_XSPRITE_H
#define DEF_XSPRITE_H
#include <string>
#include <vector>
#include <mutex>
#include "SDL.h"
#include "SDL_image.h"
#include "xElement.h"
using namespace std;
class xSprite : public xElement {
public:
xSprite(); // empty
xSprite(const int rgba[]); // color sprite
xSprite(const char *url); // image sprite
xSprite(SDL_Surface *s); // copy sprite
~xSprite();
// replace surface
void setSurface(const int rgba[]); // color sprite
void setSurface(const char *url); // image sprite
void setSurface(SDL_Surface *t); // copy surface
// move the sprite
// const bool* move(double xSpeed, double ySpeed);
// action to apply on collision
// virtual void onCollide(vector<bool> from, xSprite* by);
// get/set sprite type
string getType();
void setType(string newtype);
// set dimensions
void dimensions(); // defauts
void dimensions(SDL_Rect r);
void dimensions(SDL_Rect r, SDL_Rect clip); // w/ clip
// getters
SDL_Surface *surface();
SDL_Rect *dst();
SDL_Rect *src();
// implement xElement
virtual void draw(SDL_Renderer* renderer) override;
protected:
string _type;
SDL_Surface* _surface = NULL;
SDL_Rect _dst;
SDL_Rect _src;
mutex _mutex;
};
#endif

116
xSDL/xSpriteAnimation.cpp Normal file
View File

@ -0,0 +1,116 @@
#include "xSpriteAnimation.h"
/** clean SDL objects and frames */
xSpriteAnimation::~xSpriteAnimation(){
_mutex.try_lock();
SDL_FreeSurface( _surface );
_frames.erase( _frames.begin(), _frames.end() );
_mutex.unlock();
}
/** builds an animation */
xSpriteAnimation::xSpriteAnimation(const char *url, SDL_Rect dest)
: xSprite( url ){
this->dimensions(dest);
}
/** builds an animation from an existing surface */
xSpriteAnimation::xSpriteAnimation(SDL_Surface *s, SDL_Rect dest)
: xSprite(s) {
this->dimensions(dest);
}
/** adds an animation frame */
void xSpriteAnimation::addFrame(SDL_Rect clip){
_mutex.try_lock();
_frames.push_back( (SDL_Rect){
clip.x,
clip.y,
clip.w,
clip.h
} );
_mutex.unlock();
}
/** clears all frames */
void xSpriteAnimation::clearFrames(){
_mutex.try_lock();
_frames.erase(_frames.begin(), _frames.end());
_mutex.unlock();
}
/** draw to scene */
void xSpriteAnimation::draw(SDL_Renderer* renderer){
_mutex.try_lock();
SDL_RenderCopy(
renderer,
SDL_CreateTextureFromSurface(renderer, this->surface()),
this->src(),
this->dst()
);
_mutex.unlock();
}
/** animation process */
void xSpriteAnimationProcess(xSpriteAnimation *xSA, uint32_t t, int flags){
uint32_t timer = 0;
bool way = true;
uint32_t start = 0;
while( flags&SPRITE_ANIM_INFINITE ){
// for every frame (sprite)
for( uint32_t i = start ; i != xSA->_frames.size() ; i+=(way?1:-1) ){
timer = SDL_GetTicks();
// update current frame clip
// xSA->_mutex.try_lock();
xSA->_src = xSA->_frames.at(i);
// xSA->_mutex.unlock();
// xSA->manager()->update();
if( SDL_GetTicks()-timer < t )
SDL_Delay( t - (SDL_GetTicks()-timer) );
}
// manage reverse flag
if( flags&SPRITE_ANIM_REVERSE ){
way = !way;
start = (way) ? 0 : xSA->_frames.size()-1;
}
}
// end thread
return;
}
/** adds the animation to the render */
void xSpriteAnimation::start(int t, int flags){
_timeout = t;
_flags = flags;
// launch animation
_animation = new thread(xSpriteAnimationProcess, this, t, flags);
// don't wait for the thread to end
_animation->detach();
}
/** stops the animation */
void xSpriteAnimation::stop(){
// stop animation thread
delete _animation;
if( _animation->joinable() )
_animation->join();
_animation = NULL;
}

47
xSDL/xSpriteAnimation.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef DEF_XSPRITEANIMATION_H
#define DEF_XSPRITEANIMATION_H
#include "SDL.h"
#include "xSprite.h"
#include "xApplication.h"
#include "xElement.h"
#include <vector>
#include <thread>
using namespace std;
#define SPRITE_ANIM_ONCE 0b1
#define SPRITE_ANIM_INFINITE 0b10
#define SPRITE_ANIM_REVERSE 0b100
class xSpriteAnimation : public xSprite {
public:
// spritesheet with sprite size
xSpriteAnimation(const char *url, SDL_Rect dest);
xSpriteAnimation(SDL_Surface *s, SDL_Rect dest);
~xSpriteAnimation();
void addFrame(SDL_Rect clip);
void clearFrames();
// animation control handles
void start(int t, int flags=SPRITE_ANIM_ONCE);
void stop();
// implement xElement
void draw(SDL_Renderer* renderer) override;
protected:
vector<SDL_Rect> _frames;
// animation
int _timeout;
int _flags;
// animation thread
thread *_animation;
friend void xSpriteAnimationProcess(xSpriteAnimation *xSA, uint32_t t, int flags);
};
#endif