Split sdlpp into smaller files

This commit is contained in:
zvon 2020-11-21 20:57:40 +01:00
parent 9890da4e06
commit 633502b189
30 changed files with 2082 additions and 0 deletions

27
sdlpp/Makefile Normal file
View File

@ -0,0 +1,27 @@
CXX ?= g++
CPPFLAGS = -std=c++14 -Wall -Wextra -pedantic
LIBRARYFLAGS = -fPIC
MAJOR ?= 1
MINOR ?= 0
RELEASE ?= 0
SDLPPLIBRARY = libsdlpp.so.${MAJOR}.${MINOR}.${RELEASE}
OBJECTFILES = sdlpp_circlecolider.o sdlpp_circlerenderer.o sdlpp_collision.o sdlpp_common.o sdlpp_font.o sdlpp_linerenderer.o sdlpp_rectcolider.o sdlpp_rectrenderer.o sdlpp_renderer.o sdlpp_renderobject.o sdlpp_scene.o sdlpp_textrenderer.o sdlpp_texture.o sdlpp_window.o
all: ${SDLPPLIBRARY}
%.o: %.cpp
${CXX} ${CPPFLAGS} ${LIBRARYFLAGS} -c $< -o $@
${SDLPPLIBRARY}: ${OBJECTFILES}
${CXX} ${CPPFLAGS} -shared -Wl,-soname,libsdlpp.so.${MAJOR}\
-o ${SDLPPLIBRARY} $^
ln -sf ${SDLPPLIBRARY} libsdlpp.so
ln -sf ${SDLPPLIBRARY} libsdlpp.so.${MAJOR}
clean:
${RM} *.so* *.o
.PHONY: all clean test

20
sdlpp/sdlpp.hpp Normal file
View File

@ -0,0 +1,20 @@
#ifndef SDLPP_HPP
#define SDLPP_HPP
#include "sdlpp_common.hpp"
#include "sdlpp_collision.hpp"
#include "sdlpp_circlecolider.hpp"
#include "sdlpp_circlerenderer.hpp"
#include "sdlpp_font.hpp"
#include "sdlpp_linerenderer.hpp"
#include "sdlpp_scene.hpp"
#include "sdlpp_rectcolider.hpp"
#include "sdlpp_rectrenderer.hpp"
#include "sdlpp_renderer.hpp"
#include "sdlpp_renderobject.hpp"
#include "sdlpp_textrenderer.hpp"
#include "sdlpp_texture.hpp"
#include "sdlpp_window.hpp"
#endif

View File

@ -0,0 +1,133 @@
// TODO render function like in rectangle
#include "sdlpp_circlecolider.hpp"
namespace SDLPP {
CircleColider::CircleColider( double x, double y, double rad )
: CollisionPolygon( x, y ) {
original_rad = rad;
}
bool CircleColider::colidesWith( const SDLPP::CollisionPolygon &other ) const {
if ( other.isCircle() ) {
int otherRad = ( other.rightmost() - other.leftmost() ) / 2;
int thisRad = getRadius();
int totalDist = otherRad + thisRad;
int xdiff = other.leftmost() + otherRad - ( leftmost() + thisRad );
int ydiff = other.topmost() + otherRad - ( topmost() + thisRad );
return ( xdiff * xdiff + ydiff * ydiff ) <= totalDist * totalDist;
} else if ( other.isInfinite() ) {
return infinityIntersection( other, *this );
}
int rad = rad_;
int centerx = getX();
int centery = getY();
if ( other.topmost() <= centery && other.bottommost() >= centery ) {
return other.leftmost() <= rightmost() &&
other.rightmost() >= leftmost();
} else if ( other.leftmost() <= centerx && other.rightmost() >= centerx ) {
return other.topmost() <= bottommost() &&
other.bottommost() >= topmost();
}
int pointx = 0, pointy = 0;
if ( centerx > other.rightmost() ) {
pointx = other.rightmost();
} else {
pointx = other.leftmost();
}
if ( centery < other.topmost() ) {
pointy = other.topmost();
} else {
pointy = other.bottommost();
}
int distancesquared = ( pointx - centerx ) * ( pointx - centerx ) +
( pointy - centery ) * ( pointy - centery );
return distancesquared <= rad * rad;
}
bool CircleColider::isCircle() const {
return true;
}
int CircleColider::topmost() const {
return getY() - rad_;
}
int CircleColider::bottommost() const {
return getY() + rad_;
}
int CircleColider::leftmost() const {
return getX() - rad_;
}
int CircleColider::rightmost() const {
return getX() + rad_;
}
void CircleColider::updateCollision( int x, int y, int w, int h ) {
position_x = original_x * w + x;
position_y = original_y * h + y;
rad_ = original_rad * w;
}
void CircleColider::render( Renderer &renderer,
const std::tuple< int, int, int, int > &color ) {
std::vector< int > rect = { leftmost(), topmost(), rightmost(),
bottommost() };
auto center_x = getX();
auto center_y = getY();
auto radsq = rad_ * rad_;
for ( int i = rect[0]; i <= rect[2]; i++ ) {
auto xdiff = center_x - i;
auto xdist = xdiff * xdiff;
auto allowed_rad = sqrt( radsq - xdist );
SDL_SetRenderDrawColor( renderer.getRendererPtr(),
std::get< 0 >( color ), std::get< 1 >( color ),
std::get< 2 >( color ), 0x40 );
SDL_RenderDrawLine( renderer.getRendererPtr(), i,
center_y - allowed_rad, i, center_y + allowed_rad );
SDL_SetRenderDrawColor( renderer.getRendererPtr(),
std::get< 0 >( color ), std::get< 1 >( color ),
std::get< 2 >( color ), 0x80 );
SDL_RenderDrawLine( renderer.getRendererPtr(), i,
center_y - allowed_rad, i,
center_y - allowed_rad + 2 );
SDL_RenderDrawLine( renderer.getRendererPtr(), i,
center_y + allowed_rad, i,
center_y + allowed_rad - 2 );
}
SDL_SetRenderDrawColor( renderer.getRendererPtr(), 0xFF, 0, 0, 0xFF );
SDL_RenderDrawLine( renderer.getRendererPtr(), center_x, center_y,
center_x + rad_, center_y );
SDL_RenderDrawLine( renderer.getRendererPtr(), center_x, center_y, center_x,
center_y + rad_ );
SDL_RenderDrawLine( renderer.getRendererPtr(), center_x, center_y,
center_x - rad_, center_y );
SDL_RenderDrawLine( renderer.getRendererPtr(), center_x, center_y, center_x,
center_y - rad_ );
}
void CircleColider::render( Renderer &renderer ) {
std::vector< int > rect = { leftmost(), topmost(), rightmost(),
bottommost() };
auto center_x = getX();
auto center_y = getY();
auto radsq = rad_ * rad_;
for ( int i = rect[0]; i <= rect[2]; i++ ) {
auto xdiff = center_x - i;
auto xdist = xdiff * xdiff;
auto allowed_rad = sqrt( radsq - xdist );
SDL_SetRenderDrawColor( renderer.getRendererPtr(), sdl_color.r,
sdl_color.g, sdl_color.b, sdl_color.a );
SDL_RenderDrawLine( renderer.getRendererPtr(), i,
center_y - allowed_rad, i, center_y + allowed_rad );
SDL_SetRenderDrawColor( renderer.getRendererPtr(), sdl_outline.r,
sdl_outline.g, sdl_outline.b, sdl_outline.a );
SDL_RenderDrawLine( renderer.getRendererPtr(), i,
center_y - allowed_rad, i,
center_y - allowed_rad + 2 );
SDL_RenderDrawLine( renderer.getRendererPtr(), i,
center_y + allowed_rad, i,
center_y + allowed_rad - 2 );
}
}
int CircleColider::getRadius() const {
return rad_;
}
} // namespace SDLPP

View File

@ -0,0 +1,34 @@
#ifndef SDLPP_HPP_CIRCLE
#define SDLPP_HPP_CIRCLE
#include <vector>
#include "sdlpp_common.hpp"
#include "sdlpp_collision.hpp"
namespace SDLPP {
class CircleColider : public CollisionPolygon {
public:
CircleColider( double x, double y, double rad );
virtual ~CircleColider() {}
virtual bool colidesWith( const CollisionPolygon &other ) const override;
virtual bool isCircle() const override;
virtual int topmost() const override;
virtual int bottommost() const override;
virtual int leftmost() const override;
virtual int rightmost() const override;
virtual void updateCollision( int x, int y, int w, int h ) override;
virtual void
render( Renderer &renderer,
const std::tuple< int, int, int, int > &color ) override;
virtual void render( Renderer &renderer ) override;
private:
int getRadius() const;
double original_rad;
int rad_;
};
} // namespace SDLPP
#endif

View File

