Initial integration of nuklear as gui framework and minor additions/tweaks all around the codebase

dev
Shariq Shah 9 years ago
parent fc57ea5f31
commit 9007024b26
  1. 91
      README
  2. 14
      assets/shaders/gui.frag
  3. 17
      assets/shaders/gui.vert
  4. 22285
      include/nuklear.h
  5. 18
      orgfile.org
  6. 46
      src/file_io.c
  7. 2
      src/file_io.h
  8. 48
      src/game.c
  9. 405
      src/gui.c
  10. 46
      src/gui.h
  11. 22
      src/input.c
  12. 2
      src/input.h
  13. 45
      src/platform.c
  14. 7
      src/platform.h
  15. 47
      src/renderer.c
  16. 4
      src/renderer.h
  17. 14
      src/shader.c
  18. 1
      src/shader.h
  19. 26
      src/texture.c
  20. 2
      src/texture.h

@ -47,22 +47,27 @@ _________________
.. 2.31 CANCELED Draw light volumes
.. 2.32 TODO Fix problems with frustrum culling
.. 2.33 TODO 2d drawing routines
.. 2.34 TODO Gui
.. 2.34 DONE Gui
.. 2.35 CANCELED Image based lighting?
.. 2.36 CANCELED Deferred rendering?
.. 2.37 TODO Fix mouse bugs on windows
.. 2.38 TODO Physics
.. 2.39 TODO Allow passsing base path as commandline argument?
.. 2.40 TODO Validate necessary assets at game launch
.. 2.41 TODO Variant type
.. 2.42 TODO Event Subsystem
.. 2.43 DONE Compile and test on windows
.. 2.44 TODO Array based string type comptible with cstring(char*)
.. 2.45 DONE Fix mouse bugs
.. 2.46 DONE Fix issues with opengl context showing 2.1 only
.. 2.47 TODO Improve this readme
.. 2.48 TODO ???
.. 2.49 TODO Profit!
.. 2.38 TODO Physics/Collision detection in 2d
.. 2.39 TODO Complete gui integration
.. 2.40 TODO Allow passsing base path as commandline argument?
.. 2.41 TODO Validate necessary assets at game launch
.. 2.42 TODO Variant type
.. 2.43 TODO Log and debug/stats output in gui
.. 2.44 TODO Editor
.. 2.45 TODO Event Subsystem
.. 2.46 TODO Keybindings for gui?
.. 2.47 DONE Compile and test on windows
.. 2.48 TODO Array based string type comptible with cstring(char*)
.. 2.49 DONE Fix mouse bugs
.. 2.50 DONE Fix
.. 2.51 TODO issues with opengl context showing 2.1 only
.. 2.52 TODO Improve this readme
.. 2.53 TODO ???
.. 2.54 TODO Profit!
1 Project Symmetry
@ -285,10 +290,15 @@ _________________
2.33 TODO 2d drawing routines
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Sprite batching
- Debug drawing
2.34 TODO Gui
2.34 DONE Gui
~~~~~~~~~~~~~
- State "DONE" from "TODO" [2017-03-15 Wed 23:41]
2.35 CANCELED Image based lighting?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -308,55 +318,80 @@ _________________
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.38 TODO Physics
~~~~~~~~~~~~~~~~~
2.38 TODO Physics/Collision detection in 2d
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.39 TODO Complete gui integration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Font selection
- Font atlas proper cleanup
- Decoupled event handling of gui and input if possible
- Custom rendering for gui
2.39 TODO Allow passsing base path as commandline argument?
2.40 TODO Allow passsing base path as commandline argument?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.40 TODO Validate necessary assets at game launch
2.41 TODO Validate necessary assets at game launch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.41 TODO Variant type
2.42 TODO Variant type
~~~~~~~~~~~~~~~~~~~~~~
2.42 TODO Event Subsystem
2.43 TODO Log and debug/stats output in gui
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.44 TODO Editor
~~~~~~~~~~~~~~~~
2.45 TODO Event Subsystem
~~~~~~~~~~~~~~~~~~~~~~~~~
2.43 DONE Compile and test on windows
2.46 TODO Keybindings for gui?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.47 DONE Compile and test on windows
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- State "DONE" from "TODO" [2017-03-14 Tue 00:32]
2.44 TODO Array based string type comptible with cstring(char*)
2.48 TODO Array based string type comptible with cstring(char*)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.45 DONE Fix mouse bugs
2.49 DONE Fix mouse bugs
~~~~~~~~~~~~~~~~~~~~~~~~
- State "DONE" from "TODO" [2017-03-01 Wed 00:45]
2.46 DONE Fix issues with opengl context showing 2.1 only
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.50 DONE Fix
~~~~~~~~~~~~~
2.51 TODO issues with opengl context showing 2.1 only
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- State "DONE" from "TODO" [2017-02-26 Sun 15:39]
2.47 TODO Improve this readme
2.52 TODO Improve this readme
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.48 TODO ???
2.53 TODO ???
~~~~~~~~~~~~~
2.49 TODO Profit!
2.54 TODO Profit!
~~~~~~~~~~~~~~~~~

