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: | ||||
|     mkdir -p bin/transpiled_shaders | ||||
|     naga shaders/vertex.wgsl bin/transpiled_shaders/vertex.metal | ||||
|     naga shaders/fragment.wgsl bin/transpiled_shaders/fragment.metal | ||||
|     ../wgpu/target/debug/naga shaders/vertex.wgsl bin/transpiled_shaders/vertex.metal --metal-version 1.2 | ||||
|     ../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 | ||||
| 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 { | ||||
|      @location(0) position: vec3<f32>, | ||||
|      @location(1) tex_coord: vec2<f32>, | ||||
|     @location(0) position: vec3<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 { | ||||
|  | @ -8,11 +15,21 @@ struct VertexOutput { | |||
|     @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 | ||||
| fn vs_main(input: VertexInput) -> 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; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,3 +1,2 @@ | |||
| -I/usr/include/ | ||||
| -I../vendor/ | ||||
| -ObjC | ||||
|  |  | |||
							
								
								
									
										155
									
								
								src/main.c
								
								
								
								
							
							
						
						
									
										155
									
								
								src/main.c
								
								
								
								
							|  | @ -15,6 +15,9 @@ | |||
| #include <sokol/sokol_glue.h> | ||||
| #include <sokol/sokol_fetch.h> | ||||
| 
 | ||||
| #define STB_TRUETYPE_IMPLEMENTATION | ||||
| #include <stb/std_truetype.h> | ||||
| 
 | ||||
| #define ARENA_IMPLEMENTATION | ||||
| #include <tsoding/arena.h> | ||||
| 
 | ||||
|  | @ -28,15 +31,16 @@ void *context_alloc(size_t size) { | |||
| } | ||||
| 
 | ||||
| typedef struct { | ||||
|     double position[2]; | ||||
|     double size[2]; | ||||
|     double border_size[2]; | ||||
|     float position[2]; | ||||
|     float size[2]; | ||||
|     float border_size[2]; | ||||
| } GpuUiRect; | ||||
| 
 | ||||
| typedef struct { | ||||
|     double atlas_position[2]; | ||||
|     double size[2]; | ||||
|     double position[2]; | ||||
|     float atlas_position[2]; | ||||
|     float size[2]; | ||||
|     float position[2]; | ||||
|     float y_offset; | ||||
| } GpuGlyph; | ||||
| 
 | ||||
| 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 { | ||||
|     sg_pass_action pass_action; | ||||
|     sg_pipeline pip; | ||||
|  | @ -74,10 +82,32 @@ static struct { | |||
| 
 | ||||
|     U8Array gpu_ui_rects; | ||||
|     U8Array gpu_glyphs; | ||||
|     U8Array glyph_cache; | ||||
| 
 | ||||
|     bool should_exit; | ||||
| } 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) { | ||||
|     if (response->fetched) { | ||||
|         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() { | ||||
|     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) { | ||||
|         .environment = sglue_environment(), | ||||
|     }); | ||||
| 
 | ||||
|     float vertices[] = { | ||||
|         // positions            colors
 | ||||
|         -0.5f,  0.5f, 0.5f,     0.0f, 0.0f, | ||||
|          0.5f,  0.5f, 0.5f,     1.0f, 0.0f, | ||||
|          0.5f, -0.5f, 0.5f,     1.0f, 1.0f, | ||||
|         -0.5f, -0.5f, 0.5f,     0.0f, 1.0f, | ||||
|         -1.0f,  1.0f, 1.0f,     0.0f, 0.0f, | ||||
|          1.0f,  1.0f, 1.0f,     1.0f, 0.0f, | ||||
|          1.0f, -1.0f, 1.0f,     1.0f, 1.0f, | ||||
|         -1.0f, -1.0f, 1.0f,     0.0f, 1.0f, | ||||
|     }; | ||||
|     state.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc) { | ||||
|         .data = SG_RANGE(vertices) | ||||
|  | @ -149,9 +190,69 @@ void ed_init() { | |||
|     } | ||||
| 
 | ||||
|     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) { | ||||
|         .width = 256, | ||||
|         .height = 256, | ||||
|  | @ -161,27 +262,47 @@ void ed_init() { | |||
|     state.bind.fs.images[0] = state.text_atlas_image; | ||||
|     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); | ||||
|     state.pip = sg_make_pipeline(&(sg_pipeline_desc) { | ||||
|         .shader = shd, | ||||
|         .index_type = SG_INDEXTYPE_UINT16, | ||||
|         .layout = { | ||||
|             .buffers[1].step_func = SG_VERTEXSTEP_PER_INSTANCE, | ||||
|             .attrs = { | ||||
|                 [0] = { .offset=0, .format=SG_VERTEXFORMAT_FLOAT3 }, | ||||
|                 [1] = { .offset=12, .format=SG_VERTEXFORMAT_FLOAT2 }, | ||||
|                 [0] = { .format=SG_VERTEXFORMAT_FLOAT3, .buffer_index = 0 }, | ||||
|                 [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); | ||||
|     state.gpu_glyphs = new_u8array(sizeof(GpuGlyph) * 8000); | ||||
|     queue_text(_String("But what even is text! []!@#$%^&*()_=+"), (float[]){ 0, 0 }); | ||||
|     queue_text(_String("v0.1.0"), (float[]){ 32, 128 }); | ||||
|     queue_text(_String("an_editor - what even"), (float[]){ 32, 256 }); | ||||
| } | ||||
| 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_apply_pipeline(state.pip); | ||||
|         sg_apply_bindings(&state.bind); | ||||
|         sg_draw(0, 6, 1); | ||||
|         sg_draw(0, 6, state.gpu_glyphs.size/sizeof(GpuGlyph)); | ||||
|     } | ||||
|     sg_end_pass(); | ||||
|     sg_commit(); | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
		Reference in New Issue