@ -0,0 +1,48 @@
#include "sdlpp_circlerenderer.hpp"
namespace SDLPP {
CircleRender::CircleRender( int x, int y, int rad,
std::shared_ptr< Renderer > &r )
: RenderObject( r ) {
x_ = x;
y_ = y;
rad_ = rad;
}
CircleRender::CircleRender( int x, int y, int rad,
std::shared_ptr< Renderer > &r,
std::shared_ptr< Texture > &t )
: CircleRender( x, y, rad, r ) {
setTexture( t );
}
CircleRender::CircleRender( int x, int y, int rad,
std::shared_ptr< Renderer > &r,
const std::string &img_path )
: CircleRender( x, y, rad, r ) {
auto texture = std::make_shared< Texture >( r, img_path );
setTexture( texture );
}
void CircleRender::render() {
std::cout << "I'm a circle, look at me go!" << std::endl
<< "My dimensions are: [" << x_ << ", " << y_
<< "], radius: " << rad_ << std::endl;
}
int CircleRender::leftmost() {
return x_ - rad_;
}
int CircleRender::topmost() {
return y_ - rad_;
}
int CircleRender::collisionPushX() {
return x_;
}
int CircleRender::collisionPushY() {
return y_;
}
} // namespace SDLPP

View File

@ -0,0 +1,31 @@
#ifndef SDLPP_HPP_CIRCLE_RENDERER
#define SDLPP_HPP_CIRCLE_RENDERER
#include "sdlpp_common.hpp"
#include "sdlpp_renderobject.hpp"
#include <memory>
namespace SDLPP {
class CircleRender : public RenderObject {
public:
CircleRender() = delete;
virtual ~CircleRender(){};
CircleRender( int x, int y, int rad, std::shared_ptr< Renderer > &r );
CircleRender( int x, int y, int rad, std::shared_ptr< Renderer > &r,
std::shared_ptr< Texture > &t );
CircleRender( int x, int y, int rad, std::shared_ptr< Renderer > &r,
const std::string &img_path );
virtual void render();
virtual int leftmost();
virtual int topmost();
virtual int collisionPushX();
virtual int collisionPushY();
private:
int x_;
int y_;
int rad_;
};
} // end of namespace SDLPP
#endif

60
sdlpp/sdlpp_collision.cpp Normal file
View File

@ -0,0 +1,60 @@
#include "sdlpp_collision.hpp"
namespace SDLPP {
CollisionPolygon::CollisionPolygon( double x, double y ) {
original_x = x;
original_y = y;
position_x = 0;
position_y = 0;
}
bool CollisionPolygon::isInfinite() const {
return infinite;
}
void CollisionPolygon::setInfinite() {
infinite = true;
}
void CollisionPolygon::updateCollision( int x, int y, int w, int h ) {
position_x = original_x * w + x;
position_y = original_y * h + y;
}
int CollisionPolygon::getX() const {
return position_x;
}
int CollisionPolygon::getY() const {
return position_y;
}
void CollisionPolygon::setColor( const std::string &color ) {
sdl_color = getSDLColorHEX( color );
}
void CollisionPolygon::setOutlineColor( const std::string &color ) {
sdl_outline = getSDLColorHEX( color );
}
bool infinityIntersection( const SDLPP::CollisionPolygon &infinite,
const SDLPP::CollisionPolygon &other ) {
int ileft = infinite.leftmost();
int iright = infinite.rightmost();
int itop = infinite.topmost();
int ibottom = infinite.bottommost();
bool ret =
ileft != -1 && ileft <= other.rightmost() && ileft >= other.leftmost();
ret |= iright != -1 && iright >= other.leftmost() &&
iright <= other.rightmost();
ret |= itop != -1 && itop <= other.bottommost() && itop >= other.topmost();
ret |= ibottom != -1 && ibottom >= other.topmost() &&
ibottom <= other.bottommost();
ret |= ileft == -1 && iright == -1 && itop == -1 && ibottom == -1;
return ret;
}
bool intersects( const SDLPP::CollisionPolygon &p1,
const SDLPP::CollisionPolygon &p2 ) {
return !(
p1.rightmost() < p2.leftmost() || p2.rightmost() < p1.leftmost() ||
p1.topmost() > p2.bottommost() || p2.topmost() > p1.bottommost() );
}
} // namespace SDLPP

44
sdlpp/sdlpp_collision.hpp Normal file
View File

@ -0,0 +1,44 @@
#ifndef SDLPP_HPP_COLLISION
#define SDLPP_HPP_COLLISION
#include "sdlpp_common.hpp"
#include "sdlpp_renderer.hpp"
namespace SDLPP {
class CollisionPolygon {
public:
CollisionPolygon( double x, double y );
virtual ~CollisionPolygon() {}
virtual bool colidesWith( const CollisionPolygon &other ) const = 0;
virtual bool isCircle() const = 0;
virtual bool isInfinite() const;
virtual void setInfinite();
virtual int topmost() const = 0;
virtual int bottommost() const = 0;
virtual int leftmost() const = 0;
virtual int rightmost() const = 0;
virtual void updateCollision( int x, int y, int w, int h );
virtual void render( Renderer &renderer,
const std::tuple< int, int, int, int > &color ) = 0;
virtual void render( Renderer &renderer ) = 0;
int getX() const;
int getY() const;
void setColor( const std::string &color );
void setOutlineColor( const std::string &color );
protected:
double original_x;
double original_y;
int position_x;
int position_y;
bool infinite = false;
SDL_Color sdl_color = { 0, 0, 0, 0 };
SDL_Color sdl_outline = { 0, 0, 0, 0 };
};
bool infinityIntersection( const SDLPP::CollisionPolygon &infinite,
const SDLPP::CollisionPolygon &other );
bool intersects( const SDLPP::CollisionPolygon &p1,
const SDLPP::CollisionPolygon &p2 );
} // namespace SDLPP
#endif

122
sdlpp/sdlpp_common.cpp Normal file
View File

@ -0,0 +1,122 @@
#include "sdlpp_common.hpp"
#ifdef _WIN32
#include "SDL2/SDL_image.h"
#else
#include <SDL2/SDL_image.h>
#endif
#include <iostream>
int SDLPP::hex2num( char c ) {
if ( c <= '9' )
return c - '0';
switch ( c ) {
case 'a':
case 'A':
return 10;
case 'b':
case 'B':
return 11;
case 'c':
case 'C':
return 12;
case 'd':
case 'D':
return 13;
case 'e':
case 'E':
return 14;
default:
return 15;
}
}
bool SDLPP::init() {
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError()
<< std::endl;
return false;
}
if ( IMG_Init( IMG_INIT_PNG ) != IMG_INIT_PNG ) {
std::cerr << "SDL_image could not initialize! SDL_image Error: "
<< IMG_GetError() << std::endl;
return false;
}
if ( TTF_Init() == -1 ) {
std::cerr << "SDL_ttf could not initialize! SDL_ttf Error: "
<< TTF_GetError() << std::endl;
return false;
}
return true;
}
bool SDLPP::init( uint32_t SDL_OPTIONS ) {
if ( SDL_Init( SDL_OPTIONS ) < 0 ) {
std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError()
<< std::endl;
return false;
}
if ( IMG_Init( IMG_INIT_PNG ) != IMG_INIT_PNG ) {
std::cerr << "SDL_image could not initialize! SDL_image Error: "
<< IMG_GetError() << std::endl;
return false;
}
return true;
}
bool SDLPP::init( uint32_t SDL_OPTIONS, int IMAGE_OPTIONS ) {
if ( SDL_Init( SDL_OPTIONS ) < 0 ) {
std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError()
<< std::endl;
return false;
}
if ( IMG_Init( IMAGE_OPTIONS ) != IMAGE_OPTIONS ) {
std::cerr << "SDL_image could not initialize! SDL_image Error: "
<< IMG_GetError() << std::endl;
return false;
}
return true;
}
std::tuple< int, int, int, int >
SDLPP::getColorsHEX( const std::string &color ) {
int red = 0, green = 0, blue = 0, alpha = 255;
const char *color_ptr = color.c_str();
if ( color_ptr[0] == '#' )
color_ptr++;
red = hex2num( color_ptr[0] ) * 16 + hex2num( color_ptr[1] );
green = hex2num( color_ptr[2] ) * 16 + hex2num( color_ptr[3] );
blue = hex2num( color_ptr[4] ) * 16 + hex2num( color_ptr[5] );
if ( color_ptr[6] != '\0' )
alpha = hex2num( color_ptr[6] ) * 16 + hex2num( color_ptr[7] );
return { red, green, blue, alpha };
}
SDL_Color
SDLPP::getSDLColorTuple( const std::tuple< int, int, int, int > &tuple ) {
SDL_Color ret_color{};
ret_color.r = std::get< 0 >( tuple );
ret_color.g = std::get< 1 >( tuple );
ret_color.b = std::get< 2 >( tuple );
ret_color.a = std::get< 3 >( tuple );
return ret_color;
}
SDL_Color SDLPP::getSDLColorHEX( const std::string &color ) {
auto color_tuple = SDLPP::getColorsHEX( color );
return getSDLColorTuple( color_tuple );
}
std::tuple< int, int, int, int >
SDLPP::getColorsSDLColor( const SDL_Color &color ) {
return { color.r, color.g, color.b, color.a };
}
bool SDLPP::getSDLEvent( SDL_Event &e ) {
if ( SDL_PeepEvents( &e, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT,
SDL_LASTEVENT ) == 1 ) {
SDL_PeepEvents( &e, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT );
return true;
}
return false;
}

