From f104656d9f6c4223f179c7a2d1dd43e00a0b996d Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 15 May 2006 09:46:54 +0000 Subject: [PATCH] =?UTF-8?q?From=20Carlos=20Garc=C3=ADa=20and=20Paul=20Bake?= =?UTF-8?q?r,=20Port=20of=20Paul=20Baker's=20Quake3=20BSP=20loader=20to=20?= =?UTF-8?q?OSG=20by=20Carlos=20Garc=C3=ADa.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added Quake3 BSP plugin. --- Make/makedirdefs | 1 + src/osgPlugins/bsp/BITSET.cpp | 53 ++ src/osgPlugins/bsp/BITSET.h | 40 ++ src/osgPlugins/bsp/BSPLoad.cpp | 285 ++++++++++ src/osgPlugins/bsp/BSPLoad.h | 203 +++++++ src/osgPlugins/bsp/GNUmakefile | 18 + src/osgPlugins/bsp/ReaderWriterQ3BSP.cpp | 684 +++++++++++++++++++++++ src/osgPlugins/bsp/ReaderWriterQ3BSP.h | 27 + 8 files changed, 1311 insertions(+) create mode 100644 src/osgPlugins/bsp/BITSET.cpp create mode 100644 src/osgPlugins/bsp/BITSET.h create mode 100644 src/osgPlugins/bsp/BSPLoad.cpp create mode 100644 src/osgPlugins/bsp/BSPLoad.h create mode 100644 src/osgPlugins/bsp/GNUmakefile create mode 100644 src/osgPlugins/bsp/ReaderWriterQ3BSP.cpp create mode 100644 src/osgPlugins/bsp/ReaderWriterQ3BSP.h diff --git a/Make/makedirdefs b/Make/makedirdefs index 3a4ca571d..d0f38e8e4 100644 --- a/Make/makedirdefs +++ b/Make/makedirdefs @@ -64,6 +64,7 @@ endif PLUGIN_DIRS = \ 3dc \ + bsp \ ac3d \ bmp \ dds \ diff --git a/src/osgPlugins/bsp/BITSET.cpp b/src/osgPlugins/bsp/BITSET.cpp new file mode 100644 index 000000000..29a1a194d --- /dev/null +++ b/src/osgPlugins/bsp/BITSET.cpp @@ -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); +} diff --git a/src/osgPlugins/bsp/BITSET.h b/src/osgPlugins/bsp/BITSET.h new file mode 100644 index 000000000..eb85a8ee8 --- /dev/null +++ b/src/osgPlugins/bsp/BITSET.h @@ -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 + + +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 m_bits; +}; + +#endif diff --git a/src/osgPlugins/bsp/BSPLoad.cpp b/src/osgPlugins/bsp/BSPLoad.cpp new file mode 100644 index 000000000..df1c8c2a7 --- /dev/null +++ b/src/osgPlugins/bsp/BSPLoad.cpp @@ -0,0 +1,285 @@ + + + + + +#include "BSPLoad.h" + +#include + + + + + +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 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); +} + + + + + + + + diff --git a/src/osgPlugins/bsp/BSPLoad.h b/src/osgPlugins/bsp/BSPLoad.h new file mode 100644 index 000000000..a137c11dc --- /dev/null +++ b/src/osgPlugins/bsp/BSPLoad.h @@ -0,0 +1,203 @@ + + +#ifndef BSPLOAD_H +#define BSPLOAD_H + + +#include + +#include +#include + + +//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 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 m_loadVertices; + std::vector m_loadMeshIndices; + std::vector m_loadFaces; + std::vector m_loadTextures; + std::vector m_loadLightmaps; + std::vector m_loadLeaves; + std::vector m_loadLeafFaces; + std::vector m_loadPlanes; + std::vector m_loadNodes; + BSP_VISIBILITY_DATA m_loadVisibilityData; +}; + + + +#endif // BSPLOAD_H + diff --git a/src/osgPlugins/bsp/GNUmakefile b/src/osgPlugins/bsp/GNUmakefile new file mode 100644 index 000000000..34811eedf --- /dev/null +++ b/src/osgPlugins/bsp/GNUmakefile @@ -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 diff --git a/src/osgPlugins/bsp/ReaderWriterQ3BSP.cpp b/src/osgPlugins/bsp/ReaderWriterQ3BSP.cpp new file mode 100644 index 000000000..a30eb72fa --- /dev/null +++ b/src/osgPlugins/bsp/ReaderWriterQ3BSP.cpp @@ -0,0 +1,684 @@ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#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& aTextureArray, + osg::Vec3Array& aVertexArray,std::vector& aIndices, + osg::Vec2Array& aTextureDecalCoords,osg::Vec2Array& aTextureLMapCoords + ) const; + osg::Geometry* createPolygonFace(const BSP_LOAD_FACE& aLoadFace,const std::vector& aTextureArray,const std::vector& aTextureLMapArray, + osg::Vec3Array& aVertexArray, + osg::Vec2Array& aTextureDecalCoords,osg::Vec2Array& aTextureLMapCoords + ) const; + bool loadTextures(const BSPLoad& aLoadData,std::vector& aTextureArray) const; + bool loadLightMaps(const BSPLoad& aLoadData,std::vector& aTextureArray) const; +}; + +// Register with Registry to instantiate the above reader/writer. +osgDB::RegisterReaderWriterProxy 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 m_vertices; + std::vector m_indices; + + //arrays for multi_draw_arrays + std::vector m_trianglesPerRow; + std::vector 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 m_quadraticPatches; +}; + + + + + + + + + +osg::Geode* ReaderWriterQ3BSP::convertFromBSP(BSPLoad& aLoadData,const osgDB::ReaderWriter::Options* options) const +{ + + std::vector texture_array; + loadTextures(aLoadData,texture_array); + + std::vector 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; iaddDrawable(mesh_geom); + } + + + for(i=0; iaddDrawable(polygon_geom); + } + + + + for(i=0; i=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; ygetOrCreateStateSet(); + 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& aTextureArray, + osg::Vec3Array& aVertexArray,std::vector& 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& aTextureArray,const std::vector& 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& aTextureArray) const +{ + int num_textures=aLoadData.m_loadTextures.size(); + + int i; + for(i=0;isetImage(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& aTextureArray) const +{ + int num_textures=aLoadData.m_loadLightmaps.size(); + + int i; + for(i=0;isetImage(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; rowsetVertexArray(patch_vertex_array); + aGeometry->setTexCoordArray(0,patch_textcoord_array); + aGeometry->setTexCoordArray(1,patch_lmapcoord_array); + + + for(int row=0; rowaddPrimitiveSet(face_indices); + + } + + + + return true; +} + + + + + diff --git a/src/osgPlugins/bsp/ReaderWriterQ3BSP.h b/src/osgPlugins/bsp/ReaderWriterQ3BSP.h new file mode 100644 index 000000000..3a20c8c55 --- /dev/null +++ b/src/osgPlugins/bsp/ReaderWriterQ3BSP.h @@ -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); +*/ + + +