roleplay/client/src/engine.c

334 lines
11 KiB
C

#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_container,
context->ui.active_callbacks->data,
&context->ui,
&context->render,
codepoint)) return;
if(context->app_text != NULL) context->app_text(context, codepoint);
}
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_container,
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);
}
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->ui.active_container;
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_container,
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(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,
container_ptr->callbacks[c].data,
&context->ui,
&context->render,
position[0],
position[1],
button,
action,
mods)) return;
}
break;
}
}
}
if(context->app_button != NULL) context->app_button(context, cursor[0], cursor[1], button, action, mods);
}
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_container,
context->ui.active_callbacks->data,
&context->ui,
&context->render,
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,
container_ptr->callbacks[c].data,
&context->ui,
&context->render,
xoffset,
yoffset);
}
break;
}
}
}
if(context->app_scroll != NULL) context->app_scroll(context, xoffset, 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;
context->ui.cursor[0] = xpos;
context->ui.cursor[1] = ypos;
if(context->ui.active_callbacks != NULL && context->ui.active_callbacks->cursor != NULL) {
Container* container_ptr = context->ui.active_container;
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_container,
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(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,
container_ptr->callbacks[c].data,
&context->ui,
&context->render,
position[0],
position[1]);
}
break;
}
}
}
if(context->app_cursor != NULL) context->app_cursor(context, xpos, ypos);
}
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;
glfwPollEvents();
if(context->app_frame != NULL) context->app_frame(context);
if((context->spin[0] != 0 || context->spin[1] != 0 ||
context->velocity[0] != 0 || context->velocity[1] != 0 || context->velocity[2] != 0 ||
context->zoom != 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->spin[0]*delta_time*context->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->spin[1]*delta_time*context->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->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);
}