@ -0,0 +1,14 @@
//include version.glsl
in vec2 uv;
in vec4 color;
out vec4 frag_color;
uniform sampler2D sampler;
void main()
{
frag_color = color * texture(sampler, uv);
//frag_color = color;
}

@ -0,0 +1,17 @@
//include version.glsl
uniform mat4 proj_mat;
in vec2 vPosition;
in vec2 vUV;
in vec4 vColor;
out vec2 uv;
out vec4 color;
void main()
{
uv = vUV;
color = vColor;
gl_Position = proj_mat * vec4(vPosition, 0, 1.0);
}

File diff suppressed because it is too large Load Diff

@ -83,7 +83,10 @@ All the code in this repository is under GPLv3, see LICENSE for more information
** TODO Fix problems with frustrum culling
- Recalculate bounding boxes for rotated meshes?
** TODO 2d drawing routines
** TODO Gui
- Sprite batching
- Debug drawing
** DONE Gui
- State "DONE" from "TODO" [2017-03-15 Wed 23:41]
** CANCELED Image based lighting?
- State "CANCELED" from "TODO" [2017-03-14 Tue 00:31] \\
Not a requirement for current project
@ -91,17 +94,26 @@ All the code in this repository is under GPLv3, see LICENSE for more information
- State "CANCELED" from "TODO" [2017-02-26 Sun 01:49] \\
Sticking with forward rendering for now and focusing on tools etc.
** TODO Fix mouse bugs on windows
** TODO Physics
** TODO Physics/Collision detection in 2d
** TODO Complete gui integration
- Font selection
- Font atlas proper cleanup
- Decoupled event handling of gui and input if possible
- Custom rendering for gui
** TODO Allow passsing base path as commandline argument?
** TODO Validate necessary assets at game launch
** TODO Variant type
** TODO Log and debug/stats output in gui
** TODO Editor
** TODO Event Subsystem
** TODO Keybindings for gui?
** DONE Compile and test on windows
- State "DONE" from "TODO" [2017-03-14 Tue 00:32]
** TODO Array based string type comptible with cstring(char*)
** DONE Fix mouse bugs
- State "DONE" from "TODO" [2017-03-01 Wed 00:45]
** DONE Fix issues with opengl context showing 2.1 only
** DONE Fix
** TODO issues with opengl context showing 2.1 only
- State "DONE" from "TODO" [2017-02-26 Sun 15:39]
** TODO Improve this readme
** TODO ???

@ -17,51 +17,40 @@ void io_file_cleanup(void)
if(base_assets_path) free(base_assets_path);
}
char* io_file_read(const char* path)
char* io_file_read(const char* path, const char* mode, long* file_size)
{
/* Make path relative to base assets folder path */
char* relative_path = str_new(base_assets_path);
relative_path = str_concat(relative_path, path);
FILE* file = fopen(relative_path, "r");
FILE* file = io_file_open(path, mode);
char* data = NULL;
if(file)
if(!file) return data;
int rc = fseek(file, 0, SEEK_END);
if(rc == 0)
{
int rc = fseek(file, 0, SEEK_END);
if(rc == 0)
long size = (size_t)ftell(file);
if(file_size) *file_size = size;
rewind(file);
data = malloc(sizeof(char) * size + 1);
if(data)
{
size_t size = (size_t)ftell(file);
rewind(file);
data = malloc(sizeof(char) * size + 1);
if(data)
if(fread(data, size, 1, file) > 0)
{
if(fread(data, size, 1, file) > 0)
{
if(data[size] != '\0') data[size] = '\0';
}
else
{
log_error("io:file_read", "fread failed");
free(data);
}
if(data[size] != '\0') data[size] = '\0';
}
else
{
log_error("io:file_read", "malloc failed");
log_error("io:file_read", "fread failed");
free(data);
}
}
else
{
log_error("io:file_read", "fseek failed");
log_error("io:file_read", "malloc failed");
}
fclose(file);
}
else
{
log_error("io:file_read", "File '%s' not found", relative_path);
log_error("io:file_read", "fseek failed");
}
free(relative_path);
fclose(file);
return data;
}
@ -71,5 +60,6 @@ FILE* io_file_open(const char* path, const char* mode)
relative_path = str_concat(relative_path, path);
FILE* file = fopen(relative_path, mode);
if(!file) log_error("io:file", "Failed to open file '%s'", relative_path);
free(relative_path);
return file;
}

@ -4,7 +4,7 @@
#include <stdio.h>
void io_file_init(const char* assets_path);
char* io_file_read(const char* path);
char* io_file_read(const char* path, const char* mode, long* file_size);
FILE* io_file_open(const char* path, const char* mode);
void io_file_cleanup(void);

