#include "properties.h" #include "editor.h" #include "../render/gl.h" #include "../game/assets.h" #include "../game/object.h" const I32 PROPVIEW_TITLE_OFFSET = 15; const I32 PROPVIEW_PAD = 10; const I32 PROPVIEW_ACTION_BTN_W = 20; const I32 PROPVIEW_ACTION_BTN_GAP = 5; I32 propview_col_left() { return PROPVIEW_PAD; } I32 propview_col_right( GUI_EDITOR_PROPVIEW* view ) { if( !view ) return PROPVIEW_PAD; return max( PROPVIEW_PAD, view->w - PROPVIEW_PAD ); } I32 propview_input_width( GUI_EDITOR_PROPVIEW* view ) { return max( 120, propview_col_right( view ) - propview_col_left() ); } I32 propview_sub_input_x( I32 x ) { return x + 10; } // I32 propview_sub_input_width( GUI_EDITOR_PROPVIEW* view, I32 x ) { // I32 right = propview_col_right( view ); // return max( 100, right - propview_sub_input_x( x ) ); // } I32 propview_action_x( GUI_EDITOR_PROPVIEW* view ) { I32 right = propview_col_right( view ); return max( propview_col_left(), right - PROPVIEW_ACTION_BTN_W ); } I32 propview_action2_x( GUI_EDITOR_PROPVIEW* view ) { return max( propview_col_left(), propview_action_x( view ) - PROPVIEW_ACTION_BTN_W - PROPVIEW_ACTION_BTN_GAP ); } void gui_editor_propview_select( GUI_EDITOR_PROPVIEW* view, void* what, U8 seltype ) { if( !editor->map ) return; if( seltype == EDITOR_SELECT_WVERTEX ) { MAP_WALL* s = editor->map->walls.where( fn( MAP_WALL* s ) { return ( &s->start == what || &s->end == what ); } ); if( !s ) return gui_editor_propview_select( view, editor->map, EDITOR_SELECT_ORIGIN ); view->curselect = s; view->seltype = EDITOR_SELECT_WALL; return gui_editor_propview_update( view ); } view->curselect = what; view->seltype = seltype; gui_editor_propview_update( view ); } void gui_editor_propview_create_eobj_props( GUI_EDITOR_PROPVIEW* view, EOBJECT* e, I32* x, I32* y, I32 w ); void gui_editor_propview_create_eobj_prop( GUI_EDITOR_PROPVIEW* view, EDITOR_PROP* prop, I32* x, I32* y, I32 w, I32 space ) { F32 action_x = propview_action_x( view ); I32 action2_x = propview_action2_x( view ); const char* n = prop->displayname; F32 min = prop->min; F32 max = prop->max; F32 step; if( prop->step ) step = prop->step; else step = editor->propgrid ? editor->grid : 0.25f; switch( prop->type ) { case EPROP_F32: gui_floatinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), min, max, step ); *y += (space+18); break; case EPROP_VEC2: gui_vectorinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), 2, min, max, step, "xy", "%.03f" ); *y += (space+18); break; case EPROP_VEC3: gui_vectorinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), 3, min, max, step, "xyz", "%.02f" ); *y += (space+18); break; case EPROP_VEC4: gui_vectorinput( *x, *y, w, n, (F32*)eprop_ptr( prop ), 3, min, max, step, "xyzw", "%0.02f" ); *y += (space+18); break; case EPROP_CLR: gui_colorinput( *x, *y, w, n, (CLR*)eprop_ptr( prop ) ); *y += (space+18); break; case EPROP_MAPPROP: { MAP_PROPREF* ref = (MAP_PROPREF*)eprop_ptr( prop ); SURF_PROPS* props = map_get_props( editor->map, *ref ); gui_label( *x, *y, "prop id: %d", *ref ); GUI_BUTTON* newprop = gui_button( action2_x, *y, 20, 20, "+", pfn( void* ptr ) { GUI_BUTTON* btn = (GUI_BUTTON*)ptr; SURF_PROPS props{ .tex = 0, .clr = CLR::WHITE() }; editor->map->props.push( props ); ((MAP_PROPREF*)btn->extra)->id = editor->map->props.size - 1; editor->gui.assets_scroll = ( editor->map->props.size + 1 ) * 28; gui_editor_propview_update( editor->gui.props ); } ); newprop->extra = ref; GUI_BUTTON* goprop = gui_button( action_x, *y, 20, 20, "\x1A", pfn( void* ptr ) { GUI_BUTTON* btn = (GUI_BUTTON*)ptr; gui_editor_propview_select( editor->gui.props, btn->extra, EDITOR_SELECT_SURFPROPS ); } ); goprop->extra = props; *y += space; *x += 10; gui_editor_propview_create_eobj_props( view, props, x, y, w - 10 ); *x -= 10; } break; case EPROP_TEXTURE: { GL_TEX2D** tex = (GL_TEX2D**)eprop_ptr( prop ); if( *tex ) gui_label( *x, *y, "%s: %s", n, (*tex)->name ); else gui_label( *x, *y, "%s: none", n ); GUI_BUTTON* btn = gui_button( action_x, *y, 20, 20, "\x1A", pfn( void* ptr ) { GUI_BUTTON* btn = (GUI_BUTTON*)ptr; GL_TEX2D** ptex = (GL_TEX2D**)btn->extra; GUI_EDITOR_TEXTUREPICKER* picker = gui_editor_texturepicker( 200, 100, 400, 400, ptex ); picker->cb = pfn( void* ) { gui_editor_propview_update( editor->gui.props ); }; } ); btn->extra = tex; *y += space; } break; case EPROP_VERTEX_LIST: { LIST* list = ( LIST* )eprop_ptr( prop ); gui_label( *x, *y, "%s : %d", n, list->size ); *y += space; for( U32 i = 0; i < list->size; ++i ) { MAP_VERTEX* v = &list->data[i]; gui_label( (*x) + 10, *y, "[%d] -> [%s]", i, to_str( v->pos ).data ); GUI_BUTTON* btn = gui_button( action_x, *y, 20, 20, "\x1A", pfn( void* ptr ) { GUI_BUTTON* btn = (GUI_BUTTON*)ptr; gui_editor_propview_select( editor->gui.props, btn->extra, EDITOR_SELECT_PVERTEX ); } ); btn->extra = v; *y += space; } } break; default: break; } } void gui_editor_propview_create_eobj_prop_ro( GUI_EDITOR_PROPVIEW* view, EDITOR_PROP* prop, I32* x, I32* y, I32 w, I32 space ) { STR str = prop->displayname; str += " : ["; void* ptr = eprop_ptr( prop ); switch( prop->type ) { case EPROP_F32: str += to_str( *(F32*)ptr ); break; case EPROP_VEC2: str += to_str( *(VEC2*)ptr ); break; case EPROP_VEC3: str += to_str( *(VEC3*)ptr ); break; case EPROP_VEC4: str += to_str( *(VEC4*)ptr ); break; case EPROP_CLR: str += to_str( *(CLR*)ptr ); break; case EPROP_U32: str += to_str( *(U32*)ptr ); break; case EPROP_U64: str += to_str( *(U64*)ptr ); break; case EPROP_I32: str += to_str( *(I32*)ptr ); break; case EPROP_I64: str += to_str( *(I64*)ptr ); break; case EPROP_STRING: str += to_str( *(CLR*)ptr ); break; } str += "]"; gui_label( *x, *y, str.data ); *y += space; } void gui_editor_propview_create_eobj_props( GUI_EDITOR_PROPVIEW* view, EOBJECT* e, I32* x, I32* y, I32 w ) { I32 space = 20; for( auto& it : e->eprops ) { EDITOR_PROP* eprop = eprop_from_ref( e, it ); if( eprop->readonly ) gui_editor_propview_create_eobj_prop_ro( view, eprop, x, y, w, space ); else gui_editor_propview_create_eobj_prop( view, eprop, x, y, w, space ); } } void gui_editor_propview_create_wallprops( GUI_EDITOR_PROPVIEW* view ) { MAP_WALL* s = (MAP_WALL*)view->curselect; WORLD_MAP* m = editor->map; I32 x = 10, y = 10; I32 space = 20; I32 wall_idx = m->walls.idx_where( fn( MAP_WALL* ms ) { return s == ms; } ); gui_label( x, y, "idx: %d", wall_idx ); y += space; return gui_editor_propview_create_eobj_props( view, s, &x, &y, propview_input_width( view ) ); } void gui_editor_propview_create_polyprops( GUI_EDITOR_PROPVIEW* view ) { MAP_POLYGON* p = (MAP_POLYGON*)view->curselect; WORLD_MAP* m = editor->map; I32 x = 10, y = 10; I32 space = 20; I32 poly_idx = m->polygons.idx_where( fn( MAP_POLYGON* mp ) { return p == mp; } ); gui_label( x, y, "idx: %d", poly_idx ); y += space; return gui_editor_propview_create_eobj_props( view, p, &x, &y, propview_input_width( view ) ); } void gui_editor_propview_create_mapprops( GUI_EDITOR_PROPVIEW* view ) { WORLD_MAP* m = (WORLD_MAP*)view->curselect; I32 x = 10, y = 10; I32 space = 20; F32 step = editor->propgrid? editor->grid : 0.25f; gui_label( x, y, "name: %s", m->name.data ); y += space; gui_label( x, y, "walls: %d", m->walls.size ); y += space; gui_label( x, y, "polygons: %d", m->polygons.size ); y += space; gui_label( x, y, "props: %d", m->props.size ); y += space; I32 action_x = propview_action_x( view ); I32 i = 0; m->props.each( fn( SURF_PROPS* p ) { if( p->tex ) gui_label( x + 10, y, "[%d] -> %s", i++, assets_abspath( p->tex->name ) ); else gui_label( x + 10, y, "[%d] -> { %.02f, %.02f, %.02f, %.02f }", i++, p->clr.r, p->clr.g, p->clr.b, p->clr.a ); GUI_BUTTON* btn = gui_button( action_x, y, 20, 20, "\x1A", pfn( void* ptr ) { GUI_BUTTON* btn = (GUI_BUTTON*)ptr; gui_editor_propview_select( editor->gui.props, btn->extra, EDITOR_SELECT_SURFPROPS ); } ); btn->extra = p; y += space; } ); gui_label( x, y, "sprites: %d", m->sprites.size ); y += space; gui_label( x, y, "entities: %d", m->entities.size ); y += space; gui_label( x, y, "loaded textures: %d", m->textures.size ); y += space; gui_vectorinput( x, y, propview_input_width( view ), "spawn position", (F32*)&m->startpos, 3, -INFINITY, INFINITY, step ); y += (space+18); GUI_FLOATINPUT* ang = gui_floatinput( x, y, propview_input_width( view ), "spawn angle", &m->startang, -180.f, 180.f, 1.f ); y += (space+18); ang->wraparound = 1; } void gui_editor_propview_create_pvertexprops( GUI_EDITOR_PROPVIEW* view ) { MAP_VERTEX* v = (MAP_VERTEX*)view->curselect; WORLD_MAP* m = editor->map; I32 x = 10, y = 10; I32 space = 20; I32 vert_idx = -1; I32 poly_idx = m->polygons.idx_where( fn( MAP_POLYGON* p ) { vert_idx = p->vertices.idx_where( fn( MAP_VERTEX* pv ) { return (pv == v); } ); return vert_idx != -1; } ); I32 action_x = propview_action_x( view ); gui_label( x, y, "idx: %d", vert_idx ); y += space; gui_label( x, y, "polygon idx: %d", poly_idx ); gui_button( action_x, y - 2, 20, 20, "\x1A", pfn( void* ) { GUI_EDITOR_PROPVIEW* view = editor->gui.props; MAP_VERTEX* v = (MAP_VERTEX*)view->curselect; WORLD_MAP* m = editor->map; MAP_POLYGON* polygon = m->polygons.where( fn( MAP_POLYGON* p ) { I32 vert_idx = p->vertices.idx_where( fn( MAP_VERTEX* pv ) { return (pv == v); } ); return vert_idx != -1; } ); if( polygon ) gui_editor_propview_select( view, polygon, EDITOR_SELECT_POLY ); } ); y += space; return gui_editor_propview_create_eobj_props( view, v, &x, &y, propview_input_width( view ) ); } void gui_editor_propview_create_spriteprops( GUI_EDITOR_PROPVIEW* view ) { MAP_SPRITE* s = (MAP_SPRITE*)view->curselect; WORLD_MAP* m = editor->map; I32 x = 10, y = 10; I32 space = 20; I32 sprite_idx = m->sprites.idx_where( fn( MAP_SPRITE* ms ) { return ms == s; } ); gui_label( x, y, "idx: %d", sprite_idx ); y += space; return gui_editor_propview_create_eobj_props( view, s, &x, &y, propview_input_width( view ) ); } void gui_editor_propview_create_surfprops( GUI_EDITOR_PROPVIEW* view ) { SURF_PROPS* p = (SURF_PROPS*)view->curselect; WORLD_MAP* m = editor->map; I32 x = 10, y = 10; I32 space = 20; I32 i = m->props.idx_where( fn( SURF_PROPS* mp ) { return mp == p; } ); if( i == -1 ) return; gui_label( x, y, "prop id: %d", i ); y += space; return gui_editor_propview_create_eobj_props( view, p, &x, &y, propview_input_width( view ) ); } void gui_editor_propview_create_entprops( GUI_EDITOR_PROPVIEW* view ) { MAP_ENTITY* e = (MAP_ENTITY*)view->curselect; WORLD_MAP* m = editor->map; I32 x = 10, y = 10; I32 space = 20; F32 step = editor->propgrid ? editor->grid : 0.25f; I32 ent_idx = m->entities.idx_where( fn( MAP_ENTITY* me ) { return me == e; } ); gui_label( x, y, "idx: %d", ent_idx ); y += space; gui_label( x, y, "class: %s", obj_classid_to_name( e->classid ) ); y += space; gui_label( x, y, "class id: %u", e->classid ); y += space; gui_vectorinput( x, y, propview_input_width( view ), "position", (F32*)&e->pos, 3, -INFINITY, INFINITY, step ); y += (space+18); } void gui_editor_propview_update( GUI_EDITOR_PROPVIEW* view ) { if( !editor->map ) return; GUI_VIEW* target = gui_get_view(); defer({ if( target ) gui_set_view( target ); }); gui_empty_children( view->itemview ); gui_set_view( view->itemview ); view->itemview->initheld = 1; switch( view->seltype ) { case EDITOR_SELECT_WALL: gui_editor_propview_create_wallprops( view ); break; case EDITOR_SELECT_POLY: gui_editor_propview_create_polyprops( view ); break; case EDITOR_SELECT_ORIGIN: gui_editor_propview_create_mapprops( view ); break; case EDITOR_SELECT_ENT: gui_editor_propview_create_entprops( view ); break; case EDITOR_SELECT_PVERTEX: gui_editor_propview_create_pvertexprops( view ); break; case EDITOR_SELECT_SPRITE: gui_editor_propview_create_spriteprops( view ); break; case EDITOR_SELECT_SURFPROPS: gui_editor_propview_create_surfprops( view ); break; default: break; } } void gui_editor_propview_get_title( GUI_EDITOR_PROPVIEW* view, char* buf ) { switch( view->seltype ) { case EDITOR_SELECT_NONE: sprintf( buf, "properties" ); break; case EDITOR_SELECT_POLY: sprintf( buf, "polygon properties" ); break; case EDITOR_SELECT_ORIGIN: sprintf( buf, "properties" ); break; case EDITOR_SELECT_ENT: sprintf( buf, "entity properties" ); break; case EDITOR_SELECT_SPRITE: sprintf( buf, "sprite properties" ); break; case EDITOR_SELECT_PVERTEX: sprintf( buf, "vertex properties" ); break; case EDITOR_SELECT_SURFPROPS: sprintf( buf, "surface properties" ); break; case EDITOR_SELECT_WVERTEX: case EDITOR_SELECT_WALL: sprintf( buf, "wall properties" ); break; } } void gui_editor_propview_draw_fn( void* ptr ) { if( !editor->map ) return; GUI_EDITOR_PROPVIEW* view = (GUI_EDITOR_PROPVIEW*)ptr; I32 x = gui_relx( view ); I32 y = gui_rely( view ); I32 w = view->w; I32 h = view->h; char title[64]; gui_editor_propview_get_title( view, title ); gui_draw_str( x, y, ALIGN_L, FNT_JPN12, ui_clr.txt, title ); y += PROPVIEW_TITLE_OFFSET; CLR col = gui_is_fg_window( view )? ui_clr.border : ui_clr.border_inactive; gui_draw_frect( x, y, w, h, col ); gui_draw_frect( x+1, y+1, w-2, h-2, ui_clr.bg_sec ); view->itemview->draw_fn( view->itemview ); } GUI_EDITOR_PROPVIEW* gui_editor_propview( I32 x, I32 y, I32 w, I32 h ) { if( !gui_check_target() ) return 0; GUI_EDITOR_PROPVIEW* view = new GUI_EDITOR_PROPVIEW; view->x = x; view->y = y; view->w = w; view->h = h; view->xbound = view->w; view->ybound = view->h + PROPVIEW_TITLE_OFFSET; strcpy( view->name, "EDITOR_PROP_VIEW" ); view->draw_fn = gui_editor_propview_draw_fn; view->input_fn = gui_base_input_fn; view->curselect = 0; view->seltype = 0; GUI_VIEW* parent = gui_get_view(); parent->children.push( view ); view->parent = parent; gui_set_view( view ); view->itemview = gui_view( 0, PROPVIEW_TITLE_OFFSET, w, h ); gui_set_view( parent ); return view; }