lol
This commit is contained in:
commit
8f46b88f1d
0
renderer.c
Normal file
0
renderer.c
Normal file
217
ugui.c
Normal file
217
ugui.c
Normal file
@ -0,0 +1,217 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "ugui.h"
|
||||
|
||||
#define SALT 0xbabb0cac
|
||||
#define DEF_SCALE 1.0
|
||||
#define DEF_DPI 96.0
|
||||
#define E_STACK_STEP (1024 * 128)
|
||||
|
||||
#define TO_PPM(dpi, scale) (dpi * scale * 0.03937008)
|
||||
|
||||
// https://en.wikipedia.org/wiki/Jenkins_hash_function
|
||||
unsigned int hash(void *data, unsigned int size)
|
||||
{
|
||||
if (!size)
|
||||
return 0;
|
||||
unsigned int hash = SALT;
|
||||
unsigned char *v = (unsigned char *)data;
|
||||
|
||||
for (; size; size--) {
|
||||
hash += v[size-1];
|
||||
hash += hash << 10;
|
||||
hash ^= hash >> 6;
|
||||
}
|
||||
hash += hash << 3;
|
||||
hash ^= hash >> 11;
|
||||
hash += hash << 15;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
static void grow_stack(ug_ctx_t *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
err(EXIT_FAILURE, "__FUNCTION__:" "Cannot grow null context");
|
||||
ctx->e_size += E_STACK_STEP;
|
||||
ctx->e_stack = realloc(ctx->e_stack, ctx->e_size);
|
||||
if (!ctx->e_stack)
|
||||
err(errno, "__FUNCTION__:" "Could not grow stack: %s", strerror(errno));
|
||||
}
|
||||
|
||||
|
||||
// creates a new context, fills with default values, ctx is ready for ug_start()
|
||||
ug_ctx_t *ug_new_ctx(void)
|
||||
{
|
||||
ug_ctx_t *ctx = malloc(sizeof(ug_ctx_t));
|
||||
if (!ctx)
|
||||
err(errno, "__FUNCTION__:" "Could not allocate context: %s", strerror(errno));
|
||||
memset(ctx, 0, sizeof(ug_ctx_t));
|
||||
|
||||
ctx->scale = DEF_SCALE;
|
||||
ctx->dpi = DEF_DPI;
|
||||
ctx->ppm = TO_PPM(DEF_SCALE, DEF_DPI);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
void ug_free_ctx(ug_ctx_t *ctx)
|
||||
{
|
||||
if (!ctx) {
|
||||
warn("__FUNCTION__:" "Trying to free a null context");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx->e_stack) {
|
||||
warn("__FUNCTION__:" "Context has null element stack");
|
||||
return;
|
||||
}
|
||||
|
||||
free(ctx->e_stack);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
|
||||
// updates the context with user information
|
||||
int ug_update_ctx(ug_ctx_t *ctx,
|
||||
unsigned int window_id,
|
||||
float scale,
|
||||
float dpi,
|
||||
float ppm
|
||||
)
|
||||
{
|
||||
if (!ctx)
|
||||
return -1;
|
||||
ctx->window_id = window_id;
|
||||
|
||||
if (scale)
|
||||
ctx->scale = scale;
|
||||
if (dpi)
|
||||
ctx->dpi = dpi;
|
||||
if (!ppm)
|
||||
ctx->ppm = TO_PPM(ctx->dpi, ctx->scale);
|
||||
else
|
||||
ctx->ppm = ppm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*=============================================================================*
|
||||
* INPUT FUNCTIONS *
|
||||
*=============================================================================*/
|
||||
|
||||
#define TEST_CTX(ctx) { \
|
||||
if (!ctx) { \
|
||||
warn("__FUNCTION__:" "trying to use a null context"); \
|
||||
return; \
|
||||
} \
|
||||
}
|
||||
|
||||
void ug_input_mousemove(ug_ctx_t *ctx, int x, int y)
|
||||
{
|
||||
TEST_CTX(ctx);
|
||||
ctx->mouse.pos = (struct ug_vec2){ .x = x, .y = y };
|
||||
}
|
||||
|
||||
void ug_input_mousedown(ug_ctx_t *ctx, int x, int y, unsigned char btn)
|
||||
{
|
||||
TEST_CTX(ctx);
|
||||
ug_input_mousemove(ctx, x, y);
|
||||
ctx->mouse.down_mask |= btn;
|
||||
ctx->mouse.press_mask |= btn;
|
||||
}
|
||||
|
||||
|
||||
void ug_input_mouseup(ug_ctx_t *ctx, int x, int y, unsigned char btn)
|
||||
{
|
||||
TEST_CTX(ctx);
|
||||
ug_input_mousemove(ctx, x, y);
|
||||
ctx->mouse.down_mask &= ~btn;
|
||||
}
|
||||
|
||||
|
||||
void ug_input_scroll(ug_ctx_t *ctx, int x, int y)
|
||||
{
|
||||
TEST_CTX(ctx);
|
||||
ctx->mouse.scroll_delta.x += x;
|
||||
ctx->mouse.scroll_delta.y += y;
|
||||
}
|
||||
|
||||
|
||||
void ug_input_keydown(ug_ctx_t *ctx, int key)
|
||||
{
|
||||
TEST_CTX(ctx);
|
||||
ctx->key.down_mask |= key;
|
||||
ctx->key.press_mask |= key;
|
||||
}
|
||||
|
||||
|
||||
void ug_input_keyup(ug_ctx_t *ctx, int key)
|
||||
{
|
||||
TEST_CTX(ctx);
|
||||
ctx->key.down_mask &= ~key;
|
||||
}
|
||||
|
||||
|
||||
// append in input text
|
||||
void ug_input_text(ug_ctx_t *ctx, const char *text)
|
||||
{
|
||||
TEST_CTX(ctx);
|
||||
int size = strlen(ctx->input_text);
|
||||
int len = strlen(text);
|
||||
if ((unsigned long)(size+len) >= sizeof(ctx->input_text)) {
|
||||
warn("__FUNCTION__" "Input text exceeds context buffer");
|
||||
return;
|
||||
}
|
||||
memcpy(ctx->input_text + size, text, len);
|
||||
}
|
||||
|
||||
|
||||
/*=============================================================================*
|
||||
* BEGIN AND END *
|
||||
*=============================================================================*/
|
||||
|
||||
#undef TEST_CTX
|
||||
#define TEST_CTX(ctx) { \
|
||||
if (!ctx) { \
|
||||
warn("__FUNCTION__:" "trying to use a null context"); \
|
||||
return -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
int ug_begin(ug_ctx_t *ctx)
|
||||
{
|
||||
// it is the beginning of a new frame
|
||||
TEST_CTX(ctx);
|
||||
|
||||
// reset the command stack
|
||||
ctx->e_idx = 0;
|
||||
// next frame
|
||||
ctx->frame++;
|
||||
// update the mouse delta
|
||||
ctx->mouse.delta.x = ctx->mouse.pos.x - ctx->mouse.last_pos.x;
|
||||
ctx->mouse.delta.y = ctx->mouse.pos.y - ctx->mouse.last_pos.y;
|
||||
// TODO: other stuff
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ug_end(ug_ctx_t *ctx)
|
||||
{
|
||||
// end of a frame, check that all went well
|
||||
TEST_CTX(ctx);
|
||||
|
||||
// reset the inputs
|
||||
ctx->mouse.press_mask = 0;
|
||||
ctx->mouse.scroll_delta = (struct ug_vec2){0};
|
||||
ctx->mouse.last_pos = ctx->mouse.pos;
|
||||
ctx->key.press_mask = 0;
|
||||
ctx->input_text[0] = '\0';
|
||||
return 0;
|
||||
}
|
266
ugui.h
Normal file
266
ugui.h
Normal file
@ -0,0 +1,266 @@
|
||||
#ifndef _UGUI_H
|
||||
#define _UGUI_H
|
||||
|
||||
/* Point Coordinate */
|
||||
|
||||
// coordinate type, or how it is measured
|
||||
enum {
|
||||
UG_CTYPE_PX = 0x0,
|
||||
UG_CTYPE_MM = 0x1,
|
||||
UG_CTYPE_REL = 0x2,
|
||||
};
|
||||
|
||||
// coordinate anchor, or where it refers
|
||||
enum {
|
||||
UG_CANCHOR_TOP = 0x0, // x coordinates
|
||||
UG_CANCHOR_LEFT = 0x0,
|
||||
UG_CANCHOR_BOTTOM = 0x1, // y coordinates
|
||||
UG_CANCHOR_RIGHT = 0x1,
|
||||
UG_CANCHOR_VCENTER = 0x2, // for positions it should be centered
|
||||
UG_CANCHOR_HCENTER = 0x2,
|
||||
};
|
||||
|
||||
struct _ug_pt_flags {
|
||||
unsigned long int _:56;
|
||||
unsigned long int t:4;
|
||||
unsigned long int a:4;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
// first coordinate
|
||||
union {
|
||||
union {
|
||||
int x;
|
||||
struct _ug_pt_flags fx;
|
||||
};
|
||||
union {
|
||||
int w;
|
||||
struct _ug_pt_flags fw;
|
||||
};
|
||||
union {
|
||||
int m;
|
||||
struct _ug_pt_flags fm;
|
||||
};
|
||||
};
|
||||
// second coordinate
|
||||
union {
|
||||
union {
|
||||
int y;
|
||||
struct _ug_pt_flags fy;
|
||||
};
|
||||
union {
|
||||
int h;
|
||||
struct _ug_pt_flags fh;
|
||||
};
|
||||
union {
|
||||
int a;
|
||||
struct _ug_pt_flags fa;
|
||||
};
|
||||
};
|
||||
} ug_coord_t;
|
||||
|
||||
// TODO: define stroke style (f.s)
|
||||
typedef struct {
|
||||
int size;
|
||||
struct {
|
||||
// type of size
|
||||
unsigned char t:4;
|
||||
// stroke style
|
||||
unsigned char s:4;
|
||||
} f;
|
||||
} ug_stroke_t;
|
||||
//---//
|
||||
|
||||
/* RGBA Color type */
|
||||
typedef struct {
|
||||
unsigned char a;
|
||||
unsigned char b;
|
||||
unsigned char g;
|
||||
unsigned char r;
|
||||
} ug_color_t;
|
||||
//---//
|
||||
|
||||
/* simple position structure */
|
||||
struct ug_vec2 {
|
||||
int x, y;
|
||||
};
|
||||
//---//
|
||||
|
||||
/* Mouse button mask */
|
||||
enum ug_mouse_btn {
|
||||
UG_MOUSEBTN_LEFT = 1,
|
||||
UG_MOUSEBTN_MIDDLE = 2,
|
||||
UG_MOUSEBTN_RIGHT = 4,
|
||||
UG_MOUSEBTN_4 = 8,
|
||||
UG_MOUSEBTN_5 = 16,
|
||||
};
|
||||
//---//
|
||||
|
||||
/* event structure */
|
||||
typedef enum {
|
||||
UG_EV_WINDOWMOVE,
|
||||
UG_EV_WINDOWRESIZE,
|
||||
UG_EV_WINDOWSHOW,
|
||||
UG_EV_MOUSEMOVE,
|
||||
UG_EV_MOUSEDOWN,
|
||||
UG_EV_MOUSEUP,
|
||||
UG_EV_KEYDOWN,
|
||||
UG_EV_KEYUP,
|
||||
} ug_event_type_t;
|
||||
|
||||
typedef struct {
|
||||
ug_event_type_t type;
|
||||
union {
|
||||
int x;
|
||||
int w;
|
||||
unsigned int code;
|
||||
};
|
||||
union {
|
||||
int y;
|
||||
int h;
|
||||
unsigned int mask;
|
||||
};
|
||||
} ug_event_t;
|
||||
//---//
|
||||
|
||||
/* Primitive element type */
|
||||
typedef enum {
|
||||
UG_E_RECT = 0,
|
||||
UG_E_TRIANGLE,
|
||||
UG_E_DOT,
|
||||
UG_E_LINE,
|
||||
UG_E_ARC,
|
||||
UG_E_TEXT,
|
||||
UG_E_SPRITE,
|
||||
} ug_element_type_t;
|
||||
|
||||
typedef struct {
|
||||
ug_coord_t size;
|
||||
ug_coord_t pos;
|
||||
ug_color_t color;
|
||||
} ug_rect_t;
|
||||
|
||||
typedef struct {
|
||||
ug_coord_t size;
|
||||
ug_coord_t pos;
|
||||
ug_color_t color;
|
||||
} ug_triangle_t;
|
||||
|
||||
typedef struct {
|
||||
ug_stroke_t stroke;
|
||||
ug_coord_t pos;
|
||||
ug_color_t color;
|
||||
} ug_dot_t;
|
||||
|
||||
typedef struct {
|
||||
ug_stroke_t stroke;
|
||||
ug_coord_t vert[2];
|
||||
ug_color_t color;
|
||||
} ug_line_t;
|
||||
|
||||
typedef struct {
|
||||
ug_stroke_t stroke;
|
||||
ug_coord_t vert[3];
|
||||
ug_color_t color;
|
||||
} ug_arc_t;
|
||||
|
||||
// draw text from view[start] to view[end]
|
||||
typedef struct {
|
||||
ug_stroke_t stroke;
|
||||
ug_coord_t pos;
|
||||
ug_color_t color;
|
||||
const char *view;
|
||||
int start;
|
||||
int end;
|
||||
} ug_text_t;
|
||||
|
||||
// all sprites have to be mapped into memory, map is an array of width x height
|
||||
// bytes, the type is specified by the user
|
||||
typedef struct {
|
||||
ug_coord_t pos;
|
||||
void *map;
|
||||
int width;
|
||||
int height;
|
||||
} ug_sprite_t;
|
||||
|
||||
|
||||
// data is the actual element data, it has to be cast to the right element specified
|
||||
// by type and is variable size so that no memory is wasted, size is the size in
|
||||
// bytes of data + id + size + type
|
||||
typedef struct {
|
||||
ug_element_type_t type;
|
||||
unsigned int size;
|
||||
unsigned int id;
|
||||
unsigned char data[];
|
||||
} ug_element_t;
|
||||
//---//
|
||||
|
||||
/* Global context */
|
||||
// one context per phisical window
|
||||
// a phisical window can be anything, but here it basically represents the true
|
||||
// surface where things are drawn into, a window has a scale, dpi and ppm
|
||||
// (pixel per mm), only the latter is truly needed, the user sets these variables
|
||||
// and has to take care of updating them when needed
|
||||
typedef struct {
|
||||
unsigned int window_id;
|
||||
float scale, dpi, ppm;
|
||||
// the user pushes the things that he wants to draw onto the element stack,
|
||||
// which contains all the primitives needed to draw the wanted element
|
||||
unsigned char *e_stack;
|
||||
unsigned int e_size;
|
||||
unsigned int e_idx;
|
||||
// the element which has focus
|
||||
unsigned int focus_id;
|
||||
// the element that we are hovering
|
||||
unsigned int hover_id;
|
||||
// count the frames for fun
|
||||
unsigned long int frame;
|
||||
// mouse data
|
||||
struct {
|
||||
struct ug_vec2 pos;
|
||||
struct ug_vec2 last_pos;
|
||||
struct ug_vec2 delta;
|
||||
struct ug_vec2 scroll_delta;
|
||||
// down/pressed masks get updated on mousedown, whereas down_mask
|
||||
// only on mouseup, so the masks differ by the buttons that were
|
||||
// released
|
||||
// FIXME: is this the best way to approach this?
|
||||
unsigned char down_mask;
|
||||
unsigned char press_mask;
|
||||
} mouse;
|
||||
// keyboard key pressed
|
||||
struct {
|
||||
unsigned char down_mask;
|
||||
unsigned char press_mask;
|
||||
} key;
|
||||
// input text buffer
|
||||
char input_text[32];
|
||||
} ug_ctx_t;
|
||||
//---//
|
||||
|
||||
// creates a new context, fills with default values, ctx is ready for ug_start()
|
||||
ug_ctx_t *ug_new_ctx(void);
|
||||
void ug_free_ctx(ug_ctx_t *ctx);
|
||||
// updates the context with user information
|
||||
int ug_update_ctx(ug_ctx_t *ctx,
|
||||
unsigned int window_id,
|
||||
float scale,
|
||||
float dpi,
|
||||
float ppm
|
||||
);
|
||||
|
||||
// register inputs
|
||||
void ug_input_mousedown(ug_ctx_t *ctx, int x, int y, unsigned char btn);
|
||||
void ug_input_mouseup(ug_ctx_t *ctx, int x, int y, unsigned char btn);
|
||||
void ug_input_mousemove(ug_ctx_t *ctx, int x, int y);
|
||||
void ug_input_scroll(ug_ctx_t *ctx, int x, int y);
|
||||
void ug_input_keydown(ug_ctx_t *ctx, int key);
|
||||
void ug_input_keyup(ug_ctx_t *ctx, int key);
|
||||
void ug_input_text(ug_ctx_t *ctx, const char *text);
|
||||
|
||||
// between begin and end the user draws
|
||||
int ug_begin(ug_ctx_t *ctx);
|
||||
int ug_end(ug_ctx_t *ctx);
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user