mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-04-24 10:38:53 +00:00
Added OBJ model support based on IcedTech 1
This commit is contained in:
parent
742624d3ac
commit
0c5a6bf301
5 changed files with 739 additions and 34 deletions
|
@ -3,8 +3,8 @@
|
|||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2012-2020 Robert Beckebans
|
||||
Copyright (C) 2014-2016 Kot in Action Creative Artel
|
||||
Copyright (C) 2012-2021 Robert Beckebans
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
|
@ -38,6 +38,7 @@ If you have questions concerning this license or the applicable additional terms
|
|||
#include "Model_lwo.h"
|
||||
#include "Model_ma.h"
|
||||
#include "Model_ColladaParser.h"
|
||||
#include "Model_obj.h"
|
||||
|
||||
idCVar idRenderModelStatic::r_mergeModelSurfaces( "r_mergeModelSurfaces", "1", CVAR_BOOL | CVAR_RENDERER, "combine model surfaces with the same material" );
|
||||
idCVar idRenderModelStatic::r_slopVertex( "r_slopVertex", "0.01", CVAR_RENDERER, "merge xyz coordinates this far apart" );
|
||||
|
@ -320,13 +321,18 @@ void idRenderModelStatic::InitFromFile( const char* fileName )
|
|||
loaded = LoadASE( name, &sourceTimeStamp );
|
||||
reloadable = true;
|
||||
}
|
||||
// RB: added dae
|
||||
// RB: Collada DAE and Wavefront OBJ
|
||||
else if( extension.Icmp( "dae" ) == 0 )
|
||||
{
|
||||
loaded = LoadDAE( name, &sourceTimeStamp );
|
||||
reloadable = true;
|
||||
}
|
||||
// RB end
|
||||
else if( extension.Icmp( "obj" ) == 0 )
|
||||
{
|
||||
loaded = LoadOBJ( name, &sourceTimeStamp );
|
||||
reloadable = true;
|
||||
}
|
||||
// RB end
|
||||
else if( extension.Icmp( "lwo" ) == 0 )
|
||||
{
|
||||
loaded = LoadLWO( name, &sourceTimeStamp );
|
||||
|
@ -1343,8 +1349,6 @@ bool idRenderModelStatic::ConvertDAEToModelSurfaces( const ColladaParser* dae )
|
|||
matchVert_t* lastmv;
|
||||
matchVert_t* mv;
|
||||
idVec3 normal;
|
||||
float uOffset, vOffset, textureSin, textureCos;
|
||||
float uTiling, vTiling;
|
||||
int* mergeTo;
|
||||
byte* color;
|
||||
static byte identityColor[4] = { 255, 255, 255, 255 };
|
||||
|
@ -1753,27 +1757,6 @@ bool idRenderModelStatic::ConvertDAEToModelSurfaces( const ColladaParser* dae )
|
|||
common->FatalError( "ConvertDAEToModelSurfaces: vertex miscount in DAE file %s", name.c_str() );
|
||||
}
|
||||
|
||||
// an ASE allows the texture coordinates to be scaled, translated, and rotated
|
||||
//if( ase->materials.Num() == 0 )
|
||||
{
|
||||
uOffset = vOffset = 0.0f;
|
||||
uTiling = vTiling = 1.0f;
|
||||
textureSin = 0.0f;
|
||||
textureCos = 1.0f;
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
material = ase->materials[object->materialRef];
|
||||
uOffset = -material->uOffset;
|
||||
vOffset = material->vOffset;
|
||||
uTiling = material->uTiling;
|
||||
vTiling = material->vTiling;
|
||||
textureSin = idMath::Sin( material->angle );
|
||||
textureCos = idMath::Cos( material->angle );
|
||||
}
|
||||
*/
|
||||
|
||||
// now allocate and generate the combined vertexes
|
||||
R_AllocStaticTriSurfVerts( tri, tri->numVerts );
|
||||
for( j = 0; j < tri->numVerts; j++ )
|
||||
|
@ -1784,13 +1767,12 @@ bool idRenderModelStatic::ConvertDAEToModelSurfaces( const ColladaParser* dae )
|
|||
tri->verts[ j ].SetNormal( mv->normal );
|
||||
*( unsigned* )tri->verts[j].color = *( unsigned* )mv->color;
|
||||
|
||||
//if( mesh->numTVFaces == mesh->numFaces && mesh->numTVertexes != 0 )
|
||||
if( ( *mesh )->mTexCoords.Num() > 0 )
|
||||
{
|
||||
const idVec2& tv = ( *mesh )->mTexCoords[ mv->tv ];
|
||||
float u = tv.x * uTiling + uOffset;
|
||||
float v = tv.y * vTiling + vOffset;
|
||||
tri->verts[ j ].SetTexCoord( u * textureCos + v * textureSin, u * -textureSin + v * textureCos );
|
||||
float u = tv.x;
|
||||
float v = tv.y;
|
||||
tri->verts[ j ].SetTexCoord( u, v );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1817,6 +1799,364 @@ bool idRenderModelStatic::ConvertDAEToModelSurfaces( const ColladaParser* dae )
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idRenderModelStatic::ConvertOBJToModelSurfaces
|
||||
=================
|
||||
*/
|
||||
bool idRenderModelStatic::ConvertOBJToModelSurfaces( const objModel_t* model )
|
||||
{
|
||||
objObject_t* mesh;
|
||||
const idMaterial* im1, *im2;
|
||||
srfTriangles_t* tri;
|
||||
int objectNum;
|
||||
int i, j;
|
||||
int v, tv;
|
||||
int* vRemap;
|
||||
int* tvRemap;
|
||||
matchVert_t* mvTable; // all of the match verts
|
||||
matchVert_t** mvHash; // points inside mvTable for each xyz index
|
||||
matchVert_t* lastmv;
|
||||
matchVert_t* mv;
|
||||
idVec3 normal;
|
||||
int* mergeTo;
|
||||
byte* color;
|
||||
static byte identityColor[4] = { 255, 255, 255, 255 };
|
||||
modelSurface_t surf, *modelSurf;
|
||||
|
||||
if( !model )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if( model->objects.Num() < 1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
timeStamp = model->timeStamp;
|
||||
|
||||
// the modeling programs can save out multiple surfaces with a common
|
||||
// material, but we would like to mege them together where possible
|
||||
// meaning that this->NumSurfaces() <= ase->objects.currentElements
|
||||
mergeTo = ( int* )_alloca( model->objects.Num() * sizeof( *mergeTo ) );
|
||||
surf.geometry = NULL;
|
||||
/*
|
||||
if( model->materials.Num() == 0 )
|
||||
{
|
||||
// if we don't have any materials, dump everything into a single surface
|
||||
surf.shader = tr.defaultMaterial;
|
||||
surf.id = 0;
|
||||
this->AddSurface( surf );
|
||||
for( i = 0; i < ase->objects.Num(); i++ )
|
||||
{
|
||||
mergeTo[i] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
*/
|
||||
if( !r_mergeModelSurfaces.GetBool() )
|
||||
{
|
||||
// don't merge any
|
||||
for( i = 0; i < model->objects.Num(); i++ )
|
||||
{
|
||||
mergeTo[i] = i;
|
||||
mesh = model->objects[i];
|
||||
|
||||
surf.shader = declManager->FindMaterial( mesh->material );
|
||||
surf.id = this->NumSurfaces();
|
||||
this->AddSurface( surf );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// search for material matches
|
||||
for( i = 0; i < model->objects.Num(); i++ )
|
||||
{
|
||||
mesh = model->objects[i];
|
||||
|
||||
im1 = declManager->FindMaterial( mesh->material );
|
||||
if( im1->IsDiscrete() )
|
||||
{
|
||||
// flares, autosprites, etc
|
||||
j = this->NumSurfaces();
|
||||
}
|
||||
else
|
||||
{
|
||||
for( j = 0; j < this->NumSurfaces(); j++ )
|
||||
{
|
||||
modelSurf = &this->surfaces[j];
|
||||
im2 = modelSurf->shader;
|
||||
if( im1 == im2 )
|
||||
{
|
||||
// merge this
|
||||
mergeTo[i] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( j == this->NumSurfaces() )
|
||||
{
|
||||
// didn't merge
|
||||
mergeTo[i] = j;
|
||||
surf.shader = im1;
|
||||
surf.id = this->NumSurfaces();
|
||||
this->AddSurface( surf );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idVectorSubset<idVec3, 3> vertexSubset;
|
||||
idVectorSubset<idVec2, 2> texCoordSubset;
|
||||
|
||||
// build the surfaces
|
||||
for( objectNum = 0; objectNum < model->objects.Num(); objectNum++ )
|
||||
{
|
||||
mesh = model->objects[objectNum];
|
||||
|
||||
im1 = declManager->FindMaterial( mesh->material );
|
||||
|
||||
bool normalsParsed = mesh->normals.Num();
|
||||
|
||||
// completely ignore any explict normals on surfaces with a renderbump command
|
||||
// which will guarantee the best contours and least vertexes.
|
||||
const char* rb = im1->GetRenderBump();
|
||||
if( rb != NULL && rb[0] != '\0' )
|
||||
{
|
||||
normalsParsed = false;
|
||||
}
|
||||
|
||||
// It seems like the tools our artists are using often generate
|
||||
// verts and texcoords slightly separated that should be merged
|
||||
// note that we really should combine the surfaces with common materials
|
||||
// before doing this operation, because we can miss a slop combination
|
||||
// if they are in different surfaces
|
||||
|
||||
vRemap = ( int* )R_StaticAlloc( mesh->vertexes.Num() * sizeof( vRemap[0] ), TAG_MODEL );
|
||||
|
||||
if( fastLoad )
|
||||
{
|
||||
// renderbump doesn't care about vertex count
|
||||
for( j = 0; j < mesh->vertexes.Num(); j++ )
|
||||
{
|
||||
vRemap[j] = j;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float vertexEpsilon = r_slopVertex.GetFloat();
|
||||
float expand = 2 * 32 * vertexEpsilon;
|
||||
idVec3 mins, maxs;
|
||||
|
||||
SIMDProcessor->MinMax( mins, maxs, &mesh->vertexes[0], mesh->vertexes.Num() );
|
||||
|
||||
mins -= idVec3( expand, expand, expand );
|
||||
maxs += idVec3( expand, expand, expand );
|
||||
|
||||
vertexSubset.Init( mins, maxs, 32, 1024 );
|
||||
for( j = 0; j < mesh->vertexes.Num(); j++ )
|
||||
{
|
||||
vRemap[j] = vertexSubset.FindVector( &mesh->vertexes[0], j, vertexEpsilon );
|
||||
}
|
||||
}
|
||||
|
||||
tvRemap = ( int* )R_StaticAlloc( mesh->texcoords.Num() * sizeof( tvRemap[0] ), TAG_MODEL );
|
||||
|
||||
if( fastLoad )
|
||||
{
|
||||
// renderbump doesn't care about vertex count
|
||||
for( j = 0; j < mesh->texcoords.Num(); j++ )
|
||||
{
|
||||
tvRemap[j] = j;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float texCoordEpsilon = r_slopTexCoord.GetFloat();
|
||||
float expand = 2 * 32 * texCoordEpsilon;
|
||||
idVec2 mins, maxs;
|
||||
|
||||
SIMDProcessor->MinMax( mins, maxs, &mesh->texcoords[0], mesh->texcoords.Num() );
|
||||
|
||||
mins -= idVec2( expand, expand );
|
||||
maxs += idVec2( expand, expand );
|
||||
|
||||
texCoordSubset.Init( mins, maxs, 32, 1024 );
|
||||
|
||||
for( j = 0; j < mesh->texcoords.Num(); j++ )
|
||||
{
|
||||
tvRemap[j] = texCoordSubset.FindVector( &mesh->texcoords[0], j, texCoordEpsilon );
|
||||
}
|
||||
}
|
||||
|
||||
// we need to find out how many unique vertex / texcoord combinations
|
||||
// there are, because ASE tracks them separately but we need them unified
|
||||
|
||||
// the maximum possible number of combined vertexes is the number of indexes
|
||||
mvTable = ( matchVert_t* )R_ClearedStaticAlloc( mesh->indexes.Num() * sizeof( mvTable[0] ) );
|
||||
|
||||
// we will have a hash chain based on the xyz values
|
||||
mvHash = ( matchVert_t** )R_ClearedStaticAlloc( mesh->vertexes.Num() * sizeof( mvHash[0] ) );
|
||||
|
||||
// allocate triangle surface
|
||||
tri = R_AllocStaticTriSurf();
|
||||
tri->numVerts = 0;
|
||||
tri->numIndexes = 0;
|
||||
R_AllocStaticTriSurfIndexes( tri, mesh->indexes.Num() );
|
||||
tri->generateNormals = !normalsParsed;
|
||||
|
||||
// init default normal, color and tex coord index
|
||||
normal.Zero();
|
||||
color = identityColor;
|
||||
tv = 0;
|
||||
|
||||
// find all the unique combinations
|
||||
float normalEpsilon = 1.0f - r_slopNormal.GetFloat();
|
||||
|
||||
for( j = 0; j < ( mesh->indexes.Num() / 3 ); j++ )
|
||||
{
|
||||
// construct triangles in reverse order
|
||||
for( int k = 2; k >= 0; k-- )
|
||||
{
|
||||
int index = j * 3 + k;
|
||||
|
||||
if( index < 0 || index >= mesh->vertexes.Num() )
|
||||
{
|
||||
common->Error( "ConvertOBJToModelSurfaces: bad vertex index in ASE file %s", name.c_str() );
|
||||
}
|
||||
|
||||
// collapse the position if it was slightly offset
|
||||
v = vRemap[index];
|
||||
|
||||
// we may or may not have texcoords to compare
|
||||
if( mesh->texcoords.Num() != 0 )
|
||||
{
|
||||
tv = index;
|
||||
//tv = mesh->faces[j].tVertexNum[k];
|
||||
|
||||
if( tv < 0 || tv >= mesh->texcoords.Num() )
|
||||
{
|
||||
common->Error( "ConvertOBJToModelSurfaces: bad tex coord index in ASE file %s", name.c_str() );
|
||||
}
|
||||
// collapse the tex coord if it was slightly offset
|
||||
tv = tvRemap[tv];
|
||||
}
|
||||
|
||||
// we may or may not have normals to compare
|
||||
if( normalsParsed )
|
||||
{
|
||||
normal = mesh->normals[ index ];
|
||||
}
|
||||
|
||||
// we may or may not have colors to compare
|
||||
/*
|
||||
if( mesh->colorsParsed )
|
||||
{
|
||||
color = mesh->faces[j].vertexColors[k];
|
||||
}
|
||||
*/
|
||||
|
||||
// find a matching vert
|
||||
for( lastmv = NULL, mv = mvHash[v]; mv != NULL; lastmv = mv, mv = mv->next )
|
||||
{
|
||||
if( mv->tv != tv )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( *( unsigned* )mv->color != *( unsigned* )color )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( !normalsParsed )
|
||||
{
|
||||
// if we are going to create the normals, just
|
||||
// matching texcoords is enough
|
||||
break;
|
||||
}
|
||||
if( mv->normal * normal > normalEpsilon )
|
||||
{
|
||||
break; // we already have this one
|
||||
}
|
||||
}
|
||||
if( !mv )
|
||||
{
|
||||
// allocate a new match vert and link to hash chain
|
||||
mv = &mvTable[ tri->numVerts ];
|
||||
mv->v = v;
|
||||
mv->tv = tv;
|
||||
mv->normal = normal;
|
||||
*( unsigned* )mv->color = *( unsigned* )color;
|
||||
mv->next = NULL;
|
||||
if( lastmv )
|
||||
{
|
||||
lastmv->next = mv;
|
||||
}
|
||||
else
|
||||
{
|
||||
mvHash[v] = mv;
|
||||
}
|
||||
tri->numVerts++;
|
||||
}
|
||||
|
||||
tri->indexes[tri->numIndexes] = mv - mvTable;
|
||||
tri->numIndexes++;
|
||||
}
|
||||
}
|
||||
|
||||
// allocate space for the indexes and copy them
|
||||
if( tri->numIndexes > mesh->indexes.Num() )
|
||||
{
|
||||
common->FatalError( "ConvertOBJToModelSurfaces: index miscount in OBJ file %s", name.c_str() );
|
||||
}
|
||||
if( tri->numVerts > mesh->indexes.Num() )
|
||||
{
|
||||
common->FatalError( "ConvertOBJToModelSurfaces: vertex miscount in OBJ file %s", name.c_str() );
|
||||
}
|
||||
|
||||
// now allocate and generate the combined vertexes
|
||||
R_AllocStaticTriSurfVerts( tri, tri->numVerts );
|
||||
|
||||
for( j = 0; j < tri->numVerts; j++ )
|
||||
{
|
||||
mv = &mvTable[j];
|
||||
tri->verts[ j ].Clear();
|
||||
tri->verts[ j ].xyz = mesh->vertexes[ mv->v ];
|
||||
tri->verts[ j ].SetNormal( mv->normal );
|
||||
|
||||
*( unsigned* )tri->verts[j].color = *( unsigned* )mv->color;
|
||||
|
||||
if( mesh->texcoords.Num() != 0 )
|
||||
{
|
||||
const idVec2& tv = mesh->texcoords[ mv->tv ];
|
||||
float u = tv.x;
|
||||
float v = tv.y;
|
||||
tri->verts[j].SetTexCoord( u, v );
|
||||
}
|
||||
}
|
||||
|
||||
R_StaticFree( mvTable );
|
||||
R_StaticFree( mvHash );
|
||||
R_StaticFree( tvRemap );
|
||||
R_StaticFree( vRemap );
|
||||
|
||||
// see if we need to merge with a previous surface of the same material
|
||||
modelSurf = &this->surfaces[mergeTo[ objectNum ]];
|
||||
srfTriangles_t* mergeTri = modelSurf->geometry;
|
||||
if( !mergeTri )
|
||||
{
|
||||
modelSurf->geometry = tri;
|
||||
}
|
||||
else
|
||||
{
|
||||
modelSurf->geometry = R_MergeTriangles( mergeTri, tri );
|
||||
R_FreeStaticTriSurf( tri );
|
||||
R_FreeStaticTriSurf( mergeTri );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// RB end
|
||||
|
||||
/*
|
||||
=================
|
||||
idRenderModelStatic::ConvertASEToModelSurfaces
|
||||
|
@ -3292,6 +3632,31 @@ bool idRenderModelStatic::LoadDAE( const char* fileName, ID_TIME_T* sourceTimeSt
|
|||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
idRenderModelStatic::LoadOBJ
|
||||
=================
|
||||
*/
|
||||
bool idRenderModelStatic::LoadOBJ( const char* fileName, ID_TIME_T* sourceTimeStamp )
|
||||
{
|
||||
objModel_t* obj;
|
||||
|
||||
obj = OBJ_Load( fileName );
|
||||
if( obj == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// RB
|
||||
*sourceTimeStamp = obj->timeStamp;
|
||||
|
||||
ConvertOBJToModelSurfaces( obj );
|
||||
|
||||
OBJ_Free( obj );
|
||||
|
||||
return true;
|
||||
}
|
||||
// RB end
|
||||
|
||||
//=============================================================================
|
||||
|
|
|
@ -342,8 +342,8 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
|
|||
|
||||
idRenderModel* model = NULL;
|
||||
|
||||
// RB: added dae
|
||||
if( ( extension.Icmp( "dae" ) == 0 ) || ( extension.Icmp( "ase" ) == 0 ) || ( extension.Icmp( "lwo" ) == 0 ) || ( extension.Icmp( "flt" ) == 0 ) || ( extension.Icmp( "ma" ) == 0 ) )
|
||||
// RB: Collada DAE and Wavefront OBJ
|
||||
if( ( extension.Icmp( "dae" ) == 0 ) || ( extension.Icmp( "obj" ) == 0 ) || ( extension.Icmp( "ase" ) == 0 ) || ( extension.Icmp( "lwo" ) == 0 ) || ( extension.Icmp( "flt" ) == 0 ) || ( extension.Icmp( "ma" ) == 0 ) )
|
||||
{
|
||||
model = new( TAG_MODEL ) idRenderModelStatic;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2012-2021 Robert Beckebans
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
|
@ -39,7 +40,8 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
class idJointMat;
|
||||
struct deformInfo_t;
|
||||
class ColladaParser; // RB: Collada support
|
||||
class ColladaParser; // RB: Collada support
|
||||
struct objModel_t; // RB: Wavefront OBJ support
|
||||
|
||||
class idRenderModelStatic : public idRenderModel
|
||||
{
|
||||
|
@ -116,11 +118,13 @@ public:
|
|||
void MakeDefaultModel();
|
||||
|
||||
bool LoadASE( const char* fileName, ID_TIME_T* sourceTimeStamp );
|
||||
bool LoadDAE( const char* fileName, ID_TIME_T* sourceTimeStamp ); // RB
|
||||
bool LoadLWO( const char* fileName, ID_TIME_T* sourceTimeStamp );
|
||||
bool LoadMA( const char* filename, ID_TIME_T* sourceTimeStamp );
|
||||
bool LoadDAE( const char* fileName, ID_TIME_T* sourceTimeStamp ); // RB
|
||||
bool LoadOBJ( const char* fileName, ID_TIME_T* sourceTimeStamp ); // RB
|
||||
|
||||
bool ConvertDAEToModelSurfaces( const ColladaParser* dae ); // RB
|
||||
bool ConvertOBJToModelSurfaces( const objModel_t* obj ); // RB
|
||||
bool ConvertASEToModelSurfaces( const struct aseModel_s* ase );
|
||||
bool ConvertLWOToModelSurfaces( const struct st_lwObject* lwo );
|
||||
bool ConvertMAToModelSurfaces( const struct maModel_s* ma );
|
||||
|
|
273
neo/renderer/Model_obj.cpp
Normal file
273
neo/renderer/Model_obj.cpp
Normal file
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2019 Justin Marshal (IcedTech)
|
||||
Copyright (C) 2021 Robert Beckebans
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition 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 BFG Edition 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.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma hdrstop
|
||||
#include "precompiled.h"
|
||||
|
||||
|
||||
#include "Model_obj.h"
|
||||
|
||||
/*
|
||||
======================================================================
|
||||
|
||||
Parses Wavefront export files. This parser is designed to work with Blender and 3D Studio Max
|
||||
|
||||
|
||||
The goal is to parse the information into memory exactly as it is
|
||||
represented in the file. Users of the data will then move it
|
||||
into a form that is more convenient for them.
|
||||
|
||||
======================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
OBJ_Parse
|
||||
=================
|
||||
*/
|
||||
objModel_t* OBJ_Parse( const char* fileName, const char* objFileBuffer, int length )
|
||||
{
|
||||
objModel_t* model = new( TAG_MODEL ) objModel_t;
|
||||
|
||||
idLexer src;
|
||||
idToken token, token2;
|
||||
|
||||
// total
|
||||
idList<idVec3> vertexes;
|
||||
idList<idVec2> texCoords;
|
||||
idList<idVec3> normals;
|
||||
|
||||
int numCollectedVerts = 0;
|
||||
|
||||
// current object or group
|
||||
//idList<idDrawVert> drawVerts;
|
||||
idList<idVec3> objVertexes;
|
||||
idList<idVec2> objTexCoords;
|
||||
idList<idVec3> objNormals;
|
||||
idList<triIndex_t> objIndices;
|
||||
|
||||
idStrStatic< MAX_OSPATH > material;
|
||||
|
||||
src.LoadMemory( objFileBuffer, length, fileName, 0 );
|
||||
|
||||
while( true )
|
||||
{
|
||||
if( !src.ReadToken( &token ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if( token == "v" )
|
||||
{
|
||||
idVec3 vertex;
|
||||
#if 0
|
||||
vertex.x = src.ParseFloat();
|
||||
vertex.z = src.ParseFloat();
|
||||
vertex.y = -src.ParseFloat();
|
||||
#else
|
||||
vertex.x = src.ParseFloat();
|
||||
vertex.y = src.ParseFloat();
|
||||
vertex.z = src.ParseFloat();
|
||||
#endif
|
||||
vertexes.Append( vertex );
|
||||
}
|
||||
else if( token == "vt" )
|
||||
{
|
||||
idVec2 st;
|
||||
st.x = src.ParseFloat();
|
||||
st.y = 1.0f - src.ParseFloat();
|
||||
texCoords.Append( st );
|
||||
}
|
||||
else if( token == "#" )
|
||||
{
|
||||
idStr line;
|
||||
|
||||
// Skip comments
|
||||
src.ReadRestOfLine( line );
|
||||
}
|
||||
else if( token == "mtllib" )
|
||||
{
|
||||
idStr line;
|
||||
|
||||
// We don't use obj materials.
|
||||
src.ReadRestOfLine( line );
|
||||
}
|
||||
else if( token == "s" )
|
||||
{
|
||||
idStr line;
|
||||
src.ReadRestOfLine( line );
|
||||
}
|
||||
else if( token == "o" || token == "g" )
|
||||
{
|
||||
idStr line;
|
||||
src.ReadRestOfLine( line );
|
||||
|
||||
if( objVertexes.Num() )
|
||||
{
|
||||
objObject_t* obj = new objObject_t;
|
||||
|
||||
obj->material = material;
|
||||
obj->vertexes = objVertexes;
|
||||
obj->texcoords = objTexCoords;
|
||||
obj->normals = objNormals;
|
||||
obj->indexes = objIndices;
|
||||
|
||||
numCollectedVerts += objVertexes.Num();
|
||||
|
||||
objVertexes.Clear();
|
||||
objTexCoords.Clear();
|
||||
objNormals.Clear();
|
||||
objIndices.Clear();
|
||||
|
||||
model->objects.Append( obj );
|
||||
}
|
||||
}
|
||||
else if( token == "usemtl" )
|
||||
{
|
||||
idStr line;
|
||||
src.ReadRestOfLine( line );
|
||||
|
||||
material = line;
|
||||
}
|
||||
else if( token == "vn" )
|
||||
{
|
||||
idVec3 normal;
|
||||
normal.x = src.ParseFloat();
|
||||
normal.y = src.ParseFloat();
|
||||
normal.z = src.ParseFloat();
|
||||
normals.Append( normal );
|
||||
}
|
||||
else if( token == "f" )
|
||||
{
|
||||
idStr line;
|
||||
int vertexIndex[3];
|
||||
int uvIndex[3];
|
||||
int normalIndex[3];
|
||||
|
||||
src.ReadRestOfLine( line );
|
||||
|
||||
int matches = sscanf( line.c_str(), "%d/%d/%d %d/%d/%d %d/%d/%d", &vertexIndex[0], &uvIndex[0], &normalIndex[0], &vertexIndex[1], &uvIndex[1], &normalIndex[1], &vertexIndex[2], &uvIndex[2], &normalIndex[2] );
|
||||
if( matches != 9 )
|
||||
{
|
||||
common->FatalError( "Failed to parse face line" );
|
||||
}
|
||||
|
||||
for( int i = 0; i < 3; i++ )
|
||||
{
|
||||
idDrawVert drawVert;
|
||||
|
||||
int vertidx = vertexIndex[i] - 1;
|
||||
int texidx = uvIndex[i] - 1;
|
||||
int normalidx = normalIndex[i] - 1;
|
||||
|
||||
//drawVert.xyz = vertexes[vertidx];
|
||||
//drawVert.SetTexCoord( texCoords[texidx] );
|
||||
//drawVert.SetNormal( normals[normalidx] );
|
||||
|
||||
objVertexes.Append( vertexes[vertidx] );
|
||||
objTexCoords.Append( texCoords[texidx] );
|
||||
objNormals.Append( normals[normalidx] );
|
||||
|
||||
//objIndices.Append( vertidx - numCollectedVerts );
|
||||
objIndices.Append( objIndices.Num() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
common->FatalError( "idRenderModelStatic::ParseOBJ: Unknown or unexpected token %s", token.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
if( objVertexes.Num() )
|
||||
{
|
||||
objObject_t* obj = new objObject_t;
|
||||
|
||||
obj->material = material;
|
||||
|
||||
obj->vertexes = objVertexes;
|
||||
obj->texcoords = objTexCoords;
|
||||
obj->normals = objNormals;
|
||||
obj->indexes = objIndices;
|
||||
|
||||
model->objects.Append( obj );
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
OBJ_Load
|
||||
=================
|
||||
*/
|
||||
objModel_t* OBJ_Load( const char* fileName )
|
||||
{
|
||||
char* objBuffer;
|
||||
ID_TIME_T timeStamp;
|
||||
objModel_t* obj;
|
||||
|
||||
int objBufferLen = fileSystem->ReadFile( fileName, ( void** )&objBuffer, &timeStamp );
|
||||
if( objBufferLen <= 0 || objBuffer == nullptr )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
obj = OBJ_Parse( fileName, objBuffer, objBufferLen );
|
||||
obj->timeStamp = timeStamp;
|
||||
|
||||
fileSystem->FreeFile( objBuffer );
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
OBJ_Free
|
||||
=================
|
||||
*/
|
||||
void OBJ_Free( objModel_t* model )
|
||||
{
|
||||
if( !model )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for( int i = 0; i < model->objects.Num(); i++ )
|
||||
{
|
||||
objObject_t* obj = model->objects[i];
|
||||
|
||||
delete obj;
|
||||
}
|
||||
|
||||
model->objects.Clear();
|
||||
|
||||
delete model;
|
||||
}
|
63
neo/renderer/Model_obj.h
Normal file
63
neo/renderer/Model_obj.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2021 Robert Beckebans
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition 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 BFG Edition 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.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef __MODEL_OBJ_H__
|
||||
#define __MODEL_OBJ_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Wavefront OBJ loader.
|
||||
This is meant to be a very simple model format and we don't even care for .mtl files
|
||||
because we want all material properties to be defined through the D3 material system
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
struct objObject_t
|
||||
{
|
||||
idStrStatic< MAX_OSPATH > material;
|
||||
|
||||
idList<idVec3> vertexes;
|
||||
idList<idVec2> texcoords;
|
||||
idList<idVec3> normals;
|
||||
idList<triIndex_t> indexes;
|
||||
};
|
||||
|
||||
struct objModel_t
|
||||
{
|
||||
ID_TIME_T timeStamp;
|
||||
idList<objObject_t*, TAG_MODEL> objects;
|
||||
};
|
||||
|
||||
|
||||
objModel_t* OBJ_Load( const char* fileName );
|
||||
void OBJ_Free( objModel_t* obj );
|
||||
|
||||
#endif /* !__MODEL_ASE_H__ */
|
Loading…
Reference in a new issue