@ -23,11 +23,13 @@
#include "framebuffer.h"
#include "light.h"
#include "gl_load.h"
#include "gui.h"
static void run(void);
static void update(float dt, int* window_should_close);
static void render(void);
static void debug(float dt);
static void debug_gui(float dt);
static void scene_setup(void);
static struct Game_State* game_state = NULL;
@ -330,7 +332,9 @@ void run(void)
update(delta_time, &should_window_close);
render();
window_swap_buffers(game_state->window);
gui_input_begin();
platform_poll_events(&should_window_close);
gui_input_end();
}
}
@ -341,6 +345,50 @@ void update(float dt, int* window_should_close)
*window_should_close = 1;
debug(dt);
debug_gui(dt);
}
void debug_gui(float dt)
{
struct Gui_State* gui_state = gui_state_get();
struct nk_context* ctx = &gui_state->context;
if (nk_begin(ctx, "Demo", nk_rect(50, 50, 200, 200),
NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
{
nk_menubar_begin(ctx);
nk_layout_row_begin(ctx, NK_STATIC, 25, 2);
nk_layout_row_push(ctx, 45);
if (nk_menu_begin_label(ctx, "FILE", NK_TEXT_LEFT, nk_vec2(120, 200))) {
nk_layout_row_dynamic(ctx, 30, 1);
nk_menu_item_label(ctx, "OPEN", NK_TEXT_LEFT);
nk_menu_item_label(ctx, "CLOSE", NK_TEXT_LEFT);
nk_menu_end(ctx);
}
nk_layout_row_push(ctx, 45);
if (nk_menu_begin_label(ctx, "EDIT", NK_TEXT_LEFT, nk_vec2(120, 200))) {
nk_layout_row_dynamic(ctx, 30, 1);
nk_menu_item_label(ctx, "COPY", NK_TEXT_LEFT);
nk_menu_item_label(ctx, "CUT", NK_TEXT_LEFT);
nk_menu_item_label(ctx, "PASTE", NK_TEXT_LEFT);
nk_menu_end(ctx);
}
nk_layout_row_end(ctx);
nk_menubar_end(ctx);
enum {EASY, HARD};
static int op = EASY;
static int property = 20;
nk_layout_row_static(ctx, 30, 80, 1);
if (nk_button_label(ctx, "button"))
fprintf(stdout, "button pressed\n");
nk_layout_row_dynamic(ctx, 30, 2);
if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
nk_layout_row_dynamic(ctx, 25, 1);
nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
}
nk_end(ctx);
}
void render(void)

@ -0,0 +1,405 @@
#define NK_IMPLEMENTATION
#include "gui.h"
#include "platform.h"
#include "linmath.h"
#include "log.h"
#include "shader.h"
#include "texture.h"
#include "game.h"
#include "input.h"
#include "renderer.h"
#include "file_io.h"
#include <string.h>
#include <stdlib.h>
#define FONT_SIZE 14.f
struct Gui_Vertex
{
vec2 pos, uv;
nk_byte col[4];
};
static void gui_handle_clipbard_copy(nk_handle usr, const char *text, int len);
static void gui_handle_clipbard_paste(nk_handle usr, struct nk_text_edit *edit);
static void gui_handle_textinput_event(const char* text);
static void gui_upload_atlas(const void *image, int width, int height);
static void gui_font_stash_begin(struct nk_font_atlas **atlas);
static void gui_font_stash_end(void);
static struct Gui_State* gui_state = NULL;
int gui_init(void)
{
int success = 0;
gui_state = malloc(sizeof(*gui_state));
if(!gui_state)
{
log_error("gui:init", "Malloc failed, out of memory");
return success;
}
nk_init_default(&gui_state->context, 0);
gui_state->context.clip.copy = gui_handle_clipbard_copy;
gui_state->context.clip.paste = gui_handle_clipbard_paste;
gui_state->context.clip.userdata = nk_handle_ptr(0);
nk_buffer_init_default(&gui_state->cmds);
gui_state->shader = shader_create("gui.vert", "gui.frag");
if(gui_state->shader < 0)
{
log_error("gui:init", "Failed to create shader for gui");
free(gui_state);
return success;
}
gui_state->uniform_tex = shader_get_uniform_location(gui_state->shader, "sampler");
gui_state->uniform_proj = shader_get_uniform_location(gui_state->shader, "proj_mat");
gui_state->attrib_pos = shader_get_attribute_location(gui_state->shader, "vPosition");
gui_state->attrib_uv = shader_get_attribute_location(gui_state->shader, "vUV");
gui_state->attrib_col = shader_get_attribute_location(gui_state->shader, "vColor");
{
/* buffer setup */
GLsizei vs = sizeof(struct Gui_Vertex);
size_t vp = offsetof(struct Gui_Vertex, pos);
size_t vt = offsetof(struct Gui_Vertex, uv);
size_t vc = offsetof(struct Gui_Vertex, col);
glGenBuffers(1, &gui_state->vbo);
glGenBuffers(1, &gui_state->ebo);
glGenVertexArrays(1, &gui_state->vao);
glBindVertexArray(gui_state->vao);
glBindBuffer(GL_ARRAY_BUFFER, gui_state->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gui_state->ebo);
glEnableVertexAttribArray((GLuint)gui_state->attrib_pos);
glEnableVertexAttribArray((GLuint)gui_state->attrib_uv);
glEnableVertexAttribArray((GLuint)gui_state->attrib_col);
glVertexAttribPointer((GLuint)gui_state->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
glVertexAttribPointer((GLuint)gui_state->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
glVertexAttribPointer((GLuint)gui_state->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
platform_textinput_callback_set(&gui_handle_textinput_event);
renderer_check_glerror("Before font upload check");
/* Load default font and roboto */
struct nk_font_atlas* atlas = NULL;
gui_font_stash_begin(&atlas);
gui_font_stash_end();
long size = 0;
char* font_data = io_file_read("fonts/roboto.ttf", "rb", &size);
if(!font_data)
{
log_error("gui:init", "Could not load font %s", "roboto.ttf");
}
else
{
gui_font_stash_begin(&atlas);
struct nk_font *roboto = nk_font_atlas_add_from_memory(atlas, font_data, size, FONT_SIZE, NULL);
gui_font_stash_end();
if(roboto)
nk_style_set_font(&gui_state->context, &roboto->handle);
else
log_error("gui:init", "Could not add font %s", "roboto.ttf");
free(font_data);
}
//nk_font_atlas_cleanup(atlas);
success = 1;
return success;
}
void gui_upload_atlas(const void *image, int width, int height)
{
gui_state->font_tex = texture_create("Gui_Font_Tex",
TU_DIFFUSE,
width, height,
GL_RGBA,
GL_RGBA,
GL_UNSIGNED_BYTE,
image);
texture_set_param(gui_state->font_tex, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
texture_set_param(gui_state->font_tex, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
void gui_cleanup(void)
{
nk_font_atlas_clear(&gui_state->atlas);
nk_free(&gui_state->context);
shader_remove(gui_state->shader);
texture_remove(gui_state->font_tex);
glDeleteBuffers(1, &gui_state->vbo);
glDeleteBuffers(1, &gui_state->ebo);
nk_buffer_free(&gui_state->cmds);
free(gui_state);
}
void gui_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)
{
int width, height;
int display_width, display_height;
struct nk_vec2 scale;
mat4 gui_mat;
mat4_identity(&gui_mat);
struct Game_State* game_state = game_state_get();
window_get_size(game_state->window, &width, &height);
window_get_drawable_size(game_state->window, &display_width, &display_height);
mat4_ortho(&gui_mat, 0, width, height, 0, -100, 100);
scale.x = (float)display_width/(float)width;
scale.y = (float)display_height/(float)height;
/* setup global state */
glViewport(0,0,display_width,display_height);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
/* setup program */
shader_bind(gui_state->shader);
glUniform1i(gui_state->uniform_tex, 0);
shader_set_uniform(UT_MAT4, gui_state->uniform_proj, &gui_mat);
{
/* convert from command queue into draw list and draw to screen */
const struct nk_draw_command *cmd;
void *vertices, *elements;
const nk_draw_index *offset = NULL;
/* allocate vertex and element buffer */
glBindVertexArray(gui_state->vao);
glBindBuffer(GL_ARRAY_BUFFER, gui_state->vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gui_state->ebo);
glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);
/* load vertices/elements directly into vertex/element buffer */
vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
{
/* fill convert configuration */
struct nk_convert_config config;
static const struct nk_draw_vertex_layout_element vertex_layout[] =
{
{NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct Gui_Vertex, pos)},
{NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct Gui_Vertex, uv)},
{NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct Gui_Vertex, col)},
{NK_VERTEX_LAYOUT_END}
};
NK_MEMSET(&config, 0, sizeof(config));
config.vertex_layout = vertex_layout;
config.vertex_size = sizeof(struct Gui_Vertex);
config.vertex_alignment = NK_ALIGNOF(struct Gui_Vertex);
config.null = gui_state->null;
config.circle_segment_count = 22;
config.curve_segment_count = 22;
config.arc_segment_count = 22;
config.global_alpha = 1.0f;
config.shape_AA = AA;
config.line_AA = AA;
/* setup buffers to load vertices and elements */
struct nk_buffer vbuf, ebuf;
nk_buffer_init_fixed(&vbuf, vertices, (nk_size)max_vertex_buffer);
nk_buffer_init_fixed(&ebuf, elements, (nk_size)max_element_buffer);
nk_convert(&gui_state->context, &gui_state->cmds, &vbuf, &ebuf, &config);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
/* iterate over and execute each draw command */
nk_draw_foreach(cmd, &gui_state->context, &gui_state->cmds)
{
if (!cmd->elem_count) continue;
texture_bind(cmd->texture.id);
glScissor((GLint)(cmd->clip_rect.x * scale.x),
(GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),
(GLint)(cmd->clip_rect.w * scale.x),
(GLint)(cmd->clip_rect.h * scale.y));
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
offset += cmd->elem_count;
}
nk_clear(&gui_state->context);
}
shader_unbind();
texture_unbind(gui_state->font_tex);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glDisable(GL_BLEND);
glDisable(GL_SCISSOR_TEST);
}
void gui_handle_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
{
char *text = platform_clipboard_text_get();
if(text)
{
nk_textedit_paste(edit, text, nk_strlen(text));
free(text);
}
(void)usr;
}
void gui_handle_clipbard_copy(nk_handle usr, const char *text, int len)
{
char *str = 0;
(void)usr;
if (!len) return;
str = (char*)malloc((size_t)len+1);
if (!str) return;
memcpy(str, text, (size_t)len);
str[len] = '\0';
platform_clipboard_text_set(str);
free(str);
}
void gui_font_stash_begin(struct nk_font_atlas **atlas)
{
nk_font_atlas_init_default(&gui_state->atlas);
nk_font_atlas_begin(&gui_state->atlas);
*atlas = &gui_state->atlas;
}
void gui_font_stash_end(void)
{
const void *image; int w, h;
image = nk_font_atlas_bake(&gui_state->atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
gui_upload_atlas(image, w, h);
nk_font_atlas_end(&gui_state->atlas, nk_handle_id((int)gui_state->font_tex), &gui_state->null);
if (gui_state->atlas.default_font)
nk_style_set_font(&gui_state->context, &gui_state->atlas.default_font->handle);
}
void gui_handle_keyboard_event(int key, int state, int mod_ctrl, int mod_shift)
{
struct nk_context *ctx = &gui_state->context;
int down = (state == KS_PRESSED);
if (key == KEY_RSHIFT || key == KEY_LSHIFT)
nk_input_key(ctx, NK_KEY_SHIFT, down);
else if (key == KEY_DELETE)
nk_input_key(ctx, NK_KEY_DEL, down);
else if (key == KEY_RETURN)
nk_input_key(ctx, NK_KEY_ENTER, down);
else if (key == KEY_TAB)
nk_input_key(ctx, NK_KEY_TAB, down);
else if (key == KEY_BACKSPACE)
nk_input_key(ctx, NK_KEY_BACKSPACE, down);
else if (key == KEY_HOME)
{
nk_input_key(ctx, NK_KEY_TEXT_START, down);
nk_input_key(ctx, NK_KEY_SCROLL_START, down);
}
else if (key == KEY_END)
{
nk_input_key(ctx, NK_KEY_TEXT_END, down);
nk_input_key(ctx, NK_KEY_SCROLL_END, down);
}
else if (key == KEY_PAGEDOWN)
{
nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);
}
else if (key == KEY_PAGEUP)
{
nk_input_key(ctx, NK_KEY_SCROLL_UP, down);
}
else if (key == KEY_Z)
nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && mod_ctrl);
else if (key == KEY_R)
nk_input_key(ctx, NK_KEY_TEXT_REDO, down && mod_ctrl);
else if (key == KEY_C)
nk_input_key(ctx, NK_KEY_COPY, down && mod_ctrl);
else if (key == KEY_V)
nk_input_key(ctx, NK_KEY_PASTE, down && mod_ctrl);
else if (key == KEY_X)
nk_input_key(ctx, NK_KEY_CUT, down && mod_ctrl);
else if (key == KEY_B)
nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && mod_ctrl);
else if (key == KEY_E)
nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && mod_ctrl);
else if (key == KEY_UP)
nk_input_key(ctx, NK_KEY_UP, down);
else if (key == KEY_DOWN)
nk_input_key(ctx, NK_KEY_DOWN, down);
else if (key == KEY_LEFT)
{
if (mod_ctrl)
nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);
else nk_input_key(ctx, NK_KEY_LEFT, down);
}
else if (key == KEY_RIGHT)
{
if (mod_ctrl)
nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);
else
nk_input_key(ctx, NK_KEY_RIGHT, down);
}
}
void gui_handle_mousebutton_event(int button, int state, int x, int y)
{
int down = state == KS_PRESSED;
struct nk_context *ctx = &gui_state->context;
if(button == MB_LEFT) nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);
if(button == MB_MIDDLE) nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);
if(button == MB_RIGHT) nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);
}
void gui_handle_mousemotion_event(int x, int y, int xrel, int yrel)
{
struct nk_context *ctx = &gui_state->context;
if(ctx->input.mouse.grabbed)
{
int prev_x = (int)ctx->input.mouse.prev.x, prev_y = (int)ctx->input.mouse.prev.y;
nk_input_motion(ctx, prev_x + xrel, prev_y + yrel);
}
else
{
nk_input_motion(ctx, x, y);
}
}
void gui_handle_textinput_event(const char* text)
{
struct nk_context *ctx = &gui_state->context;
nk_glyph glyph;
memcpy(glyph, text, NK_UTF_SIZE);
nk_input_glyph(ctx, glyph);
}
void gui_handle_mousewheel_event(int x, int y)
{
struct nk_context *ctx = &gui_state->context;
nk_input_scroll(ctx,(float)y);
}
struct Gui_State* gui_state_get(void)
{
return gui_state;
}
void gui_input_begin(void)
{
nk_input_begin(&gui_state->context);
}
void gui_input_end(void)
{
nk_input_end(&gui_state->context);
}

