initial
This commit is contained in:
commit
e3aa8df99d
|
@ -0,0 +1,32 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 vurtun
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Install
|
||||||
|
BIN = x11
|
||||||
|
|
||||||
|
# Compiler
|
||||||
|
CC = gcc
|
||||||
|
DCC = clang
|
||||||
|
|
||||||
|
# Flags
|
||||||
|
CFLAGS = -std=c89 -pedantic -Wno-deprecated-declarations -D_POSIX_C_SOURCE=200809L
|
||||||
|
CFLAGS += -g -Wall -Wextra -Werror -Wformat -Wunreachable-code
|
||||||
|
CFLAGS += -Winline -Wshadow -Wwrite-strings -Wno-unused-variable -Wno-unused-parameter -Wno-unused-function
|
||||||
|
CFLAGS += -Wstrict-prototypes -Wold-style-definition
|
||||||
|
CFLAGS += -Wredundant-decls -Wnested-externs -Wmissing-include-dirs
|
||||||
|
CFLAGS += -Wshadow -Wpointer-arith -Wcast-qual -Wmissing-prototypes
|
||||||
|
CFLAGS += -Wswitch-default -Wundef -Wstrict-overflow=5
|
||||||
|
CFLAGS += -Winit-self -Wstrict-aliasing -Wunused
|
||||||
|
|
||||||
|
SRC = gui.c x11.c
|
||||||
|
OBJ = $(SRC:.c=.o)
|
||||||
|
|
||||||
|
# Modes
|
||||||
|
.PHONY: gcc
|
||||||
|
gcc: CC = gcc
|
||||||
|
gcc: CFLAGS += -Wno-unused-local-typedefs
|
||||||
|
gcc: $(BIN)
|
||||||
|
|
||||||
|
.PHONY: clang
|
||||||
|
clang: CC = clang
|
||||||
|
clang: $(BIN)
|
||||||
|
|
||||||
|
$(BIN):
|
||||||
|
@mkdir -p bin
|
||||||
|
rm -f bin/$(BIN) $(OBJS)
|
||||||
|
$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) -lX11 -lGL -lGLU
|
||||||
|
|
|
@ -0,0 +1,443 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2015
|
||||||
|
vurtun <polygone@gmx.net>
|
||||||
|
MIT licence
|
||||||
|
*/
|
||||||
|
#include "gui.h"
|
||||||
|
|
||||||
|
#define NULL (void*)0
|
||||||
|
#define UTF_INVALID 0xFFFD
|
||||||
|
#define PI 3.141592654f
|
||||||
|
|
||||||
|
#define PASTE(a,b) a##b
|
||||||
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||||
|
#define MAX(a,b) ((a) < (b) ? (b) : (a))
|
||||||
|
#define CLAMP(i,v,x) (MAX(MIN(v,x), i))
|
||||||
|
#define LEN(a) (sizeof(a)/sizeof(a)[0])
|
||||||
|
#define ABS(a) (((a) < 0) ? -(a) : (a))
|
||||||
|
#define UNUSED(a) ((void)(a))
|
||||||
|
#define DEG2RAD(a) ((a) * (PI / 180.0f))
|
||||||
|
#define RAD2DEG(a) ((a) * (180.0f / PI))
|
||||||
|
#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
|
||||||
|
#define INBOX(x, y, x0, y0, x1, y1) (BETWEEN(x, x0, x1) && BETWEEN(y, y0, y1))
|
||||||
|
|
||||||
|
#define ASSERT_LINE(p, l, f) \
|
||||||
|
typedef char PASTE(assertion_failed_##f##_,l)[2*!!(p)-1];
|
||||||
|
#define ASSERT(predicate) ASSERT_LINE(predicate,__LINE__,__FILE__)
|
||||||
|
|
||||||
|
#define vec2_load(v,a,b) (v).x = (a), (v).y = (b)
|
||||||
|
#define vec2_cpy(to,from) (to).x = (from).x, (to).y = (from).y
|
||||||
|
#define vec2_len(v) ((float)fsqrt((v).x*(v).x+(v).y*(v).y))
|
||||||
|
#define vec2_sub(r,a,b) do {(r).x=(a).x-(b).x; (r).y=(a).y-(b).y;} while(0)
|
||||||
|
#define vec2_add(r,a,b) do {(r).x=(a).x+(b).x; (r).y=(a).y+(b).y;} while(0)
|
||||||
|
#define vec2_muls(r, v, s) do {(r).x=(v).x*(s); (r).y=(v).y*(s);} while(0)
|
||||||
|
#define vec2_norm(r, v) do {float _ = vec2_len(v); if (_) vec2_muls(r, v, 1.0f/_);} while(0)
|
||||||
|
|
||||||
|
static const gui_texture null_tex = (void*)0;
|
||||||
|
static const struct gui_rect null_rect = {-9999, -9999, 9999 * 2, 9999 * 2};
|
||||||
|
static gui_char utfbyte[GUI_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
|
||||||
|
static gui_char utfmask[GUI_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
||||||
|
static long utfmin[GUI_UTF_SIZE+1] = {0, 0, 0x80, 0x800, 0x100000};
|
||||||
|
static long utfmax[GUI_UTF_SIZE+1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
|
||||||
|
|
||||||
|
static gui_float
|
||||||
|
fsqrt(float x)
|
||||||
|
{
|
||||||
|
float xhalf = 0.5f*x;
|
||||||
|
union {float f; int i;} val;
|
||||||
|
ASSERT(sizeof(int) == sizeof(float));
|
||||||
|
|
||||||
|
val.f = x;
|
||||||
|
val.i = 0x5f375a86 - (val.i>>1);
|
||||||
|
val.f = val.f*(1.5f-xhalf*val.f*val.f);
|
||||||
|
return 1.0f/val.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gui_size
|
||||||
|
utf_validate(long *u, gui_size i)
|
||||||
|
{
|
||||||
|
if (!BETWEEN(*u, utfmin[i], utfmax[i]) ||
|
||||||
|
BETWEEN(*u, 0xD800, 0xDFFF))
|
||||||
|
*u = UTF_INVALID;
|
||||||
|
for (i = 1; *u > utfmax[i]; ++i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
utf_decode_byte(gui_char c, gui_size *i)
|
||||||
|
{
|
||||||
|
for(*i = 0; *i < LEN(utfmask); ++(*i)) {
|
||||||
|
if ((c & utfmask[*i]) == utfbyte[*i])
|
||||||
|
return c & ~utfmask[*i];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gui_size
|
||||||
|
utf_decode(gui_char *c, long *u, gui_size clen)
|
||||||
|
{
|
||||||
|
gui_size i, j, len, type;
|
||||||
|
long udecoded;
|
||||||
|
|
||||||
|
*u = UTF_INVALID;
|
||||||
|
if (!clen) return 0;
|
||||||
|
udecoded = utf_decode_byte(c[0], &len);
|
||||||
|
if (!BETWEEN(len, 1, GUI_UTF_SIZE))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
|
||||||
|
udecoded = (udecoded << 6) | utf_decode_byte(c[i], &type);
|
||||||
|
if (type != 0)
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
if (j < len)
|
||||||
|
return 0;
|
||||||
|
*u = udecoded;
|
||||||
|
utf_validate(u, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gui_char
|
||||||
|
utf_encode_byte(long u, gui_size i)
|
||||||
|
{
|
||||||
|
return utfbyte[i] | (u & ~utfmask[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gui_size
|
||||||
|
utf_encode(long u, gui_char *c, gui_size clen)
|
||||||
|
{
|
||||||
|
gui_size len, i;
|
||||||
|
len = utf_validate(&u, 0);
|
||||||
|
if (clen < len)
|
||||||
|
return 0;
|
||||||
|
for (i = len - 1; i != 0; --i) {
|
||||||
|
c[i] = utf_encode_byte(u, 0);
|
||||||
|
u >>= 6;
|
||||||
|
}
|
||||||
|
c[0] = utf_encode_byte(u, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gui_input_begin(struct gui_input *in)
|
||||||
|
{
|
||||||
|
in->mouse_clicked = 0;
|
||||||
|
in->glyph_count = 0;
|
||||||
|
vec2_cpy(in->mouse_prev, in->mouse_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gui_input_motion(struct gui_input *in, gui_int x, gui_int y)
|
||||||
|
{
|
||||||
|
vec2_load(in->mouse_pos, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gui_input_key(struct gui_input *in, enum gui_keys key, gui_int down)
|
||||||
|
{
|
||||||
|
in->keys[key] = down;
|
||||||
|
if (key == GUI_KEY_SHIFT)
|
||||||
|
in->shift = gui_true;
|
||||||
|
if (key == GUI_KEY_CTRL)
|
||||||
|
in->ctrl = gui_true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gui_input_button(struct gui_input *in, gui_int x, gui_int y, gui_int down)
|
||||||
|
{
|
||||||
|
if (in->mouse_down == down) return;
|
||||||
|
vec2_load(in->mouse_clicked_pos, x, y);
|
||||||
|
in->mouse_down = down;
|
||||||
|
in->mouse_clicked++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gui_input_char(struct gui_input *in, gui_glyph glyph)
|
||||||
|
{
|
||||||
|
gui_size len = 0;
|
||||||
|
long unicode;
|
||||||
|
len = utf_decode(glyph, &unicode, GUI_UTF_SIZE);
|
||||||
|
if (len && in->glyph_count < GUI_INPUT_MAX) {
|
||||||
|
utf_encode(unicode, in->text[in->glyph_count], GUI_UTF_SIZE);
|
||||||
|
in->glyph_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gui_input_end(struct gui_input *in)
|
||||||
|
{
|
||||||
|
vec2_sub(in->mouse_delta, in->mouse_pos, in->mouse_prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct gui_draw_command*
|
||||||
|
gui_push_command(struct gui_draw_list *list, gui_int count,
|
||||||
|
const struct gui_rect *rect, gui_texture tex)
|
||||||
|
{
|
||||||
|
gui_size memory = 0;
|
||||||
|
gui_size current;
|
||||||
|
struct gui_draw_command *cmd = NULL;
|
||||||
|
memory += sizeof(struct gui_draw_command);
|
||||||
|
memory += sizeof(struct gui_vertex) * count;
|
||||||
|
list->needed += memory;
|
||||||
|
current = (gui_byte*)list->end - (gui_byte*)list->begin;
|
||||||
|
if (list->size < (current + memory))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cmd = list->end;
|
||||||
|
list->end = (struct gui_draw_command*)((gui_byte*)list->end + memory);
|
||||||
|
cmd->vertexes = (struct gui_vertex*)(cmd + 1);
|
||||||
|
cmd->vertex_write = 0;
|
||||||
|
cmd->vertex_count = count;
|
||||||
|
cmd->clip_rect = *rect;
|
||||||
|
cmd->texture = tex;
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gui_vertex(struct gui_draw_command *cmd, gui_float x, gui_float y,
|
||||||
|
struct gui_color col)
|
||||||
|
{
|
||||||
|
const gui_int i = cmd->vertex_write;
|
||||||
|
if (i < 0 || i >= cmd->vertex_count) return;
|
||||||
|
cmd->vertexes[i].pos.x = x;
|
||||||
|
cmd->vertexes[i].pos.y = y;
|
||||||
|
cmd->vertexes[i].color = col;
|
||||||
|
cmd->vertexes[i].uv.u = 0.0f;
|
||||||
|
cmd->vertexes[i].uv.v = 0.0f;
|
||||||
|
cmd->vertex_write++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gui_vertex_line(struct gui_draw_command* cmd, gui_float x0, gui_float y0,
|
||||||
|
gui_float x1, gui_float y1, struct gui_color col)
|
||||||
|
{
|
||||||
|
gui_float len;
|
||||||
|
struct gui_vec2 a, b, d;
|
||||||
|
struct gui_vec2 hn, hp0, hp1;
|
||||||
|
|
||||||
|
vec2_load(a, x0, y0);
|
||||||
|
vec2_load(b, x1, y1);
|
||||||
|
vec2_sub(d, b, a);
|
||||||
|
|
||||||
|
len = 0.5f / vec2_len(d);
|
||||||
|
vec2_muls(hn, d, len);
|
||||||
|
vec2_load(hp0, +hn.y, -hn.x);
|
||||||
|
vec2_load(hp1, -hn.y, +hn.x);
|
||||||
|
|
||||||
|
gui_vertex(cmd, a.x + hp0.x, a.y + hp0.y, col);
|
||||||
|
gui_vertex(cmd, b.x + hp0.x, b.y + hp0.y, col);
|
||||||
|
gui_vertex(cmd, a.x + hp1.x, a.y + hp1.y, col);
|
||||||
|
gui_vertex(cmd, b.x + hp0.x, b.y + hp0.y, col);
|
||||||
|
gui_vertex(cmd, b.x + hp1.x, b.y + hp1.y, col);
|
||||||
|
gui_vertex(cmd, a.x + hp1.x, a.y + hp1.y, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gui_line(struct gui_draw_list *list, gui_float x0, gui_float y0,
|
||||||
|
gui_float x1, gui_float y1, struct gui_color col)
|
||||||
|
{
|
||||||
|
struct gui_draw_command *cmd;
|
||||||
|
if (col.a == 0) return;
|
||||||
|
cmd = gui_push_command(list, 6, &null_rect, null_tex);
|
||||||
|
if (!cmd) return;
|
||||||
|
gui_vertex_line(cmd, x0, y0, x1, y1, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gui_trianglef(struct gui_draw_list *list, gui_float x0, gui_float y0,
|
||||||
|
gui_float x1, gui_float y1, gui_float x2, gui_float y2, struct gui_color c)
|
||||||
|
{
|
||||||
|
struct gui_draw_command *cmd;
|
||||||
|
if (c.a == 0) return;
|
||||||
|
cmd = gui_push_command(list, 3, &null_rect, null_tex);
|
||||||
|
if (!cmd) return;
|
||||||
|
gui_vertex(cmd, x0, y0, c);
|
||||||
|
gui_vertex(cmd, x1, y1, c);
|
||||||
|
gui_vertex(cmd, x2, y2, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gui_rect(struct gui_draw_list *list, gui_float x, gui_float y,
|
||||||
|
gui_float w, gui_float h, struct gui_color col)
|
||||||
|
{
|
||||||
|
struct gui_draw_command *cmd;
|
||||||
|
if (col.a == 0) return;
|
||||||
|
cmd = gui_push_command(list, 6 * 4, &null_rect, null_tex);
|
||||||
|
if (!cmd) return;
|
||||||
|
|
||||||
|
gui_vertex_line(cmd, x, y, x + w, y, col);
|
||||||
|
gui_vertex_line(cmd, x + w, y, x + w, y + h, col);
|
||||||
|
gui_vertex_line(cmd, x + w, y + h, x, y + h, col);
|
||||||
|
gui_vertex_line(cmd, x, y + h, x, y, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gui_rectf(struct gui_draw_list *list, gui_float x, gui_float y,
|
||||||
|
gui_float w, gui_float h, struct gui_color col)
|
||||||
|
{
|
||||||
|
struct gui_draw_command *cmd;
|
||||||
|
if (col.a == 0) return;
|
||||||
|
cmd = gui_push_command(list, 6, &null_rect, null_tex);
|
||||||
|
if (!cmd) return;
|
||||||
|
|
||||||
|
gui_vertex(cmd, x, y, col);
|
||||||
|
gui_vertex(cmd, x + w, y, col);
|
||||||
|
gui_vertex(cmd, x + w, y + h, col);
|
||||||
|
gui_vertex(cmd, x, y, col);
|
||||||
|
gui_vertex(cmd, x + w, y + h, col);
|
||||||
|
gui_vertex(cmd, x, y + h, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gui_begin(struct gui_draw_list *list, gui_byte *memory, gui_size size)
|
||||||
|
{
|
||||||
|
if (!list || !memory || !size) return;
|
||||||
|
list->begin = (struct gui_draw_command*)memory;
|
||||||
|
list->end = (struct gui_draw_command*)memory;
|
||||||
|
list->memory = memory;
|
||||||
|
list->size = size;
|
||||||
|
list->needed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct gui_draw_command*
|
||||||
|
gui_next(const struct gui_draw_list *list, const struct gui_draw_command *iter)
|
||||||
|
{
|
||||||
|
gui_size size = 0;
|
||||||
|
const struct gui_draw_command *cmd = NULL;
|
||||||
|
if (!list || !list->memory || !list->begin || !list->end || !list->size)
|
||||||
|
return NULL;
|
||||||
|
if (!iter || !iter->vertexes || iter < list->begin || iter > list->end)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size += sizeof(struct gui_draw_command);
|
||||||
|
size += sizeof(struct gui_vertex) * iter->vertex_count;
|
||||||
|
cmd = (const struct gui_draw_command*)((const gui_byte*)iter + size);
|
||||||
|
if (cmd >= list->end) return NULL;
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
gui_size
|
||||||
|
gui_end(struct gui_draw_list *list)
|
||||||
|
{
|
||||||
|
gui_size needed;
|
||||||
|
if (!list) return 0;
|
||||||
|
needed = list->needed;
|
||||||
|
list->needed = 0;
|
||||||
|
return needed;
|
||||||
|
}
|
||||||
|
|
||||||
|
gui_int
|
||||||
|
gui_button(struct gui_draw_list *list, const struct gui_input *in,
|
||||||
|
struct gui_color bg, struct gui_color fg,
|
||||||
|
gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad,
|
||||||
|
const char *str, gui_int len)
|
||||||
|
{
|
||||||
|
gui_int ret = gui_false;
|
||||||
|
if (!list || !in) return gui_false;
|
||||||
|
if (!in->mouse_down && in->mouse_clicked) {
|
||||||
|
const gui_int mx = in->mouse_clicked_pos.x;
|
||||||
|
const gui_int my = in->mouse_clicked_pos.y;
|
||||||
|
if (INBOX(mx, my, x, y, x + w, y + h))
|
||||||
|
ret = gui_true;
|
||||||
|
}
|
||||||
|
gui_rectf(list, x, y, w, h, bg);
|
||||||
|
gui_rect(list, x, y, w, h, fg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
gui_int
|
||||||
|
gui_slider(struct gui_draw_list *list, const struct gui_input *in,
|
||||||
|
struct gui_color bg, struct gui_color fg,
|
||||||
|
gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad,
|
||||||
|
gui_float min, gui_float cur, gui_float max, gui_float step)
|
||||||
|
{
|
||||||
|
const gui_float cw = (w - 2 * pad) / (((max - min) + 1) / step);
|
||||||
|
const gui_int ch = h - 2 * pad;
|
||||||
|
gui_int cx = x + pad + (cw * (cur - min));
|
||||||
|
gui_int cy = y + pad;
|
||||||
|
|
||||||
|
const gui_int mx = in->mouse_pos.x;
|
||||||
|
const gui_int my = in->mouse_pos.y;
|
||||||
|
const gui_int dx = in->mouse_clicked_pos.x;
|
||||||
|
const gui_int dy = in->mouse_clicked_pos.y;
|
||||||
|
|
||||||
|
if (!list || !in) return gui_false;
|
||||||
|
if (in->mouse_down &&
|
||||||
|
INBOX(dx, dy, x, y, x + w, y + h) &&
|
||||||
|
INBOX(mx, my, x, y, x + w, y + h))
|
||||||
|
{
|
||||||
|
gui_float cnx;
|
||||||
|
const gui_float tmp = mx - cx + (cw / 2);
|
||||||
|
gui_float next = cur + step * ((tmp < 0) ? -1.0f : 1.0f);
|
||||||
|
next = CLAMP(min, next, max);
|
||||||
|
cnx = x + pad + (cw * (next - min));
|
||||||
|
if (INBOX(mx, my, cnx, cy, cnx + cw, cy + ch)) {
|
||||||
|
cur = next;
|
||||||
|
cx = cnx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gui_rectf(list, x, y, w, h, bg);
|
||||||
|
gui_rectf(list, cx, cy, cw, ch, fg);
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
gui_int
|
||||||
|
gui_progress(struct gui_draw_list *list, const struct gui_input *in,
|
||||||
|
struct gui_color bg, struct gui_color fg,
|
||||||
|
gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad,
|
||||||
|
gui_float cur, gui_float max, gui_bool modifyable)
|
||||||
|
{
|
||||||
|
const gui_int mx = in->mouse_pos.x;
|
||||||
|
const gui_int my = in->mouse_pos.y;
|
||||||
|
gui_int cx, cy, cw, ch;
|
||||||
|
gui_float scale;
|
||||||
|
|
||||||
|
if (modifyable && in->mouse_down && INBOX(mx, my, x, y, x + w, y + h))
|
||||||
|
cur = max * (((gui_float)mx - (gui_float)x) / (gui_float)w);
|
||||||
|
|
||||||
|
if (!max) return cur;
|
||||||
|
cur = CLAMP(0, cur, max);
|
||||||
|
scale = (cur/max);
|
||||||
|
ch = h - 2 * pad;
|
||||||
|
cw = (w - 2 * pad) * scale;
|
||||||
|
cx = x + pad;
|
||||||
|
cy = y + pad;
|
||||||
|
gui_rectf(list, x, y, w, h, bg);
|
||||||
|
gui_rectf(list, cx, cy, cw, ch, fg);
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
gui_int
|
||||||
|
gui_scroll(struct gui_draw_list *list, const struct gui_input *in,
|
||||||
|
struct gui_color bg, struct gui_color fg,
|
||||||
|
gui_int x, gui_int y, gui_int w, gui_int h,
|
||||||
|
gui_int offset, gui_int dst)
|
||||||
|
{
|
||||||
|
const gui_int p = w / 4;
|
||||||
|
const gui_int bs = w;
|
||||||
|
const gui_int by = y + h - bs;
|
||||||
|
const gui_int barh = h - 2 * bs;
|
||||||
|
const gui_int bary = y + bs;
|
||||||
|
|
||||||
|
const gui_float ratio = (gui_float)barh/(gui_float)dst;
|
||||||
|
const gui_float off = (gui_float)offset/(gui_float)dst;
|
||||||
|
const gui_int ch = (gui_int)(ratio * (gui_float)barh);
|
||||||
|
const gui_int cy = bary + (gui_int)(off * barh);
|
||||||
|
const gui_int cw = w;
|
||||||
|
const gui_int cx = x;
|
||||||
|
static const struct gui_color col = {255, 0, 0, 255};
|
||||||
|
|
||||||
|
gui_rectf(list, x, y, w, h, bg);
|
||||||
|
if (dst <= h) return 0;
|
||||||
|
|
||||||
|
gui_button(list, in, fg, bg, x, y, bs, bs, 0, "", 0);
|
||||||
|
gui_button(list, in, fg, bg, x, by, bs, bs, 0, "", 0);
|
||||||
|
gui_trianglef(list, x + (bs/2), y+p, x+(bs-p), y+(bs-p), x+p, y+(bs-p), bg);
|
||||||
|
gui_trianglef(list, x+p, by + p, x + bs - p, by+p, x + (bs/2) , by + bs-p, bg);
|
||||||
|
|
||||||
|
gui_rectf(list, cx, cy, cw, ch, fg);
|
||||||
|
gui_rect(list, cx, cy, cw, ch, bg);
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2015
|
||||||
|
vurtun <polygone@gmx.net>
|
||||||
|
MIT licence
|
||||||
|
*/
|
||||||
|
#ifndef TINY_GUI_H_
|
||||||
|
#define TINY_GUI_H_
|
||||||
|
|
||||||
|
#define GUI_UTF_SIZE 4
|
||||||
|
#define GUI_INPUT_MAX 16
|
||||||
|
#define GUI_GLYPHES_MAX 512
|
||||||
|
|
||||||
|
typedef int gui_int;
|
||||||
|
typedef int gui_bool;
|
||||||
|
typedef unsigned char gui_char;
|
||||||
|
typedef float gui_float;
|
||||||
|
typedef void* gui_texture;
|
||||||
|
typedef unsigned char gui_byte;
|
||||||
|
typedef unsigned long gui_flag;
|
||||||
|
typedef unsigned long gui_size;
|
||||||
|
typedef gui_char gui_glyph[GUI_UTF_SIZE];
|
||||||
|
|
||||||
|
enum {gui_false, gui_true};
|
||||||
|
struct gui_color {gui_byte r,g,b,a;};
|
||||||
|
struct gui_texCoord {gui_float u,v;};
|
||||||
|
struct gui_vec2 {gui_float x,y;};
|
||||||
|
struct gui_rect {gui_float x,y,w,h;};
|
||||||
|
|
||||||
|
struct gui_vertex {
|
||||||
|
struct gui_vec2 pos;
|
||||||
|
struct gui_texCoord uv;
|
||||||
|
struct gui_color color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct gui_draw_command {
|
||||||
|
struct gui_vertex *vertexes;
|
||||||
|
gui_int vertex_count;
|
||||||
|
gui_int vertex_write;
|
||||||
|
struct gui_rect clip_rect;
|
||||||
|
gui_texture texture;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct gui_draw_list {
|
||||||
|
struct gui_draw_command *begin;
|
||||||
|
struct gui_draw_command *end;
|
||||||
|
gui_byte *memory;
|
||||||
|
gui_size size;
|
||||||
|
gui_size needed;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum gui_keys {
|
||||||
|
GUI_KEY_SHIFT,
|
||||||
|
GUI_KEY_CTRL,
|
||||||
|
GUI_KEY_DEL,
|
||||||
|
GUI_KEY_ENTER,
|
||||||
|
GUI_KEY_BACKSPACE,
|
||||||
|
GUI_KEY_ESCAPE,
|
||||||
|
GUI_KEY_SPACE,
|
||||||
|
GUI_KEY_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct gui_input {
|
||||||
|
gui_int keys[GUI_KEY_MAX];
|
||||||
|
gui_glyph text[GUI_INPUT_MAX];
|
||||||
|
gui_size glyph_count;
|
||||||
|
gui_bool shift;
|
||||||
|
gui_bool ctrl;
|
||||||
|
struct gui_vec2 mouse_pos;
|
||||||
|
struct gui_vec2 mouse_prev;
|
||||||
|
struct gui_vec2 mouse_delta;
|
||||||
|
gui_bool mouse_down;
|
||||||
|
gui_int mouse_clicked;
|
||||||
|
struct gui_vec2 mouse_clicked_pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct gui_font_glyph {
|
||||||
|
gui_glyph glpyh;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct gui_font {
|
||||||
|
struct gui_font_glyph glyphes[GUI_GLYPHES_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
|
void gui_begin(struct gui_draw_list *list, gui_byte *memory, gui_size size);
|
||||||
|
gui_size gui_end(struct gui_draw_list *list);
|
||||||
|
const struct gui_draw_command *gui_next(const struct gui_draw_list *list,
|
||||||
|
const struct gui_draw_command*);
|
||||||
|
|
||||||
|
void gui_input_begin(struct gui_input *in);
|
||||||
|
void gui_input_motion(struct gui_input *in, gui_int x, gui_int y);
|
||||||
|
void gui_input_key(struct gui_input *in, enum gui_keys key, gui_int down);
|
||||||
|
void gui_input_button(struct gui_input *in, gui_int x, gui_int y, gui_int down);
|
||||||
|
void gui_input_char(struct gui_input *in, gui_glyph glyph);
|
||||||
|
void gui_input_end(struct gui_input *in);
|
||||||
|
|
||||||
|
gui_int gui_button(struct gui_draw_list *list, const struct gui_input *in,
|
||||||
|
struct gui_color bg, struct gui_color fg,
|
||||||
|
gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad,
|
||||||
|
const char *str, gui_int len);
|
||||||
|
gui_int gui_toggle(struct gui_draw_list *list, const struct gui_input *in,
|
||||||
|
struct gui_color bg, struct gui_color fg,
|
||||||
|
gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad,
|
||||||
|
const char *str, gui_int len, gui_int active);
|
||||||
|
gui_int gui_slider(struct gui_draw_list *list, const struct gui_input *in,
|
||||||
|
struct gui_color bg, struct gui_color fg,
|
||||||
|
gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad,
|
||||||
|
gui_float min, gui_float v, gui_float max, gui_float step);
|
||||||
|
gui_int gui_progress(struct gui_draw_list *list, const struct gui_input *in,
|
||||||
|
struct gui_color bg, struct gui_color fg,
|
||||||
|
gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad,
|
||||||
|
gui_float cur, gui_float max, gui_bool modifyable);
|
||||||
|
gui_int gui_scroll(struct gui_draw_list *list, const struct gui_input *in,
|
||||||
|
struct gui_color bg, struct gui_color fg,
|
||||||
|
gui_int x, gui_int y, gui_int w, gui_int h,
|
||||||
|
gui_int offset, gui_int dst);
|
||||||
|
gui_int gui_input(struct gui_draw_list *list,
|
||||||
|
const struct gui_input *in, gui_char *buffer, gui_int *len,
|
||||||
|
struct gui_color bg, struct gui_color fg,
|
||||||
|
gui_int x, gui_int y, gui_int w, gui_int h, gui_int active);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,338 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2015
|
||||||
|
vurtun <polygone@gmx.net>
|
||||||
|
MIT licence
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glx.h>
|
||||||
|
#include <GL/glu.h>
|
||||||
|
|
||||||
|
#include "gui.h"
|
||||||
|
|
||||||
|
/* macros */
|
||||||
|
#define internal static
|
||||||
|
#define global static
|
||||||
|
#define persistent static
|
||||||
|
|
||||||
|
#define WIN_WIDTH 800
|
||||||
|
#define WIN_HEIGHT 600
|
||||||
|
#define DTIME 33
|
||||||
|
#define MAX_VERTEX_BUFFER (16 * 1024)
|
||||||
|
|
||||||
|
#define CONSOLE_MAX_CMDLINE 1024
|
||||||
|
#define CONSOLE_MAX_TEXT (16 * 1024)
|
||||||
|
|
||||||
|
#define MIN(a,b)((a) < (b) ? (a) : (b))
|
||||||
|
#define MAX(a,b)((a) < (b) ? (b) : (a))
|
||||||
|
#define CLAMP(i,v,x) (MAX(MIN(v,x), i))
|
||||||
|
#define LEN(a)(sizeof(a)/sizeof(a)[0])
|
||||||
|
#define UNUSED(a)((void)(a))
|
||||||
|
|
||||||
|
/* types */
|
||||||
|
struct XWindow {
|
||||||
|
Display *dpy;
|
||||||
|
Window root;
|
||||||
|
XVisualInfo *vi;
|
||||||
|
Colormap cmap;
|
||||||
|
XSetWindowAttributes swa;
|
||||||
|
XWindowAttributes gwa;
|
||||||
|
Window win;
|
||||||
|
GLXContext glc;
|
||||||
|
int running;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Console {
|
||||||
|
struct XWindow *win;
|
||||||
|
struct gui_draw_list gui;
|
||||||
|
struct gui_input input;
|
||||||
|
struct gui_font font;
|
||||||
|
/* text */
|
||||||
|
int output_len;
|
||||||
|
char output[CONSOLE_MAX_TEXT];
|
||||||
|
char line[CONSOLE_MAX_CMDLINE];
|
||||||
|
int line_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* functions */
|
||||||
|
internal void die(const char*,...);
|
||||||
|
internal long timestamp(void);
|
||||||
|
internal void sleep_for(long ms);
|
||||||
|
|
||||||
|
internal void kpress(struct Console*, XEvent*);
|
||||||
|
internal void bpress(struct Console*, XEvent*);
|
||||||
|
internal void brelease(struct Console*, XEvent*);
|
||||||
|
internal void bmotion(struct Console*, XEvent*);
|
||||||
|
internal void resize(struct Console*, XEvent*);
|
||||||
|
|
||||||
|
internal void
|
||||||
|
die(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void*
|
||||||
|
xcalloc(size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
void *p = calloc(nmemb, size);
|
||||||
|
if (!p)
|
||||||
|
die("out of memory\n");
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal long
|
||||||
|
timestamp(void)
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
if (gettimeofday(&tv, NULL) < 0) return 0;
|
||||||
|
return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
sleep_for(long t)
|
||||||
|
{
|
||||||
|
const time_t sec = (int)(t/1000);
|
||||||
|
const long ms = t - (sec * 1000);
|
||||||
|
struct timespec req;
|
||||||
|
req.tv_sec = sec;
|
||||||
|
req.tv_nsec = ms * 1000000L;
|
||||||
|
while(-1 == nanosleep(&req, &req));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
kpress(struct Console *con, XEvent* e)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct XWindow *xw = con->win;
|
||||||
|
KeySym *keysym = XGetKeyboardMapping(xw->dpy, e->xkey.keycode, 1, &ret);
|
||||||
|
if (*keysym == XK_Escape) xw->running = 0;
|
||||||
|
else if (*keysym == XK_Shift_L || *keysym == XK_Shift_R) gui_input_key(&con->input, GUI_KEY_SHIFT, gui_true);
|
||||||
|
else if (*keysym == XK_Control_L || *keysym == XK_Control_L) gui_input_key(&con->input, GUI_KEY_CTRL, gui_true);
|
||||||
|
else if (*keysym == XK_Delete) gui_input_key(&con->input, GUI_KEY_DEL, gui_true);
|
||||||
|
else if (*keysym == XK_Return) gui_input_key(&con->input, GUI_KEY_ENTER, gui_true);
|
||||||
|
else if (*keysym == XK_BackSpace) gui_input_key(&con->input, GUI_KEY_BACKSPACE, gui_true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
krelease(struct Console *con, XEvent* e)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct XWindow *xw = con->win;
|
||||||
|
KeySym *keysym = XGetKeyboardMapping(xw->dpy, e->xkey.keycode, 1, &ret);
|
||||||
|
if (*keysym == XK_Shift_L || *keysym == XK_Shift_R) gui_input_key(&con->input, GUI_KEY_SHIFT, gui_false);
|
||||||
|
else if (*keysym == XK_Control_L || *keysym == XK_Control_L) gui_input_key(&con->input, GUI_KEY_CTRL, gui_false);
|
||||||
|
else if (*keysym == XK_Delete) gui_input_key(&con->input, GUI_KEY_DEL, gui_false);
|
||||||
|
else if (*keysym == XK_Return) gui_input_key(&con->input, GUI_KEY_ENTER, gui_false);
|
||||||
|
else if (*keysym == XK_BackSpace) gui_input_key(&con->input, GUI_KEY_BACKSPACE, gui_false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bpress(struct Console *con, XEvent *evt)
|
||||||
|
{
|
||||||
|
const float x = evt->xbutton.x;
|
||||||
|
const float y = evt->xbutton.y;
|
||||||
|
if (evt->xbutton.button == Button1)
|
||||||
|
gui_input_button(&con->input, x, y, gui_true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
brelease(struct Console *con, XEvent *evt)
|
||||||
|
{
|
||||||
|
const float x = evt->xbutton.x;
|
||||||
|
const float y = evt->xbutton.y;
|
||||||
|
struct XWindow *xw = con->win;
|
||||||
|
if (evt->xbutton.button == Button1)
|
||||||
|
gui_input_button(&con->input, x, y, gui_false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bmotion(struct Console *con, XEvent *evt)
|
||||||
|
{
|
||||||
|
const float x = evt->xbutton.x;
|
||||||
|
const float y = evt->xbutton.y;
|
||||||
|
struct XWindow *xw = con->win;
|
||||||
|
gui_input_motion(&con->input, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
resize(struct Console *con, XEvent* evt)
|
||||||
|
{
|
||||||
|
struct XWindow *xw = con->win;
|
||||||
|
XGetWindowAttributes(xw->dpy, xw->win, &xw->gwa);
|
||||||
|
glViewport(0, 0, xw->gwa.width, xw->gwa.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
draw(int width, int height, const struct gui_draw_list *list)
|
||||||
|
{
|
||||||
|
const struct gui_draw_command *cmd;
|
||||||
|
persistent const size_t v = sizeof(struct gui_vertex);
|
||||||
|
persistent const size_t p = offsetof(struct gui_vertex, pos);
|
||||||
|
persistent const size_t t = offsetof(struct gui_vertex, uv);
|
||||||
|
persistent 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();
|
||||||
|
|
||||||
|
cmd = list->begin;
|
||||||
|
while (cmd) {
|
||||||
|
const int x = (int)cmd->clip_rect.x;
|
||||||
|
const int y = height - (int)(cmd->clip_rect.y + cmd->clip_rect.h);
|
||||||
|
const int w = (int)cmd->clip_rect.w;
|
||||||
|
const int h = (int)cmd->clip_rect.h;
|
||||||
|
gui_byte *buffer = (gui_byte*)cmd->vertexes;
|
||||||
|
glVertexPointer(2, GL_FLOAT, v, (void*)(buffer + p));
|
||||||
|
glTexCoordPointer(2, GL_FLOAT, v, (void*)(buffer + t));
|
||||||
|
glColorPointer(4, GL_UNSIGNED_BYTE, v, (void*)(buffer + c));
|
||||||
|
glBindTexture(GL_TEXTURE_2D, (unsigned long)cmd->texture);
|
||||||
|
glScissor(x, y, w, h);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, cmd->vertex_count);
|
||||||
|
cmd = gui_next(list, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
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[])
|
||||||
|
{
|
||||||
|
struct XWindow xw;
|
||||||
|
struct Console con;
|
||||||
|
long dt, started;
|
||||||
|
gui_byte *buffer;
|
||||||
|
gui_size buffer_size = MAX_VERTEX_BUFFER;
|
||||||
|
const struct gui_color colorA = {100, 100, 100, 255};
|
||||||
|
const struct gui_color colorB = {45, 45, 45, 255};
|
||||||
|
const struct gui_color colorC = {0, 0, 0, 255};
|
||||||
|
static GLint att[] = {GLX_RGBA, GLX_DEPTH_SIZE,24, GLX_DOUBLEBUFFER, None};
|
||||||
|
|
||||||
|
gui_float slider = 5.0f;
|
||||||
|
gui_float prog = 60.0f;
|
||||||
|
gui_float offset = 300;
|
||||||
|
|
||||||
|
/* x11 */
|
||||||
|
UNUSED(argc); UNUSED(argv);
|
||||||
|
memset(&xw, 0, sizeof xw);
|
||||||
|
memset(&con, 0, sizeof con);
|
||||||
|
xw.dpy = XOpenDisplay(NULL);
|
||||||
|
if (!xw.dpy)
|
||||||
|
die("XOpenDisplay failed\n");
|
||||||
|
xw.root = DefaultRootWindow(xw.dpy);
|
||||||
|
xw.vi = glXChooseVisual(xw.dpy, 0, att);
|
||||||
|
if (!xw.vi)
|
||||||
|
die("Failed to find appropriate visual\n");
|
||||||
|
xw.cmap = XCreateColormap(xw.dpy,xw.root,xw.vi->visual,AllocNone);
|
||||||
|
xw.swa.colormap = xw.cmap;
|
||||||
|
xw.swa.event_mask =
|
||||||
|
ExposureMask | KeyPressMask | ButtonPress |
|
||||||
|
ButtonReleaseMask | ButtonMotionMask |
|
||||||
|
Button1MotionMask | Button2MotionMask | Button3MotionMask;
|
||||||
|
xw.win = XCreateWindow(
|
||||||
|
xw.dpy, xw.root, 0, 0,WIN_WIDTH,WIN_HEIGHT, 0,
|
||||||
|
xw.vi->depth, InputOutput, xw.vi->visual,
|
||||||
|
CWColormap | CWEventMask, &xw.swa);
|
||||||
|
XGetWindowAttributes(xw.dpy, xw.win, &xw.gwa);
|
||||||
|
XStoreName(xw.dpy, xw.win, "Demo");
|
||||||
|
XMapWindow(xw.dpy, xw.win);
|
||||||
|
XFlush(xw.dpy);
|
||||||
|
XSync(xw.dpy, False);
|
||||||
|
con.win = &xw;
|
||||||
|
|
||||||
|
/* OpenGL */
|
||||||
|
xw.glc = glXCreateContext(xw.dpy, xw.vi, NULL, GL_TRUE);
|
||||||
|
glXMakeCurrent(xw.dpy, xw.win, xw.glc);
|
||||||
|
buffer = xcalloc(MAX_VERTEX_BUFFER, 1);
|
||||||
|
|
||||||
|
xw.running = 1;
|
||||||
|
while (xw.running) {
|
||||||
|
/* Input */
|
||||||
|
XEvent ev;
|
||||||
|
started = timestamp();
|
||||||
|
gui_input_begin(&con.input);
|
||||||
|
while (XCheckWindowEvent(xw.dpy, xw.win, xw.swa.event_mask, &ev)) {
|
||||||
|
if (ev.type == Expose || ev.type == ConfigureNotify) resize(&con, &ev);
|
||||||
|
else if (ev.type == MotionNotify) bmotion(&con, &ev);
|
||||||
|
else if (ev.type == ButtonPress) bpress(&con, &ev);
|
||||||
|
else if (ev.type == ButtonRelease) brelease(&con, &ev);
|
||||||
|
else if (ev.type == KeyPress) kpress(&con, &ev);
|
||||||
|
else if (ev.type == KeyRelease) kpress(&con, &ev);
|
||||||
|
}
|
||||||
|
gui_input_end(&con.input);
|
||||||
|
|
||||||
|
/* ------------------------- GUI --------------------------*/
|
||||||
|
gui_begin(&con.gui, buffer, MAX_VERTEX_BUFFER);
|
||||||
|
if (gui_button(&con.gui, &con.input, colorA, colorC, 50,50,150,30,5,"",0))
|
||||||
|
fprintf(stdout, "Button pressed!\n");
|
||||||
|
slider = gui_slider(&con.gui, &con.input, colorA, colorB, 50,100,150,30,2, 0.0f, slider, 10.0f, 1.0f);
|
||||||
|
prog = gui_progress(&con.gui, &con.input, colorA, colorB, 50,150,150,30,2, prog, 100.0f, gui_true);
|
||||||
|
offset = gui_scroll(&con.gui, &con.input, colorA, colorB, 250,50,16,332, offset, 600);
|
||||||
|
gui_end(&con.gui);
|
||||||
|
/* ---------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* Draw */
|
||||||
|
glClearColor(45.0f/255.0f,45.0f/255.0f,45.0f/255.0f,1);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
draw(xw.gwa.width, xw.gwa.height, &con.gui);
|
||||||
|
glXSwapBuffers(xw.dpy, xw.win);
|
||||||
|
|
||||||
|
/* Timing */
|
||||||
|
dt = timestamp() - started;
|
||||||
|
if (dt < DTIME) {
|
||||||
|
sleep_for(DTIME - dt);
|
||||||
|
dt = DTIME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cleanup */
|
||||||
|
glXMakeCurrent(xw.dpy, None, NULL);
|
||||||
|
glXDestroyContext(xw.dpy, xw.glc);
|
||||||
|
XDestroyWindow(xw.dpy, xw.win);
|
||||||
|
XCloseDisplay(xw.dpy);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue