#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Q3BSPReader.h" #include "Q3BSPLoad.h" #ifndef GL_RGBA8 #define GL_RGBA8 0x8058 #endif using namespace bsp; Q3BSPReader::Q3BSPReader() { root_node = NULL; } bool Q3BSPReader::readFile(const std::string& file, const osgDB::ReaderWriter::Options* options) { std::string ext = osgDB::getLowerCaseFileExtension(file); Q3BSPLoad load_data; load_data.Load(file,8); osg::Geode* geode = convertFromBSP(load_data, options); if (!geode) return false; //osg::StateSet* state_set=geode->getOrCreateStateSet(); //state_set->setMode(osg::CullFace::BACK,osg::StateAttribute::ON); root_node = geode; return true; } osg::ref_ptr Q3BSPReader::getRootNode() { return root_node; } 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_tessellation(0), m_vertices(32), m_indices(32) { } ~BSP_BIQUADRATIC_PATCH() { } bool Tessellate(int newTessellation,osg::Geometry* aGeometry); BSP_VERTEX m_controlPoints[9]; // Se accede a ellos en la carga protected: int m_tessellation; 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_textureIndex(0), m_lightmapIndex(0), m_width(0), m_height(0), m_numQuadraticPatches(0), 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* Q3BSPReader::convertFromBSP( Q3BSPLoad& 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::ref_ptr vertex_array = new osg::Vec3Array(num_load_vertices); osg::ref_ptr text_decal_array = new osg::Vec2Array(num_load_vertices); osg::ref_ptr text_lmap_array = new osg::Vec2Array(num_load_vertices); float scale = 0.0254; 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].Tessellate(8/*aCurveTessellation*/,patch_geom); map_geode->addDrawable(patch_geom); } } } //int num_primitive_sets=geom->getNumPrimitiveSets(); //const osg::BoundingSphere& bs=map_geom->getBound(); map_geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); return map_geode; } osg::Geometry* Q3BSPReader::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* Q3BSPReader::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 Q3BSPReader::loadTextures( const Q3BSPLoad& aLoadData, std::vector& aTextureArray) const { int num_textures=aLoadData.m_loadTextures.size(); int i; for(i=0;i image = osgDB::readRefImageFile(tgaExtendedName); if (!image) { image = osgDB::readRefImageFile(jpgExtendedName); if (!image) { aTextureArray.push_back(NULL); continue; //? } } osg::Texture2D* texture= new osg::Texture2D; texture->setImage(image.get()); 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 Q3BSPReader::loadLightMaps( const Q3BSPLoad& 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;whiteidx<3;whiteidx++) { data[whiteidx]=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; } //Tessellate a biquadratic patch bool BSP_BIQUADRATIC_PATCH::Tessellate(int newTessellation,osg::Geometry* aGeometry) { m_tessellation=newTessellation; float px, py; BSP_VERTEX temp[3]; m_vertices.resize((m_tessellation+1)*(m_tessellation+1)); for(int v=0; v<=m_tessellation; ++v) { px=(float)v/m_tessellation; 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_tessellation; ++u) { py=(float)u/m_tessellation; 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_tessellation; ++v) { px=(float)v/m_tessellation; m_vertices[u*(m_tessellation+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_tessellation*(m_tessellation+1)*2); int row; for(row=0; rowsetVertexArray(patch_vertex_array); aGeometry->setTexCoordArray(0,patch_textcoord_array); aGeometry->setTexCoordArray(1,patch_lmapcoord_array); for(row=0; rowaddPrimitiveSet(face_indices); } return true; }