Skip to content

Instantly share code, notes, and snippets.

@Heimdell
Last active August 29, 2015 13:56
Show Gist options
  • Save Heimdell/9172185 to your computer and use it in GitHub Desktop.
Save Heimdell/9172185 to your computer and use it in GitHub Desktop.
SDL bindings
#pragma once
#include "stdinc.h++"
static const Uint8 FF = (Uint8) -1;
struct Color
{
Uint8 r, g, b, a;
operator Uint32() {
union {
Uint32 dw;
Uint8 bs[4];
} conv;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
conv.bs[0] = a;
conv.bs[1] = b;
conv.bs[2] = g;
conv.bs[3] = r;
#else
conv.bs[3] = a;
conv.bs[2] = b;
conv.bs[1] = g;
conv.bs[0] = r;
#endif
return conv.dw;
}
static Color rMask() { return { FF, 0, 0, 0 }; }
static Color gMask() { return { 0, FF, 0, 0 }; }
static Color bMask() { return { 0, 0, FF, 0 }; }
static Color aMask() { return { 0, 0, 0, FF }; }
};
surface
- low level
location
= surf * rect
it.blit location
#pragma once
#include "stdinc.h++"
template <class... Args>
using Handler = function<bool(Args...)>;
template <class... Args>
bool pass(Args...)
{
return false;
}
template <class... Args>
bool consume(Args...)
{
return true;
}
struct Nil { } nil;
struct InputHandler
{
Handler<int, int> resized = pass<int, int>;
Handler<Nil> focusGained = pass<Nil>;
Handler<Nil> focusLost = pass<Nil>;
Handler<int, SDL_Keysym> keyDown = (pass<int, SDL_Keysym>);
Handler<int, SDL_Keysym> keyUp = (pass<int, SDL_Keysym>);
Handler<int, int> mouseMoved = pass<int, int>;
Handler<int> mouseDown = pass<int>;
Handler<int> mouseUp = pass<int>;
Handler<int, int> mouseScroll = pass<int, int>;
Handler<string> fileDropped = pass<string>;
Handler<Nil> quit = pass<Nil>;
Handler<Nil> noEvent = pass<Nil>;
bool dispatch(SDL_Event event) {
switch (event.type)
{
case SDL_QUIT:
return quit(nil);
case SDL_WINDOWEVENT:
switch (event.window.event)
{
case SDL_WINDOWEVENT_RESIZED:
return resized(event.window.data1, event.window.data2);
case SDL_WINDOWEVENT_FOCUS_GAINED:
return focusGained(nil);
case SDL_WINDOWEVENT_FOCUS_LOST:
return focusLost(nil);
case SDL_WINDOWEVENT_CLOSE:
return quit(nil);
}
case SDL_KEYDOWN:
return keyDown(event.key.repeat, event.key.keysym);
case SDL_KEYUP:
return keyUp(event.key.repeat, event.key.keysym);
case SDL_MOUSEMOTION:
return mouseMoved(event.motion.x, event.motion.y);
case SDL_MOUSEBUTTONDOWN:
return mouseDown(event.button.button);
case SDL_MOUSEBUTTONUP:
return mouseUp(event.button.button);
case SDL_MOUSEWHEEL:
return mouseScroll(event.wheel.x, event.wheel.y);
case SDL_DROPFILE:
{
string name = event.drop.file;
bool consumed = fileDropped(name);
SDL_free(event.drop.file);
return consumed;
}
}
}
};
struct InputStack
{
vector<InputHandler> handlers;
InputStack() {
handlers.emplace_back();
}
InputStack(InputHandler h)
{
handlers.push_back(h);
}
void pollAndDispatch()
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
for (auto handler : handlers)
{
if (handler.dispatch(event))
break;
}
}
}
};
#include "sprite.h++"
#include "sdl_context.h++"
#include "window.h++"
#include "render_lock.h++"
#include "view.h++"
#include "input.h++"
int main() {
SDL sdl;
auto grid = Sprite::fromFile("./grid.png").clip(64, 64);
auto watered = grid.at(320, 320 + 64 * 1);
auto dry = grid.at(320, 320 + 64 * 0);
auto grass = grid.at(320, 320 + 64 * 2);
map<Point, Sprite> m;
for (int i = -50; i < +50; i++)
for (int j = -50; j < +50; j++) {
m[{i, j}] = rand() % 8 ? grass : watered;
}
m[{1, 1}] = watered;
View level;
level.images = m;
level.buffer = Buffer::ofSize(640 * 2, 480 * 2);
level.goL = {-32, +16};
level.goU = {+32, +16};
level.chunkOffset = {-320 - 32, +180};
level.viewpoint = {0, 0};
Window window { "main" };
bool quit = false;
InputHandler handler;
handler.quit = [&quit] (Nil) {
quit = true;
return true;
};
handler.keyDown = [&level] (int repeat, SDL_Keysym key) {
switch (key.sym) {
case SDLK_w: level.goUp(); break;
case SDLK_s: level.goDown(); break;
case SDLK_a: level.goLeft(); break;
case SDLK_d: level.goRight(); break;
default: return false;
}
return true;
};
InputStack input { handler };
level.update();
while (!quit) {
level.update();
{
Render session(window);
level.blit(window.surface());
}
input.pollAndDispatch();
}
}
LD_FLAGS = -D_REENTRANT -I/usr/local/include/SDL2 -Wl,-rpath,/usr/local/lib -L/usr/local/lib -lSDL2_image -lSDL2 -lpthread
CC_FLAGS = -std=c++11 -O2
CC = c++
EXECUTABLE = ./app.out
all: app.out
app.out: *.h++ *.c++
$(CC) $(CC_FLAGS) main.c++ $(LD_FLAGS) -o $(EXECUTABLE)
run: all
$(EXECUTABLE)
#pragma once
enum Direction { UP, DOWN, LEFT, RIGHT };
struct Point
{
int x, y;
};
template <class Object>
int myHash(const Object object);
template <>
int myHash<int>(int x) {
return x * 69069;
}
template <>
int myHash<Point>(Point pt) {
return myHash(pt.x + myHash(pt.y));
}
bool operator < (Point a, Point b) {
return myHash(a) < myHash(b);
}
template <class Method>
Point move(Point pt, Direction dir) {
return Method::move(pt, dir);
}
#pragma once
#include "stdinc.h++"
struct Rect
{
SDL_Rect rect;
const int up() const { return rect.x; }
const int down() const { return rect.x + rect.w; }
const int left() const { return rect.y; }
const int right() const { return rect.y + rect.h; }
const int width() const { return rect.w; }
const int height() const { return rect.h; }
const Rect copy() const { return *this; }
Rect &setUp (int val) { rect.y = val; return *this; }
Rect &setLeft (int val) { rect.x = val; return *this; }
Rect &setDown (int val) { rect.w = val - rect.y; return *this; }
Rect &setRight(int val) { rect.h = val - rect.x; return *this; }
Rect &setWidth (int val) { rect.w = val; return *this; }
Rect &setHeight(int val) { rect.h = val; return *this; }
Rect(int x, int y, int w, int h) {
rect.x = x;
rect.y = y;
rect.w = w;
rect.h = h;
}
Rect(SDL_Rect rect = { 0, 0, 0, 0 })
: rect(rect)
{ }
operator SDL_Rect() const {
return rect;
}
static Rect standart() {
return Rect().clip(480, 640);
}
Rect clip(int w, int h) {
return Rect()
.setWidth (w)
.setHeight(h);
}
Rect at(int x, int y) {
return (*this)
.setLeft (x)
.setUp (y);
}
friend ostream &operator << (ostream &o, const Rect &rect) {
return o
<< "Rect "
<< "{ l = " << rect.left()
<< ", r = " << rect.right()
<< ", u = " << rect.up()
<< ", d = " << rect.down()
<< "}"
<< endl;
}
};
#pragma once
#include "stdinc.h++"
#include "window.h++"
struct Render
{
Window &window;
Render(Window &window)
: window(window)
{
window.startRender();
}
~Render()
{
window.endRender();
}
};
#pragma once
#include "stdinc.h++"
struct SDL
{
SDL() {
SDL_Init(SDL_INIT_EVERYTHING);
}
~SDL() {
SDL_Quit();
}
void delay(int msec) {
SDL_Delay(msec);
}
};
#pragma once
#include "stdinc.h++"
#include "surface.h++"
#include "rect.h++"
struct Sprite;
typedef Sprite Location;
typedef Sprite Buffer;
struct Sprite
{
Surface surface;
Rect rect;
operator bool() { return surface; }
static Sprite ofSize(int w, int h) {
Rect rect = Rect().clip(w, h);
Surface surface = Surface::fromRect(rect);
return { surface, rect };
}
static Sprite fromSurface(Surface surface) {
SDL_Rect rect;
SDL_GetClipRect(surface, &rect);
return { surface, rect };
}
static Sprite fromFile(string name) {
auto img = fromSurface(Surface::fromImage(name));
return img;
}
template <class... ClipArgs>
Sprite clip(ClipArgs... args) {
Sprite copy = *this;
copy.rect = rect.clip(args...);
return copy;
}
Sprite at(int x, int y) {
Sprite copy = *this;
copy.rect.at(x, y);
return copy;
}
int blitOnto(Location location) {
SDL_Rect src = rect;
SDL_Rect dst = location.rect;
return SDL_BlitSurface(this->surface, &src, location.surface, &dst);
}
int blitScaledOnto(Location location) {
SDL_Rect src = rect;
SDL_Rect dst = location.rect;
return SDL_BlitScaled(this->surface, &src, location.surface, &dst);
}
};
#pragma once
#include <string>
#include <vector>
#include <map>
#include <set>
#include <memory>
#include <iostream>
#include <functional>
using namespace std;
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
template <class T>
shared_ptr<T> shared(T * t) {
return shared_ptr<T>(t);
}
#pragma once
#include "stdinc.h++"
#include "color.h++"
#include "rect.h++"
struct Surface
{
shared_ptr<SDL_Surface> surface;
operator bool() { return (bool)surface; }
static Surface fromRect(Rect rect) {
return SDL_CreateRGBSurface
( 0
, rect.width()
, rect.height()
, 32
, Color::rMask()
, Color::gMask()
, Color::bMask()
, 0
);
}
static Surface fromImage(string name) {
auto img = IMG_Load(name.c_str());
cout << SDL_GetError() << ", " << img << endl;
return img;
}
Surface(SDL_Surface * surf = 0, bool owns = true) {
surface = shared_ptr<SDL_Surface>(surf, [owns](SDL_Surface * surface) {
if (owns)
SDL_FreeSurface(surface);
});
}
operator SDL_Surface * () { return surface.get(); }
};
#pragma once
#include "stdinc.h++"
#include "rect.h++"
#include "surface.h++"
#include <SDL2/SDL.h>
struct Texture
{
SDL_Texture * texture;
Texture(SDL_Renderer * renderer, Surface surface) {
texture = SDL_CreateTextureFromSurface(renderer, surface);
}
operator SDL_Texture * () { return texture; }
~Texture() {
SDL_DestroyTexture(texture);
}
};
Квест, выдаваемый крысами в подвале, на устранение жильцов этажом выше.
#pragma once
#include "stdinc.h++"
#include "sprite.h++"
#include "point.h++"
struct HexMove
{
static Point move(Point pt, Direction dir) {
switch (dir) {
case UP : pt.x--, pt.y--; break;
case DOWN : pt.x++, pt.y++; break;
case LEFT : pt.x++, pt.y--; break;
case RIGHT: pt.x--, pt.y++; break;
}
return pt;
}
};
static function<Point(Point, Direction)> hexmove = move<HexMove>;
struct View
{
map<Point, Sprite> images;
Buffer buffer;
Point viewpoint;
Point goL, goU;
Point chunkOffset;
View &update() {
SDL_FillRect(buffer.surface, 0, 0);
auto border = buffer.rect;
for (int i = -11; i < 11; i++)
{
for (int j = -11; j < 11; j++)
{
if (abs(i) + abs(j) > 10) continue;
Point pivot { viewpoint.x + i, viewpoint.y + j };
int x = chunkOffset.x + goL.x * i + goU.x * j + border.width() / 2;
int y = chunkOffset.y + goL.y * i + goU.y * j;
images[pivot].blitOnto(buffer.at(x, y));
}
}
return *this;
}
void blit(Location location) {
buffer.blitOnto(location);
}
void goUp() { go(UP); }
void goLeft() { go(LEFT); }
void goDown() { go(DOWN); }
void goRight() { go(RIGHT); }
void go(Direction dir) {
Point newViewpoint = hexmove(viewpoint, dir);
if (images[newViewpoint])
viewpoint = newViewpoint;
}
};
#pragma once
#include "stdinc.h++"
#include "rect.h++"
#include "surface.h++"
#include "texture.h++"
struct Window
{
SDL_Window * window;
Window(string name, Rect position = Rect::standart(), int flags = SDL_WINDOW_SHOWN) {
window = SDL_CreateWindow
( name.c_str()
, position.left()
, position.up()
, position.right()
, position.down()
, flags
);
}
Location surface() {
return Location::fromSurface(Surface(SDL_GetWindowSurface(window), false));
}
void render(function<void(Window &)> actions) {
startRender();
actions(*this);
endRender();
}
void startRender() {
SDL_FillRect(surface().surface, 0, 0);
}
void endRender() {
SDL_UpdateWindowSurface(window);
}
~Window() {
SDL_DestroyWindow(window);
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment