gcores ~/apps/Menu branch first commit

This commit is contained in:
cpi
2019-07-16 03:40:14 +00:00
parent 2d75a8d65d
commit 45737f787c
2136 changed files with 214 additions and 17128 deletions

View File

@@ -1,231 +0,0 @@
class game+, control+ {
private import rt::c, lib::sdl2;
private alias vector = std::vector;
struct control {
struct callback {
update void;
draw void;
wake void;
destructor void;
}
parent. scene;
parent_control. control;
controls vector<void>;
focus_control. control;
popup. control;
closing_popup. control;
pending_popup. control;
x int;
y int;
width int;
height int;
enable bool;
visible bool;
focus bool;
}
func constructor() {
memset(this, 0, sizeof(control));
this.enable = true;
this.visible = true;
constructor(this);
}
func destructor() {
if this.popup ~= null;
this->free_control(this.popup);
if this.closing_popup ~= null;
this->free_control(this.closing_popup);
if this.pending_popup ~= null;
this->free_control(this.pending_popup);
forvar count size_t = this.controls->count(); count;;
this->free_control(.this.controls->at(--count));
destructor(this);
}
//
inline create_control<T>(x int, y int, width int = 0, height int = 0) .T {
func = this.parent->create_control<T>(x, y, width, height);
func->set_parent_control(this);
}
inline new_control<T>(x int, y int, width int = 0, height int = 0) .T {
this.controls->push_back(
func = this->create_control<T>(this.x + x, this.y + y, width, height));
}
inline free_control(control. control) {
this.parent->free_control(control);
}
// focus
func set_focus(control. control) {
var prev. control = this.focus_control;
if prev ~= null;
prev.focus = false;
this.focus_control = control, control.focus = true;
}
inline get_focus() .control {
return this.focus_control;
}
// popup
func close_popup() {
if this.popup ~= null {
this.closing_popup = this.popup;
this.popup = null;
// xxx
if this.callback.wake ~= null {
proto fn(this void);
fn[this.callback.wake](this);
}
}
}
func close_parent_popup() {
if this.parent_control == null {
this.parent->close_popup();
else
this.parent_control->close_popup();
}
}
func set_popup(control. control) {
if this.popup == null and this.closing_popup == null {
this.popup = control;
else
if this.pending_popup ~= null;
this->free_control(this.pending_popup);
this.pending_popup = control;
}
}
func has_popup() bool {
if this.popup ~= null or
this.closing_popup ~= null or
this.pending_popup ~= null {
return true;
}
return false;
}
//
func update(render void) {
proto fn(this void, render void);
if this.closing_popup ~= null;
this->free_control(this.closing_popup), this.closing_popup = null;
if this.pending_popup ~= null {
if this.popup ~= null;
this->free_control(this.popup);
this.popup = this.pending_popup;
this.pending_popup = null;
}
// xxx
if this.popup == null {
forvar count size_t = this.controls->count(); count; {
var control. control = .this.controls->at(--count);
if control.callback.update ~= null;
fn[control.callback.update](control, render);
}
else
var popup. control = this.popup;
if popup.callback.update ~= null;
fn[popup.callback.update](popup, render);
}
}
func draw(render void) {
proto fn(this void, render void);
forvar count size_t = this.controls->count(); count; {
var control. control = .this.controls->at(--count);
if control.callback.draw ~= null;
fn[control.callback.draw](control, render);
}
if this.popup ~= null {
var popup. control = this.popup;
if popup.callback.draw ~= null;
fn[popup.callback.draw](popup, render);
}
}
func wake() {
proto fn(this void);
forvar count size_t = this.controls->count(); count; {
var control. control = .this.controls->at(--count);
if control.callback.wake ~= null;
fn[control.callback.wake](control);
}
if this.popup ~= null {
var popup. control = this.popup;
if popup.callback.wake ~= null;
fn[popup.callback.wake](popup);
}
}
//
inline set_parent(scene. scene) {
this.parent = scene;
}
inline get_parent() .scene {
return this.parent;
}
inline get_parent_t<T>() .T {
return this.parent;
}
inline set_parent_control(control. control) {
this.parent_control = control;
}
inline get_parent_control() .control {
return this.parent_control;
}
inline get_parent_control_t<T>() .T {
return this.parent_control;
}
inline get_window() .window {
return this.parent->get_window();
}
//
inline set_x(x int) { this.x = x; }
inline set_y(y int) { this.y = y; }
inline set_pos(x int, y int) { this.x = x, this.y = y; }
inline set_width(width int) { this.width = width; }
inline set_height(height int) { this.height = height; }
inline set_size(width int, height int) {
this.width = width,
this.height = height;
}
inline get_x() int { return this.x; }
inline get_y() int { return this.y; }
inline get_width() int { return this.width; }
inline get_height() int { return this.height; }
inline get_right() int { return this.x + this.width; }
inline get_bottom() int { return this.y + this.height; }
inline get_rect() SDL_Rect {
func.x = this.x,
func.y = this.y,
func.w = this.width,
func.h = this.height;
}
inline has_focus() bool { return this.focus; }
}

