Merge branch 'master' of github.com:zpl-c/eco2d

isolation_bkp/dynres
Vladyslav Hrytsenko 2021-11-01 21:34:42 +02:00
commit a7c060660e
27 changed files with 3382 additions and 3352 deletions

View File

@ -1,39 +1,39 @@
#pragma once #pragma once
#include "system.h" #include "system.h"
#define ASSET_INVALID 0xFF #define ASSET_INVALID 0xFF
typedef enum { typedef enum {
// NOTE(zaklaus): Debug // NOTE(zaklaus): Debug
ASSET_DEBUG_TILE, ASSET_DEBUG_TILE,
// NOTE(zaklaus): entities // NOTE(zaklaus): entities
ASSET_PLAYER, ASSET_PLAYER,
ASSET_THING, ASSET_THING,
// NOTE(zaklaus): items // NOTE(zaklaus): items
ASSET_DEMO_ICEMAKER, ASSET_DEMO_ICEMAKER,
MAX_ASSETS, MAX_ASSETS,
FORCE_ASSET_UINT16 = UINT16_MAX FORCE_ASSET_UINT16 = UINT16_MAX
} asset_id; } asset_id;
typedef enum { typedef enum {
AKIND_TEXTURE, AKIND_TEXTURE,
AKIND_SOUND, AKIND_SOUND,
FORCE_AKIND_UINT8 = UINT8_MAX FORCE_AKIND_UINT8 = UINT8_MAX
} asset_kind; } asset_kind;
int32_t assets_setup(void); int32_t assets_setup(void);
void assets_destroy(void); void assets_destroy(void);
uint16_t assets_find(asset_id id); uint16_t assets_find(asset_id id);
asset_kind assets_get_kind(uint16_t id); asset_kind assets_get_kind(uint16_t id);
void *assets_get_snd(uint16_t id); void *assets_get_snd(uint16_t id);
void *assets_get_tex(uint16_t id); void *assets_get_tex(uint16_t id);
// NOTE(zaklaus): client only // NOTE(zaklaus): client only
#define ASSET_SRC_RECT() ((Rectangle){0, 0, 64, 64}) #define ASSET_SRC_RECT() ((Rectangle){0, 0, 64, 64})
#define ASSET_DST_RECT(x,y) ((Rectangle){x, y, 64, 64}) #define ASSET_DST_RECT(x,y) ((Rectangle){x, y, 64, 64})

View File

@ -1,12 +1,12 @@
#include "assets.h" #include "assets.h"
static asset assets[] = { static asset assets[] = {
{ {
.id = ASSET_DEBUG_TILE, .id = ASSET_DEBUG_TILE,
.kind = AKIND_TEXTURE, .kind = AKIND_TEXTURE,
}, },
{ {
.id = ASSET_DEMO_ICEMAKER, .id = ASSET_DEMO_ICEMAKER,
.kind = AKIND_TEXTURE, .kind = AKIND_TEXTURE,
} }
}; };

View File

@ -1,52 +1,52 @@
#include "zpl.h" #include "zpl.h"
#include "camera.h" #include "camera.h"
#include "platform.h" #include "platform.h"
#include "entity_view.h" #include "entity_view.h"
#include "game.h" #include "game.h"
#define CAMERA_LERP_FACTOR 11.2f #define CAMERA_LERP_FACTOR 11.2f
static camera main_camera; static camera main_camera;
void camera_reset(void) { void camera_reset(void) {
zpl_zero_item(&main_camera); zpl_zero_item(&main_camera);
main_camera.mode = CAMERA_MODE_STATIONARY; main_camera.mode = CAMERA_MODE_STATIONARY;
main_camera.first_time = true; main_camera.first_time = true;
} }
void camera_update(void) { void camera_update(void) {
switch (main_camera.mode) { switch (main_camera.mode) {
case CAMERA_MODE_FOLLOW: { case CAMERA_MODE_FOLLOW: {
world_view *world = game_world_view_get_active(); world_view *world = game_world_view_get_active();
if (!world) break; if (!world) break;
entity_view *view = entity_view_get(&world->entities, main_camera.ent_id); entity_view *view = entity_view_get(&world->entities, main_camera.ent_id);
if (!view) break; if (!view) break;
float smooth_ms = zpl_clamp((float)platform_frametime(), 0.0f, 1.0f); float smooth_ms = zpl_clamp((float)platform_frametime(), 0.0f, 1.0f);
main_camera.x = zpl_lerp(main_camera.x, view->x, CAMERA_LERP_FACTOR*smooth_ms); main_camera.x = zpl_lerp(main_camera.x, view->x, CAMERA_LERP_FACTOR*smooth_ms);
main_camera.y = zpl_lerp(main_camera.y, view->y, CAMERA_LERP_FACTOR*smooth_ms); main_camera.y = zpl_lerp(main_camera.y, view->y, CAMERA_LERP_FACTOR*smooth_ms);
if (main_camera.first_time) { if (main_camera.first_time) {
main_camera.first_time = false; main_camera.first_time = false;
main_camera.x = view->x; main_camera.x = view->x;
main_camera.y = view->y; main_camera.y = view->y;
} }
}break; }break;
default: { default: {
}break; }break;
} }
} }
void camera_set_follow(uint64_t ent_id) { void camera_set_follow(uint64_t ent_id) {
main_camera.mode = CAMERA_MODE_FOLLOW; main_camera.mode = CAMERA_MODE_FOLLOW;
main_camera.ent_id = ent_id; main_camera.ent_id = ent_id;
} }
void camera_set_pos(double x, double y) { void camera_set_pos(double x, double y) {
main_camera.mode = CAMERA_MODE_STATIONARY; main_camera.mode = CAMERA_MODE_STATIONARY;
main_camera.x = x; main_camera.x = x;
main_camera.y = y; main_camera.y = y;
} }
camera camera_get(void) { camera camera_get(void) {
return main_camera; return main_camera;
} }

View File

@ -1,409 +1,409 @@
#include "debug_ui.h" #include "debug_ui.h"
#include "debug_draw.h" #include "debug_draw.h"
#include "raylib.h" #include "raylib.h"
#include "vehicle.h" #include "vehicle.h"
#include "camera.h" #include "camera.h"
#include "world/world.h" #include "world/world.h"
#include "game.h" #include "game.h"
#include "sfd.h" #include "sfd.h"
#include "modules/components.h" #include "modules/components.h"
typedef enum { typedef enum {
DITEM_RAW, DITEM_RAW,
DITEM_GAP, DITEM_GAP,
DITEM_TEXT, DITEM_TEXT,
DITEM_BUTTON, DITEM_BUTTON,
DITEM_SLIDER, DITEM_SLIDER,
DITEM_LIST, DITEM_LIST,
DITEM_COND, DITEM_COND,
DITEM_END, DITEM_END,
DITEM_FORCE_UINT8 = UINT8_MAX DITEM_FORCE_UINT8 = UINT8_MAX
} debug_kind; } debug_kind;
typedef struct { typedef struct {
float x, y; float x, y;
} debug_draw_result; } debug_draw_result;
#define DBG_FONT_SIZE 22 #define DBG_FONT_SIZE 22
#define DBG_FONT_SPACING DBG_FONT_SIZE * 1.2f #define DBG_FONT_SPACING DBG_FONT_SIZE * 1.2f
#define DBG_START_XPOS 15 #define DBG_START_XPOS 15
#define DBG_START_YPOS 200 #define DBG_START_YPOS 200
#define DBG_LIST_XPOS_OFFSET 10 #define DBG_LIST_XPOS_OFFSET 10
#define DBG_SHADOW_OFFSET_XPOS 1 #define DBG_SHADOW_OFFSET_XPOS 1
#define DBG_SHADOW_OFFSET_YPOS 1 #define DBG_SHADOW_OFFSET_YPOS 1
#define DBG_CTRL_HANDLE_DIM 10 #define DBG_CTRL_HANDLE_DIM 10
#define DBG_GAP_HEIGHT DBG_FONT_SPACING * 0.5f #define DBG_GAP_HEIGHT DBG_FONT_SPACING * 0.5f
static uint8_t is_shadow_rendered; static uint8_t is_shadow_rendered;
static uint8_t is_debug_open = 1; static uint8_t is_debug_open = 1;
static uint8_t is_handle_ctrl_held; static uint8_t is_handle_ctrl_held;
static float debug_xpos = DBG_START_XPOS; static float debug_xpos = DBG_START_XPOS;
static float debug_ypos = DBG_START_YPOS; static float debug_ypos = DBG_START_YPOS;
typedef struct debug_item { typedef struct debug_item {
debug_kind kind; debug_kind kind;
char const *name; char const *name;
float name_width; float name_width;
uint8_t skip; uint8_t skip;
union { union {
union { union {
char const *text; char const *text;
uint64_t val; uint64_t val;
}; };
struct { struct {
struct debug_item *items; struct debug_item *items;
uint8_t is_collapsed; uint8_t is_collapsed;
uint8_t is_sp_only; uint8_t is_sp_only;
} list; } list;
struct { struct {
float val, min, max; float val, min, max;
void (*on_change)(float); void (*on_change)(float);
} slider; } slider;
void (*on_click)(void); void (*on_click)(void);
uint8_t (*on_success)(void); uint8_t (*on_success)(void);
}; };
debug_draw_result (*proc)(struct debug_item*, float, float); debug_draw_result (*proc)(struct debug_item*, float, float);
} debug_item; } debug_item;
static void UIDrawText(const char *text, float posX, float posY, int fontSize, Color color); static void UIDrawText(const char *text, float posX, float posY, int fontSize, Color color);
static int UIMeasureText(const char *text, int fontSize); static int UIMeasureText(const char *text, int fontSize);
#include "debug_replay.c" #include "debug_replay.c"
#include "debug_ui_actions.c" #include "debug_ui_actions.c"
#include "debug_ui_widgets.c" #include "debug_ui_widgets.c"
static debug_item items[] = { static debug_item items[] = {
{ {
.kind = DITEM_LIST, .kind = DITEM_LIST,
.name = "general", .name = "general",
.list = { .list = {
.items = (debug_item[]) { .items = (debug_item[]) {
{ .kind = DITEM_TEXT, .name = "delta time", .proc = DrawDeltaTime }, { .kind = DITEM_TEXT, .name = "delta time", .proc = DrawDeltaTime },
{ .kind = DITEM_TEXT, .name = "pos", .proc = DrawCameraPos }, { .kind = DITEM_TEXT, .name = "pos", .proc = DrawCameraPos },
{ .kind = DITEM_TEXT, .name = "zoom", .proc = DrawZoom }, { .kind = DITEM_TEXT, .name = "zoom", .proc = DrawZoom },
{ .kind = DITEM_END }, { .kind = DITEM_END },
} }
} }
}, },
{ {
.kind = DITEM_LIST, .kind = DITEM_LIST,
.name = "world simulation", .name = "world simulation",
.list = { .list = {
.items = (debug_item[]) { .items = (debug_item[]) {
{ .kind = DITEM_COND, .on_success = CondIsWorldRunning }, { .kind = DITEM_COND, .on_success = CondIsWorldRunning },
{ .kind = DITEM_BUTTON, .name = "pause", .on_click = ActWorldToggleSim }, { .kind = DITEM_BUTTON, .name = "pause", .on_click = ActWorldToggleSim },
{ .kind = DITEM_COND, .on_success = CondIsWorldPaused, .skip = 6 }, { .kind = DITEM_COND, .on_success = CondIsWorldPaused, .skip = 6 },
{ .kind = DITEM_BUTTON, .name = "resume", .on_click = ActWorldToggleSim }, { .kind = DITEM_BUTTON, .name = "resume", .on_click = ActWorldToggleSim },
{ .kind = DITEM_GAP }, { .kind = DITEM_GAP },
{ .kind = DITEM_TEXT, .name = "step size", .proc = DrawWorldStepSize }, { .kind = DITEM_TEXT, .name = "step size", .proc = DrawWorldStepSize },
{ .kind = DITEM_BUTTON, .name = "single-step", .on_click = ActWorldStep }, { .kind = DITEM_BUTTON, .name = "single-step", .on_click = ActWorldStep },
{ .kind = DITEM_BUTTON, .name = "increment step size", .on_click = ActWorldIncrementSimStepSize }, { .kind = DITEM_BUTTON, .name = "increment step size", .on_click = ActWorldIncrementSimStepSize },
{ .kind = DITEM_BUTTON, .name = "decrement step size", .on_click = ActWorldDecrementSimStepSize }, { .kind = DITEM_BUTTON, .name = "decrement step size", .on_click = ActWorldDecrementSimStepSize },
{ .kind = DITEM_END }, { .kind = DITEM_END },
}, },
.is_sp_only = true, .is_sp_only = true,
} }
}, },
{ {
.kind = DITEM_LIST, .kind = DITEM_LIST,
.name = "debug actions", .name = "debug actions",
.list = { .list = {
.items = (debug_item[]) { .items = (debug_item[]) {
{ .kind = DITEM_BUTTON, .name = "spawn car", .on_click = ActSpawnCar }, { .kind = DITEM_BUTTON, .name = "spawn car", .on_click = ActSpawnCar },
{ .kind = DITEM_BUTTON, .name = "place ice rink", .on_click = ActPlaceIceRink }, { .kind = DITEM_BUTTON, .name = "place ice rink", .on_click = ActPlaceIceRink },
{ .kind = DITEM_BUTTON, .name = "erase world changes", .on_click = ActEraseWorldChanges }, { .kind = DITEM_BUTTON, .name = "erase world changes", .on_click = ActEraseWorldChanges },
{ .kind = DITEM_BUTTON, .name = "spawn circling driver", .on_click = ActSpawnCirclingDriver }, { .kind = DITEM_BUTTON, .name = "spawn circling driver", .on_click = ActSpawnCirclingDriver },
{ .kind = DITEM_BUTTON, .name = "spawn icemaker item", .on_click = ActSpawnIcemaker }, { .kind = DITEM_BUTTON, .name = "spawn icemaker item", .on_click = ActSpawnIcemaker },
{ {
.kind = DITEM_LIST, .kind = DITEM_LIST,
.name = "demo npcs", .name = "demo npcs",
.list = { .list = {
.items = (debug_item[]) { .items = (debug_item[]) {
{ .kind = DITEM_TEXT, .name = "npcs", .proc = DrawDemoNPCCount }, { .kind = DITEM_TEXT, .name = "npcs", .proc = DrawDemoNPCCount },
{ .kind = DITEM_BUTTON, .name = "spawn 1000 npcs", .on_click = ActSpawnDemoNPCs }, { .kind = DITEM_BUTTON, .name = "spawn 1000 npcs", .on_click = ActSpawnDemoNPCs },
{ .kind = DITEM_BUTTON, .name = "remove all demo npcs", .on_click = ActDespawnDemoNPCs }, { .kind = DITEM_BUTTON, .name = "remove all demo npcs", .on_click = ActDespawnDemoNPCs },
{ .kind = DITEM_END }, { .kind = DITEM_END },
}, },
.is_collapsed = true .is_collapsed = true
} }
}, },
{ .kind = DITEM_END }, { .kind = DITEM_END },
}, },
.is_sp_only = true, .is_sp_only = true,
} }
}, },
{ {
.kind = DITEM_LIST, .kind = DITEM_LIST,
.name = "replay system", .name = "replay system",
.list = { .list = {
.items = (debug_item[]) { .items = (debug_item[]) {
{ .kind = DITEM_TEXT, .name = "macro", .proc = DrawReplayFileName }, { .kind = DITEM_TEXT, .name = "macro", .proc = DrawReplayFileName },
{ .kind = DITEM_TEXT, .name = "samples", .proc = DrawReplaySamples }, { .kind = DITEM_TEXT, .name = "samples", .proc = DrawReplaySamples },
{ .kind = DITEM_COND, .on_success = CondReplayDataPresentAndNotPlaying }, { .kind = DITEM_COND, .on_success = CondReplayDataPresentAndNotPlaying },
{ .kind = DITEM_BUTTON, .name = "replay", .on_click = ActReplayRun }, { .kind = DITEM_BUTTON, .name = "replay", .on_click = ActReplayRun },
{ .kind = DITEM_COND, .on_success = CondReplayStatusOff }, { .kind = DITEM_COND, .on_success = CondReplayStatusOff },
{ .kind = DITEM_BUTTON, .name = "record", .on_click = ActReplayBegin }, { .kind = DITEM_BUTTON, .name = "record", .on_click = ActReplayBegin },
{ .kind = DITEM_COND, .on_success = CondReplayStatusOn }, { .kind = DITEM_COND, .on_success = CondReplayStatusOn },
{ .kind = DITEM_BUTTON, .name = "stop", .on_click = ActReplayEnd }, { .kind = DITEM_BUTTON, .name = "stop", .on_click = ActReplayEnd },
{ .kind = DITEM_COND, .on_success = CondReplayIsPlaying }, { .kind = DITEM_COND, .on_success = CondReplayIsPlaying },
{ .kind = DITEM_BUTTON, .name = "stop", .on_click = ActReplayEnd }, { .kind = DITEM_BUTTON, .name = "stop", .on_click = ActReplayEnd },
{ .kind = DITEM_COND, .on_success = CondReplayIsNotPlayingOrRecordsNotClear }, { .kind = DITEM_COND, .on_success = CondReplayIsNotPlayingOrRecordsNotClear },
{ .kind = DITEM_BUTTON, .name = "clear", .on_click = ActReplayClear }, { .kind = DITEM_BUTTON, .name = "clear", .on_click = ActReplayClear },
{ .kind = DITEM_GAP }, { .kind = DITEM_GAP },
{ .kind = DITEM_COND, .on_success = CondReplayIsNotPlaying, .skip = 4 }, { .kind = DITEM_COND, .on_success = CondReplayIsNotPlaying, .skip = 4 },
{ .kind = DITEM_BUTTON, .name = "new", .on_click = ActReplayNew }, { .kind = DITEM_BUTTON, .name = "new", .on_click = ActReplayNew },
{ .kind = DITEM_BUTTON, .name = "load", .on_click = ActReplayLoad }, { .kind = DITEM_BUTTON, .name = "load", .on_click = ActReplayLoad },
{ .kind = DITEM_BUTTON, .name = "save", .on_click = ActReplaySave }, { .kind = DITEM_BUTTON, .name = "save", .on_click = ActReplaySave },
{ .kind = DITEM_BUTTON, .name = "save as...", .on_click = ActReplaySaveAs }, { .kind = DITEM_BUTTON, .name = "save as...", .on_click = ActReplaySaveAs },
{ .kind = DITEM_END }, { .kind = DITEM_END },
}, },
.is_sp_only = true, .is_sp_only = true,
.is_collapsed = true, .is_collapsed = true,
} }
}, },
{ {
.kind = DITEM_LIST, .kind = DITEM_LIST,
.name = "profilers", .name = "profilers",
.list = { .list = {
.items = (debug_item[]) { .items = (debug_item[]) {
{ .kind = DITEM_RAW, .val = PROF_MAIN_LOOP, .proc = DrawProfilerDelta }, { .kind = DITEM_RAW, .val = PROF_MAIN_LOOP, .proc = DrawProfilerDelta },
{ .kind = DITEM_TEXT, .name = "unmeasured time", .proc = DrawUnmeasuredTime }, { .kind = DITEM_TEXT, .name = "unmeasured time", .proc = DrawUnmeasuredTime },
{ .kind = DITEM_RAW, .val = PROF_WORLD_WRITE, .proc = DrawProfilerDelta }, { .kind = DITEM_RAW, .val = PROF_WORLD_WRITE, .proc = DrawProfilerDelta },
{ .kind = DITEM_RAW, .val = PROF_RENDER, .proc = DrawProfilerDelta }, { .kind = DITEM_RAW, .val = PROF_RENDER, .proc = DrawProfilerDelta },
{ .kind = DITEM_RAW, .val = PROF_UPDATE_SYSTEMS, .proc = DrawProfilerDelta }, { .kind = DITEM_RAW, .val = PROF_UPDATE_SYSTEMS, .proc = DrawProfilerDelta },
{ .kind = DITEM_RAW, .val = PROF_ENTITY_LERP, .proc = DrawProfilerDelta }, { .kind = DITEM_RAW, .val = PROF_ENTITY_LERP, .proc = DrawProfilerDelta },
{ .kind = DITEM_RAW, .val = PROF_INTEGRATE_POS, .proc = DrawProfilerDelta }, { .kind = DITEM_RAW, .val = PROF_INTEGRATE_POS, .proc = DrawProfilerDelta },
{ .kind = DITEM_END }, { .kind = DITEM_END },
}, },
.is_collapsed = 1 .is_collapsed = 1
} }
}, },
{ {
.kind = DITEM_BUTTON, .kind = DITEM_BUTTON,
.name = "exit game", .name = "exit game",
.on_click = ActExitGame, .on_click = ActExitGame,
}, },
{.kind = DITEM_END}, {.kind = DITEM_END},
}; };
debug_draw_result debug_draw_list(debug_item *list, float xpos, float ypos, bool is_shadow) { debug_draw_result debug_draw_list(debug_item *list, float xpos, float ypos, bool is_shadow) {
is_shadow_rendered = is_shadow; is_shadow_rendered = is_shadow;
for (debug_item *it = list; it->kind != DITEM_END; it += 1) { for (debug_item *it = list; it->kind != DITEM_END; it += 1) {
switch (it->kind) { switch (it->kind) {
case DITEM_GAP: { case DITEM_GAP: {
ypos += DBG_GAP_HEIGHT; ypos += DBG_GAP_HEIGHT;
}break; }break;
case DITEM_COND: { case DITEM_COND: {
ZPL_ASSERT(it->on_success); ZPL_ASSERT(it->on_success);
if (!it->on_success()) { if (!it->on_success()) {
it += it->skip ? it->skip : 1; it += it->skip ? it->skip : 1;
} }
}break; }break;
case DITEM_LIST: { case DITEM_LIST: {
// NOTE(zaklaus): calculate and cache name width for future use // NOTE(zaklaus): calculate and cache name width for future use
if (it->name_width == 0) { if (it->name_width == 0) {
it->name_width = UIMeasureText(it->name, DBG_FONT_SIZE); it->name_width = UIMeasureText(it->name, DBG_FONT_SIZE);
} }
Color color = RAYWHITE; Color color = RAYWHITE;
if (is_btn_pressed(xpos, ypos, it->name_width, DBG_FONT_SIZE, &color)) { if (is_btn_pressed(xpos, ypos, it->name_width, DBG_FONT_SIZE, &color)) {
it->list.is_collapsed = !it->list.is_collapsed; it->list.is_collapsed = !it->list.is_collapsed;
} }
UIDrawText(it->name, xpos, ypos, DBG_FONT_SIZE, color); UIDrawText(it->name, xpos, ypos, DBG_FONT_SIZE, color);
ypos += DBG_FONT_SPACING; ypos += DBG_FONT_SPACING;
if (it->list.is_collapsed) break; if (it->list.is_collapsed) break;
if (it->list.is_sp_only && game_get_kind() != GAMEKIND_SINGLE) break; if (it->list.is_sp_only && game_get_kind() != GAMEKIND_SINGLE) break;
debug_draw_result res = debug_draw_list(it->list.items, xpos+DBG_LIST_XPOS_OFFSET, ypos, is_shadow); debug_draw_result res = debug_draw_list(it->list.items, xpos+DBG_LIST_XPOS_OFFSET, ypos, is_shadow);
ypos = res.y; ypos = res.y;
}break; }break;
case DITEM_TEXT: { case DITEM_TEXT: {
char const *text = TextFormat("%s: ", it->name); char const *text = TextFormat("%s: ", it->name);
if (it->name_width == 0) { if (it->name_width == 0) {
it->name_width = UIMeasureText(text, DBG_FONT_SIZE); it->name_width = UIMeasureText(text, DBG_FONT_SIZE);
} }
UIDrawText(text, xpos, ypos, DBG_FONT_SIZE, RAYWHITE); UIDrawText(text, xpos, ypos, DBG_FONT_SIZE, RAYWHITE);
ZPL_ASSERT(it->proc); ZPL_ASSERT(it->proc);
debug_draw_result res = it->proc(it, xpos + it->name_width, ypos); debug_draw_result res = it->proc(it, xpos + it->name_width, ypos);
ypos = res.y; ypos = res.y;
}break; }break;
case DITEM_RAW: { case DITEM_RAW: {
ZPL_ASSERT(it->proc); ZPL_ASSERT(it->proc);
debug_draw_result res = it->proc(it, xpos, ypos); debug_draw_result res = it->proc(it, xpos, ypos);
ypos = res.y; ypos = res.y;
}break; }break;
case DITEM_BUTTON: { case DITEM_BUTTON: {
char const *text = TextFormat("> %s", it->name); char const *text = TextFormat("> %s", it->name);
if (it->name_width == 0) { if (it->name_width == 0) {
it->name_width = UIMeasureText(text, DBG_FONT_SIZE); it->name_width = UIMeasureText(text, DBG_FONT_SIZE);
} }
Color color = RAYWHITE; Color color = RAYWHITE;
if (is_btn_pressed(xpos, ypos, it->name_width, DBG_FONT_SIZE, &color) && it->on_click) { if (is_btn_pressed(xpos, ypos, it->name_width, DBG_FONT_SIZE, &color) && it->on_click) {
it->on_click(); it->on_click();
} }
if (!it->on_click) { if (!it->on_click) {
color = GRAY; color = GRAY;
} }
debug_draw_result res = DrawColoredText(xpos, ypos, text, color); debug_draw_result res = DrawColoredText(xpos, ypos, text, color);
ypos = res.y; ypos = res.y;
}break; }break;
case DITEM_SLIDER: { case DITEM_SLIDER: {
ZPL_ASSERT(it->slider.min != it->slider.max); ZPL_ASSERT(it->slider.min != it->slider.max);
char const *text = TextFormat("%s: ", it->name); char const *text = TextFormat("%s: ", it->name);
if (it->name_width == 0) { if (it->name_width == 0) {
it->name_width = UIMeasureText(text, DBG_FONT_SIZE); it->name_width = UIMeasureText(text, DBG_FONT_SIZE);
} }
UIDrawText(text, xpos, ypos, DBG_FONT_SIZE, RAYWHITE); UIDrawText(text, xpos, ypos, DBG_FONT_SIZE, RAYWHITE);
xpos += it->name_width; xpos += it->name_width;
DrawRectangleLines(xpos, ypos, 100.0f, DBG_FONT_SIZE, RAYWHITE); DrawRectangleLines(xpos, ypos, 100.0f, DBG_FONT_SIZE, RAYWHITE);
float stick_x = xpos + ((it->slider.val / it->slider.max) * 100.0f) - 5.0f; float stick_x = xpos + ((it->slider.val / it->slider.max) * 100.0f) - 5.0f;
DrawRectangle(stick_x, ypos, 10.0f, DBG_FONT_SIZE, RED); DrawRectangle(stick_x, ypos, 10.0f, DBG_FONT_SIZE, RED);
xpos += 100.0f + 5.0f; xpos += 100.0f + 5.0f;
DrawFloat(xpos, ypos, it->slider.val); DrawFloat(xpos, ypos, it->slider.val);
ypos += DBG_FONT_SPACING; ypos += DBG_FONT_SPACING;
}break; }break;
default: { default: {
}break; }break;
} }
} }
return (debug_draw_result){xpos, ypos}; return (debug_draw_result){xpos, ypos};
} }
void debug_draw(void) { void debug_draw(void) {
// NOTE(zaklaus): Flush old debug samples // NOTE(zaklaus): Flush old debug samples
debug_draw_flush(); debug_draw_flush();
float xpos = debug_xpos; float xpos = debug_xpos;
float ypos = debug_ypos; float ypos = debug_ypos;
// NOTE(zaklaus): move debug ui // NOTE(zaklaus): move debug ui
{ {
debug_area_status area = check_mouse_area(xpos, ypos, DBG_CTRL_HANDLE_DIM, DBG_CTRL_HANDLE_DIM); debug_area_status area = check_mouse_area(xpos, ypos, DBG_CTRL_HANDLE_DIM, DBG_CTRL_HANDLE_DIM);
Color color = BLUE; Color color = BLUE;
if (area == DAREA_HOVER) color = YELLOW; if (area == DAREA_HOVER) color = YELLOW;
if (area == DAREA_HELD) { if (area == DAREA_HELD) {
color = RED; color = RED;
is_handle_ctrl_held = 1; is_handle_ctrl_held = 1;
} }
if (is_handle_ctrl_held) { if (is_handle_ctrl_held) {
debug_xpos = xpos = GetMouseX() - DBG_CTRL_HANDLE_DIM/2; debug_xpos = xpos = GetMouseX() - DBG_CTRL_HANDLE_DIM/2;
debug_ypos = ypos = GetMouseY() - DBG_CTRL_HANDLE_DIM/2; debug_ypos = ypos = GetMouseY() - DBG_CTRL_HANDLE_DIM/2;
if (area == DAREA_PRESS) { if (area == DAREA_PRESS) {
is_handle_ctrl_held = 0; is_handle_ctrl_held = 0;
} }
} }
DrawRectangle(xpos, ypos, DBG_CTRL_HANDLE_DIM, DBG_CTRL_HANDLE_DIM, color); DrawRectangle(xpos, ypos, DBG_CTRL_HANDLE_DIM, DBG_CTRL_HANDLE_DIM, color);
} }
// NOTE(zaklaus): toggle debug ui // NOTE(zaklaus): toggle debug ui
{ {
Color color = BLUE; Color color = BLUE;
debug_area_status area = check_mouse_area(xpos, 15+ypos, DBG_CTRL_HANDLE_DIM, DBG_CTRL_HANDLE_DIM); debug_area_status area = check_mouse_area(xpos, 15+ypos, DBG_CTRL_HANDLE_DIM, DBG_CTRL_HANDLE_DIM);
if (area == DAREA_HOVER) color = YELLOW; if (area == DAREA_HOVER) color = YELLOW;
if (area == DAREA_HELD) { if (area == DAREA_HELD) {
color = RED; color = RED;
} }
if (area == DAREA_PRESS) { if (area == DAREA_PRESS) {
is_debug_open = !is_debug_open; is_debug_open = !is_debug_open;
} }
DrawPoly((Vector2){xpos+DBG_CTRL_HANDLE_DIM/2, ypos+15+DBG_CTRL_HANDLE_DIM/2}, 3, 6.0f,is_debug_open ? 0.0f : 180.0f, color); DrawPoly((Vector2){xpos+DBG_CTRL_HANDLE_DIM/2, ypos+15+DBG_CTRL_HANDLE_DIM/2}, 3, 6.0f,is_debug_open ? 0.0f : 180.0f, color);
} }
if (is_debug_open) { if (is_debug_open) {
xpos += 15; xpos += 15;
debug_draw_list(items, xpos+DBG_SHADOW_OFFSET_XPOS, ypos+DBG_SHADOW_OFFSET_YPOS, 1); // NOTE(zaklaus): draw shadow debug_draw_list(items, xpos+DBG_SHADOW_OFFSET_XPOS, ypos+DBG_SHADOW_OFFSET_YPOS, 1); // NOTE(zaklaus): draw shadow
debug_draw_list(items, xpos, ypos, 0); debug_draw_list(items, xpos, ypos, 0);
} }
} }
debug_area_status check_mouse_area(float xpos, float ypos, float w, float h) { debug_area_status check_mouse_area(float xpos, float ypos, float w, float h) {
if (is_shadow_rendered) return DAREA_OUTSIDE; if (is_shadow_rendered) return DAREA_OUTSIDE;
bool is_inside = CheckCollisionPointRec(GetMousePosition(), (Rectangle){xpos, ypos, w, h}); bool is_inside = CheckCollisionPointRec(GetMousePosition(), (Rectangle){xpos, ypos, w, h});
if (is_inside) { if (is_inside) {
return IsMouseButtonReleased(MOUSE_LEFT_BUTTON) ? DAREA_PRESS : IsMouseButtonDown(MOUSE_LEFT_BUTTON) ? DAREA_HELD : DAREA_HOVER; return IsMouseButtonReleased(MOUSE_LEFT_BUTTON) ? DAREA_PRESS : IsMouseButtonDown(MOUSE_LEFT_BUTTON) ? DAREA_HELD : DAREA_HOVER;
} }
return DAREA_OUTSIDE; return DAREA_OUTSIDE;
} }
bool is_btn_pressed(float xpos, float ypos, float w, float h, Color *color) { bool is_btn_pressed(float xpos, float ypos, float w, float h, Color *color) {
ZPL_ASSERT(color); ZPL_ASSERT(color);
*color = RAYWHITE; *color = RAYWHITE;
debug_area_status area = check_mouse_area(xpos, ypos, w, h); debug_area_status area = check_mouse_area(xpos, ypos, w, h);
if (area == DAREA_PRESS) { if (area == DAREA_PRESS) {
*color = RED; *color = RED;
return true; return true;
} else if (area == DAREA_HOVER) { } else if (area == DAREA_HOVER) {
*color = YELLOW; *color = YELLOW;
} else if (area == DAREA_HELD) { } else if (area == DAREA_HELD) {
*color = RED; *color = RED;
} }
return false; return false;
} }
static inline static inline
void UIDrawText(const char *text, float posX, float posY, int fontSize, Color color) { void UIDrawText(const char *text, float posX, float posY, int fontSize, Color color) {
// Check if default font has been loaded // Check if default font has been loaded
if (GetFontDefault().texture.id != 0) { if (GetFontDefault().texture.id != 0) {
Vector2 position = { (float)posX , (float)posY }; Vector2 position = { (float)posX , (float)posY };
int defaultFontSize = 10; // Default Font chars height in pixel int defaultFontSize = 10; // Default Font chars height in pixel
int new_spacing = fontSize/defaultFontSize; int new_spacing = fontSize/defaultFontSize;
DrawTextEx(GetFontDefault(), text, position, (float)fontSize , (float)new_spacing , is_shadow_rendered ? BLACK : color); DrawTextEx(GetFontDefault(), text, position, (float)fontSize , (float)new_spacing , is_shadow_rendered ? BLACK : color);
} }
} }
static inline static inline
int UIMeasureText(const char *text, int fontSize) { int UIMeasureText(const char *text, int fontSize) {
Vector2 vec = { 0.0f, 0.0f }; Vector2 vec = { 0.0f, 0.0f };
// Check if default font has been loaded // Check if default font has been loaded
if (GetFontDefault().texture.id != 0) { if (GetFontDefault().texture.id != 0) {
int defaultFontSize = 10; // Default Font chars height in pixel int defaultFontSize = 10; // Default Font chars height in pixel
int new_spacing = fontSize/defaultFontSize; int new_spacing = fontSize/defaultFontSize;
vec = MeasureTextEx(GetFontDefault(), text, (float)fontSize, (float)new_spacing); vec = MeasureTextEx(GetFontDefault(), text, (float)fontSize, (float)new_spacing);
} }
return (int)vec.x; return (int)vec.x;
} }

