566 lines
11 KiB
C++
566 lines
11 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Logfile:: /fakk2_code/Utils/max2skl/fixmirror.cpp $
|
|
// $Revision:: 2 $
|
|
// $Date:: 6/16/00 4:15p $
|
|
//
|
|
// Copyright (C) 1999 by Ritual Entertainment, Inc.
|
|
// All rights reserved.
|
|
//
|
|
// This source is may not be distributed and/or modified without
|
|
// expressly written permission by Ritual Entertainment, Inc.
|
|
//
|
|
// $Log:: /fakk2_code/Utils/max2skl/fixmirror.cpp $
|
|
//
|
|
// 2 6/16/00 4:15p Markd
|
|
// Added more error checking for exceeding max verts
|
|
//
|
|
// 1 4/25/00 11:30a Jimdose
|
|
//
|
|
// 2 4/17/00 2:55p Jimdose
|
|
// created file
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
|
|
#include "fixmirror.h"
|
|
#include "max2skl.h"
|
|
|
|
#define SIGN( x ) ( ( x < 0 ) ? -1 : ( ( x > 0 ) ? 1 : 0 ) )
|
|
|
|
List<Vert *> vertices;
|
|
List<Tri *> triangles;
|
|
|
|
Tri::Tri
|
|
(
|
|
Vert *v0,
|
|
Vert *v1,
|
|
Vert *v2
|
|
)
|
|
|
|
{
|
|
int i;
|
|
int j;
|
|
|
|
assert( v0 != v1 && v1 != v2 && v2 != v0 );
|
|
|
|
vertex[ 0 ] = v0;
|
|
vertex[ 1 ] = v1;
|
|
vertex[ 2 ] = v2;
|
|
|
|
ComputeNormal();
|
|
triangles.Add( this );
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
{
|
|
vertex[ i ]->face.Add( this );
|
|
for( j = 0; j < 3; j++ )
|
|
{
|
|
if ( i != j )
|
|
{
|
|
vertex[ i ]->neighbor.AddUnique( vertex[ j ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
modified = v0->modified || v1->modified || v2->modified;
|
|
}
|
|
|
|
Tri::~Tri()
|
|
{
|
|
int i;
|
|
int j;
|
|
|
|
triangles.Remove( this );
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
{
|
|
if ( vertex[ i ] )
|
|
{
|
|
vertex[ i ]->face.Remove( this );
|
|
}
|
|
}
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
{
|
|
j = ( i + 1 ) % 3;
|
|
|
|
if ( !vertex[ i ] || !vertex[ j ] )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
vertex[ i ]->RemoveIfNonNeighbor( vertex[ j ] );
|
|
vertex[ j ]->RemoveIfNonNeighbor( vertex[ i ] );
|
|
}
|
|
}
|
|
|
|
int Tri::HasVertex
|
|
(
|
|
Vert *v
|
|
)
|
|
|
|
{
|
|
return ( v == vertex[ 0 ] || v == vertex[ 1 ] || v == vertex[ 2 ] );
|
|
}
|
|
|
|
void Tri::ComputeNormal
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
Vector v0;
|
|
Vector v1;
|
|
Vector v2;
|
|
|
|
v0 = vertex[ 0 ]->position;
|
|
v1 = vertex[ 1 ]->position;
|
|
v2 = vertex[ 2 ]->position;
|
|
|
|
normal = ( v1 - v0 ) * ( v2 - v1 );
|
|
if ( magnitude( normal ) == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
normal = normalize( normal );
|
|
}
|
|
|
|
void Tri::InvertFace
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
Vert *t;
|
|
|
|
t = vertex[ 0 ];
|
|
vertex[ 0 ] = vertex[ 2 ];
|
|
vertex[ 2 ] = t;
|
|
|
|
ComputeNormal();
|
|
}
|
|
|
|
Tri *Tri::GetAdjacentTriangle
|
|
(
|
|
int edge
|
|
)
|
|
|
|
{
|
|
int i;
|
|
Vert *u;
|
|
Vert *v;
|
|
Tri *tri;
|
|
|
|
u = vertex[ edge ];
|
|
v = vertex[ ( edge + 1 ) % 3 ];
|
|
|
|
for( i = 0; i < u->face.num; i++ )
|
|
{
|
|
tri = u->face[ i ];
|
|
if ( ( tri != this ) && tri->HasVertex( v ) )
|
|
{
|
|
return tri;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
Vector ProjectPointOnPlane
|
|
(
|
|
const Vector p,
|
|
const Vector normal
|
|
)
|
|
|
|
{
|
|
float d;
|
|
Vector n;
|
|
float inv_denom;
|
|
|
|
inv_denom = 1.0F / ( normal ^ normal ); // ^ is dot product
|
|
|
|
d = ( normal ^ p ) * inv_denom; // ^ is dot product
|
|
|
|
n = normal * inv_denom;
|
|
|
|
return p - d * n;
|
|
}
|
|
|
|
////////////////////////
|
|
// PerpendicularVector
|
|
// assumes "src" is normalized
|
|
////////////////////////
|
|
Vector PerpendicularVector
|
|
(
|
|
const Vector src
|
|
)
|
|
|
|
{
|
|
int pos;
|
|
int i;
|
|
float minelem;
|
|
Vector tempvec;
|
|
Vector dst;
|
|
|
|
minelem = 1.0F;
|
|
|
|
// find the smallest magnitude axially aligned vector
|
|
for( pos = 0, i = 0; i < 3; i++ )
|
|
{
|
|
if ( fabs( src[ i ] ) < minelem )
|
|
{
|
|
pos = i;
|
|
minelem = fabs( src[ i ] );
|
|
}
|
|
}
|
|
|
|
tempvec[ pos ] = 1.0F;
|
|
|
|
// project the point onto the plane defined by src
|
|
dst = ProjectPointOnPlane( tempvec, src );
|
|
|
|
// normalize the result
|
|
return normalize( dst );
|
|
}
|
|
|
|
Vector RotatePointAroundVector
|
|
(
|
|
const Vector dir,
|
|
const Vector point,
|
|
float degrees
|
|
)
|
|
|
|
{
|
|
matrix im;
|
|
matrix zrot;
|
|
matrix tmpmat;
|
|
matrix rot;
|
|
Vector vr;
|
|
Vector vup;
|
|
Vector vf;
|
|
float rad;
|
|
|
|
vf = dir;
|
|
vr = PerpendicularVector( dir );
|
|
vup = vr * vf; // Note: * is Cross product for Vector
|
|
|
|
matrix m( vr, vup, vf );
|
|
im = transpose( m );
|
|
|
|
rad = DEG2RAD( degrees );
|
|
zrot.x[0] = cos( rad );
|
|
zrot.x[1] = sin( rad );
|
|
zrot.y[0] = -sin( rad );
|
|
zrot.y[1] = cos( rad );
|
|
|
|
tmpmat = m * zrot;
|
|
rot = tmpmat * im;
|
|
|
|
return rot * point;
|
|
}
|
|
|
|
#define CANTFLIP -1
|
|
#define NOTREADYTOFLIP -2
|
|
#define DONTFLIP 0
|
|
#define FLIP 1
|
|
|
|
int Tri::CheckFlip
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
int i;
|
|
int edge;
|
|
Tri *tri;
|
|
Vert *u;
|
|
Vert *v;
|
|
Vert *w1;
|
|
Vert *w2;
|
|
Vector edgevec;
|
|
Vector midpoint;
|
|
Vector perp1;
|
|
Vector perp2;
|
|
float d1;
|
|
float d2;
|
|
|
|
if ( !modified )
|
|
{
|
|
return CANTFLIP;
|
|
}
|
|
|
|
for( edge = 0; edge < 3; edge++ )
|
|
{
|
|
tri = GetAdjacentTriangle( edge );
|
|
if ( tri && !tri->modified )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !tri || tri->modified )
|
|
{
|
|
return NOTREADYTOFLIP;
|
|
}
|
|
|
|
u = vertex[ edge ];
|
|
v = vertex[ ( edge + 1 ) % 3 ];
|
|
w1 = vertex[ ( edge + 2 ) % 3 ];
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
{
|
|
w2 = tri->vertex[ i ];
|
|
if ( ( w2 != u ) && ( w2 != v ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
edgevec = normalize( v->position - u->position );
|
|
perp1 = normal * edgevec; // NOTE : ^ is crossproduct
|
|
perp2 = edgevec * tri->normal; // NOTE : ^ is crossproduct
|
|
|
|
d1 = perp1 ^ perp2;
|
|
if ( d1 > 0.99f )
|
|
{
|
|
// triangles are folded against each other,
|
|
// so normals should be nearly opposite each other
|
|
d2 = normal ^ tri->normal;
|
|
return d2 < 0;
|
|
}
|
|
|
|
// generate a point between the two triangles and make
|
|
// sure it's in front of or in back of both triangles
|
|
midpoint = normalize( perp1 + perp2 );
|
|
|
|
d1 = midpoint ^ normal;
|
|
d2 = midpoint ^ tri->normal;
|
|
|
|
return ( SIGN( d1 ) != SIGN( d2 ) );
|
|
}
|
|
|
|
Vert::Vert
|
|
(
|
|
Vector v,
|
|
bool mod
|
|
)
|
|
|
|
{
|
|
position = v;
|
|
modified = mod;
|
|
vertices.Add( this );
|
|
}
|
|
|
|
Vert::~Vert()
|
|
{
|
|
assert( face.num == 0 );
|
|
|
|
while( neighbor.num )
|
|
{
|
|
neighbor[ neighbor.num - 1 ]->neighbor.Remove( this );
|
|
neighbor.Remove( neighbor[ neighbor.num - 1 ] );
|
|
}
|
|
|
|
vertices.Remove( this );
|
|
}
|
|
|
|
void Vert::RemoveIfNonNeighbor
|
|
(
|
|
Vert *n
|
|
)
|
|
|
|
{
|
|
int i;
|
|
|
|
// removes n from neighbor list if n isn't a neighbor.
|
|
if ( !neighbor.Contains( n ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
for( i = 0; i < face.num; i++ )
|
|
{
|
|
if ( face[ i ]->HasVertex( n ) )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
neighbor.Remove( n );
|
|
}
|
|
|
|
void ClearLists
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
int i;
|
|
|
|
for( i = triangles.num - 1; i >= 0; i-- )
|
|
{
|
|
delete triangles[ i ];
|
|
}
|
|
|
|
for( i = vertices.num - 1; i >= 0; i-- )
|
|
{
|
|
delete vertices[ i ];
|
|
}
|
|
}
|
|
|
|
void SkelModel::FixMirroredBones
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
int i;
|
|
int j;
|
|
loadframe_t *frame;
|
|
loadbone_t *bone;
|
|
UMat3 mats[ MAX_BONES ];
|
|
UMat3 mat;
|
|
loadvertx_t *vert;
|
|
blendvert_t *blend;
|
|
UVector3 temp;
|
|
UVector3 offset;
|
|
vec3_t newVerts[ TIKI_MAX_VERTS ];
|
|
bool modified[ TIKI_MAX_VERTS ];
|
|
Vert *v;
|
|
Tri *t;
|
|
Vector vec;
|
|
int nummod;
|
|
int flip;
|
|
int numfixed;
|
|
loadfacevertx_t tv;
|
|
|
|
if ( model.numverts > TIKI_MAX_VERTS )
|
|
{
|
|
Error( "Too many vertices %d out of %d in model %s\n", model.numverts, TIKI_MAX_VERTS, model.name );
|
|
}
|
|
// precalculate the first frame
|
|
bone = model.anim->bones;
|
|
for( i = 0; i < model.numbones; i++, bone++ )
|
|
{
|
|
mats[ i ] = *( UMat3 * )bone->matrix;
|
|
}
|
|
|
|
// fix all the frames
|
|
frame = model.anim;
|
|
for( i = 0; i < model.numframes; i++, frame++ )
|
|
{
|
|
bone = frame->bones;
|
|
for( j = 0; j < model.numbones; j++, bone++ )
|
|
{
|
|
( *( UMat3 * )bone->matrix ).OrthoNormalize();
|
|
}
|
|
}
|
|
|
|
// convert all the verts to the new coordinate system
|
|
bone = model.anim->bones;
|
|
vert = model.verts;
|
|
nummod = 0;
|
|
for( i = 0; i < model.numverts; i++, vert++ )
|
|
{
|
|
modified[ i ] = false;
|
|
|
|
blend = vert->blend;
|
|
for( j = 0; j < vert->numbones; j++, blend++ )
|
|
{
|
|
bone = &model.anim->bones[ blend->bone ];
|
|
|
|
mat = *( UMat3 * )bone->matrix;
|
|
|
|
mats[ blend->bone ].UnprojectVector( blend->offset, temp );
|
|
mat.ProjectVector( temp, offset );
|
|
|
|
if ( ( SIGN( offset.x ) != SIGN( blend->offset[ 0 ] ) ) ||
|
|
( SIGN( offset.y ) != SIGN( blend->offset[ 1 ] ) ) ||
|
|
( SIGN( offset.z ) != SIGN( blend->offset[ 2 ] ) ) )
|
|
{
|
|
modified[ i ] = true;
|
|
nummod++;
|
|
}
|
|
|
|
blend->offset[ 0 ] = offset[ 0 ];
|
|
blend->offset[ 1 ] = offset[ 1 ];
|
|
blend->offset[ 2 ] = offset[ 2 ];
|
|
|
|
if ( j == 0 )
|
|
{
|
|
mats[ blend->bone ].ProjectVector( vert->normal, temp );
|
|
mat.UnprojectVector( temp, offset );
|
|
|
|
vert->normal[ 0 ] = offset.x;
|
|
vert->normal[ 1 ] = offset.y;
|
|
vert->normal[ 2 ] = offset.z;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !nummod )
|
|
{
|
|
return;
|
|
}
|
|
|
|
CalcFrame( 0, newVerts );
|
|
|
|
// convert vertices
|
|
for( i = 0; i < model.numverts; i++ )
|
|
{
|
|
vec = Vector( newVerts[ i ][ 0 ], newVerts[ i ][ 1 ], newVerts[ i ][ 2 ] );
|
|
v = new Vert( vec, modified[ i ] );
|
|
}
|
|
|
|
// convert triangles
|
|
nummod = 0;
|
|
for( i = 0; i < model.numfaces; i++ )
|
|
{
|
|
t = new Tri(
|
|
vertices[ model.faces[ i ].verts[ 0 ].vertindex ],
|
|
vertices[ model.faces[ i ].verts[ 1 ].vertindex ],
|
|
vertices[ model.faces[ i ].verts[ 2 ].vertindex ]
|
|
);
|
|
|
|
if ( t->modified )
|
|
{
|
|
nummod++;
|
|
}
|
|
}
|
|
|
|
numfixed = 1;
|
|
while( ( nummod > 0 ) && ( numfixed > 0 ) )
|
|
{
|
|
numfixed = 0;
|
|
nummod = 0;
|
|
for( i = 0; i < triangles.num; i++ )
|
|
{
|
|
if ( triangles[ i ]->modified )
|
|
{
|
|
flip = triangles[ i ]->CheckFlip();
|
|
if ( flip != CANTFLIP )
|
|
{
|
|
nummod++;
|
|
triangles[ i ]->modified = ( flip == NOTREADYTOFLIP );
|
|
if ( flip == FLIP )
|
|
{
|
|
triangles[ i ]->InvertFace();
|
|
numfixed++;
|
|
|
|
memcpy( &tv, &model.faces[ i ].verts[ 0 ], sizeof( loadfacevertx_t ) );
|
|
memcpy( &model.faces[ i ].verts[ 0 ], &model.faces[ i ].verts[ 2 ], sizeof( loadfacevertx_t ) );
|
|
memcpy( &model.faces[ i ].verts[ 2 ], &tv, sizeof( loadfacevertx_t ) );
|
|
}
|
|
else if ( flip == DONTFLIP )
|
|
{
|
|
numfixed++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ClearLists();
|
|
}
|