248 lines
7.7 KiB
C
248 lines
7.7 KiB
C
|
|
||
|
void tex_gen_checkerboard(byte *data, int w, int h, uint color1, uint color2) {
|
||
|
byte color[8];
|
||
|
color1 = (color1 << 8) | (color1 >> 24);
|
||
|
color2 = (color2 << 8) | (color2 >> 24);
|
||
|
for(int z = 0; z < 4; z++) {
|
||
|
color[z] = (uint)((color1 >> ((3 - z) * 8)) & 0xff);
|
||
|
color[z+4] = (uint)((color2 >> ((3 - z) * 8)) & 0xff);
|
||
|
}
|
||
|
for(int x = 0; x < w; x++) {
|
||
|
for(int y = 0; y < h; y++) {
|
||
|
memcpy(&data[(y*w+x) << 2], &color[((x & 1) ^ (y & 1)) << 2], 4);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float tri(float x, float p, float a) {
|
||
|
return ((4.0f * a) / p) * fabsf(fmodf(x - p / 4.0f, p) - p / 2.0f) - a;
|
||
|
}
|
||
|
|
||
|
void tex_gen_triwave(byte *data, int w, int h, uint color1, uint color2, uint color3, uint color4, uint color5, uint color6) {
|
||
|
byte color[16];
|
||
|
color1 = (color1 << 8) | (color1 >> 24);
|
||
|
color2 = (color2 << 8) | (color2 >> 24);
|
||
|
color3 = (color3 << 8) | (color3 >> 24);
|
||
|
color4 = (color4 << 8) | (color4 >> 24);
|
||
|
color5 = (color5 << 8) | (color5 >> 24);
|
||
|
color6 = (color6 << 8) | (color6 >> 24);
|
||
|
for(int z = 0; z < 4; z++) {
|
||
|
color[z] = (uint)((color1 >> ((3 - z) * 8)) & 0xff);
|
||
|
color[z+4] = (uint)((color2 >> ((3 - z) * 8)) & 0xff);
|
||
|
color[z+8] = (uint)((color3 >> ((3 - z) * 8)) & 0xff);
|
||
|
color[z+12] = (uint)((color4 >> ((3 - z) * 8)) & 0xff);
|
||
|
color[z+16] = (uint)((color5 >> ((3 - z) * 8)) & 0xff);
|
||
|
color[z+20] = (uint)((color6 >> ((3 - z) * 8)) & 0xff);
|
||
|
}
|
||
|
for(int y = 0; y < h; y++) {
|
||
|
int offs = ((y / 2 == h / 16) || (y / 2 == (h / 2 - h / 16) - 1)) ? 16 : (((y / 2 == h / 16 + 1) || (y / 2 == (h / 2 - h / 16) - 2)) ? 20 : 0);
|
||
|
for(int x = 0; x < w; x++) {
|
||
|
memcpy(&data[(y*w+x) << 2], &color[offs], 4);
|
||
|
}
|
||
|
}
|
||
|
for(int x = 0; x < w; x++) {
|
||
|
int y = ((x < w / 8) || (x >= w - w / 8)) ? (h / 2) : (h / 2 + (int)tri((float)(w / 4 + x), (float)((w * 3) / 4), (float)(((h * 3) / 4) / 2)));
|
||
|
sys_assert(y - 8 >= 0 && y + 7 < h)
|
||
|
memcpy(&data[((y-8)*w+x) << 2], &color[0], 4);
|
||
|
memcpy(&data[((y-7)*w+x) << 2], &color[0], 4);
|
||
|
memcpy(&data[((y-6)*w+x) << 2], &color[0], 4);
|
||
|
memcpy(&data[((y-5)*w+x) << 2], &color[4], 4);
|
||
|
memcpy(&data[((y-4)*w+x) << 2], &color[4], 4);
|
||
|
memcpy(&data[((y-3)*w+x) << 2], &color[0], 4);
|
||
|
memcpy(&data[((y-2)*w+x) << 2], &color[0], 4);
|
||
|
memcpy(&data[((y-1)*w+x) << 2], &color[8], 4);
|
||
|
memcpy(&data[((y+0)*w+x) << 2], &color[8], 4);
|
||
|
memcpy(&data[((y+1)*w+x) << 2], &color[0], 4);
|
||
|
memcpy(&data[((y+2)*w+x) << 2], &color[0], 4);
|
||
|
memcpy(&data[((y+3)*w+x) << 2], &color[12], 4);
|
||
|
memcpy(&data[((y+4)*w+x) << 2], &color[12], 4);
|
||
|
memcpy(&data[((y+5)*w+x) << 2], &color[0], 4);
|
||
|
memcpy(&data[((y+6)*w+x) << 2], &color[0], 4);
|
||
|
memcpy(&data[((y+7)*w+x) << 2], &color[0], 4);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
void tex_pack_1bit(const byte *data, byte *pack, uint size) {
|
||
|
for(int z = 0; z < size; z++) {
|
||
|
pack[z >> 3] &= ~(1 << (z & 7));
|
||
|
if(data[(z << 2) | 3])
|
||
|
pack[z >> 3] |= 1 << (z & 7);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void tex_unpack_1bit(byte *data, const byte *pack, uint size) {
|
||
|
for(int z = 0; z < size; z++) {
|
||
|
memset(&data[z << 2], (pack[z >> 3] & (1 << (z & 7))) ? 0xff : 0x00, 4);
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
void tex_param(tex_t *tex) {
|
||
|
byte mipmap = (gdr.tex_miptype < tex->mipmap) ? gdr.tex_miptype : tex->mipmap;
|
||
|
glBindTexture(GL_TEXTURE_2D, *(tex->id));
|
||
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (gdr.tex_filter && tex->filter)
|
||
|
? (mipmap ? ((mipmap == 1) ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR) : GL_LINEAR)
|
||
|
: (mipmap ? ((mipmap == 1) ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_LINEAR) : GL_NEAREST));
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (gdr.tex_filter && tex->filter) ? GL_LINEAR : GL_NEAREST);
|
||
|
// if(gdr.aniso_avail)
|
||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, tex->filter ? MIN_VALUE(gdr.tex_aniso, gdr.aniso_max) : 1.0f);
|
||
|
}
|
||
|
|
||
|
int tex_config() {
|
||
|
int done = 0;
|
||
|
ulong iter = 0;
|
||
|
tex_t *tex;
|
||
|
while(tex = tbl_iter(&gdr.textures, &iter)) {
|
||
|
tex_param(tex);
|
||
|
done += 1;
|
||
|
}
|
||
|
logd(LOG_GFX, STR_TEX_PARAMS, done);
|
||
|
return done;
|
||
|
}
|
||
|
|
||
|
void tex_delete(uint *tex) {
|
||
|
// uint *tex;
|
||
|
// for(int z = 0; z < gdr.tex_loaded; z++) {
|
||
|
// tex = gdr.textures[z];
|
||
|
if(*tex) {
|
||
|
glDeleteTextures(1, tex);
|
||
|
logd(LOG_GFX, STR_TEX_IUNLOADED, *tex);
|
||
|
*tex = 0;
|
||
|
}
|
||
|
// }
|
||
|
}
|
||
|
|
||
|
byte tex_unload(tex_t *tex) {
|
||
|
if(!(*(tex->id))) {
|
||
|
return 0;
|
||
|
}
|
||
|
glDeleteTextures(1, tex->id);
|
||
|
gdr.tex_mem -= tex->width * tex->height * 4;
|
||
|
logd(LOG_GFX, STR_TEX_UNLOADED, tex->path ? tex->path : "[built-in]", *(tex->id));
|
||
|
*(tex->id) = 0;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void tex_remove(tex_t *tex) {
|
||
|
if(tex_unload(tex)) {
|
||
|
// tbl_pop(&gdr.textures, tex);
|
||
|
gdr.tex_loaded -= 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int tex_clear() {
|
||
|
return tbl_clear_func(&gdr.textures, (clear_func*)tex_remove);
|
||
|
}
|
||
|
|
||
|
byte *img_load(const char *filename, int *width, int *height, byte flip, byte ignmiss) {
|
||
|
byte *data;
|
||
|
int err;
|
||
|
FILE *fd;
|
||
|
if(!(fd = fopen(filename, "rb"))) {
|
||
|
err = errno;
|
||
|
if(err != ENOENT || !ignmiss)
|
||
|
loge(LOG_GFX, STR_TEX_EOPEN, filename, strerror(err), err);
|
||
|
return 0;
|
||
|
}
|
||
|
data = stbi_load(fd, width, height, flip);
|
||
|
fclose(fd);
|
||
|
if(!data) {
|
||
|
loge(LOG_GFX, STR_TEX_ELOAD, filename, stbi_failure_desc(), stbi_failure_reason());
|
||
|
}
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
void tex_push(uint *tex, const byte *data, int width, int height) {
|
||
|
glGenTextures(1, tex);
|
||
|
glBindTexture(GL_TEXTURE_2D, *tex);
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||
|
gdr.tex_mem += width * height * 4;
|
||
|
gdr.tex_peak = gdr.tex_mem > gdr.tex_peak ? gdr.tex_mem : gdr.tex_peak;
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||
|
}
|
||
|
|
||
|
void tex_gen_fallback(uint *id, int size) {
|
||
|
byte *data = mem_alloc(size * size * 4, MEM_IMAGE);
|
||
|
tex_gen_checkerboard(data, size, size, 0xff000000, 0xffff00ff);
|
||
|
tex_push(id, data, size, size);
|
||
|
mem_free(data);
|
||
|
logd(LOG_GFX, STR_TEX_ILOADED, "fallback", *id);
|
||
|
}
|
||
|
|
||
|
void tex_push_par(uint *tex, const byte *data, const char *filename, int width, int height, byte filter, byte mipmap) {
|
||
|
tex_t *bind;
|
||
|
sys_assert(bind = (tex_t*)tbl_push(&gdr.textures));
|
||
|
tex_push(tex, data, width, height);
|
||
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||
|
// mem_free(data);
|
||
|
bind->id = tex;
|
||
|
bind->width = width;
|
||
|
bind->height = height;
|
||
|
bind->filter = filter;
|
||
|
bind->mipmap = mipmap;
|
||
|
bind->path = filename;
|
||
|
tex_param(bind);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
byte tex_load_sys(uint *tex, const char *filename, byte flip) {
|
||
|
byte *data;
|
||
|
int width, height;
|
||
|
if(!(data = img_load(filename, &width, &height, flip, 0))) {
|
||
|
*tex = sys.tex_fallback;
|
||
|
return 0;
|
||
|
}
|
||
|
tex_push(tex, data, width, height);
|
||
|
mem_free(data);
|
||
|
logd(LOG_GFX, STR_TEX_ILOADED, filename, *tex);
|
||
|
return 1;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
byte tex_load(uint *tex, const char *filename, byte flags) {
|
||
|
byte *data;
|
||
|
int width, height;
|
||
|
if(!(data = img_load(filename, &width, &height, (flags & TEX_FLAG_FLIP) != 0, 0))) {
|
||
|
*tex = gdr.tex_fallback;
|
||
|
return 0;
|
||
|
}
|
||
|
tex_push_par(tex, data, filename, width, height, (flags & TEX_FLAG_FILTER) != 0, ((flags & TEX_FLAG_MIPMAP) != 0) ? 2 :
|
||
|
((flags & TEX_FLAG_NMIPMAP) != 0));
|
||
|
gdr.tex_loaded += 1;
|
||
|
mem_free(data);
|
||
|
logd(LOG_GFX, STR_TEX_LOADED, filename, *tex);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
byte img_save(const char *filename, int x, int y, byte alpha, byte flip, int stride, const byte *data) {
|
||
|
int len;
|
||
|
byte *png;
|
||
|
int err;
|
||
|
FILE *fd;
|
||
|
if(!(png = stbi_write_png_to_mem(data, stride, x, y, alpha ? 4 : 3, &len, flip))) {
|
||
|
loge(LOG_GFX, STR_TEX_ESAVE, filename);
|
||
|
return 0;
|
||
|
}
|
||
|
if(!(fd = fopen(filename, "wb"))) {
|
||
|
err = errno;
|
||
|
loge(LOG_GFX, STR_TEX_EWOPEN, filename, strerror(err), err);
|
||
|
mem_free(png);
|
||
|
return 0;
|
||
|
}
|
||
|
if(fwrite(png, 1, len, fd) != len) {
|
||
|
loge(LOG_GFX, STR_TEX_EWRITE, filename);
|
||
|
fclose(fd);
|
||
|
mem_free(png);
|
||
|
return 0;
|
||
|
}
|
||
|
fclose(fd);
|
||
|
mem_free(png);
|
||
|
return 1;
|
||
|
}
|