From Carlos García and Paul Baker, Port of Paul Baker's Quake3 BSP loader to OSG by Carlos García.

Added Quake3 BSP plugin.
This commit is contained in:
Robert Osfield 2006-05-15 09:46:54 +00:00
parent 8af7b04c5b
commit f104656d9f
8 changed files with 1311 additions and 0 deletions

View File

@ -64,6 +64,7 @@ endif
PLUGIN_DIRS = \
3dc \
bsp \
ac3d \
bmp \
dds \

View File

@ -0,0 +1,53 @@
//////////////////////////////////////////////////////////////////////////////////////////
// BITSET.cpp
// functions for class for set of bits to represent many true/falses
// You may use this code however you wish, but if you do, please credit me and
// provide a link to my website in a readme file or similar
// Downloaded from: www.paulsprojects.net
// Created: 8th August 2002
//////////////////////////////////////////////////////////////////////////////////////////
#include "memory.h"
#include "BITSET.h"
bool BITSET::Init(int numberOfBits)
{
//Delete any memory allocated to bits
m_bits.clear();
//Calculate size
m_numBytes=(numberOfBits>>3)+1;
//Create memory
m_bits.reserve(m_numBytes);
m_bits_aux=&m_bits[0];
ClearAll();
return true;
}
void BITSET::ClearAll()
{
memset(m_bits_aux, 0, m_numBytes);
}
void BITSET::SetAll()
{
memset(m_bits_aux, 0xFF, m_numBytes);
}
void BITSET::Clear(int bitNumber)
{
m_bits_aux[bitNumber>>3] &= ~(1<<(bitNumber & 7));
}
void BITSET::Set(int bitNumber)
{
m_bits_aux[bitNumber>>3] |= 1<<(bitNumber&7);
}
unsigned char BITSET::IsSet(int bitNumber) const
{
return m_bits_aux[bitNumber>>3] & 1<<(bitNumber&7);
}

View File

@ -0,0 +1,40 @@
//////////////////////////////////////////////////////////////////////////////////////////
// BITSET.h
// class declaration for set of bits to represent many true/falses
// You may use this code however you wish, but if you do, please credit me and
// provide a link to my website in a readme file or similar
// Downloaded from: www.paulsprojects.net
// Created: 8th August 2002
//////////////////////////////////////////////////////////////////////////////////////////
#ifndef BITSET_H
#define BITSET_H
#include <vector>
class BITSET
{
public:
BITSET() : m_numBytes(0)
{}
~BITSET()
{
}
bool Init(int numberOfBits);
void ClearAll();
void SetAll();
void Clear(int bitNumber);
void Set(int bitNumber);
unsigned char IsSet(int bitNumber) const;
protected:
int m_numBytes; //size of bits array
unsigned char * m_bits_aux;
std::vector<unsigned char> m_bits;
};
#endif

View File