View File

@@ -1,80 +0,0 @@
// SDL_GetTicks: This value wraps if the program runs for more than ~49 days.
class game+, delay {
private import lib::sdl2;
struct delay {
duration uint32;
t uint32;
last_t uint32;
done bool;
}
inline init(duration uint32, done bool = false) {
this.duration = duration;
this.t = 0;
this.last_t = 0;
this.done = done;
}
inline reset() {
this.t = 0;
this.last_t = 0;
this.done = false;
}
inline done() {
this.done = true;
}
inline done?() bool {
return this.done;
}
inline do() bool {
if !this.done {
this.last_t = SDL_GetTicks();
if !this.t;
this.t = this.last_t + this.duration;
if this.t > this.last_t;
return false;
this.done = true;
}
return true;
}
inline undo() {
this.last_t = SDL_GetTicks();
this.t = this.last_t + this.duration;
this.done = false;
}
//
inline get_duration() uint32 {
return this.duration;
}
inline set_duration(duration uint32) {
this.duration = duration;
}
inline inc_duration(inc int32) {
this.duration += inc;
}
inline get_remain_t() uint32 {
return this.t - this.last_t;
}
inline get_per<T>(x T) T {
return (float(this->get_remain_t()) / this.duration) * x;
}
inline get_per_r<T>(x T) T {
return x - this->get_per<T>(x);
}
}

View File

