-
-
Save johnblat/9e7006315724a03d52f972f139e3587a to your computer and use it in GitHub Desktop.
A quick guide on how to set up stb truetype(stbtt) with sdl3 on odin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package sdl3stbtruetypeexample | |
import SDL "vendor:sdl3" | |
import stbtt "vendor:stb/truetype" | |
import "core:strings" | |
Font :: struct { | |
bitmap: []u8, | |
packed_char: []stbtt.packedchar, | |
atlas: ^SDL.Texture, | |
texture_size: i32, | |
line_height: f32 | |
} | |
CharAtStart :: 32 | |
CharAmount :: 95 | |
load_font_to_data :: proc(renderer: ^SDL.Renderer, path: string, data: ^Font, texture_size: i32, line_height: f32) { | |
// dont forget to free temp allocator | |
stream := new(SDL.IOStream, context.temp_allocator) | |
stream = SDL.IOFromFile(strings.clone_to_cstring(path), "rb") | |
size := SDL.GetIOSize(stream) | |
font := make([]u8, size) | |
defer delete(font) | |
if SDL.ReadIO(stream, &font[0], uint(size)) == 0 { | |
SDL.Log("ERROR: Cannot Read file %s properly: %s", path, SDL.GetError()) | |
} | |
data.texture_size = texture_size | |
data.line_height = line_height | |
data.bitmap = make([]u8, data.texture_size * data.texture_size) | |
data.packed_char = make([]stbtt.packedchar, CharAmount) | |
// free allocator from this too | |
pack_context := new(stbtt.pack_context, context.temp_allocator) | |
stbtt.PackBegin(pack_context, &data.bitmap[0], data.texture_size, data.texture_size, 0, 1, nil) | |
stbtt.PackSetOversampling(pack_context, 1, 1) | |
stbtt.PackFontRange(pack_context, &font[0], 0, line_height, CharAtStart, CharAmount, &data.packed_char[0]) | |
stbtt.PackEnd(pack_context) | |
data.atlas = SDL.CreateTexture(renderer, .RGBA32, .STATIC, data.texture_size, data.texture_size) | |
SDL.SetTextureBlendMode(data.atlas, {.BLEND}) | |
pixels := make([]u32, data.texture_size*data.texture_size) | |
defer delete(pixels) | |
format := SDL.GetPixelFormatDetails(.RGBA32) | |
for i := 0; i < int(data.texture_size*data.texture_size); i += 1 { | |
pixels[i] = SDL.MapRGBA(format, nil, 0xFF, 0xFF, 0xFF, data.bitmap[i]) | |
} | |
SDL.UpdateTexture(data.atlas, nil, &pixels[0], data.texture_size * size_of(u32)) | |
} | |
render_font :: proc(renderer: ^SDL.Renderer, font: ^Font, x: f32, y: f32, font_size: f32, text: string) { | |
xpos: f32 = x | |
ypos: f32 = y | |
for i := 0; i < len(text); i += 1 { | |
// +1 here cuz char amount doesnt count the last char | |
if text[i] >= CharAtStart && text[i] < CharAtStart + CharAmount + 1 { | |
info := font.packed_char[text[i] - CharAtStart] | |
src := SDL.FRect{f32(info.x0), f32(info.y0), f32(info.x1) - f32(info.x0), f32(info.y1) - f32(info.y0)} | |
font_scale := font_size / font.line_height | |
dest_w :f32 = f32(info.x1 - info.x0) * font_scale | |
dest_h :f32 = f32(info.y1 - info.y0) * font_scale | |
dest_x :f32 = xpos + f32(info.xoff) * font_scale | |
dest_y :f32 = ypos | |
dst := SDL.FRect{dest_x, dest_y, dest_w, dest_h} | |
SDL.RenderTexture( renderer, | |
font.atlas, | |
&src, | |
&dst ) | |
xpos += f32(info.xadvance) * font_scale | |
} | |
} | |
} | |
main :: proc() { | |
if !SDL.Init({.VIDEO}) { | |
SDL.Log("ERROR: Could not init video %s", SDL.GetError()) | |
} | |
window: ^SDL.Window | |
renderer: ^SDL.Renderer | |
font_data: Font | |
if !SDL.CreateWindowAndRenderer("sdl3stbtruetype-example", 1280, 720, {.OPENGL}, &window, &renderer) { | |
SDL.Log("ERROR: Could not init window and renderer %s", SDL.GetError()) | |
} | |
// put your own font here | |
load_font_to_data(renderer, INSERT_FONT_PATH_HERE, &font_data, 1024, 64) | |
text := "the quick brown fox jumped over the fence" | |
running := true | |
event: SDL.Event | |
for running { | |
for SDL.PollEvent(&event) { | |
#partial switch event.type { | |
case .QUIT: | |
running = false | |
} | |
} | |
SDL.SetRenderDrawColor(renderer, 0xFF,0xFF,0xFF,0xFF) | |
SDL.RenderClear(renderer) | |
SDL.SetTextureColorMod(font_data.atlas, 0, 0, 0) | |
SDL.SetTextureAlphaMod(font_data.atlas, 255) | |
// Renders text | |
render_font(renderer, &font_data, 0, 0, 32, text) | |
// Renders atlas | |
SDL.RenderTexture( renderer, | |
font_data.atlas, | |
nil, | |
&SDL.FRect{0, 45, 512, 512}) | |
SDL.RenderPresent(renderer) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment