Files
djstdlib/gfx/Texture.c
2026-06-04 18:22:30 +02:00

138 lines
5.3 KiB
C

#include "Texture.h"
#include "../os.h"
#include <math.h>
Texture createTexture(const char* bitmap, int32 width, int32 height) {
Texture result = {0};
result.width = width;
result.height = height;
glGenTextures(1, &result.tex_id);
glBindTexture(GL_TEXTURE_2D, result.tex_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, result.width, result.height, 0, GL_RGB, GL_UNSIGNED_BYTE, bitmap);
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_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
return result;
}
DefineList(stbtt_bakedchar, STBBakedChar);
static void saveGrayscaleTarga(string location, const char *bytes, int width, int height) {
char tgaHeader[18] = {
// Image ID length
0x00,
// Color map type
0x00,
// Image type
0x03,
// Color map info (unused)
0x0, 0x0, 0x0, 0x0, 0x0,
// Image spec
0x0, 0x0, // x origin
0x0, 0x0, // y origin
width & 0xFF, (width >> 8) & 0xFF, // width
height & 0xFF, (height >> 8) & 0xFF, // width
0x8, // bits per px (depth)
0b00000000, // image descriptor
};
os_writeEntireFile(location, tgaHeader, ArrayCount(tgaHeader));
os_fileAppend(location, bytes, width * height);
}
Font createFont(Arena *arena, string ttfLocation, real32 lineHeight) {
const int CODEPOINT_START = 32;
const int CODEPOINT_END = 126;
int32 atlasWidth = ((int32)lineHeight)*(int32)sqrt(CODEPOINT_END - CODEPOINT_START);
int32 atlasHeight = ((int32)lineHeight)*(int32)sqrt(CODEPOINT_END - CODEPOINT_START);
STBBakedCharList bakedCharlist = PushFullListZero(arena, STBBakedCharList, CODEPOINT_END - CODEPOINT_START);
string fontFile = os_readEntireFile(arena, ttfLocation);
stbtt_fontinfo info;
stbtt_InitFont(&info, (unsigned char *)fontFile.str, stbtt_GetFontOffsetForIndex((unsigned char *)fontFile.str, 0));
int ascent, descent, lineGap;
stbtt_GetFontVMetrics(&info, &ascent, &descent, &lineGap);
real32 scale = stbtt_ScaleForPixelHeight(&info, lineHeight);
char *bakedFontBitmap = PushArrayZero(arena, char, atlasWidth*atlasHeight);
int32 bake_result = stbtt_BakeFontBitmap(
(unsigned char *)fontFile.str, 0,
lineHeight,
(unsigned char *)bakedFontBitmap, atlasWidth, atlasHeight,
CODEPOINT_START, CODEPOINT_END - CODEPOINT_START,
bakedCharlist.data);
GlyphMetaList glyphMeta = PushFullListZero(arena, GlyphMetaList, bakedCharlist.length);
real32 x, y;
real32 lastX, lastY;
for (EachIn(bakedCharlist, i)) {
stbtt_aligned_quad q;
stbtt_GetBakedQuad(bakedCharlist.data, atlasWidth, atlasHeight, i, &x, &y, &q, 1);
glyphMeta.data[i] = (GlyphMeta){
.uv0=(Vec2){q.s0, q.t1},
.uv1=(Vec2){q.s1, q.t0},
.xOffset=q.x0 - lastX,
.yOffset=q.y0 + lineHeight + scale * descent,
.width=q.x1-q.x0,
.height=q.y1-q.y0,
};
lastX = x;
lastY = y;
}
Font result = {0};
result.glyphMeta = glyphMeta;
result.lineHeight = lineHeight;
result.charWidth = bakedCharlist.data[0].xadvance;
//saveGrayscaleTarga(s("atlas.tga"), bakedFontBitmap, atlasWidth, atlasHeight);
glGenTextures(1, &result.texId);
glBindTexture(GL_TEXTURE_2D, result.texId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, atlasWidth, atlasHeight, 0, GL_RED, GL_UNSIGNED_BYTE, bakedFontBitmap);
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_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
glGenBuffers(1, &result.glyphTableBufId);
glBindBuffer(GL_TEXTURE_BUFFER, result.glyphTableBufId);
glBufferData(GL_TEXTURE_BUFFER, sizeof(result.glyphMeta.data[0])*result.glyphMeta.length, result.glyphMeta.data, GL_STATIC_DRAW);
glGenTextures(1, &result.glyphTableTexId);
glBindTexture(GL_TEXTURE_BUFFER, result.glyphTableTexId);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, result.glyphTableBufId);
return result;
}
Texture createTextureFromFile(const char* source_path) {
Texture result = {0};
glGenTextures(1, &result.tex_id);
glBindTexture(GL_TEXTURE_2D, result.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, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
int nr_channels;
stbi_uc *data = stbi_load(source_path, &result.width, &result.height, &nr_channels, 0);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, result.width, result.height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
} else {
print("Failed to load texture.");
}
stbi_image_free(data);
return result;
}