38
sdlpp/sdlpp_common.hpp Normal file
View File

@ -0,0 +1,38 @@
#ifndef SDLPP_HPP_COMMON
#define SDLPP_HPP_COMMON
#ifdef _WIN32
#include "SDL2/SDL.h"
#include "SDL2/SDL_image.h"
#include "SDL2/SDL_ttf.h"
#else
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#endif // UNIX
#include <cstdint>
#include <string>
#include <tuple>
#define SDLPP_TEXT_LEFT 0x0001
#define SDLPP_TEXT_RIGHT 0x0002
#define SDLPP_TEXT_CENTER 0x0004
#define SDLPP_TEXT_TOP 0x0008
#define SDLPP_TEXT_BOTTOM 0x0010
namespace SDLPP {
int hex2num( char c );
bool init();
bool init( uint32_t SDL_OPTIONS );
bool init( uint32_t SDL_OPTIONS, int IMAGE_OPTIONS );
std::tuple< int, int, int, int > getColorsHEX( const std::string &color );
SDL_Color getSDLColorHEX( const std::string &color );
std::tuple< int, int, int, int > getColorsSDLColor( const SDL_Color &color );
SDL_Color getSDLColorTuple( const std::tuple< int, int, int, int > &tuple );
bool getSDLEvent( SDL_Event &e );
} // end of namespace SDLPP
#endif

33
sdlpp/sdlpp_font.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "sdlpp_font.hpp"
namespace SDLPP {
Font::Font( const std::string &font, int size ) {
font_ptr = TTF_OpenFont( font.c_str(), size );
if ( font_ptr == NULL ) {
std::cerr << "Unable to load font '" << font
<< "': TTF Error: " << TTF_GetError() << std::endl;
throw "TTF_OpenFont error";
}
}
Font::~Font() {
TTF_CloseFont( font_ptr );
}
const TTF_Font *Font::getFont() const {
return font_ptr;
}
TTF_Font *Font::getFont() {
return font_ptr;
}
void Font::setOutline( int size ) {
TTF_SetFontOutline( font_ptr, size );
}
int Font::getOutline() {
return TTF_GetFontOutline( font_ptr );
}
void Font::setStyle( int style ) {
TTF_SetFontStyle( font_ptr, style );
}
void Font::setHinting( int hinting ) {
TTF_SetFontHinting( font_ptr, hinting );
}
} // namespace SDLPP

25
sdlpp/sdlpp_font.hpp Normal file
View File

@ -0,0 +1,25 @@
#ifndef SDLPP_HPP_FONT
#define SDLPP_HPP_FONT
#include "sdlpp_common.hpp"
#include <iostream>
namespace SDLPP {
class Font {
public:
Font() = delete;
Font( const std::string &font, int size );
virtual ~Font();
const TTF_Font *getFont() const;
TTF_Font *getFont();
void setOutline( int size );
int getOutline();
void setStyle( int style );
void setHinting( int hinting );
private:
TTF_Font *font_ptr;
};
} // namespace SDLPP
#endif

View File

@ -0,0 +1,149 @@
#include "sdlpp_linerenderer.hpp"
namespace SDLPP {
LineRenderer::LineRenderer( double x1, double y1, double x2, double y2,
const std::shared_ptr< Renderer > &r )
: RenderObject( r ) {
og_x1 = x1_ = x1;
og_y1 = y1_ = y1;
og_x2 = x2_ = x2;
og_y2 = y2_ = y2;
updateSizeAndPosition();
}
LineRenderer::LineRenderer( double x1, double y1, double x2, double y2,
const std::shared_ptr< Renderer > &r,
const std::string &color )
: LineRenderer( x1, y1, x2, y2, r ) {
setColor( color );
}
void LineRenderer::setColor( const std::string &color ) {
_color = getColorsHEX( color );
}
void LineRenderer::render() {
if ( !getHidden() ) {
SDL_SetRenderDrawColor(
renderer->getRendererPtr(), std::get< 0 >( _color ),
std::get< 1 >( _color ), std::get< 2 >( _color ),
std::get< 3 >( _color ) );
SDL_RenderDrawLine( renderer->getRendererPtr(), pixel_x1, pixel_y1,
pixel_x2, pixel_y2 );
}
if ( hasCollisions() && renderer->getRenderColiders() && !getHidden() ) {
for ( const auto &col : getCollisions() )
col->render( *renderer, colider_color );
}
}
void LineRenderer::move( int ticks ) {
if ( permanent )
return;
auto addx =
static_cast< double >( movementSpeed * movementDirection.first ) *
( static_cast< double >( ticks ) / 1000 );
auto addy =
static_cast< double >( movementSpeed * movementDirection.second ) *
( static_cast< double >( ticks ) / 1000 );
if ( std::isnan( addx ) || std::isnan( addy ) )
return;
og_x1 += addx;
og_x2 += addx;
og_y1 += addy;
og_y2 += addy;
custom_move( ticks );
updateSizeAndPosition();
}
void LineRenderer::setPos( double x, double y ) {
auto diffx = og_x2 - og_x1;
auto diffy = og_y2 - og_y1;
og_x1 = x;
og_y1 = y;
og_x2 = og_x1 + diffx;
og_y2 = og_y1 + diffy;
updateSizeAndPosition();
}
void LineRenderer::setPos( const std::pair< double, double > &pos ) {
setPos( pos.first, pos.second );
}
std::pair< double, double > LineRenderer::getPos() const {
return { og_x1, og_y1 };
}
int LineRenderer::leftmost() {
return pixel_x1 < pixel_x2 ? pixel_x1 : pixel_x2;
}
int LineRenderer::topmost() {
return pixel_y1 < pixel_y2 ? pixel_y1 : pixel_y2;
}
int LineRenderer::rightmost() {
return pixel_x1 > pixel_x2 ? pixel_x1 : pixel_x2;
}
int LineRenderer::bottommost() {
return pixel_y1 > pixel_y2 ? pixel_y1 : pixel_y2;
}
int LineRenderer::collisionPushX() {
return leftmost();
}
int LineRenderer::collisionPushY() {
return topmost();
}
int LineRenderer::collisionWidth() {
return rightmost() - leftmost();
}
int LineRenderer::collisionHeight() {
return bottommost() - topmost();
}
void LineRenderer::updateSizeAndPosition() {
updateXY();
auto dimension = renderer->getSmallerSide();
pixel_x1 = std::round( x1_ * dimension );
pixel_x2 = std::round( x2_ * dimension );
pixel_y1 = std::round( y1_ * dimension );
pixel_y2 = std::round( y2_ * dimension );
for ( auto &x : collisions ) {
x->updateCollision( collisionPushX(), collisionPushY(),
collisionWidth(), collisionHeight() );
}
}
void LineRenderer::centerX() {
centerx = true;
updateSizeAndPosition();
}
std::shared_ptr< RenderObject > LineRenderer::copySelf() {
// TODO ACTUALLY copy, don't just copy pointers to textures and whatnot,
// create new textures!!!
return std::make_shared< LineRenderer >( *this );
}
SDL_Rect LineRenderer::getRect() {
return { leftmost(), topmost(), rightmost() - leftmost(),
bottommost() - topmost() };
}
std::pair< std::pair< double, double >, std::pair< double, double > >
LineRenderer::getDoubleRect() const {
return { { og_x1, og_y1 }, { og_x2 - og_x1, og_y2 - og_y1 } };
}
void LineRenderer::updateXY() {
if ( !centerx ) {
x1_ = og_x1;
y1_ = og_y1;
x2_ = og_x2;
y2_ = og_y2;
return;
}
auto width = renderer->getWidth();
auto height = renderer->getHeight();
if ( width > height ) {
auto multiplier =
static_cast< double >( width ) / static_cast< double >( height );
x1_ = og_x1 + static_cast< double >( multiplier - 1 ) / 2;
x2_ = og_x2 + static_cast< double >( multiplier - 1 ) / 2;
} else {
x1_ = og_x1;
x2_ = og_x2;
}
y1_ = og_y1;
y2_ = og_y2;
}
} // namespace SDLPP

View File