View File

@ -1,272 +1,272 @@
#include "debug_ui.h" #include "debug_ui.h"
#include "world/blocks.h" #include "world/blocks.h"
#include "items.h" #include "items.h"
void void
ActExitGame(void) { ActExitGame(void) {
game_request_close(); game_request_close();
} }
void void
ActSpawnCar(void) { ActSpawnCar(void) {
ecs_entity_t e = vehicle_spawn(); ecs_entity_t e = vehicle_spawn();
ecs_entity_t plr = camera_get().ent_id; ecs_entity_t plr = camera_get().ent_id;
Position const* origin = ecs_get(world_ecs(), plr, Position); Position const* origin = ecs_get(world_ecs(), plr, Position);
Position * dest = ecs_get_mut(world_ecs(), e, Position, NULL); Position * dest = ecs_get_mut(world_ecs(), e, Position, NULL);
*dest = *origin; *dest = *origin;
debug_replay_special_action(RPKIND_SPAWN_CAR); debug_replay_special_action(RPKIND_SPAWN_CAR);
} }
void void
ActSpawnIcemaker(void) { ActSpawnIcemaker(void) {
ecs_entity_t e = item_spawn(IKIND_DEMO_ICEMAKER, 32); ecs_entity_t e = item_spawn(IKIND_DEMO_ICEMAKER, 32);
ecs_entity_t plr = camera_get().ent_id; ecs_entity_t plr = camera_get().ent_id;
Position const* origin = ecs_get(world_ecs(), plr, Position); Position const* origin = ecs_get(world_ecs(), plr, Position);
Position * dest = ecs_get_mut(world_ecs(), e, Position, NULL); Position * dest = ecs_get_mut(world_ecs(), e, Position, NULL);
*dest = *origin; *dest = *origin;
debug_replay_special_action(RPKIND_SPAWN_ICEMAKER_ITEM); debug_replay_special_action(RPKIND_SPAWN_ICEMAKER_ITEM);
} }
void void
ActSpawnCirclingDriver(void) { ActSpawnCirclingDriver(void) {
ecs_entity_t plr = camera_get().ent_id; ecs_entity_t plr = camera_get().ent_id;
ecs_entity_t ve = vehicle_spawn(); ecs_entity_t ve = vehicle_spawn();
ecs_entity_t e = entity_spawn(EKIND_DEMO_NPC); ecs_entity_t e = entity_spawn(EKIND_DEMO_NPC);
Position const *origin = ecs_get(world_ecs(), plr, Position); Position const *origin = ecs_get(world_ecs(), plr, Position);
Position *veh_dest = ecs_get_mut(world_ecs(), ve, Position, NULL); Position *veh_dest = ecs_get_mut(world_ecs(), ve, Position, NULL);
Position *dest = ecs_get_mut(world_ecs(), e, Position, NULL); Position *dest = ecs_get_mut(world_ecs(), e, Position, NULL);
*veh_dest = *origin; *veh_dest = *origin;
*dest = *origin; *dest = *origin;
Input *input = ecs_get_mut(world_ecs(), e, Input, NULL); Input *input = ecs_get_mut(world_ecs(), e, Input, NULL);
zpl_zero_item(input); zpl_zero_item(input);
input->x = input->y = 1.0f; input->x = input->y = 1.0f;
Vehicle *veh = ecs_get_mut(world_ecs(), ve, Vehicle, NULL); Vehicle *veh = ecs_get_mut(world_ecs(), ve, Vehicle, NULL);
veh->seats[0] = e; veh->seats[0] = e;
ecs_set(world_ecs(), e, IsInVehicle, { .veh = ve }); ecs_set(world_ecs(), e, IsInVehicle, { .veh = ve });
debug_replay_special_action(RPKIND_SPAWN_CIRCLING_DRIVER); debug_replay_special_action(RPKIND_SPAWN_CIRCLING_DRIVER);
} }
void void
ActPlaceIceRink(void) { ActPlaceIceRink(void) {
ecs_entity_t plr = camera_get().ent_id; ecs_entity_t plr = camera_get().ent_id;
uint8_t watr_id = blocks_find(BLOCK_BIOME_DEV, BLOCK_KIND_WATER); uint8_t watr_id = blocks_find(BLOCK_BIOME_DEV, BLOCK_KIND_WATER);
Position const *p = ecs_get(world_ecs(), plr, Position); Position const *p = ecs_get(world_ecs(), plr, Position);
float const bs = WORLD_BLOCK_SIZE; float const bs = WORLD_BLOCK_SIZE;
for (int y = 0; y < 100; y++) { for (int y = 0; y < 100; y++) {
for (int x = 0; x < 100; x++) { for (int x = 0; x < 100; x++) {
world_block_lookup l = world_block_from_realpos((p->x - (x*bs)/2.0f), p->y - (y*bs)/2.0f); world_block_lookup l = world_block_from_realpos((p->x - (x*bs)/2.0f), p->y - (y*bs)/2.0f);
world_chunk_replace_block(l.chunk_id, l.id, watr_id); world_chunk_replace_block(l.chunk_id, l.id, watr_id);
} }
} }
debug_replay_special_action(RPKIND_PLACE_ICE_RINK); debug_replay_special_action(RPKIND_PLACE_ICE_RINK);
} }
void void
ActEraseWorldChanges(void) { ActEraseWorldChanges(void) {
ecs_entity_t plr = camera_get().ent_id; ecs_entity_t plr = camera_get().ent_id;
Position const *p = ecs_get(world_ecs(), plr, Position); Position const *p = ecs_get(world_ecs(), plr, Position);
float const bs = WORLD_BLOCK_SIZE; float const bs = WORLD_BLOCK_SIZE;
for (int y = 0; y < 100; y++) { for (int y = 0; y < 100; y++) {
for (int x = 0; x < 100; x++) { for (int x = 0; x < 100; x++) {
world_block_lookup l = world_block_from_realpos((p->x - (x*bs)/2.0f), p->y - (y*bs)/2.0f); world_block_lookup l = world_block_from_realpos((p->x - (x*bs)/2.0f), p->y - (y*bs)/2.0f);
world_chunk_place_block(l.chunk_id, l.id, 0); world_chunk_place_block(l.chunk_id, l.id, 0);
} }
} }
debug_replay_special_action(RPKIND_PLACE_ERASE_CHANGES); debug_replay_special_action(RPKIND_PLACE_ERASE_CHANGES);
} }
// NOTE(zaklaus): Replay system // NOTE(zaklaus): Replay system
uint8_t uint8_t
CondReplayStatusOn(void) { CondReplayStatusOn(void) {
return is_recording && !is_playing; return is_recording && !is_playing;
} }
uint8_t uint8_t
CondReplayStatusOff(void) { CondReplayStatusOff(void) {
return !is_recording && !is_playing; return !is_recording && !is_playing;
} }
uint8_t uint8_t
CondReplayDataPresentAndNotPlaying(void) { CondReplayDataPresentAndNotPlaying(void) {
return records != NULL && !is_recording && !is_playing; return records != NULL && !is_recording && !is_playing;
} }
uint8_t uint8_t
CondReplayIsPlaying(void) { CondReplayIsPlaying(void) {
return records != NULL && !is_recording && is_playing; return records != NULL && !is_recording && is_playing;
} }
uint8_t uint8_t
CondReplayIsNotPlaying(void) { CondReplayIsNotPlaying(void) {
return !is_recording && !is_playing; return !is_recording && !is_playing;
} }
uint8_t uint8_t
CondReplayIsNotPlayingOrRecordsNotClear(void) { CondReplayIsNotPlayingOrRecordsNotClear(void) {
return records != NULL && !is_recording && !is_playing; return records != NULL && !is_recording && !is_playing;
} }
void void
ActReplayBegin(void) { ActReplayBegin(void) {
debug_replay_start(); debug_replay_start();
} }
void void
ActReplayEnd(void) { ActReplayEnd(void) {
debug_replay_stop(); debug_replay_stop();
} }
void void
ActReplayRun(void) { ActReplayRun(void) {
debug_replay_run(); debug_replay_run();
} }
void void
ActReplayClear(void) { ActReplayClear(void) {
debug_replay_clear(); debug_replay_clear();
} }
void void
ActReplayNew(void) { ActReplayNew(void) {
debug_replay_clear(); debug_replay_clear();
zpl_zero_size(replay_filename, sizeof(replay_filename)); zpl_zero_size(replay_filename, sizeof(replay_filename));
} }
void void
ActReplaySaveAs(void) { ActReplaySaveAs(void) {
if (!records) return; if (!records) return;
char const *workdir = GetWorkingDirectory(); char const *workdir = GetWorkingDirectory();
sfd_Options sfd = { sfd_Options sfd = {
.title = "Save Macro", .title = "Save Macro",
.path = "art", .path = "art",
.filter_name = "eco2d Macro", .filter_name = "eco2d Macro",
.filter = "*.dem", .filter = "*.dem",
}; };
char const *path = sfd_save_dialog(&sfd); char const *path = sfd_save_dialog(&sfd);
ChangeDirectory(workdir); ChangeDirectory(workdir);
if (path) { if (path) {
zpl_strcpy(replay_filename, zpl_bprintf("%s.dem", path)); zpl_strcpy(replay_filename, zpl_bprintf("%s.dem", path));
debug_replay_store(); debug_replay_store();
} }
} }
void void
ActReplaySave(void) { ActReplaySave(void) {
if (!replay_filename[0]) { if (!replay_filename[0]) {
ActReplaySaveAs(); ActReplaySaveAs();
} }
else debug_replay_store(); else debug_replay_store();
} }
void void
ActReplayLoad(void) { ActReplayLoad(void) {
char const *workdir = GetWorkingDirectory(); char const *workdir = GetWorkingDirectory();
sfd_Options sfd = { sfd_Options sfd = {
.title = "Load Macro", .title = "Load Macro",
.path = "art", .path = "art",
.filter_name = "eco2d Macro", .filter_name = "eco2d Macro",
.filter = "*.dem", .filter = "*.dem",
}; };
char const *path = sfd_open_dialog(&sfd); char const *path = sfd_open_dialog(&sfd);
ChangeDirectory(workdir); ChangeDirectory(workdir);
if (path) { if (path) {
zpl_zero_size(replay_filename, sizeof(replay_filename)); zpl_zero_size(replay_filename, sizeof(replay_filename));
zpl_strcpy(replay_filename, path); zpl_strcpy(replay_filename, path);
debug_replay_clear(); debug_replay_clear();
debug_replay_load(); debug_replay_load();
} }
} }
// NOTE(zaklaus): Demo NPCs // NOTE(zaklaus): Demo NPCs
static ecs_entity_t *demo_npcs = NULL; static ecs_entity_t *demo_npcs = NULL;
void void
ActSpawnDemoNPCs(void) { ActSpawnDemoNPCs(void) {
if (!demo_npcs) zpl_array_init(demo_npcs, zpl_heap()); if (!demo_npcs) zpl_array_init(demo_npcs, zpl_heap());
if (zpl_array_count(demo_npcs) >= 100000) return; if (zpl_array_count(demo_npcs) >= 100000) return;
for (uint32_t i = 0; i < 1000; i++) { for (uint32_t i = 0; i < 1000; i++) {
uint64_t e = entity_spawn(EKIND_DEMO_NPC); uint64_t e = entity_spawn(EKIND_DEMO_NPC);
ecs_add(world_ecs(), e, EcsDemoNPC); ecs_add(world_ecs(), e, EcsDemoNPC);
Position *pos = ecs_get_mut(world_ecs(), e, Position, NULL); Position *pos = ecs_get_mut(world_ecs(), e, Position, NULL);
pos->x=rand() % world_dim(); pos->x=rand() % world_dim();
pos->y=rand() % world_dim(); pos->y=rand() % world_dim();
Velocity *v = ecs_get_mut(world_ecs(), e, Velocity, NULL); Velocity *v = ecs_get_mut(world_ecs(), e, Velocity, NULL);
v->x = (rand()%3-1) * 10; v->x = (rand()%3-1) * 10;
v->y = (rand()%3-1) * 10; v->y = (rand()%3-1) * 10;
zpl_array_append(demo_npcs, e); zpl_array_append(demo_npcs, e);
} }
} }
void void
ActDespawnDemoNPCs(void) { ActDespawnDemoNPCs(void) {
if (!demo_npcs) return; if (!demo_npcs) return;
entity_batch_despawn(demo_npcs, zpl_array_count(demo_npcs)); entity_batch_despawn(demo_npcs, zpl_array_count(demo_npcs));
zpl_array_free(demo_npcs); zpl_array_free(demo_npcs);
demo_npcs = 0; demo_npcs = 0;
} }
// NOTE(zaklaus): world simulation controls // NOTE(zaklaus): world simulation controls
#define WORLDSIM_STEPPING 0.01f #define WORLDSIM_STEPPING 0.01f
static float sim_step_size = 0.1f; static float sim_step_size = 0.1f;
void void
ActWorldToggleSim(void) { ActWorldToggleSim(void) {
if (world_is_paused()) { if (world_is_paused()) {
world_resume(); world_resume();
} else { } else {
world_pause(); world_pause();
} }
} }
void void
ActWorldIncrementSimStepSize(void) { ActWorldIncrementSimStepSize(void) {
sim_step_size += WORLDSIM_STEPPING; sim_step_size += WORLDSIM_STEPPING;
} }
void void
ActWorldDecrementSimStepSize(void) { ActWorldDecrementSimStepSize(void) {
if (sim_step_size > WORLDSIM_STEPPING) if (sim_step_size > WORLDSIM_STEPPING)
sim_step_size -= WORLDSIM_STEPPING; sim_step_size -= WORLDSIM_STEPPING;
} }
void void
ActWorldStep(void) { ActWorldStep(void) {
world_step(sim_step_size); world_step(sim_step_size);
} }
uint8_t uint8_t
CondIsWorldPaused(void) { CondIsWorldPaused(void) {
return world_is_paused(); return world_is_paused();
} }
uint8_t uint8_t
CondIsWorldRunning(void) { CondIsWorldRunning(void) {
return !world_is_paused(); return !world_is_paused();
} }

View File

@ -1,101 +1,101 @@
#include "debug_ui.h" #include "debug_ui.h"
#include "raylib.h" #include "raylib.h"
#include "platform.h" #include "platform.h"
#include "profiler.h" #include "profiler.h"
//~ NOTE(zaklaus): helpers //~ NOTE(zaklaus): helpers
static inline debug_draw_result static inline debug_draw_result
DrawFloat(float xpos, float ypos, float val) { DrawFloat(float xpos, float ypos, float val) {
char const *text = TextFormat("%.02f\n", val); char const *text = TextFormat("%.02f\n", val);
UIDrawText(text, xpos, ypos, DBG_FONT_SIZE, RAYWHITE); UIDrawText(text, xpos, ypos, DBG_FONT_SIZE, RAYWHITE);
return (debug_draw_result){.x = xpos + UIMeasureText(text, DBG_FONT_SIZE), .y = ypos + DBG_FONT_SPACING}; return (debug_draw_result){.x = xpos + UIMeasureText(text, DBG_FONT_SIZE), .y = ypos + DBG_FONT_SPACING};
} }
static inline debug_draw_result static inline debug_draw_result
DrawColoredText(float xpos, float ypos, char const *text, Color color) { DrawColoredText(float xpos, float ypos, char const *text, Color color) {
ZPL_ASSERT(text); ZPL_ASSERT(text);
UIDrawText(text, xpos, ypos, DBG_FONT_SIZE, color); UIDrawText(text, xpos, ypos, DBG_FONT_SIZE, color);
return (debug_draw_result){.x = xpos + UIMeasureText(text, DBG_FONT_SIZE), .y = ypos + DBG_FONT_SPACING}; return (debug_draw_result){.x = xpos + UIMeasureText(text, DBG_FONT_SIZE), .y = ypos + DBG_FONT_SPACING};
} }
static inline debug_draw_result static inline debug_draw_result
DrawFormattedText(float xpos, float ypos, char const *text) { DrawFormattedText(float xpos, float ypos, char const *text) {
return DrawColoredText(xpos, ypos, text, RAYWHITE); return DrawColoredText(xpos, ypos, text, RAYWHITE);
} }
//~ NOTE(zaklaus): widgets //~ NOTE(zaklaus): widgets
static inline debug_draw_result static inline debug_draw_result
DrawCameraPos(debug_item *it, float xpos, float ypos) { DrawCameraPos(debug_item *it, float xpos, float ypos) {
(void)it; (void)it;
camera cam = camera_get(); camera cam = camera_get();
return DrawFormattedText(xpos, ypos, TextFormat("%d %d", (int)(cam.x/WORLD_BLOCK_SIZE), (int)(cam.y/WORLD_BLOCK_SIZE))); return DrawFormattedText(xpos, ypos, TextFormat("%d %d", (int)(cam.x/WORLD_BLOCK_SIZE), (int)(cam.y/WORLD_BLOCK_SIZE)));
} }
static inline debug_draw_result static inline debug_draw_result
DrawUnmeasuredTime(debug_item *it, float xpos, float ypos) { DrawUnmeasuredTime(debug_item *it, float xpos, float ypos) {
(void)it; (void)it;
float total_time = profiler_delta(PROF_TOTAL_TIME); float total_time = profiler_delta(PROF_TOTAL_TIME);
float acc_time = profiler_delta(PROF_MAIN_LOOP); float acc_time = profiler_delta(PROF_MAIN_LOOP);
return DrawFormattedText(xpos, ypos, TextFormat("%.02f ms", (total_time-acc_time) * 1000.0f)); return DrawFormattedText(xpos, ypos, TextFormat("%.02f ms", (total_time-acc_time) * 1000.0f));
} }
static inline debug_draw_result static inline debug_draw_result
DrawDeltaTime(debug_item *it, float xpos, float ypos) { DrawDeltaTime(debug_item *it, float xpos, float ypos) {
(void)it; (void)it;
float dt = GetFrameTime(); float dt = GetFrameTime();
return DrawFormattedText(xpos, ypos, TextFormat("%.02f (%.02f fps)", dt * 1000.0f, 1.0f/dt)); return DrawFormattedText(xpos, ypos, TextFormat("%.02f (%.02f fps)", dt * 1000.0f, 1.0f/dt));
} }
static inline debug_draw_result static inline debug_draw_result
DrawZoom(debug_item *it, float xpos, float ypos) { DrawZoom(debug_item *it, float xpos, float ypos) {
(void)it; (void)it;
return DrawFloat(xpos, ypos, platform_zoom_get()); return DrawFloat(xpos, ypos, platform_zoom_get());
} }
static inline debug_draw_result static inline debug_draw_result
DrawLiteral(debug_item *it, float xpos, float ypos) { DrawLiteral(debug_item *it, float xpos, float ypos) {
ZPL_ASSERT(it->text); ZPL_ASSERT(it->text);
return DrawFormattedText(xpos, ypos, it->text); return DrawFormattedText(xpos, ypos, it->text);
} }
static inline debug_draw_result static inline debug_draw_result
DrawProfilerDelta(debug_item *it, float xpos, float ypos) { DrawProfilerDelta(debug_item *it, float xpos, float ypos) {
float dt = profiler_delta(it->val); float dt = profiler_delta(it->val);
return DrawFormattedText(xpos, ypos, TextFormat("%s: %.02f ms", profiler_name(it->val), dt * 1000.0f)); return DrawFormattedText(xpos, ypos, TextFormat("%s: %.02f ms", profiler_name(it->val), dt * 1000.0f));
} }
static inline debug_draw_result static inline debug_draw_result
DrawReplaySamples(debug_item *it, float xpos, float ypos) { DrawReplaySamples(debug_item *it, float xpos, float ypos) {
(void)it; (void)it;
size_t cnt = 0; size_t cnt = 0;
if (records) { if (records) {
cnt = zpl_array_count(records); cnt = zpl_array_count(records);
} }
return DrawFormattedText(xpos, ypos, TextFormat("%d of %d", record_pos, cnt)); return DrawFormattedText(xpos, ypos, TextFormat("%d of %d", record_pos, cnt));
} }
static inline debug_draw_result static inline debug_draw_result
DrawReplayFileName(debug_item *it, float xpos, float ypos) { DrawReplayFileName(debug_item *it, float xpos, float ypos) {
(void)it; (void)it;
return DrawFormattedText(xpos, ypos, TextFormat("%s", replay_filename[0] ? replay_filename : "<unnamed>")); return DrawFormattedText(xpos, ypos, TextFormat("%s", replay_filename[0] ? replay_filename : "<unnamed>"));
} }
// NOTE(zaklaus): demo npcs // NOTE(zaklaus): demo npcs
static inline debug_draw_result static inline debug_draw_result
DrawDemoNPCCount(debug_item *it, float xpos, float ypos) { DrawDemoNPCCount(debug_item *it, float xpos, float ypos) {
(void)it; (void)it;
return DrawFormattedText(xpos, ypos, TextFormat("%d", demo_npcs ? zpl_array_count(demo_npcs) : 0)); return DrawFormattedText(xpos, ypos, TextFormat("%d", demo_npcs ? zpl_array_count(demo_npcs) : 0));
} }
// NOTE(zaklaus): world simulation // NOTE(zaklaus): world simulation
static inline debug_draw_result static inline debug_draw_result
DrawWorldStepSize(debug_item *it, float xpos, float ypos) { DrawWorldStepSize(debug_item *it, float xpos, float ypos) {
(void)it; (void)it;
return DrawFormattedText(xpos, ypos, TextFormat("%d ms", (int16_t)(sim_step_size*1000.f))); return DrawFormattedText(xpos, ypos, TextFormat("%d ms", (int16_t)(sim_step_size*1000.f)));
} }

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "system.h" #include "system.h"
uint64_t entity_spawn(uint16_t class_id /* 0 = no streaming */); uint64_t entity_spawn(uint16_t class_id /* 0 = no streaming */);
void entity_batch_despawn(uint64_t *ids, size_t num_ids); void entity_batch_despawn(uint64_t *ids, size_t num_ids);
void entity_despawn(uint64_t ent_id); void entity_despawn(uint64_t ent_id);

View File

@ -1,233 +1,233 @@
#include "game.h" #include "game.h"
#include "zpl.h" #include "zpl.h"
#include "platform.h" #include "platform.h"
#include "world/world.h" #include "world/world.h"
#include "packet.h" #include "packet.h"
#include "signal_handling.h" #include "signal_handling.h"
#include "network.h" #include "network.h"
#include "entity.h" #include "entity.h"
#include "world_view.h" #include "world_view.h"
#include "entity_view.h" #include "entity_view.h"
#include "camera.h" #include "camera.h"
#include "profiler.h" #include "profiler.h"
#include "flecs/flecs.h" #include "flecs/flecs.h"
//#include "flecs/flecs_dash.h" //#include "flecs/flecs_dash.h"
//#include "flecs/flecs_systems_civetweb.h" //#include "flecs/flecs_systems_civetweb.h"
#include "flecs/flecs_os_api_stdcpp.h" #include "flecs/flecs_os_api_stdcpp.h"
#include "modules/components.h" #include "modules/components.h"
#include "modules/systems.h" #include "modules/systems.h"
#include "packets/pkt_00_init.h" #include "packets/pkt_00_init.h"
#include "packets/pkt_01_welcome.h" #include "packets/pkt_01_welcome.h"
static uint8_t game_mode; static uint8_t game_mode;
static world_view *world_viewers; static world_view *world_viewers;
static world_view *active_viewer; static world_view *active_viewer;
static WORLD_PKT_READER(pkt_reader) { static WORLD_PKT_READER(pkt_reader) {
pkt_header header = {0}; pkt_header header = {0};
uint32_t ok = pkt_header_decode(&header, data, datalen); uint32_t ok = pkt_header_decode(&header, data, datalen);
header.udata = udata; header.udata = udata;
if (ok && header.ok) { if (ok && header.ok) {
return pkt_handlers[header.id].handler(&header) >= 0; return pkt_handlers[header.id].handler(&header) >= 0;
} else { } else {
zpl_printf("[warn] unknown packet id %d (header %d data %d)\n", header.id, ok, header.ok); zpl_printf("[warn] unknown packet id %d (header %d data %d)\n", header.id, ok, header.ok);
} }
return -1; return -1;
} }
static WORLD_PKT_WRITER(sp_pkt_writer) { static WORLD_PKT_WRITER(sp_pkt_writer) {
(void)udata; (void)udata;
return world_read(pkt->data, pkt->datalen, (void*)game_world_view_get_active()->owner_id); return world_read(pkt->data, pkt->datalen, (void*)game_world_view_get_active()->owner_id);
} }
static WORLD_PKT_WRITER(mp_pkt_writer) { static WORLD_PKT_WRITER(mp_pkt_writer) {
if (pkt->is_reliable) { if (pkt->is_reliable) {
return network_msg_send(udata, pkt->data, pkt->datalen, pkt->channel_id); return network_msg_send(udata, pkt->data, pkt->datalen, pkt->channel_id);
} }
else { else {
return network_msg_send_unreliable(udata, pkt->data, pkt->datalen, pkt->channel_id); return network_msg_send_unreliable(udata, pkt->data, pkt->datalen, pkt->channel_id);
} }
} }
static WORLD_PKT_WRITER(mp_cli_pkt_writer) { static WORLD_PKT_WRITER(mp_cli_pkt_writer) {
(void)udata; (void)udata;
if (pkt->is_reliable) { if (pkt->is_reliable) {
return network_msg_send(0, pkt->data, pkt->datalen, pkt->channel_id); return network_msg_send(0, pkt->data, pkt->datalen, pkt->channel_id);
} }
else { else {
return network_msg_send_unreliable(0, pkt->data, pkt->datalen, pkt->channel_id); return network_msg_send_unreliable(0, pkt->data, pkt->datalen, pkt->channel_id);
} }
} }
void world_viewers_init(uint32_t num_viewers) { void world_viewers_init(uint32_t num_viewers) {
zpl_buffer_init(world_viewers, zpl_heap(), num_viewers); zpl_buffer_init(world_viewers, zpl_heap(), num_viewers);
for (uint32_t i = 0; i < num_viewers; i++) { for (uint32_t i = 0; i < num_viewers; i++) {
zpl_buffer_append(world_viewers, world_view_create(i)); zpl_buffer_append(world_viewers, world_view_create(i));
} }
} }
void world_viewers_destroy() { void world_viewers_destroy() {
for (uint32_t i = 0; i < zpl_buffer_count(world_viewers); i++) { for (uint32_t i = 0; i < zpl_buffer_count(world_viewers); i++) {
world_view_destroy(&world_viewers[i]); world_view_destroy(&world_viewers[i]);
} }
zpl_buffer_free(world_viewers); zpl_buffer_free(world_viewers);
} }
world_view *game_world_view_get(uint16_t idx) { world_view *game_world_view_get(uint16_t idx) {
return &world_viewers[idx]; return &world_viewers[idx];
} }
world_view *game_world_view_get_active(void) { world_view *game_world_view_get_active(void) {
return active_viewer; return active_viewer;
} }
void game_world_view_cycle_active(int8_t dir) { void game_world_view_cycle_active(int8_t dir) {
uint16_t idx = (uint16_t)(active_viewer - world_viewers); uint16_t idx = (uint16_t)(active_viewer - world_viewers);
game_world_view_set_active_by_idx(zpl_max(0, (idx+dir)%zpl_buffer_count(world_viewers))); game_world_view_set_active_by_idx(zpl_max(0, (idx+dir)%zpl_buffer_count(world_viewers)));
} }
void game_world_view_set_active_by_idx(uint16_t idx) { void game_world_view_set_active_by_idx(uint16_t idx) {
ZPL_ASSERT(idx >= 0 && idx < zpl_buffer_count(world_viewers)); ZPL_ASSERT(idx >= 0 && idx < zpl_buffer_count(world_viewers));
game_world_view_set_active(&world_viewers[idx]); game_world_view_set_active(&world_viewers[idx]);
} }
void game_world_view_active_entity_map(void (*map_proc)(uint64_t key, entity_view * value)) { void game_world_view_active_entity_map(void (*map_proc)(uint64_t key, entity_view * value)) {
entity_view_map(&active_viewer->entities, map_proc); entity_view_map(&active_viewer->entities, map_proc);
} }
entity_view *game_world_view_active_get_entity(uint64_t ent_id) { entity_view *game_world_view_active_get_entity(uint64_t ent_id) {
return entity_view_get(&active_viewer->entities, ent_id); return entity_view_get(&active_viewer->entities, ent_id);
} }
void game_world_view_set_active(world_view *view) { void game_world_view_set_active(world_view *view) {
active_viewer = view; active_viewer = view;
camera_set_follow(view->owner_id); camera_set_follow(view->owner_id);
} }
void flecs_dash_init() { void flecs_dash_init() {
#if 0 #if 0
ECS_IMPORT(world_ecs(), FlecsDash); ECS_IMPORT(world_ecs(), FlecsDash);
ECS_IMPORT(world_ecs(), FlecsSystemsCivetweb); ECS_IMPORT(world_ecs(), FlecsSystemsCivetweb);
ecs_set(world_ecs(), 0, EcsDashServer, {.port = 27001}); ecs_set(world_ecs(), 0, EcsDashServer, {.port = 27001});
#endif #endif
} }
float game_time() { float game_time() {
return zpl_time_rel(); return zpl_time_rel();
} }
void game_init(game_kind play_mode, uint32_t num_viewers, int32_t seed, uint16_t chunk_size, uint16_t chunk_amount, int8_t is_dash_enabled) { void game_init(game_kind play_mode, uint32_t num_viewers, int32_t seed, uint16_t chunk_size, uint16_t chunk_amount, int8_t is_dash_enabled) {
game_mode = play_mode; game_mode = play_mode;
if (game_mode != GAMEKIND_HEADLESS) { if (game_mode != GAMEKIND_HEADLESS) {
platform_init(); platform_init();
world_viewers_init(num_viewers); world_viewers_init(num_viewers);
active_viewer = &world_viewers[0]; active_viewer = &world_viewers[0];
camera_reset(); camera_reset();
} }
if (game_mode != GAMEKIND_SINGLE) { if (game_mode != GAMEKIND_SINGLE) {
network_init(); network_init();
} }
if (game_mode == GAMEKIND_CLIENT) { if (game_mode == GAMEKIND_CLIENT) {
world_setup_pkt_handlers(pkt_reader, mp_cli_pkt_writer); world_setup_pkt_handlers(pkt_reader, mp_cli_pkt_writer);
#ifndef _DEBUG #ifndef _DEBUG
network_client_connect("lab.zakto.pw", 27000); network_client_connect("lab.zakto.pw", 27000);
#else #else
network_client_connect("127.0.0.1", 27000); network_client_connect("127.0.0.1", 27000);
#endif #endif
} else { } else {
stdcpp_set_os_api(); stdcpp_set_os_api();
world_setup_pkt_handlers(pkt_reader, game_mode == GAMEKIND_SINGLE ? sp_pkt_writer : mp_pkt_writer); world_setup_pkt_handlers(pkt_reader, game_mode == GAMEKIND_SINGLE ? sp_pkt_writer : mp_pkt_writer);
world_init(seed, chunk_size, chunk_amount); world_init(seed, chunk_size, chunk_amount);
if (is_dash_enabled) flecs_dash_init(); if (is_dash_enabled) flecs_dash_init();
if (game_mode == GAMEKIND_HEADLESS) { if (game_mode == GAMEKIND_HEADLESS) {
network_server_start(0, 27000); network_server_start(0, 27000);
ecs_set_target_fps(world_ecs(), 60); ecs_set_target_fps(world_ecs(), 60);
} }
} }
if (game_mode == GAMEKIND_SINGLE) { if (game_mode == GAMEKIND_SINGLE) {
for (uint32_t i = 0; i < num_viewers; i++) { for (uint32_t i = 0; i < num_viewers; i++) {
pkt_00_init_send(i); pkt_00_init_send(i);
} }
} }
} }
int8_t game_is_networked() { int8_t game_is_networked() {
return game_mode != GAMEKIND_SINGLE; return game_mode != GAMEKIND_SINGLE;
} }
void game_shutdown() { void game_shutdown() {
if (game_mode == GAMEKIND_CLIENT) { if (game_mode == GAMEKIND_CLIENT) {
network_client_disconnect(); network_client_disconnect();
} else { } else {
world_destroy(); world_destroy();
if (game_mode == GAMEKIND_HEADLESS) { if (game_mode == GAMEKIND_HEADLESS) {
network_server_stop(); network_server_stop();
} }
} }
if (game_mode != GAMEKIND_SINGLE) { if (game_mode != GAMEKIND_SINGLE) {
network_destroy(); network_destroy();
} }
if (game_mode != GAMEKIND_HEADLESS) { if (game_mode != GAMEKIND_HEADLESS) {
world_viewers_destroy(); world_viewers_destroy();
// TODO(zaklaus): crashes on exit // TODO(zaklaus): crashes on exit
//platform_shutdown(); //platform_shutdown();
} }
} }
uint8_t game_is_running() { uint8_t game_is_running() {
return game_mode == GAMEKIND_HEADLESS || platform_is_running(); return game_mode == GAMEKIND_HEADLESS || platform_is_running();
} }
game_kind game_get_kind(void) { game_kind game_get_kind(void) {
return game_mode; return game_mode;
} }
void game_input() { void game_input() {
if (game_mode != GAMEKIND_HEADLESS) { if (game_mode != GAMEKIND_HEADLESS) {
platform_input(); platform_input();
} }
} }
void game_update() { void game_update() {
if (game_mode == GAMEKIND_CLIENT) { if (game_mode == GAMEKIND_CLIENT) {
network_client_tick(); network_client_tick();
} }
else { else {
world_update(); world_update();
if (game_mode == GAMEKIND_HEADLESS) { if (game_mode == GAMEKIND_HEADLESS) {
network_server_tick(); network_server_tick();
} }
} }
} }
void game_render() { void game_render() {
if (game_mode != GAMEKIND_HEADLESS) { if (game_mode != GAMEKIND_HEADLESS) {
platform_render(); platform_render();
} }
} }
void game_action_send_keystate(game_keystate_data *data) { void game_action_send_keystate(game_keystate_data *data) {
pkt_send_keystate_send(active_viewer->view_id, data); pkt_send_keystate_send(active_viewer->view_id, data);
} }
void game_request_close() { void game_request_close() {
platform_request_close(); platform_request_close();
} }

View File