@ -0,0 +1,46 @@
#ifndef GUI_H
#define GUI_H
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_STANDARD_VARARGS
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_BUTTON_TRIGGER_ON_RELEASE
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_DEFAULT_FONT
#include <nuklear.h>
#include "gl_load.h"
struct Gui_State
{
struct nk_buffer cmds;
struct nk_draw_null_texture null;
struct nk_context context;
struct nk_font_atlas atlas;
GLuint vbo, vao, ebo;
int shader;
GLuint vert_shdr;
GLuint frag_shdr;
GLint attrib_pos;
GLint attrib_uv;
GLint attrib_col;
GLint uniform_tex;
GLint uniform_proj;
int font_tex;
//GLuint font_tex;
};
int gui_init(void);
void gui_cleanup(void);
void gui_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer);
void gui_handle_mousewheel_event(int x, int y);
void gui_handle_mousemotion_event(int x, int y, int xrel, int yrel);
void gui_handle_mousebutton_event(int button, int state, int x, int y);
void gui_handle_keyboard_event(int key, int state, int mod_ctrl, int mod_shift);
void gui_input_begin(void);
void gui_input_end(void);
struct Gui_State* gui_state_get(void);
#endif

@ -5,6 +5,7 @@
#include "array.h"
#include "platform.h"
#include "log.h"
#include "gui.h"
/* #define KS_INACTIVE -1; /\* state for input map is set to KS_INACTIVE(KeyState_Inactive) when */
/* the key is neither pressed nor released *\/ */
@ -18,7 +19,8 @@ struct Input_Map
static void input_on_key(int key, int scancode, int state, int mod_ctrl, int mod_shift);
static void input_on_mousebutton(int button, int state, int x, int y, int8 num_clicks);
static void input_on_mouse_motion(int x, int y, int xrel, int yrel);
static void input_on_mousemotion(int x, int y, int xrel, int yrel);
static void input_on_mousewheel(int x, int y);
static int map_find(const char* name);
static struct Input_Map* input_map_list;
@ -27,7 +29,8 @@ void input_init(void)
{
platform_keyboard_callback_set(&input_on_key);
platform_mousebutton_callback_set(&input_on_mousebutton);
platform_mousemotion_callback_set(&input_on_mouse_motion);
platform_mousemotion_callback_set(&input_on_mousemotion);
platform_mousewheel_callback_set(&input_on_mousewheel);
input_map_list = array_new(struct Input_Map);
}
@ -42,9 +45,16 @@ void input_cleanup(void)
array_free(input_map_list);
}
void input_on_mouse_motion(int x, int y, int xrel, int yrel)
void input_on_mousemotion(int x, int y, int xrel, int yrel)
{
/* TODO: This is temporary. After proper event loop is added this code should not be here */
gui_handle_mousemotion_event(x, y, xrel, yrel);
}
void input_on_mousewheel(int x, int y)
{
/* TODO: This is temporary. After proper event loop is added this code should not be here */
gui_handle_mousewheel_event(x, y);
}
void input_mouse_pos_get(int* xpos, int* ypos)
@ -72,6 +82,8 @@ void input_on_key(int key, int scancode, int state, int mod_ctrl, int mod_shift)
}
}
}
/* TODO: This is temporary. After proper event loop is added this code should not be here */
gui_handle_keyboard_event(key, state, mod_ctrl, mod_shift);
}
void input_on_mousebutton(int button, int state, int x, int y, int8 num_clicks)
@ -79,6 +91,8 @@ void input_on_mousebutton(int button, int state, int x, int y, int8 num_clicks)
/* Probably add 'mouse maps', same as input maps for keyvboard but with buttons
Do we even need that?
*/
/* TODO: This is temporary. After proper event loop is added this code should not be here */
gui_handle_mousebutton_event(button, state, x, y);
}
void input_mouse_mode_set(enum Mouse_Mode mode)

