mirror of
https://github.com/UberGames/GtkRadiant.git
synced 2024-12-18 08:21:09 +00:00
a06f65b042
git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/branches/ZeroRadiant@195 8a3a26a2-13c4-0310-b231-cf6edde360e5
2056 lines
56 KiB
C++
2056 lines
56 KiB
C++
/*
|
|
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 <math.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#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];
|
|
LPVOID h_func_group;
|
|
LPVOID terrainkey; // ^Fishman - Add terrain key to func_group.
|
|
|
|
//=============================================================
|
|
// 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];
|
|
patchMesh_t p;
|
|
|
|
dh = (Hur-Hll)/NH;
|
|
dv = (Vur-Vll)/NV;
|
|
memset(&p,0,sizeof(patchMesh_t));
|
|
|
|
// 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", 0, NULL);
|
|
}
|
|
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", 0, NULL);
|
|
}
|
|
|
|
p.width = NH_patch;
|
|
p.height = NV_patch;
|
|
p.type = PATCH_GENERIC;
|
|
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++)
|
|
{
|
|
p.ctrl[i][j].xyz[0] = (float)xyz[ii][j0+j].pp[0];
|
|
p.ctrl[i][j].xyz[1] = (float)xyz[ii][j0+j].pp[1];
|
|
p.ctrl[i][j].xyz[2] = (float)xyz[ii][j0+j].pp[2];
|
|
p.ctrl[i][j].st[0] = (float)i;
|
|
p.ctrl[i][j].st[1] = (float)j;
|
|
}
|
|
}
|
|
MakePatch(&p);
|
|
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(SingleBrushSelected) g_FuncTable.m_pfnDeleteSelection();
|
|
|
|
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<gNumNodes; i++)
|
|
{
|
|
if(gNode[i].used)
|
|
fprintf(f,"%g,%g,%g\n",gNode[i].p[0],gNode[i].p[1],gNode[i].p[2]);
|
|
}
|
|
fclose(f);
|
|
*/
|
|
for(i=0; i<gNumTris; i++)
|
|
PlaneFromPoints(gNode[gTri[i].v[0]].p,
|
|
gNode[gTri[i].v[1]].p,
|
|
gNode[gTri[i].v[2]].p,
|
|
&gTri[i].plane);
|
|
|
|
// Hydra: snap-to-grid begin
|
|
if (SnapToGrid > 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.);
|
|
}
|
|
|
|
//=============================================================
|
|
void MakePatch(patchMesh_t *p)
|
|
{
|
|
int ret;
|
|
char shadername[64+9];
|
|
|
|
ret = g_FuncTable.m_pfnCreatePatchHandle();
|
|
// strcpy(shadername, "textures/");
|
|
// strcpy(shadername+9, Texture[Game][0]);
|
|
strcpy(shadername, Texture[Game][0]);
|
|
g_FuncTable.m_pfnCommitPatchHandleToMap(ret,p,shadername);
|
|
g_FuncTable.m_pfnReleasePatchHandles();
|
|
}
|
|
|
|
//=============================================================
|
|
void MakeBrush(BRUSH *brush)
|
|
{
|
|
LPVOID vp;
|
|
int i;
|
|
_QERFaceData QERFaceData;
|
|
|
|
if(g_FuncTable.m_pfnCreateBrushHandle==NULL)
|
|
{
|
|
g_FuncTable.m_pfnMessageBox(g_pRadiantWnd,"m_pfnCreateBrushHandle==NULL","Aw damn",0, NULL);
|
|
return;
|
|
}
|
|
vp=(g_FuncTable.m_pfnCreateBrushHandle)();
|
|
if(!vp) return;
|
|
for(i=0; i<brush->NumFaces; i++)
|
|
{
|
|
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);
|
|
}
|
|
if(g_FuncTable.m_pfnCommitBrushHandle!=NULL)
|
|
{
|
|
if(h_func_group)
|
|
g_FuncTable.m_pfnCommitBrushHandleToEntity(vp,h_func_group);
|
|
else
|
|
g_FuncTable.m_pfnCommitBrushHandle(vp);
|
|
}
|
|
}
|
|
//=============================================================
|
|
void OpenFuncGroup()
|
|
{
|
|
if (g_FuncTable.m_pfnAllocateEpair!=NULL)
|
|
{
|
|
epair_t *ep;
|
|
|
|
h_func_group = g_FuncTable.m_pfnCreateEntityHandle();
|
|
ep = g_EntityTable.m_pfnAllocateEpair("classname","func_group");
|
|
g_EntityTable.m_pfnSetEntityKeyValList((entity_t *)h_func_group,ep);
|
|
|
|
if (AddTerrainKey) // ^Fishman - Add terrain key to func_group.
|
|
{
|
|
epair_t *ep2;
|
|
terrainkey = g_FuncTable.m_pfnCreateEntityHandle();
|
|
ep2 = g_EntityTable.m_pfnAllocateEpair("terrain","1");
|
|
ep->next = ep2;
|
|
g_EntityTable.m_pfnSetEntityKeyValList((entity_t *)h_func_group,ep);
|
|
}
|
|
}
|
|
else
|
|
h_func_group = NULL;
|
|
}
|
|
//=============================================================
|
|
void CloseFuncGroup()
|
|
{
|
|
if (h_func_group)
|
|
g_FuncTable.m_pfnCommitEntityHandleToMap (h_func_group);
|
|
if (g_FuncTable.m_pfnSysUpdateWindows != NULL)
|
|
g_FuncTable.m_pfnSysUpdateWindows (W_ALL);
|
|
}
|