mirror of
https://github.com/clockworkpi/Menu.git
synced 2026-03-22 03:42:38 +01:00
gcores ~/apps/Menu branch first commit
This commit is contained in:
@@ -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; }
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user