//! Sets a new mesh void CAnimatedMeshSceneNode::setMesh(IAnimatedMesh* mesh) { if (!mesh) return; // won't set null mesh if (Mesh != mesh) { if (Mesh) Mesh->drop(); Mesh = mesh; // grab the mesh (it's non-null!) Mesh->grab(); } // get materials and bounding box Box = Mesh->getBoundingBox(); IMesh* m = Mesh->getMesh(0,0); if (m) { Materials.clear(); Materials.reallocate(m->getMeshBufferCount()); for (u32 i=0; i<m->getMeshBufferCount(); ++i) { IMeshBuffer* mb = m->getMeshBuffer(i); if (mb) Materials.push_back(mb->getMaterial()); else Materials.push_back(video::SMaterial()); } } // clean up joint nodes if (JointsUsed) { JointsUsed=false; checkJoints(); } // get start and begin time // setAnimationSpeed(Mesh->getAnimationSpeed()); setFrameLoop(0, Mesh->getFrameCount()); }
void CMeshSceneNode::copyMaterials() { Materials.clear(); if (Mesh) { video::SMaterial mat; for (u32 i=0; i<Mesh->getMeshBufferCount(); ++i) { IMeshBuffer* mb = Mesh->getMeshBuffer(i); if (mb) mat = mb->getMaterial(); Materials.push_back(mat); } } }
//! renders the node. void CInstancedMeshSceneNode::render() { if (!IsVisible || !SceneManager->getActiveCamera()) return; if (!baseMesh || baseMesh->getMeshBuffer(0)->getVertexBuffer(1)->getVertexCount() == 0) return; IMeshBuffer* renderBuffer = baseMesh->getMeshBuffer(0); video::IVideoDriver* driver = SceneManager->getVideoDriver(); driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); driver->setMaterial(readOnlyMaterial ? material : renderBuffer->getMaterial()); driver->drawMeshBuffer(renderBuffer); // for debug purposes only: if (DebugDataVisible) { video::SMaterial m; m.Lighting = false; driver->setMaterial(m); if (DebugDataVisible & scene::EDS_BBOX) driver->draw3DBox(box, video::SColor(255, 255, 255, 255)); if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) { const u32 size = instanceNodeArray.size(); for (u32 i = 0; i < size; ++i) { core::aabbox3df box = renderBuffer->getBoundingBox(); driver->setTransform(video::ETS_WORLD, instanceNodeArray[i]->getAbsoluteTransformation()); driver->draw3DBox(box, video::SColor(255, 255, 255, 255)); } } } }
//! Sets a new mesh void CAnimatedMeshSceneNode::setMesh(IAnimatedMesh* mesh) { if (!mesh) return; // won't set null mesh if (Mesh) Mesh->drop(); Mesh = mesh; // get materials and bounding box Box = Mesh->getBoundingBox(); IMesh* m = Mesh->getMesh(0,0); if (m) { Materials.clear(); video::SMaterial mat; for (u32 i=0; i<m->getMeshBufferCount(); ++i) { IMeshBuffer* mb = m->getMeshBuffer(i); if (mb) mat = mb->getMaterial(); Materials.push_back(mat); } } // get start and begin time setFrameLoop ( 0, Mesh->getFrameCount() ); // grab the mesh if (Mesh) Mesh->grab(); }
//! creates the tree bool COctTreeSceneNode::createTree(IMesh* mesh) { if (!mesh) return false; MeshName = SceneManager->getMeshCache()->getMeshFilename( mesh ); deleteTree(); u32 beginTime = os::Timer::getRealTime(); u32 nodeCount = 0; u32 polyCount = 0; Box = mesh->getBoundingBox(); if (mesh->getMeshBufferCount()) { vertexType = mesh->getMeshBuffer(0)->getVertexType(); switch(vertexType) { case video::EVT_STANDARD: { for (u32 i=0; i<mesh->getMeshBufferCount(); ++i) { IMeshBuffer* b = mesh->getMeshBuffer(i); if (b->getVertexCount() && b->getIndexCount()) { Materials.push_back(b->getMaterial()); StdMeshes.push_back(OctTree<video::S3DVertex>::SMeshChunk()); OctTree<video::S3DVertex>::SMeshChunk &nchunk = StdMeshes.getLast(); nchunk.MaterialId = Materials.size() - 1; u32 v; nchunk.Vertices.reallocate(b->getVertexCount()); for (v=0; v<b->getVertexCount(); ++v) nchunk.Vertices.push_back(((video::S3DVertex*)b->getVertices())[v]); polyCount += b->getIndexCount(); nchunk.Indices.reallocate(b->getIndexCount()); for (v=0; v<b->getIndexCount(); ++v) nchunk.Indices.push_back(b->getIndices()[v]); } } StdOctTree = new OctTree<video::S3DVertex>(StdMeshes, MinimalPolysPerNode); nodeCount = StdOctTree->getNodeCount(); } break; case video::EVT_2TCOORDS: { for (u32 i=0; i<mesh->getMeshBufferCount(); ++i) { IMeshBuffer* b = mesh->getMeshBuffer(i); if (b->getVertexCount() && b->getIndexCount()) { Materials.push_back(b->getMaterial()); LightMapMeshes.push_back(OctTree<video::S3DVertex2TCoords>::SMeshChunk()); OctTree<video::S3DVertex2TCoords>::SMeshChunk& nchunk = LightMapMeshes.getLast(); nchunk.MaterialId = Materials.size() - 1; u32 v; nchunk.Vertices.reallocate(b->getVertexCount()); for (v=0; v<b->getVertexCount(); ++v) nchunk.Vertices.push_back(((video::S3DVertex2TCoords*)b->getVertices())[v]); polyCount += b->getIndexCount(); nchunk.Indices.reallocate(b->getIndexCount()); for (v=0; v<b->getIndexCount(); ++v) nchunk.Indices.push_back(b->getIndices()[v]); } } LightMapOctTree = new OctTree<video::S3DVertex2TCoords>(LightMapMeshes, MinimalPolysPerNode); nodeCount = LightMapOctTree->getNodeCount(); } break; case video::EVT_TANGENTS: { for (u32 i=0; i<mesh->getMeshBufferCount(); ++i) { IMeshBuffer* b = mesh->getMeshBuffer(i); if (b->getVertexCount() && b->getIndexCount()) { Materials.push_back(b->getMaterial()); TangentsMeshes.push_back(OctTree<video::S3DVertexTangents>::SMeshChunk()); OctTree<video::S3DVertexTangents>::SMeshChunk& nchunk = TangentsMeshes.getLast(); nchunk.MaterialId = Materials.size() - 1; u32 v; nchunk.Vertices.reallocate(b->getVertexCount()); for (v=0; v<b->getVertexCount(); ++v) nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]); polyCount += b->getIndexCount(); nchunk.Indices.reallocate(b->getIndexCount()); for (v=0; v<b->getIndexCount(); ++v) nchunk.Indices.push_back(b->getIndices()[v]); } } TangentsOctTree = new OctTree<video::S3DVertexTangents>(TangentsMeshes, MinimalPolysPerNode); nodeCount = TangentsOctTree->getNodeCount(); } break; } } u32 endTime = os::Timer::getRealTime(); c8 tmp[255]; sprintf(tmp, "Needed %ums to create OctTree SceneNode.(%u nodes, %u polys)", endTime - beginTime, nodeCount, polyCount/3); os::Printer::log(tmp, ELL_INFORMATION); return true; }
//! writes a mesh bool COBJMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags) { if (!file) return false; os::Printer::log("Writing mesh", file->getFileName()); // write OBJ MESH header const core::stringc name(FileSystem->getFileBasename(SceneManager->getMeshCache()->getMeshName(mesh), false)+".mtl"); file->write("# exported by Irrlicht\n",23); file->write("mtllib ",7); file->write(name.c_str(),name.size()); file->write("\n\n",2); // write mesh buffers core::array<video::SMaterial*> mat; u32 allVertexCount=1; // count vertices over the whole file for (u32 i=0; i<mesh->getMeshBufferCount(); ++i) { core::stringc num(i+1); IMeshBuffer* buffer = mesh->getMeshBuffer(i); if (buffer && buffer->getVertexCount()) { file->write("g grp", 5); file->write(num.c_str(), num.size()); file->write("\n",1); u32 j; const u32 vertexCount = buffer->getVertexCount(); for (j=0; j<vertexCount; ++j) { file->write("v ",2); getVectorAsStringLine(buffer->getPosition(j), num); file->write(num.c_str(), num.size()); } for (j=0; j<vertexCount; ++j) { file->write("vt ",3); getVectorAsStringLine(buffer->getTCoords(j), num); file->write(num.c_str(), num.size()); } for (j=0; j<vertexCount; ++j) { file->write("vn ",3); getVectorAsStringLine(buffer->getNormal(j), num); file->write(num.c_str(), num.size()); } file->write("usemtl mat",10); num = ""; for (j=0; j<mat.size(); ++j) { if (*mat[j]==buffer->getMaterial()) { num = core::stringc(j); break; } } if (num == "") { num = core::stringc(mat.size()); mat.push_back(&buffer->getMaterial()); } file->write(num.c_str(), num.size()); file->write("\n",1); const u32 indexCount = buffer->getIndexCount(); for (j=0; j<indexCount; j+=3) { file->write("f ",2); num = core::stringc(buffer->getIndices()[j+2]+allVertexCount); file->write(num.c_str(), num.size()); file->write("/",1); file->write(num.c_str(), num.size()); file->write("/",1); file->write(num.c_str(), num.size()); file->write(" ",1); num = core::stringc(buffer->getIndices()[j+1]+allVertexCount); file->write(num.c_str(), num.size()); file->write("/",1); file->write(num.c_str(), num.size()); file->write("/",1); file->write(num.c_str(), num.size()); file->write(" ",1); num = core::stringc(buffer->getIndices()[j+0]+allVertexCount); file->write(num.c_str(), num.size()); file->write("/",1); file->write(num.c_str(), num.size()); file->write("/",1); file->write(num.c_str(), num.size()); file->write(" ",1); file->write("\n",1); } file->write("\n",1); allVertexCount += vertexCount; } } if (mat.size() == 0) return true; file = FileSystem->createAndWriteFile( name ); if (file) { os::Printer::log("Writing material", file->getFileName()); file->write("# exported by Irrlicht\n\n",24); for (u32 i=0; i<mat.size(); ++i) { core::stringc num(i); file->write("newmtl mat",10); file->write(num.c_str(),num.size()); file->write("\n",1); getColorAsStringLine(mat[i]->AmbientColor, "Ka", num); file->write(num.c_str(),num.size()); getColorAsStringLine(mat[i]->DiffuseColor, "Kd", num); file->write(num.c_str(),num.size()); getColorAsStringLine(mat[i]->SpecularColor, "Ks", num); file->write(num.c_str(),num.size()); getColorAsStringLine(mat[i]->EmissiveColor, "Ke", num); file->write(num.c_str(),num.size()); num = core::stringc(mat[i]->Shininess/0.128f); file->write("Ns ", 3); file->write(num.c_str(),num.size()); file->write("\n", 1); if (mat[i]->getTexture(0)) { file->write("map_Kd ", 7); file->write(mat[i]->getTexture(0)->getName().getPath().c_str(), mat[i]->getTexture(0)->getName().getPath().size()); file->write("\n",1); } file->write("\n",1); } file->drop(); } return true; }
/* This method has a lot of duplication and overhead. Moreover, the tangents mesh conversion does not really work. I think we need a a proper mesh implementation for octrees, which handle all vertex types internally. Converting all structures to just one vertex type is always problematic. Thanks to Auria for fixing major parts of this method. */ bool COctreeSceneNode::createTree(IMesh* mesh) { if (!mesh) return false; MeshName = SceneManager->getMeshCache()->getMeshName(mesh); mesh->grab(); deleteTree(); Mesh = mesh; const u32 beginTime = os::Timer::getRealTime(); u32 nodeCount = 0; u32 polyCount = 0; u32 i; Box = mesh->getBoundingBox(); if (mesh->getMeshBufferCount()) { // check for "larger" buffer types u32 meshReserve = StdMeshes.size(); Materials.reallocate(Materials.size()+meshReserve); StdMeshesMatID.reallocate(meshReserve); for ( i=0; i < mesh->getMeshBufferCount(); ++i) { IMeshBuffer* b = mesh->getMeshBuffer(i); if (b->getVertexBuffer()->getVertexCount() && b->getIndexBuffer()->getIndexCount()) { Materials.push_back(b->getMaterial()); IMeshBuffer* nchunk = StdMeshes[i]; StdMeshesMatID.push_back(Materials.size() - 1); if (UseVisibilityAndVBOs) { nchunk->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_VERTEX); nchunk->setHardwareMappingHint(scene::EHM_DYNAMIC, scene::EBT_INDEX); } else nchunk->setHardwareMappingHint(scene::EHM_STATIC); SceneManager->getMeshManipulator()->copyVertices(b->getVertexBuffer(), nchunk->getVertexBuffer(), true); polyCount += b->getIndexBuffer()->getIndexCount(); nchunk->getIndexBuffer()->reallocate(b->getIndexBuffer()->getIndexCount()); for (u32 v=0; v<b->getIndexBuffer()->getIndexCount(); ++v) nchunk->getIndexBuffer()->addIndex(b->getIndexBuffer()->getIndex(v)); } } StdOctree = new Octree(StdMeshes, StdMeshesMatID, MinimalPolysPerNode); nodeCount = StdOctree->getNodeCount(); } const u32 endTime = os::Timer::getRealTime(); c8 tmp[255]; sprintf(tmp, "Needed %ums to create Octree SceneNode.(%u nodes, %u polys)", endTime - beginTime, nodeCount, polyCount/3); os::Printer::log(tmp, ELL_INFORMATION); return true; }
/* This method has a lot of duplication and overhead. Moreover, the tangents mesh conversion does not really work. I think we need a a proper mesh implementation for octrees, which handle all vertex types internally. Converting all structures to just one vertex type is always problematic. Thanks to Auria for fixing major parts of this method. */ bool COctreeSceneNode::createTree(IMesh* mesh) { if (!mesh) return false; MeshName = SceneManager->getMeshCache()->getMeshName(mesh); mesh->grab(); deleteTree(); Mesh = mesh; const u32 beginTime = os::Timer::getRealTime(); u32 nodeCount = 0; u32 polyCount = 0; u32 i; Box = mesh->getBoundingBox(); if (mesh->getMeshBufferCount()) { // check for "larger" buffer types u32 meshReserve = StdMeshes.size(); Materials.reallocate(Materials.size()+meshReserve); StdMeshesMatID.reallocate(meshReserve); for ( i=0; i < mesh->getMeshBufferCount(); ++i) { const scene::IMeshManipulator* meshManipulator = SceneManager->getMeshManipulator(); IMeshBuffer* meshBuffer = mesh->getMeshBuffer(i); IMeshBuffer* nchunk = StdMeshes[i]; // copy vertices video::IVertexDescriptor* srcDescriptor = meshBuffer->getVertexDescriptor(); video::IVertexDescriptor* dstDescriptor = nchunk->getVertexDescriptor(); const u32 vbCount = meshBuffer->getVertexBufferCount(); for (u32 j = 0; j < vbCount; ++j) meshManipulator->copyVertices(meshBuffer->getVertexBuffer(j), j, srcDescriptor, nchunk->getVertexBuffer(j), j, dstDescriptor, true); // copy indices scene::IIndexBuffer* srcIndexBuffer = meshBuffer->getIndexBuffer(); scene::IIndexBuffer* dstIndexBuffer = nchunk->getIndexBuffer(); meshManipulator->copyIndices(srcIndexBuffer, dstIndexBuffer); // copy material Materials.push_back(meshBuffer->getMaterial()); StdMeshesMatID.push_back(Materials.size() - 1); // others polyCount += dstIndexBuffer->getIndexCount(); if (UseVBOs) { if (UseVisibilityAndVBOs) { nchunk->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_VERTEX); nchunk->setHardwareMappingHint(scene::EHM_DYNAMIC, scene::EBT_INDEX); } else nchunk->setHardwareMappingHint(scene::EHM_STATIC); } else { nchunk->setHardwareMappingHint(scene::EHM_NEVER); } } StdOctree = new Octree(StdMeshes, StdMeshesMatID, MinimalPolysPerNode); nodeCount = StdOctree->getNodeCount(); } const u32 endTime = os::Timer::getRealTime(); c8 tmp[255]; sprintf(tmp, "Needed %ums to create Octree SceneNode.(%u nodes, %u polys)", endTime - beginTime, nodeCount, polyCount/3); os::Printer::log(tmp, ELL_INFORMATION); return true; }
int main(int, char**){ IrrlichtDevice *device; //create the irrlicht device //IrrlichtDevice *device = createDevice(video::EDT_OPENGL, core::dimension2d<s32>(1440,900), 32, false, true, true, InputHandler::getInstance()); device = createDevice(video::EDT_OPENGL, core::dimension2d<s32>(800,600), 32, false//shadows ,true, true, InputHandler::getInstance()); if(device==NULL)return 1; //create the irrKlang device // start the sound engine with default parameters ISoundEngine* soundEngine = createIrrKlangDevice(); //ISound* CurrentPlayingSound = 0; //ISoundSource* backgroundMusic = soundEngine->addSoundSourceFromFile("../media/sounds/getout.ogg"); //backgroundMusic->setDefaultVolume(0.3f); if (!soundEngine){ printf("Could not startup irrKlang sound engine\n"); return 0; // error starting up the engine } //Play some sound while all this is starting, loop it //CurrentPlayingSound = soundEngine->play2D("../media/sounds/getout.ogg", true); //soundEngine->play2D(backgroundMusic); //set the title of the window device->setWindowCaption(L"Quake the Can"); //hide the cursor device->getCursorControl()->setVisible(false); //get the driver, scene manager, and gui environment objects video::IVideoDriver* driver = device->getVideoDriver(); scene::ISceneManager* smgr = device->getSceneManager(); //Add this back in with the return of the Main GUI gui::IGUIEnvironment* guienv = device->getGUIEnvironment(); driver->setFog(irr::video::SColor(255,25,25,25), true, 0,750, 0, true, true);//set the fog properties /***Load the map***/ //load the pk3 file containing the .bsp map file into the engine file system device->getFileSystem()->addZipFileArchive("../media/map-20kdm2.pk3"); //get the mesh from the map bsp file scene::IQ3LevelMesh* mesh = (scene::IQ3LevelMesh*) (smgr->getMesh("maps/20kdm2.bsp")); //add a scene node for the map scene::ISceneNode *mapNode = NULL;//scene node representing the level itself mapNode = smgr->addOctTreeSceneNode( mesh->getMesh(quake3::E_Q3_MESH_GEOMETRY), 0, -1, 1024); if(!mesh){throw new std::string("mesh creation error");} //code i took from an irrlicht tutorial to load in quake 3 shader items scene::IMesh * additional_mesh = mesh->getMesh ( quake3::E_Q3_MESH_ITEMS ); for ( u32 i = 0; i!= additional_mesh->getMeshBufferCount (); ++i ){ IMeshBuffer *meshBuffer = additional_mesh->getMeshBuffer ( i ); const video::SMaterial &material = meshBuffer->getMaterial(); //! The ShaderIndex is stored in the material parameter s32 shaderIndex = (s32) material.MaterialTypeParam2; //the meshbuffer can be rendered without additional support, or it has no shader const quake3::SShader *shader = mesh->getShader ( shaderIndex ); if( 0 == shader ){throw new std::string("Error loading shaders");} mapNode->addChild((smgr->addQuake3SceneNode ( meshBuffer, shader ))); } mesh->releaseMesh ( quake3::E_Q3_MESH_ITEMS ); if(!mapNode)return 1; //CPTODO: get rid of local constant mapNode->setPosition(core::vector3df(-1300,-144,-1249)); mapNode->setMaterialFlag(video::EMF_LIGHTING, true);//enable lighting mapNode->setMaterialType(irr::video::EMT_LIGHTMAP_LIGHTING_M4);//set the material property of the map to blend the lightmap with dynamic lighting smgr->addSkyDomeSceneNode(driver->getTexture("../media/skydome.jpg"),32,32,1.0f,2.0f); //create the skydome mapNode->setMaterialFlag(irr::video::EMF_FOG_ENABLE, true);//enable fogging on the map node //create a triangle selector object for the map for use in creating collisions irr::scene::ITriangleSelector* selector = NULL; selector = smgr->createOctTreeTriangleSelector(mesh->getMesh(quake3::E_Q3_MESH_GEOMETRY),//map->getMesh(0), mapNode,128); if(!selector)return 1; mapNode->setTriangleSelector(selector); {//block containing the game object //create game HUD object gameHUD* display = gameHUD::getInstance(); display->setVideoDriver(driver); //create the game object irr::scene::ISceneNode* x = smgr->addCubeSceneNode(); x->setPosition(vector3df(-400,-41,-42)); x->setScale(vector3df(45,1,5)); x->setMaterialTexture(0,driver->getTexture("../media/wall.jpg")); x->setMaterialTexture(1,driver->getTexture("../media/wall.jpg")); x->setMaterialFlag(video::EMF_FOG_ENABLE, true); specialWalls.push_back(x); irr::scene::ISceneNode* x2 = smgr->addCubeSceneNode(); x2->setPosition(vector3df(-400,-41,232)); x2->setScale(vector3df(45,.9,5)); x2->setMaterialTexture(0,driver->getTexture("../media/wall.jpg")); x2->setMaterialFlag(video::EMF_FOG_ENABLE, true); specialWalls.push_back(x2); irr::scene::ISceneNode* x3 = smgr->addCubeSceneNode(); x3->setPosition(vector3df(-603,-41,104)); x3->setScale(vector3df(5,.95,45)); x3->setMaterialTexture(0,driver->getTexture("../media/wall.jpg")); x3->setMaterialFlag(video::EMF_FOG_ENABLE, true); specialWalls.push_back(x3); x3 = smgr->addCubeSceneNode(); x3->setPosition(vector3df(825,-41,104)); x3->setScale(vector3df(5,1.25,45)); x3->setMaterialTexture(0,driver->getTexture("../media/wall.jpg")); x3->setMaterialFlag(video::EMF_FOG_ENABLE, true); specialWalls.push_back(x3); x = smgr->addCubeSceneNode(); x->setPosition(vector3df(-400+1000,-41,-42)); x->setScale(vector3df(45,1.05,5)); x->setMaterialTexture(0,driver->getTexture("../media/wall.jpg")); x->setMaterialTexture(1,driver->getTexture("../media/wall.jpg")); x->setMaterialFlag(video::EMF_FOG_ENABLE, true); specialWalls.push_back(x); x2 = smgr->addCubeSceneNode(); x2->setPosition(vector3df(-400+1000,-41,232)); x2->setScale(vector3df(45,.95,5)); x2->setMaterialTexture(0,driver->getTexture("../media/wall.jpg")); x2->setMaterialFlag(video::EMF_FOG_ENABLE, true); specialWalls.push_back(x2); ktcGame game(device, selector, display); /*******************************************************/ /***************GAME UPDATE LOOP************************/ /*******************************************************/ while(device->run()){ //run update on the message handler to send any delayed messges that have passed their time stamp MsgHandler->update(device->getTimer()); game.update(device->getTimer()); //this has been taken out for planning based on menu system guienv->drawAll(); if(InputHandler::getInstance()->EXIT_MESSAGE) break; } }//scope containing the game //device->drop(); //soundEngine->drop(); return 0; }