#include "editor.h" #include "../render/gl.h" #include "../game/assets.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; static I32 propview_col_left() { return PROPVIEW_PAD; } static I32 propview_col_right( GUI_EDITOR_PROPVIEW* view ) { if( !view ) return PROPVIEW_PAD; return max( PROPVIEW_PAD, view->w - PROPVIEW_PAD ); } static I32 propview_input_width( GUI_EDITOR_PROPVIEW* view ) { return max( 120, propview_col_right( view ) - propview_col_left() ); } static I32 propview_sub_input_x( I32 x ) { return x + 10; } static 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 ) ); } static I32 propview_action_x( GUI_EDITOR_PROPVIEW* view ) { I32 right = propview_col_right( view ); return max( propview_col_left(), right - PROPVIEW_ACTION_BTN_W ); } static 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 ); } // returns the subentry height I32 gui_editor_propview_surfprops_subentry( GUI_EDITOR_PROPVIEW* view, I32 x, I32 y, I32* propid, SURF_PROPS* props ) { I32 oldy = y; I32 space = 20; I32 action_x = propview_action_x( view ); I32 action2_x = propview_action2_x( view ); gui_label( x, y, "prop id: %d", *propid ); GUI_BUTTON* newprop = gui_button( action2_x, y, 20, 20, "+", pfn( void* ptr ) { GUI_BUTTON* btn = (GUI_BUTTON*)ptr; SURF_PROPS props; props.tex = 0; props.clr = { 1.f, 1.f, 1.f, 1.f }; editor->map->props.push( props ); *(U32*)(btn->extra) = editor->map->props.size - 1; // Keep the newest prop visible in the assets panel (pixel scroll). editor->gui.assets_scroll = ( editor->map->props.size + 1 ) * 28; gui_editor_propview_update( editor->gui.props ); } ); newprop->extra = propid; 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; if( props->tex ) gui_label( x + 10, y, "texture: %s", props->tex->name ); else gui_label( x + 10, y, "texture: none" ); 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 = &props->tex; y += space; gui_colorinput( propview_sub_input_x( x ), y, propview_sub_input_width( view, x ), "color", &props->clr ); y += (space+18); return y - oldy; } void gui_editor_propview_create_wallprops( GUI_EDITOR_PROPVIEW* view ) { MAP_WALL* s = (MAP_WALL*)view->curselect; WORLD_MAP* m = editor->map; SURF_PROPS* props = wall_get_props( m, s ); I32 x = 10, y = 10; I32 space = 20; F32 step = editor->propgrid? editor->grid : 0.25f; I32 wall_idx = m->walls.idx_where( fn( MAP_WALL* ms ) { return s == ms; } ); gui_label( x, y, "idx: %d", wall_idx ); y += space; y += gui_editor_propview_surfprops_subentry( view, x, y, &s->propid, props ); GUI_VECTORINPUT* posinput; posinput = gui_vectorinput( x, y, propview_input_width( view ), "start", (F32*)&s->start, 3, -INFINITY, INFINITY, step ); y += (space+18); posinput->cb = pfn( void* ) { map_check_bounds( editor->map ); }; posinput = gui_vectorinput( x, y, propview_input_width( view ), "end", (F32*)&s->end, 3, -INFINITY, INFINITY, step ); y += (space+18); posinput->cb = pfn( void* ) { map_check_bounds( editor->map ); }; } void gui_editor_propview_create_polyprops( GUI_EDITOR_PROPVIEW* view ) { MAP_POLYGON* p = (MAP_POLYGON*)view->curselect; WORLD_MAP* m = editor->map; SURF_PROPS* props = polygon_get_props( m, p ); I32 x = 10, y = 10; I32 space = 20; I32 poly_idx = m->polygons.idx_where( fn( MAP_POLYGON* mp ) { return p == mp; } ); I32 action_x = propview_action_x( view ); gui_label( x, y, "idx: %d", poly_idx ); y += space; y += gui_editor_propview_surfprops_subentry( view, x, y, &p->propid, props ); gui_label( x, y, "vertices: %d", p->vertices.size ); y += space; I32 idx = 0; p->vertices.each( fn( MAP_VERTEX* v ) { gui_label( x + 10, y, "[%d] -> { %.02f, %.02f, %.02f }", idx, v->pos.x, v->pos.y, v->pos.z ); GUI_BUTTON* btn = gui_button( action_x, y - 2, 20, 20, "\x1A", pfn( void* ptr ) { GUI_EDITOR_PROPVIEW* view = editor->gui.props; GUI_BUTTON* btn = (GUI_BUTTON*)ptr; MAP_POLYGON* p = (MAP_POLYGON*)view->curselect; I64 idx = (I64)btn->extra; if( p ) // p100 gui_editor_propview_select( view, &p->vertices[idx], EDITOR_SELECT_PVERTEX ); } ); y += space; btn->extra = (void*)( (I64)idx++ ); } ); gui_label( x, y, "mins: { %1.02f, %1.02f, %1.02f }", p->mins.x, p->mins.y, p->mins.z ); y += space; gui_label( x, y, "maxs: { %1.02f, %1.02f, %1.02f }", p->maxs.x, p->maxs.y, p->maxs.z ); y += space; } 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 ); 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, "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; } ); F32 step = editor->propgrid? editor->grid : 0.25f; 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; GUI_VECTORINPUT* posinput = gui_vectorinput( x, y, propview_input_width( view ), "position", (F32*)&v->pos, 3, -INFINITY, INFINITY, step ); y += (space+18); posinput->cb = pfn( void* ptr ) { map_check_bounds( editor->map ); }; gui_vectorinput( x, y, propview_input_width( view ), "texture coordinates", (F32*)&v->uv, 2, 0.f, 1.f, 0.005f, "xy", "%.03f" ); y += (space+18); gui_colorinput( x, y, propview_input_width( view ), "color", &v->clr ); y += (space+18); } 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; } ); I32 action_x = propview_action_x( view ); F32 step = editor->propgrid? editor->grid : 0.25f; gui_label( x, y, "idx: %d", sprite_idx ); y += space; gui_vectorinput( x, y, propview_input_width( view ), "position", (F32*)&s->pos, 3, -INFINITY, INFINITY, step ); y += (space+18); gui_vectorinput( x, y, propview_input_width( view ), "size", (F32*)&s->size, 2, 1.f, INFINITY, 1.f, "wh" ); y += (space+18); gui_colorinput( x, y, propview_input_width( view ), "color", &s->clr ); y += (space+18); if( s->tex ) gui_label( x, y, "texture: %s", s->tex->name ); else gui_label( x, y, "texture: none" ); 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 = &s->tex; y += space; } 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; I32 action_x = propview_action_x( view ); gui_label( x, y, "prop id: %d", i ); y += space; if( p->tex ) gui_label( x, y, "texture: %s", assets_abspath( p->tex->name ) ); else gui_label( x, y, "texture: none" ); 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 = &p->tex; y += space; gui_colorinput( x, y, propview_input_width( view ), "color", &p->clr ); y += (space+18); } void gui_editor_propview_create_entprops( GUI_EDITOR_PROPVIEW* view ) { } 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; }