STreeMesh* CTreeGenerator::generateTree( s32 radialSegments, s32 seed, bool addLeaves, s32 cutoffLevel ) { STreeMesh* treeMesh = new STreeMesh(); Seed = seed; LeafSeed = seed; RadialSegments = radialSegments; CutoffLevel = cutoffLevel; AddLeaves = addLeaves; SMeshBuffer* buffer = new SMeshBuffer(); treeMesh->setMeshBuffer( buffer ); SBranch* root = getBranchWithId( RootIdRef ); if ( root != 0 ) { appendBranch( core::matrix4(), root, 1.0f, 1.0f, Levels, buffer, treeMesh->Leaves ); } buffer->drop(); return treeMesh; }
Sprite::Sprite(std::string const& name, bool const& center) :Object(name), center_(center), thismesh_(0) { if( !sprite_plane_ptr_ ) { S3DVertex vertices[4]; u16 indices[6] = {0,2,3,3,1,0}; vertices[0].Pos = vector3df(0,-1,0); vertices[1].Pos = vector3df(1,-1,0); vertices[2].Pos = vector3df(0, 0,0); vertices[3].Pos = vector3df(1, 0,0); vertices[0].Normal = vector3df(0,0,-1); vertices[1].Normal = vector3df(0,0,-1); vertices[2].Normal = vector3df(0,0,-1); vertices[3].Normal = vector3df(0,0,-1); vertices[0].TCoords = vector2df(0,1); vertices[1].TCoords = vector2df(1,1); vertices[2].TCoords = vector2df(0,0); vertices[3].TCoords = vector2df(1,0); SMeshBuffer* buf = new SMeshBuffer(); buf->append(vertices, 4, indices, 6); sprite_plane_.addMeshBuffer( buf ); sprite_plane_.recalculateBoundingBox(); sprite_plane_ptr_ = &sprite_plane_; buf->drop(); //the addMeshBuffer method will grab it, so we can drop this ptr. } }
IMesh* MeshTools::createMeshFromSoftBody(btSoftBody* softBody) { SMeshBuffer* buffer = new SMeshBuffer(); video::S3DVertex vtx; vtx.Color.set(255,255,255,255); /* Each soft body contain an array of vertices (nodes/particles_mass) */ btSoftBody::tNodeArray& nodes(softBody->m_nodes); // Convert bullet nodes to vertices for(int i=0;i<nodes.size();++i) { const btSoftBody::Node& n=nodes[i]; const btVector3 normal=n.m_n; const btVector3 pos=n.m_x; vtx.Pos.set(pos.getX(), pos.getY(), pos.getZ()); vtx.Normal.set(normal.getX(), normal.getY(), normal.getZ()); // TODO: calculate texture coords //vtx.TCoords.set(tsx, tsy); buffer->Vertices.push_back(vtx); } // Convert triangles of the softbody to an index list for(int i=0;i<softBody->m_faces.size();++i) { auto faces = softBody->m_faces; btSoftBody::Node* node_0=faces[i].m_n[0]; btSoftBody::Node* node_1=faces[i].m_n[1]; btSoftBody::Node* node_2=faces[i].m_n[2]; const int indices[] = { int(node_0-&nodes[0]), int(node_1-&nodes[0]), int(node_2-&nodes[0]) }; for(int j=0;j<3;++j) buffer->Indices.push_back(indices[j]); } buffer->recalculateBoundingBox(); // Default the mesh to stream because most likely we will be updating // the vertex positions every frame to deal with softbody movement. buffer->setHardwareMappingHint(EHM_STREAM); SMesh* mesh = new SMesh(); mesh->addMeshBuffer(buffer); mesh->recalculateBoundingBox(); buffer->drop(); return mesh; }
void MeshBuffer_SetVertex(IntPtr meshb, unsigned int nr, IntPtr vert) { SMeshBuffer *mb = ((SMeshBuffer*)meshb); if(nr >= mb->getVertexCount()) { mb->Vertices.push_back(*((S3DVertex*)vert)); MeshBuffer_SetVertex(meshb, nr, vert); } else (((S3DVertex*)(mb->getVertices()))[nr]) = *((S3DVertex*)vert); }
void addstrip(const HeightMap &hm, colour_func cf, u16 y0, u16 y1, u32 bufNum) { SMeshBuffer *buf = 0; if (bufNum<Mesh->getMeshBufferCount()) { buf = (SMeshBuffer*)Mesh->getMeshBuffer(bufNum); } else { // create new buffer buf = new SMeshBuffer(); Mesh->addMeshBuffer(buf); // to simplify things we drop here but continue using buf buf->drop(); } buf->Vertices.set_used((1 + y1 - y0) * Width); u32 i=0; for (u16 y = y0; y <= y1; ++y) { for (u16 x = 0; x < Width; ++x) { const f32 z = hm.get(x, y); const f32 xx = (f32)x/(f32)Width; const f32 yy = (f32)y/(f32)Height; S3DVertex& v = buf->Vertices[i++]; v.Pos.set(x, Scale * z, y); v.Normal.set(hm.getnormal(x, y, Scale)); v.Color=cf(xx, yy, z); v.TCoords.set(xx, yy); } } buf->Indices.set_used(6 * (Width - 1) * (y1 - y0)); i=0; for(u16 y = y0; y < y1; ++y) { for(u16 x = 0; x < Width - 1; ++x) { const u16 n = (y-y0) * Width + x; buf->Indices[i]=n; buf->Indices[++i]=n + Width; buf->Indices[++i]=n + Width + 1; buf->Indices[++i]=n + Width + 1; buf->Indices[++i]=n + 1; buf->Indices[++i]=n; ++i; } } buf->recalculateBoundingBox(); }
void MeshBuffer_SetColor(IntPtr meshb, M_SCOLOR color) { SMeshBuffer *mb = ((SMeshBuffer*)meshb); int cnt = mb->getVertexCount(); //mb->grab(); for (int i=0;i<cnt;i++) { mb->Vertices[i].Color = MU_SCOLOR(color); } mb->setDirty(irr::scene::EBT_VERTEX); }
//! constructor CBillboardTextSceneNode::CBillboardTextSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, gui::IGUIFont* font,const wchar_t* text, const core::vector3df& position, const core::dimension2d<f32>& size, video::SColor colorTop,video::SColor shade_bottom ) : IBillboardTextSceneNode(parent, mgr, id, position), Font(0), ColorTop(colorTop), ColorBottom(shade_bottom), Mesh(0) { #ifdef _DEBUG setDebugName("CBillboardTextSceneNode"); #endif Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; Material.MaterialTypeParam = 1.f / 255.f; Material.BackfaceCulling = false; Material.Lighting = false; Material.ZBuffer = video::ECFN_LESSEQUAL; Material.ZWriteEnable = false; if (font) { // doesn't support other font types if (font->getType() == gui::EGFT_BITMAP) { Font = (gui::IGUIFontBitmap*)font; Font->grab(); // mesh with one buffer per texture Mesh = new SMesh(); for (u32 i=0; i<Font->getSpriteBank()->getTextureCount(); ++i) { SMeshBuffer *mb = new SMeshBuffer(); mb->Material = Material; mb->Material.setTexture(0, Font->getSpriteBank()->getTexture(i)); Mesh->addMeshBuffer(mb); mb->drop(); } } else { os::Printer::log("Sorry, CBillboardTextSceneNode does not support this font type", ELL_INFORMATION); } } setText(text); setSize(size); setAutomaticCulling ( scene::EAC_BOX ); }
IMeshSceneNode* CustomSceneNodeManager::CreateConeSceneNode(scene::ISceneManager* sceneManager, s32 id, SColor& color, unsigned int resolution, float radius, float height) { if (resolution >= 4) { /*IMesh* newConeMesh = sceneManager->getGeometryCreator()->createConeMesh(radius, height, resolution, color, color); IMeshSceneNode* node = sceneManager->addMeshSceneNode(newConeMesh); sceneManager->getMeshCache()->addMesh(irr::io::path("ConeMesh"), (irr::scene::IAnimatedMesh*)newConeMesh); newConeMesh->drop();*/ SMesh* newConeMesh = new SMesh(); SMeshBuffer* buf = new SMeshBuffer(); newConeMesh->addMeshBuffer(buf); buf->MappingHint_Vertex = EHM_STATIC; buf->MappingHint_Index = EHM_STATIC; buf->drop(); int noWarningSignedResolution = resolution; float currentTheta = 0.0f; float skipAmount = 2.0f*PI / (float)resolution; float halfHeight = height / 2.0f; S3DVertex temp1 = S3DVertex(Vector3(0.0f, halfHeight, 0.0f), Vector3_Zero, color, vector2d<f32>(0.0f, 0.0f)); S3DVertex temp2 = S3DVertex(Vector3(0.0f, -halfHeight, 0.0f), Vector3_Zero, color, vector2d<f32>(0.0f, 1.0f)); for(int i = 0; i < noWarningSignedResolution; i++) { float x = cosf(currentTheta) * radius; float z = sinf(currentTheta) * radius; temp2.Pos.X = x; temp2.Pos.Z = z; temp2.TCoords.X = currentTheta / 2.0f*PI; buf->Vertices.push_back(temp2); currentTheta += skipAmount; } buf->Vertices.push_back(temp1); //Get side indices for(int i = 0; i < noWarningSignedResolution - 1; i++) { buf->Indices.push_back(i); buf->Indices.push_back(buf->Vertices.size()-1); buf->Indices.push_back(i+1); } buf->Indices.push_back(buf->Vertices.size()-2); buf->Indices.push_back(buf->Vertices.size()-1); buf->Indices.push_back(0); temp2.Pos.X = 0.0f; temp2.Pos.Z = 0.0f; buf->Vertices.push_back(temp2); //Get bottom indices for(int i = 0; i < noWarningSignedResolution - 1; i++) { buf->Indices.push_back(i); buf->Indices.push_back(i+1); buf->Indices.push_back(buf->Vertices.size()-1); } buf->Indices.push_back(buf->Vertices.size()-1); buf->Indices.push_back(buf->Vertices.size()-3); buf->Indices.push_back(0); //Calculate normals CalculateNormals(buf->Vertices, buf->Indices); buf->recalculateBoundingBox(); newConeMesh->recalculateBoundingBox(); IMeshSceneNode* node = sceneManager->addMeshSceneNode(newConeMesh); newConeMesh->drop(); return node; } return NULL; }
IAnimatedMesh* CGeometryCreator::createTerrainMesh(video::IImage* texture, video::IImage* heightmap, const core::dimension2d<f32>& stretchSize, f32 maxHeight, video::IVideoDriver* driver, const core::dimension2d<s32> maxVtxBlockSize, bool debugBorders) { u32 tm = os::Timer::getRealTime()/1000; if (!texture || !heightmap) return 0; video::SMaterial material; c8 textureName[64]; c8 tmp[255]; // debug border s32 borderSkip = debugBorders ? 0 : 1; video::S3DVertex vtx; vtx.Color.set(255,255,255,255); SMesh* mesh = new SMesh(); core::dimension2d<s32> hMapSize= heightmap->getDimension(); core::dimension2d<s32> tMapSize= texture->getDimension(); core::position2d<f32> thRel((f32)tMapSize.Width / (s32)hMapSize.Width, (f32)tMapSize.Height / (s32)hMapSize.Height); core::position2d<s32> processed(0,0); while (processed.Y<hMapSize.Height) { while(processed.X<hMapSize.Width) { core::dimension2d<s32> blockSize = maxVtxBlockSize; if (processed.X + blockSize.Width > hMapSize.Width) blockSize.Width = hMapSize.Width - processed.X; if (processed.Y + blockSize.Height > hMapSize.Height) blockSize.Height = hMapSize.Height - processed.Y; SMeshBuffer* buffer = new SMeshBuffer(); s32 x,y; // add vertices of vertex block for (y=0; y<blockSize.Height; ++y) for (x=0; x<blockSize.Width; ++x) { video::SColor clr = heightmap->getPixel(x+processed.X, y+processed.Y); f32 height = ((clr.getRed() + clr.getGreen() + clr.getBlue()) / 3.0f)/255.0f * maxHeight; vtx.Pos.set((f32)(x+processed.X) * stretchSize.Width, height, (f32)(y+processed.Y) * stretchSize.Height); vtx.TCoords.set((f32)(x+0.5f) / ((f32)blockSize.Width), (f32)(y+0.5f) / ((f32)blockSize.Height)); buffer->Vertices.push_back(vtx); } // add indices of vertex block for (y=0; y<blockSize.Height-1; ++y) for (x=0; x<blockSize.Width-1; ++x) { s32 c = (y*blockSize.Width) + x; buffer->Indices.push_back(c); buffer->Indices.push_back(c + blockSize.Width); buffer->Indices.push_back(c + 1); buffer->Indices.push_back(c + 1); buffer->Indices.push_back(c + blockSize.Width); buffer->Indices.push_back(c + 1 + blockSize.Width); } // recalculate normals for (s32 i=0; i<(s32)buffer->Indices.size(); i+=3) { core::plane3d<f32> p( buffer->Vertices[buffer->Indices[i+0]].Pos, buffer->Vertices[buffer->Indices[i+1]].Pos, buffer->Vertices[buffer->Indices[i+2]].Pos); p.Normal.normalize(); buffer->Vertices[buffer->Indices[i+0]].Normal = p.Normal; buffer->Vertices[buffer->Indices[i+1]].Normal = p.Normal; buffer->Vertices[buffer->Indices[i+2]].Normal = p.Normal; } if (buffer->Vertices.size()) { // create texture for this block video::IImage* img = new video::CImage(texture, core::position2d<s32>((s32)(processed.X*thRel.X), (s32)(processed.Y*thRel.Y)), core::dimension2d<s32>((s32)(blockSize.Width*thRel.X), (s32)(blockSize.Height*thRel.Y))); sprintf(textureName, "terrain%d_%d", tm, mesh->getMeshBufferCount()); material.Texture1 = driver->addTexture(textureName, img); if (material.Texture1) { sprintf(tmp, "Generated terrain texture (%dx%d): %s", material.Texture1->getSize().Width, material.Texture1->getSize().Height, textureName); os::Printer::log(tmp); } else os::Printer::log("Could not create terrain texture.", textureName, ELL_ERROR); buffer->Material = material; img->drop(); } buffer->recalculateBoundingBox(); mesh->addMeshBuffer(buffer); buffer->drop(); // keep on processing processed.X += maxVtxBlockSize.Width - borderSkip; } // keep on processing processed.X = 0; processed.Y += maxVtxBlockSize.Height - borderSkip; } SAnimatedMesh* animatedMesh = new SAnimatedMesh(); mesh->recalculateBoundingBox(); animatedMesh->addMesh(mesh); animatedMesh->recalculateBoundingBox(); mesh->drop(); return animatedMesh; }
PlayerFrame::PlayerFrame(FrameInfo info, bool load_volumic) { // increase total number of loaded frames PlayerFrame::totalLoadedFrames++; device->getLogger()->log((stringw("Loading frame number ")+stringw(info.id)+L". Total of frames loaded : "+stringw(PlayerFrame::totalLoadedFrames)).c_str()); core::array<stringc> _lastEleFileNames; core::array<stringc> _lastFaceFileNames; core::array<scene::SMeshBuffer*> _lastBuffers; // initialize some variables this->id = info.id; for (u32 o=0; o < info.nodefiles.size(); o++) { SMeshBuffer* buffer = new SMeshBuffer(); IMeshSceneNode* node = NULL; stringc nodeFileName = info.nodefiles[o]; stringc faceFileName = info.facefiles[o]; stringc eleFileName = info.elefiles[o]; // LOADING ifstream innode; ifstream inele; ifstream inface; int nb_of_points, nb_of_tetrahedra, nb_of_faces; int p1, p2, p3, p4; yohan::base::DATA x, y, z; // used to know if an error occured in the while loop bool error = false; // ----------------------------------------------------------------------- // - POINTS -------------------------------------------------------------- // ----------------------------------------------------------------------- innode.open(nodeFileName.c_str(), ios::in | ios::binary); // opens the nodes file if (!innode || !innode.good()) { device->getLogger()->log(( stringc("ERROR: This node file could not be opened : ") + nodeFileName ).c_str()); buffer->drop(); continue; } // first line data : innode >> nb_of_points >> dim >> nb_of_attr >> boundary_marker; innode.read(reinterpret_cast < char * > (&nb_of_points), sizeof(int)); // we should have at least one tetrahedra (4 points) and each point should have 3 coordinates if (nb_of_points > 65535 || nb_of_points < 4) { device->getLogger()->log("ERROR: a node file should not contain more than 65535 points and less than 4 points."); buffer->drop(); continue; } device->getLogger()->log((stringw("Loading ")+stringw(nb_of_points)+L" points from "+stringw(nodeFileName.c_str())+L"...").c_str()); // default color video::SColor clr(255,100,100,200); // lets add the vertices to the buffer buffer->Vertices.reallocate( nb_of_points ); // this is one line : innode >> index >> x >> y >> z; innode.read(reinterpret_cast < char * > (&x), sizeof(yohan::base::DATA)); innode.read(reinterpret_cast < char * > (&y), sizeof(yohan::base::DATA)); innode.read(reinterpret_cast < char * > (&z), sizeof(yohan::base::DATA)); while (!innode.eof() && innode.good())// && (int)buffer->Vertices.size() < nb_of_points) { buffer->Vertices.push_back(video::S3DVertex((f32)x, (f32)y, (f32)z, 1,0,0, clr, 0,0)); // this is one line : innode >> index >> x >> y >> z; innode.read(reinterpret_cast < char * > (&x), sizeof(yohan::base::DATA)); innode.read(reinterpret_cast < char * > (&y), sizeof(yohan::base::DATA)); innode.read(reinterpret_cast < char * > (&z), sizeof(yohan::base::DATA)); } innode.close(); innode.clear(); // ----------------------------------------------------------------------- // lets check if verticies have been added well if (buffer->Vertices.size() != nb_of_points) { device->getLogger()->log("ERROR: the node file does not seem to be valid."); buffer->drop(); continue; } if (load_volumic) { // ----------------------------------------------------------------------- // - TETRAHEDRAS --------------------------------------------------------- // ----------------------------------------------------------------------- // at first we check if the ele file has not been already opened s32 eleLoadedIndex = -1; for (u32 e=0; e < PlayerFrame::lastEleFileNames.size(); e++) { if (PlayerFrame::lastEleFileNames[e] == eleFileName) { eleLoadedIndex = e; device->getLogger()->log("The ele file is already in memory. We do not need to reload it."); break; } } // if is not in memory, load it from file if (!PlayerFrame::last_was_volumic || eleLoadedIndex == -1 || PlayerFrame::lastBuffers[eleLoadedIndex]->Vertices.size() != buffer->Vertices.size()) { if (eleLoadedIndex != -1) device->getLogger()->log((stringc(PlayerFrame::lastBuffers[eleLoadedIndex]->Vertices.size())+ " This is weird: the ele file which is already in memory don't have the same number of vertices than this one.").c_str()); inele.open(eleFileName.c_str(), ios::in | ios::binary); // opens the ele file if (!inele || !inele.good()) { device->getLogger()->log(( stringc("ERROR: This ele file could not be opened : ") + eleFileName ).c_str()); buffer->drop(); continue; } // first line data : inele >> nb_of_tetrahedra >> dim >> nb_of_attr; inele.read(reinterpret_cast < char * > (&nb_of_tetrahedra), sizeof(int)); device->getLogger()->log((stringw("Loading ")+stringw(nb_of_tetrahedra)+L" tetrahedras from "+stringw(eleFileName.c_str())+L"...").c_str()); // we should have at least one tetrahedra and each tetrahedra should have 4 points if (nb_of_tetrahedra < 1) { buffer->drop(); continue; } // lets add the indices to the buffer buffer->Indices.set_used( (u32)(3 * 4 * nb_of_tetrahedra) ); u32 i = 0; // this is one line : inele >> index >> p1 >> p2 >> p3 >> p4; inele.read(reinterpret_cast < char * > (&p1), sizeof(int)); inele.read(reinterpret_cast < char * > (&p2), sizeof(int)); inele.read(reinterpret_cast < char * > (&p3), sizeof(int)); inele.read(reinterpret_cast < char * > (&p4), sizeof(int)); while (!inele.eof() && inele.good())// && i < 3 * 4 * nb_of_tetrahedra - 12) { // check if we are not out of bounds if (i > (u32)(3 * 4 * nb_of_tetrahedra - 12) || p1 > nb_of_points || p2 > nb_of_points || p3 > nb_of_points || p4 > nb_of_points) { device->getLogger()->log("ERROR: the ele file does not seem to be valid. "); buffer->drop(); error = true; break; } // add 4 polygons per tetrahedra. Not optimized ! s32 ajust_index = 0; buffer->Indices[(u32)(i+0)] = (u32)(p1 + ajust_index); buffer->Indices[(u32)(i+1)] = (u32)(p3 + ajust_index); buffer->Indices[(u32)(i+2)] = (u32)(p2 + ajust_index); core::triangle3df t4( buffer->Vertices[(u32)(p1 + ajust_index)].Pos, buffer->Vertices[(u32)(p3 + ajust_index)].Pos, buffer->Vertices[(u32)(p2 + ajust_index)].Pos); i += 3; buffer->Indices[(u32)(i+0)] = (u32)(p1 + ajust_index); buffer->Indices[(u32)(i+1)] = (u32)(p2 + ajust_index); buffer->Indices[(u32)(i+2)] = (u32)(p4 + ajust_index); core::triangle3df t3( buffer->Vertices[(u32)(p1 + ajust_index)].Pos, buffer->Vertices[(u32)(p2 + ajust_index)].Pos, buffer->Vertices[(u32)(p4 + ajust_index)].Pos); i += 3; buffer->Indices[(u32)(i+0)] = (u32)(p3 + ajust_index); buffer->Indices[(u32)(i+1)] = (u32)(p4 + ajust_index); buffer->Indices[(u32)(i+2)] = (u32)(p2 + ajust_index); core::triangle3df t1( buffer->Vertices[(u32)(p3 + ajust_index)].Pos, buffer->Vertices[(u32)(p4 + ajust_index)].Pos, buffer->Vertices[(u32)(p2 + ajust_index)].Pos); i += 3; buffer->Indices[(u32)(i+0)] = (u32)(p1 + ajust_index); buffer->Indices[(u32)(i+1)] = (u32)(p4 + ajust_index); buffer->Indices[(u32)(i+2)] = (u32)(p3 + ajust_index); core::triangle3df t2( buffer->Vertices[(u32)(p1 + ajust_index)].Pos, buffer->Vertices[(u32)(p4 + ajust_index)].Pos, buffer->Vertices[(u32)(p3 + ajust_index)].Pos); i += 3; buffer->Vertices[(u32)(p1 + ajust_index)].Normal = t1.getNormal(); buffer->Vertices[(u32)(p2 + ajust_index)].Normal = t2.getNormal(); buffer->Vertices[(u32)(p3 + ajust_index)].Normal = t3.getNormal(); buffer->Vertices[(u32)(p4 + ajust_index)].Normal = t4.getNormal(); // this is one line : inele >> index >> p1 >> p2 >> p3 >> p4; inele.read(reinterpret_cast < char * > (&p1), sizeof(int)); inele.read(reinterpret_cast < char * > (&p2), sizeof(int)); inele.read(reinterpret_cast < char * > (&p3), sizeof(int)); inele.read(reinterpret_cast < char * > (&p4), sizeof(int)); } inele.close(); inele.clear(); } else // we do not need to reload from the file ! { buffer->Indices.reallocate(PlayerFrame::lastBuffers[eleLoadedIndex]->Indices.size()); buffer->Indices = PlayerFrame::lastBuffers[eleLoadedIndex]->Indices; for (u32 j=0; j < buffer->Vertices.size(); j++) buffer->Vertices[j].Normal = PlayerFrame::lastBuffers[eleLoadedIndex]->Vertices[j].Normal; } // ----------------------------------------------------------------------- } else // load_volumic == false { // ----------------------------------------------------------------------- // - FACES --------------------------------------------------------------- // ----------------------------------------------------------------------- // at first we check if the ele file has not been already opened s32 faceLoadedIndex = -1; for (u32 e=0; e < PlayerFrame::lastFaceFileNames.size(); e++) { if (PlayerFrame::lastFaceFileNames[e] == faceFileName) { faceLoadedIndex = e; device->getLogger()->log("The face file is already in memory. We do not need to reload it."); break; } } // if is not in memory, load it from file if (PlayerFrame::last_was_volumic || faceLoadedIndex == -1 || PlayerFrame::lastBuffers[faceLoadedIndex]->Vertices.size() != buffer->Vertices.size()) { inface.open(faceFileName.c_str(), ios::in | ios::binary); // opens the face file if (!inface || !inface.good()) { device->getLogger()->log(( stringc("ERROR: This face file could not be opened : ") + faceFileName ).c_str()); buffer->drop(); continue; } // first line data : inface >> nb_of_tetrahedra >> dim >> nb_of_attr; inface.read(reinterpret_cast < char * > (&nb_of_faces), sizeof(int)); device->getLogger()->log((stringw("Loading ")+stringw(nb_of_faces)+L" faces from "+stringw(faceFileName.c_str())+L"...").c_str()); // we should have at least one face if (nb_of_faces < 1) { buffer->drop(); continue; } // lets add the indices to the buffer buffer->Indices.set_used( (u32)(3 * nb_of_faces) ); u32 i = 0; // this is one line : inface >> index >> p1 >> p2 >> p3; inface.read(reinterpret_cast < char * > (&p1), sizeof(int)); inface.read(reinterpret_cast < char * > (&p2), sizeof(int)); inface.read(reinterpret_cast < char * > (&p3), sizeof(int)); while (!inface.eof() && inface.good()) { // check if we are not out of bounds if (i > (u32)(3 * nb_of_faces - 3) || p1 > nb_of_points || p2 > nb_of_points || p3 > nb_of_points) { device->getLogger()->log("ERROR: the face file does not seem to be valid. "); buffer->drop(); error = true; break; } // add 1 polygon per face. s32 ajust_index = -1; buffer->Indices[(u32)(i+0)] = (u32)(p1 + ajust_index); buffer->Indices[(u32)(i+1)] = (u32)(p3 + ajust_index); buffer->Indices[(u32)(i+2)] = (u32)(p2 + ajust_index); core::triangle3df t( buffer->Vertices[(u32)(p1 + ajust_index)].Pos, buffer->Vertices[(u32)(p3 + ajust_index)].Pos, buffer->Vertices[(u32)(p2 + ajust_index)].Pos); i += 3; buffer->Vertices[(u32)(p1 + ajust_index)].Normal = t.getNormal(); buffer->Vertices[(u32)(p2 + ajust_index)].Normal = t.getNormal(); buffer->Vertices[(u32)(p3 + ajust_index)].Normal = t.getNormal(); // this is one line : inface >> index >> p1 >> p2 >> p3; inface.read(reinterpret_cast < char * > (&p1), sizeof(int)); inface.read(reinterpret_cast < char * > (&p2), sizeof(int)); inface.read(reinterpret_cast < char * > (&p3), sizeof(int)); } inface.close(); inface.clear(); } else // we do not need to reload from the file ! { buffer->Indices.reallocate(PlayerFrame::lastBuffers[faceLoadedIndex]->Indices.size()); buffer->Indices = PlayerFrame::lastBuffers[faceLoadedIndex]->Indices; for (u32 j=0; j < buffer->Vertices.size(); j++) buffer->Vertices[j].Normal = PlayerFrame::lastBuffers[faceLoadedIndex]->Vertices[j].Normal; } // ----------------------------------------------------------------------- } if (error) continue; // lets recalculate the bounding box and create the mesh for (u32 j=0; j < buffer->Vertices.size(); ++j) buffer->BoundingBox.addInternalPoint(buffer->Vertices[j].Pos); SMesh* mesh = new SMesh; mesh->addMeshBuffer(buffer); mesh->recalculateBoundingBox(); // here we go, lets create the node that will owns the mesh data node = smgr->addMeshSceneNode( mesh ); mesh->drop(); if (!node) { node = NULL; continue; } node->setVisible(false); //node->setMaterialFlag(video::EMF_WIREFRAME, true); this->nodes.push_back( node ); // updating last _lastEleFileNames.push_back( eleFileName ); _lastFaceFileNames.push_back( faceFileName ); _lastBuffers.push_back( buffer ); } // clean history and update it PlayerFrame::lastEleFileNames = _lastEleFileNames; PlayerFrame::lastFaceFileNames = _lastFaceFileNames; for (u32 e=0; e < lastBuffers.size(); e++) { if (_lastBuffers.binary_search(PlayerFrame::lastBuffers[e]) == -1) { PlayerFrame::lastBuffers[e]->drop(); } } PlayerFrame::lastBuffers = _lastBuffers; PlayerFrame::last_was_volumic = load_volumic; // that's it ! device->getLogger()->log("Loaded."); }
IMeshSceneNode* CustomSceneNodeManager::CreateCapsuleSceneNode(scene::ISceneManager* sceneManager, s32 id, SColor& color, unsigned int resolution, float radius, float heightFromSphereCenters) { if (resolution >= 4) { SMesh* newCapsuleMesh = new SMesh(); SMeshBuffer* buf = new SMeshBuffer(); newCapsuleMesh->addMeshBuffer(buf); buf->MappingHint_Vertex = EHM_STATIC; buf->MappingHint_Index = EHM_STATIC; buf->drop(); int noWarningSignedResolution = resolution; float thetaSkipAmount = 2.0f*PI / (float)resolution; float halfHeight = heightFromSphereCenters / 2.0f; float phiSkipAmount = PI*0.5f / (float)resolution; S3DVertex temp1 = S3DVertex(Vector3(0.0f, halfHeight, 0.0f), Vector3_Zero, color, vector2d<f32>(0.0f, 0.0f)); S3DVertex temp2 = S3DVertex(Vector3(0.0f, -halfHeight, 0.0f), Vector3_Zero, color, vector2d<f32>(0.0f, 1.0f)); float currentTheta = 0.0f; float currentPhi = phiSkipAmount; temp1.Pos.Y = halfHeight + radius; buf->Vertices.push_back(temp1); //Semi-sphere Tips for(unsigned int i = 1; i < resolution; i++) { for(unsigned int j = 0; j < resolution; j++) { float x = sinf(currentPhi) * cosf(currentTheta) * radius; float y = cosf(currentPhi) * radius; float z = sinf(currentPhi) * sinf(currentTheta) * radius; temp1.Pos.X = x; temp1.Pos.Y = y + halfHeight; temp1.Pos.Z = z; temp1.TCoords.X = currentTheta / 2.0f*PI; temp1.TCoords.Y = currentPhi / PI; buf->Vertices.push_back(temp1); currentTheta += thetaSkipAmount; } currentTheta = 0.0f; currentPhi += phiSkipAmount; } currentTheta = 0.0f; currentPhi = PI/2.0f; //Semi-sphere Tips for(unsigned int i = 1; i < resolution; i++) { for(unsigned int j = 0; j < resolution; j++) { float x = sinf(currentPhi) * cosf(currentTheta) * radius; float y = cosf(currentPhi) * radius; float z = sinf(currentPhi) * sinf(currentTheta) * radius; temp1.Pos.X = x; temp1.Pos.Y = y - halfHeight; temp1.Pos.Z = z; temp1.TCoords.X = currentTheta / 2.0f*PI; temp1.TCoords.Y = currentPhi / PI; buf->Vertices.push_back(temp1); currentTheta += thetaSkipAmount; } currentTheta = 0.0f; currentPhi += phiSkipAmount; } temp1.Pos.X = 0.0f; temp1.Pos.Y = -(halfHeight + radius); temp1.Pos.Z = 0.0f; buf->Vertices.push_back(temp1); //Top vertex indices for(unsigned int i = 1; i <= resolution; i++) { if (i == resolution) { buf->Indices.push_back(i); buf->Indices.push_back(0); buf->Indices.push_back(1); } else { buf->Indices.push_back(i); buf->Indices.push_back(0); buf->Indices.push_back(i + 1); } } //Get indices int i = 1 + resolution; while(i < buf->Vertices.size() - 1) { for(unsigned int j = 1; j < resolution; j++) { buf->Indices.push_back(i); buf->Indices.push_back(i - noWarningSignedResolution); buf->Indices.push_back(i - noWarningSignedResolution + 1); buf->Indices.push_back(i); buf->Indices.push_back(i - noWarningSignedResolution + 1); buf->Indices.push_back(i + 1); i++; } buf->Indices.push_back(i); buf->Indices.push_back(i - noWarningSignedResolution); buf->Indices.push_back(i - noWarningSignedResolution + 1 - resolution); buf->Indices.push_back(i); buf->Indices.push_back(i - noWarningSignedResolution + 1 - resolution); buf->Indices.push_back(i + 1 - resolution); i++; } //Bottom vertex indices for(int i = resolution; i >= 1 ; i--) { if (i == 1) { /*buf->Indices.push_back(i); buf->Indices.push_back(0); buf->Indices.push_back(1);*/ buf->Indices.push_back(buf->Vertices.size() -1); buf->Indices.push_back(buf->Vertices.size() -1 - i); buf->Indices.push_back(buf->Vertices.size() - 1 - resolution); } else { buf->Indices.push_back(buf->Vertices.size() -1); buf->Indices.push_back(buf->Vertices.size() -1 - i); buf->Indices.push_back(buf->Vertices.size() - i); } } //Calculate normals CalculateNormals(buf->Vertices, buf->Indices); buf->recalculateBoundingBox(); newCapsuleMesh->recalculateBoundingBox(); IMeshSceneNode* node = sceneManager->addMeshSceneNode(newCapsuleMesh); newCapsuleMesh->drop(); return node; } return NULL; }
IMeshSceneNode* CustomSceneNodeManager::CreateCylinderSceneNode(scene::ISceneManager* sceneManager, s32 id, SColor& color, unsigned int resolution, float radius, float height) { /*if (!cylinderMesh) {*/ if (resolution >= 4) { SMesh* newCylinderMesh = new SMesh(); SMeshBuffer* buf = new SMeshBuffer(); newCylinderMesh->addMeshBuffer(buf); buf->MappingHint_Vertex = EHM_STATIC; buf->MappingHint_Index = EHM_STATIC; buf->drop(); int noWarningSignedResolution = resolution; float currentTheta = 0.0f; float skipAmount = 2.0f*PI / (float)resolution; float halfHeight = height / 2.0f; S3DVertex temp1 = S3DVertex(Vector3(0.0f, halfHeight, 0.0f), Vector3_Zero, color, vector2d<f32>(0.0f, 0.0f)); S3DVertex temp2 = S3DVertex(Vector3(0.0f, -halfHeight, 0.0f), Vector3_Zero, color, vector2d<f32>(0.0f, 1.0f)); for(int i = 0; i < noWarningSignedResolution; i++) { float x = cosf(currentTheta) * radius; float z = sinf(currentTheta) * radius; temp1.Pos.X = x; temp1.Pos.Z = z; temp1.TCoords.X = currentTheta / 2.0f*PI; temp2.Pos.X = x; temp2.Pos.Z = z; temp2.TCoords.X = currentTheta / 2.0f*PI; buf->Vertices.push_back(temp1); buf->Vertices.push_back(temp2); currentTheta += skipAmount; } temp1.Pos.X = 0.0f; temp1.Pos.Z = 0.0f; temp1.TCoords.X = 0.0f; temp2.Pos.X = 0.0f; temp2.Pos.Z = 0.0f; temp1.TCoords.X = 0.0f; buf->Vertices.push_back(temp1); buf->Vertices.push_back(temp2); //Get indices for(int i = 0; i < noWarningSignedResolution - 1; i++) { buf->Indices.push_back(i*2); buf->Indices.push_back(i*2+2); buf->Indices.push_back(i*2+1); buf->Indices.push_back(i*2+1); buf->Indices.push_back(i*2+2); buf->Indices.push_back(i*2+3); buf->Indices.push_back(i*2); buf->Indices.push_back(buf->Vertices.size()-2); buf->Indices.push_back(i*2+2); buf->Indices.push_back(i*2+1); buf->Indices.push_back(i*2+3); buf->Indices.push_back(buf->Vertices.size()-1); } buf->Indices.push_back(buf->Vertices.size()-4); buf->Indices.push_back(0); buf->Indices.push_back(buf->Vertices.size()-3); buf->Indices.push_back(buf->Vertices.size()-3); buf->Indices.push_back(0); buf->Indices.push_back(1); buf->Indices.push_back(buf->Vertices.size()-4); buf->Indices.push_back(buf->Vertices.size()-2); buf->Indices.push_back(0); buf->Indices.push_back(buf->Vertices.size()-3); buf->Indices.push_back(1); buf->Indices.push_back(buf->Vertices.size()-1); //Calculate normals CalculateNormals(buf->Vertices, buf->Indices); buf->recalculateBoundingBox(); newCylinderMesh->recalculateBoundingBox(); IMeshSceneNode* node = sceneManager->addMeshSceneNode(newCylinderMesh); newCylinderMesh->drop(); return node; } /* return NULL; } else { IMeshSceneNode* node = sceneManager->addMeshSceneNode(cylinderMesh); node->setScale(Vector3(radius, height, radius)); return node; }*/ return NULL; }
void drawFrame() { u32 i,color = 0; Matrix4 rotX,rotY; Vector4 objEyePos,objLightPos; Matrix4 viewMatrix,modelMatrix,modelMatrixIT,modelViewMatrix; Point3 lightPos = Point3(250.0f,150.0f,150.0f); f32 globalAmbientColor[3] = {0.1f,0.1f,0.1f}; f32 lightColor[3] = {0.95f,0.95f,0.95f}; f32 materialColorDiffuse[3] = {0.5f,0.0f,0.0f}; f32 materialColorSpecular[3] = {0.7f,0.6f,0.6f}; f32 shininess = 17.8954f; static f32 rot = 0.0f; SMeshBuffer *mesh = NULL; setTexture(); setDrawEnv(); rsxSetClearColor(context,color); rsxSetClearDepthValue(context,0xffff); rsxClearSurface(context,GCM_CLEAR_R | GCM_CLEAR_G | GCM_CLEAR_B | GCM_CLEAR_A | GCM_CLEAR_S | GCM_CLEAR_Z); rsxZControl(context,0,1,1); for(i=0; i<8; i++) rsxSetViewportClip(context,i,display_width,display_height); viewMatrix = Matrix4::lookAt(eye_pos,eye_dir,up_vec); mesh = sphere; rotX = Matrix4::rotationX(DEGTORAD(30.0f)); rotY = Matrix4::rotationY(DEGTORAD(rot)); modelMatrix = rotX*rotY; modelMatrixIT = inverse(modelMatrix); modelViewMatrix = transpose(viewMatrix*modelMatrix); objEyePos = modelMatrixIT*eye_pos; objLightPos = modelMatrixIT*lightPos; wait_signal_spu(); rsxBindVertexArrayAttrib(context,vertexPosition_id,mesh->pos_off,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); rsxBindVertexArrayAttrib(context,vertexNormal_id,mesh->nrm_off,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); rsxBindVertexArrayAttrib(context,vertexTexcoord_id,mesh->uv_off,sizeof(S3DVertex),2,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); rsxLoadVertexProgram(context,vpo,vp_ucode); rsxSetVertexProgramParameter(context,vpo,projMatrix_id,(float*)&P); rsxSetVertexProgramParameter(context,vpo,modelViewMatrix_id,(float*)&modelViewMatrix); rsxSetFragmentProgramParameter(context,fpo,eyePosition_id,(float*)&objEyePos,fp_offset); rsxSetFragmentProgramParameter(context,fpo,globalAmbient_id,globalAmbientColor,fp_offset); rsxSetFragmentProgramParameter(context,fpo,lightPosition_id,(float*)&objLightPos,fp_offset); //rsxSetFragmentProgramParameter(context,fpo,lightColor_id,lightColor,fp_offset); rsxSetFragmentProgramParameter(context,fpo,shininess_id,&shininess,fp_offset); rsxSetFragmentProgramParameter(context,fpo,Kd_id,materialColorDiffuse,fp_offset); rsxSetFragmentProgramParameter(context,fpo,Ks_id,materialColorSpecular,fp_offset); rsxLoadFragmentProgramLocation(context,fpo,fp_offset,GCM_LOCATION_RSX); rsxSetUserClipPlaneControl(context,GCM_USER_CLIP_PLANE_DISABLE, GCM_USER_CLIP_PLANE_DISABLE, GCM_USER_CLIP_PLANE_DISABLE, GCM_USER_CLIP_PLANE_DISABLE, GCM_USER_CLIP_PLANE_DISABLE, GCM_USER_CLIP_PLANE_DISABLE); rsxDrawIndexArray(context,GCM_TYPE_TRIANGLES,mesh->ind_off,mesh->getIndexCount(),GCM_INDEX_TYPE_32B,GCM_LOCATION_RSX); mesh = donut; rotX = Matrix4::rotationX(DEGTORAD(rot)); rotY = Matrix4::rotationY(DEGTORAD(30.0f)); modelMatrix = rotX*rotY; modelMatrix.setTranslation(Vector3(3.0f,5.0f,-8.0f)); modelMatrixIT = inverse(modelMatrix); modelViewMatrix = transpose(viewMatrix*modelMatrix); objEyePos = modelMatrixIT*eye_pos; objLightPos = modelMatrixIT*lightPos; rsxBindVertexArrayAttrib(context,vertexPosition_id,mesh->pos_off,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); rsxBindVertexArrayAttrib(context,vertexNormal_id,mesh->nrm_off,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); rsxBindVertexArrayAttrib(context,vertexTexcoord_id,mesh->uv_off,sizeof(S3DVertex),2,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); rsxLoadVertexProgram(context,vpo,vp_ucode); rsxSetVertexProgramParameter(context,vpo,projMatrix_id,(float*)&P); rsxSetVertexProgramParameter(context,vpo,modelViewMatrix_id,(float*)&modelViewMatrix); rsxSetFragmentProgramParameter(context,fpo,eyePosition_id,(float*)&objEyePos,fp_offset); rsxSetFragmentProgramParameter(context,fpo,globalAmbient_id,globalAmbientColor,fp_offset); rsxSetFragmentProgramParameter(context,fpo,lightPosition_id,(float*)&objLightPos,fp_offset); rsxSetFragmentProgramParameter(context,fpo,lightColor_id,lightColor,fp_offset); rsxSetFragmentProgramParameter(context,fpo,shininess_id,&shininess,fp_offset); rsxSetFragmentProgramParameter(context,fpo,Kd_id,materialColorDiffuse,fp_offset); rsxSetFragmentProgramParameter(context,fpo,Ks_id,materialColorSpecular,fp_offset); rsxLoadFragmentProgramLocation(context,fpo,fp_offset,GCM_LOCATION_RSX); rsxSetUserClipPlaneControl(context,GCM_USER_CLIP_PLANE_DISABLE, GCM_USER_CLIP_PLANE_DISABLE, GCM_USER_CLIP_PLANE_DISABLE, GCM_USER_CLIP_PLANE_DISABLE, GCM_USER_CLIP_PLANE_DISABLE, GCM_USER_CLIP_PLANE_DISABLE); rsxDrawIndexArray(context,GCM_TYPE_TRIANGLES,mesh->ind_off,mesh->getIndexCount(),GCM_INDEX_TYPE_32B,GCM_LOCATION_RSX); clear_signal_spu(); signal_spu_rsx(); rot += 4.0f; if(rot>=360.0f) rot = 0.0f; }
//! creates/loads an animated mesh from the file. //! \return Pointer to the created mesh. Returns 0 if loading failed. //! If you no longer need the mesh, you should call IAnimatedMesh::drop(). //! See IReferenceCounted::drop() for more information. IAnimatedMesh* CSTLMeshFileLoader::createMesh(io::IReadFile* file) { const long filesize = file->getSize(); if (filesize < 6) // we need a header return 0; const u32 WORD_BUFFER_LENGTH = 512; SMesh* mesh = new SMesh(); SMeshBuffer* meshBuffer = new SMeshBuffer(); mesh->addMeshBuffer(meshBuffer); meshBuffer->drop(); core::vector3df vertex[3]; core::vector3df normal; c8 buffer[WORD_BUFFER_LENGTH]; bool binary = false; file->read(buffer, 5); if (strncmp("solid", buffer, 5)) binary = true; // read/skip header u32 binFaceCount = 0; if (binary) { file->seek(80); file->read(&binFaceCount, 4); #ifdef __BIG_ENDIAN__ binFaceCount = os::Byteswap::byteswap(binFaceCount); #endif } else goNextLine(file); u16 attrib=0; core::stringc token; token.reserve(32); while (file->getPos() < filesize) { if (!binary) { if (getNextToken(file, token) != "facet") { if (token=="endsolid") break; mesh->drop(); return 0; } if (getNextToken(file, token) != "normal") { mesh->drop(); return 0; } } getNextVector(file, normal, binary); if (!binary) { if (getNextToken(file, token) != "outer") { mesh->drop(); return 0; } if (getNextToken(file, token) != "loop") { mesh->drop(); return 0; } } for (u32 i=0; i<3; ++i) { if (!binary) { if (getNextToken(file, token) != "vertex") { mesh->drop(); return 0; } } getNextVector(file, vertex[i], binary); } if (!binary) { if (getNextToken(file, token) != "endloop") { mesh->drop(); return 0; } if (getNextToken(file, token) != "endfacet") { mesh->drop(); return 0; } } else { file->read(&attrib, 2); #ifdef __BIG_ENDIAN__ attrib = os::Byteswap::byteswap(attrib); #endif } SMeshBuffer* mb = reinterpret_cast<SMeshBuffer*>(mesh->getMeshBuffer(mesh->getMeshBufferCount()-1)); u32 vCount = mb->getVertexCount(); video::SColor color(0xffffffff); if (attrib & 0x8000) color = video::A1R5G5B5toA8R8G8B8(attrib); if (normal==core::vector3df()) normal=core::plane3df(vertex[2],vertex[1],vertex[0]).Normal; mb->Vertices.push_back(video::S3DVertex(vertex[2],normal,color, core::vector2df())); mb->Vertices.push_back(video::S3DVertex(vertex[1],normal,color, core::vector2df())); mb->Vertices.push_back(video::S3DVertex(vertex[0],normal,color, core::vector2df())); mb->Indices.push_back(vCount); mb->Indices.push_back(vCount+1); mb->Indices.push_back(vCount+2); } // end while (file->getPos() < filesize) mesh->getMeshBuffer(0)->recalculateBoundingBox(); // Create the Animated mesh if there's anything in the mesh SAnimatedMesh* pAM = 0; if ( 0 != mesh->getMeshBufferCount() ) { mesh->recalculateBoundingBox(); pAM = new SAnimatedMesh(); pAM->Type = EAMT_OBJ; pAM->addMesh(mesh); pAM->recalculateBoundingBox(); } mesh->drop(); return pAM; }
irr::scene::IMesh* MeshTools::createHillMesh(SurfaceQuadTree& tree, rectf section, double min_height, double max_height) { std::vector<PsblVertPtr> triangles; /* tree.split(1); auto ptr = tree.child[1]; for (int i=0; i<2; ++i) { ptr->split(1); ptr = ptr->child[3*(i+1)%4]; } ptr = tree.child[2]; for (int i=0; i<5; ++i) { ptr->split(1); ptr = ptr->child[3*(i+1)%4]; } */ struct Visitor : public SurfaceQuadTree::Visitor { vector<pair<QuadTreePtr, QuadTreePtr>> pairs; typedef tuple<QuadTreePtr, QuadTreePtr> edge; typedef vector<edge> triangle; vector<triangle> triangles; typedef vector<triangle>::const_iterator triangle_iter; std::map<edge, vector<triangle>> edge_to_triangle; bool crosses(edge e1, edge e2) { // Ignore if the edges share a vertex; that is not a crossing. if ( get<0>(e1)->vert == get<0>(e2)->vert || get<0>(e1)->vert == get<1>(e2)->vert || get<1>(e1)->vert == get<0>(e2)->vert || get<1>(e1)->vert == get<1>(e2)->vert ) return false; // line2d(T xa, T ya, T xb, T yb) vector3df pos1a = get<0>(e1)->vert->getPos(); vector3df pos1b = get<1>(e1)->vert->getPos(); line2df line1(pos1a.X, pos1a.Y, pos1b.X, pos1b.Y); vector3df pos2a = get<0>(e2)->vert->getPos(); vector3df pos2b = get<1>(e2)->vert->getPos(); line2df line2(pos2a.X, pos2a.Y, pos2b.X, pos2b.Y); vector2df out; return line1.intersectWith(line2, out); } bool compareEdge(edge e, std::string from, std::string to) { return get<0>(e)->getPath() == from && get<1>(e)->getPath() == to; } bool findEdge(triangle t, std::string from, std::string to) { return compareEdge(t[0], from, to) || compareEdge(t[1], from, to) || compareEdge(t[2], from, to); } virtual void addTriangle(QuadTreePtr a, QuadTreePtr b, QuadTreePtr c) { // If a,b,c already in triangles, duplicate triangle error. // foreach edge in the new triangle, // find other triangles that share one edge with this one // test the other 2x2 edges for intersection. triangle new_triangle( { make_tuple(a,b), make_tuple(b,c), make_tuple(c,a) }); //if (findEdge(new_triangle, "Root SW SW SW NW SE", "Root SW SW SW NW NW")) // cout << "found" << endl; //if (findEdge(new_triangle, "Root SW SW SW NW NE", "Root SW SW SW NW SW")) // cout << "found" << endl; for (edge e_same : new_triangle) for (edge e_check : new_triangle) if (e_same != e_check) for (triangle contiguous : edge_to_triangle[e_same]) for (edge e_existing : contiguous) if (e_existing != e_same) if (crosses(e_check, e_existing)) { cout << "detected crossing, new is " << get<0>(e_check)->getPath() << "-" << get<1>(e_check)->getPath() << " old is " << get<0>(e_existing)->getPath() << "-" << get<1>(e_existing)->getPath() << endl; } triangles.push_back(new_triangle); edge_to_triangle[make_tuple(a,b)].push_back(new_triangle); edge_to_triangle[make_tuple(b,c)].push_back(new_triangle); edge_to_triangle[make_tuple(c,a)].push_back(new_triangle); edge_to_triangle[make_tuple(b,a)].push_back(new_triangle); edge_to_triangle[make_tuple(c,b)].push_back(new_triangle); edge_to_triangle[make_tuple(a,c)].push_back(new_triangle); } virtual void check(QuadTreePtr a1, QuadTreePtr a2, QuadTreePtr b1, QuadTreePtr b2) { } }; Visitor visitor; tree.triangulate(triangles, section, min_height, max_height, &visitor); //tree.sweep(triangles, section, &visitor); //cout << "num triangle points: " << triangles.size() << endl; vector<QuadTreePtr> leaves; tree.dumpLeaves(leaves); //cout << "num leaves: " << leaves.size() << endl; /* for (QuadTreePtr p1 : leaves) for (QuadTreePtr p2 : leaves) if (p1 != p2) if (p1->isAdjacent(p2)) if (!visitor.has(p1, p2)) { auto sz1 = p1->region.getSize(); auto sz2 = p2->region.getSize(); auto c1 = p1->region.getCenter(); auto c2 = p2->region.getCenter(); char const* path1 = p1->getPath().c_str(); char const* path2 = p2->getPath().c_str(); cout << path1 << endl; cout << path2 << endl; cout << "Missing pair of adjacent vertices." << endl; } float x1 = section.UpperLeftCorner.X; float x2 = section.LowerRightCorner.X; float y1 = section.UpperLeftCorner.Y; float y2 = section.LowerRightCorner.Y; */ /* d---c | / | a---b */ /* S3DVertex sa; sa.Pos = vector3df(x1, y1, 0); PsblVertPtr a = new PossibleVertex(sa); S3DVertex sb; sb.Pos = vector3df(x2, y1, 0); PsblVertPtr b = new PossibleVertex(sb); S3DVertex sc; sc.Pos = vector3df(x2, y2, 0); PsblVertPtr c = new PossibleVertex(sc); S3DVertex sd; sd.Pos = vector3df(x1, y2, 0); PsblVertPtr d = new PossibleVertex(sd); // a-b-c // a-c-d triangles.push_back(a); triangles.push_back(b); triangles.push_back(c); triangles.push_back(a); triangles.push_back(c); triangles.push_back(d); triangles.push_back(c); triangles.push_back(b); triangles.push_back(a); triangles.push_back(d); triangles.push_back(c); triangles.push_back(a); */ SMeshBuffer* buffer = new SMeshBuffer(); for (auto pv : triangles) pv->addToMeshBuf(buffer, vector3df()); if (buffer->getIndexCount() % 3 > 0) throw std::logic_error("SurfaceQuadTree triangulation added a 'triangle' with less than 3 vertices in it."); //cout << "num vertices " << buffer->getVertexCount() << endl; //cout << "num indices " << buffer->getIndexCount() << endl; buffer->recalculateBoundingBox(); buffer->setHardwareMappingHint(EHM_STATIC); SMesh* mesh = new SMesh(); mesh->addMeshBuffer(buffer); mesh->recalculateBoundingBox(); buffer->drop(); return mesh; }
IMesh* MeshTools::createMeshFromHeightmap(IImage* image, dimension2du tileSizeInPixels, vector2di tilePosInTiles, bool extraStripsOnEdges) { // Use top corner of image to get bias for centering the Z axis. float imageZeroBias = image->getPixel(0,0).getAverage(); dimension2du imageDimension = image->getDimension(); // Easier to think of script working in whole tile units, so handle conversion to pixel pos in this method: vector2di startAtPixel = tilePosInTiles * vector2di(tileSizeInPixels.Width, tileSizeInPixels.Height); // However we're going to invert the image Y axis so that the bottom of the picture will be at 0,0 in world space, // and the top of the picture will be at +Y in world space. startAtPixel.Y = (imageDimension.Height-1) - startAtPixel.Y; // Return nothing if the tile is outside the image, or if the resulting mesh would have only 0 or 1 rows or columns. // Doing this check early prevents getting underflow when we clip the tile size to the image dimensions a few statements down. if (startAtPixel.X < 0 || startAtPixel.X >= (imageDimension.Width-1) || startAtPixel.Y <= 0 || startAtPixel.Y > (imageDimension.Height-1)) return NULL; // Calculate whether to use tile size or tile size + 1 (for generating overlap) // Adding the extra strip amount before clipping to image dimensions prevents overflowing the image edges after clipping. dimension2du useTileSize = tileSizeInPixels + (extraStripsOnEdges? dimension2du(1,1) : dimension2du(0,0)); // Clip the tile size if we're dealing with a "leftover" amount at the edge that's not a whole tile's width or height. // Most heightmap implementations require exactly a power of 2 + 1 square dimensions like 257x257, but supporting // image sizes that are not whole multiples of tile size is as simple as this one line of code and supporting // image sizes that are not square is a nice feature for a platformer game so you can have levels that are longer // than they are tall. useTileSize.set(min(useTileSize.Width, imageDimension.Width-startAtPixel.X), min(useTileSize.Height, (u32)startAtPixel.Y+1)); SMeshBuffer* buffer = new SMeshBuffer(); // Preallocate vertex buffer to the size we know we'll need. buffer->Vertices.set_used(useTileSize.Width*useTileSize.Height); // Amount of TCoord per unit of x,y in image. vector2df tCoordsScale(1.0f / useTileSize.Width, 1.0f / useTileSize.Height); // Whether we put y on the outside or x on the outside, doesn't matter, because we are // using getIndex() to find where x and y map too. However, I happen to know I made getIndex // put x's together, y in rows, and looping in the same rank order might have better cache performance // because it should access the vertices in the same order they are in the array. for (u32 y=0; y < useTileSize.Height; ++y) { for (u32 x=0; x < useTileSize.Width; ++x) { u32 index = getIndex(useTileSize, x, y); S3DVertex& vert = buffer->Vertices[index]; // No special coloration vert.Color = SColor(255,255,255,255); // Scale texture to tile. vert.TCoords = vector2df(x,y) * tCoordsScale; // y axis starts with 0 at image bottom and goes up. vector2di pixelPos( startAtPixel.X+x, startAtPixel.Y-y ); SColor heightColor = image->getPixel(pixelPos.X, pixelPos.Y); float thisHeight = imageZeroBias - heightColor.getAverage(); vert.Pos.set(x, y, thisHeight); // I'm only averaging normals along the 4 compass directions. It's // arguable whether diagonals should count; I chose to ignore diagonals. // Ignoring diagonals allows me to assume the "run" in rise/run is always // just one unit; if you add diagonals here you'll also need to change // the slope calculation to use the actual distance instead of assuming 1. vector2di offsetsArray[] = { vector2di( 1, 0), // 3 o'clock vector2di( 0, 1), // 12 o'clock vector2di(-1, 0), // 9 o'clock vector2di( 0,-1) // 6 o'clock }; // Calculate the normals of the surrounding slopes. // Uses the image, not just the tile patch size, so it will // calculate correct normals for vertices on tile edges. for (size_t i=-0; i < 4; ++i) { vector2di offset = vector2di(x,y) + offsetsArray[i]; // Skip this offset if it's outside the image if (offset.X < 0 || offset.Y < 0 || offset.X >= (s32)imageDimension.Width || offset.Y >= (s32)imageDimension.Height) continue; vector2di otherPixelPos( startAtPixel.X+x+offset.X, startAtPixel.Y-y-offset.Y ); float otherHeight = 255 - image->getPixel((u32)otherPixelPos.X, (u32)otherPixelPos.Y).getAverage(); // The code Irrlicht's in terrain scene node does all kinds of complicated // business with cross products and such - waaay over complicated. You don't need // all that stuff. Dude it' s a heightmap: all you need to worray about is // rise over run on unit intervals! Algebra 1 type stuff, y = mx + c // Calculate the rise of the line over the run, taking into account the fact // that the offset could be in either direction. float rise = (offset.X < 0 || offset.Y < 0)? thisHeight - otherHeight : otherHeight - thisHeight; // Assuming that run = 1, m = rise / run is just m = rise. float m = rise; // The the slope of the normal is just the negative of the reciprocal of the line slope. float n = -1.0f / rise; // The X,Y of the normal vector is just going to be the X and Y of the offset // (think about it - obviously the normal of the slope must tilt in the direction of the run) // and the Z of the normal vector is just the slope of the normal over that run. vector3df normVect(offset.X, offset.Y, n); //vert.Normal += normVect; } //vert.Normal.normalize(); vert.Normal.set(0,0,-1.0f); } } // Pre-allocate index data to 2*3*Width*Height for triangles. // There is actually 1 less square per count of vertices though, // for instance if you had 2x2 vertices, you only have 1 square. buffer->Indices.set_used(2*3*(useTileSize.Width-1)*(useTileSize.Height-1)); // Start with 1 and generate all the triangles from their top right corners. // Like this (A is top right corner at x,y): // // y=1 B---A // | / | // y=0 C---D // x=0 x=1 for (u32 dst=0, x=1; x < useTileSize.Width; ++x) { for (u32 y=1; y < useTileSize.Height; ++y) { u32 A = getIndex(useTileSize, x, y ); u32 B = getIndex(useTileSize, x-1, y ); u32 C = getIndex(useTileSize, x-1, y-1 ); u32 D = getIndex(useTileSize, x, y-1 ); buffer->Indices[dst++] = C; buffer->Indices[dst++] = B; buffer->Indices[dst++] = A; buffer->Indices[dst++] = D; buffer->Indices[dst++] = C; buffer->Indices[dst++] = A; } } buffer->recalculateBoundingBox(); buffer->setHardwareMappingHint(EHM_STATIC); SMesh* mesh = new SMesh(); mesh->addMeshBuffer(buffer); mesh->recalculateBoundingBox(); buffer->drop(); return mesh; }
// creates a hill plane IAnimatedMesh* CGeometryCreator::createHillPlaneMesh(const core::dimension2d<f32>& tileSize, const core::dimension2d<s32>& tc, video::SMaterial* material, f32 hillHeight, const core::dimension2d<f32>& ch, const core::dimension2d<f32>& textureRepeatCount) { core::dimension2d<s32> tileCount = tc; tileCount.Height += 1; tileCount.Width += 1; core::dimension2d<f32> countHills = ch; SMeshBuffer* buffer = new SMeshBuffer(); SMesh* mesh = new SMesh(); video::S3DVertex vtx; vtx.Color.set(255,255,255,255); vtx.Normal.set(0,0,0); if (countHills.Width < 0.01f) countHills.Width = 1; if (countHills.Height < 0.01f) countHills.Height = 1; f32 halfX = (tileSize.Width * tileCount.Width) / 2; f32 halfY = (tileSize.Height * tileCount.Height) / 2; // create vertices s32 x = 0; s32 y = 0; core::dimension2d<f32> tx; tx.Width = 1.0f / (tileCount.Width / textureRepeatCount.Width); tx.Height = 1.0f / (tileCount.Height / textureRepeatCount.Height); for (x=0; x<tileCount.Width; ++x) for (y=0; y<tileCount.Height; ++y) { vtx.Pos.set(tileSize.Width * x - halfX, 0, tileSize.Height * y - halfY); vtx.TCoords.set(-(f32)x * tx.Width, (f32)y * tx.Height); if (hillHeight) vtx.Pos.Y = (f32)(sin(vtx.Pos.X * countHills.Width * engine::core::PI / halfX) * cos(vtx.Pos.Z * countHills.Height * engine::core::PI / halfY)) *hillHeight; buffer->Vertices.push_back(vtx); } // create indices for (x=0; x<tileCount.Width-1; ++x) for (y=0; y<tileCount.Height-1; ++y) { s32 current = y*tileCount.Width + x; buffer->Indices.push_back(current); buffer->Indices.push_back(current + 1); buffer->Indices.push_back(current + tileCount.Width); buffer->Indices.push_back(current + 1); buffer->Indices.push_back(current + 1 + tileCount.Width); buffer->Indices.push_back(current + tileCount.Width); } // recalculate normals for (s32 i=0; i<(s32)buffer->Indices.size(); i+=3) { core::plane3d<f32> p( buffer->Vertices[buffer->Indices[i+0]].Pos, buffer->Vertices[buffer->Indices[i+1]].Pos, buffer->Vertices[buffer->Indices[i+2]].Pos); p.Normal.normalize(); buffer->Vertices[buffer->Indices[i+0]].Normal = p.Normal; buffer->Vertices[buffer->Indices[i+1]].Normal = p.Normal; buffer->Vertices[buffer->Indices[i+2]].Normal = p.Normal; } if (material) buffer->Material = *material; buffer->recalculateBoundingBox(); SAnimatedMesh* animatedMesh = new SAnimatedMesh(); mesh->addMeshBuffer(buffer); mesh->recalculateBoundingBox(); animatedMesh->addMesh(mesh); animatedMesh->recalculateBoundingBox(); mesh->drop(); buffer->drop(); return animatedMesh; }
MeshTools::SplitMeshResult MeshTools::splitMeshZ(IMesh* oldMesh, float zCut, float zInsert, bool marginalTrisInLeft, bool marginalTrisInRight) { IMeshBuffer* oldMeshBuf = oldMesh->getMeshBuffer(0); u16* oldInd = oldMeshBuf->getIndices(); SMeshBuffer* leftMeshBuf = new SMeshBuffer(); SMeshBuffer* rightMeshBuf = new SMeshBuffer(); LinkSplitter linkSplitter(oldMeshBuf, zCut); vector3df const offset(0,0, zInsert); set<pair<PsblVertPtr, PsblVertPtr>> leftEdgeLinks; set<pair<PsblVertPtr, PsblVertPtr>> rightEdgeLinks; for (u32 i=0; i < oldMeshBuf->getIndexCount(); i += 3) { // Calling these shapes instead of triangles because they could be triangle or a quad after slice, // (it could also be a degenerate case of a line or a point - those will be discarded by addConvexShape) vector<PsblVertPtr> leftShape; vector<PsblVertPtr> rightShape; int a = oldInd[i]; int b = oldInd[i+1]; int c = oldInd[i+2]; PsblVertPtr mid1; PsblVertPtr mid2; PsblVertPtr mid3; // Don't create a copy just for a triangle that is just kissing the edge. Leave it in the background. if (linkSplitter.compareZ(a)==0 && linkSplitter.compareZ(b)==0 && linkSplitter.compareZ(c)==0) { if (marginalTrisInLeft) { leftShape.push_back(linkSplitter.getVert(a)); leftShape.push_back(linkSplitter.getVert(b)); leftShape.push_back(linkSplitter.getVert(c)); } if (marginalTrisInRight) { rightShape.push_back(linkSplitter.getVert(a)); rightShape.push_back(linkSplitter.getVert(b)); rightShape.push_back(linkSplitter.getVert(c)); } } else { // This is something I had to think hard about so I'm writing this comment so I don't // have to think it through again or forget it: // // Both the left shape and the right shape, and both the triangle and the quad, "magically" // come out with correct winding order when the triangle is split. Here's why: // Let the original triangle vertices be A-B-C. // Let the split midpoints be AB' and CA' as A-B is split and C-A are split respectively. // The shapes (ignore which shape is left or right, call them P and Q instead) // will be filled in the following order: // // round P Q Comment // 1 A - A is not in Q at all // 1 cont. AB' AB' AB' replaces B in P // 2 - B B proper is in Q and not in P // 2 cont. - - Link B-C is not split // 3 - C C proper is in Q and not in P // 3 cont. CA' CA' CA' replaces C in P // // Now, read the columns P and Q vertically top to bottom to see the resultant vertex order. // The triangle P is trivially still the correct winding order; it is just a smaller triangle now. // The new quad Q retains the old triangle's winding order property for the following reason: // As you wrapped around a full circle in old triangle A-B-C you would have traversed C-A then A-B. // The link C-A has been cut and vertex CA' inserted. // The link A-B has been cut and vertex AB' inserted. // If you traverse the new shape starting from the _middle_ you follow the following path: // B-C C-CA' CA'-AB' AB'-B B-C (again) // Compare to old triangle: // B-C C-A A-B B-C (again) // Even though vertex A has been cut off and replaced with two vertices, the two // new vertices lie along the path that the old links took and are in the new shape in the right order. mid1 = linkSplitter.processLink(leftShape, rightShape, a, b); mid2 = linkSplitter.processLink(leftShape, rightShape, b, c); mid3 = linkSplitter.processLink(leftShape, rightShape, c, a); } // If a triangle was split then two of those three midpoints are inhabited by a vertex. // We want to get them both in mid1 and mid2 AND we need them in correct order. PsblVertPtr cut1 = (mid1 && mid2)? mid1 : mid2; PsblVertPtr cut2 = (mid2 && mid3)? mid3 : mid2; if (cut1 && cut2) { vector<PsblVertPtr> chain = linkSplitter.chopLink(cut1, cut2, 1); linkSplitter.insertPoints(leftShape, cut1, cut2, chain); linkSplitter.insertPoints(rightShape, cut1, cut2, chain); } linkSplitter.addConvexShape(leftShape, leftMeshBuf, -offset/2); linkSplitter.addConvexShape(rightShape, rightMeshBuf, offset/2); // Add any edges of the left shape that lie along the border. linkSplitter.addEdgeLinks(leftShape, leftEdgeLinks); // Right side polys that share a border with left side ones will have // opposite winding order. In order for set_intersection to consider them // as matches, we'll store the right side links in reversed order. std::reverse(rightShape.begin(), rightShape.end()); linkSplitter.addEdgeLinks(rightShape, rightEdgeLinks); } SMesh* leftMesh = new SMesh(); leftMeshBuf->recalculateBoundingBox(); leftMeshBuf->setHardwareMappingHint(EHM_STATIC); leftMesh->addMeshBuffer(leftMeshBuf); leftMesh->recalculateBoundingBox(); leftMeshBuf->drop(); // we drop the buf, mesh obj has it now SMesh* rightMesh = new SMesh(); rightMeshBuf->recalculateBoundingBox(); rightMeshBuf->setHardwareMappingHint(EHM_STATIC); rightMesh->addMeshBuffer(rightMeshBuf); rightMesh->recalculateBoundingBox(); rightMeshBuf->drop(); // we drop the buf, mesh obj has it now SMesh* middleMesh = NULL; if (zInsert > 0) { set<pair<PsblVertPtr,PsblVertPtr>> result; std::set_intersection( leftEdgeLinks.begin(), leftEdgeLinks.end(), rightEdgeLinks.begin(), rightEdgeLinks.end(), std::inserter(result, result.begin()) ); size_t debugsize = result.size(); if (result.size() > 0) { SMeshBuffer* middleMeshBuf = new SMeshBuffer(); vector<PsblVertPtr> shape(4); for (auto it=result.begin(); it!=result.end(); ++it) { shape[0] = it->second; shape[1] = it->first; shape[2] = it->first->duplicate(offset); shape[3] = it->second->duplicate(offset); linkSplitter.addConvexShape(shape, middleMeshBuf, -offset/2); } middleMesh = new SMesh(); middleMeshBuf->recalculateBoundingBox(); middleMeshBuf->setHardwareMappingHint(EHM_STATIC); middleMesh->addMeshBuffer(middleMeshBuf); middleMesh->recalculateBoundingBox(); middleMeshBuf->drop(); // we drop the buf, mesh obj has it now } } return SplitMeshResult {leftMesh, middleMesh, rightMesh}; }
GLlink(ISceneNode *i_parent, ISceneManager *i_mgr, s32 i_id, const LinkInfo &i_li, BodyInfo_var i_binfo) : ISceneNode(i_parent, i_mgr, i_id), m_jointId(i_li.jointId) { setAutomaticCulling(scene::EAC_OFF); setPosition(vector3df( i_li.translation[0], -i_li.translation[1], i_li.translation[2])); Vector3 axis(i_li.rotation[0], i_li.rotation[1], i_li.rotation[2]); Matrix33 R; hrp::calcRodrigues(R, axis, i_li.rotation[3]); Vector3 rpy(rpyFromRot(R)); //std::cout << "rpy:" << rpy << std::endl; setRotation(vector3df(-180/M_PI*rpy[0], 180/M_PI*rpy[1], -180/M_PI*rpy[2])); m_axis << i_li.jointAxis[0], i_li.jointAxis[1], i_li.jointAxis[2]; ShapeInfoSequence_var sis = i_binfo->shapes(); AppearanceInfoSequence_var ais = i_binfo->appearances(); MaterialInfoSequence_var mis = i_binfo->materials(); TextureInfoSequence_var txs = i_binfo->textures(); const TransformedShapeIndexSequence& tsis = i_li.shapeIndices; core::vector3df vertex; core::vector3df normal; for (unsigned int l=0; l<tsis.length(); l++) { SMesh* mesh = new SMesh(); SMeshBuffer* meshBuffer = new SMeshBuffer(); mesh->addMeshBuffer(meshBuffer); meshBuffer->drop(); const TransformedShapeIndex &tsi = tsis[l]; short index = tsi.shapeIndex; ShapeInfo& si = sis[index]; const float *vertices = si.vertices.get_buffer(); const LongSequence& triangles = si.triangles; const AppearanceInfo& ai = ais[si.appearanceIndex]; const float *normals = ai.normals.get_buffer(); //std::cout << "length of normals = " << ai.normals.length() << std::endl; const LongSequence& normalIndices = ai.normalIndices; //std::cout << "length of normalIndices = " << normalIndices.length() << std::endl; const int numTriangles = triangles.length() / 3; //std::cout << "numTriangles = " << numTriangles << std::endl; video::SColor color(0xffffffff); if (ai.colors.length()) { color.set(0xff, 0xff*ai.colors[0], 0xff*ai.colors[1], 0xff*ai.colors[2]); } else if (ai.materialIndex >= 0) { const MaterialInfo& mi = mis[ai.materialIndex]; color.set(0xff, 0xff*mi.diffuseColor[0], 0xff*mi.diffuseColor[1], 0xff*mi.diffuseColor[2]); } else { std::cout << "no material" << std::endl; } SMeshBuffer* mb = reinterpret_cast<SMeshBuffer*>(mesh->getMeshBuffer(mesh->getMeshBufferCount()-1)); u32 vCount = mb->getVertexCount(); const DblArray12& tfm = tsi.transformMatrix; CMatrix4<f32> cmat; for (int i=0; i<3; i++) { for (int j=0; j<4; j++) { cmat[j*4+i] = tfm[i*4+j]; } } cmat[3] = cmat[7] = cmat[11] = 0.0; cmat[15] = 1.0; vector3df pos = cmat.getTranslation(); pos.Y *= -1; vector3df rpy = cmat.getRotationDegrees(); rpy.X *= -1; rpy.Z *= -1; vector3df scale = cmat.getScale(); const float *textureCoordinate = NULL; if (ai.textureIndex >= 0) { textureCoordinate = ai.textureCoordinate.get_buffer(); //std::cout << "length of textureCoordinate:" << ai.textureCoordinate.length() << std::endl; //std::cout << "length of vertices:" << si.vertices.length() << std::endl; } for(int j=0; j < numTriangles; ++j) { if (!ai.normalPerVertex) { int p; if (normalIndices.length() == 0) { p = j*3; } else { p = normalIndices[j]*3; } if ( normals != NULL ) { normal.X = normals[p]; normal.Y = -normals[p+1]; //left-handed->right-handed normal.Z = normals[p+2]; } else { normal.X = 0; normal.Y = 0; normal.Z = 1; } } for(int k=0; k < 3; ++k) { long orgVertexIndex = si.triangles[j * 3 + k]; if (ai.normalPerVertex) { int p; if (normalIndices.length()) { p = normalIndices[j*3+k]*3; } else { p = orgVertexIndex*3; } normal.X = normals[p]; normal.Y = -normals[p+1]; //left-handed -> right-handed normal.Z = normals[p+2]; } int p = orgVertexIndex * 3; vertex.X = scale.X*vertices[p]; vertex.Y = -scale.Y*vertices[p+1]; // left-handed -> right-handed vertex.Z = scale.Z*vertices[p+2]; //std::cout << vertices[p] <<"," << vertices[p+1] << "," << vertices[p+2] << std::endl; vector2df texc; if (textureCoordinate) { texc.X = textureCoordinate[ai.textureCoordIndices[j*3+k]*2]; texc.Y = textureCoordinate[ai.textureCoordIndices[j*3+k]*2+1]; } // redundant vertices mb->Vertices.push_back(video::S3DVertex(vertex,normal,color, texc)); } mb->Indices.push_back(vCount); mb->Indices.push_back(vCount+2); mb->Indices.push_back(vCount+1); vCount += 3; } mesh->getMeshBuffer(0)->recalculateBoundingBox(); // Create the Animated mesh if there's anything in the mesh SAnimatedMesh* pAM = 0; if ( 0 != mesh->getMeshBufferCount() ) { mesh->recalculateBoundingBox(); pAM = new SAnimatedMesh(); pAM->Type = EAMT_OBJ; pAM->addMesh(mesh); pAM->recalculateBoundingBox(); } mesh->drop(); vector3df noscale(1,1,1); IMeshSceneNode *node = i_mgr->addMeshSceneNode(mesh, this, -1, pos, rpy, noscale); if (ai.textureIndex >= 0) { const TextureInfo& ti = txs[ai.textureIndex]; //std::cout << "url:" << ti.url << std::endl; video::IVideoDriver* driver = i_mgr->getVideoDriver(); const char *path = ti.url; SMaterial& mat = node->getMaterial(0); ITexture *texture = driver->getTexture(path); mat.setTexture( 0, texture); } } const SensorInfoSequence& sensors = i_li.sensors; for (unsigned int i=0; i<sensors.length(); i++) { const SensorInfo& si = sensors[i]; std::string type(si.type); if (type == "Vision") { //std::cout << si.name << std::endl; ISceneNode *camera = i_mgr->addEmptySceneNode(this); camera->setName(si.name); camera->setPosition(vector3df( si.translation[0], -si.translation[1], si.translation[2])); Vector3 axis(si.rotation[0], si.rotation[1], si.rotation[2]); Matrix33 R; hrp::calcRodrigues(R, axis, si.rotation[3]); Vector3 rpy(rpyFromRot(R)); camera->setRotation(vector3df(-180/M_PI*rpy[0], 180/M_PI*rpy[1], -180/M_PI*rpy[2])); m_cameraInfos.push_back(new GLcamera(si, camera)); } } }
SMeshBuffer* createRainbowMeshBuffer( // XY-plane, normale is -Z f32 outerRadius, f32 innerRadius, f32 zAngleStart, f32 zAngleEnd, u32 segments, const core::vector3df& pos) { SMeshBuffer* buffer = new SMeshBuffer(); if (!buffer) return 0; //! outer-cylinder material buffer->Material.Lighting = false; buffer->Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; buffer->Material.Wireframe = false; buffer->Material.FogEnable = false; buffer->Material.BackfaceCulling = true; buffer->Vertices.clear(); buffer->Indices.clear(); // buffer->Vertices.reallocate(); // buffer->Vertices.set_used(0); // buffer->Indices.reallocate(); // buffer->Indices.set_used(0); //! Constants const f32 phi = 2.0f*core::PI * (zAngleEnd-zAngleStart) / (360.0f * (f32)segments); const f32 phiStart = 2.0f*core::PI * (zAngleStart-90.0f) / 360.0f; const f32 z = pos.Z; //! Locals f32 x0,y0,x1,y1,x2,y2,x3,y3,sinPhi,cosPhi; //! Tables f32* sinTable = new f32[segments+1]; f32* cosTable = new f32[segments+1]; for (u32 i=0; i<segments+1; ++i) { const f32 angle = (f32)i*phi + phiStart; sinTable[i] = sinf(angle); cosTable[i] = cosf(angle); } //! build MeshBuffer (each segment consists of 2 triangles, important for texturing, each segment contains one complete texture) for (u32 i=0; i<segments; ++i) { x0 = pos.X - innerRadius * sinTable[i+1]; y0 = pos.Y + innerRadius * cosTable[i+1]; x1 = pos.X - outerRadius * sinTable[i+1]; y1 = pos.Y + outerRadius * cosTable[i+1]; x2 = pos.X - outerRadius * sinTable[i]; y2 = pos.Y + outerRadius * cosTable[i]; x3 = pos.X - innerRadius * sinTable[i]; y3 = pos.Y + innerRadius * cosTable[i]; buffer->Vertices.push_back(video::S3DVertex(x0,y0,z,0,0,-1,0xFFFFFFFF,0,1)); // A buffer->Vertices.push_back(video::S3DVertex(x1,y1,z,0,0,-1,0xFFFFFFFF,0,0)); // B buffer->Vertices.push_back(video::S3DVertex(x2,y2,z,0,0,-1,0xFFFFFFFF,1,0)); // C buffer->Vertices.push_back(video::S3DVertex(x3,y3,z,0,0,-1,0xFFFFFFFF,1,1)); // D buffer->Indices.push_back(4*i+0); // A buffer->Indices.push_back(4*i+1); // B buffer->Indices.push_back(4*i+2); // C buffer->Indices.push_back(4*i+0); // A buffer->Indices.push_back(4*i+2); // C buffer->Indices.push_back(4*i+3); // D } delete [] sinTable; delete [] cosTable; //! BBox buffer->recalculateBoundingBox(); return buffer; } // END FUNCTION