console : *Console; Command_Proc :: struct { name: string; proc: (arguments: [] string); } Buffer_Entry :: struct { text: string; color: Color; } Console :: struct { buffer: [..] Buffer_Entry; current_string: string; commands: [..] Command_Proc; active: bool; visible: bool; open_amount: float; animation_position: float; // 1.0 means fully visible font: Font_Handle; rect_pipeline: Pipeline_State_Handle; text_pipeline: Pipeline_State_Handle; vb: Buffer_Handle; cursor_vb: Buffer_Handle; verts: [..] Colored_Vert; } console_error :: (str: string, args: ..Any) { array_add(*console.buffer, .{sprint(str, ..args), .{1,0,0,1}}); } console_success :: (str: string, args: ..Any) { array_add(*console.buffer, .{sprint(str, ..args), .{0,1,0,1}}); } add_command :: (console: *Console, cmd: string, proc: (arguments: [] string)) { command : Command_Proc; command.name = copy_string(cmd); command.proc = proc; array_add(*console.commands, command); } init_console :: () { console = New(Console); //console.verts.allocator = temp; buffer_size := size_of(Colored_Vert) * 12; console.vb = create_vertex_buffer(engine.renderer, null, xx buffer_size, stride=size_of(Colored_Vert), mappable=true); console.cursor_vb = create_vertex_buffer(engine.renderer, null, xx buffer_size, stride=size_of(Colored_Vert), mappable=true); { vs := create_vertex_shader(engine.renderer, "../assets/shaders/ui_rect.hlsl", "VS"); ps := create_pixel_shader(engine.renderer, "../assets/shaders/ui_rect.hlsl", "PS"); layout : [2] Vertex_Data_Info; layout[0] = .{0, .POSITION2D, 0}; layout[1] = .{0, .COLOR_WITH_ALPHA, 0}; params : [0] Shader_Parameter; console.rect_pipeline = create_pipeline_state(engine.renderer, vs, ps, layout, params, blend_type=.TRANSPARENT); } { vs := create_vertex_shader(engine.renderer, "../assets/shaders/font.hlsl", "VS"); ps := create_pixel_shader(engine.renderer, "../assets/shaders/font.hlsl", "PS"); layout : [3] Vertex_Data_Info; layout[0] = .{0,.POSITION2D, 0}; layout[1] = .{0,.TEXCOORD0, 0}; layout[2] = .{0,.COLOR_WITH_ALPHA, 0}; params : [0] Shader_Parameter; console.text_pipeline = create_pipeline_state(engine.renderer, vs, ps, layout, params, blend_type=.TRANSPARENT); } console.font = create_font(engine.renderer, "../assets/fonts/Inconsolata-Regular.ttf", 18); console.current_string = alloc_string(256); console.current_string.count = 0; //add_command(console, "stats", toggle_stats); //add_command(console, "camset", save_camera); //add_command(console, "load", load_scene); //add_command(console, "copy", copy_scene); //add_command(console, "vsync", set_vsync); add_engine_console_commands(); //engine.console = console; } find_command :: (console: *Console, cmd_str: string) -> Command_Proc, bool { for console.commands { if equal(it.name, cmd_str) { return it, true; } } return .{}, false; } update_console :: () { if key_down(.TILDE) { console.active = !console.active; engine.input.has_char = false; // Make sure that the tilde is not used as the first input character in the console } if console.active { if key_down(.BACKSPACE) { if console.current_string.count > 0 { console.current_string.count -= 1; } } if key_down(.RETURN) { if console.current_string.count > 0 { // @Incomplete(niels): Using split with space will take spaces as part of the args. // So each subsequent space will be an argument itself. // This is a bit of a hacky fix for now arguments := split(console.current_string, " "); index := 0; command := arguments[0]; while index < arguments.count - 1 { if arguments[index].count == 0 { arguments[index] = arguments[arguments.count - 1]; arguments.count -= 1; } else { if index > 0 { } index += 1; } } if arguments[arguments.count - 1].count == 0 { arguments.count -= 1; } for_cmd : [..] string; for_cmd.allocator = temp; array_reserve(*for_cmd, arguments.count-1); for arguments { if it_index == 0 continue; array_add(*for_cmd, it); } cmd, success := find_command(console, arguments[0]); push_entry(*console.buffer, console.current_string, .{1,1,1,1}); if success { cmd.proc(for_cmd); } else { push_entry(*console.buffer, console.current_string, .{1,0,0,1}); } console.current_string.count = 0; } } if engine.input.has_char { if console.current_string.count < 256 { console.current_string.data[console.current_string.count] = xx engine.input.current_char; console.current_string.count += 1; engine.input.has_char = false; } } eat_all_input(*engine.input); } } make_vert :: (x: float, y: float, color: Color) -> Colored_Vert { vert : Colored_Vert; vert.position.x = x; vert.position.y = y; vert.color = color; return vert; } add_rect :: (renderer: *Renderer, x: float, y: float, width: float, height: float, color: Color, verts: *[..] Colored_Vert) { inv_w := 1.0 / cast(float)engine.renderer.render_target_width; inv_h := 1.0 / cast(float)engine.renderer.render_target_height; x = x * inv_w * 2.0 - 1.0; y = (cast(float)engine.renderer.render_target_height - y) * inv_h * 2.0 - 1.0; w : float = width * inv_w * 2.0; h : float = height * inv_h * 2.0; array_add(verts, make_vert(x + w, y - h, color)); array_add(verts, make_vert(x, y - h, color)); array_add(verts, make_vert(x, y, color)); array_add(verts, make_vert(x + w, y - h, color)); array_add(verts, make_vert(x, y, color)); array_add(verts, make_vert(x + w, y, color)); } render_console :: () { if console.active { console.visible = true; console.open_amount += dt * 3.0; } else { console.open_amount -= dt * 3.0; if console.open_amount <= 0.0 { console.visible = false; } } console.open_amount = clamp(console.open_amount, 0.0, 1.0); if !console.visible return; offset_y := (1.0 - console.open_amount) * 200.0 - 75; console.verts.count = 0; console_color : Color = .{48.0/255.0, 64.0/255.0, 36.0/255.0, 0.7}; console_line_color : Color = .{18.0/255.0, 34.0/255.0, 6.0/255.0, 0.7}; add_rect(engine.renderer, 0.0, cast(float)engine.renderer.render_target_height - 200 + offset_y, cast(float)engine.renderer.render_target_width, 200.0, console_color, *console.verts); add_rect(engine.renderer, 0.0, cast(float)engine.renderer.render_target_height - 30 + offset_y, cast(float)engine.renderer.render_target_width, 30.0, console_line_color , *console.verts); upload_data_to_buffer(engine.renderer, console.vb, console.verts.data, cast(s32)console.verts.count * size_of(Colored_Vert)); push_cmd_set_draw_mode(engine.renderer, .FILL); push_cmd_set_depth_write(engine.renderer, false); push_cmd_set_pipeline_state(engine.renderer, console.rect_pipeline); push_cmd_set_vertex_buffer(engine.renderer, console.vb); push_cmd_draw(engine.renderer, console.verts.count); push_cmd_set_pipeline_state(engine.renderer, console.text_pipeline); font := *engine.renderer.fonts[console.font - 1]; push_cmd_set_texture(engine.renderer, 0, font.texture); size := get_text_size(engine.renderer, ">", console.font); render_data := bake_text(engine.renderer, 5.0, size.y - offset_y, ">", console.font, .{1,1,1,1}); push_cmd_set_vertex_buffer(engine.renderer, render_data.vb); push_cmd_draw(engine.renderer, render_data.vert_count); x := 15.0; if console.current_string.count > 0 { render_data := bake_text(engine.renderer, x, size.y - offset_y, console.current_string, console.font, .{1,1,1,1}); push_cmd_set_vertex_buffer(engine.renderer, render_data.vb); push_cmd_draw(engine.renderer, render_data.vert_count); x = 10 + render_data.size.x + 2.0; } y := 37.0; i := console.buffer.count - 1; count := 0; while i >= 0 && count < 8 { defer i -= 1; defer count += 1; entry := console.buffer[i]; render_data := bake_text(engine.renderer, 15.0, y - offset_y, entry.text, console.font, entry.color); push_cmd_set_vertex_buffer(engine.renderer, render_data.vb); push_cmd_draw(engine.renderer, render_data.vert_count); y += 20.0; } console.verts.count = 0; //#if !NEW_UI { add_rect(engine.renderer, x, cast(float)engine.renderer.render_target_height - 25 + offset_y, 10, 20.0, .{1,1,1,1}, *console.verts); //} upload_data_to_buffer(engine.renderer, console.cursor_vb, console.verts.data, cast(s32)console.verts.count * size_of(Colored_Vert)); push_cmd_set_draw_mode(engine.renderer, .FILL); push_cmd_set_depth_write(engine.renderer, false); push_cmd_set_pipeline_state(engine.renderer, console.rect_pipeline); push_cmd_set_vertex_buffer(engine.renderer, console.cursor_vb); push_cmd_draw(engine.renderer, console.verts.count); } push_entry :: (buffer: *[..] Buffer_Entry, text: string, color: Color) { entry : Buffer_Entry; entry.text = copy_string(text); entry.color = color; array_add(buffer, entry); } #import "File_Utilities"; #load "console_commands.jai";