@ -1,7 +1,7 @@
#ifndef input_H
#define input_H
#include <stdlib.h>
#include <stdlib.h>
#include "num_types.h"
#include <SDL2/SDL_keycode.h>
#include <SDL2/SDL_mouse.h>

@ -17,7 +17,9 @@ struct Platform_State
Keyboard_Event_Func on_keyboard_func;
Mousebutton_Event_Func on_mousebutton_func;
Mousemotion_Event_Func on_mousemotion_func;
Mousewheel_Event_Func on_mousewheel_func;
Windowresize_Event_Func on_windowresize_func;
Textinput_Event_Func on_textinput_func;
};
/* TODO: Find a better way to handle internal state */
@ -48,6 +50,7 @@ struct Window* window_create(const char* title, int width, int height)
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
//SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
#ifdef GL_DEBUG_CONTEXT
@ -134,6 +137,11 @@ void window_get_size(struct Window* window, int* out_width, int* out_height)
SDL_GetWindowSize((SDL_Window*)window->sdl_window, out_width, out_height);
}
void window_get_drawable_size(struct Window* window, int* out_width, int* out_height)
{
SDL_GL_GetDrawableSize((SDL_Window*)window->sdl_window, out_width, out_height);
}
void window_swap_buffers(struct Window* window)
{
SDL_GL_SwapWindow(window->sdl_window);
@ -203,6 +211,16 @@ void platform_poll_events(int* out_quit)
int y = event.motion.y;
platform_state->on_mousemotion_func(x, y, xrel, yrel);
}
case SDL_MOUSEWHEEL:
{
int x = event.wheel.x;
int y = event.wheel.y;
platform_state->on_mousewheel_func(x, y);
}
case SDL_TEXTINPUT:
{
platform_state->on_textinput_func(event.text.text);
}
case SDL_WINDOWEVENT:
{
if(event.window.type == SDL_WINDOWEVENT_RESIZED)
@ -231,6 +249,16 @@ void platform_mousemotion_callback_set(Mousemotion_Event_Func func)
platform_state->on_mousemotion_func = func;
}
void platform_mousewheel_callback_set(Mousewheel_Event_Func func)
{
platform_state->on_mousewheel_func = func;
}
void platform_textinput_callback_set(Textinput_Event_Func func)
{
platform_state->on_textinput_func = func;
}
void platform_windowresize_callback_set(Windowresize_Event_Func func)
{
platform_state->on_windowresize_func = func;
@ -297,3 +325,20 @@ char* platform_get_base_path(void)
}
return path;
}
void platform_clipboard_text_set(const char* text)
{
SDL_SetClipboardText(text);
}
char* platform_clipboard_text_get(void)
{
char* returned_text = SDL_GetClipboardText();
char* text = NULL;
if(returned_text)
{
text = str_new(returned_text);
SDL_free(returned_text);
}
return text;
}

