/* =========== AddRegionBrushes a regioned map will have temp walls put up at the region boundary =========== */ void AddRegionBrushes (void) { vec3_t mins, maxs; int i; texdef_t td; if (!region_active) return; memset (&td, 0, sizeof(td)); //strcpy (td.name, "REGION"); td.SetName("REGION"); mins[0] = region_mins[0] - 16; maxs[0] = region_mins[0] + 1; mins[1] = region_mins[1] - 16; maxs[1] = region_maxs[1] + 16; mins[2] = MIN_WORLD_COORD; maxs[2] = MAX_WORLD_COORD; region_sides[0] = Brush_Create (mins, maxs, &td); mins[0] = region_maxs[0] - 1; maxs[0] = region_maxs[0] + 16; region_sides[1] = Brush_Create (mins, maxs, &td); mins[0] = region_mins[0] - 16; maxs[0] = region_maxs[0] + 16; mins[1] = region_mins[1] - 16; maxs[1] = region_mins[1] + 1; region_sides[2] = Brush_Create (mins, maxs, &td); mins[1] = region_maxs[1] - 1; maxs[1] = region_maxs[1] + 16; region_sides[3] = Brush_Create (mins, maxs, &td); for (i=0 ; i<4 ; i++) { Brush_AddToList (region_sides[i], &selected_brushes); Entity_LinkBrush (world_entity, region_sides[i]); Brush_Build( region_sides[i] ); } }
// creates a dummy brush in the active brushes list // FIXME : is this one really USED ? void WINAPI QERApp_CreateBrush(vec3_t vMin, vec3_t vMax) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); brush_t* pBrush = Brush_Create(vMin, vMax, &g_qeglobals.d_texturewin.texdef); Entity_LinkBrush (world_entity, pBrush); Brush_Build(pBrush); Brush_AddToList (pBrush, &active_brushes); Select_Brush(pBrush); Sys_UpdateWindows(W_ALL); }
/* ======================================================================================================================= AddRegionBrushes a regioned map will have temp walls put up at the region boundary ======================================================================================================================= */ void AddRegionBrushes(void) { idVec3 mins, maxs; int i; texdef_t td; if (!region_active) { return; } memset(&td, 0, sizeof(td)); td = g_qeglobals.d_texturewin.texdef; // strcpy (td.name, "REGION"); td.SetName("textures/REGION"); const int REGION_WIDTH = 1024; mins[0] = region_mins[0] - REGION_WIDTH; maxs[0] = region_mins[0] + 1; mins[1] = region_mins[1] - REGION_WIDTH; maxs[1] = region_maxs[1] + REGION_WIDTH; mins[2] = MIN_WORLD_COORD; maxs[2] = MAX_WORLD_COORD; region_sides[0] = Brush_Create(mins, maxs, &td); mins[0] = region_maxs[0] - 1; maxs[0] = region_maxs[0] + REGION_WIDTH; region_sides[1] = Brush_Create(mins, maxs, &td); mins[0] = region_mins[0] - REGION_WIDTH; maxs[0] = region_maxs[0] + REGION_WIDTH; mins[1] = region_mins[1] - REGION_WIDTH; maxs[1] = region_mins[1] + 1; region_sides[2] = Brush_Create(mins, maxs, &td); mins[1] = region_maxs[1] - 1; maxs[1] = region_maxs[1] + REGION_WIDTH; region_sides[3] = Brush_Create(mins, maxs, &td); mins = region_mins; maxs = region_maxs; maxs[2] = mins[2] + REGION_WIDTH; region_sides[4] = Brush_Create(mins, maxs, &td); mins = region_mins; maxs = region_maxs; mins[2] = maxs[2] - REGION_WIDTH; region_sides[5] = Brush_Create(mins, maxs, &td); for (i = 0; i < 6; i++) { Brush_AddToList(region_sides[i], &selected_brushes); Entity_LinkBrush(world_entity, region_sides[i]); Brush_Build(region_sides[i]); } }
/* ============== NewBrushDrag ============== */ void NewBrushDrag (int x, int y) { vec3_t mins, maxs, junk; int i; float temp; brush_t *n; if (!DragDelta (x,y, junk)) return; // delete the current selection if (selected_brushes.next != &selected_brushes) Brush_Free (selected_brushes.next); XY_ToGridPoint (pressx, pressy, mins); mins[2] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom_z/g_qeglobals.d_gridsize)); XY_ToGridPoint (x, y, maxs); maxs[2] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top_z/g_qeglobals.d_gridsize)); if (maxs[2] <= mins[2]) maxs[2] = mins[2] + g_qeglobals.d_gridsize; for (i=0 ; i<3 ; i++) { if (mins[i] == maxs[i]) return; // don't create a degenerate brush if (mins[i] > maxs[i]) { temp = mins[i]; mins[i] = maxs[i]; maxs[i] = temp; } } n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef); if (!n) return; Brush_AddToList (n, &selected_brushes); Entity_LinkBrush (world_entity, n); Brush_Build( n ); // Sys_UpdateWindows (W_ALL); Sys_UpdateWindows (W_XY| W_CAMERA); }
brush_t *AddBrushForTerrain( terrainMesh_t *pm, bool bLinkToWorld ) { int j; vec3_t vMin; vec3_t vMax; brush_t *b; face_t *f; // calculate the face normals Terrain_CalcNormals( pm ); // find the farthest points in x,y,z Terrain_CalcBounds( pm, vMin, vMax ); for( j = 0; j < 3; j++ ) { if ( vMin[ j ] == vMax[ j ] ) { vMin[ j ] -= 4; vMax[ j ] += 4; } } b = Brush_Create( vMin, vMax, &pm->heightmap->tri.texdef ); for( f = b->brush_faces; f != NULL; f = f->next ) { // copy the texdef to the brush faces texdef f->texdef = pm->heightmap->tri.texdef; } // FIXME: this entire type of linkage needs to be fixed b->pTerrain = pm; b->terrainBrush = true; pm->pSymbiot = b; pm->bSelected = false; pm->bDirty = true; pm->nListID = -1; if ( bLinkToWorld ) { Brush_AddToList( b, &active_brushes ); Entity_LinkBrush( world_entity, b ); Brush_Build( b, true ); } return b; }
Brush *BrushTemplate_CreateCylinder (const BrushTemplate_Cylinder *pTemplate) { double CurrentXDiameter, CurrentZDiameter; double DeltaXDiameter, DeltaZDiameter; double CurrentXOffset, CurrentZOffset; double DeltaXOffset, DeltaZOffset, sqrcheck; double EllipseZ; int NumVerticalBands, HBand, VBand; int VertexCount=0; geVec3d *Verts, *TopPoints; geVec3d Current, Final, Delta; geXForm3d YRotation; FaceList *fl; Face *f; Brush *b; NumVerticalBands = (int)(pTemplate->VerticalStripes); if (NumVerticalBands < 3) { return NULL; } Verts =(geVec3d *)geRam_Allocate(sizeof(geVec3d)*NumVerticalBands * 2); TopPoints =(geVec3d *)geRam_Allocate(sizeof(geVec3d)*NumVerticalBands); fl =FaceList_Create(NumVerticalBands + 2); if(!Verts || !TopPoints ||!fl) { return NULL; } geXForm3d_SetIdentity(&YRotation); geXForm3d_SetYRotation(&YRotation, (M_PI * 2.0f)/(geFloat)NumVerticalBands); // Start with the top of cylinder CurrentXDiameter =pTemplate->TopXSize; CurrentZDiameter =pTemplate->TopZSize; DeltaXDiameter =(pTemplate->BotXSize - pTemplate->TopXSize); DeltaZDiameter =(pTemplate->BotZSize - pTemplate->TopZSize); // Get the offset amounts CurrentXOffset =pTemplate->TopXOffset; CurrentZOffset =pTemplate->TopZOffset; DeltaXOffset =(pTemplate->BotXOffset - pTemplate->TopXOffset); DeltaZOffset =(pTemplate->BotZOffset - pTemplate->TopZOffset); // Get the band positions and deltas geVec3d_Set(&Current, (float)(pTemplate->TopXSize / 2), (float)(pTemplate->YSize / 2), 0.0); geVec3d_Set(&Delta, (float)((pTemplate->BotXSize / 2) - Current.X), (float)(-(pTemplate->YSize/2) - Current.Y), 0.0); for(HBand = 0;HBand <= 1;HBand++) { Final = Current; for(VBand = 0;VBand < NumVerticalBands;VBand++) { // Get the elliptical Z value // (x^2/a^2) + (z^2/b^2) = 1 // z = sqrt(b^2(1 - x^2/a^2)) sqrcheck=( ((CurrentZDiameter/2)*(CurrentZDiameter/2)) * (1.0 - (Final.X*Final.X) / ( (CurrentXDiameter/2)*(CurrentXDiameter/2) )) ); if(sqrcheck <0.0) sqrcheck=0.0; EllipseZ = sqrt(sqrcheck); // Check if we need to negate this thing if(VBand > (NumVerticalBands/2)) EllipseZ = -EllipseZ; geVec3d_Set ( &Verts[VertexCount], (float)(Final.X + CurrentXOffset), Final.Y, (float)(EllipseZ + CurrentZOffset) ); VertexCount++; // Rotate the point around the Y to get the next vertical band geXForm3d_Rotate(&YRotation, &Final, &Final); } CurrentXDiameter +=DeltaXDiameter; CurrentZDiameter +=DeltaZDiameter; CurrentXOffset +=DeltaXOffset; CurrentZOffset +=DeltaZOffset; geVec3d_Add(&Current, &Delta, &Current); } for(VBand=0;VBand < NumVerticalBands;VBand++) { TopPoints[VBand] =Verts[VBand]; } f =Face_Create(NumVerticalBands, TopPoints, 0); if(f) { if(pTemplate->Solid > 1) { Face_SetFixedHull(f, GE_TRUE); } FaceList_AddFace(fl, f); } for(VBand=NumVerticalBands-1, HBand=0;VBand >=0;VBand--, HBand++) { TopPoints[HBand] =Verts[VBand + NumVerticalBands]; } f =Face_Create(NumVerticalBands, TopPoints, 0); if(f) { if(pTemplate->Solid > 1) { Face_SetFixedHull(f, GE_TRUE); } FaceList_AddFace(fl, f); } // Generate the polygons for(HBand = 0;HBand < 1;HBand++) { for(VBand = 0;VBand < NumVerticalBands;VBand++) { TopPoints[3] =Verts[(HBand * NumVerticalBands) + VBand]; TopPoints[2] =Verts[(HBand * NumVerticalBands) + ((VBand + 1) % NumVerticalBands)]; TopPoints[1] =Verts[((HBand + 1) * NumVerticalBands) + ((VBand + 1) % NumVerticalBands)]; TopPoints[0] =Verts[((HBand + 1) * NumVerticalBands) + VBand]; f =Face_Create(4, TopPoints, 0); if(f) { FaceList_AddFace(fl, f); } } } geRam_Free(Verts); geRam_Free(TopPoints); if(!pTemplate->Solid) { b =Brush_Create(BRUSH_LEAF, fl, NULL); if(b) { Brush_SetSubtract(b, pTemplate->TCut); } return b; } else { BrushList *bl =BrushList_Create(); Brush *bh, *bm; b =Brush_Create(BRUSH_LEAF, fl, NULL); if(b) { Brush_SetHollow(b, GE_TRUE); Brush_SetHullSize(b, (float)pTemplate->Thickness); bh =Brush_CreateHollowFromBrush(b); if(bh) { Brush_SetHollowCut(bh, GE_TRUE); BrushList_Append(bl, b); BrushList_Append(bl, bh); bm =Brush_Create(BRUSH_MULTI, NULL, bl); if(bm) { Brush_SetHollow(bm, GE_TRUE); Brush_SetSubtract(bm, pTemplate->TCut); Brush_SetHullSize(bm, (float)pTemplate->Thickness); return bm; } } else { Brush_Destroy(&b); BrushList_Destroy(&bl); } } else { BrushList_Destroy(&bl); } } return NULL; }
Brush *BrushTemplate_CreateCone (const BrushTemplate_Cone *pTemplate) { int index, BottomCount; geVec3d StartPoint, CurPoint, OldPoint, OuterFocus; geVec3d FaceVerts[3], *BottomVerts; FaceList *fl; Face *f; Brush *b; double CurAngle; double AngleDeltaDegrees = 360.0f/(float)pTemplate->VerticalStrips; double AngleDelta = UNITS_DEGREES_TO_RADIANS (AngleDeltaDegrees); fl =FaceList_Create(pTemplate->VerticalStrips + 1); geVec3d_Set (&OuterFocus, 0, (float)(pTemplate->Height/2), 0); geVec3d_Set (&StartPoint, (float)(pTemplate->Width/2), (float)-(pTemplate->Height/2), 0); CurPoint =OldPoint =StartPoint; BottomVerts =(geVec3d *)geRam_Allocate (sizeof(geVec3d) * pTemplate->VerticalStrips); BottomVerts[0] =CurPoint; CurAngle =BottomCount =0; for( index = 1; index < pTemplate->VerticalStrips; index++ ) { // Rotate around to create our successive points... CurAngle += AngleDelta; geVec3d_Set ( &CurPoint, (float)(( StartPoint.X * cos( CurAngle ) ) +( StartPoint.Z * sin( CurAngle ) )), StartPoint.Y, (float)(( StartPoint.Z * cos( CurAngle ) ) -( StartPoint.X * sin( CurAngle ) )) ); FaceVerts[2] =OuterFocus; FaceVerts[1] =OldPoint; FaceVerts[0] =CurPoint; f =Face_Create(3, FaceVerts, 0); FaceList_AddFace(fl, f); OldPoint =CurPoint; // Assign the current point to bottom plane... BottomVerts[++BottomCount] =CurPoint; } // Create the final polygon... CurAngle += AngleDelta; geVec3d_Set ( &CurPoint, (float)(( StartPoint.X * cos( CurAngle ) ) + ( StartPoint.Z * sin( CurAngle ) )), StartPoint.Y, (float)(( StartPoint.Z * cos( CurAngle ) ) - ( StartPoint.X * sin( CurAngle ) )) ); FaceVerts[2] =OuterFocus; FaceVerts[1] =OldPoint; FaceVerts[0] =CurPoint; f =Face_Create(3, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } f =Face_Create(pTemplate->VerticalStrips, BottomVerts, 0); if(f) { if(pTemplate->Style > 1) //default to hollow (if they make hollow later) { Face_SetFixedHull(f, GE_TRUE); } FaceList_AddFace(fl, f); } geRam_Free(BottomVerts); if(!pTemplate->Style) { b =Brush_Create(BRUSH_LEAF, fl, NULL); if(b) { Brush_SetSubtract(b, pTemplate->TCut); } return b; } else { BrushList *bl =BrushList_Create(); Brush *bh, *bm; b =Brush_Create(BRUSH_LEAF, fl, NULL); if(b) { Brush_SetHollow(b, GE_TRUE); Brush_SetHullSize(b, (float)pTemplate->Thickness); bh =Brush_CreateHollowFromBrush(b); if(bh) { Brush_SetHollowCut(bh, GE_TRUE); BrushList_Append(bl, b); BrushList_Append(bl, bh); bm =Brush_Create(BRUSH_MULTI, NULL, bl); if(bm) { Brush_SetHollow(bm, GE_TRUE); Brush_SetSubtract(bm, pTemplate->TCut); Brush_SetHullSize(bm, (float)pTemplate->Thickness); return bm; } } else { Brush_Destroy(&b); BrushList_Destroy(&bl); } } else { BrushList_Destroy(&bl); } } return NULL; }
Brush *BrushTemplate_CreateBox (const BrushTemplate_Box *pTemplate) { //revisit for error handling when merged geVec3d Verts[8]; geVec3d FaceVerts[4]; FaceList *fl; Face *f; Brush *b; fl =FaceList_Create(6); // Vertices 0 to 3 are the 4 corners of the top face geVec3d_Set (&Verts[0], (float)-(pTemplate->XSizeTop/2), (float)(pTemplate->YSize/2), (float)-(pTemplate->ZSizeTop/2)); geVec3d_Set (&Verts[1], (float)-(pTemplate->XSizeTop/2), (float)(pTemplate->YSize/2), (float)(pTemplate->ZSizeTop/2)); geVec3d_Set (&Verts[2], (float)(pTemplate->XSizeTop/2), (float)(pTemplate->YSize/2), (float)(pTemplate->ZSizeTop/2)); geVec3d_Set (&Verts[3], (float)(pTemplate->XSizeTop/2), (float)(pTemplate->YSize/2), (float)-(pTemplate->ZSizeTop/2)); // Vertices 4 to 7 are the 4 corners of the bottom face geVec3d_Set (&Verts[4], (float)-(pTemplate->XSizeBot/2), (float)-(pTemplate->YSize/2), (float)-(pTemplate->ZSizeBot/2)); geVec3d_Set (&Verts[5], (float)(pTemplate->XSizeBot/2), (float)-(pTemplate->YSize/2), (float)-(pTemplate->ZSizeBot/2)); geVec3d_Set (&Verts[6], (float)(pTemplate->XSizeBot/2), (float)-(pTemplate->YSize/2), (float)(pTemplate->ZSizeBot/2)); geVec3d_Set (&Verts[7], (float)-(pTemplate->XSizeBot/2), (float)-(pTemplate->YSize/2), (float)(pTemplate->ZSizeBot/2)); FaceVerts[3] =Verts[0]; FaceVerts[2] =Verts[1]; FaceVerts[1] =Verts[2]; FaceVerts[0] =Verts[3]; f =Face_Create(4, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } FaceVerts[3] =Verts[4]; FaceVerts[2] =Verts[5]; FaceVerts[1] =Verts[6]; FaceVerts[0] =Verts[7]; f =Face_Create(4, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } FaceVerts[3] =Verts[1]; FaceVerts[2] =Verts[7]; FaceVerts[1] =Verts[6]; FaceVerts[0] =Verts[2]; f =Face_Create(4, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } FaceVerts[3] =Verts[0]; FaceVerts[2] =Verts[3]; FaceVerts[1] =Verts[5]; FaceVerts[0] =Verts[4]; f =Face_Create(4, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } FaceVerts[3] =Verts[0]; FaceVerts[2] =Verts[4]; FaceVerts[1] =Verts[7]; FaceVerts[0] =Verts[1]; f =Face_Create(4, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } FaceVerts[3] =Verts[3]; FaceVerts[2] =Verts[2]; FaceVerts[1] =Verts[6]; FaceVerts[0] =Verts[5]; f =Face_Create(4, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } if(!pTemplate->Solid) { b =Brush_Create(BRUSH_LEAF, fl, NULL); if(b) { Brush_SetSubtract(b, pTemplate->TCut); Brush_SetSheet (b, pTemplate->TSheet); } return b; } else { // hollow brush BrushList *bl =BrushList_Create(); Brush *bh, *bm; b =Brush_Create(BRUSH_LEAF, fl, NULL); if(b) { Brush_SetHollow(b, GE_TRUE); Brush_SetHullSize(b, (float)pTemplate->Thickness); bh =Brush_CreateHollowFromBrush(b); if(bh) { Brush_SetHollowCut(bh, GE_TRUE); BrushList_Append(bl, b); BrushList_Append(bl, bh); bm =Brush_Create(BRUSH_MULTI, NULL, bl); if(bm) { Brush_SetHollow(bm, GE_TRUE); Brush_SetSubtract(bm, pTemplate->TCut); Brush_SetHullSize(bm, (float)pTemplate->Thickness); return bm; } } else { Brush_Destroy(&b); BrushList_Destroy(&bl); } } else { BrushList_Destroy(&bl); } } return NULL; }
Brush *BrushTemplate_CreateArch (const BrushTemplate_Arch *pTemplate) { Brush *b, *b2; BrushList *MBList =BrushList_Create(); FaceList *fl; Face *f; geVec3d FaceVerts[4]; int i, NumSlits =pTemplate->NumSlits; int NumCrossSections =NumSlits + 2; geFloat Thickness =pTemplate->Thickness; geFloat Width =pTemplate->Width; geFloat InnerRadius =pTemplate->Radius; // geFloat WallSize =pTemplate->WallSize; double StartAngleDegrees =pTemplate->StartAngle; double EndAngleDegrees =pTemplate->EndAngle; double AngleDelta =0; double CurAngle =0; double StartAngle =Units_DegreesToRadians (StartAngleDegrees); double EndAngle =Units_DegreesToRadians (EndAngleDegrees); double Temp; geVec3d TopInnerPoint; geVec3d TopOuterPoint; geVec3d FinalTopInnerPoint; geVec3d FinalTopOuterPoint; geVec3d FinalBottomInnerPoint; geVec3d FinalBottomOuterPoint; geVec3d OldTopInner; geVec3d OldTopOuter; geVec3d OldBottomInner; geVec3d OldBottomOuter; //If angles are equal, we have an empty shape... if(StartAngle==EndAngle) { return NULL; } // Put the angles in order... if(StartAngle > EndAngle) { Temp =StartAngle; StartAngle =EndAngle; EndAngle =Temp; } geVec3d_Set(&TopInnerPoint, (float)InnerRadius, 0.0, (float)(Width / 2)); geVec3d_Set(&TopOuterPoint, (float)(InnerRadius + Thickness), 0.0, (float)(Width / 2)); AngleDelta =(EndAngle - StartAngle)/(NumCrossSections - 1); CurAngle =StartAngle + AngleDelta; // Create first cross section of 4 vertices ( outer face @ start angle)... geVec3d_Set ( &FinalTopInnerPoint, (float)(( TopInnerPoint.X * cos( StartAngle ) ) - ( TopInnerPoint.Y * sin( StartAngle ) )), (float)(( TopInnerPoint.X * sin( StartAngle ) ) + ( TopInnerPoint.Y * cos( StartAngle ) )), TopInnerPoint.Z ); geVec3d_Set ( &FinalTopOuterPoint, (float)(( TopOuterPoint.X * cos( StartAngle ) ) - ( TopInnerPoint.Y * sin( StartAngle ) )), (float)(( TopOuterPoint.X * sin( StartAngle ) ) + ( TopInnerPoint.Y * cos( StartAngle ) )), TopOuterPoint.Z ); FinalBottomInnerPoint =FinalTopInnerPoint; FinalBottomInnerPoint.Z =-FinalTopInnerPoint.Z; FinalBottomOuterPoint =FinalTopOuterPoint; FinalBottomOuterPoint.Z =-FinalTopOuterPoint.Z; OldTopInner =FinalTopInnerPoint; OldTopOuter =FinalTopOuterPoint; OldBottomInner =FinalBottomInnerPoint; OldBottomOuter =FinalBottomOuterPoint; //Create the other cross sections and assign verts to polys after each... for(i=0;i < (NumCrossSections-1);i++) { geVec3d_Set ( &FinalTopInnerPoint, (float)(( TopInnerPoint.X * cos( CurAngle ) ) - ( TopInnerPoint.Y * sin( CurAngle ) )), (float)(( TopInnerPoint.X * sin( CurAngle ) ) + ( TopInnerPoint.Y * cos( CurAngle ) )), TopInnerPoint.Z ); geVec3d_Set ( &FinalTopOuterPoint, (float)(( TopOuterPoint.X * cos( CurAngle ) ) - ( TopInnerPoint.Y * sin( CurAngle ) )), (float)(( TopOuterPoint.X * sin( CurAngle ) ) + ( TopInnerPoint.Y * cos( CurAngle ) )), TopOuterPoint.Z ); FinalBottomInnerPoint = FinalTopInnerPoint; FinalBottomInnerPoint.Z = -FinalTopInnerPoint.Z; FinalBottomOuterPoint = FinalTopOuterPoint; FinalBottomOuterPoint.Z = -FinalTopOuterPoint.Z; CurAngle += AngleDelta; fl =FaceList_Create(6); //Assign points to the 4 outer poly faces... //Top face... FaceVerts[0] =FinalTopInnerPoint; FaceVerts[1] =FinalTopOuterPoint; FaceVerts[2] =OldTopOuter; FaceVerts[3] =OldTopInner; f =Face_Create(4, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } // Bottom face... FaceVerts[3] =FinalBottomInnerPoint; FaceVerts[2] =FinalBottomOuterPoint; FaceVerts[1] =OldBottomOuter; FaceVerts[0] =OldBottomInner; f =Face_Create(4, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } // Inner side face... FaceVerts[0] =FinalTopInnerPoint; FaceVerts[1] =OldTopInner; FaceVerts[2] =OldBottomInner; FaceVerts[3] =FinalBottomInnerPoint; f =Face_Create(4, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } // Outer side face... FaceVerts[3] =FinalTopOuterPoint; FaceVerts[2] =OldTopOuter; FaceVerts[1] =OldBottomOuter; FaceVerts[0] =FinalBottomOuterPoint; f =Face_Create(4, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } //make the end faces FaceVerts[0] =OldTopOuter; FaceVerts[1] =OldBottomOuter; FaceVerts[2] =OldBottomInner; FaceVerts[3] =OldTopInner; f =Face_Create(4, FaceVerts, 0); if(f) { if(pTemplate->Style < 2) //default to hollow (if they make hollow later) { if(i) { Face_SetFixedHull(f, GE_TRUE); } } else { Face_SetFixedHull(f, GE_TRUE); } FaceList_AddFace(fl, f); } FaceVerts[3] =FinalTopOuterPoint; FaceVerts[2] =FinalBottomOuterPoint; FaceVerts[1] =FinalBottomInnerPoint; FaceVerts[0] =FinalTopInnerPoint; f =Face_Create(4, FaceVerts, 0); if(f) { if(pTemplate->Style < 2) //default to hollow (if they make hollow later) { if(i < (NumCrossSections-2)) { Face_SetFixedHull(f, GE_TRUE); } } else { Face_SetFixedHull(f, GE_TRUE); } FaceList_AddFace(fl, f); } if(!pTemplate->Style) { b2 =Brush_Create(BRUSH_LEAF, fl, NULL); if(b2) { Brush_SetSubtract(b2, pTemplate->TCut); } BrushList_Append(MBList, b2); } else { BrushList *bl =BrushList_Create(); Brush *bh, *bm; b2 =Brush_Create(BRUSH_LEAF, fl, NULL); if(b2) { Brush_SetHollow(b2, GE_TRUE); Brush_SetHullSize(b2, pTemplate->WallSize); bh =Brush_CreateHollowFromBrush(b2); if(bh) { Brush_SetHollowCut(bh, GE_TRUE); BrushList_Append(bl, b2); BrushList_Append(bl, bh); bm =Brush_Create(BRUSH_MULTI, NULL, bl); if(bm) { Brush_SetHollow(bm, GE_TRUE); Brush_SetSubtract(bm, pTemplate->TCut); Brush_SetHullSize(bm, pTemplate->WallSize); BrushList_Append(MBList, bm); } } else { Brush_Destroy(&b2); BrushList_Destroy(&bl); } } else { BrushList_Destroy(&bl); } } // Set old points... OldTopInner =FinalTopInnerPoint; OldTopOuter =FinalTopOuterPoint; OldBottomInner =FinalBottomInnerPoint; OldBottomOuter =FinalBottomOuterPoint; } b =Brush_Create(BRUSH_MULTI, NULL, MBList); if(b) { Brush_SetSubtract(b, pTemplate->TCut); } return b; }
/* =========== AddRegionBrushes a regioned map will have temp walls put up at the region boundary \todo TODO TTimo old implementation of region brushes we still add them straight in the worldspawn and take them out after the map is saved with the new implementation we should be able to append them in a temporary manner to the data we pass to the map module =========== */ void AddRegionBrushes( void ){ vec3_t mins, maxs; int i; texdef_t td; if ( !region_active ) { #ifdef _DEBUG Sys_FPrintf( SYS_WRN, "Unexpected AddRegionBrushes call.\n" ); #endif return; } memset( &td, 0, sizeof( td ) ); td.SetName( SHADER_NOT_FOUND ); // set mins VectorSet( mins, region_mins[0] - 32, region_mins[1] - 32, region_mins[2] - 32 ); // vary maxs for ( i = 0; i < 3; i++ ) { VectorSet( maxs, region_maxs[0] + 32, region_maxs[1] + 32, region_maxs[2] + 32 ); maxs[i] = region_mins[i]; region_sides[i] = Brush_Create( mins, maxs, &td ); } // set maxs VectorSet( maxs, region_maxs[0] + 32, region_maxs[1] + 32, region_maxs[2] + 32 ); // vary mins for ( i = 0; i < 3; i++ ) { VectorSet( mins, region_mins[0] - 32, region_mins[1] - 32, region_mins[2] - 32 ); mins[i] = region_maxs[i]; region_sides[i + 3] = Brush_Create( mins, maxs, &td ); } // this is a safe check, but it should not really happen anymore vec3_t vOrig; VectorSet( vOrig, (int)g_pParentWnd->GetCamWnd()->Camera()->origin[0], (int)g_pParentWnd->GetCamWnd()->Camera()->origin[1], (int)g_pParentWnd->GetCamWnd()->Camera()->origin[2] ); for ( i = 0 ; i < 3 ; i++ ) { if ( vOrig[i] > region_maxs[i] || vOrig[i] < region_mins[i] ) { Sys_FPrintf( SYS_ERR, "Camera is NOT in the region, it's likely that the region won't compile correctly\n" ); } } // write the info_playerstart region_startpoint = Entity_Alloc(); SetKeyValue( region_startpoint, "classname", "info_player_start" ); region_startpoint->eclass = Eclass_ForName( "info_player_start", false ); char sTmp[1024]; sprintf( sTmp, "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2] ); SetKeyValue( region_startpoint, "origin", sTmp ); sprintf( sTmp, "%d", (int)g_pParentWnd->GetCamWnd()->Camera()->angles[YAW] ); SetKeyValue( region_startpoint, "angle", sTmp ); // empty array of children region_startpoint->pData = new CPtrArray; }
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++; } } } }
entity_t *Entity_PostParse(entity_t *ent, brush_t *pList) { bool has_brushes; eclass_t *e; brush_t *b; idVec3 mins, maxs, zero; idBounds bo; zero.Zero(); Entity_SetCurveData( ent ); if (ent->brushes.onext == &ent->brushes) { has_brushes = false; } else { has_brushes = true; } bool needsOrigin = !GetVectorForKey(ent, "origin", ent->origin); const char *pModel = ValueForKey(ent, "model"); const char *cp = ValueForKey(ent, "classname"); if (strlen(cp)) { e = Eclass_ForName(cp, has_brushes); } else { const char *cp2 = ValueForKey(ent, "name"); if (strlen(cp2)) { char buff[1024]; strcpy(buff, cp2); int len = strlen(buff); while ((isdigit(buff[len-1]) || buff[len-1] == '_') && len > 0) { buff[len-1] = '\0'; len--; } e = Eclass_ForName(buff, has_brushes); SetKeyValue(ent, "classname", buff, false); } else { e = Eclass_ForName("", has_brushes); } } idStr str; if (e->defArgs.GetString("model", "", str) && e->entityModel == NULL) { e->entityModel = gameEdit->ANIM_GetModelFromEntityDef( &e->defArgs ); } ent->eclass = e; bool hasModel = EntityHasModel(ent); if (hasModel) { ent->eclass->defArgs.GetString("model", "", str); if (str.Length()) { hasModel = false; ent->epairs.Delete("model"); } } if (e->nShowFlags & ECLASS_WORLDSPAWN) { ent->origin.Zero(); needsOrigin = false; ent->epairs.Delete( "model" ); } else if (e->nShowFlags & ECLASS_LIGHT) { if (GetVectorForKey(ent, "light_origin", ent->lightOrigin)) { GetMatrixForKey(ent, "light_rotation", ent->lightRotation); ent->trackLightOrigin = true; } else if (hasModel) { SetKeyValue(ent, "light_origin", ValueForKey(ent, "origin")); ent->lightOrigin = ent->origin; if (GetMatrixForKey(ent, "rotation", ent->lightRotation)) { SetKeyValue(ent, "light_rotation", ValueForKey(ent, "rotation")); } ent->trackLightOrigin = true; } } else if ( e->nShowFlags & ECLASS_ENV ) { // need to create an origin from the bones here idVec3 org; idAngles ang; bo.Clear(); bool hasBody = false; const idKeyValue *arg = ent->epairs.MatchPrefix( "body ", NULL ); while ( arg ) { sscanf( arg->GetValue(), "%f %f %f %f %f %f", &org.x, &org.y, &org.z, &ang.pitch, &ang.yaw, &ang.roll ); bo.AddPoint( org ); arg = ent->epairs.MatchPrefix( "body ", arg ); hasBody = true; } if (hasBody) { ent->origin = bo.GetCenter(); } } if (e->fixedsize || hasModel) // fixed size entity { if (ent->brushes.onext != &ent->brushes) { for (b = ent->brushes.onext; b != &ent->brushes; b = b->onext) { b->entityModel = true; } } if (hasModel) { // model entity idRenderModel *modelHandle = renderModelManager->FindModel( pModel ); if ( dynamic_cast<idRenderModelPrt*>( modelHandle ) || dynamic_cast<idRenderModelLiquid*>( modelHandle ) ) { bo.Zero(); bo.ExpandSelf( 12.0f ); } else { bo = modelHandle->Bounds( NULL ); } VectorCopy(bo[0], mins); VectorCopy(bo[1], maxs); for (int i = 0; i < 3; i++) { if (mins[i] == maxs[i]) { mins[i]--; maxs[i]++; } } VectorAdd(mins, ent->origin, mins); VectorAdd(maxs, ent->origin, maxs); b = Brush_Create(mins, maxs, &e->texdef); b->modelHandle = modelHandle; float yaw = 0; bool convertAngles = GetFloatForKey(ent, "angle", &yaw); extern void Brush_Rotate(brush_t *b, idMat3 matrix, idVec3 origin, bool bBuild); extern void Brush_Rotate(brush_t *b, idVec3 rot, idVec3 origin, bool bBuild); if (convertAngles) { idVec3 rot(0, 0, yaw); Brush_Rotate(b, rot, ent->origin, false); } if (GetMatrixForKey(ent, "rotation", ent->rotation)) { idBounds bo2; bo2.FromTransformedBounds(bo, ent->origin, ent->rotation); b->owner = ent; Brush_Resize(b, bo2[0], bo2[1]); } Entity_LinkBrush(ent, b); } if (!hasModel || (ent->eclass->nShowFlags & ECLASS_LIGHT && hasModel)) { // create a custom brush if (ent->trackLightOrigin) { mins = e->mins + ent->lightOrigin; maxs = e->maxs + ent->lightOrigin; } else { mins = e->mins + ent->origin; maxs = e->maxs + ent->origin; } b = Brush_Create(mins, maxs, &e->texdef); GetMatrixForKey(ent, "rotation", ent->rotation); Entity_LinkBrush(ent, b); b->trackLightOrigin = ent->trackLightOrigin; if ( e->texdef.name == NULL ) { brushprimit_texdef_t bp; texdef_t td; td.SetName( ent->eclass->defMaterial ); Brush_SetTexture( b, &td, &bp, false ); } } } else // brush entity { if (ent->brushes.next == &ent->brushes) { printf("Warning: Brush entity with no brushes\n"); } if (!needsOrigin) { idStr cn = ValueForKey(ent, "classname"); idStr name = ValueForKey(ent, "name"); idStr model = ValueForKey(ent, "model"); if (cn.Icmp("func_static") == 0) { if (name.Icmp(model) == 0) { needsOrigin = true; } } } if (needsOrigin) { idVec3 mins, maxs, mid; int i; char text[32]; mins[0] = mins[1] = mins[2] = 999999; maxs[0] = maxs[1] = maxs[2] = -999999; // add in the origin for (b = ent->brushes.onext; b != &ent->brushes; b = b->onext) { Brush_Build(b, true, false, false); for (i = 0; i < 3; i++) { if (b->mins[i] < mins[i]) { mins[i] = b->mins[i]; } if (b->maxs[i] > maxs[i]) { maxs[i] = b->maxs[i]; } } } for (i = 0; i < 3; i++) { ent->origin[i] = (mins[i] + ((maxs[i] - mins[i]) / 2)); } sprintf(text, "%i %i %i", (int)ent->origin[0], (int)ent->origin[1], (int)ent->origin[2]); SetKeyValue(ent, "origin", text); } if (!(e->nShowFlags & ECLASS_WORLDSPAWN)) { if (e->defArgs.FindKey("model") == NULL && (pModel == NULL || (pModel && strlen(pModel) == 0))) { SetKeyValue(ent, "model", ValueForKey(ent, "name")); } } else { DeleteKey(ent, "origin"); } } // 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; } } FixFloats(&ent->epairs); return ent; }
/* ======================================================================================================================= Entity_Create Creates a new entity out of the selected_brushes list. If the entity class is fixed size, the brushes are only used to find a midpoint. Otherwise, the brushes have their ownership transfered to the new entity. ======================================================================================================================= */ entity_t *Entity_Create(eclass_t *c, bool forceFixed) { entity_t *e; brush_t *b; idVec3 mins, maxs, origin; char text[32]; texdef_t td; brushprimit_texdef_t bp; // check to make sure the brushes are ok for (b = selected_brushes.next; b != &selected_brushes; b = b->next) { if (b->owner != world_entity) { Sys_Status("Entity NOT created, brushes not all from world\n"); Sys_Beep(); return NULL; } } idStr str; if (c->defArgs.GetString("model", "", str) && c->entityModel == NULL) { c->entityModel = gameEdit->ANIM_GetModelFromEntityDef( &c->defArgs ); } // create it e = Entity_New(); e->brushes.onext = e->brushes.oprev = &e->brushes; e->eclass = c; e->epairs.Copy(c->args); SetKeyValue(e, "classname", c->name); Entity_Name(e, false); // add the entity to the entity list Entity_AddToList(e, &entities); if (c->fixedsize) { // // just use the selection for positioning b = selected_brushes.next; for (i=0 ; // i<3 ; i++) { e->origin[i] = b->mins[i] - c->mins[i]; } // Select_GetMid(e->origin); VectorCopy(e->origin, origin); // create a custom brush VectorAdd(c->mins, e->origin, mins); VectorAdd(c->maxs, e->origin, maxs); b = Brush_Create(mins, maxs, &c->texdef); Entity_LinkBrush(e, b); if (c->defMaterial.Length()) { td.SetName(c->defMaterial); Brush_SetTexture(b, &td, &bp, false); } // delete the current selection Select_Delete(); // select the new brush b->next = b->prev = &selected_brushes; selected_brushes.next = selected_brushes.prev = b; Brush_Build(b); } else { Select_GetMid(origin); // change the selected brushes over to the new entity for (b = selected_brushes.next; b != &selected_brushes; b = b->next) { Entity_UnlinkBrush(b); Entity_LinkBrush(e, b); Brush_Build(b); // so the key brush gets a name if (c->defMaterial.Length()) { td.SetName(c->defMaterial); Brush_SetTexture(b, &td, &bp, false); } } //for (int i = 0; i < 3; i++) { // origin[i] = vMin[i] + vMax[i] * 0.5; //} if (!forceFixed) { SetKeyValue(e, "model", ValueForKey(e, "name")); } } sprintf(text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]); SetKeyValue(e, "origin", text); VectorCopy(origin, e->origin); Sys_UpdateWindows(W_ALL); return e; }
/* ============ Entity_Create Creates a new entity out of the selected_brushes list. If the entity class is fixed size, the brushes are only used to find a midpoint. Otherwise, the brushes have their ownershi[ transfered to the new entity. ============ */ entity_t *Entity_Create (eclass_t *c) { entity_t *e; brush_t *b; vec3_t mins, maxs; int i; // check to make sure the brushes are ok for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) if (b->owner != world_entity) { Sys_Printf ("Entity NOT created, brushes not all from world\n"); Sys_Beep (); return NULL; } // create it e = (entity_t*)qmalloc(sizeof(*e)); e->brushes.onext = e->brushes.oprev = &e->brushes; e->eclass = c; SetKeyValue (e, "classname", c->name); // add the entity to the entity list e->next = entities.next; entities.next = e; e->next->prev = e; e->prev = &entities; if (c->fixedsize) { // // just use the selection for positioning // b = selected_brushes.next; for (i=0 ; i<3 ; i++) e->origin[i] = b->mins[i] - c->mins[i]; // create a custom brush VectorAdd (c->mins, e->origin, mins); VectorAdd (c->maxs, e->origin, maxs); b = Brush_Create (mins, maxs, &c->texdef); Entity_LinkBrush (e, b); // delete the current selection Select_Delete (); // select the new brush b->next = b->prev = &selected_brushes; selected_brushes.next = selected_brushes.prev = b; Brush_Build( b ); } else { // // change the selected brushes over to the new entity // for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) { Entity_UnlinkBrush (b); Entity_LinkBrush (e, b); Brush_Build( b ); // so the key brush gets a name } } Sys_UpdateWindows (W_ALL); return e; }
/* ================ 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; }
Brush *BrushTemplate_CreateSpheroid (const BrushTemplate_Spheroid *pTemplate) { double z, ring_radius, r, dz, t, dt; int vcnt, HBand, VBand; geVec3d *sv, FaceVerts[4]; FaceList *fl; Face *f; Brush *b; if((pTemplate->HorizontalBands < 2) || (pTemplate->VerticalBands < 3)) { return GE_FALSE ; } fl =FaceList_Create((pTemplate->HorizontalBands)* pTemplate->VerticalBands); sv =(geVec3d *)geRam_Allocate(sizeof(geVec3d) * (((pTemplate->HorizontalBands-1) * pTemplate->VerticalBands)+2)); r =pTemplate->YSize; vcnt =0; geVec3d_Set (&sv[vcnt], 0.0f, pTemplate->YSize, 0.0f); vcnt++; dz =2.0*r/(double)(pTemplate->HorizontalBands-1); for(z=(-r)+dz/2.0; z<(r-dz/2.0+dz/4.0); z+=dz) { ring_radius =sqrt(r*r - z*z); dt =PI2 /(double)(pTemplate->VerticalBands); for(t=0.0;t < PI2-(dt*0.5);t+=dt) { sv[vcnt].X =(float)(sin(t) * ring_radius); sv[vcnt].Z =(float)(cos(t) * ring_radius); sv[vcnt++].Y=(float)(-z); } } sv[vcnt].X =0.0f; sv[vcnt].Y =(float)(-pTemplate->YSize); sv[vcnt++].Z=0.0f; for(VBand=0;VBand < pTemplate->VerticalBands;VBand++) { FaceVerts[0] =sv[0]; FaceVerts[1] =sv[(((1 + VBand) % pTemplate->VerticalBands) + 1)]; FaceVerts[2] =sv[(VBand % pTemplate->VerticalBands)+1]; f =Face_Create(3, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } } for(HBand=1;HBand < (pTemplate->HorizontalBands-1);HBand++) { for(VBand=0;VBand < pTemplate->VerticalBands;VBand++) { FaceVerts[0] =sv[(((HBand-1)*pTemplate->VerticalBands)+1)+VBand]; FaceVerts[1] =sv[(((HBand-1)*pTemplate->VerticalBands)+1)+((VBand+1)%pTemplate->VerticalBands)]; FaceVerts[2] =sv[((HBand*pTemplate->VerticalBands)+1)+((VBand+1)%pTemplate->VerticalBands)]; FaceVerts[3] =sv[((HBand*pTemplate->VerticalBands)+1)+VBand]; f =Face_Create(4, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } } } for(VBand=0;VBand < pTemplate->VerticalBands;VBand++) { FaceVerts[0] =sv[1+((pTemplate->HorizontalBands-2)*pTemplate->VerticalBands)+VBand]; FaceVerts[1] =sv[1+((pTemplate->HorizontalBands-2)*pTemplate->VerticalBands)+((VBand+1)%pTemplate->VerticalBands)]; FaceVerts[2] =sv[((pTemplate->HorizontalBands-1)*pTemplate->VerticalBands)+1]; f =Face_Create(3, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } } geRam_Free(sv); if(!pTemplate->Solid) { b =Brush_Create(BRUSH_LEAF, fl, NULL); if(b) { Brush_SetSubtract(b, pTemplate->TCut); } return b; } else { BrushList *bl =BrushList_Create(); Brush *bh, *bm; b =Brush_Create(BRUSH_LEAF, fl, NULL); if(b) { Brush_SetHollow(b, GE_TRUE); Brush_SetHullSize(b, (float)pTemplate->Thickness); bh =Brush_CreateHollowFromBrush(b); if(bh) { Brush_SetHollowCut(bh, GE_TRUE); BrushList_Append(bl, b); BrushList_Append(bl, bh); bm =Brush_Create(BRUSH_MULTI, NULL, bl); if(bm) { Brush_SetHollow(bm, GE_TRUE); Brush_SetSubtract(bm, pTemplate->TCut); Brush_SetHullSize(bm, (float)pTemplate->Thickness); return bm; } } else { Brush_Destroy(&b); BrushList_Destroy(&bl); } } else { BrushList_Destroy(&bl); } } return NULL; }
Brush *BrushTemplate_CreateStaircase (const BrushTemplate_Staircase *pTemplate) { int i; geFloat HalfWidth = (geFloat)(pTemplate->Width/2); geFloat HalfHeight = (geFloat)(pTemplate->Height/2); geFloat HalfLength = (geFloat)(pTemplate->Length/2); Brush *b, *b2; BrushList *MBList =BrushList_Create(); FaceList *fl; Face *f; geVec3d v, FaceVerts[4]; if( pTemplate->MakeRamp ) { fl =FaceList_Create(5); geVec3d_Set (&(FaceVerts[3]), -HalfWidth, -HalfHeight, HalfLength); geVec3d_Set (&(FaceVerts[2]), HalfWidth, -HalfHeight, HalfLength); geVec3d_Set (&(FaceVerts[1]), HalfWidth, HalfHeight, HalfLength); geVec3d_Set (&(FaceVerts[0]), -HalfWidth, HalfHeight, HalfLength); f =Face_Create(4, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } geVec3d_Set (&(FaceVerts[3]), HalfWidth, -HalfHeight, HalfLength); geVec3d_Set (&(FaceVerts[2]), -HalfWidth, -HalfHeight, HalfLength); geVec3d_Set (&(FaceVerts[1]), -HalfWidth, -HalfHeight, -HalfLength); geVec3d_Set (&(FaceVerts[0]), HalfWidth, -HalfHeight, -HalfLength); f =Face_Create(4, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } geVec3d_Set (&(FaceVerts[3]), -HalfWidth, HalfHeight, HalfLength); geVec3d_Set (&(FaceVerts[2]), HalfWidth, HalfHeight, HalfLength); geVec3d_Set (&(FaceVerts[1]), HalfWidth, -HalfHeight, -HalfLength); geVec3d_Set (&(FaceVerts[0]), -HalfWidth, -HalfHeight, -HalfLength); f =Face_Create(4, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } geVec3d_Set (&(FaceVerts[2]), HalfWidth, HalfHeight, HalfLength); geVec3d_Set (&(FaceVerts[1]), HalfWidth, -HalfHeight, HalfLength); geVec3d_Set (&(FaceVerts[0]), HalfWidth, -HalfHeight, -HalfLength); f =Face_Create(3, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } geVec3d_Set (&(FaceVerts[0]), -HalfWidth, HalfHeight, HalfLength); geVec3d_Set (&(FaceVerts[1]), -HalfWidth, -HalfHeight, HalfLength); geVec3d_Set (&(FaceVerts[2]), -HalfWidth, -HalfHeight, -HalfLength); f =Face_Create(3, FaceVerts, 0); if(f) { FaceList_AddFace(fl, f); } b =Brush_Create(BRUSH_LEAF, fl, NULL); } else { float StairYSize =(geFloat)pTemplate->Height/(geFloat)pTemplate->NumberOfStairs; float DZ =(geFloat)pTemplate->Length/(geFloat)pTemplate->NumberOfStairs; float ZSize =(geFloat)pTemplate->Length; BrushTemplate_Box BoxTemplate; BoxTemplate.Solid = 0; BoxTemplate.TCut = pTemplate->TCut; BoxTemplate.Thickness = 0.0f; BoxTemplate.XSizeTop = pTemplate->Width; BoxTemplate.XSizeBot = pTemplate->Width; BoxTemplate.YSize = StairYSize; for(i=0;i < pTemplate->NumberOfStairs;i++) { BoxTemplate.ZSizeTop = ZSize; BoxTemplate.ZSizeBot = ZSize; BoxTemplate.TSheet = GE_FALSE; // nasty, nasty, nasty b2 = BrushTemplate_CreateBox (&BoxTemplate); ZSize -=DZ; geVec3d_Set(&v, 0.0f, i*StairYSize, (i*DZ)/2); Brush_Move(b2, &v); BrushList_Append(MBList, b2); } b =Brush_Create(BRUSH_MULTI, NULL, MBList); } if(b) { Brush_SetSubtract(b, pTemplate->TCut); } return b; }
/*!\todo Possibly make the import Undo-friendly by calling Undo_End for new brushes and ents */ void Map_ImportEntities( CPtrArray *ents, bool bAddSelected = false ){ int num_ents, num_brushes; CPtrArray *brushes; vec3_t mins, maxs; entity_t *e; brush_t *b; face_t *f; int i,j; GPtrArray *new_ents = g_ptr_array_new(); g_qeglobals.bPrimitBrushes = false; brush_t *pBrushList = ( bAddSelected ) ? &selected_brushes : &active_brushes; bool bDoneBPCheck = false; g_qeglobals.bNeedConvert = false; // HACK: find out if this map file was a BP one // check the first brush in the file that is NOT a patch // this will not be necessary when we allow both formats in the same file num_ents = ents->GetSize(); for ( i = 0; !bDoneBPCheck && i < num_ents; i++ ) { e = (entity_t*)ents->GetAt( i ); brushes = (CPtrArray*)e->pData; num_brushes = brushes->GetSize(); for ( j = 0; !bDoneBPCheck && j < num_brushes; j++ ) { /*!todo Allow mixing texdef formats per-face. */ b = (brush_t *)brushes->GetAt( j ); if ( b->patchBrush ) { continue; } bDoneBPCheck = true; int BP_param = -1; if ( b->bBrushDef && !g_qeglobals.m_bBrushPrimitMode ) { BP_param = 0; } else if ( !b->bBrushDef && g_qeglobals.m_bBrushPrimitMode ) { BP_param = 1; } if ( BP_param != -1 ) { switch ( BP_MessageBox( BP_param ) ) { case 0: Map_FreeEntities( ents ); return; case 1: g_qeglobals.bNeedConvert = true; break; case 2: g_qeglobals.bNeedConvert = false; break; } } } } // process the entities into the world geometry num_ents = ents->GetSize(); for ( i = 0; i < num_ents; i++ ) { num_brushes = 0; e = (entity_t*)ents->GetAt( i ); brushes = (CPtrArray*)e->pData; num_brushes = brushes->GetSize(); // link brushes into entity for ( j = 0; j < num_brushes; j++ ) { Entity_LinkBrush( e, (brush_t *)brushes->GetAt( j ) ); g_qeglobals.d_parsed_brushes++; } brushes->RemoveAll(); delete brushes; e->pData = NULL; // set entity origin GetVectorForKey( e, "origin", e->origin ); // set entity eclass /*!\todo Make SetKeyValue check for "classname" change and assign appropriate eclass */ e->eclass = Eclass_ForName( ValueForKey( e, "classname" ), ( e->brushes.onext != &e->brushes ) ); // go through all parsed brushes and build stuff for ( b = e->brushes.onext; b != &e->brushes; b = b->onext ) { for ( f = b->brush_faces; f != NULL; f = f->next ) { f->pShader = QERApp_Shader_ForName( f->texdef.GetName() ); f->d_texture = f->pShader->getTexture(); } // when brushes are in final state, build the planes and windings // NOTE: also converts BP brushes if g_qeglobals.bNeedConvert is true Brush_Build( b ); } //#define TERRAIN_HACK #undef TERRAIN_HACK #ifdef TERRAIN_HACK if ( ( strcmp( ValueForKey( e, "terrain" ),"1" ) == 0 && strcmp( e->eclass->name,"func_group" ) == 0 ) ) { // two aux pointers to the shaders used in the terrain entity // we don't keep refcount on them since they are only temporary // this avoids doing expensive lookups by name for all faces IShader *pTerrainShader, *pCaulk; pTerrainShader = NULL; pCaulk = QERApp_Shader_ForName( SHADER_CAULK ); for ( b = e->brushes.onext; b != &e->brushes; b = b->onext ) { if ( pTerrainShader == NULL ) { for ( f = b->brush_faces; f != NULL; f = f->next ) if ( strcmp( f->texdef.GetName(), SHADER_CAULK ) != 0 ) { pTerrainShader = f->pShader; } } if ( pTerrainShader ) { for ( f = b->brush_faces; f != NULL; f = f->next ) { if ( strcmp( f->texdef.GetName(), SHADER_CAULK ) != 0 ) { // not caulk Face_SetShader( f, pTerrainShader->getName() ); } else{ Face_SetShader( f, pCaulk->getName() ); } } } else{ Sys_FPrintf( SYS_WRN, "WARNING: no terrain shader found for brush\n" ); } } } #endif #define PATCH_HACK #ifdef PATCH_HACK for ( b = e->brushes.onext; b != &e->brushes; b = b->onext ) { // patch hack, to be removed when dependency on brush_faces is removed if ( b->patchBrush ) { Patch_CalcBounds( b->pPatch, mins, maxs ); for ( int i = 0; i < 3; i++ ) { if ( (int)mins[i] == (int)maxs[i] ) { mins[i] -= 4; maxs[i] += 4; } } Brush_Resize( b, mins, maxs ); Brush_Build( b ); } } #endif // add brush for fixedsize entity if ( e->eclass->fixedsize ) { vec3_t mins, maxs; VectorAdd( e->eclass->mins, e->origin, mins ); VectorAdd( e->eclass->maxs, e->origin, maxs ); b = Brush_Create( mins, maxs, &e->eclass->texdef ); Entity_LinkBrush( e, b ); Brush_Build( b ); } for ( b = e->brushes.onext; b != &e->brushes; b = b->onext ) Brush_AddToList( b, pBrushList ); if ( strcmp( e->eclass->name, "worldspawn" ) == 0 ) { if ( world_entity ) { while ( e->brushes.onext != &e->brushes ) { b = e->brushes.onext; Entity_UnlinkBrush( b ); Entity_LinkBrush( world_entity, b ); } Entity_Free( e ); } else { world_entity = e; } } else if ( strcmp( e->eclass->name, "group_info" ) == 0 ) { // it's a group thing! Group_Add( e ); Entity_Free( e ); } else { // fix target/targetname collisions if ( ( g_PrefsDlg.m_bDoTargetFix ) && ( strcmp( ValueForKey( e, "target" ), "" ) != 0 ) ) { GPtrArray *t_ents = g_ptr_array_new(); entity_t *e_target; const char *target = ValueForKey( e, "target" ); qboolean bCollision = FALSE; // check the current map entities for an actual collision for ( e_target = entities.next; e_target != &entities; e_target = e_target->next ) { if ( !strcmp( target, ValueForKey( e_target, "target" ) ) ) { bCollision = TRUE; // make sure the collision is not between two imported entities for ( j = 0; j < (int)new_ents->len; j++ ) { if ( e_target == g_ptr_array_index( new_ents, j ) ) { bCollision = FALSE; } } } } // find the matching targeted entity(s) if ( bCollision ) { for ( j = num_ents - 1; j > 0; j-- ) { e_target = (entity_t*)ents->GetAt( j ); if ( e_target != NULL && e_target != e ) { const char *targetname = ValueForKey( e_target, "targetname" ); if ( ( targetname != NULL ) && ( strcmp( target, targetname ) == 0 ) ) { g_ptr_array_add( t_ents, (gpointer)e_target ); } } } if ( t_ents->len > 0 ) { // link the first to get a unique target/targetname Entity_Connect( e, (entity_t*)g_ptr_array_index( t_ents,0 ) ); // set the targetname of the rest of them manually for ( j = 1; j < (int)t_ents->len; j++ ) SetKeyValue( (entity_t*)g_ptr_array_index( t_ents, j ), "targetname", ValueForKey( e, "target" ) ); } g_ptr_array_free( t_ents, FALSE ); } } // add the entity to the end of the entity list Entity_AddToList( e, &entities ); g_qeglobals.d_num_entities++; // keep a list of ents added to avoid testing collisions against them g_ptr_array_add( new_ents, (gpointer)e ); } } g_ptr_array_free( new_ents, FALSE ); ents->RemoveAll(); g_qeglobals.bNeedConvert = false; }