@ -0,0 +1,61 @@
#ifndef SDLPP_HPP_LINE_RENDERER
#define SDLPP_HPP_LINE_RENDERER
#include "sdlpp_common.hpp"
#include "sdlpp_renderobject.hpp"
namespace SDLPP {
class LineRenderer : public RenderObject {
public:
LineRenderer() = delete;
virtual ~LineRenderer(){};
LineRenderer( double x1, double y1, double x2, double y2,
const std::shared_ptr< Renderer > &r );
LineRenderer( double x1, double y1, double x2, double y2,
const std::shared_ptr< Renderer > &r,
const std::string &color );
virtual void setColor( const std::string &color ) override;
virtual void specialAction( int /*UNUSED*/ ) override{};
virtual void render() override;
virtual void move( int ticks ) override;
virtual void custom_move( int /*UNUSED*/ ) override {}
virtual void setPos( double x, double y ) override;
virtual void setPos( const std::pair< double, double > &pos ) override;
virtual std::pair< double, double > getPos() const override;
virtual int leftmost() override;
virtual int topmost() override;
virtual int rightmost() override;
virtual int bottommost() override;
virtual int collisionPushX() override;
virtual int collisionPushY() override;
virtual int collisionWidth() override;
virtual int collisionHeight() override;
virtual void updateSizeAndPosition() override;
virtual void centerX() override;
virtual std::shared_ptr< RenderObject > copySelf() override;
virtual SDL_Rect getRect() override;
virtual std::pair< std::pair< double, double >,
std::pair< double, double > >
getDoubleRect() const override;
void setOutlineColor( const std::string & /*UNUSED*/ ) override {}
protected:
void updateXY();
double og_x1;
double og_y1;
double x1_;
double y1_;
double og_x2;
double og_y2;
double x2_;
double y2_;
int pixel_x1{};
int pixel_y1{};
int pixel_x2{};
int pixel_y2{};
bool centerx = false;
std::tuple< int, int, int, int > _color;
};
} // end of namespace SDLPP
#endif

View File

@ -0,0 +1,91 @@
#include "sdlpp_rectcolider.hpp"
namespace SDLPP {
RectColider::RectColider( double x, double y, double w, double h )
: CollisionPolygon( x, y ) {
w_ = w;
h_ = h;
}
bool RectColider::colidesWith( const SDLPP::CollisionPolygon &other ) const {
if ( other.isCircle() ) {
return other.colidesWith( *this );
}
if ( other.isInfinite() ) {
return infinityIntersection( other, *this );
}
if ( isInfinite() )
return infinityIntersection( *this, other );
return intersects( *this, other );
}
bool RectColider::isCircle() const {
return false;
}
int RectColider::topmost() const {
return ( !isInfinite() || original_y != -1 ) * getY() + isInfinite() * -1;
}
int RectColider::bottommost() const {
return ( !isInfinite() || h_ != -1 ) * ( getY() + pixel_h ) +
isInfinite() * -1;
}
int RectColider::leftmost() const {
return ( !isInfinite() || original_x != -1 ) * getX() + isInfinite() * -1;
}
int RectColider::rightmost() const {
return ( !isInfinite() || w_ != -1 ) * ( getX() + pixel_w ) +
isInfinite() * -1;
}
void RectColider::updateCollision( int x, int y, int w, int h ) {
position_x = original_x * w + x;
position_y = original_y * h + y;
pixel_w = w_ * w;
pixel_h = h_ * h;
}
void RectColider::render( Renderer &renderer,
const std::tuple< int, int, int, int > &color ) {
auto rect = getRect();
// outline with desired color at 50% opacity
SDL_SetRenderDrawColor( renderer.getRendererPtr(), std::get< 0 >( color ),
std::get< 1 >( color ), std::get< 2 >( color ),
0x80 );
SDL_RenderDrawRect( renderer.getRendererPtr(), &rect );
// fill with desired color at 25% opacity
SDL_SetRenderDrawColor( renderer.getRendererPtr(), std::get< 0 >( color ),
std::get< 1 >( color ), std::get< 2 >( color ),
0x40 );
SDL_RenderFillRect( renderer.getRendererPtr(), &rect );
}
void RectColider::render( Renderer &renderer ) {
auto rect = getRect();
SDL_SetRenderDrawColor( renderer.getRendererPtr(), sdl_color.r, sdl_color.g,
sdl_color.b, sdl_color.a );
SDL_RenderFillRect( renderer.getRendererPtr(), &rect );
SDL_SetRenderDrawColor( renderer.getRendererPtr(), sdl_outline.r,
sdl_outline.g, sdl_outline.b, sdl_outline.a );
SDL_RenderDrawRect( renderer.getRendererPtr(), &rect );
}
SDL_Rect RectColider::getRect() {
if ( !isInfinite() )
return { leftmost(), topmost(), pixel_w, pixel_h };
SDL_Rect r = { 0, 0, 0, 0 };
if ( ( r.x = leftmost() ) == -1 )
r.x = 0;
if ( ( r.y = topmost() ) == -1 )
r.y = 0;
if ( rightmost() == -1 )
r.w = std::numeric_limits< int >::max();
else
r.w = pixel_w;
if ( bottommost() == -1 )
r.h = std::numeric_limits< int >::max();
else
r.h = pixel_h;
return r;
}
} // namespace SDLPP

View File

@ -0,0 +1,35 @@
#ifndef SDLPP_HPP_RECT_COLIDER
#define SDLPP_HPP_RECT_COLIDER
#include "sdlpp_common.hpp"
#include "sdlpp_collision.hpp"
#include <limits>
namespace SDLPP {
class RectColider : public CollisionPolygon {
public:
RectColider( double x, double y, double w, double h );
virtual ~RectColider() {}
virtual bool colidesWith( const CollisionPolygon &other ) const override;
virtual bool isCircle() const override;
virtual int topmost() const override;
virtual int bottommost() const override;
virtual int leftmost() const override;
virtual int rightmost() const override;
virtual void updateCollision( int x, int y, int w, int h ) override;
virtual void
render( Renderer &renderer,
const std::tuple< int, int, int, int > &color ) override;
virtual void render( Renderer &renderer ) override;
private:
SDL_Rect getRect();
double w_;
double h_;
int pixel_w;
int pixel_h;
};
} // end of namespace SDLPP
#endif

View File

@ -0,0 +1,166 @@
#include "sdlpp_rectrenderer.hpp"
namespace SDLPP {
RectangleRender::RectangleRender( double x, double y, double w, double h,
const std::shared_ptr< Renderer > &r )
: RenderObject( r ) {
og_x = x_ = x;
og_y = y_ = y;
og_w = w_ = w;
og_h = h_ = h;
updateSizeAndPosition();
}
RectangleRender::RectangleRender( double x, double y, double w, double h,
const std::shared_ptr< Renderer > &r,
const std::shared_ptr< Texture > &t )
: RectangleRender( x, y, w, h, r ) {
setTexture( t );
}
RectangleRender::RectangleRender( double x, double y, double w, double h,
const std::shared_ptr< Renderer > &r,
const std::string &img_or_color,
bool is_polygon )
: RectangleRender( x, y, w, h, r ) {
if ( !is_polygon ) {
setTexture( img_or_color );
} else {
setColor( img_or_color );
color = img_or_color;
}
}
void RectangleRender::setColor( const std::string &color ) {
if ( !polygon ) {
polygon = std::make_shared< RectColider >( 0, 0, 1, 1 );
polygon->updateCollision( collisionPushX(), collisionPushY(),
collisionWidth(), collisionHeight() );
}
polygon->setColor( color );
}
void RectangleRender::setOutlineColor( const std::string &color ) {
if ( !polygon ) {
polygon = std::make_shared< RectColider >( 0, 0, 1, 1 );
polygon->updateCollision( collisionPushX(), collisionPushY(),
collisionWidth(), collisionHeight() );
}
polygon->setOutlineColor( color );
}
void RectangleRender::render() {
if ( !getHidden() ) {
if ( polygon )
polygon->render( *renderer );
if ( texture != NULL )
SDL_RenderCopy( renderer->getRendererPtr(),
texture->getTexturePtr(), NULL, &rect );
}
if ( hasCollisions() && renderer->getRenderColiders() && !getHidden() ) {
for ( const auto &col : getCollisions() )
col->render( *renderer, colider_color );
}
}
void RectangleRender::move( int ticks ) {
if ( permanent )
return;
auto addx =
static_cast< double >( movementSpeed * movementDirection.first ) *
( static_cast< double >( ticks ) / 1000 );
auto addy =
static_cast< double >( movementSpeed * movementDirection.second ) *
( static_cast< double >( ticks ) / 1000 );
if ( std::isnan( addx ) || std::isnan( addy ) )
return;
og_x += addx;
og_y += addy;
custom_move( ticks );
updateSizeAndPosition();
}
std::pair< std::pair< double, double >, std::pair< double, double > >
RectangleRender::getDoubleRect() const {
return { { og_x, og_y }, { og_w, og_h } };
}
void RectangleRender::setPos( double x, double y ) {
og_x = x;
og_y = y;
updateSizeAndPosition();
}
void RectangleRender::setPos( const std::pair< double, double > &pos ) {
setPos( pos.first, pos.second );
}
std::pair< double, double > RectangleRender::getPos() const {
return { og_x, og_y };
}
int RectangleRender::leftmost() {
return rect.x;
}
int RectangleRender::topmost() {
return rect.y;
}
int RectangleRender::rightmost() {
return rect.x + rect.w;
}
int RectangleRender::bottommost() {
return rect.y + rect.h;
}
int RectangleRender::collisionPushX() {
return rect.x;
}
int RectangleRender::collisionPushY() {
return rect.y;
}
int RectangleRender::collisionWidth() {
return rect.w;
}
int RectangleRender::collisionHeight() {
return rect.h;
}
void RectangleRender::updateSizeAndPosition() {
updateXY();
auto dimension = renderer->getSmallerSide();
rect.x = std::round( x_ * dimension );
rect.y = std::round( y_ * dimension );
rect.w = std::round( ( x_ + w_ ) * dimension ) - rect.x;
rect.h = std::round( ( y_ + h_ ) * dimension ) - rect.y;
if ( polygon )
polygon->updateCollision( collisionPushX(), collisionPushY(),
collisionWidth(), collisionHeight() );
for ( auto &x : collisions ) {
x->updateCollision( collisionPushX(), collisionPushY(),
collisionWidth(), collisionHeight() );
}
}
SDL_Rect RectangleRender::getRect() {
return rect;
}
void RectangleRender::centerX() {
centerx = true;
updateSizeAndPosition();
}
std::shared_ptr< RenderObject > RectangleRender::copySelf() {
// TODO ACTUALLY copy, don't just copy pointers to textures and whatnot,
// create new textures!!!
return std::make_shared< RectangleRender >( *this );
}
std::string RectangleRender::getColor() const {
return color;
}
void RectangleRender::updateXY() {
if ( !centerx ) {
x_ = og_x;
y_ = og_y;
return;
}
auto width = renderer->getWidth();
auto height = renderer->getHeight();
if ( width > height ) {
auto multiplier =
static_cast< double >( width ) / static_cast< double >( height );
x_ = og_x + static_cast< double >( multiplier - 1 ) / 2;
} else {
x_ = og_x;
}
y_ = og_y;
}
} // namespace SDLPP

View File

@ -0,0 +1,62 @@
#ifndef SDLPP_HPP_RECT_RENDERER
#define SDLPP_HPP_RECT_RENDERER
#include "sdlpp_common.hpp"
#include "sdlpp_renderobject.hpp"
#include "sdlpp_rectcolider.hpp"
namespace SDLPP {
class RectangleRender : public RenderObject {
public:
RectangleRender() = delete;
virtual ~RectangleRender(){};
RectangleRender( double x, double y, double w, double h,
const std::shared_ptr< Renderer > &r );
RectangleRender( double x, double y, double w, double h,
const std::shared_ptr< Renderer > &r,
const std::shared_ptr< Texture > &t );
RectangleRender( double x, double y, double w, double h,
const std::shared_ptr< Renderer > &r,
const std::string &img_or_color, bool is_polygon = false );
virtual void setColor( const std::string &color ) override;
virtual void setOutlineColor( const std::string &color ) override;
virtual void specialAction( int /*UNUSED*/ ) override{};
virtual void render() override;
virtual void move( int ticks ) override;
virtual void custom_move( int /*UNUSED*/ ) override {}
virtual std::pair< std::pair< double, double >,
std::pair< double, double > >
getDoubleRect() const override;
virtual void setPos( double x, double y ) override;
virtual void setPos( const std::pair< double, double > &pos ) override;
virtual std::pair< double, double > getPos() const override;
virtual int leftmost() override;
virtual int topmost() override;
virtual int rightmost() override;
virtual int bottommost() override;
virtual int collisionPushX() override;
virtual int collisionPushY() override;
virtual int collisionWidth() override;
virtual int collisionHeight() override;
virtual void updateSizeAndPosition() override;
virtual SDL_Rect getRect() override;
virtual void centerX() override;
virtual std::shared_ptr< RenderObject > copySelf() override;
std::string getColor() const;
protected:
void updateXY();
double og_x;
double og_y;
double og_w;
double og_h;
double x_;
double y_;
double w_;
double h_;
bool centerx = false;
SDL_Rect rect;
std::string color = "";
};
} // end of namespace SDLPP
#endif

56
sdlpp/sdlpp_renderer.cpp Normal file
View File

@ -0,0 +1,56 @@
#include "sdlpp_renderer.hpp"
namespace SDLPP {
Renderer::Renderer( Window &window ) {
renderer = SDL_CreateRenderer( window.getWindowPtr(), -1,
SDL_RENDERER_ACCELERATED );
if ( renderer == NULL ) {
std::cerr << "SDL could not create a renderer! SDL_Error: "
<< SDL_GetError();
throw "Couldn't create renderer";
}
SDL_SetRenderDrawColor( renderer, 0xFF, 0xFF, 0xFF, 0xFF );
}
Renderer::~Renderer() {
SDL_DestroyRenderer( renderer );
}
SDL_Renderer *Renderer::getRendererPtr() {
return renderer;
}
std::pair< int, int > Renderer::getDimensions() const {
int width = 0, height = 0;
SDL_GetRendererOutputSize( renderer, &width, &height );
return { width, height };
}
int Renderer::getWidth() const {
return getDimensions().first;
}
int Renderer::getHeight() const {
return getDimensions().second;
}
int Renderer::getSmallerSide() const {
auto dimensions = getDimensions();
return dimensions.first < dimensions.second ? dimensions.first
: dimensions.second;
}
int Renderer::getLargerSide() const {
auto dimensions = getDimensions();
return dimensions.first > dimensions.second ? dimensions.first
: dimensions.second;
}
void Renderer::setBlendMode( SDL_BlendMode blendMode ) {
SDL_SetRenderDrawBlendMode( renderer, blendMode );
}
void Renderer::setRenderColiders( bool render ) {
render_coliders = render;
}
bool Renderer::getRenderColiders() {
return render_coliders;
}
void Renderer::clearRenderer() {
SDL_RenderClear( getRendererPtr() );
}
void Renderer::presentRenderer() {
SDL_RenderPresent( getRendererPtr() );
}
} // namespace SDLPP

32
sdlpp/sdlpp_renderer.hpp Normal file
View File

@ -0,0 +1,32 @@
#ifndef SDLPP_HPP_RENDERER
#define SDLPP_HPP_RENDERER
#include "sdlpp_common.hpp"
#include "sdlpp_window.hpp"
#include <iostream>
namespace SDLPP {
class Renderer {
public:
Renderer() = delete;
Renderer( Window &window );
virtual ~Renderer();
SDL_Renderer *getRendererPtr();
std::pair< int, int > getDimensions() const;
int getWidth() const;
int getHeight() const;
int getSmallerSide() const;
int getLargerSide() const;
void setBlendMode( SDL_BlendMode blendMode );
void setRenderColiders( bool render );
bool getRenderColiders();
void clearRenderer();
void presentRenderer();
private:
SDL_Renderer *renderer = NULL;
bool render_coliders = false;
};
} // end of namespace SDLPP
#endif

View File

@ -0,0 +1,107 @@
#include "sdlpp_renderobject.hpp"
namespace SDLPP {
bool RenderObject::colidesWith( const RenderObject &other ) const {
if ( !hasCollisions() || !other.hasCollisions() || getHidden() ||
other.getHidden() ) {
return false;
}
for ( const auto &x : collisions ) {
for ( const auto &y : other.getCollisions() ) {
if ( x->colidesWith( *y ) )
return true;
}
}
return false;
}
bool RenderObject::hasCollisions() const {
return !collisions.empty();
}
const std::vector< std::shared_ptr< CollisionPolygon > > &
RenderObject::getCollisions() const {
return collisions;
}
void RenderObject::setTexture( const std::shared_ptr< Texture > &t ) {
texture = t;
}
void RenderObject::setTexture( const std::string &img_path ) {
texture = std::make_shared< Texture >( renderer, img_path );
}
void RenderObject::setTexture( Font &font, const std::string &text,
const std::string &color,
const std::string &outline_color,
int outline_size ) {
texture = std::make_shared< Texture >( renderer, font, text, color,
outline_color, outline_size );
}
void RenderObject::unsetTexture() {
texture.reset();
}
void RenderObject::unsetColor() {
polygon.reset();
}
// per second, relative to window width
void RenderObject::setMovementSpeed( double speed ) {
movementSpeed = speed;
}
void RenderObject::addMovement( int x, int y ) {
movementDirection.first += x;
movementDirection.second += y;
}
void RenderObject::resetMovementX() {
movementDirection.first = 0;
}
void RenderObject::resetMovementY() {
movementDirection.second = 0;
}
void RenderObject::clearColided() {
colidedWith.clear();
}
void RenderObject::addColided( std::shared_ptr< RenderObject > &obj ) {
colidedWith.push_back( obj );
}
std::vector< std::shared_ptr< RenderObject > > &RenderObject::getColidedWith() {
return colidedWith;
}
void RenderObject::setId( uint64_t input_id ) {
id = input_id;
}
uint64_t RenderObject::getId() {
return id;
}
void RenderObject::setHidden( bool hid ) {
hidden = hid;
}
bool RenderObject::getHidden() const {
return hidden;
}
void RenderObject::destroy() {
setHidden( true );
kill = true;
}
bool RenderObject::getKilled() {
return kill;
}
void RenderObject::setColiderColor( const std::string &color ) {
colider_color = getColorsHEX( color );
}
void RenderObject::setPermanent( bool perm ) {
permanent = perm;
setStatic( perm );
}
bool RenderObject::getPermanent() const {
return permanent;
}
bool RenderObject::isStatic() {
return is_static;
}
void RenderObject::setStatic( bool stat ) {
is_static = stat;
}
std::shared_ptr< Renderer > RenderObject::getRenderer() const {
return renderer;
}
void RenderObject::setSceneID( int id ) {
scene_id = id;
}
} // namespace SDLPP