@@ -1,87 +0,0 @@
class game+, fadeio {
private import rt::c, lib::sdl2;
struct fadeio {
delay delay;
texture texture;
rect SDL_Rect;
render void;
done bool;
r uint8;
g uint8;
b uint8;
}
func constructor() {
memset(this, 0, sizeof(fadeio));
constructor(this);
}
func destructor() {
destructor(this);
}
//
inline init(wnd. window, duration uint32) {
this.delay->init(duration);
this.render = wnd->get_render();
wnd->get_size(&this.rect.w, &this.rect.h);
}
//
inline set_color(r uint8, g uint8, b uint8) {
this.texture->destroy();
this.r = r;
this.g = g;
this.b = b;
}
inline set_texture(texture void, auto_destroy bool = true) bool {
if func = this.texture->init(texture, auto_destroy);
this.texture->set_blend_mode(SDL_BLENDMODE_BLEND);
}
//
inline done() {
this.delay->done();
}
inline reset() {
this.delay->reset();
}
//
inline do() bool {
if func = this.delay->do() {
if !this.done;
this.texture->destroy(), this.done = true;
else
this->fade();
}
}
//
private func fade() {
var alpha uint8 = this.delay->get_per<uint8>(0xff);
var texture void = this.texture->get_texture();
if texture == null {
SDL_SetRenderDrawBlendMode(this.render, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(this.render, this.r, this.g, this.b, alpha);
SDL_RenderFillRect(this.render, &this.rect);
SDL_SetRenderDrawBlendMode(this.render, SDL_BLENDMODE_NONE);
else
this.texture->set_alpha_mod(alpha);
this.texture->draw(this.render,
this.rect.w - (this.rect.w + this.texture->get_width()) / 2,
this.rect.h - (this.rect.h + this.texture->get_height()) / 2);
}
}
}

View File

@@ -1,58 +0,0 @@
class game+, focus_map {
private import rt::c, lib::sdl2;
private alias vector = std::vector;
struct map {
control. control;
up. control;
down. control;
left. control;
right. control;
}
struct focus_map {
map vector<map>;
}
func constructor() {
constructor(this);
}
func destructor() {
destructor(this);
}
func register(control. control, up. control, down. control, left. control, right. control) {
var map. map = this.map->new();
map.control = control;
map.up = up;
map.down = down;
map.left = left;
map.right = right;
}
func get(control. control, scancode SDL_Scancode) .control {
var count size_t = this.map->count();
while count {
var map. map = this.map->at(--count);
if map.control == control {
if scancode == CPI_SCANCODE_UP {
return map.up;
elseif scancode == CPI_SCANCODE_DOWN;
return map.down;
elseif scancode == CPI_SCANCODE_LEFT;
return map.left;
elseif scancode == CPI_SCANCODE_RIGHT;
return map.right;
else
return null;
}
}
}
return null;
}
}

View File

@@ -1,98 +0,0 @@
class game+, font {
private import rt::c, lib::sdl2_ttf;
struct font {
obj void;
tex texture;
}
func constructor() {
this.obj = null;
constructor(this);
}
func destructor() {
this->close();
destructor(this);
}
func open(font_name. char, size int) bool {
this->close();
if (this.obj = TTF_OpenFont(font_name, size)) == null {
printf("TTF_OpenFont: %s\n", font_name);
return false;
}
return true;
}
func close() {
this.tex->destroy();
if this.obj ~= null;
TTF_CloseFont(this.obj), this.obj = null;
}
// xxx
inline get_width() int {
return this.tex->get_width();
}
inline get_height() int {
return TTF_FontHeight(this.obj);
}
inline get_line_skip() int {
return TTF_FontLineSkip(this.obj);
}
inline get_size(text. char, width. int, height. int) bool {
return TTF_SizeUTF8(this.obj, text, width, height) == 0;
}
func create_tex(render void, text. char, color uint32) void {
var surface void = TTF_RenderUTF8_Solid(this.obj, text, color);
if surface == null;
return null;
func = SDL_CreateTextureFromSurface(render, surface);
SDL_FreeSurface(surface);
}
// fixme
func create_outlined_tex(render void, text. char, text_color uint32, outline_color uint32, outline_size int) void {
TTF_SetFontOutline(this.obj, outline_size);
var outline_texture. SDL_Surface = TTF_RenderUTF8_Solid(this.obj, text, outline_color);
TTF_SetFontOutline(this.obj, 0);
if outline_texture == null;
return null;
var text_texture. SDL_Surface = TTF_RenderUTF8_Solid(this.obj, text, text_color);
if text_texture == null {
SDL_FreeSurface(outline_texture);
return null;
}
SDL_SetSurfaceBlendMode(outline_texture, SDL_BLENDMODE_BLEND);
var rect SDL_Rect;
rect.x = outline_size;
rect.y = outline_size;
rect.w = text_texture.w;
rect.h = text_texture.h;
SDL_BlitSurface(text_texture, null, outline_texture, &rect);
func = SDL_CreateTextureFromSurface(render, outline_texture);
SDL_FreeSurface(outline_texture);
SDL_FreeSurface(text_texture);
}
inline prepare(render void, text. char, color uint32) bool {
return this.tex->init(this->create_tex(render, text, color));
}
inline draw(render void, x int, y int) {
this.tex->draw(render, x, y);
}
inline draw2(render void, x int, y int, text. char, color uint32) {
if this->prepare(render, text, color);
this->draw(render, x, y);
}
}

View File

@@ -1,24 +0,0 @@
class game+, norepeat {
struct norepeat {
lock bool;
}
func constructor() {
this.lock = true;
}
inline do() bool {
if !this.lock {
this.lock = true;
return true;
}
return false;
}
inline set(lock bool = false) {
this.lock = lock;
}
}

View File

@@ -1,39 +0,0 @@
class game+, repeat {
private import lib::sdl2;
struct repeat {
delay delay;
duration int;
inc int;
count int;
remains int;
}
func init(duration uint32, inc int, count int) {
this.delay->init(duration, true);
this.duration = duration;
this.inc = inc;
this.count = count;
this.remains = count;
}
inline reset(done bool = true) {
this.delay->init(this.duration, done);
this.remains = this.count;
}
inline do() bool {
return this.delay->do();
}
func undo() {
if this.remains > 0 {
this.remains--;
this.delay->inc_duration(this.inc);
}
this.delay->undo();
}
}

View File

@@ -1,206 +0,0 @@
class game+, scene+ {
private import rt::c;
private alias vector = std::vector;
struct scene {
struct callback {
update void;
draw void;
wake void;
destructor void;
}
parent. window;
name. char;
controls vector<void>;
focus_control. control;
popup. control;
closing_popup. control;
pending_popup. control;
}
func constructor() {
memset(this, 0, sizeof(scene));
constructor(this);
}
func destructor() {
if this.popup ~= null;
free_control(this.popup);
if this.closing_popup ~= null;
free_control(this.closing_popup);
if this.pending_popup ~= null;
free_control(this.pending_popup);
forvar count size_t = this.controls->count(); count;;
free_control(.this.controls->at(--count));
destructor(this);
}
//
inline set_window(wnd. window) {
this.parent = wnd;
}
inline get_window() .window {
return this.parent;
}
inline set_name(name. char) {
this.name = name;
}
inline get_name() .char {
return this.name;
}
//
inline quit() bool {
return this.parent->pop_scene() ~= null;
}
// control
func new_control<T>(x int, y int, width int = 0, height int = 0, standalone bool = false) .T {
func = malloc_t<T>();
#if objectid(T).func.update;
func.super.callback.update = T::update*;
#endif
#if objectid(T).func.draw;
func.super.callback.draw = T::draw*;
#endif
#if objectid(T).func.wake;
func.super.callback.wake = T::wake*;
#endif
#if objectid(T).func.destructor;
func.super.callback.destructor = T::destructor*;
#endif
func->set_parent(this);
func->set_pos(x, y);
func->set_size(width, height);
#if objectid(T).func.init;
if !func->init(this.parent->get_render()) {
printf("Failed to load \"%s\" control.\n", objectid(T).name);
exit(1);
}
#endif
if !standalone;
this.controls->push_back(func);
}
inline create_control<T>(x int, y int, width int = 0, height int = 0) .T {
return this->new_control<T>(x, y, width, height, true);
}
static func free_control(control. control) {
if control.callback.destructor ~= null {
proto fn(this void);
fn[control.callback.destructor](control);
}
free(control);
}
// focus
func set_focus(control. control) {
var prev. control = this.focus_control;
if prev ~= null;
prev.focus = false;
this.focus_control = control, control.focus = true;
}
inline get_focus() .control {
return this.focus_control;
}
// popup
func close_popup() {
if this.popup ~= null {
this.closing_popup = this.popup;
this.popup = null;
// xxx
if this.callback.wake ~= null {
proto fn(this void);
fn[this.callback.wake](this);
}
}
}
func set_popup(control. control) {
if this.popup == null and this.closing_popup == null {
this.popup = control;
else
if this.pending_popup ~= null;
free_control(this.pending_popup);
this.pending_popup = control;
}
}
func has_popup() bool {
if this.popup ~= null or
this.closing_popup ~= null or
this.pending_popup ~= null {
return true;
}
return false;
}
//
func update(render void) {
proto fn(this void, render void);
if this.closing_popup ~= null;
free_control(this.closing_popup), this.closing_popup = null;
if this.pending_popup ~= null {
if this.popup ~= null;
free_control(this.popup);
this.popup = this.pending_popup;
this.pending_popup = null;
}
// xxx
if this.popup == null {
forvar count size_t = this.controls->count(); count; {
var control. control = .this.controls->at(--count);
if control.callback.update ~= null;
fn[control.callback.update](control, render);
}
else
var popup. control = this.popup;
if popup.callback.update ~= null;
fn[popup.callback.update](popup, render);
}
}
func draw(render void) {
proto fn(this void, render void);
forvar count size_t = this.controls->count(); count; {
var control. control = .this.controls->at(--count);
if control.callback.draw ~= null;
fn[control.callback.draw](control, render);
}
if this.popup ~= null {
var popup. control = this.popup;
if popup.callback.draw ~= null;
fn[popup.callback.draw](popup, render);
}
}
func wake() {
proto fn(this void);
forvar count size_t = this.controls->count(); count; {
var control. control = .this.controls->at(--count);
if control.callback.wake ~= null;
fn[control.callback.wake](control);
}
if this.popup ~= null {
var popup. control = this.popup;
if popup.callback.wake ~= null;
fn[popup.callback.wake](popup);
}
}
}

View File

@@ -1,79 +0,0 @@
class game+, small_font {
private import rt::c, lib::sdl2;
struct small_font {
textures(13) texture;
font_width int;
font_height int;
}
func constructor() {
constructor(this);
this.font_width = 0;
this.font_height = 0;
}
func destructor() {
destructor(this);
}
func init(render void, font_width int, font_height int, filename. char) bool {
var tex texture;
if !tex->load_file(render, filename);
return false;
if tex->get_width() ~= (font_width * 13) or tex->get_height() ~= font_height;
return false;
forvar i int = 0; i < 13; i++;
this.textures[i]->init(tex->clone_tex(render, i * font_width, 0, font_width, font_height, SDL_BLENDMODE_BLEND));
this.font_width = font_width;
this.font_height = font_height;
return true;
}
func draw_cap(render void, x int, y int, cap uint) {
var str(8) char;
forvar index int = 0, count int = snprintf(&str, 8, "%u", cap); index < count; index++ {
this.textures[str[index] - '0']->draw(render, x, y);
x += this.font_width;
}
this.textures[10]->draw(render, x, y);
}
func draw_time(render void, x int, y int, t time_t, draw_colon bool = true) {
var tm. struct_tm = localtime(&t);
if !tm.tm_hour {
tm.tm_hour = 12;
elseif tm.tm_hour > 12;
tm.tm_hour -= 12;
}
var str(8) char;
forvar index int = 0, count int =
sprintf(&str, "%u:%02u",
tm.tm_hour,
tm.tm_min); index < count; index++ {
var c char = str[index];
if isdigit(c) {
this.textures[c - '0']->draw(render, x, y);
elseif draw_colon;
this.textures[11]->draw(render, x, y);
}
x += this.font_width;
}
}
func draw_page(render void, x int, y int, cur uint, last uint) {
var str(16) char;
forvar index int = 0, count int = snprintf(&str, 16, "%u/%u", cur, last); index < count; index++ {
var c char = str[index];
if isdigit(c) {
this.textures[c - '0']->draw(render, x, y);
else
this.textures[12]->draw(render, x, y);
}
x += this.font_width;
}
}
}

View File

@@ -1,151 +0,0 @@
class game+, texture {
private import
rt::c,
lib::sdl2,
lib::sdl2_image;
struct texture {
obj void;
format uint32;
width int;
height int;
auto_destroy bool;
}
func constructor() {
memset(this, 0, sizeof(texture));
this.auto_destroy = true;
}
func destructor() {
this->destroy();
}
func destroy() {
if this.auto_destroy {
if this.obj ~= null;
SDL_DestroyTexture(this.obj);
}
this.obj = null;
this.width = 0;
this.height = 0;
}
func init(texture void, auto_destroy bool = true) bool {
this->destroy();
if texture == null {
return false;
}
if SDL_QueryTexture(texture, &this.format, null, &this.width, &this.height);
return false;
this.obj = texture;
this.auto_destroy = auto_destroy;
return true;
}
func load_file(render void, filename. char) bool {
this->destroy();
if (this.obj = IMG_LoadTexture(render, filename)) == null {
printf("IMG_LoadTexture: %s\n", SDL_GetError());
return false;
}
if SDL_QueryTexture(this.obj, &this.format, null, &this.width, &this.height) {
this->destroy();
return false;
}
this.auto_destroy = true;
return true;
}
func load_file_with_colorkey(render void, filename. char, r uint8, g uint8, b uint8) bool {
var surface. SDL_Surface = IMG_Load(filename);
if surface == null {
printf("IMG_Load: %s\n", SDL_GetError());
return false;
}
if SDL_SetColorKey(surface, SDL_RLEACCEL, SDL_MapRGB(surface.format, r, g, b)) {
SDL_FreeSurface(surface);
return false;
}
var texture void = SDL_CreateTextureFromSurface(render, surface);
SDL_FreeSurface(surface);
if texture == null;
return false;
return this->init(texture);
}
func clone_tex(render void, x int, y int, width int, height int, blend_mode SDL_BlendMode = SDL_BLENDMODE_NONE) void {
if this.obj == null;
return null;
if (func = SDL_CreateTexture(render, this.format, SDL_TEXTUREACCESS_TARGET, width, height)) == null;
return;
SDL_SetRenderTarget(render, func);
SDL_SetTextureBlendMode(func, blend_mode);
SDL_RenderCopy(render, this.obj,
&global::make_rect(x, y, width, height),
&global::make_rect(0, 0, width, height));
SDL_SetRenderTarget(render, null);
}
//
inline draw(render void, x int, y int) {
SDL_RenderCopy(render, this.obj, null,
&this->make_rect(x, y));
}
inline draw2(render void, x int, y int, width int, height int) {
SDL_RenderCopy(render, this.obj,
&global::make_rect(0, 0, width, height),
&global::make_rect(x, y, width, height));
}
inline draw3(render void, x int, y int, width int, height int) {
SDL_RenderCopy(render, this.obj, &this->make_rect(0, 0),
&global::make_rect(x, y, width, height));
}
//
inline make_rect(x int, y int) SDL_Rect {
func.x = x,
func.y = y,
func.w = this.width,
func.h = this.height;
}
//
inline get_texture() void {
return this.obj;
}
inline get_width() int {
return this.width;
}
inline get_height() int {
return this.height;
}
inline get_blend_mode() SDL_BlendMode {
if SDL_GetTextureBlendMode(this.obj, &func);
func = SDL_BLENDMODE_INVALID;
}
inline set_blend_mode(mode SDL_BlendMode) int {
return SDL_SetTextureBlendMode(this.obj, mode);
}
inline get_alpha_mod() uint8 {
if SDL_GetTextureAlphaMod(this.obj, &func);
func = 0;
}
inline set_alpha_mod(alpha uint8) int {
return SDL_SetTextureAlphaMod(this.obj, alpha);
}
}

View File

@@ -1,312 +0,0 @@
class game+, window {
private import rt::c, lib::sdl2, lib::sdl2_image;
private alias
string = std::string,
vector_ptr = std::vector_ptr;
struct window {
wnd void;
render void;
scenes vector_ptr<scene>;
garbage vector_ptr<scene>;
current_scene. scene;
pending_scene. scene;
turbo uint32;
quit bool;
}
func constructor() {
memset(this, 0, sizeof(window));
constructor(this);
}
func destructor() {
if this.current_scene ~= null;
this->safe_free_scene(this.current_scene);
if this.pending_scene ~= null;
this->safe_free_scene(this.pending_scene);
using count size_t = this.scenes->count() {
while count {
this->free_scene_internal(this.scenes->at(--count));
}
}
this->dump();
if this.render ~= null;
SDL_DestroyRenderer(this.render);
if this.wnd ~= null;
SDL_DestroyWindow(this.wnd);
destructor(this);
}
func create_wnd(title. char, w int, h int,
x int = SDL_WINDOWPOS_UNDEFINED,
y int = SDL_WINDOWPOS_UNDEFINED) bool {
if (this.wnd = SDL_CreateWindow(title, x, y, w, h,
SDL_WINDOW_FULLSCREEN |
SDL_WINDOW_OPENGL |
SDL_WINDOW_SHOWN)) == null;
return false;
if (this.render = SDL_CreateRenderer(this.wnd, -1,
SDL_RENDERER_ACCELERATED |
SDL_RENDERER_TARGETTEXTURE)) == null {
SDL_DestroyWindow(this.wnd), this.wnd = null;
return false;
}
return true;
}
// scene
func new_scene<T>() .T {
func = malloc_t<T>();
#if objectid(T).func.update;
func.super.callback.update = T::update*;
#endif
#if objectid(T).func.draw;
func.super.callback.draw = T::draw*;
#endif
#if objectid(T).func.wake;
func.super.callback.wake = T::wake*;
#endif
#if objectid(T).func.destructor;
func.super.callback.destructor = T::destructor*;
#endif
func->set_window(this);
func->set_name(objectid(T).name);
#if objectid(T).func.init;
if !func->init(this.render) {
printf("Failed to load \"%s\" scene.\n", objectid(T).name);
exit(1);
}
#endif
}
private static func free_scene_internal(scene. scene) {
if scene.callback.destructor ~= null {
proto fn(this void);
fn[scene.callback.destructor](scene);
}
free(scene);
}
inline free_scene(scene. scene) {
this.garbage->push_back(scene);
}
func safe_free_scene(scene. scene) {
var count size_t = this.scenes->count();
while count {
if this.scenes->at(--count) == scene {
return;
}
}
this->free_scene(scene);
}
inline push_scene(scene. scene) {
this.scenes->push_back(scene);
}
inline get_last_scene() .scene {
if this.scenes->empty();
return null;
return this.scenes->back();
}
inline pop_scene() .scene {
if this.scenes->empty();
return null;
this->set_scene(func = this.scenes->back());
this.scenes->pop_back();
if func.callback.wake ~= null {
proto fn(this void);
fn[func.callback.wake](func);
}
}
func set_scene(scene. scene) {
if this.current_scene == null {
this.current_scene = scene;
else
if this.pending_scene ~= null;
this->safe_free_scene(this.pending_scene);
this.pending_scene = scene;
}
}
inline set_new_scene<T>() {
this->set_scene(this->new_scene<T>());
}
private inline swap_scene() {
if this.pending_scene ~= null {
if this.current_scene ~= null;
this->safe_free_scene(this.current_scene);
this.current_scene = this.pending_scene;
this.pending_scene = null;
}
}
//
inline dump() {
var count size_t = this.garbage->count();
while count {
this->free_scene_internal(this.garbage->at(--count));
}
this.garbage->clear();
}
//
inline update() {
var scene. scene = this.current_scene;
if scene.callback.update ~= null {
proto fn(this void, render void);
fn[scene.callback.update](scene, this.render);
}
}
inline draw() {
var scene. scene = this.current_scene;
if scene.callback.draw ~= null {
proto fn(this void, render void);
fn[scene.callback.draw](scene, this.render);
}
}
inline present() {
SDL_RenderPresent(this.render);
}
//
inline enable_turbo(ms int) {
this.turbo = SDL_GetTicks() + ms;
}
//
inline quit() {
this.quit = true;
}
//
func on_keydown(event. SDL_KeyboardEvent) {
if !event.repeat {
if event.keysym.scancode == CPI_SCANCODE_SHIFT_START {
var surface void = this->screen_capture_to_surface2();
if surface ~= null {
var tm. struct_tm = localtime(&time(null));
var filename string;
IMG_SavePNG(surface, filename->format("screenshots/%04d-%02d-%02d-%02d_%02d_%02d_%04d.png",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, random<int>(10000)));
SDL_FreeSurface(surface);
}
}
}
}
//
func game_loop() {
this->enable_turbo(8000);
while !this.quit {
var event SDL_Event;
while SDL_PollEvent(&event) {
if event.type == SDL_KEYDOWN {
this->on_keydown(&event.key);
this->enable_turbo(3000);
elseif event.type == SDL_QUIT;
return;
}
}
this->update();
if this.pending_scene == null {
this->draw();
this->present();
}
this->swap_scene();
this->dump();
if this.turbo < SDL_GetTicks() {
forvar standby uint32 = SDL_GetTicks() + 300 ;; {
if SDL_PollEvent(&event) {
if event.type == SDL_KEYDOWN {
this->on_keydown(&event.key);
this->enable_turbo(3000);
break;
elseif event.type == SDL_QUIT;
return;
}
}
if SDL_GetTicks() > standby;
break;
usleep(50000);
}
else
usleep(3000);
}
}
}
//
inline get_handle() void {
return this.wnd;
}
inline get_render() void {
return this.render;
}
inline get_scene() .scene {
return this.scene;
}
inline get_size(w. int, h. int) {
SDL_GetWindowSize(this.wnd, w, h);
}
//
func screen_capture_to_surface(rect. SDL_Rect) void {
var format uint32 = SDL_GetWindowPixelFormat(this.wnd);
var surface. SDL_Surface = SDL_CreateRGBSurfaceWithFormat(0, rect.w, rect.h, 24, format);
if surface == null;
return null;
if SDL_LockSurface(surface) {
SDL_FreeSurface(surface);
return null;
}
SDL_RenderReadPixels(this.render, rect, format, surface.pixels, surface.pitch);
SDL_UnlockSurface(surface);
return surface;
}
func screen_capture_to_surface2() void {
var rect SDL_Rect = 0;
this->get_size(&rect.w, &rect.h);
return this->screen_capture_to_surface(&rect);
}
func screen_capture(rect. SDL_Rect) void {
var surface void = this->screen_capture_to_surface(rect);
if surface == null;
return null;
func = SDL_CreateTextureFromSurface(this.render, surface);
SDL_FreeSurface(surface);
}
func screen_capture2() void {
var surface void = this->screen_capture_to_surface2();
if surface == null;
return null;
func = SDL_CreateTextureFromSurface(this.render, surface);
SDL_FreeSurface(surface);
}
}