@ -7,7 +7,9 @@
typedef void (*Keyboard_Event_Func) (int key, int scancode, int state, int mod_ctrl, int mod_shift);
typedef void (*Mousebutton_Event_Func) (int button, int state, int x, int y, int8 num_clicks);
typedef void (*Mousemotion_Event_Func) (int x, int y, int xrel, int yrel);
typedef void (*Mousewheel_Event_Func) (int x, int y);
typedef void (*Windowresize_Event_Func) (int x, int y);
typedef void (*Textinput_Event_Func) (const char* text);
// Window Related functions
struct Window;
@ -21,6 +23,7 @@ void window_make_context_current(struct Window* window);
void window_cleanup(void);
void window_set_size(struct Window* window, int width, int height);
void window_get_size(struct Window* window, int* out_width, int* out_height);
void window_get_drawable_size(struct Window* window, int* out_width, int* out_height);
void window_swap_buffers(struct Window* window);
// Platform functions
@ -30,7 +33,9 @@ void platform_poll_events(int* out_quit);
void platform_keyboard_callback_set(Keyboard_Event_Func func);
void platform_mousebutton_callback_set(Mousebutton_Event_Func func);
void platform_mousemotion_callback_set(Mousemotion_Event_Func func);
void platform_mousewheel_callback_set(Mousewheel_Event_Func func);
void platform_windowresize_callback_set(Windowresize_Event_Func func);
void platform_textinput_callback_set(Textinput_Event_Func func);
int platform_key_state_get(int key);
int platform_mousebutton_state_get(uint button);
void platform_mouse_position_get(int* x, int* y);
@ -41,5 +46,7 @@ void platform_mouse_relative_mode_set(int relative_mode);
int platform_mouse_relative_mode_get(void);
uint32 platform_get_ticks(void);
char* platform_get_base_path(void);
void platform_clipboard_text_set(const char* text);
char* platform_clipboard_text_get(void);
#endif

