Sfoglia il codice sorgente

Some ideas for override vertex input for successive draws

Karl Zylinski 6 mesi fa
parent
commit
f585b54ffa
4 ha cambiato i file con 137 aggiunte e 44 eliminazioni
  1. 27 0
      examples/snake/shader.hlsl
  2. 13 0
      examples/snake/snake.odin
  3. 6 4
      karl2d.odin
  4. 91 40
      karl2d_windows.odin

+ 27 - 0
examples/snake/shader.hlsl

@@ -0,0 +1,27 @@
+cbuffer constants : register(b0) {
+	float4x4 mvp;
+}
+struct vs_in {
+	float2 position : POS;
+	float2 uv       : UV;
+	float4 color    : COL;
+	float4 color2   : WAA;
+};
+struct vs_out {
+	float4 position : SV_POSITION;
+	float2 uv       : UV;
+	float4 color    : COL;
+};
+Texture2D    tex : register(t0);
+SamplerState smp : register(s0);
+vs_out vs_main(vs_in input) {
+	vs_out output;
+	output.position = mul(mvp, float4(input.position, 0, 1.0f));
+	output.uv = input.uv;
+	output.color = input.color2;
+	return output;
+}
+float4 ps_main(vs_out input) : SV_TARGET {
+	float4 c = tex.Sample(smp, input.uv);
+	return c * input.color;
+}

+ 13 - 0
examples/snake/snake.odin

@@ -78,6 +78,16 @@ main :: proc() {
 	}
 
 	k2.init(WINDOW_SIZE, WINDOW_SIZE, "Snake")
+
+	SHADER_SOURCE :: #load("shader.hlsl")
+
+	shader := k2.load_shader(string(SHADER_SOURCE), {
+		.RG32_Float,
+		.RG32_Float,
+		.RGBA8_Norm,
+		.RGBA8_Norm,
+	})
+
 	prev_time := time.now()
 
 	restart()
@@ -147,11 +157,14 @@ main :: proc() {
 		}
 
 		k2.clear({76, 53, 83, 255})
+		k2.set_shader(shader)
 
 		camera := k2.Camera {
 			zoom = f32(WINDOW_SIZE) / CANVAS_SIZE,
 		}
 
+		k2.set_vertex_input_override(shader, 3, k2.create_vertex_input_override(k2.Color{255, 255, 255, 128}))
+
 		k2.set_camera(camera)
 		food_sprite.width = CELL_SIZE
 		food_sprite.height = CELL_SIZE

+ 6 - 4
karl2d.odin

@@ -38,6 +38,8 @@ set_window_position: proc(x: int, y: int) : _set_window_position
 get_screen_width: proc() -> int : _get_screen_width
 get_screen_height: proc() -> int : _get_screen_height
 
+get_default_shader: proc() -> Shader_Handle : _get_default_shader
+
 load_texture_from_file: proc(filename: string) -> Texture : _load_texture_from_file
 load_texture_from_memory: proc(data: []u8, width: int, height: int) -> Texture : _load_texture_from_memory
 // load_texture_from_bytes or buffer or something ()
@@ -47,6 +49,8 @@ set_camera: proc(camera: Maybe(Camera)) : _set_camera
 set_scissor_rect: proc(scissor_rect: Maybe(Rect)) : _set_scissor_rect
 set_shader: proc(shader: Shader_Handle) : _set_shader
 
+//set_vertex_value :: _set_vertex_value
+
 draw_texture: proc(tex: Texture, pos: Vec2, tint := WHITE) : _draw_texture
 draw_texture_rect: proc(tex: Texture, rect: Rect, pos: Vec2, tint := WHITE) : _draw_texture_rect
 draw_texture_ex: proc(tex: Texture, src: Rect, dest: Rect, origin: Vec2, rotation: f32, tint := WHITE) : _draw_texture_ex
@@ -55,7 +59,7 @@ draw_rect_outline: proc(rect: Rect, thickness: f32, color: Color) : _draw_rectan
 draw_circle: proc(center: Vec2, radius: f32, color: Color) : _draw_circle
 draw_line: proc(start: Vec2, end: Vec2, thickness: f32, color: Color) : _draw_line
 
-load_shader: proc(shader_source: string) -> Shader_Handle : _load_shader
+load_shader: proc(shader_source: string, layout_formats: []Shader_Input_Format = {}) -> Shader_Handle : _load_shader
 destroy_shader: proc(shader: Shader_Handle) : _destroy_shader
 
 get_shader_constant_location: proc(shader: Shader_Handle, name: string) -> Shader_Constant_Location : _get_shader_constant_location
