/* Copyright (C) 1997-2001 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "ui_local.h" //============================================================================= // // LIST OF PLAYER MODELS // //============================================================================= #define MAX_DISPLAYNAME 16 #define MAX_PLAYERMODELS 1024 m_itemslisthead_t playermodelsItemsList; byte_vec4_t playerColor; void UI_ColorRedCallback( menucommon_t *menuitem ) { playerColor[0] = menuitem->curvalue; } void UI_ColorGreenCallback( menucommon_t *menuitem ) { playerColor[1] = menuitem->curvalue; } void UI_ColorBlueCallback( menucommon_t *menuitem ) { playerColor[2] = menuitem->curvalue; } //============================== // UI_FindIndexForModelAndSkin // if it fails returns 0 which will be the first indexed one //============================== void UI_FindIndexForModelAndSkin( char *model, char *skin, int *modelindex, int *skinindex ) { m_listitem_t *item; playermodelinfo_s *playermodel; int i, j; int currentdirectoryindex = 0; int currentskinindex = 0; if( model && model[0] ) { // find the skin and model matching our user settings (if any) for( i = 0; i < playermodelsItemsList.numItems; i++ ) { item = UI_FindItemInScrollListWithId( &playermodelsItemsList, i ); if( item ) { playermodel = (playermodelinfo_s*)item->data; if( !Q_stricmp( playermodel->directory, model ) ) { currentdirectoryindex = i; if( skin && skin[0] ) { for( j = 0; j < playermodel->nskins; j++ ) { if( !Q_stricmp( playermodel->skinnames[j], skin ) ) { currentskinindex = j; break; } } } break; } } } } *modelindex = currentdirectoryindex; *skinindex = currentdirectoryindex; } //============================== // ui_PModel_ValidModel - skelmod //============================== qboolean ui_PModel_ValidModel( char *model_name ) { qboolean found = qfalse; char scratch[MAX_QPATH]; Q_snprintfz( scratch, sizeof(scratch), "models/players/%s/tris.skm", model_name ); found = ( trap_FS_FOpenFile(scratch, NULL, FS_READ) != -1 ); if( !found ) return qfalse; Q_snprintfz( scratch, sizeof(scratch), "models/players/%s/animation.cfg", model_name ); found = ( trap_FS_FOpenFile(scratch, NULL, FS_READ) != -1 ); if( !found ) return qfalse; // verify the existence of the "default" skin file Q_snprintfz( scratch, sizeof(scratch), "models/players/%s/default.skin", model_name ); found = ( trap_FS_FOpenFile(scratch, NULL, FS_READ) != -1 ); if( !found ) return qfalse; return qtrue; } //================= //UI_Playermodels_ScanDirectories //================= static void UI_Playermodels_CreateItemList( m_itemslisthead_t *itemlist ) { int ndirs, dirlen; char scratch[MAX_STRING_CHARS]; char dirnames[1024]; char *dirptr; int i, j; UI_FreeScrollItemList( itemlist ); // get a list of directories (model names) ndirs = trap_FS_GetFileList( "models/players", "/", dirnames, sizeof(dirnames) ); if ( !ndirs ) return; // go through the subdirectories //------------------------------ if ( ndirs > MAX_PLAYERMODELS ) ndirs = MAX_PLAYERMODELS; dirptr = dirnames; for( i = 0; i < ndirs; i++, dirptr += dirlen+1 ) { int k; char skinnamesstring[1024]; char **skinnames, *skinptr; int skincount; int nskins = 0, skinlen; dirlen = strlen(dirptr); if( dirlen && dirptr[dirlen-1]=='/' ) dirptr[dirlen-1]='\0'; if( !strcmp(dirptr,".") || !strcmp(dirptr,"..") ) // invalid indirections continue; //check for being already in the list for( j = 0; j < itemlist->numItems; j++ ) { m_listitem_t *item = UI_FindItemInScrollListWithId( itemlist, j ); if( item && !Q_stricmp( item->name, dirptr ) ) continue; } if( !ui_PModel_ValidModel(dirptr) ) continue; // get the list of skins skincount = trap_FS_GetFileList( va("models/players/%s",dirptr), ".skin", skinnamesstring, sizeof(skinnamesstring) ); if ( !skincount ) // we already checked that the default one was there, so this can never be false, but anyway. continue; //there are valid skins. So: skinnames = UI_Malloc( sizeof( char * ) * ( skincount + 1 ) ); skinptr = skinnamesstring; skinlen = 0; //copy the valid skins for( nskins = 0, k = 0; k < skincount; k++, skinptr += skinlen+1 ) { qboolean add = qtrue; skinlen = strlen( skinptr ); Q_strncpyz( scratch, skinptr, sizeof(scratch) ); COM_StripExtension( scratch ); // see if this skin is already in the list for( j = 0; j < nskins; j++ ) { if( !Q_stricmp( scratch, skinnames[j] ) ) { add = qfalse; break; } } if( add ) { skinnames[nskins] = UI_CopyString( scratch ); nskins++; } } //Ignore the model if none of the skin files were valid if( !nskins ) continue; { // put it in the list playermodelinfo_s *playermodel = UI_Malloc( sizeof(playermodelinfo_s) ); Q_strncpyz( playermodel->directory, dirptr, sizeof(playermodel->directory) ); playermodel->skinnames = skinnames; playermodel->nskins = nskins; UI_AddItemToScrollList( itemlist, playermodel->directory, (void*)playermodel ); } } } //=============== // UI_Playermodel_Init //=============== void UI_Playermodel_Init( void ) { UI_Playermodels_CreateItemList( &playermodelsItemsList ); } //------------------------------------------------------------------------ //=============== // UI_SkelposeBounds //=============== static void UI_SkelposeBounds( cgs_skeleton_t *skel, bonepose_t *boneposes, vec3_t mins, vec3_t maxs ) { int j, i; VectorClear( mins ); VectorClear( maxs ); for( j = 0; j < skel->numBones; j++ ) { for( i = 0; i < 3; i++ ) { if( boneposes[j].origin[i] > maxs[i] ) maxs[i] = boneposes[j].origin[i]; if( boneposes[j].origin[i] < mins[i] ) mins[i] = boneposes[j].origin[i]; } } // HACK: since the model is always some bigger than the skeleton, expand it a 40% for( i = 0; i < 3; i++ ) { maxs[i] *= 1.45f; mins[i] *= 1.45f; } } //=============== // UI_DrawPlayerModel //=============== void UI_DrawPlayerModel( char *model, char *skin, byte_vec4_t color, int xpos, int ypos, int width, int height ) { refdef_t refdef; static vec3_t angles; entity_t entity; vec3_t mins, maxs; cgs_skeleton_t *skel = NULL; char scratch[MAX_QPATH]; if( !skin || !model ) return; // refdef memset( &refdef, 0, sizeof( refdef ) ); refdef.x = xpos; refdef.y = ypos; refdef.width = width; refdef.height = height; refdef.fov_x = 30; refdef.fov_y = 30; refdef.areabits = 0; refdef.time = uis.time * 0.001; refdef.rdflags = RDF_NOWORLDMODEL; // draw player model memset( &entity, 0, sizeof( entity ) ); Q_snprintfz( scratch, sizeof( scratch ), "models/players/%s/%s.skin", model, skin ); entity.customShader = NULL; entity.customSkin = trap_R_RegisterSkinFile( scratch ); if( !entity.customSkin ) return; Q_snprintfz( scratch, sizeof( scratch ), "models/players/%s/tris.skm", model ); entity.model = trap_R_RegisterModel( scratch ); if( trap_R_SkeletalGetNumBones( entity.model, NULL ) ) { skel = UI_SkeletonForModel( entity.model ); if( !skel ) return; } entity.frame = entity.oldframe = 234; UI_SetBoneposesForTemporaryEntity( &entity ); UI_SkelposeBounds( skel, entity.boneposes, mins, maxs ); //trap_R_ModelBounds( entity.model, mins, maxs ); entity.origin[0] = 0.5 * (maxs[2] - mins[2]) * (1.0 / 0.268); entity.origin[1] = 0.5 * (mins[1] + maxs[1]); entity.origin[2] = -0.5 * (mins[2] + maxs[2]); entity.flags = RF_FULLBRIGHT | RF_NOSHADOW | RF_FORCENOLOD; entity.scale = 0.9f; Vector4Set( entity.color, color[0], color[1], color[2], 255 ); VectorCopy( entity.origin, entity.oldorigin ); VectorCopy( entity.origin, entity.lightingOrigin ); angles[1] += 1.0f; if( angles[1] > 360 ) angles[1] -= 360; AnglesToAxis( angles, entity.axis ); trap_R_ClearScene(); trap_R_AddEntityToScene( &entity ); entity.customSkin = NULL; entity.customShader = trap_R_RegisterPic( PATH_NOLODOUTLINE_SHADER ); Vector4Set( entity.color, color[0] * 0.25f, color[1] * 0.25f, color[2] * 0.25f, 255 ); trap_R_AddEntityToScene( &entity ); trap_R_RenderScene( &refdef ); UI_ResetTemporaryBoneposesCache(); }