jhhj
This commit is contained in:
Julia 2024-04-09 17:10:30 -05:00
parent c941f8b7fb
commit 879e8f2af2
12 changed files with 227 additions and 182 deletions

View file

@ -14,3 +14,16 @@ typedef uint_fast32_t u32f;
typedef uint64_t u64; typedef uint64_t u64;
typedef uint_fast64_t u64f; typedef uint_fast64_t u64f;
typedef int8_t i8;
typedef int_fast8_t i8f;
typedef int16_t i16;
typedef int_fast16_t i16f;
typedef int32_t i32;
typedef int_fast32_t i32f;
typedef int64_t i64;
typedef int_fast64_t i64f;

View file

@ -17,13 +17,19 @@ size_t delegate_size(size_t capacity)
return sizeof(void(*)(void *)) * capacity; return sizeof(void(*)(void *)) * capacity;
} }
struct Delegate NewDelegate(size_t capacity) bool NewDelegate(struct Delegate *d, size_t capacity)
{ {
return (struct Delegate) { void (**events)(void *args) = malloc(delegate_size(capacity));
if (events == nullptr)
return false;
*d = (struct Delegate) {
.len = 0, .len = 0,
.capacity = capacity, .capacity = capacity,
.events = malloc(delegate_size(capacity)) .events = malloc(delegate_size(capacity))
}; };
return true;
} }
void Subscribe(struct Delegate *d, void (*event)(void *args)) void Subscribe(struct Delegate *d, void (*event)(void *args))

View file

@ -13,7 +13,7 @@ struct Delegate {
void (**events)(void *args); void (**events)(void *args);
}; };
struct Delegate NewDelegate(size_t capacity); bool NewDelegate(struct Delegate *d, size_t capacity);
void Subscribe(struct Delegate *d, void (*event)(void *args)); void Subscribe(struct Delegate *d, void (*event)(void *args));

View file