@ -1,36 +1,36 @@
#pragma once #pragma once
#include "system.h" #include "system.h"
#include "world_view.h" #include "world_view.h"
#include "packets/pkt_send_keystate.h" #include "packets/pkt_send_keystate.h"
typedef enum { typedef enum {
GAMEKIND_SINGLE, GAMEKIND_SINGLE,
GAMEKIND_CLIENT, GAMEKIND_CLIENT,
GAMEKIND_HEADLESS, GAMEKIND_HEADLESS,
FORCE_GAMEKIND_UINT8 = UINT8_MAX FORCE_GAMEKIND_UINT8 = UINT8_MAX
} game_kind; } game_kind;
void game_init(game_kind play_mode, uint32_t num_viewers, int32_t seed, uint16_t chunk_size, uint16_t chunk_amount, int8_t is_dash_enabled); void game_init(game_kind play_mode, uint32_t num_viewers, int32_t seed, uint16_t chunk_size, uint16_t chunk_amount, int8_t is_dash_enabled);
void game_shutdown(); void game_shutdown();
void game_request_close(); void game_request_close();
uint8_t game_is_running(); uint8_t game_is_running();
int8_t game_is_networked(); int8_t game_is_networked();
float game_time(); float game_time();
game_kind game_get_kind(void); game_kind game_get_kind(void);
//~ NOTE(zaklaus): game events //~ NOTE(zaklaus): game events
void game_input(); void game_input();
void game_update(); void game_update();
void game_render(); void game_render();
//~ NOTE(zaklaus): world view management //~ NOTE(zaklaus): world view management
world_view *game_world_view_get_active(void); world_view *game_world_view_get_active(void);
world_view *game_world_view_get(uint16_t idx); world_view *game_world_view_get(uint16_t idx);
void game_world_view_set_active_by_idx(uint16_t idx); void game_world_view_set_active_by_idx(uint16_t idx);
void game_world_view_set_active(world_view *view); void game_world_view_set_active(world_view *view);
void game_world_view_cycle_active(int8_t dir); void game_world_view_cycle_active(int8_t dir);
void game_world_view_active_entity_map(void (*map_proc)(uint64_t key, entity_view * value)); void game_world_view_active_entity_map(void (*map_proc)(uint64_t key, entity_view * value));
entity_view *game_world_view_active_get_entity(uint64_t ent_id); entity_view *game_world_view_active_get_entity(uint64_t ent_id);
//~ NOTE(zaklaus): viewer -> host actions //~ NOTE(zaklaus): viewer -> host actions
void game_action_send_keystate(game_keystate_data *data); void game_action_send_keystate(game_keystate_data *data);

View File

@ -1,189 +1,189 @@
#include "zpl.h" #include "zpl.h"
#define ENET_IMPLEMENTATION #define ENET_IMPLEMENTATION
#include "enet.h" #include "enet.h"
#define LIBRG_IMPL #define LIBRG_IMPL
#define LIBRG_CUSTOM_ZPL #define LIBRG_CUSTOM_ZPL
#define LIBRG_ENTITY_MAXCHUNKS 1 #define LIBRG_ENTITY_MAXCHUNKS 1
#include "librg.h" #include "librg.h"
#include "network.h" #include "network.h"
#include "packet.h" #include "packet.h"
#include "packets/pkt_00_init.h" #include "packets/pkt_00_init.h"
#include "world/world.h" #include "world/world.h"
#include "game.h" #include "game.h"
#include "player.h" #include "player.h"
#define NETWORK_UPDATE_DELAY 0.100 #define NETWORK_UPDATE_DELAY 0.100
static ENetHost *host = NULL; static ENetHost *host = NULL;
static ENetHost *server = NULL; static ENetHost *server = NULL;
static ENetPeer *peer = NULL; static ENetPeer *peer = NULL;
static librg_world *world = NULL; static librg_world *world = NULL;
int32_t network_init() { int32_t network_init() {
return enet_initialize() != 0; return enet_initialize() != 0;
} }
int32_t network_destroy() { int32_t network_destroy() {
enet_deinitialize(); enet_deinitialize();
return 0; return 0;
} }
//~ NOTE(zaklaus): client //~ NOTE(zaklaus): client
int32_t network_client_connect(const char *hostname, uint16_t port) { int32_t network_client_connect(const char *hostname, uint16_t port) {
ENetAddress address = {0}; address.port = port; ENetAddress address = {0}; address.port = port;
enet_address_set_host(&address, hostname); enet_address_set_host(&address, hostname);
host = enet_host_create(NULL, 1, 2, 0, 0); host = enet_host_create(NULL, 1, 2, 0, 0);
peer = enet_host_connect(host, &address, 2, 0); peer = enet_host_connect(host, &address, 2, 0);
if (peer == NULL) { if (peer == NULL) {
zpl_printf("[ERROR] Cannot connect to specicied server: %s:%d\n", hostname, port); zpl_printf("[ERROR] Cannot connect to specicied server: %s:%d\n", hostname, port);
return 1; return 1;
} }
world = librg_world_create(); world = librg_world_create();
librg_world_userdata_set(world, peer); librg_world_userdata_set(world, peer);
return 0; return 0;
} }
int32_t network_client_disconnect() { int32_t network_client_disconnect() {
enet_peer_disconnect_now(peer, 0); enet_peer_disconnect_now(peer, 0);
enet_host_destroy(host); enet_host_destroy(host);
librg_world_destroy(world); librg_world_destroy(world);
peer = NULL; peer = NULL;
host = NULL; host = NULL;
world = NULL; world = NULL;
return 0; return 0;
} }
int32_t network_client_tick() { int32_t network_client_tick() {
ENetEvent event = {0}; ENetEvent event = {0};
while (enet_host_service(host, &event, 1) > 0) { while (enet_host_service(host, &event, 1) > 0) {
switch (event.type) { switch (event.type) {
case ENET_EVENT_TYPE_CONNECT: { case ENET_EVENT_TYPE_CONNECT: {
zpl_printf("[INFO] We connected to the server.\n"); zpl_printf("[INFO] We connected to the server.\n");
pkt_00_init_send(0); pkt_00_init_send(0);
} break; } break;
case ENET_EVENT_TYPE_DISCONNECT: case ENET_EVENT_TYPE_DISCONNECT:
case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: { case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: {
zpl_printf("[INFO] We disconnected from server.\n"); zpl_printf("[INFO] We disconnected from server.\n");
} break; } break;
case ENET_EVENT_TYPE_RECEIVE: { case ENET_EVENT_TYPE_RECEIVE: {
if (!world_read(event.packet->data, event.packet->dataLength, event.peer)) { if (!world_read(event.packet->data, event.packet->dataLength, event.peer)) {
zpl_printf("[INFO] Server sent us an unsupported packet.\n"); zpl_printf("[INFO] Server sent us an unsupported packet.\n");
} }
/* Clean up the packet now that we're done using it. */ /* Clean up the packet now that we're done using it. */
enet_packet_destroy(event.packet); enet_packet_destroy(event.packet);
} break; } break;
case ENET_EVENT_TYPE_NONE: break; case ENET_EVENT_TYPE_NONE: break;
} }
} }
return 0; return 0;
} }
bool network_client_is_connected() { bool network_client_is_connected() {
return peer ? enet_peer_get_state(peer) == ENET_PEER_STATE_CONNECTED : false; return peer ? enet_peer_get_state(peer) == ENET_PEER_STATE_CONNECTED : false;
} }
//~ NOTE(zaklaus): server //~ NOTE(zaklaus): server
int32_t network_server_start(const char *host, uint16_t port) { int32_t network_server_start(const char *host, uint16_t port) {
(void)host; (void)host;
ENetAddress address = {0}; ENetAddress address = {0};
address.host = ENET_HOST_ANY; address.host = ENET_HOST_ANY;
address.port = port; address.port = port;
server = enet_host_create(&address, 8, 2, 0, 0); server = enet_host_create(&address, 8, 2, 0, 0);
if (server == NULL) { if (server == NULL) {
zpl_printf("[ERROR] An error occured while trying to create a server host.\n"); zpl_printf("[ERROR] An error occured while trying to create a server host.\n");
return 1; return 1;
} }
return 0; return 0;
} }
int32_t network_server_stop(void) { int32_t network_server_stop(void) {
enet_host_destroy(server); enet_host_destroy(server);
server = 0; server = 0;
return 0; return 0;
} }
int32_t network_server_tick(void) { int32_t network_server_tick(void) {
ENetEvent event = {0}; ENetEvent event = {0};
while (enet_host_service(server, &event, 1) > 0) { while (enet_host_service(server, &event, 1) > 0) {
switch (event.type) { switch (event.type) {
case ENET_EVENT_TYPE_CONNECT: { case ENET_EVENT_TYPE_CONNECT: {
zpl_printf("[INFO] A new user %d connected.\n", event.peer->incomingPeerID); zpl_printf("[INFO] A new user %d connected.\n", event.peer->incomingPeerID);
} break; } break;
case ENET_EVENT_TYPE_DISCONNECT: case ENET_EVENT_TYPE_DISCONNECT:
case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: { case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: {
zpl_printf("[INFO] A user %d disconnected.\n", event.peer->incomingPeerID); zpl_printf("[INFO] A user %d disconnected.\n", event.peer->incomingPeerID);
if (event.peer->data) { if (event.peer->data) {
player_despawn((ecs_entity_t)event.peer->data); player_despawn((ecs_entity_t)event.peer->data);
event.peer->data = 0; event.peer->data = 0;
} }
} break; } break;
case ENET_EVENT_TYPE_RECEIVE: { case ENET_EVENT_TYPE_RECEIVE: {
if (!world_read(event.packet->data, event.packet->dataLength, event.peer)) { if (!world_read(event.packet->data, event.packet->dataLength, event.peer)) {
zpl_printf("[INFO] User %d sent us a malformed packet.\n", event.peer->incomingPeerID); zpl_printf("[INFO] User %d sent us a malformed packet.\n", event.peer->incomingPeerID);
} }
/* Clean up the packet now that we're done using it. */ /* Clean up the packet now that we're done using it. */
enet_packet_destroy(event.packet); enet_packet_destroy(event.packet);
} break; } break;
case ENET_EVENT_TYPE_NONE: break; case ENET_EVENT_TYPE_NONE: break;
} }
} }
return 0; return 0;
} }
void network_server_assign_entity(void *peer_id, uint64_t ent_id) { void network_server_assign_entity(void *peer_id, uint64_t ent_id) {
ENetPeer *peer = (ENetPeer *)peer_id; ENetPeer *peer = (ENetPeer *)peer_id;
peer->data = (void*)ent_id; peer->data = (void*)ent_id;
} }
uint64_t network_server_get_entity(void *peer_id) { uint64_t network_server_get_entity(void *peer_id) {
if (game_get_kind() == GAMEKIND_SINGLE) { if (game_get_kind() == GAMEKIND_SINGLE) {
return (uint64_t)peer_id; return (uint64_t)peer_id;
} }
ENetPeer *peer = (ENetPeer *)peer_id; ENetPeer *peer = (ENetPeer *)peer_id;
ZPL_ASSERT(peer->data); ZPL_ASSERT(peer->data);
return (uint64_t)peer->data; return (uint64_t)peer->data;
} }
//~ NOTE(zaklaus): messaging //~ NOTE(zaklaus): messaging
static int32_t network_msg_send_raw(ENetPeer *peer_id, void *data, size_t datalen, uint32_t flags, uint16_t channel_id) { static int32_t network_msg_send_raw(ENetPeer *peer_id, void *data, size_t datalen, uint32_t flags, uint16_t channel_id) {
if (peer_id == 0) peer_id = peer; if (peer_id == 0) peer_id = peer;
ENetPacket *packet = enet_packet_create(data, datalen, flags); ENetPacket *packet = enet_packet_create(data, datalen, flags);
return enet_peer_send(peer_id, channel_id, packet); return enet_peer_send(peer_id, channel_id, packet);
} }
int32_t network_msg_send(void *peer_id, void *data, size_t datalen, uint16_t channel_id) { int32_t network_msg_send(void *peer_id, void *data, size_t datalen, uint16_t channel_id) {
return network_msg_send_raw(peer_id, data, datalen, ENET_PACKET_FLAG_RELIABLE, channel_id); return network_msg_send_raw(peer_id, data, datalen, ENET_PACKET_FLAG_RELIABLE, channel_id);
} }
int32_t network_msg_send_unreliable(void *peer_id, void *data, size_t datalen, uint16_t channel_id) { int32_t network_msg_send_unreliable(void *peer_id, void *data, size_t datalen, uint16_t channel_id) {
return network_msg_send_raw(peer_id, data, datalen, 0, channel_id); return network_msg_send_raw(peer_id, data, datalen, 0, channel_id);
} }

View File

@ -1,71 +1,71 @@
#include "packet_utils.h" #include "packet_utils.h"
#include "network.h" #include "network.h"
#include "packets/pkt_send_keystate.h" #include "packets/pkt_send_keystate.h"
#include "modules/components.h" #include "modules/components.h"
#include "modules/systems.h" #include "modules/systems.h"
#include "world/world.h" #include "world/world.h"
#include "debug_replay.h" #include "debug_replay.h"
pkt_desc pkt_send_keystate_desc[] = { pkt_desc pkt_send_keystate_desc[] = {
{ PKT_REAL(pkt_send_keystate, x) }, { PKT_REAL(pkt_send_keystate, x) },
{ PKT_REAL(pkt_send_keystate, y) }, { PKT_REAL(pkt_send_keystate, y) },
{ PKT_REAL(pkt_send_keystate, mx) }, { PKT_REAL(pkt_send_keystate, mx) },
{ PKT_REAL(pkt_send_keystate, my) }, { PKT_REAL(pkt_send_keystate, my) },
{ PKT_UINT(pkt_send_keystate, use) }, { PKT_UINT(pkt_send_keystate, use) },
{ PKT_UINT(pkt_send_keystate, sprint) }, { PKT_UINT(pkt_send_keystate, sprint) },
{ PKT_UINT(pkt_send_keystate, ctrl) }, { PKT_UINT(pkt_send_keystate, ctrl) },
{ PKT_UINT(pkt_send_keystate, selected_item) }, { PKT_UINT(pkt_send_keystate, selected_item) },
{ PKT_UINT(pkt_send_keystate, drop) }, { PKT_UINT(pkt_send_keystate, drop) },
{ PKT_UINT(pkt_send_keystate, swap) }, { PKT_UINT(pkt_send_keystate, swap) },
{ PKT_UINT(pkt_send_keystate, swap_from) }, { PKT_UINT(pkt_send_keystate, swap_from) },
{ PKT_UINT(pkt_send_keystate, swap_to) }, { PKT_UINT(pkt_send_keystate, swap_to) },
{ PKT_UINT(pkt_send_keystate, placement_num) }, { PKT_UINT(pkt_send_keystate, placement_num) },
{ PKT_ARRAY(pkt_send_keystate, placements) }, { PKT_ARRAY(pkt_send_keystate, placements) },
{ PKT_END }, { PKT_END },
}; };
size_t pkt_send_keystate_send(uint16_t view_id, size_t pkt_send_keystate_send(uint16_t view_id,
game_keystate_data *data) { game_keystate_data *data) {
return pkt_world_write(MSG_ID_SEND_KEYSTATE, pkt_send_keystate_encode(data), 1, view_id, NULL, 1); return pkt_world_write(MSG_ID_SEND_KEYSTATE, pkt_send_keystate_encode(data), 1, view_id, NULL, 1);
} }
size_t pkt_send_keystate_encode(pkt_send_keystate *table) { size_t pkt_send_keystate_encode(pkt_send_keystate *table) {
cw_pack_context pc = {0}; cw_pack_context pc = {0};
pkt_pack_msg(&pc, pkt_pack_desc_args(pkt_send_keystate_desc)); pkt_pack_msg(&pc, pkt_pack_desc_args(pkt_send_keystate_desc));
pkt_pack_struct(&pc, pkt_send_keystate_desc, PKT_STRUCT_PTR(table)); pkt_pack_struct(&pc, pkt_send_keystate_desc, PKT_STRUCT_PTR(table));
return pkt_pack_msg_size(&pc); return pkt_pack_msg_size(&pc);
} }
int32_t pkt_send_keystate_handler(pkt_header *header) { int32_t pkt_send_keystate_handler(pkt_header *header) {
pkt_send_keystate table; pkt_send_keystate table;
PKT_IF(pkt_msg_decode(header, pkt_send_keystate_desc, pkt_pack_desc_args(pkt_send_keystate_desc), PKT_STRUCT_PTR(&table))); PKT_IF(pkt_msg_decode(header, pkt_send_keystate_desc, pkt_pack_desc_args(pkt_send_keystate_desc), PKT_STRUCT_PTR(&table)));
ecs_entity_t e = network_server_get_entity(header->udata); ecs_entity_t e = network_server_get_entity(header->udata);
if (!world_entity_valid(e)) if (!world_entity_valid(e))
return 1; return 1;
Input *i = ecs_get_mut(world_ecs(), e, Input, NULL); Input *i = ecs_get_mut(world_ecs(), e, Input, NULL);
if (i && !i->is_blocked) { if (i && !i->is_blocked) {
i->x = zpl_clamp(table.x, -1.0f, 1.0f); i->x = zpl_clamp(table.x, -1.0f, 1.0f);
i->y = zpl_clamp(table.y, -1.0f, 1.0f); i->y = zpl_clamp(table.y, -1.0f, 1.0f);
i->mx = table.mx; i->mx = table.mx;
i->my = table.my; i->my = table.my;
i->use = table.use; i->use = table.use;
i->sprint = table.sprint; i->sprint = table.sprint;
i->ctrl = table.ctrl; i->ctrl = table.ctrl;
i->selected_item = zpl_clamp(table.selected_item, 0, ITEMS_INVENTORY_SIZE-1); i->selected_item = zpl_clamp(table.selected_item, 0, ITEMS_INVENTORY_SIZE-1);
i->drop = table.drop; i->drop = table.drop;
i->swap = table.swap; i->swap = table.swap;
i->swap_from = zpl_clamp(table.swap_from, 0, ITEMS_INVENTORY_SIZE-1); i->swap_from = zpl_clamp(table.swap_from, 0, ITEMS_INVENTORY_SIZE-1);
i->swap_to = zpl_clamp(table.swap_to, 0, ITEMS_INVENTORY_SIZE-1); i->swap_to = zpl_clamp(table.swap_to, 0, ITEMS_INVENTORY_SIZE-1);
i->num_placements = zpl_clamp(table.placement_num, 0, BUILD_MAX_PLACEMENTS); i->num_placements = zpl_clamp(table.placement_num, 0, BUILD_MAX_PLACEMENTS);
for (uint8_t j = 0; j < i->num_placements; j++) { for (uint8_t j = 0; j < i->num_placements; j++) {
i->placements_x[j] = table.placements[j].x; i->placements_x[j] = table.placements[j].x;
i->placements_y[j] = table.placements[j].y; i->placements_y[j] = table.placements[j].y;
} }
debug_replay_record_keystate(table); debug_replay_record_keystate(table);
} }
return 0; return 0;
} }

View File

@ -1,33 +1,33 @@
#pragma once #pragma once
#include "system.h" #include "system.h"
#include "packet_utils.h" #include "packet_utils.h"
#include "item_placement.h" #include "item_placement.h"
typedef struct { typedef struct {
float x; float x;
float y; float y;
float mx; float mx;
float my; float my;
uint8_t use; uint8_t use;
uint8_t sprint; uint8_t sprint;
uint8_t ctrl; uint8_t ctrl;
uint8_t selected_item; uint8_t selected_item;
uint8_t drop; uint8_t drop;
uint8_t swap; uint8_t swap;
uint8_t swap_from; uint8_t swap_from;
uint8_t swap_to; uint8_t swap_to;
// TODO(zaklaus): build mode // TODO(zaklaus): build mode
uint8_t placement_num; uint8_t placement_num;
item_placement placements[BUILD_MAX_PLACEMENTS]; item_placement placements[BUILD_MAX_PLACEMENTS];
} pkt_send_keystate; } pkt_send_keystate;
typedef pkt_send_keystate game_keystate_data; typedef pkt_send_keystate game_keystate_data;
size_t pkt_send_keystate_send(uint16_t view_id, size_t pkt_send_keystate_send(uint16_t view_id,
game_keystate_data *data); game_keystate_data *data);
size_t pkt_send_keystate_encode(pkt_send_keystate *table); size_t pkt_send_keystate_encode(pkt_send_keystate *table);
extern pkt_desc pkt_send_keystate_desc[]; extern pkt_desc pkt_send_keystate_desc[];
PKT_HANDLER_PROC(pkt_send_keystate_handler); PKT_HANDLER_PROC(pkt_send_keystate_handler);

View File

@ -58,6 +58,29 @@ uint8_t platform_is_running() {
return !WindowShouldClose(); return !WindowShouldClose();
} }
static game_keystate_data last_input_data = {0};
void platform_input_update_input_frame(game_keystate_data data) {
// NOTE(zaklaus): Test if there are any changes
if (data.x != last_input_data.x) goto send_data;
if (data.y != last_input_data.y) goto send_data;
if (data.use != last_input_data.use) goto send_data;
if (data.sprint != last_input_data.sprint) goto send_data;
if (data.ctrl != last_input_data.ctrl) goto send_data;
if (data.selected_item != last_input_data.selected_item) goto send_data;
if (data.drop != last_input_data.drop) goto send_data;
if (data.swap != last_input_data.swap) goto send_data;
if (data.swap_from != last_input_data.swap_from) goto send_data;
if (data.swap_to != last_input_data.swap_to) goto send_data;
if (data.placement_num != last_input_data.placement_num) goto send_data;
if (zpl_memcompare(data.placements, last_input_data.placements, zpl_size_of(data.placements))) goto send_data;
return;
send_data:
last_input_data = data;
game_action_send_keystate(&data);
}
void platform_input() { void platform_input() {
float mouse_z = (GetMouseWheelMove()*0.5f); float mouse_z = (GetMouseWheelMove()*0.5f);
@ -92,7 +115,7 @@ void platform_input() {
y = -mouse_pos.y; y = -mouse_pos.y;
} }
game_keystate_data data = { game_keystate_data in_data = {
.x = x, .x = x,
.y = y, .y = y,
.mx = mouse_pos.x, .mx = mouse_pos.x,
@ -111,11 +134,11 @@ void platform_input() {
if (build_submit_placements) { if (build_submit_placements) {
build_submit_placements = false; build_submit_placements = false;
data.placement_num = build_num_placements; in_data.placement_num = build_num_placements;
zpl_memcopy(data.placements, build_placements, build_num_placements*zpl_size_of(item_placement)); zpl_memcopy(in_data.placements, build_placements, build_num_placements*zpl_size_of(item_placement));
} }
game_action_send_keystate(&data); platform_input_update_input_frame(in_data);
} }
// NOTE(zaklaus): cycle through viewers // NOTE(zaklaus): cycle through viewers

View File

@ -1,36 +1,36 @@
#include "player.h" #include "player.h"
#include "entity.h" #include "entity.h"
#include "entity_view.h" #include "entity_view.h"
#include "flecs/flecs.h" #include "flecs/flecs.h"
#include "flecs/flecs_meta.h" #include "flecs/flecs_meta.h"
#include "librg.h" #include "librg.h"
#include "world/world.h" #include "world/world.h"
#include "modules/components.h" #include "modules/components.h"
#include "modules/systems.h" #include "modules/systems.h"
#include "zpl.h" #include "zpl.h"
#define PLAYER_MAX_HP 100.0f #define PLAYER_MAX_HP 100.0f
uint64_t player_spawn(char *name) { uint64_t player_spawn(char *name) {
ecs_entity_t e = entity_spawn(EKIND_PLAYER); ecs_entity_t e = entity_spawn(EKIND_PLAYER);
if (!name) { if (!name) {
name = zpl_bprintf("player_%d", e); name = zpl_bprintf("player_%d", e);
} }
ecs_set_name(world_ecs(), e, name); ecs_set_name(world_ecs(), e, name);
ecs_set(world_ecs(), e, ClientInfo, {0}); ecs_set(world_ecs(), e, ClientInfo, {0});
ecs_set(world_ecs(), e, Input, {0}); ecs_set(world_ecs(), e, Input, {0});
ecs_set(world_ecs(), e, Inventory, {0}); ecs_set(world_ecs(), e, Inventory, {0});
ecs_set(world_ecs(), e, Health, {.hp = PLAYER_MAX_HP, .max_hp = PLAYER_MAX_HP}); ecs_set(world_ecs(), e, Health, {.hp = PLAYER_MAX_HP, .max_hp = PLAYER_MAX_HP});
ecs_add(world_ecs(), e, Player); ecs_add(world_ecs(), e, Player);
librg_entity_owner_set(world_tracker(), e, (int64_t)e); librg_entity_owner_set(world_tracker(), e, (int64_t)e);
return (uint64_t)e; return (uint64_t)e;
} }
void player_despawn(uint64_t ent_id) { void player_despawn(uint64_t ent_id) {
entity_despawn(ent_id); entity_despawn(ent_id);
} }

View File

@ -1,120 +1,120 @@
#include "zpl.h" #include "zpl.h"
#include "prediction.h" #include "prediction.h"
#include "platform.h" #include "platform.h"
#include "world/world.h" #include "world/world.h"
#include "game.h" #include "game.h"
#define PREDICT_SMOOTH_FACTOR_LO 7.5 #define PREDICT_SMOOTH_FACTOR_LO 7.5
#define PREDICT_SMOOTH_FACTOR_HI 12.5 #define PREDICT_SMOOTH_FACTOR_HI 12.5
static inline float map_factor(float x) { static inline float map_factor(float x) {
x = 1.0f - zpl_clamp01(x); x = 1.0f - zpl_clamp01(x);
return 1.0f - x*x*x*x*x*x*x*x; return 1.0f - x*x*x*x*x*x*x*x;
} }
static inline float base_angle(float x) { static inline float base_angle(float x) {
while (x > ZPL_TAU) x -= ZPL_TAU; while (x > ZPL_TAU) x -= ZPL_TAU;
while (x < 0.0f) x += ZPL_TAU; while (x < 0.0f) x += ZPL_TAU;
return x; return x;
} }
static inline float spherical_lerp(float a, float b, float t) { static inline float spherical_lerp(float a, float b, float t) {
a = base_angle(a); a = base_angle(a);
b = base_angle(b); b = base_angle(b);
float d = b - a; float d = b - a;
if (d < -ZPL_PI) { if (d < -ZPL_PI) {
b += ZPL_TAU; b += ZPL_TAU;
} else if (d > ZPL_PI) { } else if (d > ZPL_PI) {
b -= ZPL_TAU; b -= ZPL_TAU;
} }
return base_angle(zpl_lerp(a, b, t)); return base_angle(zpl_lerp(a, b, t));
} }
float smooth_val(float cur, float tgt, uint64_t dt) { float smooth_val(float cur, float tgt, uint64_t dt) {
float factor = zpl_clamp01(map_factor(zpl_unlerp(dt, WORLD_TRACKER_UPDATE_MP_FAST_MS, WORLD_TRACKER_UPDATE_MP_SLOW_MS))); float factor = zpl_clamp01(map_factor(zpl_unlerp(dt, WORLD_TRACKER_UPDATE_MP_FAST_MS, WORLD_TRACKER_UPDATE_MP_SLOW_MS)));
#if 0 #if 0
dt = 200; dt = 200;
factor = map_factor(zpl_unlerp(dt, WORLD_TRACKER_UPDATE_MP_FAST_MS, WORLD_TRACKER_UPDATE_MP_SLOW_MS)); factor = map_factor(zpl_unlerp(dt, WORLD_TRACKER_UPDATE_MP_FAST_MS, WORLD_TRACKER_UPDATE_MP_SLOW_MS));
zpl_printf("lerp factor: %f\n", factor); zpl_printf("lerp factor: %f\n", factor);
zpl_exit(0); zpl_exit(0);
#endif #endif
return zpl_lerp(cur, tgt, zpl_clamp01(zpl_lerp(PREDICT_SMOOTH_FACTOR_LO, PREDICT_SMOOTH_FACTOR_HI, factor)*platform_frametime())); return zpl_lerp(cur, tgt, zpl_clamp01(zpl_lerp(PREDICT_SMOOTH_FACTOR_LO, PREDICT_SMOOTH_FACTOR_HI, factor)*platform_frametime()));
} }
float smooth_val_spherical(float cur, float tgt, uint64_t dt) { float smooth_val_spherical(float cur, float tgt, uint64_t dt) {
float factor = zpl_clamp01(map_factor(zpl_unlerp(dt, WORLD_TRACKER_UPDATE_MP_FAST_MS, WORLD_TRACKER_UPDATE_MP_SLOW_MS))); float factor = zpl_clamp01(map_factor(zpl_unlerp(dt, WORLD_TRACKER_UPDATE_MP_FAST_MS, WORLD_TRACKER_UPDATE_MP_SLOW_MS)));
return spherical_lerp(cur, tgt, zpl_clamp01(zpl_lerp(PREDICT_SMOOTH_FACTOR_LO, PREDICT_SMOOTH_FACTOR_HI, factor)*platform_frametime())); return spherical_lerp(cur, tgt, zpl_clamp01(zpl_lerp(PREDICT_SMOOTH_FACTOR_LO, PREDICT_SMOOTH_FACTOR_HI, factor)*platform_frametime()));
} }
void predict_receive_update(entity_view *d, entity_view *data) { void predict_receive_update(entity_view *d, entity_view *data) {
if (d && data->flag & EFLAG_INTERP) { if (d && data->flag & EFLAG_INTERP) {
// NOTE(zaklaus): store target pos but keep x,y unchanged // NOTE(zaklaus): store target pos but keep x,y unchanged
float tx = data->x; float tx = data->x;
float ty = data->y; float ty = data->y;
float theading = data->heading; float theading = data->heading;
data->x = d->x; data->x = d->x;
data->y = d->y; data->y = d->y;
data->heading = d->heading; data->heading = d->heading;
data->tx = tx; data->tx = tx;
data->ty = ty; data->ty = ty;
data->theading = theading; data->theading = theading;
} }
data->tran_effect = d->tran_effect; data->tran_effect = d->tran_effect;
data->tran_time = d->tran_time; data->tran_time = d->tran_time;
} }
#define ENTITY_DO_LERP_SP 0 #define ENTITY_DO_LERP_SP 0
void lerp_entity_positions(uint64_t key, entity_view *data) { void lerp_entity_positions(uint64_t key, entity_view *data) {
(void)key; (void)key;
world_view *view = game_world_view_get_active(); world_view *view = game_world_view_get_active();
if (data->flag == EFLAG_INTERP) { if (data->flag == EFLAG_INTERP) {
#if ENTITY_DO_LERP_SP==0 #if ENTITY_DO_LERP_SP==0
if (game_get_kind() == GAMEKIND_CLIENT) if (game_get_kind() == GAMEKIND_CLIENT)
#else #else
if (1) if (1)
#endif #endif
{ {
data->x = smooth_val(data->x, data->tx, view->delta_time[data->layer_id]); data->x = smooth_val(data->x, data->tx, view->delta_time[data->layer_id]);
data->y = smooth_val(data->y, data->ty, view->delta_time[data->layer_id]); data->y = smooth_val(data->y, data->ty, view->delta_time[data->layer_id]);
data->heading = smooth_val_spherical(data->heading, data->theading, view->delta_time[data->layer_id]); data->heading = smooth_val_spherical(data->heading, data->theading, view->delta_time[data->layer_id]);
} else { } else {
(void)view; (void)view;
data->x = data->tx; data->x = data->tx;
data->y = data->ty; data->y = data->ty;
data->heading = data->theading; data->heading = data->theading;
} }
} }
} }
void do_entity_fadeinout(uint64_t key, entity_view * data) { void do_entity_fadeinout(uint64_t key, entity_view * data) {
(void)key; (void)key;
switch (data->tran_effect) { switch (data->tran_effect) {
case ETRAN_FADEIN: { case ETRAN_FADEIN: {
data->tran_time += platform_frametime(); data->tran_time += platform_frametime();
if (data->tran_time > 1.0f) { if (data->tran_time > 1.0f) {
data->tran_effect = ETRAN_NONE; data->tran_effect = ETRAN_NONE;
data->tran_time = 1.0f; data->tran_time = 1.0f;
} }
}break; }break;
case ETRAN_FADEOUT: { case ETRAN_FADEOUT: {
data->tran_time -= platform_frametime(); data->tran_time -= platform_frametime();
if (data->tran_time < 0.0f) { if (data->tran_time < 0.0f) {
data->tran_effect = ETRAN_REMOVE; data->tran_effect = ETRAN_REMOVE;
data->tran_time = 0.0f; data->tran_time = 0.0f;
} }
}break; }break;
default: break; default: break;
} }
} }

View File

@ -1,61 +1,61 @@
#include "profiler.h" #include "profiler.h"
#include "raylib.h" #include "raylib.h"
#include <assert.h> #include <assert.h>
#define PROF_COLLATE_WINDOW 0.5 #define PROF_COLLATE_WINDOW 0.5
// NOTE(zaklaus): KEEP ORDER IN SYNC WITH profiler_kind ENUM !!! // NOTE(zaklaus): KEEP ORDER IN SYNC WITH profiler_kind ENUM !!!
static profiler profilers[] = { static profiler profilers[] = {
{ .id = PROF_TOTAL_TIME, .name = "measured time" }, { .id = PROF_TOTAL_TIME, .name = "measured time" },
{ .id = PROF_MAIN_LOOP, .name = "main loop" }, { .id = PROF_MAIN_LOOP, .name = "main loop" },
{ .id = PROF_WORLD_WRITE, .name = "world write" }, { .id = PROF_WORLD_WRITE, .name = "world write" },
{ .id = PROF_RENDER, .name = "render" }, { .id = PROF_RENDER, .name = "render" },
{ .id = PROF_UPDATE_SYSTEMS, .name = "update systems" }, { .id = PROF_UPDATE_SYSTEMS, .name = "update systems" },
{ .id = PROF_ENTITY_LERP, .name = "entity lerp" }, { .id = PROF_ENTITY_LERP, .name = "entity lerp" },
{ .id = PROF_INTEGRATE_POS, .name = "entity movement" }, { .id = PROF_INTEGRATE_POS, .name = "entity movement" },
}; };
static_assert((sizeof(profilers)/sizeof(profilers[0])) == MAX_PROF, "mismatched profilers"); static_assert((sizeof(profilers)/sizeof(profilers[0])) == MAX_PROF, "mismatched profilers");
void profiler_reset(profiler_kind id) { void profiler_reset(profiler_kind id) {
profilers[id].num_invocations = 0; profilers[id].num_invocations = 0;
profilers[id].total_time = 0.0; profilers[id].total_time = 0.0;
} }
void profiler_start(profiler_kind id) { void profiler_start(profiler_kind id) {
profilers[id].start_time = GetTime(); profilers[id].start_time = GetTime();
} }
void profiler_stop(profiler_kind id) { void profiler_stop(profiler_kind id) {
profilers[id].num_invocations += 1; profilers[id].num_invocations += 1;
profilers[id].total_time += GetTime() - profilers[id].start_time; profilers[id].total_time += GetTime() - profilers[id].start_time;
profilers[id].start_time = 0.0; profilers[id].start_time = 0.0;
} }
void profiler_collate() { void profiler_collate() {
static double frame_counter = 0.0; static double frame_counter = 0.0;
static uint64_t frames = 0; static uint64_t frames = 0;
frame_counter += GetFrameTime(); frame_counter += GetFrameTime();
frames++; frames++;
if (frame_counter >= PROF_COLLATE_WINDOW) { if (frame_counter >= PROF_COLLATE_WINDOW) {
profilers[PROF_TOTAL_TIME].delta_time = frame_counter / (double)frames; profilers[PROF_TOTAL_TIME].delta_time = frame_counter / (double)frames;
for (uint32_t i = PROF_MAIN_LOOP; i < MAX_PROF; i += 1) { for (uint32_t i = PROF_MAIN_LOOP; i < MAX_PROF; i += 1) {
profiler *p = &profilers[i]; profiler *p = &profilers[i];
p->delta_time = p->num_invocations == 0 ? 0.0 : p->total_time / (double)p->num_invocations; p->delta_time = p->num_invocations == 0 ? 0.0 : p->total_time / (double)p->num_invocations;
} }
frame_counter = 0.0; frame_counter = 0.0;
frames = 0; frames = 0;
} }
} }
double profiler_delta(profiler_kind id) { double profiler_delta(profiler_kind id) {
return profilers[id].delta_time; return profilers[id].delta_time;
} }
char const *profiler_name(profiler_kind id) { char const *profiler_name(profiler_kind id) {
return profilers[id].name; return profilers[id].name;
} }

View File

@ -1,36 +1,36 @@
#pragma once #pragma once
#include "system.h" #include "system.h"
typedef enum { typedef enum {
PROF_TOTAL_TIME, PROF_TOTAL_TIME,
PROF_MAIN_LOOP, PROF_MAIN_LOOP,
PROF_WORLD_WRITE, PROF_WORLD_WRITE,
PROF_RENDER, PROF_RENDER,
PROF_UPDATE_SYSTEMS, PROF_UPDATE_SYSTEMS,
PROF_ENTITY_LERP, PROF_ENTITY_LERP,
PROF_INTEGRATE_POS, PROF_INTEGRATE_POS,
MAX_PROF, MAX_PROF,
PROF_FORCE_UINT8 = UINT8_MAX PROF_FORCE_UINT8 = UINT8_MAX
} profiler_kind; } profiler_kind;
typedef struct { typedef struct {
profiler_kind id; profiler_kind id;
char const *name; char const *name;
uint32_t num_invocations; uint32_t num_invocations;
double start_time; double start_time;
double delta_time; double delta_time;
double total_time; double total_time;
} profiler; } profiler;
void profiler_reset(profiler_kind id); void profiler_reset(profiler_kind id);
void profiler_start(profiler_kind id); void profiler_start(profiler_kind id);
void profiler_stop(profiler_kind id); void profiler_stop(profiler_kind id);
void profiler_collate(void); void profiler_collate(void);
double profiler_delta(profiler_kind id); double profiler_delta(profiler_kind id);
char const *profiler_name(profiler_kind id); char const *profiler_name(profiler_kind id);
#define profile(id) defer(profiler_start(id), profiler_stop(id)) #define profile(id) defer(profiler_start(id), profiler_stop(id))

View File

@ -1,209 +1,209 @@
static Camera2D render_camera; static Camera2D render_camera;
static float zoom_overlay_tran = 0.0f; static float zoom_overlay_tran = 0.0f;
#define CAM_OVERLAY_ZOOM_LEVEL 0.80f #define CAM_OVERLAY_ZOOM_LEVEL 0.80f
#define ALPHA(x) ColorAlpha(x, data->tran_time) #define ALPHA(x) ColorAlpha(x, data->tran_time)
float zpl_lerp(float,float,float); float zpl_lerp(float,float,float);
float zpl_to_degrees(float); float zpl_to_degrees(float);
void DEBUG_draw_ground(uint64_t key, entity_view * data) { void DEBUG_draw_ground(uint64_t key, entity_view * data) {
(void)key; (void)key;
switch (data->kind) { switch (data->kind) {
case EKIND_CHUNK: { case EKIND_CHUNK: {
world_view *view = game_world_view_get_active(); world_view *view = game_world_view_get_active();
int32_t size = view->chunk_size * WORLD_BLOCK_SIZE; int32_t size = view->chunk_size * WORLD_BLOCK_SIZE;
int16_t offset = 0; int16_t offset = 0;
float x = data->x * size + offset; float x = data->x * size + offset;
float y = data->y * size + offset; float y = data->y * size + offset;
RenderTexture2D tex = GetChunkTexture(key); RenderTexture2D tex = GetChunkTexture(key);
float scale = (size)/(float)(tex.texture.width); float scale = (size)/(float)(tex.texture.width);
tex.texture.width *= scale; tex.texture.width *= scale;
tex.texture.height *= scale; tex.texture.height *= scale;
DrawTextureRec(tex.texture, (Rectangle){0, 0, size, -size}, (Vector2){x, y}, ColorAlpha(WHITE, data->tran_time)); DrawTextureRec(tex.texture, (Rectangle){0, 0, size, -size}, (Vector2){x, y}, ColorAlpha(WHITE, data->tran_time));
if (zoom_overlay_tran > 0.02f) { if (zoom_overlay_tran > 0.02f) {
DrawRectangleEco(x, y, size-offset, size-offset, ColorAlpha(ColorFromHSV(data->color, 0.13f, 0.89f), data->tran_time*zoom_overlay_tran*0.75f)); DrawRectangleEco(x, y, size-offset, size-offset, ColorAlpha(ColorFromHSV(data->color, 0.13f, 0.89f), data->tran_time*zoom_overlay_tran*0.75f));
DrawTextEco(TextFormat("%d %d", (int)data->x, (int)data->y), (int16_t)x+15, (int16_t)y+15, 200 , ColorAlpha(BLACK, data->tran_time*zoom_overlay_tran), 0.0); DrawTextEco(TextFormat("%d %d", (int)data->x, (int)data->y), (int16_t)x+15, (int16_t)y+15, 200 , ColorAlpha(BLACK, data->tran_time*zoom_overlay_tran), 0.0);
} }
}break; }break;
default:break; default:break;
} }
} }
extern bool inv_is_open; extern bool inv_is_open;
void DEBUG_draw_entities(uint64_t key, entity_view * data) { void DEBUG_draw_entities(uint64_t key, entity_view * data) {
uint16_t size = 16; uint16_t size = 16;
uint16_t font_size = (uint16_t)lerp(4.0f, 32.0f, 0.5f/(float)render_camera.zoom); uint16_t font_size = (uint16_t)lerp(4.0f, 32.0f, 0.5f/(float)render_camera.zoom);
float font_spacing = 1.1f; float font_spacing = 1.1f;
float title_bg_offset = 4; float title_bg_offset = 4;
float fixed_title_offset = 8; float fixed_title_offset = 8;
switch (data->kind) { switch (data->kind) {
case EKIND_DEMO_NPC: { case EKIND_DEMO_NPC: {
float x = data->x; float x = data->x;
float y = data->y; float y = data->y;
DrawCircleEco(x, y, size, ColorAlpha(BLUE, data->tran_time)); DrawCircleEco(x, y, size, ColorAlpha(BLUE, data->tran_time));
}break; }break;
case EKIND_PLAYER: { case EKIND_PLAYER: {
float x = data->x; float x = data->x;
float y = data->y; float y = data->y;
float health = (data->hp / data->max_hp); float health = (data->hp / data->max_hp);
const char *title = TextFormat("Player %d", key); const char *title = TextFormat("Player %d", key);
int title_w = MeasureTextEco(title, font_size, font_spacing); int title_w = MeasureTextEco(title, font_size, font_spacing);
DrawRectangleEco(x-title_w/2-title_bg_offset/2, y-size-font_size-fixed_title_offset, title_w+title_bg_offset, font_size, ColorAlpha(BLACK, data->tran_time)); DrawRectangleEco(x-title_w/2-title_bg_offset/2, y-size-font_size-fixed_title_offset, title_w+title_bg_offset, font_size, ColorAlpha(BLACK, data->tran_time));
DrawRectangleEco(x-title_w/2-title_bg_offset/2, y-size-fixed_title_offset, title_w*health+title_bg_offset, font_size*0.2f, ColorAlpha(RED, data->tran_time)); DrawRectangleEco(x-title_w/2-title_bg_offset/2, y-size-fixed_title_offset, title_w*health+title_bg_offset, font_size*0.2f, ColorAlpha(RED, data->tran_time));
DrawTextEco(title, x-title_w/2, y-size-font_size-fixed_title_offset, font_size, ColorAlpha(RAYWHITE, data->tran_time), font_spacing); DrawTextEco(title, x-title_w/2, y-size-font_size-fixed_title_offset, font_size, ColorAlpha(RAYWHITE, data->tran_time), font_spacing);
DrawCircleEco(x, y, size, ColorAlpha(YELLOW, data->tran_time)); DrawCircleEco(x, y, size, ColorAlpha(YELLOW, data->tran_time));
if (data->has_items && !data->inside_vehicle) { if (data->has_items && !data->inside_vehicle) {
float ix = data->x; float ix = data->x;
float iy = data->y; float iy = data->y;
if (data->items[data->selected_item].quantity > 0) { if (data->items[data->selected_item].quantity > 0) {
item_kind it_kind = data->items[data->selected_item].kind; item_kind it_kind = data->items[data->selected_item].kind;
uint32_t qty = data->items[data->selected_item].quantity; uint32_t qty = data->items[data->selected_item].quantity;
uint16_t it_id = item_find(it_kind); uint16_t it_id = item_find(it_kind);
DrawTexturePro(GetSpriteTexture2D(assets_find(item_get_asset(it_id))), ASSET_SRC_RECT(), ((Rectangle){ix, iy, 32, 32}), (Vector2){0.5f,0.5f}, 0.0f, ALPHA(WHITE)); DrawTexturePro(GetSpriteTexture2D(assets_find(item_get_asset(it_id))), ASSET_SRC_RECT(), ((Rectangle){ix, iy, 32, 32}), (Vector2){0.5f,0.5f}, 0.0f, ALPHA(WHITE));
if (!inv_is_open) if (!inv_is_open)
DrawTextEco(zpl_bprintf("%d", qty), ix+24, iy+24, 8, RAYWHITE, 0.0f); DrawTextEco(zpl_bprintf("%d", qty), ix+24, iy+24, 8, RAYWHITE, 0.0f);
} }
} }
}break; }break;
case EKIND_MACRO_BOT: { case EKIND_MACRO_BOT: {
float x = data->x; float x = data->x;
float y = data->y; float y = data->y;
const char *title = TextFormat("Bot %d", key); const char *title = TextFormat("Bot %d", key);
int title_w = MeasureTextEco(title, font_size, font_spacing); int title_w = MeasureTextEco(title, font_size, font_spacing);
DrawRectangleEco(x-title_w/2-title_bg_offset/2, y-size-font_size-fixed_title_offset, title_w+title_bg_offset, font_size, ColorAlpha(GRAY, data->tran_time)); DrawRectangleEco(x-title_w/2-title_bg_offset/2, y-size-font_size-fixed_title_offset, title_w+title_bg_offset, font_size, ColorAlpha(GRAY, data->tran_time));
DrawTextEco(title, x-title_w/2, y-size-font_size-fixed_title_offset, font_size, ColorAlpha(BLACK, data->tran_time), font_spacing); DrawTextEco(title, x-title_w/2, y-size-font_size-fixed_title_offset, font_size, ColorAlpha(BLACK, data->tran_time), font_spacing);
DrawCircleEco(x, y, size, ColorAlpha(PURPLE, data->tran_time)); DrawCircleEco(x, y, size, ColorAlpha(PURPLE, data->tran_time));
}break; }break;
case EKIND_ITEM: { case EKIND_ITEM: {
float x = data->x - 32.f; float x = data->x - 32.f;
float y = data->y - 32.f; float y = data->y - 32.f;
DrawTexturePro(GetSpriteTexture2D(assets_find(data->asset)), ASSET_SRC_RECT(), ASSET_DST_RECT(x,y), (Vector2){0.5f,0.5f}, 0.0f, ALPHA(WHITE)); DrawTexturePro(GetSpriteTexture2D(assets_find(data->asset)), ASSET_SRC_RECT(), ASSET_DST_RECT(x,y), (Vector2){0.5f,0.5f}, 0.0f, ALPHA(WHITE));
DrawTextEco(zpl_bprintf("%d", data->quantity), x, y, 10, ALPHA(RAYWHITE), 0.0f); DrawTextEco(zpl_bprintf("%d", data->quantity), x, y, 10, ALPHA(RAYWHITE), 0.0f);
}break; }break;
default:break; default:break;
} }
} }
void DEBUG_draw_entities_low(uint64_t key, entity_view * data) { void DEBUG_draw_entities_low(uint64_t key, entity_view * data) {
(void)key; (void)key;
switch (data->kind) { switch (data->kind) {
case EKIND_VEHICLE: { case EKIND_VEHICLE: {
float x = data->x; float x = data->x;
float y = data->y; float y = data->y;
float const w = 80; float const w = 80;
float const h = 50; float const h = 50;
DrawRectanglePro((Rectangle){x,y,w,h}, (Vector2){w/2.0f,h/2.0f}, zpl_to_degrees(data->heading), ColorAlpha(RED, data->tran_time)); DrawRectanglePro((Rectangle){x,y,w,h}, (Vector2){w/2.0f,h/2.0f}, zpl_to_degrees(data->heading), ColorAlpha(RED, data->tran_time));
}break; }break;
default:break; default:break;
} }
} }
void renderer_draw_v0(void) { void renderer_draw_v0(void) {
render_camera.zoom = zpl_lerp(render_camera.zoom, target_zoom, GetFrameTime()*2.9978f); render_camera.zoom = zpl_lerp(render_camera.zoom, target_zoom, GetFrameTime()*2.9978f);
camera_update(); camera_update();
camera game_camera = camera_get(); camera game_camera = camera_get();
render_camera.target = (Vector2){game_camera.x, game_camera.y}; render_camera.target = (Vector2){game_camera.x, game_camera.y};
zoom_overlay_tran = zpl_lerp(zoom_overlay_tran, (target_zoom <= CAM_OVERLAY_ZOOM_LEVEL) ? 1.0f : 0.0f, GetFrameTime()*2.0f); zoom_overlay_tran = zpl_lerp(zoom_overlay_tran, (target_zoom <= CAM_OVERLAY_ZOOM_LEVEL) ? 1.0f : 0.0f, GetFrameTime()*2.0f);
ClearBackground(GetColor(0x222034)); ClearBackground(GetColor(0x222034));
BeginMode2D(render_camera); BeginMode2D(render_camera);
game_world_view_active_entity_map(DEBUG_draw_ground); game_world_view_active_entity_map(DEBUG_draw_ground);
game_world_view_active_entity_map(DEBUG_draw_entities_low); game_world_view_active_entity_map(DEBUG_draw_entities_low);
game_world_view_active_entity_map(DEBUG_draw_entities); game_world_view_active_entity_map(DEBUG_draw_entities);
EndMode2D(); EndMode2D();
} }
float renderer_zoom_get_v0(void) { float renderer_zoom_get_v0(void) {
return render_camera.zoom; return render_camera.zoom;
} }
void renderer_init_v0(void) { void renderer_init_v0(void) {
render_camera.target = (Vector2){0.0f,0.0f}; render_camera.target = (Vector2){0.0f,0.0f};
render_camera.offset = (Vector2){screenWidth >> 1, screenHeight >> 1}; render_camera.offset = (Vector2){screenWidth >> 1, screenHeight >> 1};
render_camera.rotation = 0.0f; render_camera.rotation = 0.0f;
render_camera.zoom = 1.5f; render_camera.zoom = 1.5f;
// NOTE(zaklaus): Paint the screen before we load the game // NOTE(zaklaus): Paint the screen before we load the game
// TODO(zaklaus): Render a cool loading screen background maybe? :wink: :wink: // TODO(zaklaus): Render a cool loading screen background maybe? :wink: :wink:
BeginDrawing(); BeginDrawing();
ClearBackground(GetColor(0x222034)); ClearBackground(GetColor(0x222034));
char const *loading_text = "zpl.eco2d is loading..."; char const *loading_text = "zpl.eco2d is loading...";
int text_w = MeasureText(loading_text, 120); int text_w = MeasureText(loading_text, 120);
DrawText(loading_text, GetScreenWidth()-text_w-15, GetScreenHeight()-135, 120, RAYWHITE); DrawText(loading_text, GetScreenWidth()-text_w-15, GetScreenHeight()-135, 120, RAYWHITE);
EndDrawing(); EndDrawing();
blocks_setup(); blocks_setup();
assets_setup(); assets_setup();
} }
void renderer_shutdown_v0(void) { void renderer_shutdown_v0(void) {
blocks_destroy(); blocks_destroy();
assets_destroy(); assets_destroy();
} }
void renderer_debug_draw_v0(void) { void renderer_debug_draw_v0(void) {
BeginMode2D(render_camera); BeginMode2D(render_camera);
debug_draw_queue *que = debug_draw_samples(); debug_draw_queue *que = debug_draw_samples();
for (size_t i = 0; i < que->num_entries; i += 1) { for (size_t i = 0; i < que->num_entries; i += 1) {
debug_draw_entry *e = &que->entries[i]; debug_draw_entry *e = &que->entries[i];
Color color = GetColor(e->color); Color color = GetColor(e->color);
switch (e->kind) { switch (e->kind) {
case DDRAW_LINE: { case DDRAW_LINE: {
float x = e->a.x; float x = e->a.x;
float y = e->a.y; float y = e->a.y;
float x2 = e->b.x; float x2 = e->b.x;
float y2 = e->b.y; float y2 = e->b.y;
DrawLineV((Vector2){x, y}, (Vector2){x2, y2}, color); DrawLineV((Vector2){x, y}, (Vector2){x2, y2}, color);
}break; }break;
case DDRAW_CIRCLE:{ case DDRAW_CIRCLE:{
float x = e->a.x; float x = e->a.x;
float y = e->a.y; float y = e->a.y;
DrawCircleLinesEco(x, y, e->radius, color); DrawCircleLinesEco(x, y, e->radius, color);
}break; }break;
case DDRAW_RECT:{ case DDRAW_RECT:{
float x = e->bmin.x; float x = e->bmin.x;
float y = e->bmin.y; float y = e->bmin.y;
float w = e->bmax.x - e->bmin.x; float w = e->bmax.x - e->bmin.x;
float h = e->bmax.y - e->bmin.y; float h = e->bmax.y - e->bmin.y;
DrawRectangleLinesEco(x, y, w, h, color); DrawRectangleLinesEco(x, y, w, h, color);
}break; }break;
default: { default: {
}break; }break;
} }
} }
EndMode2D(); EndMode2D();
} }
void renderer_draw_single_v0(float x, float y, asset_id id, Color color) { void renderer_draw_single_v0(float x, float y, asset_id id, Color color) {
BeginMode2D(render_camera); BeginMode2D(render_camera);
x -= 32.0f; x -= 32.0f;
y -= 32.0f; y -= 32.0f;
DrawTexturePro(GetSpriteTexture2D(assets_find(id)), ASSET_SRC_RECT(), ASSET_DST_RECT(x,y), (Vector2){0.5f,0.5f}, 0.0f, color); DrawTexturePro(GetSpriteTexture2D(assets_find(id)), ASSET_SRC_RECT(), ASSET_DST_RECT(x,y), (Vector2){0.5f,0.5f}, 0.0f, color);
EndMode2D(); EndMode2D();
} }

View File

@ -1,377 +1,377 @@
#pragma once #pragma once
#include "system.h" #include "system.h"
#include "raylib.h" #include "raylib.h"
#include "world/blocks.h" #include "world/blocks.h"
#include "assets.h" #include "assets.h"
#define RAYLIB_NEW_RLGL #define RAYLIB_NEW_RLGL
#include "rlgl.h" #include "rlgl.h"
static inline float lerp(float a, float b, float t) { return a * (1.0f - t) + b * t; } static inline float lerp(float a, float b, float t) { return a * (1.0f - t) + b * t; }
static inline static inline
void DrawTextEco(const char *text, float posX, float posY, int fontSize, Color color, float spacing) { void DrawTextEco(const char *text, float posX, float posY, int fontSize, Color color, float spacing) {
#if 1 #if 1
// Check if default font has been loaded // Check if default font has been loaded
if (GetFontDefault().texture.id != 0) { if (GetFontDefault().texture.id != 0) {
Vector2 position = { (float)posX , (float)posY }; Vector2 position = { (float)posX , (float)posY };
int defaultFontSize = 10; // Default Font chars height in pixel int defaultFontSize = 10; // Default Font chars height in pixel
int new_spacing = spacing == 0.0f ? fontSize/defaultFontSize : spacing; int new_spacing = spacing == 0.0f ? fontSize/defaultFontSize : spacing;
DrawTextEx(GetFontDefault(), text, position, (float)fontSize , (float)new_spacing , color); DrawTextEx(GetFontDefault(), text, position, (float)fontSize , (float)new_spacing , color);
} }
#endif #endif
} }
static inline static inline
int MeasureTextEco(const char *text, int fontSize, float spacing) { int MeasureTextEco(const char *text, int fontSize, float spacing) {
#if 1 #if 1
Vector2 vec = { 0.0f, 0.0f }; Vector2 vec = { 0.0f, 0.0f };
// Check if default font has been loaded // Check if default font has been loaded
if (GetFontDefault().texture.id != 0) { if (GetFontDefault().texture.id != 0) {
int defaultFontSize = 10; // Default Font chars height in pixel int defaultFontSize = 10; // Default Font chars height in pixel
int new_spacing = spacing == 0.0f ? fontSize/defaultFontSize : spacing; int new_spacing = spacing == 0.0f ? fontSize/defaultFontSize : spacing;
vec = MeasureTextEx(GetFontDefault(), text, (float)fontSize, (float)new_spacing); vec = MeasureTextEx(GetFontDefault(), text, (float)fontSize, (float)new_spacing);
} }
return (int)vec.x; return (int)vec.x;
#else #else
return 0; return 0;
#endif #endif
} }
static inline static inline
void DrawCircleEco(float centerX, float centerY, float radius, Color color) void DrawCircleEco(float centerX, float centerY, float radius, Color color)
{ {
DrawCircleV((Vector2){ (float)centerX , (float)centerY }, radius , color); DrawCircleV((Vector2){ (float)centerX , (float)centerY }, radius , color);
} }
static inline static inline
void DrawRectangleEco(float posX, float posY, float width, float height, Color color) void DrawRectangleEco(float posX, float posY, float width, float height, Color color)
{ {
DrawRectangleV((Vector2){ (float)posX , (float)posY }, (Vector2){ width , height }, color); DrawRectangleV((Vector2){ (float)posX , (float)posY }, (Vector2){ width , height }, color);
} }
static inline static inline
Texture2D GetBlockImage(uint8_t id) { Texture2D GetBlockImage(uint8_t id) {
return *(Texture2D*)blocks_get_img(id); return *(Texture2D*)blocks_get_img(id);
} }
static inline static inline
RenderTexture2D GetChunkTexture(uint64_t id) { RenderTexture2D GetChunkTexture(uint64_t id) {
RenderTexture2D *tex = (RenderTexture2D*)blocks_get_chunk_tex(id); RenderTexture2D *tex = (RenderTexture2D*)blocks_get_chunk_tex(id);
if (!tex) return (RenderTexture2D){0}; if (!tex) return (RenderTexture2D){0};
return *tex; return *tex;
} }
static inline static inline
Texture2D GetSpriteTexture2D(uint16_t id) { Texture2D GetSpriteTexture2D(uint16_t id) {
return *(Texture2D*)assets_get_tex(id); return *(Texture2D*)assets_get_tex(id);
} }
static inline static inline
Sound GetSound(uint16_t id) { Sound GetSound(uint16_t id) {
return *(Sound*)assets_get_snd(id); return *(Sound*)assets_get_snd(id);
} }
// Draw cube // Draw cube
// NOTE: Cube position is the center position // NOTE: Cube position is the center position
static inline static inline
void EcoDrawCube(Vector3 position, float width, float height, float length, float heading, Color color) void EcoDrawCube(Vector3 position, float width, float height, float length, float heading, Color color)
{ {
float x = 0.0f; float x = 0.0f;
float y = 0.0f; float y = 0.0f;
float z = 0.0f; float z = 0.0f;
rlCheckRenderBatchLimit(36); rlCheckRenderBatchLimit(36);
rlPushMatrix(); rlPushMatrix();
// NOTE: Transformation is applied in inverse order (scale -> rotate -> translate) // NOTE: Transformation is applied in inverse order (scale -> rotate -> translate)
rlTranslatef(position.x, position.y, position.z); rlTranslatef(position.x, position.y, position.z);
rlRotatef(heading, 0, 1, 0); rlRotatef(heading, 0, 1, 0);
//rlScalef(1.0f, 1.0f, 1.0f); // NOTE: Vertices are directly scaled on definition //rlScalef(1.0f, 1.0f, 1.0f); // NOTE: Vertices are directly scaled on definition
rlBegin(RL_TRIANGLES); rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
// Front face // Front face
rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left
rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Right rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Right
rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
// Back face // Back face
rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Left rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Left
rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left
rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right
rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left
// Top face // Top face
rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left
rlVertex3f(x - width/2, y + height/2, z + length/2); // Bottom Left rlVertex3f(x - width/2, y + height/2, z + length/2); // Bottom Left
rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right
rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right
rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left
rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right
// Bottom face // Bottom face
rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left
rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left
rlVertex3f(x + width/2, y - height/2, z - length/2); // Top Right rlVertex3f(x + width/2, y - height/2, z - length/2); // Top Right
rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left
// Right face // Right face
rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right
rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left
rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left
rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left
// Left face // Left face
rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right
rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Right rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Right
rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left
rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right
rlEnd(); rlEnd();
rlPopMatrix(); rlPopMatrix();
} }
// Draw codepoint at specified position in 3D space // Draw codepoint at specified position in 3D space
void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontSize, bool backface, Color tint) void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontSize, bool backface, Color tint)
{ {
#if 0 #if 0
// Character index position in sprite font // Character index position in sprite font
// NOTE: In case a codepoint is not available in the font, index returned points to '?' // NOTE: In case a codepoint is not available in the font, index returned points to '?'
int index = GetGlyphIndex(font, codepoint); int index = GetGlyphIndex(font, codepoint);
float scale = fontSize/(float)font.baseSize; float scale = fontSize/(float)font.baseSize;
// Character destination rectangle on screen // Character destination rectangle on screen
// NOTE: We consider charsPadding on drawing // NOTE: We consider charsPadding on drawing
position.x += (float)(font.chars[index].offsetX - font.charsPadding)/(float)font.baseSize*scale; position.x += (float)(font.chars[index].offsetX - font.charsPadding)/(float)font.baseSize*scale;
position.z += (float)(font.chars[index].offsetY - font.charsPadding)/(float)font.baseSize*scale; position.z += (float)(font.chars[index].offsetY - font.charsPadding)/(float)font.baseSize*scale;
// Character source rectangle from font texture atlas // Character source rectangle from font texture atlas
// NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects // NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects
Rectangle srcRec = { font.recs[index].x - (float)font.charsPadding, font.recs[index].y - (float)font.charsPadding, Rectangle srcRec = { font.recs[index].x - (float)font.charsPadding, font.recs[index].y - (float)font.charsPadding,
font.recs[index].width + 2.0f*font.charsPadding, font.recs[index].height + 2.0f*font.charsPadding }; font.recs[index].width + 2.0f*font.charsPadding, font.recs[index].height + 2.0f*font.charsPadding };
float width = (float)(font.recs[index].width + 2.0f*font.charsPadding)/(float)font.baseSize*scale; float width = (float)(font.recs[index].width + 2.0f*font.charsPadding)/(float)font.baseSize*scale;
float height = (float)(font.recs[index].height + 2.0f*font.charsPadding)/(float)font.baseSize*scale; float height = (float)(font.recs[index].height + 2.0f*font.charsPadding)/(float)font.baseSize*scale;
if (font.texture.id > 0) if (font.texture.id > 0)
{ {
const float x = 0.0f; const float x = 0.0f;
const float y = 0.0f; const float y = 0.0f;
const float z = 0.0f; const float z = 0.0f;
// normalized texture coordinates of the glyph inside the font texture (0.0f -> 1.0f) // normalized texture coordinates of the glyph inside the font texture (0.0f -> 1.0f)
const float tx = srcRec.x/font.texture.width; const float tx = srcRec.x/font.texture.width;
const float ty = srcRec.y/font.texture.height; const float ty = srcRec.y/font.texture.height;
const float tw = (srcRec.x+srcRec.width)/font.texture.width; const float tw = (srcRec.x+srcRec.width)/font.texture.width;
const float th = (srcRec.y+srcRec.height)/font.texture.height; const float th = (srcRec.y+srcRec.height)/font.texture.height;
{ {
#if defined(RAYLIB_NEW_RLGL) #if defined(RAYLIB_NEW_RLGL)
} }
rlCheckRenderBatchLimit(4 + 4*backface); rlCheckRenderBatchLimit(4 + 4*backface);
rlSetTexture(font.texture.id); rlSetTexture(font.texture.id);
#else #else
if (rlCheckBufferLimit(4 + 4*backface)) rlglDraw(); if (rlCheckBufferLimit(4 + 4*backface)) rlglDraw();
rlEnableTexture(font.texture.id); rlEnableTexture(font.texture.id);
#endif #endif
rlPushMatrix(); rlPushMatrix();
rlTranslatef(position.x, position.y, position.z); rlTranslatef(position.x, position.y, position.z);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(tint.r, tint.g, tint.b, tint.a); rlColor4ub(tint.r, tint.g, tint.b, tint.a);
// Front Face // Front Face
rlNormal3f(0.0f, 1.0f, 0.0f); // Normal Pointing Up rlNormal3f(0.0f, 1.0f, 0.0f); // Normal Pointing Up
rlTexCoord2f(tx, ty); rlVertex3f(x, y, z); // Top Left Of The Texture and Quad rlTexCoord2f(tx, ty); rlVertex3f(x, y, z); // Top Left Of The Texture and Quad
rlTexCoord2f(tx, th); rlVertex3f(x, y, z + height); // Bottom Left Of The Texture and Quad rlTexCoord2f(tx, th); rlVertex3f(x, y, z + height); // Bottom Left Of The Texture and Quad
rlTexCoord2f(tw, th); rlVertex3f(x + width, y, z + height); // Bottom Right Of The Texture and Quad rlTexCoord2f(tw, th); rlVertex3f(x + width, y, z + height); // Bottom Right Of The Texture and Quad
rlTexCoord2f(tw, ty); rlVertex3f(x + width, y, z); // Top Right Of The Texture and Quad rlTexCoord2f(tw, ty); rlVertex3f(x + width, y, z); // Top Right Of The Texture and Quad
if (backface) if (backface)
{ {
// Back Face // Back Face
rlNormal3f(0.0f, -1.0f, 0.0f); // Normal Pointing Down rlNormal3f(0.0f, -1.0f, 0.0f); // Normal Pointing Down
rlTexCoord2f(tx, ty); rlVertex3f(x, y, z); // Top Right Of The Texture and Quad rlTexCoord2f(tx, ty); rlVertex3f(x, y, z); // Top Right Of The Texture and Quad
rlTexCoord2f(tw, ty); rlVertex3f(x + width, y, z); // Top Left Of The Texture and Quad rlTexCoord2f(tw, ty); rlVertex3f(x + width, y, z); // Top Left Of The Texture and Quad
rlTexCoord2f(tw, th); rlVertex3f(x + width, y, z + height); // Bottom Left Of The Texture and Quad rlTexCoord2f(tw, th); rlVertex3f(x + width, y, z + height); // Bottom Left Of The Texture and Quad
rlTexCoord2f(tx, th); rlVertex3f(x, y, z + height); // Bottom Right Of The Texture and Quad rlTexCoord2f(tx, th); rlVertex3f(x, y, z + height); // Bottom Right Of The Texture and Quad
} }
rlEnd(); rlEnd();
rlPopMatrix(); rlPopMatrix();
#if defined(RAYLIB_NEW_RLGL) #if defined(RAYLIB_NEW_RLGL)
rlSetTexture(0); rlSetTexture(0);
#else #else
rlDisableTexture(); rlDisableTexture();
#endif #endif
} }
#endif #endif
} }
void DrawText3D(Font font, const char *text, Vector3 position, float fontSize, float fontSpacing, float lineSpacing, bool backface, Color tint) { void DrawText3D(Font font, const char *text, Vector3 position, float fontSize, float fontSpacing, float lineSpacing, bool backface, Color tint) {
#if 0 #if 0
int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop
float textOffsetY = 0.0f; // Offset between lines (on line break '\n') float textOffsetY = 0.0f; // Offset between lines (on line break '\n')
float textOffsetX = 0.0f; // Offset X to next character to draw float textOffsetX = 0.0f; // Offset X to next character to draw
float scale = fontSize/(float)font.baseSize; float scale = fontSize/(float)font.baseSize;
for (int i = 0; i < length;) for (int i = 0; i < length;)
{ {
// Get next codepoint from byte string and glyph index in font // Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0; int codepointByteCount = 0;
int codepoint = GetCodepoint(&text[i], &codepointByteCount); int codepoint = GetCodepoint(&text[i], &codepointByteCount);
int index = GetGlyphIndex(font, codepoint); int index = GetGlyphIndex(font, codepoint);
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol moving one byte // but we need to draw all of the bad bytes using the '?' symbol moving one byte
if (codepoint == 0x3f) codepointByteCount = 1; if (codepoint == 0x3f) codepointByteCount = 1;
if (codepoint == '\n') if (codepoint == '\n')
{ {
// NOTE: Fixed line spacing of 1.5 line-height // NOTE: Fixed line spacing of 1.5 line-height
// TODO: Support custom line spacing defined by user // TODO: Support custom line spacing defined by user
textOffsetY += scale + lineSpacing/(float)font.baseSize*scale; textOffsetY += scale + lineSpacing/(float)font.baseSize*scale;
textOffsetX = 0.0f; textOffsetX = 0.0f;
} }
else else
{ {
if ((codepoint != ' ') && (codepoint != '\t')) if ((codepoint != ' ') && (codepoint != '\t'))
{ {
DrawTextCodepoint3D(font, codepoint, (Vector3){ position.x + textOffsetX, position.y, position.z + textOffsetY }, fontSize, backface, tint); DrawTextCodepoint3D(font, codepoint, (Vector3){ position.x + textOffsetX, position.y, position.z + textOffsetY }, fontSize, backface, tint);
} }
if (font.chars[index].advanceX == 0) textOffsetX += (float)(font.recs[index].width + fontSpacing)/(float)font.baseSize*scale; if (font.chars[index].advanceX == 0) textOffsetX += (float)(font.recs[index].width + fontSpacing)/(float)font.baseSize*scale;
else textOffsetX += (float)(font.chars[index].advanceX + fontSpacing)/(float)font.baseSize*scale; else textOffsetX += (float)(font.chars[index].advanceX + fontSpacing)/(float)font.baseSize*scale;
} }
i += codepointByteCount; // Move text bytes counter to next codepoint i += codepointByteCount; // Move text bytes counter to next codepoint
} }
#endif #endif
} }
Vector3 MeasureText3D(Font font, const char* text, float fontSize, float fontSpacing, float lineSpacing) { Vector3 MeasureText3D(Font font, const char* text, float fontSize, float fontSpacing, float lineSpacing) {
#if 0 #if 0
int len = TextLength(text); int len = TextLength(text);
int tempLen = 0; // Used to count longer text line num chars int tempLen = 0; // Used to count longer text line num chars
int lenCounter = 0; int lenCounter = 0;
float tempTextWidth = 0.0f; // Used to count longer text line width float tempTextWidth = 0.0f; // Used to count longer text line width
float scale = fontSize/(float)font.baseSize; float scale = fontSize/(float)font.baseSize;
float textHeight = scale; float textHeight = scale;
float textWidth = 0.0f; float textWidth = 0.0f;
int letter = 0; // Current character int letter = 0; // Current character
int index = 0; // Index position in sprite font int index = 0; // Index position in sprite font
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
{ {
lenCounter++; lenCounter++;
int next = 0; int next = 0;
letter = GetCodepoint(&text[i], &next); letter = GetCodepoint(&text[i], &next);
index = GetGlyphIndex(font, letter); index = GetGlyphIndex(font, letter);
// NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1 // but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1
if (letter == 0x3f) next = 1; if (letter == 0x3f) next = 1;
i += next - 1; i += next - 1;
if (letter != '\n') if (letter != '\n')
{ {
if (font.chars[index].advanceX != 0) textWidth += (font.chars[index].advanceX+fontSpacing)/(float)font.baseSize*scale; if (font.chars[index].advanceX != 0) textWidth += (font.chars[index].advanceX+fontSpacing)/(float)font.baseSize*scale;
else textWidth += (font.recs[index].width + font.chars[index].offsetX)/(float)font.baseSize*scale; else textWidth += (font.recs[index].width + font.chars[index].offsetX)/(float)font.baseSize*scale;
} }
else else
{ {
if (tempTextWidth < textWidth) tempTextWidth = textWidth; if (tempTextWidth < textWidth) tempTextWidth = textWidth;
lenCounter = 0; lenCounter = 0;
textWidth = 0.0f; textWidth = 0.0f;
textHeight += scale + lineSpacing/(float)font.baseSize*scale; textHeight += scale + lineSpacing/(float)font.baseSize*scale;
} }
if (tempLen < lenCounter) tempLen = lenCounter; if (tempLen < lenCounter) tempLen = lenCounter;
} }
if (tempTextWidth < textWidth) tempTextWidth = textWidth; if (tempTextWidth < textWidth) tempTextWidth = textWidth;
Vector3 vec = { 0 }; Vector3 vec = { 0 };
vec.x = tempTextWidth + (float)((tempLen - 1)*fontSpacing/(float)font.baseSize*scale); // Adds chars spacing to measure vec.x = tempTextWidth + (float)((tempLen - 1)*fontSpacing/(float)font.baseSize*scale); // Adds chars spacing to measure
vec.y = 0.25f; vec.y = 0.25f;
vec.z = textHeight; vec.z = textHeight;
return vec; return vec;
#endif #endif
} }
Color GenerateRandomColor(float s, float v) { Color GenerateRandomColor(float s, float v) {
const float Phi = 0.618033988749895f; // Golden ratio conjugate const float Phi = 0.618033988749895f; // Golden ratio conjugate
float h = GetRandomValue(0, 360); float h = GetRandomValue(0, 360);
h = fmodf((h + h*Phi), 360.0f); h = fmodf((h + h*Phi), 360.0f);
return ColorFromHSV(h, s, v); return ColorFromHSV(h, s, v);
} }
// Draw circle outline // Draw circle outline
void DrawCircleLinesEco(float centerX, float centerY, float radius, Color color) void DrawCircleLinesEco(float centerX, float centerY, float radius, Color color)
{ {
rlCheckRenderBatchLimit(2*36); rlCheckRenderBatchLimit(2*36);
rlBegin(RL_LINES); rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
// NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360) // NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360)
for (int i = 0; i < 360; i += 10) for (int i = 0; i < 360; i += 10)
{ {
rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius); rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius);
rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius); rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius);
} }
rlEnd(); rlEnd();
} }
void DrawRectangleLinesEco(float posX, float posY, float width, float height, Color color) void DrawRectangleLinesEco(float posX, float posY, float width, float height, Color color)
{ {
rlBegin(RL_LINES); rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(posX + 1, posY + 1); rlVertex2f(posX + 1, posY + 1);
rlVertex2f(posX + width, posY + 1); rlVertex2f(posX + width, posY + 1);
rlVertex2f(posX + width, posY + 1); rlVertex2f(posX + width, posY + 1);
rlVertex2f(posX + width, posY + height); rlVertex2f(posX + width, posY + height);
rlVertex2f(posX + width, posY + height); rlVertex2f(posX + width, posY + height);
rlVertex2f(posX + 1, posY + height); rlVertex2f(posX + 1, posY + height);
rlVertex2f(posX + 1, posY + height); rlVertex2f(posX + 1, posY + height);
rlVertex2f(posX + 1, posY + 1); rlVertex2f(posX + 1, posY + 1);
rlEnd(); rlEnd();
} }

View File

@ -1,23 +1,23 @@
#include "vehicle.h" #include "vehicle.h"
#include "entity.h" #include "entity.h"
#include "entity_view.h" #include "entity_view.h"
#include "world/world.h" #include "world/world.h"
#include "modules/components.h" #include "modules/components.h"
uint64_t vehicle_spawn(void) { uint64_t vehicle_spawn(void) {
ecs_entity_t e = entity_spawn(EKIND_VEHICLE); ecs_entity_t e = entity_spawn(EKIND_VEHICLE);
Vehicle *veh = ecs_get_mut(world_ecs(), e, Vehicle, NULL); Vehicle *veh = ecs_get_mut(world_ecs(), e, Vehicle, NULL);
*veh = (Vehicle){ *veh = (Vehicle){
.wheel_base = 50.0f, .wheel_base = 50.0f,
.speed = 50.0f, .speed = 50.0f,
.reverse_speed = -20.0f, .reverse_speed = -20.0f,
.force = 0.0f, .force = 0.0f,
}; };
return (uint64_t)e; return (uint64_t)e;
} }
void vehicle_despawn(uint64_t ent_id) { void vehicle_despawn(uint64_t ent_id) {
entity_despawn(ent_id); entity_despawn(ent_id);
} }

View File

@ -1,144 +1,144 @@
#define ZPL_NANO #define ZPL_NANO
#include "zpl.h" #include "zpl.h"
#include "world/world.h" #include "world/world.h"
#include "world/blocks.h" #include "world/blocks.h"
#include "raylib.h" #include "raylib.h"
#include "gen/texgen.h" #include "gen/texgen.h"
#include "world_view.h" #include "world_view.h"
#include "perlin.h" #include "perlin.h"
#define BLOCKS_COUNT (sizeof(blocks)/sizeof(block)) #define BLOCKS_COUNT (sizeof(blocks)/sizeof(block))
#define WORLD_TEXTURE_BLOCK_SCALE 0.5f #define WORLD_TEXTURE_BLOCK_SCALE 0.5f
ZPL_TABLE(static, blocks__chunk_tbl, blocks__chunk_tbl_, RenderTexture2D); ZPL_TABLE(static, blocks__chunk_tbl, blocks__chunk_tbl_, RenderTexture2D);
static blocks__chunk_tbl baked_chunks; static blocks__chunk_tbl baked_chunks;
static void chunks_unload_textures(uint64_t key, RenderTexture2D *value) { static void chunks_unload_textures(uint64_t key, RenderTexture2D *value) {
(void)key; (void)key;
UnloadRenderTexture(*value); UnloadRenderTexture(*value);
} }
typedef struct { typedef struct {
char *name; char *name;
uint32_t flags; uint32_t flags;
uint32_t kind; uint32_t kind;
uint32_t biome; uint32_t biome;
char symbol; char symbol;
float drag; float drag;
float friction; float friction;
float bounce; float bounce;
// NOTE(zaklaus): viewer data // NOTE(zaklaus): viewer data
Texture2D img; Texture2D img;
} block; } block;
#include "blocks_list.c" #include "blocks_list.c"
int32_t blocks_setup(void) { int32_t blocks_setup(void) {
for (uint32_t i=0; i<BLOCKS_COUNT; i++) { for (uint32_t i=0; i<BLOCKS_COUNT; i++) {
block *b = &blocks[i]; block *b = &blocks[i];
b->img = texgen_build_block(b->biome, b->kind); b->img = texgen_build_block(b->biome, b->kind);
} }
blocks__chunk_tbl_init(&baked_chunks, zpl_heap()); blocks__chunk_tbl_init(&baked_chunks, zpl_heap());
return 0; return 0;
} }
void blocks_destroy(void) { void blocks_destroy(void) {
for (uint32_t i=0; i<BLOCKS_COUNT; i++) { for (uint32_t i=0; i<BLOCKS_COUNT; i++) {
UnloadTexture(blocks[i].img); UnloadTexture(blocks[i].img);
} }
blocks__chunk_tbl_map_mut(&baked_chunks, chunks_unload_textures); blocks__chunk_tbl_map_mut(&baked_chunks, chunks_unload_textures);
blocks__chunk_tbl_destroy(&baked_chunks); blocks__chunk_tbl_destroy(&baked_chunks);
} }
uint8_t blocks_find(uint32_t biome, uint32_t kind) { uint8_t blocks_find(uint32_t biome, uint32_t kind) {
for (uint32_t i=0; i<BLOCKS_COUNT; i++) { for (uint32_t i=0; i<BLOCKS_COUNT; i++) {
if (blocks[i].biome == biome && blocks[i].kind == kind) if (blocks[i].biome == biome && blocks[i].kind == kind)
return i; return i;
} }
return BLOCK_INVALID; return BLOCK_INVALID;
} }
char *blocks_get_name(uint8_t id) { char *blocks_get_name(uint8_t id) {
return blocks[id].name; return blocks[id].name;
} }
char blocks_get_symbol(uint8_t id) { char blocks_get_symbol(uint8_t id) {
return blocks[id].symbol; return blocks[id].symbol;
} }
uint32_t blocks_get_flags(uint8_t id) { uint32_t blocks_get_flags(uint8_t id) {
return blocks[id].flags; return blocks[id].flags;
} }
uint32_t blocks_get_biome(uint8_t id) { uint32_t blocks_get_biome(uint8_t id) {
return blocks[id].biome; return blocks[id].biome;
} }
uint32_t blocks_get_kind(uint8_t id) { uint32_t blocks_get_kind(uint8_t id) {
return blocks[id].kind; return blocks[id].kind;
} }
float blocks_get_drag(uint8_t id) { float blocks_get_drag(uint8_t id) {
return blocks[id].drag; return blocks[id].drag;
} }
float blocks_get_friction(uint8_t id) { float blocks_get_friction(uint8_t id) {
return blocks[id].friction; return blocks[id].friction;
} }
float blocks_get_bounce(uint8_t id) { float blocks_get_bounce(uint8_t id) {
return blocks[id].bounce; return blocks[id].bounce;
} }
void *blocks_get_img(uint8_t id) { void *blocks_get_img(uint8_t id) {
return (void*)&blocks[id].img; return (void*)&blocks[id].img;
} }
void blocks_build_chunk_tex(uint64_t id, uint8_t *chunk_blocks, uint8_t *outer_chunk_blocks, void *raw_view) { void blocks_build_chunk_tex(uint64_t id, uint8_t *chunk_blocks, uint8_t *outer_chunk_blocks, void *raw_view) {
world_view *view = (world_view*)raw_view; world_view *view = (world_view*)raw_view;
uint16_t blk_dims = WORLD_BLOCK_SIZE * WORLD_TEXTURE_BLOCK_SCALE; uint16_t blk_dims = WORLD_BLOCK_SIZE * WORLD_TEXTURE_BLOCK_SCALE;
uint16_t dims = blk_dims * view->chunk_size; uint16_t dims = blk_dims * view->chunk_size;
RenderTexture2D canvas = LoadRenderTexture(dims, dims); RenderTexture2D canvas = LoadRenderTexture(dims, dims);
BeginTextureMode(canvas); BeginTextureMode(canvas);
ClearBackground(WHITE); ClearBackground(WHITE);
for (int y = 0; y < view->chunk_size; y += 1) { for (int y = 0; y < view->chunk_size; y += 1) {
for (int x = 0; x < view->chunk_size; x += 1) { for (int x = 0; x < view->chunk_size; x += 1) {
#if 0 #if 0
Texture2D blk = blocks[chunk_blocks[(y*view->chunk_size)+x]].img; Texture2D blk = blocks[chunk_blocks[(y*view->chunk_size)+x]].img;
Rectangle src = {0, 0, WORLD_BLOCK_SIZE, WORLD_BLOCK_SIZE}; Rectangle src = {0, 0, WORLD_BLOCK_SIZE, WORLD_BLOCK_SIZE};
Rectangle dst = {x*blk_dims, y*blk_dims, blk_dims, blk_dims}; Rectangle dst = {x*blk_dims, y*blk_dims, blk_dims, blk_dims};
DrawTexturePro(blk, src, dst, (Vector2){0.0f,0.0f}, 0.0f, WHITE); DrawTexturePro(blk, src, dst, (Vector2){0.0f,0.0f}, 0.0f, WHITE);
#else #else
static float rots[] = { 0.0f, 90.0f, 180.f, 270.0f }; static float rots[] = { 0.0f, 90.0f, 180.f, 270.0f };
float rot = rots[(int32_t)(perlin_fbm(view->seed, x, y, 1.2f, 3) * 4.0f) % 4]; float rot = rots[(int32_t)(perlin_fbm(view->seed, x, y, 1.2f, 3) * 4.0f) % 4];
float half_block = blk_dims / 2.0f; float half_block = blk_dims / 2.0f;
Texture2D blk = blocks[chunk_blocks[(y*view->chunk_size)+x]].img; Texture2D blk = blocks[chunk_blocks[(y*view->chunk_size)+x]].img;
Rectangle src = {0, 0, WORLD_BLOCK_SIZE, WORLD_BLOCK_SIZE}; Rectangle src = {0, 0, WORLD_BLOCK_SIZE, WORLD_BLOCK_SIZE};
Rectangle dst = {x*blk_dims + half_block, y*blk_dims + half_block, blk_dims, blk_dims}; Rectangle dst = {x*blk_dims + half_block, y*blk_dims + half_block, blk_dims, blk_dims};
DrawTexturePro(blk, src, dst, (Vector2){half_block, half_block}, rot, WHITE); DrawTexturePro(blk, src, dst, (Vector2){half_block, half_block}, rot, WHITE);
if (outer_chunk_blocks[(y*view->chunk_size)+x] != 0) { if (outer_chunk_blocks[(y*view->chunk_size)+x] != 0) {
Texture2D blk2 = blocks[outer_chunk_blocks[(y*view->chunk_size)+x]].img; Texture2D blk2 = blocks[outer_chunk_blocks[(y*view->chunk_size)+x]].img;
DrawTexturePro(blk2, src, dst, (Vector2){half_block, half_block}, rot, WHITE); DrawTexturePro(blk2, src, dst, (Vector2){half_block, half_block}, rot, WHITE);
} }
#endif #endif
} }
} }
EndTextureMode(); EndTextureMode();
blocks__chunk_tbl_set(&baked_chunks, id, canvas); blocks__chunk_tbl_set(&baked_chunks, id, canvas);
} }
void *blocks_get_chunk_tex(uint64_t id) { void *blocks_get_chunk_tex(uint64_t id) {
return blocks__chunk_tbl_get(&baked_chunks, id); return blocks__chunk_tbl_get(&baked_chunks, id);
} }
void blocks_remove_chunk_tex(uint64_t id) { void blocks_remove_chunk_tex(uint64_t id) {
RenderTexture2D *tex = blocks__chunk_tbl_get(&baked_chunks, id); RenderTexture2D *tex = blocks__chunk_tbl_get(&baked_chunks, id);
if (!tex) return; if (!tex) return;
UnloadRenderTexture(*tex); UnloadRenderTexture(*tex);
blocks__chunk_tbl_remove(&baked_chunks, id); blocks__chunk_tbl_remove(&baked_chunks, id);
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,101 +1,101 @@
#pragma once #pragma once
#include "system.h" #include "system.h"
#include "librg.h" #include "librg.h"
#include "packet.h" #include "packet.h"
#include "flecs/flecs.h" #include "flecs/flecs.h"
#include "flecs/flecs_meta.h" #include "flecs/flecs_meta.h"
#include "modules/components.h" #include "modules/components.h"
#define WORLD_ERROR_NONE +0x0000 #define WORLD_ERROR_NONE +0x0000
#define WORLD_ERROR_OUTOFMEM -0x0001 #define WORLD_ERROR_OUTOFMEM -0x0001
#define WORLD_ERROR_INVALID_BLOCKS -0x0002 #define WORLD_ERROR_INVALID_BLOCKS -0x0002
#define WORLD_ERROR_INVALID_DIMENSIONS -0x0003 #define WORLD_ERROR_INVALID_DIMENSIONS -0x0003
#define WORLD_ERROR_INVALID_BUFFER -0x0004 #define WORLD_ERROR_INVALID_BUFFER -0x0004
#define WORLD_ERROR_TRACKER_FAILED -0x0005 #define WORLD_ERROR_TRACKER_FAILED -0x0005
#define WORLD_LAYERING 0 #define WORLD_LAYERING 0
#define WORLD_TRACKER_LAYERS 3 #define WORLD_TRACKER_LAYERS 3
#define WORLD_TRACKER_UPDATE_FAST_MS 0 #define WORLD_TRACKER_UPDATE_FAST_MS 0
#define WORLD_TRACKER_UPDATE_NORMAL_MS 50 #define WORLD_TRACKER_UPDATE_NORMAL_MS 50
#define WORLD_TRACKER_UPDATE_SLOW_MS 100 #define WORLD_TRACKER_UPDATE_SLOW_MS 100
#define WORLD_TRACKER_UPDATE_MP_FAST_MS 50 #define WORLD_TRACKER_UPDATE_MP_FAST_MS 50
#define WORLD_TRACKER_UPDATE_MP_NORMAL_MS 150 #define WORLD_TRACKER_UPDATE_MP_NORMAL_MS 150
#define WORLD_TRACKER_UPDATE_MP_SLOW_MS 300 #define WORLD_TRACKER_UPDATE_MP_SLOW_MS 300
#define WORLD_BLOCK_SIZE 64 #define WORLD_BLOCK_SIZE 64
#define WORLD_PKT_READER(name) int32_t name(void* data, uint32_t datalen, void *udata) #define WORLD_PKT_READER(name) int32_t name(void* data, uint32_t datalen, void *udata)
typedef WORLD_PKT_READER(world_pkt_reader_proc); typedef WORLD_PKT_READER(world_pkt_reader_proc);
#define WORLD_PKT_WRITER(name) int32_t name(pkt_header *pkt, void *udata) #define WORLD_PKT_WRITER(name) int32_t name(pkt_header *pkt, void *udata)
typedef WORLD_PKT_WRITER(world_pkt_writer_proc); typedef WORLD_PKT_WRITER(world_pkt_writer_proc);
typedef struct { typedef struct {
bool is_paused; bool is_paused;
uint8_t *data; uint8_t *data;
uint32_t seed; uint32_t seed;
uint32_t size; uint32_t size;
uint16_t chunk_size; uint16_t chunk_size;
uint16_t chunk_amount; uint16_t chunk_amount;
uint8_t **block_mapping; uint8_t **block_mapping;
uint8_t **outer_block_mapping; uint8_t **outer_block_mapping;
uint16_t dim; uint16_t dim;
uint64_t tracker_update[3]; uint64_t tracker_update[3];
uint8_t active_layer_id; uint8_t active_layer_id;
ecs_world_t *ecs; ecs_world_t *ecs;
ecs_world_t *ecs_stage; ecs_world_t *ecs_stage;
ecs_query_t *ecs_update; ecs_query_t *ecs_update;
ecs_entity_t *chunk_mapping; ecs_entity_t *chunk_mapping;
librg_world *tracker; librg_world *tracker;
world_pkt_reader_proc *reader_proc; world_pkt_reader_proc *reader_proc;
world_pkt_writer_proc *writer_proc; world_pkt_writer_proc *writer_proc;
} world_data; } world_data;
void world_setup_pkt_handlers(world_pkt_reader_proc *reader_proc, world_pkt_writer_proc *writer_proc); void world_setup_pkt_handlers(world_pkt_reader_proc *reader_proc, world_pkt_writer_proc *writer_proc);
int32_t world_init(int32_t seed, uint16_t chunk_size, uint16_t chunk_amount); int32_t world_init(int32_t seed, uint16_t chunk_size, uint16_t chunk_amount);
int32_t world_destroy(void); int32_t world_destroy(void);
int32_t world_update(void); int32_t world_update(void);
int32_t world_read(void* data, uint32_t datalen, void *udata); int32_t world_read(void* data, uint32_t datalen, void *udata);
int32_t world_write(pkt_header *pkt, void *udata); int32_t world_write(pkt_header *pkt, void *udata);
uint32_t world_buf(uint8_t const **ptr, uint32_t *width); uint32_t world_buf(uint8_t const **ptr, uint32_t *width);
uint32_t world_seed(void); uint32_t world_seed(void);
ecs_world_t *world_ecs(void); ecs_world_t *world_ecs(void);
void world_set_stage(ecs_world_t *ecs); void world_set_stage(ecs_world_t *ecs);
librg_world *world_tracker(void); librg_world *world_tracker(void);
// NOTE(zaklaus): World simulation time control // NOTE(zaklaus): World simulation time control
void world_pause(void); void world_pause(void);
void world_resume(void); void world_resume(void);
bool world_is_paused(void); bool world_is_paused(void);
void world_step(float step_size); void world_step(float step_size);
uint16_t world_chunk_size(void); uint16_t world_chunk_size(void);
uint16_t world_chunk_amount(void); uint16_t world_chunk_amount(void);
uint16_t world_dim(void); uint16_t world_dim(void);
ecs_entity_t world_chunk_mapping(librg_chunk id); ecs_entity_t world_chunk_mapping(librg_chunk id);
typedef struct { typedef struct {
uint32_t id; uint32_t id;
uint8_t block_id; uint8_t block_id;
ecs_entity_t chunk_e; ecs_entity_t chunk_e;
int64_t chunk_id; int64_t chunk_id;
float ox, oy; float ox, oy;
} world_block_lookup; } world_block_lookup;
world_block_lookup world_block_from_realpos(float x, float y); world_block_lookup world_block_from_realpos(float x, float y);
world_block_lookup world_block_from_index(int64_t id, uint16_t block_idx); world_block_lookup world_block_from_index(int64_t id, uint16_t block_idx);
int64_t world_chunk_from_realpos(float x, float y); int64_t world_chunk_from_realpos(float x, float y);
int64_t world_chunk_from_entity(ecs_entity_t id); int64_t world_chunk_from_entity(ecs_entity_t id);
void world_chunk_replace_block(int64_t id, uint16_t block_idx, uint8_t block_id); void world_chunk_replace_block(int64_t id, uint16_t block_idx, uint8_t block_id);
bool world_chunk_place_block(int64_t id, uint16_t block_idx, uint8_t block_id); bool world_chunk_place_block(int64_t id, uint16_t block_idx, uint8_t block_id);
uint8_t *world_chunk_get_blocks(int64_t id); uint8_t *world_chunk_get_blocks(int64_t id);
void world_chunk_mark_dirty(ecs_entity_t e); void world_chunk_mark_dirty(ecs_entity_t e);
uint8_t world_chunk_is_dirty(ecs_entity_t e); uint8_t world_chunk_is_dirty(ecs_entity_t e);
// NOTE(zaklaus): Uses locally persistent buffer !! // NOTE(zaklaus): Uses locally persistent buffer !!
int64_t *world_chunk_fetch_entities(librg_chunk chunk_id, size_t *ents_len); int64_t *world_chunk_fetch_entities(librg_chunk chunk_id, size_t *ents_len);
int64_t *world_chunk_fetch_entities_realpos(float x, float y, size_t *ents_len); int64_t *world_chunk_fetch_entities_realpos(float x, float y, size_t *ents_len);
int64_t *world_chunk_query_entities(int64_t e, size_t *ents_len, int8_t radius); int64_t *world_chunk_query_entities(int64_t e, size_t *ents_len, int8_t radius);
uint8_t world_entity_valid(ecs_entity_t e); uint8_t world_entity_valid(ecs_entity_t e);

View File

@ -1,95 +1,95 @@
#include "zpl.h" #include "zpl.h"
#include "world_view.h" #include "world_view.h"
#include "entity_view.h" #include "entity_view.h"
#include "prediction.h" #include "prediction.h"
#include "librg.h" #include "librg.h"
#include "world/world.h" #include "world/world.h"
#include "game.h" #include "game.h"
int32_t tracker_read_remove(librg_world *w, librg_event *e) { int32_t tracker_read_remove(librg_world *w, librg_event *e) {
int64_t entity_id = librg_event_entity_get(w, e); int64_t entity_id = librg_event_entity_get(w, e);
world_view *view = (world_view*)librg_world_userdata_get(w); world_view *view = (world_view*)librg_world_userdata_get(w);
entity_view_remove_chunk_texture(&view->entities, entity_id); entity_view_remove_chunk_texture(&view->entities, entity_id);
entity_view_destroy(&view->entities, entity_id); entity_view_destroy(&view->entities, entity_id);
return 0; return 0;
} }
int32_t tracker_read_update(librg_world *w, librg_event *e) { int32_t tracker_read_update(librg_world *w, librg_event *e) {
int64_t entity_id = librg_event_entity_get(w, e); int64_t entity_id = librg_event_entity_get(w, e);
size_t actual_length = librg_event_size_get(w, e); size_t actual_length = librg_event_size_get(w, e);
char *buffer = librg_event_buffer_get(w, e); char *buffer = librg_event_buffer_get(w, e);
world_view *view = (world_view*)librg_world_userdata_get(w); world_view *view = (world_view*)librg_world_userdata_get(w);
entity_view data = entity_view_unpack_struct(buffer, actual_length); entity_view data = entity_view_unpack_struct(buffer, actual_length);
entity_view *d = entity_view_get(&view->entities, entity_id); entity_view *d = entity_view_get(&view->entities, entity_id);
#if 1 #if 1
if (d && d->layer_id < view->active_layer_id) { if (d && d->layer_id < view->active_layer_id) {
if (zpl_time_rel_ms() - d->last_update > WORLD_TRACKER_UPDATE_NORMAL_MS) { if (zpl_time_rel_ms() - d->last_update > WORLD_TRACKER_UPDATE_NORMAL_MS) {
d->layer_id = zpl_min(WORLD_TRACKER_LAYERS-1, d->layer_id+1); d->layer_id = zpl_min(WORLD_TRACKER_LAYERS-1, d->layer_id+1);
} }
// NOTE(zaklaus): reject updates from slower layers // NOTE(zaklaus): reject updates from slower layers
else return 0; else return 0;
} }
#endif #endif
data.last_update = zpl_time_rel_ms(); data.last_update = zpl_time_rel_ms();
data.layer_id = view->active_layer_id; data.layer_id = view->active_layer_id;
predict_receive_update(d, &data); predict_receive_update(d, &data);
entity_view_update_or_create(&view->entities, entity_id, data); entity_view_update_or_create(&view->entities, entity_id, data);
entity_view_remove_chunk_texture(&view->entities, entity_id); entity_view_remove_chunk_texture(&view->entities, entity_id);
entity_view_update_chunk_texture(&view->entities, entity_id, view); entity_view_update_chunk_texture(&view->entities, entity_id, view);
return 0; return 0;
} }
int32_t tracker_read_create(librg_world *w, librg_event *e) { int32_t tracker_read_create(librg_world *w, librg_event *e) {
int64_t entity_id = librg_event_entity_get(w, e); int64_t entity_id = librg_event_entity_get(w, e);
size_t actual_length = librg_event_size_get(w, e); size_t actual_length = librg_event_size_get(w, e);
char *buffer = librg_event_buffer_get(w, e); char *buffer = librg_event_buffer_get(w, e);
world_view *view = (world_view*)librg_world_userdata_get(w); world_view *view = (world_view*)librg_world_userdata_get(w);
entity_view data = entity_view_unpack_struct(buffer, actual_length); entity_view data = entity_view_unpack_struct(buffer, actual_length);
data.ent_id = entity_id; data.ent_id = entity_id;
data.layer_id = view->active_layer_id; data.layer_id = view->active_layer_id;
data.tran_time = 0.0f; data.tran_time = 0.0f;
data.color = rand(); // TODO(zaklaus): feed from server data.color = rand(); // TODO(zaklaus): feed from server
if (data.flag & EFLAG_INTERP) { if (data.flag & EFLAG_INTERP) {
data.tx = data.x; data.tx = data.x;
data.ty = data.y; data.ty = data.y;
data.theading = data.heading; data.theading = data.heading;
} }
entity_view_update_or_create(&view->entities, entity_id, data); entity_view_update_or_create(&view->entities, entity_id, data);
entity_view_mark_for_fadein(&view->entities, entity_id); entity_view_mark_for_fadein(&view->entities, entity_id);
entity_view_update_chunk_texture(&view->entities, entity_id, view); entity_view_update_chunk_texture(&view->entities, entity_id, view);
return 0; return 0;
} }
world_view world_view_create(uint16_t view_id) { world_view world_view_create(uint16_t view_id) {
world_view view = {0}; world_view view = {0};
view.view_id = view_id; view.view_id = view_id;
view.tracker = librg_world_create(); view.tracker = librg_world_create();
entity_view_init(&view.entities); entity_view_init(&view.entities);
return view; return view;
} }
void world_view_init(world_view *view, uint32_t seed, uint64_t ent_id, uint16_t chunk_size, uint16_t chunk_amount) { void world_view_init(world_view *view, uint32_t seed, uint64_t ent_id, uint16_t chunk_size, uint16_t chunk_amount) {
view->seed = seed; view->seed = seed;
view->owner_id = ent_id; view->owner_id = ent_id;
view->chunk_size = chunk_size; view->chunk_size = chunk_size;
view->chunk_amount = chunk_amount; view->chunk_amount = chunk_amount;
view->dim = WORLD_BLOCK_SIZE * chunk_size * chunk_amount; view->dim = WORLD_BLOCK_SIZE * chunk_size * chunk_amount;
view->size = view->dim * view->dim; view->size = view->dim * view->dim;
librg_config_chunksize_set(view->tracker, WORLD_BLOCK_SIZE * chunk_size, WORLD_BLOCK_SIZE * chunk_size, 1); librg_config_chunksize_set(view->tracker, WORLD_BLOCK_SIZE * chunk_size, WORLD_BLOCK_SIZE * chunk_size, 1);
librg_config_chunkamount_set(view->tracker, chunk_amount, chunk_amount, 1); librg_config_chunkamount_set(view->tracker, chunk_amount, chunk_amount, 1);
librg_config_chunkoffset_set(view->tracker, LIBRG_OFFSET_BEG, LIBRG_OFFSET_BEG, 0); librg_config_chunkoffset_set(view->tracker, LIBRG_OFFSET_BEG, LIBRG_OFFSET_BEG, 0);
librg_event_set(view->tracker, LIBRG_READ_CREATE, tracker_read_create); librg_event_set(view->tracker, LIBRG_READ_CREATE, tracker_read_create);
librg_event_set(view->tracker, LIBRG_READ_REMOVE, tracker_read_remove); librg_event_set(view->tracker, LIBRG_READ_REMOVE, tracker_read_remove);
librg_event_set(view->tracker, LIBRG_READ_UPDATE, tracker_read_update); librg_event_set(view->tracker, LIBRG_READ_UPDATE, tracker_read_update);
librg_world_userdata_set(view->tracker, view); librg_world_userdata_set(view->tracker, view);
} }
void world_view_destroy(world_view *view) { void world_view_destroy(world_view *view) {
librg_world_destroy(view->tracker); librg_world_destroy(view->tracker);
entity_view_free(&view->entities); entity_view_free(&view->entities);
} }

View File

@ -1,176 +1,176 @@
#pragma once #pragma once
#include "flecs/flecs.h" #include "flecs/flecs.h"
#include "flecs/flecs_meta.h" #include "flecs/flecs_meta.h"
//NOTE(zaklaus): custom macro to define meta components outside the current scope //NOTE(zaklaus): custom macro to define meta components outside the current scope
#ifndef ECS_META_DEFINE #ifndef ECS_META_DEFINE
#define ECS_META_DEFINE(world, T)\ #define ECS_META_DEFINE(world, T)\
ECS_COMPONENT_DEFINE(world, T);\ ECS_COMPONENT_DEFINE(world, T);\
ecs_new_meta(world, ecs_entity(T), &__##T##__); ecs_new_meta(world, ecs_entity(T), &__##T##__);
#endif #endif
#ifndef ecs_get_mut_if #ifndef ecs_get_mut_if
#define ecs_get_mut_if(world, entity, component)\ #define ecs_get_mut_if(world, entity, component)\
(ecs_get(world, entity, component) ? ecs_get_mut(world, entity, component, NULL) : NULL) (ecs_get(world, entity, component) ? ecs_get_mut(world, entity, component, NULL) : NULL)
#endif #endif
#define ITEMS_INVENTORY_SIZE 9 #define ITEMS_INVENTORY_SIZE 9
ECS_STRUCT(Vector2D, { ECS_STRUCT(Vector2D, {
float x; float x;
float y; float y;
}); });
ECS_STRUCT(Chunk, { ECS_STRUCT(Chunk, {
uint32_t id; uint32_t id;
int16_t x; int16_t x;
int16_t y; int16_t y;
uint8_t is_dirty; uint8_t is_dirty;
}); });
ECS_STRUCT(Drawable, { ECS_STRUCT(Drawable, {
uint16_t id; uint16_t id;
}); });
ECS_ALIAS(Vector2D, Position); ECS_ALIAS(Vector2D, Position);
ECS_ALIAS(Vector2D, Velocity); ECS_ALIAS(Vector2D, Velocity);
ECS_STRUCT(Input, { ECS_STRUCT(Input, {
float x; float x;
float y; float y;
float mx; float mx;
float my; float my;
uint8_t use; uint8_t use;
uint8_t sprint; uint8_t sprint;
uint8_t ctrl; uint8_t ctrl;
uint8_t is_blocked; uint8_t is_blocked;
// NOTE(zaklaus): inventory // NOTE(zaklaus): inventory
uint8_t selected_item; uint8_t selected_item;
uint8_t drop; uint8_t drop;
uint8_t swap; uint8_t swap;
uint8_t swap_from; uint8_t swap_from;
uint8_t swap_to; uint8_t swap_to;
// NOTE(zaklaus): build mode // NOTE(zaklaus): build mode
uint8_t num_placements; uint8_t num_placements;
float placements_x[20]; float placements_x[20];
float placements_y[20]; float placements_y[20];
}); });
ECS_STRUCT(ClientInfo, { ECS_STRUCT(ClientInfo, {
uintptr_t peer; uintptr_t peer;
uint16_t view_id; uint16_t view_id;
}); });
ECS_STRUCT(Health, { ECS_STRUCT(Health, {
float hp; float hp;
float max_hp; float max_hp;
//NOTE(zaklaus): Intentionally global, to allow for creative use of damage combos //NOTE(zaklaus): Intentionally global, to allow for creative use of damage combos
float pain_time; float pain_time;
float heal_time; float heal_time;
}); });
ECS_STRUCT(Classify, { ECS_STRUCT(Classify, {
uint16_t id; uint16_t id;
}); });
ECS_STRUCT(Vehicle, { ECS_STRUCT(Vehicle, {
uint64_t seats[4]; uint64_t seats[4];
float force; float force;
float heading; float heading;
float steer; float steer;
float wheel_base; float wheel_base;
float speed; float speed;
float reverse_speed; float reverse_speed;
}); });
typedef struct { typedef struct {
ecs_entity_t veh; ecs_entity_t veh;
} IsInVehicle; } IsInVehicle;
typedef struct { typedef struct {
uint16_t kind; uint16_t kind;
uint32_t quantity; uint32_t quantity;
float merger_time; float merger_time;
} ItemDrop; } ItemDrop;
typedef struct { typedef struct {
ItemDrop items[ITEMS_INVENTORY_SIZE]; ItemDrop items[ITEMS_INVENTORY_SIZE];
float pickup_time; float pickup_time;
} Inventory; } Inventory;
ECS_COMPONENT_EXTERN(Chunk); ECS_COMPONENT_EXTERN(Chunk);
ECS_COMPONENT_EXTERN(Position); ECS_COMPONENT_EXTERN(Position);
ECS_COMPONENT_EXTERN(Vector2D); ECS_COMPONENT_EXTERN(Vector2D);
ECS_COMPONENT_EXTERN(Drawable); ECS_COMPONENT_EXTERN(Drawable);
ECS_COMPONENT_EXTERN(Input); ECS_COMPONENT_EXTERN(Input);
ECS_COMPONENT_EXTERN(Velocity); ECS_COMPONENT_EXTERN(Velocity);
ECS_COMPONENT_EXTERN(ClientInfo); ECS_COMPONENT_EXTERN(ClientInfo);
ECS_COMPONENT_EXTERN(Health); ECS_COMPONENT_EXTERN(Health);
ECS_COMPONENT_EXTERN(Classify); ECS_COMPONENT_EXTERN(Classify);
ECS_COMPONENT_EXTERN(Vehicle); ECS_COMPONENT_EXTERN(Vehicle);
ECS_COMPONENT_EXTERN(IsInVehicle); ECS_COMPONENT_EXTERN(IsInVehicle);
ECS_COMPONENT_EXTERN(ItemDrop); ECS_COMPONENT_EXTERN(ItemDrop);
ECS_COMPONENT_EXTERN(Inventory); ECS_COMPONENT_EXTERN(Inventory);
ECS_TAG_EXTERN(EcsActor); ECS_TAG_EXTERN(EcsActor);
ECS_TAG_EXTERN(EcsDemoNPC); ECS_TAG_EXTERN(EcsDemoNPC);
ECS_TYPE_EXTERN(Player); ECS_TYPE_EXTERN(Player);
ECS_TYPE_EXTERN(Movement); ECS_TYPE_EXTERN(Movement);
ECS_TYPE_EXTERN(Walking); ECS_TYPE_EXTERN(Walking);
ECS_TYPE_EXTERN(Flying); ECS_TYPE_EXTERN(Flying);
ECS_TYPE_EXTERN(EcsClient); ECS_TYPE_EXTERN(EcsClient);
// NOTE(zaklaus): @1 EXTERN // NOTE(zaklaus): @1 EXTERN
typedef struct { typedef struct {
ECS_DECLARE_COMPONENT(Chunk); ECS_DECLARE_COMPONENT(Chunk);
ECS_DECLARE_COMPONENT(Position); ECS_DECLARE_COMPONENT(Position);
ECS_DECLARE_COMPONENT(Vector2D); ECS_DECLARE_COMPONENT(Vector2D);
ECS_DECLARE_COMPONENT(Drawable); ECS_DECLARE_COMPONENT(Drawable);
ECS_DECLARE_COMPONENT(Input); ECS_DECLARE_COMPONENT(Input);
ECS_DECLARE_COMPONENT(Velocity); ECS_DECLARE_COMPONENT(Velocity);
ECS_DECLARE_COMPONENT(ClientInfo); ECS_DECLARE_COMPONENT(ClientInfo);
ECS_DECLARE_COMPONENT(Health); ECS_DECLARE_COMPONENT(Health);
ECS_DECLARE_COMPONENT(Classify); ECS_DECLARE_COMPONENT(Classify);
ECS_DECLARE_COMPONENT(Vehicle); ECS_DECLARE_COMPONENT(Vehicle);
ECS_DECLARE_COMPONENT(IsInVehicle); ECS_DECLARE_COMPONENT(IsInVehicle);
ECS_DECLARE_COMPONENT(ItemDrop); ECS_DECLARE_COMPONENT(ItemDrop);
ECS_DECLARE_COMPONENT(Inventory); ECS_DECLARE_COMPONENT(Inventory);
ECS_DECLARE_ENTITY(EcsActor); ECS_DECLARE_ENTITY(EcsActor);
ECS_DECLARE_ENTITY(EcsDemoNPC); ECS_DECLARE_ENTITY(EcsDemoNPC);
ECS_DECLARE_TYPE(Player); ECS_DECLARE_TYPE(Player);
ECS_DECLARE_TYPE(Builder); ECS_DECLARE_TYPE(Builder);
ECS_DECLARE_TYPE(Movement); ECS_DECLARE_TYPE(Movement);
ECS_DECLARE_ENTITY(Walking); ECS_DECLARE_ENTITY(Walking);
ECS_DECLARE_ENTITY(Flying); ECS_DECLARE_ENTITY(Flying);
// NOTE(zaklaus): @2 DECLARE // NOTE(zaklaus): @2 DECLARE
} Components; } Components;
#define ComponentsImportHandles(handles)\ #define ComponentsImportHandles(handles)\
ECS_IMPORT_COMPONENT(handles, Chunk);\ ECS_IMPORT_COMPONENT(handles, Chunk);\
ECS_IMPORT_COMPONENT(handles, Vector2D);\ ECS_IMPORT_COMPONENT(handles, Vector2D);\
ECS_IMPORT_COMPONENT(handles, Position);\ ECS_IMPORT_COMPONENT(handles, Position);\
ECS_IMPORT_COMPONENT(handles, Drawable);\ ECS_IMPORT_COMPONENT(handles, Drawable);\
ECS_IMPORT_COMPONENT(handles, Input);\ ECS_IMPORT_COMPONENT(handles, Input);\
ECS_IMPORT_COMPONENT(handles, Velocity);\ ECS_IMPORT_COMPONENT(handles, Velocity);\
ECS_IMPORT_COMPONENT(handles, ClientInfo);\ ECS_IMPORT_COMPONENT(handles, ClientInfo);\
ECS_IMPORT_COMPONENT(handles, Health);\ ECS_IMPORT_COMPONENT(handles, Health);\
ECS_IMPORT_COMPONENT(handles, Classify);\ ECS_IMPORT_COMPONENT(handles, Classify);\
ECS_IMPORT_COMPONENT(handles, Vehicle);\ ECS_IMPORT_COMPONENT(handles, Vehicle);\
ECS_IMPORT_COMPONENT(handles, IsInVehicle);\ ECS_IMPORT_COMPONENT(handles, IsInVehicle);\
ECS_IMPORT_COMPONENT(handles, ItemDrop);\ ECS_IMPORT_COMPONENT(handles, ItemDrop);\
ECS_IMPORT_COMPONENT(handles, Inventory);\ ECS_IMPORT_COMPONENT(handles, Inventory);\
ECS_IMPORT_TYPE(handles, Player);\ ECS_IMPORT_TYPE(handles, Player);\
ECS_IMPORT_TYPE(handles, Builder);\ ECS_IMPORT_TYPE(handles, Builder);\
ECS_IMPORT_TYPE(handles, Movement);\ ECS_IMPORT_TYPE(handles, Movement);\
ECS_IMPORT_ENTITY(handles, EcsActor);\ ECS_IMPORT_ENTITY(handles, EcsActor);\
ECS_IMPORT_ENTITY(handles, EcsDemoNPC);\ ECS_IMPORT_ENTITY(handles, EcsDemoNPC);\
ECS_IMPORT_ENTITY(handles, Walking);\ ECS_IMPORT_ENTITY(handles, Walking);\
ECS_IMPORT_ENTITY(handles, Flying);\ ECS_IMPORT_ENTITY(handles, Flying);\
// NOTE(zaklaus): @3 IMPORT // NOTE(zaklaus): @3 IMPORT
void ComponentsImport(ecs_world_t *ecs); void ComponentsImport(ecs_world_t *ecs);

View File

@ -1,12 +1,12 @@
#define DEMO_NPC_MOVE_SPEED 500 #define DEMO_NPC_MOVE_SPEED 500
#define DEMO_NPC_STEER_SPEED 300 #define DEMO_NPC_STEER_SPEED 300
void DemoNPCMoveAround(ecs_iter_t *it) { void DemoNPCMoveAround(ecs_iter_t *it) {
Velocity *v = ecs_column(it, Velocity, 1); Velocity *v = ecs_column(it, Velocity, 1);
for (int i = 0; i < it->count; i++) { for (int i = 0; i < it->count; i++) {
float d = zpl_quake_rsqrt(v[i].x*v[i].x + v[i].y*v[i].y); float d = zpl_quake_rsqrt(v[i].x*v[i].x + v[i].y*v[i].y);
v[i].x += (v[i].x*d*DEMO_NPC_MOVE_SPEED*safe_dt(it) + zpl_cos(zpl_to_radians(rand()%360))*DEMO_NPC_STEER_SPEED*safe_dt(it)); v[i].x += (v[i].x*d*DEMO_NPC_MOVE_SPEED*safe_dt(it) + zpl_cos(zpl_to_radians(rand()%360))*DEMO_NPC_STEER_SPEED*safe_dt(it));
v[i].y += (v[i].y*d*DEMO_NPC_MOVE_SPEED*safe_dt(it) + zpl_sin(zpl_to_radians(rand()%360))*DEMO_NPC_STEER_SPEED*safe_dt(it)); v[i].y += (v[i].y*d*DEMO_NPC_MOVE_SPEED*safe_dt(it) + zpl_sin(zpl_to_radians(rand()%360))*DEMO_NPC_STEER_SPEED*safe_dt(it));
} }
} }

7
dos2unix_conv.sh 100644
View File

@ -0,0 +1,7 @@
#!/bin/sh
script_path=$(cd -P -- "$(dirname -- "$0")" && pwd -P)
cd "$script_path/" || exit 1
find code/modules/ -type f -print0 | xargs -0 dos2unix -ic0 | xargs -0 dos2unix -b
find code/game/ -type f -print0 | xargs -0 dos2unix -ic0 | xargs -0 dos2unix -b