247 lines
8.2 KiB
C++
Executable File
247 lines
8.2 KiB
C++
Executable File
// ======================================================================== //
|
|
// Copyright 2009-2014 Intel Corporation //
|
|
// //
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); //
|
|
// you may not use this file except in compliance with the License. //
|
|
// You may obtain a copy of the License at //
|
|
// //
|
|
// http://www.apache.org/licenses/LICENSE-2.0 //
|
|
// //
|
|
// Unless required by applicable law or agreed to in writing, software //
|
|
// distributed under the License is distributed on an "AS IS" BASIS, //
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
|
|
// See the License for the specific language governing permissions and //
|
|
// limitations under the License. //
|
|
// ======================================================================== //
|
|
|
|
#include "hair_loader.h"
|
|
|
|
#define CONVERT_TO_BINARY 0
|
|
|
|
namespace embree
|
|
{
|
|
float g_reduce_hair_segment_error = 0.0f;
|
|
const int hair_bin_magick = 0x12EF3F90;
|
|
|
|
int loadHairASCII(const FileName& fileName, OBJScene::HairSet* hairset, Vec3fa& offset)
|
|
{
|
|
/* open hair file */
|
|
FILE* f = fopen(fileName.c_str(),"r");
|
|
if (!f) THROW_RUNTIME_ERROR("could not open " + fileName.str());
|
|
|
|
char line[10000];
|
|
fgets(line,10000,f);
|
|
int numCurves = 0;
|
|
|
|
while (fgets(line,10000,f) && !feof(f))
|
|
{
|
|
/* comment */
|
|
if (line[0] == '#')
|
|
continue;
|
|
|
|
if (!strncmp(line,"Curve:",strlen("Curve:")))
|
|
{
|
|
char name[1000];
|
|
unsigned int tracks, points;
|
|
sscanf(line,"Curve: %s %d Tracks %d Points",name,&tracks,&points);
|
|
|
|
/* skip Tracks line */
|
|
fgets(line,10000,f);
|
|
|
|
const int vertex_start_id = hairset->v.size();
|
|
|
|
unsigned int id = 0;
|
|
for (int i=0; i<points; i++)
|
|
{
|
|
fgets(line,10000,f);
|
|
|
|
/* comment */
|
|
if (line[0] == '#' || !strncmp(line," Tracks:",strlen(" Tracks:")))
|
|
continue;
|
|
|
|
Vec3fa v;
|
|
if (i == 0) sscanf(line,"%d : Bezier %f %f %f %f",&id,&v.x,&v.y,&v.z,&v.w);
|
|
else sscanf(line,"%d : %f %f %f %f",&id,&v.x,&v.y,&v.z,&v.w);
|
|
//printf("%d %d : %f %f %f %f \n",id,vertex_start_id+id,v.x,v.y,v.z,v.w);
|
|
v.x-=offset.x;
|
|
v.y-=offset.y;
|
|
v.z-=offset.z;
|
|
hairset->v.push_back(v);
|
|
}
|
|
|
|
/* add indices to hair starts */
|
|
for (int i=0; i<points-1; i+=3)
|
|
hairset->hairs.push_back(OBJScene::Hair(vertex_start_id + i,numCurves));
|
|
|
|
if (id != points-1)
|
|
THROW_RUNTIME_ERROR("hair parsing error");
|
|
|
|
numCurves++;
|
|
}
|
|
}
|
|
fclose(f);
|
|
return numCurves;
|
|
}
|
|
|
|
int loadHairBin(const FileName& fileName, OBJScene::HairSet* hairset, Vec3fa& offset)
|
|
{
|
|
FILE* fin = fopen(fileName.c_str(),"rb");
|
|
if (!fin) THROW_RUNTIME_ERROR("could not open " + fileName.str());
|
|
int magick; fread(&magick,sizeof(int),1,fin);
|
|
if (magick != hair_bin_magick)
|
|
THROW_RUNTIME_ERROR("invalid binary hair file " + fileName.str());
|
|
int numHairs; fread(&numHairs,sizeof(int),1,fin);
|
|
int numPoints; fread(&numPoints,sizeof(int),1,fin);
|
|
int numSegments; fread(&numSegments,sizeof(int),1,fin);
|
|
hairset->v.resize(numPoints);
|
|
hairset->hairs.resize(numSegments);
|
|
if (numPoints) fread(&hairset->v[0],sizeof(Vec3fa),numPoints,fin);
|
|
if (numSegments) fread(&hairset->hairs[0],sizeof(OBJScene::Hair),numSegments,fin);
|
|
fclose(fin);
|
|
|
|
for (size_t i=0; i<numPoints; i++) {
|
|
hairset->v[i].x-=offset.x;
|
|
hairset->v[i].y-=offset.y;
|
|
hairset->v[i].z-=offset.z;
|
|
}
|
|
return numHairs;
|
|
}
|
|
|
|
OBJScene::HairSet* reduce_hairs(OBJScene::HairSet* in, float relative_error)
|
|
{
|
|
OBJScene::HairSet* out = new OBJScene::HairSet;
|
|
int numSegments = in->hairs.size();
|
|
|
|
for (size_t i=0; i<numSegments; i++)
|
|
{
|
|
const OBJScene::Hair h0 = in->hairs[i+0];
|
|
const Vec3fa a0 = in->v[h0.vertex+0];
|
|
const Vec3fa a1 = in->v[h0.vertex+1];
|
|
const Vec3fa a2 = in->v[h0.vertex+2];
|
|
const Vec3fa a3 = in->v[h0.vertex+3];
|
|
|
|
if (i+1 >= numSegments)
|
|
{
|
|
if (out->v.size() == 0 || out->v.back() != a0)
|
|
out->v.push_back(a0);
|
|
out->v.push_back(a1);
|
|
out->v.push_back(a2);
|
|
out->v.push_back(a3);
|
|
out->hairs.push_back(OBJScene::Hair(out->v.size()-4,h0.id));
|
|
continue;
|
|
}
|
|
|
|
const OBJScene::Hair h1 = in->hairs[i+1];
|
|
const Vec3fa b0 = in->v[h1.vertex+0];
|
|
const Vec3fa b1 = in->v[h1.vertex+1];
|
|
const Vec3fa b2 = in->v[h1.vertex+2];
|
|
const Vec3fa b3 = in->v[h1.vertex+3];
|
|
|
|
if (h0.vertex+3 != h1.vertex || h0.id != h1.id)
|
|
{
|
|
if (out->v.size() == 0 || out->v.back() != a0)
|
|
out->v.push_back(a0);
|
|
out->v.push_back(a1);
|
|
out->v.push_back(a2);
|
|
out->v.push_back(a3);
|
|
out->hairs.push_back(OBJScene::Hair(out->v.size()-4,h0.id));
|
|
continue;
|
|
}
|
|
|
|
const Vec3fa c0 = a0;
|
|
const Vec3fa c1 = 2*a1-a0;
|
|
const Vec3fa c2 = 2*b2-b3;
|
|
const Vec3fa c3 = b3;
|
|
|
|
const Vec3fa p00 = c0;
|
|
const Vec3fa p01 = c1;
|
|
const Vec3fa p02 = c2;
|
|
const Vec3fa p03 = c3;
|
|
const Vec3fa p10 = 0.5f*(p00 + p01);
|
|
const Vec3fa p11 = 0.5f*(p01 + p02);
|
|
const Vec3fa p12 = 0.5f*(p02 + p03);
|
|
const Vec3fa p20 = 0.5f*(p10 + p11);
|
|
const Vec3fa p21 = 0.5f*(p11 + p12);
|
|
const Vec3fa p30 = 0.5f*(p20 + p21);
|
|
|
|
const float len = length(a3-a0) + length(b3-b0);
|
|
const float err = length(p30-a3);
|
|
|
|
if (err > relative_error*len)
|
|
{
|
|
if (out->v.size() == 0 || out->v.back() != a0)
|
|
out->v.push_back(a0);
|
|
out->v.push_back(a1);
|
|
out->v.push_back(a2);
|
|
out->v.push_back(a3);
|
|
out->hairs.push_back(OBJScene::Hair(out->v.size()-4,h0.id));
|
|
}
|
|
else
|
|
{
|
|
if (out->v.size() == 0 || out->v.back() != c0)
|
|
out->v.push_back(c0);
|
|
out->v.push_back(c1);
|
|
out->v.push_back(c2);
|
|
out->v.push_back(c3);
|
|
out->hairs.push_back(OBJScene::Hair(out->v.size()-4,h0.id));
|
|
i++;
|
|
}
|
|
}
|
|
|
|
delete in;
|
|
return out;
|
|
}
|
|
|
|
void loadHair(const FileName& fileName, OBJScene& scene, Vec3fa& offset)
|
|
{
|
|
/* add new hair set to scene */
|
|
OBJScene::HairSet* hairset = new OBJScene::HairSet;
|
|
#if CONVERT_TO_BINARY
|
|
offset = Vec3fa(zero);
|
|
#endif
|
|
|
|
int numHairs = 0;
|
|
if (fileName.ext() == "txt")
|
|
numHairs = loadHairASCII(fileName,hairset,offset);
|
|
else
|
|
numHairs = loadHairBin(fileName,hairset,offset);
|
|
|
|
/* reduce number of hairs */
|
|
if (g_reduce_hair_segment_error != 0.0f)
|
|
{
|
|
std::ios_base :: fmtflags flag = std::cout.flags();
|
|
std :: streamsize prec = std::cout.precision();
|
|
std::cout << "reducing number of hair segments ... " << std::flush;
|
|
std::cout.precision(3);
|
|
std::cout << 1E-6*float(hairset->hairs.size()) << "M" << std::flush;
|
|
for (size_t i=0; i<10; i++) {
|
|
hairset = reduce_hairs(hairset,g_reduce_hair_segment_error);
|
|
std::cout << " " << 1E-6*float(hairset->hairs.size()) << "M" << std::flush;
|
|
}
|
|
std::cout << " [DONE]" << std::endl;
|
|
std::cout.flags (flag);
|
|
std::cout.precision(prec);
|
|
}
|
|
|
|
/* add hairset to scene */
|
|
scene.hairsets.push_back(hairset);
|
|
|
|
int numPoints = hairset->v.size();
|
|
int numSegments = hairset->hairs.size();
|
|
|
|
#if CONVERT_TO_BINARY
|
|
FILE* fout = fopen(fileName.setExt(".bin").c_str(),"wb");
|
|
if (!fout) THROW_RUNTIME_ERROR("could not open " + fileName.str());
|
|
fwrite(&hair_bin_magick,sizeof(int),1,fout);
|
|
fwrite(&numHairs,sizeof(int),1,fout);
|
|
fwrite(&numPoints,sizeof(int),1,fout);
|
|
fwrite(&numSegments,sizeof(int),1,fout);
|
|
if (numPoints) fwrite(&hairset->v[0],sizeof(Vec3fa),numPoints,fout);
|
|
if (numSegments) fwrite(&hairset->hairs[0],sizeof(OBJScene::Hair),numSegments,fout);
|
|
fclose(fout);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|