View File

@ -0,0 +1,104 @@
#ifndef SDLPP_HPP_RENDER_OBJECT
#define SDLPP_HPP_RENDER_OBJECT
#include "sdlpp_common.hpp"
#include "sdlpp_collision.hpp"
#include "sdlpp_renderer.hpp"
#include "sdlpp_texture.hpp"
#include <memory>
#include <vector>
namespace SDLPP {
class Scene;
class RenderObject {
public:
RenderObject( const std::shared_ptr< Renderer > &r ) : renderer( r ) {}
virtual ~RenderObject() {}
virtual void render() = 0;
virtual int leftmost() = 0;
virtual int topmost() = 0;
virtual int rightmost() = 0;
virtual int bottommost() = 0;
virtual int collisionPushX() = 0;
virtual int collisionPushY() = 0;
virtual int collisionWidth() = 0;
virtual int collisionHeight() = 0;
virtual void specialAction( int code ) = 0;
virtual std::pair< std::pair< double, double >,
std::pair< double, double > >
getDoubleRect() const = 0;
virtual void setPos( double x, double y ) = 0;
virtual void setPos( const std::pair< double, double > &pos ) = 0;
virtual std::pair< double, double > getPos() const = 0;
bool colidesWith( const RenderObject &other ) const;
template < class T > void addCollision( const T &p ) {
collisions.push_back( std::make_shared< T >( p ) );
collisions.back()->updateCollision( collisionPushX(), collisionPushY(),
collisionWidth(),
collisionHeight() );
}
bool hasCollisions() const;
const std::vector< std::shared_ptr< CollisionPolygon > > &
getCollisions() const;
virtual void setTexture( const std::shared_ptr< Texture > &t );
virtual void setTexture( const std::string &img_path );
virtual void setTexture( Font &font, const std::string &text,
const std::string &color = "FFFFFF",
const std::string &outline_color = "000000",
int outline_size = -1 );
virtual void setColor( const std::string &color ) = 0;
virtual void setOutlineColor( const std::string &color ) = 0;
virtual void unsetTexture();
virtual void unsetColor();
// per second, relative to window width
void setMovementSpeed( double speed );
void addMovement( int x, int y );
void resetMovementX();
void resetMovementY();
void clearColided();
void addColided( std::shared_ptr< RenderObject > &obj );
std::vector< std::shared_ptr< RenderObject > > &getColidedWith();
void setId( uint64_t input_id );
uint64_t getId();
void setHidden( bool hid );
bool getHidden() const;
void destroy();
bool getKilled();
void setColiderColor( const std::string &color );
virtual void move( int ticks ) = 0;
virtual void custom_move( int ticks ) = 0;
virtual void updateSizeAndPosition() = 0;
virtual SDL_Rect getRect() = 0;
void setPermanent( bool perm = true );
bool getPermanent() const;
virtual void centerX() = 0;
virtual std::shared_ptr< RenderObject > copySelf() = 0;
bool isStatic();
void setStatic( bool stat = true );
std::shared_ptr< Renderer > getRenderer() const;
protected:
std::vector< std::shared_ptr< CollisionPolygon > > collisions;
std::shared_ptr< Texture > texture;
std::shared_ptr< Renderer > renderer;
std::shared_ptr< CollisionPolygon > polygon;
double movementSpeed = 0;
std::pair< int, int > movementDirection = { 0, 0 };
std::vector< std::shared_ptr< RenderObject > > colidedWith;
uint64_t id = -1;
bool hidden = false;
bool kill = false;
std::tuple< int, int, int, int > colider_color = { 0x00, 0xFF, 0xFF, 0xFF };
uint64_t scene_id = -1;
bool permanent = false;
bool is_static = true;
private:
void setSceneID( int id );
friend Scene;
};
} // end of namespace SDLPP
#endif

235
sdlpp/sdlpp_scene.cpp Normal file
View File

