get text working squash me with above PLZ
							parent
							
								
									26df55b198
								
							
						
					
					
						commit
						a02c4d2b0a
					
				
							
								
								
									
										4
									
								
								justfile
								
								
								
								
							
							
						
						
									
										4
									
								
								justfile
								
								
								
								
							|  | @ -10,6 +10,6 @@ run: build | ||||||
| 
 | 
 | ||||||
| transpile_shaders_metal: | transpile_shaders_metal: | ||||||
|     mkdir -p bin/transpiled_shaders |     mkdir -p bin/transpiled_shaders | ||||||
|     naga shaders/vertex.wgsl bin/transpiled_shaders/vertex.metal |     ../wgpu/target/debug/naga shaders/vertex.wgsl bin/transpiled_shaders/vertex.metal --metal-version 1.2 | ||||||
|     naga shaders/fragment.wgsl bin/transpiled_shaders/fragment.metal |     ../wgpu/target/debug/naga shaders/fragment.wgsl bin/transpiled_shaders/fragment.metal --metal-version 1.2 | ||||||
|      |      | ||||||
|  |  | ||||||
|  | @ -10,5 +10,7 @@ var texture_sampler: sampler; | ||||||
| 
 | 
 | ||||||
| @fragment | @fragment | ||||||
| fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> { | fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> { | ||||||
|     return textureSample(texture, texture_sampler, input.tex_coord); |     var text_color = textureSample(texture, texture_sampler, vec2<f32>(input.tex_coord.x, input.tex_coord.y)).r; | ||||||
|  | 
 | ||||||
|  |     return vec4<f32>(text_color * vec3<f32>(1., 1., 1.), text_color); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,13 @@ | ||||||
| struct VertexInput { | struct VertexInput { | ||||||
|      @location(0) position: vec3<f32>, |     @location(0) position: vec3<f32>, | ||||||
|      @location(1) tex_coord: vec2<f32>, |     @location(1) tex_coord: vec2<f32>, | ||||||
|  | 
 | ||||||
|  |     @location(2) atlas_position: vec2<f32>, | ||||||
|  |     @location(3) size: vec2<f32>, | ||||||
|  |     @location(4) target_position: vec2<f32>, | ||||||
|  |     @location(5) y_offset: f32, | ||||||
|  | 
 | ||||||
|  |     @builtin(instance_index) glyph_id: u32, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct VertexOutput { | struct VertexOutput { | ||||||
|  | @ -8,11 +15,21 @@ struct VertexOutput { | ||||||
|     @location(0) tex_coord: vec2<f32>, |     @location(0) tex_coord: vec2<f32>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn to_device_position(position: vec2<f32>, size: vec2<f32>) -> vec4<f32> { | ||||||
|  |     return vec4<f32>((((position / size) * 2.) - 1.), 1., 1.); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @vertex | @vertex | ||||||
| fn vs_main(input: VertexInput) -> VertexOutput { | fn vs_main(input: VertexInput) -> VertexOutput { | ||||||
|     var out: VertexOutput; |     var out: VertexOutput; | ||||||
|     out.position = vec4<f32>(input.position, 1.); | 
 | ||||||
|     out.tex_coord = input.tex_coord; |     var vertex_pos = to_device_position(((input.position.xy + 1.) / 2.) * input.size + input.target_position + vec2<f32>(0., input.y_offset+17), vec2<f32>(640., 480.)); | ||||||
|  |     vertex_pos.y = -vertex_pos.y; | ||||||
|  |     var atlas_position = (((input.position.xy + 1.) / 2.) * input.size + input.atlas_position) / vec2<f32>(256); | ||||||
|  | 
 | ||||||
|  |     out.position = vertex_pos; | ||||||
|  |     out.tex_coord = atlas_position; | ||||||
|  | 
 | ||||||
|     return out; |     return out; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,3 +1,2 @@ | ||||||
| -I/usr/include/ |  | ||||||
| -I../vendor/ | -I../vendor/ | ||||||
| -ObjC | -ObjC | ||||||
|  |  | ||||||
							
								
								
									
										155
									
								
								src/main.c
								
								
								
								
							
							
						
						
									
										155
									
								
								src/main.c
								
								
								
								
							|  | @ -15,6 +15,9 @@ | ||||||
| #include <sokol/sokol_glue.h> | #include <sokol/sokol_glue.h> | ||||||
| #include <sokol/sokol_fetch.h> | #include <sokol/sokol_fetch.h> | ||||||
| 
 | 
 | ||||||
|  | #define STB_TRUETYPE_IMPLEMENTATION | ||||||
|  | #include <stb/std_truetype.h> | ||||||
|  | 
 | ||||||
| #define ARENA_IMPLEMENTATION | #define ARENA_IMPLEMENTATION | ||||||
| #include <tsoding/arena.h> | #include <tsoding/arena.h> | ||||||
| 
 | 
 | ||||||
|  | @ -28,15 +31,16 @@ void *context_alloc(size_t size) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     double position[2]; |     float position[2]; | ||||||
|     double size[2]; |     float size[2]; | ||||||
|     double border_size[2]; |     float border_size[2]; | ||||||
| } GpuUiRect; | } GpuUiRect; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     double atlas_position[2]; |     float atlas_position[2]; | ||||||
|     double size[2]; |     float size[2]; | ||||||
|     double position[2]; |     float position[2]; | ||||||
|  |     float y_offset; | ||||||
| } GpuGlyph; | } GpuGlyph; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|  | @ -62,6 +66,10 @@ void push_u8array(U8Array *array, uint8_t *items, size_t num) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void clear_u8array(U8Array *array) { | ||||||
|  |     array->size = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static struct { | static struct { | ||||||
|     sg_pass_action pass_action; |     sg_pass_action pass_action; | ||||||
|     sg_pipeline pip; |     sg_pipeline pip; | ||||||
|  | @ -74,10 +82,32 @@ static struct { | ||||||
| 
 | 
 | ||||||
|     U8Array gpu_ui_rects; |     U8Array gpu_ui_rects; | ||||||
|     U8Array gpu_glyphs; |     U8Array gpu_glyphs; | ||||||
|  |     U8Array glyph_cache; | ||||||
| 
 | 
 | ||||||
|     bool should_exit; |     bool should_exit; | ||||||
| } state; | } state; | ||||||
| 
 | 
 | ||||||
|  | #define _String(text) ((String) { .data = text, .len = sizeof(text) }) | ||||||
|  | typedef struct { | ||||||
|  |     char *data; | ||||||
|  |     size_t len; | ||||||
|  | } String; | ||||||
|  | 
 | ||||||
|  | void queue_text(String text, float position[2]) { | ||||||
|  |     float x = 0; | ||||||
|  |     for (size_t i=0; i < text.len; ++i) { | ||||||
|  |         if (text.data[i] >= 32 && text.data[i] <= 32+95) { | ||||||
|  |             GpuGlyph glyph = *((GpuGlyph *)(state.glyph_cache.data+((text.data[i] - 32) * sizeof(GpuGlyph)))); | ||||||
|  | 
 | ||||||
|  |             glyph.position[0] = x+position[0]; | ||||||
|  |             glyph.position[1] = position[1]; | ||||||
|  |             x += glyph.size[0]; | ||||||
|  | 
 | ||||||
|  |             push_u8array(&state.gpu_glyphs, &glyph, sizeof(GpuGlyph)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void vertex_shader_loaded(const sfetch_response_t *response) { | void vertex_shader_loaded(const sfetch_response_t *response) { | ||||||
|     if (response->fetched) { |     if (response->fetched) { | ||||||
|         state.scratch_shader_desc.vs.source = response->data.ptr; |         state.scratch_shader_desc.vs.source = response->data.ptr; | ||||||
|  | @ -106,16 +136,27 @@ void fragment_shader_loaded(const sfetch_response_t *response) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ed_init() { | void ed_init() { | ||||||
|  |     uint8_t ttf_buffer[1<<20]; | ||||||
|  |     FILE *ttf_file = fopen("../c_editor/JetBrainsMono-Medium.ttf", "rb"); | ||||||
|  |     if (!ttf_file) { | ||||||
|  |         exit(1); | ||||||
|  |     } | ||||||
|  |     fread(ttf_buffer, 1, 1<<20, ttf_file); | ||||||
|  |     fclose(ttf_file); | ||||||
|  | 
 | ||||||
|  |     stbtt_fontinfo font; | ||||||
|  |     stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0)); | ||||||
|  | 
 | ||||||
|     sg_setup(&(sg_desc) { |     sg_setup(&(sg_desc) { | ||||||
|         .environment = sglue_environment(), |         .environment = sglue_environment(), | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     float vertices[] = { |     float vertices[] = { | ||||||
|         // positions            colors
 |         // positions            colors
 | ||||||
|         -0.5f,  0.5f, 0.5f,     0.0f, 0.0f, |         -1.0f,  1.0f, 1.0f,     0.0f, 0.0f, | ||||||
|          0.5f,  0.5f, 0.5f,     1.0f, 0.0f, |          1.0f,  1.0f, 1.0f,     1.0f, 0.0f, | ||||||
|          0.5f, -0.5f, 0.5f,     1.0f, 1.0f, |          1.0f, -1.0f, 1.0f,     1.0f, 1.0f, | ||||||
|         -0.5f, -0.5f, 0.5f,     0.0f, 1.0f, |         -1.0f, -1.0f, 1.0f,     0.0f, 1.0f, | ||||||
|     }; |     }; | ||||||
|     state.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc) { |     state.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc) { | ||||||
|         .data = SG_RANGE(vertices) |         .data = SG_RANGE(vertices) | ||||||
|  | @ -149,9 +190,69 @@ void ed_init() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     uint8_t *font_bitmap = context_alloc(256*256 * sizeof(uint8_t)); |     uint8_t *font_bitmap = context_alloc(256*256 * sizeof(uint8_t)); | ||||||
|     font_bitmap[4 + 4 * 256] = 255; |  | ||||||
| 
 | 
 | ||||||
|     state.text_atlas_sampler = sg_make_sampler(&(sg_sampler_desc) { .mag_filter = SG_FILTER_LINEAR }); |     state.gpu_ui_rects = new_u8array(sizeof(GpuUiRect) * 2000); | ||||||
|  |     state.gpu_glyphs = new_u8array(sizeof(GpuGlyph) * 1024); | ||||||
|  |     state.glyph_cache = new_u8array(sizeof(GpuGlyph) * 96); | ||||||
|  | 
 | ||||||
|  |     int ascent, descent, line_gap; | ||||||
|  |     float scale = stbtt_ScaleForPixelHeight(&font, 32); | ||||||
|  |     stbtt_GetFontVMetrics(&font, &ascent, &descent, &line_gap); | ||||||
|  | 
 | ||||||
|  |     int xxx = 0; | ||||||
|  |     for (size_t xx=0; xx < 16; ++xx) { | ||||||
|  |         for (size_t yy=0; yy < 16; ++yy) { | ||||||
|  |             font_bitmap[xx + yy * 256] = 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     // manually add glyph for SPACE
 | ||||||
|  |     push_u8array(&state.glyph_cache, &(GpuGlyph){ | ||||||
|  |         .atlas_position = { 0 }, | ||||||
|  |         .size = { 16, 16 }, | ||||||
|  |         .position = { 0 }, | ||||||
|  |         .y_offset = -16.0, | ||||||
|  |     }, 1 * sizeof(GpuGlyph)); | ||||||
|  | 
 | ||||||
|  |     int x = 16; | ||||||
|  |     int y = 0; | ||||||
|  |     for (size_t i = 33; i < 33+96; ++i) { | ||||||
|  |         int width,height, xoff,yoff; | ||||||
|  |         uint8_t *bitmap = stbtt_GetCodepointBitmap(&font, scale, scale, (int)i, &width, &height, &xoff, &yoff); | ||||||
|  | 
 | ||||||
|  |         if (x + width >= 256) { | ||||||
|  |             x = 0; | ||||||
|  |             y += (int)((float)(ascent - descent + line_gap)*scale); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         int xxx = x; | ||||||
|  |         for (size_t xx=0; xx < width; ++xx) { | ||||||
|  |             int yyy = y; | ||||||
|  |             for (size_t yy=0; yy < height; ++yy) { | ||||||
|  |                 font_bitmap[xxx + yyy * 256] = bitmap[xx + yy * width]; | ||||||
|  | 
 | ||||||
|  |                 yyy += 1; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             xxx += 1; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         push_u8array(&state.glyph_cache, &(GpuGlyph){ | ||||||
|  |             .atlas_position = { (float)(x), (float)(y) }, | ||||||
|  |             .size = { (float)width, (float)height }, | ||||||
|  |             .position = { (float)x, (float)y }, | ||||||
|  |             .y_offset = (float)(yoff), | ||||||
|  |         }, 1 * sizeof(GpuGlyph)); | ||||||
|  | 
 | ||||||
|  |         x += width; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     state.bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc) { | ||||||
|  |         .size = state.gpu_glyphs.capacity, | ||||||
|  |         .usage = SG_USAGE_STREAM, | ||||||
|  |         .label = "glyph buffer" | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     state.text_atlas_sampler = sg_make_sampler(&(sg_sampler_desc) { .mag_filter = SG_FILTER_NEAREST }); | ||||||
|     state.text_atlas_image = sg_make_image(&(sg_image_desc) { |     state.text_atlas_image = sg_make_image(&(sg_image_desc) { | ||||||
|         .width = 256, |         .width = 256, | ||||||
|         .height = 256, |         .height = 256, | ||||||
|  | @ -161,27 +262,47 @@ void ed_init() { | ||||||
|     state.bind.fs.images[0] = state.text_atlas_image; |     state.bind.fs.images[0] = state.text_atlas_image; | ||||||
|     state.bind.fs.samplers[0] = state.text_atlas_sampler; |     state.bind.fs.samplers[0] = state.text_atlas_sampler; | ||||||
| 
 | 
 | ||||||
|  |     state.pass_action = (sg_pass_action) { | ||||||
|  |         .colors[0] = { | ||||||
|  |             .load_action = SG_LOADACTION_CLEAR, | ||||||
|  |             .clear_value = { 0.0f, 0.0f, 0.0f, 1.0f } | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|     sg_shader shd = sg_make_shader(&state.scratch_shader_desc); |     sg_shader shd = sg_make_shader(&state.scratch_shader_desc); | ||||||
|     state.pip = sg_make_pipeline(&(sg_pipeline_desc) { |     state.pip = sg_make_pipeline(&(sg_pipeline_desc) { | ||||||
|         .shader = shd, |         .shader = shd, | ||||||
|         .index_type = SG_INDEXTYPE_UINT16, |         .index_type = SG_INDEXTYPE_UINT16, | ||||||
|         .layout = { |         .layout = { | ||||||
|  |             .buffers[1].step_func = SG_VERTEXSTEP_PER_INSTANCE, | ||||||
|             .attrs = { |             .attrs = { | ||||||
|                 [0] = { .offset=0, .format=SG_VERTEXFORMAT_FLOAT3 }, |                 [0] = { .format=SG_VERTEXFORMAT_FLOAT3, .buffer_index = 0 }, | ||||||
|                 [1] = { .offset=12, .format=SG_VERTEXFORMAT_FLOAT2 }, |                 [1] = { .format=SG_VERTEXFORMAT_FLOAT2, .buffer_index = 0 }, | ||||||
|  | 
 | ||||||
|  |                 [2] = { .format=SG_VERTEXFORMAT_FLOAT2, .buffer_index = 1 }, | ||||||
|  |                 [3] = { .format=SG_VERTEXFORMAT_FLOAT2, .buffer_index = 1 }, | ||||||
|  |                 [4] = { .format=SG_VERTEXFORMAT_FLOAT2, .buffer_index = 1 }, | ||||||
|  |                 [5] = { .format=SG_VERTEXFORMAT_FLOAT, .buffer_index = 1 }, | ||||||
|             }, |             }, | ||||||
|         }, |         }, | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     state.gpu_ui_rects = new_u8array(sizeof(GpuUiRect) * 2000); |     queue_text(_String("But what even is text! []!@#$%^&*()_=+"), (float[]){ 0, 0 }); | ||||||
|     state.gpu_glyphs = new_u8array(sizeof(GpuGlyph) * 8000); |     queue_text(_String("v0.1.0"), (float[]){ 32, 128 }); | ||||||
|  |     queue_text(_String("an_editor - what even"), (float[]){ 32, 256 }); | ||||||
| } | } | ||||||
| void ed_frame() { | void ed_frame() { | ||||||
|  |     if (state.gpu_glyphs.size > 0) { | ||||||
|  |         sg_update_buffer(state.bind.vertex_buffers[1], &(sg_range) { | ||||||
|  |             .ptr = state.gpu_glyphs.data, | ||||||
|  |             .size = state.gpu_glyphs.size | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     sg_begin_pass(&(sg_pass) { .action = state.pass_action, .swapchain = sglue_swapchain() }); |     sg_begin_pass(&(sg_pass) { .action = state.pass_action, .swapchain = sglue_swapchain() }); | ||||||
|     { |     { | ||||||
|         sg_apply_pipeline(state.pip); |         sg_apply_pipeline(state.pip); | ||||||
|         sg_apply_bindings(&state.bind); |         sg_apply_bindings(&state.bind); | ||||||
|         sg_draw(0, 6, 1); |         sg_draw(0, 6, state.gpu_glyphs.size/sizeof(GpuGlyph)); | ||||||
|     } |     } | ||||||
|     sg_end_pass(); |     sg_end_pass(); | ||||||
|     sg_commit(); |     sg_commit(); | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
		Reference in New Issue