@ -11,54 +11,48 @@
#define IO_BUF_SIZE 16 #define IO_BUF_SIZE 16
enum CtrlType { enum InputType {
KEY, KEY,
AXIS, AXIS,
JOYSTICK, JOYSTICK,
ESCAPE ESCAPE
}; };
struct Record { struct Button {
u16 id; u32 value;
bool is_down;
bool is_held;
bool is_up;
};
struct Axis {
i64 value;
};
struct Joystick {
i32 x;
i32 y;
};
struct InputRecord {
u16 bind;
u8 type; u8 type;
union { union {
struct { struct Button but;
bool is_down; struct Axis axis;
} key; struct Joystick js;
struct { };
u64 value;
} axis;
struct {
u32 x;
u32 y;
} joystick;
} data;
struct timespec timestamp; struct timespec timestamp;
}; };
struct RecordBuffer { struct InputAxis {
struct Record records[IO_BUF_SIZE];
size_t count;
pthread_mutex_t mutex;
};
struct Axis {
union { union {
struct { struct Button but;
u32 value; struct Axis axis;
u32 is_down : 1; struct Joystick js;
u32 is_up : 1; };
} key;
struct {
u64 value;
} axis;
struct {
u32 x;
u32 y;
} joystick;
} data;
struct timespec last_pressed; struct timespec last_pressed;
struct timespec last_released; struct timespec last_released;
@ -81,41 +75,44 @@ hashtype Hash(void *item, size_t size)
hashtype hash_id(u16f value, u8f type) hashtype hash_id(u16f value, u8f type)
{ {
struct id { struct { u16 id; u8 type; } id = { value, type };
u16 id; return Hash(&id, sizeof(id));
u8 type;
};
struct id id = { value, type };
return Hash(&id, sizeof(struct id));
} }
struct ctrl_dict {
size_t capacity;
size_t filled;
struct ctrl_bkt { struct ctrl_bkt {
hashtype hash; hashtype hash;
u16 value; u16 value;
u8 type; u8 type;
struct Axis *axis;
struct InputAxis *axis;
} *bkts;
}; };
struct ctrl_dict { struct Controller {
size_t capacity;
size_t filled;
struct ctrl_bkt *bkts;
};
struct Ctrl {
struct ctrl_dict codes; struct ctrl_dict codes;
struct ctrl_dict binds; struct ctrl_dict binds;
struct InputAxis *axes;
struct RecordBuffer buf; struct {
pthread_t thread; struct InputRecord records[IO_BUF_SIZE];
size_t len;
} input_buf;
struct {
size_t indexes[IO_BUF_SIZE];
size_t len;
} pending_state_buf;
}; };
bool NewCtrl(struct Ctrl *ctrl, size_t code_cap, size_t bind_cap) bool NewCtrl(struct Controller *ctrl, size_t code_cap, size_t bind_cap)
{ {
struct ctrl_bkt *code_bkts = calloc(code_cap, sizeof(struct ctrl_bkt)); struct ctrl_bkt *code_bkts = calloc(code_cap, sizeof(struct ctrl_bkt));
struct ctrl_bkt *bind_bkts = calloc(bind_cap, sizeof(struct ctrl_bkt)); struct ctrl_bkt *bind_bkts = calloc(bind_cap, sizeof(struct ctrl_bkt));
struct Axis *axes = calloc(code_cap, sizeof(struct Axis)); struct InputAxis *axes = calloc(code_cap, sizeof(struct InputAxis));
if (code_bkts == nullptr or bind_bkts == nullptr or axes == nullptr) if (code_bkts == nullptr or bind_bkts == nullptr or axes == nullptr)
return false; return false;
@ -124,7 +121,7 @@ bool NewCtrl(struct Ctrl *ctrl, size_t code_cap, size_t bind_cap)
code_bkts[i].axis = axes + i; code_bkts[i].axis = axes + i;
} }
*ctrl = (struct Ctrl) { *ctrl = (struct Controller) {
.codes = (struct ctrl_dict) { .codes = (struct ctrl_dict) {
.capacity = code_cap, .capacity = code_cap,
.filled = 0, .filled = 0,
@ -135,19 +132,23 @@ bool NewCtrl(struct Ctrl *ctrl, size_t code_cap, size_t bind_cap)
.filled = 0, .filled = 0,
.bkts = bind_bkts, .bkts = bind_bkts,
}, },
.axes = axes,
.buf = (struct RecordBuffer) { .input_buf = {
.count = 0, .len = 0,
.mutex = PTHREAD_MUTEX_INITIALIZER, },
.pending_state_buf = {
.len = 0,
}, },
}; };
return true; return true;
} }
void FreeCtrl(struct Ctrl *ctrl) void FreeCtrl(struct Controller *ctrl)
{ {
free(ctrl->codes.bkts); free(ctrl->codes.bkts);
free(ctrl->binds.bkts); free(ctrl->binds.bkts);
free(ctrl->axes);
} }
struct ctrl_bkt *get_bkt(struct ctrl_dict *dict, size_t i) struct ctrl_bkt *get_bkt(struct ctrl_dict *dict, size_t i)
@ -216,7 +217,7 @@ next:
return nullptr; return nullptr;
} }
struct Axis *find_axis(struct ctrl_dict *dict, u16f value, u8f type) struct InputAxis *find_axis(struct ctrl_dict *dict, u16f value, u8f type)
{ {
struct ctrl_bkt *bkt = find(dict, value, type); struct ctrl_bkt *bkt = find(dict, value, type);
if (bkt == nullptr) if (bkt == nullptr)
@ -225,7 +226,7 @@ struct Axis *find_axis(struct ctrl_dict *dict, u16f value, u8f type)
return bkt->axis; return bkt->axis;
} }
bool CtrlMap(struct Ctrl *ctrl, u16f code, u16f bind, u8f type) bool CtrlMap(struct Controller *ctrl, u16f code, u16f bind, u8f type)
{ {
if (ctrl->codes.filled >= ctrl->codes.capacity or ctrl->binds.filled >= ctrl->binds.capacity) { if (ctrl->codes.filled >= ctrl->codes.capacity or ctrl->binds.filled >= ctrl->binds.capacity) {
printf("fatal error"); printf("fatal error");
@ -245,7 +246,7 @@ bool CtrlMap(struct Ctrl *ctrl, u16f code, u16f bind, u8f type)
return true; return true;
} }
struct Axis *CtrlGet(struct Ctrl *ctrl, u16f code, u8f type) struct InputAxis *CtrlGet(struct Controller *ctrl, u16f code, u8f type)
{ {
struct ctrl_bkt *code_bkt = find(&ctrl->codes, code, type); struct ctrl_bkt *code_bkt = find(&ctrl->codes, code, type);
if (code_bkt == nullptr) if (code_bkt == nullptr)
@ -254,53 +255,69 @@ struct Axis *CtrlGet(struct Ctrl *ctrl, u16f code, u8f type)
return code_bkt->axis; return code_bkt->axis;
} }
void update_key(struct Axis *axis, struct Record *record) void update_key(struct InputAxis *axis, struct InputRecord *rec)
{ {
if (record->data.key.is_down) if (rec->but.is_down) {
axis->last_pressed = record->timestamp; axis->last_pressed = rec->timestamp;
else axis->but.is_held = true;
axis->last_released = record->timestamp; } else {
axis->last_released = rec->timestamp;
axis->data.key.is_down = record->data.key.is_down; axis->but.is_held = false;
} }
void update_axis(struct Axis *axis, struct Record *record) axis->but.is_down |= rec->but.is_down;
{ axis->but.is_up |= rec->but.is_up;
axis->data.axis.value = record->data.axis.value;
axis->last_pressed = record->timestamp;
} }
void update_joystick(struct Axis *axis, struct Record *record) void update_axis(struct InputAxis *axis, struct InputRecord *rec)
{ {
axis->data.joystick.x = record->data.joystick.x; axis->axis.value = rec->axis.value;
axis->data.joystick.y = record->data.joystick.y;
axis->last_pressed = record->timestamp; axis->last_pressed = rec->timestamp;
} }
bool CtrlPoll(struct Ctrl *ctrl) void update_joystick(struct InputAxis *axis, struct InputRecord *rec)
{ {
for (size_t i = 0; i < ctrl->buf.count; i++) { axis->js.x = rec->js.x;
struct Record *rec = &ctrl->buf.records[i]; axis->js.y = rec->js.y;
struct Axis *axis = find_axis(&ctrl->binds, rec->id, rec->type); axis->last_pressed = rec->timestamp;
if (axis == nullptr) }
continue;
bool dispatch_update(struct InputAxis *axis, struct InputRecord *rec)
{
switch (rec->type) { switch (rec->type) {
case KEY: case KEY:
update_key(axis, rec); update_key(axis, rec);
break; printf("axis:%hu\n", axis->but.is_down);
return true;
case AXIS: case AXIS:
update_axis(axis, rec); update_axis(axis, rec);
break; return true;
case JOYSTICK: case JOYSTICK:
update_joystick(axis, rec); update_joystick(axis, rec);
break; return true;
default: }
return false;
} return false;
} }
ctrl->buf.count = 0; bool CtrlPoll(struct Controller *ctrl)
{
for (size_t i = 0; i < ctrl->input_buf.len; i++) {
struct InputRecord *rec = &ctrl->input_buf.records[i];
printf("i:%hu\n", rec->bind);
struct InputAxis *axis = find_axis(&ctrl->binds, rec->bind, rec->type);
if (axis == nullptr)
continue;
if (!dispatch_update(axis, rec))
return false;
}
ctrl->input_buf.len = 0;
return true; return true;
} }

View file

@ -12,21 +12,22 @@
#define IO_BUF_SIZE 16 #define IO_BUF_SIZE 16
enum CtrlType { enum InputType {
KEY, KEY,
AXIS, AXIS,
JOYSTICK, JOYSTICK,
ESCAPE ESCAPE
}; };
struct Record { struct InputRecord {
u16 id; u16 bind;
u8 type; u8 type;
union { union {
struct { struct {
bool is_down; bool is_down;
} key; bool is_up;
} button;
struct { struct {
u64 value; u64 value;
} axis; } axis;
@ -34,24 +35,25 @@ struct Record {
u32 x; u32 x;
u32 y; u32 y;
} joystick; } joystick;
} data; };
struct timespec timestamp; struct timespec timestamp;
}; };
struct RecordBuffer { struct RecordBuffer {
struct Record records[IO_BUF_SIZE]; struct InputRecord records[IO_BUF_SIZE];
size_t count; size_t count;
pthread_mutex_t mutex; pthread_mutex_t mutex;
}; };
struct Axis { struct InputAxis {
union { union {
struct { struct {
u32 value; u32 value;
u32 is_down : 1; bool is_down;
u32 is_up : 1; bool is_held;
} key; bool is_up;
} button;
struct { struct {
u64 value; u64 value;
} axis; } axis;
@ -59,7 +61,7 @@ struct Axis {
u32 x; u32 x;
u32 y; u32 y;
} joystick; } joystick;
} data; };
struct timespec last_pressed; struct timespec last_pressed;
struct timespec last_released; struct timespec last_released;
@ -86,7 +88,7 @@ struct ctrl_bkt {
hashtype hash; hashtype hash;
u16 value; u16 value;
u8 type; u8 type;
struct Axis *axis; struct InputAxis *axis;
}; };
struct ctrl_dict { struct ctrl_dict {
@ -95,20 +97,21 @@ struct ctrl_dict {
struct ctrl_bkt *bkts; struct ctrl_bkt *bkts;
}; };
struct Ctrl { struct Controller {
struct ctrl_dict codes; struct ctrl_dict codes;
struct ctrl_dict binds; struct ctrl_dict binds;
struct InputAxis *axes;
struct RecordBuffer buf; struct RecordBuffer buf;
pthread_t thread; pthread_t thread;
}; };
bool NewCtrl(struct Ctrl *ctrl, size_t code_cap, size_t bind_cap); bool NewCtrl(struct Controller *ctrl, size_t code_cap, size_t bind_cap);
void FreeCtrl(struct Ctrl *ctrl); void FreeCtrl(struct Controller *ctrl);
bool CtrlMap(struct Ctrl *ctrl, u16f code, u16f bind, u8f type); bool CtrlMap(struct Controller *ctrl, u16f code, u16f bind, u8f type);
struct Axis *CtrlGet(struct Ctrl *ctrl, u16f code, u8f type); struct InputAxis *CtrlGet(struct Controller *ctrl, u16f code, u8f type);
bool CtrlPoll(struct Ctrl *ctrl); bool CtrlPoll(struct Controller *ctrl);

View file

@ -32,12 +32,12 @@ void *block_input(void *args_ptr)
return nullptr; return nullptr;
} }
void StartInput(struct Ctrl *ctrl) void StartInput(struct Controller *ctrl)
{ {
pthread_create(&ctrl->thread, nullptr, block_input, &ctrl->buf); pthread_create(&ctrl->thread, nullptr, block_input, &ctrl->buf);
} }
void JoinInput(struct Ctrl *ctrl) void JoinInput(struct Controller *ctrl)
{ {
pthread_join(ctrl->thread, nullptr); pthread_join(ctrl->thread, nullptr);
} }

