void drawVector(RenderingContext & rc, const Geometry::Vec3 & from, const Geometry::Vec3 & to) { static Util::Reference<Mesh> mesh; if (mesh.isNull()) { VertexDescription vertexDescription; vertexDescription.appendPosition3D(); mesh = new Mesh(vertexDescription, 2, 2); mesh->setDrawMode(Mesh::DRAW_LINES); MeshIndexData & id = mesh->openIndexData(); uint32_t * indices = id.data(); indices[0] = 0; indices[1] = 1; id.updateIndexRange(); id.markAsChanged(); mesh->setDataStrategy(SimpleMeshDataStrategy::getPureLocalStrategy()); } MeshVertexData & vd = mesh->openVertexData(); float * vertices = reinterpret_cast<float *> (vd.data()); *vertices++ = from.getX(); // From *vertices++ = from.getY(); *vertices++ = from.getZ(); *vertices++ = to.getX(); // To *vertices++ = to.getY(); *vertices++ = to.getZ(); vd.updateBoundingBox(); vd.markAsChanged(); rc.displayMesh(mesh.get()); }
void drawTriangle(RenderingContext & rc, const Geometry::Vec3f & vertexA, const Geometry::Vec3f & vertexB, const Geometry::Vec3f & vertexC) { static Util::Reference<Mesh> mesh; if (mesh.isNull()) { VertexDescription vertexDescription; vertexDescription.appendPosition3D(); mesh = new Mesh(vertexDescription, 3, 3); MeshIndexData & id = mesh->openIndexData(); uint32_t * indices = id.data(); indices[0] = 0; indices[1] = 1; indices[2] = 2; id.updateIndexRange(); id.markAsChanged(); } MeshVertexData & vd = mesh->openVertexData(); float * vertices = reinterpret_cast<float *>(vd.data()); // First vertex *vertices++ = vertexA.getX(); *vertices++ = vertexA.getY(); *vertices++ = vertexA.getZ(); // Second vertex *vertices++ = vertexB.getX(); *vertices++ = vertexB.getY(); *vertices++ = vertexB.getZ(); // Third vertex *vertices++ = vertexC.getX(); *vertices++ = vertexC.getY(); *vertices++ = vertexC.getZ(); vd.updateBoundingBox(); vd.markAsChanged(); rc.displayMesh(mesh.get()); }
void drawWireframeBox(RenderingContext & rc, const Geometry::Box & box) { static Util::Reference<Mesh> mesh; if (mesh.isNull()) { VertexDescription vertexDescription; vertexDescription.appendPosition3D(); mesh = new Mesh(vertexDescription, 8, 16); mesh->setDataStrategy(SimpleMeshDataStrategy::getPureLocalStrategy()); mesh->setDrawMode(Mesh::DRAW_LINE_STRIP); MeshIndexData & id = mesh->openIndexData(); uint32_t * indices = id.data(); /* * Corners: * 6---------7 * /| /| * / | / | * 2---------3 | * | | | | * | 4------|--5 * | / | / * |/ |/ * 0---------1 */ indices[0] = 0; indices[1] = 2; indices[2] = 3; indices[3] = 1; indices[4] = 5; indices[5] = 7; indices[6] = 6; indices[7] = 4; indices[8] = 0; indices[9] = 1; indices[10] = 3; indices[11] = 7; indices[12] = 5; indices[13] = 4; indices[14] = 6; indices[15] = 2; id.updateIndexRange(); id.markAsChanged(); } MeshVertexData & vd = mesh->openVertexData(); float * vertices = reinterpret_cast<float *>(vd.data()); for (uint_fast8_t c = 0; c < 8; ++c) { const Geometry::Vec3 & corner = box.getCorner(static_cast<Geometry::corner_t> (c)); *vertices++ = corner.getX(); *vertices++ = corner.getY(); *vertices++ = corner.getZ(); } vd._setBoundingBox(box); vd.markAsChanged(); rc.displayMesh(mesh.get()); }
void drawGrid(RenderingContext & rc, float scale) { static Util::Reference<Mesh> mesh; if (mesh.isNull()) { VertexDescription vertexDescription; vertexDescription.appendPosition3D(); mesh = new Mesh(vertexDescription, 4 * 101, 4 * 101); mesh->setDrawMode(Mesh::DRAW_LINES); MeshVertexData & vd = mesh->openVertexData(); float * vertices = reinterpret_cast<float *> (vd.data()); MeshIndexData & id = mesh->openIndexData(); uint32_t * indices = id.data(); uint32_t nextIndex = 0; const float step = 1.0f / 100.0f; for (uint_fast8_t line = 0; line < 101; ++line) { const float pos = -0.5f + static_cast<float> (line) * step; *vertices++ = -0.5f; *vertices++ = 0.0f; *vertices++ = pos; *vertices++ = 0.5f; *vertices++ = 0.0f; *vertices++ = pos; *indices++ = nextIndex++; *indices++ = nextIndex++; *vertices++ = pos; *vertices++ = 0.0f; *vertices++ = -0.5f; *vertices++ = pos; *vertices++ = 0.0f; *vertices++ = 0.5f; *indices++ = nextIndex++; *indices++ = nextIndex++; } vd.updateBoundingBox(); vd.markAsChanged(); id.updateIndexRange(); id.markAsChanged(); } Geometry::Matrix4x4 matrix; matrix.scale(scale); rc.pushMatrix_modelToCamera(); rc.multMatrix_modelToCamera(matrix); rc.displayMesh(mesh.get()); rc.popMatrix_modelToCamera(); }
void drawFrustum(RenderingContext & rc, const Geometry::Frustum & frustum, const Util::Color4f & color, float lineWidth) { static Util::Reference<Mesh> mesh; if (mesh.isNull()) { VertexDescription vertexDescription; vertexDescription.appendPosition3D(); mesh = new Mesh(vertexDescription, 8, 16); mesh->setDrawMode(Mesh::DRAW_LINE_STRIP); MeshIndexData & id = mesh->openIndexData(); uint32_t * indices = id.data(); indices[0] = 0; indices[1] = 2; indices[2] = 3; indices[3] = 1; indices[4] = 5; indices[5] = 7; indices[6] = 6; indices[7] = 4; indices[8] = 0; indices[9] = 1; indices[10] = 3; indices[11] = 7; indices[12] = 5; indices[13] = 4; indices[14] = 6; indices[15] = 2; id.updateIndexRange(); } MeshVertexData & vd = mesh->openVertexData(); float * vertices = reinterpret_cast<float *>(vd.data()); for (uint_fast8_t c = 0; c < 8; ++c) { const Geometry::Vec3 & corner = frustum[static_cast<Geometry::corner_t> (c)]; *vertices++ = corner.getX(); *vertices++ = corner.getY(); *vertices++ = corner.getZ(); } vd.updateBoundingBox(); vd.markAsChanged(); rc.pushAndSetLine(lineWidth); rc.pushAndSetLighting(LightingParameters(false)); rc.pushAndSetColorMaterial(color); rc.displayMesh(mesh.get()); rc.popMaterial(); rc.popLighting(); rc.popLine(); }
void drawRect(RenderingContext & rc, const Geometry::Rect & rect) { static Util::Reference<Mesh> mesh; if (mesh.isNull()) { VertexDescription vertexDescription; vertexDescription.appendPosition2D(); mesh = new Mesh(vertexDescription, 4, 6); mesh->setDrawMode(Mesh::DRAW_TRIANGLES); MeshVertexData & vd = mesh->openVertexData(); float * vertices = reinterpret_cast<float *> (vd.data()); *vertices++ = 0.0f; // Bottom left *vertices++ = 0.0f; *vertices++ = 1.0f; // Bottom right *vertices++ = 0.0f; *vertices++ = 1.0f; // Top right *vertices++ = 1.0f; *vertices++ = 0.0f; // Top left *vertices++ = 1.0f; vd.updateBoundingBox(); vd.markAsChanged(); MeshIndexData & id = mesh->openIndexData(); uint32_t * indices = id.data(); indices[0] = 0; indices[1] = 2; indices[2] = 1; indices[3] = 0; indices[4] = 3; indices[5] = 2; id.updateIndexRange(); id.markAsChanged(); } Geometry::Matrix4x4 matrix; matrix.translate(rect.getX(), rect.getY(), 0.0f); matrix.scale(rect.getWidth(), rect.getHeight(), 1.0f); rc.pushMatrix_modelToCamera(); rc.multMatrix_modelToCamera(matrix); rc.displayMesh(mesh.get()); rc.popMatrix_modelToCamera(); }
void ParticlePointRenderer::operator()(ParticleSystemNode* psys, FrameContext & context, const RenderParam & rp /* = 0 */) { if ( (rp.getFlag(NO_GEOMETRY)) ) return; // render particles std::vector<Particle> & particles = psys->getParticles(); uint32_t count = psys->getParticleCount(); Rendering::VertexDescription vertexDesc; const Rendering::VertexAttribute & posAttrib = vertexDesc.appendPosition3D(); const Rendering::VertexAttribute & colorAttrib = vertexDesc.appendColorRGBAByte(); // The usage of a cache for the mesh has been tested. Reusing a preallocated mesh is not faster. Util::Reference<Rendering::Mesh> mesh = new Rendering::Mesh(vertexDesc, count, count); mesh->setDataStrategy(Rendering::SimpleMeshDataStrategy::getPureLocalStrategy()); mesh->setDrawMode(Rendering::Mesh::DRAW_POINTS); // mesh->setUseIndexData(false); Rendering::MeshIndexData & indexData = mesh->openIndexData(); Rendering::MeshVertexData & vertexData = mesh->openVertexData(); Util::Reference<Rendering::PositionAttributeAccessor> positionAccessor = Rendering::PositionAttributeAccessor::create(vertexData, posAttrib.getNameId()); Util::Reference<Rendering::ColorAttributeAccessor> colorAccessor = Rendering::ColorAttributeAccessor::create(vertexData, colorAttrib.getNameId()); uint32_t * indices = indexData.data(); for(uint_fast32_t index = 0; index < count; ++index) { const Particle & p = particles[index]; colorAccessor->setColor(index, p.color); positionAccessor->setPosition(index, p.position); *indices++ = index; } indexData.markAsChanged(); indexData.updateIndexRange(); vertexData.markAsChanged(); vertexData.updateBoundingBox(); context.displayMesh(mesh.get()); }
void drawCoordSys(RenderingContext & rc, float scale) { static Util::Reference<Mesh> arrow; static Util::Reference<Mesh> sphere; static Util::Reference<Mesh> charX; static Util::Reference<Mesh> charY; static Util::Reference<Mesh> charZ; const float radius = 0.025f; if (arrow.isNull()) { std::deque<Mesh *> meshes; std::deque<Geometry::Matrix4x4> transformations; Geometry::Matrix4x4 transform; meshes.push_back(MeshUtils::MeshBuilder::createConicalFrustum(radius, radius, 0.7f, 16)); transformations.push_back(transform); meshes.push_back(MeshUtils::MeshBuilder::createConicalFrustum(radius, 2.0f * radius, 0.01f, 16)); transform.translate(0.7f, 0.0f, 0.0f); transformations.push_back(transform); meshes.push_back(MeshUtils::MeshBuilder::createCone(2.0f * radius, 0.29f, 16)); transform.translate(0.01f, 0.0f, 0.0f); transformations.push_back(transform); arrow = MeshUtils::combineMeshes(meshes, transformations); MeshUtils::optimizeIndices(arrow.get()); while (!meshes.empty()) { delete meshes.back(); meshes.pop_back(); } } if (sphere.isNull()) { Util::Reference<Mesh> icosahedron = MeshUtils::PlatonicSolids::createIcosahedron(); sphere = MeshUtils::PlatonicSolids::createEdgeSubdivisionSphere(icosahedron.get(), 2); Geometry::Matrix4x4 transform; transform.scale(1.1f * radius); MeshUtils::transform(sphere.get()->openVertexData(), transform); } if(charX.isNull()) { std::deque<Mesh *> meshes; std::deque<Geometry::Matrix4x4> transformations; VertexDescription vertexDescription; vertexDescription.appendPosition3D(); vertexDescription.appendNormalFloat(); const Geometry::Box box(Geometry::Vec3f(0.0f, 0.0f, 0.0f), 0.02f, 0.2f, 0.05f); { meshes.push_back(MeshUtils::MeshBuilder::createBox(vertexDescription, box)); Geometry::Matrix4x4 transform; transform.translate(1.2f, 0.0f, 0.0f); transform.rotate_deg(30.0f, 0.0f, 0.0f, -1.0f); transformations.push_back(transform); } { meshes.push_back(MeshUtils::MeshBuilder::createBox(vertexDescription, box)); Geometry::Matrix4x4 transform; transform.translate(1.2f, 0.0f, 0.0f); transform.rotate_deg(-30.0f, 0.0f, 0.0f, -1.0f); transformations.push_back(transform); } charX = MeshUtils::combineMeshes(meshes, transformations); MeshUtils::optimizeIndices(charX.get()); while(!meshes.empty()) { delete meshes.back(); meshes.pop_back(); } } if(charY.isNull()) { std::deque<Mesh *> meshes; std::deque<Geometry::Matrix4x4> transformations; VertexDescription vertexDescription; vertexDescription.appendPosition3D(); vertexDescription.appendNormalFloat(); const Geometry::Box box(Geometry::Vec3f(0.0f, 0.0f, 0.0f), 0.02f, 0.1f, 0.05f); { meshes.push_back(MeshUtils::MeshBuilder::createBox(vertexDescription, box)); Geometry::Matrix4x4 transform; transform.translate(0.025f, 0.045f, 0.0f); transform.rotate_deg(30.0f, 0.0f, 0.0f, -1.0f); transformations.push_back(transform); } { meshes.push_back(MeshUtils::MeshBuilder::createBox(vertexDescription, box)); Geometry::Matrix4x4 transform; transform.translate(-0.025f, 0.045f, 0.0f); transform.rotate_deg(-30.0f, 0.0f, 0.0f, -1.0f); transformations.push_back(transform); } { meshes.push_back(MeshUtils::MeshBuilder::createBox(vertexDescription, box)); Geometry::Matrix4x4 transform; transform.translate(0.0f, -0.045f, 0.0f); transformations.push_back(transform); } charY = MeshUtils::combineMeshes(meshes, transformations); Geometry::Matrix4x4 transform; transform.translate(1.2f, 0.0f, 0.0f); transform.rotate_deg(90.0f, 0.0f, 0.0f, -1.0f); MeshUtils::transform(charY->openVertexData(), transform); MeshUtils::optimizeIndices(charY.get()); while(!meshes.empty()) { delete meshes.back(); meshes.pop_back(); } } if(charZ.isNull()) { std::deque<Mesh *> meshes; std::deque<Geometry::Matrix4x4> transformations; VertexDescription vertexDescription; vertexDescription.appendPosition3D(); vertexDescription.appendNormalFloat(); const Geometry::Box box(Geometry::Vec3f(0.0f, 0.0f, 0.0f), 0.02f, 0.1f, 0.05f); { meshes.push_back(MeshUtils::MeshBuilder::createBox(vertexDescription, box)); Geometry::Matrix4x4 transform; transform.translate(1.2f, 0.075f, 0.0f); transform.rotate_deg(90.0f, 0.0f, 0.0f, -1.0f); transformations.push_back(transform); } { meshes.push_back(MeshUtils::MeshBuilder::createBox(vertexDescription, box)); Geometry::Matrix4x4 transform; transform.translate(1.2f, 0.0f, 0.0f); transform.rotate_deg(-30.0f, 0.0f, 0.0f, -1.0f); transform.scale(1.0f, 1.6f, 1.0f); transformations.push_back(transform); } { meshes.push_back(MeshUtils::MeshBuilder::createBox(vertexDescription, box)); Geometry::Matrix4x4 transform; transform.translate(1.2f, -0.075f, 0.0f); transform.rotate_deg(-90.0f, 0.0f, 0.0f, -1.0f); transformations.push_back(transform); } charZ = MeshUtils::combineMeshes(meshes, transformations); MeshUtils::optimizeIndices(charZ.get()); while(!meshes.empty()) { delete meshes.back(); meshes.pop_back(); } } // Origin rc.pushAndSetColorMaterial(Util::ColorLibrary::WHITE); rc.displayMesh(sphere.get()); rc.popMaterial(); // X axis Geometry::Matrix4x4 transform; transform.scale(scale, 1.0f, 1.0f); rc.pushMatrix_modelToCamera(); rc.multMatrix_modelToCamera(transform); rc.pushAndSetColorMaterial(Util::ColorLibrary::RED); rc.displayMesh(arrow.get()); rc.displayMesh(charX.get()); rc.popMaterial(); rc.popMatrix_modelToCamera(); // Y axis transform.setIdentity(); transform.scale(1.0f, scale, 1.0f); transform.rotate_deg(90.0f, 0.0f, 0.0f, 1.0f); rc.pushMatrix_modelToCamera(); rc.multMatrix_modelToCamera(transform); rc.pushAndSetColorMaterial(Util::ColorLibrary::GREEN); rc.displayMesh(arrow.get()); rc.displayMesh(charY.get()); rc.popMaterial(); rc.popMatrix_modelToCamera(); // Z axis transform.setIdentity(); transform.scale(1.0f, 1.0f, scale); transform.rotate_deg(90.0f, 0.0f, -1.0f, 0.0f); rc.pushMatrix_modelToCamera(); rc.multMatrix_modelToCamera(transform); rc.pushAndSetColorMaterial(Util::ColorLibrary::BLUE); rc.displayMesh(arrow.get()); rc.displayMesh(charZ.get()); rc.popMaterial(); rc.popMatrix_modelToCamera(); }
int test_spherical_sampling_serialization() { #ifdef MINSG_EXT_SVS std::cout << "Test serialization of SVS objects ... "; Util::Timer timer; timer.reset(); using namespace MinSG::SVS; MinSG::SceneManagement::SceneManager sceneManager; const uint32_t count = 10; std::array<Util::Reference<MinSG::GeometryNode>, count> nodes; for(uint_fast32_t i = 0; i < count; ++i) { nodes[i] = new MinSG::GeometryNode; sceneManager.registerNode(std::string("Node") + Util::StringUtils::toString(i), nodes[i].get()); } MinSG::VisibilitySubdivision::VisibilityVector vv; for(uint_fast32_t i = 0; i < count; ++i) { vv.setNode(nodes[i].get(), i); } std::vector<SamplePoint> samples; { using namespace Rendering::MeshUtils::PlatonicSolids; Util::Reference<Rendering::Mesh> mesh = createEdgeSubdivisionSphere(createIcosahedron(), 4); auto accessor = Rendering::PositionAttributeAccessor::create(mesh->openVertexData(), Rendering::VertexAttributeIds::POSITION); for(std::size_t i = 0; accessor->checkRange(i); ++i) { samples.emplace_back(accessor->getPosition(i)); } } { std::stringstream stream; stream.precision(std::numeric_limits<long double>::digits10); // Serialize for(const auto & sample : samples) { stream << sample.getPosition() << ' '; sample.getValue().serialize(stream, sceneManager); stream << ' '; } // Unserialize std::vector<SamplePoint> newSamples; for(std::size_t s = 0; s < samples.size(); ++s) { Geometry::Vec3f pos; stream >> pos; SamplePoint sample(pos); sample.setValue(MinSG::VisibilitySubdivision::VisibilityVector::unserialize(stream, sceneManager)); newSamples.push_back(sample); } for(std::size_t s = 0; s < samples.size(); ++s) { const SamplePoint & oldSample = samples[s]; const SamplePoint & newSample = newSamples[s]; if(oldSample.getPosition().distance(newSample.getPosition()) > std::numeric_limits<float>::epsilon()) { std::cout << "Serialization/unserialization failed." << std::endl; return EXIT_FAILURE; } const auto & oldVV = oldSample.getValue(); const auto & newVV = newSample.getValue(); for(uint_fast32_t n = 0; n < count; ++n) { if(oldVV.getBenefits(nodes[n].get()) != newVV.getBenefits(nodes[n].get())) { std::cout << "Serialization/unserialization failed." << std::endl; return EXIT_FAILURE; } } } } VisibilitySphere visibilitySphere(Geometry::Sphere_f(Geometry::Vec3f(1.0f, 2.0f, 3.0f), 17.0f), samples); { std::stringstream stream; stream.precision(std::numeric_limits<long double>::digits10); // Serialize stream << visibilitySphere.getSphere() << ' ' << samples.size(); for(const auto & sample : samples) { stream << ' ' << sample.getPosition() << ' '; sample.getValue().serialize(stream, sceneManager); stream << ' '; } // Unserialize Geometry::Sphere_f sphere; stream >> sphere; std::size_t sampleCount; stream >> sampleCount; std::vector<SamplePoint> newSamples; for(std::size_t s = 0; s < sampleCount; ++s) { Geometry::Vec3f pos; stream >> pos; SamplePoint sample(pos); sample.setValue(MinSG::VisibilitySubdivision::VisibilityVector::unserialize(stream, sceneManager)); newSamples.push_back(sample); } VisibilitySphere newVisibilitySphere(sphere, newSamples); if(!(visibilitySphere.getSphere() == newVisibilitySphere.getSphere())) { std::cout << "Serialization/unserialization failed." << std::endl; return EXIT_FAILURE; } for(std::size_t s = 0; s < samples.size(); ++s) { const SamplePoint & oldSample = visibilitySphere.getSamples()[s]; const SamplePoint & newSample = newVisibilitySphere.getSamples()[s]; if(oldSample.getPosition().distance(newSample.getPosition()) > std::numeric_limits<float>::epsilon()) { std::cout << "Serialization/unserialization failed." << std::endl; return EXIT_FAILURE; } const auto & oldVV = oldSample.getValue(); const auto & newVV = newSample.getValue(); for(uint_fast32_t n = 0; n < count; ++n) { if(oldVV.getBenefits(nodes[n].get()) != newVV.getBenefits(nodes[n].get())) { std::cout << "Serialization/unserialization failed." << std::endl; return EXIT_FAILURE; } } } } timer.stop(); std::cout << "done (duration: " << timer.getSeconds() << " s).\n"; #endif /* MINSG_EXT_SVS */ return EXIT_SUCCESS; }
void drawQuad(RenderingContext & rc, const Geometry::Vec3 & lowerLeft, const Geometry::Vec3 & lowerRight, const Geometry::Vec3 & upperRight, const Geometry::Vec3 & upperLeft) { static Util::Reference<Mesh> mesh; if (mesh.isNull()) { VertexDescription vertexDescription; vertexDescription.appendPosition3D(); vertexDescription.appendNormalFloat(); vertexDescription.appendTexCoord(); mesh = new Mesh(vertexDescription, 4, 6); MeshIndexData & id = mesh->openIndexData(); uint32_t * indices = id.data(); indices[0] = 0; indices[1] = 1; indices[2] = 2; indices[3] = 0; indices[4] = 2; indices[5] = 3; id.updateIndexRange(); id.markAsChanged(); } const Geometry::Vec3 edgeA = lowerRight - lowerLeft; const Geometry::Vec3 edgeB = upperLeft - lowerLeft; Geometry::Vec3 normal = edgeA.cross(edgeB); normal.normalize(); MeshVertexData & vd = mesh->openVertexData(); float * vertices = reinterpret_cast<float *> (vd.data()); // Lower left *vertices++ = lowerLeft.getX(); *vertices++ = lowerLeft.getY(); *vertices++ = lowerLeft.getZ(); *vertices++ = normal.getX(); *vertices++ = normal.getY(); *vertices++ = normal.getZ(); *vertices++ = 0.0f; *vertices++ = 0.0f; // Lower right *vertices++ = lowerRight.getX(); *vertices++ = lowerRight.getY(); *vertices++ = lowerRight.getZ(); *vertices++ = normal.getX(); *vertices++ = normal.getY(); *vertices++ = normal.getZ(); *vertices++ = 1.0f; *vertices++ = 0.0f; // Upper right *vertices++ = upperRight.getX(); *vertices++ = upperRight.getY(); *vertices++ = upperRight.getZ(); *vertices++ = normal.getX(); *vertices++ = normal.getY(); *vertices++ = normal.getZ(); *vertices++ = 1.0f; *vertices++ = 1.0f; // Upper left *vertices++ = upperLeft.getX(); *vertices++ = upperLeft.getY(); *vertices++ = upperLeft.getZ(); *vertices++ = normal.getX(); *vertices++ = normal.getY(); *vertices++ = normal.getZ(); *vertices++ = 0.0f; *vertices++ = 1.0f; vd.updateBoundingBox(); vd.markAsChanged(); rc.displayMesh(mesh.get()); }
void ParticleBillboardRenderer::operator()(ParticleSystemNode * psys, FrameContext & context, const RenderParam & rp) { if(rp.getFlag(NO_GEOMETRY)) { return; } const auto & worldToCamera = context.getRenderingContext().getMatrix_worldToCamera(); const auto cameraToWorld = worldToCamera.inverse(); const auto halfRight = cameraToWorld.transformDirection(context.getWorldRightVector() * 0.5f); const auto halfUp = cameraToWorld.transformDirection(context.getWorldUpVector() * 0.5f); // 2. just update position for each particle and render // render particles const uint32_t count = psys->getParticleCount(); Rendering::VertexDescription vertexDesc; const Rendering::VertexAttribute & posAttrib = vertexDesc.appendPosition3D(); const Rendering::VertexAttribute & colorAttrib = vertexDesc.appendColorRGBAByte(); const Rendering::VertexAttribute & texCoordAttrib = vertexDesc.appendTexCoord(); // The usage of a cache for the mesh has been tested. Reusing a preallocated mesh is not faster. Util::Reference<Rendering::Mesh> mesh = new Rendering::Mesh(vertexDesc, 4 * count, 6 * count); mesh->setDataStrategy(Rendering::SimpleMeshDataStrategy::getPureLocalStrategy()); Rendering::MeshIndexData & indexData = mesh->openIndexData(); Rendering::MeshVertexData & vertexData = mesh->openVertexData(); Util::Reference<Rendering::PositionAttributeAccessor> positionAccessor = Rendering::PositionAttributeAccessor::create(vertexData, posAttrib.getNameId()); Util::Reference<Rendering::ColorAttributeAccessor> colorAccessor = Rendering::ColorAttributeAccessor::create(vertexData, colorAttrib.getNameId()); Util::Reference<Rendering::TexCoordAttributeAccessor> texCoordAccessor = Rendering::TexCoordAttributeAccessor::create(vertexData, texCoordAttrib.getNameId()); uint32_t * indices = indexData.data(); uint_fast32_t index = 0; for(const auto & p : psys->getParticles()) { const Geometry::Vec3f upOffset = halfUp * p.size.getHeight(); const Geometry::Vec3f rightOffset = halfRight * p.size.getWidth(); colorAccessor->setColor(index + 0, p.color); texCoordAccessor->setCoordinate(index + 0, Geometry::Vec2f(0.0f, 0.0f)); positionAccessor->setPosition(index + 0, p.position + upOffset - rightOffset); colorAccessor->setColor(index + 1, p.color); texCoordAccessor->setCoordinate(index + 1, Geometry::Vec2f(0.0f, 1.0f)); positionAccessor->setPosition(index + 1, p.position - upOffset - rightOffset); colorAccessor->setColor(index + 2, p.color); texCoordAccessor->setCoordinate(index + 2, Geometry::Vec2f(1.0f, 1.0f)); positionAccessor->setPosition(index + 2, p.position - upOffset + rightOffset); colorAccessor->setColor(index + 3, p.color); texCoordAccessor->setCoordinate(index + 3, Geometry::Vec2f(1.0f, 0.0f)); positionAccessor->setPosition(index + 3, p.position + upOffset + rightOffset); *indices++ = index + 0; *indices++ = index + 1; *indices++ = index + 3; *indices++ = index + 1; *indices++ = index + 2; *indices++ = index + 3; index += 4; } indexData.markAsChanged(); indexData.updateIndexRange(); vertexData.markAsChanged(); vertexData.updateBoundingBox(); context.displayMesh(mesh.get()); }
int test_OutOfCore() { #ifdef MINSG_EXT_OUTOFCORE const bool verbose = true; // Tests for MinSG::OutOfCore::CacheObjectPriority if(sizeof(MinSG::OutOfCore::CacheObjectPriority) != 8) { return EXIT_FAILURE; } if(!(MinSG::OutOfCore::CacheObjectPriority(1, 2, 3) == MinSG::OutOfCore::CacheObjectPriority(1, 2, 3))) { return EXIT_FAILURE; } if(!(MinSG::OutOfCore::CacheObjectPriority(1, 100, 100) < MinSG::OutOfCore::CacheObjectPriority(2, 0, 0))) { return EXIT_FAILURE; } if(!(MinSG::OutOfCore::CacheObjectPriority(2, 1, 100) < MinSG::OutOfCore::CacheObjectPriority(2, 2, 0))) { return EXIT_FAILURE; } if(!(MinSG::OutOfCore::CacheObjectPriority(2, 2, 1) < MinSG::OutOfCore::CacheObjectPriority(2, 2, 2))) { return EXIT_FAILURE; } std::default_random_engine engine; std::uniform_int_distribution<std::size_t> vertexCountDist(10, 1000); const uint32_t numMeshes = 30000; const Util::TemporaryDirectory tempDir("MinSGTest_OutOfCore"); // Create empty meshes and save them into a subdirectory. { Rendering::VertexDescription vertexDesc; vertexDesc.appendPosition3D(); for(uint_fast32_t i = 0; i < numMeshes; ++i) { Util::Reference<Rendering::Mesh> mesh = new Rendering::Mesh(vertexDesc, vertexCountDist(engine), 64); Rendering::MeshVertexData & vertexData = mesh->openVertexData(); std::fill_n(vertexData.data(), vertexData.dataSize(), 0); vertexData.markAsChanged(); Rendering::MeshIndexData & indexData = mesh->openIndexData(); std::fill_n(indexData.data(), indexData.getIndexCount(), 0); indexData.markAsChanged(); const std::string numberString = Util::StringUtils::toString<uint32_t>(i); Rendering::Serialization::saveMesh(mesh.get(), Util::FileName(tempDir.getPath().getDir() + numberString + ".mmf")); } } // Set up the OutOfCore system. MinSG::FrameContext frameContext; MinSG::OutOfCore::setUp(frameContext); MinSG::OutOfCore::CacheManager & manager = MinSG::OutOfCore::getCacheManager(); manager.addCacheLevel(MinSG::OutOfCore::CacheLevelType::FILE_SYSTEM, 0); manager.addCacheLevel(MinSG::OutOfCore::CacheLevelType::FILES, 512 * kibibyte); manager.addCacheLevel(MinSG::OutOfCore::CacheLevelType::MAIN_MEMORY, 256 * kibibyte); Util::Timer addTimer; addTimer.reset(); std::cout << "Adding meshes ..." << std::flush; // Add the meshes to the OutOfCore system. std::vector<Util::Reference<Rendering::Mesh> > meshes; meshes.reserve(numMeshes); static const Geometry::Box boundingBox(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); for(uint_fast32_t i = 0; i < numMeshes; ++i) { const std::string numberString = Util::StringUtils::toString<uint32_t>(i); meshes.push_back(MinSG::OutOfCore::addMesh(Util::FileName(tempDir.getPath().getDir() + numberString + ".mmf"), boundingBox)); } manager.trigger(); addTimer.stop(); std::cout << " done (" << addTimer.getSeconds() << " s)" << std::endl; Util::Timer displayTimer; Util::Timer assureLocalTimer; Util::Timer overallTimer; overallTimer.reset(); uint32_t frame = 0; { // Simulate frames to get the OutOfCore system working. std::uniform_int_distribution<std::size_t> indexDist(0, meshes.size() - 1); for(; frame < 10; ++frame) { std::cout << "Executing frame " << frame << " ..." << std::flush; frameContext.beginFrame(); displayTimer.reset(); // Simulate display of meshes to change the priorities of the system. for(uint32_t i = 0; i < meshes.size() / 2; ++i) { const uint32_t meshIndex = indexDist(engine); Rendering::Mesh * mesh = meshes[meshIndex].get(); manager.meshDisplay(mesh); } manager.trigger(); displayTimer.stop(); assureLocalTimer.reset(); for(uint32_t i = 0; i < 10; ++i) { const uint32_t meshIndex = indexDist(engine); Rendering::Mesh * mesh = meshes[meshIndex].get(); const Rendering::MeshVertexData & vd = mesh->openVertexData(); const Rendering::MeshIndexData & id = mesh->openIndexData(); if (!vd.hasLocalData() || !id.hasLocalData()) { std::cout << "Error: Mesh has no local data." << std::endl; return EXIT_FAILURE; } } assureLocalTimer.stop(); frameContext.endFrame(); std::cout << " done (display: " << displayTimer.getSeconds() << " s, assureLocal: " << assureLocalTimer.getSeconds() << " s)" << std::endl; if(verbose) { outputCacheLevelInformation(); } } } for(uint32_t round = 0; round < 10; ++round) { Util::Timer addAgainTimer; addAgainTimer.reset(); std::cout << "Adding additional meshes ..." << std::flush; // Simulate loading a second scene by adding meshes again. meshes.reserve(meshes.size() + 3 * numMeshes); for(uint_fast32_t i = 0; i < numMeshes; ++i) { const std::string numberString = Util::StringUtils::toString<uint32_t>(i); meshes.push_back(MinSG::OutOfCore::addMesh(Util::FileName(tempDir.getPath().getDir() + numberString + ".mmf"), boundingBox)); meshes.push_back(MinSG::OutOfCore::addMesh(Util::FileName(tempDir.getPath().getDir() + numberString + ".mmf"), boundingBox)); meshes.push_back(MinSG::OutOfCore::addMesh(Util::FileName(tempDir.getPath().getDir() + numberString + ".mmf"), boundingBox)); } manager.trigger(); addAgainTimer.stop(); std::cout << " done (" << addAgainTimer.getSeconds() << " s)" << std::endl; // Simulate frames to get the OutOfCore system working. std::normal_distribution<double> indexDist(meshes.size() / 2, std::sqrt(meshes.size() / 2)); const auto untilFrame = frame + 5; for(; frame < untilFrame; ++frame) { std::cout << "Executing frame " << frame << " ..." << std::flush; frameContext.beginFrame(); displayTimer.reset(); // Simulate display of meshes to change the priorities of the system. for(uint32_t i = 0; i < meshes.size() / 10; ++i) { const std::size_t meshIndex = std::max(static_cast<std::size_t>(0), std::min(static_cast<std::size_t>(indexDist(engine)), meshes.size() - 1)); Rendering::Mesh * mesh = meshes[meshIndex].get(); manager.meshDisplay(mesh); } manager.trigger(); displayTimer.stop(); frameContext.endFrame(); std::cout << " done (display: " << displayTimer.getSeconds() << " s)" << std::endl; if(verbose) { outputCacheLevelInformation(); } } } overallTimer.stop(); std::cout << "Overall duration: " << overallTimer.getSeconds() << " s" << std::endl; MinSG::OutOfCore::shutDown(); return EXIT_SUCCESS; #else /* MINSG_EXT_OUTOFCORE */ return EXIT_FAILURE; #endif /* MINSG_EXT_OUTOFCORE */ }