@@ -64,9 +68,8 @@ set_shader_constant_mat4: proc(shader: Shader_Handle, loc: Shader_Constant_Locat
 set_shader_constant_f32: proc(shader: Shader_Handle, loc: Shader_Constant_Location, val: f32) : _set_shader_constant_f32
 set_shader_constant_vec2: proc(shader: Shader_Handle, loc: Shader_Constant_Location, val: Vec2) : _set_shader_constant_vec2
 
-set_vertex_field :: proc(input: Shader_Input)
-
 Shader_Input_Format :: enum {
+	Unknown,
 	RGBA32_Float,
 	RGBA8_Norm,
 	RGBA8_Norm_SRGB,
@@ -74,7 +77,6 @@ Shader_Input_Format :: enum {
 	R32_Float,
 }
 
-set_shader_vertex_layout: proc(shader: Shader_Handle, layout: []Shader_Input_Format) : _set_shader_vertex_layout
 
 // WARNING: Not proper text rendering yet... No font support etc
 draw_text: proc(text: string, pos: Vec2, font_size: f32, color: Color) : _draw_text

+ 91 - 40
karl2d_windows.odin

@@ -177,7 +177,11 @@ _init :: proc(width: int, height: int, title: string,
 	}
 	s.device->CreateSamplerState(&sampler_desc, &s.sampler_state)
 
-	s.default_shader = _load_shader(string(shader_hlsl))
+	s.default_shader = _load_shader(string(shader_hlsl), {
+		.RG32_Float,
+		.RG32_Float,
+		.RGBA8_Norm,
+	})
 
 	white_rect: [16*16*4]u8
 	slice.fill(white_rect[:], 255)
@@ -235,6 +239,7 @@ Shader :: struct {
 	constant_builtin_locations: [Shader_Builtin_Constant]Maybe(Shader_Constant_Location),
 
 	inputs: []Shader_Input,
+	input_overrides: []Shader_Input_Value_Override,
 	default_input_offsets: [Shader_Default_Inputs]int,
 	vertex_size: int,
 }
@@ -484,6 +489,35 @@ _draw_texture_rect :: proc(tex: Texture, rect: Rect, pos: Vec2, tint := WHITE) {
 	)
 }
 
+Shader_Input_Value_Override :: struct {
+	val: [256]u8,
+	used: int,
+}
+
+create_vertex_input_override :: proc(val: $T) -> Shader_Input_Value_Override {
+	assert(size_of(T) < 256)
+	res: Shader_Input_Value_Override
+	((^T)(raw_data(&res.val)))^ = val
+	res.used = size_of(T)
+	return res
+}
+
+set_vertex_input_override :: proc(shader: Shader_Handle, input_idx: int, override: Shader_Input_Value_Override) {
+	shd := hm.get(&s.shaders, shader)
+
+	if shd == nil {
+		log.error("Valid shader")
+		return
+	}
+
+	if input_idx < 0 || input_idx >= len(shd.input_overrides) {
+		log.error("Override input idx out of bounds")
+		return
+	}
+
+	shd.input_overrides[input_idx] = override
+}
+
 batch_vertex :: proc(v: Vec2, uv: Vec2, color: Color) {
 	v := v
 
@@ -514,6 +548,18 @@ batch_vertex :: proc(v: Vec2, uv: Vec2, color: Color) {
 	if color_offset != -1 {
 		(^Color)(&s.vertex_buffer_cpu[base_offset + color_offset])^ = color
 	}
+
+	override_offset: int
+	for &o, idx in shd.input_overrides {
+		input := &shd.inputs[idx]
+		sz := shader_input_format_size(input.format)
+
+		if o.used != 0 {
+			mem.copy(&s.vertex_buffer_cpu[base_offset + override_offset], raw_data(&o.val), o.used)
+		}
+
+		override_offset += sz
+	}
 	
 	s.vertex_buffer_cpu_used += shd.vertex_size
 }
@@ -652,6 +698,10 @@ _get_screen_height :: proc() -> int {
 	return s.height
 }
 
+_get_default_shader :: proc() -> Shader_Handle {
+	return s.default_shader
+}
+
 _key_went_down :: proc(key: Keyboard_Key) -> bool {
 	return s.keys_went_down[key]
 }
@@ -762,28 +812,6 @@ _set_shader :: proc(shader: Shader_Handle) {
 	s.batch_shader = shader
 }
 
-_set_shader_vertex_layout :: proc(shader: Shader_Handle, layout: []Shader_Input_Format) {
-	shd := hm.get(&s.shaders, shader)
-
-	if shd == nil {
-		log.error("Invalid shader")
-		return
-	}
-
-	if len(layout) != len(shd.inputs) {
-		log.error("Shader has %v inputs but layout only specifies %v. The inputs are:", len(shd.inputs), len(layout))
-
-		for i in shd.inputs {
-			log.error(i)
-		}
-		return
-	}
-
-	for _, idx in shd.inputs {
-		shd.inputs[idx].format = layout[idx]
-	}
-}
-
 _set_shader_constant :: proc(shader: Shader_Handle, loc: Shader_Constant_Location, val: $T) {
 	_draw_current_batch()
 
@@ -937,7 +965,7 @@ Shader_Constant_Location :: struct {
 	offset: u32,
 }
 
-_load_shader :: proc(shader: string) -> Shader_Handle {
+_load_shader :: proc(shader: string, layout_formats: []Shader_Input_Format = {}) -> Shader_Handle {
 	vs_blob: ^d3d11.IBlob
 	vs_blob_errors: ^d3d11.IBlob
 	ch(d3d_compiler.Compile(raw_data(shader), len(shader), nil, nil, nil, "vs_main", "vs_5_0", 0, 0, &vs_blob, &vs_blob_errors))
@@ -1071,26 +1099,46 @@ _load_shader :: proc(shader: string) -> Shader_Handle {
 	}
 	input_offset: int
 
-	for &i in inputs {
-		if i.name == "POS" && i.type == .Vec2 {
-			i.format = .RG32_Float
-			default_input_offsets[.Position] = input_offset
-		} else if i.name == "UV" && i.type == .Vec2 {
-			i.format = .RG32_Float
-			default_input_offsets[.UV] = input_offset
-		} else if i.name == "COL" && i.type == .Vec4 {
-			i.format = .RGBA8_Norm
-			default_input_offsets[.Color] = input_offset
+	if len(layout_formats) > 0 {
+		if len(layout_formats) != len(inputs) {
+			log.error("Passed number of layout formats isn't same as number of shader inputs")
 		} else {
-			switch i.type {
-			case .F32: i.format = .R32_Float
-			case .Vec2: i.format = .RG32_Float
-			case .Vec3: i.format = .RGBA32_Float
-			case .Vec4: i.format = .RGBA32_Float
+			for &i, idx in inputs {
+				i.format = layout_formats[idx]
+
+				if i.name == "POS" && i.type == .Vec2 {
+					default_input_offsets[.Position] = input_offset
+				} else if i.name == "UV" && i.type == .Vec2 {
+					default_input_offsets[.UV] = input_offset
+				} else if i.name == "COL" && i.type == .Vec4 {
+					default_input_offsets[.Color] = input_offset
+				}
+
+				input_offset += shader_input_format_size(i.format)
 			}
 		}
+	} else {
+		for &i in inputs {
+			if i.name == "POS" && i.type == .Vec2 {
+				i.format = .RG32_Float
+				default_input_offsets[.Position] = input_offset
+			} else if i.name == "UV" && i.type == .Vec2 {
+				i.format = .RG32_Float
+				default_input_offsets[.UV] = input_offset
+			} else if i.name == "COL" && i.type == .Vec4 {
+				i.format = .RGBA8_Norm
+				default_input_offsets[.Color] = input_offset
+			} else {
+				switch i.type {
+				case .F32: i.format = .R32_Float
+				case .Vec2: i.format = .RG32_Float
+				case .Vec3: i.format = .RGBA32_Float
+				case .Vec4: i.format = .RGBA32_Float
+				}
+			}
 
-		input_offset += shader_input_format_size(i.format)
+			input_offset += shader_input_format_size(i.format)
+		}
 	}
 
 	input_layout_desc := make([]d3d11.INPUT_ELEMENT_DESC, len(inputs), context.temp_allocator)
@@ -1128,6 +1176,7 @@ _load_shader :: proc(shader: string) -> Shader_Handle {
 		constant_lookup = constant_lookup,
 		constant_builtin_locations = constant_builtin_locations,
 		inputs = inputs,
+		input_overrides = make([]Shader_Input_Value_Override, len(inputs)),
 		default_input_offsets = default_input_offsets,
 		vertex_size = input_offset,
 	}
@@ -1138,6 +1187,7 @@ _load_shader :: proc(shader: string) -> Shader_Handle {
 
 dxgi_format_from_shader_input_format :: proc(f: Shader_Input_Format) -> dxgi.FORMAT {
 	switch f {
+	case .Unknown: return .UNKNOWN
 	case .RGBA32_Float: return .R32G32B32A32_FLOAT
 	case .RGBA8_Norm: return .R8G8B8A8_UNORM
 	case .RGBA8_Norm_SRGB: return .R8G8B8A8_UNORM_SRGB
@@ -1151,6 +1201,7 @@ dxgi_format_from_shader_input_format :: proc(f: Shader_Input_Format) -> dxgi.FOR
 
 shader_input_format_size :: proc(f: Shader_Input_Format) -> int {
 	switch f {
+	case .Unknown: return 0
 	case .RGBA32_Float: return 32
 	case .RGBA8_Norm: return 4
 	case .RGBA8_Norm_SRGB: return 4