View file

@ -8,6 +8,6 @@
#include "ctrl.h" #include "ctrl.h"
#include "fumotris.h" #include "fumotris.h"
void StartInput(struct Ctrl *ctrl); void StartInput(struct Controller *ctrl);
void JoinInput(struct Ctrl *ctrl); void JoinInput(struct Controller *ctrl);

View file

@ -10,22 +10,17 @@
#include "winhandler.h" #include "winhandler.h"
#include "term.h" #include "term.h"
#include <windows.h>
bool WindowsInit(struct Terminal *term) bool WindowsInit(struct Terminal *term)
{ {
if (!WinInitHandles()) if (!WinInitHandles())
return false; return false;
printf("shid ");
if (!WinInitConsole()) { if (!WinInitConsole())
printf("%u\n", GetLastError());
return false; return false;
}
printf("console");
if (!WinGetRefreshRate(&term->refresh_rate)) if (!WinGetRefreshRate(&term->refresh_rate))
return false; return false;
printf("???");
return true; return true;
} }

View file

@ -39,9 +39,9 @@ bool WinInitConsole()
{ {
DWORD mode = ENABLE_EXTENDED_FLAGS DWORD mode = ENABLE_EXTENDED_FLAGS
| ENABLE_PROCESSED_INPUT | ENABLE_PROCESSED_INPUT
| ENABLE_PROCESSED_OUTPUT
| ENABLE_MOUSE_INPUT | ENABLE_MOUSE_INPUT
| ENABLE_WINDOW_INPUT | ENABLE_WINDOW_INPUT;
| ENABLE_VIRTUAL_TERMINAL_PROCESSING;
return SetConsoleMode(win.input_handle, mode) != 0; return SetConsoleMode(win.input_handle, mode) != 0;
} }
@ -62,34 +62,36 @@ bool WinGetRefreshRate(u16f *out)
return true; return true;
} }
void set_key_record(struct Record *record, KEY_EVENT_RECORD win_key) void set_key_record(struct InputRecord *rec, KEY_EVENT_RECORD win_key)
{ {
record->type = KEY; rec->type = KEY;
record->id = win_key.wVirtualKeyCode; rec->bind = win_key.wVirtualKeyCode;
record->data.key.is_down = win_key.bKeyDown;
rec->button.is_down = win_key.bKeyDown;
rec->button.is_up = !win_key.bKeyDown;
if (win_key.wVirtualKeyCode == VK_ESCAPE) if (win_key.wVirtualKeyCode == VK_ESCAPE)
record->type = ESCAPE; rec->type = ESCAPE;
} }
bool set_mouse_record(struct Record *record, MOUSE_EVENT_RECORD win_mouse) bool set_mouse_record(struct InputRecord *rec, MOUSE_EVENT_RECORD win_mouse)
{ {
switch (win_mouse.dwEventFlags) { switch (win_mouse.dwEventFlags) {
case MOUSE_WHEELED: case MOUSE_WHEELED:
record->type = AXIS; rec->type = AXIS;
record->id = 0; rec->bind = 0;
record->data.axis.value = win_mouse.dwButtonState; rec->axis.value = win_mouse.dwButtonState;
break; break;
case MOUSE_HWHEELED: case MOUSE_HWHEELED:
record->type = AXIS; rec->type = AXIS;
record->id = 1; rec->bind = 1;
record->data.axis.value = win_mouse.dwButtonState; rec->axis.value = win_mouse.dwButtonState;
break; break;
case MOUSE_MOVED: case MOUSE_MOVED:
record->type = JOYSTICK; rec->type = JOYSTICK;
record->id = 0; rec->bind = 0;
record->data.joystick.x = win_mouse.dwMousePosition.X; rec->joystick.x = win_mouse.dwMousePosition.X;
record->data.joystick.y = win_mouse.dwMousePosition.Y; rec->joystick.y = win_mouse.dwMousePosition.Y;
break; break;
default: default:
return false; return false;
@ -97,19 +99,19 @@ bool set_mouse_record(struct Record *record, MOUSE_EVENT_RECORD win_mouse)
return true; return true;
} }
bool dispatch_record(struct Record *record, INPUT_RECORD win_record) bool dispatch_record(struct InputRecord *rec, INPUT_RECORD win_rec)
{ {
switch (win_record.EventType) { switch (win_rec.EventType) {
case KEY_EVENT: case KEY_EVENT:
set_key_record(record, win_record.Event.KeyEvent); set_key_record(rec, win_rec.Event.KeyEvent);
break; break;
case MOUSE_EVENT: case MOUSE_EVENT:
return set_mouse_record(record, win_record.Event.MouseEvent); return set_mouse_record(rec, win_rec.Event.MouseEvent);
case WINDOW_BUFFER_SIZE_EVENT: case WINDOW_BUFFER_SIZE_EVENT:
// TODO: Handle window resizing // TODO: Handle window resizing
return false; return false;
default: default:
record->type = ESCAPE; rec->type = ESCAPE;
} }
return true; return true;
} }
@ -134,14 +136,14 @@ bool WinBlockInput(struct RecordBuffer *buf)
pthread_mutex_lock(&buf->mutex); pthread_mutex_lock(&buf->mutex);
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
struct Record record; struct InputRecord rec;
record.timestamp = now; rec.timestamp = now;
bool include = dispatch_record(&record, win_buf[i]); bool include = dispatch_record(&rec, win_buf[i]);
if (!include) if (!include)
continue; continue;
buf->records[buf->count++] = record; buf->records[buf->count++] = rec;
} }
pthread_mutex_unlock(&buf->mutex); pthread_mutex_unlock(&buf->mutex);

