Compare commits

..

No commits in common. "36678c11279e54e61abd06b34b717777f541a552" and "08fff0f6fad117cc8d9365b0a5dbabe029b627d4" have entirely different histories.

22 changed files with 466 additions and 486 deletions

View File

@ -6,33 +6,33 @@ The choice was made to keep the LRU cache implementation as close to the origina
import "base:runtime"
Pool_ListIter :: i32
Pool_ListValue :: u64
PoolListIter :: i32
PoolListValue :: u64
Pool_List_Item :: struct {
prev : Pool_ListIter,
next : Pool_ListIter,
value : Pool_ListValue,
PoolListItem :: struct {
prev : PoolListIter,
next : PoolListIter,
value : PoolListValue,
}
Pool_List :: struct {
items : [dynamic]Pool_List_Item,
free_list : [dynamic]Pool_ListIter,
front : Pool_ListIter,
back : Pool_ListIter,
PoolList :: struct {
items : [dynamic]PoolListItem,
free_list : [dynamic]PoolListIter,
front : PoolListIter,
back : PoolListIter,
size : i32,
capacity : i32,
dbg_name : string,
}
pool_list_init :: proc( pool : ^Pool_List, capacity : i32, dbg_name : string = "" )
pool_list_init :: proc( pool : ^PoolList, capacity : i32, dbg_name : string = "" )
{
error : Allocator_Error
pool.items, error = make( [dynamic]Pool_List_Item, int(capacity) )
error : AllocatorError
pool.items, error = make( [dynamic]PoolListItem, int(capacity) )
assert( error == .None, "VEFontCache.pool_list_init : Failed to allocate items array")
resize( & pool.items, capacity )
pool.free_list, error = make( [dynamic]Pool_ListIter, len = 0, cap = int(capacity) )
pool.free_list, error = make( [dynamic]PoolListIter, len = 0, cap = int(capacity) )
assert( error == .None, "VEFontCache.pool_list_init : Failed to allocate free_list array")
resize( & pool.free_list, capacity )
@ -53,17 +53,17 @@ pool_list_init :: proc( pool : ^Pool_List, capacity : i32, dbg_name : string = "
back = -1
}
pool_list_free :: proc( pool : ^Pool_List ) {
pool_list_free :: proc( pool : ^PoolList ) {
delete( pool.items)
delete( pool.free_list)
}
pool_list_reload :: proc( pool : ^Pool_List, allocator : Allocator ) {
pool_list_reload :: proc( pool : ^PoolList, allocator : Allocator ) {
reload_array( & pool.items, allocator )
reload_array( & pool.free_list, allocator )
}
pool_list_push_front :: proc( pool : ^Pool_List, value : Pool_ListValue )
pool_list_push_front :: proc( pool : ^PoolList, value : PoolListValue )
{
using pool
if size >= capacity do return
@ -90,7 +90,7 @@ pool_list_push_front :: proc( pool : ^Pool_List, value : Pool_ListValue )
size += 1
}
pool_list_erase :: proc( pool : ^Pool_List, iter : Pool_ListIter )
pool_list_erase :: proc( pool : ^PoolList, iter : PoolListIter )
{
using pool
if size <= 0 do return
@ -119,7 +119,7 @@ pool_list_erase :: proc( pool : ^Pool_List, iter : Pool_ListIter )
}
}
pool_list_move_to_front :: #force_inline proc( pool : ^Pool_List, iter : Pool_ListIter )
pool_list_move_to_front :: #force_inline proc( pool : ^PoolList, iter : PoolListIter )
{
using pool
@ -136,13 +136,13 @@ pool_list_move_to_front :: #force_inline proc( pool : ^Pool_List, iter : Pool_Li
front = iter
}
pool_list_peek_back :: #force_inline proc ( pool : ^Pool_List ) -> Pool_ListValue {
pool_list_peek_back :: #force_inline proc ( pool : ^PoolList ) -> PoolListValue {
assert( pool.back != - 1 )
value := pool.items[ pool.back ].value
return value
}
pool_list_pop_back :: #force_inline proc( pool : ^Pool_List ) -> Pool_ListValue {
pool_list_pop_back :: #force_inline proc( pool : ^PoolList ) -> PoolListValue {
if pool.size <= 0 do return 0
assert( pool.back != -1 )
@ -153,10 +153,8 @@ pool_list_pop_back :: #force_inline proc( pool : ^Pool_List ) -> Pool_ListValue
LRU_Link :: struct {
pad_top : u64,
value : i32,
ptr : Pool_ListIter,
ptr : PoolListIter,
pad_bottom : u64,
}
@ -164,34 +162,34 @@ LRU_Cache :: struct {
capacity : i32,
num : i32,
table : map[u64]LRU_Link,
key_queue : Pool_List,
key_queue : PoolList,
}
lru_init :: proc( cache : ^LRU_Cache, capacity : i32, dbg_name : string = "" ) {
error : Allocator_Error
LRU_init :: proc( cache : ^LRU_Cache, capacity : i32, dbg_name : string = "" ) {
error : AllocatorError
cache.capacity = capacity
cache.table, error = make( map[u64]LRU_Link, uint(capacity) )
assert( error == .None, "VEFontCache.lru_init : Failed to allocate cache's table")
assert( error == .None, "VEFontCache.LRU_init : Failed to allocate cache's table")
pool_list_init( & cache.key_queue, capacity, dbg_name = dbg_name )
}
lru_free :: proc( cache : ^LRU_Cache ) {
LRU_free :: proc( cache : ^LRU_Cache ) {
pool_list_free( & cache.key_queue )
delete( cache.table )
}
lru_reload :: #force_inline proc( cache : ^LRU_Cache, allocator : Allocator ) {
LRU_reload :: #force_inline proc( cache : ^LRU_Cache, allocator : Allocator ) {
reload_map( & cache.table, allocator )
pool_list_reload( & cache.key_queue, allocator )
}
lru_find :: #force_inline proc "contextless" ( cache : ^LRU_Cache, key : u64, must_find := false ) -> (LRU_Link, bool) {
LRU_find :: #force_inline proc "contextless" ( cache : ^LRU_Cache, key : u64, must_find := false ) -> (LRU_Link, bool) {
link, success := cache.table[key]
return link, success
}
lru_get :: #force_inline proc( cache: ^LRU_Cache, key : u64 ) -> i32 {
LRU_get :: #force_inline proc( cache: ^LRU_Cache, key : u64 ) -> i32 {
if link, ok := &cache.table[ key ]; ok {
pool_list_move_to_front(&cache.key_queue, link.ptr)
return link.value
@ -199,7 +197,7 @@ lru_get :: #force_inline proc( cache: ^LRU_Cache, key : u64 ) -> i32 {
return -1
}
lru_get_next_evicted :: #force_inline proc ( cache : ^LRU_Cache ) -> u64 {
LRU_get_next_evicted :: #force_inline proc ( cache : ^LRU_Cache ) -> u64 {
if cache.key_queue.size >= cache.capacity {
evict := pool_list_peek_back( & cache.key_queue )
return evict
@ -207,15 +205,15 @@ lru_get_next_evicted :: #force_inline proc ( cache : ^LRU_Cache ) -> u64 {
return 0xFFFFFFFFFFFFFFFF
}
lru_peek :: #force_inline proc ( cache : ^LRU_Cache, key : u64, must_find := false ) -> i32 {
iter, success := lru_find( cache, key, must_find )
LRU_peek :: #force_inline proc ( cache : ^LRU_Cache, key : u64, must_find := false ) -> i32 {
iter, success := LRU_find( cache, key, must_find )
if success == false {
return -1
}
return iter.value
}
lru_put :: #force_inline proc( cache : ^LRU_Cache, key : u64, value : i32 ) -> u64
LRU_put :: #force_inline proc( cache : ^LRU_Cache, key : u64, value : i32 ) -> u64
{
if link, ok := & cache.table[ key ]; ok {
pool_list_move_to_front( & cache.key_queue, link.ptr )
@ -239,8 +237,8 @@ lru_put :: #force_inline proc( cache : ^LRU_Cache, key : u64, value : i32 ) -> u
return evict
}
lru_refresh :: proc( cache : ^LRU_Cache, key : u64 ) {
link, success := lru_find( cache, key )
LRU_refresh :: proc( cache : ^LRU_Cache, key : u64 ) {
link, success := LRU_find( cache, key )
pool_list_erase( & cache.key_queue, link.ptr )
pool_list_push_front( & cache.key_queue, key )
link.ptr = cache.key_queue.front

View File

@ -4,24 +4,24 @@ This is a port of the [VEFontCache](https://github.com/hypernewbie/VEFontCache)
Its original purpose was for use in game engines, however its rendeirng quality and performance is more than adequate for many other applications.
See: [docs/Readme.md](docs/Readme.md) for the library's interface.
See: [docs/Readme.md](docs/Readme.md) for the library's interface
## Building
See [scripts/Readme.md](scripts/Readme.md) for building examples or utilizing the provided backends.
Currently the scripts provided & the library itself were developed & tested on Windows. There are bash scripts for building on linux (they build on WSL but need additional testing).
Currently the scripts provided & the library itself where developed & tested on Windows. The library itself should not be limited to that OS platform however, just don't have the configuration setup for alternative platforms (yet).
The library depends on freetype, harfbuzz, & stb_truetype to build.
The library depends on freetype, harfbuzz, & stb_truetype currently to build.
Note: freetype and harfbuzz could technically be gutted if the user removes their definitions, however they have not been made into a conditional compilation option (yet).
## Changes from orignal
* Font Parser & Glyph shaper are abstracted to their own warpper interface
* Font Parser & Glyph shaper are abstracted to their own interface
* ve_fontcache_loadfile not ported (ust use core:os or os2, then call load_font)
* Macro defines have been coverted (mostly) to runtime parameters
* Support for hot_reloading
* Curve quality step interpolation for glyph rendering can be set on a per font basis.
* Curve quality step granularity for glyph rendering can be set on a per font basis.
## TODOs
@ -35,12 +35,18 @@ Note: freetype and harfbuzz could technically be gutted if the user removes thei
### Optimization:
* Check if its better to store the glyph vertices if they need to be re-cached to atlas or directly drawn.
* Check if its better to store the generated glyph vertices if they need to be re-cached or directly drawn.
* Look into setting up multi-threading by giving each thread a context
* There is a heavy performance bottleneck in iterating the text/shape/glyphs on the cpu (single-thread) vs the actual rendering *(if doing thousands of drawing commands)*
* draw_text can provide in the context a job list per thread for the user to thenk hookup to their own threading solution to handle.
* Context would need to be segregated into staged data structures for each thread to utilize
* This would need to converge to the singlar draw_list on a per layer basis. The interface expects the user to issue commands single-threaded unless, its assumed the user is going to feed the gpu the commands & data through separate threads as well (not ideal ux).
* Each should have their own?
* draw_list
* draw_layer
* atlas.next_idx
* glyph_draw_buffer
* shape_cache
* This would need to converge to the singlar draw_list on a per layer basis (then user reqeusts a draw_list layer there could a yield to wait for the jobs to finish); if the interface expects the user to issue the commands single-threaded unless, we just assume the user is going to feed the gpu the commands & data through separate threads as well (not ideal ux).
* How the contexts are given jobs should be left up to the user (can recommend a screen quadrant based approach in demo examples)
Failed Attempts:

View File

@ -1,6 +1,6 @@
package vefontcache
Atlas_Region_Kind :: enum u8 {
AtlasRegionKind :: enum u8 {
None = 0x00,
A = 0x41,
B = 0x42,
@ -10,7 +10,7 @@ Atlas_Region_Kind :: enum u8 {
Ignore = 0xFF, // ve_fontcache_cache_glyph_to_atlas uses a -1 value in clear draw call
}
Atlas_Region :: struct {
AtlasRegion :: struct {
state : LRU_Cache,
width : i32,
@ -29,13 +29,13 @@ Atlas :: struct {
glyph_padding : i32,
region_a : Atlas_Region,
region_b : Atlas_Region,
region_c : Atlas_Region,
region_d : Atlas_Region,
region_a : AtlasRegion,
region_b : AtlasRegion,
region_c : AtlasRegion,
region_d : AtlasRegion,
}
atlas_bbox :: proc( atlas : ^Atlas, region : Atlas_Region_Kind, local_idx : i32 ) -> (position, size: Vec2)
atlas_bbox :: proc( atlas : ^Atlas, region : AtlasRegionKind, local_idx : i32 ) -> (position, size: Vec2)
{
switch region
{
@ -79,12 +79,14 @@ atlas_bbox :: proc( atlas : ^Atlas, region : Atlas_Region_Kind, local_idx : i32
position.x += f32(atlas.region_d.offset.x)
position.y += f32(atlas.region_d.offset.y)
case .Ignore, .None, .E:
case .Ignore: fallthrough
case .None: fallthrough
case .E:
}
return
}
decide_codepoint_region :: proc(ctx : ^Context, entry : ^Entry, glyph_index : Glyph ) -> (region_kind : Atlas_Region_Kind, region : ^Atlas_Region, over_sample : Vec2)
decide_codepoint_region :: proc(ctx : ^Context, entry : ^Entry, glyph_index : Glyph ) -> (region_kind : AtlasRegionKind, region : ^AtlasRegion, over_sample : Vec2)
{
if parser_is_glyph_empty(&entry.parser_info, glyph_index) {
return .None, nil, {}
@ -102,11 +104,11 @@ decide_codepoint_region :: proc(ctx : ^Context, entry : ^Entry, glyph_index : Gl
bounds_height_scaled := i32(bounds_height * entry.size_scale + glyph_padding)
// Use a lookup table for faster region selection
region_lookup := [4]struct { kind: Atlas_Region_Kind, region: ^Atlas_Region } {
{ .A, & atlas.region_a },
{ .B, & atlas.region_b },
{ .C, & atlas.region_c },
{ .D, & atlas.region_d },
region_lookup := [4]struct { kind: AtlasRegionKind, region: ^AtlasRegion } {
{ .A, & atlas.region_a },
{ .B, & atlas.region_b },
{ .C, & atlas.region_c },
{ .D, & atlas.region_d },
}
for region in region_lookup do if bounds_width_scaled <= region.region.width && bounds_height_scaled <= region.region.height {

View File

@ -3,9 +3,7 @@
Notes
---
The freetype setup is not finished. Specifically due to cache_glyph_freetype not parsing the glyph outline data structure properly.
Freetype supports specifying a FT_Memory handle which is a pointer to a FT_MemoryRect. This can be used to define an allocator for the parser. Currently this library does not wrap this interface (yet). If using freetype its recommend to update `parser_init` with the necessary changes to wrap the context's backing allocator for freetype to utilize.
Freetype implementation supports specifying a FT_Memory handle which is a pointer to a FT_MemoryRect. This can be used to define an allocator for the parser. Currently this library does not wrap this interface (yet). If using freetype its recommend to update `parser_init` with the necessary changes to wrap the context's backing allocator for freetype to utilize.
```c
struct FT_MemoryRec_
@ -17,19 +15,19 @@ Freetype supports specifying a FT_Memory handle which is a pointer to a FT_Memor
};
```
This library (seems) to perform best if the text commands are fed in 'whitespace aware chunks', where instead of feeding it entire blobs of text, the user identfies "words" in the text and feeding the visible and whitespce chunks derived from this to draw_text as separate calls. It improves the caching of the text shapes. The downside is there has to be a time where the text is parsed into tokens beforehand so that the this iteration does not have to occur continously.
This library (seems) to perform best if the text commands are fed in 'whitespace aware chunks', where instead of feeding it entire blobs of text, the user identfies the "words" in the text and feeding the visible and whitespce chunks derived from this to draw_text as separate calls. This improves the caching of the text shapes. The downside is there has to be a time where the text is parsed into tokens beforehand so that the this iteration does not have to occur continously.
### startup
Initializes a provided context.
There are a large amount of parameters to tune the library instance to the user's preference. By default, keep in mind the library defaults to utilize stb_truetype as the font parser and harfbuzz for the shaper.
There are a large amount of parameters to tune the library instance to the user's preference. By default, keep in mind the library defaults to utilize stb_truetype as the font parser and harfbuzz (soon...) for the shaper.
Much of the data structures within the context struct are not fixed-capacity allocations so make sure that the backing allocator can handle it.
Much of the data structures within the context struct are not fixed-capacity allocations so make sure that the backing allocator utilized can handle it.
### hot_reload
The library supports being used in a dynamically loaded module. If its hot-reloaded simply make sure to call this procedure with a reference to the backing allocator provided during startup as all dynamic containers tend to lose a proper reference to the allocator's procedure.
The library supports being used in a dynamically loaded module. If this occurs simply make sure to call this procedure with a reference to the backing allocator provided during startup as all dynamic containers tend to lose a proper reference to the allocator's procedure.
### shutdown
@ -47,7 +45,7 @@ Will provide the current cursor_pos for the resulting text drawn.
### set_color
Sets the color to utilize on `Draw_Call`s for FrameBuffer.Target or .Target_Uncached passes
Sets the color to utilize on `DrawCall`s for FrameBuffer.Target or .Target_Uncached passes
### get_draw_list
@ -57,8 +55,8 @@ By default, if get_draw_list is called, it will first call `optimize_draw_list`
### get_draw_list_layer
Get the enqueued draw_list for the current "layer".
A layer is considered the slice of the `Draw_List`'s content from the last call to `flush_draw_list_layer` onward.
By default, if `get_draw_list_layer` is called, it will first call `optimize_draw_list` for the user to optimize the slice (exlusively) of the draw list's draw calls. If this is undesired, make sure to pass `optimize_before_returning = false` in the arguments.
A layer is considered the slice of the drawlist's content from the last call to `flush_draw_list_layer` onward.
By default, if get_draw_list_layer is called, it will first call `optimize_draw_list` for the user to optimize the slice (exlusively) of the draw list's draw calls. If this is undesired, make sure to pass `optimize_before_returning = false` in the arguments.
The draw layer offsets are cleared with `flush_draw_list`
@ -72,7 +70,7 @@ Will update the draw list layer with the latest offset based on the current leng
### measure_text_size
Provides a Vec2 the width and height occupied by the provided text string. The y is measured to be the the largest glyph box bounds height of the text. The width is derived from the `end_cursor_pos` field from a `Shaped_Text` entry.
Provides a Vec2 the width and height occupied by the provided text string. The y is measured to be the the largest glyph box bounds height of the text. The width is derived from the `end_cursor_pos` field from a `ShapedText` entry.
### get_font_vertical_metrics

View File

@ -8,16 +8,16 @@ Vertex :: struct {
u, v : f32,
}
Draw_Call :: struct {
pass : Frame_Buffer_Pass,
DrawCall :: struct {
pass : FrameBufferPass,
start_index : u32,
end_index : u32,
clear_before_draw : b32,
region : Atlas_Region_Kind,
region : AtlasRegionKind,
colour : Colour,
}
Draw_Call_Default :: Draw_Call {
DrawCall_Default :: DrawCall {
pass = .None,
start_index = 0,
end_index = 0,
@ -26,14 +26,14 @@ Draw_Call_Default :: Draw_Call {
colour = { 1.0, 1.0, 1.0, 1.0 }
}
Draw_List :: struct {
DrawList :: struct {
vertices : [dynamic]Vertex,
indices : [dynamic]u32,
calls : [dynamic]Draw_Call,
calls : [dynamic]DrawCall,
}
// TODO(Ed): This was a rough translation of the raw values the orignal was using, need to give better names...
Frame_Buffer_Pass :: enum u32 {
FrameBufferPass :: enum u32 {
None = 0,
Glyph = 1,
Atlas = 2,
@ -41,7 +41,7 @@ Frame_Buffer_Pass :: enum u32 {
Target_Uncached = 4,
}
Glyph_Draw_Buffer :: struct {
GlyphDrawBuffer :: struct {
over_sample : Vec2,
batch : i32,
width : i32,
@ -49,11 +49,11 @@ Glyph_Draw_Buffer :: struct {
draw_padding : i32,
batch_x : i32,
clear_draw_list : Draw_List,
draw_list : Draw_List,
clear_draw_list : DrawList,
draw_list : DrawList,
}
blit_quad :: proc( draw_list : ^Draw_List, p0 : Vec2 = {0, 0}, p1 : Vec2 = {1, 1}, uv0 : Vec2 = {0, 0}, uv1 : Vec2 = {1, 1} )
blit_quad :: proc( draw_list : ^DrawList, p0 : Vec2 = {0, 0}, p1 : Vec2 = {1, 1}, uv0 : Vec2 = {0, 0}, uv1 : Vec2 = {1, 1} )
{
// profile(#procedure)
// logf("Blitting: xy0: %0.2f, %0.2f xy1: %0.2f, %0.2f uv0: %0.2f, %0.2f uv1: %0.2f, %0.2f",
@ -89,9 +89,9 @@ blit_quad :: proc( draw_list : ^Draw_List, p0 : Vec2 = {0, 0}, p1 : Vec2 = {1, 1
}
// TODO(Ed): glyph caching cannot be handled in a 'font parser' abstraction. Just going to have explicit procedures to grab info neatly...
cache_glyph_freetype :: proc(ctx: ^Context, font: Font_ID, glyph_index: Glyph, entry: ^Entry, bounds_0, bounds_1: Vec2, scale, translate: Vec2) -> b32
cache_glyph_freetype :: proc(ctx: ^Context, font: FontID, glyph_index: Glyph, entry: ^Entry, bounds_0, bounds_1: Vec2, scale, translate: Vec2) -> b32
{
draw_filled_path_freetype :: proc( draw_list : ^Draw_List, outside_point : Vec2, path : []Vertex,
draw_filled_path_freetype :: proc( draw_list : ^DrawList, outside_point : Vec2, path : []Vertex,
scale := Vec2 { 1, 1 },
translate := Vec2 { 0, 0 },
debug_print_verbose : b32 = false
@ -106,7 +106,7 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: Font_ID, glyph_index: Glyph, e
}
v_offset := cast(u32) len(draw_list.vertices)
for point in path
for point in path
{
transformed_point := Vertex {
pos = point.pos * scale + translate,
@ -130,9 +130,9 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: Font_ID, glyph_index: Glyph, e
// Close the path by connecting the last vertex to the first two
to_add := [3]u32 {
v_offset,
v_offset + cast(u32)(len(path) - 1),
v_offset + 1
v_offset,
v_offset + cast(u32)(len(path) - 1),
v_offset + 1
}
append( indices, ..to_add[:] )
}
@ -158,8 +158,8 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: Font_ID, glyph_index: Glyph, e
return false
}
draw := Draw_Call_Default
draw.pass = Frame_Buffer_Pass.Glyph
draw := DrawCall_Default
draw.pass = FrameBufferPass.Glyph
draw.start_index = cast(u32) len(ctx.draw_list.indices)
contours := slice.from_ptr(cast( [^]i16) outline.contours, int(outline.n_contours))
@ -178,57 +178,57 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: Font_ID, glyph_index: Glyph, e
prev_point: Vec2
first_point: Vec2
for idx := start_index; idx < end_index; idx += 1
{
current_pos := Vec2 { f32( points[idx].x ), f32( points[idx].y ) }
if ( tags[idx] & 1 ) == 0
for idx := start_index; idx < end_index; idx += 1
{
// If current point is off-curve
if (idx == start_index || (tags[ idx - 1 ] & 1) != 0)
current_pos := Vec2 { f32( points[idx].x ), f32( points[idx].y ) }
if ( tags[idx] & 1 ) == 0
{
// current is the first or following an on-curve point
prev_point = current_pos
// If current point is off-curve
if (idx == start_index || (tags[ idx - 1 ] & 1) != 0)
{
// current is the first or following an on-curve point
prev_point = current_pos
}
else
{
// current and previous are off-curve, calculate midpoint
midpoint := (prev_point + current_pos) * 0.5
append( path, Vertex { pos = midpoint } ) // Add midpoint as on-curve point
if idx < end_index - 1
{
// perform interp from prev_point to current_pos via midpoint
step := 1.0 / entry.curve_quality
for alpha : f32 = 0.0; alpha <= 1.0; alpha += step
{
bezier_point := eval_point_on_bezier3( prev_point, midpoint, current_pos, alpha )
append( path, Vertex{ pos = bezier_point } )
}
}
prev_point = current_pos
}
}
else
{
// current and previous are off-curve, calculate midpoint
midpoint := (prev_point + current_pos) * 0.5
append( path, Vertex { pos = midpoint } ) // Add midpoint as on-curve point
if idx < end_index - 1
{
// perform interp from prev_point to current_pos via midpoint
step := 1.0 / entry.curve_quality
for alpha : f32 = 0.0; alpha <= 1.0; alpha += step
{
bezier_point := eval_point_on_bezier3( prev_point, midpoint, current_pos, alpha )
append( path, Vertex{ pos = bezier_point } )
}
if idx == start_index {
first_point = current_pos
}
prev_point = current_pos
if prev_point != (Vec2{}) {
// there was an off-curve point before this
append(path, Vertex{ pos = prev_point}) // Ensure previous off-curve is handled
}
append(path, Vertex{ pos = current_pos})
prev_point = {}
}
}
else
{
if idx == start_index {
first_point = current_pos
}
if prev_point != (Vec2{}) {
// there was an off-curve point before this
append(path, Vertex{ pos = prev_point}) // Ensure previous off-curve is handled
}
append(path, Vertex{ pos = current_pos})
prev_point = {}
}
}
// ensure the contour is closed
if path[0].pos != path[ len(path) - 1 ].pos {
append(path, Vertex{pos = path[0].pos})
}
draw_filled_path(&ctx.draw_list, bounds_0, path[:], scale, translate, ctx.debug_print_verbose)
clear(path)
start_index = end_index
// ensure the contour is closed
if path[0].pos != path[ len(path) - 1 ].pos {
append(path, Vertex{pos = path[0].pos})
}
draw_filled_path(&ctx.draw_list, bounds_0, path[:], scale, translate, ctx.debug_print_verbose)
clear(path)
start_index = end_index
}
if len(path) > 0 {
@ -244,7 +244,7 @@ cache_glyph_freetype :: proc(ctx: ^Context, font: Font_ID, glyph_index: Glyph, e
}
// TODO(Ed): Is it better to cache the glyph vertices for when it must be re-drawn (directly or two atlas)?
cache_glyph :: proc(ctx : ^Context, font : Font_ID, glyph_index : Glyph, entry : ^Entry, bounds_0, bounds_1 : Vec2, scale, translate : Vec2) -> b32
cache_glyph :: proc(ctx : ^Context, font : FontID, glyph_index : Glyph, entry : ^Entry, bounds_0, bounds_1 : Vec2, scale, translate : Vec2) -> b32
{
// profile(#procedure)
if glyph_index == Glyph(0) {
@ -265,8 +265,8 @@ cache_glyph :: proc(ctx : ^Context, font : Font_ID, glyph_index : Glyph, entry :
outside := Vec2{bounds_0.x - 21, bounds_0.y - 33}
draw := Draw_Call_Default
draw.pass = Frame_Buffer_Pass.Glyph
draw := DrawCall_Default
draw.pass = FrameBufferPass.Glyph
draw.start_index = u32(len(ctx.draw_list.indices))
path := &ctx.temp_path
@ -276,8 +276,8 @@ cache_glyph :: proc(ctx : ^Context, font : Font_ID, glyph_index : Glyph, entry :
{
case .Move:
if len(path) > 0 {
draw_filled_path(&ctx.draw_list, outside, path[:], scale, translate, ctx.debug_print_verbose)
clear(path)
draw_filled_path(&ctx.draw_list, outside, path[:], scale, translate, ctx.debug_print_verbose)
clear(path)
}
fallthrough
@ -329,13 +329,13 @@ cache_glyph :: proc(ctx : ^Context, font : Font_ID, glyph_index : Glyph, entry :
* draw_text_shape : Glyph
*/
cache_glyph_to_atlas :: proc( ctx : ^Context,
font : Font_ID,
font : FontID,
glyph_index : Glyph,
lru_code : u64,
atlas_index : i32,
entry : ^Entry,
region_kind : Atlas_Region_Kind,
region : ^Atlas_Region,
region_kind : AtlasRegionKind,
region : ^AtlasRegion,
over_sample : Vec2 )
{
// profile(#procedure)
@ -356,24 +356,24 @@ cache_glyph_to_atlas :: proc( ctx : ^Context,
{
if region.next_idx < region.state.capacity
{
evicted := lru_put( & region.state, lru_code, i32(region.next_idx) )
evicted := LRU_put( & region.state, lru_code, i32(region.next_idx) )
atlas_index = i32(region.next_idx)
region.next_idx += 1
assert( evicted == lru_code )
}
else
{
next_evict_codepoint := lru_get_next_evicted( & region.state )
next_evict_codepoint := LRU_get_next_evicted( & region.state )
assert( next_evict_codepoint != 0xFFFFFFFFFFFFFFFF )
atlas_index = lru_peek( & region.state, next_evict_codepoint, must_find = true )
atlas_index = LRU_peek( & region.state, next_evict_codepoint, must_find = true )
assert( atlas_index != -1 )
evicted := lru_put( & region.state, lru_code, atlas_index )
evicted := LRU_put( & region.state, lru_code, atlas_index )
assert( evicted == next_evict_codepoint )
}
assert( lru_get( & region.state, lru_code ) != - 1 )
assert( LRU_get( & region.state, lru_code ) != - 1 )
}
atlas := & ctx.atlas
@ -420,7 +420,7 @@ cache_glyph_to_atlas :: proc( ctx : ^Context,
glyph_buffer.batch_x += i32(gwidth_scaled_px)
screenspace_x_form( & glyph_draw_translate, & glyph_draw_scale, glyph_buffer_size )
clear_target_region : Draw_Call
clear_target_region : DrawCall
{
using clear_target_region
pass = .Atlas
@ -434,7 +434,7 @@ cache_glyph_to_atlas :: proc( ctx : ^Context,
end_index = cast(u32) len(glyph_buffer.clear_draw_list.indices)
}
blit_to_atlas : Draw_Call
blit_to_atlas : DrawCall
{
using blit_to_atlas
pass = .Atlas
@ -456,11 +456,11 @@ cache_glyph_to_atlas :: proc( ctx : ^Context,
}
// If the glyuph is found in the atlas, nothing occurs, otherwise, the glyph call is setup to catch it to the atlas
check_glyph_in_atlas :: #force_inline proc( ctx : ^Context, font : Font_ID, entry : ^Entry, glyph_index : Glyph,
check_glyph_in_atlas :: #force_inline proc( ctx : ^Context, font : FontID, entry : ^Entry, glyph_index : Glyph,
lru_code : u64,
atlas_index : i32,
region_kind : Atlas_Region_Kind,
region : ^Atlas_Region,
region_kind : AtlasRegionKind,
region : ^AtlasRegion,
over_sample : Vec2
) -> b32
{
@ -476,7 +476,7 @@ check_glyph_in_atlas :: #force_inline proc( ctx : ^Context, font : Font_ID, entr
{
if region.next_idx > region.state.capacity {
// We will evict LRU. We must predict which LRU will get evicted, and if it's something we've seen then we need to take slowpath and flush batch.
next_evict_codepoint := lru_get_next_evicted( & region.state )
next_evict_codepoint := LRU_get_next_evicted( & region.state )
seen, success := ctx.temp_codepoint_seen[next_evict_codepoint]
assert(success != false)
@ -488,13 +488,13 @@ check_glyph_in_atlas :: #force_inline proc( ctx : ^Context, font : Font_ID, entr
cache_glyph_to_atlas( ctx, font, glyph_index, lru_code, atlas_index, entry, region_kind, region, over_sample )
}
assert( lru_get( & region.state, lru_code ) != -1 )
assert( LRU_get( & region.state, lru_code ) != -1 )
mark_batch_codepoint_seen( ctx, lru_code)
return true
}
// ve_fontcache_clear_Draw_List
clear_draw_list :: #force_inline proc ( draw_list : ^Draw_List ) {
// ve_fontcache_clear_drawlist
clear_draw_list :: #force_inline proc ( draw_list : ^DrawList ) {
clear( & draw_list.calls )
clear( & draw_list.indices )
clear( & draw_list.vertices )
@ -538,8 +538,8 @@ directly_draw_massive_glyph :: proc( ctx : ^Context,
dst_size := glyph_dst_size * scale
textspace_x_form( & glyph_position, & glyph_size, glyph_buffer_size )
// Add the glyph Draw_Call.
calls : [2]Draw_Call
// Add the glyph drawcall.
calls : [2]DrawCall
draw_to_target := & calls[0]
{
@ -549,8 +549,8 @@ directly_draw_massive_glyph :: proc( ctx : ^Context,
start_index = u32(len(ctx.draw_list.indices))
blit_quad( & ctx.draw_list,
dst, dst + dst_size,
glyph_position, glyph_position + glyph_size )
dst, dst + dst_size,
glyph_position, glyph_position + glyph_size )
end_index = u32(len(ctx.draw_list.indices))
}
@ -570,9 +570,9 @@ directly_draw_massive_glyph :: proc( ctx : ^Context,
// outside_point represents the center point of the fan.
//
// Note(Original Author):
// WARNING: doesn't actually append Draw_Call; caller is responsible for actually appending the Draw_Call.
// WARNING: doesn't actually append drawcall; caller is responsible for actually appending the drawcall.
// ve_fontcache_draw_filled_path
draw_filled_path :: proc( draw_list : ^Draw_List, outside_point : Vec2, path : []Vertex,
draw_filled_path :: proc( draw_list : ^DrawList, outside_point : Vec2, path : []Vertex,
scale := Vec2 { 1, 1 },
translate := Vec2 { 0, 0 },
debug_print_verbose : b32 = false
@ -615,7 +615,7 @@ draw_filled_path :: proc( draw_list : ^Draw_List, outside_point : Vec2, path : [
}
}
draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^Shaped_Text,
draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^ShapedText,
batch_start_idx, batch_end_idx : i32,
position, scale : Vec2,
snap_width, snap_height : f32 )
@ -634,7 +634,7 @@ draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^Shaped_Text,
region_kind, region, over_sample := decide_codepoint_region( ctx, entry, glyph_index )
lru_code := font_glyph_lru_code( entry.id, glyph_index )
atlas_index := region_kind != .E ? lru_get( & region.state, lru_code ) : -1
atlas_index := region_kind != .E ? LRU_get( & region.state, lru_code ) : -1
bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index )
vbounds_0 := vec2(bounds_0)
vbounds_1 := vec2(bounds_1)
@ -660,7 +660,7 @@ draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^Shaped_Text,
dst_scale := glyph_scale * scale
textspace_x_form( & slot_position, & glyph_scale, atlas_size )
call := Draw_Call_Default
call := DrawCall_Default
call.pass = .Target
call.colour = ctx.colour
call.start_index = u32(len(ctx.draw_list.indices))
@ -677,9 +677,9 @@ draw_text_batch :: proc(ctx: ^Context, entry: ^Entry, shaped: ^Shaped_Text,
// Helper for draw_text, all raw text content should be confirmed to be either formatting or visible shapes before getting cached.
draw_text_shape :: proc( ctx : ^Context,
font : Font_ID,
font : FontID,
entry : ^Entry,
shaped : ^Shaped_Text,
shaped : ^ShapedText,
position, scale : Vec2,
snap_width, snap_height : f32
) -> (cursor_pos : Vec2)
@ -695,7 +695,7 @@ draw_text_shape :: proc( ctx : ^Context,
lru_code := font_glyph_lru_code(entry.id, glyph_index)
atlas_index := cast(i32) -1
if region_kind != .E do atlas_index = lru_get( & region.state, lru_code )
if region_kind != .E do atlas_index = LRU_get( & region.state, lru_code )
if check_glyph_in_atlas( ctx, font, entry, glyph_index, lru_code, atlas_index, region_kind, region, over_sample ) do continue
// We can no longer directly append the shape as it has missing glyphs in the atlas
@ -720,7 +720,7 @@ draw_text_shape :: proc( ctx : ^Context,
flush_glyph_buffer_to_atlas :: proc( ctx : ^Context )
{
// profile(#procedure)
// Flush Draw_Calls to draw list
// Flush drawcalls to draw list
merge_draw_list( & ctx.draw_list, & ctx.glyph_buffer.clear_draw_list )
merge_draw_list( & ctx.draw_list, & ctx.glyph_buffer.draw_list)
clear_draw_list( & ctx.glyph_buffer.draw_list )
@ -729,7 +729,7 @@ flush_glyph_buffer_to_atlas :: proc( ctx : ^Context )
// Clear glyph_update_FBO
if ctx.glyph_buffer.batch_x != 0
{
call := Draw_Call_Default
call := DrawCall_Default
call.pass = .Glyph
call.start_index = 0
call.end_index = 0
@ -739,11 +739,11 @@ flush_glyph_buffer_to_atlas :: proc( ctx : ^Context )
}
}
// ve_fontcache_merge_Draw_List
merge_draw_list :: proc( dst, src : ^Draw_List )
// ve_fontcache_merge_drawlist
merge_draw_list :: proc( dst, src : ^DrawList )
{
// profile(#procedure)
error : Allocator_Error
error : AllocatorError
v_offset := cast(u32) len( dst.vertices )
num_appended : int
@ -766,11 +766,11 @@ merge_draw_list :: proc( dst, src : ^Draw_List )
}
}
optimize_draw_list :: proc(draw_list: ^Draw_List, call_offset: int) {
optimize_draw_list :: proc(draw_list: ^DrawList, call_offset: int) {
// profile(#procedure)
assert(draw_list != nil)
can_merge_draw_calls :: #force_inline proc "contextless" ( a, b : ^Draw_Call ) -> bool {
can_merge_draw_calls :: #force_inline proc "contextless" ( a, b : ^DrawCall ) -> bool {
result := \
a.pass == b.pass &&
a.end_index == b.start_index &&

View File

@ -27,12 +27,16 @@ import "core:mem"
Kilobyte :: mem.Kilobyte
slice_ptr :: mem.slice_ptr
Allocator :: mem.Allocator
Allocator_Error :: mem.Allocator_Error
Allocator :: mem.Allocator
AllocatorError :: mem.Allocator_Error
Arena :: mem.Arena
arena_allocator :: mem.arena_allocator
arena_init :: mem.arena_init
import "codebase:grime"
log :: grime.log
logf :: grime.logf
profile :: grime.profile
//#region("Proc overload mappings")

View File

@ -4,7 +4,7 @@ import "base:runtime"
import "core:simd"
import "core:math"
import core_log "core:log"
// import core_log "core:log"
Colour :: [4]f32
Vec2 :: [2]f32
@ -23,21 +23,21 @@ vec2i_from_vec2 :: #force_inline proc "contextless" ( v2 : Vec2 ) -> Vec2
// This means a single line is limited to 4k buffer
// Logger_Allocator_Buffer : [4 * Kilobyte]u8
log :: proc( msg : string, level := core_log.Level.Info, loc := #caller_location ) {
// log :: proc( msg : string, level := core_log.Level.Info, loc := #caller_location ) {
// temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:])
// context.allocator = arena_allocator(& temp_arena)
// context.temp_allocator = arena_allocator(& temp_arena)
core_log.log( level, msg, location = loc )
}
// core_log.log( level, msg, location = loc )
// }
logf :: proc( fmt : string, args : ..any, level := core_log.Level.Info, loc := #caller_location ) {
// logf :: proc( fmt : string, args : ..any, level := core_log.Level.Info, loc := #caller_location ) {
// temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:])
// context.allocator = arena_allocator(& temp_arena)
// context.temp_allocator = arena_allocator(& temp_arena)
core_log.logf( level, fmt, ..args, location = loc )
}
// core_log.logf( level, fmt, ..args, location = loc )
// }
reload_array :: proc( self : ^[dynamic]$Type, allocator : Allocator ) {
raw := transmute( ^runtime.Raw_Dynamic_Array) self
@ -49,7 +49,7 @@ reload_map :: proc( self : ^map [$KeyType] $EntryType, allocator : Allocator ) {
raw.allocator = allocator
}
font_glyph_lru_code :: #force_inline proc "contextless" ( font : Font_ID, glyph_index : Glyph ) -> (lru_code : u64) {
font_glyph_lru_code :: #force_inline proc "contextless" ( font : FontID, glyph_index : Glyph ) -> (lru_code : u64) {
lru_code = u64(glyph_index) + ( ( 0x100000000 * u64(font) ) & 0xFFFFFFFF00000000 )
return
}
@ -71,11 +71,9 @@ reset_batch_codepoint_state :: #force_inline proc( ctx : ^Context ) {
ctx.temp_codepoint_seen_num = 0
}
USE_F64_PRECISION_ON_X_FORM_OPS :: false
screenspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, size : Vec2 )
{
when USE_F64_PRECISION_ON_X_FORM_OPS
if true
{
pos_64 := vec2_64_from_vec2(position^)
scale_64 := vec2_64_from_vec2(scale^)
@ -103,7 +101,7 @@ screenspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2
textspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2, size : Vec2 )
{
when USE_F64_PRECISION_ON_X_FORM_OPS
if true
{
pos_64 := vec2_64_from_vec2(position^)
scale_64 := vec2_64_from_vec2(scale^)
@ -123,9 +121,9 @@ textspace_x_form :: #force_inline proc "contextless" ( position, scale : ^Vec2,
}
}
USE_MANUAL_SIMD_FOR_BEZIER_OPS :: false
Use_SIMD_For_Bezier_Ops :: false
when ! USE_MANUAL_SIMD_FOR_BEZIER_OPS
when ! Use_SIMD_For_Bezier_Ops
{
// For a provided alpha value,
// allows the function to calculate the position of a point along the curve at any given fraction of its total length

View File

@ -16,14 +16,14 @@ import "core:slice"
import stbtt "vendor:stb/truetype"
import freetype "thirdparty:freetype"
Parser_Kind :: enum u32 {
ParserKind :: enum u32 {
STB_TrueType,
Freetype,
}
Parser_Font_Info :: struct {
ParserFontInfo :: struct {
label : string,
kind : Parser_Kind,
kind : ParserKind,
using _ : struct #raw_union {
stbtt_info : stbtt.fontinfo,
freetype_info : freetype.Face
@ -31,7 +31,7 @@ Parser_Font_Info :: struct {
data : []byte,
}
Glyph_Vert_Type :: enum u8 {
GlyphVertType :: enum u8 {
None,
Move = 1,
Line,
@ -40,22 +40,22 @@ Glyph_Vert_Type :: enum u8 {
}
// Based directly off of stb_truetype's vertex
Parser_Glyph_Vertex :: struct {
ParserGlyphVertex :: struct {
x, y : i16,
contour_x0, contour_y0 : i16,
contour_x1, contour_y1 : i16,
type : Glyph_Vert_Type,
type : GlyphVertType,
padding : u8,
}
// A shape can be a dynamic array free_type or an opaque set of data handled by stb_truetype
Parser_Glyph_Shape :: [dynamic]Parser_Glyph_Vertex
ParserGlyphShape :: [dynamic]ParserGlyphVertex
Parser_Context :: struct {
kind : Parser_Kind,
ParserContext :: struct {
kind : ParserKind,
ft_library : freetype.Library,
}
parser_init :: proc( ctx : ^Parser_Context, kind : Parser_Kind )
parser_init :: proc( ctx : ^ParserContext, kind : ParserKind )
{
switch kind
{
@ -70,23 +70,17 @@ parser_init :: proc( ctx : ^Parser_Context, kind : Parser_Kind )
ctx.kind = kind
}
parser_shutdown :: proc( ctx : ^Parser_Context ) {
parser_shutdown :: proc( ctx : ^ParserContext ) {
// TODO(Ed): Implement
}
parser_load_font :: proc( ctx : ^Parser_Context, label : string, data : []byte ) -> (font : Parser_Font_Info)
parser_load_font :: proc( ctx : ^ParserContext, label : string, data : []byte ) -> (font : ParserFontInfo)
{
switch ctx.kind
{
case .Freetype:
when ODIN_OS == .Windows {
error := freetype.new_memory_face( ctx.ft_library, raw_data(data), cast(i32) len(data), 0, & font.freetype_info )
if error != .Ok do return
}
else when ODIN_OS == .Linux {
error := freetype.new_memory_face( ctx.ft_library, raw_data(data), cast(i64) len(data), 0, & font.freetype_info )
if error != .Ok do return
}
error := freetype.new_memory_face( ctx.ft_library, raw_data(data), cast(i32) len(data), 0, & font.freetype_info )
if error != .Ok do return
case .STB_TrueType:
success := stbtt.InitFont( & font.stbtt_info, raw_data(data), 0 )
@ -99,7 +93,7 @@ parser_load_font :: proc( ctx : ^Parser_Context, label : string, data : []byte )
return
}
parser_unload_font :: proc( font : ^Parser_Font_Info )
parser_unload_font :: proc( font : ^ParserFontInfo )
{
switch font.kind {
case .Freetype:
@ -111,17 +105,12 @@ parser_unload_font :: proc( font : ^Parser_Font_Info )
}
}
parser_find_glyph_index :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, codepoint : rune ) -> (glyph_index : Glyph)
parser_find_glyph_index :: #force_inline proc "contextless" ( font : ^ParserFontInfo, codepoint : rune ) -> (glyph_index : Glyph)
{
switch font.kind
{
case .Freetype:
when ODIN_OS == .Windows {
glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) codepoint )
}
else when ODIN_OS == .Linux {
glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, cast(u64) codepoint )
}
glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) codepoint )
return
case .STB_TrueType:
@ -131,7 +120,7 @@ parser_find_glyph_index :: #force_inline proc "contextless" ( font : ^Parser_Fon
return Glyph(-1)
}
parser_free_shape :: proc( font : ^Parser_Font_Info, shape : Parser_Glyph_Shape )
parser_free_shape :: proc( font : ^ParserFontInfo, shape : ParserGlyphShape )
{
switch font.kind
{
@ -143,19 +132,12 @@ parser_free_shape :: proc( font : ^Parser_Font_Info, shape : Parser_Glyph_Shape
}
}
parser_get_codepoint_horizontal_metrics :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, codepoint : rune ) -> ( advance, to_left_side_glyph : i32 )
parser_get_codepoint_horizontal_metrics :: #force_inline proc "contextless" ( font : ^ParserFontInfo, codepoint : rune ) -> ( advance, to_left_side_glyph : i32 )
{
switch font.kind
{
case .Freetype:
glyph_index : Glyph
when ODIN_OS == .Windows {
glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) codepoint )
}
else when ODIN_OS == .Linux {
glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, cast(u64) codepoint )
}
glyph_index := transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) codepoint )
if glyph_index != 0
{
freetype.load_glyph( font.freetype_info, c.uint(codepoint), { .No_Bitmap, .No_Hinting, .No_Scale } )
@ -174,22 +156,13 @@ parser_get_codepoint_horizontal_metrics :: #force_inline proc "contextless" ( fo
return
}
parser_get_codepoint_kern_advance :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, prev_codepoint, codepoint : rune ) -> i32
parser_get_codepoint_kern_advance :: #force_inline proc "contextless" ( font : ^ParserFontInfo, prev_codepoint, codepoint : rune ) -> i32
{
switch font.kind
{
case .Freetype:
prev_glyph_index : Glyph
glyph_index : Glyph
when ODIN_OS == .Windows {
prev_glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) prev_codepoint )
glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) codepoint )
}
else when ODIN_OS == .Linux {
prev_glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, cast(u64) prev_codepoint )
glyph_index = transmute(Glyph) freetype.get_char_index( font.freetype_info, cast(u64) codepoint )
}
prev_glyph_index := transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) prev_codepoint )
glyph_index := transmute(Glyph) freetype.get_char_index( font.freetype_info, transmute(u32) codepoint )
if prev_glyph_index != 0 && glyph_index != 0
{
kerning : freetype.Vector
@ -203,7 +176,7 @@ parser_get_codepoint_kern_advance :: #force_inline proc "contextless" ( font : ^
return -1
}
parser_get_font_vertical_metrics :: #force_inline proc "contextless" ( font : ^Parser_Font_Info ) -> (ascent, descent, line_gap : i32 )
parser_get_font_vertical_metrics :: #force_inline proc "contextless" ( font : ^ParserFontInfo ) -> (ascent, descent, line_gap : i32 )
{
switch font.kind
{
@ -219,7 +192,7 @@ parser_get_font_vertical_metrics :: #force_inline proc "contextless" ( font : ^P
return
}
parser_get_glyph_box :: #force_inline proc ( font : ^Parser_Font_Info, glyph_index : Glyph ) -> (bounds_0, bounds_1 : Vec2i)
parser_get_glyph_box :: #force_inline proc ( font : ^ParserFontInfo, glyph_index : Glyph ) -> (bounds_0, bounds_1 : Vec2i)
{
switch font.kind
{
@ -242,7 +215,7 @@ parser_get_glyph_box :: #force_inline proc ( font : ^Parser_Font_Info, glyph_ind
return
}
parser_get_glyph_shape :: proc( font : ^Parser_Font_Info, glyph_index : Glyph ) -> (shape : Parser_Glyph_Shape, error : Allocator_Error)
parser_get_glyph_shape :: proc( font : ^ParserFontInfo, glyph_index : Glyph ) -> (shape : ParserGlyphShape, error : AllocatorError)
{
switch font.kind
{
@ -259,14 +232,14 @@ parser_get_glyph_shape :: proc( font : ^Parser_Font_Info, glyph_index : Glyph )
shape_raw.len = int(nverts)
shape_raw.cap = int(nverts)
shape_raw.allocator = runtime.nil_allocator()
error = Allocator_Error.None
error = AllocatorError.None
return
}
return
}
parser_is_glyph_empty :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, glyph_index : Glyph ) -> b32
parser_is_glyph_empty :: #force_inline proc "contextless" ( font : ^ParserFontInfo, glyph_index : Glyph ) -> b32
{
switch font.kind
{
@ -289,7 +262,7 @@ parser_is_glyph_empty :: #force_inline proc "contextless" ( font : ^Parser_Font_
return false
}
parser_scale :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, size : f32 ) -> f32
parser_scale :: #force_inline proc "contextless" ( font : ^ParserFontInfo, size : f32 ) -> f32
{
size_scale := size < 0.0 ? \
parser_scale_for_pixel_height( font, -size ) \
@ -298,7 +271,7 @@ parser_scale :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, siz
return size_scale
}
parser_scale_for_pixel_height :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, size : f32 ) -> f32
parser_scale_for_pixel_height :: #force_inline proc "contextless" ( font : ^ParserFontInfo, size : f32 ) -> f32
{
switch font.kind {
case .Freetype:
@ -312,7 +285,7 @@ parser_scale_for_pixel_height :: #force_inline proc "contextless" ( font : ^Pars
return 0
}
parser_scale_for_mapping_em_to_pixels :: #force_inline proc "contextless" ( font : ^Parser_Font_Info, size : f32 ) -> f32
parser_scale_for_mapping_em_to_pixels :: #force_inline proc "contextless" ( font : ^ParserFontInfo, size : f32 ) -> f32
{
switch font.kind {
case .Freetype:

View File

@ -1,14 +1,14 @@
package vefontcache
Shaped_Text :: struct {
ShapedText :: struct {
glyphs : [dynamic]Glyph,
positions : [dynamic]Vec2,
end_cursor_pos : Vec2,
size : Vec2,
}
Shaped_Text_Cache :: struct {
storage : [dynamic]Shaped_Text,
ShapedTextCache :: struct {
storage : [dynamic]ShapedText,
state : LRU_Cache,
next_cache_id : i32,
}
@ -19,11 +19,11 @@ shape_lru_hash :: #force_inline proc "contextless" ( hash : ^u64, bytes : []byte
}
}
shape_text_cached :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string, entry : ^Entry ) -> ^Shaped_Text
shape_text_cached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, entry : ^Entry ) -> ^ShapedText
{
// profile(#procedure)
font := font
font_bytes := slice_ptr( transmute(^byte) & font, size_of(Font_ID) )
font_bytes := slice_ptr( transmute(^byte) & font, size_of(FontID) )
text_bytes := transmute( []byte) text_utf8
lru_code : u64
@ -33,23 +33,23 @@ shape_text_cached :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string, e
shape_cache := & ctx.shape_cache
state := & ctx.shape_cache.state
shape_cache_idx := lru_get( state, lru_code )
shape_cache_idx := LRU_get( state, lru_code )
if shape_cache_idx == -1
{
if shape_cache.next_cache_id < i32(state.capacity) {
shape_cache_idx = shape_cache.next_cache_id
shape_cache.next_cache_id += 1
evicted := lru_put( state, lru_code, shape_cache_idx )
evicted := LRU_put( state, lru_code, shape_cache_idx )
}
else
{
next_evict_idx := lru_get_next_evicted( state )
next_evict_idx := LRU_get_next_evicted( state )
assert( next_evict_idx != 0xFFFFFFFFFFFFFFFF )
shape_cache_idx = lru_peek( state, next_evict_idx, must_find = true )
shape_cache_idx = LRU_peek( state, next_evict_idx, must_find = true )
assert( shape_cache_idx != - 1 )
lru_put( state, lru_code, shape_cache_idx )
LRU_put( state, lru_code, shape_cache_idx )
}
shape_entry := & shape_cache.storage[ shape_cache_idx ]
@ -59,7 +59,7 @@ shape_text_cached :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string, e
return & shape_cache.storage[ shape_cache_idx ]
}
shape_text_uncached :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string, entry : ^Entry, output : ^Shaped_Text )
shape_text_uncached :: proc( ctx : ^Context, font : FontID, text_utf8 : string, entry : ^Entry, output : ^ShapedText )
{
// profile(#procedure)
assert( ctx != nil )
@ -106,7 +106,7 @@ shape_text_uncached :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string,
prev_codepoint = rune(0)
continue
}
if abs( entry.size ) <= ADVANCE_SNAP_SMALLFONT_SIZE {
if abs( entry.size ) <= Advance_Snap_Smallfont_Size {
position.x = position.x
}

View File

@ -6,35 +6,35 @@ Note(Ed): The only reason I didn't directly use harfbuzz is because hamza exists
import "core:c"
import "thirdparty:harfbuzz"
Shaper_Kind :: enum {
ShaperKind :: enum {
Naive = 0,
Harfbuzz = 1,
}
Shaper_Context :: struct {
ShaperContext :: struct {
hb_buffer : harfbuzz.Buffer,
}
Shaper_Info :: struct {
ShaperInfo :: struct {
blob : harfbuzz.Blob,
face : harfbuzz.Face,
font : harfbuzz.Font,
}
shaper_init :: proc( ctx : ^Shaper_Context )
shaper_init :: proc( ctx : ^ShaperContext )
{
ctx.hb_buffer = harfbuzz.buffer_create()
assert( ctx.hb_buffer != nil, "VEFontCache.shaper_init: Failed to create harfbuzz buffer")
}
shaper_shutdown :: proc( ctx : ^Shaper_Context )
shaper_shutdown :: proc( ctx : ^ShaperContext )
{
if ctx.hb_buffer != nil {
harfbuzz.buffer_destroy( ctx.hb_buffer )
}
}
shaper_load_font :: proc( ctx : ^Shaper_Context, label : string, data : []byte, user_data : rawptr ) -> (info : Shaper_Info)
shaper_load_font :: proc( ctx : ^ShaperContext, label : string, data : []byte, user_data : rawptr ) -> (info : ShaperInfo)
{
using info
blob = harfbuzz.blob_create( raw_data(data), cast(c.uint) len(data), harfbuzz.Memory_Mode.READONLY, user_data, nil )
@ -43,7 +43,7 @@ shaper_load_font :: proc( ctx : ^Shaper_Context, label : string, data : []byte,
return
}
shaper_unload_font :: proc( ctx : ^Shaper_Info )
shaper_unload_font :: proc( ctx : ^ShaperInfo )
{
using ctx
if blob != nil do harfbuzz.font_destroy( font )
@ -51,7 +51,7 @@ shaper_unload_font :: proc( ctx : ^Shaper_Info )
if blob != nil do harfbuzz.blob_destroy( blob )
}
shaper_shape_from_text :: proc( ctx : ^Shaper_Context, info : ^Shaper_Info, output :^Shaped_Text, text_utf8 : string,
shaper_shape_from_text :: proc( ctx : ^ShaperContext, info : ^ShaperInfo, output :^ShapedText, text_utf8 : string,
ascent, descent, line_gap : i32, size, size_scale : f32 )
{
// profile(#procedure)
@ -69,7 +69,7 @@ shaper_shape_from_text :: proc( ctx : ^Shaper_Context, info : ^Shaper_Info, outp
line_height := (ascent - descent + line_gap) * size_scale
position, vertical_position : f32
shape_run :: proc( buffer : harfbuzz.Buffer, script : harfbuzz.Script, font : harfbuzz.Font, output : ^Shaped_Text,
shape_run :: proc( buffer : harfbuzz.Buffer, script : harfbuzz.Script, font : harfbuzz.Font, output : ^ShapedText,
position, vertical_position, max_line_width: ^f32, line_count: ^int,
ascent, descent, line_gap, size, size_scale: f32 )
{
@ -105,7 +105,7 @@ shaper_shape_from_text :: proc( ctx : ^Shaper_Context, info : ^Shaper_Info, outp
(line_count^) += 1
continue
}
if abs( size ) <= ADVANCE_SNAP_SMALLFONT_SIZE
if abs( size ) <= Advance_Snap_Smallfont_Size
{
(position^) = ceil( position^ )
}

View File

@ -7,15 +7,15 @@ package vefontcache
import "base:runtime"
ADVANCE_SNAP_SMALLFONT_SIZE :: 0
Advance_Snap_Smallfont_Size :: 0
Font_ID :: distinct i64
FontID :: distinct i64
Glyph :: distinct i32
Entry :: struct {
parser_info : Parser_Font_Info,
shaper_info : Shaper_Info,
id : Font_ID,
parser_info : ParserFontInfo,
shaper_info : ShaperInfo,
id : FontID,
used : b32,
curve_quality : f32,
size : f32,
@ -32,8 +32,8 @@ Entry_Default :: Entry {
Context :: struct {
backing : Allocator,
parser_ctx : Parser_Context,
shaper_ctx : Shaper_Context,
parser_ctx : ParserContext,
shaper_ctx : ShaperContext,
entries : [dynamic]Entry,
@ -54,10 +54,10 @@ Context :: struct {
calls_offset : int,
},
draw_list : Draw_List,
draw_list : DrawList,
atlas : Atlas,
glyph_buffer : Glyph_Draw_Buffer,
shape_cache : Shaped_Text_Cache,
glyph_buffer : GlyphDrawBuffer,
shape_cache : ShapedTextCache,
default_curve_quality : i32,
text_shape_adv : b32,
@ -69,23 +69,23 @@ Context :: struct {
//#region("lifetime")
Init_Atlas_Region_Params :: struct {
InitAtlasRegionParams :: struct {
width : u32,
height : u32,
}
Init_Atlas_Params :: struct {
width : u32,
height : u32,
glyph_padding : u32,
InitAtlasParams :: struct {
width : u32,
height : u32,
glyph_padding : u32,
region_a : Init_Atlas_Region_Params,
region_b : Init_Atlas_Region_Params,
region_c : Init_Atlas_Region_Params,
region_d : Init_Atlas_Region_Params,
region_a : InitAtlasRegionParams,
region_b : InitAtlasRegionParams,
region_c : InitAtlasRegionParams,
region_d : InitAtlasRegionParams,
}
Init_Atlas_Params_Default :: Init_Atlas_Params {
InitAtlasParams_Default :: InitAtlasParams {
width = 4096,
height = 2048,
glyph_padding = 4,
@ -108,34 +108,34 @@ Init_Atlas_Params_Default :: Init_Atlas_Params {
}
}
Init_Glyph_Draw_Params :: struct {
over_sample : Vec2i,
buffer_batch : u32,
draw_padding : u32,
InitGlyphDrawParams :: struct {
over_sample : Vec2i,
buffer_batch : u32,
draw_padding : u32,
}
Init_Glyph_Draw_Params_Default :: Init_Glyph_Draw_Params {
InitGlyphDrawParams_Default :: InitGlyphDrawParams {
over_sample = { 8, 8 },
buffer_batch = 4,
draw_padding = Init_Atlas_Params_Default.glyph_padding,
draw_padding = InitAtlasParams_Default.glyph_padding,
}
Init_Shape_Cache_Params :: struct {
InitShapeCacheParams :: struct {
capacity : u32,
reserve_length : u32,
}
Init_Shape_Cache_Params_Default :: Init_Shape_Cache_Params {
capacity = 8 * 1024,
reserve_length = 256,
InitShapeCacheParams_Default :: InitShapeCacheParams {
capacity = 8 * 1024,
reserve_length = 256,
}
// ve_fontcache_init
startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType,
startup :: proc( ctx : ^Context, parser_kind : ParserKind,
allocator := context.allocator,
atlas_params := Init_Atlas_Params_Default,
glyph_draw_params := Init_Glyph_Draw_Params_Default,
shape_cache_params := Init_Shape_Cache_Params_Default,
atlas_params := InitAtlasParams_Default,
glyph_draw_params := InitGlyphDrawParams_Default,
shape_cache_params := InitShapeCacheParams_Default,
use_advanced_text_shaper : b32 = true,
snap_shape_position : b32 = true,
default_curve_quality : u32 = 3,
@ -158,7 +158,7 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType,
}
ctx.default_curve_quality = default_curve_quality
error : Allocator_Error
error : AllocatorError
entries, error = make( [dynamic]Entry, len = 0, cap = entires_reserve )
assert(error == .None, "VEFontCache.init : Failed to allocate entries")
@ -174,10 +174,10 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType,
draw_list.indices, error = make( [dynamic]u32, len = 0, cap = 8 * Kilobyte )
assert(error == .None, "VEFontCache.init : Failed to allocate draw_list.indices")
draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = 512 )
draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = 512 )
assert(error == .None, "VEFontCache.init : Failed to allocate draw_list.calls")
init_atlas_region :: proc( region : ^Atlas_Region, params : Init_Atlas_Params, region_params : Init_Atlas_Region_Params, factor : Vec2i, expected_cap : i32 )
init_atlas_region :: proc( region : ^AtlasRegion, params : InitAtlasParams, region_params : InitAtlasRegionParams, factor : Vec2i, expected_cap : i32 )
{
using region
@ -194,8 +194,8 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType,
}
assert( capacity.x * capacity.y == expected_cap )
error : Allocator_Error
lru_init( & state, capacity.x * capacity.y )
error : AllocatorError
LRU_init( & state, capacity.x * capacity.y )
}
init_atlas_region( & atlas.region_a, atlas_params, atlas_params.region_a, { 4, 2}, 1024 )
init_atlas_region( & atlas.region_b, atlas_params, atlas_params.region_b, { 4, 2}, 512 )
@ -214,9 +214,9 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType,
atlas.region_d.offset.x = atlas.width / 2
atlas.region_d.offset.y = 0
lru_init( & shape_cache.state, i32(shape_cache_params.capacity) )
LRU_init( & shape_cache.state, i32(shape_cache_params.capacity) )
shape_cache.storage, error = make( [dynamic]Shaped_Text, shape_cache_params.capacity )
shape_cache.storage, error = make( [dynamic]ShapedText, shape_cache_params.capacity )
assert(error == .None, "VEFontCache.init : Failed to allocate shape_cache.storage")
for idx : u32 = 0; idx < shape_cache_params.capacity; idx += 1 {
@ -228,7 +228,7 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType,
positions, error = make( [dynamic]Vec2, len = 0, cap = shape_cache_params.reserve_length )
assert( error == .None, "VEFontCache.init : Failed to allocate positions array for shape cache storage" )
draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
assert( error == .None, "VEFontCache.init : Failed to allocate calls for draw_list" )
draw_list.indices, error = make( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 6 )
@ -247,7 +247,7 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType,
height = atlas.region_d.height * i32(over_sample.y)
draw_padding = cast(i32) glyph_draw_params.draw_padding
draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
assert( error == .None, "VEFontCache.init : Failed to allocate calls for draw_list" )
draw_list.indices, error = make( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 6 )
@ -256,7 +256,7 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType,
draw_list.vertices, error = make( [dynamic]Vertex, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 4 )
assert( error == .None, "VEFontCache.init : Failed to allocate vertices array for draw_list" )
clear_draw_list.calls, error = make( [dynamic]Draw_Call, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
clear_draw_list.calls, error = make( [dynamic]DrawCall, len = 0, cap = glyph_draw_params.buffer_batch * 2 )
assert( error == .None, "VEFontCache.init : Failed to allocate calls for calls for clear_draw_list" )
clear_draw_list.indices, error = make( [dynamic]u32, len = 0, cap = glyph_draw_params.buffer_batch * 2 * 4 )
@ -285,12 +285,12 @@ hot_reload :: proc( ctx : ^Context, allocator : Allocator )
reload_array( & draw_list.indices, allocator )
reload_array( & draw_list.calls, allocator )
lru_reload( & atlas.region_a.state, allocator)
lru_reload( & atlas.region_b.state, allocator)
lru_reload( & atlas.region_c.state, allocator)
lru_reload( & atlas.region_d.state, allocator)
LRU_reload( & atlas.region_a.state, allocator)
LRU_reload( & atlas.region_b.state, allocator)
LRU_reload( & atlas.region_c.state, allocator)
LRU_reload( & atlas.region_d.state, allocator)
lru_reload( & shape_cache.state, allocator )
LRU_reload( & shape_cache.state, allocator )
for idx : i32 = 0; idx < i32(len(shape_cache.storage)); idx += 1 {
stroage_entry := & shape_cache.storage[idx]
using stroage_entry
@ -308,7 +308,7 @@ hot_reload :: proc( ctx : ^Context, allocator : Allocator )
reload_array( & glyph_buffer.clear_draw_list.vertices, allocator )
reload_array( & shape_cache.storage, allocator )
lru_reload( & shape_cache.state, allocator )
LRU_reload( & shape_cache.state, allocator )
}
// ve_foncache_shutdown
@ -330,10 +330,10 @@ shutdown :: proc( ctx : ^Context )
delete( draw_list.indices )
delete( draw_list.calls )
lru_free( & atlas.region_a.state )
lru_free( & atlas.region_b.state )
lru_free( & atlas.region_c.state )
lru_free( & atlas.region_d.state )
LRU_free( & atlas.region_a.state )
LRU_free( & atlas.region_b.state )
LRU_free( & atlas.region_c.state )
LRU_free( & atlas.region_d.state )
for idx : i32 = 0; idx < i32(len(shape_cache.storage)); idx += 1 {
stroage_entry := & shape_cache.storage[idx]
@ -342,7 +342,7 @@ shutdown :: proc( ctx : ^Context )
delete( glyphs )
delete( positions )
}
lru_free( & shape_cache.state )
LRU_free( & shape_cache.state )
delete( glyph_buffer.draw_list.vertices )
delete( glyph_buffer.draw_list.indices )
@ -357,7 +357,7 @@ shutdown :: proc( ctx : ^Context )
}
// ve_fontcache_load
load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32, glyph_curve_quality : u32 = 0 ) -> (font_id : Font_ID)
load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32, glyph_curve_quality : u32 = 0 ) -> (font_id : FontID)
{
assert( ctx != nil )
assert( len(data) > 0 )
@ -386,9 +386,9 @@ load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32,
shaper_info = shaper_load_font( & shaper_ctx, label, data, transmute(rawptr) id )
size = size_px
size_scale = size_px < 0.0 ? \
size_scale = size_px < 0.0 ? \
parser_scale_for_pixel_height( & parser_info, -size_px ) \
: parser_scale_for_mapping_em_to_pixels( & parser_info, size_px )
: parser_scale_for_mapping_em_to_pixels( & parser_info, size_px )
if glyph_curve_quality == 0 {
curve_quality = f32(ctx.default_curve_quality)
@ -397,15 +397,15 @@ load_font :: proc( ctx : ^Context, label : string, data : []byte, size_px : f32,
curve_quality = f32(glyph_curve_quality)
}
}
entry.id = Font_ID(id)
ctx.entries[ id ].id = Font_ID(id)
entry.id = FontID(id)
ctx.entries[ id ].id = FontID(id)
font_id = Font_ID(id)
font_id = FontID(id)
return
}
// ve_fontcache_unload
unload_font :: proc( ctx : ^Context, font : Font_ID )
unload_font :: proc( ctx : ^Context, font : FontID )
{
assert( ctx != nil )
assert( font >= 0 && int(font) < len(ctx.entries) )
@ -430,12 +430,12 @@ configure_snap :: #force_inline proc( ctx : ^Context, snap_width, snap_height :
ctx.snap_height = f32(snap_height)
}
get_cursor_pos :: #force_inline proc( ctx : ^Context ) -> Vec2 { assert(ctx != nil); return ctx.cursor_pos }
set_colour :: #force_inline proc( ctx : ^Context, colour : Colour ) { assert(ctx != nil); ctx.colour = colour }
get_cursor_pos :: #force_inline proc "contextless" ( ctx : ^Context ) -> Vec2 { return ctx.cursor_pos }
set_colour :: #force_inline proc "contextless" ( ctx : ^Context, colour : Colour ) { ctx.colour = colour }
draw_text :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string, position, scale : Vec2 ) -> b32
draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position, scale : Vec2 ) -> b32
{
// profile(#procedure)
profile(#procedure)
assert( ctx != nil )
assert( font >= 0 && int(font) < len(ctx.entries) )
@ -463,14 +463,14 @@ draw_text :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string, position,
return true
}
// ve_fontcache_Draw_List
get_draw_list :: proc( ctx : ^Context, optimize_before_returning := true ) -> ^Draw_List {
// ve_fontcache_drawlist
get_draw_list :: proc( ctx : ^Context, optimize_before_returning := true ) -> ^DrawList {
assert( ctx != nil )
if optimize_before_returning do optimize_draw_list( & ctx.draw_list, 0 )
return & ctx.draw_list
}
get_draw_list_layer :: proc( ctx : ^Context, optimize_before_returning := true ) -> (vertices : []Vertex, indices : []u32, calls : []Draw_Call) {
get_draw_list_layer :: proc( ctx : ^Context, optimize_before_returning := true ) -> (vertices : []Vertex, indices : []u32, calls : []DrawCall) {
assert( ctx != nil )
if optimize_before_returning do optimize_draw_list( & ctx.draw_list, ctx.draw_layer.calls_offset )
vertices = ctx.draw_list.vertices[ ctx.draw_layer.vertices_offset : ]
@ -479,7 +479,7 @@ get_draw_list_layer :: proc( ctx : ^Context, optimize_before_returning := true )
return
}
// ve_fontcache_flush_Draw_List
// ve_fontcache_flush_drawlist
flush_draw_list :: proc( ctx : ^Context ) {
assert( ctx != nil )
using ctx
@ -501,7 +501,7 @@ flush_draw_list_layer :: proc( ctx : ^Context ) {
//#region("metrics")
measure_text_size :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string ) -> (measured : Vec2)
measure_text_size :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) -> (measured : Vec2)
{
// profile(#procedure)
assert( ctx != nil )
@ -512,7 +512,7 @@ measure_text_size :: proc( ctx : ^Context, font : Font_ID, text_utf8 : string )
return shaped.size
}
get_font_vertical_metrics :: #force_inline proc ( ctx : ^Context, font : Font_ID ) -> ( ascent, descent, line_gap : f32 )
get_font_vertical_metrics :: #force_inline proc ( ctx : ^Context, font : FontID ) -> ( ascent, descent, line_gap : f32 )
{
assert( ctx != nil )
assert( font >= 0 && int(font) < len(ctx.entries) )

View File

@ -52,7 +52,7 @@ sokol_app_cleanup_callback :: proc "c" () {
log("sokol_app: Confirmed cleanup")
}
sokol_app_alloc :: proc "c" ( size : uint, user_data : rawptr ) -> rawptr {
sokol_app_alloc :: proc "c" ( size : u64, user_data : rawptr ) -> rawptr {
context = get_state().sokol_context
block, error := alloc( int(size), allocator = persistent_slab_allocator() )
ensure(error == AllocatorError.None, "sokol_app allocation failed")
@ -235,7 +235,7 @@ sokol_app_event_callback :: proc "c" (sokol_event : ^sokol_app.Event)
#region("Sokol GFX")
sokol_gfx_alloc :: proc "c" ( size : uint, user_data : rawptr ) -> rawptr {
sokol_gfx_alloc :: proc "c" ( size : u64, user_data : rawptr ) -> rawptr {
context = get_state().sokol_context
block, error := alloc( int(size), allocator = persistent_slab_allocator() )
ensure(error == AllocatorError.None, "sokol_gfx allocation failed")

View File

@ -223,7 +223,7 @@ render_mode_screenspace :: proc( screen_extent : Extents2, screen_ui : ^UI_State
debug_text("Mouse Position (Workspace View): %0.2f", screen_to_ws_view_pos(input.mouse.pos) )
}
if true
if false
{
ui := & project.workspace.ui
@ -243,7 +243,7 @@ render_mode_screenspace :: proc( screen_extent : Extents2, screen_ui : ^UI_State
}
}
if true
if false
{
ui := & screen_ui
@ -260,7 +260,7 @@ render_mode_screenspace :: proc( screen_extent : Extents2, screen_ui : ^UI_State
}
}
if true {
if false {
state.config.font_size_canvas_scalar = 1.5
zoom_adjust_size := 16 * state.project.workspace.cam.zoom
over_sample := f32(state.config.font_size_canvas_scalar)
@ -301,8 +301,8 @@ render_text_layer :: proc( screen_extent : Vec2, ve_ctx : ^ve.Context, render :
vbuf_layer_slice, ibuf_layer_slice, calls_layer_slice := ve.get_draw_list_layer( ve_ctx )
vbuf_ve_range := Range{ raw_data(vbuf_layer_slice), cast(uint) len(vbuf_layer_slice) * size_of(ve.Vertex) }
ibuf_ve_range := Range{ raw_data(ibuf_layer_slice), cast(uint) len(ibuf_layer_slice) * size_of(u32) }
vbuf_ve_range := Range{ raw_data(vbuf_layer_slice), cast(u64) len(vbuf_layer_slice) * size_of(ve.Vertex) }
ibuf_ve_range := Range{ raw_data(ibuf_layer_slice), cast(u64) len(ibuf_layer_slice) * size_of(u32) }
gfx.append_buffer( draw_list_vbuf, vbuf_ve_range )
gfx.append_buffer( draw_list_ibuf, ibuf_ve_range )
@ -353,6 +353,7 @@ render_text_layer :: proc( screen_extent : Vec2, ve_ctx : ^ve.Context, render :
},
index_buffer = draw_list_ibuf,
index_buffer_offset = 0,//i32(draw_call.start_index) * size_of(u32),
fs = {},
}
gfx.apply_bindings( bindings )
@ -380,7 +381,7 @@ render_text_layer :: proc( screen_extent : Vec2, ve_ctx : ^ve.Context, render :
gfx.apply_pipeline( atlas_pipeline )
fs_uniform := Ve_Blit_Atlas_Fs_Params { region = cast(i32) draw_call.region }
gfx.apply_uniforms( UB_ve_blit_atlas_fs_params, Range { & fs_uniform, size_of(Ve_Blit_Atlas_Fs_Params) })
gfx.apply_uniforms( ShaderStage.FS, SLOT_ve_blit_atlas_fs_params, Range { & fs_uniform, size_of(Ve_Blit_Atlas_Fs_Params) })
gfx.apply_bindings(Bindings {
vertex_buffers = {
@ -391,8 +392,10 @@ render_text_layer :: proc( screen_extent : Vec2, ve_ctx : ^ve.Context, render :
},
index_buffer = draw_list_ibuf,
index_buffer_offset = 0,//i32(draw_call.start_index) * size_of(u32),
images = { IMG_ve_blit_atlas_src_texture = glyph_rt_color, },
samplers = { SMP_ve_blit_atlas_src_sampler = glyph_rt_sampler, },
fs = {
images = { SLOT_ve_blit_atlas_src_texture = glyph_rt_color, },
samplers = { SLOT_ve_blit_atlas_src_sampler = glyph_rt_sampler, },
},
})
// 3. Use the atlas to then render the text.
@ -425,7 +428,7 @@ render_text_layer :: proc( screen_extent : Vec2, ve_ctx : ^ve.Context, render :
src_rt = glyph_rt_color
src_sampler = glyph_rt_sampler
}
gfx.apply_uniforms( UB_ve_draw_text_fs_params, Range { & fs_target_uniform, size_of(Ve_Draw_Text_Fs_Params) })
gfx.apply_uniforms( ShaderStage.FS, SLOT_ve_draw_text_fs_params, Range { & fs_target_uniform, size_of(Ve_Draw_Text_Fs_Params) })
gfx.apply_bindings(Bindings {
vertex_buffers = {
@ -436,8 +439,10 @@ render_text_layer :: proc( screen_extent : Vec2, ve_ctx : ^ve.Context, render :
},
index_buffer = draw_list_ibuf,
index_buffer_offset = 0,//i32(draw_call.start_index) * size_of(u32),
images = { IMG_ve_draw_text_src_texture = src_rt, },
samplers = { SMP_ve_draw_text_src_sampler = src_sampler, },
fs = {
images = { SLOT_ve_draw_text_src_texture = src_rt, },
samplers = { SLOT_ve_draw_text_src_sampler = src_sampler, },
},
})
}

View File

@ -23,7 +23,7 @@ FontID :: struct {
FontDef :: struct {
path_file : string,
default_size : i32,
size_table : [Font_Largest_Px_Size / Font_Size_Interval] ve.Font_ID,
size_table : [Font_Largest_Px_Size / Font_Size_Interval] ve.FontID,
}
FontProviderContext :: struct
@ -114,7 +114,7 @@ font_load :: proc(path_file : string,
Font_Use_Default_Size :: f32(0.0)
font_provider_resolve_draw_id :: proc( id : FontID, size := Font_Use_Default_Size ) -> (ve_id :ve.Font_ID, resolved_size : i32)
font_provider_resolve_draw_id :: proc( id : FontID, size := Font_Use_Default_Size ) -> (ve_id :ve.FontID, resolved_size : i32)
{
provider_data := get_state().font_provider_ctx; using provider_data

View File

@ -87,12 +87,12 @@ font_provider_setup_sokol_gfx_objects :: proc( ctx : ^VE_RenderData, ve_ctx : ve
vs_layout : VertexLayoutState
{
using vs_layout
attrs[ATTR_ve_render_glyph_v_position] = VertexAttributeState {
attrs[ATTR_ve_render_glyph_vs_v_position] = VertexAttributeState {
format = VertexFormat.FLOAT2,
offset = 0,
buffer_index = 0,
}
attrs[ATTR_ve_render_glyph_v_texture] = VertexAttributeState {
attrs[ATTR_ve_render_glyph_vs_v_texture] = VertexAttributeState {
format = VertexFormat.FLOAT2,
offset = size_of(Vec2),
buffer_index = 0,
@ -226,12 +226,12 @@ font_provider_setup_sokol_gfx_objects :: proc( ctx : ^VE_RenderData, ve_ctx : ve
vs_layout : VertexLayoutState
{
using vs_layout
attrs[ATTR_ve_blit_atlas_v_position] = VertexAttributeState {
attrs[ATTR_ve_blit_atlas_vs_v_position] = VertexAttributeState {
format = VertexFormat.FLOAT2,
offset = 0,
buffer_index = 0,
}
attrs[ATTR_ve_blit_atlas_v_texture] = VertexAttributeState {
attrs[ATTR_ve_blit_atlas_vs_v_texture] = VertexAttributeState {
format = VertexFormat.FLOAT2,
offset = size_of(Vec2),
buffer_index = 0,
@ -365,12 +365,12 @@ font_provider_setup_sokol_gfx_objects :: proc( ctx : ^VE_RenderData, ve_ctx : ve
vs_layout : VertexLayoutState
{
using vs_layout
attrs[ATTR_ve_draw_text_v_position] = VertexAttributeState {
attrs[ATTR_ve_draw_text_vs_v_position] = VertexAttributeState {
format = VertexFormat.FLOAT2,
offset = 0,
buffer_index = 0,
}
attrs[ATTR_ve_draw_text_v_texture] = VertexAttributeState {
attrs[ATTR_ve_draw_text_vs_v_texture] = VertexAttributeState {
format = VertexFormat.FLOAT2,
offset = size_of(Vec2),
buffer_index = 0,

View File

@ -12,29 +12,31 @@ import sg "thirdparty:sokol/gfx"
=========
Shader program: 've_blit_atlas':
Get shader desc: ve_blit_atlas_shader_desc(sg.query_backend())
Vertex Shader: ve_blit_atlas_vs
Fragment Shader: ve_blit_atlas_fs
Attributes:
ATTR_ve_blit_atlas_v_position => 0
ATTR_ve_blit_atlas_v_texture => 1
Bindings:
Uniform block 've_blit_atlas_fs_params':
Odin struct: Ve_Blit_Atlas_Fs_Params
Bind slot: UB_ve_blit_atlas_fs_params => 0
Image 've_blit_atlas_src_texture':
Image type: ._2D
Sample type: .FLOAT
Multisampled: false
Bind slot: IMG_ve_blit_atlas_src_texture => 0
Sampler 've_blit_atlas_src_sampler':
Type: .FILTERING
Bind slot: SMP_ve_blit_atlas_src_sampler => 0
Vertex shader: ve_blit_atlas_vs
Attributes:
ATTR_ve_blit_atlas_vs_v_position => 0
ATTR_ve_blit_atlas_vs_v_texture => 1
Fragment shader: ve_blit_atlas_fs
Uniform block 've_blit_atlas_fs_params':
Odin struct: Ve_Blit_Atlas_Fs_Params
Bind slot: SLOT_ve_blit_atlas_fs_params => 0
Image 've_blit_atlas_src_texture':
Image type: ._2D
Sample type: .FLOAT
Multisampled: false
Bind slot: SLOT_ve_blit_atlas_src_texture => 0
Sampler 've_blit_atlas_src_sampler':
Type: .FILTERING
Bind slot: SLOT_ve_blit_atlas_src_sampler => 0
Image Sampler Pair 've_blit_atlas_src_texture_ve_blit_atlas_src_sampler':
Image: ve_blit_atlas_src_texture
Sampler: ve_blit_atlas_src_sampler
*/
ATTR_ve_blit_atlas_v_position :: 0
ATTR_ve_blit_atlas_v_texture :: 1
UB_ve_blit_atlas_fs_params :: 0
IMG_ve_blit_atlas_src_texture :: 0
SMP_ve_blit_atlas_src_sampler :: 0
ATTR_ve_blit_atlas_vs_v_position :: 0
ATTR_ve_blit_atlas_vs_v_texture :: 1
SLOT_ve_blit_atlas_fs_params :: 0
SLOT_ve_blit_atlas_src_texture :: 0
SLOT_ve_blit_atlas_src_sampler :: 0
Ve_Blit_Atlas_Fs_Params :: struct #align(16) {
using _: struct #packed {
region: i32,
@ -76,7 +78,7 @@ Ve_Blit_Atlas_Fs_Params :: struct #align(16) {
return stage_output;
}
*/
@(private="file")
@(private)
ve_blit_atlas_vs_source_hlsl4 := [705]u8 {
0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x67,0x6c,
0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,
@ -199,7 +201,7 @@ ve_blit_atlas_vs_source_hlsl4 := [705]u8 {
return stage_output;
}
*/
@(private="file")
@(private)
ve_blit_atlas_fs_source_hlsl4 := [2140]u8 {
0x63,0x62,0x75,0x66,0x66,0x65,0x72,0x20,0x76,0x65,0x5f,0x62,0x6c,0x69,0x74,0x5f,
0x61,0x74,0x6c,0x61,0x73,0x5f,0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x20,
@ -341,31 +343,27 @@ ve_blit_atlas_shader_desc :: proc (backend: sg.Backend) -> sg.Shader_Desc {
desc.label = "ve_blit_atlas_shader"
#partial switch backend {
case .D3D11:
desc.vertex_func.source = transmute(cstring)&ve_blit_atlas_vs_source_hlsl4
desc.vertex_func.d3d11_target = "vs_4_0"
desc.vertex_func.entry = "main"
desc.fragment_func.source = transmute(cstring)&ve_blit_atlas_fs_source_hlsl4
desc.fragment_func.d3d11_target = "ps_4_0"
desc.fragment_func.entry = "main"
desc.attrs[0].hlsl_sem_name = "TEXCOORD"
desc.attrs[0].hlsl_sem_index = 0
desc.attrs[1].hlsl_sem_name = "TEXCOORD"
desc.attrs[1].hlsl_sem_index = 1
desc.uniform_blocks[0].stage = .FRAGMENT
desc.uniform_blocks[0].layout = .STD140
desc.uniform_blocks[0].size = 16
desc.uniform_blocks[0].hlsl_register_b_n = 0
desc.images[0].stage = .FRAGMENT
desc.images[0].multisampled = false
desc.images[0].image_type = ._2D
desc.images[0].sample_type = .FLOAT
desc.images[0].hlsl_register_t_n = 0
desc.samplers[0].stage = .FRAGMENT
desc.samplers[0].sampler_type = .FILTERING
desc.samplers[0].hlsl_register_s_n = 0
desc.image_sampler_pairs[0].stage = .FRAGMENT
desc.image_sampler_pairs[0].image_slot = 0
desc.image_sampler_pairs[0].sampler_slot = 0
desc.attrs[0].sem_name = "TEXCOORD"
desc.attrs[0].sem_index = 0
desc.attrs[1].sem_name = "TEXCOORD"
desc.attrs[1].sem_index = 1
desc.vs.source = transmute(cstring)&ve_blit_atlas_vs_source_hlsl4
desc.vs.d3d11_target = "vs_4_0"
desc.vs.entry = "main"
desc.fs.source = transmute(cstring)&ve_blit_atlas_fs_source_hlsl4
desc.fs.d3d11_target = "ps_4_0"
desc.fs.entry = "main"
desc.fs.uniform_blocks[0].size = 16
desc.fs.uniform_blocks[0].layout = .STD140
desc.fs.images[0].used = true
desc.fs.images[0].multisampled = false
desc.fs.images[0].image_type = ._2D
desc.fs.images[0].sample_type = .FLOAT
desc.fs.samplers[0].used = true
desc.fs.samplers[0].sampler_type = .FILTERING
desc.fs.image_sampler_pairs[0].used = true
desc.fs.image_sampler_pairs[0].image_slot = 0
desc.fs.image_sampler_pairs[0].sampler_slot = 0
}
return desc
}

View File

@ -11,10 +11,10 @@
in vec2 uv;
out vec4 frag_color;
layout(binding = 0) uniform texture2D ve_blit_atlas_src_texture;
layout(binding = 0) uniform sampler ve_blit_atlas_src_sampler;
uniform texture2D ve_blit_atlas_src_texture;
uniform sampler ve_blit_atlas_src_sampler;
layout(binding = 0) uniform ve_blit_atlas_fs_params {
uniform ve_blit_atlas_fs_params {
int region;
};

View File

@ -12,29 +12,31 @@ import sg "thirdparty:sokol/gfx"
=========
Shader program: 've_draw_text':
Get shader desc: ve_draw_text_shader_desc(sg.query_backend())
Vertex Shader: ve_draw_text_vs
Fragment Shader: ve_draw_text_fs
Attributes:
ATTR_ve_draw_text_v_position => 0
ATTR_ve_draw_text_v_texture => 1
Bindings:
Uniform block 've_draw_text_fs_params':
Odin struct: Ve_Draw_Text_Fs_Params
Bind slot: UB_ve_draw_text_fs_params => 0
Image 've_draw_text_src_texture':
Image type: ._2D
Sample type: .FLOAT
Multisampled: false
Bind slot: IMG_ve_draw_text_src_texture => 0
Sampler 've_draw_text_src_sampler':
Type: .FILTERING
Bind slot: SMP_ve_draw_text_src_sampler => 0
Vertex shader: ve_draw_text_vs
Attributes:
ATTR_ve_draw_text_vs_v_position => 0
ATTR_ve_draw_text_vs_v_texture => 1
Fragment shader: ve_draw_text_fs
Uniform block 've_draw_text_fs_params':
Odin struct: Ve_Draw_Text_Fs_Params
Bind slot: SLOT_ve_draw_text_fs_params => 0
Image 've_draw_text_src_texture':
Image type: ._2D
Sample type: .FLOAT
Multisampled: false
Bind slot: SLOT_ve_draw_text_src_texture => 0
Sampler 've_draw_text_src_sampler':
Type: .FILTERING
Bind slot: SLOT_ve_draw_text_src_sampler => 0
Image Sampler Pair 've_draw_text_src_texture_ve_draw_text_src_sampler':
Image: ve_draw_text_src_texture
Sampler: ve_draw_text_src_sampler
*/
ATTR_ve_draw_text_v_position :: 0
ATTR_ve_draw_text_v_texture :: 1
UB_ve_draw_text_fs_params :: 0
IMG_ve_draw_text_src_texture :: 0
SMP_ve_draw_text_src_sampler :: 0
ATTR_ve_draw_text_vs_v_position :: 0
ATTR_ve_draw_text_vs_v_texture :: 1
SLOT_ve_draw_text_fs_params :: 0
SLOT_ve_draw_text_src_texture :: 0
SLOT_ve_draw_text_src_sampler :: 0
Ve_Draw_Text_Fs_Params :: struct #align(16) {
using _: struct #packed {
down_sample: i32,
@ -77,7 +79,7 @@ Ve_Draw_Text_Fs_Params :: struct #align(16) {
return stage_output;
}
*/
@(private="file")
@(private)
ve_draw_text_vs_source_hlsl4 := [724]u8 {
0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x67,0x6c,
0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,
@ -168,7 +170,7 @@ ve_draw_text_vs_source_hlsl4 := [724]u8 {
return stage_output;
}
*/
@(private="file")
@(private)
ve_draw_text_fs_source_hlsl4 := [1296]u8 {
0x63,0x62,0x75,0x66,0x66,0x65,0x72,0x20,0x76,0x65,0x5f,0x64,0x72,0x61,0x77,0x5f,
0x74,0x65,0x78,0x74,0x5f,0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x20,0x3a,
@ -258,31 +260,27 @@ ve_draw_text_shader_desc :: proc (backend: sg.Backend) -> sg.Shader_Desc {
desc.label = "ve_draw_text_shader"
#partial switch backend {
case .D3D11:
desc.vertex_func.source = transmute(cstring)&ve_draw_text_vs_source_hlsl4
desc.vertex_func.d3d11_target = "vs_4_0"
desc.vertex_func.entry = "main"
desc.fragment_func.source = transmute(cstring)&ve_draw_text_fs_source_hlsl4
desc.fragment_func.d3d11_target = "ps_4_0"
desc.fragment_func.entry = "main"
desc.attrs[0].hlsl_sem_name = "TEXCOORD"
desc.attrs[0].hlsl_sem_index = 0
desc.attrs[1].hlsl_sem_name = "TEXCOORD"
desc.attrs[1].hlsl_sem_index = 1
desc.uniform_blocks[0].stage = .FRAGMENT
desc.uniform_blocks[0].layout = .STD140
desc.uniform_blocks[0].size = 32
desc.uniform_blocks[0].hlsl_register_b_n = 0
desc.images[0].stage = .FRAGMENT
desc.images[0].multisampled = false
desc.images[0].image_type = ._2D
desc.images[0].sample_type = .FLOAT
desc.images[0].hlsl_register_t_n = 0
desc.samplers[0].stage = .FRAGMENT
desc.samplers[0].sampler_type = .FILTERING
desc.samplers[0].hlsl_register_s_n = 0
desc.image_sampler_pairs[0].stage = .FRAGMENT
desc.image_sampler_pairs[0].image_slot = 0
desc.image_sampler_pairs[0].sampler_slot = 0
desc.attrs[0].sem_name = "TEXCOORD"
desc.attrs[0].sem_index = 0
desc.attrs[1].sem_name = "TEXCOORD"
desc.attrs[1].sem_index = 1
desc.vs.source = transmute(cstring)&ve_draw_text_vs_source_hlsl4
desc.vs.d3d11_target = "vs_4_0"
desc.vs.entry = "main"
desc.fs.source = transmute(cstring)&ve_draw_text_fs_source_hlsl4
desc.fs.d3d11_target = "ps_4_0"
desc.fs.entry = "main"
desc.fs.uniform_blocks[0].size = 32
desc.fs.uniform_blocks[0].layout = .STD140
desc.fs.images[0].used = true
desc.fs.images[0].multisampled = false
desc.fs.images[0].image_type = ._2D
desc.fs.images[0].sample_type = .FLOAT
desc.fs.samplers[0].used = true
desc.fs.samplers[0].sampler_type = .FILTERING
desc.fs.image_sampler_pairs[0].used = true
desc.fs.image_sampler_pairs[0].image_slot = 0
desc.fs.image_sampler_pairs[0].sampler_slot = 0
}
return desc
}

View File

@ -19,10 +19,10 @@ void main()
in vec2 uv;
out vec4 frag_color;
layout(binding = 0) uniform texture2D ve_draw_text_src_texture;
layout(binding = 0) uniform sampler ve_draw_text_src_sampler;
uniform texture2D ve_draw_text_src_texture;
uniform sampler ve_draw_text_src_sampler;
layout(binding = 0) uniform ve_draw_text_fs_params {
uniform ve_draw_text_fs_params {
int down_sample;
vec4 colour;
};

View File

@ -12,15 +12,14 @@ import sg "thirdparty:sokol/gfx"
=========
Shader program: 've_render_glyph':
Get shader desc: ve_render_glyph_shader_desc(sg.query_backend())
Vertex Shader: ve_render_glyph_vs
Fragment Shader: ve_render_glyph_fs
Attributes:
ATTR_ve_render_glyph_v_position => 0
ATTR_ve_render_glyph_v_texture => 1
Bindings:
Vertex shader: ve_render_glyph_vs
Attributes:
ATTR_ve_render_glyph_vs_v_position => 0
ATTR_ve_render_glyph_vs_v_texture => 1
Fragment shader: ve_render_glyph_fs
*/
ATTR_ve_render_glyph_v_position :: 0
ATTR_ve_render_glyph_v_texture :: 1
ATTR_ve_render_glyph_vs_v_position :: 0
ATTR_ve_render_glyph_vs_v_texture :: 1
/*
static float4 gl_Position;
static float2 uv;
@ -56,7 +55,7 @@ ATTR_ve_render_glyph_v_texture :: 1
return stage_output;
}
*/
@(private="file")
@(private)
ve_render_glyph_vs_source_hlsl4 := [705]u8 {
0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x67,0x6c,
0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,
@ -132,7 +131,7 @@ ve_render_glyph_vs_source_hlsl4 := [705]u8 {
return stage_output;
}
*/
@(private="file")
@(private)
ve_render_glyph_fs_source_hlsl4 := [427]u8 {
0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,
0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,
@ -167,16 +166,16 @@ ve_render_glyph_shader_desc :: proc (backend: sg.Backend) -> sg.Shader_Desc {
desc.label = "ve_render_glyph_shader"
#partial switch backend {
case .D3D11:
desc.vertex_func.source = transmute(cstring)&ve_render_glyph_vs_source_hlsl4
desc.vertex_func.d3d11_target = "vs_4_0"
desc.vertex_func.entry = "main"
desc.fragment_func.source = transmute(cstring)&ve_render_glyph_fs_source_hlsl4
desc.fragment_func.d3d11_target = "ps_4_0"
desc.fragment_func.entry = "main"
desc.attrs[0].hlsl_sem_name = "TEXCOORD"
desc.attrs[0].hlsl_sem_index = 0
desc.attrs[1].hlsl_sem_name = "TEXCOORD"
desc.attrs[1].hlsl_sem_index = 1
desc.attrs[0].sem_name = "TEXCOORD"
desc.attrs[0].sem_index = 0
desc.attrs[1].sem_name = "TEXCOORD"
desc.attrs[1].sem_index = 1
desc.vs.source = transmute(cstring)&ve_render_glyph_vs_source_hlsl4
desc.vs.d3d11_target = "vs_4_0"
desc.vs.entry = "main"
desc.fs.source = transmute(cstring)&ve_render_glyph_fs_source_hlsl4
desc.fs.d3d11_target = "ps_4_0"
desc.fs.entry = "main"
}
return desc
}

Binary file not shown.

View File

@ -32,6 +32,7 @@ $flag_format_odin = '--format=sokol_odin'
$flag_module = '--module'
push-location $path_shaders
& $sokol_shdc --input $shadersrc_simple_font_glyph --output $shaderout_simple_font_glyph --slang 'hlsl4' $flag_format_odin
& $sokol_shdc --input $shadersrc_ve_blit_atlas --output $shaderout_ve_blit_atlas --slang 'hlsl4' $flag_format_odin $flag_module='vefc_blit_atlas'
& $sokol_shdc --input $shadersrc_ve_render_glyph --output $shaderout_ve_render_glyph --slang 'hlsl4' $flag_format_odin $flag_module='vefc_render_glyph'
& $sokol_shdc --input $shadersrc_ve_draw_text --output $shaderout_ve_draw_text --slang 'hlsl4' $flag_format_odin $flag_module='vefc_draw_text'