Seperate engine and app logic, and moved editor to different build target/source file

main
noah metz 2024-11-17 19:27:42 -07:00
parent 60f518580a
commit ff46b21e11
7 changed files with 1742 additions and 1662 deletions

1
.gitignore vendored

@ -26,6 +26,7 @@ compile_commands.json
*.dSYM
roleplay
editor
.cache

@ -2,10 +2,13 @@ ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
CFLAGS = -I $(ROOT_DIR)/include -I/usr/local/include -O0 -g -Wall -Wextra
LDFLAGS = -lfreetype -lz -lglfw -lvulkan -ldl -Xlinker -rpath -Xlinker /opt/homebrew/lib
SOURCES = src/draw.c src/ui.c src/gpu.c src/hex.c src/hsv.h lib/spng.c lib/vma.cpp
APP_SOURCES = src/main.c $(SOURCES)
TEST_SOURCES = test/hsv.c $(SOURCES)
ENGINE_SOURCES = src/engine.c src/draw.c src/ui.c src/gpu.c src/hex.c src/hsv.c lib/spng.c lib/vma.cpp
APP_SOURCES = src/main.c $(ENGINE_SOURCES)
EDITOR_SOURCES = src/editor.c $(ENGINE_SOURCES)
TEST_SOURCES = test/hsv.c $(ENGINE_SOURCES)
APP_OBJECTS = $(addsuffix .o, $(basename $(APP_SOURCES)))
EDITOR_OBJECTS = $(addsuffix .o, $(basename $(EDITOR_SOURCES)))
TEST_OBJECTS = $(addsuffix .o, $(basename $(TEST_SOURCES)))
VERT_SPV = $(addsuffix .vert.spv, $(basename $(wildcard shader/*.vert)))
@ -36,6 +39,9 @@ all: roleplay $(SPV_FILES)
roleplay: $(APP_OBJECTS)
$(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $^
editor: $(EDITOR_OBJECTS)
$(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $^
test/test_hsv: $(TEST_OBJECTS)
$(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $^
@ -43,14 +49,13 @@ test/test_hsv: $(TEST_OBJECTS)
test: test/test_hsv
./test/test_hsv
%.o: %.cpp
$(CXX) $(CFLAGS) -std=c++17 -Wno-nullability-completeness -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-private-field -Wno-unused-variable -c -o $@ $<
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
.PHONY: clean clean_compdb run
.PHONY: clean clean_compdb run run_editor
clean:
rm -f $(SPV_FILES)
@ -66,6 +71,9 @@ clean_compdb:
run: roleplay $(SPV_FILES)
./roleplay
run_editor: editor $(SPV_FILES)
./editor
.PHONY: debug-sign
debug-sign:
codesign --entitlements ./ent.plist -f -s "fake-apple-signing" ./roleplay

@ -0,0 +1,87 @@
#ifndef ENGINE_H
#define ENGINE_H
#include "GLFW/glfw3.h"
#include "gpu.h"
#include "ui.h"
#include "hex.h"
typedef struct ClientContextStruct ClientContext;
typedef bool (*app_text_callback)(
ClientContext* context,
unsigned int codepoint);
typedef bool (*app_key_callback)(
ClientContext* context,
int key,
int action,
int mods);
typedef bool (*app_button_callback)(
ClientContext* context,
float x,
float y,
int button,
int action,
int mods);
typedef bool (*app_scroll_callback)(
ClientContext* context,
double x,
double y);
typedef bool (*app_cursor_callback)(
ClientContext* context,
float x,
float y);
typedef void (*app_frame_function)(
ClientContext* context);
typedef void (*app_startup_function)(
ClientContext* context);
struct ClientContextStruct {
GLFWwindow* window;
RenderContext render;
UIContext ui;
HexContext hex;
vec3 position;
vec3 velocity;
vec2 rotation;
int32_t key_spin[2];
vec2 cur_spin;
double distance;
int32_t zoom;
bool camera_mode;
float key_spin_speed;
float cur_spin_speed;
float zoom_speed;
float move_speed;
void* app_data;
app_frame_function app_frame;
app_text_callback app_text;
app_key_callback app_key;
app_button_callback app_button;
app_scroll_callback app_scroll;
app_cursor_callback app_cursor;
};
int run_app(
void* app_data,
app_startup_function app_startup,
app_frame_function app_frame,
app_text_callback app_text,
app_key_callback app_key,
app_button_callback app_button,
app_scroll_callback app_scroll,
app_cursor_callback app_cursor);
#endif

@ -145,11 +145,11 @@ typedef struct GPUContainerStruct {
typedef struct UIContextStruct UIContext;
typedef void (*ui_text_callback)(void* data, UIContext* ui, RenderContext* gpu, unsigned int codepoint);
typedef bool (*ui_text_callback)(void* data, UIContext* ui, RenderContext* gpu, unsigned int codepoint);
typedef bool (*ui_key_callback)(void* data, UIContext* ui, RenderContext* gpu, int key, int action, int mods);
typedef void (*ui_button_callback)(void* data, UIContext* ui, RenderContext* gpu, float x, float y, int button, int action, int mods);
typedef void (*ui_scroll_callback)(void* data, UIContext* ui, RenderContext* gpu, double x, double y);
typedef void (*ui_cursor_callback)(void* data, UIContext* ui, RenderContext* gpu, float x, float y);
typedef bool (*ui_button_callback)(void* data, UIContext* ui, RenderContext* gpu, float x, float y, int button, int action, int mods);
typedef bool (*ui_scroll_callback)(void* data, UIContext* ui, RenderContext* gpu, double x, double y);
typedef bool (*ui_cursor_callback)(void* data, UIContext* ui, RenderContext* gpu, float x, float y);
typedef void (*ui_deselect_callback)(void* data, UIContext* ui, RenderContext* gpu);
typedef struct UICallbacksStruct {

File diff suppressed because it is too large Load Diff

@ -0,0 +1,432 @@
#include "engine.h"
#include "gpu.h"
#include "draw.h"
void text_callback(GLFWwindow* window, unsigned int codepoint) {
ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window);
if(context->ui.active_callbacks != NULL
&& context->ui.active_callbacks->text != NULL
&& context->ui.active_callbacks->text(
context->ui.active_callbacks->data,
&context->ui,
&context->render,
codepoint)) return;
if(context->app_text != NULL && context->app_text(context, codepoint)) return;
}
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
(void)scancode;
(void)mods;
ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window);
if(context->ui.active_callbacks != NULL
&& context->ui.active_callbacks->key != NULL
&& context->ui.active_callbacks->key(
context->ui.active_callbacks->data,
&context->ui,
&context->render,
key, action, mods)) return;
if(context->app_key != NULL && context->app_key(context, key, action, mods)) return;
switch(key) {
case GLFW_KEY_A:
if(action == GLFW_PRESS) {
context->key_spin[0] -= 1;
} else if(action == GLFW_RELEASE) {
context->key_spin[0] += 1;
}
break;
case GLFW_KEY_D:
if(action == GLFW_PRESS) {
context->key_spin[0] += 1;
} else if(action == GLFW_RELEASE) {
context->key_spin[0] -= 1;
}
break;
case GLFW_KEY_W:
if(action == GLFW_PRESS) {
context->key_spin[1] += 1;
} else if(action == GLFW_RELEASE) {
context->key_spin[1] -= 1;
}
break;
case GLFW_KEY_S:
if(action == GLFW_PRESS) {
context->key_spin[1] -= 1;
} else if(action == GLFW_RELEASE) {
context->key_spin[1] += 1;
}
break;
case GLFW_KEY_UP:
if(action == GLFW_PRESS) {
context->velocity[2] += 1;
} else if(action == GLFW_RELEASE) {
context->velocity[2] -= 1;
}
break;
case GLFW_KEY_DOWN:
if(action == GLFW_PRESS) {
context->velocity[2] -= 1;
} else if(action == GLFW_RELEASE) {
context->velocity[2] += 1;
}
break;
case GLFW_KEY_LEFT:
if(action == GLFW_PRESS) {
context->velocity[0] -= 1;
} else if(action == GLFW_RELEASE) {
context->velocity[0] += 1;
}
break;
case GLFW_KEY_RIGHT:
if(action == GLFW_PRESS) {
context->velocity[0] += 1;
} else if(action == GLFW_RELEASE) {
context->velocity[0] -= 1;
}
break;
case GLFW_KEY_LEFT_SHIFT:
if(action == GLFW_PRESS) {
context->velocity[1] -= 1;
} else if(action == GLFW_RELEASE) {
context->velocity[1] += 1;
}
break;
case GLFW_KEY_SPACE:
if(action == GLFW_PRESS) {
context->velocity[1] += 1;
} else if(action == GLFW_RELEASE) {
context->velocity[1] -= 1;
}
break;
}
}
void button_callback(GLFWwindow* window, int button, int action, int mods) {
double cursor[2];
uint32_t container;
uint32_t layer;
uint32_t element;
vec2 position;
ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window);
glfwGetCursorPos(window, &cursor[0], &cursor[1]);
if(context->ui.active_callbacks != NULL && context->ui.active_callbacks->button != NULL) {
Container* container_ptr = context_container(context->ui.active_container, &context->ui);
GPUDrawable* drawable_ptr = &container_ptr->layers[context->ui.active_layer].drawables_buffer[context->ui.active_element];
vec2 element_pos = {
drawable_ptr->pos[0] + container_ptr->data.offset[0],
drawable_ptr->pos[1] + container_ptr->data.offset[1],
};
anchor_offset(&context->render, container_ptr, element_pos);
vec2 element_size = {
drawable_ptr->size[0],
drawable_ptr->size[1],
};
vec2 point = {
(cursor[0] - element_pos[0])/element_size[0],
(cursor[1] - element_pos[1])/element_size[1],
};
if((point[0] <= 1 && point[0] >= 0 && point[1] <= 1 && point[1] >= 0) || action == GLFW_RELEASE) {
context->ui.active_callbacks->button(
context->ui.active_callbacks->data,
&context->ui,
&context->render,
point[0],
point[1],
button,
action,
mods);
return;
} else {
clear_active_element(&context->ui, &context->render);
}
}
if(context->app_button != NULL && context->app_button(context, cursor[0], cursor[1], button, action, mods)) return;
if(ui_intersect(cursor, &context->render, &context->ui, UI_EVENT_BUTTON, &container, &layer, &element, position)) {
Container* container_ptr = context_container(container, &context->ui);
for(uint32_t c = 0; c < container_ptr->callback_count; c++) {
if(container_ptr->callbacks[c].element == element) {
if(container_ptr->callbacks[c].button != NULL) {
if(container_ptr->callbacks[c].button(
container_ptr->callbacks[c].data,
&context->ui,
&context->render,
position[0],
position[1],
button,
action,
mods)) return;
}
break;
}
}
}
update_hex_click(cursor, &context->hex, &context->render);
if(button == GLFW_MOUSE_BUTTON_MIDDLE) {
if(action == GLFW_PRESS) {
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
context->camera_mode = true;
} else {
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
context->camera_mode = false;
}
}
}
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
(void)xoffset;
uint32_t container;
uint32_t layer;
uint32_t element;
vec2 position;
ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window);
if(context->ui.active_callbacks != NULL
&& context->ui.active_callbacks->scroll != NULL
&& context->ui.active_callbacks->scroll(
context->ui.active_callbacks->data,
&context->ui,
&context->render,
xoffset, yoffset)) return;
if(context->app_scroll != NULL && context->app_scroll(context, xoffset, yoffset)) return;
if(ui_intersect(
context->ui.cursor,
&context->render,
&context->ui,
UI_EVENT_SCROLL,
&container,
&layer,
&element,
position)) {
Container* container_ptr = context_container(container, &context->ui);
for(uint32_t c = 0; c < container_ptr->callback_count; c++) {
if(container_ptr->callbacks[c].element == element) {
if(container_ptr->callbacks[c].scroll != NULL) {
container_ptr->callbacks[c].scroll(
container_ptr->callbacks[c].data,
&context->ui,
&context->render,
xoffset,
yoffset);
}
break;
}
}
} else {
context->zoom = -yoffset;
}
}
void cursor_callback(GLFWwindow* window, double xpos, double ypos) {
ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window);
uint32_t container;
uint32_t element;
uint32_t layer;
vec2 position;
vec2 last_cursor = {
context->ui.cursor[0],
context->ui.cursor[1],
};
context->ui.cursor[0] = xpos;
context->ui.cursor[1] = ypos;
if(context->camera_mode == true) {
context->cur_spin[0] = (xpos - last_cursor[0])/context->render.swapchain_extent.width*-100;
context->cur_spin[1] = (ypos - last_cursor[1])/context->render.swapchain_extent.height*100;
} else {
if(context->ui.active_callbacks != NULL && context->ui.active_callbacks->cursor != NULL) {
Container* container_ptr = context_container(context->ui.active_container, &context->ui);
GPUDrawable* drawable_ptr = &container_ptr->layers[context->ui.active_layer].drawables_buffer[context->ui.active_element];
vec2 element_pos = {
drawable_ptr->pos[0] + container_ptr->data.offset[0],
drawable_ptr->pos[1] + container_ptr->data.offset[1],
};
anchor_offset(&context->render, container_ptr, element_pos);
vec2 element_size = {
drawable_ptr->size[0],
drawable_ptr->size[1],
};
if(context->ui.active_callbacks->cursor(
context->ui.active_callbacks->data,
&context->ui,
&context->render,
(context->ui.cursor[0] - element_pos[0])/element_size[0],
(context->ui.cursor[1] - element_pos[1])/element_size[1])) return;
}
if(context->app_cursor != NULL && context->app_cursor(context, xpos, ypos)) return;
if(ui_intersect(context->ui.cursor, &context->render, &context->ui, UI_EVENT_CURSOR, &container, &layer, &element, position)) {
Container* container_ptr = context_container(container, &context->ui);
for(uint32_t c = 0; c < container_ptr->callback_count; c++) {
if(container_ptr->callbacks[c].element == element) {
if(container_ptr->callbacks[c].cursor != NULL) {
container_ptr->callbacks[c].cursor(
container_ptr->callbacks[c].data,
&context->ui,
&context->render,
position[0],
position[1]);
}
break;
}
}
} else {
update_hex_hover(context->ui.cursor, &context->hex, &context->render);
}
}
}
int app_main(ClientContext* context) {
VkResult result;
//
double last_frame_time = 0;
while(glfwWindowShouldClose(context->window) == 0) {
double frame_time = glfwGetTime();
double delta_time = (frame_time - last_frame_time);
// Reset callback variables
context->zoom = 0;
context->cur_spin[0] = 0;
context->cur_spin[1] = 0;
glfwPollEvents();
if(context->app_frame != NULL) context->app_frame(context);
if((context->key_spin[0] != 0 || context->key_spin[1] != 0 ||
context->velocity[0] != 0 || context->velocity[1] != 0 || context->velocity[2] != 0 ||
context->zoom != 0 ||
context->cur_spin[0] != 0 || context->cur_spin[1] != 0 ||
context->render.framebuffer_recreated == true)) {
if(context->render.framebuffer_recreated == true) {
context->render.framebuffer_recreated = false;
VK_RESULT(update_hex_proj(&context->render, &context->hex));
VK_RESULT(update_ui_context_resolution(&context->ui, &context->render));
}
context->rotation[0] += (float)context->key_spin[0]*delta_time*context->key_spin_speed;
context->rotation[0] += (float)context->cur_spin[0]*delta_time*context->cur_spin_speed;
if(context->rotation[0] > 2*M_PI) {
context->rotation[0] -= 2*M_PI;
} else if(context->rotation[0] < 0) {
context->rotation[0] += 2*M_PI;
}
context->rotation[1] += (float)context->key_spin[1]*delta_time*context->key_spin_speed;
context->rotation[1] += (float)context->cur_spin[1]*delta_time*context->cur_spin_speed;
if(context->rotation[1] > (M_PI/2 - 0.1)) {
context->rotation[1] = (M_PI/2 - 0.1);
} else if(context->rotation[1] < 0) {
context->rotation[1] = 0;
}
context->position[0] += - context->velocity[2]*context->move_speed*cos(context->rotation[0])
- context->velocity[0]*context->move_speed*sin(context->rotation[0]);
context->position[2] += context->velocity[0]*context->move_speed*cos(context->rotation[0])
- context->velocity[2]*context->move_speed*sin(context->rotation[0]);
context->position[1] += context->velocity[1]*context->move_speed;
context->distance += context->zoom*delta_time*context->zoom_speed;
if(context->distance < 1) {
context->distance = 1;
}
VK_RESULT(update_hex_view(
context->position,
context->rotation,
context->distance,
&context->render,
&context->hex));
}
//
VkResult result = draw_frame(&context->render, &context->ui, &context->hex, frame_time);
if(result != VK_SUCCESS) {
fprintf(stderr, "draw_frame error: %s\n", string_VkResult(result));
glfwDestroyWindow(context->window);
}
last_frame_time = frame_time;
}
return 0;
}
int run_app(
void* app_data,
app_startup_function app_startup,
app_frame_function app_frame,
app_text_callback app_text,
app_key_callback app_key,
app_button_callback app_button,
app_scroll_callback app_scroll,
app_cursor_callback app_cursor) {
ClientContext* context = malloc(sizeof(ClientContext));
if(context == NULL) {
return -1;
}
memset(context, 0, sizeof(ClientContext));
context->window = init_window();
context->rotation[0] = 3*M_PI/2;
context->rotation[1] = M_PI/4;
context->distance = 25;
context->key_spin_speed = 1.0;
context->cur_spin_speed = 1.0;
context->zoom_speed = 1.0;
context->move_speed = 0.1;
memset(&context->render, 0, sizeof(RenderContext));
memset(&context->ui, 0, sizeof(UIContext));
memset(&context->hex, 0, sizeof(HexContext));
context->app_data = app_data;
context->app_frame = app_frame;
context->app_text = app_text;
context->app_key = app_key;
context->app_button = app_button;
context->app_scroll = app_scroll;
context->app_cursor = app_cursor;
glfwSetWindowUserPointer(context->window, context);
glfwSetKeyCallback(context->window, key_callback);
glfwSetMouseButtonCallback(context->window, button_callback);
glfwSetScrollCallback(context->window, scroll_callback);
glfwSetCursorPosCallback(context->window, cursor_callback);
glfwSetCharCallback(context->window, text_callback);
if(init_vulkan(context->window, &context->render) != VK_SUCCESS) return -2;
// TODO: make # of fonts/textures/containers scaling, recreate GPU buffers as necessary
if(create_ui_context(10, 10, 10, &context->render, &context->ui) != VK_SUCCESS) return -3;
if(create_hex_context(&context->render, &context->hex) != VK_SUCCESS) return -4;
if(app_startup != NULL) app_startup(context);
return app_main(context);
}

File diff suppressed because it is too large Load Diff