/* GenSurf plugin for GtkRadiant Copyright (C) 2001 David Hyde, Loki software and qeradiant.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "gensurf.h" double xmin,xmax,ymin,ymax,zmin,zmax; double backface; extern double dh, dv; FILE *fmap; XYZ xyz[MAX_ROWS + 1][MAX_ROWS + 1]; int contents; int surface[3]; #include "iundo.h" #include "refcounted_ptr.h" #include #include #include #include #include "scenelib.h" scene::Node* h_func_group; scene::Node* h_worldspawn; //============================================================= // Hydra : snap-to-grid begin double CalculateSnapValue( double value ){ long snapvalue; // simple uncomplicated snapping, rounding both UP and DOWN to the nearest // grid unit. if ( SnapToGrid > 0 ) { snapvalue = (int)value / SnapToGrid; if ( (long)value % SnapToGrid < ( SnapToGrid / 2 ) ) { // Snap Downwards if less than halfway between to grid units value = snapvalue * SnapToGrid; } else{ // Snap Upwards if more than halfway between to grid units value = ( snapvalue + 1 ) * SnapToGrid; } } return value; } // Hydra : snap-to-grid end //============================================================= bool ValidSurface(){ if ( WaveType == WAVE_BITMAP && !gbmp.colors ) { return FALSE; } if ( NH < 1 ) { return FALSE; } if ( NH > MAX_ROWS ) { return FALSE; } if ( NV < 1 ) { return FALSE; } if ( NV > MAX_ROWS ) { return FALSE; } if ( Hll >= Hur ) { return FALSE; } if ( Vll >= Vur ) { return FALSE; } return TRUE; } //============================================================= int MapPatches(){ int NH_remain; int NV_remain; int NH_patch; int NV_patch; int BrushNum = 0; int i, j, k1, k2, k3; int i0, j0, ii; char szOops[128]; dh = ( Hur - Hll ) / NH; dv = ( Vur - Vll ) / NV; // Generate control points in pp array to give desired values currently // in p array. switch ( Plane ) { case PLANE_XY0: case PLANE_XY1: k1 = 0; k2 = 1; k3 = 2; break; case PLANE_XZ0: case PLANE_XZ1: k1 = 0; k2 = 2; k3 = 1; break; case PLANE_YZ0: case PLANE_YZ1: k1 = 1; k2 = 2; k3 = 0; break; } for ( i = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++ ) { xyz[i][j].pp[k1] = xyz[i][j].p[k1]; xyz[i][j].pp[k2] = xyz[i][j].p[k2]; } } for ( i = 0; i <= NH; i += 2 ) { for ( j = 0; j <= NV; j += 2 ) xyz[i][j].pp[k3] = xyz[i][j].p[k3]; } for ( i = 1; i < NH; i += 2 ) { for ( j = 0; j <= NV; j += 2 ) { xyz[i][j].pp[k3] = ( 4 * xyz[i][j].p[k3] - xyz[i - 1][j].p[k3] - xyz[i + 1][j].p[k3] ) / 2; } } for ( j = 1; j < NV; j += 2 ) { for ( i = 0; i <= NH; i += 2 ) { xyz[i][j].pp[k3] = ( 4 * xyz[i][j].p[k3] - xyz[i][j - 1].p[k3] - xyz[i][j + 1].p[k3] ) / 2; } } for ( i = 1; i < NH; i += 2 ) { for ( j = 1; j < NV; j += 2 ) { xyz[i][j].pp[k3] = ( 16 * xyz[i][j].p[k3] - xyz[i - 1][j - 1].p[k3] - 2 * xyz[i][j - 1].p[k3] - xyz[i + 1][j - 1].p[k3] - 2 * xyz[i - 1][j].p[k3] - 2 * xyz[i + 1][j].p[k3] - xyz[i - 1][j + 1].p[k3] - 2 * xyz[i][j + 1].p[k3] - xyz[i + 1][j + 1].p[k3] ) / 4; } } NH_remain = NH + 1; i0 = 0; while ( NH_remain > 1 ) { if ( ( ( NH_remain - 1 ) % 14 ) == 0 ) { NH_patch = 15; } else if ( ( ( NH_remain - 1 ) % 12 ) == 0 ) { NH_patch = 13; } else if ( ( ( NH_remain - 1 ) % 10 ) == 0 ) { NH_patch = 11; } else if ( ( ( NH_remain - 1 ) % 8 ) == 0 ) { NH_patch = 9; } else if ( ( ( NH_remain - 1 ) % 6 ) == 0 ) { NH_patch = 7; } else if ( ( ( NH_remain - 1 ) % 4 ) == 0 ) { NH_patch = 5; } else if ( ( ( NH_remain - 1 ) % 2 ) == 0 ) { NH_patch = 3; } else if ( NH_remain > 16 ) { NH_patch = 7; } else if ( NH_remain > 4 ) { NH_patch = 5; } else{ NH_patch = 3; } while ( NH_patch > 3 && ( NH_patch - 1 ) * dh > 512 ) NH_patch -= 2; NH_remain -= ( NH_patch - 1 ); if ( NH_remain < 0 ) { sprintf( szOops,"Oops... screwed up with NH=%d",NH ); g_FuncTable.m_pfnMessageBox( NULL,szOops,"Uh oh" ); } NV_remain = NV + 1; j0 = 0; while ( NV_remain > 1 ) { if ( ( ( NV_remain - 1 ) % 14 ) == 0 ) { NV_patch = 15; } else if ( ( ( NV_remain - 1 ) % 12 ) == 0 ) { NV_patch = 13; } else if ( ( ( NV_remain - 1 ) % 10 ) == 0 ) { NV_patch = 11; } else if ( ( ( NV_remain - 1 ) % 8 ) == 0 ) { NV_patch = 9; } else if ( ( ( NV_remain - 1 ) % 6 ) == 0 ) { NV_patch = 7; } else if ( ( ( NV_remain - 1 ) % 4 ) == 0 ) { NV_patch = 5; } else if ( ( ( NV_remain - 1 ) % 2 ) == 0 ) { NV_patch = 3; } else if ( NV_remain > 16 ) { NV_patch = 7; } else if ( NV_remain > 4 ) { NV_patch = 5; } else{ NV_patch = 3; } while ( NV_patch > 3 && ( NV_patch - 1 ) * dh > 512 ) NV_patch -= 2; NV_remain -= ( NV_patch - 1 ); if ( NV_remain < 0 ) { sprintf( szOops,"Oops... screwed up with NV=%d",NV ); g_FuncTable.m_pfnMessageBox( NULL,szOops,"Uh oh" ); } scene::Node* patch = MakePatch(); #if 0 b->pPatch->setDims( NH_patch, NV_patch ); for ( i = 0; i < NH_patch; i++ ) { switch ( Plane ) { case PLANE_XY1: case PLANE_XZ0: case PLANE_YZ1: ii = i0 + NH_patch - 1 - i; break; default: ii = i0 + i; } for ( j = 0; j < NV_patch; j++ ) { b->pPatch->ctrlAt( COL,i,j )[0] = (float)xyz[ii][j0 + j].pp[0]; b->pPatch->ctrlAt( COL,i,j )[1] = (float)xyz[ii][j0 + j].pp[1]; b->pPatch->ctrlAt( COL,i,j )[2] = (float)xyz[ii][j0 + j].pp[2]; b->pPatch->ctrlAt( COL,i,j )[3] = (float)i; b->pPatch->ctrlAt( COL,i,j )[4] = (float)j; } } b->pPatch->UpdateCachedData(); #endif BrushNum++; j0 += NV_patch - 1; } i0 += NH_patch - 1; } return BrushNum; } //============================================================= void MapBrushes(){ char hint[128]; char skip[128]; char sidetext[64]; char surftext[64]; char surftext2[64]; char surft[64]; float Steep; vec3_t PlaneNormal,SurfNormal; vec3_t t[2]; int i, j, k; int surf; bool CheckAngle; BRUSH brush; XYZ v[8]; strcpy( surftext,Texture[Game][0] ); strcpy( sidetext,( strlen( Texture[Game][1] ) ? Texture[Game][1] : Texture[Game][0] ) ); strcpy( surftext2,( strlen( Texture[Game][2] ) ? Texture[Game][2] : Texture[Game][0] ) ); // if surftext2 is identical to surftext, there's no need to // check surface angle if ( !g_strcasecmp( surftext,surftext2 ) ) { CheckAngle = FALSE; } else { CheckAngle = TRUE; Steep = (float)cos( (double)SlantAngle / 57.2957795 ); switch ( Plane ) { case PLANE_XY0: PlaneNormal[0] = 0.; PlaneNormal[1] = 0.; PlaneNormal[2] = 1.; break; case PLANE_XY1: PlaneNormal[0] = 0.; PlaneNormal[1] = 0.; PlaneNormal[2] = -1.; break; case PLANE_XZ0: PlaneNormal[0] = 0.; PlaneNormal[1] = 1.; PlaneNormal[2] = 1.; break; case PLANE_XZ1: PlaneNormal[0] = 0.; PlaneNormal[1] = -1.; PlaneNormal[2] = 1.; break; case PLANE_YZ0: PlaneNormal[0] = 1.; PlaneNormal[1] = 0.; PlaneNormal[2] = 1.; break; case PLANE_YZ1: PlaneNormal[0] = -1.; PlaneNormal[1] = 0.; PlaneNormal[2] = 1.; break; } } OpenFuncGroup(); for ( i = 0; i < NH; i++ ) { for ( j = 0; j < NV; j++ ) { if ( ( i + j ) % 2 ) { VectorCopy( xyz[i ][j ].p, v[0].p ); switch ( Plane ) { case PLANE_XY1: case PLANE_XZ1: case PLANE_YZ1: VectorCopy( xyz[i + 1][j ].p, v[1].p ); VectorCopy( xyz[i + 1][j + 1].p, v[2].p ); break; default: VectorCopy( xyz[i + 1][j + 1].p, v[1].p ); VectorCopy( xyz[i + 1][j ].p, v[2].p ); } } else { VectorCopy( xyz[i ][j ].p, v[0].p ); switch ( Plane ) { case PLANE_XY1: case PLANE_XZ1: case PLANE_YZ1: VectorCopy( xyz[i + 1][j ].p, v[1].p ); VectorCopy( xyz[i ][j + 1].p, v[2].p ); break; default: VectorCopy( xyz[i ][j + 1].p, v[1].p ); VectorCopy( xyz[i + 1][j ].p, v[2].p ); } } VectorCopy( v[0].p,v[3].p ); VectorCopy( v[1].p,v[4].p ); VectorCopy( v[2].p,v[5].p ); switch ( Plane ) { case PLANE_XZ0: case PLANE_XZ1: v[0].p[1] = backface; v[1].p[1] = backface; v[2].p[1] = backface; break; case PLANE_YZ0: case PLANE_YZ1: v[3].p[0] = backface; v[4].p[0] = backface; v[5].p[0] = backface; break; default: v[3].p[2] = backface; v[4].p[2] = backface; v[5].p[2] = backface; } brush.Number = i * NV * 2 + j * 2; brush.NumFaces = 5; XYZtoV( &v[0],&brush.face[0].v[0] ); XYZtoV( &v[3],&brush.face[0].v[1] ); XYZtoV( &v[4],&brush.face[0].v[2] ); strcpy( brush.face[0].texture, ( strlen( Texture[Game][1] ) ? Texture[Game][1] : Texture[Game][0] ) ); brush.face[0].Shift[0] = (float)TexOffset[0]; brush.face[0].Shift[1] = (float)TexOffset[1]; brush.face[0].Rotate = 0.; brush.face[0].Scale[0] = (float)TexScale[0]; brush.face[0].Scale[1] = (float)TexScale[1]; brush.face[0].Contents = contents; brush.face[0].Surface = surface[1]; brush.face[0].Value = 0; XYZtoV( &v[1],&brush.face[1].v[0] ); XYZtoV( &v[4],&brush.face[1].v[1] ); XYZtoV( &v[5],&brush.face[1].v[2] ); strcpy( brush.face[1].texture, ( strlen( Texture[Game][1] ) ? Texture[Game][1] : Texture[Game][0] ) ); brush.face[1].Shift[0] = (float)TexOffset[0]; brush.face[1].Shift[1] = (float)TexOffset[1]; brush.face[1].Rotate = 0.; brush.face[1].Scale[0] = (float)TexScale[0]; brush.face[1].Scale[1] = (float)TexScale[1]; brush.face[1].Contents = contents; brush.face[1].Surface = surface[1]; brush.face[1].Value = 0; XYZtoV( &v[2],&brush.face[2].v[0] ); XYZtoV( &v[5],&brush.face[2].v[1] ); XYZtoV( &v[3],&brush.face[2].v[2] ); strcpy( brush.face[2].texture, ( strlen( Texture[Game][1] ) ? Texture[Game][1] : Texture[Game][0] ) ); brush.face[2].Shift[0] = (float)TexOffset[0]; brush.face[2].Shift[1] = (float)TexOffset[1]; brush.face[2].Rotate = 0.; brush.face[2].Scale[0] = (float)TexScale[0]; brush.face[2].Scale[1] = (float)TexScale[1]; brush.face[2].Contents = contents; brush.face[2].Surface = surface[1]; brush.face[2].Value = 0; if ( CheckAngle && ( Plane == PLANE_XZ0 || Plane == PLANE_XZ1 ) ) { XYZVectorSubtract( v[4].p,v[3].p,t[0] ); XYZVectorSubtract( v[5].p,v[4].p,t[1] ); CrossProduct( t[0],t[1],SurfNormal ); VectorNormalize( SurfNormal,SurfNormal ); if ( DotProduct( SurfNormal,PlaneNormal ) < Steep ) { strcpy( surft,surftext2 ); surf = surface[2]; } else { strcpy( surft,surftext ); surf = surface[0]; } } else { strcpy( surft,surftext ); surf = surface[0]; } XYZtoV( &v[3],&brush.face[3].v[0] ); XYZtoV( &v[5],&brush.face[3].v[1] ); XYZtoV( &v[4],&brush.face[3].v[2] ); strcpy( brush.face[3].texture, ( Plane == PLANE_XZ0 || Plane == PLANE_XZ1 ? surft : sidetext ) ); brush.face[3].Shift[0] = (float)TexOffset[0]; brush.face[3].Shift[1] = (float)TexOffset[1]; brush.face[3].Rotate = 0.; brush.face[3].Scale[0] = (float)TexScale[0]; brush.face[3].Scale[1] = (float)TexScale[1]; brush.face[3].Contents = contents; brush.face[3].Surface = ( Plane == PLANE_XZ0 || Plane == PLANE_XZ1 ? surf : surface[1] ); brush.face[3].Value = ( Plane == PLANE_XZ0 || Plane == PLANE_XZ1 ? ArghRad2 : 0 ); if ( CheckAngle && Plane != PLANE_XZ0 && Plane != PLANE_XZ1 ) { XYZVectorSubtract( v[2].p,v[0].p,t[0] ); XYZVectorSubtract( v[1].p,v[2].p,t[1] ); CrossProduct( t[0],t[1],SurfNormal ); VectorNormalize( SurfNormal,SurfNormal ); if ( DotProduct( SurfNormal,PlaneNormal ) < Steep ) { strcpy( surft,surftext2 ); surf = surface[2]; } else { strcpy( surft,surftext ); surf = surface[0]; } } else { strcpy( surft,surftext ); surf = surface[0]; } XYZtoV( &v[0],&brush.face[4].v[0] ); XYZtoV( &v[1],&brush.face[4].v[1] ); XYZtoV( &v[2],&brush.face[4].v[2] ); strcpy( brush.face[4].texture, ( Plane == PLANE_XZ0 || Plane == PLANE_XZ1 ? sidetext : surft ) ); brush.face[4].Shift[0] = (float)TexOffset[0]; brush.face[4].Shift[1] = (float)TexOffset[1]; brush.face[4].Rotate = 0.; brush.face[4].Scale[0] = (float)TexScale[0]; brush.face[4].Scale[1] = (float)TexScale[1]; brush.face[4].Contents = contents; brush.face[4].Surface = ( Plane == PLANE_XZ0 || Plane == PLANE_XZ1 ? surface[1] : surf ); brush.face[4].Value = ( Plane == PLANE_XZ0 || Plane == PLANE_XZ1 ? 0 : ArghRad2 ); MakeBrush( &brush ); if ( ( i + j ) % 2 ) { VectorCopy( xyz[i ][j + 1].p,v[0].p ); switch ( Plane ) { case PLANE_XY1: case PLANE_XZ1: case PLANE_YZ1: VectorCopy( xyz[i ][j ].p,v[1].p ); VectorCopy( xyz[i + 1][j + 1].p,v[2].p ); break; default: VectorCopy( xyz[i + 1][j + 1].p,v[1].p ); VectorCopy( xyz[i ][j ].p,v[2].p ); } } else { VectorCopy( xyz[i ][j + 1].p,v[0].p ); switch ( Plane ) { case PLANE_XY1: case PLANE_XZ1: case PLANE_YZ1: VectorCopy( xyz[i + 1][j ].p,v[1].p ); VectorCopy( xyz[i + 1][j + 1].p,v[2].p ); break; default: VectorCopy( xyz[i + 1][j + 1].p,v[1].p ); VectorCopy( xyz[i + 1][j ].p,v[2].p ); } } VectorCopy( v[0].p,v[3].p ); VectorCopy( v[1].p,v[4].p ); VectorCopy( v[2].p,v[5].p ); switch ( Plane ) { case PLANE_XZ0: case PLANE_XZ1: v[0].p[1] = backface; v[1].p[1] = backface; v[2].p[1] = backface; break; case PLANE_YZ0: case PLANE_YZ1: v[3].p[0] = backface; v[4].p[0] = backface; v[5].p[0] = backface; break; default: v[3].p[2] = backface; v[4].p[2] = backface; v[5].p[2] = backface; } brush.Number = i * NV * 2 + j * 2 + 1; brush.NumFaces = 5; XYZtoV( &v[0],&brush.face[0].v[0] ); XYZtoV( &v[3],&brush.face[0].v[1] ); XYZtoV( &v[4],&brush.face[0].v[2] ); strcpy( brush.face[0].texture, ( strlen( Texture[Game][1] ) ? Texture[Game][1] : Texture[Game][0] ) ); brush.face[0].Shift[0] = (float)TexOffset[0]; brush.face[0].Shift[1] = (float)TexOffset[1]; brush.face[0].Rotate = 0.; brush.face[0].Scale[0] = (float)TexScale[0]; brush.face[0].Scale[1] = (float)TexScale[1]; brush.face[0].Contents = contents; brush.face[0].Surface = surface[1]; brush.face[0].Value = 0; XYZtoV( &v[1],&brush.face[1].v[0] ); XYZtoV( &v[4],&brush.face[1].v[1] ); XYZtoV( &v[5],&brush.face[1].v[2] ); strcpy( brush.face[1].texture, ( strlen( Texture[Game][1] ) ? Texture[Game][1] : Texture[Game][0] ) ); brush.face[1].Shift[0] = (float)TexOffset[0]; brush.face[1].Shift[1] = (float)TexOffset[1]; brush.face[1].Rotate = 0.; brush.face[1].Scale[0] = (float)TexScale[0]; brush.face[1].Scale[1] = (float)TexScale[1]; brush.face[1].Contents = contents; brush.face[1].Surface = surface[1]; brush.face[1].Value = 0; XYZtoV( &v[2],&brush.face[2].v[0] ); XYZtoV( &v[5],&brush.face[2].v[1] ); XYZtoV( &v[3],&brush.face[2].v[2] ); strcpy( brush.face[2].texture, ( strlen( Texture[Game][1] ) ? Texture[Game][1] : Texture[Game][0] ) ); brush.face[2].Shift[0] = (float)TexOffset[0]; brush.face[2].Shift[1] = (float)TexOffset[1]; brush.face[2].Rotate = 0.; brush.face[2].Scale[0] = (float)TexScale[0]; brush.face[2].Scale[1] = (float)TexScale[1]; brush.face[2].Contents = contents; brush.face[2].Surface = surface[1]; brush.face[2].Value = 0; if ( CheckAngle && ( Plane == PLANE_XZ0 || Plane == PLANE_XZ1 ) ) { XYZVectorSubtract( v[4].p,v[3].p,t[0] ); XYZVectorSubtract( v[5].p,v[4].p,t[1] ); CrossProduct( t[0],t[1],SurfNormal ); VectorNormalize( SurfNormal,SurfNormal ); if ( DotProduct( SurfNormal,PlaneNormal ) < Steep ) { strcpy( surft,surftext2 ); surf = surface[2]; } else { strcpy( surft,surftext ); surf = surface[0]; } } else { strcpy( surft,surftext ); surf = surface[0]; } XYZtoV( &v[3],&brush.face[3].v[0] ); XYZtoV( &v[5],&brush.face[3].v[1] ); XYZtoV( &v[4],&brush.face[3].v[2] ); strcpy( brush.face[3].texture, ( Plane == PLANE_XZ0 || Plane == PLANE_XZ1 ? surft : sidetext ) ); brush.face[3].Shift[0] = (float)TexOffset[0]; brush.face[3].Shift[1] = (float)TexOffset[1]; brush.face[3].Rotate = 0.; brush.face[3].Scale[0] = (float)TexScale[0]; brush.face[3].Scale[1] = (float)TexScale[1]; brush.face[3].Contents = contents; brush.face[3].Surface = ( Plane == PLANE_XZ0 || Plane == PLANE_XZ1 ? surf : surface[1] ); brush.face[3].Value = ( Plane == PLANE_XZ0 || Plane == PLANE_XZ1 ? ArghRad2 : 0 ); if ( CheckAngle && Plane != PLANE_XZ0 && Plane != PLANE_XZ1 ) { XYZVectorSubtract( v[2].p,v[0].p,t[0] ); XYZVectorSubtract( v[1].p,v[2].p,t[1] ); CrossProduct( t[0],t[1],SurfNormal ); VectorNormalize( SurfNormal,SurfNormal ); if ( DotProduct( SurfNormal,PlaneNormal ) < Steep ) { strcpy( surft,surftext2 ); surf = surface[2]; } else { strcpy( surft,surftext ); surf = surface[0]; } } else { strcpy( surft,surftext ); surf = surface[0]; } XYZtoV( &v[0],&brush.face[4].v[0] ); XYZtoV( &v[1],&brush.face[4].v[1] ); XYZtoV( &v[2],&brush.face[4].v[2] ); strcpy( brush.face[4].texture, ( Plane == PLANE_XZ0 || Plane == PLANE_XZ1 ? sidetext : surft ) ); brush.face[4].Shift[0] = (float)TexOffset[0]; brush.face[4].Shift[1] = (float)TexOffset[1]; brush.face[4].Rotate = 0.; brush.face[4].Scale[0] = (float)TexScale[0]; brush.face[4].Scale[1] = (float)TexScale[1]; brush.face[4].Contents = contents; brush.face[4].Surface = ( Plane == PLANE_XZ0 || Plane == PLANE_XZ1 ? surface[1] : surf ); brush.face[4].Value = ( Plane == PLANE_XZ0 || Plane == PLANE_XZ1 ? 0 : ArghRad2 ); MakeBrush( &brush ); } } CloseFuncGroup(); if ( AddHints || GimpHints ) { int detail, i1, j1, N; double front; switch ( Game ) { case HALFLIFE: strcpy( hint,"HINT" ); strcpy( skip,"HINT" ); break; case SIN: strcpy( hint,"generic/misc/hint" ); strcpy( skip,"generic/misc/skip" ); break; case HERETIC2: strcpy( hint,"general/hint" ); strcpy( skip,"general/hint" ); // Heretic2 doesn't have a skip texture break; case KINGPIN: strcpy( hint,"common/0_hint" ); strcpy( skip,"common/0_skip" ); break; case GENESIS3D: strcpy( hint,"hint" ); strcpy( skip,"hint" ); break; case QUAKE3: strcpy( hint,"textures/common/hint" ); strcpy( skip,"textures/common/skip" ); break; default: strcpy( hint,"e1u1/hint" ); strcpy( skip,"e1u1/skip" ); } OpenFuncGroup(); if ( AddHints == 1 ) { detail = CONTENTS_DETAIL; N = 0; for ( i = 0; i < NH; i++ ) { i1 = i + 1; for ( j = 0; j < NV; j++ ) { // For detail hint brushes, no need to use a hint brush over // EVERY grid square... it would be redundant. Instead use // a checkerboard pattern if ( ( i + j ) % 2 ) { continue; } j1 = j + 1; VectorCopy( xyz[i ][j ].p, v[0].p ); switch ( Plane ) { case PLANE_XY1: case PLANE_XZ1: case PLANE_YZ1: VectorCopy( xyz[i1][j ].p, v[1].p ); VectorCopy( xyz[i1][j1].p, v[2].p ); VectorCopy( xyz[i ][j1].p, v[3].p ); break; default: VectorCopy( xyz[i ][j1].p, v[1].p ); VectorCopy( xyz[i1][j1].p, v[2].p ); VectorCopy( xyz[i1][j ].p, v[3].p ); } VectorCopy( v[0].p,v[4].p ); VectorCopy( v[1].p,v[5].p ); VectorCopy( v[2].p,v[6].p ); VectorCopy( v[3].p,v[7].p ); switch ( Plane ) { case PLANE_XY1: front = LessThan( zmin,32. ); v[4].p[2] = backface; v[5].p[2] = backface; v[6].p[2] = backface; v[7].p[2] = backface; break; case PLANE_XZ0: front = MoreThan( ymax,32. ); v[0].p[1] = backface; v[1].p[1] = backface; v[2].p[1] = backface; v[3].p[1] = backface; break; case PLANE_XZ1: front = LessThan( ymin,32. ); v[0].p[1] = backface; v[1].p[1] = backface; v[2].p[1] = backface; v[3].p[1] = backface; break; case PLANE_YZ0: front = MoreThan( xmax,32. ); v[4].p[0] = backface; v[5].p[0] = backface; v[6].p[0] = backface; v[7].p[0] = backface; break; case PLANE_YZ1: front = LessThan( xmin,32. ); v[4].p[0] = backface; v[5].p[0] = backface; v[6].p[0] = backface; v[7].p[0] = backface; break; default: front = MoreThan( zmax,32. ); v[4].p[2] = backface; v[5].p[2] = backface; v[6].p[2] = backface; v[7].p[2] = backface; } switch ( Plane ) { case PLANE_XZ0: case PLANE_XZ1: v[4].p[1] = front; v[5].p[1] = v[4].p[1]; v[6].p[1] = v[4].p[1]; v[7].p[1] = v[4].p[1]; break; case PLANE_YZ0: case PLANE_YZ1: v[0].p[0] = front; v[1].p[0] = v[0].p[0]; v[2].p[0] = v[0].p[0]; v[3].p[0] = v[0].p[0]; break; default: v[0].p[2] = front; v[1].p[2] = v[0].p[2]; v[2].p[2] = v[0].p[2]; v[3].p[2] = v[0].p[2]; } brush.NumFaces = 6; brush.Number = N; XYZtoV( &v[0],&brush.face[0].v[0] ); XYZtoV( &v[1],&brush.face[0].v[1] ); XYZtoV( &v[2],&brush.face[0].v[2] ); strcpy( brush.face[0].texture,skip ); brush.face[0].Shift[0] = 0.; brush.face[0].Shift[1] = 0.; brush.face[0].Rotate = 0.; brush.face[0].Scale[0] = 1.; brush.face[0].Scale[1] = 1.; brush.face[0].Contents = detail; brush.face[0].Surface = SURF_SKIP; brush.face[0].Value = 0; XYZtoV( &v[4],&brush.face[1].v[0] ); XYZtoV( &v[7],&brush.face[1].v[1] ); XYZtoV( &v[6],&brush.face[1].v[2] ); strcpy( brush.face[1].texture,skip ); brush.face[1].Shift[0] = 0.; brush.face[1].Shift[1] = 0.; brush.face[1].Rotate = 0.; brush.face[1].Scale[0] = 1.; brush.face[1].Scale[1] = 1.; brush.face[1].Contents = detail; brush.face[1].Surface = SURF_SKIP; brush.face[1].Value = 0; XYZtoV( &v[0],&brush.face[2].v[0] ); XYZtoV( &v[4],&brush.face[2].v[1] ); XYZtoV( &v[5],&brush.face[2].v[2] ); strcpy( brush.face[2].texture,hint ); brush.face[2].Shift[0] = 0.; brush.face[2].Shift[1] = 0.; brush.face[2].Rotate = 0.; brush.face[2].Scale[0] = 1.; brush.face[2].Scale[1] = 1.; brush.face[2].Contents = detail; brush.face[2].Surface = SURF_HINT; brush.face[2].Value = 0; XYZtoV( &v[1],&brush.face[3].v[0] ); XYZtoV( &v[5],&brush.face[3].v[1] ); XYZtoV( &v[6],&brush.face[3].v[2] ); strcpy( brush.face[3].texture,hint ); brush.face[3].Shift[0] = 0.; brush.face[3].Shift[1] = 0.; brush.face[3].Rotate = 0.; brush.face[3].Scale[0] = 1.; brush.face[3].Scale[1] = 1.; brush.face[3].Contents = detail; brush.face[3].Surface = SURF_HINT; brush.face[3].Value = 0; XYZtoV( &v[2],&brush.face[4].v[0] ); XYZtoV( &v[6],&brush.face[4].v[1] ); XYZtoV( &v[7],&brush.face[4].v[2] ); strcpy( brush.face[4].texture,hint ); brush.face[4].Shift[0] = 0.; brush.face[4].Shift[1] = 0.; brush.face[4].Rotate = 0.; brush.face[4].Scale[0] = 1.; brush.face[4].Scale[1] = 1.; brush.face[4].Contents = detail; brush.face[4].Surface = SURF_HINT; brush.face[4].Value = 0; XYZtoV( &v[3],&brush.face[5].v[0] ); XYZtoV( &v[7],&brush.face[5].v[1] ); XYZtoV( &v[4],&brush.face[5].v[2] ); strcpy( brush.face[5].texture,hint ); brush.face[5].Shift[0] = 0.; brush.face[5].Shift[1] = 0.; brush.face[5].Rotate = 0.; brush.face[5].Scale[0] = 1.; brush.face[5].Scale[1] = 1.; brush.face[5].Contents = detail; brush.face[5].Surface = SURF_HINT; brush.face[5].Value = 0; MakeBrush( &brush ); N++; } } } if ( GimpHints ) { N = 0; // these brush parameters never change brush.NumFaces = 5; for ( i = 0; i < 6; i++ ) { strcpy( brush.face[i].texture,hint ); brush.face[i].Shift[0] = 0.; brush.face[i].Shift[1] = 0.; brush.face[i].Rotate = 0.; brush.face[i].Scale[0] = 1.; brush.face[i].Scale[1] = 1.; brush.face[i].Contents = 0; brush.face[i].Surface = SURF_HINT; brush.face[i].Value = 0; } for ( i = 0; i < NH; i++ ) { for ( j = 0; j < NV; j++ ) { for ( k = 0; k < 2; k++ ) { if ( k == 0 ) { if ( ( i + j ) % 2 ) { VectorCopy( xyz[i ][j ].p, v[0].p ); switch ( Plane ) { case PLANE_XY1: case PLANE_XZ1: case PLANE_YZ1: VectorCopy( xyz[i + 1][j ].p, v[1].p ); VectorCopy( xyz[i + 1][j + 1].p, v[2].p ); break; default: VectorCopy( xyz[i + 1][j + 1].p, v[1].p ); VectorCopy( xyz[i + 1][j ].p, v[2].p ); } } else { VectorCopy( xyz[i ][j ].p, v[0].p ); switch ( Plane ) { case PLANE_XY1: case PLANE_XZ1: case PLANE_YZ1: VectorCopy( xyz[i + 1][j ].p, v[1].p ); VectorCopy( xyz[i ][j + 1].p, v[2].p ); break; default: VectorCopy( xyz[i ][j + 1].p, v[1].p ); VectorCopy( xyz[i + 1][j ].p, v[2].p ); } } } else { if ( ( i + j ) % 2 ) { VectorCopy( xyz[i ][j + 1].p,v[0].p ); switch ( Plane ) { case PLANE_XY1: case PLANE_XZ1: case PLANE_YZ1: VectorCopy( xyz[i ][j ].p,v[1].p ); VectorCopy( xyz[i + 1][j + 1].p,v[2].p ); break; default: VectorCopy( xyz[i + 1][j + 1].p,v[1].p ); VectorCopy( xyz[i ][j ].p,v[2].p ); } } else { VectorCopy( xyz[i ][j + 1].p,v[0].p ); switch ( Plane ) { case PLANE_XY1: case PLANE_XZ1: case PLANE_YZ1: VectorCopy( xyz[i + 1][j ].p,v[1].p ); VectorCopy( xyz[i + 1][j + 1].p,v[2].p ); break; default: VectorCopy( xyz[i + 1][j + 1].p,v[1].p ); VectorCopy( xyz[i + 1][j ].p,v[2].p ); } } } VectorCopy( v[0].p,v[3].p ); VectorCopy( v[1].p,v[4].p ); VectorCopy( v[2].p,v[5].p ); switch ( Plane ) { case PLANE_XY0: v[0].p[2] += HINT_OFFSET; v[1].p[2] += HINT_OFFSET; v[2].p[2] += HINT_OFFSET; // v[3].p[2] = backface; // v[4].p[2] = backface; // v[5].p[2] = backface; break; case PLANE_XY1: v[0].p[2] -= HINT_OFFSET; v[1].p[2] -= HINT_OFFSET; v[2].p[2] -= HINT_OFFSET; // v[3].p[2] = backface; // v[4].p[2] = backface; // v[5].p[2] = backface; break; case PLANE_XZ0: // v[0].p[1] = backface; // v[1].p[1] = backface; // v[2].p[1] = backface; v[3].p[1] += HINT_OFFSET; v[4].p[1] += HINT_OFFSET; v[5].p[1] += HINT_OFFSET; break; case PLANE_XZ1: // v[0].p[1] = backface; // v[1].p[1] = backface; // v[2].p[1] = backface; v[3].p[1] -= HINT_OFFSET; v[4].p[1] -= HINT_OFFSET; v[5].p[1] -= HINT_OFFSET; break; case PLANE_YZ0: v[0].p[0] += HINT_OFFSET; v[1].p[0] += HINT_OFFSET; v[2].p[0] += HINT_OFFSET; // v[3].p[0] = backface; // v[4].p[0] = backface; // v[5].p[0] = backface; break; case PLANE_YZ1: v[0].p[0] -= HINT_OFFSET; v[1].p[0] -= HINT_OFFSET; v[2].p[0] -= HINT_OFFSET; // v[3].p[0] = backface; // v[4].p[0] = backface; // v[5].p[0] = backface; break; } brush.Number = N; XYZtoV( &v[0],&brush.face[0].v[0] ); XYZtoV( &v[3],&brush.face[0].v[1] ); XYZtoV( &v[4],&brush.face[0].v[2] ); XYZtoV( &v[1],&brush.face[1].v[0] ); XYZtoV( &v[4],&brush.face[1].v[1] ); XYZtoV( &v[5],&brush.face[1].v[2] ); XYZtoV( &v[2],&brush.face[2].v[0] ); XYZtoV( &v[5],&brush.face[2].v[1] ); XYZtoV( &v[3],&brush.face[2].v[2] ); XYZtoV( &v[3],&brush.face[3].v[0] ); XYZtoV( &v[5],&brush.face[3].v[1] ); XYZtoV( &v[4],&brush.face[3].v[2] ); XYZtoV( &v[0],&brush.face[4].v[0] ); XYZtoV( &v[1],&brush.face[4].v[1] ); XYZtoV( &v[2],&brush.face[4].v[2] ); MakeBrush( &brush ); N++; } } } } // endif AddHints==1 CloseFuncGroup(); } } // end MapBrushes //============================================================= void GenerateMap(){ extern void MapOut( int,int,NODE *,TRI * ); extern bool SingleBrushSelected; int ntri; if ( !ValidSurface() ) { return; } /* ghCursorCurrent = LoadCursor(NULL,IDC_WAIT); SetCursor(ghCursorCurrent); */ #if 0 if ( SingleBrushSelected ) { g_FuncTable.m_pfnDeleteSelection(); } #endif GenerateXYZ(); ntri = NH * NV * 2; if ( Game == QUAKE3 && UsePatches != 0 ) { MapPatches(); } if ( Decimate > 0 && ( Game != QUAKE3 || UsePatches == 0 ) ) { MapOut( gNumNodes,gNumTris,gNode,gTri ); /* ghCursorCurrent = ghCursorDefault; SetCursor(ghCursorCurrent); */ return; } contents = 0; // HL doesn't have detail property if ( ( Game != HALFLIFE ) && UseDetail ) { contents += CONTENTS_DETAIL; } // HL and Q3 don't have ladder property if ( ( Game != HALFLIFE && Game != QUAKE3 ) && UseLadder ) { contents += CONTENTS_LADDER; } // Genesis requires solid property to be set explicitly if ( Game == GENESIS3D ) { contents |= CONTENTS_SOLID; } // Heretic 2 uses different sounds (in surface props) for different texture types if ( Game == HERETIC2 ) { surface[0] = GetDefSurfaceProps( Texture[Game][0] ); surface[1] = GetDefSurfaceProps( Texture[Game][1] ); surface[2] = GetDefSurfaceProps( Texture[Game][2] ); } else { surface[0] = 0; surface[1] = 0; surface[2] = 0; } if ( Game != QUAKE3 || UsePatches == 0 ) { MapBrushes(); } /* ghCursorCurrent = ghCursorDefault; SetCursor(ghCursorCurrent); */ } //============================================================= void GenerateXYZ(){ extern void MakeDecimatedMap( int *, int *, NODE * *, TRI * * ); double zl, zu; double wh, wv; int NHalfcycles; double a,v,h,ha,va; double delta, dr, rate; double range, maxrange; double r; int i, j, k, N; int i0, i1, j0, j1; int ii, jj; // FILE *f; // char CSV[64]; if ( !ValidSurface() ) { return; } srand( 1 ); srand( RandomSeed ); dh = ( Hur - Hll ) / NH; dv = ( Vur - Vll ) / NV; // H & V for ( i = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++ ) { switch ( Plane ) { case PLANE_XZ0: case PLANE_XZ1: xyz[i][j].p[0] = Hll + i * dh; xyz[i][j].p[2] = Vll + j * dv; break; case PLANE_YZ0: case PLANE_YZ1: xyz[i][j].p[1] = Hll + i * dh; xyz[i][j].p[2] = Vll + j * dv; break; default: xyz[i][j].p[0] = Hll + i * dh; xyz[i][j].p[1] = Vll + j * dv; } } } if ( WaveType == WAVE_BITMAP ) { GenerateBitmapMapping(); } /* else if(WaveType == WAVE_FORMULA) DoFormula(); */ else { // Initialize Z values using bilinear interpolation for ( i = 0; i <= NH; i++ ) { zl = Z00 + i * ( Z10 - Z00 ) / NH; zu = Z01 + i * ( Z11 - Z01 ) / NH; switch ( Plane ) { case PLANE_XZ0: case PLANE_XZ1: for ( j = 0; j <= NV; j++ ) xyz[i][j].p[1] = zl + j * ( zu - zl ) / NV; break; case PLANE_YZ0: case PLANE_YZ1: for ( j = 0; j <= NV; j++ ) xyz[i][j].p[0] = zl + j * ( zu - zl ) / NV; break; default: for ( j = 0; j <= NV; j++ ) xyz[i][j].p[2] = zl + j * ( zu - zl ) / NV; } } } switch ( WaveType ) { case WAVE_COS_SIN: if ( FixBorders ) { NHalfcycles = (int)( ( Hur - Hll ) / ( WaveLength / 2. ) ); NHalfcycles = max( NHalfcycles,1 ); wh = 2. * ( Hur - Hll ) / NHalfcycles; NHalfcycles = (int)( ( Vur - Vll ) / ( WaveLength / 2. ) ); wv = 2. * ( Vur - Vll ) / NHalfcycles; NHalfcycles = max( NHalfcycles,1 ); i0 = 1; i1 = NH - 1; j0 = 1; j1 = NV - 1; } else { wh = WaveLength; wv = WaveLength; i0 = 0; i1 = NH; j0 = 0; j1 = NV; } for ( i = i0; i <= i1; i++ ) { h = Hll + i * dh; ha = ( ( h - Hll ) / wh ) * 2. * PI - PI / 2.; for ( j = j0; j <= j1; j++ ) { v = Vll + j * dv; va = ( ( v - Vll ) / wv ) * 2. * PI; a = Amplitude * cos( ha ) * sin( va ); switch ( Plane ) { case PLANE_XY1: xyz[i][j].p[2] -= a; break; case PLANE_XZ0: xyz[i][j].p[1] += a; break; case PLANE_XZ1: xyz[i][j].p[1] -= a; break; case PLANE_YZ0: xyz[i][j].p[0] += a; break; case PLANE_YZ1: xyz[i][j].p[0] -= a; break; default: xyz[i][j].p[2] += a; } } } break; case WAVE_HCYLINDER: for ( i = 0; i <= NH; i++ ) { h = Hll + i * dh; ha = ( ( h - Hll ) / WaveLength ) * 2. * PI - PI / 2.; for ( j = 0; j <= NV; j++ ) { a = Amplitude * cos( ha ); switch ( Plane ) { case PLANE_XY1: xyz[i][j].p[2] -= a; break; case PLANE_XZ0: xyz[i][j].p[1] += a; break; case PLANE_XZ1: xyz[i][j].p[1] -= a; break; case PLANE_YZ0: xyz[i][j].p[0] += a; break; case PLANE_YZ1: xyz[i][j].p[0] -= a; break; default: xyz[i][j].p[2] += a; } } } break; case WAVE_VCYLINDER: for ( i = 0; i <= NH; i++ ) { h = Hll + i * dh; for ( j = 0; j <= NV; j++ ) { v = Vll + j * dv; va = ( ( v - Vll ) / WaveLength ) * 2. * PI; a = Amplitude * sin( va ); switch ( Plane ) { case PLANE_XY1: xyz[i][j].p[2] -= a; break; case PLANE_XZ0: xyz[i][j].p[1] += a; break; case PLANE_XZ1: xyz[i][j].p[1] -= a; break; case PLANE_YZ0: xyz[i][j].p[0] += a; break; case PLANE_YZ1: xyz[i][j].p[0] -= a; break; default: xyz[i][j].p[2] += a; } } } break; case WAVE_ROUGH_ONLY: PlasmaCloud(); break; } if ( WaveType != WAVE_ROUGH_ONLY ) { // Fixed values for ( i = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++ ) { if ( xyz[i][j].fixed ) { switch ( Plane ) { case PLANE_XZ0: case PLANE_XZ1: xyz[i][j].p[1] = xyz[i][j].fixed_value; break; case PLANE_YZ0: case PLANE_YZ1: xyz[i][j].p[0] = xyz[i][j].fixed_value; break; default: xyz[i][j].p[2] = xyz[i][j].fixed_value; } if ( xyz[i][j].range > 0 ) { maxrange = pow( xyz[i][j].range,2 ); // so we don't have to do sqrt's i0 = i - (int)( floor( xyz[i][j].range / dh - 0.5 ) + 1 ); i1 = i + i - i0; j0 = j - (int)( floor( xyz[i][j].range / dv - 0.5 ) + 1 ); j1 = j + j - j0; if ( FixBorders ) { i0 = max( i0,1 ); i1 = min( i1,NH - 1 ); j0 = max( j0,1 ); j1 = min( j1,NV - 1 ); } else { i0 = max( i0,0 ); i1 = min( i1,NH ); j0 = max( j0,0 ); j1 = min( j1,NV ); } for ( ii = i0; ii <= i1; ii++ ) { for ( jj = j0; jj <= j1; jj++ ) { if ( ii == i && jj == j ) { continue; } range = pow( dh * ( i - ii ), 2 ) + pow( dv * ( j - jj ), 2 ); if ( range > maxrange ) { continue; } dr = sqrt( range / maxrange ); rate = max( -30.,min( xyz[i][j].rate,30. ) ); if ( rate < -1. ) { delta = pow( ( 1. - dr ),-rate + 1. ); } else if ( rate < 0. ) { delta = ( 1 + rate ) * 0.5 * ( cos( dr * PI ) + 1.0 ) - rate*pow( ( 1. - dr ),2 ); } else if ( rate == 0. ) { delta = 0.5 * ( cos( dr * PI ) + 1.0 ); } else if ( rate <= 1. ) { delta = ( 1. - rate ) * 0.5 * ( cos( dr * PI ) + 1.0 ) + rate * ( 1. - pow( dr,2 ) ); } else { delta = 1. - pow( dr,rate + 1 ); } switch ( Plane ) { case PLANE_XZ0: case PLANE_XZ1: xyz[ii][jj].p[1] += ( xyz[i][j].p[1] - xyz[ii][jj].p[1] ) * delta; break; case PLANE_YZ0: case PLANE_YZ1: xyz[ii][jj].p[0] += ( xyz[i][j].p[0] - xyz[ii][jj].p[0] ) * delta; break; default: xyz[ii][jj].p[2] += ( xyz[i][j].p[2] - xyz[ii][jj].p[2] ) * delta; } } } } } } } } if ( ( Roughness > 0. ) && ( WaveType != WAVE_ROUGH_ONLY ) ) { for ( i = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++ ) { if ( CanEdit( i,j ) && !xyz[i][j].fixed ) { switch ( Plane ) { case PLANE_XZ0: case PLANE_XZ1: xyz[i][j].p[1] += -Roughness / 2. + Roughness * ( (double)rand() / (double)RAND_MAX ); break; case PLANE_YZ0: case PLANE_YZ1: xyz[i][j].p[0] += -Roughness / 2. + Roughness * ( (double)rand() / (double)RAND_MAX ); break; default: xyz[i][j].p[2] += -Roughness / 2. + Roughness * ( (double)rand() / (double)RAND_MAX ); } } else{ r = rand(); // We still get a random number, so that fixing points } // doesn't change the sequence. } } } for ( i = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++ ) { for ( k = 0; k < 3; k++ ) { xyz[i][j].p[k] = Nearest( xyz[i][j].p[k],2.0 ); } } } // Find minima and maxima switch ( Plane ) { case PLANE_XZ0: case PLANE_XZ1: xmin = Hll; xmax = Hur; zmin = Vll; zmax = Vur; ymin = xyz[0][0].p[1]; ymax = ymin; for ( i = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++ ) { ymin = min( ymin,xyz[i][j].p[1] ); ymax = max( ymax,xyz[i][j].p[1] ); } } break; case PLANE_YZ0: case PLANE_YZ1: ymin = Hll; ymax = Hur; zmin = Vll; zmax = Vur; xmin = xyz[0][0].p[0]; xmax = ymin; for ( i = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++ ) { xmin = min( xmin,xyz[i][j].p[0] ); xmax = max( xmax,xyz[i][j].p[0] ); } } break; break; default: xmin = Hll; xmax = Hur; ymin = Vll; ymax = Vur; zmin = xyz[0][0].p[2]; zmax = zmin; for ( i = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++ ) { zmin = min( zmin,xyz[i][j].p[2] ); zmax = max( zmax,xyz[i][j].p[2] ); } } } xmin = Nearest( xmin,2. ); xmax = Nearest( xmax,2. ); ymin = Nearest( ymin,2. ); ymax = Nearest( ymax,2. ); zmin = Nearest( zmin,2. ); zmax = Nearest( zmax,2. ); switch ( Plane ) { case PLANE_XY1: backface = AtLeast( zmax + 32.,32. ); break; case PLANE_XZ0: backface = NoMoreThan( ymin - 32.,32. ); break; case PLANE_XZ1: backface = AtLeast( ymax + 32.,32. ); break; case PLANE_YZ0: backface = NoMoreThan( xmin - 32.,32. ); break; case PLANE_YZ1: backface = AtLeast( xmax + 32.,32. ); break; default: backface = NoMoreThan( zmin - 32.,32. ); } if ( gNode ) { free( gNode ); free( gTri ); gNode = (NODE *)NULL; gTri = (TRI *)NULL; } if ( Decimate > 0 && ( Game != QUAKE3 || UsePatches == 0 ) ) { MakeDecimatedMap( &gNumNodes,&gNumTris,&gNode,&gTri ); } else { gNumNodes = ( NH + 1 ) * ( NV + 1 ); gNumTris = NH * NV * 2; gNode = (NODE *) malloc( gNumNodes * sizeof( NODE ) ); gTri = (TRI *) malloc( gNumTris * sizeof( TRI ) ); for ( i = 0,N = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++, N++ ) { gNode[N].used = 1; gNode[N].p[0] = (float)xyz[i][j].p[0]; gNode[N].p[1] = (float)xyz[i][j].p[1]; gNode[N].p[2] = (float)xyz[i][j].p[2]; } } for ( i = 0; i < NH; i++ ) { for ( j = 0; j < NV; j++ ) { k = i * NV * 2 + j * 2; if ( ( i + j ) % 2 ) { switch ( Plane ) { case PLANE_XY1: case PLANE_XZ1: case PLANE_YZ1: gTri[k ].v[0] = i * ( NV + 1 ) + j; gTri[k ].v[1] = ( i + 1 ) * ( NV + 1 ) + j + 1; gTri[k ].v[2] = ( i + 1 ) * ( NV + 1 ) + j; gTri[k + 1].v[0] = i * ( NV + 1 ) + j; gTri[k + 1].v[1] = i * ( NV + 1 ) + j + 1; gTri[k + 1].v[2] = ( i + 1 ) * ( NV + 1 ) + j + 1; break; default: gTri[k ].v[0] = i * ( NV + 1 ) + j; gTri[k ].v[1] = ( i + 1 ) * ( NV + 1 ) + j; gTri[k ].v[2] = ( i + 1 ) * ( NV + 1 ) + j + 1; gTri[k + 1].v[0] = i * ( NV + 1 ) + j; gTri[k + 1].v[1] = ( i + 1 ) * ( NV + 1 ) + j + 1; gTri[k + 1].v[2] = i * ( NV + 1 ) + j + 1; } } else { switch ( Plane ) { case PLANE_XY1: case PLANE_XZ1: case PLANE_YZ1: gTri[k ].v[0] = i * ( NV + 1 ) + j; gTri[k ].v[1] = i * ( NV + 1 ) + j + 1; gTri[k ].v[2] = ( i + 1 ) * ( NV + 1 ) + j; gTri[k + 1].v[0] = ( i + 1 ) * ( NV + 1 ) + j; gTri[k + 1].v[1] = i * ( NV + 1 ) + j + 1; gTri[k + 1].v[2] = ( i + 1 ) * ( NV + 1 ) + j + 1; break; default: gTri[k ].v[0] = i * ( NV + 1 ) + j; gTri[k ].v[1] = ( i + 1 ) * ( NV + 1 ) + j; gTri[k ].v[2] = i * ( NV + 1 ) + j + 1; gTri[k + 1].v[0] = ( i + 1 ) * ( NV + 1 ) + j; gTri[k + 1].v[1] = ( i + 1 ) * ( NV + 1 ) + j + 1; gTri[k + 1].v[2] = i * ( NV + 1 ) + j + 1; } } } } } /* sprintf(CSV,"csv%03d.csv",Decimate); f = fopen(CSV,"w"); for(i=0; i 0 ) { for ( i = 0; i < NH; i++ ) { for ( j = 0; j < NV; j++ ) { switch ( Plane ) { case PLANE_XZ0: case PLANE_XZ1: xyz[i][j].p[1] = CalculateSnapValue( xyz[i][j].p[1] ); break; case PLANE_YZ0: case PLANE_YZ1: xyz[i][j].p[0] = CalculateSnapValue( xyz[i][j].p[0] ); break; default: xyz[i][j].p[2] = CalculateSnapValue( xyz[i][j].p[2] ); } } } } // Hydra: snap-to-grid end } //============================================================= double Nearest( double x, double dx ){ double xx; xx = (double)( floor( x / dx - 0.5 ) + 1. ) * dx; if ( fabs( xx ) < dx / 2 ) { xx = 0.; } return xx; } //============================================================= double NoMoreThan( double x, double dx ){ double xx; xx = (double)( floor( x / dx - 0.5 ) + 1. ) * dx; if ( xx > x ) { xx -= dx; } return xx; } //============================================================= double AtLeast( double x, double dx ){ double xx; xx = (double)( floor( x / dx - 0.5 ) + 1. ) * dx; if ( xx < x ) { xx += dx; } return xx; } //============================================================= double LessThan( double x,double dx ){ double xx; xx = (double)( floor( x / dx - 0.5 ) + 1. ) * dx; if ( xx >= x ) { xx -= dx; } return xx; } //============================================================= double MoreThan( double x,double dx ){ double xx; xx = (double)( floor( x / dx - 0.5 ) + 1. ) * dx; while ( xx <= x ) xx += dx; return xx; } //============================================================= void SubdividePlasma( int i0,int j0,int i1,int j1 ){ int i, j; double z1, z2; double r; // NOTE: This is used to keep the random number sequence the same // when we fix a point. If we did NOT do this, then simply // fixing a point at its current value would change the entire // surface. i = ( i0 + i1 ) / 2; j = ( j0 + j1 ) / 2; if ( i1 > i0 + 1 ) { if ( !xyz[i][j0].done ) { xyz[i][j0].pp[2] = xyz[i0][j0].pp[2] + ( xyz[i1][j0].pp[2] - xyz[i0][j0].pp[2] ) * (double)( i - i0 ) / (double)( i1 - i0 ) + ( (double)( i - i0 ) ) * ( -Roughness / 2. + Roughness * ( (double)rand() / (double)RAND_MAX ) ); xyz[i][j0].done = 1; } else{ r = rand(); } if ( ( j1 > j0 ) && ( !xyz[i][j1].done ) ) { xyz[i][j1].pp[2] = xyz[i0][j1].pp[2] + ( xyz[i1][j1].pp[2] - xyz[i0][j1].pp[2] ) * (double)( i - i0 ) / (double)( i1 - i0 ) + ( (double)( i - i0 ) ) * ( -Roughness / 2. + Roughness * ( (double)rand() / (double)RAND_MAX ) ); xyz[i][j1].done = 1; } else{ r = rand(); } } if ( j1 > j0 + 1 ) { if ( !xyz[i0][j].done ) { xyz[i0][j].pp[2] = xyz[i0][j0].pp[2] + ( xyz[i0][j1].pp[2] - xyz[i0][j0].pp[2] ) * (double)( j - j0 ) / (double)( j1 - j0 ) + ( (double)( j - j0 ) ) * ( -Roughness / 2. + Roughness * ( (double)rand() / (double)RAND_MAX ) ); xyz[i0][j].done = 1; } else{ r = rand(); } if ( ( i1 > i0 ) && ( !xyz[i1][j].done ) ) { xyz[i1][j].pp[2] = xyz[i1][j0].pp[2] + ( xyz[i1][j1].pp[2] - xyz[i1][j0].pp[2] ) * (double)( j - j0 ) / (double)( j1 - j0 ) + ( (double)( j - j0 ) ) * ( -Roughness / 2. + Roughness * ( (double)rand() / (double)RAND_MAX ) ); xyz[i1][j].done = 1; } else{ r = rand(); } } if ( ( i1 > i0 + 1 ) && ( j1 > j0 + 1 ) ) { if ( !xyz[i][j].done ) { z1 = xyz[i0][j].pp[2] + ( xyz[i1][j].pp[2] - xyz[i0][j].pp[2] ) * (double)( i - i0 ) / (double)( i1 - i0 ); z2 = xyz[i][j0].pp[2] + ( xyz[i][j1].pp[2] - xyz[i][j0].pp[2] ) * (double)( j - j0 ) / (double)( j1 - j0 ); xyz[i][j].pp[2] = ( z1 + z2 ) / 2. + ( (double)( i - i0 ) ) * ( -Roughness / 2. + Roughness * ( (double)rand() / (double)RAND_MAX ) ); xyz[i][j].done = 1; } else{ r = rand(); } } if ( i > i0 + 1 || j > j0 + 1 ) { SubdividePlasma( i0,j0,i,j ); } if ( i1 > i + 1 || j > j0 + 1 ) { SubdividePlasma( i,j0,i1,j ); } if ( i > i0 + 1 || j1 > j0 + 1 ) { SubdividePlasma( i0,j,i,j1 ); } if ( i1 > i + 1 || j1 > j0 + 1 ) { SubdividePlasma( i,j,i1,j1 ); } } //================================================================================== void PlasmaCloud(){ int i, j; /* use pp[2] values until done to avoid messing with a bunch of switch statements */ for ( i = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++ ) { if ( FixedPoint( i,j ) ) { xyz[i][j].done = 1; } else{ xyz[i][j].done = 0; } } } switch ( Plane ) { case PLANE_XZ0: case PLANE_XZ1: for ( i = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++ ) { if ( xyz[i][j].fixed ) { xyz[i][j].pp[2] = xyz[i][j].fixed_value; } else{ xyz[i][j].pp[2] = xyz[i][j].p[1]; } } } break; case PLANE_YZ0: case PLANE_YZ1: for ( i = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++ ) { if ( xyz[i][j].fixed ) { xyz[i][j].pp[2] = xyz[i][j].fixed_value; } else{ xyz[i][j].pp[2] = xyz[i][j].p[0]; } } } break; default: for ( i = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++ ) { if ( xyz[i][j].fixed ) { xyz[i][j].pp[2] = xyz[i][j].fixed_value; } else{ xyz[i][j].pp[2] = xyz[i][j].p[2]; } } } break; } SubdividePlasma( 0,0,NH,NV ); switch ( Plane ) { case PLANE_XZ0: case PLANE_XZ1: for ( i = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++ ) { xyz[i][j].p[1] = xyz[i][j].pp[2]; } } break; case PLANE_YZ0: case PLANE_YZ1: for ( i = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++ ) { xyz[i][j].p[0] = xyz[i][j].pp[2]; } } break; default: for ( i = 0; i <= NH; i++ ) { for ( j = 0; j <= NV; j++ ) { xyz[i][j].p[2] = xyz[i][j].pp[2]; } } break; } } //=========================================================================== bool FixedPoint( int i, int j ){ if ( xyz[i][j].fixed ) { return TRUE; } return !CanEdit( i,j ); } //=========================================================================== bool CanEdit( int i, int j ){ if ( FixBorders && ( ( WaveType == WAVE_COS_SIN ) || ( WaveType == WAVE_ROUGH_ONLY ) ) ) { if ( i == 0 ) { return FALSE; } if ( i == NH ) { return FALSE; } if ( j == 0 ) { return FALSE; } if ( j == NV ) { return FALSE; } } if ( i == 0 && j == 0 ) { return FALSE; } if ( i == NH && j == 0 ) { return FALSE; } if ( i == 0 && j == NV ) { return FALSE; } if ( i == NH && j == NV ) { return FALSE; } return TRUE; } /*============================================================================ TriangleFromPoint Determines which triangle in the gTri array bounds the input point. Doesn't do anything special with border points. */ int TriangleFromPoint( double x, double y ){ int j, tri; if ( !gTri ) { return -1; } for ( j = 0, tri = -1; j < gNumTris && tri == -1; j++ ) { if ( side( x,y, gNode[gTri[j].v[0]].p[0],gNode[gTri[j].v[0]].p[1], gNode[gTri[j].v[1]].p[0],gNode[gTri[j].v[1]].p[1] ) < 0. ) { continue; } if ( side( x,y, gNode[gTri[j].v[1]].p[0],gNode[gTri[j].v[1]].p[1], gNode[gTri[j].v[2]].p[0],gNode[gTri[j].v[2]].p[1] ) < 0. ) { continue; } if ( side( x,y, gNode[gTri[j].v[2]].p[0],gNode[gTri[j].v[2]].p[1], gNode[gTri[j].v[0]].p[0],gNode[gTri[j].v[0]].p[1] ) < 0. ) { continue; } tri = j; } return tri; } /*============================================================================ PlayerStartZ Determines minimum height to place the player start such that he doesn't intersect any surface brushes. */ int PlayerStartZ( double x, double y ){ int k,t[5]; double z, zt; if ( !gTri ) { return (int)zmax; } t[0] = TriangleFromPoint( x,y ); t[1] = TriangleFromPoint( x + PlayerBox[Game].x[0],y + PlayerBox[Game].y[0] ); t[2] = TriangleFromPoint( x + PlayerBox[Game].x[0],y + PlayerBox[Game].y[1] ); t[3] = TriangleFromPoint( x + PlayerBox[Game].x[1],y + PlayerBox[Game].y[0] ); t[4] = TriangleFromPoint( x + PlayerBox[Game].x[1],y + PlayerBox[Game].y[1] ); z = zmin; for ( k = 0; k < 5; k++ ) { zt = ( gTri[t[k]].plane.dist - gTri[t[k]].plane.normal[0] * x - gTri[t[k]].plane.normal[1] * y ) / gTri[t[k]].plane.normal[2]; z = max( z,zt ); } return (int)( AtLeast( z,2. ) - PlayerBox[Game].z[0] ); } //============================================================= void XYZtoV( XYZ *xyz, vec3 *v ){ v[0][0] = (vec)Nearest( xyz->p[0],2. ); v[0][1] = (vec)Nearest( xyz->p[1],2. ); v[0][2] = (vec)Nearest( xyz->p[2],2. ); } //============================================================= scene::Node* MakePatch( void ){ scene::Node* patch = Patch_AllocNode(); #if 0 patch->m_patch->SetShader( Texture[Game][0] ); #endif Node_getTraversable( h_worldspawn )->insert( patch ); return patch; } //============================================================= void MakeBrush( BRUSH *brush ){ NodePtr node( Brush_AllocNode() ); #if 0 for ( int i = 0; i < brush->NumFaces; i++ ) { _QERFaceData QERFaceData; if ( !strncmp( brush->face[i].texture, "textures/", 9 ) ) { strcpy( QERFaceData.m_TextureName,brush->face[i].texture ); } else { strcpy( QERFaceData.m_TextureName,"textures/" ); strcpy( QERFaceData.m_TextureName + 9,brush->face[i].texture ); } QERFaceData.m_nContents = brush->face[i].Contents; QERFaceData.m_nFlags = brush->face[i].Surface; QERFaceData.m_nValue = brush->face[i].Value; QERFaceData.m_fShift[0] = brush->face[i].Shift[0]; QERFaceData.m_fShift[1] = brush->face[i].Shift[1]; QERFaceData.m_fRotate = brush->face[i].Rotate; QERFaceData.m_fScale[0] = brush->face[i].Scale[0]; QERFaceData.m_fScale[1] = brush->face[i].Scale[1]; QERFaceData.m_v1[0] = brush->face[i].v[0][0]; QERFaceData.m_v1[1] = brush->face[i].v[0][1]; QERFaceData.m_v1[2] = brush->face[i].v[0][2]; QERFaceData.m_v2[0] = brush->face[i].v[1][0]; QERFaceData.m_v2[1] = brush->face[i].v[1][1]; QERFaceData.m_v2[2] = brush->face[i].v[1][2]; QERFaceData.m_v3[0] = brush->face[i].v[2][0]; QERFaceData.m_v3[1] = brush->face[i].v[2][1]; QERFaceData.m_v3[2] = brush->face[i].v[2][2]; QERFaceData.m_bBPrimit = false; ( g_FuncTable.m_pfnAddFaceData )( vp,&QERFaceData ); } #endif Node_getTraversable( h_func_group )->insert( node ); } //============================================================= void OpenFuncGroup(){ h_func_group = GlobalEntityCreator().createEntity( "func_group" ); h_func_group->IncRef(); if ( AddTerrainKey ) { h_func_group->m_entity->setkeyvalue( "terrain", "1" ); } } //============================================================= void CloseFuncGroup(){ h_func_group->DecRef(); if ( g_FuncTable.m_pfnSysUpdateWindows != NULL ) { g_FuncTable.m_pfnSysUpdateWindows( W_ALL ); } }