138 lines
5.3 KiB
C
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;
|
|
}
|