#include "Texture.h" #include "../os.h" #include 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; }