View file

@ -16,6 +16,15 @@
#include "win.h" #include "win.h"
#endif #endif
struct Instance {
struct Controller ctrl;
struct Terminal term;
struct Delegate on_start;
struct Delegate on_update;
struct Delegate on_draw;
};
const u8 I[16] = { const u8 I[16] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@ -58,16 +67,6 @@ const u8 L[9] = {
0, 0, 0 0, 0, 0
}; };
struct Instance {
struct Ctrl ctrl;
struct Delegate on_start;
struct Delegate on_update;
struct Delegate on_draw;
struct Terminal term;
};
struct CtrlBind { struct CtrlBind {
enum CtrlCode code; enum CtrlCode code;
u16 bind; u16 bind;
@ -94,19 +93,18 @@ void *Update(void *args)
{ {
struct Instance *game = args; struct Instance *game = args;
struct TChar4 blks[game->term.area];
game->term.blks = blks;
while (true) { while (true) {
// Input // Input
CtrlPoll(&game->ctrl); CtrlPoll(&game->ctrl);
if (CtrlGet(&game->ctrl, LEFT, KEY)->button.is_down)
printf("left down this frame\n");
// Game logic // Game logic
Invoke(&game->on_update, game); //Invoke(&game->on_update, game);
// Draw // Draw
TermOut(&game->term); //TermOut(&game->term);
puts(game->term.buf); //puts(game->term.buf);
} }
} }
@ -129,21 +127,26 @@ bool Start(struct Instance *game)
if (!NewTerm(&game->term, 20, 20)) if (!NewTerm(&game->term, 20, 20))
return false; return false;
if (!NewDelegate(&game->on_start, 16))
return false;
if (!NewDelegate(&game->on_update, 16))
return false;
if (!NewDelegate(&game->on_draw, 16))
return false;
return true; return true;
} }
int main() int main()
{ {
struct Instance game; struct Instance game;
Start(&game); if (!Start(&game))
exit(1);
#ifdef _WIN32 #ifdef _WIN32
if(!WindowsInit(&game.term)) { if(!WindowsInit(&game.term))
printf("FUCK");
exit(1); exit(1);
}
#endif #endif
printf("does it work");
StartInput(&game.ctrl); StartInput(&game.ctrl);
Loop(&game); Loop(&game);

View file

@ -35,9 +35,14 @@ size_t term_buf_size(size_t area, size_t hgt)
return reset_str_len + (max_color_str_len + 1) * area + hgt + 1; return reset_str_len + (max_color_str_len + 1) * area + hgt + 1;
} }
size_t blks_size(size_t area) struct TChar4 *alloc_blks(size_t area)
{ {
return area * sizeof(struct TChar4); return calloc(area, sizeof(struct TChar4));
}
char *alloc_buf(size_t buf_size)
{
return malloc(buf_size);
} }
bool NewTerm(struct Terminal *term, size_t wid, size_t hgt) bool NewTerm(struct Terminal *term, size_t wid, size_t hgt)
@ -45,17 +50,17 @@ bool NewTerm(struct Terminal *term, size_t wid, size_t hgt)
size_t area = wid * hgt; size_t area = wid * hgt;
size_t buf_size = term_buf_size(area, hgt); size_t buf_size = term_buf_size(area, hgt);
struct TChar4 *tchs = malloc(blks_size(area)); struct TChar4 *blks = alloc_blks(area);
char *buf = malloc(buf_size); char *buf = alloc_buf(buf_size);
if (tchs == nullptr or buf == nullptr) if (blks == nullptr or buf == nullptr)
return false; return false;
*term = (struct Terminal) { *term = (struct Terminal) {
.wid = wid, .wid = wid,
.hgt = hgt, .hgt = hgt,
.area = area, .area = area,
.blks = tchs, .blks = blks,
.buf_size = buf_size, .buf_size = buf_size,
.buf = buf, .buf = buf,
@ -70,8 +75,9 @@ bool ResizeTerm(struct Terminal *term, size_t wid, size_t hgt)
size_t area = wid * hgt; size_t area = wid * hgt;
size_t buf_size = term_buf_size(area, hgt); size_t buf_size = term_buf_size(area, hgt);
struct TChar4 *tchs = realloc(term->blks, blks_size(area)); struct TChar4 *tchs = realloc(term->blks, area * sizeof(struct TChar4));
char *buf = realloc(term->buf, buf_size); char *buf = realloc(term->buf, buf_size);
if (tchs == nullptr or buf == nullptr) if (tchs == nullptr or buf == nullptr)
return false; return false;

BIN
test.exe

Binary file not shown.