Initial commit.

This commit is contained in:
hal8174 2024-04-23 10:14:24 +02:00
commit d3bb49b3f5
1073 changed files with 484757 additions and 0 deletions

View file

@ -0,0 +1,17 @@
## Copyright 2009-2021 Intel Corporation
## SPDX-License-Identifier: Apache-2.0
ADD_LIBRARY(scenegraph STATIC
xml_parser.cpp
xml_loader.cpp
xml_writer.cpp
obj_loader.cpp
ply_loader.cpp
corona_loader.cpp
texture.cpp
scenegraph.cpp
geometry_creation.cpp)
TARGET_LINK_LIBRARIES(scenegraph sys math lexers image embree)
SET_PROPERTY(TARGET scenegraph PROPERTY FOLDER tutorials/common)
SET_PROPERTY(TARGET scenegraph APPEND PROPERTY COMPILE_FLAGS " ${FLAGS_LOWEST}")

View file

@ -0,0 +1,299 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#include "corona_loader.h"
#include "xml_parser.h"
#include "obj_loader.h"
namespace embree
{
class CoronaLoader
{
public:
static Ref<SceneGraph::Node> load(const FileName& fileName, const AffineSpace3fa& space);
CoronaLoader(const FileName& fileName, const AffineSpace3fa& space);
private:
template<typename T> T load(const Ref<XML>& xml) { assert(false); return T(zero); }
Ref<SceneGraph::MaterialNode> loadMaterial(const Ref<XML>& xml);
void loadMaterialDefinition(const Ref<XML>& xml);
std::shared_ptr<Texture> loadMap(const Ref<XML>& xml);
void loadMapDefinition(const Ref<XML>& xml);
Ref<SceneGraph::Node> loadMaterialLibrary(const FileName& fileName);
Ref<SceneGraph::Node> loadObject(const Ref<XML>& xml);
std::pair<Ref<SceneGraph::MaterialNode>, avector<AffineSpace3fa> > loadInstances(const Ref<XML>& xml);
Ref<SceneGraph::Node> loadGroupNode(const Ref<XML>& xml);
Ref<SceneGraph::Node> loadNode(const Ref<XML>& xml);
private:
FileName path;
std::map<std::string,Ref<SceneGraph::MaterialNode> > materialMap;
std::map<std::string,std::shared_ptr<Texture>> textureMap;
std::map<std::string,std::shared_ptr<Texture>> textureFileMap;
public:
Ref<SceneGraph::Node> root;
};
template<> FileName CoronaLoader::load<FileName>(const Ref<XML>& xml)
{
if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong FileName body");
return xml->body[0].Identifier();
}
template<> std::string CoronaLoader::load<std::string>(const Ref<XML>& xml)
{
if (xml->body.size() != 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong string body");
return xml->body[0].Identifier();
}
template<> int CoronaLoader::load<int>(const Ref<XML>& xml) {
if (xml->body.size() < 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong int body");
return xml->body[0].Int();
}
template<> float CoronaLoader::load<float>(const Ref<XML>& xml) {
if (xml->body.size() < 1) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float body");
return xml->body[0].Float();
}
template<> Vec3f CoronaLoader::load<Vec3f>(const Ref<XML>& xml) {
if (xml->body.size() < 3) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float3 body");
return Vec3f(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float());
}
template<> Vec3fa CoronaLoader::load<Vec3fa>(const Ref<XML>& xml) {
if (xml->body.size() < 3) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong float3 body");
return Vec3fa(xml->body[0].Float(),xml->body[1].Float(),xml->body[2].Float());
}
template<> AffineSpace3fa CoronaLoader::load<AffineSpace3fa>(const Ref<XML>& xml)
{
if (xml->body.size() != 12) THROW_RUNTIME_ERROR(xml->loc.str()+": wrong AffineSpace body");
return AffineSpace3fa(LinearSpace3fa(xml->body[0].Float(),xml->body[1].Float(),xml->body[ 2].Float(),
xml->body[4].Float(),xml->body[5].Float(),xml->body[ 6].Float(),
xml->body[8].Float(),xml->body[9].Float(),xml->body[10].Float()),
Vec3fa(xml->body[3].Float(),xml->body[7].Float(),xml->body[11].Float()));
}
Ref<SceneGraph::MaterialNode> CoronaLoader::loadMaterial(const Ref<XML>& xml)
{
if (xml->name != "material")
THROW_RUNTIME_ERROR(xml->loc.str()+": invalid material: "+xml->name);
/* native material */
if (xml->parm("class") == "Native")
{
/* we convert into an OBJ material */
Ref<OBJMaterial> objmaterial = new OBJMaterial;
for (auto& child : xml->children)
{
if (child->name == "diffuse") {
objmaterial->Kd = load<Vec3fa>(child);
if (child->children.size() && child->children[0]->name == "map")
objmaterial->_map_Kd = loadMap(child->children[0]);
}
else if (child->name == "reflect") {
objmaterial->Ks = load<Vec3fa>(child->child("color"));
objmaterial->Ni = load<float >(child->child("ior"));
objmaterial->Ns = load<float >(child->child("glossiness"));
}
else if (child->name == "translucency") {
objmaterial->Kt = load<Vec3fa>(child->child("color"));
}
else if (child->name == "opacity") {
objmaterial->d = load<Vec3fa>(child).x;
if (child->children.size() && child->children[0]->name == "map")
objmaterial->_map_d = loadMap(child->children[0]);
}
}
return objmaterial.dynamicCast<SceneGraph::MaterialNode>();
}
/* reference by name */
else if (xml->parm("class") == "Reference")
{
const std::string name = load<std::string>(xml);
return materialMap[name];
}
/* else return default material */
else
return new OBJMaterial;
}
void CoronaLoader::loadMaterialDefinition(const Ref<XML>& xml)
{
if (xml->name != "materialDefinition")
THROW_RUNTIME_ERROR(xml->loc.str()+": invalid material definition: "+xml->name);
if (xml->children.size() != 1)
THROW_RUNTIME_ERROR(xml->loc.str()+": invalid material definition");
const std::string name = xml->parm("name");
materialMap[name] = loadMaterial(xml->children[0]);
}
std::shared_ptr<Texture> CoronaLoader::loadMap(const Ref<XML>& xml)
{
/* process map node */
if (xml->name == "map")
{
std::string mapClass = xml->parm("class");
/* load textures */
if (mapClass == "Texture")
{
const FileName src = load<FileName>(xml->child("image"));
/* load images only once */
if (textureFileMap.find(src) != textureFileMap.end())
return textureFileMap[src];
try {
return Texture::load(path+src);
} catch (const std::runtime_error& e) {
std::cerr << "failed to load " << path+src << ": " << e.what() << std::endl;
}
}
else if (mapClass == "Reference") {
const std::string name = load<std::string>(xml);
return textureMap[name];
}
}
/* recurse into every unknown node to find some texture */
for (auto& child : xml->children) {
std::shared_ptr<Texture> texture = loadMap(child);
if (texture) return texture;
}
return std::shared_ptr<Texture>();
}
void CoronaLoader::loadMapDefinition(const Ref<XML>& xml)
{
if (xml->name != "mapDefinition")
THROW_RUNTIME_ERROR(xml->loc.str()+": invalid map definition: "+xml->name);
if (xml->children.size() != 1)
THROW_RUNTIME_ERROR(xml->loc.str()+": invalid map definition");
const std::string name = xml->parm("name");
std::shared_ptr<Texture> texture = loadMap(xml->children[0]);
if (texture) textureMap[name] = texture;
}
Ref<SceneGraph::Node> CoronaLoader::loadMaterialLibrary(const FileName& fileName)
{
Ref<XML> xml = parseXML(path+fileName,"/.-",false);
if (xml->name != "mtlLib")
THROW_RUNTIME_ERROR(xml->loc.str()+": invalid material library");
for (auto& child : xml->children)
{
if (child->name == "materialDefinition") {
loadMaterialDefinition(child);
}
else if (child->name == "mapDefinition")
loadMapDefinition(child);
}
return nullptr;
}
Ref<SceneGraph::Node> CoronaLoader::loadObject(const Ref<XML>& xml)
{
if (xml->name != "object")
THROW_RUNTIME_ERROR(xml->loc.str()+": invalid object node");
if (xml->parm("class") != "file")
THROW_RUNTIME_ERROR(xml->loc.str()+": invalid object class");
const FileName fileName = load<FileName>(xml);
return SceneGraph::load(path+fileName);
}
std::pair<Ref<SceneGraph::MaterialNode>, avector<AffineSpace3fa> > CoronaLoader::loadInstances(const Ref<XML>& xml)
{
if (xml->name != "instance")
THROW_RUNTIME_ERROR(xml->loc.str()+": invalid instance node");
/* create default material */
Ref<SceneGraph::MaterialNode> material = new OBJMaterial;
avector<AffineSpace3fa> xfms;
for (size_t i=0; i<xml->children.size(); i++)
{
Ref<XML> child = xml->children[i];
if (child->name == "material" ) material = loadMaterial(child);
else if (child->name == "transform") xfms.push_back(load<AffineSpace3fa>(child));
else THROW_RUNTIME_ERROR(child->loc.str()+": unknown node: "+child->name);
}
return std::make_pair(material,xfms);
}
Ref<SceneGraph::Node> CoronaLoader::loadGroupNode(const Ref<XML>& xml)
{
if (xml->children.size() < 1)
THROW_RUNTIME_ERROR(xml->loc.str()+": invalid group node");
/* load instances */
auto p = loadInstances(xml->children[0]);
Ref<SceneGraph::MaterialNode> material = p.first;
avector<AffineSpace3fa>& xfms = p.second;
/* load meshes */
Ref<SceneGraph::GroupNode> objects = new SceneGraph::GroupNode;
for (size_t i=1; i<xml->children.size(); i++)
objects->add(loadObject(xml->children[i]));
/* force material */
objects->setMaterial(material);
/* create instances */
Ref<SceneGraph::GroupNode> instances = new SceneGraph::GroupNode;
for (size_t i=0; i<xfms.size(); i++)
instances->add(new SceneGraph::TransformNode(xfms[i],objects.cast<SceneGraph::Node>()));
return instances.cast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> CoronaLoader::loadNode(const Ref<XML>& xml)
{
if (xml->name == "conffile" ) return nullptr;
else if (xml->name == "mtllib" ) return loadMaterialLibrary(load<FileName>(xml));
else if (xml->name == "camera" ) return nullptr;
else if (xml->name == "environment" ) return nullptr;
else if (xml->name == "geometryGroup") return loadGroupNode(xml);
else if (xml->name == "renderElement") return nullptr;
else THROW_RUNTIME_ERROR(xml->loc.str()+": unknown tag: "+xml->name);
return nullptr;
}
Ref<SceneGraph::Node> CoronaLoader::load(const FileName& fileName, const AffineSpace3fa& space) {
CoronaLoader loader(fileName,space); return loader.root;
}
CoronaLoader::CoronaLoader(const FileName& fileName, const AffineSpace3fa& space)
{
path = fileName.path();
Ref<XML> xml = parseXML(fileName,"/.-",false);
if (xml->name == "scene")
{
Ref<SceneGraph::GroupNode> group = new SceneGraph::GroupNode;
for (size_t i=0; i<xml->children.size(); i++) {
group->add(loadNode(xml->children[i]));
}
root = group.cast<SceneGraph::Node>();
}
else
THROW_RUNTIME_ERROR(xml->loc.str()+": invalid scene tag");
if (space == AffineSpace3fa(one))
return;
root = new SceneGraph::TransformNode(space,root);
}
/*! read from disk */
Ref<SceneGraph::Node> SceneGraph::loadCorona(const FileName& fileName, const AffineSpace3fa& space) {
return CoronaLoader::load(fileName,space);
}
}

View file

@ -0,0 +1,14 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include "scenegraph.h"
namespace embree
{
namespace SceneGraph
{
Ref<SceneGraph::Node> loadCorona(const FileName& fileName, const AffineSpace3fa& space = one);
}
}

View file

@ -0,0 +1,693 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#include "geometry_creation.h"
namespace embree
{
Ref<SceneGraph::Node> SceneGraph::createTrianglePlane (const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy, size_t width, size_t height, Ref<MaterialNode> material)
{
Ref<SceneGraph::TriangleMeshNode> mesh = new SceneGraph::TriangleMeshNode(material,BBox1f(0,1),1);
mesh->positions[0].resize((width+1)*(height+1));
mesh->triangles.resize(2*width*height);
for (size_t y=0; y<=height; y++) {
for (size_t x=0; x<=width; x++) {
Vec3fa p = p0+float(x)/float(width)*dx+float(y)/float(height)*dy;
size_t i = y*(width+1)+x;
mesh->positions[0][i].x = p.x;
mesh->positions[0][i].y = p.y;
mesh->positions[0][i].z = p.z;
}
}
for (size_t y=0; y<height; y++) {
for (size_t x=0; x<width; x++) {
size_t i = 2*y*width+2*x;
size_t p00 = (y+0)*(width+1)+(x+0);
size_t p01 = (y+0)*(width+1)+(x+1);
size_t p10 = (y+1)*(width+1)+(x+0);
size_t p11 = (y+1)*(width+1)+(x+1);
mesh->triangles[i+0].v0 = unsigned(p00); mesh->triangles[i+0].v1 = unsigned(p01); mesh->triangles[i+0].v2 = unsigned(p10);
mesh->triangles[i+1].v0 = unsigned(p11); mesh->triangles[i+1].v1 = unsigned(p10); mesh->triangles[i+1].v2 = unsigned(p01);
}
}
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createQuadPlane (const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy, size_t width, size_t height, Ref<MaterialNode> material)
{
Ref<SceneGraph::QuadMeshNode> mesh = new SceneGraph::QuadMeshNode(material,BBox1f(0,1),1);
mesh->positions[0].resize((width+1)*(height+1));
mesh->quads.resize(width*height);
for (size_t y=0; y<=height; y++) {
for (size_t x=0; x<=width; x++) {
Vec3fa p = p0+float(x)/float(width)*dx+float(y)/float(height)*dy;
size_t i = y*(width+1)+x;
mesh->positions[0][i].x = p.x;
mesh->positions[0][i].y = p.y;
mesh->positions[0][i].z = p.z;
}
}
for (size_t y=0; y<height; y++) {
for (size_t x=0; x<width; x++) {
size_t i = y*width+x;
size_t p00 = (y+0)*(width+1)+(x+0);
size_t p01 = (y+0)*(width+1)+(x+1);
size_t p10 = (y+1)*(width+1)+(x+0);
size_t p11 = (y+1)*(width+1)+(x+1);
mesh->quads[i].v0 = unsigned(p00);
mesh->quads[i].v1 = unsigned(p01);
mesh->quads[i].v2 = unsigned(p11);
mesh->quads[i].v3 = unsigned(p10);
}
}
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createGridPlane (const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy, size_t width, size_t height, Ref<MaterialNode> material)
{
Ref<SceneGraph::GridMeshNode> mesh = new SceneGraph::GridMeshNode(material,BBox1f(0,1),1);
mesh->positions[0].resize((width+1)*(height+1));
mesh->grids.push_back(SceneGraph::GridMeshNode::Grid(0,(unsigned)width+1,(unsigned)width+1,(unsigned)height+1));
for (size_t y=0; y<=height; y++) {
for (size_t x=0; x<=width; x++) {
Vec3fa p = p0+float(x)/float(width)*dx+float(y)/float(height)*dy;
size_t i = y*(width+1)+x;
mesh->positions[0][i].x = p.x;
mesh->positions[0][i].y = p.y;
mesh->positions[0][i].z = p.z;
}
}
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createSubdivPlane (const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy, size_t width, size_t height, float tessellationRate, Ref<MaterialNode> material)
{
Ref<SceneGraph::SubdivMeshNode> mesh = new SceneGraph::SubdivMeshNode(material,BBox1f(0,1),1);
mesh->tessellationRate = tessellationRate;
mesh->positions[0].resize((width+1)*(height+1));
mesh->position_indices.resize(4*width*height);
mesh->verticesPerFace.resize(width*height);
for (size_t y=0; y<=height; y++) {
for (size_t x=0; x<=width; x++) {
Vec3fa p = p0+float(x)/float(width)*dx+float(y)/float(height)*dy;
size_t i = y*(width+1)+x;
mesh->positions[0][i].x = p.x;
mesh->positions[0][i].y = p.y;
mesh->positions[0][i].z = p.z;
}
}
for (size_t y=0; y<height; y++) {
for (size_t x=0; x<width; x++) {
size_t i = y*width+x;
size_t p00 = (y+0)*(width+1)+(x+0);
size_t p01 = (y+0)*(width+1)+(x+1);
size_t p10 = (y+1)*(width+1)+(x+0);
size_t p11 = (y+1)*(width+1)+(x+1);
mesh->position_indices[4*i+0] = unsigned(p00);
mesh->position_indices[4*i+1] = unsigned(p01);
mesh->position_indices[4*i+2] = unsigned(p11);
mesh->position_indices[4*i+3] = unsigned(p10);
mesh->verticesPerFace[i] = 4;
}
}
mesh->position_subdiv_mode = RTC_SUBDIVISION_MODE_PIN_CORNERS;
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createTriangleSphere (const Vec3fa& center, const float radius, size_t N, Ref<MaterialNode> material)
{
unsigned numPhi = unsigned(N);
unsigned numTheta = 2*numPhi;
unsigned numVertices = numTheta*(numPhi+1);
Ref<SceneGraph::TriangleMeshNode> mesh = new SceneGraph::TriangleMeshNode(material,BBox1f(0,1),1);
mesh->positions[0].resize(numVertices);
/* create sphere geometry */
const float rcpNumTheta = rcp(float(numTheta));
const float rcpNumPhi = rcp(float(numPhi));
for (unsigned int phi=0; phi<=numPhi; phi++)
{
for (unsigned int theta=0; theta<numTheta; theta++)
{
const float phif = phi*float(pi)*rcpNumPhi;
const float thetaf = theta*2.0f*float(pi)*rcpNumTheta;
mesh->positions[0][phi*numTheta+theta].x = center.x + radius*sin(phif)*sin(thetaf);
mesh->positions[0][phi*numTheta+theta].y = center.y + radius*cos(phif);
mesh->positions[0][phi*numTheta+theta].z = center.z + radius*sin(phif)*cos(thetaf);
}
if (phi == 0) continue;
if (phi == 1)
{
for (unsigned int theta=1; theta<=numTheta; theta++)
{
unsigned int p00 = numTheta-1;
unsigned int p10 = phi*numTheta+theta-1;
unsigned int p11 = phi*numTheta+theta%numTheta;
mesh->triangles.push_back(TriangleMeshNode::Triangle(p10,p00,p11));
}
}
else if (phi == numPhi)
{
for (unsigned int theta=1; theta<=numTheta; theta++)
{
unsigned int p00 = (phi-1)*numTheta+theta-1;
unsigned int p01 = (phi-1)*numTheta+theta%numTheta;
unsigned int p10 = numPhi*numTheta;
mesh->triangles.push_back(TriangleMeshNode::Triangle(p10,p00,p01));
}
}
else
{
for (unsigned int theta=1; theta<=numTheta; theta++)
{
unsigned int p00 = (phi-1)*numTheta+theta-1;
unsigned int p01 = (phi-1)*numTheta+theta%numTheta;
unsigned int p10 = phi*numTheta+theta-1;
unsigned int p11 = phi*numTheta+theta%numTheta;
mesh->triangles.push_back(TriangleMeshNode::Triangle(p10,p00,p11));
mesh->triangles.push_back(TriangleMeshNode::Triangle(p01,p11,p00));
}
}
}
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createQuadSphere (const Vec3fa& center, const float radius, size_t N, Ref<MaterialNode> material)
{
unsigned numPhi = unsigned(N);
unsigned numTheta = 2*numPhi;
unsigned numVertices = numTheta*(numPhi+1);
Ref<SceneGraph::QuadMeshNode> mesh = new SceneGraph::QuadMeshNode(material,BBox1f(0,1),1);
mesh->positions[0].resize(numVertices);
/* create sphere geometry */
const float rcpNumTheta = rcp(float(numTheta));
const float rcpNumPhi = rcp(float(numPhi));
for (unsigned int phi=0; phi<=numPhi; phi++)
{
for (unsigned int theta=0; theta<numTheta; theta++)
{
const float phif = phi*float(pi)*rcpNumPhi;
const float thetaf = theta*2.0f*float(pi)*rcpNumTheta;
mesh->positions[0][phi*numTheta+theta].x = center.x + radius*sin(phif)*sin(thetaf);
mesh->positions[0][phi*numTheta+theta].y = center.y + radius*cos(phif);
mesh->positions[0][phi*numTheta+theta].z = center.z + radius*sin(phif)*cos(thetaf);
}
if (phi == 0) continue;
if (phi == 1)
{
for (unsigned int theta=1; theta<=numTheta; theta++)
{
unsigned int p00 = numTheta-1;
unsigned int p10 = phi*numTheta+theta-1;
unsigned int p11 = phi*numTheta+theta%numTheta;
mesh->quads.push_back(QuadMeshNode::Quad(p10,p00,p11,p11));
}
}
else if (phi == numPhi)
{
for (unsigned int theta=1; theta<=numTheta; theta++)
{
unsigned int p00 = (phi-1)*numTheta+theta-1;
unsigned int p01 = (phi-1)*numTheta+theta%numTheta;
unsigned int p10 = numPhi*numTheta;
mesh->quads.push_back(QuadMeshNode::Quad(p10,p00,p01,p01));
}
}
else
{
for (unsigned int theta=1; theta<=numTheta; theta++)
{
unsigned int p00 = (phi-1)*numTheta+theta-1;
unsigned int p01 = (phi-1)*numTheta+theta%numTheta;
unsigned int p10 = phi*numTheta+theta-1;
unsigned int p11 = phi*numTheta+theta%numTheta;
mesh->quads.push_back(QuadMeshNode::Quad(p10,p00,p01,p11));
}
}
}
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createGridSphere (const Vec3fa& center, const float radius, size_t N, Ref<MaterialNode> material)
{
size_t grid_size = (N+1)*(N+1);
Ref<SceneGraph::GridMeshNode> mesh = new SceneGraph::GridMeshNode(material,BBox1f(0,1),1);
mesh->positions[0].resize(grid_size*6);
for (size_t i=0; i<6; i++)
{
mesh->grids.push_back(SceneGraph::GridMeshNode::Grid(unsigned(i*grid_size),unsigned(N+1),unsigned(N+1),unsigned(N+1)));
Vec3fa p0, dx, dy;
switch (i) {
case 0: p0 = Vec3fa(-0.5f,-0.5f,-0.5f); dx = Vec3fa(+1,0, 0); dy = Vec3fa(0,1,0); break;
case 1: p0 = Vec3fa(+0.5f,-0.5f,-0.5f); dx = Vec3fa( 0,0,+1); dy = Vec3fa(0,1,0); break;
case 2: p0 = Vec3fa(+0.5f,-0.5f,+0.5f); dx = Vec3fa(-1,0, 0); dy = Vec3fa(0,1,0); break;
case 3: p0 = Vec3fa(-0.5f,-0.5f,+0.5f); dx = Vec3fa( 0,0,-1); dy = Vec3fa(0,1,0); break;
case 4: p0 = Vec3fa(-0.5f,-0.5f,-0.5f); dx = Vec3fa( 0,0,+1); dy = Vec3fa(1,0,0); break;
case 5: p0 = Vec3fa(-0.5f,+0.5f,-0.5f); dx = Vec3fa( 1,0, 0); dy = Vec3fa(0,0,1); break;
default: assert(false);
}
for (size_t y=0; y<=N; y++) {
for (size_t x=0; x<=N; x++) {
size_t j = i*grid_size + y*(N+1) + x;
Vec3fa p = p0+float(x)/float(N)*dx+float(y)/float(N)*dy;
mesh->positions[0][j] = center + radius*normalize(p);
}
}
}
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createSubdivSphere (const Vec3fa& center, const float radius, size_t N, float tessellationRate, Ref<MaterialNode> material)
{
unsigned numPhi = unsigned(N);
unsigned numTheta = 2*numPhi;
unsigned numVertices = numTheta*(numPhi+1);
Ref<SceneGraph::SubdivMeshNode> mesh = new SceneGraph::SubdivMeshNode(material,BBox1f(0,1),1);
mesh->tessellationRate = tessellationRate;
mesh->positions[0].resize(numVertices);
/* create sphere geometry */
const float rcpNumTheta = rcp((float)numTheta);
const float rcpNumPhi = rcp((float)numPhi);
for (unsigned int phi=0; phi<=numPhi; phi++)
{
for (unsigned int theta=0; theta<numTheta; theta++)
{
const float phif = phi*float(pi)*rcpNumPhi;
const float thetaf = theta*2.0f*float(pi)*rcpNumTheta;
mesh->positions[0][phi*numTheta+theta].x = center.x + radius*sin(phif)*sin(thetaf);
mesh->positions[0][phi*numTheta+theta].y = center.y + radius*cos(phif);
mesh->positions[0][phi*numTheta+theta].z = center.z + radius*sin(phif)*cos(thetaf);
}
if (phi == 0) continue;
if (phi == 1)
{
for (unsigned int theta=1; theta<=numTheta; theta++)
{
unsigned int p00 = numTheta-1;
unsigned int p10 = phi*numTheta+theta-1;
unsigned int p11 = phi*numTheta+theta%numTheta;
mesh->verticesPerFace.push_back(3);
mesh->position_indices.push_back(p10);
mesh->position_indices.push_back(p00);
mesh->position_indices.push_back(p11);
}
}
else if (phi == numPhi)
{
for (unsigned int theta=1; theta<=numTheta; theta++)
{
unsigned int p00 = (phi-1)*numTheta+theta-1;
unsigned int p01 = (phi-1)*numTheta+theta%numTheta;
unsigned int p10 = numPhi*numTheta;
mesh->verticesPerFace.push_back(3);
mesh->position_indices.push_back(p10);
mesh->position_indices.push_back(p00);
mesh->position_indices.push_back(p01);
}
}
else
{
for (unsigned int theta=1; theta<=numTheta; theta++)
{
unsigned int p00 = (phi-1)*numTheta+theta-1;
unsigned int p01 = (phi-1)*numTheta+theta%numTheta;
unsigned int p10 = phi*numTheta+theta-1;
unsigned int p11 = phi*numTheta+theta%numTheta;
mesh->verticesPerFace.push_back(4);
mesh->position_indices.push_back(p10);
mesh->position_indices.push_back(p00);
mesh->position_indices.push_back(p01);
mesh->position_indices.push_back(p11);
}
}
}
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createSphereShapedHair(const Vec3fa& center, const float radius, Ref<MaterialNode> material)
{
Ref<SceneGraph::HairSetNode> mesh = new SceneGraph::HairSetNode(RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE,material,BBox1f(0,1),1);
mesh->hairs.push_back(SceneGraph::HairSetNode::Hair(0,0));
mesh->positions[0].push_back(Vec3ff(center+Vec3fa(-radius,0,0),radius));
mesh->positions[0].push_back(Vec3ff(center+Vec3fa(0,0,0),radius));
mesh->positions[0].push_back(Vec3ff(center+Vec3fa(0,0,0),radius));
mesh->positions[0].push_back(Vec3ff(center+Vec3fa(+radius,0,0),radius));
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createSphere (const Vec3fa& center, const float radius, Ref<MaterialNode> material)
{
RTCGeometryType type = RTC_GEOMETRY_TYPE_SPHERE_POINT;
Ref<SceneGraph::PointSetNode> mesh = new SceneGraph::PointSetNode(type, material, BBox1f(0,1), 1);
mesh->positions[0].resize(1);
mesh->positions[0][0].x = center.x;
mesh->positions[0][0].y = center.y;
mesh->positions[0][0].z = center.z;
mesh->positions[0][0].w = radius;
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createPointSphere (const Vec3fa& center, const float radius, const float pointRadius,
size_t N, PointSubtype subtype, Ref<MaterialNode> material)
{
unsigned numPhi = unsigned(N);
unsigned numTheta = 2 * numPhi;
unsigned numVertices = numTheta * (numPhi + 1);
RTCGeometryType type;
switch (subtype) {
case SPHERE:
type = RTC_GEOMETRY_TYPE_SPHERE_POINT;
break;
case DISC:
type = RTC_GEOMETRY_TYPE_DISC_POINT;
break;
case ORIENTED_DISC:
type = RTC_GEOMETRY_TYPE_ORIENTED_DISC_POINT;
break;
}
Ref<SceneGraph::PointSetNode> mesh = new SceneGraph::PointSetNode(type, material, BBox1f(0,1), 1);
mesh->positions[0].resize(numVertices);
if (subtype == ORIENTED_DISC) {
mesh->normals.push_back(avector<Vec3fa>());
mesh->normals[0].resize(numVertices);
}
/* create sphere geometry */
const float rcpNumTheta = rcp(float(numTheta));
const float rcpNumPhi = rcp(float(numPhi));
for (unsigned int phi = 0; phi <= numPhi; phi++)
{
for (unsigned int theta = 0; theta < numTheta; theta++)
{
const float phif = phi * float(pi) * rcpNumPhi;
const float thetaf = theta * 2.0f * float(pi) * rcpNumTheta;
mesh->positions[0][phi * numTheta + theta].x = center.x + radius * sin(phif) * sin(thetaf);
mesh->positions[0][phi * numTheta + theta].y = center.y + radius * cos(phif);
mesh->positions[0][phi * numTheta + theta].z = center.z + radius * sin(phif) * cos(thetaf);
mesh->positions[0][phi * numTheta + theta].w = pointRadius;
if (subtype == ORIENTED_DISC)
mesh->normals[0][phi * numTheta + theta] =
normalize(mesh->positions[0][phi * numTheta + theta] - center);
}
}
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createHairyPlane (int hash, const Vec3fa& pos, const Vec3fa& dx, const Vec3fa& dy, const float len, const float r, size_t numHairs, CurveSubtype subtype, Ref<MaterialNode> material)
{
RandomSampler sampler;
RandomSampler_init(sampler,hash);
RTCGeometryType type = (subtype == ROUND_CURVE) ? RTC_GEOMETRY_TYPE_ROUND_BEZIER_CURVE : RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE;
Ref<SceneGraph::HairSetNode> mesh = new SceneGraph::HairSetNode(type,material,BBox1f(0,1),1);
if (numHairs == 1) {
const Vec3fa p0 = pos;
const Vec3fa p1 = p0 + len*Vec3fa(1,0,0);
const Vec3fa p2 = p0 + len*Vec3fa(0,1,1);
const Vec3fa p3 = p0 + len*Vec3fa(0,1,0);
mesh->hairs.push_back(HairSetNode::Hair(0,0));
mesh->positions[0].push_back(Vec3ff(p0,r));
mesh->positions[0].push_back(Vec3ff(p1,r));
mesh->positions[0].push_back(Vec3ff(p2,r));
mesh->positions[0].push_back(Vec3ff(p3,r));
return mesh.dynamicCast<SceneGraph::Node>();
}
Vec3fa dz = cross(dx,dy);
for (size_t i=0; i<numHairs; i++)
{
const Vec3fa p0 = pos + RandomSampler_getFloat(sampler)*dx + RandomSampler_getFloat(sampler)*dy;
const Vec3fa p1 = p0 + len*normalize(dx);
const Vec3fa p2 = p0 + len*(normalize(dz)+normalize(dy));
const Vec3fa p3 = p0 + len*normalize(dz);
mesh->hairs.push_back(HairSetNode::Hair(unsigned(4*i),unsigned(i)));
mesh->positions[0].push_back(Vec3ff(p0,r));
mesh->positions[0].push_back(Vec3ff(p1,r));
mesh->positions[0].push_back(Vec3ff(p2,r));
mesh->positions[0].push_back(Vec3ff(p3,r));
}
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createGarbageTriangleMesh (int hash, size_t numTriangles, bool mblur, Ref<MaterialNode> material)
{
RandomSampler sampler;
RandomSampler_init(sampler,hash);
Ref<SceneGraph::TriangleMeshNode> mesh = new SceneGraph::TriangleMeshNode(material,BBox1f(0,1),mblur?2:1);
mesh->triangles.resize(numTriangles);
for (size_t i=0; i<numTriangles; i++) {
const unsigned v0 = (RandomSampler_getInt(sampler) % 32 == 0) ? RandomSampler_getUInt(sampler) : unsigned(3*i+0);
const unsigned v1 = (RandomSampler_getInt(sampler) % 32 == 0) ? RandomSampler_getUInt(sampler) : unsigned(3*i+1);
const unsigned v2 = (RandomSampler_getInt(sampler) % 32 == 0) ? RandomSampler_getUInt(sampler) : unsigned(3*i+2);
mesh->triangles[i] = TriangleMeshNode::Triangle(v0,v1,v2);
}
mesh->positions[0].resize(3*numTriangles);
for (size_t i=0; i<3*numTriangles; i++) {
const float x = cast_i2f(RandomSampler_getUInt(sampler));
const float y = cast_i2f(RandomSampler_getUInt(sampler));
const float z = cast_i2f(RandomSampler_getUInt(sampler));
const float w = cast_i2f(RandomSampler_getUInt(sampler));
mesh->positions[0][i] = Vec3ff(x,y,z,w);
}
if (mblur)
{
mesh->positions[1].resize(3*numTriangles);
for (size_t i=0; i<3*numTriangles; i++) {
const float x = cast_i2f(RandomSampler_getUInt(sampler));
const float y = cast_i2f(RandomSampler_getUInt(sampler));
const float z = cast_i2f(RandomSampler_getUInt(sampler));
const float w = cast_i2f(RandomSampler_getUInt(sampler));
mesh->positions[1][i] = Vec3ff(x,y,z,w);
}
}
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createGarbageQuadMesh (int hash, size_t numQuads, bool mblur, Ref<MaterialNode> material)
{
RandomSampler sampler;
RandomSampler_init(sampler,hash);
Ref<SceneGraph::QuadMeshNode> mesh = new SceneGraph::QuadMeshNode(material,BBox1f(0,1),mblur?2:1);
mesh->quads.resize(numQuads);
for (size_t i=0; i<numQuads; i++) {
const unsigned v0 = (RandomSampler_getInt(sampler) % 32 == 0) ? RandomSampler_getUInt(sampler) : unsigned(4*i+0);
const unsigned v1 = (RandomSampler_getInt(sampler) % 32 == 0) ? RandomSampler_getUInt(sampler) : unsigned(4*i+1);
const unsigned v2 = (RandomSampler_getInt(sampler) % 32 == 0) ? RandomSampler_getUInt(sampler) : unsigned(4*i+2);
const unsigned v3 = (RandomSampler_getInt(sampler) % 32 == 0) ? RandomSampler_getUInt(sampler) : unsigned(4*i+3);
mesh->quads[i] = QuadMeshNode::Quad(v0,v1,v2,v3);
}
mesh->positions[0].resize(4*numQuads);
for (size_t i=0; i<4*numQuads; i++) {
const float x = cast_i2f(RandomSampler_getUInt(sampler));
const float y = cast_i2f(RandomSampler_getUInt(sampler));
const float z = cast_i2f(RandomSampler_getUInt(sampler));
const float w = cast_i2f(RandomSampler_getUInt(sampler));
mesh->positions[0][i] = Vec3fa(Vec3ff(x,y,z,w));
}
if (mblur)
{
mesh->positions[1].resize(4*numQuads);
for (size_t i=0; i<4*numQuads; i++) {
const float x = cast_i2f(RandomSampler_getUInt(sampler));
const float y = cast_i2f(RandomSampler_getUInt(sampler));
const float z = cast_i2f(RandomSampler_getUInt(sampler));
const float w = cast_i2f(RandomSampler_getUInt(sampler));
mesh->positions[1][i] = Vec3fa(Vec3ff(x,y,z,w));
}
}
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createGarbageGridMesh (int hash, size_t numGrids, bool mblur, Ref<MaterialNode> material)
{
RandomSampler sampler;
RandomSampler_init(sampler,hash);
Ref<SceneGraph::GridMeshNode> mesh = new SceneGraph::GridMeshNode(material,BBox1f(0,1),mblur?2:1);
mesh->grids.resize(numGrids);
for (size_t i=0; i<numGrids; i++) {
const unsigned v0 = (RandomSampler_getInt(sampler) % 32 == 0) ? RandomSampler_getUInt(sampler) : unsigned(4*i+0);
mesh->grids[i] = GridMeshNode::Grid(v0,2,2,2);
}
mesh->positions[0].resize(4*numGrids);
for (size_t i=0; i<4*numGrids; i++) {
const float x = cast_i2f(RandomSampler_getUInt(sampler));
const float y = cast_i2f(RandomSampler_getUInt(sampler));
const float z = cast_i2f(RandomSampler_getUInt(sampler));
const float w = cast_i2f(RandomSampler_getUInt(sampler));
mesh->positions[0][i] = Vec3fa(Vec3ff(x,y,z,w));
}
if (mblur)
{
mesh->positions[1].resize(4*numGrids);
for (size_t i=0; i<4*numGrids; i++) {
const float x = cast_i2f(RandomSampler_getUInt(sampler));
const float y = cast_i2f(RandomSampler_getUInt(sampler));
const float z = cast_i2f(RandomSampler_getUInt(sampler));
const float w = cast_i2f(RandomSampler_getUInt(sampler));
mesh->positions[1][i] = Vec3fa(Vec3ff(x,y,z,w));
}
}
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createGarbageLineSegments (int hash, size_t numLineSegments, bool mblur, Ref<MaterialNode> material)
{
RandomSampler sampler;
RandomSampler_init(sampler,hash);
Ref<SceneGraph::HairSetNode> mesh = new SceneGraph::HairSetNode(RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE,material,BBox1f(0,1),mblur?2:1);
mesh->hairs.resize(numLineSegments);
for (size_t i=0; i<numLineSegments; i++) {
mesh->hairs[i].vertex = (RandomSampler_getInt(sampler) % 32 == 0) ? RandomSampler_getUInt(sampler) : unsigned(2*i);
mesh->hairs[i].id = 0;
}
mesh->positions[0].resize(2*numLineSegments);
for (size_t i=0; i<2*numLineSegments; i++) {
const float x = cast_i2f(RandomSampler_getUInt(sampler));
const float y = cast_i2f(RandomSampler_getUInt(sampler));
const float z = cast_i2f(RandomSampler_getUInt(sampler));
const float r = cast_i2f(RandomSampler_getUInt(sampler));
mesh->positions[0][i] = Vec3ff(x,y,z,r);
}
if (mblur)
{
mesh->positions[1].resize(2*numLineSegments);
for (size_t i=0; i<2*numLineSegments; i++) {
const float x = cast_i2f(RandomSampler_getUInt(sampler));
const float y = cast_i2f(RandomSampler_getUInt(sampler));
const float z = cast_i2f(RandomSampler_getUInt(sampler));
const float r = cast_i2f(RandomSampler_getUInt(sampler));
mesh->positions[1][i] = Vec3ff(x,y,z,r);
}
}
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createGarbageHair (int hash, size_t numHairs, bool mblur, Ref<MaterialNode> material)
{
RandomSampler sampler;
RandomSampler_init(sampler,hash);
Ref<SceneGraph::HairSetNode> mesh = new SceneGraph::HairSetNode(RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE,material,BBox1f(0,1),mblur?2:1);
mesh->hairs.resize(numHairs);
for (size_t i=0; i<numHairs; i++) {
const unsigned v0 = (RandomSampler_getInt(sampler) % 32 == 0) ? RandomSampler_getUInt(sampler) : unsigned(4*i);
mesh->hairs[i] = HairSetNode::Hair(v0,0);
}
mesh->positions[0].resize(4*numHairs);
for (size_t i=0; i<4*numHairs; i++) {
const float x = cast_i2f(RandomSampler_getUInt(sampler));
const float y = cast_i2f(RandomSampler_getUInt(sampler));
const float z = cast_i2f(RandomSampler_getUInt(sampler));
const float r = cast_i2f(RandomSampler_getUInt(sampler));
mesh->positions[0][i] = Vec3ff(x,y,z,r);
}
if (mblur)
{
mesh->positions[1].resize(4*numHairs);
for (size_t i=0; i<4*numHairs; i++) {
const float x = cast_i2f(RandomSampler_getUInt(sampler));
const float y = cast_i2f(RandomSampler_getUInt(sampler));
const float z = cast_i2f(RandomSampler_getUInt(sampler));
const float r = cast_i2f(RandomSampler_getUInt(sampler));
mesh->positions[1][i] = Vec3ff(x,y,z,r);
}
}
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createGarbageSubdivMesh (int hash, size_t numFaces, bool mblur, Ref<MaterialNode> material)
{
RandomSampler sampler;
RandomSampler_init(sampler,hash);
Ref<SceneGraph::SubdivMeshNode> mesh = new SceneGraph::SubdivMeshNode(material,BBox1f(0,1),mblur?2:1);
for (size_t i=0; i<numFaces; i++)
{
const unsigned f = RandomSampler_getInt(sampler) % 20;
mesh->verticesPerFace.push_back(f);
for (size_t j=0; j<f; j++)
{
mesh->position_indices.push_back((RandomSampler_getInt(sampler) % 32 == 0) ? RandomSampler_getUInt(sampler) : unsigned(mesh->numPositions()));
const float x = cast_i2f(RandomSampler_getUInt(sampler));
const float y = cast_i2f(RandomSampler_getUInt(sampler));
const float z = cast_i2f(RandomSampler_getUInt(sampler));
const float w = cast_i2f(RandomSampler_getUInt(sampler));
mesh->positions[0].push_back(Vec3fa(Vec3ff(x,y,z,w)));
if (mblur)
{
const float x = cast_i2f(RandomSampler_getUInt(sampler));
const float y = cast_i2f(RandomSampler_getUInt(sampler));
const float z = cast_i2f(RandomSampler_getUInt(sampler));
const float w = cast_i2f(RandomSampler_getUInt(sampler));
mesh->positions[1].push_back(Vec3fa(Vec3ff(x,y,z,w)));
}
}
}
return mesh.dynamicCast<SceneGraph::Node>();
}
Ref<SceneGraph::Node> SceneGraph::createGarbagePointSet(int hash, size_t numPoints, bool mblur, Ref<MaterialNode> material)
{
RandomSampler sampler;
RandomSampler_init(sampler,hash);
Ref<SceneGraph::PointSetNode> mesh = new SceneGraph::PointSetNode(RTC_GEOMETRY_TYPE_SPHERE_POINT, material,BBox1f(0,1),mblur?2:1);
for (size_t i = 0; i < numPoints; i++)
{
const float x = cast_i2f(RandomSampler_getUInt(sampler));
const float y = cast_i2f(RandomSampler_getUInt(sampler));
const float z = cast_i2f(RandomSampler_getUInt(sampler));
const float r = cast_i2f(RandomSampler_getUInt(sampler));
mesh->positions[0].push_back(Vec3ff(x, y, z, r));
if (mblur)
{
const float x = cast_i2f(RandomSampler_getUInt(sampler));
const float y = cast_i2f(RandomSampler_getUInt(sampler));
const float z = cast_i2f(RandomSampler_getUInt(sampler));
const float r = cast_i2f(RandomSampler_getUInt(sampler));
mesh->positions[1].push_back(Vec3ff(x, y, z, r));
}
}
return mesh.dynamicCast<SceneGraph::Node>();
}
}

View file

@ -0,0 +1,35 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include "scenegraph.h"
namespace embree
{
namespace SceneGraph
{
Ref<Node> createTrianglePlane (const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy, size_t width, size_t height, Ref<MaterialNode> material = nullptr);
Ref<Node> createQuadPlane (const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy, size_t width, size_t height, Ref<MaterialNode> material = nullptr);
Ref<Node> createGridPlane (const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy, size_t width, size_t height, Ref<MaterialNode> material = nullptr);
Ref<Node> createSubdivPlane (const Vec3fa& p0, const Vec3fa& dx, const Vec3fa& dy, size_t width, size_t height, float tessellationRate, Ref<MaterialNode> material = nullptr);
Ref<Node> createSphere (const Vec3fa& center, const float radius, Ref<MaterialNode> materiall = nullptr);
Ref<Node> createTriangleSphere(const Vec3fa& center, const float radius, size_t numPhi, Ref<MaterialNode> material = nullptr);
Ref<Node> createQuadSphere (const Vec3fa& center, const float radius, size_t numPhi, Ref<MaterialNode> material = nullptr);
Ref<Node> createGridSphere (const Vec3fa& center, const float radius, size_t size, Ref<MaterialNode> material = nullptr);
Ref<Node> createSubdivSphere (const Vec3fa& center, const float radius, size_t numPhi, float tessellationRate, Ref<MaterialNode> material = nullptr);
Ref<Node> createSphereShapedHair(const Vec3fa& center, const float radius, Ref<MaterialNode> material = nullptr);
Ref<Node> createPointSphere (const Vec3fa& center, const float radius, const float pointRadius, size_t numPhi, PointSubtype subtype, Ref<MaterialNode> materiall = nullptr);
Ref<Node> createHairyPlane (int hash, const Vec3fa& pos, const Vec3fa& dx, const Vec3fa& dy, const float len, const float r, size_t numHairs, CurveSubtype subtype, Ref<MaterialNode> material = nullptr);
Ref<Node> createGarbageTriangleMesh (int hash, size_t numTriangles, bool mblur, Ref<MaterialNode> material = nullptr);
Ref<Node> createGarbageQuadMesh (int hash, size_t numQuads, bool mblur, Ref<MaterialNode> material = nullptr);
Ref<Node> createGarbageGridMesh (int hash, size_t numGrids, bool mblur, Ref<MaterialNode> material = nullptr);
Ref<Node> createGarbageHair (int hash, size_t numHairs, bool mblur, Ref<MaterialNode> material = nullptr);
Ref<Node> createGarbageLineSegments (int hash, size_t numLineSegments, bool mblur, Ref<MaterialNode> material = nullptr);
Ref<Node> createGarbageSubdivMesh (int hash, size_t numFaces, bool mblur, Ref<MaterialNode> material = nullptr);
Ref<Node> createGarbagePointSet(int hash, size_t numPoints, bool mblur, Ref<MaterialNode> material = nullptr);
}
}

View file

@ -0,0 +1,199 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include "../default.h"
namespace embree
{
namespace SceneGraph
{
enum LightType
{
LIGHT_AMBIENT,
LIGHT_POINT,
LIGHT_DIRECTIONAL,
LIGHT_SPOT,
LIGHT_DISTANT,
LIGHT_TRIANGLE,
LIGHT_QUAD,
};
class Light
{
ALIGNED_CLASS_(16)
public:
Light(LightType type) : type(type) {}
LightType getType() const { return type; }
private:
LightType type;
};
class AmbientLight : public Light
{
public:
AmbientLight (const Vec3fa& L)
: Light(LIGHT_AMBIENT), L(L) {}
AmbientLight transform(const AffineSpace3fa& space) const {
return AmbientLight(L);
}
static AmbientLight lerp(const AmbientLight& light0, const AmbientLight& light1, const float f) {
return AmbientLight(embree::lerp(light0.L,light1.L,f));
}
public:
Vec3fa L; //!< radiance of ambient light
};
class PointLight : public Light
{
public:
PointLight (const Vec3fa& P, const Vec3fa& I)
: Light(LIGHT_POINT), P(P), I(I) {}
PointLight transform(const AffineSpace3fa& space) const {
return PointLight(xfmPoint(space,P),I);
}
static PointLight lerp(const PointLight& light0, const PointLight& light1, const float f)
{
return PointLight(embree::lerp(light0.P,light1.P,f),
embree::lerp(light0.I,light1.I,f));
}
public:
Vec3fa P; //!< position of point light
Vec3fa I; //!< radiant intensity of point light
};
class DirectionalLight : public Light
{
public:
DirectionalLight (const Vec3fa& D, const Vec3fa& E)
: Light(LIGHT_DIRECTIONAL), D(D), E(E) {}
DirectionalLight transform(const AffineSpace3fa& space) const {
return DirectionalLight(xfmVector(space,D),E);
}
static DirectionalLight lerp(const DirectionalLight& light0, const DirectionalLight& light1, const float f)
{
return DirectionalLight(embree::lerp(light0.D,light1.D,f),
embree::lerp(light0.E,light1.E,f));
}
public:
Vec3fa D; //!< Light direction
Vec3fa E; //!< Irradiance (W/m^2)
};
class SpotLight : public Light
{
public:
SpotLight (const Vec3fa& P, const Vec3fa& D, const Vec3fa& I, float angleMin, float angleMax)
: Light(LIGHT_SPOT), P(P), D(D), I(I), angleMin(angleMin), angleMax(angleMax) {}
SpotLight transform(const AffineSpace3fa& space) const {
return SpotLight(xfmPoint(space,P),xfmVector(space,D),I,angleMin,angleMax);
}
static SpotLight lerp(const SpotLight& light0, const SpotLight& light1, const float f)
{
return SpotLight(embree::lerp(light0.P,light1.P,f),
embree::lerp(light0.D,light1.D,f),
embree::lerp(light0.I,light1.I,f),
embree::lerp(light0.angleMin,light1.angleMin,f),
embree::lerp(light0.angleMax,light1.angleMax,f));
}
public:
Vec3fa P; //!< Position of the spot light
Vec3fa D; //!< Light direction of the spot light
Vec3fa I; //!< Radiant intensity (W/sr)
float angleMin, angleMax; //!< Linear falloff region
};
class DistantLight : public Light
{
public:
DistantLight (const Vec3fa& D, const Vec3fa& L, const float halfAngle)
: Light(LIGHT_DISTANT), D(D), L(L), halfAngle(halfAngle), radHalfAngle(deg2rad(halfAngle)), cosHalfAngle(cos(deg2rad(halfAngle))) {}
DistantLight transform(const AffineSpace3fa& space) const {
return DistantLight(xfmVector(space,D),L,halfAngle);
}
static DistantLight lerp(const DistantLight& light0, const DistantLight& light1, const float f)
{
return DistantLight(embree::lerp(light0.D,light1.D,f),
embree::lerp(light0.L,light1.L,f),
embree::lerp(light0.halfAngle,light1.halfAngle,f));
}
public:
Vec3fa D; //!< Light direction
Vec3fa L; //!< Radiance (W/(m^2*sr))
float halfAngle; //!< Half illumination angle
float radHalfAngle; //!< Half illumination angle in radians
float cosHalfAngle; //!< Cosine of half illumination angle
};
class TriangleLight : public Light
{
public:
TriangleLight (const Vec3fa& v0, const Vec3fa& v1, const Vec3fa& v2, const Vec3fa& L)
: Light(LIGHT_TRIANGLE), v0(v0), v1(v1), v2(v2), L(L) {}
TriangleLight transform(const AffineSpace3fa& space) const {
return TriangleLight(xfmPoint(space,v0),xfmPoint(space,v1),xfmPoint(space,v2),L);
}
static TriangleLight lerp(const TriangleLight& light0, const TriangleLight& light1, const float f)
{
return TriangleLight(embree::lerp(light0.v0,light1.v0,f),
embree::lerp(light0.v1,light1.v1,f),
embree::lerp(light0.v2,light1.v2,f),
embree::lerp(light0.L,light1.L,f));
}
public:
Vec3fa v0;
Vec3fa v1;
Vec3fa v2;
Vec3fa L;
};
class QuadLight : public Light
{
public:
QuadLight (const Vec3fa& v0, const Vec3fa& v1, const Vec3fa& v2, const Vec3fa& v3, const Vec3fa& L)
: Light(LIGHT_QUAD), v0(v0), v1(v1), v2(v2), v3(v3), L(L) {}
QuadLight transform(const AffineSpace3fa& space) const {
return QuadLight(xfmPoint(space,v0),xfmPoint(space,v1),xfmPoint(space,v2),xfmPoint(space,v3),L);
}
static QuadLight lerp(const QuadLight& light0, const QuadLight& light1, const float f)
{
return QuadLight(embree::lerp(light0.v0,light1.v0,f),
embree::lerp(light0.v1,light1.v1,f),
embree::lerp(light0.v2,light1.v2,f),
embree::lerp(light0.v3,light1.v3,f),
embree::lerp(light0.L,light1.L,f));
}
public:
Vec3fa v0;
Vec3fa v1;
Vec3fa v2;
Vec3fa v3;
Vec3fa L;
};
}
}

View file

@ -0,0 +1,260 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#if defined (CPPTUTORIAL) && !defined(_MATERIALS_H_CPPTUTORIAL) || !defined(_MATERIALS_H_)
#if defined (CPPTUTORIAL)
#define _MATERIALS_H_CPPTUTORIAL
#else
#define _MATERIALS_H_
#endif
//#pragma once
#if !defined(ISPC)
#include "texture.h"
#include "scenegraph.h"
#endif
#if !defined(ISPC)
namespace embree
{
#endif
#if defined(ISPC) || defined(CPPTUTORIAL)
#define MATERIAL_BASE_CLASS
#define PREFIX(x) ISPC##x
#else
#define MATERIAL_BASE_CLASS : public SceneGraph::MaterialNode
#define PREFIX(x) x
#endif
#if !defined(CPPTUTORIAL)
enum MaterialType
{
MATERIAL_OBJ,
MATERIAL_THIN_DIELECTRIC,
MATERIAL_METAL,
MATERIAL_VELVET,
MATERIAL_DIELECTRIC,
MATERIAL_METALLIC_PAINT,
MATERIAL_MATTE,
MATERIAL_MIRROR,
MATERIAL_REFLECTIVE_METAL,
MATERIAL_HAIR
};
#endif
struct PREFIX(Material)
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
Material (MaterialType type)
: type(type) {}
#endif
#if !defined(ISPC)
__aligned(16)
#endif
int type;
int align[3];
};
struct PREFIX(MatteMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
MatteMaterial (const Vec3fa& reflectance)
: base(MATERIAL_MATTE), reflectance(reflectance) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa reflectance;
};
struct PREFIX(MirrorMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
MirrorMaterial (const Vec3fa& reflectance)
: base(MATERIAL_MIRROR), reflectance(reflectance) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa reflectance;
};
struct PREFIX(ThinDielectricMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
ThinDielectricMaterial (const Vec3fa& transmission, const float eta, const float thickness)
: base(MATERIAL_THIN_DIELECTRIC), transmission(transmission), transmissionFactor(log(transmission)*thickness), eta(eta), thickness(thickness) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa transmission;
Vec3fa transmissionFactor;
float eta;
float thickness;
};
struct PREFIX(OBJMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
OBJMaterial (const std::string name = "")
: SceneGraph::MaterialNode(name), base(MATERIAL_OBJ), illum(0), d(1.f), Ns(1.f), Ni(1.f), Ka(0.f), Kd(1.f), Ks(0.f), Kt(1.0f),
map_d(nullptr), map_Ka(nullptr), map_Kd(nullptr), map_Ks(nullptr), map_Kt(nullptr), map_Ns(nullptr), map_Displ(nullptr) {}
OBJMaterial (float d, const Vec3fa& Kd, const Vec3fa& Ks, const float Ns, const std::string name = "")
: base(MATERIAL_OBJ), illum(0), d(d), Ns(Ns), Ni(1.f), Ka(0.f), Kd(Kd), Ks(Ks), Kt(1.0f),
map_d(nullptr), map_Ka(nullptr), map_Kd(nullptr), map_Ks(nullptr), map_Kt(nullptr), map_Ns(nullptr), map_Displ(nullptr) {}
OBJMaterial (float d, const std::shared_ptr<Texture> map_d,
const Vec3fa& Ka, const std::shared_ptr<Texture> map_Ka,
const Vec3fa& Kd, const std::shared_ptr<Texture> map_Kd,
const Vec3fa& Ks, const std::shared_ptr<Texture> map_Ks,
const Vec3fa& Kt, const std::shared_ptr<Texture> map_Kt,
const float Ns, const std::shared_ptr<Texture> map_Ns,
const std::shared_ptr<Texture> map_Displ)
: base(MATERIAL_OBJ), illum(0), d(d), Ns(Ns), Ni(1.f), Ka(Ka), Kd(Kd), Ks(Ks), Kt(Kt),
map_d(nullptr), map_Ka(nullptr), map_Kd(nullptr), map_Ks(nullptr), map_Kt(nullptr), map_Ns(nullptr), map_Displ(nullptr),
_map_d(map_d), _map_Ka(map_Ka), _map_Kd(map_Kd), _map_Ks(map_Ks), _map_Kt(map_Kt), _map_Ns(map_Ns), _map_Displ(map_Displ) {}
virtual Material* material()
{
map_d = _map_d.get();
map_Ka = _map_Ka.get();
map_Kd = _map_Kd.get();
map_Ks = _map_Ks.get();
map_Kt = _map_Kt.get();
map_Ns = _map_Ns.get();
map_Displ = _map_Displ.get();
return &base;
}
~OBJMaterial() { // FIXME: destructor never called
}
#endif
PREFIX(Material) base;
int illum; /*< illumination model */
float d; /*< dissolve factor, 1=opaque, 0=transparent */
float Ns; /*< specular exponent */
float Ni; /*< optical density for the surface (index of refraction) */
Vec3fa Ka; /*< ambient reflectivity */
Vec3fa Kd; /*< diffuse reflectivity */
Vec3fa Ks; /*< specular reflectivity */
Vec3fa Kt; /*< transmission filter */
const Texture* map_d; /*< d texture */
const Texture* map_Ka; /*< Ka texture */
const Texture* map_Kd; /*< Kd texture */
const Texture* map_Ks; /*< Ks texture */
const Texture* map_Kt; /*< Kt texture */
const Texture* map_Ns; /*< Ns texture */
const Texture* map_Displ; /*< Displ texture */
#if !defined(ISPC) && !defined(CPPTUTORIAL)
std::shared_ptr<Texture> _map_d; /*< d texture */
std::shared_ptr<Texture> _map_Ka; /*< Ka texture */
std::shared_ptr<Texture> _map_Kd; /*< Kd texture */
std::shared_ptr<Texture> _map_Ks; /*< Ks texture */
std::shared_ptr<Texture> _map_Kt; /*< Kt texture */
std::shared_ptr<Texture> _map_Ns; /*< Ns texture */
std::shared_ptr<Texture> _map_Displ; /*< Displ texture */
#endif
};
struct PREFIX(MetalMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
MetalMaterial (const Vec3fa& reflectance, const Vec3fa& eta, const Vec3fa& k)
: base(MATERIAL_REFLECTIVE_METAL), reflectance(reflectance), eta(eta), k(k), roughness(0.0f) {}
MetalMaterial (const Vec3fa& reflectance, const Vec3fa& eta, const Vec3fa& k, const float roughness)
: base(MATERIAL_METAL), reflectance(reflectance), eta(eta), k(k), roughness(roughness) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa reflectance;
Vec3fa eta;
Vec3fa k;
float roughness;
};
typedef PREFIX(MetalMaterial) PREFIX(ReflectiveMetalMaterial);
struct PREFIX(VelvetMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
VelvetMaterial (const Vec3fa& reflectance, const float backScattering, const Vec3fa& horizonScatteringColor, const float horizonScatteringFallOff)
: base(MATERIAL_VELVET), reflectance(reflectance), horizonScatteringColor(horizonScatteringColor), backScattering(backScattering), horizonScatteringFallOff(horizonScatteringFallOff) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa reflectance;
Vec3fa horizonScatteringColor;
float backScattering;
float horizonScatteringFallOff;
};
struct PREFIX(DielectricMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
DielectricMaterial (const Vec3fa& transmissionOutside, const Vec3fa& transmissionInside, const float etaOutside, const float etaInside)
: base(MATERIAL_DIELECTRIC), transmissionOutside(transmissionOutside), transmissionInside(transmissionInside), etaOutside(etaOutside), etaInside(etaInside) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa transmissionOutside;
Vec3fa transmissionInside;
float etaOutside;
float etaInside;
};
struct PREFIX(MetallicPaintMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
MetallicPaintMaterial (const Vec3fa& shadeColor, const Vec3fa& glitterColor, float glitterSpread, float eta)
: base(MATERIAL_METALLIC_PAINT), shadeColor(shadeColor), glitterColor(glitterColor), glitterSpread(glitterSpread), eta(eta) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa shadeColor;
Vec3fa glitterColor;
float glitterSpread;
float eta;
};
struct PREFIX(HairMaterial) MATERIAL_BASE_CLASS
{
#if !defined(ISPC) && !defined(CPPTUTORIAL)
HairMaterial (const Vec3fa& Kr, const Vec3fa& Kt, float nx, float ny)
: base(MATERIAL_HAIR), Kr(Kr), Kt(Kt), nx(nx), ny(ny) {}
virtual Material* material() { return &base; }
#endif
PREFIX(Material) base;
Vec3fa Kr;
Vec3fa Kt;
float nx;
float ny;
};
#undef MATERIAL_BASE_CLASS
#undef PREFIX
#if !defined(ISPC)
}
#endif
#endif

View file

@ -0,0 +1,652 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#include "obj_loader.h"
#include "texture.h"
namespace embree
{
/*! Three-index vertex, indexing start at 0, -1 means invalid vertex. */
struct Vertex {
unsigned int v, vt, vn;
Vertex() {};
Vertex(unsigned int v) : v(v), vt(v), vn(v) {};
Vertex(unsigned int v, unsigned int vt, unsigned int vn) : v(v), vt(vt), vn(vn) {};
};
struct Crease {
float w;
unsigned int a, b;
Crease() : w(0), a(-1), b(-1) {};
Crease(float w, unsigned int a, unsigned int b) : w(w), a(a), b(b) {};
};
static inline bool operator < ( const Vertex& a, const Vertex& b ) {
if (a.v != b.v) return a.v < b.v;
if (a.vn != b.vn) return a.vn < b.vn;
if (a.vt != b.vt) return a.vt < b.vt;
return false;
}
/*! Fill space at the end of the token with 0s. */
static inline const char* trimEnd(const char* token)
{
if (*token == 0) return token;
char* pe = (char*) token;
while (*pe) pe++;
pe--;
while ((*pe == ' ' || *pe == '\t' || *pe == '\r') && pe >= token) *pe-- = 0;
return token;
}
/*! Determine if character is a separator. */
static inline bool isSep(const char c) {
return (c == ' ') || (c == '\t');
}
/*! Parse separator. */
static inline const char* parseSep(const char*& token) {
size_t sep = strspn(token, " \t");
if (!sep) THROW_RUNTIME_ERROR("separator expected");
return token+=sep;
}
/*! Parse optional separator. */
static inline const char* parseSepOpt(const char*& token) {
return token+=strspn(token, " \t");
}
/*! Read float from a string. */
static inline float getFloat(const char*& token) {
token += strspn(token, " \t");
float n = (float)atof(token);
token += strcspn(token, " \t\r");
return n;
}
/*! Read int from a string. */
static inline int getInt(const char*& token) {
token += strspn(token, " \t");
int n = atoi(token);
token += strcspn(token, " \t\r");
return n;
}
/*! Read Vec2f from a string. */
static inline Vec2f getVec2f(const char*& token) {
float x = getFloat(token);
float y = getFloat(token);
return Vec2f(x,y);
}
/*! Read Vec3f from a string. */
static inline Vec3f getVec3f(const char*& token) {
float x = getFloat(token);
token += strspn(token, " \t");
if (*token == 0) return Vec3f(x);
float y = getFloat(token);
float z = getFloat(token);
return Vec3f(x,y,z);
}
/*! Read Vec3fa from a string. */
static inline Vec3fa getVec3fa(const char*& token) {
float x = getFloat(token);
token += strspn(token, " \t");
if (*token == 0) return Vec3f(x);
float y = getFloat(token);
float z = getFloat(token);
return Vec3fa(x,y,z);
}
class OBJLoader
{
public:
/*! Constructor. */
OBJLoader(const FileName& fileName, const bool subdivMode, const bool combineIntoSingleObject);
/*! output model */
Ref<SceneGraph::GroupNode> group;
private:
/*! file to load */
FileName path;
/*! load only quads and ignore triangles */
bool subdivMode;
/*! Geometry buffer. */
avector<Vec3fa> v;
avector<Vec3fa> vn;
std::vector<Vec2f> vt;
std::vector<Crease> ec;
std::vector<std::vector<Vertex> > curGroup;
std::vector<avector<Vec3ff> > curGroupHair;
/*! Material handling. */
std::string curMaterialName;
Ref<SceneGraph::MaterialNode> curMaterial;
std::map<std::string, Ref<SceneGraph::MaterialNode> > material;
std::map<std::string, std::shared_ptr<Texture>> textureMap;
private:
void loadMTL(const FileName& fileName);
unsigned int fix_v (int index);
unsigned int fix_vt(int index);
unsigned int fix_vn(int index);
void flushFaceGroup();
void flushTriGroup();
void flushHairGroup();
Vertex getUInt3(const char*& token);
uint32_t getVertex(std::map<Vertex,uint32_t>& vertexMap, Ref<SceneGraph::TriangleMeshNode> mesh, const Vertex& i);
std::shared_ptr<Texture> loadTexture(const FileName& fname);
};
OBJLoader::OBJLoader(const FileName &fileName, const bool subdivMode, const bool combineIntoSingleObject)
: group(new SceneGraph::GroupNode), path(fileName.path()), subdivMode(subdivMode)
{
/* open file */
std::ifstream cin;
cin.open(fileName.c_str());
if (!cin.is_open()) {
THROW_RUNTIME_ERROR("cannot open " + fileName.str());
return;
}
/* generate default material */
Ref<SceneGraph::MaterialNode> defaultMaterial = new OBJMaterial("default");
curMaterialName = "default";
curMaterial = defaultMaterial;
while (cin.peek() != -1)
{
/* load next multiline */
std::string line; std::getline(cin,line);
while (!line.empty() && line[line.size()-1] == '\\') {
line[line.size()-1] = ' ';
std::string next_line; std::getline(cin,next_line);
if (next_line.empty()) break;
line += next_line;
}
const char* token = trimEnd(line.c_str() + strspn(line.c_str(), " \t"));
if (token[0] == 0) continue;
/*! parse position */
if (token[0] == 'v' && isSep(token[1])) {
v.push_back(getVec3f(token += 2)); continue;
}
/* parse normal */
if (token[0] == 'v' && token[1] == 'n' && isSep(token[2])) {
vn.push_back(getVec3f(token += 3));
continue;
}
/* parse texcoord */
if (token[0] == 'v' && token[1] == 't' && isSep(token[2])) { vt.push_back(getVec2f(token += 3)); continue; }
/*! parse face */
if (token[0] == 'f' && isSep(token[1]))
{
parseSep(token += 1);
std::vector<Vertex> face;
while (token[0]) {
Vertex vtx = getUInt3(token);
face.push_back(vtx);
parseSepOpt(token);
}
curGroup.push_back(face);
continue;
}
/*! parse corona hair */
if (!strncmp(token,"hair",4) && isSep(token[4]))
{
parseSep(token += 4);
bool plane = !strncmp(token,"plane",5) && isSep(token[5]);
if (plane) {
parseSep(token += 5);
}
else if (!strncmp(token,"cylinder",8) && isSep(token[8])) {
parseSep(token += 8);
}
else continue;
unsigned int N = getInt(token);
avector<Vec3ff> hair;
for (unsigned int i=0; i<3*N+1; i++) {
hair.push_back((Vec3ff)getVec3fa(token));
}
for (unsigned int i=0; i<N+1; i++)
{
float r = getFloat(token);
MAYBE_UNUSED float t = (float)getInt(token);
if (i != 0) hair[3*i-1].w = r;
hair[3*i+0].w = r;
if (i != N) hair[3*i+1].w = r;
}
curGroupHair.push_back(hair);
}
/*! parse edge crease */
if (token[0] == 'e' && token[1] == 'c' && isSep(token[2]))
{
parseSep(token += 2);
float w = getFloat(token);
parseSepOpt(token);
unsigned int a = fix_v(getInt(token));
parseSepOpt(token);
unsigned int b = fix_v(getInt(token));
parseSepOpt(token);
ec.push_back(Crease(w, a, b));
continue;
}
/*! use material */
if (!strncmp(token, "usemtl", 6) && isSep(token[6]))
{
if (!combineIntoSingleObject) flushFaceGroup();
std::string name(parseSep(token += 6));
if (material.find(name) == material.end()) {
curMaterial = defaultMaterial;
curMaterialName = "default";
}
else {
curMaterial = material[name];
curMaterialName = name;
}
continue;
}
/* load material library */
if (!strncmp(token, "mtllib", 6) && isSep(token[6])) {
loadMTL(path + std::string(parseSep(token += 6)));
continue;
}
// ignore unknown stuff
}
flushFaceGroup();
cin.close();
}
struct ExtObjMaterial
{
public:
enum Type { NONE, MATTE, GLASS, METAL, METALLIC_PAINT };
Ref<SceneGraph::MaterialNode> select() const
{
std::shared_ptr<Texture> nulltex;
if (type == NONE) {
return new OBJMaterial(d,map_d,Ka,map_Ka,Kd,map_Kd,Ks,map_Ks,Kt,map_Kt,Ns,map_Ns,map_Displ);
} else if (type == MATTE) {
if (coat_eta != 1.0f) return new MetallicPaintMaterial (Kd,zero,0.0f,eta.x);
else return new OBJMaterial(1.0f,nulltex,zero,nulltex,Kd,map_Kd,Ks,nulltex,zero,nulltex,1.0f/(1E-6f+roughness),nulltex,nulltex);
} else if (type == GLASS) {
return new ThinDielectricMaterial(Vec3fa(1.0f),eta.x,0.1f);
} else if (type == METAL) {
if (roughness == 0.0f) {
if (eta == Vec3fa(1.0f) && k == Vec3fa(0.0f)) return new MirrorMaterial(Kd);
else return new MetalMaterial(Kd,eta,k);
}
else return new MetalMaterial(Kd,eta,k,roughness);
} else if (type == METALLIC_PAINT) {
return new MetallicPaintMaterial (Kd,Ks,0.0f,coat_eta);
}
return new MatteMaterial(Vec3fa(0.5f));
}
public:
Type type = NONE;
int illum = 0; /*< illumination model */
float d = 1.0f; /*< dissolve factor, 1=opaque, 0=transparent */
float Ns = 1.0f; /*< specular exponent */
float Ni = 1.0f; /*< optical density for the surface (index of refraction) */
Vec3fa Ka = zero; /*< ambient reflectivity */
Vec3fa Kd = one; /*< diffuse reflectivity */
Vec3fa Ks = zero; /*< specular reflectivity */
Vec3fa Kt = zero; /*< transmission filter */
std::shared_ptr<Texture> map_d; /*< d texture */
std::shared_ptr<Texture> map_Ka; /*< Ka texture */
std::shared_ptr<Texture> map_Kd; /*< Kd texture */
std::shared_ptr<Texture> map_Ks; /*< Ks texture */
std::shared_ptr<Texture> map_Kt; /*< Kt texture */
std::shared_ptr<Texture> map_Ns; /*< Ns texture */
std::shared_ptr<Texture> map_Displ; /*< Displ texture */
float roughness = zero;
std::shared_ptr<Texture> roughnessMap;
float coat_eta = one;
float coat_roughness = zero;
std::shared_ptr<Texture> coat_roughnessMap;
float bump = zero;
Vec3f eta = Vec3f(1.4f);
Vec3f k = Vec3f(3.0f);
};
std::shared_ptr<Texture> OBJLoader::loadTexture(const FileName& fname)
{
if (textureMap.find(fname.str()) != textureMap.end())
return textureMap[fname.str()];
return std::shared_ptr<Texture>(Texture::load(path+fname));
}
/* load material file */
void OBJLoader::loadMTL(const FileName &fileName)
{
std::ifstream cin;
cin.open(fileName.c_str());
if (!cin.is_open()) {
std::cerr << "cannot open " << fileName.str() << std::endl;
return;
}
std::string name;
ExtObjMaterial cur;
while (cin.peek() != -1)
{
/* load next multiline */
std::string line; std::getline(cin,line);
while (!line.empty() && line[line.size()-1] == '\\') {
line[line.size()-1] = ' ';
std::string next_line; std::getline(cin,next_line);
if (next_line.empty()) break;
line += next_line;
}
const char* token = trimEnd(line.c_str() + strspn(line.c_str(), " \t"));
if (token[0] == 0 ) continue; // ignore empty lines
if (token[0] == '#') continue; // ignore comments
if (!strncmp(token, "newmtl", 6))
{
if (name != "") {
material[name] = cur.select();
material[name]->name = name;
}
parseSep(token+=6);
name = token;
cur = ExtObjMaterial();
continue;
}
if (name == "") THROW_RUNTIME_ERROR("invalid material file: newmtl expected first");
try
{
if (!strncmp(token, "illum", 5)) { parseSep(token += 5); continue; }
if (!strncmp(token, "d", 1)) { parseSep(token += 1); cur.d = getFloat(token); continue; }
if (!strncmp(token, "Ns", 2)) { parseSep(token += 2); cur.Ns = getFloat(token); continue; }
if (!strncmp(token, "Ni", 2)) { parseSep(token += 2); cur.Ni = getFloat(token); continue; }
if (!strncmp(token, "map_d", 5) || !strncmp(token, "d_map", 5)) {
parseSep(token += 5);
cur.map_d = loadTexture(FileName(token));
continue;
}
if (!strncmp(token, "map_Ka", 6) || !strncmp(token, "Ka_map", 6)) {
parseSep(token += 6);
cur.map_Ka = loadTexture(FileName(token));
continue;
}
if (!strncmp(token, "map_Kd", 6) || !strncmp(token, "Kd_map", 6)) {
parseSep(token += 6);
cur.map_Kd = loadTexture(FileName(token));
continue;
}
if (!strncmp(token, "map_Ks", 6) || !strncmp(token, "Ks_map", 6)) {
parseSep(token += 6);
cur.map_Ks = loadTexture(FileName(token));
continue;
}
if (!strncmp(token, "map_Kt", 6) || !strncmp(token, "Kt_map", 6)) {
parseSep(token += 6);
cur.map_Kt = loadTexture(FileName(token));
continue;
}
if (!strncmp(token, "map_Tf", 6) || !strncmp(token, "Tf_map", 6)) {
parseSep(token += 6);
cur.map_Kt = loadTexture(FileName(token));
continue;
}
if (!strncmp(token, "map_Ns", 6) || !strncmp(token, "Ns_map", 6)) {
parseSep(token += 6);
cur.map_Ns = loadTexture(FileName(token));
continue;
}
if (!strncmp(token, "map_Displ", 9) || !strncmp(token, "Displ_map", 9)) {
parseSep(token += 9);
cur.map_Displ = loadTexture(FileName(token));
continue;
}
if (!strncmp(token, "Ka", 2)) { parseSep(token += 2); cur.Ka = getVec3f(token); continue; }
if (!strncmp(token, "Kd", 2)) { parseSep(token += 2); cur.Kd = getVec3f(token); continue; }
if (!strncmp(token, "Ks", 2)) { parseSep(token += 2); cur.Ks = getVec3f(token); continue; }
if (!strncmp(token, "Kt", 2)) { parseSep(token += 2); cur.Kt = getVec3f(token); continue; }
if (!strncmp(token, "Tf", 2)) { parseSep(token += 2); cur.Kt = getVec3f(token); continue; }
/* extended OBJ */
if (!strncmp(token, "type", 4)) {
parseSep(token += 4); std::string type = token;
if (type == "matte") cur.type = ExtObjMaterial::MATTE;
else if (type == "glass") cur.type = ExtObjMaterial::GLASS;
else if (type == "metal") cur.type = ExtObjMaterial::METAL;
else if (type == "metallicPaint") cur.type = ExtObjMaterial::METALLIC_PAINT;
else if (type == "principled") cur.type = ExtObjMaterial::NONE;
else if (type == "luminous") cur.type = ExtObjMaterial::NONE;
continue;
}
/* OSPRay principled material extensions */
if (!strncmp(token, "baseColor", 9)) { parseSep(token += 9); cur.Kd = getVec3f(token); continue; }
if (!strncmp(token, "ior", 3)) { parseSep(token += 3); cur.Ni = getFloat(token); continue; }
if (!strncmp(token, "map_baseColor", 13)) { parseSep(token += 13); cur.map_Kd = loadTexture(FileName(token)); continue; }
if (!strncmp(token, "map_specular", 12)) { parseSep(token += 12); cur.map_Ks = loadTexture(FileName(token)); continue; }
if (!strncmp(token, "map_normal.scale", 16)) { parseSep(token += 16); continue; }
if (!strncmp(token, "map_normal", 10)) { parseSep(token += 10); cur.map_Displ = loadTexture(FileName(token)); continue; }
if (!strncmp(token, "transmissionColor",17)) { parseSep(token += 17); cur.Kt = getVec3f(token); continue; }
if (!strncmp(token, "transmission", 12)) { parseSep(token += 12); cur.Kt = Vec3f(getFloat(token)); continue; }
if (!strncmp(token, "roughnessMap", 12)) { parseSep(token += 12); cur.roughnessMap = loadTexture(FileName(token)); continue; }
if (!strncmp(token, "roughness", 9)) { parseSep(token += 9); cur.roughness = getFloat(token); cur.Ns = 1.0f/(cur.roughness+1E-6f); continue; }
if (!strncmp(token, "colorMap", 8)) { parseSep(token += 8); cur.map_Kd = loadTexture(FileName(token)); continue; }
if (!strncmp(token, "color", 5)) { parseSep(token += 5); cur.Kd = getVec3f(token); continue; }
if (!strncmp(token, "coat.color", 10)) { parseSep(token += 10); cur.Kd = getVec3f(token); continue; }
if (!strncmp(token, "coat.eta", 8)) { parseSep(token += 8); cur.coat_eta = getFloat(token); continue; }
if (!strncmp(token, "coat.roughnessMap",17)) { parseSep(token += 17); cur.coat_roughnessMap = loadTexture(FileName(token)); continue; }
if (!strncmp(token, "coat.roughness", 14)) { parseSep(token += 14); cur.coat_roughness = getFloat(token); continue; }
if (!strncmp(token, "bumpMap", 7)) { parseSep(token += 7); cur.map_Displ = loadTexture(FileName(token)); continue; }
if (!strncmp(token, "bump", 4)) { parseSep(token += 4); cur.bump = getFloat(token); continue; }
if (!strncmp(token, "eta", 3)) { parseSep(token += 3); cur.eta = getVec3f(token); continue; }
if (!strncmp(token, "k", 1)) { parseSep(token += 1); cur.k = getVec3f(token); continue; }
}
catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
if (name != "") {
material[name] = cur.select();
material[name]->name = name;
}
cin.close();
}
/*! handles relative indices and starts indexing from 0 */
unsigned int OBJLoader::fix_v (int index) { return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) v .size() + index)); }
unsigned int OBJLoader::fix_vt(int index) { return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) vt.size() + index)); }
unsigned int OBJLoader::fix_vn(int index) { return (index > 0 ? index - 1 : (index == 0 ? 0 : (int) vn.size() + index)); }
/*! Parse differently formatted triplets like: n0, n0/n1/n2, n0//n2, n0/n1. */
/*! All indices are converted to C-style (from 0). Missing entries are assigned -1. */
Vertex OBJLoader::getUInt3(const char*& token)
{
Vertex v(-1);
v.v = fix_v(atoi(token));
token += strcspn(token, "/ \t\r");
if (token[0] != '/') return(v);
token++;
// it is i//n
if (token[0] == '/') {
token++;
v.vn = fix_vn(atoi(token));
token += strcspn(token, " \t\r");
return(v);
}
// it is i/t/n or i/t
v.vt = fix_vt(atoi(token));
token += strcspn(token, "/ \t\r");
if (token[0] != '/') return(v);
token++;
// it is i/t/n
v.vn = fix_vn(atoi(token));
token += strcspn(token, " \t\r");
return(v);
}
uint32_t OBJLoader::getVertex(std::map<Vertex,uint32_t>& vertexMap, Ref<SceneGraph::TriangleMeshNode> mesh, const Vertex& i)
{
const std::map<Vertex, uint32_t>::iterator& entry = vertexMap.find(i);
if (entry != vertexMap.end()) return(entry->second);
if (i.v >= v.size()) std::cout << "WARNING: corrupted OBJ file" << std::endl;
else mesh->positions[0].push_back(v[i.v]);
if (i.vn != -1) {
while (mesh->normals[0].size() < mesh->positions[0].size()) mesh->normals[0].push_back(zero); // some vertices might not had a normal
if (i.vn >= vn.size()) std::cout << "WARNING: corrupted OBJ file" << std::endl;
else mesh->normals[0][mesh->positions[0].size()-1] = vn[i.vn];
}
if (i.vt != -1) {
while (mesh->texcoords.size() < mesh->positions[0].size()) mesh->texcoords.push_back(zero); // some vertices might not had a texture coordinate
if (i.vt >= vt.size()) std::cout << "WARNING: corrupted OBJ file" << std::endl;
else mesh->texcoords[mesh->positions[0].size()-1] = vt[i.vt];
}
return (vertexMap[i] = (unsigned int)(mesh->positions[0].size()) - 1);
}
void OBJLoader::flushFaceGroup()
{
flushTriGroup();
flushHairGroup();
}
/*! end current facegroup and append to mesh */
void OBJLoader::flushTriGroup()
{
if (curGroup.empty()) return;
if (subdivMode)
{
Ref<SceneGraph::SubdivMeshNode> mesh = new SceneGraph::SubdivMeshNode(curMaterial,BBox1f(0,1),1);
mesh->normals.resize(1);
group->add(mesh.cast<SceneGraph::Node>());
for (size_t i=0; i<v.size(); i++) mesh->positions[0].push_back(v[i]);
for (size_t i=0; i<vn.size(); i++) mesh->normals[0].push_back(vn[i]);
for (size_t i=0; i<vt.size(); i++) mesh->texcoords.push_back(vt[i]);
for (size_t i=0; i<ec.size(); ++i) {
assert(((size_t)ec[i].a < v.size()) && ((size_t)ec[i].b < v.size()));
mesh->edge_creases.push_back(Vec2i(ec[i].a, ec[i].b));
mesh->edge_crease_weights.push_back(ec[i].w);
}
for (size_t j=0; j<curGroup.size(); j++)
{
const std::vector<Vertex>& face = curGroup[j];
mesh->verticesPerFace.push_back(int(face.size()));
for (size_t i=0; i<face.size(); i++)
mesh->position_indices.push_back(face[i].v);
}
if (mesh->normals[0].size() == 0)
mesh->normals.clear();
mesh->verify();
}
else
{
Ref<SceneGraph::TriangleMeshNode> mesh = new SceneGraph::TriangleMeshNode(curMaterial,BBox1f(0,1),1);
mesh->normals.resize(1);
group->add(mesh.cast<SceneGraph::Node>());
// merge three indices into one
std::map<Vertex, uint32_t> vertexMap;
for (size_t j=0; j<curGroup.size(); j++)
{
/* iterate over all faces */
const std::vector<Vertex>& face = curGroup[j];
/* triangulate the face with a triangle fan */
Vertex i0 = face[0], i1 = Vertex(-1), i2 = face[1];
for (size_t k=2; k < face.size(); k++)
{
i1 = i2; i2 = face[k];
uint32_t v0,v1,v2;
v0 = getVertex(vertexMap, mesh, i0);
v1 = getVertex(vertexMap, mesh, i1);
v2 = getVertex(vertexMap, mesh, i2);
assert(v0 < mesh->numVertices());
assert(v1 < mesh->numVertices());
assert(v2 < mesh->numVertices());
mesh->triangles.push_back(SceneGraph::TriangleMeshNode::Triangle(v0,v1,v2));
}
}
/* there may be vertices without normals or texture coordinates, thus we have to make these arrays the same size here */
if (mesh->normals[0].size()) while (mesh->normals[0].size() < mesh->numVertices()) mesh->normals[0].push_back(zero);
if (mesh->texcoords.size()) while (mesh->texcoords.size() < mesh->numVertices()) mesh->texcoords.push_back(zero);
if (mesh->normals[0].size() == 0)
mesh->normals.clear();
mesh->verify();
}
curGroup.clear();
ec.clear();
}
void OBJLoader::flushHairGroup()
{
if (curGroupHair.empty()) return;
avector<Vec3ff> vertices;
std::vector<SceneGraph::HairSetNode::Hair> curves;
for (size_t i=0; i<curGroupHair.size(); i++) {
for (size_t j=0; j<curGroupHair[i].size(); j++) {
if (j%3 == 0) curves.push_back(SceneGraph::HairSetNode::Hair((unsigned int)vertices.size(),(unsigned int)i));
vertices.push_back(curGroupHair[i][j]);
}
}
Ref<SceneGraph::HairSetNode> mesh = new SceneGraph::HairSetNode(vertices,curves,curMaterial,RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE);
group->add(mesh.cast<SceneGraph::Node>());
mesh->verify();
curGroupHair.clear();
}
Ref<SceneGraph::Node> loadOBJ(const FileName& fileName, const bool subdivMode, const bool combineIntoSingleObject) {
OBJLoader loader(fileName,subdivMode,combineIntoSingleObject);
return loader.group.cast<SceneGraph::Node>();
}
}

View file

@ -0,0 +1,13 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include "scenegraph.h"
namespace embree
{
Ref<SceneGraph::Node> loadOBJ(const FileName& fileName,
const bool subdivMode = false,
const bool combineIntoSingleObject = false);
}

View file

@ -0,0 +1,332 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#include "ply_loader.h"
#include <list>
namespace embree
{
namespace SceneGraph
{
/*! PLY type */
struct Type {
enum Tag { PTY_CHAR, PTY_UCHAR, PTY_SHORT, PTY_USHORT, PTY_INT, PTY_UINT, PTY_FLOAT, PTY_DOUBLE, PTY_LIST, PTY_NONE } ty, index, data;
Type() : ty(PTY_NONE), index(PTY_NONE), data(PTY_NONE) {}
Type(Tag ty) : ty(ty), index(PTY_NONE), data(PTY_NONE) {}
Type(Tag ty, Tag index, Tag data) : ty(ty), index(index), data(data) {}
};
/*! an element stored in the PLY file, such as vertex, face, etc. */
struct Element {
std::string name;
size_t size; /// number of data items of the element
std::vector<std::string> properties; /// list of all properties of the element (e.g. x, y, z) (not strictly necessary)
std::map<std::string,Type> type; /// mapping of property name to type
std::map<std::string,std::vector<float> > data; /// data array properties (all represented as floats)
std::map<std::string,std::vector<std::vector<size_t> > > list; /// list properties (integer lists supported only)
};
/*! mesh structure that reflects the PLY file format */
struct Mesh {
std::vector<std::string> order; /// order of all elements in file (not strictly necessary)
std::map<std::string,Element> elements; /// all elements of the file, e.g. vertex, face, ...
};
/* returns the size of a type in bytes */
size_t sizeOfType(Type::Tag ty)
{
switch (ty) {
case Type::PTY_CHAR : return 1;
case Type::PTY_UCHAR : return 1;
case Type::PTY_SHORT : return 2;
case Type::PTY_USHORT : return 2;
case Type::PTY_INT : return 4;
case Type::PTY_UINT : return 4;
case Type::PTY_FLOAT : return 4;
case Type::PTY_DOUBLE : return 8;
default : throw std::runtime_error("invalid type");
}
}
/* compute the type of a string */
Type::Tag typeTagOfString(const std::string& ty) {
if (ty == "char") return Type::PTY_CHAR;
if (ty == "int8") return Type::PTY_CHAR;
if (ty == "uchar") return Type::PTY_UCHAR;
if (ty == "uint8") return Type::PTY_UCHAR;
if (ty == "short") return Type::PTY_SHORT;
if (ty == "int16") return Type::PTY_SHORT;
if (ty == "ushort") return Type::PTY_USHORT;
if (ty == "uint16") return Type::PTY_USHORT;
if (ty == "int") return Type::PTY_INT;
if (ty == "int32") return Type::PTY_INT;
if (ty == "uint") return Type::PTY_UINT;
if (ty == "uint32") return Type::PTY_UINT;
if (ty == "float") return Type::PTY_FLOAT;
if (ty == "float32") return Type::PTY_FLOAT;
if (ty == "double") return Type::PTY_DOUBLE;
throw std::runtime_error("invalid type " + ty);
return Type::PTY_NONE;
}
/* compute the type of a string */
std::string stringOfTypeTag(Type::Tag ty) {
if (ty == Type::PTY_CHAR) return "char";
if (ty == Type::PTY_UCHAR) return "uchar";
if (ty == Type::PTY_SHORT) return "short";
if (ty == Type::PTY_USHORT) return "ushort";
if (ty == Type::PTY_INT) return "int";
if (ty == Type::PTY_UINT) return "uint";
if (ty == Type::PTY_FLOAT) return "float";
if (ty == Type::PTY_DOUBLE) return "double";
if (ty == Type::PTY_LIST) return "list";
throw std::runtime_error("invalid type");
return "";
}
/* compute the type of a string */
std::string stringOfType(Type ty) {
if (ty.ty == Type::PTY_LIST) return "list " + stringOfTypeTag(ty.index) + " " + stringOfTypeTag(ty.data);
else return stringOfTypeTag(ty.ty);
}
/* PLY parser class */
struct PlyParser
{
std::fstream fs;
Mesh mesh;
Ref<SceneGraph::Node> scene;
/* storage format of data in file */
enum Format { ASCII, BINARY_BIG_ENDIAN, BINARY_LITTLE_ENDIAN } format;
/* constructor parses the input stream */
PlyParser(const FileName& fileName) : format(ASCII)
{
/* open file */
fs.open (fileName.c_str(), std::fstream::in | std::fstream::binary);
if (!fs.is_open()) throw std::runtime_error("cannot open file : " + fileName.str());
/* check for file signature */
std::string signature; getline(fs,signature);
if (signature != "ply") throw std::runtime_error("invalid PLY file signature: " + signature);
/* read header */
std::list<std::string> header;
while (true) {
std::string line; getline(fs,line);
if (line == "end_header") break;
if (line.find_first_of('#') == 0) continue;
if (line == "") continue;
header.push_back(line);
}
/* parse header */
parseHeader(header);
/* now parse all elements */
for (std::vector<std::string>::iterator i = mesh.order.begin(); i!=mesh.order.end(); i++)
parseElementData(mesh.elements[*i]);
/* create triangle mesh */
scene = import();
}
/* parse the PLY header */
void parseHeader(std::list<std::string>& header)
{
while (!header.empty())
{
std::stringstream line(header.front());
header.pop_front();
std::string tag; line >> tag;
/* ignore comments */
if (tag == "comment") {
}
/* parse format */
else if (tag == "format")
{
std::string fmt; line >> fmt;
if (fmt == "ascii") format = ASCII;
else if (fmt == "binary_big_endian") format = BINARY_BIG_ENDIAN;
else if (fmt == "binary_little_endian") format = BINARY_LITTLE_ENDIAN;
else throw std::runtime_error("invalid PLY file format: " + fmt);
std::string version; line >> version;
if (version != "1.0") throw std::runtime_error("invalid PLY file version: " + version);
}
/* parse end of header tag */
else if (tag == "end_header")
break;
/* parse elements */
else if (tag == "element") parseElementDescr(line,header);
/* report unknown tags */
else throw std::runtime_error("unknown tag in PLY file: " + tag);
}
}
/* parses a PLY element description */
void parseElementDescr(std::stringstream& cin, std::list<std::string>& header)
{
Element elt;
std::string name; cin >> name;
size_t num; cin >> num;
mesh.order.push_back(name);
elt.name = name;
elt.size = num;
/* parse all properties */
while (!header.empty())
{
std::stringstream line(header.front());
std::string tag; line >> tag;
if (tag != "property") break;
header.pop_front();
Type ty = parseType(line);
std::string name; line >> name;
elt.type[name] = ty;
elt.properties.push_back(name);
}
mesh.elements[name] = elt;
}
/* parses a PLY type */
Type parseType(std::stringstream& cin)
{
std::string ty; cin >> ty;
if (ty == "list") {
std::string ty0; cin >> ty0;
std::string ty1; cin >> ty1;
return Type(Type::PTY_LIST,typeTagOfString(ty0),typeTagOfString(ty1));
} else return Type(typeTagOfString(ty));
}
/* parses data of a PLY element */
void parseElementData(Element& elt)
{
/* allocate data for all properties */
for (std::vector<std::string>::iterator i=elt.properties.begin(); i!=elt.properties.end(); i++) {
if (elt.type[*i].ty == Type::PTY_LIST) elt.list[*i] = std::vector<std::vector<size_t> >();
else elt.data[*i] = std::vector<float>();
}
/* parse all elements */
for (size_t e=0; e<elt.size; e++)
{
/* load all properties of the element */
for (std::vector<std::string>::iterator i=elt.properties.begin(); i!=elt.properties.end(); i++) {
Type ty = elt.type[*i];
if (ty.ty == Type::PTY_LIST) loadPropertyList(elt.list[*i],ty.index,ty.data);
else loadPropertyData(elt.data[*i],ty.ty);
}
}
}
/* load bytes from file and take care of little and big endian encoding */
void readBytes(void* dst, int num) {
if (format == BINARY_LITTLE_ENDIAN) fs.read((char*)dst,num);
else if (format == BINARY_BIG_ENDIAN) for (int i=0; i<num; i++) fs.read((char*)dst+num-i-1,1);
else throw std::runtime_error("internal error on PLY loader");
}
int read_ascii_int () { int i; fs >> i; return i; }
float read_ascii_float() { float f; fs >> f; return f; }
signed char read_char () { if (format == ASCII) return read_ascii_int(); signed char r = 0; readBytes(&r,1); return r; }
unsigned char read_uchar () { if (format == ASCII) return read_ascii_int(); unsigned char r = 0; readBytes(&r,1); return r; }
signed short read_short () { if (format == ASCII) return read_ascii_int(); signed short r = 0; readBytes(&r,2); return r; }
unsigned short read_ushort() { if (format == ASCII) return read_ascii_int(); unsigned short r = 0; readBytes(&r,2); return r; }
signed int read_int () { if (format == ASCII) return read_ascii_int(); signed int r = 0; readBytes(&r,4); return r; }
unsigned int read_uint () { if (format == ASCII) return read_ascii_int(); unsigned int r = 0; readBytes(&r,4); return r; }
float read_float () { if (format == ASCII) return read_ascii_float(); float r = 0; readBytes(&r,4); return r; }
double read_double() { if (format == ASCII) return read_ascii_float(); double r = 0; readBytes(&r,8); return r; }
/* load an integer type */
size_t loadInteger(Type::Tag ty)
{
switch (ty) {
case Type::PTY_CHAR : return read_char(); break;
case Type::PTY_UCHAR : return read_uchar(); break;
case Type::PTY_SHORT : return read_short(); break;
case Type::PTY_USHORT : return read_ushort(); break;
case Type::PTY_INT : return read_int(); break;
case Type::PTY_UINT : return read_uint(); break;
default : throw std::runtime_error("invalid type"); return 0;
}
}
/* load a list */
void loadPropertyList(std::vector<std::vector<size_t> >& vec,Type::Tag index_ty,Type::Tag data_ty)
{
std::vector<size_t> lst;
size_t num = loadInteger(index_ty);
for (size_t i=0; i<num; i++) lst.push_back(loadInteger(data_ty));
vec.push_back(lst);
}
/* load a data element */
void loadPropertyData(std::vector<float>& vec, Type::Tag ty)
{
switch (ty) {
case Type::PTY_CHAR : vec.push_back(float(read_char())); break;
case Type::PTY_UCHAR : vec.push_back(float(read_uchar())); break;
case Type::PTY_SHORT : vec.push_back(float(read_short())); break;
case Type::PTY_USHORT : vec.push_back(float(read_ushort())); break;
case Type::PTY_INT : vec.push_back(float(read_int())); break;
case Type::PTY_UINT : vec.push_back(float(read_uint())); break;
case Type::PTY_FLOAT : vec.push_back(float(read_float())); break;
case Type::PTY_DOUBLE : vec.push_back(float(read_double())); break;
default : throw std::runtime_error("invalid type");
}
}
Ref<SceneGraph::Node> import()
{
Ref<SceneGraph::MaterialNode> material = new OBJMaterial;
Ref<SceneGraph::TriangleMeshNode> mesh_o = new SceneGraph::TriangleMeshNode(material,BBox1f(0,1),1);
/* convert all vertices */
const Element& vertices = mesh.elements.at("vertex");
const std::vector<float>& posx = vertices.data.at("x");
const std::vector<float>& posy = vertices.data.at("y");
const std::vector<float>& posz = vertices.data.at("z");
mesh_o->positions[0].resize(vertices.size);
for (size_t i=0; i<vertices.size; i++) {
mesh_o->positions[0][i].x = posx[i];
mesh_o->positions[0][i].y = posy[i];
mesh_o->positions[0][i].z = posz[i];
}
/* convert all faces */
const Element& faces = mesh.elements.at("face");
const std::vector<std::vector<size_t> >& polygons = faces.list.at("vertex_indices");
for (size_t j=0; j<polygons.size(); j++)
{
const std::vector<size_t>& face = polygons[j];
if (face.size() < 3) continue;
/* triangulate the face with a triangle fan */
size_t i0 = face[0], i1 = 0, i2 = face[1];
for (size_t k=2; k<face.size(); k++) {
i1 = i2; i2 = face[k];
mesh_o->triangles.push_back(SceneGraph::TriangleMeshNode::Triangle((unsigned int)i0, (unsigned int)i1, (unsigned int)i2));
}
}
return mesh_o.dynamicCast<SceneGraph::Node>();
}
};
Ref<Node> loadPLY(const FileName& fileName) {
return PlyParser(fileName).scene;
}
}
}

View file

@ -0,0 +1,14 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include "scenegraph.h"
namespace embree
{
namespace SceneGraph
{
Ref<Node> loadPLY(const FileName& fileName);
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,91 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#include "texture.h"
namespace embree
{
bool isPowerOf2 (unsigned int x)
{
while (((x % 2) == 0) && x > 1)
x /= 2;
return (x == 1);
}
static std::map<std::string,std::shared_ptr<Texture>> texture_cache;
void Texture::clearTextureCache() {
texture_cache.clear();
}
Texture::Texture ()
: width(-1), height(-1), format(INVALID), bytesPerTexel(0), width_mask(0), height_mask(0), data(nullptr) {}
Texture::Texture(Ref<Image> img, const std::string fileName)
: width(unsigned(img->width)), height(unsigned(img->height)), format(RGBA8), bytesPerTexel(4), width_mask(0), height_mask(0), data(nullptr), fileName(fileName)
{
width_mask = isPowerOf2(width) ? width-1 : 0;
height_mask = isPowerOf2(height) ? height-1 : 0;
data = alignedUSMMalloc(4*width*height,16);
img->convertToRGBA8((unsigned char*)data);
}
Texture::Texture (unsigned width, unsigned height, const Format format, const char* in)
: width(width), height(height), format(format), bytesPerTexel(getFormatBytesPerTexel(format)), width_mask(0), height_mask(0), data(nullptr)
{
width_mask = isPowerOf2(width) ? width-1 : 0;
height_mask = isPowerOf2(height) ? height-1 : 0;
data = alignedUSMMalloc(bytesPerTexel*width*height,16);
if (in) {
for (size_t i=0; i<bytesPerTexel*width*height; i++)
((char*)data)[i] = in[i];
}
else {
memset(data,0 ,bytesPerTexel*width*height);
}
}
Texture::~Texture () {
alignedUSMFree(data);
}
const char* Texture::format_to_string(const Format format)
{
switch (format) {
case RGBA8 : return "RGBA8";
case RGB8 : return "RGB8";
case FLOAT32: return "FLOAT32";
default : THROW_RUNTIME_ERROR("invalid texture format");
}
}
Texture::Format Texture::string_to_format(const std::string& str)
{
if (str == "RGBA8") return RGBA8;
else if (str == "RGB8") return RGB8;
else if (str == "FLOAT32") return FLOAT32;
else THROW_RUNTIME_ERROR("invalid texture format string");
}
unsigned Texture::getFormatBytesPerTexel(const Format format)
{
switch (format) {
case RGBA8 : return 4;
case RGB8 : return 3;
case FLOAT32: return 4;
default : THROW_RUNTIME_ERROR("invalid texture format");
}
}
/*! read png texture from disk */
std::shared_ptr<Texture> Texture::load(const FileName& fileName)
{
if (texture_cache.find(fileName.str()) != texture_cache.end())
return texture_cache[fileName.str()];
std::shared_ptr<Texture> tex(new Texture(loadImage(fileName),fileName));
return texture_cache[fileName.str()] = tex;
}
}

View file

@ -0,0 +1,71 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#pragma once
#if defined(ISPC)
enum TEXTURE_FORMAT {
Texture_RGBA8 = 1,
Texture_RGB8 = 2,
Texture_FLOAT32 = 3,
};
struct Texture {
int width;
int height;
int format;
int bytesPerTexel;
int width_mask;
int height_mask;
void* data;
};
#else
#include "../default.h"
#include "../image/image.h"
namespace embree
{
struct Texture // FIXME: should be derived from SceneGraph::Node
{
ALIGNED_STRUCT_USM_(16);
enum Format {
INVALID = 0,
RGBA8 = 1,
RGB8 = 2,
FLOAT32 = 3,
};
public:
Texture ();
Texture (Ref<Image> image, const std::string fileName);
Texture (unsigned width, unsigned height, const Format format, const char* in = nullptr);
~Texture ();
private:
Texture (const Texture& other) DELETED; // do not implement
Texture& operator= (const Texture& other) DELETED; // do not implement
public:
static const char* format_to_string(const Format format);
static Format string_to_format(const std::string& str);
static unsigned getFormatBytesPerTexel(const Format format);
static std::shared_ptr<Texture> load(const FileName& fileName);
static void clearTextureCache();
public:
unsigned width;
unsigned height;
Format format;
unsigned bytesPerTexel;
unsigned width_mask;
unsigned height_mask;
void* data;
std::string fileName;
};
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,15 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include "scenegraph.h"
namespace embree
{
namespace SceneGraph
{
Ref<Node> loadXML(const FileName& fileName, const AffineSpace3fa& space = one);
}
}

View file

@ -0,0 +1,196 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#include "xml_parser.h"
#include <fstream>
namespace embree
{
//////////////////////////////////////////////////////////////////////////////
/// XML Input
//////////////////////////////////////////////////////////////////////////////
/*! parse a list of XML comments */
void parseComments(Ref<Stream<Token> >& cin)
{
while (cin->peek() == Token::Sym("<!--")) {
cin->drop();
while (cin->peek() != Token::Sym("-->")) {
if (cin->peek() == Token::Eof())
THROW_RUNTIME_ERROR(cin->get().Location().str()+": --> expected");
cin->drop();
}
cin->drop();
}
}
/*! parse XML parameter */
void parseParm(Ref<Stream<Token> >& cin, std::map<std::string,std::string>& parms)
{
std::string name = cin->get().Identifier();
if (cin->get() != Token::Sym("=")) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": symbol \"=\" expected");
parms[name] = cin->get().String();
}
/*! parse XML header */
Ref<XML> parseHeader(Ref<Stream<Token> >& cin)
{
Ref<XML> xml = new XML;
if (cin->get() != Token::Sym("<?")) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": wrong XML header");
xml->name = cin->get().Identifier();
parseComments(cin);
while (cin->peek() != Token::Sym("?>")) {
parseParm(cin,xml->parms);
parseComments(cin);
}
cin->drop();
return xml;
}
/*! parse XML tag */
Ref<XML> parseXML(Ref<Stream<Token> >& cin, size_t depth)
{
if (depth > 1024)
THROW_RUNTIME_ERROR(cin->peek().Location().str()+": maximal nesting depth reached");
Ref<XML> xml = new XML;
xml->loc = cin->peek().Location();
/* parse tag opening */
if (cin->get() != Token::Sym("<")) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": tag expected");
xml->name = cin->get().Identifier();
parseComments(cin);
while (cin->peek() != Token::Sym("/>") && cin->peek() != Token::Sym(">")) {
parseParm(cin,xml->parms);
parseComments(cin);
}
if (cin->peek() == Token::Sym("/>")) {
cin->drop();
return xml;
}
cin->drop();
/* parse body token list */
parseComments(cin);
while (cin->peek() != Token::Sym("<") && cin->peek() != Token::Sym("</")) {
xml->body.push_back(cin->get());
parseComments(cin);
}
/* the body also contains children */
if (cin->peek() == Token::Sym("<")) {
while (cin->peek() != Token::Sym("</")) {
xml->children.push_back(parseXML(cin,depth+1));
parseComments(cin);
}
}
/* parse tag closing */
if (cin->get() != Token::Sym("</") ) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": symbol \"</\" expected");
if (cin->get() != Token::Id(xml->name)) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": closing "+xml->name+" expected");
if (cin->get() != Token::Sym(">") ) THROW_RUNTIME_ERROR(cin->unget().Location().str()+": symbol \">\" expected");
return xml;
}
/* load XML from token stream */
Ref<XML> parseXML(Ref<Stream<int> > chars, std::string id, bool hasHeader = true, bool hasTail = false)
{
/* create lexer for XML file */
std::vector<std::string> symbols;
symbols.push_back("<!--");
symbols.push_back("-->");
symbols.push_back("<?");
symbols.push_back("?>");
symbols.push_back("</");
symbols.push_back("/>");
symbols.push_back("<");
symbols.push_back(">");
symbols.push_back("=");
Ref<Stream<Token> > cin = new TokenStream(chars,TokenStream::alpha + TokenStream::ALPHA + "_" + id, TokenStream::separators, symbols);
if (hasHeader) parseHeader(cin);
parseComments(cin);
Ref<XML> xml = parseXML(cin,0);
parseComments(cin);
if (!hasTail)
if (cin->peek() != Token::Eof()) THROW_RUNTIME_ERROR(cin->peek().Location().str()+": end of file expected");
return xml;
}
/*! load XML file from stream */
std::istream& operator>>(std::istream& cin, Ref<XML>& xml) {
xml = parseXML(new StdStream(cin),"",false,true);
return cin;
}
/*! load XML file from disk */
Ref<XML> parseXML(const FileName& fileName, std::string id, bool hasHeader) {
return parseXML(new FileStream(fileName),id,hasHeader,false);
}
//////////////////////////////////////////////////////////////////////////////
/// XML Output
//////////////////////////////////////////////////////////////////////////////
/* indent to some hierarchy level using spaces */
void indent(std::ostream& cout, size_t depth) {
for (size_t i=0; i<2*depth; i++) cout << " ";
}
/* store XML to a stream */
std::ostream& emitXML(std::ostream& cout, const Ref<XML>& xml, size_t depth = 0)
{
/* print header */
if (depth == 0) cout << "<?xml version=\"1.0\"?>" << std::endl << std::endl;
/* print tag opening */
indent(cout,depth); cout << "<" << xml->name;
for (std::map<std::string,std::string>::const_iterator i=xml->parms.begin(); i!=xml->parms.end(); i++)
cout << " " << i->first << "=" << "\"" << i->second << "\"";
if (xml->children.size() == 0 && xml->body.size() == 0) {
cout << "/>" << std::endl;
return cout;
}
cout << ">";
bool compact = xml->body.size() < 16 && xml->children.size() == 0;
if (!compact) cout << std::endl;
/* print token list */
if (xml->body.size()) {
if (!compact) indent(cout,depth+1);
for (size_t i=0; i<xml->body.size(); i++)
cout << xml->body[i] << (i!=xml->body.size()-1?" ":"");
if (!compact) cout << std::endl;
}
/* print children */
for (size_t i=0; i<xml->children.size(); i++)
emitXML(cout,xml->children[i],depth+1);
/* print tag closing */
if (!compact) indent(cout,depth);
return cout << "</" << xml->name << ">" << std::endl;
}
/* store XML to stream */
std::ostream& operator<<(std::ostream& cout, const Ref<XML>& xml) {
return emitXML(cout,xml);
}
/*! store XML to disk */
void emitXML(const FileName& fileName, const Ref<XML>& xml)
{
std::ofstream cout(fileName.c_str());
if (!cout.is_open()) THROW_RUNTIME_ERROR("cannot open file " + fileName.str() + " for writing");
emitXML(cout,xml);
cout.close();
}
}

View file

@ -0,0 +1,127 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include "../default.h"
namespace embree
{
/* an XML node */
class XML : public RefCount
{
public:
XML (const std::string& name = "") : name(name) {}
/*! returns number of children of XML node */
size_t size() const { return children.size(); }
/*! checks if child with specified node tag exists */
bool hasChild(const std::string& childID) const
{
for (size_t i=0; i<children.size(); i++)
if (children[i]->name == childID) return true;
return false;
}
/*! returns a parameter of the XML node */
std::string parm(const std::string& parmID) const {
std::map<std::string,std::string>::const_iterator i = parms.find(parmID);
if (i == parms.end()) return ""; else return i->second;
}
Vec2f parm_Vec2f(const std::string& parmID) const {
std::map<std::string,std::string>::const_iterator i = parms.find(parmID);
if (i == parms.end()) THROW_RUNTIME_ERROR (loc.str()+": XML node has no parameter \"" + parmID + "\"");
return string_to_Vec2f(i->second);
}
Vec3fa parm_Vec3fa(const std::string& parmID) const {
std::map<std::string,std::string>::const_iterator i = parms.find(parmID);
if (i == parms.end()) THROW_RUNTIME_ERROR (loc.str()+": XML node has no parameter \"" + parmID + "\"");
return Vec3fa(string_to_Vec3f(i->second));
}
float parm_float(const std::string& parmID) const {
std::map<std::string,std::string>::const_iterator i = parms.find(parmID);
if (i == parms.end()) THROW_RUNTIME_ERROR (loc.str()+": XML node has no parameter \"" + parmID + "\"");
return std::stof(i->second);
}
/*! returns the nth child */
const Ref<XML> child(const size_t id) const
{
if (id >= children.size())
THROW_RUNTIME_ERROR (loc.str()+": XML node has no child \"" + toString(id) + "\"");
return children[id];
}
/*! returns child by node tag */
const Ref<XML> child(const std::string& childID) const
{
for (size_t i=0; i<children.size(); i++)
if (children[i]->name == childID) return children[i];
THROW_RUNTIME_ERROR (loc.str()+": XML node has no child \"" + childID + "\"");
}
/*! returns child by node tag without failing */
const Ref<XML> childOpt(const std::string& childID) const
{
for (size_t i=0; i<children.size(); i++)
if (children[i]->name == childID) return children[i];
return null;
}
/*! adds a new parameter to the node */
Ref<XML> add(const std::string& name, const std::string& val) {
parms[name] = val;
return this;
}
/*! adds a new child */
Ref<XML> add(const Ref<XML>& xml) {
children.push_back(xml);
return this;
}
/*! adds new data tokens to the body of the node */
Ref<XML> add(const Token& tok) {
body.push_back(tok);
return this;
}
/*! compares two XML nodes */
friend bool operator ==( const Ref<XML>& a, const Ref<XML>& b ) {
return a->name == b->name && a->parms == b->parms && a->children == b->children && a->body == b->body;
}
/*! orders two XML nodes */
friend bool operator <( const Ref<XML>& a, const Ref<XML>& b ) {
if (a->name != b->name ) return a->name < b->name;
if (a->parms != b->parms ) return a->parms < b->parms;
if (a->children != b->children) return a->children < b->children;
if (a->body != b->body ) return a->body < b->body;
return false;
}
public:
ParseLocation loc;
std::string name;
std::map<std::string,std::string> parms;
std::vector<Ref<XML> > children;
std::vector<Token> body;
};
/*! load XML file from stream */
std::istream& operator>>(std::istream& cin, Ref<XML>& xml);
/*! load XML file from disk */
Ref<XML> parseXML(const FileName& fileName, std::string id = "", bool hasHeader = true);
/* store XML to stream */
std::ostream& operator<<(std::ostream& cout, const Ref<XML>& xml);
/*! store XML to disk */
void emitXML(const FileName& fileName, const Ref<XML>& xml);
}

View file

@ -0,0 +1,798 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#include "xml_writer.h"
namespace embree
{
class XMLWriter
{
public:
XMLWriter(Ref<SceneGraph::Node> root, const FileName& fileName, bool embedTextures, bool referenceMaterials, bool binaryFormat);
public:
void tab();
void open(std::string str);
void open(std::string str, size_t id);
void open(std::string str, size_t id, std::string name);
void close(std::string str);
void store(const char* name, const char* str);
void store(const char* name, const float& v);
void store(const char* name, const Vec3fa& v);
void store_array_elt(const int& v);
void store_array_elt(const Vec2f& v);
void store_array_elt(const Vec3f& v);
void store_array_elt(const Vec3fa& v);
void store_array_elt(const Vec3ff& v);
void store_array_elt(const SceneGraph::TriangleMeshNode::Triangle& v);
void store_array_elt(const SceneGraph::QuadMeshNode::Quad& v);
template<typename T> void store_array_text (const char* name, const std::vector<T>& vec);
template<typename T> void store_array_binary(const char* name, const std::vector<T>& vec);
template<typename T> void store (const char* name, const std::vector<T>& vec);
void store_array_text (const char* name, const avector<Vec3fa>& vec);
void store_array_binary(const char* name, const avector<Vec3fa>& vec);
void store (const char* name, const avector<Vec3fa>& vec);
void store_array_text (const char* name, const avector<Vec3ff>& vec);
void store_array_binary(const char* name, const avector<Vec3ff>& vec);
void store (const char* name, const avector<Vec3ff>& vec);
void store_parm(const char* name, const float& v);
void store_parm(const char* name, const Vec3fa& v);
void store_parm(const char* name, const std::shared_ptr<Texture> tex);
void store(const char* name, const AffineSpace3fa& space);
void store(const SceneGraph::PointLight& light, ssize_t id);
void store(const SceneGraph::SpotLight& light, ssize_t id);
void store(const SceneGraph::DirectionalLight& light, ssize_t id);
void store(const SceneGraph::DistantLight& light, ssize_t id);
void store(const SceneGraph::AmbientLight& light, ssize_t id);
void store(const SceneGraph::TriangleLight& light, ssize_t id);
void store(const SceneGraph::QuadLight& light, ssize_t id);
void store(Ref<SceneGraph::LightNode> light, ssize_t id);
void store(Ref<SceneGraph::AnimatedLightNode> light, ssize_t id);
void store(Ref<MatteMaterial> material, ssize_t id);
void store(Ref<MirrorMaterial> material, ssize_t id);
void store(Ref<ThinDielectricMaterial> material, ssize_t id);
void store(Ref<OBJMaterial> material, ssize_t id);
void store(Ref<MetalMaterial> material, ssize_t id);
void store(Ref<VelvetMaterial> material, ssize_t id);
void store(Ref<DielectricMaterial> material, ssize_t id);
void store(Ref<MetallicPaintMaterial> material, ssize_t id);
void store(Ref<HairMaterial> material, ssize_t id);
void store(Ref<SceneGraph::MaterialNode> material);
void store(Ref<SceneGraph::TriangleMeshNode> mesh, ssize_t id);
void store(Ref<SceneGraph::QuadMeshNode> mesh, ssize_t id);
void store(Ref<SceneGraph::SubdivMeshNode> mesh, ssize_t id);
void store(Ref<SceneGraph::HairSetNode> hair, ssize_t id);
void store(Ref<SceneGraph::PerspectiveCameraNode> camera, ssize_t id);
void store(Ref<SceneGraph::AnimatedPerspectiveCameraNode> camera, ssize_t id);
void store(Ref<SceneGraph::TransformNode> node, ssize_t id);
void store(std::vector<Ref<SceneGraph::TransformNode>> nodes);
void store(Ref<SceneGraph::GroupNode> group, ssize_t id);
void store(Ref<SceneGraph::Node> node);
private:
std::fstream xml; //!< .xml file for writing XML data
std::fstream bin; //!< .bin file for writing binary data
private:
size_t ident;
size_t currentNodeID;
std::map<Ref<SceneGraph::Node>, size_t> nodeMap;
std::map<std::shared_ptr<Texture>, size_t> textureMap; // FIXME: use Ref<Texture>
bool embedTextures;
bool referenceMaterials;
bool binaryFormat;
};
//////////////////////////////////////////////////////////////////////////////
//// Storing of objects to XML file
//////////////////////////////////////////////////////////////////////////////
void XMLWriter::tab()
{
for (size_t i=0; i<ident; i++)
xml << " ";
}
void XMLWriter::open(std::string str)
{
tab(); xml << "<" << str << ">" << std::endl;
ident+=2;
}
void XMLWriter::open(std::string str, size_t id)
{
tab(); xml << "<" << str << " id=\"" << id << "\">" << std::endl;
ident+=2;
}
void XMLWriter::open(std::string str, size_t id, std::string name)
{
tab(); xml << "<" << str << " id=\"" << id << "\" name=\"" << name << "\">" << std::endl;
ident+=2;
}
void XMLWriter::close(std::string str)
{
assert(ident>=2);
ident-=2;
tab(); xml << "</" << str << ">" << std::endl;
}
void XMLWriter::store(const char* name, const char* str) {
tab(); xml << "<" << name << ">\"" << str << "\"</" << name << ">" << std::endl;
}
void XMLWriter::store(const char* name, const float& v) {
tab(); xml << "<" << name << ">" << v << "</" << name << ">" << std::endl;
}
void XMLWriter::store(const char* name, const Vec3fa& v) {
tab(); xml << "<" << name << ">" << v.x << " " << v.y << " " << v.z << "</" << name << ">" << std::endl;
}
void XMLWriter::store_array_elt(const int& v) {
xml << v << std::endl;
}
void XMLWriter::store_array_elt(const Vec2f& v) {
xml << v.x << " " << v.y << std::endl;
}
void XMLWriter::store_array_elt(const Vec3f& v) {
xml << v.x << " " << v.y << " " << v.z << std::endl;
}
void XMLWriter::store_array_elt(const Vec3fa& v) {
xml << v.x << " " << v.y << " " << v.z << std::endl;
}
void XMLWriter::store_array_elt(const Vec3ff& v) {
xml << v.x << " " << v.y << " " << v.z << " " << v.w << std::endl;
}
void XMLWriter::store_array_elt(const SceneGraph::TriangleMeshNode::Triangle& v) {
xml << v.v0 << " " << v.v1 << " " << v.v2 << std::endl;
}
void XMLWriter::store_array_elt(const SceneGraph::QuadMeshNode::Quad& v) {
xml << v.v0 << " " << v.v1 << " " << v.v2 << " " << v.v3 << std::endl;
}
template<typename T>
void XMLWriter::store_array_text(const char* name, const std::vector<T>& vec)
{
open(name);
for (size_t i=0; i<vec.size(); i++) {
tab(); store_array_elt(vec[i]);
}
close(name);
}
template<typename T>
void XMLWriter::store_array_binary(const char* name, const std::vector<T>& vec)
{
std::streampos offset = bin.tellg();
tab(); xml << "<" << name << " ofs=\"" << offset << "\" size=\"" << vec.size() << "\"/>" << std::endl;
if (vec.size()) bin.write((char*)vec.data(),vec.size()*sizeof(T));
}
template<typename T>
void XMLWriter::store(const char* name, const std::vector<T>& vec)
{
if (binaryFormat) store_array_binary(name,vec);
else store_array_text (name,vec);
}
void XMLWriter::store_array_text(const char* name, const avector<Vec3fa>& vec)
{
open(name);
for (size_t i=0; i<vec.size(); i++) {
tab(); store_array_elt(vec[i]);
}
close(name);
}
void XMLWriter::store_array_binary(const char* name, const avector<Vec3fa>& vec)
{
std::streampos offset = bin.tellg();
tab(); xml << "<" << name << " ofs=\"" << offset << "\" size=\"" << vec.size() << "\"/>" << std::endl;
for (size_t i=0; i<vec.size(); i++) bin.write((char*)&vec[i],sizeof(Vec3f));
}
void XMLWriter::store(const char* name, const avector<Vec3fa>& vec)
{
if (binaryFormat) store_array_binary(name,vec);
else store_array_text (name,vec);
}
void XMLWriter::store_array_text(const char* name, const avector<Vec3ff>& vec)
{
open(name);
for (size_t i=0; i<vec.size(); i++) {
tab(); store_array_elt(vec[i]);
}
close(name);
}
void XMLWriter::store_array_binary(const char* name, const avector<Vec3ff>& vec)
{
std::streampos offset = bin.tellg();
tab(); xml << "<" << name << " ofs=\"" << offset << "\" size=\"" << vec.size() << "\"/>" << std::endl;
for (size_t i=0; i<vec.size(); i++) bin.write((char*)&vec[i],sizeof(Vec3ff));
}
void XMLWriter::store(const char* name, const avector<Vec3ff>& vec)
{
if (binaryFormat) store_array_binary(name,vec);
else store_array_text (name,vec);
}
void XMLWriter::store_parm(const char* name, const float& v) {
tab(); xml << "<float name=\"" << name << "\">" << v << "</float>" << std::endl;
}
void XMLWriter::store_parm(const char* name, const Vec3fa& v) {
tab(); xml << "<float3 name=\"" << name << "\">" << v.x << " " << v.y << " " << v.z << "</float3>" << std::endl;
}
void XMLWriter::store_parm(const char* name, const std::shared_ptr<Texture> tex)
{
if (tex == nullptr) return;
if (textureMap.find(tex) != textureMap.end()) {
tab(); xml << "<texture3d name=\"" << name << "\" id=\"" << textureMap[tex] << "\"/>" << std::endl;
} else if (embedTextures) {
std::streampos offset = bin.tellg();
bin.write((char*)tex->data,tex->width*tex->height*tex->bytesPerTexel);
const size_t id = textureMap[tex] = currentNodeID++;
tab(); xml << "<texture3d name=\"" << name << "\" id=\"" << id << "\" ofs=\"" << offset
<< "\" width=\"" << tex->width << "\" height=\"" << tex->height
<< "\" format=\"" << Texture::format_to_string(tex->format) << "\"/>" << std::endl;
}
else {
const size_t id = textureMap[tex] = currentNodeID++;
tab(); xml << "<texture3d name=\"" << name << "\" id=\"" << id << "\" src=\"" << tex->fileName << "\"/>" << std::endl;
}
}
void XMLWriter::store(const char* name, const AffineSpace3fa& space)
{
tab(); xml << "<" << name << ">" << std::endl;
tab(); xml << " " << space.l.vx.x << " " << space.l.vy.x << " " << space.l.vz.x << " " << space.p.x << std::endl;
tab(); xml << " " << space.l.vx.y << " " << space.l.vy.y << " " << space.l.vz.y << " " << space.p.y << std::endl;
tab(); xml << " " << space.l.vx.z << " " << space.l.vy.z << " " << space.l.vz.z << " " << space.p.z << std::endl;
tab(); xml << "</" << name << ">" << std::endl;
}
void XMLWriter::store(const SceneGraph::PointLight& light, ssize_t id)
{
open("PointLight",id);
store("AffineSpace",AffineSpace3fa::translate(light.P));
store("I",light.I);
close("PointLight");
}
void XMLWriter::store(const SceneGraph::SpotLight& light, ssize_t id)
{
open("SpotLight",id);
store("AffineSpace",AffineSpace3fa(frame(light.D),light.P));
store("I",light.I);
store("angleMin",light.angleMin);
store("angleMax",light.angleMax);
close("SpotLight");
}
void XMLWriter::store(const SceneGraph::DirectionalLight& light, ssize_t id)
{
open("DirectionalLight",id);
store("AffineSpace",frame(light.D));
store("E",light.E);
close("DirectionalLight");
}
void XMLWriter::store(const SceneGraph::DistantLight& light, ssize_t id)
{
open("DistantLight",id);
store("AffineSpace",frame(light.D));
store("L",light.L);
store("halfAngle",light.halfAngle);
close("DistantLight");
}
void XMLWriter::store(const SceneGraph::AmbientLight& light, ssize_t id)
{
open("AmbientLight");
store("L",light.L);
close("AmbientLight");
}
void XMLWriter::store(const SceneGraph::TriangleLight& light, ssize_t id)
{
open("TriangleLight",id);
const Vec3fa dx = light.v0-light.v2;
const Vec3fa dy = light.v1-light.v2;
const Vec3fa dz = cross(dx,dy);
const Vec3fa p = light.v2;
store("AffineSpace",AffineSpace3fa(dx,dy,dz,p));
store("L",light.L);
close("TriangleLight");
}
void XMLWriter::store(const SceneGraph::QuadLight& light, ssize_t id)
{
open("QuadLight",id);
const Vec3fa dx = light.v3-light.v0;
const Vec3fa dy = light.v1-light.v0;
const Vec3fa dz = cross(dx,dy);
const Vec3fa p = light.v2;
store("AffineSpace",AffineSpace3fa(dx,dy,dz,p));
store("L",light.L);
close("QuadLight");
}
void XMLWriter::store(Ref<SceneGraph::LightNode> node, ssize_t id)
{
if (auto light = node.dynamicCast<SceneGraph::LightNodeImpl<SceneGraph::AmbientLight>>())
store(light->light,id);
else if (auto light = node.dynamicCast<SceneGraph::LightNodeImpl<SceneGraph::PointLight>>())
store(light->light,id);
else if (auto light = node.dynamicCast<SceneGraph::LightNodeImpl<SceneGraph::DirectionalLight>>())
store(light->light,id);
else if (auto light = node.dynamicCast<SceneGraph::LightNodeImpl<SceneGraph::SpotLight>>())
store(light->light,id);
else if (auto light = node.dynamicCast<SceneGraph::LightNodeImpl<SceneGraph::DistantLight>>())
store(light->light,id);
else if (auto light = node.dynamicCast<SceneGraph::LightNodeImpl<SceneGraph::TriangleLight>>())
store(light->light,id);
else if (auto light = node.dynamicCast<SceneGraph::LightNodeImpl<SceneGraph::QuadLight>>())
store(light->light,id);
else
throw std::runtime_error("unsupported light");
}
void XMLWriter::store(Ref<SceneGraph::AnimatedLightNode> node, ssize_t id)
{
open(std::string("AnimatedLight ")+
"time_range=\""+std::to_string(node->time_range.lower)+" "+std::to_string(node->time_range.upper)+"\"");
for (size_t i=0; i<node->lights.size(); i++)
store(node->lights[i].dynamicCast<SceneGraph::Node>());
close("AnimatedLight");
}
void XMLWriter::store(Ref<MatteMaterial> material, ssize_t id)
{
open("material",id,material->name);
store("code","Matte");
open("parameters");
store_parm("reflectance",material->reflectance);
close("parameters");
close("material");
}
void XMLWriter::store(Ref<MirrorMaterial> material, ssize_t id)
{
open("material",id,material->name);
store("code","Mirror");
open("parameters");
store_parm("reflectance",material->reflectance);
close("parameters");
close("material");
}
void XMLWriter::store(Ref<ThinDielectricMaterial> material, ssize_t id)
{
open("material",id,material->name);
store("code","ThinDielectric");
open("parameters");
store_parm("transmission",material->transmission);
store_parm("eta",material->eta);
store_parm("thickness",material->thickness);
close("parameters");
close("material");
}
void XMLWriter::store(Ref<OBJMaterial> material, ssize_t id)
{
open("material",id,material->name);
store("code","OBJ");
open("parameters");
store_parm("d",material->d);
store_parm("Ka",material->Ka);
store_parm("Kd",material->Kd);
store_parm("Ks",material->Ks);
store_parm("Kt",material->Kt);
store_parm("Ns",material->Ns);
store_parm("Ni",material->Ni);
store_parm("map_d",material->_map_d);
store_parm("map_Kd",material->_map_Kd);
store_parm("map_Ks",material->_map_Ks);
store_parm("map_Ns",material->_map_Ns);
store_parm("map_Displ",material->_map_Displ);
close("parameters");
close("material");
}
void XMLWriter::store(Ref<MetalMaterial> material, ssize_t id)
{
open("material",id,material->name);
store("code","Metal");
open("parameters");
store_parm("reflectance",material->reflectance);
store_parm("eta",material->eta);
store_parm("k",material->k);
store_parm("roughness",material->roughness);
close("parameters");
close("material");
}
void XMLWriter::store(Ref<VelvetMaterial> material, ssize_t id)
{
open("material",id,material->name);
store("code","Velvet");
open("parameters");
store_parm("reflectance",material->reflectance);
store_parm("backScattering",material->backScattering);
store_parm("horizonScatteringColor",material->horizonScatteringColor);
store_parm("horizonScatteringFallOff",material->horizonScatteringFallOff);
close("parameters");
close("material");
}
void XMLWriter::store(Ref<DielectricMaterial> material, ssize_t id)
{
open("material",id,material->name);
store("code","Dielectric");
open("parameters");
store_parm("transmissionOutside",material->transmissionOutside);
store_parm("transmission",material->transmissionInside);
store_parm("etaOutside",material->etaOutside);
store_parm("etaInside",material->etaInside);
close("parameters");
close("material");
}
void XMLWriter::store(Ref<MetallicPaintMaterial> material, ssize_t id)
{
open("material",id,material->name);
store("code","MetallicPaint");
open("parameters");
store_parm("shadeColor",material->shadeColor);
store_parm("glitterColor",material->glitterColor);
store_parm("glitterSpread",material->glitterSpread);
store_parm("eta",material->eta);
close("parameters");
close("material");
}
void XMLWriter::store(Ref<HairMaterial> material, ssize_t id)
{
open("material",id,material->name);
store("code","Hair");
open("parameters");
store_parm("Kr",material->Kr);
store_parm("Kt",material->Kt);
store_parm("nx",material->nx);
store_parm("ny",material->ny);
close("parameters");
close("material");
}
void XMLWriter::store(Ref<SceneGraph::MaterialNode> mnode)
{
/* let materials reference by their name, allows separate bindings of materials */
if (referenceMaterials) {
tab(); xml << "<material id=\""+mnode->name+"\"/>" << std::endl;
return;
}
Ref<SceneGraph::Node> node = mnode.dynamicCast<SceneGraph::Node>();
if (nodeMap.find(node) != nodeMap.end()) {
tab(); xml << "<material id=\"" << nodeMap[node] << "\"/>" << std::endl;
return;
}
const ssize_t id = nodeMap[node] = currentNodeID++;
if (Ref<OBJMaterial> m = mnode.dynamicCast<OBJMaterial>()) store(m,id);
else if (Ref<ThinDielectricMaterial> m = mnode.dynamicCast<ThinDielectricMaterial>()) store(m,id);
else if (Ref<MetalMaterial> m = mnode.dynamicCast<MetalMaterial>()) store(m,id);
else if (Ref<VelvetMaterial> m = mnode.dynamicCast<VelvetMaterial>()) store(m,id);
else if (Ref<DielectricMaterial> m = mnode.dynamicCast<DielectricMaterial>()) store(m,id);
else if (Ref<MetallicPaintMaterial> m = mnode.dynamicCast<MetallicPaintMaterial>()) store(m,id);
else if (Ref<MatteMaterial> m = mnode.dynamicCast<MatteMaterial>()) store(m,id);
else if (Ref<MirrorMaterial> m = mnode.dynamicCast<MirrorMaterial>()) store(m,id);
else if (Ref<ReflectiveMetalMaterial> m = mnode.dynamicCast<ReflectiveMetalMaterial>()) store(m,id);
else if (Ref<HairMaterial> m = mnode.dynamicCast<HairMaterial>()) store(m,id);
else throw std::runtime_error("unsupported material");
}
void XMLWriter::store(Ref<SceneGraph::TriangleMeshNode> mesh, ssize_t id)
{
open("TriangleMesh",id);
store(mesh->material);
if (mesh->numTimeSteps() != 1) open("animated_positions");
for (const auto& p : mesh->positions) store("positions",p);
if (mesh->numTimeSteps() != 1) close("animated_positions");
if (mesh->numTimeSteps() != 1) open("animated_normals");
for (const auto& p : mesh->normals) store("normals",p);
if (mesh->numTimeSteps() != 1) close("animated_normals");
store("texcoords",mesh->texcoords);
store("triangles",mesh->triangles);
close("TriangleMesh");
}
void XMLWriter::store(Ref<SceneGraph::QuadMeshNode> mesh, ssize_t id)
{
open("QuadMesh",id);
store(mesh->material);
if (mesh->numTimeSteps() != 1) open("animated_positions");
for (const auto& p : mesh->positions) store("positions",p);
if (mesh->numTimeSteps() != 1) close("animated_positions");
if (mesh->numTimeSteps() != 1) open("animated_normals");
for (const auto& p : mesh->normals) store("normals",p);
if (mesh->numTimeSteps() != 1) close("animated_normals");
store("texcoords",mesh->texcoords);
store("indices",mesh->quads);
close("QuadMesh");
}
void XMLWriter::store(Ref<SceneGraph::SubdivMeshNode> mesh, ssize_t id)
{
open("SubdivisionMesh",id);
store(mesh->material);
if (mesh->numTimeSteps() != 1) open("animated_positions");
for (const auto& p : mesh->positions) store("positions",p);
if (mesh->numTimeSteps() != 1) close("animated_positions");
if (mesh->numTimeSteps() != 1) open("animated_normals");
for (const auto& p : mesh->normals) store("normals",p);
if (mesh->numTimeSteps() != 1) close("animated_normals");
store("texcoords",mesh->texcoords);
store("position_indices",mesh->position_indices);
store("normal_indices",mesh->normal_indices);
store("texcoord_indices",mesh->texcoord_indices);
store("faces",mesh->verticesPerFace);
store("holes",mesh->holes);
store("edge_creases",mesh->edge_creases);
store("edge_crease_weights",mesh->edge_crease_weights);
store("vertex_creases",mesh->vertex_creases);
store("vertex_crease_weights",mesh->vertex_crease_weights);
close("SubdivisionMesh");
}
void XMLWriter::store(Ref<SceneGraph::HairSetNode> mesh, ssize_t id)
{
std::string str_type = "";
std::string str_subtype = "";
switch (mesh->type) {
case RTC_GEOMETRY_TYPE_FLAT_LINEAR_CURVE:
str_type = "linear";
str_subtype = "flat";
break;
case RTC_GEOMETRY_TYPE_ROUND_BEZIER_CURVE:
str_type = "bezier";
str_subtype = "round";
break;
case RTC_GEOMETRY_TYPE_FLAT_BEZIER_CURVE:
str_type = "bezier";
str_subtype = "flat";
break;
case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BEZIER_CURVE:
str_type = "bezier";
str_subtype = "oriented";
break;
case RTC_GEOMETRY_TYPE_ROUND_BSPLINE_CURVE:
str_type = "bspline";
str_subtype = "round";
break;
case RTC_GEOMETRY_TYPE_FLAT_BSPLINE_CURVE:
str_type = "bspline";
str_subtype = "flat";
break;
case RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_BSPLINE_CURVE:
str_type = "bspline";
str_subtype = "oriented";
break;
default:
throw std::runtime_error("invalid curve type");
}
std::vector<int> indices(mesh->hairs.size());
std::vector<int> hairid(mesh->hairs.size());
for (size_t i=0; i<mesh->hairs.size(); i++) {
indices[i] = mesh->hairs[i].vertex;
hairid[i] = mesh->hairs[i].id;
}
open("Curves type=\""+str_subtype+"\" basis=\""+str_type+"\"",id);
store(mesh->material);
if (mesh->numTimeSteps() != 1) open("animated_positions");
for (const auto& p : mesh->positions) store("positions",p);
if (mesh->numTimeSteps() != 1) close("animated_positions");
if (mesh->normals.size()) {
if (mesh->numTimeSteps() != 1) open("animated_normals");
for (const auto& p : mesh->normals) store("normals",p);
if (mesh->numTimeSteps() != 1) close("animated_normals");
}
store("indices",indices);
store("hairid",hairid);
close("Curves");
}
void XMLWriter::store(Ref<SceneGraph::PerspectiveCameraNode> camera, ssize_t id)
{
tab();
xml << "<PerspectiveCamera " <<
"id=\"" << id << "\" " <<
"name=\"" << camera->name << "\" " <<
"from=\"" << camera->data.from.x << " " << camera->data.from.y << " " << camera->data.from.z << "\" " <<
"to=\"" << camera->data.to.x << " " << camera->data.to.y << " " << camera->data.to.z << "\" " <<
"up=\"" << camera->data.up.x << " " << camera->data.up.y << " " << camera->data.up.z << "\" " <<
"fov=\"" << camera->data.fov << "\" " << "/>" << std::endl;
}
void XMLWriter::store(Ref<SceneGraph::AnimatedPerspectiveCameraNode> camera, ssize_t id)
{
open(std::string("AnimatedPerspectiveCamera ")+
"name=\"" + camera->name + "\" "
"time_range=\""+std::to_string(camera->time_range.lower)+" "+std::to_string(camera->time_range.upper)+"\"");
for (size_t i=0; i<camera->size(); i++)
store(camera->cameras[i].dynamicCast<SceneGraph::Node>());
close("AnimatedPerspectiveCamera");
}
void XMLWriter::store(Ref<SceneGraph::TransformNode> node, ssize_t id)
{
if (node->spaces.size() == 1)
{
open("Transform",id);
store("AffineSpace",node->spaces[0]);
store(node->child);
close("Transform");
}
else
{
open("TransformAnimation",id);
for (size_t i=0; i<node->spaces.size(); i++)
store("AffineSpace",node->spaces[i]);
store(node->child);
close("TransformAnimation");
}
}
void XMLWriter::store(std::vector<Ref<SceneGraph::TransformNode>> nodes)
{
if (nodes.size() == 0)
return;
if (nodes.size() == 1) {
store(nodes[0].dynamicCast<SceneGraph::Node>());
return;
}
open("MultiTransform");
std::streampos offset = bin.tellg();
tab(); xml << "<AffineSpace3f ofs=\"" << offset << "\" size=\"" << nodes.size() << "\"/>" << std::endl;
for (size_t i=0; i<nodes.size(); i++) {
assert(nodes[i]->spaces.size() == 1);
assert(nodes[i]->child == nodes[0]->child);
bin.write((char*)&nodes[i]->spaces[0].l.vx,sizeof(Vec3f));
bin.write((char*)&nodes[i]->spaces[0].l.vy,sizeof(Vec3f));
bin.write((char*)&nodes[i]->spaces[0].l.vz,sizeof(Vec3f));
bin.write((char*)&nodes[i]->spaces[0].p,sizeof(Vec3f));
}
store(nodes[0]->child);
close("MultiTransform");
}
void XMLWriter::store(Ref<SceneGraph::GroupNode> group, ssize_t id)
{
open("Group",id);
std::map<Ref<SceneGraph::Node>,std::vector<Ref<SceneGraph::TransformNode>>> object_to_transform_map;
for (size_t i=0; i<group->children.size(); i++)
{
/* compress transformation of the same object into MultiTransform nodes if possible */
if (Ref<SceneGraph::TransformNode> xfmNode = group->children[i].dynamicCast<SceneGraph::TransformNode>())
{
/* we can only compress non-animated transform nodes and only ones that are referenced once */
if (xfmNode->spaces.size() == 1 && xfmNode->indegree == 1)
{
Ref<SceneGraph::Node> child = xfmNode->child;
if (object_to_transform_map.find(child) == object_to_transform_map.end()) {
object_to_transform_map[child] = std::vector<Ref<SceneGraph::TransformNode>>();
}
object_to_transform_map[child].push_back(xfmNode);
continue;
}
}
store(group->children[i]);
}
/* store all compressed transform nodes */
for (auto& i : object_to_transform_map)
store(i.second);
close("Group");
}
void XMLWriter::store(Ref<SceneGraph::Node> node)
{
if (nodeMap.find(node) != nodeMap.end()) {
tab(); xml << "<ref id=\"" << nodeMap[node] << "\"/>" << std::endl; return;
}
const ssize_t id = nodeMap[node] = currentNodeID++;
if (node->fileName != "") {
tab(); xml << "<extern id=\"" << id << "\" src=\"" << node->fileName << "\"/>" << std::endl; return;
}
if (Ref<SceneGraph::AnimatedLightNode> cnode = node.dynamicCast<SceneGraph::AnimatedLightNode>()) store(cnode,id);
else if (Ref<SceneGraph::LightNode> cnode = node.dynamicCast<SceneGraph::LightNode>()) store(cnode,id);
//else if (Ref<SceneGraph::MaterialNode> cnode = node.dynamicCast<SceneGraph::MaterialNode>()) store(cnode,id);
else if (Ref<SceneGraph::TriangleMeshNode> cnode = node.dynamicCast<SceneGraph::TriangleMeshNode>()) store(cnode,id);
else if (Ref<SceneGraph::QuadMeshNode> cnode = node.dynamicCast<SceneGraph::QuadMeshNode>()) store(cnode,id);
else if (Ref<SceneGraph::SubdivMeshNode> cnode = node.dynamicCast<SceneGraph::SubdivMeshNode>()) store(cnode,id);
else if (Ref<SceneGraph::HairSetNode> cnode = node.dynamicCast<SceneGraph::HairSetNode>()) store(cnode,id);
else if (Ref<SceneGraph::AnimatedPerspectiveCameraNode> cnode = node.dynamicCast<SceneGraph::AnimatedPerspectiveCameraNode>()) store(cnode,id);
else if (Ref<SceneGraph::PerspectiveCameraNode> cnode = node.dynamicCast<SceneGraph::PerspectiveCameraNode>()) store(cnode,id);
else if (Ref<SceneGraph::TransformNode> cnode = node.dynamicCast<SceneGraph::TransformNode>()) store(cnode,id);
else if (Ref<SceneGraph::GroupNode> cnode = node.dynamicCast<SceneGraph::GroupNode>()) store(cnode,id);
else throw std::runtime_error("unknown node type");
}
XMLWriter::XMLWriter(Ref<SceneGraph::Node> root, const FileName& fileName, bool embedTextures, bool referenceMaterials, bool binaryFormat)
: ident(0), currentNodeID(0), embedTextures(embedTextures), referenceMaterials(referenceMaterials), binaryFormat(binaryFormat)
{
xml.exceptions (std::fstream::failbit | std::fstream::badbit);
xml.open (fileName, std::fstream::out);
if (binaryFormat)
{
const FileName binFileName = fileName.addExt(".bin");
bin.exceptions (std::fstream::failbit | std::fstream::badbit);
bin.open (binFileName, std::fstream::out | std::fstream::binary);
}
xml << "<?xml version=\"1.0\"?>" << std::endl;
root->calculateInDegree();
open("scene");
store(root);
close("scene");
root->resetInDegree();
}
void SceneGraph::storeXML(Ref<SceneGraph::Node> root, const FileName& fileName, bool embedTextures, bool referenceMaterials, bool binaryFormat) {
XMLWriter(root,fileName,embedTextures,referenceMaterials,binaryFormat);
}
}

View file

@ -0,0 +1,15 @@
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include "scenegraph.h"
namespace embree
{
namespace SceneGraph
{
void storeXML(Ref<SceneGraph::Node> root, const FileName& fileName, bool embedTextures, bool referenceMaterials, bool binaryFormat);
}
}