@ -0,0 +1,235 @@
#include "sdlpp_scene.hpp"
namespace SDLPP {
Scene::Scene( std::shared_ptr< Renderer > &r ) : renderer( r ) {
SDL_SetRenderDrawColor( renderer->getRendererPtr(), 0xFF, 0xFF, 0xFF,
0xFF );
prev_ticks = SDL_GetTicks();
}
void Scene::addObject( const std::shared_ptr< RenderObject > &obj ) {
std::lock_guard< std::mutex > lock( render_mutex );
render_objects.push_back( obj );
obj->setSceneID( ++max_object_id );
if ( obj->hasCollisions() ) {
collision_objects.push_back( obj );
}
if ( render_objects.size() == 1 ) {
leftmost_obj = obj;
rightmost_obj = obj;
} else {
auto rect = obj->getDoubleRect();
auto leftmost_rect = leftmost_obj->getDoubleRect();
if ( rect.first.first < leftmost_rect.first.first )
leftmost_obj = obj;
auto rightmost_rect = rightmost_obj->getDoubleRect();
if ( rect.first.first + rect.second.first >
rightmost_rect.first.first + rightmost_rect.second.first )
rightmost_obj = obj;
}
}
void Scene::setZIndex( const std::shared_ptr< RenderObject > &obj, int index ) {
std::lock_guard< std::mutex > guard( render_mutex );
int original_index = 0;
for ( long unsigned int i = 0; i < render_objects.size(); i++ ) {
if ( render_objects[i] == obj ) {
original_index = i;
}
}
if ( original_index == index )
return;
if ( original_index > index )
original_index++;
render_objects.insert( render_objects.begin() + index, obj );
render_objects.erase( render_objects.begin() + original_index );
}
void Scene::moveDownZ( const std::shared_ptr< RenderObject > &obj ) {
moveZ( obj, -1 );
}
void Scene::moveUpZ( const std::shared_ptr< RenderObject > &obj ) {
moveZ( obj, 1 );
}
void Scene::moveZ( const std::shared_ptr< RenderObject > &obj, int addition ) {
int original_index = 0;
for ( long unsigned int i = 0; i < render_objects.size(); i++ ) {
if ( render_objects[i] == obj ) {
original_index = i;
}
}
std::iter_swap( render_objects.begin() + original_index,
render_objects.begin() + original_index + addition );
}
// TODO addCollision
std::shared_ptr< RenderObject > Scene::getObject( int index ) {
return render_objects[index];
}
std::vector< std::shared_ptr< RenderObject > > Scene::getObjects() {
return render_objects;
}
std::vector< std::shared_ptr< RenderObject > >
Scene::getObjects( const std::unordered_set< int > &objectIDs ) {
std::vector< std::shared_ptr< RenderObject > > ret{};
for ( const auto &x : render_objects ) {
// check if object exists because of possible race condition
if ( x && objectIDs.find( x->getId() ) != objectIDs.end() ) {
ret.push_back( x );
}
}
return ret;
}
void Scene::movement() {
checkKilled();
std::lock_guard< std::mutex > lock( render_mutex );
int now_ticks = SDL_GetTicks();
for ( const auto &x : render_objects ) {
x->move( now_ticks - prev_ticks );
}
prev_ticks = now_ticks;
}
std::vector< std::shared_ptr< RenderObject > >
Scene::getCollisions( RenderObject &r ) {
if ( r.getHidden() )
return {};
std::vector< std::shared_ptr< RenderObject > > ret{};
for ( const auto &x : collision_objects ) {
if ( x->colidesWith( r ) ) {
ret.push_back( x );
}
}
return ret;
}
std::vector< std::shared_ptr< RenderObject > >
Scene::getCollisions( RenderObject &r,
const std::unordered_set< int > &objectIDs ) {
if ( r.getHidden() )
return {};
std::vector< std::shared_ptr< RenderObject > > ret{};
for ( const auto &x : collision_objects ) {
if ( objectIDs.find( x->getId() ) != objectIDs.end() &&
x->colidesWith( r ) ) {
ret.push_back( x );
}
}
return ret;
}
void Scene::renderScene( bool clear_renderer ) {
checkKilled();
std::lock_guard< std::mutex > lock( render_mutex );
if ( clear_renderer )
SDL_RenderClear( renderer->getRendererPtr() );
if ( background && background->getTexturePtr() )
SDL_RenderCopy( renderer->getRendererPtr(), background->getTexturePtr(),
NULL, NULL );
for ( const auto &x : render_objects ) {
x->render();
}
}
void Scene::presentScene() {
SDL_RenderPresent( renderer->getRendererPtr() );
}
void Scene::setBackground( std::shared_ptr< Texture > bg ) {
background = bg;
}
void Scene::setBackground( const std::string &img_path ) {
background = std::make_shared< Texture >( renderer, img_path );
}
void Scene::updateSizeAndPosition() {
checkKilled();
std::lock_guard< std::mutex > lock( render_mutex );
for ( auto &x : render_objects ) {
x->updateSizeAndPosition();
for ( auto &col : x->getCollisions() ) {
col->updateCollision( x->collisionPushX(), x->collisionPushY(),
x->collisionWidth(), x->collisionHeight() );
}
}
}
void Scene::moveEverything( double x, double y ) {
checkKilled();
std::lock_guard< std::mutex > lock( render_mutex );
for ( auto &obj : render_objects ) {
if ( obj->getPermanent() )
continue;
auto curPos = obj->getDoubleRect();
obj->setPos( curPos.first.first + x, curPos.first.second + y );
}
}
const std::shared_ptr< RenderObject > &Scene::leftmost() {
return leftmost_obj;
}
const std::shared_ptr< RenderObject > &Scene::rightmost() {
return rightmost_obj;
}
std::pair< int, int > Scene::getDimensions() const {
return renderer->getDimensions();
}
int Scene::getWidth() const {
return renderer->getWidth();
}
int Scene::getHeight() const {
return renderer->getHeight();
}
Renderer &Scene::getRenderer() {
return *renderer;
}
std::shared_ptr< Renderer > Scene::getRendererShared() {
return renderer;
}
void Scene::setPrevTicks( int ticks ) {
prev_ticks = ticks;
}
void Scene::saveScene() {
saved_render_objects.clear();
saved_collision_objects.clear();
for ( auto &obj : render_objects ) {
if ( !obj->isStatic() )
saved_render_objects.push_back( obj->copySelf() );
else
saved_render_objects.push_back( obj );
}
for ( auto &obj : collision_objects ) {
if ( !obj->isStatic() )
saved_collision_objects.push_back( obj->copySelf() );
else
saved_collision_objects.push_back( obj );
}
}
void Scene::resetScene() {
render_objects.clear();
collision_objects.clear();
for ( auto &obj : saved_render_objects ) {
if ( !obj->isStatic() )
render_objects.push_back( obj->copySelf() );
else
render_objects.push_back( obj );
}
for ( auto &obj : saved_collision_objects ) {
if ( !obj->isStatic() )
collision_objects.push_back( obj->copySelf() );
else
collision_objects.push_back( obj );
}
}
void Scene::checkKilled() {
std::lock_guard< std::mutex > lock( render_mutex );
std::vector< int > killed;
std::vector< int > killed_collisions;
for ( long unsigned int i = 0; i < render_objects.size(); i++ ) {
if ( render_objects[i]->getKilled() )
killed.push_back( i );
if ( i < collision_objects.size() && collision_objects[i]->getKilled() )
killed_collisions.push_back( i );
}
// reverse so we don't screw up indexing while going thorugh the kill
// indices
std::reverse( killed.begin(), killed.end() );
std::reverse( killed_collisions.begin(), killed_collisions.end() );
for ( auto &index : killed ) {
render_objects.erase( render_objects.begin() + index );
}
for ( auto &index : killed_collisions ) {
collision_objects.erase( collision_objects.begin() + index );
}
}
} // namespace SDLPP

66
sdlpp/sdlpp_scene.hpp Normal file
View File

@ -0,0 +1,66 @@
#ifndef SDLPP_HPP_SCENE
#define SDLPP_HPP_SCENE
#include <algorithm>
#include <memory>
#include <mutex>
#include <unordered_set>
#include "sdlpp_common.hpp"
#include "sdlpp_renderer.hpp"
#include "sdlpp_renderobject.hpp"
namespace SDLPP {
class Scene {
public:
Scene( std::shared_ptr< Renderer > &r );
void addObject( const std::shared_ptr< RenderObject > &obj );
void setZIndex( const std::shared_ptr< RenderObject > &obj, int index );
void moveDownZ( const std::shared_ptr< RenderObject > &obj );
void moveUpZ( const std::shared_ptr< RenderObject > &obj );
void moveZ( const std::shared_ptr< RenderObject > &obj, int addition );
// TODO addCollision
std::shared_ptr< RenderObject > getObject( int index );
std::vector< std::shared_ptr< RenderObject > > getObjects();
std::vector< std::shared_ptr< RenderObject > >
getObjects( const std::unordered_set< int > &objectIDs );
void movement();
std::vector< std::shared_ptr< RenderObject > >
getCollisions( RenderObject &r );
std::vector< std::shared_ptr< RenderObject > >
getCollisions( RenderObject &r,
const std::unordered_set< int > &objectIDs );
void renderScene( bool clear_renderer = true );
void presentScene();
void setBackground( std::shared_ptr< Texture > bg );
void setBackground( const std::string &img_path );
void updateSizeAndPosition();
void moveEverything( double x, double y );
const std::shared_ptr< RenderObject > &leftmost();
const std::shared_ptr< RenderObject > &rightmost();
std::pair< int, int > getDimensions() const;
int getWidth() const;
int getHeight() const;
Renderer &getRenderer();
std::shared_ptr< Renderer > getRendererShared();
void setPrevTicks( int ticks );
void saveScene();
void resetScene();
private:
void checkKilled();
std::vector< std::shared_ptr< RenderObject > > render_objects;
std::vector< std::shared_ptr< RenderObject > > collision_objects;
std::vector< std::shared_ptr< RenderObject > > saved_render_objects;
std::vector< std::shared_ptr< RenderObject > > saved_collision_objects;
std::shared_ptr< Renderer > renderer;
std::shared_ptr< Texture > background;
int prev_ticks = 0;
std::shared_ptr< RenderObject > leftmost_obj;
std::shared_ptr< RenderObject > rightmost_obj;
uint64_t max_object_id = 0;
std::mutex render_mutex;
};
} // end of namespace SDLPP
#endif

View File

@ -0,0 +1,98 @@
#include "sdlpp_textrenderer.hpp"
namespace SDLPP {
TextRenderer::TextRenderer( double x, double y, double w, double h,
std::shared_ptr< Renderer > &r )
: RectangleRender( x, y, w, h, r ) {}
TextRenderer::TextRenderer( double x, double y, double w, double h,
std::shared_ptr< Renderer > &r, Font &font,
const std::string &text, const std::string &color,
const std::string &outline_color, int outline_size,
int flags )
: RectangleRender( x, y, w, h, r ) {
position_flags = flags;
setText( font, text, color, outline_color, outline_size );
}
void TextRenderer::setText( Font &font, const std::string &text,
const std::string &color,
const std::string &outline_color,
int outline_size ) {
_text = text;
setTextColor( font, color, outline_color, outline_size );
}
void TextRenderer::setTextColor( Font &font, const std::string &color,
const std::string &outline_color,
int outline_size ) {
setTexture( font, _text, color, outline_color, outline_size );
updateDstRect();
}
void TextRenderer::changeText( const std::string &text ) {
_text = text;
}
void TextRenderer::setFlags( int flags ) {
position_flags = flags;
updateDstRect();
}
void TextRenderer::render() {
if ( !getHidden() ) {
if ( polygon )
polygon->render( *renderer );
if ( texture != NULL )
SDL_RenderCopy( renderer->getRendererPtr(),
texture->getTexturePtr(), NULL, &dst_rect );
}
if ( hasCollisions() && renderer->getRenderColiders() && !getHidden() ) {
for ( const auto &col : getCollisions() )
col->render( *renderer, colider_color );
}
}
void TextRenderer::updateSizeAndPosition() {
RectangleRender::updateSizeAndPosition();
updateDstRect();
}
std::shared_ptr< RenderObject > TextRenderer::copySelf() {
// TODO ACTUALLY copy, don't just copy pointers to textures and whatnot,
// create new textures!!!
return std::make_shared< TextRenderer >( *this );
}
void TextRenderer::updateDstRect() {
if ( !texture )
return;
int text_width{}, text_height{};
SDL_QueryTexture( texture->getTexturePtr(), NULL, NULL, &text_width,
&text_height );
if ( text_width < rect.w && text_height < rect.h ) {
dst_rect.w = text_width;
dst_rect.h = text_height;
} else {
double x_div = static_cast< double >( text_width ) /
static_cast< double >( rect.w );
double y_div = static_cast< double >( text_height ) /
static_cast< double >( rect.h );
if ( x_div > y_div ) {
dst_rect.w = text_width / x_div;
dst_rect.h = text_height / x_div;
} else {
dst_rect.w = text_width / y_div;
dst_rect.h = text_height / y_div;
}
}
if ( !( position_flags & SDLPP_TEXT_LEFT ||
position_flags & SDLPP_TEXT_RIGHT ) ) {
dst_rect.x = rect.x + ( rect.w - dst_rect.w ) / 2;
} else if ( position_flags & SDLPP_TEXT_LEFT ) {
dst_rect.x = rect.x;
} else if ( position_flags & SDLPP_TEXT_RIGHT ) {
dst_rect.x = rect.x + rect.w - dst_rect.w;
}
if ( !( position_flags & SDLPP_TEXT_TOP ||
position_flags & SDLPP_TEXT_BOTTOM ) ) {
dst_rect.y = rect.y + ( rect.h - dst_rect.h ) / 2;
} else if ( position_flags & SDLPP_TEXT_TOP ) {
dst_rect.y = rect.y;
} else if ( position_flags & SDLPP_TEXT_BOTTOM ) {
dst_rect.y = rect.y + rect.h - dst_rect.h;
}
}
} // namespace SDLPP

