Compare commits
No commits in common. "a571d2d999ea11ec5b62cc4314a6b74b9cbbe7a9" and "69f355eae41a143ec3b3964d94cfb4fe75188dc2" have entirely different histories.
a571d2d999
...
69f355eae4
@ -1,388 +0,0 @@
|
|||||||
/*
|
|
||||||
* This is a mostly standalone file that implements an SDF glyph cache.
|
|
||||||
* It can support any graphics backend as long as it can modify and load subtextures.
|
|
||||||
*
|
|
||||||
* It is SDF-only since this way it is less critical to support different font sizes.
|
|
||||||
*
|
|
||||||
* Example initialization:
|
|
||||||
* FT_Library ftlib;
|
|
||||||
* FT_Init_FreeType(&ftlib);
|
|
||||||
*
|
|
||||||
* FT_Property_Set(ftlib, "sdf", "spread", &(int) {24});
|
|
||||||
*
|
|
||||||
* FT_Face face;
|
|
||||||
* assert(FT_New_Face(ftlib, "my font file.ttf", 0, &face) == 0);
|
|
||||||
* FT_Select_Charmap(face, FT_ENCODING_UNICODE);
|
|
||||||
* FT_Set_Pixel_Sizes(face, 64, 0);
|
|
||||||
*
|
|
||||||
* void *userdata = NULL;
|
|
||||||
*
|
|
||||||
* GlyphCache gc = {};
|
|
||||||
* glca_init(&gc, face, 2048, 2048, userdata, my_set_image, my_get_image, my_fill_custom_data);
|
|
||||||
*
|
|
||||||
* my_fill_custom_data can be used in case you need glyph metrics.
|
|
||||||
* If GLCA_CUSTOM_GLYPH_DATA is not defined, my_fill_custom_data is unused.
|
|
||||||
*
|
|
||||||
* Example usage:
|
|
||||||
* // Should be called regularly (recommended once per frame)
|
|
||||||
* glca_set_time(&gc, get_time_now_somehow());
|
|
||||||
* ...
|
|
||||||
* // When you need to render text:
|
|
||||||
* GlyphCacheGlyph *glyph = glca_request(&gc, 'Ь');
|
|
||||||
* if(!glyph) {
|
|
||||||
* // Skip
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* Safety padding is added (in height) to each new row. It is by default
|
|
||||||
* zero but it is a good idea to experiment with other values.
|
|
||||||
*
|
|
||||||
* WARNING: GlyphCache relies on a few heuristics that assume the following:
|
|
||||||
* 1. Glyphs are roughly equal in size (true for text)
|
|
||||||
* 2. The atlas is reasonably larger in area than a single glyph (at least ~100x)
|
|
||||||
* If either does not hold, GlyphCache will perform AWFULLY.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef GLCA_H
|
|
||||||
#define GLCA_H
|
|
||||||
|
|
||||||
#include<freetype/freetype.h>
|
|
||||||
#include<unistd.h>
|
|
||||||
#include<assert.h>
|
|
||||||
#include<stdint.h>
|
|
||||||
#include<stddef.h>
|
|
||||||
#include<stdbool.h>
|
|
||||||
|
|
||||||
#ifndef GLCA_CUSTOM_GLYPH_DATA
|
|
||||||
typedef struct GlyphCacheGlyphData {} GlyphCacheGlyphData;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct GlyphCacheGlyph {
|
|
||||||
uint32_t codepoint;
|
|
||||||
|
|
||||||
uint16_t x;
|
|
||||||
uint16_t y;
|
|
||||||
uint16_t w;
|
|
||||||
uint16_t h;
|
|
||||||
|
|
||||||
GlyphCacheGlyphData data;
|
|
||||||
|
|
||||||
uint64_t last_use;
|
|
||||||
} GlyphCacheGlyph;
|
|
||||||
|
|
||||||
typedef struct GlyphCacheRow {
|
|
||||||
size_t y;
|
|
||||||
size_t width;
|
|
||||||
size_t height;
|
|
||||||
|
|
||||||
size_t entry_count;
|
|
||||||
uint32_t *entries;
|
|
||||||
} GlyphCacheRow;
|
|
||||||
|
|
||||||
struct GlyphCache;
|
|
||||||
typedef void(*GlyphCacheSetImage)(struct GlyphCache *gc, int x, int y, int w, int h, const void *buf);
|
|
||||||
typedef void(*GlyphCacheGetImage)(struct GlyphCache *gc, int x, int y, int w, int h, void *buf);
|
|
||||||
typedef void(*GlyphCacheFillCustomData)(struct GlyphCache *gc, FT_GlyphSlot, GlyphCacheGlyph*);
|
|
||||||
|
|
||||||
typedef struct GlyphCache {
|
|
||||||
FT_Face face;
|
|
||||||
uint64_t current_time;
|
|
||||||
int safety_padding;
|
|
||||||
|
|
||||||
size_t total_width;
|
|
||||||
size_t total_height;
|
|
||||||
|
|
||||||
size_t row_count;
|
|
||||||
GlyphCacheRow *rows;
|
|
||||||
|
|
||||||
size_t item_count;
|
|
||||||
size_t item_capacity;
|
|
||||||
GlyphCacheGlyph *items;
|
|
||||||
|
|
||||||
void *userdata;
|
|
||||||
GlyphCacheSetImage set_image;
|
|
||||||
GlyphCacheGetImage get_image;
|
|
||||||
GlyphCacheFillCustomData fill_custom_data;
|
|
||||||
} GlyphCache;
|
|
||||||
|
|
||||||
int glca_init(GlyphCache*, FT_Face, size_t w, size_t h, void *userdata, GlyphCacheSetImage, GlyphCacheGetImage, GlyphCacheFillCustomData);
|
|
||||||
|
|
||||||
GlyphCacheGlyph *glca_get_noupdate(GlyphCache *gc, uint32_t codepoint);
|
|
||||||
GlyphCacheGlyph *glca_get(GlyphCache *gc, uint32_t codepoint);
|
|
||||||
GlyphCacheGlyph *glca_request(GlyphCache *gc, uint32_t codepoint);
|
|
||||||
void glca_try_evict(GlyphCache *gc);
|
|
||||||
|
|
||||||
void glca_set_safety_padding(GlyphCache *gc, int safety_padding);
|
|
||||||
|
|
||||||
void glca_set_time(GlyphCache *gc, uint64_t time);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef GLCA_IMPLEMENTATION
|
|
||||||
static uint32_t glca_hash(uint32_t x) {
|
|
||||||
x = ((x >> 16) ^ x) * 0x45d9f3bu;
|
|
||||||
x = ((x >> 16) ^ x) * 0x45d9f3bu;
|
|
||||||
x = (x >> 16) ^ x;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
int glca_init(GlyphCache *gc, FT_Face face, size_t total_width, size_t total_height, void *userdata, GlyphCacheSetImage set_image, GlyphCacheGetImage get_image, GlyphCacheFillCustomData fill_custom_data) {
|
|
||||||
memset(gc, 0, sizeof(*gc));
|
|
||||||
gc->face = face;
|
|
||||||
gc->total_width = total_width;
|
|
||||||
gc->total_height = total_height;
|
|
||||||
gc->userdata = userdata;
|
|
||||||
gc->set_image = set_image;
|
|
||||||
gc->get_image = get_image;
|
|
||||||
gc->fill_custom_data = fill_custom_data;
|
|
||||||
gc->item_capacity = 128;
|
|
||||||
gc->items = calloc(gc->item_capacity, sizeof(*gc->items));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns row number for new glyph. If == -1, impossible.
|
|
||||||
static int choose_row(GlyphCache *gc, size_t w, size_t h) {
|
|
||||||
size_t y = 0;
|
|
||||||
|
|
||||||
if(gc->row_count == 0) {
|
|
||||||
goto make_new;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
int bestRow = -1;
|
|
||||||
int bestRowHDiff = 10000000;
|
|
||||||
for(int row = 0; row < gc->row_count; row++) {
|
|
||||||
y += gc->rows[row].height;
|
|
||||||
|
|
||||||
if(gc->total_width - gc->rows[row].width < w) {
|
|
||||||
// No width remains in row.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(gc->rows[row].height < h) {
|
|
||||||
// Row too short.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int diff = gc->rows[row].height - h;
|
|
||||||
|
|
||||||
if(bestRowHDiff > diff) {
|
|
||||||
bestRowHDiff = diff;
|
|
||||||
bestRow = row;
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(found) {
|
|
||||||
return bestRow;
|
|
||||||
}
|
|
||||||
|
|
||||||
make_new:
|
|
||||||
if(y + h > gc->total_height) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
h += gc->safety_padding;
|
|
||||||
if(y + h > gc->total_height) {
|
|
||||||
h = gc->total_height - y;
|
|
||||||
}
|
|
||||||
|
|
||||||
int row = gc->row_count;
|
|
||||||
gc->rows = realloc(gc->rows, sizeof(*gc->rows) * (++gc->row_count));
|
|
||||||
memset(&gc->rows[row], 0, sizeof(*gc->rows));
|
|
||||||
gc->rows[row].y = y;
|
|
||||||
gc->rows[row].height = h;
|
|
||||||
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
GlyphCacheGlyph *glca_get_noupdate(GlyphCache *gc, uint32_t codepoint) {
|
|
||||||
uint32_t i = glca_hash(codepoint);
|
|
||||||
for(size_t probe = 0; probe < 5; probe++) {
|
|
||||||
i &= gc->item_capacity - 1;
|
|
||||||
|
|
||||||
if(gc->items[i].codepoint == 0 && gc->items[i].w == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(gc->items[i].codepoint == codepoint) {
|
|
||||||
return &gc->items[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
GlyphCacheGlyph *glca_get(GlyphCache *gc, uint32_t codepoint) {
|
|
||||||
GlyphCacheGlyph *glyph = glca_get_noupdate(gc, codepoint);
|
|
||||||
if(glyph) {
|
|
||||||
glyph->last_use = gc->current_time;
|
|
||||||
}
|
|
||||||
return glyph;
|
|
||||||
}
|
|
||||||
|
|
||||||
void glca_try_evict(GlyphCache *gc) {
|
|
||||||
uint64_t min_time = gc->current_time, max_time = 0;
|
|
||||||
for(size_t i = 0; i < gc->item_count; i++) {
|
|
||||||
if(gc->items[i].codepoint == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(min_time > gc->items[i].last_use) {
|
|
||||||
min_time = gc->items[i].last_use;
|
|
||||||
}
|
|
||||||
if(max_time < gc->items[i].last_use) {
|
|
||||||
max_time = gc->items[i].last_use;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t threshold = max_time / 2 + min_time / 2;
|
|
||||||
|
|
||||||
for(size_t r = 0; r < gc->row_count; r++) {
|
|
||||||
GlyphCacheRow *gcr = &gc->rows[r];
|
|
||||||
|
|
||||||
size_t x_shift = 0;
|
|
||||||
for(size_t i = 0; i < gcr->entry_count;) {
|
|
||||||
GlyphCacheGlyph *glyph = glca_get_noupdate(gc, gcr->entries[i]);
|
|
||||||
|
|
||||||
if(x_shift) {
|
|
||||||
void *buf = malloc(glyph->w * glyph->h);
|
|
||||||
gc->get_image(gc, glyph->x, glyph->y, glyph->w, glyph->h, buf);
|
|
||||||
glyph->x -= x_shift;
|
|
||||||
gc->set_image(gc, glyph->x, glyph->y, glyph->w, glyph->h, buf);
|
|
||||||
free(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(glyph->last_use >= threshold) {
|
|
||||||
// Do not evict.
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
x_shift += glyph->w;
|
|
||||||
|
|
||||||
memmove(gcr->entries + i, gcr->entries + i + 1, sizeof(*gcr->entries) * (gcr->entry_count - i - 1));
|
|
||||||
gcr->width -= glyph->w;
|
|
||||||
gcr->entry_count--;
|
|
||||||
|
|
||||||
glyph->codepoint = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void glca_expand(GlyphCache *gc, size_t shift) {
|
|
||||||
size_t new_capacity = gc->item_capacity << shift;
|
|
||||||
GlyphCacheGlyph *newarray = calloc(new_capacity, sizeof(*newarray));
|
|
||||||
|
|
||||||
for(size_t idx = 0; idx < gc->item_capacity; idx++) {
|
|
||||||
|
|
||||||
if(gc->items[idx].codepoint == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t i = glca_hash(gc->items[idx].codepoint);
|
|
||||||
size_t probe;
|
|
||||||
for(probe = 0; probe < 5; probe++) {
|
|
||||||
i &= new_capacity - 1;
|
|
||||||
|
|
||||||
if(newarray[i].codepoint == 0) {
|
|
||||||
newarray[i] = gc->items[idx];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(probe == 5) {
|
|
||||||
goto failed_to_expand;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
free(gc->items);
|
|
||||||
|
|
||||||
gc->item_capacity = new_capacity;
|
|
||||||
gc->items = newarray;
|
|
||||||
|
|
||||||
return;
|
|
||||||
failed_to_expand:
|
|
||||||
free(newarray);
|
|
||||||
glca_expand(gc, shift + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
GlyphCacheGlyph *glca_request(GlyphCache *gc, uint32_t codepoint) {
|
|
||||||
GlyphCacheGlyph *glyph = glca_get(gc, codepoint);
|
|
||||||
if(glyph) {
|
|
||||||
return glyph;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(FT_Load_Char(gc->face, codepoint, 0) == 0);
|
|
||||||
assert(FT_Render_Glyph(gc->face->glyph, FT_RENDER_MODE_NORMAL) == 0);
|
|
||||||
assert(FT_Render_Glyph(gc->face->glyph, FT_RENDER_MODE_SDF) == 0);
|
|
||||||
|
|
||||||
size_t w = gc->face->glyph->bitmap.width, h = gc->face->glyph->bitmap.rows;
|
|
||||||
|
|
||||||
int row = choose_row(gc, w, h);
|
|
||||||
if(row == -1) {
|
|
||||||
glca_try_evict(gc);
|
|
||||||
row = choose_row(gc, w, h);
|
|
||||||
if(row == -1) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GlyphCacheRow *gcr = &gc->rows[row];
|
|
||||||
|
|
||||||
size_t x = gcr->width;
|
|
||||||
size_t y = gcr->y;
|
|
||||||
gcr->width += w;
|
|
||||||
gcr->entries = realloc(gcr->entries, sizeof(*gcr->entries) * (gcr->entry_count + 1));
|
|
||||||
gcr->entries[gcr->entry_count++] = codepoint;
|
|
||||||
|
|
||||||
glyph = NULL;
|
|
||||||
while(1) {
|
|
||||||
uint32_t i = glca_hash(codepoint);
|
|
||||||
for(size_t probe = 0; probe < 5; probe++) {
|
|
||||||
i &= gc->item_capacity - 1;
|
|
||||||
if(gc->items[i].codepoint == 0) {
|
|
||||||
glyph = &gc->items[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if(glyph) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
glca_expand(gc, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
*glyph = (GlyphCacheGlyph) {
|
|
||||||
.codepoint = codepoint,
|
|
||||||
.x = x,
|
|
||||||
.y = y,
|
|
||||||
.w = w,
|
|
||||||
.h = h,
|
|
||||||
};
|
|
||||||
#ifdef GLCA_CUSTOM_GLYPH_DATA
|
|
||||||
if(gc->fill_custom_data) {
|
|
||||||
gc->fill_custom_data(gc, gc->face->glyph, glyph);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint8_t *buf = malloc(w * h);
|
|
||||||
for(int y = 0; y < h; y++) {
|
|
||||||
memcpy(buf + y * w, gc->face->glyph->bitmap.buffer + y * gc->face->glyph->bitmap.pitch, w);
|
|
||||||
}
|
|
||||||
gc->set_image(gc, x, y, w, h, buf);
|
|
||||||
free(buf);
|
|
||||||
|
|
||||||
return glca_get(gc, codepoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
void glca_set_safety_padding(GlyphCache *gc, int safety_padding) {
|
|
||||||
gc->safety_padding = safety_padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
void glca_set_time(GlyphCache *gc, uint64_t time) {
|
|
||||||
gc->current_time = time;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@ -10,7 +10,7 @@ static inline void immdraw_fill_rect(int16_t x, int16_t y, int16_t w, int16_t h,
|
|||||||
k3BatchAdd(NULL, (struct k3RectF) {0, 0, 1, 1}, (struct k3RectF) {
|
k3BatchAdd(NULL, (struct k3RectF) {0, 0, 1, 1}, (struct k3RectF) {
|
||||||
x, GameWndH - y - h,
|
x, GameWndH - y - h,
|
||||||
w, h
|
w, h
|
||||||
}, 0, (vec4) {r, g, b, a}, borderRadius, 0);
|
}, 0, (vec4) {r, g, b, a}, borderRadius);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void immdraw_font_draw(struct k3Font *font, int16_t x, int16_t y, int16_t w, float sz, size_t len, const char *txt, int alignment, float r, float g, float b, float a) {
|
static inline void immdraw_font_draw(struct k3Font *font, int16_t x, int16_t y, int16_t w, float sz, size_t len, const char *txt, int alignment, float r, float g, float b, float a) {
|
||||||
@ -26,7 +26,7 @@ static inline void immdraw_font_size(struct k3Font *font, float sz, const char *
|
|||||||
|
|
||||||
static inline void immdraw_image_draw(k3MImageData *data, int16_t x, int16_t y, int16_t w, int16_t h, float r, float g, float b, float a) {
|
static inline void immdraw_image_draw(k3MImageData *data, int16_t x, int16_t y, int16_t w, int16_t h, float r, float g, float b, float a) {
|
||||||
struct k3Tex *tex = *data;
|
struct k3Tex *tex = *data;
|
||||||
k3BatchAdd(tex, (struct k3RectF) {0, 0, 1, 1}, (struct k3RectF) {x, GameWndH - y - h, w, h}, 0, (vec4) {r, g, b, a}, 0, 0);
|
k3BatchAdd(tex, (struct k3RectF) {0, 0, 1, 1}, (struct k3RectF) {x, GameWndH - y - h, w, h}, 0, (vec4) {r, g, b, a}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int16_t crop_aabb[4] = {-1, -1, -1, -1};
|
static int16_t crop_aabb[4] = {-1, -1, -1, -1};
|
||||||
|
|||||||
399
src/k3.c
399
src/k3.c
@ -1,7 +1,6 @@
|
|||||||
#include"k3_internal.h"
|
#include"k3_internal.h"
|
||||||
|
|
||||||
#include"gl.h"
|
#include"gl.h"
|
||||||
#include"komihash.h"
|
|
||||||
|
|
||||||
#include<stdlib.h>
|
#include<stdlib.h>
|
||||||
#include<string.h>
|
#include<string.h>
|
||||||
@ -624,8 +623,6 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(compressed && TextureOfflineCompressor) {
|
if(compressed && TextureOfflineCompressor) {
|
||||||
k3Log(k3_DEBUG, "Compressing texture...");
|
|
||||||
|
|
||||||
size_t len;
|
size_t len;
|
||||||
data = TextureOfflineCompressor(data, width, height, externalFmt, intype, &len);
|
data = TextureOfflineCompressor(data, width, height, externalFmt, intype, &len);
|
||||||
|
|
||||||
@ -645,8 +642,6 @@ void k3TexUpdate(struct k3Tex *tex, enum k3TexType type, int index, uint16_t wid
|
|||||||
tex->szZ = 0;
|
tex->szZ = 0;
|
||||||
|
|
||||||
tex->glInternalFormat = internalFmt;
|
tex->glInternalFormat = internalFmt;
|
||||||
tex->glExternalFormat = externalFmt;
|
|
||||||
tex->glInType = intype;
|
|
||||||
}
|
}
|
||||||
uint32_t k3TexSzX(struct k3Tex *this) {
|
uint32_t k3TexSzX(struct k3Tex *this) {
|
||||||
return this->szX;
|
return this->szX;
|
||||||
@ -696,7 +691,7 @@ struct Renderable {
|
|||||||
struct k3Mdl *mdl;
|
struct k3Mdl *mdl;
|
||||||
struct k3Mesh *mesh;
|
struct k3Mesh *mesh;
|
||||||
struct k3AnimationBone *bones;
|
struct k3AnimationBone *bones;
|
||||||
struct k3GLSLP *glslp;
|
GLhandleARB glsl;
|
||||||
GLuint arbvp;
|
GLuint arbvp;
|
||||||
GLuint arbfp;
|
GLuint arbfp;
|
||||||
} __attribute__((aligned(16)));
|
} __attribute__((aligned(16)));
|
||||||
@ -737,7 +732,7 @@ static intmax_t rblecompar1(const void *a, const void *b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(i == 0) {
|
if(i == 0) {
|
||||||
i = ((const struct Renderable*) a)->glslp->handle - ((const struct Renderable*) b)->glslp->handle;
|
i = ((const struct Renderable*) a)->glsl - ((const struct Renderable*) b)->glsl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(i == 0) {
|
if(i == 0) {
|
||||||
@ -774,7 +769,7 @@ void k3Batch(struct k3Mdl *mdl, mat4 modelmat, struct k3AnimationBone *bones) {
|
|||||||
r->mesh = &mdl->meshes[mesh];
|
r->mesh = &mdl->meshes[mesh];
|
||||||
glm_mat4_copy(modelmat, r->modelmat);
|
glm_mat4_copy(modelmat, r->modelmat);
|
||||||
r->bones = bones;
|
r->bones = bones;
|
||||||
r->glslp = r->mesh->mat.passes[0].glsl.hp;
|
r->glsl = GL_FROM_K3GLSL(r->mesh->mat.passes[0].glsl.hp);
|
||||||
r->arbvp = GL_FROM_K3ARBVP(r->mesh->mat.passes[0].arbvp.vp);
|
r->arbvp = GL_FROM_K3ARBVP(r->mesh->mat.passes[0].arbvp.vp);
|
||||||
r->arbfp = GL_FROM_K3ARBFP(r->mesh->mat.passes[0].arbfp.fp);
|
r->arbfp = GL_FROM_K3ARBFP(r->mesh->mat.passes[0].arbfp.fp);
|
||||||
}
|
}
|
||||||
@ -788,9 +783,9 @@ static void setup_ff_projection(mat4 proj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_core_projection(struct k3GLSLP *p, mat4 proj) {
|
static void setup_core_projection(GLuint prog, mat4 proj) {
|
||||||
if(k3IsCore) {
|
if(k3IsCore) {
|
||||||
GLint u = k3ProgramGetUId(p, "u_projection");
|
GLint u = glGetUniformLocation(prog, "u_projection");
|
||||||
|
|
||||||
if(u != -1) {
|
if(u != -1) {
|
||||||
glUniformMatrix4fv(u, 1, GL_FALSE, (float*) proj);
|
glUniformMatrix4fv(u, 1, GL_FALSE, (float*) proj);
|
||||||
@ -849,29 +844,31 @@ static void setup_arbprog_globals() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_glsl_globals(struct k3GLSLP *p, mat4 view) {
|
static void setup_glsl_globals(GLuint bound, mat4 view) {
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
glUniform1fARB(k3ProgramGetUId(p, "u_time"), Time);
|
glUniform1fARB(glGetUniformLocationARB(bound, "u_time"), Time);
|
||||||
glUniform3fARB(k3ProgramGetUId(p, "u_cam"), CamMat[3][0], CamMat[3][1], CamMat[3][2]);
|
glUniform3fARB(glGetUniformLocationARB(bound, "u_cam"), CamMat[3][0], CamMat[3][1], CamMat[3][2]);
|
||||||
glUniformMatrix4fvARB(k3ProgramGetUId(p, "u_view"), 1, GL_FALSE, (float*) view);
|
glUniformMatrix4fvARB(glGetUniformLocationARB(bound, "u_view"), 1, GL_FALSE, (float*) view);
|
||||||
} else {
|
} else {
|
||||||
glUniform1f(k3ProgramGetUId(p, "u_time"), Time);
|
glUniform1f(glGetUniformLocationARB(bound, "u_time"), Time);
|
||||||
glUniform3f(k3ProgramGetUId(p, "u_cam"), CamMat[3][0], CamMat[3][1], CamMat[3][2]);
|
glUniform3f(glGetUniformLocationARB(bound, "u_cam"), CamMat[3][0], CamMat[3][1], CamMat[3][2]);
|
||||||
glUniformMatrix4fv(k3ProgramGetUId(p, "u_view"), 1, GL_FALSE, (float*) view);
|
glUniformMatrix4fv(glGetUniformLocationARB(bound, "u_view"), 1, GL_FALSE, (float*) view);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_glsl_mat_uniforms(struct k3GLSLP *p, struct k3Mat *mat, int pass) {
|
static void setup_glsl_mat_uniforms(GLhandleARB bound, struct k3Mat *mat, int pass) {
|
||||||
for(int u = 0; u < mat->passes[pass].glsl.uCount; u++) {
|
for(int u = 0; u < mat->passes[pass].glsl.uCount; u++) {
|
||||||
GLuint id = k3ProgramGetUId(p, mat->passes[pass].glsl.u[u].name);
|
|
||||||
|
|
||||||
if(mat->passes[pass].glsl.u[u].type == k3_MAT_UNIFORM_I1) {
|
if(mat->passes[pass].glsl.u[u].type == k3_MAT_UNIFORM_I1) {
|
||||||
|
GLuint id = glGetUniformLocationARB(bound, mat->passes[pass].glsl.u[u].name);
|
||||||
|
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
glUniform1iARB(id, mat->passes[pass].glsl.u[u].i1);
|
glUniform1iARB(id, mat->passes[pass].glsl.u[u].i1);
|
||||||
} else {
|
} else {
|
||||||
glUniform1i(id, mat->passes[pass].glsl.u[u].i1);
|
glUniform1i(id, mat->passes[pass].glsl.u[u].i1);
|
||||||
}
|
}
|
||||||
} else if(mat->passes[pass].glsl.u[u].type == k3_MAT_UNIFORM_F1) {
|
} else if(mat->passes[pass].glsl.u[u].type == k3_MAT_UNIFORM_F1) {
|
||||||
|
GLuint id = glGetUniformLocationARB(bound, mat->passes[pass].glsl.u[u].name);
|
||||||
|
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
glUniform1fARB(id, mat->passes[pass].glsl.u[u].f1);
|
glUniform1fARB(id, mat->passes[pass].glsl.u[u].f1);
|
||||||
} else {
|
} else {
|
||||||
@ -881,20 +878,20 @@ static void setup_glsl_mat_uniforms(struct k3GLSLP *p, struct k3Mat *mat, int pa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_glsl_model_uniforms(struct k3GLSLP *p, float *modelmat) {
|
static void setup_glsl_model_uniforms(GLuint bound, float *modelmat) {
|
||||||
mat4 invmodel;
|
mat4 invmodel;
|
||||||
glm_mat4_inv(modelmat, invmodel);
|
glm_mat4_inv(modelmat, invmodel);
|
||||||
|
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
glUniformMatrix4fvARB(k3ProgramGetUId(p, "u_model"), 1, GL_FALSE, (float*) modelmat);
|
glUniformMatrix4fvARB(glGetUniformLocationARB(bound, "u_model"), 1, GL_FALSE, (float*) modelmat);
|
||||||
glUniformMatrix4fvARB(k3ProgramGetUId(p, "u_imodel"), 1, GL_FALSE, (float*) invmodel);
|
glUniformMatrix4fvARB(glGetUniformLocationARB(bound, "u_imodel"), 1, GL_FALSE, (float*) invmodel);
|
||||||
} else {
|
} else {
|
||||||
glUniformMatrix4fv(k3ProgramGetUId(p, "u_model"), 1, GL_FALSE, (float*) modelmat);
|
glUniformMatrix4fv(glGetUniformLocationARB(bound, "u_model"), 1, GL_FALSE, (float*) modelmat);
|
||||||
glUniformMatrix4fv(k3ProgramGetUId(p, "u_imodel"), 1, GL_FALSE, (float*) invmodel);
|
glUniformMatrix4fv(glGetUniformLocationARB(bound, "u_imodel"), 1, GL_FALSE, (float*) invmodel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_glsl_lighting_uniforms(struct k3GLSLP *p, int lightsStart, int lightsCount) {
|
static void setup_glsl_lighting_uniforms(GLuint bound, int lightsStart, int lightsCount) {
|
||||||
if(lightsCount > 4) {
|
if(lightsCount > 4) {
|
||||||
lightsCount = 4;
|
lightsCount = 4;
|
||||||
k3Log(k3_ERR, "Max 4 lights per pass");
|
k3Log(k3_ERR, "Max 4 lights per pass");
|
||||||
@ -957,19 +954,19 @@ static void setup_glsl_lighting_uniforms(struct k3GLSLP *p, int lightsStart, int
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
glUniform4fvARB(k3ProgramGetUId(p, "u_BaseLightSettings1"), 4, (float*) settings1);
|
glUniform4fvARB(glGetUniformLocationARB(bound, "u_BaseLightSettings1"), 4, (float*) settings1);
|
||||||
glUniform4fvARB(k3ProgramGetUId(p, "u_BaseLightSettings2"), 4, (float*) settings2);
|
glUniform4fvARB(glGetUniformLocationARB(bound, "u_BaseLightSettings2"), 4, (float*) settings2);
|
||||||
glUniform4fvARB(k3ProgramGetUId(p, "u_BaseLightColors"), 4, (float*) colors);
|
glUniform4fvARB(glGetUniformLocationARB(bound, "u_BaseLightColors"), 4, (float*) colors);
|
||||||
glUniform4fvARB(k3ProgramGetUId(p, "u_AmbientLight"), 1, (float*) ambient);
|
glUniform4fvARB(glGetUniformLocationARB(bound, "u_AmbientLight"), 1, (float*) ambient);
|
||||||
} else {
|
} else {
|
||||||
glUniform4fv(k3ProgramGetUId(p, "u_BaseLightSettings1"), 4, (float*) settings1);
|
glUniform4fv(glGetUniformLocationARB(bound, "u_BaseLightSettings1"), 4, (float*) settings1);
|
||||||
glUniform4fv(k3ProgramGetUId(p, "u_BaseLightSettings2"), 4, (float*) settings2);
|
glUniform4fv(glGetUniformLocationARB(bound, "u_BaseLightSettings2"), 4, (float*) settings2);
|
||||||
glUniform4fv(k3ProgramGetUId(p, "u_BaseLightColors"), 4, (float*) colors);
|
glUniform4fv(glGetUniformLocationARB(bound, "u_BaseLightColors"), 4, (float*) colors);
|
||||||
glUniform4fv(k3ProgramGetUId(p, "u_AmbientLight"), 1, (float*) ambient);
|
glUniform4fv(glGetUniformLocationARB(bound, "u_AmbientLight"), 1, (float*) ambient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_glsl_shadow_uniforms(struct k3GLSLP *p, int atlasUnit, int lightsStart, int lightsCount) {
|
static void setup_glsl_shadow_uniforms(GLuint bound, int atlasUnit, int lightsStart, int lightsCount) {
|
||||||
if(lightsCount > 4) {
|
if(lightsCount > 4) {
|
||||||
lightsCount = 4;
|
lightsCount = 4;
|
||||||
k3Log(k3_ERR, "Max 4 lights per pass");
|
k3Log(k3_ERR, "Max 4 lights per pass");
|
||||||
@ -980,7 +977,7 @@ static void setup_glsl_shadow_uniforms(struct k3GLSLP *p, int atlasUnit, int lig
|
|||||||
if(LightShadowIrregularMode) {
|
if(LightShadowIrregularMode) {
|
||||||
assert(k3IsCore);
|
assert(k3IsCore);
|
||||||
|
|
||||||
glUniform1i(k3ProgramGetUId(p, "u_pixelsinshadow"), 0);
|
glUniform1i(glGetUniformLocation(bound, "u_pixelsinshadow"), 0);
|
||||||
} else {
|
} else {
|
||||||
size_t vpi = 0;
|
size_t vpi = 0;
|
||||||
mat4 m[6];
|
mat4 m[6];
|
||||||
@ -1007,43 +1004,27 @@ static void setup_glsl_shadow_uniforms(struct k3GLSLP *p, int atlasUnit, int lig
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
glUniformMatrix4fvARB(k3ProgramGetUId(p, "u_shadows0vp"), vpi, GL_FALSE, (float*) m);
|
glUniformMatrix4fvARB(glGetUniformLocationARB(bound, "u_shadows0vp"), vpi, GL_FALSE, (float*) m);
|
||||||
glUniform4fvARB(k3ProgramGetUId(p, "u_shadows0seg"), 4, (float*) seg);
|
glUniform4fvARB(glGetUniformLocationARB(bound, "u_shadows0seg"), 4, (float*) seg);
|
||||||
|
|
||||||
glUniform1iARB(k3ProgramGetUId(p, "u_shadows0atlas"), atlasUnit);
|
glUniform1iARB(glGetUniformLocationARB(bound, "u_shadows0atlas"), atlasUnit);
|
||||||
} else {
|
} else {
|
||||||
glUniformMatrix4fv(k3ProgramGetUId(p, "u_shadows0vp"), vpi, GL_FALSE, (float*) m);
|
glUniformMatrix4fv(glGetUniformLocationARB(bound, "u_shadows0vp"), vpi, GL_FALSE, (float*) m);
|
||||||
glUniform4fv(k3ProgramGetUId(p, "u_shadows0seg"), 4, (float*) seg);
|
glUniform4fv(glGetUniformLocationARB(bound, "u_shadows0seg"), 4, (float*) seg);
|
||||||
|
|
||||||
glUniform1i(k3ProgramGetUId(p, "u_shadows0atlas"), atlasUnit);
|
glUniform1i(glGetUniformLocationARB(bound, "u_shadows0atlas"), atlasUnit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bind_mat_textures(struct k3Mat *mat, int pass) {
|
static int bind_mat_textures(struct k3Mat *mat, int pass) {
|
||||||
int i;
|
int i;
|
||||||
if(GLAD_GL_ARB_direct_state_access) {
|
if(GLAD_GL_EXT_direct_state_access) {
|
||||||
for(i = 0; i < k3_MAX_GLSL_UNITS; i++) {
|
for(i = 0; i < k3_MAX_GLSL_UNITS; i++) {
|
||||||
GLuint tex = GL_FROM_K3TEX(mat->passes[pass].units[i]);
|
glBindMultiTextureEXT(GL_TEXTURE0 + i, GL_TEXTURE_2D, GL_FROM_K3TEX(mat->passes[pass].units[i]));
|
||||||
if(tex == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
glBindTextureUnit(i, tex);
|
|
||||||
}
|
|
||||||
} else if(GLAD_GL_EXT_direct_state_access) {
|
|
||||||
for(i = 0; i < k3_MAX_GLSL_UNITS; i++) {
|
|
||||||
GLuint tex = GL_FROM_K3TEX(mat->passes[pass].units[i]);
|
|
||||||
if(tex == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
glBindMultiTextureEXT(GL_TEXTURE0 + i, GL_TEXTURE_2D, tex);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for(i = 0; i < k3_MAX_GLSL_UNITS; i++) {
|
for(i = 0; i < k3_MAX_GLSL_UNITS; i++) {
|
||||||
GLuint tex = GL_FROM_K3TEX(mat->passes[pass].units[i]);
|
|
||||||
if(tex == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
glActiveTexture(GL_TEXTURE0 + i);
|
glActiveTexture(GL_TEXTURE0 + i);
|
||||||
glBindTexture(GL_TEXTURE_2D, GL_FROM_K3TEX(mat->passes[pass].units[i]));
|
glBindTexture(GL_TEXTURE_2D, GL_FROM_K3TEX(mat->passes[pass].units[i]));
|
||||||
}
|
}
|
||||||
@ -1060,9 +1041,7 @@ static int bind_shadow_texture(int textureUnit) {
|
|||||||
}
|
}
|
||||||
return textureUnit;
|
return textureUnit;
|
||||||
} else {
|
} else {
|
||||||
if(GLAD_GL_ARB_direct_state_access) {
|
if(GLAD_GL_EXT_direct_state_access) {
|
||||||
glBindTextureUnit(textureUnit, GL_FROM_K3TEX(ShadowAtlas->depth));
|
|
||||||
} else if(GLAD_GL_EXT_direct_state_access) {
|
|
||||||
glBindMultiTextureEXT(GL_TEXTURE0 + textureUnit, GL_TEXTURE_2D, GL_FROM_K3TEX(ShadowAtlas->depth));
|
glBindMultiTextureEXT(GL_TEXTURE0 + textureUnit, GL_TEXTURE_2D, GL_FROM_K3TEX(ShadowAtlas->depth));
|
||||||
} else {
|
} else {
|
||||||
glActiveTexture(GL_TEXTURE0 + textureUnit);
|
glActiveTexture(GL_TEXTURE0 + textureUnit);
|
||||||
@ -1072,16 +1051,16 @@ static int bind_shadow_texture(int textureUnit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enable_glsl_bones(struct k3GLSLP *p, struct k3Mdl *mdl, struct k3AnimationBone *bones) {
|
static void enable_glsl_bones(GLuint bound, struct k3Mdl *mdl, struct k3AnimationBone *bones) {
|
||||||
GLint a0;
|
GLint a0;
|
||||||
GLint a1;
|
GLint a1;
|
||||||
|
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
a0 = glGetAttribLocationARB(p->handle, "a_boneids");
|
a0 = glGetAttribLocationARB(bound, "a_boneids");
|
||||||
a1 = glGetAttribLocationARB(p->handle, "a_boneweights");
|
a1 = glGetAttribLocationARB(bound, "a_boneweights");
|
||||||
} else {
|
} else {
|
||||||
a0 = glGetAttribLocation(p->handle, "a_boneids");
|
a0 = glGetAttribLocation(bound, "a_boneids");
|
||||||
a1 = glGetAttribLocation(p->handle, "a_boneweights");
|
a1 = glGetAttribLocation(bound, "a_boneweights");
|
||||||
}
|
}
|
||||||
|
|
||||||
if((a0 == -1) != (a1 == -1)) {
|
if((a0 == -1) != (a1 == -1)) {
|
||||||
@ -1114,9 +1093,9 @@ static void enable_glsl_bones(struct k3GLSLP *p, struct k3Mdl *mdl, struct k3Ani
|
|||||||
|
|
||||||
if(bones) {
|
if(bones) {
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
glUniform4fvARB(k3ProgramGetUId(p, "u_bonedata"), 2 * mdl->boneCount, (float*) bones);
|
glUniform4fvARB(glGetUniformLocationARB(bound, "u_bonedata"), 2 * mdl->boneCount, (float*) bones);
|
||||||
} else {
|
} else {
|
||||||
glUniform4fv(k3ProgramGetUId(p, "u_bonedata"), 2 * mdl->boneCount, (float*) bones);
|
glUniform4fv(glGetUniformLocationARB(bound, "u_bonedata"), 2 * mdl->boneCount, (float*) bones);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
vec4 data[48] = {};
|
vec4 data[48] = {};
|
||||||
@ -1125,19 +1104,19 @@ static void enable_glsl_bones(struct k3GLSLP *p, struct k3Mdl *mdl, struct k3Ani
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
glUniform4fvARB(k3ProgramGetUId(p, "u_bonedata"), 48, (float*) data);
|
glUniform4fvARB(glGetUniformLocationARB(bound, "u_bonedata"), 48, (float*) data);
|
||||||
} else {
|
} else {
|
||||||
glUniform4fv(k3ProgramGetUId(p, "u_bonedata"), 48, (float*) data);
|
glUniform4fv(glGetUniformLocationARB(bound, "u_bonedata"), 48, (float*) data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disable_glsl_bones(struct k3Mdl *mdl, struct k3GLSLP *p) {
|
static void disable_glsl_bones(struct k3Mdl *mdl, GLuint bound) {
|
||||||
GLint a0;
|
GLint a0;
|
||||||
GLint a1;
|
GLint a1;
|
||||||
|
|
||||||
a0 = (glGetAttribLocationARB ? glGetAttribLocationARB : glGetAttribLocation)(p->handle, "a_boneids");
|
a0 = glGetAttribLocationARB(bound, "a_boneids");
|
||||||
a1 = (glGetAttribLocationARB ? glGetAttribLocationARB : glGetAttribLocation)(p->handle, "a_boneweights");
|
a1 = glGetAttribLocationARB(bound, "a_boneweights");
|
||||||
|
|
||||||
if(a0 != -1) {
|
if(a0 != -1) {
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
@ -1150,7 +1129,7 @@ static void disable_glsl_bones(struct k3Mdl *mdl, struct k3GLSLP *p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enable_glsl_tangents(struct k3GLSLP *p, struct k3Mdl *mdl) {
|
static void enable_glsl_tangents(GLuint bound, struct k3Mdl *mdl) {
|
||||||
if(mdl->offT == -1) {
|
if(mdl->offT == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1158,9 +1137,9 @@ static void enable_glsl_tangents(struct k3GLSLP *p, struct k3Mdl *mdl) {
|
|||||||
GLint a;
|
GLint a;
|
||||||
|
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
a = glGetAttribLocationARB(p->handle, "a_tangent");
|
a = glGetAttribLocationARB(bound, "a_tangent");
|
||||||
} else {
|
} else {
|
||||||
a = glGetAttribLocation(p->handle, "a_tangent");
|
a = glGetAttribLocation(bound, "a_tangent");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(a == -1) {
|
if(a == -1) {
|
||||||
@ -1176,7 +1155,7 @@ static void enable_glsl_tangents(struct k3GLSLP *p, struct k3Mdl *mdl) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disable_glsl_tangents(struct k3GLSLP *p, struct k3Mdl *mdl) {
|
static void disable_glsl_tangents(GLuint bound, struct k3Mdl *mdl) {
|
||||||
if(mdl->offT == -1) {
|
if(mdl->offT == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1184,9 +1163,9 @@ static void disable_glsl_tangents(struct k3GLSLP *p, struct k3Mdl *mdl) {
|
|||||||
GLint a;
|
GLint a;
|
||||||
|
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
a = glGetAttribLocationARB(p->handle, "a_tangent");
|
a = glGetAttribLocationARB(bound, "a_tangent");
|
||||||
} else {
|
} else {
|
||||||
a = glGetAttribLocation(p->handle, "a_tangent");
|
a = glGetAttribLocation(bound, "a_tangent");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(a == -1) {
|
if(a == -1) {
|
||||||
@ -1200,7 +1179,7 @@ static void disable_glsl_tangents(struct k3GLSLP *p, struct k3Mdl *mdl) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enable_vertex_buffers(struct k3Mdl *mdl, struct k3GLSLP *p) {
|
static void enable_vertex_buffers(struct k3Mdl *mdl, GLuint prog) {
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
glEnableClientState(GL_NORMAL_ARRAY);
|
glEnableClientState(GL_NORMAL_ARRAY);
|
||||||
@ -1216,11 +1195,11 @@ static void enable_vertex_buffers(struct k3Mdl *mdl, struct k3GLSLP *p) {
|
|||||||
} else {
|
} else {
|
||||||
glColor4f(1, 1, 1, 1);
|
glColor4f(1, 1, 1, 1);
|
||||||
}
|
}
|
||||||
} else if(p) {
|
} else if(prog) {
|
||||||
GLint aPos = glGetAttribLocation(p->handle, "a_pos");
|
GLint aPos = glGetAttribLocation(prog, "a_pos");
|
||||||
GLint aNormal = glGetAttribLocation(p->handle, "a_normal");
|
GLint aNormal = glGetAttribLocation(prog, "a_normal");
|
||||||
GLint aUv = glGetAttribLocation(p->handle, "a_uv");
|
GLint aUv = glGetAttribLocation(prog, "a_uv");
|
||||||
GLint aColor = glGetAttribLocation(p->handle, "a_color");
|
GLint aColor = glGetAttribLocation(prog, "a_color");
|
||||||
|
|
||||||
if(aPos != -1) {
|
if(aPos != -1) {
|
||||||
glEnableVertexAttribArray(aPos);
|
glEnableVertexAttribArray(aPos);
|
||||||
@ -1246,7 +1225,7 @@ static void enable_vertex_buffers(struct k3Mdl *mdl, struct k3GLSLP *p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disable_vertex_buffers(struct k3Mdl *mdl, struct k3GLSLP *p) {
|
static void disable_vertex_buffers(struct k3Mdl *mdl, GLuint prog) {
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
glDisableClientState(GL_NORMAL_ARRAY);
|
glDisableClientState(GL_NORMAL_ARRAY);
|
||||||
@ -1255,11 +1234,11 @@ static void disable_vertex_buffers(struct k3Mdl *mdl, struct k3GLSLP *p) {
|
|||||||
if(mdl->offC != -1) {
|
if(mdl->offC != -1) {
|
||||||
glDisableClientState(GL_COLOR_ARRAY);
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
}
|
}
|
||||||
} else if(p) {
|
} else if(prog) {
|
||||||
GLint aPos = glGetAttribLocation(p->handle, "a_pos");
|
GLint aPos = glGetAttribLocation(prog, "a_pos");
|
||||||
GLint aNormal = glGetAttribLocation(p->handle, "a_normal");
|
GLint aNormal = glGetAttribLocation(prog, "a_normal");
|
||||||
GLint aUv = glGetAttribLocation(p->handle, "a_uv");
|
GLint aUv = glGetAttribLocation(prog, "a_uv");
|
||||||
GLint aColor = glGetAttribLocation(p->handle, "a_color");
|
GLint aColor = glGetAttribLocation(prog, "a_color");
|
||||||
|
|
||||||
if(aPos != -1) {
|
if(aPos != -1) {
|
||||||
glDisableVertexAttribArray(aPos);
|
glDisableVertexAttribArray(aPos);
|
||||||
@ -1408,8 +1387,6 @@ static bool outside_frustum(vec3 *aabb, float *modelmat, vec4 *frustum) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void forward_subpass(mat4 projection, mat4 view, int transparent, int lightsStart, int lightsCount, size_t rbleStart, size_t rbleEnd) {
|
static void forward_subpass(mat4 projection, mat4 view, int transparent, int lightsStart, int lightsCount, size_t rbleStart, size_t rbleEnd) {
|
||||||
struct k3Timer timer = k3StartTimer("forward_subpass");
|
|
||||||
|
|
||||||
setup_ff_lights(view, lightsStart, lightsCount);
|
setup_ff_lights(view, lightsStart, lightsCount);
|
||||||
|
|
||||||
mat4 viewProj;
|
mat4 viewProj;
|
||||||
@ -1418,19 +1395,18 @@ static void forward_subpass(mat4 projection, mat4 view, int transparent, int lig
|
|||||||
vec4 cameraFrustum[6];
|
vec4 cameraFrustum[6];
|
||||||
glm_frustum_planes(viewProj, cameraFrustum);
|
glm_frustum_planes(viewProj, cameraFrustum);
|
||||||
|
|
||||||
struct k3GLSLP *lastGLSLP = NULL;
|
GLhandleARB lastGLSL = -1;
|
||||||
GLuint lastVP = 0, lastFP = 0;
|
GLuint lastVP = 0, lastFP = 0;
|
||||||
struct k3Mat *lastMaterial = NULL;
|
struct k3Mat *lastMaterial = NULL;
|
||||||
int lastAdditive = -1;
|
int lastAdditive = -1;
|
||||||
int lastDepthwrite = -1;
|
int lastDepthwrite = -1;
|
||||||
int lastNocull = -1;
|
|
||||||
|
|
||||||
for(size_t rble = rbleStart; rble < rbleEnd; rble++) {
|
for(size_t rble = rbleStart; rble < rbleEnd; rble++) {
|
||||||
struct k3Mdl *mdl = renderQueue[rble].mdl;
|
struct k3Mdl *mdl = renderQueue[rble].mdl;
|
||||||
struct k3Mesh *mesh = renderQueue[rble].mesh;
|
struct k3Mesh *mesh = renderQueue[rble].mesh;
|
||||||
float *modelmat = (float*) renderQueue[rble].modelmat;
|
float *modelmat = (float*) renderQueue[rble].modelmat;
|
||||||
struct k3AnimationBone *bones = renderQueue[rble].bones;
|
struct k3AnimationBone *bones = renderQueue[rble].bones;
|
||||||
struct k3GLSLP *glslp = renderQueue[rble].glslp;
|
GLhandleARB glsl = renderQueue[rble].glsl;
|
||||||
GLuint arbvp = renderQueue[rble].arbvp;
|
GLuint arbvp = renderQueue[rble].arbvp;
|
||||||
GLuint arbfp = renderQueue[rble].arbfp;
|
GLuint arbfp = renderQueue[rble].arbfp;
|
||||||
|
|
||||||
@ -1483,42 +1459,35 @@ static void forward_subpass(mat4 projection, mat4 view, int transparent, int lig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(lastNocull != mat->passes[0].nocull) {
|
if(glsl) {
|
||||||
lastNocull = mat->passes[0].nocull;
|
if(lastGLSL != glsl) {
|
||||||
if(lastNocull) {
|
|
||||||
glDisable(GL_CULL_FACE);
|
|
||||||
} else {
|
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(glslp) {
|
|
||||||
if(lastGLSLP != glslp) {
|
|
||||||
if(k3IsCore)
|
if(k3IsCore)
|
||||||
glUseProgram(glslp->handle);
|
glUseProgram(glsl);
|
||||||
else
|
else
|
||||||
glUseProgramObjectARB(glslp->handle);
|
glUseProgramObjectARB(glsl);
|
||||||
|
|
||||||
lastGLSLP = glslp;
|
lastGLSL = glsl;
|
||||||
|
|
||||||
setup_glsl_globals(glslp, view);
|
setup_glsl_globals(glsl, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_core_projection(glslp, ProjMat);
|
setup_core_projection(glsl, ProjMat);
|
||||||
|
|
||||||
setup_glsl_mat_uniforms(glslp, mat, 0);
|
setup_glsl_mat_uniforms(glsl, mat, 0);
|
||||||
setup_glsl_shadow_uniforms(glslp, mat->passes[0].unitsUsed, lightsStart, lightsCount);
|
setup_glsl_shadow_uniforms(glsl, mat->passes[0].unitsUsed, lightsStart, lightsCount);
|
||||||
setup_glsl_lighting_uniforms(glslp, lightsStart, lightsCount);
|
setup_glsl_lighting_uniforms(glsl, lightsStart, lightsCount);
|
||||||
|
|
||||||
setup_glsl_model_uniforms(glslp, modelmat);
|
setup_glsl_model_uniforms(glsl, modelmat);
|
||||||
|
|
||||||
bind_mat_textures(mat, 0);
|
if(mat != lastMaterial) {
|
||||||
bind_shadow_texture(mat->passes[0].unitsUsed);
|
bind_mat_textures(mat, 0);
|
||||||
|
bind_shadow_texture(mat->passes[0].unitsUsed);
|
||||||
|
}
|
||||||
} else if(!k3IsCore) {
|
} else if(!k3IsCore) {
|
||||||
if(lastGLSLP && GLAD_GL_ARB_shading_language_100) {
|
if(lastGLSL && GLAD_GL_ARB_shading_language_100) {
|
||||||
glUseProgramObjectARB(0);
|
glUseProgramObjectARB(0);
|
||||||
}
|
}
|
||||||
lastGLSLP = NULL;
|
lastGLSL = 0;
|
||||||
|
|
||||||
if(lastVP != arbvp) {
|
if(lastVP != arbvp) {
|
||||||
if(lastVP && !arbvp) {
|
if(lastVP && !arbvp) {
|
||||||
@ -1569,6 +1538,12 @@ static void forward_subpass(mat4 projection, mat4 view, int transparent, int lig
|
|||||||
}
|
}
|
||||||
|
|
||||||
lastMaterial = mat;
|
lastMaterial = mat;
|
||||||
|
|
||||||
|
if(mat->passes[0].nocull) {
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
} else {
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
}
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
if(mat->passes[0].alphatest) {
|
if(mat->passes[0].alphatest) {
|
||||||
glEnable(GL_ALPHA_TEST);
|
glEnable(GL_ALPHA_TEST);
|
||||||
@ -1588,9 +1563,9 @@ static void forward_subpass(mat4 projection, mat4 view, int transparent, int lig
|
|||||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, mdl->vstore->gl);
|
glBindBufferARB(GL_ARRAY_BUFFER_ARB, mdl->vstore->gl);
|
||||||
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mdl->estore->gl);
|
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mdl->estore->gl);
|
||||||
|
|
||||||
if(glslp) {
|
if(glsl) {
|
||||||
enable_glsl_bones(glslp, mdl, bones);
|
enable_glsl_bones(glsl, mdl, bones);
|
||||||
enable_glsl_tangents(glslp, mdl);
|
enable_glsl_tangents(glsl, mdl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(k3IsSoftSkinning && bones) {
|
if(k3IsSoftSkinning && bones) {
|
||||||
@ -1598,27 +1573,23 @@ static void forward_subpass(mat4 projection, mat4 view, int transparent, int lig
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(isnanf(mat->passes[0].aabb)) {
|
if(isnanf(mat->passes[0].aabb)) {
|
||||||
enable_vertex_buffers(mdl, glslp);
|
enable_vertex_buffers(mdl, glsl);
|
||||||
|
|
||||||
glDrawElements(GL_TRIANGLES, mesh->idxNumber, GL_UNSIGNED_SHORT, (void*) (mesh->idxStart * 2));
|
glDrawElements(GL_TRIANGLES, mesh->idxNumber, GL_UNSIGNED_SHORT, (void*) (mesh->idxStart * 2));
|
||||||
|
|
||||||
disable_vertex_buffers(mdl, glslp);
|
disable_vertex_buffers(mdl, glsl);
|
||||||
} else {
|
} else {
|
||||||
push_aabb(mat, 0, mdl);
|
push_aabb(mat, 0, mdl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(glslp) {
|
if(glsl) {
|
||||||
disable_glsl_tangents(glslp, mdl);
|
disable_glsl_tangents(glsl, mdl);
|
||||||
disable_glsl_bones(mdl, glslp);
|
disable_glsl_bones(mdl, glsl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
k3EndTimer(timer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void k3PassForward(mat4 projection, mat4 cam) {
|
void k3PassForward(mat4 projection, mat4 cam) {
|
||||||
struct k3Timer timer = k3StartTimer("k3PassForward");
|
|
||||||
|
|
||||||
glm_mat4_copy(cam, CamMat);
|
glm_mat4_copy(cam, CamMat);
|
||||||
glm_mat4_copy(projection, ProjMat);
|
glm_mat4_copy(projection, ProjMat);
|
||||||
queuesort();
|
queuesort();
|
||||||
@ -1640,6 +1611,7 @@ void k3PassForward(mat4 projection, mat4 cam) {
|
|||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glEnable(GL_MULTISAMPLE);
|
glEnable(GL_MULTISAMPLE);
|
||||||
|
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
glFrontFace(GL_CCW);
|
glFrontFace(GL_CCW);
|
||||||
|
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
@ -1674,13 +1646,9 @@ void k3PassForward(mat4 projection, mat4 cam) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
k3EndTimer(timer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void k3PassDepthOnly(mat4 projection, mat4 cam, int clear, int cull) {
|
void k3PassDepthOnly(mat4 projection, mat4 cam, int clear, int cull) {
|
||||||
struct k3Timer timer = k3StartTimer("k3PassDepthOnly");
|
|
||||||
|
|
||||||
glm_mat4_copy(cam, CamMat);
|
glm_mat4_copy(cam, CamMat);
|
||||||
glm_mat4_copy(projection, ProjMat);
|
glm_mat4_copy(projection, ProjMat);
|
||||||
queuesort();
|
queuesort();
|
||||||
@ -1720,7 +1688,7 @@ void k3PassDepthOnly(mat4 projection, mat4 cam, int clear, int cull) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GLuint lastVP = 0;
|
GLuint lastVP = 0;
|
||||||
struct k3GLSLP *lastGLSLP = NULL;
|
GLhandleARB lastGLSL = -1;
|
||||||
|
|
||||||
for(size_t rble = 0; rble < renderQueueSize; rble++) {
|
for(size_t rble = 0; rble < renderQueueSize; rble++) {
|
||||||
struct k3Mdl *mdl = renderQueue[rble].mdl;
|
struct k3Mdl *mdl = renderQueue[rble].mdl;
|
||||||
@ -1737,35 +1705,34 @@ void k3PassDepthOnly(mat4 projection, mat4 cam, int clear, int cull) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct k3GLSLP *glslp = renderQueue[rble].glslp;
|
GLhandleARB glsl = renderQueue[rble].glsl;
|
||||||
GLuint arbvp = renderQueue[rble].arbvp;
|
GLuint arbvp = renderQueue[rble].arbvp;
|
||||||
|
|
||||||
if(glslp) {
|
if(glsl) {
|
||||||
if(lastGLSLP != glslp) {
|
if(lastGLSL != glsl) {
|
||||||
if(k3IsCore)
|
if(k3IsCore)
|
||||||
glUseProgram(glslp->handle);
|
glUseProgram(glsl);
|
||||||
else
|
else
|
||||||
glUseProgramObjectARB(glslp->handle);
|
glUseProgramObjectARB(glsl);
|
||||||
|
|
||||||
lastGLSLP = glslp;
|
lastGLSL = glsl;
|
||||||
|
|
||||||
setup_glsl_globals(glslp, view);
|
setup_glsl_globals(glsl, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_core_projection(glslp, projection);
|
setup_core_projection(glsl, projection);
|
||||||
|
|
||||||
bind_mat_textures(mat, 0);
|
setup_glsl_mat_uniforms(glsl, mat, 0);
|
||||||
setup_glsl_mat_uniforms(glslp, mat, 0);
|
|
||||||
|
|
||||||
setup_glsl_model_uniforms(glslp, modelmat);
|
setup_glsl_model_uniforms(glsl, modelmat);
|
||||||
} else if(!k3IsCore) {
|
} else if(!k3IsCore) {
|
||||||
if(lastGLSLP && GLAD_GL_ARB_shading_language_100) {
|
if(lastGLSL && GLAD_GL_ARB_shading_language_100) {
|
||||||
if(k3IsCore)
|
if(k3IsCore)
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
else
|
else
|
||||||
glUseProgramObjectARB(0);
|
glUseProgramObjectARB(0);
|
||||||
}
|
}
|
||||||
lastGLSLP = NULL;
|
lastGLSL = 0;
|
||||||
|
|
||||||
if(arbvp != lastVP) {
|
if(arbvp != lastVP) {
|
||||||
if(arbvp && !lastVP) {
|
if(arbvp && !lastVP) {
|
||||||
@ -1789,20 +1756,11 @@ void k3PassDepthOnly(mat4 projection, mat4 cam, int clear, int cull) {
|
|||||||
glLoadMatrixf((float*) modelview);
|
glLoadMatrixf((float*) modelview);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!k3IsCore) {
|
|
||||||
if(mat->passes[0].alphatest) {
|
|
||||||
glEnable(GL_ALPHA_TEST);
|
|
||||||
glAlphaFunc(GL_GREATER, 0.9f);
|
|
||||||
} else {
|
|
||||||
glDisable(GL_ALPHA_TEST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, mdl->vstore->gl);
|
glBindBufferARB(GL_ARRAY_BUFFER_ARB, mdl->vstore->gl);
|
||||||
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mdl->estore->gl);
|
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mdl->estore->gl);
|
||||||
|
|
||||||
if(glslp) {
|
if(glsl) {
|
||||||
enable_glsl_bones(glslp, mdl, bones);
|
enable_glsl_bones(glsl, mdl, bones);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(k3IsSoftSkinning && bones) {
|
if(k3IsSoftSkinning && bones) {
|
||||||
@ -1810,23 +1768,21 @@ void k3PassDepthOnly(mat4 projection, mat4 cam, int clear, int cull) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(isnanf(mat->passes[0].aabb)) {
|
if(isnanf(mat->passes[0].aabb)) {
|
||||||
enable_vertex_buffers(mdl, glslp);
|
enable_vertex_buffers(mdl, glsl);
|
||||||
|
|
||||||
glDrawElements(GL_TRIANGLES, mesh->idxNumber, GL_UNSIGNED_SHORT, (void*) (mesh->idxStart * 2));
|
glDrawElements(GL_TRIANGLES, mesh->idxNumber, GL_UNSIGNED_SHORT, (void*) (mesh->idxStart * 2));
|
||||||
|
|
||||||
disable_vertex_buffers(mdl, glslp);
|
disable_vertex_buffers(mdl, glsl);
|
||||||
} else {
|
} else {
|
||||||
push_aabb(mat, 0, mdl);
|
push_aabb(mat, 0, mdl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(glslp) {
|
if(glsl) {
|
||||||
disable_glsl_bones(mdl, glslp);
|
disable_glsl_bones(mdl, glsl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glFrontFace(GL_CCW);
|
glFrontFace(GL_CCW);
|
||||||
|
|
||||||
k3EndTimer(timer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void split_frustum(mat4 proj, int cascades, mat4 croppeds[]) {
|
static void split_frustum(mat4 proj, int cascades, mat4 croppeds[]) {
|
||||||
@ -2049,8 +2005,8 @@ static void pass_irregular(int passnum, mat4 mainproj, mat4 maincam, mat4 lightp
|
|||||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, mdl->vstore->gl);
|
glBindBufferARB(GL_ARRAY_BUFFER_ARB, mdl->vstore->gl);
|
||||||
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mdl->estore->gl);
|
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mdl->estore->gl);
|
||||||
|
|
||||||
if(glslp) {
|
if(glsl) {
|
||||||
enable_glsl_bones(glslp, mdl, bones);
|
enable_glsl_bones(glsl, mdl, bones);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(k3IsSoftSkinning && bones) {
|
if(k3IsSoftSkinning && bones) {
|
||||||
@ -2058,17 +2014,17 @@ static void pass_irregular(int passnum, mat4 mainproj, mat4 maincam, mat4 lightp
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(isnanf(mat->passes[0].aabb)) {
|
if(isnanf(mat->passes[0].aabb)) {
|
||||||
enable_vertex_buffers(mdl, glslp);
|
enable_vertex_buffers(mdl, glsl);
|
||||||
|
|
||||||
glDrawElements(GL_TRIANGLES, mesh->idxNumber, GL_UNSIGNED_SHORT, (void*) (mesh->idxStart * 2));
|
glDrawElements(GL_TRIANGLES, mesh->idxNumber, GL_UNSIGNED_SHORT, (void*) (mesh->idxStart * 2));
|
||||||
|
|
||||||
disable_vertex_buffers(mdl, glslp);
|
disable_vertex_buffers(mdl, glsl);
|
||||||
} else {
|
} else {
|
||||||
push_aabb(mat, 0, mdl);
|
push_aabb(mat, 0, mdl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(glslp) {
|
if(glsl) {
|
||||||
disable_glsl_bones(mdl, glslp);
|
disable_glsl_bones(mdl, glsl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2194,9 +2150,7 @@ void k3PassIrregular(struct k3Offscreen *mainview, mat4 mainproj, mat4 maincam)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Constructs shadowmap atlas, saves `offscr` for own use
|
// Constructs shadowmap atlas, saves `offscr` for own use
|
||||||
void k3PassShadowmap(mat4 projection, mat4 cam, struct k3Offscreen *offscr, float cellSizeLimit) {
|
void k3PassShadowmap(mat4 projection, mat4 cam, struct k3Offscreen *offscr) {
|
||||||
struct k3Timer timer = k3StartTimer("k3PassShadowmap");
|
|
||||||
|
|
||||||
glm_mat4_copy(projection, ProjMat);
|
glm_mat4_copy(projection, ProjMat);
|
||||||
glm_mat4_copy(cam, CamMat);
|
glm_mat4_copy(cam, CamMat);
|
||||||
|
|
||||||
@ -2240,10 +2194,6 @@ void k3PassShadowmap(mat4 projection, mat4 cam, struct k3Offscreen *offscr, floa
|
|||||||
uint16_t sz = k3TexSzX(offscr->depth);
|
uint16_t sz = k3TexSzX(offscr->depth);
|
||||||
float cellSz = (float) sz / cellsPerDimension;
|
float cellSz = (float) sz / cellsPerDimension;
|
||||||
|
|
||||||
if(cellSizeLimit > 0) {
|
|
||||||
cellSz = fminf(cellSizeLimit, cellSz);
|
|
||||||
}
|
|
||||||
|
|
||||||
k3BeginOffscreen(offscr);
|
k3BeginOffscreen(offscr);
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for(size_t li = 0; li < LightCount; li++) {
|
for(size_t li = 0; li < LightCount; li++) {
|
||||||
@ -2281,8 +2231,6 @@ void k3PassShadowmap(mat4 projection, mat4 cam, struct k3Offscreen *offscr, floa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
k3EndOffscreen(offscr);
|
k3EndOffscreen(offscr);
|
||||||
|
|
||||||
k3EndTimer(timer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void k3BatchClear() {
|
void k3BatchClear() {
|
||||||
@ -2749,8 +2697,6 @@ struct k3GLSLG *k3ShaderGLSLG(const char *src_, const char*(*ldr)(const char *fn
|
|||||||
struct k3GLSLP *k3ProgramGLSL(struct k3GLSLV *vs, struct k3GLSLF *fs, struct k3GLSLG *gs) {
|
struct k3GLSLP *k3ProgramGLSL(struct k3GLSLV *vs, struct k3GLSLF *fs, struct k3GLSLG *gs) {
|
||||||
GLhandleARB prog;
|
GLhandleARB prog;
|
||||||
|
|
||||||
struct k3GLSLP *ret = calloc(1, sizeof(*ret));
|
|
||||||
|
|
||||||
if(!k3IsCore) {
|
if(!k3IsCore) {
|
||||||
prog = glCreateProgramObjectARB();
|
prog = glCreateProgramObjectARB();
|
||||||
|
|
||||||
@ -2780,31 +2726,13 @@ struct k3GLSLP *k3ProgramGLSL(struct k3GLSLV *vs, struct k3GLSLF *fs, struct k3G
|
|||||||
GLint uniformCount;
|
GLint uniformCount;
|
||||||
glGetObjectParameterivARB(prog, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &uniformCount);
|
glGetObjectParameterivARB(prog, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &uniformCount);
|
||||||
|
|
||||||
ret->handle = prog;
|
|
||||||
ret->ucount = uniformCount;
|
|
||||||
ret->uloc = calloc(uniformCount, sizeof(*ret->uloc));
|
|
||||||
ret->uname = calloc(uniformCount, sizeof(*ret->uname));
|
|
||||||
|
|
||||||
for(i = 0; i < uniformCount; i++) {
|
for(i = 0; i < uniformCount; i++) {
|
||||||
int size;
|
int size;
|
||||||
int type;
|
int type;
|
||||||
glGetActiveUniformARB(prog, i, maxLength, NULL, &size, &type, name);
|
glGetActiveUniformARB(prog, i, maxLength, NULL, &size, &type, name);
|
||||||
|
|
||||||
if(strchr(name, '[')) {
|
k3Log(k3_DEBUG, "%i %s", size, name);
|
||||||
*strchr(name, '[') = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t idx = komihash(name, strlen(name), 0);
|
|
||||||
for(size_t iter = 0; iter < uniformCount; iter++, idx++) {
|
|
||||||
idx = idx % uniformCount;
|
|
||||||
if(ret->uname[idx] == NULL) {
|
|
||||||
ret->uname[idx] = strdup(name);
|
|
||||||
ret->uloc[idx] = glGetUniformLocationARB(prog, name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
k3Log(k3_DEBUG, "%i %s @ %i", size, name, ret->uloc[idx]);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
prog = glCreateProgram();
|
prog = glCreateProgram();
|
||||||
@ -2835,47 +2763,20 @@ struct k3GLSLP *k3ProgramGLSL(struct k3GLSLV *vs, struct k3GLSLF *fs, struct k3G
|
|||||||
GLint uniformCount;
|
GLint uniformCount;
|
||||||
glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &uniformCount);
|
glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &uniformCount);
|
||||||
|
|
||||||
ret->handle = prog;
|
|
||||||
ret->ucount = uniformCount;
|
|
||||||
ret->uloc = calloc(uniformCount, sizeof(*ret->uloc));
|
|
||||||
ret->uname = calloc(uniformCount, sizeof(*ret->uname));
|
|
||||||
|
|
||||||
for(i = 0; i < uniformCount; i++) {
|
for(i = 0; i < uniformCount; i++) {
|
||||||
int size;
|
int size;
|
||||||
int type;
|
int type;
|
||||||
glGetActiveUniform(prog, i, maxLength, NULL, &size, &type, name);
|
glGetActiveUniform(prog, i, maxLength, NULL, &size, &type, name);
|
||||||
|
|
||||||
if(strchr(name, '[')) {
|
k3Log(k3_DEBUG, "%i %s", size, name);
|
||||||
*strchr(name, '[') = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t idx = komihash(name, strlen(name), 0);
|
|
||||||
for(size_t iter = 0; iter < uniformCount; iter++, idx++) {
|
|
||||||
idx = idx % uniformCount;
|
|
||||||
if(ret->uname[idx] == NULL) {
|
|
||||||
ret->uname[idx] = strdup(name);
|
|
||||||
ret->uloc[idx] = glGetUniformLocation(prog, name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
k3Log(k3_DEBUG, "%i %s @ %i", size, name, ret->uloc[idx]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return (struct k3GLSLP*) (uintptr_t) prog;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t k3ProgramGetUId(struct k3GLSLP *p, const char *key) {
|
uint16_t k3ProgramGetUId(struct k3GLSLP *p, const char *key) {
|
||||||
uint64_t idx = komihash(key, strlen(key), 0);
|
return glGetUniformLocationARB(GL_FROM_K3GLSL(p), key);
|
||||||
for(size_t i = 0; i < p->ucount; i++, idx++) {
|
|
||||||
idx = idx % p->ucount;
|
|
||||||
|
|
||||||
if(!strcmp(p->uname[idx], key)) {
|
|
||||||
return p->uloc[idx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct k3ARBVP *k3ProgramARBVP(const char *src) {
|
struct k3ARBVP *k3ProgramARBVP(const char *src) {
|
||||||
@ -3178,29 +3079,3 @@ uint16_t k3TexSzMax() {
|
|||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct k3Timer *k3Timers;
|
|
||||||
size_t k3TimerCount;
|
|
||||||
void k3Update() {
|
|
||||||
for(size_t ti = 0; ti < k3TimerCount;) {
|
|
||||||
struct k3Timer *t = &k3Timers[ti];
|
|
||||||
|
|
||||||
GLint b1 = 0, b2 = 0;
|
|
||||||
glGetQueryObjectiv(t->qStart, GL_QUERY_RESULT_AVAILABLE, &b1);
|
|
||||||
glGetQueryObjectiv(t->qEnd, GL_QUERY_RESULT_AVAILABLE, &b2);
|
|
||||||
|
|
||||||
if(b1 && b2) {
|
|
||||||
uint64_t t1, t2;
|
|
||||||
glGetQueryObjectui64v(t->qStart, GL_QUERY_RESULT, &t1);
|
|
||||||
glGetQueryObjectui64v(t->qEnd, GL_QUERY_RESULT, &t2);
|
|
||||||
|
|
||||||
k3Log(k3_TRACE, "Routine %s took %lu us", t->name, (t2 - t1) / 1000);
|
|
||||||
|
|
||||||
glDeleteQueries(2, (GLuint*) t);
|
|
||||||
memmove(t, t + 1, sizeof(*t) * (k3TimerCount - ti - 1));
|
|
||||||
k3TimerCount--;
|
|
||||||
} else {
|
|
||||||
ti++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
6
src/k3.h
6
src/k3.h
@ -40,7 +40,7 @@ struct k3GLSLG *k3ShaderGLSLG(const char *src_, const char*(*ldr)(const char *fn
|
|||||||
|
|
||||||
struct k3GLSLP;
|
struct k3GLSLP;
|
||||||
struct k3GLSLP *k3ProgramGLSL(struct k3GLSLV*, struct k3GLSLF*, struct k3GLSLG*);
|
struct k3GLSLP *k3ProgramGLSL(struct k3GLSLV*, struct k3GLSLF*, struct k3GLSLG*);
|
||||||
int16_t k3ProgramGetUId(struct k3GLSLP*, const char *key);
|
uint16_t k3ProgramGetUId(struct k3GLSLP*, const char *key);
|
||||||
|
|
||||||
struct k3ARBVP;
|
struct k3ARBVP;
|
||||||
struct k3ARBVP *k3ProgramARBVP(const char *src);
|
struct k3ARBVP *k3ProgramARBVP(const char *src);
|
||||||
@ -185,7 +185,7 @@ void k3BatchClear();
|
|||||||
void k3PassForward(mat4 projection, mat4 cam);
|
void k3PassForward(mat4 projection, mat4 cam);
|
||||||
void k3PassDepthOnly(mat4 projection, mat4 cam, int clear, int cull);
|
void k3PassDepthOnly(mat4 projection, mat4 cam, int clear, int cull);
|
||||||
|
|
||||||
void k3PassShadowmap(mat4 projection, mat4 cam, struct k3Offscreen *offscr, float cellSizeLimit);
|
void k3PassShadowmap(mat4 projection, mat4 cam, struct k3Offscreen *offscr);
|
||||||
|
|
||||||
struct k3Offscreen;
|
struct k3Offscreen;
|
||||||
struct k3Offscreen *k3OffscreenCreateMultisampled(struct k3Tex *diffuse, struct k3Tex *depth, uint8_t samples);
|
struct k3Offscreen *k3OffscreenCreateMultisampled(struct k3Tex *diffuse, struct k3Tex *depth, uint8_t samples);
|
||||||
@ -205,7 +205,7 @@ int k3CubemapTraditional(struct k3Tex*, mat4 proj, mat4 cam);
|
|||||||
void k3SetTime(float t);
|
void k3SetTime(float t);
|
||||||
|
|
||||||
enum k3LogLevel {
|
enum k3LogLevel {
|
||||||
k3_TRACE, k3_DEBUG, k3_INFO, k3_WARN, k3_ERR
|
k3_DEBUG, k3_INFO, k3_WARN, k3_ERR
|
||||||
};
|
};
|
||||||
typedef void(*k3LogCallback)(enum k3LogLevel, const char *str, size_t len);
|
typedef void(*k3LogCallback)(enum k3LogLevel, const char *str, size_t len);
|
||||||
void k3SetLogCallback(k3LogCallback);
|
void k3SetLogCallback(k3LogCallback);
|
||||||
|
|||||||
@ -7,13 +7,12 @@
|
|||||||
#include<cglm/vec2.h>
|
#include<cglm/vec2.h>
|
||||||
#include<cglm/frustum.h>
|
#include<cglm/frustum.h>
|
||||||
#include<cglm/cam.h>
|
#include<cglm/cam.h>
|
||||||
#include<string.h>
|
|
||||||
|
|
||||||
#define GL_FROM_K3TEX(k3t) ((k3t) ? (k3t)->tex : 0)
|
#define GL_FROM_K3TEX(k3t) ((k3t) ? (k3t)->tex : 0)
|
||||||
#define GL_FROM_K3MARCHER(k3m) ((GLuint) (uintptr_t) (k3m))
|
#define GL_FROM_K3MARCHER(k3m) ((GLuint) (uintptr_t) (k3m))
|
||||||
#define GL_FROM_K3ARBVP(k3m) ((GLuint) (uintptr_t) (k3m))
|
#define GL_FROM_K3ARBVP(k3m) ((GLuint) (uintptr_t) (k3m))
|
||||||
#define GL_FROM_K3ARBFP(k3m) ((GLuint) (uintptr_t) (k3m))
|
#define GL_FROM_K3ARBFP(k3m) ((GLuint) (uintptr_t) (k3m))
|
||||||
#define GL_FROM_K3GLSL(k3m) (((struct k3GLSLP*) k3m)->handle)
|
#define GL_FROM_K3GLSL(k3m) ((GLuint) (uintptr_t) (k3m))
|
||||||
|
|
||||||
extern bool k3IsCore;
|
extern bool k3IsCore;
|
||||||
|
|
||||||
@ -85,52 +84,3 @@ struct k3Mdl {
|
|||||||
|
|
||||||
const char *debugname;
|
const char *debugname;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct k3GLSLP {
|
|
||||||
GLhandleARB handle;
|
|
||||||
|
|
||||||
size_t ucount;
|
|
||||||
char **uname;
|
|
||||||
GLint *uloc;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct k3Timer {
|
|
||||||
GLuint qStart;
|
|
||||||
GLuint qEnd;
|
|
||||||
char name[64];
|
|
||||||
};
|
|
||||||
extern struct k3Timer *k3Timers;
|
|
||||||
extern size_t k3TimerCount;
|
|
||||||
static inline struct k3Timer k3StartTimer(char *name) {
|
|
||||||
struct k3Timer t = {};
|
|
||||||
|
|
||||||
if(!GLAD_GL_ARB_timer_query) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
glGenQueries(2, (GLuint*) &t);
|
|
||||||
|
|
||||||
strncpy(t.name, name, sizeof(t.name));
|
|
||||||
|
|
||||||
glQueryCounter(t.qStart, GL_TIMESTAMP);
|
|
||||||
|
|
||||||
if(GLAD_GL_KHR_debug) {
|
|
||||||
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
static inline void k3EndTimer(struct k3Timer t) {
|
|
||||||
if(!GLAD_GL_ARB_timer_query) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
glQueryCounter(t.qEnd, GL_TIMESTAMP);
|
|
||||||
|
|
||||||
if(GLAD_GL_KHR_debug) {
|
|
||||||
glPopDebugGroup();
|
|
||||||
}
|
|
||||||
|
|
||||||
k3Timers = realloc(k3Timers, sizeof(*k3Timers) * (k3TimerCount + 1));
|
|
||||||
k3Timers[k3TimerCount++] = t;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -14,7 +14,6 @@ struct S {
|
|||||||
|
|
||||||
static struct k3Tex *activeTex;
|
static struct k3Tex *activeTex;
|
||||||
static float activeBorderRadius;
|
static float activeBorderRadius;
|
||||||
static float activeMinAlpha;
|
|
||||||
|
|
||||||
static size_t SCount, SCapacity;
|
static size_t SCount, SCapacity;
|
||||||
static struct S *S;
|
static struct S *S;
|
||||||
@ -49,7 +48,6 @@ void k3BatchInit() {
|
|||||||
"uniform sampler2D u_tex;\n"
|
"uniform sampler2D u_tex;\n"
|
||||||
"uniform float u_texuse;\n"
|
"uniform float u_texuse;\n"
|
||||||
"uniform float u_borderradius;\n"
|
"uniform float u_borderradius;\n"
|
||||||
"uniform float u_minalpha;\n"
|
|
||||||
"in vec2 v_uv;\n"
|
"in vec2 v_uv;\n"
|
||||||
"in vec4 v_color;\n"
|
"in vec4 v_color;\n"
|
||||||
"in vec2 v_size;\n"
|
"in vec2 v_size;\n"
|
||||||
@ -62,11 +60,7 @@ void k3BatchInit() {
|
|||||||
" if(length(c) > u_borderradius) {\n"
|
" if(length(c) > u_borderradius) {\n"
|
||||||
" discard;\n"
|
" discard;\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
" vec4 col = texture2D(u_tex, v_uv);\n"
|
" fragcolor = mix(vec4(1, 1, 1, 1), texture2D(u_tex, v_uv), u_texuse) * v_color;\n"
|
||||||
" if(u_minalpha > 0.0) {\n"
|
|
||||||
" col.a = clamp((col.a - u_minalpha + 0.1) / 0.1, 0.0, 1.0);\n"
|
|
||||||
" }\n"
|
|
||||||
" fragcolor = mix(vec4(1, 1, 1, 1), col, u_texuse) * v_color;\n"
|
|
||||||
"}\n"
|
"}\n"
|
||||||
, NULL), NULL);
|
, NULL), NULL);
|
||||||
|
|
||||||
@ -76,12 +70,11 @@ void k3BatchInit() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void k3BatchAdd(struct k3Tex *tex, struct k3RectF src, struct k3RectF dst, float rot, vec4 color, float borderRadius, float minAlpha) {
|
void k3BatchAdd(struct k3Tex *tex, struct k3RectF src, struct k3RectF dst, float rot, vec4 color, float borderRadius) {
|
||||||
if(activeTex != tex || borderRadius != activeBorderRadius || minAlpha != activeMinAlpha) {
|
if(activeTex != tex || borderRadius != activeBorderRadius) {
|
||||||
k3BatchFlush();
|
k3BatchFlush();
|
||||||
activeTex = tex;
|
activeTex = tex;
|
||||||
activeBorderRadius = borderRadius;
|
activeBorderRadius = borderRadius;
|
||||||
activeMinAlpha = minAlpha;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(SCount == SCapacity) {
|
if(SCount == SCapacity) {
|
||||||
@ -125,6 +118,9 @@ void k3BatchFlush() {
|
|||||||
glDisable(GL_FRAGMENT_PROGRAM_ARB);
|
glDisable(GL_FRAGMENT_PROGRAM_ARB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
if(activeTex) {
|
if(activeTex) {
|
||||||
@ -136,12 +132,7 @@ void k3BatchFlush() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(k3IsCore) {
|
if(k3IsCore) {
|
||||||
glEnable(GL_BLEND);
|
glUseProgram((GLuint) coreProg);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
|
|
||||||
GLuint handle = GL_FROM_K3GLSL(coreProg);
|
|
||||||
|
|
||||||
glUseProgram(handle);
|
|
||||||
glUniform2f(coreUResolution, ResolutionX, ResolutionY);
|
glUniform2f(coreUResolution, ResolutionX, ResolutionY);
|
||||||
|
|
||||||
float *farr = alloca(SCount * 60 * sizeof(*farr));
|
float *farr = alloca(SCount * 60 * sizeof(*farr));
|
||||||
@ -220,14 +211,14 @@ void k3BatchFlush() {
|
|||||||
glBindBufferARB(GL_ARRAY_BUFFER_ARB, coreVBO);
|
glBindBufferARB(GL_ARRAY_BUFFER_ARB, coreVBO);
|
||||||
glBufferDataARB(GL_ARRAY_BUFFER_ARB, SCount * 60 * sizeof(*farr), farr, GL_DYNAMIC_DRAW);
|
glBufferDataARB(GL_ARRAY_BUFFER_ARB, SCount * 60 * sizeof(*farr), farr, GL_DYNAMIC_DRAW);
|
||||||
|
|
||||||
glUniform1f(k3ProgramGetUId(coreProg, "u_texuse"), !!activeTex);
|
glUniform1f(glGetUniformLocation((GLuint) coreProg, "u_texuse"), !!activeTex);
|
||||||
glUniform1f(k3ProgramGetUId(coreProg, "u_borderradius"), activeBorderRadius);
|
|
||||||
glUniform1f(k3ProgramGetUId(coreProg, "u_minalpha"), activeMinAlpha);
|
|
||||||
|
|
||||||
GLint aPos = glGetAttribLocation(handle, "a_pos");
|
glUniform1f(glGetUniformLocation((GLuint) coreProg, "u_borderradius"), activeBorderRadius);
|
||||||
GLint aUv = glGetAttribLocation(handle, "a_uv");
|
|
||||||
GLint aColor = glGetAttribLocation(handle, "a_color");
|
GLint aPos = glGetAttribLocation((GLuint) coreProg, "a_pos");
|
||||||
GLint aSize = glGetAttribLocation(handle, "a_size");
|
GLint aUv = glGetAttribLocation((GLuint) coreProg, "a_uv");
|
||||||
|
GLint aColor = glGetAttribLocation((GLuint) coreProg, "a_color");
|
||||||
|
GLint aSize = glGetAttribLocation((GLuint) coreProg, "a_size");
|
||||||
|
|
||||||
glEnableVertexAttribArray(aPos);
|
glEnableVertexAttribArray(aPos);
|
||||||
glEnableVertexAttribArray(aUv);
|
glEnableVertexAttribArray(aUv);
|
||||||
@ -250,16 +241,6 @@ void k3BatchFlush() {
|
|||||||
glUseProgramObjectARB(0);
|
glUseProgramObjectARB(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(activeMinAlpha) {
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
} else {
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
}
|
|
||||||
|
|
||||||
glEnable(GL_ALPHA_TEST);
|
|
||||||
glAlphaFunc(GL_GREATER, activeMinAlpha);
|
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
struct S *s = S;
|
struct S *s = S;
|
||||||
for(size_t i = 0; i < SCount; i++) {
|
for(size_t i = 0; i < SCount; i++) {
|
||||||
@ -281,8 +262,6 @@ void k3BatchFlush() {
|
|||||||
}
|
}
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
glDisable(GL_ALPHA_TEST);
|
|
||||||
|
|
||||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ struct k3RectF {
|
|||||||
float h;
|
float h;
|
||||||
};
|
};
|
||||||
|
|
||||||
void k3BatchAdd(struct k3Tex *tex, struct k3RectF src, struct k3RectF dst, float rot, vec4 color, float borderRadius, float minAlpha);
|
void k3BatchAdd(struct k3Tex *tex, struct k3RectF src, struct k3RectF dst, float rot, vec4 color, float borderRadius);
|
||||||
void k3BatchFlush();
|
void k3BatchFlush();
|
||||||
|
|
||||||
void k3BatchSetResolution(float w, float h);
|
void k3BatchSetResolution(float w, float h);
|
||||||
|
|||||||
138
src/k3font.c
138
src/k3font.c
@ -3,60 +3,72 @@
|
|||||||
#include"k3batch.h"
|
#include"k3batch.h"
|
||||||
#include<string.h>
|
#include<string.h>
|
||||||
#include"gl.h"
|
#include"gl.h"
|
||||||
#include<freetype/freetype.h>
|
|
||||||
|
|
||||||
#define GLCA_IMPLEMENTATION
|
|
||||||
#include"glyphcache/glca.h"
|
|
||||||
|
|
||||||
#include"k3_internal.h"
|
|
||||||
|
|
||||||
static _Thread_local FT_Library ftlib;
|
|
||||||
|
|
||||||
struct k3Font *k3FontCreate() {
|
struct k3Font *k3FontCreate() {
|
||||||
if(!ftlib) {
|
|
||||||
assert(FT_Init_FreeType(&ftlib) == 0);
|
|
||||||
FT_Property_Set(ftlib, "sdf", "spread", &(int) {64});
|
|
||||||
}
|
|
||||||
|
|
||||||
struct k3Font *ret = calloc(sizeof(*ret), 1);
|
struct k3Font *ret = calloc(sizeof(*ret), 1);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void my_set_image(struct GlyphCache *gc, int x, int y, int w, int h, const void *buf) {
|
static int cmpglyph(const void *a, const void *b) {
|
||||||
struct k3Font *this = gc->userdata;
|
return *(const uint32_t*) a - *(const uint32_t*) b;
|
||||||
|
}
|
||||||
for(size_t row = 0; row < h; row++) {
|
|
||||||
memcpy(&this->atlasCPU[this->atlasSize * (y + row) + x], buf + w * row, w);
|
int k3FontLoad(struct k3Font *this, const uint8_t *buf, size_t len, k3FontTexLoader texldr) {
|
||||||
|
if(*(uint32_t*) buf != 0x03464D42) {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//k3TexUpdateSub(this->atlas, 0, x, y, w, h, buf);
|
const uint8_t *end = buf + len;
|
||||||
k3TexUpdate(this->atlas, k3_ALPHA, 0, this->atlasSize, this->atlasSize, this->atlasCPU);
|
|
||||||
}
|
|
||||||
void my_get_image(struct GlyphCache *gc, int x, int y, int w, int h, void *buf) {
|
|
||||||
struct k3Font *this = gc->userdata;
|
|
||||||
|
|
||||||
for(size_t row = 0; row < h; row++) {
|
buf += 4;
|
||||||
memcpy(buf + w * row, &this->atlasCPU[this->atlasSize * (y + row)], w);
|
|
||||||
|
uint16_t pages = 0;
|
||||||
|
|
||||||
|
while(buf + 5 < end) {
|
||||||
|
uint8_t blockType = *buf;
|
||||||
|
uint32_t blockSize = *(uint32_t*) (buf + 1);
|
||||||
|
buf += 5;
|
||||||
|
|
||||||
|
if(blockType == 1) { //Info block
|
||||||
|
buf += 14;
|
||||||
|
while(*buf) buf++;
|
||||||
|
buf++;
|
||||||
|
} else if(blockType == 2) { //Common block
|
||||||
|
this->lineScale = 1.f / *(uint16_t*) buf;
|
||||||
|
buf += 2;
|
||||||
|
this->baseline = *(uint16_t*) buf;
|
||||||
|
buf += 2;
|
||||||
|
this->texW = *(uint16_t*) buf;
|
||||||
|
buf += 2;
|
||||||
|
this->texH = *(uint16_t*) buf;
|
||||||
|
buf += 2;
|
||||||
|
pages = *(uint16_t*) buf;
|
||||||
|
buf += 7;
|
||||||
|
} else if(blockType == 3) { //Pages block
|
||||||
|
if(pages == 0) return 0;
|
||||||
|
|
||||||
|
this->pageCount = pages;
|
||||||
|
this->pages = malloc(sizeof(*this->pages) * this->pageCount);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < this->pageCount; i++) {
|
||||||
|
this->pages[i] = texldr(this, buf);
|
||||||
|
buf += strlen(buf) + 1;
|
||||||
|
}
|
||||||
|
} else if(blockType == 4) { //Chars block
|
||||||
|
size_t num = blockSize / 20;
|
||||||
|
|
||||||
|
this->glyphs = calloc(sizeof(*this->glyphs), this->glyphCount = num);
|
||||||
|
|
||||||
|
memcpy(this->glyphs, buf, num * 20);
|
||||||
|
|
||||||
|
qsort(this->glyphs, num, sizeof(*this->glyphs), cmpglyph);
|
||||||
|
|
||||||
|
buf += blockSize;
|
||||||
|
} else if(blockType == 5) { //Kerning block
|
||||||
|
// Ignore kerning for now
|
||||||
|
buf += blockSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
void my_fill_custom_data(struct GlyphCache *gc, FT_GlyphSlot slot, GlyphCacheGlyph *glyph) {
|
|
||||||
glyph->data.xAdvance = slot->metrics.horiAdvance / 64.f;
|
|
||||||
glyph->data.xOffset = slot->metrics.horiBearingX / 64.f;
|
|
||||||
glyph->data.yOffset = slot->metrics.horiBearingY / 64.f;
|
|
||||||
}
|
|
||||||
int k3FontLoad(struct k3Font *this, const char *fn) {
|
|
||||||
this->atlasSize = k3TexSzMax() / 4;
|
|
||||||
this->atlas = k3TexCreate(k3_ALPHA);
|
|
||||||
this->atlasCPU = malloc(this->atlasSize * this->atlasSize);
|
|
||||||
k3TexUpdate(this->atlas, k3_ALPHA, 0, this->atlasSize, this->atlasSize, NULL);
|
|
||||||
|
|
||||||
this->fontPixelSize = this->atlasSize / 16;
|
|
||||||
|
|
||||||
assert(FT_New_Face(ftlib, fn, 0, &this->ftface) == 0);
|
|
||||||
FT_Select_Charmap(this->ftface, FT_ENCODING_UNICODE);
|
|
||||||
FT_Set_Pixel_Sizes(this->ftface, this->fontPixelSize, 0);
|
|
||||||
|
|
||||||
glca_init(&this->glca, this->ftface, this->atlasSize, this->atlasSize, this, my_set_image, my_get_image, my_fill_custom_data);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -105,16 +117,16 @@ void k3FontSz(struct k3Font *this, float sz, const char *txt, float wall, struct
|
|||||||
y += sz;
|
y += sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GlyphCacheGlyph *g = glca_request(&this->glca, cp);
|
struct k3FontGlyph *g = k3FontGetGlyph(this, cp);
|
||||||
|
|
||||||
if(!g) continue;
|
if(!g) continue;
|
||||||
|
|
||||||
if(x + sz * g->w / this->fontPixelSize > wall) {
|
if(x + g->width * this->lineScale * sz > wall) {
|
||||||
x = 0;
|
x = 0;
|
||||||
y += sz;
|
y += sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
x += sz * g->data.xAdvance / this->fontPixelSize;
|
x += g->xadvance * this->lineScale * sz;
|
||||||
maxX = fmaxf(maxX, x);
|
maxX = fmaxf(maxX, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,16 +153,16 @@ void k3FontDraw(struct k3Font *this, float xStart, float yStart, float sz, const
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GlyphCacheGlyph *g = glca_request(&this->glca, cp2);
|
struct k3FontGlyph *g = k3FontGetGlyph(this, cp2);
|
||||||
if(g) {
|
if(g) {
|
||||||
if(lineWidth + sz * g->w / this->fontPixelSize > wall) {
|
if(lineWidth + g->width * this->lineScale * sz > wall) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lineLength++;
|
lineLength++;
|
||||||
if(g) {
|
if(g) {
|
||||||
lineWidth += sz * g->data.xAdvance / this->fontPixelSize;
|
lineWidth += g->xadvance * this->lineScale * sz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,24 +182,24 @@ void k3FontDraw(struct k3Font *this, float xStart, float yStart, float sz, const
|
|||||||
for(size_t i = 0; i < lineLength; i++) {
|
for(size_t i = 0; i < lineLength; i++) {
|
||||||
uint32_t cp = read_utf8(&txt);
|
uint32_t cp = read_utf8(&txt);
|
||||||
|
|
||||||
struct GlyphCacheGlyph *g = glca_request(&this->glca, cp);
|
struct k3FontGlyph *g = k3FontGetGlyph(this, cp);
|
||||||
|
|
||||||
if(!g) continue;
|
if(!g) continue;
|
||||||
|
|
||||||
struct k3Tex *tex = this->atlas;
|
struct k3Tex *tex = this->pages[g->page];
|
||||||
size_t texW = k3TexSzX(tex);
|
size_t texW = this->texW;
|
||||||
size_t texH = k3TexSzY(tex);
|
size_t texH = this->texH;
|
||||||
|
|
||||||
k3BatchAdd(tex,
|
k3BatchAdd(tex,
|
||||||
(struct k3RectF) {(float) (g->x + 0.5) / texW, (float) (g->y - 0.5) / texH, (float) (g->w - 1) / texW, (float) (g->h - 1) / texH},
|
(struct k3RectF) {(float) (g->x + 0.5) / texW, (float) (g->y + 0.5) / texH, (float) (g->width - 1) / texW, (float) (g->height - 1) / texH},
|
||||||
(struct k3RectF) {
|
(struct k3RectF) {
|
||||||
x + sz * g->data.xOffset / this->fontPixelSize,
|
x + g->xoffset * this->lineScale * sz,
|
||||||
y - sz * ((g->h - g->data.yOffset) / (float) this->fontPixelSize - 0.5f),
|
y + ((-g->height - g->yoffset) * this->lineScale + 1) * sz,
|
||||||
sz * g->w / this->fontPixelSize,
|
g->width * this->lineScale * sz,
|
||||||
sz * g->h / this->fontPixelSize
|
g->height * this->lineScale * sz
|
||||||
}, 0, color, 0, k3IsCore ? 0.5 : 0.45);
|
}, 0, color, 0);
|
||||||
|
|
||||||
x += sz * g->data.xAdvance / this->fontPixelSize;
|
x += g->xadvance * this->lineScale * sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the line break was caused directly by a LF, skip over it for next line
|
// If the line break was caused directly by a LF, skip over it for next line
|
||||||
@ -199,3 +211,7 @@ void k3FontDraw(struct k3Font *this, float xStart, float yStart, float sz, const
|
|||||||
}
|
}
|
||||||
k3BatchFlush();
|
k3BatchFlush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct k3FontGlyph *k3FontGetGlyph(struct k3Font *this, uint32_t cp) {
|
||||||
|
return bsearch(&cp, this->glyphs, this->glyphCount, sizeof(*this->glyphs), cmpglyph);
|
||||||
|
}
|
||||||
|
|||||||
45
src/k3font.h
45
src/k3font.h
@ -4,32 +4,49 @@
|
|||||||
#include"k3batch.h"
|
#include"k3batch.h"
|
||||||
#include<string.h>
|
#include<string.h>
|
||||||
|
|
||||||
#define GLCA_CUSTOM_GLYPH_DATA
|
#define k3_FONT_ALIGN_LEFT 0
|
||||||
typedef struct GlyphCacheGlyphData {
|
#define k3_FONT_ALIGN_CENTER 1
|
||||||
float xAdvance;
|
#define k3_FONT_ALIGN_RIGHT 2
|
||||||
float xOffset;
|
|
||||||
float yOffset;
|
struct k3FontGlyph {
|
||||||
} GlyphCacheGlyphData;
|
uint32_t cp;
|
||||||
#include"glyphcache/glca.h"
|
uint16_t x;
|
||||||
|
uint16_t y;
|
||||||
|
uint16_t width;
|
||||||
|
uint16_t height;
|
||||||
|
int16_t xoffset;
|
||||||
|
int16_t yoffset;
|
||||||
|
uint16_t xadvance;
|
||||||
|
uint8_t page;
|
||||||
|
uint8_t chnl;
|
||||||
|
};
|
||||||
|
|
||||||
struct k3Font {
|
struct k3Font {
|
||||||
void *ud;
|
void *ud;
|
||||||
|
|
||||||
int atlasSize;
|
float lineScale;
|
||||||
uint8_t *atlasCPU;
|
|
||||||
struct k3Tex *atlas;
|
|
||||||
|
|
||||||
int fontPixelSize;
|
uint16_t baseline;
|
||||||
FT_Face ftface;
|
|
||||||
GlyphCache glca;
|
uint16_t texW, texH;
|
||||||
|
|
||||||
|
size_t glyphCount;
|
||||||
|
struct k3FontGlyph *glyphs;
|
||||||
|
|
||||||
|
size_t pageCount;
|
||||||
|
struct k3Tex **pages;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct k3Tex*(*k3FontTexLoader)(struct k3Font*, const char *name);
|
||||||
|
|
||||||
struct k3Font *k3FontCreate();
|
struct k3Font *k3FontCreate();
|
||||||
int k3FontLoad(struct k3Font*, const char *fn);
|
int k3FontLoad(struct k3Font*, const uint8_t *buf, size_t len, k3FontTexLoader);
|
||||||
|
|
||||||
void k3FontSz(struct k3Font*, float sz, const char *txt, float wall, struct k3RectF *ret);
|
void k3FontSz(struct k3Font*, float sz, const char *txt, float wall, struct k3RectF *ret);
|
||||||
void k3FontDraw(struct k3Font*, float x, float y, float sz, const char *txt, float wall, int alignment, vec4 color);
|
void k3FontDraw(struct k3Font*, float x, float y, float sz, const char *txt, float wall, int alignment, vec4 color);
|
||||||
|
|
||||||
|
struct k3FontGlyph *k3FontGetGlyph(struct k3Font*, uint32_t cp);
|
||||||
|
|
||||||
static inline int k3UTF8Encode(uint32_t cp, uint8_t ret[static 4]) {
|
static inline int k3UTF8Encode(uint32_t cp, uint8_t ret[static 4]) {
|
||||||
if(cp < 0x80) {
|
if(cp < 0x80) {
|
||||||
ret[0] = cp;
|
ret[0] = cp;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user