@ -0,0 +1,285 @@
#include "BSPLoad.h"
#include <fstream>
bool BSPLoad::Load(const std::string& filename, int curveTesselation)
{
std::ifstream file(filename.c_str(),std::ios::binary);
if(!file.is_open())
{
//errorLog.OutputError("Unable to open %s", filename);
return false;
}
//read in header
file.read((char*)&m_header, sizeof(BSP_HEADER));
//check header data is correct
if( m_header.m_string[0]!='I' || m_header.m_string[1]!='B' ||
m_header.m_string[2]!='S' || m_header.m_string[3]!='P' ||
m_header.m_version !=0x2E )
{
//errorLog.OutputError("%s is not a version 0x2E .bsp map file", filename);
return false;
}
//Load in vertices
LoadVertices(file);
//Load in mesh indices
//Calculate number of indices
int numMeshIndices=m_header.m_directoryEntries[bspMeshIndices].m_length/sizeof(int);
//Create space
m_loadMeshIndices.resize(numMeshIndices);
//read in the mesh indices
file.seekg(m_header.m_directoryEntries[bspMeshIndices].m_offset,std::ios::beg);
file.read((char*) &m_loadMeshIndices[0], m_header.m_directoryEntries[bspMeshIndices].m_length);
//Load in faces
LoadFaces(file, curveTesselation);
//Load textures
LoadTextures(file);
//Load Lightmaps
LoadLightmaps(file);
//Load BSP Data
LoadBSPData(file);
//Load in entity string
m_entityString.resize(m_header.m_directoryEntries[bspEntities].m_length);
//Go to entity string in file
file.seekg(m_header.m_directoryEntries[bspEntities].m_offset,std::ios::beg);
file.read(&m_entityString[0], m_header.m_directoryEntries[bspEntities].m_length);
//errorLog.OutputSuccess("%s Loaded successfully", filename);
return true;
}
void BSPLoad::LoadVertices(std::ifstream& aFile)
{
//calculate number of vertices
int num_vertices=m_header.m_directoryEntries[bspVertices].m_length/sizeof(BSP_LOAD_VERTEX);
//Create space for this many BSP_LOAD_VERTICES
m_loadVertices.resize(num_vertices);
//go to vertices in file
aFile.seekg(m_header.m_directoryEntries[bspVertices].m_offset,std::ios::beg);
//read in the vertices
aFile.read((char*)&m_loadVertices[0], m_header.m_directoryEntries[bspVertices].m_length);
}
void BSPLoad::LoadFaces(std::ifstream& aFile, int curveTesselation)
{
//calculate number of load faces
int numTotalFaces=m_header.m_directoryEntries[bspFaces].m_length/sizeof(BSP_LOAD_FACE);
//Create space for this many BSP_LOAD_FACES
m_loadFaces.resize(numTotalFaces);
//go to faces in file
aFile.seekg(m_header.m_directoryEntries[bspFaces].m_offset,std::ios::beg);
//read in the faces
aFile.read((char*)&m_loadFaces[0], m_header.m_directoryEntries[bspFaces].m_length);
}
void BSPLoad::LoadTextures(std::ifstream& aFile)
{
//Calculate number of textures
int num_textures=m_header.m_directoryEntries[bspTextures].m_length/sizeof(BSP_LOAD_TEXTURE);
//Create space for this many BSP_LOAD_TEXTUREs
m_loadTextures.resize(num_textures);
//Load textures
aFile.seekg(m_header.m_directoryEntries[bspTextures].m_offset,std::ios::beg);
aFile.read((char*)&m_loadTextures[0], m_header.m_directoryEntries[bspTextures].m_length);
}
void BSPLoad::LoadLightmaps(std::ifstream& aFile)
{
//Calculate number of lightmaps
int num_lightmaps=m_header.m_directoryEntries[bspLightmaps].m_length/sizeof(BSP_LOAD_LIGHTMAP);
//Create space for this many BSP_LOAD_LIGHTMAPs
m_loadLightmaps.resize(num_lightmaps);
//Load textures
aFile.seekg(m_header.m_directoryEntries[bspLightmaps].m_offset,std::ios::beg);
aFile.read((char*)&m_loadLightmaps[0], m_header.m_directoryEntries[bspLightmaps].m_length);
//Change the gamma settings on the lightmaps (make them brighter)
float gamma=2.5f;
for(int i=0; i<num_lightmaps; ++i)
{
for(int j=0; j<128*128; ++j)
{
float r, g, b;
r=m_loadLightmaps[i].m_lightmapData[j*3+0];
g=m_loadLightmaps[i].m_lightmapData[j*3+1];
b=m_loadLightmaps[i].m_lightmapData[j*3+2];
r*=gamma/255.0f;
g*=gamma/255.0f;
b*=gamma/255.0f;
//find the value to scale back up
float scale=1.0f;
float temp;
if(r > 1.0f && (temp = (1.0f/r)) < scale) scale=temp;
if(g > 1.0f && (temp = (1.0f/g)) < scale) scale=temp;
if(b > 1.0f && (temp = (1.0f/b)) < scale) scale=temp;
// scale up color values
scale*=255.0f;
r*=scale;
g*=scale;
b*=scale;
//fill data back in
m_loadLightmaps[i].m_lightmapData[j*3+0]=(unsigned char)r;
m_loadLightmaps[i].m_lightmapData[j*3+1]=(unsigned char)g;
m_loadLightmaps[i].m_lightmapData[j*3+2]=(unsigned char)b;
//m_loadLightmaps[i].m_lightmapData[j*3+0]=(GLubyte)255;
//m_loadLightmaps[i].m_lightmapData[j*3+1]=(GLubyte)255;
//m_loadLightmaps[i].m_lightmapData[j*3+2]=(GLubyte)255;
}
}
}
void BSPLoad::LoadBSPData(std::ifstream& aFile)
{
//Load leaves
//Calculate number of leaves
int numLeaves=m_header.m_directoryEntries[bspLeaves].m_length/sizeof(BSP_LOAD_LEAF);
//Create space for this many BSP_LOAD_LEAFS
m_loadLeaves.resize(numLeaves);
//Load leaves
aFile.seekg(m_header.m_directoryEntries[bspLeaves].m_offset,std::ios::beg);
aFile.read((char*)&m_loadLeaves[0], m_header.m_directoryEntries[bspLeaves].m_length);
//Load leaf faces array
int num_leaf_faces=m_header.m_directoryEntries[bspLeafFaces].m_length/sizeof(int);
//Create space for this many leaf faces
m_loadLeafFaces.resize(num_leaf_faces);
//Load leaf faces
aFile.seekg(m_header.m_directoryEntries[bspLeafFaces].m_offset,std::ios::beg);
aFile.read((char*)&m_loadLeafFaces[0], m_header.m_directoryEntries[bspLeafFaces].m_length);
//Load Planes
int num_planes=m_header.m_directoryEntries[bspPlanes].m_length/sizeof(BSP_LoadPlane);
//Create space for this many planes
m_loadPlanes.resize(num_planes);
aFile.seekg(m_header.m_directoryEntries[bspPlanes].m_offset,std::ios::beg);
aFile.read((char*)&m_loadPlanes[0], m_header.m_directoryEntries[bspPlanes].m_length);
//Load nodes
int num_nodes=m_header.m_directoryEntries[bspNodes].m_length/sizeof(BSP_NODE);
//Create space for this many nodes
m_loadNodes.resize(num_nodes);
aFile.seekg(m_header.m_directoryEntries[bspNodes].m_offset,std::ios::beg);
aFile.read((char*)&m_loadNodes[0], m_header.m_directoryEntries[bspNodes].m_length);
//Load visibility data
//load numClusters and bytesPerCluster
aFile.seekg(m_header.m_directoryEntries[bspVisData].m_offset,std::ios::beg);
aFile.read((char*)&m_loadVisibilityData, 2 * sizeof(int));
//Calculate the size of the bitset
int bitsetSize=m_loadVisibilityData.m_numClusters*m_loadVisibilityData.m_bytesPerCluster;
//Create space for bitset
m_loadVisibilityData.m_bitset.resize(bitsetSize);
//read bitset
aFile.read((char*)&m_loadVisibilityData.m_bitset[0], bitsetSize);
}

View File

@ -0,0 +1,203 @@
#ifndef BSPLOAD_H
#define BSPLOAD_H
#include <osg/Vec3f>
#include <vector>
#include <string>
//Directory entry in header
class BSP_DIRECTORY_ENTRY
{
public:
int m_offset;
int m_length;
};
//Types of directory entry
enum BSP_DIRECTORY_ENTRY_TYPE
{
bspEntities=0,
bspTextures,
bspPlanes,
bspNodes,
bspLeaves,
bspLeafFaces,
bspLeafBrushes,
bspModels,
bspBrushes,
bspBrushSides,
bspVertices,
bspMeshIndices,
bspEffect,
bspFaces,
bspLightmaps,
bspLightVols,
bspVisData
};
//BSP file header
class BSP_HEADER
{
public:
char m_string[4];
int m_version;
BSP_DIRECTORY_ENTRY m_directoryEntries[17];
};
//vertex as found in file
class BSP_LOAD_VERTEX
{
public:
osg::Vec3f m_position;
float m_decalS, m_decalT;
float m_lightmapS, m_lightmapT;
osg::Vec3f m_normal;
unsigned char m_color[4];
};
struct BSP_LoadPlane
{
osg::Vec3f m_Normal;
float m_Dist;
};
//face as found in the file
class BSP_LOAD_FACE
{
public:
int m_texture;
int m_effect; // No se usa
int m_type;
int m_firstVertexIndex;
int m_numVertices;
unsigned int m_firstMeshIndex;
unsigned int m_numMeshIndices;
int m_lightmapIndex;
int m_lightmapStart[2]; // No se usa
int m_lightmapSize[2]; // No se usa
//VECTOR3D m_lightmapOrigin; // No se usa
//VECTOR3D m_sTangent, m_tTangent; // No se usa
//VECTOR3D m_normal; // No se usa
osg::Vec3f m_lightmapOrigin; // No se usa
osg::Vec3f m_sTangent, m_tTangent; // No se usa
osg::Vec3f m_normal; // No se usa
int m_patchSize[2];
};
//texture as found in file
class BSP_LOAD_TEXTURE
{
public:
char m_name[64];
int m_flags, m_contents; //unknown, no se usa
};
//lightmap as found in file
class BSP_LOAD_LIGHTMAP
{
public:
unsigned char m_lightmapData[128*128*3];
};
//leaf of bsp tree as found in file
class BSP_LOAD_LEAF
{
public:
int m_cluster; //cluster index for visdata
int m_area; //areaportal area, No se usa
int m_mins[3]; //min x,y,z (bounding box)
int m_maxs[3];
int m_firstLeafFace; //first index in leafFaces array
int m_numFaces;
int m_firstLeafBrush; //first index into leaf brushes array, No se usa
int m_numBrushes; // No se usa
};
//node of BSP tree
class BSP_NODE
{
public:
int m_planeIndex;
int m_front, m_back; //child nodes
int m_mins[3]; //min x,y,z (bounding box) No se usa
int m_maxs[3]; // No se usa
};
//VIS data table
class BSP_VISIBILITY_DATA
{
public:
int m_numClusters;
int m_bytesPerCluster;
std::vector<unsigned char> m_bitset;
};
class BSPLoad
{
public:
bool Load(const std::string& filename, int curveTesselation);
void LoadVertices(std::ifstream& aFile);
void LoadFaces(std::ifstream& aFile, int curveTesselation);
void LoadTextures(std::ifstream& aFile);
void LoadLightmaps(std::ifstream& aFile);
void LoadBSPData(std::ifstream& aFile);
std::string m_entityString;
//header
BSP_HEADER m_header;
// Load Data
std::vector<BSP_LOAD_VERTEX> m_loadVertices;
std::vector<unsigned int> m_loadMeshIndices;
std::vector<BSP_LOAD_FACE> m_loadFaces;
std::vector<BSP_LOAD_TEXTURE> m_loadTextures;
std::vector<BSP_LOAD_LIGHTMAP> m_loadLightmaps;
std::vector<BSP_LOAD_LEAF> m_loadLeaves;
std::vector<int> m_loadLeafFaces;
std::vector<BSP_LoadPlane> m_loadPlanes;
std::vector<BSP_NODE> m_loadNodes;
BSP_VISIBILITY_DATA m_loadVisibilityData;
};
#endif // BSPLOAD_H

