doom3-bfg/neo/tools/compilers/dmap/glfile.cpp

596 lines
13 KiB
C++
Raw Normal View History

/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
Copyright (C) 2015 Robert Beckebans
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "precompiled.h"
#pragma hdrstop
#include "dmap.h"
struct OBJFace
{
OBJFace()
{
material = nullptr;
}
const idMaterial* material;
idList<idDrawVert> verts;
idList<triIndex_t> indexes;
};
struct OBJGroup
{
idStr name;
//idList<OBJObject> objects;
idList<OBJFace> faces;
};
int PortalVisibleSides( uPortal_t* p )
{
int fcon, bcon;
if( !p->onnode )
return 0; // outside
fcon = p->nodes[0]->opaque;
bcon = p->nodes[1]->opaque;
// same contents never create a face
if( fcon == bcon )
return 0;
if( !fcon )
return 1;
if( !bcon )
return 2;
return 0;
}
void OutputWinding( idWinding* w, OBJGroup& group )
{
static int level = 128;
float light;
int i;
level += 28;
light = ( level & 255 ) / 255.0;
OBJFace& face = group.faces.Alloc();
//for( i = 0; i < w->GetNumPoints(); i++ )
for( i = w->GetNumPoints() - 1; i >= 0; i-- )
{
idDrawVert& dv = face.verts.Alloc();
dv.xyz.x = ( *w )[i][0];
dv.xyz.y = ( *w )[i][1];
dv.xyz.z = ( *w )[i][2];
dv.SetColor( level & 255 );
//dv.SetNormal( w->GetPlane() )
}
}
/*
void OutputWinding( const idFixedWinding& w, OBJGroup& group )
{
static int level = 128;
float light;
int i;
level += 28;
light = ( level & 255 ) / 255.0;
OBJFace& face = group.faces.Alloc();
//for( i = 0; i < w->GetNumPoints(); i++ )
for( i = w.GetNumPoints() - 1; i >= 0; i-- )
{
idDrawVert& dv = face.verts.Alloc();
dv.xyz.x = ( w )[i][0];
dv.xyz.y = ( w )[i][1];
dv.xyz.z = ( w )[i][2];
dv.SetColor( level & 255 );
//dv.SetNormal( w->GetPlane() )
}
}
*/
/*
=============
OutputPortal
=============
*/
void OutputPortal( uPortal_t* p, OBJGroup& group )
{
idWinding* w;
int sides;
sides = PortalVisibleSides( p );
if( !sides )
{
return;
}
//c_glfaces++;
w = p->winding;
if( sides == 2 ) // back side
{
w = w->Reverse();
}
OutputWinding( w, group );
if( sides == 2 )
{
delete w;
}
}
void CollectPortals_r( node_t* node, OBJGroup& group )
{
uPortal_t* p, *nextp;
if( node->planenum != PLANENUM_LEAF )
{
CollectPortals_r( node->children[0], group );
CollectPortals_r( node->children[1], group );
return;
}
// write all the portals
for( p = node->portals; p; p = nextp )
{
if( p->nodes[0] == node )
{
OutputPortal( p, group );
nextp = p->next[0];
}
else
{
nextp = p->next[1];
}
}
}
void OutputQuad( const idVec3 verts[4], OBJGroup* group, bool reverse )
{
OBJFace& face = group->faces.Alloc();
idDrawVert& dv0 = face.verts.Alloc();
idDrawVert& dv1 = face.verts.Alloc();
idDrawVert& dv2 = face.verts.Alloc();
idDrawVert& dv3 = face.verts.Alloc();
if( reverse )
{
dv0.xyz = verts[3];
dv1.xyz = verts[2];
dv2.xyz = verts[1];
dv3.xyz = verts[0];
}
else
{
dv0.xyz = verts[0];
dv1.xyz = verts[1];
dv2.xyz = verts[2];
dv3.xyz = verts[3];
}
}
void OutputNode( const node_t* node, idList<OBJGroup>& groups )
{
const idBounds& bounds = node->bounds;
if( bounds.IsCleared() )
{
return;
}
OBJGroup* group = NULL;
bool reverse = false;
if( node->planenum == PLANENUM_LEAF )
{
if( node->occupied )
{
group = &groups.Alloc();
group->name.Format( "area%i_leaf_occupied.%i", node->area, node->nodeNumber );
}
else if( node->opaque )
{
group = &groups.Alloc();
if( node->area != -1 )
{
group->name.Format( "area%i_leaf_opaque.%i", node->area, node->nodeNumber );
}
else
{
group->name.Format( "void_leaf_opaque.%i", node->nodeNumber );
}
reverse = true;
}
else
{
group = &groups.Alloc();
if( node->area != -1 )
{
group->name.Format( "area%i_leaf.%i", node->area, node->nodeNumber );
}
else
{
group->name.Format( "void_leaf.%i", node->nodeNumber );
}
}
}
else
{
//group = &groups.Alloc();
//group->name.Format( "node.%i", node->nodeNumber ) ;
}
if( group )
{
idVec3 verts[4];
verts[0].Set( bounds[0][0], bounds[0][1], bounds[0][2] );
verts[1].Set( bounds[0][0], bounds[1][1], bounds[0][2] );
verts[2].Set( bounds[0][0], bounds[1][1], bounds[1][2] );
verts[3].Set( bounds[0][0], bounds[0][1], bounds[1][2] );
OutputQuad( verts, group, reverse );
verts[0].Set( bounds[1][0], bounds[0][1], bounds[1][2] );
verts[1].Set( bounds[1][0], bounds[1][1], bounds[1][2] );
verts[2].Set( bounds[1][0], bounds[1][1], bounds[0][2] );
verts[3].Set( bounds[1][0], bounds[0][1], bounds[0][2] );
OutputQuad( verts, group, reverse );
verts[0].Set( bounds[0][0], bounds[0][1], bounds[1][2] );
verts[1].Set( bounds[0][0], bounds[1][1], bounds[1][2] );
verts[2].Set( bounds[1][0], bounds[1][1], bounds[1][2] );
verts[3].Set( bounds[1][0], bounds[0][1], bounds[1][2] );
OutputQuad( verts, group, reverse );
verts[0].Set( bounds[1][0], bounds[0][1], bounds[0][2] );
verts[1].Set( bounds[1][0], bounds[1][1], bounds[0][2] );
verts[2].Set( bounds[0][0], bounds[1][1], bounds[0][2] );
verts[3].Set( bounds[0][0], bounds[0][1], bounds[0][2] );
OutputQuad( verts, group, reverse );
verts[0].Set( bounds[0][0], bounds[0][1], bounds[0][2] );
verts[1].Set( bounds[0][0], bounds[0][1], bounds[1][2] );
verts[2].Set( bounds[1][0], bounds[0][1], bounds[1][2] );
verts[3].Set( bounds[1][0], bounds[0][1], bounds[0][2] );
OutputQuad( verts, group, reverse );
verts[0].Set( bounds[1][0], bounds[1][1], bounds[0][2] );
verts[1].Set( bounds[1][0], bounds[1][1], bounds[1][2] );
verts[2].Set( bounds[0][0], bounds[1][1], bounds[1][2] );
verts[3].Set( bounds[0][0], bounds[1][1], bounds[0][2] );
OutputQuad( verts, group, reverse );
}
}
void OutputSplitPlane( const node_t* node, idList<OBJGroup>& groups )
{
const idBounds& bounds = node->bounds;
if( bounds.IsCleared() )
{
return;
}
OBJGroup* group = NULL;
bool reverse = false;
if( node->planenum != PLANENUM_LEAF )
{
idPlane plane;
idFixedWinding w;
w.BaseForPlane( dmapGlobals.mapPlanes[node->planenum] );
group = &groups.Alloc();
group->name.Format( "splitplane.%i", node->nodeNumber ) ;
// cut down to AABB size
for( int i = 0 ; i < 3 ; i++ )
{
plane[0] = plane[1] = plane[2] = 0;
plane[i] = 1;
plane[3] = -bounds[1][i];
w.ClipInPlace( -plane );
plane[i] = -1;
plane[3] = bounds[0][i];
w.ClipInPlace( -plane );
}
OutputWinding( &w, *group );
}
}
void OutputAreaPortalTriangles( const node_t* node, idList<OBJGroup>& groups )
{
const idBounds& bounds = node->bounds;
if( bounds.IsCleared() )
{
return;
}
if( node->planenum == PLANENUM_LEAF && node->areaPortalTris )
{
OBJGroup& group = groups.Alloc();
group.name.Format( "areaPortalTris.%i", node->nodeNumber ) ;
for( mapTri_t* tri = node->areaPortalTris; tri; tri = tri->next )
{
OBJFace& face = group.faces.Alloc();
for( int i = 0; i < 3; i++ )
{
idDrawVert& dv = face.verts.Alloc();
dv = tri->v[i];
}
}
}
}
void CollectNodes_r( node_t* node, idList<OBJGroup>& groups )
{
OutputNode( node, groups );
OutputSplitPlane( node, groups );
OutputAreaPortalTriangles( node, groups );
if( node->planenum != PLANENUM_LEAF )
{
CollectNodes_r( node->children[0], groups );
CollectNodes_r( node->children[1], groups );
return;
}
}
int NumberNodes_r( node_t* node, int nextNode, int& nextLeaf )
{
if( node->planenum == PLANENUM_LEAF )
{
node->nodeNumber = nextLeaf++;
return nextNode;
}
node->nodeNumber = nextNode;
nextNode++;
nextNode = NumberNodes_r( node->children[0], nextNode, nextLeaf );
nextNode = NumberNodes_r( node->children[1], nextNode, nextLeaf );
return nextNode;
}
void OutputAreaPortals( idList<OBJGroup>& groups )
{
int i;
interAreaPortal_t* iap;
idWinding* w;
for( i = 0; i < interAreaPortals.Num(); i++ )
{
iap = &interAreaPortals[i];
if( iap->side )
{
w = iap->side->winding;
}
else
{
w = & iap->w;
}
OBJGroup& group = groups.Alloc();
group.name.Format( "interAreaPortal.%i", i );
OutputWinding( w, group );
}
}
/*
=============
WriteGLView
=============
*/
void WriteGLView( tree_t* tree, const char* source, int entityNum, bool force )
{
//c_glfaces = 0;
//common->Printf( "Writing %s\n", source );
if( entityNum != 0 && !force )
{
return;
}
idStrStatic< MAX_OSPATH > path;
path.Format( "%s_BSP_%s_%i.obj", dmapGlobals.mapFileBase, source, entityNum );
idFileLocal objFile( fileSystem->OpenFileWrite( path, "fs_basepath" ) );
//path.SetFileExtension( ".mtl" );
//idFileLocal mtlFile( fileSystem->OpenFileWrite( path, "fs_basepath" ) );
idList<OBJGroup> groups;
OBJGroup& portals = groups.Alloc();
portals.name = "portals";
CollectPortals_r( tree->headnode, portals );
common->Printf( "%5i c_glfaces\n", portals.faces.Num() );
int numLeafs = 0;
int numNodes = NumberNodes_r( tree->headnode, 0, numLeafs );
CollectNodes_r( tree->headnode, groups );
if( entityNum == 0 )
{
OutputAreaPortals( groups );
}
int numVerts = 0;
for( int g = 0; g < groups.Num(); g++ )
{
const OBJGroup& group = groups[g];
objFile->Printf( "g %s\n", group.name.c_str() );
for( int i = 0; i < group.faces.Num(); i++ )
{
const OBJFace& face = group.faces[i];
for( int j = 0; j < face.verts.Num(); j++ )
{
const idVec3& v = face.verts[j].xyz;
objFile->Printf( "v %1.6f %1.6f %1.6f\n", v.x, v.y, v.z );
}
/*
for( int j = 0; j < face.verts.Num(); j++ )
{
const idVec2& vST = face.verts[j].GetTexCoord();
objFile->Printf( "vt %1.6f %1.6f\n", vST.x, vST.y );
}
for( int j = 0; j < face.verts.Num(); j++ )
{
const idVec3& n = face.verts[j].GetNormal();
objFile->Printf( "vn %1.6f %1.6f %1.6f\n", n.x, n.y, n.z );
}
objFile->Printf( "usemtl %s\n", face.material->GetName() );
*/
//for( int j = 0; j < face.indexes.Num(); j += 3 )
objFile->Printf( "f " );
for( int j = 0; j < face.verts.Num(); j++ )
{
objFile->Printf( "%i// ", numVerts + 1 + j );
}
numVerts += face.verts.Num();
objFile->Printf( "\n\n" );
}
}
}
void WriteGLView( bspface_t* list, const char* source )
{
if( dmapGlobals.entityNum != 0 )
{
return;
}
idStrStatic< MAX_OSPATH > path;
path.Format( "%s_BSP_%s_%i.obj", dmapGlobals.mapFileBase, source, dmapGlobals.entityNum );
idFileLocal objFile( fileSystem->OpenFileWrite( path, "fs_basepath" ) );
//path.SetFileExtension( ".mtl" );
//idFileLocal mtlFile( fileSystem->OpenFileWrite( path, "fs_basepath" ) );
idList<OBJFace> faces;
for( bspface_t* face = list ; face ; face = face->next )
{
OBJFace& objFace = faces.Alloc();
for( int i = 0; i < face->w->GetNumPoints(); i++ )
//for( int i = face->w->GetNumPoints() - 1; i >= 0; i-- )
{
idDrawVert& dv = objFace.verts.Alloc();
dv.xyz.x = ( *face->w )[i][0];
dv.xyz.y = ( *face->w )[i][1];
dv.xyz.z = ( *face->w )[i][2];
//dv.SetColor( level & 255 );
}
}
//common->Printf( "%5i c_glfaces\n", faces.Num() );
int numVerts = 0;
for( int i = 0; i < faces.Num(); i++ )
{
OBJFace& face = faces[i];
for( int j = 0; j < face.verts.Num(); j++ )
{
const idVec3& v = face.verts[j].xyz;
objFile->Printf( "v %1.6f %1.6f %1.6f\n", v.x, v.y, v.z );
}
objFile->Printf( "f " );
for( int j = 0; j < face.verts.Num(); j++ )
{
objFile->Printf( "%i// ", numVerts + 1 + j );
}
numVerts += face.verts.Num();
objFile->Printf( "\n\n" );
}
}