📄 face.cpp
字号:
/****************************************************************************************/
/* face.c */
/* */
/* Author: Jim Mischel, Ken Baird */
/* Description: Face csg, management, io, etc... */
/* */
/* The contents of this file are subject to the Genesis3D Public License */
/* Version 1.01 (the "License"); you may not use this file except in */
/* compliance with the License. You may obtain a copy of the License at */
/* http://www.genesis3d.com */
/* */
/* Software distributed under the License is distributed on an "AS IS" */
/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */
/* the License for the specific language governing rights and limitations */
/* under the License. */
/* */
/* The Original Code is Genesis3D, released March 25, 1999. */
/*Genesis3D Version 1.1 released November 15, 1999 */
/* Copyright (C) 1999 WildTangent, Inc. All Rights Reserved */
/* */
/* Prepared for GenEdit-Classic ver. 0.5, Dec. 15, 2000 */
/****************************************************************************************/
#include "stdafx.h"
#include "face.h"
#include <assert.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include "basetype.h"
#include "units.h"
#include "box3d.h"
#include "typeio.h"
//#include "consoletab.h"
#include "ram.h"
#include "quatern.h"
#include "util.h"
#include "Globals.h"
const geVec3d VecOrigin ={ 0.0f, 0.0f, 0.0f };
//temp buffers for splitting faces
//use caution in recursive code that uses these...
static geVec3d spf[256], spb[256];
#define VCOMPARE_EPSILON (0.001f)
#define MAX_POINTS 64
#define ON_EPSILON (0.1f)
#define VectorToSUB(a, b) (*((((geFloat *)(&a))) + (b)))
#define FACE_DEFAULT_LIGHT 300
#define FACE_DEFAULT_BIAS (1.0f)
#define FACE_DEFAULT_TRANSLUCENCY (255.0f)
#define FACE_DEFAULT_REFLECTIVITY (1.0f)
enum FaceFlags
{
FACE_MIRROR = (1<<0),
FACE_FULLBRIGHT = (1<<1),
FACE_SKY = (1<<2),
FACE_LIGHT = (1<<3),
FACE_SELECTED = (1<<4),
FACE_FIXEDHULL = (1<<5), //doesn't expand (rings)
FACE_GOURAUD = (1<<6),
FACE_FLAT = (1<<7),
FACE_TEXTURELOCKED = (1<<8),
FACE_VISIBLE = (1<<9),
FACE_SHEET = (1<<10), //visible from both sides
FACE_TRANSPARENT= (1<<11) //use transparency value for something
};
enum OldFaceFlags
{
oldINSOLID =1,
oldSELECTED =2,
oldLIGHT =4,
oldMIRROR =8,
oldFULLBRIGHT =16,
oldSKY =32
};
enum SideFlags
{
SIDE_FRONT =0,
SIDE_BACK =1,
SIDE_ON =2
};
typedef struct TexInfoTag
{
geVec3d VecNormal;
geFloat xScale, yScale;
int xShift, yShift;
geFloat Rotate; // texture rotation angle in degrees
TexInfo_Vectors TVecs;
int Dib; // index into the wad
char Name[16];
geBoolean DirtyFlag;
geVec3d Pos;
int txSize, tySize; // texture size (not currently used)
geXForm3d XfmFaceAngle; // face rotation angle
} TexInfo;
typedef struct FaceTag
{
int NumPoints;
int Flags;
Plane Face_Plane;
int LightIntensity;
geFloat Reflectivity;
geFloat Translucency;
geFloat MipMapBias;
geFloat LightXScale, LightYScale;
TexInfo Tex;
geVec3d *Points;
} Face;
enum NewFaceFlags
{
ffMirror = (1<<0), // face is a mirror
ffFullBright = (1<<1), // give face full brightness
ffSky = (1<<2), // face is sky
ffLight = (1<<3), // face emits light
ffTranslucent = (1<<4), // internal to tools
ffGouraud = (1<<5), // shading
ffFlat = (1<<6)
};
static void Face_SetTexInfoPlane
(
TexInfo *t,
geVec3d const *pNormal
)
{
assert (t != NULL);
assert (pNormal != NULL);
assert (geVec3d_IsNormalized (pNormal));
t->VecNormal = *pNormal;
t->DirtyFlag = GE_TRUE;
}
static void Face_InitFaceAngle
(
TexInfo *t,
geVec3d const *pNormal
)
{
geVec3d VecDest;
geVec3d VecAxis;
geFloat cosv, Theta;
geVec3d PosNormal;
PosNormal = *pNormal;
if (fabs(pNormal->X) > fabs(pNormal->Y))
{
if (fabs(pNormal->X) > fabs(pNormal->Z))
{
if (pNormal->X > 0)
geVec3d_Inverse(&PosNormal);
}
else
{
if (pNormal->Z > 0)
geVec3d_Inverse(&PosNormal);
}
}
else
{
if (fabs(pNormal->Y) > fabs(pNormal->Z))
{
if (pNormal->Y > 0)
geVec3d_Inverse(&PosNormal);
}
else
{
if (pNormal->Z > 0)
geVec3d_Inverse(&PosNormal);
}
}
// Create rotation matrix that will put this face into the X,Y plane.
geVec3d_Set (&VecDest, 0.0f, 0.0f, 1.0f);
geVec3d_CrossProduct (&VecDest, &PosNormal, &VecAxis);
cosv = geVec3d_DotProduct (&VecDest, &PosNormal);
if (cosv > 1.0f)
{
cosv = 1.0f;
}
Theta = (geFloat)acos (cosv);
if (geVec3d_Normalize (&VecAxis) == 0.0f)
{
// If the resulting vector is 0 length,
// then a rotation about X will put us where we need to be.
geXForm3d_SetIdentity (&t->XfmFaceAngle);
geXForm3d_RotateX (&t->XfmFaceAngle, -Theta); // old gedit
// geXForm3d_RotateX (&t->XfmFaceAngle, Theta); // new g3dc
}
else
{
geQuaternion QRot;
geQuaternion_SetFromAxisAngle (&QRot, &VecAxis, -Theta); // old gedit
// geQuaternion_SetFromAxisAngle (&QRot, &VecAxis, Theta); // new g3dc
geQuaternion_ToMatrix (&QRot, &t->XfmFaceAngle);
}
}
static void Face_InitTexInfo
(
TexInfo *t,
geVec3d const *pNormal
)
{
assert (t != NULL);
assert (pNormal != NULL);
t->Name[0] = '\0';
t->xScale = 1.0f;
t->yScale = 1.0f;
t->xShift = 0;
t->yShift = 0;
t->Rotate = 0.0f;
t->Dib = 0;
t->DirtyFlag = GE_FALSE;
t->txSize = 0;
t->tySize = 0;
geVec3d_Clear (&t->Pos);
Face_SetTexInfoPlane (t, pNormal);
Face_InitFaceAngle( t, pNormal );
}
static geBoolean Face_SetPlaneFromFace(Face *f)
{
int i;
geVec3d v1, v2;
assert(f != NULL);
//catches colinear points now
for(i=0;i < f->NumPoints;i++)
{
//gen a plane normal from the cross of edge vectors
geVec3d_Subtract(&f->Points[i], &f->Points[(i+1) % f->NumPoints], &v1);
geVec3d_Subtract(&f->Points[(i+2) % f->NumPoints], &f->Points[(i+1) % f->NumPoints], &v2);
geVec3d_CrossProduct(&v1, &v2, &f->Face_Plane.Normal);
if(!geVec3d_Compare(&f->Face_Plane.Normal, &VecOrigin, VCOMPARE_EPSILON))
{
break;
}
//try the next three if there are three
}
if(i >= f->NumPoints)
{
// ConPrintf("Face with no normal!\n"); // old gedit
CGlobals::GetActiveDocument()->mpMainFrame->ConPrintf("Face with no normal!\n"); // new g3dc
return GE_FALSE;
}
geVec3d_Normalize(&f->Face_Plane.Normal);
f->Face_Plane.Dist =geVec3d_DotProduct(&f->Points[1], &f->Face_Plane.Normal);
Face_SetTexInfoPlane(&f->Tex, &f->Face_Plane.Normal);
return GE_TRUE;
}
static void Face_SetTexturePos (Face *f)
{
// Face_GetCenter (f, &f->Tex.Pos);
geVec3d_Clear (&f->Tex.Pos);
f->Tex.DirtyFlag = GE_TRUE;
}
Face *Face_Create(int NumPnts, const geVec3d *pnts, int DibId)
{
Face *f;
assert(NumPnts > 0);
assert(NumPnts < MAX_POINTS);
assert(pnts != NULL);
f =(Face*)geRam_Allocate(sizeof(Face));
if(f)
{
memset(f, 0, sizeof(Face));
f->NumPoints=NumPnts;
f->LightIntensity = FACE_DEFAULT_LIGHT;
f->MipMapBias = FACE_DEFAULT_BIAS;
f->Translucency = FACE_DEFAULT_TRANSLUCENCY;
f->Reflectivity = FACE_DEFAULT_REFLECTIVITY;
f->LightXScale = 1.0f;
f->LightYScale = 1.0f;
Face_SetVisible(f, GE_TRUE);
f->Points = (geVec3d*)geRam_Allocate(sizeof(geVec3d) * NumPnts);
if(f->Points)
{
memcpy(f->Points, pnts, sizeof(geVec3d) * NumPnts);
if(Face_SetPlaneFromFace(f))
{
Face_InitTexInfo(&f->Tex, &f->Face_Plane.Normal);
Face_SetTextureDibId (f, DibId);
Face_SetTexturePos (f);
}
else
{
geRam_Free (f->Points);
geRam_Free (f);
f =NULL;
}
}
else
{
geRam_Free (f);
f =NULL;
}
}
return f;
}
//builds a large face based on p
Face *Face_CreateFromPlane(const Plane *p, geFloat Radius, int DibId)
{
geFloat v;
geVec3d vup, vright, org, pnts[4];
assert(p != NULL);
//find the major axis of p->Normal
geVec3d_Set (&vup, 0.0f, 0.0f, 1.0f);
if((fabs(p->Normal.Z) > fabs(p->Normal.X))
&&(fabs(p->Normal.Z) > fabs(p->Normal.Y)))
{
geVec3d_Set(&vup, 1.0f, 0.0f, 0.0f);
}
v =geVec3d_DotProduct(&vup, &p->Normal);
geVec3d_AddScaled (&vup, &p->Normal, -v, &vup);
geVec3d_Normalize(&vup);
geVec3d_AddScaled (&VecOrigin, &p->Normal, p->Dist, &org);
geVec3d_CrossProduct(&vup, &p->Normal, &vright);
geVec3d_Scale(&vup, Radius, &vup);
geVec3d_Scale(&vright, Radius, &vright);
geVec3d_Subtract(&org, &vright, &pnts[0]);
geVec3d_Add(&pnts[0], &vup, &pnts[0]);
geVec3d_Add(&org, &vright, &pnts[1]);
geVec3d_Add(&pnts[1], &vup, &pnts[1]);
geVec3d_Add(&org, &vright, &pnts[2]);
geVec3d_Subtract(&pnts[2], &vup, &pnts[2]);
geVec3d_Subtract(&org, &vright, &pnts[3]);
geVec3d_Subtract(&pnts[3], &vup, &pnts[3]);
return Face_Create(4, pnts, DibId);
}
void Face_Destroy(Face **f)
{
assert(f != NULL);
assert(*f != NULL);
if((*f)->Points)
{
geRam_Free ((*f)->Points);
}
geRam_Free (*f);
*f =NULL;
}
Face *Face_Clone(const Face *src)
{
Face *dst;
assert(src != NULL);
assert(src->NumPoints > 0);
assert(src->Points != NULL);
dst =Face_Create(src->NumPoints, src->Points, Face_GetTextureDibId (src));
if(dst)
{
Face_CopyFaceInfo(src, dst);
}
return dst;
}
Face *Face_CloneReverse(const Face *src)
{
int i;
Face *dst;
geVec3d pt;
assert(src != NULL);
assert(src->NumPoints >0);
assert(src->Points != NULL);
dst =Face_Clone(src);
if(dst)
{
dst->Face_Plane.Dist=-dst->Face_Plane.Dist;
geVec3d_Inverse(&dst->Face_Plane.Normal);
for(i=0;i < dst->NumPoints/2;i++)
{
pt =dst->Points[i];
dst->Points[i] =dst->Points[dst->NumPoints-i-1];
dst->Points[dst->NumPoints-i-1] =pt;
}
Face_SetPlaneFromFace(dst);
}
return dst;
}
int Face_GetNumPoints(const Face *f)
{
assert(f != NULL);
return f->NumPoints;
}
const Plane *Face_GetPlane(const Face *f)
{
assert(f != NULL);
return &f->Face_Plane;
}
const geVec3d *Face_GetPoints(const Face *f)
{
assert(f != NULL);
return f->Points;
}
int Face_GetLightIntensity(const Face *f)
{
assert (f != NULL);
return f->LightIntensity;
}
void Face_GetLightScale(const Face *f, geFloat *pxScale, geFloat *pyScale)
{
assert(f != NULL);
assert(pxScale != NULL);
assert(pyScale != NULL);
*pxScale = f->LightXScale;
*pyScale = f->LightYScale;
}
void Face_GetTextureScale(const Face *f, geFloat *pxScale, geFloat *pyScale)
{
assert(f != NULL);
assert(pxScale != NULL);
assert(pyScale != NULL);
*pxScale = f->Tex.xScale;
*pyScale = f->Tex.yScale;
}
void Face_GetTextureShift(const Face *f, int *pxShift, int *pyShift)
{
assert(f != NULL);
assert(pxShift != NULL);
assert(pyShift != NULL);
*pxShift = f->Tex.xShift;
*pyShift = f->Tex.yShift;
}
geFloat Face_GetTextureRotate(const Face *f)
{
assert(f != NULL);
return f->Tex.Rotate;
}
static void Face_UpdateLockedTextureVecs
(
Face *f
)
{
geXForm3d XfmTexture;
TexInfo *t = &f->Tex;
assert (t != NULL);
// assert (t->xScale != 0.0f);
// assert (t->yScale != 0.0f);
#pragma message ("this is an ugly hack. Values should never be == 0.")
if (t->xScale == 0.0f) t->xScale = 1.0f;
if (t->yScale == 0.0f) t->yScale = 1.0f;
// the normal has to be normal, no?
assert ((t->VecNormal.X != 0.0f) ||
(t->VecNormal.Y != 0.0f) ||
(t->VecNormal.Z != 0.0f));
// Compute rotation
geVec3d_Clear (&t->XfmFaceAngle.Translation);
// g3dc tuning comment: the old gedit line was causing texlocked faces to rotate
// in the OPPOSITE direction... I'm not sure why.
// geXForm3d_SetZRotation (&XfmTexture, Units_DegreesToRadians (-t->Rotate)); // old gedit
// geXForm3d_SetZRotation (&XfmTexture, Units_DegreesToRadians (t->Rotate)); // new g3dc
// new g3dc
// This code implemented in order to increase the consistency of texture
// orientation when toggling a face between Locked and unlocked texture
// mode.The below code works best for cubes positined square along world
// xyz axes. But it fails when cubes are oriented otherwise. Also, more
// complex geomentric shapes receive almost no benefit from this code...
// Must check x, y, z in order to match tools.
int WhichAxis = 0; // sides
if (fabs (t->VecNormal.Y) > fabs (t->VecNormal.X))
{
if (fabs (t->VecNormal.Z) > fabs (t->VecNormal.Y))
{
WhichAxis = 2; // front / back
}
else
{
WhichAxis = 1; // top / bottom
}
}
else if (fabs (t->VecNormal.Z) > fabs (t->VecNormal.X))
{
WhichAxis = 2;
}
switch (WhichAxis)
{
case 0: // sides
geXForm3d_SetZRotation (&XfmTexture, Units_DegreesToRadians (t->Rotate)); // new g3dc
geXForm3d_Multiply (&t->XfmFaceAngle, &XfmTexture, &XfmTexture); // old gedit
geVec3d_Set (&t->TVecs.uVec, XfmTexture.AX, -XfmTexture.BX, -XfmTexture.CX); // old gedit
geVec3d_Set (&t->TVecs.vVec, XfmTexture.AY, -XfmTexture.BY, -XfmTexture.CY); // old gedit
break;
case 1: // top / bottom
geXForm3d_SetZRotation (&XfmTexture, Units_DegreesToRadians (-t->Rotate)); // new g3dc
geXForm3d_Multiply (&t->XfmFaceAngle, &XfmTexture, &XfmTexture); // old gedit
geVec3d_Set (&t->TVecs.uVec, XfmTexture.AX, -XfmTexture.BX, -XfmTexture.CX); // old gedit
geVec3d_Set (&t->TVecs.vVec, XfmTexture.AY, -XfmTexture.BY, -XfmTexture.CY); // old gedit
break;
case 2: // front / back
geXForm3d_SetZRotation (&XfmTexture, Units_DegreesToRadians (t->Rotate)); // new g3dc
geXForm3d_Multiply (&t->XfmFaceAngle, &XfmTexture, &XfmTexture); // old gedit
geVec3d_Set (&t->TVecs.uVec, XfmTexture.AX, XfmTexture.BX, XfmTexture.CX); // old gedit
geVec3d_Set (&t->TVecs.vVec, XfmTexture.AY, XfmTexture.BY, XfmTexture.CY); // old gedit
break;
}
// geXForm3d_Multiply (&t->XfmFaceAngle, &XfmTexture, &XfmTexture); // old gedit
// get info from transform into texture vectors.
// geVec3d_Set (&t->TVecs.uVec, XfmTexture.AX, XfmTexture.BX, XfmTexture.CX); // old gedit
// geVec3d_Set (&t->TVecs.vVec, XfmTexture.AY, XfmTexture.BY, XfmTexture.CY); // old gedit
// and scale accordingly
geVec3d_Scale (&t->TVecs.uVec, 1.0f/t->xScale, &t->TVecs.uVec);
geVec3d_Scale (&t->TVecs.vVec, 1.0f/t->yScale, &t->TVecs.vVec);
// compute offsets...
{
geFloat uOffset, vOffset;
uOffset = geVec3d_DotProduct (&t->TVecs.uVec, &f->Tex.Pos);
vOffset = geVec3d_DotProduct (&t->TVecs.vVec, &f->Tex.Pos);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -