Nuklear/demo/opengl.c
2015-04-10 21:50:42 +02:00

304 lines
9.1 KiB
C

/*
Copyright (c) 2015
vurtun <polygone@gmx.net>
MIT licence
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <GL/glu.h>
#include <SDL2/SDL.h>
#include "../gui.h"
/* macros */
#define LEN(a) (sizeof(a)/sizeof(a)[0])
#define UNUSED(v) (void)v
#define WIN_WIDTH 800
#define WIN_HEIGHT 600
#define MAX_MEMORY (256 * 1024)
#define MAX_BUFFER 64
#define DTIME 33
#include "example.c"
static void
delfont(struct gui_font *font)
{
free(font->glyphes);
free(font);
}
static struct gui_font*
mkfont(const char *path, gui_uint font_height, gui_uint bake_height,
gui_size range, enum gui_font_atlas_dimension dim)
{
gui_byte *ttf_blob;
gui_size ttf_blob_size;
struct gui_font_atlas atlas;
struct gui_font *font = calloc(sizeof(struct gui_font), 1);
atlas.dim = dim;
atlas.range = range;
atlas.size = gui_font_atlas_alloc_size(atlas.dim);
atlas.memory = calloc((gui_size)atlas.size, 1);
memset(font, 0, sizeof(*font));
font->glyph_count = (gui_uint)atlas.range;
font->glyphes = calloc(atlas.range, sizeof(struct gui_font_glyph));
font->fallback = &font->glyphes['?'];
font->scale = (gui_float)font_height / (gui_float)bake_height;
font->height = (gui_float)font_height;
ttf_blob = (gui_byte*)ldfile(path, &ttf_blob_size);
if (!gui_font_load(font, &atlas, bake_height, ttf_blob, ttf_blob_size))
goto failed;
glGenTextures(1, &font->texture.gl);
glBindTexture(GL_TEXTURE_2D, font->texture.gl);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dim, dim, 0,
GL_RGBA, GL_UNSIGNED_BYTE, atlas.memory);
free(atlas.memory);
free(ttf_blob);
return font;
failed:
free(atlas.memory);
free(ttf_blob);
delfont(font);
return NULL;
}
static void
key(struct gui_input *in, SDL_Event* e, gui_bool down)
{
SDL_Keycode code = e->key.keysym.sym;
if (code == SDLK_LCTRL || code == SDLK_RCTRL)
gui_input_key(in, GUI_KEY_CTRL, down);
else if (code == SDLK_LSHIFT || code == SDLK_RSHIFT)
gui_input_key(in, GUI_KEY_SHIFT, down);
else if (code == SDLK_DELETE)
gui_input_key(in, GUI_KEY_DEL, down);
else if (code == SDLK_RETURN)
gui_input_key(in, GUI_KEY_ENTER, down);
else if (code == SDLK_SPACE)
gui_input_key(in, GUI_KEY_SPACE, down);
else if (code == SDLK_BACKSPACE)
gui_input_key(in, GUI_KEY_BACKSPACE, down);
}
static void
button(struct gui_input *in, SDL_Event *evt, gui_bool down)
{
const int x = evt->button.x;
const int y = evt->button.y;
if (evt->button.button == SDL_BUTTON_LEFT)
gui_input_button(in, x, y, down);
}
static void
bmotion(struct gui_input *in, SDL_Event *evt)
{
const gui_int x = evt->motion.x;
const gui_int y = evt->motion.y;
gui_input_motion(in, x, y);
}
static void
text(struct gui_input *in, SDL_Event *evt)
{
gui_input_char(in, (const gui_char*)evt->text.text);
}
static void
resize(SDL_Event* evt)
{
if (evt->window.event == SDL_WINDOWEVENT_RESIZED)
glViewport(0, 0, evt->window.data1, evt->window.data2);
}
static void
draw(int width, int height, struct gui_draw_call_list **list, gui_size count)
{
gui_size i = 0;
gui_size n = 0;
const gui_byte *vertexes;
const struct gui_draw_command *cmd;
static const size_t v = sizeof(struct gui_vertex);
static const size_t p = offsetof(struct gui_vertex, pos);
static const size_t t = offsetof(struct gui_vertex, uv);
static const size_t c = offsetof(struct gui_vertex, color);
if (!list) return;
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnable(GL_TEXTURE_2D);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0f, width, height, 0.0f, 0.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
for (n = 0; n < count; ++n) {
GLint offset = 0;
vertexes = (const gui_char*)list[n]->vertexes;
glVertexPointer(2, GL_FLOAT, (GLsizei)v, (const void*)(vertexes + p));
glTexCoordPointer(2, GL_FLOAT, (GLsizei)v, (const void*)(vertexes + t));
glColorPointer(4, GL_UNSIGNED_BYTE, (GLsizei)v, (const void*)(vertexes + c));
for (i = 0; i < list[n]->command_size; ++i) {
int x,y,w,h;
cmd = &list[n]->commands[i];
x = (int)cmd->clip_rect.x;
w = (int)cmd->clip_rect.w;
h = (int)cmd->clip_rect.h;
y = height - (int)(cmd->clip_rect.y + cmd->clip_rect.h);
glScissor(x, y, w, h);
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.gl);
glDrawArrays(GL_TRIANGLES, offset, (GLsizei)cmd->vertex_count);
offset += (GLint)cmd->vertex_count;
}
}
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
}
int
main(int argc, char *argv[])
{
int width, height;
uint32_t dt, started;
gui_bool running;
SDL_Window *win;
SDL_GLContext glContext;
struct color_picker picker;
struct demo demo;
struct gui_memory memory;
struct gui_config config;
struct gui_font *font;
struct gui_input input;
struct gui_output output;
struct gui_context *ctx;
struct gui_panel *panel;
struct gui_panel *message;
struct gui_panel *color_panel;
if (argc < 2) {
fprintf(stdout, "missing font file path!\n");
exit(EXIT_FAILURE);
}
/* Window */
UNUSED(argc); UNUSED(argv);
SDL_Init(SDL_INIT_VIDEO);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
win = SDL_CreateWindow("clone", 0, 0,
WIN_WIDTH, WIN_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN);
glContext = SDL_GL_CreateContext(win);
glViewport(0, 0, WIN_WIDTH, WIN_HEIGHT);
/* GUI */
memset(&demo, 0, sizeof(demo));
memset(&picker, 0, sizeof(picker));
demo.tab.minimized = gui_true;
demo.spinner = 250;
demo.slider = 2.0f;
demo.prog = 60;
/* Context */
memset(&input, 0, sizeof(input));
memory.max_panels = 8;
memory.max_depth = 4;
memory.memory = calloc(MAX_MEMORY , 1);
memory.size = MAX_MEMORY;
memory.vertex_percentage = 0.80f;
memory.command_percentage = 0.19f;
ctx = gui_new(&memory, &input);
/* Panel */
gui_default_config(&config);
font = mkfont(argv[1], 14, 16, 255, GUI_ATLAS_DIM_256);
panel = gui_panel_new(ctx, 50, 50, 500, 320, &config, font);
message = gui_panel_new(ctx, 150, 150, 200, 100, &config, font);
color_panel = gui_panel_new(ctx, 250, 250, 400, 235, &config, font);
running = gui_true;
while (running) {
SDL_Event ev;
started = SDL_GetTicks();
gui_input_begin(&input);
while (SDL_PollEvent(&ev)) {
if (ev.type == SDL_WINDOWEVENT) resize(&ev);
else if (ev.type == SDL_MOUSEMOTION) bmotion(&input, &ev);
else if (ev.type == SDL_MOUSEBUTTONDOWN) button(&input, &ev, gui_true);
else if (ev.type == SDL_MOUSEBUTTONUP) button(&input, &ev, gui_false);
else if (ev.type == SDL_KEYDOWN) key( &input, &ev, gui_true);
else if (ev.type == SDL_KEYUP) key(&input, &ev, gui_false);
else if (ev.type == SDL_TEXTINPUT) text(&input, &ev);
else if (ev.type == SDL_QUIT) goto cleanup;
}
gui_input_end(&input);
SDL_GetWindowSize(win, &width, &height);
/* ------------------------- GUI --------------------------*/
gui_begin(ctx, (gui_float)width, (gui_float)height);
running = demo_panel(ctx, panel, &demo);
if (message_panel(ctx, message) >= 0)
running = gui_false;
if (color_picker_panel(ctx, color_panel, &picker) >= 0) {
struct gui_color c = picker.color;
fprintf(stdout, "color picked: {%u, %u, %u, %u}\n", c.r, c.g, c.b, c.a);
}
gui_end(ctx, &output, NULL);
/* ---------------------------------------------------------*/
/* Draw */
glClearColor(120.0f/255.0f, 120.0f/255.0f, 120.0f/255.0f, 120.0f/255.0f);
glClear(GL_COLOR_BUFFER_BIT);
draw(width, height, output.list, output.list_size);
SDL_GL_SwapWindow(win);
/* Timing */
dt = SDL_GetTicks() - started;
if (dt < DTIME)
SDL_Delay(DTIME - dt);
}
/* Cleanup */
cleanup:
free(memory.memory);
delfont(font);
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}