@ -14,6 +14,7 @@
#include "entity.h"
#include "transform.h"
#include "game.h"
#include "gui.h"
static int def_fbo = -1;
static int def_albedo_tex = -1;
@ -28,17 +29,20 @@ void renderer_init(void)
{
glClearColor(0.3f, 0.6f, 0.9f, 1.0f);
glEnable(GL_DEPTH_TEST);
/* glEnable(GL_TEXTURE_2D); */
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
platform_windowresize_callback_set(on_framebuffer_size_change);
settings.fog.mode = FM_EXPONENTIAL;
settings.fog.density = 0.01f;
settings.fog.start_dist = 50.f;
settings.fog.max_dist = 150.f;
vec3_fill(&settings.fog.color, 60.f/255.f, 60.f/255.f, 75.f/255.f);
vec3_fill(&settings.ambient_light, 0.1f, 0.1f, 0.12f);
settings.max_gui_vertex_memory = 512 * 1024;
settings.max_gui_element_memory = 128 * 1024;
gui_init();
/* Quad geometry for final render */
vec3* vertices = array_new(vec3);
@ -145,10 +149,15 @@ void renderer_draw(void)
geom_render(quad_geo);
shader_unbind();
texture_unbind(final_render_tex);
renderer_check_glerror("Before Gui Render");
gui_render(NK_ANTI_ALIASING_ON, settings.max_gui_vertex_memory, settings.max_gui_element_memory);
renderer_check_glerror("After Gui Render");
}
void renderer_cleanup(void)
{
gui_cleanup();
geom_remove(quad_geo);
framebuffer_remove(def_fbo);
texture_remove(def_albedo_tex);
@ -173,37 +182,19 @@ int renderer_check_glerror(const char* context)
{
int error = 1;
GLenum error_code = glGetError();
const char* errorString = "No Error";
const char* error_string = "No Error";
switch(error_code)
{
case GL_INVALID_OPERATION:
errorString = "Invalid Operation";
break;
case GL_NO_ERROR:
errorString = "No Error";
break;
case GL_INVALID_ENUM:
errorString = "Invalid ENUM";
break;
case GL_INVALID_VALUE:
errorString = "Invalid Value";
break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
errorString = "Invalid FrameBuffer Operation";
break;
case GL_OUT_OF_MEMORY:
errorString = "Out of Memory";
break;
/* case GL_STACK_UNDERFLOW: */
/* errorString = "Stack Underflow"; */
/* break; */
/* case GL_STACK_OVERFLOW: */
/* errorString = "Stack Overflow"; */
/* break; */
case GL_INVALID_OPERATION: error_string = "Invalid Operation"; break;
case GL_NO_ERROR: error_string = "No Error"; break;
case GL_INVALID_ENUM: error_string = "Invalid ENUM"; break;
case GL_INVALID_VALUE: error_string = "Invalid Value"; break;
case GL_INVALID_FRAMEBUFFER_OPERATION: error_string = "Invalid FrameBuffer Operation"; break;
case GL_OUT_OF_MEMORY: error_string = "Out of Memory"; break;
}
if(error_code != GL_NO_ERROR)
log_error(context, errorString);
log_error(context, error_string);
else
error = 0;

@ -24,7 +24,9 @@ struct Fog
struct Render_Settings
{
struct Fog fog;
vec3 ambient_light;
vec3 ambient_light;
int max_gui_vertex_memory;
int max_gui_element_memory;
};
struct Render_Settings* renderer_get_settings(void);

@ -20,7 +20,7 @@ const int UV_LOC = 2;
const int COLOR_LOC = 3;
static uint* shader_list;
static int* empty_indices;
static int* empty_indices;
void debug_print_shader(const char* shaderText)
{
@ -56,7 +56,7 @@ char* run_preprocessor(char* shader_text)
{
char* path = str_new("shaders/");
path = str_concat(path, filename);
char* file = io_file_read(path);
char* file = io_file_read(path, "r", NULL);
char* shader_copy = str_new(shader_text);
char* temp = realloc(shader_text, (strlen(shader_text) + strlen(file) + 2));
if(temp)
@ -96,8 +96,8 @@ int shader_create(const char* vert_shader_name, const char* frag_shader_name)
GLuint vert_shader = glCreateShader(GL_VERTEX_SHADER);
GLuint frag_shader = glCreateShader(GL_FRAGMENT_SHADER);
char* vert_source = io_file_read(vs_path);
char* frag_source = io_file_read(fs_path);
char* vert_source = io_file_read(vs_path, "r", NULL);
char* frag_source = io_file_read(fs_path, "r", NULL);
assert(vert_source != NULL);
assert(frag_source != NULL);
@ -350,3 +350,9 @@ void shader_set_uniform(const int uniform_type, const int uniform_loc, void* val
}
}
}
int shader_get_attribute_location(const int shader_index, const char* attrib_name)
{
assert(shader_index > -1 && shader_index < array_len(shader_list));
return glGetAttribLocation(shader_list[shader_index], attrib_name);
}

@ -28,5 +28,6 @@ void shader_set_uniform_mat4(const int shader_index, const char* name, const ma
void shader_set_uniform(const int uniform_type, const int uniform_loc, void* value);
void shader_cleanup(void);
int shader_get_uniform_location(const int shader_index, const char* name);
int shader_get_attribute_location(const int shader_index, const char* attrib_name);
#endif

@ -42,14 +42,14 @@ static int* empty_indices;
#define MAX_PIXEL_BYTES 5
int load_img(FILE* file, GLubyte** image_data, int* width, int* height, int* fmt, int* internal_fmt);
void debug_write_tga(struct Tga_Header* header, GLubyte* image_data);
void copy_tga_pixel(GLubyte* source, GLubyte* dest, size_t bytes_per_pixel);
int create_gl_texture(uint* out_handle, int width, int height, int format, int int_fmt, int type, void* data);
static int load_img(FILE* file, GLubyte** image_data, int* width, int* height, int* fmt, int* internal_fmt);
static void debug_write_tga(struct Tga_Header* header, GLubyte* image_data);
static void copy_tga_pixel(GLubyte* source, GLubyte* dest, size_t bytes_per_pixel);
static int create_gl_texture(uint* out_handle, int width, int height, int format, int int_fmt, int type, const void* data);
void texture_init(void)
{
texture_list = array_new(struct Texture);
texture_list = array_new(struct Texture);
empty_indices = array_new(int);
}
@ -368,13 +368,13 @@ void texture_dec_refcount(int index)
}
int texture_create(const char* name,
int texture_unit,
int width,
int height,
int format,
int int_fmt,
int type,
void* data)
int texture_unit,
int width,
int height,
int format,
int int_fmt,
int type,
const void* data)
{
assert(name && texture_unit > -1 && texture_unit <= TU_SHADOWMAP4);
int index = -1;
@ -402,7 +402,7 @@ int texture_create(const char* name,
return index;
}
int create_gl_texture(uint* out_handle, int width, int height, int format, int int_fmt, int type, void* data)
int create_gl_texture(uint* out_handle, int width, int height, int format, int int_fmt, int type, const void* data)
{
int success = 1;
glGenTextures(1, out_handle);

@ -29,6 +29,6 @@ int texture_create(const char* name,
int format,
int int_fmt,
int type,
void* data);
const void* data);
#endif

Loading…
Cancel
Save