diff --git a/src/data/fonts/scape.bmp b/src/data/fonts/scape.bmp new file mode 100644 index 0000000..6f212fb Binary files /dev/null and b/src/data/fonts/scape.bmp differ diff --git a/src/data/fonts/scape.dat b/src/data/fonts/scape.dat new file mode 100644 index 0000000..1fa6e60 Binary files /dev/null and b/src/data/fonts/scape.dat differ diff --git a/src/data/map-colors.bmp b/src/data/map-colors.bmp deleted file mode 100644 index ce9a07c..0000000 Binary files a/src/data/map-colors.bmp and /dev/null differ diff --git a/src/data/map-heights.bmp b/src/data/map-heights.bmp deleted file mode 100644 index 5347b81..0000000 Binary files a/src/data/map-heights.bmp and /dev/null differ diff --git a/src/data/map-reserve.bmp b/src/data/map-reserve.bmp deleted file mode 100644 index 5da9d6a..0000000 Binary files a/src/data/map-reserve.bmp and /dev/null differ diff --git a/src/data/cube.obj b/src/data/models/cube.obj similarity index 100% rename from src/data/cube.obj rename to src/data/models/cube.obj diff --git a/src/data/cube.rbm b/src/data/models/cube.rbm similarity index 100% rename from src/data/cube.rbm rename to src/data/models/cube.rbm diff --git a/src/data/cube2.obj b/src/data/models/cube2.obj similarity index 100% rename from src/data/cube2.obj rename to src/data/models/cube2.obj diff --git a/src/data/cube2.rbm b/src/data/models/cube2.rbm similarity index 100% rename from src/data/cube2.rbm rename to src/data/models/cube2.rbm diff --git a/src/data/monkey.obj b/src/data/models/monkey.obj similarity index 100% rename from src/data/monkey.obj rename to src/data/models/monkey.obj diff --git a/src/data/monkey.rbm b/src/data/models/monkey.rbm similarity index 100% rename from src/data/monkey.rbm rename to src/data/models/monkey.rbm diff --git a/src/data/player.obj b/src/data/models/player.obj similarity index 100% rename from src/data/player.obj rename to src/data/models/player.obj diff --git a/src/data/player.rbm b/src/data/models/player.rbm similarity index 100% rename from src/data/player.rbm rename to src/data/models/player.rbm diff --git a/src/data/rbm.sh b/src/data/models/rbm.sh similarity index 100% rename from src/data/rbm.sh rename to src/data/models/rbm.sh diff --git a/src/shaders/test.frag b/src/data/shaders/test.frag similarity index 95% rename from src/shaders/test.frag rename to src/data/shaders/test.frag index 1033257..db2f29b 100644 --- a/src/shaders/test.frag +++ b/src/data/shaders/test.frag @@ -15,7 +15,7 @@ void main() { float diff = max(0.0, dot(norm, light_dir)); vec3 diffuse = diff * light_color; - vec3 color = (ambient + diffuse) * f_color; + vec3 color = (ambient + diffuse) * vec3(f_color); gl_FragColor = vec4(color, 1.0); //gl_FragColor = vec4(f_normal, 1.0); } diff --git a/src/shaders/test.vert b/src/data/shaders/test.vert similarity index 100% rename from src/shaders/test.vert rename to src/data/shaders/test.vert diff --git a/src/data/terrains/map-colors.bmp b/src/data/terrains/map-colors.bmp new file mode 100644 index 0000000..46ba94a Binary files /dev/null and b/src/data/terrains/map-colors.bmp differ diff --git a/src/data/terrains/map-heights.bmp b/src/data/terrains/map-heights.bmp new file mode 100644 index 0000000..31cd83e Binary files /dev/null and b/src/data/terrains/map-heights.bmp differ diff --git a/src/data/terrains/map-reserve.bmp b/src/data/terrains/map-reserve.bmp new file mode 100644 index 0000000..dc612ee Binary files /dev/null and b/src/data/terrains/map-reserve.bmp differ diff --git a/src/data/map.xcf b/src/data/terrains/map.xcf similarity index 90% rename from src/data/map.xcf rename to src/data/terrains/map.xcf index 182d438..b872272 100644 Binary files a/src/data/map.xcf and b/src/data/terrains/map.xcf differ diff --git a/src/koa/etc.c b/src/koa/etc.c index 94b0520..396b724 100644 --- a/src/koa/etc.c +++ b/src/koa/etc.c @@ -1,15 +1,11 @@ #include "etc.h" -int color_eq(color_t a, color_t b) { - return color_eqp(&a, &b); +int color_eq(const color_t a, const color_t b) { + return color_eqp(a, b); } -int color_eqp(const color_t* a, const color_t* b) { - return - (a->r == b->r) && - (a->g == b->g) && - (a->b == b->b) && - (a->a == b->a); +int color_eqp(const color_t a, const color_t b) { + return memcmp(a, b, 4) == 0; } void mfree(int n, ...) { diff --git a/src/koa/etc.h b/src/koa/etc.h index 38c3954..37d58c5 100644 --- a/src/koa/etc.h +++ b/src/koa/etc.h @@ -9,12 +9,15 @@ #define __MIN(A, B) ((A) < (B) ? (A) : (B)) #define __MAX(A, B) ((A) > (B) ? (A) : (B)) -typedef struct { - uint8_t r, g, b, a; -} color_t; +#define _R_ 0 +#define _G_ 1 +#define _B_ 2 +#define _A_ 3 -int color_eq(color_t, color_t); -int color_eqp(const color_t*, const color_t*); +typedef uint8_t color_t[4]; + +int color_eq(const color_t, const color_t); +int color_eqp(const color_t, const color_t); void mfree(int n, ...); uint8_t* ltoh(uint8_t*, int); diff --git a/src/koa/file.c b/src/koa/file.c index ea59daa..71c5e5b 100644 --- a/src/koa/file.c +++ b/src/koa/file.c @@ -158,21 +158,21 @@ int bmp_reload_chunk(bmp_t* bmp, int x, int y, int width, int height) { uint8_t buffer[4]; for(int ay = 0; ay < height; ++ay) { - fseek(fp, - data->header_size - + (data->width * (data->height - (y + ay) - 1) * data->bytepp) - + x * data->bytepp, - SEEK_SET + fseek( + fp, + data->header_size + + (data->width * (data->height - (y + ay) - 1) * data->bytepp) + + x * data->bytepp, + SEEK_SET ); for(int ax = 0; ax < width; ++ax) { fread(buffer, 1, data->bytepp, fp); - color_t* px = &bmp->pixels[ay][ax]; - px->b = buffer[0]; - px->g = buffer[1]; - px->r = buffer[2]; - px->a = 0xFF; + bmp->pixels[ay][ax][_B_] = buffer[0]; + bmp->pixels[ay][ax][_G_] = buffer[1]; + bmp->pixels[ay][ax][_R_] = buffer[2]; + bmp->pixels[ay][ax][_A_] = 0xFF; } } @@ -180,6 +180,42 @@ int bmp_reload_chunk(bmp_t* bmp, int x, int y, int width, int height) { return 1; } +int _bmp_comp_cnt(int col) { + int cnt = 0; + for(int i = 0; i < KOA_COMPONENTS; ++i) + cnt += (col >> i) & 0x1; + + return cnt; +} + +uint8_t* bmp_gl_data(bmp_t* bmp, int col) { + float* out = malloc(bmp_gl_data_size(bmp, col)); + bmp_gl_data_out(bmp, out, col); + return out; +} + +void bmp_gl_data_out(bmp_t* bmp, uint8_t* out, int col) { + const int comps = _bmp_comp_cnt(col); + for(uint32_t y = 0; y < bmp->height; ++y) { + for(uint32_t x = 0; x < bmp->width; ++x) { + int at = 0; + for(int i = 0; i < KOA_COMPONENTS; ++i) { + if(!((col >> i) & 0x1)) + continue; + + out[y * bmp->width * comps + x * comps + at] = + bmp->pixels[y][x][i]; + ++at; + } + } + } +} + +uint32_t bmp_gl_data_size(bmp_t* bmp, int col) { + return sizeof(uint8_t) * _bmp_comp_cnt(col) + * bmp->width * bmp->height; +} + void bmp_discard_pixels(bmp_t* bmp) { if(bmp->pixels == NULL) return; diff --git a/src/koa/file.h b/src/koa/file.h index f09b025..f34311a 100644 --- a/src/koa/file.h +++ b/src/koa/file.h @@ -20,6 +20,14 @@ char* file_read(const char*); // BEGIN BMP LOADING FUNCTIONS +#define KOA_COMPONENTS 4 +#define KOA_R 1 +#define KOA_G 2 +#define KOA_B 4 +#define KOA_A 8 +#define KOA_RGB 7 +#define KOA_RGBA F + typedef struct { char file[4096]; uint32_t width, height, size, @@ -35,9 +43,15 @@ typedef struct { } bmp_t; bmp_t* bmp_load(const char*); + bmp_t* bmp_load_chunk(const char*, int, int, int, int); int bmp_reload_chunk(bmp_t*, int, int, int, int); int bmp_load_metadata(const char*, bmp_meta_t*); + +uint8_t* bmp_gl_data(bmp_t*, int); +void bmp_gl_data_out(bmp_t*, uint8_t*, int); +uint32_t bmp_gl_data_size(bmp_t*, int); + void bmp_discard_pixels(bmp_t*); void bmp_unload(bmp_t*); diff --git a/src/main.c b/src/main.c index 3afde3b..bcd6669 100644 --- a/src/main.c +++ b/src/main.c @@ -11,6 +11,7 @@ #include "okuu/mesh.h" #include "okuu/shader.h" #include "okuu/terrain.h" +#include "okuu/font.h" #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 @@ -20,7 +21,11 @@ struct { SDL_GLContext ctx; const uint8_t* keys; int mode, running; + int mouse[3]; + vec2 tlocs[10]; + font_t* scape; + text_t* text; mesh_t* monkey; terrain_t* map; } _g; @@ -39,15 +44,37 @@ int init(); void deinit(); void run(); +void reset_text_locs() { + for(int i = 0; i < 10; ++i) { + _g.tlocs[i][0] = rand() % (WINDOW_WIDTH / 2); + _g.tlocs[i][1] = rand() % WINDOW_HEIGHT; + } +} + int main(int argc, char* argv[]) { if(init() < 0) return -1; - _g.monkey = mesh_load("data/player.rbm"); + font_init_subsystem(_g.window); + + _g.scape = font_load( + "data/fonts/scape.bmp", + "data/fonts/scape.dat", + GL_NEAREST + ); + font_set_default(_g.scape); + + _g.text = text_create(NULL); + text_set(_g.text, "flashwave is cool !!!"); + text_set_size(_g.text, 32); + text_set_rgb_hex(_g.text, 0x55007e); + reset_text_locs(); + + _g.monkey = mesh_load("data/models/player.rbm"); _g.map = terrain_load( - "data/map-heights.bmp", - "data/map-colors.bmp", + "data/terrains/map-heights.bmp", + "data/terrains/map-colors.bmp", 10, 10 ); @@ -55,9 +82,9 @@ int main(int argc, char* argv[]) { shader_layout(_s_def.shader, 4, "vertex", "texuv", "normal", "color" ); - shader_source(_s_def.shader, 2, - "shaders/test.vert", GL_VERTEX_SHADER, - "shaders/test.frag", GL_FRAGMENT_SHADER + shader_source(_s_def.shader, SHADER_FILE, 2, + "data/shaders/test.vert", GL_VERTEX_SHADER, + "data/shaders/test.frag", GL_FRAGMENT_SHADER ); shader_attribs(_s_def.shader, 3, "model", "view", "projection" @@ -81,6 +108,7 @@ void run() { if(init) { //glm_rotate_make(model, glm_rad(90), (vec3){ 0.f, -1.f, 0.f }); glm_mat4_identity(model); + glm_mat4_identity(map); glm_mat4_identity(view); @@ -117,12 +145,14 @@ void run() { view ); + for(int i = 0; i < 10; ++i) { + text_move(_g.text, _g.tlocs[i]); + text_render(_g.text); + } + shader_start(_s_def.shader); { glUniformMatrix4fv(_ATTR(DEF_VIEW), 1, GL_FALSE, (float*)view); - /*mesh_bind(_g.monkey); - mesh_render(_g.monkey); - mesh_unbind();*/ glm_translate_make(model, (vec3){-x, -(_g.map->heights[(int)y][(int)x] + 2.f), -y}); glm_mat4_mul(model, map, model); glUniformMatrix4fv(_ATTR(DEF_MODEL), 1, GL_FALSE, (float*)model); @@ -173,10 +203,41 @@ void run() { glm_translate_make(map, (vec3){__MAX(0, x - CHUNK_SIZE / 2), 0, __MAX(0, y - CHUNK_SIZE / 2)}); } + if(_g.keys[SDL_SCANCODE_P]) + reset_text_locs(); + + _g.mouse[2] = SDL_GetMouseState(&_g.mouse[0], &_g.mouse[1]); + if(_g.mouse[2] & SDL_BUTTON(SDL_BUTTON_LEFT)) { + + } + SDL_Event ev; while(SDL_PollEvent(&ev)) { if(ev.type == SDL_QUIT) _g.running = 0; + else if(ev.type == SDL_WINDOWEVENT && + ev.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) + { + glViewport(0, 0, ev.window.data1, ev.window.data2); + font_window_changed(_g.window); + } + /*else if(ev.type == SDL_MOUSEBUTTONDOWN) { + float mx = (float)ev.button.x / (float)WINDOW_WIDTH; + float my = (float)ev.button.y / (float)WINDOW_HEIGHT; + vec4 mouse = {mx * 2 - 1, (1 - my) * 2 - 1, -1.f, 1.f}; + mat4 imat; + + glm_mat4_inv(projection, imat); + glm_mat4_mulv(imat, mouse, mouse); + mouse[2] = -1.f; + mouse[3] = 0.f; + + glm_mat4_inv(view, imat); + glm_mat4_mulv(imat, mouse, mouse); + + + + }*/ } } diff --git a/src/okuu/font.c b/src/okuu/font.c new file mode 100644 index 0000000..d0fdcec --- /dev/null +++ b/src/okuu/font.c @@ -0,0 +1,419 @@ +#include "font.h" + +// SUBSYSTEM // + +const char* _vertex_shader = + "#version 100 \r\n" + + "attribute vec2 coords;" + "attribute vec2 texuv;" + + "varying vec2 f_texuv;" + + "uniform mat4 trans;" + "uniform mat4 ortho;" + + "void main() {" + "gl_Position = ortho * trans * vec4(coords, 0.0, 1.0);" + "f_texuv = texuv;" + "}\r\n"; +const char* _fragment_shader = + "#version 100 \n" + "precision mediump float;\n" + + "varying vec2 f_texuv;\n" + + "uniform vec4 color;\n" + "uniform sampler2D font;\n" + + "void main() {\n" + "vec4 fcol = texture2D(font, f_texuv);\n" + "if(fcol.rgb == vec3(0.0)) discard;\n" + "gl_FragColor = color * fcol;\n" + "}\n"; + +struct { + shader_t* shader; + font_t* default_font; + + enum { + FONT_TRANS, + FONT_ORTHO, + FONT_COLOR, + FONT_FONT + }; +} _ss; + +void _font_window_change(SDL_Window* window) { + shader_start(_ss.shader); + + mat4 ortho; + int width, height; + SDL_GetWindowSize(window, &width, &height); + + glm_ortho(0.f, (float)width, (float)height, 0.f, -1.f, 1.f, ortho); + glUniformMatrix4fv( + _ATTR(FONT_ORTHO), 1, GL_FALSE, (float*)ortho + ); +} + +void font_init_subsystem(SDL_Window* window) { + _ss.shader = shader_create("font"); + shader_layout(_ss.shader, 2, + "coords", "texuv" + ); + shader_source(_ss.shader, SHADER_SRC, 2, + _vertex_shader, GL_VERTEX_SHADER, + _fragment_shader, GL_FRAGMENT_SHADER + ); + shader_attribs(_ss.shader, 4, + "trans", "ortho", "color", "font" + ); + + _font_window_change(window); +} + +void font_window_changed(SDL_Window* window) { + _font_window_change(window); +} + +void font_set_default(font_t* font) { + _ss.default_font = font; +} + +void font_deinit_subsystem() { + shader_destroy(_ss.shader); +} + +// FONT FUNCTIONS // + +font_t* font_load(const char* bmp_path, const char* data_path, int filter) { + const int buffer_size = 0x111; + int buffer_read = 0; + uint8_t buffer[buffer_size]; + + FILE* fp = fopen(data_path, "rb"); + if(fp == NULL) + return NULL; + buffer_read = fread(buffer, 1, buffer_size, fp); + fclose(fp); + if(buffer_read != buffer_size) + return NULL; + if(buffer[0x10] != 0) + return NULL; + + bmp_t* bmp = bmp_load(bmp_path); + if(bmp == NULL) + return NULL; + + font_t* font = malloc(sizeof(font_t)); + + font->width = bmp->width; + font->height = bmp->height; + font->cell_width = *(uint32_t*)ltoh(buffer + 0x08, 4); + font->cell_height = *(uint32_t*)ltoh(buffer + 0x0C, 4); + + for(int i = 0; i < 256; ++i) { + glyph_t* glyph = font->glyphs + i; + uint32_t width = buffer[0x11 + i]; + + glyph->width = (float)width / (float)font->cell_width; + int x = (font->cell_width * i) % font->width; + int y = ((font->cell_width * i) / font->width) * font->cell_height; + + glyph->top_left[0] = (float)x / (float)font->width; + glyph->top_left[1] = (float)y / (float)font->height; + + glyph->bottom_right[0] = (float)(x + width) / (float)font->width; + glyph->bottom_right[1] = + (float)(y + font->cell_height) / (float)font->height; + } + + uint8_t* pixels = bmp_gl_data(bmp, KOA_RGB); + + glGenTextures(1, &font->texture); + glBindTexture(GL_TEXTURE_2D, font->texture); + glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGB, + font->width, font->height, 0, + GL_RGB, GL_UNSIGNED_BYTE, + pixels + ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + + bmp_unload(bmp); + free(pixels); + + return font; +} + +void font_bind(font_t* font) { + glBindTexture(GL_TEXTURE_2D, font->texture); +} + +void font_unbind() { + glBindTexture(GL_TEXTURE_2D, 0); +} + +void font_unload(font_t* font) { + glDeleteTextures(1, font->texture); + free(font); +} + +// TEXT FUNCTIONS // + +text_t* text_create(font_t* font) { + text_t* text = malloc(sizeof(text_t)); + + if(font == NULL) + text->font = _ss.default_font; + text->text = NULL; + glm_vec4_copy((vec4){0.f, 0.f, 0.f, 1.f}, text->color); + + text->length = + text->size = + text->wrap = + text->tri_cnt = 0; + + text->vert_inv = + text->texuv_inv = 1; + + glm_mat4_identity(text->trans_mat); + glGenVertexArrays(1, &text->vao); + glGenBuffers(2, text->buffers); + + glBindVertexArray(text->vao); { + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, text->buffers[0]); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); + + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, text->buffers[1]); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0); + } glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + return text; +} + +void text_set(text_t* text, const char* value) { + uint32_t value_len = strlen(value); + if(text->text == NULL || strcmp(value, text->text) != 0) { + text->texuv_inv = 1; + text->vert_inv = 1; + } + + free(text->text); + text->length = value_len; + text->text = strdup(value); +} + +void text_set_font(text_t* text, font_t* font) { + text->font = font; + + text->texuv_inv = 1; + text->vert_inv = 1; +} + +void text_set_size(text_t* text, uint32_t size) { + text->size = size; + text->vert_inv = 1; +} + +void text_set_rgb + (text_t* text, uint8_t r, uint8_t g, uint8_t b) +{ + text_set_rgba(text, r, g, b, 0xFF); +} + +void text_set_rgba + (text_t* text, uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + glm_vec4_copy( + (vec4){ + (float)r / 255.f, + (float)g / 255.f, + (float)b / 255.f, + (float)a / 255.f + }, + text->color + ); +} + +void text_set_rgb_gl(text_t* text, vec3 color) { + vec4 color4; + glm_vec4(color, 1.f, color4); + text_set_rgba_gl(text, color4); +} + +void text_set_rgba_gl(text_t* text, vec4 color) { + glm_vec4_copy(color, text->color); +} + +void text_set_rgb_hex(text_t* text, uint32_t color) { + color &= 0x00FFFFFF; + color <<= 8; + color |= 0xFF; + + text_set_rgba_hex(text, color); +} + +void text_set_rgba_hex(text_t* text, uint32_t color) { + text_set_rgba(text, + (color >> 24) & 0xFF, + (color >> 16) & 0xFF, + (color >> 8) & 0xFF, + color & 0xFF + ); +} + +void text_move(text_t* text, vec2 coords) { + vec3 coords3 = { coords[0], coords[1], 0.f }; + glm_translate_make(text->trans_mat, coords3); +} + +void text_move_xy(text_t* text, float x, float y) { + vec2 coords = { x, y }; + text_move(text, coords); +} + +void text_wrap(text_t* text, uint32_t wrap) { + text->wrap = wrap; + text->vert_inv = 1; +} + +void text_redraw(text_t* text) { + if(!text->vert_inv && !text->texuv_inv) + return; + + text->tri_cnt = 2 * text->length; + + float* verts = NULL; + float* texuvs = NULL; + + if(text->vert_inv) + verts = malloc(sizeof(float) * 6 * text->tri_cnt); + if(text->texuv_inv) + texuvs = malloc(sizeof(float) * 6 * text->tri_cnt); + + uint32_t top_x = 0, top_y = 0; + for(uint32_t i = 0; i < text->length; ++i) { + glyph_t* glyph = text->font->glyphs + text->text[i]; + uint32_t width = (uint32_t)(text->size * glyph->width), + height = text->size; + + if(top_x + width > text->wrap && text->wrap != 0) { + top_x = 0; + top_y += height; + } + + // !! TRIANGLES WOUND CCW FOR CULLING !! // + + if(verts != NULL) { + // TRIANGLE 1 // + // TOP LEFT + verts[i * 12] = top_x; + verts[i * 12 + 1] = top_y; + // BOTTOM LEFT + verts[i * 12 + 2] = top_x; + verts[i * 12 + 3] = top_y + height; + // TOP RIGHT + verts[i * 12 + 4] = top_x + width; + verts[i * 12 + 5] = top_y; + + // TRIANGLE 2 // + // BOTTOM RIGHT + verts[i * 12 + 6] = top_x + width; + verts[i * 12 + 7] = top_y + height; + // TOP RIGHT + verts[i * 12 + 8] = top_x + width; + verts[i * 12 + 9] = top_y; + // BOTTOM LEFT + verts[i * 12 + 10] = top_x; + verts[i * 12 + 11] = top_y + height; + } + + if(texuvs != NULL) { + // TRIANGLE 1 // + // TOP LEFT + texuvs[i * 12] = glyph->top_left[0]; + texuvs[i * 12 + 1] = glyph->top_left[1]; + // BOTTOM LEFT + texuvs[i * 12 + 2] = glyph->top_left[0]; + texuvs[i * 12 + 3] = glyph->bottom_right[1]; + // TOP RIGHT + texuvs[i * 12 + 4] = glyph->bottom_right[0]; + texuvs[i * 12 + 5] = glyph->top_left[1]; + + // TRIANGLE 2 // + // BOTTOM RIGHT + texuvs[i * 12 + 6] = glyph->bottom_right[0]; + texuvs[i * 12 + 7] = glyph->bottom_right[1]; + // TOP RIGHT + texuvs[i * 12 + 8] = glyph->bottom_right[0]; + texuvs[i * 12 + 9] = glyph->top_left[1]; + // BOTTOM LEFT + texuvs[i * 12 + 10] = glyph->top_left[0]; + texuvs[i * 12 + 11] = glyph->bottom_right[1]; + } + + top_x += width; + } + + if(verts != NULL) { + glBindBuffer(GL_ARRAY_BUFFER, text->buffers[0]); + glBufferData( + GL_ARRAY_BUFFER, + text->tri_cnt * 6 * sizeof(float), + verts, + GL_DYNAMIC_DRAW + ); + } + + if(texuvs != NULL) { + glBindBuffer(GL_ARRAY_BUFFER, text->buffers[1]); + glBufferData( + GL_ARRAY_BUFFER, + text->tri_cnt * 6 * sizeof(float), + texuvs, + GL_DYNAMIC_DRAW + ); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + free(verts); + free(texuvs); + + text->vert_inv = 0; + text->texuv_inv = 0; +} + +void text_render(text_t* text) { + text_redraw(text); + shader_start(_ss.shader); + + glUniformMatrix4fv( + _ATTR(FONT_TRANS), + 1, GL_FALSE, + (float*)text->trans_mat + ); + glUniform4fv( + _ATTR(FONT_COLOR), 1, + (float*)text->color + ); + glActiveTexture(GL_TEXTURE0); + + font_bind(text->font); + glBindVertexArray(text->vao); + glDrawArrays(GL_TRIANGLES, 0, text->tri_cnt * 3); +} + +void text_destroy(text_t* text) { + glDeleteBuffers(2, text->buffers); + glDeleteVertexArrays(1, &text->vao); + + free(text->text); + free(text); +} \ No newline at end of file diff --git a/src/okuu/font.h b/src/okuu/font.h new file mode 100644 index 0000000..9366f14 --- /dev/null +++ b/src/okuu/font.h @@ -0,0 +1,78 @@ +#ifndef OKUU_FONT_H +#define OKUU_FONT_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "shader.h" +#include "koa/etc.h" + +typedef struct { + float width; + vec2 top_left, + bottom_right; +} glyph_t; + +typedef struct { + GLuint texture; + uint32_t width, height, + cell_width, cell_height; + glyph_t glyphs[256]; +} font_t; + +typedef struct { + font_t* font; + char* text; + vec4 color; + uint32_t + length, size, + wrap, tri_cnt; + + mat4 trans_mat; + GLuint vao, buffers[2]; + uint8_t vert_inv, texuv_inv; +} text_t; + +void font_init_subsystem(SDL_Window*); +void font_window_changed(SDL_Window*); +void font_set_default(font_t*); +void font_deinit_subsystem(); + +font_t* font_load(const char*, const char*, int); +void font_bind(font_t*); +void font_unbind(); +void font_unload(font_t*); + +text_t* text_create(font_t*); +void text_set(text_t*, const char*); +void text_set_font(text_t*, font_t*); +void text_set_size(text_t*, uint32_t); + +void text_set_rgb(text_t*, uint8_t, uint8_t, uint8_t); +void text_set_rgba(text_t*, uint8_t, uint8_t, uint8_t, uint8_t); +void text_set_rgb_gl(text_t*, vec3); +void text_set_rgba_gl(text_t*, vec4); +void text_set_rgb_hex(text_t*, uint32_t); +void text_set_rgba_hex(text_t*, uint32_t); + +void text_move(text_t*, vec2); +void text_move_xy(text_t*, float, float); +void text_wrap(text_t*, uint32_t); + +void text_redraw(text_t*); +void text_render(text_t*); + +/*void text_get_bounds(text_t*, vec2); +uint32_t text_line_count(text_t*);*/ + +void text_destroy(text_t*); + +#endif diff --git a/src/okuu/shader.c b/src/okuu/shader.c index a5d1969..0ec0af2 100644 --- a/src/okuu/shader.c +++ b/src/okuu/shader.c @@ -31,7 +31,7 @@ int shader_layout(shader_t* shader, int count, ...) { return 0; } -int shader_source(shader_t* shader, int files, ...) { +int shader_source(shader_t* shader, int is_src, int files, ...) { if(shader->loaded) return -1; @@ -42,16 +42,23 @@ int shader_source(shader_t* shader, int files, ...) { va_list args; va_start(args, files); for(int i = 0; i < files; ++i) { - const char* file_name = va_arg(args, const char*); - char* source = file_read(file_name); - if(source == NULL) { - failed = 1; - break; - } + char* file_name = "INLINE"; + char* source = NULL; + + if(!is_src) { + file_name = va_arg(args, char*); + source = file_read(file_name); + if(source == NULL) { + failed = 1; + break; + } + } else + source = va_arg(args, char*); shaders[i] = glCreateShader(va_arg(args, GLuint)); if(shaders[i] == 0) { - free(source); + if(!is_src) + free(source); failed = 1; break; } @@ -68,13 +75,15 @@ int shader_source(shader_t* shader, int files, ...) { fprintf(__STDERR, "[ERROR] (%s (COMPILER)) %s\n", file_name, msg); free(msg); - free(source); + if(!is_src) + free(source); failed = 1; break; } glAttachShader(shader->program, shaders[i]); - free(source); + if(!is_src) + free(source); } va_end(args); @@ -149,8 +158,10 @@ shader_t* shader_active() { } void shader_start(shader_t* shader) { - glUseProgram(shader->program); - _active = shader; + if(_active == NULL || _active->program != shader->program) { + glUseProgram(shader->program); + _active = shader; + } } void shader_stop() { diff --git a/src/okuu/shader.h b/src/okuu/shader.h index 75add8c..d277211 100644 --- a/src/okuu/shader.h +++ b/src/okuu/shader.h @@ -12,6 +12,9 @@ #define _SHADER shader_active() #define _ATTR(I) shader_attr(_SHADER, I) +#define SHADER_FILE 0 +#define SHADER_SRC 1 + typedef char layout_name_t[256]; typedef struct { @@ -27,7 +30,7 @@ typedef struct { shader_t* shader_create(const char*); int shader_layout(shader_t*, int, ...); -int shader_source(shader_t*, int, ...); +int shader_source(shader_t*, int, int, ...); int shader_attribs(shader_t*, int, ...); GLint shader_attr(const shader_t*, int); diff --git a/src/okuu/terrain.c b/src/okuu/terrain.c index 49788d8..1fbd390 100644 --- a/src/okuu/terrain.c +++ b/src/okuu/terrain.c @@ -1,11 +1,11 @@ #include "terrain.h" -#define _HGT_AT(A, X, Y) (A->bmps[0]->pixels[Y][X].r / 10.f) +#define _HGT_AT(A, X, Y) (A->bmps[0]->pixels[Y][X][_R_] / 10.f) #define _RWCOL_AT(A, X, Y) (A->bmps[1]->pixels[Y][X]) -#define _RCOL_AT(A, X, Y, C) (_RWCOL_AT(A, X, Y).C) +#define _RCOL_AT(A, X, Y, C) (_RWCOL_AT(A, X, Y)[C]) #define _COL_AT(A, X, Y, C) (_RCOL_AT(A, X, Y, C) / 255.f) #define _COL_EQ(A, X1, Y1, X2, Y2) \ - (color_eqp(&A->bmps[1]->pixels[Y1][X1], &A->bmps[1]->pixels[Y2][X2])) + (color_eqp(A->bmps[1]->pixels[Y1][X1], A->bmps[1]->pixels[Y2][X2])) float _avg_hgt(terrain_t* map, int x, int y) { return @@ -250,14 +250,12 @@ void terrain_move(terrain_t* terrain, int center_x, int center_y) { memcpy(data + at + 12, data + at + 3, 3 * sizeof(float)); memcpy(data + at + 24, data + at + 3, 3 * sizeof(float)); memcpy(data + at + 33, data + at + 3, 3 * sizeof(float)); - - //_norm_smooth(data, x, y); break; case 3: for(int j = 0; j < 12; ++j) { - data[at + j * 3] = _COL_AT(terrain, x, y, r); - data[at + j * 3 + 1] = _COL_AT(terrain, x, y, g); - data[at + j * 3 + 2] = _COL_AT(terrain, x, y, b); + data[at + j * 3] = _COL_AT(terrain, x, y, _R_); + data[at + j * 3 + 1] = _COL_AT(terrain, x, y, _G_); + data[at + j * 3 + 2] = _COL_AT(terrain, x, y, _B_); } const color_t path_colors[] = { @@ -267,7 +265,7 @@ void terrain_move(terrain_t* terrain, int center_x, int center_y) { int found = 0; for(int j = 0; j < sizeof(path_colors) / sizeof(color_t); ++j) { - if(color_eqp(&path_colors[j], &_RWCOL_AT(terrain, x, y))) { + if(color_eqp(path_colors[j], _RWCOL_AT(terrain, x, y))) { found = 1; break; } @@ -301,17 +299,17 @@ void terrain_move(terrain_t* terrain, int center_x, int center_y) { { data[at + j * 9] = _COL_AT(terrain, x + coords[j][0], - y + coords[j][1], r + y + coords[j][1], _R_ ); data[at + j * 9 + 1] = _COL_AT(terrain, x + coords[j][0], - y + coords[j][1], g + y + coords[j][1], _G_ ); data[at + j * 9 + 2] = _COL_AT(terrain, x + coords[j][0], - y + coords[j][1], b + y + coords[j][1], _B_ ); memcpy(data + at + j * 9 + 3, data + at + j * 9, 3 * sizeof(float)); @@ -319,31 +317,6 @@ void terrain_move(terrain_t* terrain, int center_x, int center_y) { } } - /* - for(int j = 0; j < 4; ++j) { - if(_COL_EQ(terrain, - x + coords[j][0], - y + coords[j][1], - x + coords[j][2], - y + coords[j][3])) - { - for(int k = 0; k < 6; ++k) { - data[at + ((k * 3 + j * 9) % 36)] = - _COL_AT(terrain, - x + coords[j][0], - y + coords[j][1], r); - data[at + ((k * 3 + j * 9 + 1) % 36)] = - _COL_AT(terrain, - x + coords[j][0], - y + coords[j][1], g); - data[at + ((k * 3 + j * 9 + 2) % 36)] = - _COL_AT(terrain, - x + coords[j][0], - y + coords[j][1], b); - } - } - }*/ - break; } }