0xc3 3 hete
szülő
commit
b8cded03e4
4 módosított fájl, 244 hozzáadás és 47 törlés
  1. 1 1
      .gitignore
  2. 1 1
      Makefile
  3. 19 1
      res/shaders/3d.glsl
  4. 223 44
      src/cmd/sandbox/main.odin

+ 1 - 1
.gitignore

@@ -1,3 +1,3 @@
 build/
 
-src/cmd/*/shader.odin
+*_gen.odin

+ 1 - 1
Makefile

@@ -4,5 +4,5 @@ build_third_party:
 run_sandbox_debug:
 	# TODO
 	# ./tools/sokol-shdc -i ./res/shaders/2d.glsl -o ./src/cmd/sandbox/2d_shader_gen.odin -l glsl430 -f sokol_odin
-	# ./tools/sokol-shdc -i ./res/shaders/3d.glsl -o ./src/cmd/sandbox/3d_shader_gen.odin -l glsl430 -f sokol_odin
+	./tools/sokol-shdc -i ./res/shaders/3d.glsl -o ./src/cmd/sandbox/3d_shader_gen.odin -l glsl430 -f sokol_odin
 	odin run src/cmd/sandbox -o:none -debug -collection:huginn=src -collection:third-party=third-party

+ 19 - 1
res/shaders/3d.glsl

@@ -1,9 +1,27 @@
 @header package main
 
+@header import sg "third-party:sokol/gfx"
+@header import m "huginn:core/math"
+
 @vs vs
+in vec4 position;
+in vec4 color0;
+
+out vec4 color;
+
+void main() {
+    gl_Position = position;
+    color = color0;
+}
 @end
 
 @fs fs
+in vec4 color;
+out vec4 frag_color;
+
+void main() {
+    frag_color = color;
+}
 @end
 
-@program ... vs fs
+@program triangle vs fs

+ 223 - 44
src/cmd/sandbox/main.odin

@@ -1,60 +1,220 @@
 package main
 
 import "base:runtime"
-
+import "core:fmt"
 import mu "third-party:microui"
-
 import sapp "third-party:sokol/app"
 import sg "third-party:sokol/gfx"
 import sgl "third-party:sokol/gl"
 import sglue "third-party:sokol/glue"
 import slog "third-party:sokol/log"
 
-state: struct {
+State :: struct {
+	pip:         sg.Pipeline,
+	bind:        sg.Bindings,
 	pass_action: sg.Pass_Action,
-} = {
-	pass_action = {colors = {0 = {load_action = .CLEAR, clear_value = {1.0, 0.0, 1.0, 1.0}}}},
+	mu_ctx:      mu.Context,
+
+	// Ресурсы
+	atlas_img:   sg.Image,
+	atlas_view:  sg.View,
+	atlas_smp:   sg.Sampler,
+	ui_pip:      sgl.Pipeline,
 }
 
-mu_ctx: mu.Context
+state: State
+
+map_mouse_button :: proc(btn: sapp.Mousebutton) -> (mu.Mouse, bool) {
+	switch btn {
+	case .LEFT:
+		return .LEFT, true
+	case .RIGHT:
+		return .RIGHT, true
+	case .MIDDLE:
+		return .MIDDLE, true
+	case .INVALID:
+		return nil, false
+	}
+	return nil, false
+}
+
+map_key :: proc(key: sapp.Keycode) -> (mu.Key, bool) {
+	#partial switch key {
+	case .LEFT_SHIFT, .RIGHT_SHIFT:
+		return .SHIFT, true
+	case .LEFT_CONTROL, .RIGHT_CONTROL:
+		return .CTRL, true
+	case .LEFT_ALT, .RIGHT_ALT:
+		return .ALT, true
+	case .ENTER:
+		return .RETURN, true
+	case .BACKSPACE:
+		return .BACKSPACE, true
+	}
+	return nil, false
+}
+
+event :: proc "c" (ev: ^sapp.Event) {
+	context = runtime.default_context()
+
+	#partial switch ev.type {
+	case .MOUSE_DOWN:
+		if btn, ok := map_mouse_button(ev.mouse_button); ok {
+			mu.input_mouse_down(&state.mu_ctx, i32(ev.mouse_x), i32(ev.mouse_y), btn)
+		}
+
+	case .MOUSE_UP:
+		if btn, ok := map_mouse_button(ev.mouse_button); ok {
+			mu.input_mouse_up(&state.mu_ctx, i32(ev.mouse_x), i32(ev.mouse_y), btn)
+		}
+
+	case .MOUSE_MOVE:
+		mu.input_mouse_move(&state.mu_ctx, i32(ev.mouse_x), i32(ev.mouse_y))
+
+	case .MOUSE_SCROLL:
+		mu.input_scroll(&state.mu_ctx, 0, i32(ev.scroll_y))
+
+	case .KEY_DOWN:
+		if k, ok := map_key(ev.key_code); ok {
+			mu.input_key_down(&state.mu_ctx, k)
+		}
+
+	case .KEY_UP:
+		if k, ok := map_key(ev.key_code); ok {
+			mu.input_key_up(&state.mu_ctx, k)
+		}
+
+	case .CHAR:
+		if ev.char_code != 127 && ev.char_code >= 32 {
+			text := fmt.tprintf("%r", rune(ev.char_code))
+			mu.input_text(&state.mu_ctx, text)
+		}
+	}
+}
 
 init :: proc "c" () {
 	context = runtime.default_context()
+
 	sg.setup({environment = sglue.environment(), logger = {func = slog.func}})
 	sgl.setup({logger = {func = slog.func}})
 
-	mu.init(&mu_ctx)
-	mu_ctx.text_width = mu.default_atlas_text_width
-	mu_ctx.text_height = mu.default_atlas_text_height
-}
+	mu.init(&state.mu_ctx)
+	state.mu_ctx.text_width = mu.default_atlas_text_width
+	state.mu_ctx.text_height = mu.default_atlas_text_height
 
-frame :: proc "c" () {
-	context = runtime.default_context()
+	width := mu.DEFAULT_ATLAS_WIDTH
+	height := mu.DEFAULT_ATLAS_HEIGHT
+	pixels := make([]u32, width * height)
+	defer delete(pixels)
+
+	for alpha, i in mu.default_atlas_alpha {
+		pixels[i] = 0x00FFFFFF | (u32(alpha) << 24)
+	}
+
+	img_desc: sg.Image_Desc
+	img_desc.width = i32(width)
+	img_desc.height = i32(height)
+	img_desc.pixel_format = .RGBA8
+	img_desc.data.mip_levels[0] = {
+		ptr  = raw_data(pixels),
+		size = len(pixels) * 4,
+	}
+	state.atlas_img = sg.make_image(img_desc)
 
-	t := f32(sapp.frame_duration() * 60.0)
+	view_desc: sg.View_Desc
+	view_desc.texture.image = state.atlas_img
+	state.atlas_view = sg.make_view(view_desc)
 
-	mu.begin(&mu_ctx)
+	smp_desc: sg.Sampler_Desc
+	smp_desc.min_filter = .NEAREST
+	smp_desc.mag_filter = .NEAREST
+	state.atlas_smp = sg.make_sampler(smp_desc)
 
-	@(static) opts := mu.Options{}
-	if mu.begin_window(&mu_ctx, "Window", {0, 0, 400, 400}, opts) {
-		mu.button(&mu_ctx, "Button")
+	pip_desc: sg.Pipeline_Desc
+	pip_desc.colors[0].blend.enabled = true
+	pip_desc.colors[0].blend.src_factor_rgb = .SRC_ALPHA
+	pip_desc.colors[0].blend.dst_factor_rgb = .ONE_MINUS_SRC_ALPHA
+	state.ui_pip = sgl.make_pipeline(pip_desc)
 
-		mu.end_window(&mu_ctx)
+	vertices := [?]f32 {
+		0.0,
+		0.5,
+		0.5,
+		1.0,
+		0.0,
+		0.0,
+		1.0,
+		0.5,
+		-0.5,
+		0.5,
+		0.0,
+		1.0,
+		0.0,
+		1.0,
+		-0.5,
+		-0.5,
+		0.5,
+		0.0,
+		0.0,
+		1.0,
+		1.0,
 	}
+	state.bind.vertex_buffers[0] = sg.make_buffer(
+		{data = {ptr = &vertices, size = size_of(vertices)}},
+	)
+	state.pip = sg.make_pipeline(
+		{
+			shader = sg.make_shader(triangle_shader_desc(sg.query_backend())),
+			layout = {attrs = {0 = {format = .FLOAT3}, 1 = {format = .FLOAT4}}},
+		},
+	)
+	state.pass_action = {
+		colors = {0 = {load_action = .CLEAR, clear_value = {0.4, 0.4, 0.5, 1}}},
+	}
+}
+
+frame :: proc "c" () {
+	context = runtime.default_context()
+
+	mu.begin(&state.mu_ctx)
 
-	mu.end(&mu_ctx)
+	if mu.begin_window(&state.mu_ctx, "Interactive Window", {40, 40, 300, 250}) {
+		mu.label(&state.mu_ctx, "Try interacting!")
+		mu.button(&state.mu_ctx, "Button")
+		mu.end_window(&state.mu_ctx)
+	}
+	mu.end(&state.mu_ctx)
 
 	sgl.defaults()
 	sgl.push_pipeline()
+	sgl.load_pipeline(state.ui_pip)
+	sgl.enable_texture()
+	sgl.texture(state.atlas_view, state.atlas_smp)
+
 	sgl.matrix_mode_projection()
 	sgl.push_matrix()
 	sgl.ortho(0.0, sapp.widthf(), sapp.heightf(), 0.0, -1.0, +1.0)
 	sgl.begin_quads()
+
 	current_command: ^mu.Command
-	for cmd_variant in mu.next_command_iterator(&mu_ctx, &current_command) {
+	for cmd_variant in mu.next_command_iterator(&state.mu_ctx, &current_command) {
 		#partial switch cmd in cmd_variant {
 		case ^mu.Command_Rect:
 			draw_rect(cmd.rect, cmd.color)
+		case ^mu.Command_Text:
+			draw_text(cmd.str, cmd.pos, cmd.color)
+		case ^mu.Command_Icon:
+			draw_icon(cmd.id, cmd.rect, cmd.color)
+		case ^mu.Command_Clip:
+			sgl.end()
+			sgl.scissor_rect(
+				f32(cmd.rect.x),
+				f32(cmd.rect.y),
+				f32(cmd.rect.w),
+				f32(cmd.rect.h),
+				true,
+			)
+			sgl.begin_quads()
 		}
 	}
 	sgl.end()
@@ -62,11 +222,52 @@ frame :: proc "c" () {
 	sgl.pop_pipeline()
 
 	sg.begin_pass({action = state.pass_action, swapchain = sglue.swapchain()})
+	sg.apply_pipeline(state.pip)
+	sg.apply_bindings(state.bind)
+	sg.draw(0, 3, 1)
 	sgl.draw()
 	sg.end_pass()
 	sg.commit()
 }
 
+draw_rect :: proc(rect: mu.Rect, color: mu.Color) {
+	push_quad(rect, mu.default_atlas[mu.DEFAULT_ATLAS_WHITE], color)
+}
+
+draw_text :: proc(str: string, pos: mu.Vec2, color: mu.Color) {
+	cur_pos := pos
+	for char in str {
+		idx := int(char)
+		if idx > 127 do idx = 0
+		rect := mu.default_atlas[mu.DEFAULT_ATLAS_FONT + idx]
+		dst := mu.Rect{cur_pos.x, cur_pos.y, rect.w, rect.h}
+		push_quad(dst, rect, color)
+		cur_pos.x += rect.w
+	}
+}
+
+draw_icon :: proc(id: mu.Icon, rect: mu.Rect, color: mu.Color) {
+	src := mu.default_atlas[int(id)]
+	x := rect.x + (rect.w - src.w) / 2
+	y := rect.y + (rect.h - src.h) / 2
+	push_quad({x, y, src.w, src.h}, src, color)
+}
+
+push_quad :: proc(dst: mu.Rect, src: mu.Rect, color: mu.Color) {
+	u0 := f32(src.x) / f32(mu.DEFAULT_ATLAS_WIDTH)
+	v0 := f32(src.y) / f32(mu.DEFAULT_ATLAS_HEIGHT)
+	u1 := f32(src.x + src.w) / f32(mu.DEFAULT_ATLAS_WIDTH)
+	v1 := f32(src.y + src.h) / f32(mu.DEFAULT_ATLAS_HEIGHT)
+	x0, y0 := f32(dst.x), f32(dst.y)
+	x1, y1 := f32(dst.x + dst.w), f32(dst.y + dst.h)
+
+	sgl.c4b(color.r, color.g, color.b, color.a)
+	sgl.v2f_t2f(x0, y0, u0, v0)
+	sgl.v2f_t2f(x1, y0, u1, v0)
+	sgl.v2f_t2f(x1, y1, u1, v1)
+	sgl.v2f_t2f(x0, y1, u0, v1)
+}
+
 cleanup :: proc "c" () {
 	context = runtime.default_context()
 	sgl.shutdown()
@@ -79,34 +280,12 @@ main :: proc() {
 			init_cb = init,
 			frame_cb = frame,
 			cleanup_cb = cleanup,
+			event_cb = event,
 			width = 1280,
 			height = 720,
-			sample_count = 4,
-			window_title = "huginn",
+			window_title = "Sokol + MicroUI",
 			icon = {sokol_default = true},
 			logger = {func = slog.func},
 		},
 	)
 }
-
-push_quad :: proc(dst: mu.Rect, src: mu.Rect, color: mu.Color) {
-	u0 := f32(src.x) / f32(mu.DEFAULT_ATLAS_WIDTH)
-	v0 := f32(src.y) / f32(mu.DEFAULT_ATLAS_HEIGHT)
-	u1 := f32(src.x + src.w) / f32(mu.DEFAULT_ATLAS_WIDTH)
-	v1 := f32(src.y + src.h) / f32(mu.DEFAULT_ATLAS_HEIGHT)
-
-	x0 := f32(dst.x)
-	y0 := f32(dst.y)
-	x1 := f32(dst.x + dst.w)
-	y1 := f32(dst.y + dst.h)
-
-	sgl.c4b(color.r, color.g, color.b, color.a)
-	sgl.v2f_t2f(x0, y0, u0, v0)
-	sgl.v2f_t2f(x1, y0, u1, v0)
-	sgl.v2f_t2f(x1, y1, u1, v1)
-	sgl.v2f_t2f(x0, y1, u0, v1)
-}
-
-draw_rect :: proc(rect: mu.Rect, color: mu.Color) {
-	push_quad(rect, mu.default_atlas[mu.DEFAULT_ATLAS_WHITE], color)
-}