View File

@ -0,0 +1,18 @@
TOPDIR = ../../..
include $(TOPDIR)/Make/makedefs
CXXFILES =\
BITSET.cpp\
BSPLoad.cpp\
ReaderWriterQ3BSP.cpp\
INC += -I$(THISDIR)
LIBS += $(OSG_LIBS) $(OTHER_LIBS)
TARGET_BASENAME = bsp
include $(TOPDIR)/Make/cygwin_plugin_def
PLUGIN = $(PLUGIN_PREFIX)$(TARGET_BASENAME).$(PLUGIN_EXT)
include $(TOPDIR)/Make/makerules

View File

@ -0,0 +1,684 @@
#include <osg/TexEnv>
#include <osg/CullFace>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Image>
#include <osg/Texture2D>
#include <osg/PolygonMode>
#include <osg/BlendColor>
#include <osgDB/ReadFile>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <assert.h>
#include <fstream>
#include "BSPLoad.h"
class ReaderWriterQ3BSP: public osgDB::ReaderWriter
{
public:
ReaderWriterQ3BSP() { }
virtual const char* className() const
{
return "Quake3 BSP Reader";
}
virtual bool acceptsExtension(const std::string& extension) const
{
return osgDB::equalCaseInsensitive(extension,"bsp");
}
virtual ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const;
private:
osg::Geode* convertFromBSP(BSPLoad& aLoadData,const osgDB::ReaderWriter::Options* options) const;
osg::Geometry* createMeshFace(const BSP_LOAD_FACE& aLoadFace,const std::vector<osg::Texture2D*>& aTextureArray,
osg::Vec3Array& aVertexArray,std::vector<GLuint>& aIndices,
osg::Vec2Array& aTextureDecalCoords,osg::Vec2Array& aTextureLMapCoords
) const;
osg::Geometry* createPolygonFace(const BSP_LOAD_FACE& aLoadFace,const std::vector<osg::Texture2D*>& aTextureArray,const std::vector<osg::Texture2D*>& aTextureLMapArray,
osg::Vec3Array& aVertexArray,
osg::Vec2Array& aTextureDecalCoords,osg::Vec2Array& aTextureLMapCoords
) const;
bool loadTextures(const BSPLoad& aLoadData,std::vector<osg::Texture2D*>& aTextureArray) const;
bool loadLightMaps(const BSPLoad& aLoadData,std::vector<osg::Texture2D*>& aTextureArray) const;
};
// Register with Registry to instantiate the above reader/writer.
osgDB::RegisterReaderWriterProxy<ReaderWriterQ3BSP> g_readerWriter_Q3BSP_Proxy;
// Read node
osgDB::ReaderWriter::ReadResult ReaderWriterQ3BSP::readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const
{
std::string ext = osgDB::getLowerCaseFileExtension(file);
if (!acceptsExtension(ext))
return ReadResult::FILE_NOT_HANDLED;
std::string file_name = osgDB::findDataFile( file, options );
if (file_name.empty())
return ReadResult::FILE_NOT_FOUND;
//osg::notify(osg::INFO) << "ReaderWriterQ3BSP::readNode(" << fileName.c_str() << ")\n";
BSPLoad load_data;
load_data.Load(file_name,8);
osg::Geode* geode = convertFromBSP(load_data, options);
if (!geode)
return ReadResult::FILE_NOT_HANDLED;
//osg::StateSet* state_set=geode->getOrCreateStateSet();
//state_set->setMode(osg::CullFace::BACK,osg::StateAttribute::ON);
return geode;
return ReadResult::FILE_NOT_HANDLED;
}
enum BSP_FACE_TYPE
{
bspPolygonFace=1,
bspPatch,
bspMeshFace,
bspBillboard
};
class BSP_VERTEX
{
public:
osg::Vec3f m_position;
float m_decalS, m_decalT;
float m_lightmapS, m_lightmapT;
BSP_VERTEX operator+(const BSP_VERTEX & rhs) const
{
BSP_VERTEX result;
result.m_position=m_position+rhs.m_position;
result.m_decalS=m_decalS+rhs.m_decalS;
result.m_decalT=m_decalT+rhs.m_decalT;
result.m_lightmapS=m_lightmapS+rhs.m_lightmapS;
result.m_lightmapT=m_lightmapT+rhs.m_lightmapT;
return result;
}
BSP_VERTEX operator*(const float rhs) const
{
BSP_VERTEX result;
result.m_position=m_position*rhs;
result.m_decalS=m_decalS*rhs;
result.m_decalT=m_decalT*rhs;
result.m_lightmapS=m_lightmapS*rhs;
result.m_lightmapT=m_lightmapT*rhs;
return result;
}
};
//every patch (curved surface) is split into biquadratic (3x3) patches
class BSP_BIQUADRATIC_PATCH
{
public:
BSP_BIQUADRATIC_PATCH():m_vertices(32),m_indices(32)
{
}
~BSP_BIQUADRATIC_PATCH()
{
}
bool Tesselate(int newTesselation,osg::Geometry* aGeometry);
BSP_VERTEX m_controlPoints[9]; // Se accede a ellos en la carga
protected:
int m_tesselation;
std::vector<BSP_VERTEX> m_vertices;
std::vector<GLuint> m_indices;
//arrays for multi_draw_arrays
std::vector<int> m_trianglesPerRow;
std::vector<unsigned int *> m_rowIndexPointers;
};
//curved surface
class BSP_PATCH
{
public:
BSP_PATCH():m_quadraticPatches(32)
{
}
~BSP_PATCH()
{
}
int m_textureIndex;
int m_lightmapIndex;
int m_width, m_height;
int m_numQuadraticPatches;
std::vector<BSP_BIQUADRATIC_PATCH> m_quadraticPatches;
};
osg::Geode* ReaderWriterQ3BSP::convertFromBSP(BSPLoad& aLoadData,const osgDB::ReaderWriter::Options* options) const
{
std::vector<osg::Texture2D*> texture_array;
loadTextures(aLoadData,texture_array);
std::vector<osg::Texture2D*> lightmap_array;
loadLightMaps(aLoadData,lightmap_array);
osg::Geode* map_geode=new osg::Geode;
// Convertir los vertices
unsigned int num_load_vertices=aLoadData.m_loadVertices.size();
osg::Vec3Array* vertex_array = new osg::Vec3Array(num_load_vertices);
osg::Vec2Array* text_decal_array = new osg::Vec2Array(num_load_vertices);
osg::Vec2Array* text_lmap_array = new osg::Vec2Array(num_load_vertices);
unsigned int i;
for(i=0; i<num_load_vertices; ++i)
{
BSP_LOAD_VERTEX& vtx=aLoadData.m_loadVertices[i];
//swap y and z and negate z
(*vertex_array)[i]=(osg::Vec3d( vtx.m_position[0]/64,
vtx.m_position[2]/64,
-vtx.m_position[1]/64 ) );
//Transfer texture coordinates (Invert t)
(*text_decal_array)[i]=(osg::Vec2d(vtx.m_decalS,-vtx.m_decalT) );
//Transfer lightmap coordinates
(*text_lmap_array)[i]=(osg::Vec2d(vtx.m_lightmapS,vtx.m_lightmapT) );
}
unsigned int num_loadfaces=aLoadData.m_loadFaces.size();
//convert loadFaces to faces
for(i=0; i<num_loadfaces; ++i)
{
const BSP_LOAD_FACE& current_load_face=aLoadData.m_loadFaces[i];
if(current_load_face.m_type!=bspMeshFace) //skip this loadFace if it is not a mesh face
continue;
osg::Geometry* mesh_geom=createMeshFace(current_load_face,texture_array,*vertex_array,aLoadData.m_loadMeshIndices,*text_decal_array,*text_lmap_array);
map_geode->addDrawable(mesh_geom);
}
for(i=0; i<num_loadfaces; ++i)
{
const BSP_LOAD_FACE& current_face=aLoadData.m_loadFaces[i];
if(current_face.m_type!=bspPolygonFace) //skip this loadFace if it is not a polygon face
continue;
osg::Geometry* polygon_geom=createPolygonFace(current_face,texture_array,lightmap_array,*vertex_array,*text_decal_array,*text_lmap_array);
map_geode->addDrawable(polygon_geom);
}
for(i=0; i<num_loadfaces; ++i)
{
const BSP_LOAD_FACE& current_face=aLoadData.m_loadFaces[i];
if(current_face.m_type!=bspPatch) //skip this loadFace if it is not a patch face
continue;
//osg::Group* patch_group=new osg::Group;
BSP_PATCH current_patch;
current_patch.m_textureIndex=current_face.m_texture;
current_patch.m_lightmapIndex=current_face.m_lightmapIndex;
current_patch.m_width=current_face.m_patchSize[0];
current_patch.m_height=current_face.m_patchSize[1];
osg::Texture2D *texture=texture_array[current_face.m_texture];
osg::Texture2D *lightmap_texture=NULL;
if(current_face.m_lightmapIndex>=0)
{
lightmap_texture=lightmap_array[current_face.m_lightmapIndex];
}
else
{
lightmap_texture=lightmap_array[lightmap_array.size()-1];
}
//Create space to hold quadratic patches
int numPatchesWide=(current_patch.m_width-1)/2;
int numPatchesHigh=(current_patch.m_height-1)/2;
current_patch.m_numQuadraticPatches = numPatchesWide*numPatchesHigh;
current_patch.m_quadraticPatches.resize(current_patch.m_numQuadraticPatches);
//fill in the quadratic patches
for(int y=0; y<numPatchesHigh; ++y)
{
for(int x=0; x<numPatchesWide; ++x)
{
for(int row=0; row<3; ++row)
{
for(int point=0; point<3; ++point)
{
BSP_BIQUADRATIC_PATCH& curr_quadraticpatch=current_patch.m_quadraticPatches[y*numPatchesWide+x];
osg::Vec3f vtx= (*vertex_array) [aLoadData.m_loadFaces[i].m_firstVertexIndex+(y*2*current_patch.m_width+x*2)+
row*current_patch.m_width+point];
curr_quadraticpatch.m_controlPoints[row*3+point].m_position[0] = vtx.x();
curr_quadraticpatch.m_controlPoints[row*3+point].m_position[1] = vtx.y();
curr_quadraticpatch.m_controlPoints[row*3+point].m_position[2] = vtx.z();
}
}
osg::Geometry* patch_geom = new osg::Geometry;
//tesselate the patch
osg::StateSet* stateset = patch_geom->getOrCreateStateSet();
if(texture)
stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
if(lightmap_texture)
{
stateset->setTextureAttributeAndModes(1,lightmap_texture,osg::StateAttribute::ON);
}
//patch_group->addChild(map_geode);
current_patch.m_quadraticPatches[y*numPatchesWide+x].Tesselate(8/*aCurveTesselation*/,patch_geom);
map_geode->addDrawable(patch_geom);
}
}
}
//int num_primitive_sets=geom->getNumPrimitiveSets();
//const osg::BoundingSphere& bs=map_geom->getBound();
return map_geode;
}
osg::Geometry* ReaderWriterQ3BSP::createMeshFace( const BSP_LOAD_FACE& aLoadFace,const std::vector<osg::Texture2D*>& aTextureArray,
osg::Vec3Array& aVertexArray,std::vector<GLuint>& aIndices,
osg::Vec2Array& aTextureDecalCoords,osg::Vec2Array& aTextureLMapCoords
) const
{
osg::Geometry* obj_geom = new osg::Geometry;
osg::Vec3Array* obj_vertex_array = new osg::Vec3Array(aLoadFace.m_numMeshIndices,
&(aVertexArray)[aLoadFace.m_firstVertexIndex]
);
obj_geom->setVertexArray(obj_vertex_array);
osg::DrawElementsUInt* face_indices = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES,
aLoadFace.m_numMeshIndices,
&(aIndices)[0]+aLoadFace.m_firstMeshIndex
);
obj_geom->addPrimitiveSet(face_indices);
osg::Texture2D *texture=aTextureArray[aLoadFace.m_texture];
if(texture)
{
osg::StateSet* stateset = obj_geom->getOrCreateStateSet();
stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
stateset->setTextureAttributeAndModes(1,texture,osg::StateAttribute::ON);
osg::Vec2Array* obj_texcoords_array = new osg::Vec2Array(aLoadFace.m_numMeshIndices,
&(aTextureDecalCoords)[aLoadFace.m_firstVertexIndex]
);
obj_geom->setTexCoordArray(0,obj_texcoords_array);
osg::Vec2Array* obj_lmapcoords_array = new osg::Vec2Array(aLoadFace.m_numMeshIndices,
&(aTextureLMapCoords)[aLoadFace.m_firstVertexIndex]
);
obj_geom->setTexCoordArray(1,obj_lmapcoords_array);
}
return obj_geom;
}
osg::Geometry* ReaderWriterQ3BSP::createPolygonFace(const BSP_LOAD_FACE& aLoadFace,const std::vector<osg::Texture2D*>& aTextureArray,const std::vector<osg::Texture2D*>& aTextureLMapArray,
osg::Vec3Array& aVertexArray,
osg::Vec2Array& aTextureDecalCoords,osg::Vec2Array& aTextureLMapCoords
) const
{
osg::Texture2D *texture=aTextureArray[aLoadFace.m_texture];
osg::Geometry* polygon_geom = new osg::Geometry;
polygon_geom->setVertexArray(&aVertexArray);
polygon_geom->setTexCoordArray(0, &aTextureDecalCoords);
polygon_geom->setTexCoordArray(1, &aTextureLMapCoords);
osg::DrawArrays* face_indices = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN,
aLoadFace.m_firstVertexIndex,
aLoadFace.m_numVertices
);
osg::StateSet* stateset = polygon_geom->getOrCreateStateSet();
if(texture)
{
stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
if(aLoadFace.m_lightmapIndex>=0)
{
texture=aTextureLMapArray[aLoadFace.m_lightmapIndex];
if(texture)
{
stateset->setTextureAttributeAndModes(1,texture,osg::StateAttribute::ON);
}
}
else
{
texture=aTextureLMapArray[aTextureLMapArray.size()-1];
if(texture)
{
stateset->setTextureAttributeAndModes(1,texture,osg::StateAttribute::ON);
}
}
}
else
{
osg::PolygonMode* polygon_mode=new osg::PolygonMode;
polygon_mode->setMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE);
stateset->setAttributeAndModes(polygon_mode, osg::StateAttribute::ON);
}
polygon_geom->addPrimitiveSet(face_indices);
return polygon_geom;
}
bool ReaderWriterQ3BSP::loadTextures(const BSPLoad& aLoadData,std::vector<osg::Texture2D*>& aTextureArray) const
{
int num_textures=aLoadData.m_loadTextures.size();
int i;
for(i=0;i<num_textures;i++)
{
//add file extension to the name
std::string tgaExtendedName(aLoadData.m_loadTextures[i].m_name);
tgaExtendedName+=".tga";
std::string jpgExtendedName(aLoadData.m_loadTextures[i].m_name);
jpgExtendedName+=".jpg";
osg::Image* image = osgDB::readImageFile(tgaExtendedName);
if (!image)
{
image = osgDB::readImageFile(jpgExtendedName);
if (!image)
{
aTextureArray.push_back(NULL);
continue; //?
}
}
osg::Texture2D* texture= new osg::Texture2D;
texture->setImage(image);
texture->setDataVariance(osg::Object::DYNAMIC); // protect from being optimized away as static state.
texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
aTextureArray.push_back(texture);
}
return true;
}
bool ReaderWriterQ3BSP::loadLightMaps(const BSPLoad& aLoadData,std::vector<osg::Texture2D*>& aTextureArray) const
{
int num_textures=aLoadData.m_loadLightmaps.size();
int i;
for(i=0;i<num_textures;i++)
{
osg::Image* image=new osg::Image;
unsigned char *data=new unsigned char[128*128*3];
memcpy(data,aLoadData.m_loadLightmaps[i].m_lightmapData,128*128*3);
image->setImage(128,128,1,GL_RGBA8,GL_RGB,GL_UNSIGNED_BYTE,data,osg::Image::USE_NEW_DELETE);
osg::Texture2D* texture= new osg::Texture2D;
texture->setImage(image);
texture->setDataVariance(osg::Object::DYNAMIC); // protect from being optimized away as static state.
texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR_MIPMAP_LINEAR);
texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
aTextureArray.push_back(texture);
}
// A continuación, añado el blanco
osg::Image* image=new osg::Image;
unsigned char *data=new unsigned char[3];
for(int whiteidx=0;i<3;i++)
{
data[i]=255;
}
image->setImage(1,1,1,GL_RGBA8,GL_RGB,GL_UNSIGNED_BYTE,data,osg::Image::USE_NEW_DELETE);
osg::Texture2D* texture= new osg::Texture2D;
texture->setImage(image);
texture->setDataVariance(osg::Object::DYNAMIC); // protect from being optimized away as static state.
texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR_MIPMAP_LINEAR);
texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
aTextureArray.push_back(texture);
return true;
}
//Tesselate a biquadratic patch
bool BSP_BIQUADRATIC_PATCH::Tesselate(int newTesselation,osg::Geometry* aGeometry)
{
m_tesselation=newTesselation;
float px, py;
BSP_VERTEX temp[3];
m_vertices.resize((m_tesselation+1)*(m_tesselation+1));
for(int v=0; v<=m_tesselation; ++v)
{
px=(float)v/m_tesselation;
m_vertices[v]=m_controlPoints[0]*((1.0f-px)*(1.0f-px))+
m_controlPoints[3]*((1.0f-px)*px*2)+
m_controlPoints[6]*(px*px);
}
for(int u=1; u<=m_tesselation; ++u)
{
py=(float)u/m_tesselation;
temp[0]=m_controlPoints[0]*((1.0f-py)*(1.0f-py))+
m_controlPoints[1]*((1.0f-py)*py*2)+
m_controlPoints[2]*(py*py);
temp[1]=m_controlPoints[3]*((1.0f-py)*(1.0f-py))+
m_controlPoints[4]*((1.0f-py)*py*2)+
m_controlPoints[5]*(py*py);
temp[2]=m_controlPoints[6]*((1.0f-py)*(1.0f-py))+
m_controlPoints[7]*((1.0f-py)*py*2)+
m_controlPoints[8]*(py*py);
for(int v=0; v<=m_tesselation; ++v)
{
px=(float)v/m_tesselation;
m_vertices[u*(m_tesselation+1)+v]=temp[0]*((1.0f-px)*(1.0f-px))+
temp[1]*((1.0f-px)*px*2)+
temp[2]*(px*px);
}
}
//Create indices
m_indices.resize(m_tesselation*(m_tesselation+1)*2);
for(int row=0; row<m_tesselation; ++row)
{
for(int point=0; point<=m_tesselation; ++point)
{
//calculate indices
//reverse them to reverse winding
m_indices[(row*(m_tesselation+1)+point)*2+1]= row*(m_tesselation+1)+point;
m_indices[(row*(m_tesselation+1)+point)*2]= (row+1)*(m_tesselation+1)+point;
}
}
//Fill in the arrays for multi_draw_arrays
m_trianglesPerRow.resize(m_tesselation);
m_rowIndexPointers.resize(m_tesselation);
for(int row=0; row<m_tesselation; ++row)
{
m_trianglesPerRow[row]=2*(m_tesselation+1);
m_rowIndexPointers[row]=&m_indices[row*2*(m_tesselation+1)];
}
osg::Vec3Array* patch_vertex_array = new osg::Vec3Array( (m_tesselation+1)*(m_tesselation+1) );
osg::Vec2Array* patch_textcoord_array = new osg::Vec2Array( (m_tesselation+1)*(m_tesselation+1) );
osg::Vec2Array* patch_lmapcoord_array = new osg::Vec2Array( (m_tesselation+1)*(m_tesselation+1) );
for(int i=0;i<(m_tesselation+1)*(m_tesselation+1);i++)
{
(*patch_vertex_array)[i].set( m_vertices[ i ].m_position[0],
m_vertices[ i ].m_position[1],
m_vertices[ i ].m_position[2]
);
(*patch_textcoord_array)[i].set( m_vertices[ i ].m_decalS,
m_vertices[ i ].m_decalT
);
(*patch_lmapcoord_array)[i].set( m_vertices[ i ].m_lightmapS,
m_vertices[ i ].m_lightmapT
);
}
aGeometry->setVertexArray(patch_vertex_array);
aGeometry->setTexCoordArray(0,patch_textcoord_array);
aGeometry->setTexCoordArray(1,patch_lmapcoord_array);
for(int row=0; row<m_tesselation; ++row)
{
osg::DrawElementsUInt* face_indices = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLE_STRIP,
m_tesselation*(m_tesselation+1)*2,
&m_indices[0]
);
aGeometry->addPrimitiveSet(face_indices);
}
return true;
}

View File

@ -0,0 +1,27 @@
// El siguiente bloque ifdef muestra la forma estándar de crear macros que facilitan
// la exportación de archivos DLL. Todos los archivos de este archivo DLL se compilan con el símbolo Q3BSP_EXPORTS
// definido en la línea de comandos. Este símbolo no se debe definir en ningún proyecto
// que utilice este archivo DLL. De este modo, otros proyectos cuyos archivos de código fuente incluyan el archivo
// interpreta que las funciones Q3BSP_API se importan de un archivo DLL, mientras que este archivo DLL interpreta los símbolos
// definidos en esta macro como si fueran exportados.
/*
#ifdef Q3BSP_EXPORTS
#define Q3BSP_API __declspec(dllexport)
#else
#define Q3BSP_API __declspec(dllimport)
#endif
// Clase exportada de q3bsp.dll
class Q3BSP_API Cq3bsp {
public:
Cq3bsp(void);
// TODO: agregar métodos aquí.
};
extern Q3BSP_API int nq3bsp;
Q3BSP_API int fnq3bsp(void);
*/