Files
Edit2D/interface.odin
2026-03-29 06:34:00 +05:45

189 lines
4.6 KiB
Odin

#+feature dynamic-literals
package edit2d
//import im "shared:odin-imgui"
import mu "vendor:microui"
import e2_glyph "./glyph"
import "core:fmt"
import "vendor:glfw"
import b2 "vendor:box2d"
/*
This library will only account for box2d's entities editing
It only deals with one world_id, which means typically one level
All the interface follows a pattern
i.e. It takes interface_state pointer and returns a boolean indicating weather the world needs to be reloaded
Interface should handle microui
*/
Edit_Mode :: enum
{
ENTITY,
VERTICES,
OVERVIEW,
CHAIN,
JOINT,
}
Interface_State :: struct
{
entity_defs : [dynamic]^Engine_Entity_Def,
entities : [dynamic]^Engine_Entity,
selected_entity : i32,
world : ^Engine_World,
state : ^Engine_State,
vertex_index : i32,
chain_index : i32,
edit_mode : Edit_Mode,
curr_joint_index : i32,
curr_joint_type : b2.JointType,
curr_static_index : Static_Index_Global,
}
key_map : map[i32]mu.Key = {
glfw.KEY_LEFT_SHIFT = .SHIFT,
glfw.KEY_RIGHT_SHIFT = .SHIFT,
glfw.KEY_LEFT_CONTROL = .CTRL,
glfw.KEY_RIGHT = .CTRL,
glfw.KEY_LEFT_ALT = .ALT,
glfw.KEY_RIGHT_ALT = .ALT,
glfw.KEY_BACKSPACE = .BACKSPACE,
glfw.KEY_DELETE = .DELETE,
glfw.KEY_ENTER = .RETURN,
glfw.KEY_LEFT = .LEFT,
glfw.KEY_RIGHT = .RIGHT,
glfw.KEY_HOME = .HOME,
glfw.KEY_END = .END,
glfw.KEY_A = .A,
glfw.KEY_X = .X,
glfw.KEY_C = .C,
glfw.KEY_V = .V
}
mouse_map : map[i32]mu.Mouse = {
glfw.MOUSE_BUTTON_LEFT = .LEFT,
glfw.MOUSE_BUTTON_RIGHT = .RIGHT,
glfw.MOUSE_BUTTON_MIDDLE= .MIDDLE,
}
//interface_get_font
mui_text_width :: proc(font: mu.Font, str: string) -> i32
{
glyph := cast(^e2_glyph.GlyphState)font
return i32(len(str)) * i32(glyph.font_size_pt)
}
mui_text_height :: proc(font: mu.Font) -> i32
{
glyph := cast(^e2_glyph.GlyphState)font
return i32(glyph.font_size_pt)
}
interface_get_default :: proc(interface: ^Interface_State)
{
interface.selected_entity = 0
interface.vertex_index = 0
interface.chain_index = 0
}
mu_interface_game_mode :: proc(state: ^Engine_State, interface: ^Interface_State)
{
width :i32 = 250
if mu.begin_window(&state.mu_ctx, "Edit Mode", {state.width - width, 0, width, 170})
{
for type in Edit_Mode
{
b : bool = interface.edit_mode == type
if .CHANGE in mu.checkbox(&state.mu_ctx, fmt.tprint(type), &b) do interface.edit_mode = type
}
mu.end_window(&state.mu_ctx)
}
}
mu_interface_draw_options :: proc(state: ^Engine_State)
{
if mu.begin_window(&state.mu_ctx, "Options", {0, 150, 200, 400}){
debug_draw := &state.debug_draw
mu.label(&state.mu_ctx, "Zoom")
mu.slider(&state.mu_ctx, &state.draw.cam.zoom,0, 100)
mu.checkbox(&state.mu_ctx, "Shapes", &debug_draw.drawShapes)
mu.checkbox(&state.mu_ctx, "Joints", &debug_draw.drawJoints)
mu.checkbox(&state.mu_ctx, "Joint Extras", &debug_draw.drawJointExtras)
mu.checkbox(&state.mu_ctx, "Bounds", &debug_draw.drawBounds)
mu.checkbox(&state.mu_ctx, "Contact Points", &debug_draw.drawContacts)
mu.checkbox(&state.mu_ctx, "Contact Normals", &debug_draw.drawContactNormals)
mu.checkbox(&state.mu_ctx, "Contact Inpulses", &debug_draw.drawContactImpulses)
mu.checkbox(&state.mu_ctx, "Contact Features", &debug_draw.drawContactFeatures)
mu.checkbox(&state.mu_ctx, "Friction Inpulses", &debug_draw.drawFrictionImpulses)
mu.checkbox(&state.mu_ctx, "Mass ", &debug_draw.drawMass)
mu.checkbox(&state.mu_ctx, "Body Names", &debug_draw.drawBodyNames)
mu.checkbox(&state.mu_ctx, "Graph Colors", &debug_draw.drawGraphColors)
mu.checkbox(&state.mu_ctx, "Islands ", &debug_draw.drawIslands)
mu.label(&state.mu_ctx, "Rotation")
mu.slider(&state.mu_ctx, &state.draw.cam.rotation, 0, 360)
mu.end_window(&state.mu_ctx)
}
}
interface_all :: proc($E: typeid, interface: ^Interface_State, game_data : $G) -> bool
{
ret := false
if interface.selected_entity <0
{
interface.selected_entity = 0
}
state := interface.state
mu.begin(&state.mu_ctx)
mu_interface_draw_options(interface.state)
mu_interface_game_mode(state, interface)
width : i32 = 250
if mu.begin_window(&state.mu_ctx, "B2d Interface", {state.width - width, 170, width, 450}, { .NO_TITLE})
{
if interface.edit_mode == .ENTITY
{
if .ACTIVE in mu.header(&state.mu_ctx, "Entity", {.AUTO_SIZE})
{
if interface_entity(interface) do ret = true
}
}
mu.end_window(&state.mu_ctx)
}
//if interface_joints(interface) do ret = true
mu.end(&state.mu_ctx)
return ret
}