// Scale object bounding box void TrackMD3Scale(entity_t *e, LPCSTR key, LPCSTR value) { float oldscale,scale; if (strcmpi(key, "scale") != 0) { return; } if (e->eclass->fixedsize && ((strnicmp(e->eclass->name, "misc_",5) == 0) || (strnicmp(e->eclass->name, "light_",6) == 0))) { oldscale = FloatForKey (e, "scale"); scale = atof(value); if (oldscale != scale) // Value unchanged?????? { Brush_Scale2(e->eclass,e->brushes.onext, scale,e->origin,true); float a = FloatForKey (e, "angle"); if (a) { // Re-rotate bbox vec3_t vAngle; vAngle[0] = vAngle[1] = 0; vAngle[2] = a; Brush_Rotate(e->brushes.onext, vAngle, e->origin, true); } } } }
//=========================================================================== // this function sets the func_rotating_door in it's final position // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_PositionFuncRotatingBrush(entity_t *mapent, mapbrush_t *brush) { int spawnflags, i; float distance; vec3_t movedir, angles, pos1, pos2; side_t *s; spawnflags = FloatForKey(mapent, "spawnflags"); VectorClear(movedir); if (spawnflags & DOOR_X_AXIS) { movedir[2] = 1.0; //roll } else if (spawnflags & DOOR_Y_AXIS) { movedir[0] = 1.0; //pitch } else // Z_AXIS { movedir[1] = 1.0; //yaw } // check for reverse rotation if (spawnflags & DOOR_REVERSE) { VectorInverse(movedir); } distance = FloatForKey(mapent, "distance"); if (!distance) { distance = 90; } GetVectorForKey(mapent, "angles", angles); VectorCopy(angles, pos1); VectorMA(angles, -distance, movedir, pos2); // if it starts open, switch the positions if (spawnflags & DOOR_START_OPEN) { VectorCopy(pos2, angles); VectorCopy(pos1, pos2); VectorCopy(angles, pos1); VectorInverse(movedir); } //end if // for (i = 0; i < brush->numsides; i++) { s = &brush->original_sides[i]; s->planenum = AAS_TransformPlane(s->planenum, mapent->origin, pos2); } //end for // FreeBrushWindings(brush); AAS_MakeBrushWindings(brush); AddBrushBevels(brush); FreeBrushWindings(brush); } //end of the function AAS_PositionFuncRotatingBrush
/* ================== LoadEntities ================== */ void LoadEntities (void) { char *s, *s2; entity_t *e; lightentity_t *le; int i, j; ParseEntities (); // go through all the entities for (i=1 ; i<num_entities ; i++) { e = &entities[i]; s = ValueForKey (e, "classname"); if (strncmp (s, "light", 5)) continue; le = &lightentities[numlightentities]; numlightentities++; strcpy (le->classname, s); le->light = FloatForKey (e, "light"); if (!le->light) le->light = DEFAULTLIGHTLEVEL; le->style = FloatForKey (e, "style"); le->angle = FloatForKey (e, "angle"); GetVectorForKey (e, "origin", le->origin); s = ValueForKey (e, "target"); if (!s[0]) continue; // find matching targetname for (j=1 ; j<num_entities ; j++) { s2 = ValueForKey (&entities[j], "targetname"); if (!strcmp (s, s2)) { le->targetent = true; GetVectorForKey (&entities[j], "origin", le->targetorigin); break; } } if (j == num_entities) printf ("WARNING: entity %i has unmatched target %s\n", i, s); } qprintf ("%d lightentities\n", numlightentities); }
void TrackMD3Angles(entity_t *e, LPCSTR key, LPCSTR value) { if (strcmpi(key, "angle") != 0) { return; } #ifdef SOF if (e->eclass->fixedsize && ( (strnicmp(e->eclass->name, "misc_", 5) == 0) || (strnicmp(e->eclass->name, "light_", 6) == 0) || (strnicmp(e->eclass->name, "m_", 2) == 0) || (strnicmp(e->eclass->name, "item_weapon_", 12)== 0) || (strnicmp(e->eclass->name, "item_ammo_", 10)== 0) ) ) #else if (e->eclass->fixedsize && strnicmp (e->eclass->name, "misc_model",10) == 0) #endif { float a = FloatForKey (e, "angle"); float b = atof(value); if (a != b) { vec3_t vAngle; vAngle[0] = vAngle[1] = 0; vAngle[2] = -a; Brush_Rotate(e->brushes.onext, vAngle, e->origin, true); vAngle[2] = b; Brush_Rotate(e->brushes.onext, vAngle, e->origin, true); #ifdef QUAKE3 // // auto assign new bounding box to model? // char *_p = ValueForKey(e, "mins"); char *_p2= ValueForKey(e, "maxs"); char *_p3= ValueForKey(e, sKEYFIELD_AUTOBOUND); // // if either key is missing then update both... (or if they do exist, but were only set by this code in the first place and therefore can be overwritten) // if ( ((strlen(_p) == 0) || (strlen(_p2) == 0)) || strlen(_p3) ) { SetKeyValue (e, sKEYFIELD_AUTOBOUND, "1"); vec3_t vMins,vMaxs; VectorSubtract(e->brushes.onext->mins, e->origin, vMins); VectorSubtract(e->brushes.onext->maxs, e->origin, vMaxs); SetKeyValue (e, "mins", va("%i %i %i", (int)vMins[0], (int)vMins[1], (int)vMins[2])); SetKeyValue (e, "maxs", va("%i %i %i", (int)vMaxs[0], (int)vMaxs[1], (int)vMaxs[2])); } #endif } } }
void DrawBrushEntityName (brush_t *b) { char *name; float a, s, c; vec3_t mid; int i; if (!b->owner) return; // during contruction if (b->owner == world_entity) return; if (b != b->owner->brushes.onext) return; // not key brush // draw the angle pointer a = FloatForKey (b->owner, "angle"); if (a) { s = sin(a/180*pMath_PI); c = cos(a/180*pMath_PI); for (i=0 ; i<3 ; i++) mid[i] = (b->mins[i] + b->maxs[i])*0.5; glBegin (GL_LINE_STRIP); glVertex3fv (mid); mid[0] += c*8; mid[1] += s*8; glVertex3fv (mid); mid[0] -= c*4; mid[1] -= s*4; mid[0] -= s*4; mid[1] += c*4; glVertex3fv (mid); mid[0] += c*4; mid[1] += s*4; mid[0] += s*4; mid[1] -= c*4; glVertex3fv (mid); mid[0] -= c*4; mid[1] -= s*4; mid[0] += s*4; mid[1] -= c*4; glVertex3fv (mid); glEnd (); } if (!g_qeglobals.d_savedinfo.show_names) return; name = ValueForKey (b->owner, "classname"); glRasterPos2f (b->mins[0]+4, b->mins[1]+4); glCallLists (strlen(name), GL_UNSIGNED_BYTE, name); }
// // move the view to a start position // void Map_StartPosition(){ entity_t *ent = AngledEntity(); g_pParentWnd->GetCamWnd()->Camera()->angles[PITCH] = 0; if ( ent ) { GetVectorForKey( ent, "origin", g_pParentWnd->GetCamWnd()->Camera()->origin ); GetVectorForKey( ent, "origin", g_pParentWnd->GetXYWnd()->GetOrigin() ); g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = FloatForKey( ent, "angle" ); } else { g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] = 0; VectorCopy( vec3_origin, g_pParentWnd->GetCamWnd()->Camera()->origin ); VectorCopy( vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin() ); } }
/* ======================================================================================================================= ======================================================================================================================= */ void TrackMD3Angles(entity_t *e, const char *key, const char *value) { if ( idStr::Icmp(key, "angle") != 0 ) { return; } if ((e->eclass->fixedsize && e->eclass->nShowFlags & ECLASS_MISCMODEL) || EntityHasModel(e)) { float a = FloatForKey(e, "angle"); float b = atof(value); if (a != b) { idVec3 vAngle; vAngle[0] = vAngle[1] = 0; vAngle[2] = -a; Brush_Rotate(e->brushes.onext, vAngle, e->origin, true); vAngle[2] = b; Brush_Rotate(e->brushes.onext, vAngle, e->origin, true); } } }
//----------------------------------------------------------------------------- // Compute the bounding box, excluding 3D skybox + skybox, add it to keyvalues //----------------------------------------------------------------------------- float DetermineVisRadius( ) { float flRadius = -1; // Check the max vis range to determine the vis radius for (int i = 0; i < num_entities; ++i) { char* pEntity = ValueForKey(&entities[i], "classname"); if (!stricmp(pEntity, "env_fog_controller")) { flRadius = FloatForKey (&entities[i], "farz"); if (flRadius == 0.0f) flRadius = -1.0f; break; } } return flRadius; }
/* ================ Map_LoadFile ================ */ void Map_LoadFile (char *filename) { char *buf; entity_t *ent; char temp[1024]; Sys_BeginWait (); Select_Deselect(); //SetInspectorMode(W_CONSOLE); QE_ConvertDOSToUnixName( temp, filename ); Sys_Printf ("Map_LoadFile: %s\n", temp ); Map_Free (); //++timo FIXME: maybe even easier to have Group_Init called from Map_Free? Group_Init(); g_qeglobals.d_parsed_brushes = 0; strcpy (currentmap, filename); if (LoadFile (filename, (void **)&buf) != -1) { StartTokenParsing (buf); g_qeglobals.d_num_entities = 0; // Timo // will be used in Entity_Parse to detect if a conversion between brush formats is needed g_qeglobals.bNeedConvert = false; g_qeglobals.bOldBrushes = false; g_qeglobals.bPrimitBrushes = false; while (1) { ent = Entity_Parse (false, &active_brushes); if (!ent) break; if (!strcmp(ValueForKey (ent, "classname"), "worldspawn")) { if (world_entity) Sys_Printf ("WARNING: multiple worldspawn\n"); world_entity = ent; } else if (!strcmp(ValueForKey (ent, "classname"), "group_info")) { // it's a group thing! Group_Add(ent); Entity_Free(ent); } else { // add the entity to the end of the entity list ent->next = &entities; ent->prev = entities.prev; entities.prev->next = ent; entities.prev = ent; g_qeglobals.d_num_entities++; } } } free (buf); if (!world_entity) { Sys_Printf ("No worldspawn in map.\n"); Map_New (); return; } Sys_Printf ("--- LoadMapFile ---\n"); Sys_Printf ("%s\n", temp ); Sys_Printf ("%5i brushes\n", g_qeglobals.d_parsed_brushes ); Sys_Printf ("%5i entities\n", g_qeglobals.d_num_entities); Map_RestoreBetween (); Sys_Printf ("Map_BuildAllDisplayLists\n"); Map_BuildBrushData(); // reset the "need conversion" flag // conversion to the good format done in Map_BuildBrushData g_qeglobals.bNeedConvert=false; // // move the view to a start position // ent = AngledEntity(); g_pParentWnd->GetCamera()->Camera().angles[PITCH] = 0; if (ent) { GetVectorForKey (ent, "origin", g_pParentWnd->GetCamera()->Camera().origin); GetVectorForKey (ent, "origin", g_pParentWnd->GetXYWnd()->GetOrigin()); g_pParentWnd->GetCamera()->Camera().angles[YAW] = FloatForKey (ent, "angle"); } else { g_pParentWnd->GetCamera()->Camera().angles[YAW] = 0; VectorCopy (vec3_origin, g_pParentWnd->GetCamera()->Camera().origin); VectorCopy (vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin()); } Map_RegionOff (); modified = false; Sys_SetTitle (temp); Texture_ShowInuse (); Sys_EndWait(); Sys_UpdateWindows (W_ALL); }
void CPlugInManager::CommitEntityHandleToMap(LPVOID vpEntity) { entity_t *pe; eclass_t *e; brush_t *b; vec3_t mins,maxs; bool has_brushes; for (int i=0 ; i < m_EntityHandles.GetSize() ; i++ ) { if (vpEntity == m_EntityHandles.GetAt(i)) { m_EntityHandles.RemoveAt(i); pe = reinterpret_cast<entity_t*>(vpEntity); // fill additional fields // straight copy from Entity_Parse // entity_t::origin GetVectorForKey (pe, "origin", pe->origin); // entity_t::eclass if (pe->brushes.onext == &pe->brushes) has_brushes = false; else has_brushes = true; e = Eclass_ForName (ValueForKey (pe, "classname"), has_brushes); pe->eclass = e; // fixedsize if (e->fixedsize) { if (pe->brushes.onext != &pe->brushes) { Sys_Printf("Warning : Fixed size entity with brushes in CPlugInManager::CommitEntityHandleToMap\n"); } // create a custom brush VectorAdd(e->mins, pe->origin, mins); VectorAdd(e->maxs, pe->origin, maxs); float a = 0; if (e->nShowFlags & ECLASS_MISCMODEL) { char* p = ValueForKey(pe, "model"); if (p != NULL && strlen(p) > 0) { vec3_t vMin, vMax; a = FloatForKey (pe, "angle"); if (GetCachedModel(pe, p, vMin, vMax)) { // create a custom brush VectorAdd (pe->md3Class->mins, pe->origin, mins); VectorAdd (pe->md3Class->maxs, pe->origin, maxs); } } } b = Brush_Create (mins, maxs, &e->texdef); if (a) { vec3_t vAngle; vAngle[0] = vAngle[1] = 0; vAngle[2] = a; Brush_Rotate(b, vAngle, pe->origin, false); } b->owner = pe; b->onext = pe->brushes.onext; b->oprev = &pe->brushes; pe->brushes.onext->oprev = b; pe->brushes.onext = b; } else { // brush entity if (pe->brushes.next == &pe->brushes) Sys_Printf ("Warning: Brush entity with no brushes in CPlugInManager::CommitEntityHandleToMap\n"); } // add brushes to the active brushes list // and build them along the way for (b=pe->brushes.onext ; b != &pe->brushes ; b=b->onext) { // convert between old brushes and brush primitive if (g_qeglobals.m_bBrushPrimitMode) { // we only filled the shift scale rot fields, needs conversion Brush_Build( b, true, true, true ); } else { // we are using old brushes Brush_Build( b ); } b->next = active_brushes.next; active_brushes.next->prev = b; b->prev = &active_brushes; active_brushes.next = b; } // handle worldspawn entities // if worldspawn has no brushes, use the new one if (!strcmp(ValueForKey (pe, "classname"), "worldspawn")) { if ( world_entity && ( world_entity->brushes.onext != &world_entity->brushes ) ) { // worldspawn already has brushes Sys_Printf ("Commiting worldspawn as func_group\n"); SetKeyValue(pe, "classname", "func_group"); // add the entity to the end of the entity list pe->next = &entities; pe->prev = entities.prev; entities.prev->next = pe; entities.prev = pe; g_qeglobals.d_num_entities++; } else { // there's a worldspawn with no brushes, we assume the map is empty if ( world_entity ) { Entity_Free( world_entity ); world_entity = pe; } else Sys_Printf("Warning : unexpected world_entity == NULL in CommitEntityHandleToMap\n"); } } else { // add the entity to the end of the entity list pe->next = &entities; pe->prev = entities.prev; entities.prev->next = pe; entities.prev = pe; g_qeglobals.d_num_entities++; } } } }
/* ======================================================================================================================= Map_LoadFile ======================================================================================================================= */ void Map_LoadFile(const char *filename) { entity_t *ent; CWaitDlg dlg; idStr fileStr, status; idMapFile mapfile; Sys_BeginWait(); Select_Deselect(); dlg.AllowCancel( true ); idStr( filename ).ExtractFileName( fileStr ); sprintf( status, "Loading %s...", fileStr.c_str() ); dlg.SetWindowText( status ); sprintf( status, "Reading file %s...", fileStr.c_str() ); dlg.SetText( status ); // SetInspectorMode(W_CONSOLE); fileStr = filename; fileStr.BackSlashesToSlashes(); common->Printf( "Map_LoadFile: %s\n", fileStr.c_str() ); Map_Free(); g_qeglobals.d_parsed_brushes = 0; strcpy( currentmap, filename ); if(mapfile.Parse(filename, true, true)) { g_qeglobals.bNeedConvert = false; g_qeglobals.bOldBrushes = false; g_qeglobals.bPrimitBrushes = false; g_qeglobals.mapVersion = 1.0; long lastUpdate = 0; int count = mapfile.GetNumEntities(); for (int i = 0; i < count; i++) { idMapEntity *mapent = mapfile.GetEntity(i); if (mapent) { idStr classname = mapent->epairs.GetString("classname"); // Update 20 times a second if ( (GetTickCount() - lastUpdate) > 50 ) { lastUpdate = GetTickCount(); sprintf(status, "Loading entity %i (%s)...", i, classname.c_str()); dlg.SetText(status); } if ( dlg.CancelPressed() ) { Sys_Status("Map load cancelled.\n"); Map_New(); return; } if (classname == "worldspawn") { world_entity = EntityFromMapEntity(mapent, &dlg); Entity_PostParse(world_entity, &active_brushes); } else { ent = EntityFromMapEntity(mapent, &dlg); Entity_PostParse(ent, &active_brushes); Entity_Name(ent, true); // add the entity to the end of the entity list ent->next = &entities; ent->prev = entities.prev; entities.prev->next = ent; entities.prev = ent; g_qeglobals.d_num_entities++; } } } } if (!world_entity) { Sys_Status("No worldspawn in map.\n"); Map_New(); return; } common->Printf("--- LoadMapFile ---\n"); common->Printf("%s\n", fileStr.c_str()); common->Printf("%5i brushes\n", g_qeglobals.d_parsed_brushes); common->Printf("%5i entities\n", g_qeglobals.d_num_entities); dlg.SetText("Restoring Between"); Map_RestoreBetween(); dlg.SetText("Building Brush Data"); common->Printf("Map_BuildAllDisplayLists\n"); Map_BuildBrushData(); // // reset the "need conversion" flag conversion to the good format done in // Map_BuildBrushData // g_qeglobals.bNeedConvert = false; // move the view to a start position ent = AngledEntity(); g_pParentWnd->GetCamera()->Camera().angles[PITCH] = 0; if (ent) { GetVectorForKey(ent, "origin", g_pParentWnd->GetCamera()->Camera().origin); GetVectorForKey(ent, "origin", g_pParentWnd->GetXYWnd()->GetOrigin()); g_pParentWnd->GetCamera()->Camera().angles[YAW] = FloatForKey(ent, "angle"); } else { g_pParentWnd->GetCamera()->Camera().angles[YAW] = 0; VectorCopy(vec3_origin, g_pParentWnd->GetCamera()->Camera().origin); VectorCopy(vec3_origin, g_pParentWnd->GetXYWnd()->GetOrigin()); } Map_RegionOff(); mapModified = 0; if (GetFileAttributes(filename) & FILE_ATTRIBUTE_READONLY) { fileStr += " (read only) "; } Sys_SetTitle(fileStr); Texture_ShowInuse(); if (g_pParentWnd->GetCamera()->GetRenderMode()) { g_pParentWnd->GetCamera()->BuildRendererState(); } Sys_EndWait(); Sys_UpdateWindows(W_ALL); }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_PositionBrush(entity_t *mapent, mapbrush_t *brush) { side_t *s; float newdist; int i, notteam; char *model; if (!strcmp(ValueForKey(mapent, "classname"), "func_door_rotating")) { AAS_PositionFuncRotatingBrush(mapent, brush); } //end if else { if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2]) { for (i = 0; i < brush->numsides; i++) { s = &brush->original_sides[i]; newdist = mapplanes[s->planenum].dist + DotProduct(mapplanes[s->planenum].normal, mapent->origin); s->planenum = FindFloatPlane(mapplanes[s->planenum].normal, newdist); } //end for } //end if //if it's a trigger hurt if (!strcmp("trigger_hurt", ValueForKey(mapent, "classname"))) { notteam = FloatForKey(mapent, "bot_notteam"); if ( notteam == 1 ) { brush->contents |= CONTENTS_NOTTEAM1; } else if ( notteam == 2 ) { brush->contents |= CONTENTS_NOTTEAM2; } else { // always avoid so set lava contents brush->contents |= CONTENTS_LAVA; } } //end if // else if (!strcmp("trigger_push", ValueForKey(mapent, "classname"))) { //set the jumppad contents brush->contents = CONTENTS_JUMPPAD; //Log_Print("found trigger_push brush\n"); } //end if // else if (!strcmp("trigger_multiple", ValueForKey(mapent, "classname"))) { //set teleporter contents brush->contents = CONTENTS_TELEPORTER; //Log_Print("found trigger_multiple teleporter brush\n"); } //end if // else if (!strcmp("trigger_teleport", ValueForKey(mapent, "classname"))) { //set teleporter contents brush->contents = CONTENTS_TELEPORTER; //Log_Print("found trigger_teleport teleporter brush\n"); } //end if else if (!strcmp("func_door", ValueForKey(mapent, "classname"))) { //set mover contents brush->contents = CONTENTS_MOVER; //get the model number model = ValueForKey(mapent, "model"); brush->modelnum = atoi(model+1); } //end if } //end else } //end of the function AAS_PositionBrush
//----------------------------------------------------------------------------- // Places Detail Objects in the level //----------------------------------------------------------------------------- void EmitDetailModels() { StartPacifier("Placing detail props : "); // Place stuff on each face dface_t* pFace = dfaces; for (int j = 0; j < numfaces; ++j) { UpdatePacifier( (float)j / (float)numfaces ); // Get at the material associated with this face texinfo_t* pTexInfo = &texinfo[pFace[j].texinfo]; dtexdata_t* pTexData = GetTexData( pTexInfo->texdata ); // Try to get at the material bool found; MaterialSystemMaterial_t handle = FindOriginalMaterial( TexDataStringTable_GetString( pTexData->nameStringTableID ), &found, false ); if (!found) continue; // See if its got any detail objects on it const char* pDetailType = GetMaterialVar( handle, "%detailtype" ); if (!pDetailType) continue; // Get the detail type... DetailObject_t search; search.m_Name = pDetailType; int objectType = s_DetailObjectDict.Find(search); if (objectType < 0) { Warning("Material %s uses unknown detail object type %s!\n", TexDataStringTable_GetString( pTexData->nameStringTableID ), pDetailType); continue; } // Emit objects on a particular face DetailObject_t& detail = s_DetailObjectDict[objectType]; if (pFace[j].dispinfo < 0) { EmitDetailObjectsOnFace( &pFace[j], detail ); } else { // Get a CCoreDispInfo. All we need is the triangles and lightmap texture coordinates. mapdispinfo_t *pMapDisp = &mapdispinfo[pFace[j].dispinfo]; CCoreDispInfo coreDispInfo; DispMapToCoreDispInfo( pMapDisp, &coreDispInfo, &pFace[j] ); EmitDetailObjectsOnDisplacementFace( &pFace[j], detail, coreDispInfo ); } } // Emit specifically specified detail props Vector origin; QAngle angles; Vector2D pos[2]; Vector2D tex[2]; for (int i = 0; i < num_entities; ++i) { char* pEntity = ValueForKey(&entities[i], "classname"); if (!strcmp(pEntity, "detail_prop") || !strcmp(pEntity, "prop_detail")) { GetVectorForKey( &entities[i], "origin", origin ); GetAnglesForKey( &entities[i], "angles", angles ); char* pModelName = ValueForKey( &entities[i], "model" ); int nOrientation = IntForKey( &entities[i], "detailOrientation" ); AddDetailToLump( pModelName, origin, angles, nOrientation ); // strip this ent from the .bsp file entities[i].epairs = 0; continue; } if (!strcmp(pEntity, "prop_detail_sprite")) { GetVectorForKey( &entities[i], "origin", origin ); GetAnglesForKey( &entities[i], "angles", angles ); int nOrientation = IntForKey( &entities[i], "detailOrientation" ); GetVector2DForKey( &entities[i], "position_ul", pos[0] ); GetVector2DForKey( &entities[i], "position_lr", pos[1] ); GetVector2DForKey( &entities[i], "tex_ul", tex[0] ); GetVector2DForKey( &entities[i], "tex_size", tex[1] ); float flTextureSize = FloatForKey( &entities[i], "tex_total_size" ); tex[1].x += tex[0].x - 0.5f; tex[1].y += tex[0].y - 0.5f; tex[0].x += 0.5f; tex[0].y += 0.5f; tex[0] /= flTextureSize; tex[1] /= flTextureSize; AddDetailSpriteToLump( origin, angles, nOrientation, pos, tex, 1.0f ); // strip this ent from the .bsp file entities[i].epairs = 0; continue; } } EndPacifier( true ); }
/** * @brief Create lights out of patches and entity lights * @sa LightWorld * @sa BuildPatch */ void BuildLights (void) { int i; light_t* l; /* surfaces */ for (i = 0; i < MAX_MAP_FACES; i++) { /* iterate subdivided patches */ for(const patch_t* p = face_patches[i]; p; p = p->next) { if (VectorEmpty(p->light)) continue; numlights[config.compile_for_day]++; l = Mem_AllocType(light_t); VectorCopy(p->origin, l->origin); l->next = lights[config.compile_for_day]; lights[config.compile_for_day] = l; l->type = emit_surface; l->intensity = ColorNormalize(p->light, l->color); l->intensity *= p->area * config.surface_scale; } } /* entities (skip the world) */ for (i = 1; i < num_entities; i++) { float intensity; const char* color; const char* target; const entity_t* e = &entities[i]; const char* name = ValueForKey(e, "classname"); if (!Q_strstart(name, "light")) continue; /* remove those lights that are only for the night version */ if (config.compile_for_day) { const int spawnflags = atoi(ValueForKey(e, "spawnflags")); if (!(spawnflags & 1)) /* day */ continue; } numlights[config.compile_for_day]++; l = Mem_AllocType(light_t); GetVectorForKey(e, "origin", l->origin); /* link in */ l->next = lights[config.compile_for_day]; lights[config.compile_for_day] = l; intensity = FloatForKey(e, "light"); if (!intensity) intensity = 300.0; color = ValueForKey(e, "_color"); if (color && color[0] != '\0'){ if (sscanf(color, "%f %f %f", &l->color[0], &l->color[1], &l->color[2]) != 3) Sys_Error("Invalid _color entity property given: %s", color); ColorNormalize(l->color, l->color); } else VectorSet(l->color, 1.0, 1.0, 1.0); l->intensity = intensity * config.entity_scale; l->type = emit_point; target = ValueForKey(e, "target"); if (target[0] != '\0' || Q_streq(name, "light_spot")) { l->type = emit_spotlight; l->stopdot = FloatForKey(e, "_cone"); if (!l->stopdot) l->stopdot = 10; l->stopdot = cos(l->stopdot * torad); if (target[0] != '\0') { /* point towards target */ entity_t* e2 = FindTargetEntity(target); if (!e2) Com_Printf("WARNING: light at (%i %i %i) has missing target '%s' - e.g. create an info_null that has a 'targetname' set to '%s'\n", (int)l->origin[0], (int)l->origin[1], (int)l->origin[2], target, target); else { vec3_t dest; GetVectorForKey(e2, "origin", dest); VectorSubtract(dest, l->origin, l->normal); VectorNormalize(l->normal); } } else { /* point down angle */ const float angle = FloatForKey(e, "angle"); if (angle == ANGLE_UP) { l->normal[0] = l->normal[1] = 0.0; l->normal[2] = 1.0; } else if (angle == ANGLE_DOWN) { l->normal[0] = l->normal[1] = 0.0; l->normal[2] = -1.0; } else { l->normal[2] = 0; l->normal[0] = cos(angle * torad); l->normal[1] = sin(angle * torad); } } } } /* handle worldspawn light settings */ { const entity_t* e = &entities[0]; const char* ambient, *light, *angles, *color; float f; int i; if (config.compile_for_day) { ambient = ValueForKey(e, "ambient_day"); light = ValueForKey(e, "light_day"); angles = ValueForKey(e, "angles_day"); color = ValueForKey(e, "color_day"); } else { ambient = ValueForKey(e, "ambient_night"); light = ValueForKey(e, "light_night"); angles = ValueForKey(e, "angles_night"); color = ValueForKey(e, "color_night"); } if (light[0] != '\0') sun_intensity = atoi(light); if (angles[0] != '\0') { VectorClear(sun_angles); if (sscanf(angles, "%f %f", &sun_angles[0], &sun_angles[1]) != 2) Sys_Error("wrong angles values given: '%s'", angles); AngleVectors(sun_angles, sun_normal, nullptr, nullptr); } if (color[0] != '\0') { GetVectorFromString(color, sun_color); ColorNormalize(sun_color, sun_color); } if (ambient[0] != '\0') GetVectorFromString(ambient, sun_ambient_color); /* optionally pull brightness from worldspawn */ f = FloatForKey(e, "brightness"); if (f > 0.0) config.brightness = f; /* saturation as well */ f = FloatForKey(e, "saturation"); if (f > 0.0) config.saturation = f; else Verb_Printf(VERB_EXTRA, "Invalid saturation setting (%f) in worldspawn found\n", f); f = FloatForKey(e, "contrast"); if (f > 0.0) config.contrast = f; else Verb_Printf(VERB_EXTRA, "Invalid contrast setting (%f) in worldspawn found\n", f); /* lightmap resolution downscale (e.g. 4 = 1 << 4) */ i = atoi(ValueForKey(e, "quant")); if (i >= 1 && i <= 6) config.lightquant = i; else Verb_Printf(VERB_EXTRA, "Invalid quant setting (%i) in worldspawn found\n", i); } Verb_Printf(VERB_EXTRA, "light settings:\n * intensity: %i\n * sun_angles: pitch %f yaw %f\n * sun_color: %f:%f:%f\n * sun_ambient_color: %f:%f:%f\n", sun_intensity, sun_angles[0], sun_angles[1], sun_color[0], sun_color[1], sun_color[2], sun_ambient_color[0], sun_ambient_color[1], sun_ambient_color[2]); Verb_Printf(VERB_NORMAL, "%i direct lights for %s lightmap\n", numlights[config.compile_for_day], (config.compile_for_day ? "day" : "night")); }
static void PopulateTraceNodes(void) { int i, m, frame, castShadows; float temp; entity_t *e; const char *value; picoModel_t *model; vec3_t origin, scale, angles; matrix_t rotation; matrix_t transform; /* add worldspawn triangles */ MatrixIdentity(transform); PopulateWithBSPModel(&bspModels[0], transform); /* walk each entity list */ for(i = 1; i < numEntities; i++) { /* get entity */ e = &entities[i]; /* get shadow flags */ castShadows = ENTITY_CAST_SHADOWS; GetEntityShadowFlags(e, NULL, &castShadows, NULL); /* early out? */ if(!castShadows) continue; /* get entity origin */ GetVectorForKey(e, "origin", origin); /* get "angle" (yaw) or "angles" (pitch yaw roll) */ MatrixIdentity(rotation); angles[0] = angles[1] = angles[2] = 0.0f; value = ValueForKey(e, "angle"); if(value[0] != '\0') { angles[1] = atof(value); MatrixFromAngles(rotation, angles[PITCH], angles[YAW], angles[ROLL]); } value = ValueForKey(e, "angles"); if(value[0] != '\0') { sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]); MatrixFromAngles(rotation, angles[PITCH], angles[YAW], angles[ROLL]); } value = ValueForKey(e, "rotation"); if(value[0] != '\0') { sscanf(value, "%f %f %f %f %f %f %f %f %f", &rotation[0], &rotation[1], &rotation[2], &rotation[4], &rotation[5], &rotation[6], &rotation[8], &rotation[9], &rotation[10]); } /* get scale */ scale[0] = scale[1] = scale[2] = 1.0f; temp = FloatForKey(e, "modelscale"); if(temp != 0.0f) scale[0] = scale[1] = scale[2] = temp; value = ValueForKey(e, "modelscale_vec"); if(value[0] != '\0') sscanf(value, "%f %f %f", &scale[0], &scale[1], &scale[2]); MatrixMultiplyScale(rotation, scale[0], scale[1], scale[2]); /* set transform matrix */ MatrixIdentity(transform); MatrixSetupTransformFromRotation(transform, rotation, origin); //% m4x4_pivoted_transform_by_vec3(transform, origin, angles, eXYZ, scale, vec3_origin); /* get model */ value = ValueForKey(e, "model"); /* switch on model type */ switch (value[0]) { /* no model */ case '\0': break; /* bsp model */ case '*': m = atoi(&value[1]); if(m <= 0 || m >= numBSPModels) continue; PopulateWithBSPModel(&bspModels[m], transform); break; /* external model */ default: frame = IntForKey(e, "_frame"); model = LoadModel((char *)value, frame); if(model == NULL) continue; PopulateWithPicoModel(castShadows, model, transform); continue; } /* get model2 */ value = ValueForKey(e, "model2"); /* switch on model type */ switch (value[0]) { /* no model */ case '\0': break; /* bsp model */ case '*': m = atoi(&value[1]); if(m <= 0 || m >= numBSPModels) continue; PopulateWithBSPModel(&bspModels[m], transform); break; /* external model */ default: frame = IntForKey(e, "_frame2"); model = LoadModel((char *)value, frame); if(model == NULL) continue; PopulateWithPicoModel(castShadows, model, transform); continue; } } }
void ProcessDecals( void ) { int i, j, x, y, pw[ 5 ], r, iterations, smoothNormals; float distance, lightmapScale, backfaceAngle; vec4_t projection, plane; vec3_t origin, target, delta, lightmapAxis; vec3_t minlight, minvertexlight, ambient, colormod; entity_t *e, *e2; parseMesh_t *p; mesh_t *mesh, *subdivided; bspDrawVert_t *dv[ 4 ]; const char *value; /* note it */ Sys_FPrintf( SYS_VRB, "--- ProcessDecals ---\n" ); /* no decals */ if (nodecals) { for( i = 0; i < numEntities; i++ ) { /* get entity */ e = &entities[ i ]; value = ValueForKey( e, "classname" ); if( Q_stricmp( value, "_decal" ) && Q_stricmp( value, "misc_decal" ) ) continue; /* clear entity patches */ e->patches = NULL; // fixme: LEAK! } return; } /* walk entity list */ for( i = 0; i < numEntities; i++ ) { /* get entity */ e = &entities[ i ]; value = ValueForKey( e, "classname" ); if( Q_stricmp( value, "_decal" ) && Q_stricmp( value, "misc_decal" ) ) continue; /* any patches? */ if( e->patches == NULL ) { Sys_Warning( e->mapEntityNum, "Decal entity without any patch meshes, ignoring." ); e->epairs = NULL; /* fixme: leak! */ continue; } /* find target */ value = ValueForKey( e, "target" ); e2 = FindTargetEntity( value ); /* no target? */ if( e2 == NULL ) { Sys_Warning( e->mapEntityNum, "Decal entity without a valid target, ignoring." ); continue; } /* vortex: get lightmap scaling value for this entity */ GetEntityLightmapScale( e, &lightmapScale, 0); /* vortex: get lightmap axis for this entity */ GetEntityLightmapAxis( e, lightmapAxis, NULL ); /* vortex: per-entity normal smoothing */ GetEntityNormalSmoothing( e, &smoothNormals, 0); /* vortex: per-entity _minlight, _ambient, _color, _colormod */ GetEntityMinlightAmbientColor( e, NULL, minlight, minvertexlight, ambient, colormod, qtrue ); /* vortex: _backfacecull */ if ( KeyExists(e, "_backfacecull") ) backfaceAngle = FloatForKey(e, "_backfacecull"); else if ( KeyExists(e, "_bfc") ) backfaceAngle = FloatForKey(e, "_bfc"); else backfaceAngle = 90.0f; /* walk entity patches */ for( p = e->patches; p != NULL; p = e->patches ) { /* setup projector */ if( VectorCompare( e->origin, vec3_origin ) ) { VectorAdd( p->eMins, p->eMaxs, origin ); VectorScale( origin, 0.5f, origin ); } else VectorCopy( e->origin, origin ); VectorCopy( e2->origin, target ); VectorSubtract( target, origin, delta ); /* setup projection plane */ distance = VectorNormalize( delta, projection ); projection[ 3 ] = DotProduct( origin, projection ); /* create projectors */ if( distance > 0.125f ) { /* tesselate the patch */ iterations = IterationsForCurve( p->longestCurve, patchSubdivisions ); subdivided = SubdivideMesh2( p->mesh, iterations ); /* fit it to the curve and remove colinear verts on rows/columns */ PutMeshOnCurve( *subdivided ); mesh = RemoveLinearMeshColumnsRows( subdivided ); FreeMesh( subdivided ); /* offset by projector origin */ for( j = 0; j < (mesh->width * mesh->height); j++ ) VectorAdd( mesh->verts[ j ].xyz, e->origin, mesh->verts[ j ].xyz ); /* iterate through the mesh quads */ for( y = 0; y < (mesh->height - 1); y++ ) { for( x = 0; x < (mesh->width - 1); x++ ) { /* set indexes */ pw[ 0 ] = x + (y * mesh->width); pw[ 1 ] = x + ((y + 1) * mesh->width); pw[ 2 ] = x + 1 + ((y + 1) * mesh->width); pw[ 3 ] = x + 1 + (y * mesh->width); pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */ /* set radix */ r = (x + y) & 1; /* get drawverts */ dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ]; dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ]; dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ]; dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ]; /* planar? (nuking this optimization as it doesn't work on non-rectangular quads) */ plane[ 0 ] = 0.0f; /* stupid msvc */ if( 0 && PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) && fabs( DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ] ) <= PLANAR_EPSILON ) { /* make a quad projector */ MakeDecalProjector( i, p->shaderInfo, projection, distance, 4, dv, cos(backfaceAngle / 180.0f * Q_PI), lightmapScale, lightmapAxis, minlight, minvertexlight, ambient, colormod, smoothNormals); } else { /* make first triangle */ MakeDecalProjector( i, p->shaderInfo, projection, distance, 3, dv, cos(backfaceAngle / 180.0f * Q_PI), lightmapScale, lightmapAxis, minlight, minvertexlight, ambient, colormod, smoothNormals); /* make second triangle */ dv[ 1 ] = dv[ 2 ]; dv[ 2 ] = dv[ 3 ]; MakeDecalProjector( i, p->shaderInfo, projection, distance, 3, dv, cos(backfaceAngle / 180.0f * Q_PI), lightmapScale, lightmapAxis, minlight, minvertexlight, ambient, colormod, smoothNormals); } } } /* clean up */ free( mesh ); } /* remove patch from entity (fixme: leak!) */ e->patches = p->next; /* push patch to worldspawn (enable this to debug projectors) */ #if 0 p->next = entities[ 0 ].patches; entities[ 0 ].patches = p; #endif } } /* emit some stats */ Sys_FPrintf( SYS_VRB, "%9d decal projectors\n", numProjectors ); }
/* ================= ParseMapEntity parses a single entity out of a map file ================= */ static bool ParseMapEntity( bool onlyLights ) { epair_t *ep; token_t token; const char *classname, *value; float lightmapScale; char shader[ MAX_SHADERPATH ]; shaderInfo_t *celShader = NULL; brush_t *brush; parseMesh_t *patch; bool funcGroup; int castShadows, recvShadows; static bool map_type = false; if( !Com_ReadToken( mapfile, SC_ALLOW_NEWLINES|SC_COMMENT_SEMICOLON, &token )) return false; // end of .map file if( com.stricmp( token.string, "{" )) Sys_Break( "ParseEntity: found %s instead {\n", token.string ); if( numEntities >= MAX_MAP_ENTITIES ) Sys_Break( "MAX_MAP_ENTITIES limit exceeded\n" ); entitySourceBrushes = 0; mapEnt = &entities[numEntities]; numEntities++; memset( mapEnt, 0, sizeof( *mapEnt )); mapEnt->mapEntityNum = numMapEntities; numMapEntities++; while( 1 ) { if( !Com_ReadToken( mapfile, SC_ALLOW_NEWLINES|SC_COMMENT_SEMICOLON, &token )) Sys_Break( "ParseEntity: EOF without closing brace\n" ); if( !com.stricmp( token.string, "}" )) break; if( !com.stricmp( token.string, "{" )) { // parse a brush or patch if( !Com_ReadToken( mapfile, SC_ALLOW_NEWLINES, &token )) break; if( !com.stricmp( token.string, "patchDef2" )) { numMapPatches++; ParsePatch( onlyLights ); g_bBrushPrimit = BRUSH_RADIANT; } else if( !com.stricmp( token.string, "terrainDef" )) { MsgDev( D_WARN, "Terrain entity parsing not supported in this build.\n" ); Com_SkipBracedSection( mapfile, 0 ); g_bBrushPrimit = BRUSH_RADIANT; } else if( !com.stricmp( token.string, "brushDef" )) { // parse brush primitive g_bBrushPrimit = BRUSH_RADIANT; ParseBrush( onlyLights ); } else { if( g_bBrushPrimit == BRUSH_RADIANT ) Sys_Break( "mixed brush primitive with another format\n" ); if( g_bBrushPrimit == BRUSH_UNKNOWN ) g_bBrushPrimit = BRUSH_WORLDCRAFT_21; // QuArK or WorldCraft map (unknown at this point) Com_SaveToken( mapfile, &token ); ParseBrush( onlyLights ); } entitySourceBrushes++; } else { // parse a key / value pair ep = ParseEpair( mapfile, &token ); if( !com.strcmp( ep->key, "mapversion" )) { if( com.atoi( ep->value ) == VALVE_FORMAT ) { Msg( "Valve Format Map detected\n" ); g_bBrushPrimit = BRUSH_WORLDCRAFT_22; } else if( com.atoi( ep->value ) == GEARBOX_FORMAT ) { Msg( "Gearcraft Format Map detected\n" ); g_bBrushPrimit = BRUSH_GEARCRAFT_40; } else g_bBrushPrimit = BRUSH_WORLDCRAFT_21; } if( ep->key[0] != '\0' && ep->value[0] != '\0' ) { ep->next = mapEnt->epairs; mapEnt->epairs = ep; } } } if( !map_type && g_bBrushPrimit != BRUSH_UNKNOWN ) { MAPTYPE(); map_type = true; } classname = ValueForKey( mapEnt, "classname" ); if( onlyLights && com.strnicmp( classname, "light", 5 )) { numEntities--; return true; } if( !com.stricmp( "func_group", classname )) funcGroup = true; else funcGroup = false; // worldspawn (and func_groups) default to cast/recv shadows in worldspawn group if( funcGroup || mapEnt->mapEntityNum == 0 ) { castShadows = WORLDSPAWN_CAST_SHADOWS; recvShadows = WORLDSPAWN_RECV_SHADOWS; } else // other entities don't cast any shadows, but recv worldspawn shadows { castShadows = ENTITY_CAST_SHADOWS; recvShadows = ENTITY_RECV_SHADOWS; } // get explicit shadow flags GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows ); // get lightmap scaling value for this entity if( com.strcmp( "", ValueForKey( mapEnt, "lightmapscale" )) || com.strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ))) { // get lightmap scale from entity lightmapScale = FloatForKey( mapEnt, "lightmapscale" ); if( lightmapScale <= 0.0f ) lightmapScale = FloatForKey( mapEnt, "_lightmapscale" ); if( lightmapScale > 0.0f ) Msg( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale ); } else lightmapScale = 0.0f; // get cel shader :) for this entity value = ValueForKey( mapEnt, "_celshader" ); if( value[0] == '\0' ) value = ValueForKey( &entities[0], "_celshader" ); if( value[0] != '\0' ) { com.snprintf( shader, sizeof( shader ), "textures/%s", value ); celShader = ShaderInfoForShader( shader ); Msg( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader ); } else celShader = NULL; // attach stuff to everything in the entity for( brush = mapEnt->brushes; brush != NULL; brush = brush->next ) { brush->entityNum = mapEnt->mapEntityNum; brush->castShadows = castShadows; brush->recvShadows = recvShadows; brush->lightmapScale = lightmapScale; brush->celShader = celShader; } for( patch = mapEnt->patches; patch != NULL; patch = patch->next ) { patch->entityNum = mapEnt->mapEntityNum; patch->castShadows = castShadows; patch->recvShadows = recvShadows; patch->lightmapScale = lightmapScale; patch->celShader = celShader; } SetEntityBounds( mapEnt ); // load shader index map (equivalent to old terrain alphamap) LoadEntityIndexMap( mapEnt ); // get entity origin and adjust brushes GetVectorForKey( mapEnt, "origin", mapEnt->origin ); if( mapEnt->origin[0] || mapEnt->origin[1] || mapEnt->origin[2] ) AdjustBrushesForOrigin( mapEnt ); // group_info entities are just for editor grouping if( !com.stricmp( "group_info", classname )) { numEntities--; return true; } // group entities are just for editor convenience, toss all brushes into worldspawn if( funcGroup ) { MoveBrushesToWorld( mapEnt ); numEntities--; return true; } return true; }
void AddTriangleModels(entity_t * e) { int num, frame, castShadows, recvShadows, spawnFlags; entity_t *e2; const char *targetName; const char *target, *model, *value; char shader[MAX_QPATH]; shaderInfo_t *celShader; float temp, baseLightmapScale, lightmapScale; float shadeAngle; int lightmapSampleSize; vec3_t origin, scale, angles; matrix_t rotation, rotationScaled, transform; epair_t *ep; remap_t *remap, *remap2; char *split; /* note it */ Sys_FPrintf(SYS_VRB, "--- AddTriangleModels ---\n"); /* get current brush entity targetname */ if(e == entities) targetName = ""; else { targetName = ValueForKey(e, "name"); /* misc_model entities target non-worldspawn brush model entities */ if(targetName[0] == '\0') return; } /* get lightmap scale */ /* vortex: added _ls key (short name of lightmapscale) */ baseLightmapScale = 0.0f; if(strcmp("", ValueForKey(e, "lightmapscale")) || strcmp("", ValueForKey(e, "_lightmapscale")) || strcmp("", ValueForKey(e, "_ls"))) { baseLightmapScale = FloatForKey(e, "lightmapscale"); if(baseLightmapScale <= 0.0f) baseLightmapScale = FloatForKey(e, "_lightmapscale"); if(baseLightmapScale <= 0.0f) baseLightmapScale = FloatForKey(e, "_ls"); if(baseLightmapScale < 0.0f) baseLightmapScale = 0.0f; if(baseLightmapScale > 0.0f) Sys_Printf("World Entity has lightmap scale of %.4f\n", baseLightmapScale); } /* walk the entity list */ for(num = 1; num < numEntities; num++) { /* get e2 */ e2 = &entities[num]; /* convert misc_models into raw geometry */ if(Q_stricmp("misc_model", ValueForKey(e2, "classname"))) continue; /* ydnar: added support for md3 models on non-worldspawn models */ target = ValueForKey(e2, "target"); if(strcmp(target, targetName)) continue; /* get model name */ model = ValueForKey(e2, "model"); if(model[0] == '\0') { Sys_Printf("WARNING: misc_model at %i %i %i without a model key\n", (int)origin[0], (int)origin[1], (int)origin[2]); continue; } /* get model frame */ frame = IntForKey(e2, "_frame"); /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */ if(e == entities) { castShadows = WORLDSPAWN_CAST_SHADOWS; recvShadows = WORLDSPAWN_RECV_SHADOWS; } /* other entities don't cast any shadows, but recv worldspawn shadows */ else { castShadows = ENTITY_CAST_SHADOWS; recvShadows = ENTITY_RECV_SHADOWS; } /* get explicit shadow flags */ GetEntityShadowFlags(e2, e, &castShadows, &recvShadows); /* get spawnflags */ spawnFlags = IntForKey(e2, "spawnflags"); /* Tr3B: added clipModel option */ spawnFlags |= (IntForKey(e2, "clipModel") > 0) ? 2 : 0; /* Tr3B: added forceMeta option */ spawnFlags |= (IntForKey(e2, "forceMeta") > 0) ? 4 : 0; /* get origin */ GetVectorForKey(e2, "origin", origin); VectorSubtract(origin, e->origin, origin); /* offset by parent */ /* get "angle" (yaw) or "angles" (pitch yaw roll) */ MatrixIdentity(rotation); angles[0] = angles[1] = angles[2] = 0.0f; value = ValueForKey(e2, "angle"); if(value[0] != '\0') { angles[1] = atof(value); MatrixFromAngles(rotation, angles[PITCH], angles[YAW], angles[ROLL]); } value = ValueForKey(e2, "angles"); if(value[0] != '\0') { sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]); MatrixFromAngles(rotation, angles[PITCH], angles[YAW], angles[ROLL]); } value = ValueForKey(e2, "rotation"); if(value[0] != '\0') { sscanf(value, "%f %f %f %f %f %f %f %f %f", &rotation[0], &rotation[1], &rotation[2], &rotation[4], &rotation[5], &rotation[6], &rotation[8], &rotation[9], &rotation[10]); } /* get scale */ scale[0] = scale[1] = scale[2] = 1.0f; temp = FloatForKey(e2, "modelscale"); if(temp != 0.0f) scale[0] = scale[1] = scale[2] = temp; value = ValueForKey(e2, "modelscale_vec"); if(value[0] != '\0') sscanf(value, "%f %f %f", &scale[0], &scale[1], &scale[2]); MatrixCopy(rotation, rotationScaled); MatrixMultiplyScale(rotationScaled, scale[0], scale[1], scale[2]); /* set transform matrix */ MatrixIdentity(transform); MatrixSetupTransformFromRotation(transform, rotationScaled, origin); /* get shader remappings */ remap = NULL; for(ep = e2->epairs; ep != NULL; ep = ep->next) { /* look for keys prefixed with "_remap" */ if(ep->key != NULL && ep->value != NULL && ep->key[0] != '\0' && ep->value[0] != '\0' && !Q_strncasecmp(ep->key, "_remap", 6)) { /* create new remapping */ remap2 = remap; remap = safe_malloc(sizeof(*remap)); remap->next = remap2; strcpy(remap->from, ep->value); /* split the string */ split = strchr(remap->from, ';'); if(split == NULL) { Sys_Printf("WARNING: Shader _remap key found in misc_model without a ; character\n"); free(remap); remap = remap2; continue; } /* store the split */ *split = '\0'; strcpy(remap->to, (split + 1)); /* note it */ //% Sys_FPrintf( SYS_VRB, "Remapping %s to %s\n", remap->from, remap->to ); } } /* ydnar: cel shader support */ value = ValueForKey(e2, "_celshader"); if(value[0] == '\0') value = ValueForKey(&entities[0], "_celshader"); if(value[0] != '\0') { sprintf(shader, "textures/%s", value); celShader = ShaderInfoForShader(shader); } else celShader = NULL; /* jal : entity based _samplesize */ lightmapSampleSize = 0; if(strcmp("", ValueForKey(e2, "_lightmapsamplesize"))) lightmapSampleSize = IntForKey(e2, "_lightmapsamplesize"); else if(strcmp("", ValueForKey(e2, "_samplesize"))) lightmapSampleSize = IntForKey(e2, "_samplesize"); if(lightmapSampleSize < 0) lightmapSampleSize = 0; if(lightmapSampleSize > 0.0f) Sys_Printf("misc_model has lightmap sample size of %.d\n", lightmapSampleSize); /* get lightmap scale */ /* vortex: added _ls key (short name of lightmapscale) */ lightmapScale = 0.0f; if(strcmp("", ValueForKey(e2, "lightmapscale")) || strcmp("", ValueForKey(e2, "_lightmapscale")) || strcmp("", ValueForKey(e2, "_ls"))) { lightmapScale = FloatForKey(e2, "lightmapscale"); if(lightmapScale <= 0.0f) lightmapScale = FloatForKey(e2, "_lightmapscale"); if(lightmapScale <= 0.0f) lightmapScale = FloatForKey(e2, "_ls"); if(lightmapScale < 0.0f) lightmapScale = 0.0f; if(lightmapScale > 0.0f) Sys_Printf("misc_model has lightmap scale of %.4f\n", lightmapScale); } /* jal : entity based _shadeangle */ shadeAngle = 0.0f; if(strcmp("", ValueForKey(e2, "_shadeangle"))) shadeAngle = FloatForKey(e2, "_shadeangle"); /* vortex' aliases */ else if(strcmp("", ValueForKey(mapEnt, "_smoothnormals"))) shadeAngle = FloatForKey(mapEnt, "_smoothnormals"); else if(strcmp("", ValueForKey(mapEnt, "_sn"))) shadeAngle = FloatForKey(mapEnt, "_sn"); else if(strcmp("", ValueForKey(mapEnt, "_smooth"))) shadeAngle = FloatForKey(mapEnt, "_smooth"); if(shadeAngle < 0.0f) shadeAngle = 0.0f; if(shadeAngle > 0.0f) Sys_Printf("misc_model has shading angle of %.4f\n", shadeAngle); /* insert the model */ InsertModel((char *)model, frame, transform, rotation, remap, celShader, mapEntityNum, castShadows, recvShadows, spawnFlags, lightmapScale, lightmapSampleSize, shadeAngle); /* free shader remappings */ while(remap != NULL) { remap2 = remap->next; free(remap); remap = remap2; } } }
void AddTriangleModel(entity_t * e) { int frame, castShadows, recvShadows, spawnFlags; const char *name, *model, *value; char shader[MAX_QPATH]; shaderInfo_t *celShader; float temp, baseLightmapScale, lightmapScale; float shadeAngle; int lightmapSampleSize; vec3_t scale; matrix_t rotation, transform; epair_t *ep; remap_t *remap, *remap2; char *split; /* note it */ Sys_FPrintf(SYS_VRB, "--- AddTriangleModel ---\n"); /* get current brush entity name */ name = ValueForKey(e, "name"); /* misc_model entities target non-worldspawn brush model entities */ if(name[0] == '\0') return; /* get model name */ model = ValueForKey(e, "model"); if(model[0] == '\0') return; /* Tr3B: skip triggers and other entities */ if(!Q_stricmp(name, model)) return; /* get model frame */ frame = IntForKey(e, "_frame"); /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */ if(e == entities) { castShadows = WORLDSPAWN_CAST_SHADOWS; recvShadows = WORLDSPAWN_RECV_SHADOWS; } /* other entities don't cast any shadows, but recv worldspawn shadows */ else { castShadows = ENTITY_CAST_SHADOWS; recvShadows = ENTITY_RECV_SHADOWS; } /* get explicit shadow flags */ GetEntityShadowFlags(NULL, e, &castShadows, &recvShadows); /* get spawnflags */ spawnFlags = IntForKey(e, "spawnflags"); /* Tr3B: added clipModel option */ spawnFlags |= (IntForKey(e, "clipModel") > 0) ? 2 : 0; /* Tr3B: added forceMeta option */ spawnFlags |= (IntForKey(e, "forceMeta") > 0) ? 4 : 0; /* get scale */ scale[0] = scale[1] = scale[2] = 1.0f; temp = FloatForKey(e, "modelscale"); if(temp != 0.0f) scale[0] = scale[1] = scale[2] = temp; value = ValueForKey(e, "modelscale_vec"); if(value[0] != '\0') sscanf(value, "%f %f %f", &scale[0], &scale[1], &scale[2]); /* set transform matrix */ MatrixIdentity(transform); MatrixMultiplyScale(transform, scale[0], scale[1], scale[2]); MatrixIdentity(rotation); /* get shader remappings */ remap = NULL; for(ep = e->epairs; ep != NULL; ep = ep->next) { /* look for keys prefixed with "_remap" */ if(ep->key != NULL && ep->value != NULL && ep->key[0] != '\0' && ep->value[0] != '\0' && !Q_strncasecmp(ep->key, "_remap", 6)) { /* create new remapping */ remap2 = remap; remap = safe_malloc(sizeof(*remap)); remap->next = remap2; strcpy(remap->from, ep->value); /* split the string */ split = strchr(remap->from, ';'); if(split == NULL) { Sys_Printf("WARNING: Shader _remap key found in misc_model without a ; character\n"); free(remap); remap = remap2; continue; } /* store the split */ *split = '\0'; strcpy(remap->to, (split + 1)); /* note it */ //% Sys_FPrintf( SYS_VRB, "Remapping %s to %s\n", remap->from, remap->to ); } } /* ydnar: cel shader support */ value = ValueForKey(e, "_celshader"); if(value[0] == '\0') value = ValueForKey(&entities[0], "_celshader"); if(value[0] != '\0') { sprintf(shader, "textures/%s", value); celShader = ShaderInfoForShader(shader); } else celShader = NULL; /* get lightmap scale */ /* jal : entity based _samplesize */ lightmapSampleSize = 0; if(strcmp("", ValueForKey(e, "_lightmapsamplesize"))) lightmapSampleSize = IntForKey(e, "_lightmapsamplesize"); else if(strcmp("", ValueForKey(e, "_samplesize"))) lightmapSampleSize = IntForKey(e, "_samplesize"); if(lightmapSampleSize < 0) lightmapSampleSize = 0; if(lightmapSampleSize > 0.0f) Sys_Printf(" has lightmap sample size of %.d\n", lightmapSampleSize); /* get lightmap scale */ /* vortex: added _ls key (short name of lightmapscale) */ lightmapScale = 0.0f; if(strcmp("", ValueForKey(e, "lightmapscale")) || strcmp("", ValueForKey(e, "_lightmapscale")) || strcmp("", ValueForKey(e, "_ls"))) { lightmapScale = FloatForKey(e, "lightmapscale"); if(lightmapScale <= 0.0f) lightmapScale = FloatForKey(e, "_lightmapscale"); if(lightmapScale <= 0.0f) lightmapScale = FloatForKey(e, "_ls"); if(lightmapScale < 0.0f) lightmapScale = 0.0f; if(lightmapScale > 0.0f) Sys_Printf("misc_model has lightmap scale of %.4f\n", lightmapScale); } /* jal : entity based _shadeangle */ shadeAngle = 0.0f; if(strcmp("", ValueForKey(e, "_shadeangle"))) shadeAngle = FloatForKey(e, "_shadeangle"); /* vortex' aliases */ else if(strcmp("", ValueForKey(e, "_smoothnormals"))) shadeAngle = FloatForKey(e, "_smoothnormals"); else if(strcmp("", ValueForKey(e, "_sn"))) shadeAngle = FloatForKey(e, "_sn"); else if(strcmp("", ValueForKey(e, "_smooth"))) shadeAngle = FloatForKey(e, "_smooth"); if(shadeAngle < 0.0f) shadeAngle = 0.0f; if(shadeAngle > 0.0f) Sys_Printf("misc_model has shading angle of %.4f\n", shadeAngle); /* insert the model */ InsertModel((char *)model, frame, transform, rotation, remap, celShader, mapEntityNum, castShadows, recvShadows, spawnFlags, lightmapScale, lightmapSampleSize, shadeAngle); /* free shader remappings */ while(remap != NULL) { remap2 = remap->next; free(remap); remap = remap2; } }
int ScaleBSPMain( int argc, char **argv ){ int i, j; float f, a; vec3_t scale; vec3_t vec; char str[ 1024 ]; int uniform, axis; qboolean texscale; float *old_xyzst = NULL; float spawn_ref = 0; /* arg checking */ if ( argc < 3 ) { Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref <value>] <value> <mapname>\n" ); return 0; } texscale = qfalse; for ( i = 1; i < argc - 2; ++i ) { if ( !strcmp( argv[i], "-tex" ) ) { texscale = qtrue; } else if ( !strcmp( argv[i], "-spawn_ref" ) ) { spawn_ref = atof( argv[i + 1] ); ++i; } else{ break; } } /* get scale */ // if(argc-2 >= i) // always true scale[2] = scale[1] = scale[0] = atof( argv[ argc - 2 ] ); if ( argc - 3 >= i ) { scale[1] = scale[0] = atof( argv[ argc - 3 ] ); } if ( argc - 4 >= i ) { scale[0] = atof( argv[ argc - 4 ] ); } uniform = ( ( scale[0] == scale[1] ) && ( scale[1] == scale[2] ) ); if ( scale[0] == 0.0f || scale[1] == 0.0f || scale[2] == 0.0f ) { Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref <value>] <value> <mapname>\n" ); Sys_Printf( "Non-zero scale value required.\n" ); return 0; } /* do some path mangling */ strcpy( source, ExpandArg( argv[ argc - 1 ] ) ); StripExtension( source ); DefaultExtension( source, ".bsp" ); /* load the bsp */ Sys_Printf( "Loading %s\n", source ); LoadBSPFile( source ); ParseEntities(); /* note it */ Sys_Printf( "--- ScaleBSP ---\n" ); Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities ); /* scale entity keys */ for ( i = 0; i < numBSPEntities && i < numEntities; i++ ) { /* scale origin */ GetVectorForKey( &entities[ i ], "origin", vec ); if ( ( vec[ 0 ] || vec[ 1 ] || vec[ 2 ] ) ) { if ( !strncmp( ValueForKey( &entities[i], "classname" ), "info_player_", 12 ) ) { vec[2] += spawn_ref; } vec[0] *= scale[0]; vec[1] *= scale[1]; vec[2] *= scale[2]; if ( !strncmp( ValueForKey( &entities[i], "classname" ), "info_player_", 12 ) ) { vec[2] -= spawn_ref; } sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] ); SetKeyValue( &entities[ i ], "origin", str ); } a = FloatForKey( &entities[ i ], "angle" ); if ( a == -1 || a == -2 ) { // z scale axis = 2; } else if ( fabs( sin( DEG2RAD( a ) ) ) < 0.707 ) { axis = 0; } else{ axis = 1; } /* scale door lip */ f = FloatForKey( &entities[ i ], "lip" ); if ( f ) { f *= scale[axis]; sprintf( str, "%f", f ); SetKeyValue( &entities[ i ], "lip", str ); } /* scale plat height */ f = FloatForKey( &entities[ i ], "height" ); if ( f ) { f *= scale[2]; sprintf( str, "%f", f ); SetKeyValue( &entities[ i ], "height", str ); } // TODO maybe allow a definition file for entities to specify which values are scaled how? } /* scale models */ for ( i = 0; i < numBSPModels; i++ ) { bspModels[ i ].mins[0] *= scale[0]; bspModels[ i ].mins[1] *= scale[1]; bspModels[ i ].mins[2] *= scale[2]; bspModels[ i ].maxs[0] *= scale[0]; bspModels[ i ].maxs[1] *= scale[1]; bspModels[ i ].maxs[2] *= scale[2]; } /* scale nodes */ for ( i = 0; i < numBSPNodes; i++ ) { bspNodes[ i ].mins[0] *= scale[0]; bspNodes[ i ].mins[1] *= scale[1]; bspNodes[ i ].mins[2] *= scale[2]; bspNodes[ i ].maxs[0] *= scale[0]; bspNodes[ i ].maxs[1] *= scale[1]; bspNodes[ i ].maxs[2] *= scale[2]; } /* scale leafs */ for ( i = 0; i < numBSPLeafs; i++ ) { bspLeafs[ i ].mins[0] *= scale[0]; bspLeafs[ i ].mins[1] *= scale[1]; bspLeafs[ i ].mins[2] *= scale[2]; bspLeafs[ i ].maxs[0] *= scale[0]; bspLeafs[ i ].maxs[1] *= scale[1]; bspLeafs[ i ].maxs[2] *= scale[2]; } if ( texscale ) { Sys_Printf( "Using texture unlocking (and probably breaking texture alignment a lot)\n" ); old_xyzst = safe_malloc( sizeof( *old_xyzst ) * numBSPDrawVerts * 5 ); for ( i = 0; i < numBSPDrawVerts; i++ ) { old_xyzst[5 * i + 0] = bspDrawVerts[i].xyz[0]; old_xyzst[5 * i + 1] = bspDrawVerts[i].xyz[1]; old_xyzst[5 * i + 2] = bspDrawVerts[i].xyz[2]; old_xyzst[5 * i + 3] = bspDrawVerts[i].st[0]; old_xyzst[5 * i + 4] = bspDrawVerts[i].st[1]; } } /* scale drawverts */ for ( i = 0; i < numBSPDrawVerts; i++ ) { bspDrawVerts[i].xyz[0] *= scale[0]; bspDrawVerts[i].xyz[1] *= scale[1]; bspDrawVerts[i].xyz[2] *= scale[2]; bspDrawVerts[i].normal[0] /= scale[0]; bspDrawVerts[i].normal[1] /= scale[1]; bspDrawVerts[i].normal[2] /= scale[2]; VectorNormalize( bspDrawVerts[i].normal, bspDrawVerts[i].normal ); } if ( texscale ) { for ( i = 0; i < numBSPDrawSurfaces; i++ ) { switch ( bspDrawSurfaces[i].surfaceType ) { case SURFACE_FACE: case SURFACE_META: if ( bspDrawSurfaces[i].numIndexes % 3 ) { Error( "Not a triangulation!" ); } for ( j = bspDrawSurfaces[i].firstIndex; j < bspDrawSurfaces[i].firstIndex + bspDrawSurfaces[i].numIndexes; j += 3 ) { int ia = bspDrawIndexes[j] + bspDrawSurfaces[i].firstVert, ib = bspDrawIndexes[j + 1] + bspDrawSurfaces[i].firstVert, ic = bspDrawIndexes[j + 2] + bspDrawSurfaces[i].firstVert; bspDrawVert_t *a = &bspDrawVerts[ia], *b = &bspDrawVerts[ib], *c = &bspDrawVerts[ic]; float *oa = &old_xyzst[ia * 5], *ob = &old_xyzst[ib * 5], *oc = &old_xyzst[ic * 5]; // extrapolate: // a->xyz -> oa // b->xyz -> ob // c->xyz -> oc ExtrapolateTexcoords( &oa[0], &oa[3], &ob[0], &ob[3], &oc[0], &oc[3], a->xyz, a->st, b->xyz, b->st, c->xyz, c->st ); } break; } } } /* scale planes */ if ( uniform ) { for ( i = 0; i < numBSPPlanes; i++ ) { bspPlanes[ i ].dist *= scale[0]; } } else { for ( i = 0; i < numBSPPlanes; i++ ) { bspPlanes[ i ].normal[0] /= scale[0]; bspPlanes[ i ].normal[1] /= scale[1]; bspPlanes[ i ].normal[2] /= scale[2]; f = 1 / VectorLength( bspPlanes[i].normal ); VectorScale( bspPlanes[i].normal, f, bspPlanes[i].normal ); bspPlanes[ i ].dist *= f; } } /* scale gridsize */ GetVectorForKey( &entities[ 0 ], "gridsize", vec ); if ( ( vec[ 0 ] + vec[ 1 ] + vec[ 2 ] ) == 0.0f ) { VectorCopy( gridSize, vec ); } vec[0] *= scale[0]; vec[1] *= scale[1]; vec[2] *= scale[2]; sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] ); SetKeyValue( &entities[ 0 ], "gridsize", str ); /* inject command line parameters */ InjectCommandLine( argv, 0, argc - 1 ); /* write the bsp */ UnparseEntities(); StripExtension( source ); DefaultExtension( source, "_s.bsp" ); Sys_Printf( "Writing %s\n", source ); WriteBSPFile( source ); /* return to sender */ return 0; }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int Overlay_GetFromEntity( entity_t *pMapEnt ) { int iAccessorID = -1; // Allocate the new overlay. int iOverlay = g_aMapOverlays.AddToTail(); mapoverlay_t *pMapOverlay = &g_aMapOverlays[iOverlay]; // Get the overlay data. pMapOverlay->nId = g_aMapOverlays.Count() - 1; if ( ValueForKey( pMapEnt, "targetname" )[ 0 ] != '\0' ) { // Overlay has a name, remember it's ID for accessing iAccessorID = pMapOverlay->nId; } pMapOverlay->flU[0] = FloatForKey( pMapEnt, "StartU" ); pMapOverlay->flU[1] = FloatForKey( pMapEnt, "EndU" ); pMapOverlay->flV[0] = FloatForKey( pMapEnt, "StartV" ); pMapOverlay->flV[1] = FloatForKey( pMapEnt, "EndV" ); pMapOverlay->flFadeDistMinSq = FloatForKey( pMapEnt, "fademindist" ); if ( pMapOverlay->flFadeDistMinSq > 0 ) { pMapOverlay->flFadeDistMinSq *= pMapOverlay->flFadeDistMinSq; } pMapOverlay->flFadeDistMaxSq = FloatForKey( pMapEnt, "fademaxdist" ); if ( pMapOverlay->flFadeDistMaxSq > 0 ) { pMapOverlay->flFadeDistMaxSq *= pMapOverlay->flFadeDistMaxSq; } GetVectorForKey( pMapEnt, "BasisOrigin", pMapOverlay->vecOrigin ); pMapOverlay->m_nRenderOrder = IntForKey( pMapEnt, "RenderOrder" ); if ( pMapOverlay->m_nRenderOrder < 0 || pMapOverlay->m_nRenderOrder >= OVERLAY_NUM_RENDER_ORDERS ) Error( "Overlay (%s) at %f %f %f has invalid render order (%d).\n", ValueForKey( pMapEnt, "material" ), pMapOverlay->vecOrigin ); GetVectorForKey( pMapEnt, "uv0", pMapOverlay->vecUVPoints[0] ); GetVectorForKey( pMapEnt, "uv1", pMapOverlay->vecUVPoints[1] ); GetVectorForKey( pMapEnt, "uv2", pMapOverlay->vecUVPoints[2] ); GetVectorForKey( pMapEnt, "uv3", pMapOverlay->vecUVPoints[3] ); GetVectorForKey( pMapEnt, "BasisU", pMapOverlay->vecBasis[0] ); GetVectorForKey( pMapEnt, "BasisV", pMapOverlay->vecBasis[1] ); GetVectorForKey( pMapEnt, "BasisNormal", pMapOverlay->vecBasis[2] ); const char *pMaterialName = ValueForKey( pMapEnt, "material" ); Assert( strlen( pMaterialName ) < OVERLAY_MAP_STRLEN ); if ( strlen( pMaterialName ) >= OVERLAY_MAP_STRLEN ) { Error( "Overlay Material Name (%s) too long! > OVERLAY_MAP_STRLEN (%d)", pMaterialName, OVERLAY_MAP_STRLEN ); return -1; } strcpy( pMapOverlay->szMaterialName, pMaterialName ); // Convert the sidelist to side id(s). const char *pSideList = ValueForKey( pMapEnt, "sides" ); char *pTmpList = ( char* )_alloca( strlen( pSideList ) + 1 ); strcpy( pTmpList, pSideList ); const char *pScan = strtok( pTmpList, " " ); if ( !pScan ) return iAccessorID; pMapOverlay->aSideList.Purge(); pMapOverlay->aFaceList.Purge(); do { int nSideId; if ( sscanf( pScan, "%d", &nSideId ) == 1 ) { pMapOverlay->aSideList.AddToTail( nSideId ); } } while ( ( pScan = strtok( NULL, " " ) ) ); return iAccessorID; }
/* ============= FinalLightFace Add the indirect lighting on top of the direct lighting and save into final map format ============= */ void FinalLightFace( int iThread, int facenum ) { dface_t *f; int i, j, k; facelight_t *fl; float minlight; int lightstyles; LightingValue_t lb[NUM_BUMP_VECTS + 1], v[NUM_BUMP_VECTS + 1]; unsigned char *pdata[NUM_BUMP_VECTS + 1]; int bumpSample; radial_t *rad = NULL; radial_t *prad = NULL; f = &g_pFaces[facenum]; // test for non-lit texture if ( texinfo[f->texinfo].flags & TEX_SPECIAL) return; fl = &facelight[facenum]; for (lightstyles=0; lightstyles < MAXLIGHTMAPS; lightstyles++ ) { if ( f->styles[lightstyles] == 255 ) break; } if ( !lightstyles ) return; // // sample the triangulation // minlight = FloatForKey (face_entity[facenum], "_minlight") * 128; bool needsBumpmap = ( texinfo[f->texinfo].flags & SURF_BUMPLIGHT ) ? true : false; int bumpSampleCount = needsBumpmap ? NUM_BUMP_VECTS + 1 : 1; bool bDisp = ( f->dispinfo != -1 ); //#define RANDOM_COLOR #ifdef RANDOM_COLOR unsigned char randomColor[3]; GetRandomColor( randomColor ); #endif // NOTE: I'm using these RB trees to sort all the illumination values // to compute median colors. Turns out that this is a somewhat better // method that using the average; usually if there are surfaces // with a large light intensity variation, the extremely bright regions // have a very small area and tend to influence the average too much. CUtlRBTree< float, int > m_Red( 0, 256, FloatLess ); CUtlRBTree< float, int > m_Green( 0, 256, FloatLess ); CUtlRBTree< float, int > m_Blue( 0, 256, FloatLess ); for (k=0 ; k < lightstyles; k++ ) { m_Red.RemoveAll(); m_Green.RemoveAll(); m_Blue.RemoveAll(); if (!do_fast) { if( !bDisp ) { rad = BuildLuxelRadial( facenum, k ); } else { rad = StaticDispMgr()->BuildLuxelRadial( facenum, k, needsBumpmap ); } } if (numbounce > 0 && k == 0) { // currently only radiosity light non-displacement surfaces! if( !bDisp ) { prad = BuildPatchRadial( facenum ); } else { prad = StaticDispMgr()->BuildPatchRadial( facenum, needsBumpmap ); } } // pack the nonbump texture and the three bump texture for the given // lightstyle right next to each other. // NOTE: Even though it's building positions for all bump-mapped data, // it isn't going to use those positions (see loop over bumpSample below) // The file offset is correctly computed to only store space for 1 set // of light data if we don't have bumped lighting. for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample ) { pdata[bumpSample] = &(*pdlightdata)[f->lightofs + (k * bumpSampleCount + bumpSample) * fl->numluxels*4]; } // Compute the average luxel color, but not for the bump samples Vector avg( 0.0f, 0.0f, 0.0f ); int avgCount = 0; for (j=0 ; j<fl->numluxels; j++) { // garymct - direct lighting bool baseSampleOk = true; if (!do_fast) { if( !bDisp ) { baseSampleOk = SampleRadial( rad, fl->luxel[j], lb, bumpSampleCount ); } else { baseSampleOk = StaticDispMgr()->SampleRadial( facenum, rad, fl->luxel[j], j, lb, bumpSampleCount, false ); } } else { for ( int iBump = 0 ; iBump < bumpSampleCount; iBump++ ) { lb[iBump] = fl->light[0][iBump][j]; } } if (prad) { // garymct - bounced light // v is indirect light that is received on the luxel. if( !bDisp ) { SampleRadial( prad, fl->luxel[j], v, bumpSampleCount ); } else { StaticDispMgr()->SampleRadial( facenum, prad, fl->luxel[j], j, v, bumpSampleCount, true ); } for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample ) { lb[bumpSample].AddLight( v[bumpSample] ); } } if ( bDisp && g_bDumpPatches ) { for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample ) { DumpDispLuxels( facenum, lb[bumpSample].m_vecLighting, j, bumpSample ); } } if (fl->numsamples == 0) { for( i = 0; i < bumpSampleCount; i++ ) { lb[i].Init( 255, 0, 0 ); } baseSampleOk = false; } int bumpSample; for( bumpSample = 0; bumpSample < bumpSampleCount; bumpSample++ ) { // clip from the bottom first // garymct: minlight is a per entity minimum light value? for( i=0; i<3; i++ ) { lb[bumpSample].m_vecLighting[i] = max( lb[bumpSample].m_vecLighting[i], minlight ); } // Do the average light computation, I'm assuming (perhaps incorrectly?) // that all luxels in a particular lightmap have the same area here. // Also, don't bother doing averages for the bump samples. Doing it here // because of the minlight clamp above + the random color testy thingy. // Also have to do it before Vec3toColorRGBExp32 because it // destructively modifies lb[bumpSample] (Feh!) if ((bumpSample == 0) && baseSampleOk) { ++avgCount; ApplyMacroTextures( facenum, fl->luxel[j], lb[0].m_vecLighting ); // For median computation m_Red.Insert( lb[bumpSample].m_vecLighting[0] ); m_Green.Insert( lb[bumpSample].m_vecLighting[1] ); m_Blue.Insert( lb[bumpSample].m_vecLighting[2] ); } #ifdef RANDOM_COLOR pdata[bumpSample][0] = randomColor[0] / ( bumpSample + 1 ); pdata[bumpSample][1] = randomColor[1] / ( bumpSample + 1 ); pdata[bumpSample][2] = randomColor[2] / ( bumpSample + 1 ); pdata[bumpSample][3] = 0; #else // convert to a 4 byte r,g,b,signed exponent format VectorToColorRGBExp32( Vector( lb[bumpSample].m_vecLighting.x, lb[bumpSample].m_vecLighting.y, lb[bumpSample].m_vecLighting.z ), *( ColorRGBExp32 *)pdata[bumpSample] ); #endif pdata[bumpSample] += 4; } } FreeRadial( rad ); if (prad) { FreeRadial( prad ); prad = NULL; } // Compute the median color for this lightstyle // Remember, the data goes *before* the specified light_ofs, in *reverse order* ColorRGBExp32 *pAvgColor = dface_AvgLightColor( f, k ); if (avgCount == 0) { Vector median( 0, 0, 0 ); VectorToColorRGBExp32( median, *pAvgColor ); } else { unsigned int r, g, b; r = m_Red.FirstInorder(); g = m_Green.FirstInorder(); b = m_Blue.FirstInorder(); avgCount >>= 1; while (avgCount > 0) { r = m_Red.NextInorder(r); g = m_Green.NextInorder(g); b = m_Blue.NextInorder(b); --avgCount; } Vector median( m_Red[r], m_Green[g], m_Blue[b] ); VectorToColorRGBExp32( median, *pAvgColor ); } } }
qboolean FloodEntities( tree_t *tree ) { int i, s; vec3_t origin, offset, scale, angles; qboolean r, inside, tripped, skybox; node_t *headnode; entity_t *e; const char *value; headnode = tree->headnode; Sys_FPrintf( SYS_VRB,"--- FloodEntities ---\n" ); inside = qfalse; tree->outside_node.occupied = 0; tripped = qfalse; c_floodedleafs = 0; for( i = 1; i < numEntities; i++ ) { /* get entity */ e = &entities[ i ]; /* get origin */ GetVectorForKey( e, "origin", origin ); if( VectorCompare( origin, vec3_origin ) ) continue; /* handle skybox entities */ value = ValueForKey( e, "classname" ); if( !Q_stricmp( value, "_skybox" ) ) { skybox = qtrue; skyboxPresent = qtrue; /* invert origin */ VectorScale( origin, -1.0f, offset ); /* get scale */ VectorSet( scale, 64.0f, 64.0f, 64.0f ); value = ValueForKey( e, "_scale" ); if( value[ 0 ] != '\0' ) { s = sscanf( value, "%f %f %f", &scale[ 0 ], &scale[ 1 ], &scale[ 2 ] ); if( s == 1 ) { scale[ 1 ] = scale[ 0 ]; scale[ 2 ] = scale[ 0 ]; } } /* get "angle" (yaw) or "angles" (pitch yaw roll) */ VectorClear( angles ); angles[ 2 ] = FloatForKey( e, "angle" ); value = ValueForKey( e, "angles" ); if( value[ 0 ] != '\0' ) sscanf( value, "%f %f %f", &angles[ 1 ], &angles[ 2 ], &angles[ 0 ] ); /* set transform matrix (thanks spog) */ m4x4_identity( skyboxTransform ); m4x4_pivoted_transform_by_vec3( skyboxTransform, offset, angles, eXYZ, scale, origin ); } else skybox = qfalse; /* nudge off floor */ origin[ 2 ] += 1; /* debugging code */ //% if( i == 1 ) //% origin[ 2 ] += 4096; /* find leaf */ r = PlaceOccupant( headnode, origin, e, skybox ); if( r ) inside = qtrue; if( (!r || tree->outside_node.occupied) && !tripped ) { xml_Select( "Entity leaked", e->mapEntityNum, 0, qfalse ); tripped = qtrue; } } Sys_FPrintf( SYS_VRB, "%9d flooded leafs\n", c_floodedleafs ); if( !inside ) Sys_FPrintf( SYS_VRB, "no entities in open -- no filling\n" ); else if( tree->outside_node.occupied ) Sys_FPrintf( SYS_VRB, "entity reached from outside -- no filling\n" ); return (qboolean) (inside && !tree->outside_node.occupied); }
/* ================== ParseLightEntities ================== */ void ParseLightEntities( void ) { int i, j; entity_t *ent; char *value, *targetname, *style; directlight_t *l; double vec[4], color2[3]; qboolean isLight; num_directlights = 0; for( i = 0, ent = entities; i < num_entities; i++, ent++ ) { value = ValueForKey( ent, "classname" ); if( strncmp (value, "light", 5) ) continue; if( !strcmp (value, "light") ) isLight = true; else isLight = false; if( num_directlights == MAP_DIRECTLIGHTS ) Error( "numdirectlights == MAP_DIRECTLIGHTS" ); l = &directlights[num_directlights++]; memset( l, 0, sizeof (*l) ); color2[0] = color2[1] = color2[2] = 1.0f; l->color[0] = l->color[1] = l->color[2] = 1.0f; GetVectorForKey( ent, "origin", l->origin ); l->type = defaultlighttype; if (!overridelighttypes && (j = FloatForKey( ent, "delay" ))) { if (j < 0 || j >= LIGHTTYPE_TOTAL) Error("error in light at %.0f %.0f %.0f:\nunknown light type \"delay\" \"%s\"\n", l->origin[0], l->origin[1], l->origin[2], ValueForKey( ent, "delay" )); l->type = j; } l->style = FloatForKey( ent, "style" ); if( (unsigned)l->style > 254 ) Error( "error in light at %.0f %.0f %.0f:\nBad light style %i (must be 0-254)", l->origin[0], l->origin[1], l->origin[2], l->style ); l->angle = FloatForKey( ent, "angle" ); value = ValueForKey( ent, "color" ); if( !value[0] ) value = ValueForKey( ent, "_color" ); if( value[0] ) if( sscanf (value, "%lf %lf %lf", &color2[0], &color2[1], &color2[2]) != 3 ) Error( "error in light at %.0f %.0f %.0f:\ncolor must be given 3 values", l->origin[0], l->origin[1], l->origin[2] ); value = ValueForKey( ent, "light" ); if( !value[0] ) value = ValueForKey( ent, "_light" ); if( value[0] ) { j = sscanf ( value, "%lf %lf %lf %lf", &vec[0], &vec[1], &vec[2], &vec[3] ); switch( j ) { case 4:// HalfLife light l->color[0] = vec[0]; l->color[1] = vec[1]; l->color[2] = vec[2]; l->radius = vec[3]; break; case 1: // quake light l->radius = vec[0]; l->color[0] = vec[0]; l->color[1] = vec[0]; l->color[2] = vec[0]; break; default: Error( "error in light at %.0f %.0f %.0f:\n_light (or light) key must be 1 (Quake) or 4 (HalfLife) numbers, \"%s\" is not valid\n", l->origin[0], l->origin[1], l->origin[2], value ); } } if( !l->radius ) { l->radius = DEFAULTLIGHTLEVEL; l->color[0] = DEFAULTLIGHTLEVEL; l->color[1] = DEFAULTLIGHTLEVEL; l->color[2] = DEFAULTLIGHTLEVEL; } // for some reason this * 0.5 is needed to match quake light VectorScale(l->color, 0.5, l->color); // fix tyrlite darklight radius value (but color remains negative) l->radius = fabs(l->radius); // apply scaling to radius vec[0] = FloatForKey( ent, "wait" ); if( !vec[0] ) vec[0] = 1; if (vec[0] != 1) { if (vec[0] <= 0.0001) { l->type = LIGHTTYPE_NONE; l->radius = BOGUS_RANGE; VectorScale(l->color, 0.25, l->color); } else l->radius /= vec[0]; } l->radius *= globallightradiusscale; l->clampradius = l->radius; switch (l->type) { case LIGHTTYPE_RECIPX: l->clampradius = BOGUS_RANGE; break; case LIGHTTYPE_RECIPXX: l->clampradius = BOGUS_RANGE; break; default: break; } l->color[0] *= color2[0] * globallightscale; l->color[1] *= color2[1] * globallightscale; l->color[2] *= color2[2] * globallightscale; // this confines the light to a specified radius (typically used on RECIPX and RECIPXX) vec[0] = FloatForKey( ent, "_lightradius" ); if (vec[0]) l->clampradius = vec[0]; if( isLight ) { value = ValueForKey( ent, "targetname" ); if( value[0] && !l->style ) { char s[16]; l->style = LightStyleForTargetname( value ); memset( s, 0, sizeof(s) ); sprintf( s, "%i", l->style ); SetKeyValue( ent, "style", s ); } } value = ValueForKey( ent, "target" ); if( !value[0] ) { if (l->type == LIGHTTYPE_SUN) Error("error in light at %.0f %.0f %.0f:\nLIGHTTYPE_SUN (delay 4) requires a target for the sun direction\n", l->origin[0], l->origin[1], l->origin[2]); continue; } for( j = 0; j < num_entities; j++ ) { if( i == j ) continue; targetname = ValueForKey( &entities[j], "targetname" ); if( !strcmp (targetname, value) ) { vec3_t origin; GetVectorForKey( &entities[j], "origin", origin ); // set up spotlight values for lighting code to use VectorSubtract( origin, l->origin, l->spotdir ); VectorNormalize( l->spotdir ); if( !l->angle ) l->spotcone = -cos( 20 * Q_PI / 180 ); else l->spotcone = -cos( l->angle / 2 * Q_PI / 180 ); break; } } if( j == num_entities ) { printf( "warning in light at %.0f %.0f %.0f:\nunmatched spotlight target\n", l->origin[0], l->origin[1], l->origin[2]); if (l->type == LIGHTTYPE_SUN) Error("error in light at %.0f %.0f %.0f:\nLIGHTTYPE_SUN (delay 4) requires a target for the sun direction\n", l->origin[0], l->origin[1], l->origin[2]); continue; } // set the style on the source ent for switchable lights style = ValueForKey( &entities[j], "style" ); if( style[0] && atof (style) ) { char s[16]; l->style = atof( style ); if( (unsigned)l->style > 254 ) Error( "error in light at %.0f %.0f %.0f:\nBad target light style %i (must be 0-254)", l->origin[0], l->origin[1], l->origin[2], l->style ); memset( s, 0, sizeof(s) ); sprintf( s, "%i", l->style ); SetKeyValue( ent, "style", s ); } } }
int ScaleBSPMain( int argc, char **argv ) { int i; float f, scale; vec3_t vec; char str[ 1024 ]; /* arg checking */ if( argc < 2 ) { Sys_Printf( "Usage: q3map -scale <value> [-v] <mapname>\n" ); return 0; } /* get scale */ scale = atof( argv[ argc - 2 ] ); if( scale == 0.0f ) { Sys_Printf( "Usage: q3map -scale <value> [-v] <mapname>\n" ); Sys_Printf( "Non-zero scale value required.\n" ); return 0; } /* do some path mangling */ strcpy( source, ExpandArg( argv[ argc - 1 ] ) ); StripExtension( source ); DefaultExtension( source, ".bsp" ); /* load the bsp */ Sys_Printf( "Loading %s\n", source ); LoadBSPFile( source ); ParseEntities(); /* note it */ Sys_Printf( "--- ScaleBSP ---\n" ); Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities ); /* scale entity keys */ for( i = 0; i < numBSPEntities && i < numEntities; i++ ) { /* scale origin */ GetVectorForKey( &entities[ i ], "origin", vec ); if( (vec[ 0 ] + vec[ 1 ] + vec[ 2 ]) ) { VectorScale( vec, scale, vec ); sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] ); SetKeyValue( &entities[ i ], "origin", str ); } /* scale door lip */ f = FloatForKey( &entities[ i ], "lip" ); if( f ) { f *= scale; sprintf( str, "%f", f ); SetKeyValue( &entities[ i ], "lip", str ); } } /* scale models */ for( i = 0; i < numBSPModels; i++ ) { VectorScale( bspModels[ i ].mins, scale, bspModels[ i ].mins ); VectorScale( bspModels[ i ].maxs, scale, bspModels[ i ].maxs ); } /* scale nodes */ for( i = 0; i < numBSPNodes; i++ ) { VectorScale( bspNodes[ i ].mins, scale, bspNodes[ i ].mins ); VectorScale( bspNodes[ i ].maxs, scale, bspNodes[ i ].maxs ); } /* scale leafs */ for( i = 0; i < numBSPLeafs; i++ ) { VectorScale( bspLeafs[ i ].mins, scale, bspLeafs[ i ].mins ); VectorScale( bspLeafs[ i ].maxs, scale, bspLeafs[ i ].maxs ); } /* scale drawverts */ for( i = 0; i < numBSPDrawVerts; i++ ) VectorScale( bspDrawVerts[ i ].xyz, scale, bspDrawVerts[ i ].xyz ); /* scale planes */ for( i = 0; i < numBSPPlanes; i++ ) bspPlanes[ i ].dist *= scale; /* scale gridsize */ GetVectorForKey( &entities[ 0 ], "gridsize", vec ); if( (vec[ 0 ] + vec[ 1 ] + vec[ 2 ]) == 0.0f ) VectorCopy( gridSize, vec ); VectorScale( vec, scale, vec ); sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] ); SetKeyValue( &entities[ 0 ], "gridsize", str ); /* write the bsp */ UnparseEntities(); StripExtension( source ); DefaultExtension( source, "_s.bsp" ); Sys_Printf( "Writing %s\n", source ); WriteBSPFile( source ); /* return to sender */ return 0; }
/* ================ Entity_Parse If onlypairs is set, the classname info will not be looked up, and the entity will not be added to the global list. Used for parsing the project. ================ */ entity_t *Entity_Parse (qboolean onlypairs, brush_t* pList) { entity_t *ent; eclass_t *e; brush_t *b; vec3_t mins, maxs; epair_t *ep; qboolean has_brushes; #ifdef SOF float scale; #endif if (!GetToken (true)) return NULL; if (strcmp (token, "{") ) Error ("ParseEntity: { not found"); ent = (entity_t*)qmalloc (sizeof(*ent)); ent->brushes.onext = ent->brushes.oprev = &ent->brushes; do { if (!GetToken (true)) { Warning ("ParseEntity: EOF without closing brace"); return NULL; } if (!strcmp (token, "}") ) break; if (!strcmp (token, "{") ) { b = Brush_Parse (); if (b != NULL) { b->owner = ent; // add to the end of the entity chain b->onext = &ent->brushes; b->oprev = ent->brushes.oprev; ent->brushes.oprev->onext = b; ent->brushes.oprev = b; } else { break; } } else { ep = ParseEpair (); { // update: the original code here may have been simple, but it meant that every map load/save // the key/value pair fields were reversed in the save file, which messes up SourceSafe when it // tries to delta the two versions during check-in... -slc #if 0 ep->next = ent->epairs; ent->epairs = ep; #else // join this onto the END of the chain instead... // if (ent->epairs == NULL) // special case for if there isn't a chain yet... :-) { ep->next = ent->epairs; ent->epairs = ep; } else { for (epair_t* ep2 = ent->epairs ; ep2 ; ep2=ep2->next) { if (ep2->next == NULL) { // found the end, so... // ep2->next = ep; ep->next = NULL; break; } } } #endif } } } while (1); if (onlypairs) return ent; if (ent->brushes.onext == &ent->brushes) has_brushes = false; else has_brushes = true; GetVectorForKey (ent, "origin", ent->origin); e = Eclass_ForName (ValueForKey (ent, "classname"), has_brushes); ent->eclass = e; if (e->fixedsize) { // fixed size entity if (ent->brushes.onext != &ent->brushes) { printf ("Warning: Fixed size entity with brushes\n"); #if 0 while (ent->brushes.onext != &ent->brushes) { // FIXME: this will free the entity and crash! Brush_Free (b); } #endif ent->brushes.next = ent->brushes.prev = &ent->brushes; } // create a custom brush VectorAdd (e->mins, ent->origin, mins); VectorAdd (e->maxs, ent->origin, maxs); float a = 0; if (strnicmp(e->name, "misc_model",10) == 0) { char* p = ValueForKey(ent, "model"); if (p != NULL && strlen(p) > 0) { vec3_t vMin, vMax; a = FloatForKey (ent, "angle"); gEntityToSetBoundsOf = ent; if (GetCachedModel(ent, p, vMin, vMax)) { // create a custom brush VectorAdd (ent->md3Class->mins, ent->origin, mins); VectorAdd (ent->md3Class->maxs, ent->origin, maxs); } } } #ifdef SOF if (strnicmp(e->name, "misc_", 5) == 0 || strnicmp(e->name, "light_", 6) == 0 || strnicmp(e->name, "m_", 2) == 0 || strnicmp(e->name, "item_weapon_", 12)== 0 || strnicmp(e->name, "item_ammo_", 10)== 0 ) a = FloatForKey (ent, "angle"); #endif b = Brush_Create (mins, maxs, &e->texdef); /////// b->owner = ent; b->onext = ent->brushes.onext; b->oprev = &ent->brushes; ent->brushes.onext->oprev = b; ent->brushes.onext = b; /////// Brush_Build(b); #ifdef SOF scale = FloatForKey (ent, "scale"); if (scale) { Brush_Scale2(e, b, scale, ent->origin,false); } #endif // if (a) // { // vec3_t vAngle; // vAngle[0] = vAngle[1] = 0; // vAngle[2] = a; // Brush_Rotate(b, vAngle, ent->origin, false); // } /* b->owner = ent; b->onext = ent->brushes.onext; b->oprev = &ent->brushes; ent->brushes.onext->oprev = b; ent->brushes.onext = b; */ // do this AFTER doing the brush stuff just above, so don't join to the other "if (a)"... // if (a) { // pick any old value to rotate away to, then back from, to avoid 0/360 weirdness on key-compares // SetKeyValue(ent, "angle", "0", false); // false = no tracking, ie just set the angle and nothing else SetKeyValue(ent, "angle", va("%g",a), true); // true = do tracking, ie actually do the brush rotate } } else { // brush entity if (ent->brushes.next == &ent->brushes) printf ("Warning: Brush entity with no brushes\n"); } // add all the brushes to the main list if (pList) { for (b=ent->brushes.onext ; b != &ent->brushes ; b=b->onext) { b->next = pList->next; pList->next->prev = b; b->prev = pList; pList->next = b; } } return ent; }
static void PopulateTraceNodes( void ){ int i, m, frame, castShadows; float temp; entity_t *e; const char *value; picoModel_t *model; vec3_t origin, scale, angles; m4x4_t transform; /* add worldspawn triangles */ m4x4_identity( transform ); PopulateWithBSPModel( &bspModels[ 0 ], transform ); /* walk each entity list */ for ( i = 1; i < numEntities; i++ ) { /* get entity */ e = &entities[ i ]; /* get shadow flags */ castShadows = ENTITY_CAST_SHADOWS; GetEntityShadowFlags( e, NULL, &castShadows, NULL ); /* early out? */ if ( !castShadows ) { continue; } /* get entity origin */ GetVectorForKey( e, "origin", origin ); /* get scale */ scale[ 0 ] = scale[ 1 ] = scale[ 2 ] = 1.0f; temp = FloatForKey( e, "modelscale" ); if ( temp != 0.0f ) { scale[ 0 ] = scale[ 1 ] = scale[ 2 ] = temp; } value = ValueForKey( e, "modelscale_vec" ); if ( value[ 0 ] != '\0' ) { sscanf( value, "%f %f %f", &scale[ 0 ], &scale[ 1 ], &scale[ 2 ] ); } /* get "angle" (yaw) or "angles" (pitch yaw roll) */ angles[ 0 ] = angles[ 1 ] = angles[ 2 ] = 0.0f; angles[ 2 ] = FloatForKey( e, "angle" ); value = ValueForKey( e, "angles" ); if ( value[ 0 ] != '\0' ) { sscanf( value, "%f %f %f", &angles[ 1 ], &angles[ 2 ], &angles[ 0 ] ); } /* set transform matrix (thanks spog) */ m4x4_identity( transform ); m4x4_pivoted_transform_by_vec3( transform, origin, angles, eXYZ, scale, vec3_origin ); /* hack: Stable-1_2 and trunk have differing row/column major matrix order this transpose is necessary with Stable-1_2 uncomment the following line with old m4x4_t (non 1.3/spog_branch) code */ //% m4x4_transpose( transform ); /* get model */ value = ValueForKey( e, "model" ); /* switch on model type */ switch ( value[ 0 ] ) { /* no model */ case '\0': break; /* bsp model */ case '*': m = atoi( &value[ 1 ] ); if ( m <= 0 || m >= numBSPModels ) { continue; } PopulateWithBSPModel( &bspModels[ m ], transform ); break; /* external model */ default: frame = 0; if ( strcmp( "", ValueForKey( e, "_frame" ) ) ) { frame = IntForKey( e, "_frame" ); } else if ( strcmp( "", ValueForKey( e, "frame" ) ) ) { frame = IntForKey( e, "frame" ); } model = LoadModel( value, frame ); if ( model == NULL ) { continue; } PopulateWithPicoModel( castShadows, model, transform ); continue; } /* get model2 */ value = ValueForKey( e, "model2" ); /* switch on model type */ switch ( value[ 0 ] ) { /* no model */ case '\0': break; /* bsp model */ case '*': m = atoi( &value[ 1 ] ); if ( m <= 0 || m >= numBSPModels ) { continue; } PopulateWithBSPModel( &bspModels[ m ], transform ); break; /* external model */ default: frame = IntForKey( e, "_frame2" ); model = LoadModel( value, frame ); if ( model == NULL ) { continue; } PopulateWithPicoModel( castShadows, model, transform ); continue; } } }
void EmitStaticProps() { CreateInterfaceFn physicsFactory = GetPhysicsFactory(); if ( physicsFactory ) { s_pPhysCollision = (IPhysicsCollision *)physicsFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL ); if( !s_pPhysCollision ) return; } // Generate a list of lighting origins, and strip them out int i; for ( i = 0; i < num_entities; ++i) { char* pEntity = ValueForKey(&entities[i], "classname"); if (!Q_strcmp(pEntity, "info_lighting")) { s_LightingInfo.AddToTail(i); } } // Emit specifically specified static props for ( i = 0; i < num_entities; ++i) { char* pEntity = ValueForKey(&entities[i], "classname"); if (!strcmp(pEntity, "static_prop") || !strcmp(pEntity, "prop_static")) { StaticPropBuild_t build; GetVectorForKey( &entities[i], "origin", build.m_Origin ); GetAnglesForKey( &entities[i], "angles", build.m_Angles ); build.m_pModelName = ValueForKey( &entities[i], "model" ); build.m_Solid = IntForKey( &entities[i], "solid" ); build.m_Skin = IntForKey( &entities[i], "skin" ); build.m_FadeMaxDist = FloatForKey( &entities[i], "fademaxdist" ); build.m_Flags = 0;//IntForKey( &entities[i], "spawnflags" ) & STATIC_PROP_WC_MASK; if (IntForKey( &entities[i], "disableshadows" ) == 1) { build.m_Flags |= STATIC_PROP_NO_SHADOW; } if (IntForKey( &entities[i], "disablevertexlighting" ) == 1) { build.m_Flags |= STATIC_PROP_NO_PER_VERTEX_LIGHTING; } if (IntForKey( &entities[i], "disableselfshadowing" ) == 1) { build.m_Flags |= STATIC_PROP_NO_SELF_SHADOWING; } if (IntForKey( &entities[i], "screenspacefade" ) == 1) { build.m_Flags |= STATIC_PROP_SCREEN_SPACE_FADE; } const char *pKey = ValueForKey( &entities[i], "fadescale" ); if ( pKey && pKey[0] ) { build.m_flForcedFadeScale = FloatForKey( &entities[i], "fadescale" ); } else { build.m_flForcedFadeScale = 1; } build.m_FadesOut = (build.m_FadeMaxDist > 0); build.m_pLightingOrigin = ValueForKey( &entities[i], "lightingorigin" ); if (build.m_FadesOut) { build.m_FadeMinDist = FloatForKey( &entities[i], "fademindist" ); if (build.m_FadeMinDist < 0) { build.m_FadeMinDist = build.m_FadeMaxDist; } } else { build.m_FadeMinDist = 0; } AddStaticPropToLump( build ); // strip this ent from the .bsp file entities[i].epairs = 0; } } // Strip out lighting origins; has to be done here because they are used when // static props are made for ( i = s_LightingInfo.Count(); --i >= 0; ) { // strip this ent from the .bsp file entities[s_LightingInfo[i]].epairs = 0; } SetLumpData( ); }