View File

@ -0,0 +1,41 @@
#ifndef SDLPP_HPP_TEXT_RENDERER
#define SDLPP_HPP_TEXT_RENDERER
#include "sdlpp_common.hpp"
#include "sdlpp_rectrenderer.hpp"
#include <memory>
#include <string>
namespace SDLPP {
class TextRenderer : public RectangleRender {
public:
TextRenderer() = delete;
TextRenderer( double x, double y, double w, double h,
std::shared_ptr< Renderer > &r );
TextRenderer( double x, double y, double w, double h,
std::shared_ptr< Renderer > &r, Font &font,
const std::string &text, const std::string &color = "FFFFFF",
const std::string &outline_color = "000000",
int outline_size = -1, int flags = SDLPP_TEXT_CENTER );
void setText( Font &font, const std::string &text,
const std::string &color = "FFFFFF",
const std::string &outline_color = "000000",
int outline_size = -1 );
void setTextColor( Font &font, const std::string &color = "FFFFFF",
const std::string &outline_color = "000000",
int outline_size = -1 );
void changeText( const std::string &text );
void setFlags( int flags );
virtual void render() override;
virtual void updateSizeAndPosition() override;
virtual std::shared_ptr< RenderObject > copySelf() override;
private:
void updateDstRect();
std::string _text{};
int position_flags = 0;
SDL_Rect dst_rect{};
};
} // end of namespace SDLPP
#endif

75
sdlpp/sdlpp_texture.cpp Normal file
View File

@ -0,0 +1,75 @@
#include "sdlpp_texture.hpp"
namespace SDLPP {
Texture::Texture( std::shared_ptr< Renderer > &renderer,
const std::string &img_path, const std::string &color_key ) {
SDL_Surface *surface = IMG_Load( img_path.c_str() );
if ( surface == NULL ) {
std::cerr << "Unable to load image '" << img_path
<< "': IMG Error: " << IMG_GetError() << std::endl;
throw "IMG_Load error";
}
if ( !color_key.empty() ) {
auto colors = getColorsHEX( color_key );
SDL_SetColorKey( surface, SDL_TRUE,
SDL_MapRGB( surface->format, std::get< 0 >( colors ),
std::get< 1 >( colors ),
std::get< 2 >( colors ) ) );
}
setTextureFromSurface( renderer, surface );
}
Texture::Texture( std::shared_ptr< Renderer > &renderer, Font &font,
const std::string &text, const std::string &color,
const std::string &outline_color, const int outline_size ) {
if ( outline_size != -1 ) {
font.setOutline( outline_size );
}
int og_outline = 0;
SDL_Surface *bg_surface = NULL;
if ( ( og_outline = font.getOutline() ) != 0 ) {
bg_surface = TTF_RenderUTF8_Blended( font.getFont(), text.c_str(),
getSDLColorHEX( outline_color ) );
if ( bg_surface == NULL ) {
std::cerr << "Unable to render text '" << text
<< "': TTF Error: " << TTF_GetError() << std::endl;
throw "TTF_RenderUTF8_Shaded error";
}
font.setOutline( 0 );
}
SDL_Surface *surface = TTF_RenderUTF8_Blended( font.getFont(), text.c_str(),
getSDLColorHEX( color ) );
if ( surface == NULL ) {
std::cerr << "Unable to render text '" << text
<< "': TTF Error: " << TTF_GetError() << std::endl;
throw "TTF_RenderUTF8_Shaded error";
}
if ( og_outline != 0 ) {
SDL_Rect rect = { og_outline, og_outline, surface->w, surface->h };
SDL_SetSurfaceBlendMode( surface, SDL_BLENDMODE_BLEND );
SDL_BlitSurface( surface, NULL, bg_surface, &rect );
SDL_FreeSurface( surface );
surface = bg_surface;
bg_surface = NULL;
font.setOutline( og_outline );
}
setTextureFromSurface( renderer, surface );
}
Texture::~Texture() {
SDL_DestroyTexture( texture );
}
SDL_Texture *Texture::getTexturePtr() {
return texture;
}
void Texture::setTextureFromSurface( std::shared_ptr< Renderer > &renderer,
SDL_Surface *surface ) {
texture =
SDL_CreateTextureFromSurface( renderer->getRendererPtr(), surface );
if ( texture == NULL ) {
std::cerr << "Unable to create texture from surface! SDL Error: "
<< SDL_GetError() << std::endl;
throw "Texture error";
}
SDL_FreeSurface( surface );
}
} // namespace SDLPP

32
sdlpp/sdlpp_texture.hpp Normal file
View File

@ -0,0 +1,32 @@
#ifndef SDLPP_HPP_TEXTURE
#define SDLPP_HPP_TEXTURE
#include <memory>
#include "sdlpp_common.hpp"
#include "sdlpp_font.hpp"
#include "sdlpp_renderer.hpp"
namespace SDLPP {
class Texture {
public:
Texture() = delete;
Texture( std::shared_ptr< Renderer > &renderer,
const std::string &img_path )
: Texture( renderer, img_path, "" ) {}
Texture( std::shared_ptr< Renderer > &renderer, const std::string &img_path,
const std::string &color_key );
Texture( std::shared_ptr< Renderer > &renderer, Font &font,
const std::string &text, const std::string &color = "FFFFFF",
const std::string &outline_color = "000000",
const int outline_size = -1 );
virtual ~Texture();
SDL_Texture *getTexturePtr();
private:
void setTextureFromSurface( std::shared_ptr< Renderer > &renderer,
SDL_Surface *surface );
SDL_Texture *texture = NULL;
};
} // end of namespace SDLPP
#endif

33
sdlpp/sdlpp_window.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "sdlpp_window.hpp"
namespace SDLPP {
Window::Window()
: Window( "SDL Window", 640, 480, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED ) {}
Window::Window( const std::string &window_name )
: Window( window_name, 640, 480, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED ) {}
Window::Window( const std::string &window_name, uint32_t width,
uint32_t height )
: Window( window_name, width, height, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED ) {}
Window::Window( const std::string &window_name, uint32_t width, uint32_t height,
uint32_t posx, uint32_t posy ) {
window = SDL_CreateWindow( window_name.c_str(), posx, posy, width, height,
SDL_WINDOW_SHOWN );
if ( window == NULL ) {
std::cerr << "SDL could not create a window! SDL_Error: "
<< SDL_GetError() << std::endl;
throw "Couldn't create window";
}
}
void Window::setResizable( bool resizable ) {
SDL_SetWindowResizable( window, resizable ? SDL_TRUE : SDL_FALSE );
}
Window::~Window() {
SDL_DestroyWindow( window );
}
SDL_Window *Window::getWindowPtr() {
return window;
}
} // namespace SDLPP

24
sdlpp/sdlpp_window.hpp Normal file
View File

@ -0,0 +1,24 @@
#ifndef SDLPP_HPP_WINDOW
#define SDLPP_HPP_WINDOW
#include "sdlpp_common.hpp"
#include <iostream>
namespace SDLPP {
class Window {
public:
Window();
Window( const std::string &window_name );
Window( const std::string &window_name, uint32_t width, uint32_t height );
Window( const std::string &window_name, uint32_t width, uint32_t height,
uint32_t posx, uint32_t posy );
void setResizable( bool resizable );
virtual ~Window();
SDL_Window *getWindowPtr();
private:
SDL_Window *window = NULL;
};
} // namespace SDLPP
#endif