Add Chromium-only Blender WebEngine parity work
This commit is contained in:
44
blender-5.2.0/extern/opensubdiv-source/regression/common/CMakeLists.txt
vendored
Normal file
44
blender-5.2.0/extern/opensubdiv-source/regression/common/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
|
||||
set(REGRESSION_COMMON_SOURCE_FILES
|
||||
arg_utils.cpp
|
||||
shape_utils.cpp
|
||||
)
|
||||
|
||||
set(REGRESSION_COMMON_HEADER_FILES
|
||||
arg_utils.h
|
||||
cmp_utils.h
|
||||
hbr_utils.h
|
||||
shape_utils.h
|
||||
far_utils.h
|
||||
)
|
||||
|
||||
include_directories("${OPENSUBDIV_INCLUDE_DIR}")
|
||||
|
||||
add_library(regression_common_obj
|
||||
OBJECT
|
||||
${REGRESSION_COMMON_SOURCE_FILES}
|
||||
${REGRESSION_COMMON_HEADER_FILES}
|
||||
)
|
||||
|
||||
set_target_properties(regression_common_obj
|
||||
PROPERTIES
|
||||
FOLDER "regression"
|
||||
)
|
||||
|
||||
add_library(regression_far_utils_obj
|
||||
OBJECT
|
||||
far_utils.cpp
|
||||
far_utils.h
|
||||
)
|
||||
|
||||
set_target_properties(regression_far_utils_obj
|
||||
PROPERTIES
|
||||
FOLDER "regression"
|
||||
)
|
||||
|
||||
109
blender-5.2.0/extern/opensubdiv-source/regression/common/arg_utils.cpp
vendored
Normal file
109
blender-5.2.0/extern/opensubdiv-source/regression/common/arg_utils.cpp
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// Copyright 2019 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#include "arg_utils.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static int
|
||||
parseIntArg(const char* argString, int dfltValue = 0) {
|
||||
char *argEndptr;
|
||||
int argValue = (int) strtol(argString, &argEndptr, 10);
|
||||
if (*argEndptr != 0) {
|
||||
printf("Warning: non-integer option parameter '%s' ignored\n",
|
||||
argString);
|
||||
argValue = dfltValue;
|
||||
}
|
||||
return argValue;
|
||||
}
|
||||
|
||||
|
||||
ArgOptions::ArgOptions()
|
||||
: _adaptive(true)
|
||||
, _fullscreen(false)
|
||||
, _level(2)
|
||||
, _objsAreAnim(false)
|
||||
, _yup(false)
|
||||
, _repeatCount(0)
|
||||
, _defaultScheme(kCatmark)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ArgOptions::Parse(int argc, char **argv)
|
||||
{
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
|
||||
if (strstr(argv[i], ".obj")) {
|
||||
_objFiles.push_back(argv[i]);
|
||||
} else if (!strcmp(argv[i], "-a")) {
|
||||
_adaptive = true;
|
||||
} else if (!strcmp(argv[i], "-u")) {
|
||||
_adaptive = false;
|
||||
} else if (!strcmp(argv[i], "-l")) {
|
||||
if (++i < argc) _level = parseIntArg(argv[i], 2);
|
||||
} else if (!strcmp(argv[i], "-c")) {
|
||||
if (++i < argc) _repeatCount = parseIntArg(argv[i], 0);
|
||||
} else if (!strcmp(argv[i], "-f")) {
|
||||
_fullscreen = true;
|
||||
} else if (!strcmp(argv[i], "-yup")) {
|
||||
_yup = true;
|
||||
} else if (!strcmp(argv[i], "-anim")) {
|
||||
_objsAreAnim = true;
|
||||
} else if (!strcmp(argv[i], "-bilinear")) {
|
||||
_defaultScheme = kBilinear;
|
||||
} else if (!strcmp(argv[i], "-catmark")) {
|
||||
_defaultScheme = kCatmark;
|
||||
} else if (!strcmp(argv[i], "-loop")) {
|
||||
_defaultScheme = kLoop;
|
||||
} else {
|
||||
_remainingArgs.push_back(argv[i]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ArgOptions::PrintUnrecognizedArgWarning(const char *arg) const
|
||||
{
|
||||
printf("Warning: unrecognized argument '%s' ignored\n", arg);
|
||||
}
|
||||
|
||||
void
|
||||
ArgOptions::PrintUnrecognizedArgsWarnings() const
|
||||
{
|
||||
for(size_t i = 0; i < _remainingArgs.size(); ++i) {
|
||||
PrintUnrecognizedArgWarning(_remainingArgs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
ArgOptions::AppendObjShapes(std::vector<ShapeDesc>& shapes, bool warn) const
|
||||
{
|
||||
size_t originalShapesSize = shapes.size();
|
||||
|
||||
for (size_t i = 0; i < GetObjFiles().size(); ++i) {
|
||||
std::ifstream ifs(GetObjFiles()[i]);
|
||||
if (ifs) {
|
||||
std::stringstream ss;
|
||||
ss << ifs.rdbuf();
|
||||
ifs.close();
|
||||
std::string str = ss.str();
|
||||
shapes.push_back(ShapeDesc(
|
||||
GetObjFiles()[i], str.c_str(),
|
||||
GetDefaultScheme()));
|
||||
} else if (warn) {
|
||||
printf("Warning: cannot open shape file '%s'\n",
|
||||
GetObjFiles()[i]);
|
||||
}
|
||||
}
|
||||
return shapes.size() - originalShapesSize;
|
||||
}
|
||||
85
blender-5.2.0/extern/opensubdiv-source/regression/common/arg_utils.h
vendored
Normal file
85
blender-5.2.0/extern/opensubdiv-source/regression/common/arg_utils.h
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
//
|
||||
// Copyright 2019 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef ARG_UTILS_H
|
||||
#define ARG_UTILS_H
|
||||
|
||||
#include "shape_utils.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class ArgOptions
|
||||
{
|
||||
public:
|
||||
|
||||
ArgOptions();
|
||||
|
||||
// Uses argc and argv to initialize the members of this object.
|
||||
void Parse(int argc, char **argv);
|
||||
|
||||
// Prints out unrecognized argument warnings for each argument left in
|
||||
// remainingArgs
|
||||
void PrintUnrecognizedArgsWarnings() const;
|
||||
|
||||
// Print unrecognized warning for arg
|
||||
void PrintUnrecognizedArgWarning(const char *arg) const;
|
||||
|
||||
|
||||
// Accessors to parsed arguments
|
||||
//
|
||||
|
||||
bool GetAdaptive() const { return _adaptive; }
|
||||
|
||||
bool GetFullScreen() const { return _fullscreen; }
|
||||
|
||||
int GetLevel() const { return _level; }
|
||||
|
||||
bool GetObjsAreAnim() const { return _objsAreAnim; }
|
||||
|
||||
bool GetYUp() const { return _yup; }
|
||||
|
||||
int GetRepeatCount() const { return _repeatCount; }
|
||||
|
||||
Scheme GetDefaultScheme() const { return _defaultScheme; }
|
||||
|
||||
const std::vector<const char *> GetObjFiles() const { return _objFiles; }
|
||||
|
||||
const std::vector<const char *> GetRemainingArgs() const {
|
||||
return _remainingArgs; }
|
||||
|
||||
|
||||
// Operations on parsed arguments
|
||||
//
|
||||
|
||||
size_t AppendObjShapes(std::vector<ShapeDesc>& shapes,
|
||||
bool warn = true) const;
|
||||
|
||||
private:
|
||||
|
||||
bool _adaptive;
|
||||
|
||||
bool _fullscreen;
|
||||
|
||||
int _level;
|
||||
|
||||
bool _objsAreAnim;
|
||||
|
||||
bool _yup;
|
||||
|
||||
int _repeatCount;
|
||||
|
||||
Scheme _defaultScheme;
|
||||
|
||||
// .obj files that we've parsed
|
||||
std::vector<const char *> _objFiles;
|
||||
|
||||
// Remaining args that we have not parsed, in order that they've appeared
|
||||
std::vector<const char *> _remainingArgs;
|
||||
|
||||
};
|
||||
|
||||
#endif // COMMON_ARGS_H
|
||||
187
blender-5.2.0/extern/opensubdiv-source/regression/common/cmp_utils.h
vendored
Normal file
187
blender-5.2.0/extern/opensubdiv-source/regression/common/cmp_utils.h
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef CMP_UTILS_H
|
||||
#define CMP_UTILS_H
|
||||
|
||||
#include <opensubdiv/far/topologyRefinerFactory.h>
|
||||
|
||||
#include "hbr_utils.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
template <class Face, class Edge, class Vertex>
|
||||
struct LevelMapT {
|
||||
std::vector<Face *> faces;
|
||||
std::vector<Edge *> edges;
|
||||
std::vector<Vertex *> verts;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Copies vertex data from hbrMesh into hbrVertexData reordered to match
|
||||
// the given refiner and subdivision level. This is used for later easy
|
||||
// comparison between the two.
|
||||
template<class T>
|
||||
void
|
||||
GetReorderedHbrVertexData(
|
||||
const OpenSubdiv::Far::TopologyRefiner &farRefiner,
|
||||
const OpenSubdiv::HbrMesh<T> &hbrMesh,
|
||||
std::vector<T> *hbrVertexData,
|
||||
std::vector<bool> *hbrVertexOnBoundaryData = NULL)
|
||||
{
|
||||
typedef OpenSubdiv::HbrVertex<T> Hvertex;
|
||||
typedef OpenSubdiv::HbrFace<T> Hface;
|
||||
typedef OpenSubdiv::HbrHalfedge<T> Hhalfedge;
|
||||
|
||||
struct Mapper {
|
||||
typedef LevelMapT<Hface, Hhalfedge, Hvertex> LevelMap;
|
||||
std::vector<LevelMap> maps;
|
||||
|
||||
Mapper(const OpenSubdiv::Far::TopologyRefiner &refiner,
|
||||
const OpenSubdiv::HbrMesh<T> &hmesh) {
|
||||
|
||||
bool schemeIsLoop = (refiner.GetSchemeType() == OpenSubdiv::Sdc::SCHEME_LOOP);
|
||||
|
||||
maps.resize(refiner.GetMaxLevel()+1);
|
||||
|
||||
typedef OpenSubdiv::Far::Index Index;
|
||||
typedef OpenSubdiv::Far::ConstIndexArray ConstIndexArray;
|
||||
|
||||
{ // Populate base level
|
||||
// note : topological ordering is identical between Hbr and Far
|
||||
// for the base level
|
||||
OpenSubdiv::Far::TopologyLevel const & refBaseLevel = refiner.GetLevel(0);
|
||||
|
||||
int nfaces = refBaseLevel.GetNumFaces(),
|
||||
nedges = refBaseLevel.GetNumEdges(),
|
||||
nverts = refBaseLevel.GetNumVertices();
|
||||
|
||||
maps[0].faces.resize(nfaces, 0);
|
||||
maps[0].edges.resize(nedges, 0);
|
||||
maps[0].verts.resize(nverts, 0);
|
||||
|
||||
for (int face=0; face<nfaces; ++face) {
|
||||
maps[0].faces[face] = hmesh.GetFace(face);
|
||||
}
|
||||
|
||||
for (int edge = 0; edge <nedges; ++edge) {
|
||||
|
||||
ConstIndexArray farVerts = refBaseLevel.GetEdgeVertices(edge);
|
||||
|
||||
Hvertex const * v0 = hmesh.GetVertex(farVerts[0]),
|
||||
* v1 = hmesh.GetVertex(farVerts[1]);
|
||||
|
||||
Hhalfedge * e = v0->GetEdge(v1);
|
||||
if (! e) {
|
||||
e = v1->GetEdge(v0);
|
||||
}
|
||||
assert(e);
|
||||
|
||||
maps[0].edges[edge] = e;
|
||||
}
|
||||
|
||||
for (int vert = 0; vert<nverts; ++vert) {
|
||||
maps[0].verts[vert] = hmesh.GetVertex(vert);
|
||||
}
|
||||
}
|
||||
|
||||
// Populate refined levels
|
||||
for (int level=1, ecount=0; level<=refiner.GetMaxLevel(); ++level) {
|
||||
|
||||
LevelMap & previous = maps[level-1],
|
||||
& current = maps[level];
|
||||
|
||||
OpenSubdiv::Far::TopologyLevel const & refLevel = refiner.GetLevel(level);
|
||||
OpenSubdiv::Far::TopologyLevel const & refPrevLevel = refiner.GetLevel(level-1);
|
||||
|
||||
current.faces.resize(refLevel.GetNumFaces(), 0);
|
||||
current.edges.resize(refLevel.GetNumEdges(), 0);
|
||||
current.verts.resize(refLevel.GetNumVertices(), 0);
|
||||
|
||||
for (int face=0; face < refPrevLevel.GetNumFaces(); ++face) {
|
||||
|
||||
// populate child faces
|
||||
Hface * f = previous.faces[face];
|
||||
|
||||
ConstIndexArray childFaces = refPrevLevel.GetFaceChildFaces(face);
|
||||
for (int i=0; i<childFaces.size(); ++i) {
|
||||
current.faces[childFaces[i]] = f->GetChild(i);
|
||||
}
|
||||
|
||||
// populate child face-verts -- when present (none for Loop subdivision)
|
||||
if (!schemeIsLoop) {
|
||||
Hvertex * v = f->Subdivide();
|
||||
Index childVert = refPrevLevel.GetFaceChildVertex(face);
|
||||
assert(v->GetParentFace());
|
||||
current.verts[childVert] = v;
|
||||
}
|
||||
}
|
||||
|
||||
for (int edge=0; edge < refPrevLevel.GetNumEdges(); ++edge) {
|
||||
// populate child edge-verts
|
||||
Index childVert = refPrevLevel.GetEdgeChildVertex(edge);
|
||||
Hhalfedge * e = previous.edges[edge];
|
||||
Hvertex * v = e->Subdivide();
|
||||
assert(v->GetParentEdge());
|
||||
current.verts[childVert] = v;
|
||||
}
|
||||
|
||||
for (int vert = 0; vert < refPrevLevel.GetNumVertices(); ++vert) {
|
||||
// populate child vert-verts
|
||||
Index childVert = refPrevLevel.GetVertexChildVertex(vert);
|
||||
Hvertex * v = previous.verts[vert]->Subdivide();
|
||||
current.verts[childVert] = v;
|
||||
assert(v->GetParentVertex());
|
||||
}
|
||||
|
||||
// populate child edges
|
||||
for (int edge=0; edge < refLevel.GetNumEdges(); ++edge) {
|
||||
|
||||
ConstIndexArray farVerts = refLevel.GetEdgeVertices(edge);
|
||||
|
||||
Hvertex const * v0 = current.verts[farVerts[0]],
|
||||
* v1 = current.verts[farVerts[1]];
|
||||
assert(v0 && v1);
|
||||
|
||||
Hhalfedge * e= v0->GetEdge(v1);
|
||||
if (! e) {
|
||||
e = v1->GetEdge(v0);
|
||||
}
|
||||
assert(e);
|
||||
current.edges[edge] = e;
|
||||
}
|
||||
ecount += refPrevLevel.GetNumEdges();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Mapper mapper(farRefiner, hbrMesh);
|
||||
|
||||
int nverts = hbrMesh.GetNumVertices();
|
||||
assert( nverts==farRefiner.GetNumVerticesTotal() );
|
||||
|
||||
hbrVertexData->resize(nverts);
|
||||
|
||||
for (int level=0, ofs=0; level<(farRefiner.GetMaxLevel()+1); ++level) {
|
||||
|
||||
typename Mapper::LevelMap & map = mapper.maps[level];
|
||||
for (int i=0; i<(int)map.verts.size(); ++i) {
|
||||
Hvertex * v = map.verts[i];
|
||||
if (hbrVertexOnBoundaryData) {
|
||||
(*hbrVertexOnBoundaryData)[ofs] = hbrVertexOnBoundary(v);
|
||||
}
|
||||
(*hbrVertexData)[ofs++] = v->GetData();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endif /* CMP_UTILS_H */
|
||||
79
blender-5.2.0/extern/opensubdiv-source/regression/common/far_utils.cpp
vendored
Normal file
79
blender-5.2.0/extern/opensubdiv-source/regression/common/far_utils.cpp
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#include "far_utils.h"
|
||||
|
||||
struct FVarVertex {
|
||||
|
||||
float u,v;
|
||||
|
||||
void Clear() {
|
||||
u=v=0.0f;
|
||||
}
|
||||
|
||||
void AddWithWeight(FVarVertex const & src, float weight) {
|
||||
u += weight * src.u;
|
||||
v += weight * src.v;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
InterpolateFVarData(OpenSubdiv::Far::TopologyRefiner & refiner,
|
||||
Shape const & shape, std::vector<float> & fvarData) {
|
||||
|
||||
int channel = 0, // shapes only have 1 UV channel
|
||||
fvarWidth = 2;
|
||||
|
||||
int maxlevel = refiner.GetMaxLevel(),
|
||||
numValuesM = refiner.GetLevel(maxlevel).GetNumFVarValues(channel),
|
||||
numValuesTotal = refiner.GetNumFVarValuesTotal(channel);
|
||||
|
||||
if (shape.uvs.empty() || numValuesTotal<=0) {
|
||||
return;
|
||||
}
|
||||
|
||||
OpenSubdiv::Far::PrimvarRefiner primvarRefiner(refiner);
|
||||
|
||||
if (refiner.IsUniform()) {
|
||||
|
||||
// For uniform we only keep the highest level of refinement:
|
||||
fvarData.resize(numValuesM * fvarWidth);
|
||||
|
||||
std::vector<FVarVertex> buffer(numValuesTotal - numValuesM);
|
||||
|
||||
FVarVertex * src = &buffer[0];
|
||||
memcpy(src, &shape.uvs[0], shape.uvs.size()*sizeof(float));
|
||||
|
||||
// Defer the last level to treat separately with its alternate destination:
|
||||
for (int level = 1; level < maxlevel; ++level) {
|
||||
FVarVertex * dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);
|
||||
|
||||
primvarRefiner.InterpolateFaceVarying(level, src, dst, channel);
|
||||
|
||||
src = dst;
|
||||
}
|
||||
|
||||
FVarVertex * dst = reinterpret_cast<FVarVertex *>(&fvarData[0]);
|
||||
primvarRefiner.InterpolateFaceVarying(maxlevel, src, dst, channel);
|
||||
|
||||
} else {
|
||||
|
||||
// For adaptive we keep all levels:
|
||||
fvarData.resize(numValuesTotal * fvarWidth);
|
||||
|
||||
FVarVertex * src = reinterpret_cast<FVarVertex *>(&fvarData[0]);
|
||||
memcpy(src, &shape.uvs[0], shape.uvs.size()*sizeof(float));
|
||||
|
||||
for (int level = 1; level <= maxlevel; ++level) {
|
||||
FVarVertex * dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);
|
||||
|
||||
primvarRefiner.InterpolateFaceVarying(level, src, dst, channel);
|
||||
|
||||
src = dst;
|
||||
}
|
||||
}
|
||||
}
|
||||
346
blender-5.2.0/extern/opensubdiv-source/regression/common/far_utils.h
vendored
Normal file
346
blender-5.2.0/extern/opensubdiv-source/regression/common/far_utils.h
vendored
Normal file
@@ -0,0 +1,346 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef FAR_UTILS_H
|
||||
#define FAR_UTILS_H
|
||||
|
||||
#include "shape_utils.h"
|
||||
|
||||
#include <opensubdiv/far/topologyRefinerFactory.h>
|
||||
#include <opensubdiv/far/primvarRefiner.h>
|
||||
#include <opensubdiv/far/types.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline Scheme
|
||||
ConvertSdcTypeToShapeScheme(OpenSubdiv::Sdc::SchemeType sdcScheme) {
|
||||
|
||||
switch (sdcScheme) {
|
||||
case OpenSubdiv::Sdc::SCHEME_BILINEAR: return kBilinear;
|
||||
case OpenSubdiv::Sdc::SCHEME_CATMARK: return kCatmark;
|
||||
case OpenSubdiv::Sdc::SCHEME_LOOP: return kLoop;
|
||||
default: printf("unknown Sdc::SchemeType : %d\n", (int)sdcScheme); break;
|
||||
}
|
||||
return kCatmark;
|
||||
}
|
||||
|
||||
inline OpenSubdiv::Sdc::SchemeType
|
||||
ConvertShapeSchemeToSdcType(Scheme shapeScheme) {
|
||||
|
||||
switch (shapeScheme) {
|
||||
case kBilinear: return OpenSubdiv::Sdc::SCHEME_BILINEAR;
|
||||
case kCatmark: return OpenSubdiv::Sdc::SCHEME_CATMARK;
|
||||
case kLoop: return OpenSubdiv::Sdc::SCHEME_LOOP;
|
||||
default: printf("unknown Shape Scheme : %d\n", (int)shapeScheme); break;
|
||||
}
|
||||
return OpenSubdiv::Sdc::SCHEME_CATMARK;
|
||||
}
|
||||
|
||||
inline OpenSubdiv::Sdc::SchemeType
|
||||
GetSdcType(Shape const & shape) {
|
||||
|
||||
return ConvertShapeSchemeToSdcType(shape.scheme);
|
||||
}
|
||||
|
||||
inline OpenSubdiv::Sdc::Options
|
||||
GetSdcOptions(Shape const & shape) {
|
||||
|
||||
typedef OpenSubdiv::Sdc::Options Options;
|
||||
|
||||
Options result;
|
||||
|
||||
result.SetVtxBoundaryInterpolation(Options::VTX_BOUNDARY_EDGE_ONLY);
|
||||
result.SetCreasingMethod(Options::CREASE_UNIFORM);
|
||||
result.SetTriangleSubdivision(Options::TRI_SUB_CATMARK);
|
||||
|
||||
for (int i=0; i<(int)shape.tags.size(); ++i) {
|
||||
|
||||
Shape::tag * t = shape.tags[i];
|
||||
|
||||
if (t->name=="interpolateboundary") {
|
||||
if ((int)t->intargs.size()!=1) {
|
||||
printf("expecting 1 integer for \"interpolateboundary\" tag n. %d\n", i);
|
||||
continue;
|
||||
}
|
||||
switch( t->intargs[0] ) {
|
||||
case 0 : result.SetVtxBoundaryInterpolation(Options::VTX_BOUNDARY_NONE); break;
|
||||
case 1 : result.SetVtxBoundaryInterpolation(Options::VTX_BOUNDARY_EDGE_AND_CORNER); break;
|
||||
case 2 : result.SetVtxBoundaryInterpolation(Options::VTX_BOUNDARY_EDGE_ONLY); break;
|
||||
default: printf("unknown interpolate boundary : %d\n", t->intargs[0] ); break;
|
||||
}
|
||||
} else if (t->name=="facevaryinginterpolateboundary") {
|
||||
if ((int)t->intargs.size()!=1) {
|
||||
printf("expecting 1 integer for \"facevaryinginterpolateboundary\" tag n. %d\n", i);
|
||||
continue;
|
||||
}
|
||||
switch( t->intargs[0] ) {
|
||||
case 0 : result.SetFVarLinearInterpolation(Options::FVAR_LINEAR_NONE); break;
|
||||
case 1 : result.SetFVarLinearInterpolation(Options::FVAR_LINEAR_CORNERS_ONLY); break;
|
||||
case 2 : result.SetFVarLinearInterpolation(Options::FVAR_LINEAR_CORNERS_PLUS1); break;
|
||||
case 3 : result.SetFVarLinearInterpolation(Options::FVAR_LINEAR_CORNERS_PLUS2); break;
|
||||
case 4 : result.SetFVarLinearInterpolation(Options::FVAR_LINEAR_BOUNDARIES); break;
|
||||
case 5 : result.SetFVarLinearInterpolation(Options::FVAR_LINEAR_ALL); break;
|
||||
default: printf("unknown interpolate boundary : %d\n", t->intargs[0] ); break;
|
||||
}
|
||||
} else if (t->name=="facevaryingpropagatecorners") {
|
||||
if ((int)t->intargs.size()==1) {
|
||||
// XXXX no propagate corners in Options
|
||||
assert(0);
|
||||
} else
|
||||
printf( "expecting single int argument for \"facevaryingpropagatecorners\"\n" );
|
||||
} else if (t->name=="creasemethod") {
|
||||
|
||||
if ((int)t->stringargs.size()==0) {
|
||||
printf("the \"creasemethod\" tag expects a string argument\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t->stringargs[0]=="normal") {
|
||||
result.SetCreasingMethod(Options::CREASE_UNIFORM);
|
||||
} else if (t->stringargs[0]=="chaikin") {
|
||||
result.SetCreasingMethod(Options::CREASE_CHAIKIN);
|
||||
} else {
|
||||
printf("the \"creasemethod\" tag only accepts \"normal\" or \"chaikin\" as value (%s)\n", t->stringargs[0].c_str());
|
||||
}
|
||||
} else if (t->name=="smoothtriangles") {
|
||||
|
||||
if (shape.scheme!=kCatmark) {
|
||||
printf("the \"smoothtriangles\" tag can only be applied to Catmark meshes\n");
|
||||
continue;
|
||||
}
|
||||
if (t->stringargs[0]=="catmark") {
|
||||
result.SetTriangleSubdivision(Options::TRI_SUB_CATMARK);
|
||||
} else if (t->stringargs[0]=="smooth") {
|
||||
result.SetTriangleSubdivision(Options::TRI_SUB_SMOOTH);
|
||||
} else {
|
||||
printf("the \"smoothtriangles\" tag only accepts \"catmark\" or \"smooth\" as value (%s)\n", t->stringargs[0].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
InterpolateFVarData(OpenSubdiv::Far::TopologyRefiner & refiner,
|
||||
Shape const & shape, std::vector<float> & fvarData);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class T>
|
||||
OpenSubdiv::Far::TopologyRefiner *
|
||||
InterpolateFarVertexData(Shape const & shape, int maxlevel, std::vector<T> &data) {
|
||||
|
||||
typedef OpenSubdiv::Far::TopologyRefiner FarTopologyRefiner;
|
||||
typedef OpenSubdiv::Far::TopologyRefinerFactory<Shape> FarTopologyRefinerFactory;
|
||||
|
||||
// Far interpolation
|
||||
FarTopologyRefiner * refiner =
|
||||
FarTopologyRefinerFactory::Create(shape,
|
||||
FarTopologyRefinerFactory::Options(
|
||||
GetSdcType(shape), GetSdcOptions(shape)));
|
||||
assert(refiner);
|
||||
|
||||
FarTopologyRefiner::UniformOptions options(maxlevel);
|
||||
options.fullTopologyInLastLevel=true;
|
||||
refiner->RefineUniform(options);
|
||||
|
||||
// populate coarse mesh positions
|
||||
data.resize(refiner->GetNumVerticesTotal());
|
||||
for (int i=0; i<refiner->GetLevel(0).GetNumVertices(); i++) {
|
||||
data[i].SetPosition(shape.verts[i*3+0],
|
||||
shape.verts[i*3+1],
|
||||
shape.verts[i*3+2]);
|
||||
}
|
||||
|
||||
T * srcVerts = &data[0];
|
||||
T * dstVerts = srcVerts + refiner->GetLevel(0).GetNumVertices();
|
||||
OpenSubdiv::Far::PrimvarRefiner primvarRefiner(*refiner);
|
||||
|
||||
for (int i = 1; i <= refiner->GetMaxLevel(); ++i) {
|
||||
primvarRefiner.Interpolate(i, srcVerts, dstVerts);
|
||||
srcVerts = dstVerts;
|
||||
dstVerts += refiner->GetLevel(i).GetNumVertices();
|
||||
}
|
||||
return refiner;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
OpenSubdiv::Far::TopologyRefiner *
|
||||
InterpolateFarVertexData(const char *shapeStr, Scheme scheme, int maxlevel,
|
||||
std::vector<T> &data) {
|
||||
|
||||
Shape const * shape = Shape::parseObj(shapeStr, scheme);
|
||||
|
||||
OpenSubdiv::Far::TopologyRefiner * refiner =
|
||||
InterpolateFarVertexData(*shape, maxlevel, data);
|
||||
|
||||
delete shape;
|
||||
return refiner;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
template <>
|
||||
inline bool
|
||||
TopologyRefinerFactory<Shape>::resizeComponentTopology(
|
||||
Far::TopologyRefiner & refiner, Shape const & shape) {
|
||||
|
||||
int nfaces = shape.GetNumFaces(),
|
||||
nverts = shape.GetNumVertices();
|
||||
|
||||
setNumBaseFaces(refiner, nfaces);
|
||||
for (int i=0; i<nfaces; ++i) {
|
||||
|
||||
int nv = shape.nvertsPerFace[i];
|
||||
setNumBaseFaceVertices(refiner, i, nv);
|
||||
}
|
||||
|
||||
// Vertices and vert-faces and vert-edges
|
||||
setNumBaseVertices(refiner, nverts);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
template <>
|
||||
inline bool
|
||||
TopologyRefinerFactory<Shape>::assignComponentTopology(
|
||||
Far::TopologyRefiner & refiner, Shape const & shape) {
|
||||
|
||||
{ // Face relations:
|
||||
int nfaces = getNumBaseFaces(refiner);
|
||||
|
||||
for (int i=0, ofs=0; i < nfaces; ++i) {
|
||||
|
||||
Far::IndexArray dstFaceVerts = getBaseFaceVertices(refiner, i);
|
||||
|
||||
if (shape.isLeftHanded) {
|
||||
dstFaceVerts[0] = shape.faceverts[ofs++];
|
||||
for (int j=dstFaceVerts.size()-1; j>0; --j) {
|
||||
dstFaceVerts[j] = shape.faceverts[ofs++];
|
||||
}
|
||||
} else {
|
||||
for (int j=0; j<dstFaceVerts.size(); ++j) {
|
||||
dstFaceVerts[j] = shape.faceverts[ofs++];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
template <>
|
||||
inline bool
|
||||
TopologyRefinerFactory<Shape>::assignFaceVaryingTopology(
|
||||
Far::TopologyRefiner & refiner, Shape const & shape) {
|
||||
|
||||
// UV layout (we only parse 1 channel)
|
||||
if (! shape.faceuvs.empty()) {
|
||||
|
||||
int nfaces = getNumBaseFaces(refiner),
|
||||
channel = createBaseFVarChannel(refiner, (int)shape.uvs.size()/2 );
|
||||
|
||||
for (int i=0, ofs=0; i < nfaces; ++i) {
|
||||
|
||||
Far::IndexArray dstFaceUVs = getBaseFaceFVarValues(refiner, i, channel);
|
||||
|
||||
if (shape.isLeftHanded) {
|
||||
dstFaceUVs[0] = shape.faceuvs[ofs++];
|
||||
for (int j=dstFaceUVs.size()-1; j > 0; --j) {
|
||||
dstFaceUVs[j] = shape.faceuvs[ofs++];
|
||||
}
|
||||
} else {
|
||||
for (int j=0; j<dstFaceUVs.size(); ++j) {
|
||||
dstFaceUVs[j] = shape.faceuvs[ofs++];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
template <>
|
||||
inline bool
|
||||
TopologyRefinerFactory<Shape>::assignComponentTags(
|
||||
Far::TopologyRefiner & refiner, Shape const & shape) {
|
||||
|
||||
|
||||
for (int i=0; i<(int)shape.tags.size(); ++i) {
|
||||
|
||||
Shape::tag * t = shape.tags[i];
|
||||
|
||||
if (t->name=="crease") {
|
||||
|
||||
for (int j=0; j<(int)t->intargs.size()-1; j += 2) {
|
||||
|
||||
OpenSubdiv::Far::Index edge = findBaseEdge(refiner, t->intargs[j], t->intargs[j+1]);
|
||||
if (edge==OpenSubdiv::Far::INDEX_INVALID) {
|
||||
printf("cannot find edge for crease tag (%d,%d)\n", t->intargs[j], t->intargs[j+1] );
|
||||
return false;
|
||||
} else {
|
||||
int nfloat = (int) t->floatargs.size();
|
||||
setBaseEdgeSharpness(refiner, edge,
|
||||
std::max(0.0f, ((nfloat > 1) ? t->floatargs[j] : t->floatargs[0])));
|
||||
}
|
||||
}
|
||||
} else if (t->name=="corner") {
|
||||
|
||||
for (int j=0; j<(int)t->intargs.size(); ++j) {
|
||||
int vertex = t->intargs[j];
|
||||
if (vertex<0 || vertex>=getNumBaseVertices(refiner)) {
|
||||
printf("cannot find vertex for corner tag (%d)\n", vertex );
|
||||
return false;
|
||||
} else {
|
||||
int nfloat = (int) t->floatargs.size();
|
||||
setBaseVertexSharpness(refiner, vertex,
|
||||
std::max(0.0f, ((nfloat > 1) ? t->floatargs[j] : t->floatargs[0])));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{ // Hole tags
|
||||
for (int i=0; i<(int)shape.tags.size(); ++i) {
|
||||
Shape::tag * t = shape.tags[i];
|
||||
if (t->name=="hole") {
|
||||
for (int j=0; j<(int)t->intargs.size(); ++j) {
|
||||
setBaseFaceHole(refiner, t->intargs[j], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void
|
||||
TopologyRefinerFactory<Shape>::reportInvalidTopology(
|
||||
TopologyRefinerFactory::TopologyError /* errCode */, char const * msg, Shape const & /* shape */) {
|
||||
Warning(msg);
|
||||
}
|
||||
|
||||
} // namespace Far
|
||||
|
||||
} // namespace OPENSUBDIV_VERSION
|
||||
} // namespace OpenSubdiv
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endif /* FAR_UTILS_H */
|
||||
700
blender-5.2.0/extern/opensubdiv-source/regression/common/hbr_utils.h
vendored
Normal file
700
blender-5.2.0/extern/opensubdiv-source/regression/common/hbr_utils.h
vendored
Normal file
@@ -0,0 +1,700 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef HBR_UTILS_H
|
||||
#define HBR_UTILS_H
|
||||
|
||||
#ifndef HBR_ADAPTIVE
|
||||
#define HBR_ADAPTIVE
|
||||
#endif
|
||||
|
||||
#include "shape_utils.h"
|
||||
|
||||
#include <opensubdiv/hbr/mesh.h>
|
||||
#include <opensubdiv/hbr/bilinear.h>
|
||||
#include <opensubdiv/hbr/loop.h>
|
||||
#include <opensubdiv/hbr/catmark.h>
|
||||
#include <opensubdiv/hbr/vertexEdit.h>
|
||||
#include <opensubdiv/hbr/cornerEdit.h>
|
||||
#include <opensubdiv/hbr/holeEdit.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
void applyTags( OpenSubdiv::HbrMesh<T> * mesh, Shape const * sh ) {
|
||||
|
||||
for (int i=0; i<(int)sh->tags.size(); ++i) {
|
||||
Shape::tag * t = sh->tags[i];
|
||||
|
||||
if (t->name=="crease") {
|
||||
for (int j=0; j<(int)t->intargs.size()-1; j += 2) {
|
||||
OpenSubdiv::HbrVertex<T> * v = mesh->GetVertex( t->intargs[j] ),
|
||||
* w = mesh->GetVertex( t->intargs[j+1] );
|
||||
OpenSubdiv::HbrHalfedge<T> * e = 0;
|
||||
if( v && w ) {
|
||||
if((e = v->GetEdge(w)) == 0)
|
||||
e = w->GetEdge(v);
|
||||
if(e) {
|
||||
int nfloat = (int) t->floatargs.size();
|
||||
e->SetSharpness( std::max(0.0f, ((nfloat > 1) ? t->floatargs[j] : t->floatargs[0])) );
|
||||
} else
|
||||
printf("cannot find edge for crease tag (%d,%d)\n", t->intargs[j], t->intargs[j+1] );
|
||||
}
|
||||
}
|
||||
} else if (t->name=="corner") {
|
||||
for (int j=0; j<(int)t->intargs.size(); ++j) {
|
||||
OpenSubdiv::HbrVertex<T> * v = mesh->GetVertex( t->intargs[j] );
|
||||
if(v) {
|
||||
int nfloat = (int) t->floatargs.size();
|
||||
v->SetSharpness( std::max(0.0f, ((nfloat > 1) ? t->floatargs[j] : t->floatargs[0])) );
|
||||
} else
|
||||
printf("cannot find vertex for corner tag (%d)\n", t->intargs[j] );
|
||||
}
|
||||
} else if (t->name=="hole") {
|
||||
for (int j=0; j<(int)t->intargs.size(); ++j) {
|
||||
OpenSubdiv::HbrFace<T> * f = mesh->GetFace( t->intargs[j] );
|
||||
if(f) {
|
||||
f->SetHole();
|
||||
} else
|
||||
printf("cannot find face for hole tag (%d)\n", t->intargs[j] );
|
||||
}
|
||||
} else if (t->name=="interpolateboundary") {
|
||||
if ((int)t->intargs.size()!=1) {
|
||||
printf("expecting 1 integer for \"interpolateboundary\" tag n. %d\n", i);
|
||||
continue;
|
||||
}
|
||||
switch( t->intargs[0] ) {
|
||||
case 0 : mesh->SetInterpolateBoundaryMethod(OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryNone); break;
|
||||
case 1 : mesh->SetInterpolateBoundaryMethod(OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryEdgeAndCorner); break;
|
||||
case 2 : mesh->SetInterpolateBoundaryMethod(OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryEdgeOnly); break;
|
||||
default: printf("unknown interpolate boundary : %d\n", t->intargs[0] ); break;
|
||||
}
|
||||
} else if (t->name=="facevaryinginterpolateboundary") {
|
||||
if ((int)t->intargs.size()!=1) {
|
||||
printf("expecting 1 integer for \"facevaryinginterpolateboundary\" tag n. %d\n", i);
|
||||
continue;
|
||||
}
|
||||
switch( t->intargs[0] ) {
|
||||
case 0 : mesh->SetFVarInterpolateBoundaryMethod(OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryNone); break;
|
||||
case 1 : mesh->SetFVarInterpolateBoundaryMethod(OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryEdgeAndCorner); break;
|
||||
case 2 : mesh->SetFVarInterpolateBoundaryMethod(OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryEdgeOnly); break;
|
||||
case 3 : mesh->SetFVarInterpolateBoundaryMethod(OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryAlwaysSharp); break;
|
||||
default: printf("unknown facevarying interpolate boundary : %d\n", t->intargs[0] ); break;
|
||||
}
|
||||
} else if (t->name=="facevaryingpropagatecorners") {
|
||||
if ((int)t->intargs.size()==1)
|
||||
mesh->SetFVarPropagateCorners( t->intargs[0] != 0 );
|
||||
else
|
||||
printf( "expecting single int argument for \"facevaryingpropagatecorners\"\n" );
|
||||
} else if (t->name=="smoothtriangles") {
|
||||
|
||||
OpenSubdiv::HbrCatmarkSubdivision<T> * scheme =
|
||||
dynamic_cast<OpenSubdiv::HbrCatmarkSubdivision<T> *>( mesh->GetSubdivision() );
|
||||
|
||||
if (! scheme) {
|
||||
printf("the \"smoothtriangles\" tag can only be applied to Catmark meshes\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((int)t->intargs.size()==0) {
|
||||
printf("the \"smoothtriangles\" tag expects an int argument\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if( t->intargs[0]==1 )
|
||||
scheme->SetTriangleSubdivisionMethod(
|
||||
OpenSubdiv::HbrCatmarkSubdivision<T>::k_Old);
|
||||
else if( t->intargs[0]==2 )
|
||||
scheme->SetTriangleSubdivisionMethod(
|
||||
OpenSubdiv::HbrCatmarkSubdivision<T>::k_New);
|
||||
else
|
||||
printf("the \"smoothtriangles\" tag only accepts 1 or 2 as value (%d)\n", t->intargs[0]);
|
||||
|
||||
} else if (t->name=="creasemethod") {
|
||||
|
||||
OpenSubdiv::HbrSubdivision<T> * scheme = mesh->GetSubdivision();
|
||||
|
||||
assert(scheme);
|
||||
|
||||
if ((int)t->stringargs.size()==0) {
|
||||
printf("the \"creasemethod\" tag expects a string argument\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if( t->stringargs[0]=="normal" )
|
||||
scheme->SetCreaseSubdivisionMethod(
|
||||
OpenSubdiv::HbrSubdivision<T>::k_CreaseNormal);
|
||||
else if( t->stringargs[0]=="chaikin" )
|
||||
scheme->SetCreaseSubdivisionMethod(
|
||||
OpenSubdiv::HbrSubdivision<T>::k_CreaseChaikin);
|
||||
else
|
||||
printf("the \"creasemethod\" tag only accepts \"normal\" or \"chaikin\" as value (%s)\n", t->stringargs[0].c_str());
|
||||
|
||||
} else if (t->name=="vertexedit" || t->name=="edgeedit") {
|
||||
int nops = 0;
|
||||
int floatstride = 0;
|
||||
int maxfloatwidth = 0;
|
||||
std::vector<typename OpenSubdiv::HbrHierarchicalEdit<T>::Operation > ops;
|
||||
std::vector<std::string> opnames;
|
||||
std::vector<std::string> varnames;
|
||||
std::vector<typename OpenSubdiv::HbrHierarchicalEdit<T>::Operation > opmodifiers;
|
||||
std::vector<int> floatwidths;
|
||||
std::vector<bool> isP;
|
||||
std::vector<int> vvindex;
|
||||
|
||||
for (int j=0; j<(int)t->stringargs.size(); j+=3) {
|
||||
const std::string & opname = t->stringargs[j+2];
|
||||
const std::string & opmodifiername = t->stringargs[j];
|
||||
const std::string & varname = t->stringargs[j+1];
|
||||
|
||||
typename OpenSubdiv::HbrHierarchicalEdit<T>::Operation opmodifier = OpenSubdiv::HbrVertexEdit<T>::Set;
|
||||
if (opmodifiername == "set") {
|
||||
opmodifier = OpenSubdiv::HbrHierarchicalEdit<T>::Set;
|
||||
} else if (opmodifiername == "add") {
|
||||
opmodifier = OpenSubdiv::HbrHierarchicalEdit<T>::Add;
|
||||
} else if (opmodifiername == "subtract") {
|
||||
opmodifier = OpenSubdiv::HbrHierarchicalEdit<T>::Subtract;
|
||||
} else {
|
||||
printf("invalid modifier %s\n", opmodifiername.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((t->name=="vertexedit" && opname=="value") || opname=="sharpness") {
|
||||
nops++;
|
||||
|
||||
// only varname="P" is supported here for now.
|
||||
if (varname != "P") continue;
|
||||
|
||||
vvindex.push_back(0);
|
||||
isP.push_back(true);
|
||||
opnames.push_back(opname);
|
||||
opmodifiers.push_back(opmodifier);
|
||||
varnames.push_back(varname);
|
||||
|
||||
if (opname=="sharpness") {
|
||||
floatwidths.push_back(1);
|
||||
floatstride += 1;
|
||||
} else {
|
||||
// assuming width of P == 3. should be replaced with 'P 0 3' like declaration
|
||||
int numElements = 3;
|
||||
maxfloatwidth = std::max(maxfloatwidth, numElements);
|
||||
floatwidths.push_back(numElements);
|
||||
floatstride += numElements;
|
||||
}
|
||||
} else {
|
||||
printf("%s tag specifies invalid operation '%s %s' on Subdivmesh\n", t->name.c_str(), opmodifiername.c_str(), opname.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
float *xformed = (float*)alloca(maxfloatwidth * sizeof(float));
|
||||
|
||||
int floatoffset = 0;
|
||||
for(int j=0; j<nops; ++j) {
|
||||
int floatidx = floatoffset;
|
||||
for (int k=0; k < (int)t->intargs.size();) {
|
||||
int pathlength = t->intargs[k];
|
||||
|
||||
int faceid = t->intargs[k+1];
|
||||
int vertexid = t->intargs[k+pathlength];
|
||||
int nsubfaces = pathlength - 2;
|
||||
int *subfaces = &t->intargs[k+2];
|
||||
OpenSubdiv::HbrFace<T> * f = mesh->GetFace(faceid);
|
||||
if (!f) {
|
||||
printf("Invalid face %d specified for %s tag on SubdivisionMesh.\n", faceid, t->name.c_str());
|
||||
goto nexttag;
|
||||
}
|
||||
// Found the face. Do some preliminary error checking to make sure the path is
|
||||
// correct. First value in path depends on the number of vertices of the face
|
||||
// which we have in hand
|
||||
if (nsubfaces && (subfaces[0] < 0 || subfaces[0] >= f->GetNumVertices()) ) {
|
||||
printf("Invalid path component %d in %s tag on SubdivisionMesh.\n", subfaces[0], t->name.c_str());
|
||||
goto nexttag;
|
||||
}
|
||||
|
||||
// All subsequent values must be less than 4 (FIXME or 3 in the loop case?)
|
||||
for (int l=1; l<nsubfaces; ++l) {
|
||||
if (subfaces[l] < 0 || subfaces[l] > 3) {
|
||||
printf("Invalid path component %d in %s tag on SubdivisionMesh.\n", subfaces[0], t->name.c_str());
|
||||
goto nexttag;
|
||||
}
|
||||
}
|
||||
if (vertexid < 0 || vertexid > 3) {
|
||||
printf("Invalid path component (vertexid) %d in %s tag on SubdivisionMesh.\n", vertexid, t->name.c_str());
|
||||
goto nexttag;
|
||||
}
|
||||
|
||||
// Transform all the float values associated with the tag if needed
|
||||
if(opnames[j] != "sharpness") {
|
||||
for(int l=0; l<floatwidths[j]; ++l) {
|
||||
xformed[l] = t->floatargs[l + floatidx];
|
||||
}
|
||||
|
||||
// Edits of facevarying data are a different hierarchical edit type altogether
|
||||
OpenSubdiv::HbrVertexEdit<T> * edit = new OpenSubdiv::HbrVertexEdit<T>(faceid, nsubfaces, subfaces,
|
||||
vertexid, vvindex[j], floatwidths[j],
|
||||
isP[j], opmodifiers[j], xformed);
|
||||
mesh->AddHierarchicalEdit(edit);
|
||||
} else {
|
||||
if (t->name == "vertexedit") {
|
||||
OpenSubdiv::HbrCornerEdit<T> * edit = new OpenSubdiv::HbrCornerEdit<T>(faceid, nsubfaces, subfaces,
|
||||
vertexid, opmodifiers[j], t->floatargs[floatidx]);
|
||||
mesh->AddHierarchicalEdit(edit);
|
||||
} else {
|
||||
OpenSubdiv::HbrCreaseEdit<T> * edit = new OpenSubdiv::HbrCreaseEdit<T>(faceid, nsubfaces, subfaces,
|
||||
vertexid, opmodifiers[j], t->floatargs[floatidx]);
|
||||
mesh->AddHierarchicalEdit(edit);
|
||||
}
|
||||
}
|
||||
|
||||
// Advance to next path
|
||||
k += pathlength + 1;
|
||||
|
||||
// Advance to start of float data
|
||||
floatidx += floatstride;
|
||||
} // End of integer processing loop
|
||||
|
||||
// Next subop
|
||||
floatoffset += floatwidths[j];
|
||||
|
||||
} // End of subop processing loop
|
||||
} else if (t->name=="faceedit") {
|
||||
|
||||
int nint = (int)t->intargs.size();
|
||||
for (int k=0; k<nint; ) {
|
||||
int pathlength = t->intargs[k];
|
||||
|
||||
if (k+pathlength>=nint) {
|
||||
printf("Invalid path length for %s tag on SubdivisionMesh", t->name.c_str());
|
||||
goto nexttag;
|
||||
}
|
||||
|
||||
int faceid = t->intargs[k+1];
|
||||
int nsubfaces = pathlength - 1;
|
||||
int *subfaces = &t->intargs[k+2];
|
||||
OpenSubdiv::HbrFace<T> * f = mesh->GetFace(faceid);
|
||||
if (!f) {
|
||||
printf("Invalid face %d specified for %s tag on SubdivisionMesh.\n", faceid, t->name.c_str());
|
||||
goto nexttag;
|
||||
}
|
||||
|
||||
// Found the face. Do some preliminary error checking to make sure the path is
|
||||
// correct. First value in path depends on the number of vertices of the face
|
||||
// which we have in hand
|
||||
if (nsubfaces && (subfaces[0] < 0 || subfaces[0] >= f->GetNumVertices()) ) {
|
||||
printf("Invalid path component %d in %s tag on SubdivisionMesh.\n", subfaces[0], t->name.c_str());
|
||||
goto nexttag;
|
||||
}
|
||||
|
||||
// All subsequent values must be less than 4 (FIXME or 3 in the loop case?)
|
||||
for (int l=1; l<nsubfaces; ++l) {
|
||||
if (subfaces[l] < 0 || subfaces[l] > 3) {
|
||||
printf("Invalid path component %d in %s tag on SubdivisionMesh.\n", subfaces[0], t->name.c_str());
|
||||
goto nexttag;
|
||||
}
|
||||
}
|
||||
|
||||
// Now loop over string ops
|
||||
int nstring = (int)t->stringargs.size();
|
||||
for (int l = 0; l < nstring; ) {
|
||||
if ( t->stringargs[l] == "hole" ) {
|
||||
// Construct the edit
|
||||
OpenSubdiv::HbrHoleEdit<T> * edit = new OpenSubdiv::HbrHoleEdit<T>(faceid, nsubfaces, subfaces);
|
||||
mesh->AddHierarchicalEdit(edit);
|
||||
++l;
|
||||
} else if ( t->stringargs[l] == "attributes" ) {
|
||||
// see NgpSubdivMesh.cpp:4341
|
||||
printf("\"attributes\" face tag not supported yet.\n");
|
||||
goto nexttag;
|
||||
} else if ( t->stringargs[l] == "set" || t->stringargs[l] == "add" ) {
|
||||
// see NgpSubdivMesh.cpp:4341
|
||||
printf("\"set\" and \"add\" face tag not supported yet.\n");
|
||||
goto nexttag;
|
||||
} else {
|
||||
printf("Faceedit tag specifies invalid operation '%s' on Subdivmesh.\n", t->stringargs[l].c_str());
|
||||
goto nexttag;
|
||||
}
|
||||
}
|
||||
// Advance to next path
|
||||
k += pathlength + 1;
|
||||
} // end face path loop
|
||||
|
||||
} else {
|
||||
printf("Unknown tag : \"%s\" - skipping\n", t->name.c_str());
|
||||
}
|
||||
nexttag: ;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T> std::string
|
||||
hbrToObj( OpenSubdiv::HbrMesh<T> * mesh ) {
|
||||
|
||||
std::stringstream sh;
|
||||
|
||||
sh<<"# This file uses centimeters as units for non-parametric coordinates.\n\n";
|
||||
|
||||
int nv = mesh->GetNumVertices();
|
||||
for (int i=0; i<nv; ++i) {
|
||||
const float * pos = mesh->GetVertex(i)->GetData().GetPos();
|
||||
sh << "v " << pos[0] << " " << pos[1] << " " << pos[2] <<"\n";
|
||||
}
|
||||
|
||||
int nf = mesh->GetNumFaces();
|
||||
for (int i=0; i<nf; ++i) {
|
||||
|
||||
sh << "f ";
|
||||
|
||||
OpenSubdiv::HbrFace<T> * f = mesh->GetFace(i);
|
||||
|
||||
for (int j=0; j<f->GetNumVertices(); ++j) {
|
||||
int vert = f->GetVertex(j)->GetID()+1;
|
||||
sh << vert << "/" << vert << "/" << vert << " ";
|
||||
}
|
||||
sh << "\n";
|
||||
}
|
||||
|
||||
sh << "\n";
|
||||
|
||||
return sh.str();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T> OpenSubdiv::HbrMesh<T> *
|
||||
createMesh( Scheme scheme=kCatmark, int fvarwidth=0) {
|
||||
|
||||
OpenSubdiv::HbrMesh<T> * mesh = 0;
|
||||
|
||||
static OpenSubdiv::HbrBilinearSubdivision<T> _bilinear;
|
||||
static OpenSubdiv::HbrLoopSubdivision<T> _loop;
|
||||
static OpenSubdiv::HbrCatmarkSubdivision<T> _catmark;
|
||||
|
||||
static int indices[2] = { 0, 1 },
|
||||
widths[2] = { 1, 1 };
|
||||
|
||||
int const fvarcount = fvarwidth > 0 ? 2 : 0,
|
||||
* fvarindices = fvarwidth > 0 ? indices : NULL,
|
||||
* fvarwidths = fvarwidth > 0 ? widths : NULL;
|
||||
|
||||
|
||||
switch (scheme) {
|
||||
case kBilinear : mesh = new OpenSubdiv::HbrMesh<T>( &_bilinear,
|
||||
fvarcount,
|
||||
fvarindices,
|
||||
fvarwidths,
|
||||
fvarwidth ); break;
|
||||
|
||||
case kLoop : mesh = new OpenSubdiv::HbrMesh<T>( &_loop,
|
||||
fvarcount,
|
||||
fvarindices,
|
||||
fvarwidths,
|
||||
fvarwidth ); break;
|
||||
|
||||
case kCatmark : mesh = new OpenSubdiv::HbrMesh<T>( &_catmark,
|
||||
fvarcount,
|
||||
fvarindices,
|
||||
fvarwidths,
|
||||
fvarwidth ); break;
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T> void
|
||||
createVerticesWithPositions(Shape const * sh, OpenSubdiv::HbrMesh<T> * mesh) {
|
||||
|
||||
T v;
|
||||
for(int i=0;i<sh->GetNumVertices(); i++ ) {
|
||||
v.SetPosition( sh->verts[i*3], sh->verts[i*3+1], sh->verts[i*3+2] );
|
||||
mesh->NewVertex( i, v );
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T> void
|
||||
createVertices(Shape const * sh, OpenSubdiv::HbrMesh<T> * mesh) {
|
||||
|
||||
T v;
|
||||
for(int i=0;i<sh->GetNumVertices(); i++ )
|
||||
mesh->NewVertex( i, v );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T> void
|
||||
copyVertexPositions( Shape const * sh, OpenSubdiv::HbrMesh<T> * mesh, std::vector<float> & verts ) {
|
||||
|
||||
int nverts = mesh->GetNumVertices();
|
||||
|
||||
verts.resize( nverts * 3 );
|
||||
|
||||
std::copy(sh->verts.begin(), sh->verts.end(), verts.begin());
|
||||
|
||||
// Sometimes Hbr dupes some vertices during Mesh::Finish() and our example
|
||||
// code uses those vertices to draw coarse control cages and such
|
||||
std::vector<std::pair<int, int> > const splits = mesh->GetSplitVertices();
|
||||
for (int i=0; i<(int)splits.size(); ++i) {
|
||||
memcpy(&verts[splits[i].first*3], &sh->verts[splits[i].second*3], 3*sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T> void
|
||||
createTopology( Shape const * sh, OpenSubdiv::HbrMesh<T> * mesh, Scheme scheme) {
|
||||
|
||||
const int * fv=&(sh->faceverts[0]);
|
||||
for(int f=0, ptxidx=0;f<sh->GetNumFaces(); f++ ) {
|
||||
|
||||
int nv = sh->nvertsPerFace[f];
|
||||
|
||||
if ((scheme==kLoop) && (nv!=3)) {
|
||||
printf("Trying to create a Loop subd with non-triangle face\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bool valid = true;
|
||||
|
||||
for(int j=0;j<nv;j++) {
|
||||
OpenSubdiv::HbrVertex<T> * origin = mesh->GetVertex( fv[j] );
|
||||
OpenSubdiv::HbrVertex<T> * destination = mesh->GetVertex( fv[(j+1)%nv] );
|
||||
OpenSubdiv::HbrHalfedge<T> * opposite = destination->GetEdge(origin);
|
||||
|
||||
if(origin==NULL || destination==NULL) {
|
||||
printf(" An edge was specified that connected a nonexistent vertex\n");
|
||||
valid=false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(origin == destination) {
|
||||
printf(" An edge was specified that connected a vertex to itself\n");
|
||||
valid=false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(opposite && opposite->GetOpposite() ) {
|
||||
printf(" A non-manifold edge incident to more than 2 faces was found\n");
|
||||
valid=false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(origin->GetEdge(destination)) {
|
||||
printf(" An edge connecting two vertices was specified more than once."
|
||||
" It's likely that an incident face was flipped\n");
|
||||
valid=false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
|
||||
OpenSubdiv::HbrFace<T> * face = mesh->NewFace(nv, (int *)fv, 0);
|
||||
|
||||
face->SetPtexIndex(ptxidx);
|
||||
|
||||
if ( (scheme==kCatmark || scheme==kBilinear) && nv != 4 ) {
|
||||
ptxidx+=nv;
|
||||
} else {
|
||||
ptxidx++;
|
||||
}
|
||||
}
|
||||
|
||||
fv+=nv;
|
||||
}
|
||||
|
||||
mesh->SetInterpolateBoundaryMethod(
|
||||
OpenSubdiv::HbrMesh<T>::k_InterpolateBoundaryEdgeOnly);
|
||||
|
||||
mesh->GetSubdivision()->SetCreaseSubdivisionMethod(
|
||||
OpenSubdiv::HbrSubdivision<T>::k_CreaseNormal);
|
||||
|
||||
if (OpenSubdiv::HbrCatmarkSubdivision<T> * hscheme =
|
||||
dynamic_cast<OpenSubdiv::HbrCatmarkSubdivision<T> *>(mesh->GetSubdivision())) {
|
||||
|
||||
hscheme->SetTriangleSubdivisionMethod(
|
||||
OpenSubdiv::HbrCatmarkSubdivision<T>::k_Normal);
|
||||
}
|
||||
|
||||
applyTags<T>( mesh, sh );
|
||||
|
||||
mesh->Finish();
|
||||
|
||||
// check for disconnected vertices
|
||||
if (mesh->GetNumDisconnectedVertices()) {
|
||||
printf("The specified subdivmesh contains disconnected surface components.\n");
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T> void
|
||||
createFaceVaryingUV( Shape const * sh, OpenSubdiv::HbrMesh<T> * mesh) {
|
||||
|
||||
if (! sh->HasUV())
|
||||
return;
|
||||
|
||||
for (int i=0, idx=0; i<sh->GetNumFaces(); ++i ) {
|
||||
|
||||
OpenSubdiv::HbrFace<T> * f = mesh->GetFace(i);
|
||||
|
||||
int nv = sh->nvertsPerFace[i];
|
||||
|
||||
OpenSubdiv::HbrHalfedge<T> * e = f->GetFirstEdge();
|
||||
|
||||
for (int j=0; j<nv; ++j, e=e->GetNext()) {
|
||||
|
||||
OpenSubdiv::HbrFVarData<T> & fvt = e->GetOrgVertex()->GetFVarData(f);
|
||||
|
||||
float const * fvdata = &sh->uvs[ sh->faceuvs[idx++]*2 ];
|
||||
|
||||
if (! fvt.IsInitialized()) {
|
||||
fvt.SetAllData(2, fvdata);
|
||||
} else if (! fvt.CompareAll(2, fvdata)) {
|
||||
OpenSubdiv::HbrFVarData<T> & nfvt = e->GetOrgVertex()->NewFVarData(f);
|
||||
nfvt.SetAllData(2, fvdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T> OpenSubdiv::HbrMesh<T> *
|
||||
simpleHbr(Shape const * sh, std::vector<float> * verts=0, bool fvar=false) {
|
||||
|
||||
int fvarwidth = fvar && sh->HasUV() ? 2 : 0;
|
||||
|
||||
OpenSubdiv::HbrMesh<T> * mesh = createMesh<T>(sh->scheme, fvarwidth);
|
||||
|
||||
createVerticesWithPositions<T>(sh, mesh);
|
||||
|
||||
createTopology<T>(sh, mesh, sh->scheme);
|
||||
|
||||
if (fvar)
|
||||
createFaceVaryingUV<T>(sh, mesh);
|
||||
|
||||
if (verts)
|
||||
copyVertexPositions<T>(sh, mesh, *verts);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
template <class T> OpenSubdiv::HbrMesh<T> *
|
||||
simpleHbr(char const * Shapestr, Scheme scheme, std::vector<float> * verts=0, bool fvar=false) {
|
||||
|
||||
Shape const * sh = Shape::parseObj( Shapestr, scheme );
|
||||
|
||||
OpenSubdiv::HbrMesh<T> * mesh = simpleHbr<T>(sh, verts, fvar);
|
||||
|
||||
delete sh;
|
||||
return mesh;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T> OpenSubdiv::HbrMesh<T> *
|
||||
simpleHbr(Shape const * sh, std::vector<float> & verts, bool fvar=false) {
|
||||
|
||||
int fvarwidth = fvar && sh->HasUV() ? 2 : 0;
|
||||
|
||||
OpenSubdiv::HbrMesh<T> * mesh = createMesh<T>(sh->scheme, fvarwidth);
|
||||
|
||||
createVertices<T>(sh, mesh);
|
||||
|
||||
createTopology<T>(sh, mesh, sh->scheme);
|
||||
|
||||
if (fvar)
|
||||
createFaceVaryingUV<T>(sh, mesh);
|
||||
|
||||
copyVertexPositions<T>(sh, mesh, verts);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
template <class T> OpenSubdiv::HbrMesh<T> *
|
||||
simpleHbr(char const * Shapestr, Scheme scheme, std::vector<float> & verts, bool fvar=false) {
|
||||
|
||||
Shape const * sh = Shape::parseObj( Shapestr, scheme );
|
||||
|
||||
OpenSubdiv::HbrMesh<T> *mesh = simpleHbr<T>(sh, verts, fvar);
|
||||
|
||||
delete sh;
|
||||
return mesh;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
OpenSubdiv::HbrMesh<T> *
|
||||
interpolateHbrVertexData(Shape const * sh, int maxlevel) {
|
||||
|
||||
// Hbr interpolation
|
||||
OpenSubdiv::HbrMesh<T> *hmesh = simpleHbr<T>(sh, /* verts vector */ 0, /* fvar */ false);
|
||||
assert(hmesh);
|
||||
|
||||
for (int level=0, firstface=0; level<maxlevel; ++level ) {
|
||||
int nfaces = hmesh->GetNumFaces();
|
||||
for (int i=firstface; i<nfaces; ++i) {
|
||||
|
||||
OpenSubdiv::HbrFace<T> * f = hmesh->GetFace(i);
|
||||
assert(f->GetDepth()==level);
|
||||
if (! f->IsHole()) {
|
||||
f->Refine();
|
||||
}
|
||||
}
|
||||
// Hbr allocates faces sequentially, skip faces that have already been
|
||||
// refined.
|
||||
firstface = nfaces;
|
||||
}
|
||||
return hmesh;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
OpenSubdiv::HbrMesh<T> *
|
||||
interpolateHbrVertexData(char const * Shapestr, Scheme scheme, int maxlevel) {
|
||||
|
||||
Shape const * sh = Shape::parseObj( Shapestr, scheme );
|
||||
|
||||
OpenSubdiv::HbrMesh<T> *mesh = interpolateHbrVertexData<T>(sh, maxlevel);
|
||||
|
||||
delete sh;
|
||||
return mesh;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Returns true if a vertex or any of its parents is on a boundary
|
||||
template <class T>
|
||||
bool
|
||||
hbrVertexOnBoundary(const OpenSubdiv::HbrVertex<T> *v)
|
||||
{
|
||||
if (! v)
|
||||
return false;
|
||||
|
||||
if (v->OnBoundary())
|
||||
return true;
|
||||
|
||||
OpenSubdiv::HbrVertex<T> const * pv = v->GetParentVertex();
|
||||
if (pv)
|
||||
return hbrVertexOnBoundary(pv);
|
||||
else {
|
||||
OpenSubdiv::HbrHalfedge<T> const * pe = v->GetParentEdge();
|
||||
if (pe) {
|
||||
return hbrVertexOnBoundary(pe->GetOrgVertex()) ||
|
||||
hbrVertexOnBoundary(pe->GetDestVertex());
|
||||
} else {
|
||||
OpenSubdiv::HbrFace<T> const * pf = v->GetParentFace(), * rootf = pf;
|
||||
while (pf) {
|
||||
pf = pf->GetParent();
|
||||
if (pf)
|
||||
rootf=pf;
|
||||
}
|
||||
if (rootf)
|
||||
for (int i=0; i<rootf->GetNumVertices(); ++i)
|
||||
if (rootf->GetVertex(i)->OnBoundary())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#endif /* HBR_UTILS_H */
|
||||
375
blender-5.2.0/extern/opensubdiv-source/regression/common/shape_utils.cpp
vendored
Normal file
375
blender-5.2.0/extern/opensubdiv-source/regression/common/shape_utils.cpp
vendored
Normal file
@@ -0,0 +1,375 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
|
||||
#include "shape_utils.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static char const * sgets( char * s, int size, char ** stream ) {
|
||||
for (int i=0; i<size; ++i) {
|
||||
if ( (*stream)[i]=='\n' || (*stream)[i]=='\0') {
|
||||
|
||||
memcpy(s, *stream, i);
|
||||
s[i]='\0';
|
||||
|
||||
if ((*stream)[i]=='\0')
|
||||
return 0;
|
||||
else {
|
||||
(*stream) += i+1;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Shape::~Shape() {
|
||||
for (int i=0; i<(int)tags.size(); ++i)
|
||||
delete tags[i];
|
||||
|
||||
for (int i=0; i<(int)mtls.size(); ++i)
|
||||
delete mtls[i];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Shape * Shape::parseObj(char const * shapestr, Scheme shapescheme, bool isLeftHanded,
|
||||
bool parsemtl) {
|
||||
|
||||
Shape * s = new Shape;
|
||||
|
||||
s->scheme = shapescheme;
|
||||
s->isLeftHanded = isLeftHanded;
|
||||
|
||||
char * str=const_cast<char *>(shapestr), line[256], buf[256], usemtl=-1;
|
||||
bool done = false;
|
||||
while (! done) {
|
||||
done = sgets(line, sizeof(line), &str)==0;
|
||||
if (line[0]) {
|
||||
char* end = &line[strlen(line)-1];
|
||||
if (*end == '\n') *end = '\0'; // strip trailing nl
|
||||
}
|
||||
float x, y, z, u, v;
|
||||
switch (line[0]) {
|
||||
case 'v': switch (line[1]) {
|
||||
case ' ': if (sscanf(line, "v %f %f %f", &x, &y, &z) == 3) {
|
||||
s->verts.push_back(x);
|
||||
s->verts.push_back(y);
|
||||
s->verts.push_back(z);
|
||||
} break;
|
||||
case 't': if (sscanf(line, "vt %f %f", &u, &v) == 2) {
|
||||
s->uvs.push_back(u);
|
||||
s->uvs.push_back(v);
|
||||
} break;
|
||||
case 'n' : if (sscanf(line, "vn %f %f %f", &x, &y, &z) == 3) {
|
||||
s->normals.push_back(x);
|
||||
s->normals.push_back(y);
|
||||
s->normals.push_back(z);
|
||||
} break; // skip normals for now
|
||||
} break;
|
||||
case 'f': if (line[1] == ' ') {
|
||||
int vi, ti, ni;
|
||||
const char* cp = &line[2];
|
||||
while (*cp == ' ') cp++;
|
||||
int nverts = 0, nitems=0;
|
||||
while( (nitems=sscanf(cp, "%d/%d/%d", &vi, &ti, &ni))>0) {
|
||||
nverts++;
|
||||
s->faceverts.push_back(vi-1);
|
||||
if(nitems > 1) s->faceuvs.push_back(ti-1);
|
||||
if(nitems > 2) s->facenormals.push_back(ni-1);
|
||||
while (*cp && *cp != ' ') cp++;
|
||||
while (*cp == ' ') cp++;
|
||||
}
|
||||
s->nvertsPerFace.push_back(nverts);
|
||||
if (! s->mtls.empty()) {
|
||||
s->mtlbind.push_back(usemtl);
|
||||
}
|
||||
} break;
|
||||
case 't' : if (line[1] == ' ') {
|
||||
Shape::tag * t = tag::parseTag( line );
|
||||
if (t)
|
||||
s->tags.push_back(t);
|
||||
} break;
|
||||
case 'u' : if (parsemtl && sscanf(line, "usemtl %s", buf)==1) {
|
||||
usemtl = s->FindMaterial(buf);
|
||||
} break;
|
||||
case 'm' : if (parsemtl && sscanf(line, "mtllib %s", buf)==1) {
|
||||
std::ifstream ifs(buf);
|
||||
if (ifs) {
|
||||
std::stringstream ss;
|
||||
ss << ifs.rdbuf();
|
||||
ifs.close();
|
||||
std::string tmpStr = ss.str();
|
||||
s->parseMtllib(tmpStr.c_str());
|
||||
s->mtllib = buf;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Shape * Shape::parseObj(ShapeDesc const & shapeDesc, bool parsemtl) {
|
||||
return parseObj(shapeDesc.data.c_str(), shapeDesc.scheme, shapeDesc.isLeftHanded,
|
||||
parsemtl);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Shape::tag * Shape::tag::parseTag(char const * line) {
|
||||
tag * t = 0;
|
||||
|
||||
const char* cp = &line[2];
|
||||
|
||||
char tname[50];
|
||||
while (*cp == ' ') cp++;
|
||||
if (sscanf(cp, "%s", tname )!=1) return t;
|
||||
while (*cp && *cp != ' ') cp++;
|
||||
|
||||
int nints=0, nfloats=0, nstrings=0;
|
||||
while (*cp == ' ') cp++;
|
||||
if (sscanf(cp, "%d/%d/%d", &nints, &nfloats, &nstrings)!=3) return t;
|
||||
while (*cp && *cp != ' ') cp++;
|
||||
|
||||
std::vector<int> tintargs;
|
||||
for (int i=0; i<nints; ++i) {
|
||||
int val;
|
||||
while (*cp == ' ') cp++;
|
||||
if (sscanf(cp, "%d", &val)!=1) return t;
|
||||
tintargs.push_back(val);
|
||||
while (*cp && *cp != ' ') cp++;
|
||||
}
|
||||
|
||||
std::vector<float> tfloatargs;
|
||||
for (int i=0; i<nfloats; ++i) {
|
||||
float val;
|
||||
while (*cp == ' ') cp++;
|
||||
if (sscanf(cp, "%f", &val)!=1) return t;
|
||||
tfloatargs.push_back(val);
|
||||
while (*cp && *cp != ' ') cp++;
|
||||
}
|
||||
|
||||
std::vector<std::string> tstringargs;
|
||||
for (int i=0; i<nstrings; ++i) {
|
||||
char val[512];
|
||||
while (*cp == ' ') cp++;
|
||||
if (sscanf(cp, "%s", val)!=1) return t;
|
||||
tstringargs.push_back(std::string(val));
|
||||
while (*cp && *cp != ' ') cp++;
|
||||
}
|
||||
|
||||
t = new Shape::tag;
|
||||
t->name = tname;
|
||||
t->intargs = tintargs;
|
||||
t->floatargs = tfloatargs;
|
||||
t->stringargs = tstringargs;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Shape::material::material() {
|
||||
memset(ka, 0, sizeof(float)*3);
|
||||
memset(kd, 0, sizeof(float)*3);
|
||||
memset(ks, 0, sizeof(float)*3);
|
||||
memset(tf, 0, sizeof(float)*3);
|
||||
ns = ni = d = 0.0f;
|
||||
illum=0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Shape::parseMtllib(char const * mtlstr) {
|
||||
|
||||
char * str=const_cast<char *>(mtlstr), line[256];
|
||||
|
||||
material * mtl=0;
|
||||
|
||||
bool done = false;
|
||||
float r, g, b, a;
|
||||
while (! done) {
|
||||
done = sgets(line, sizeof(line), &str)==0;
|
||||
char* end = &line[strlen(line)-1];
|
||||
if (*end == '\n') *end = '\0'; // strip trailing nl
|
||||
switch (line[0]) {
|
||||
case 'n': char name[256];
|
||||
if (sscanf(line, "newmtl %s", name) == 1) {
|
||||
mtl = new material;
|
||||
mtl->name = name;
|
||||
mtls.push_back(mtl);
|
||||
} break;
|
||||
case 'K': if (sscanf(line+2, " %f %f %f", &r, &g, &b) == 3) {
|
||||
switch (line[1]) {
|
||||
case 'a': mtl->ka[0]=r; mtl->ka[1]=g; mtl->ka[2]=b; break;
|
||||
case 'd': mtl->kd[0]=r; mtl->kd[1]=g; mtl->kd[2]=b; break;
|
||||
case 's': mtl->ks[0]=r; mtl->ks[1]=g; mtl->ks[2]=b; break;
|
||||
}
|
||||
} break;
|
||||
case 'N': if (sscanf(line+2, " %f", &a) == 1) {
|
||||
switch (line[1]) {
|
||||
case 's' : mtl->ns = a; break;
|
||||
case 'i' : mtl->ni = a; break;
|
||||
}
|
||||
} break;
|
||||
case 'd': if (sscanf(line, "d %f", &a) == 1) {
|
||||
mtl->d = a;
|
||||
} break;
|
||||
case 'T': if (line[1]=='f') {
|
||||
if (sscanf(line, "Tf %f %f %f", &r, &g, &b) == 3) {
|
||||
mtl->tf[0]=r; mtl->tf[1]=g; mtl->tf[2]=b;
|
||||
} break;
|
||||
} break;
|
||||
case 'i': int illum;
|
||||
if (sscanf(line, "illum %d", &illum) == 1) {
|
||||
mtl->illum = illum;
|
||||
} break;
|
||||
case 's': if (sscanf(line, "sharpness %f", &a) == 1) {
|
||||
mtl->sharpness = a;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
std::string Shape::tag::genTag() const {
|
||||
std::stringstream t;
|
||||
|
||||
t<<"\"t \""<<name<<"\" ";
|
||||
|
||||
t<<intargs.size()<<"/"<<floatargs.size()<<"/"<<stringargs.size()<<" ";
|
||||
|
||||
std::copy(intargs.begin(), intargs.end(), std::ostream_iterator<int>(t));
|
||||
t<<" ";
|
||||
|
||||
std::copy(floatargs.begin(), floatargs.end(), std::ostream_iterator<float>(t));
|
||||
t<<" ";
|
||||
|
||||
std::copy(stringargs.begin(), stringargs.end(), std::ostream_iterator<std::string>(t));
|
||||
t<<"\\n\"\n";
|
||||
|
||||
return t.str();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
std::string Shape::genShape(char const * name) const {
|
||||
std::stringstream sh;
|
||||
|
||||
sh<<"static char const * "<<name<<" = \n";
|
||||
|
||||
for (int i=0; i<(int)verts.size(); i+=3)
|
||||
sh << "\"v " << verts[i] << " " << verts[i+1] << " " << verts[i+2] <<"\\n\"\n";
|
||||
|
||||
for (int i=0; i<(int)uvs.size(); i+=2)
|
||||
sh << "\"vt " << uvs[i] << " " << uvs[i+1] << "\\n\"\n";
|
||||
|
||||
for (int i=0; i<(int)normals.size(); i+=3)
|
||||
sh << "\"vn " << normals[i] << " " << normals[i+1] << " " << normals[i+2] <<"\\n\"\n";
|
||||
|
||||
sh << "\"s off\\n\"\n";
|
||||
|
||||
for (int i=0, idx=0; i<(int)nvertsPerFace.size();++i) {
|
||||
sh << "\"f ";
|
||||
for (int j=0; j<nvertsPerFace[i];++j) {
|
||||
int vert = faceverts[idx+j]+1,
|
||||
uv = (int)faceuvs.size()>0 ? faceuvs[idx+j]+1 : vert,
|
||||
normal = (int)facenormals.size()>0 ? facenormals[idx+j]+1 : vert;
|
||||
sh << vert << "/" << uv << "/" << normal << " ";
|
||||
}
|
||||
sh << "\\n\"\n";
|
||||
idx+=nvertsPerFace[i];
|
||||
}
|
||||
|
||||
for (int i=0; i<(int)tags.size(); ++i)
|
||||
sh << tags[i]->genTag();
|
||||
|
||||
return sh.str();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
std::string Shape::genObj() const {
|
||||
std::stringstream sh;
|
||||
|
||||
sh<<"# This file uses centimeters as units for non-parametric coordinates.\n\n";
|
||||
|
||||
for (int i=0; i<(int)verts.size(); i+=3)
|
||||
sh << "v " << verts[i] << " " << verts[i+1] << " " << verts[i+2] <<"\n";
|
||||
|
||||
for (int i=0; i<(int)uvs.size(); i+=2)
|
||||
sh << "vt " << uvs[i] << " " << uvs[i+1] << "\n";
|
||||
|
||||
for (int i=0; i<(int)normals.size(); i+=3)
|
||||
sh << "vn " << normals[i] << " " << normals[i+1] << " " << normals[i+2] <<"\n";
|
||||
|
||||
for (int i=0, idx=0; i<(int)nvertsPerFace.size();++i) {
|
||||
sh << "f ";
|
||||
for (int j=0; j<nvertsPerFace[i];++j) {
|
||||
int vert = faceverts[idx+j]+1,
|
||||
uv = (int)faceuvs.size()>0 ? faceuvs[idx+j]+1 : vert,
|
||||
normal = (int)facenormals.size()>0 ? facenormals[idx+j]+1 : vert;
|
||||
sh << vert << "/" << uv << "/" << normal << " ";
|
||||
}
|
||||
sh << "\n";
|
||||
idx+=nvertsPerFace[i];
|
||||
}
|
||||
|
||||
for (int i=0; i<(int)tags.size(); ++i)
|
||||
sh << tags[i]->genTag();
|
||||
|
||||
return sh.str();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
std::string Shape::genRIB() const {
|
||||
std::stringstream rib;
|
||||
|
||||
rib << "HierarchicalSubdivisionMesh \"catmull-clark\" ";
|
||||
|
||||
rib << "[";
|
||||
std::copy(nvertsPerFace.begin(), nvertsPerFace.end(), std::ostream_iterator<int>(rib));
|
||||
rib << "] ";
|
||||
|
||||
rib << "[";
|
||||
std::copy(faceverts.begin(), faceverts.end(), std::ostream_iterator<int>(rib));
|
||||
rib << "] ";
|
||||
|
||||
std::stringstream names, nargs, intargs, floatargs, strargs;
|
||||
for (int i=0; i<(int)tags.size();) {
|
||||
tag * t = tags[i];
|
||||
|
||||
names << t->name;
|
||||
|
||||
nargs << t->intargs.size() << " " << t->floatargs.size() << " " << t->stringargs.size();
|
||||
|
||||
std::copy(t->intargs.begin(), t->intargs.end(), std::ostream_iterator<int>(intargs));
|
||||
|
||||
std::copy(t->floatargs.begin(), t->floatargs.end(), std::ostream_iterator<float>(floatargs));
|
||||
|
||||
std::copy(t->stringargs.begin(), t->stringargs.end(), std::ostream_iterator<std::string>(strargs));
|
||||
|
||||
if (++i<(int)tags.size()) {
|
||||
names << " ";
|
||||
nargs << " ";
|
||||
intargs << " ";
|
||||
floatargs << " ";
|
||||
strargs << " ";
|
||||
}
|
||||
}
|
||||
|
||||
rib << "["<<names.str()<<"] " << "["<<nargs.str()<<"] " << "["<<intargs.str()<<"] " << "["<<floatargs.str()<<"] " << "["<<strargs.str()<<"] ";
|
||||
|
||||
rib << "\"P\" [";
|
||||
std::copy(verts.begin(), verts.end(), std::ostream_iterator<float>(rib));
|
||||
rib << "] ";
|
||||
|
||||
return rib.str();
|
||||
}
|
||||
121
blender-5.2.0/extern/opensubdiv-source/regression/common/shape_utils.h
vendored
Normal file
121
blender-5.2.0/extern/opensubdiv-source/regression/common/shape_utils.h
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef SHAPE_UTILS_H
|
||||
#define SHAPE_UTILS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
enum Scheme {
|
||||
kBilinear=0,
|
||||
kCatmark,
|
||||
kLoop
|
||||
};
|
||||
|
||||
struct ShapeDesc
|
||||
{
|
||||
ShapeDesc(char const * iname, std::string const & idata, Scheme ischeme,
|
||||
bool iIsLeftHanded = false) :
|
||||
name(iname), data(idata), scheme(ischeme), isLeftHanded(iIsLeftHanded)
|
||||
{ }
|
||||
|
||||
std::string name;
|
||||
std::string data;
|
||||
Scheme scheme;
|
||||
bool isLeftHanded;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
struct Shape {
|
||||
// full(er) spec here: http://paulbourke.net/dataformats/mtl/
|
||||
struct material {
|
||||
|
||||
material();
|
||||
|
||||
std::string name;
|
||||
|
||||
float ka[3], // ambient
|
||||
kd[3], // diffuse
|
||||
ks[3], // specular
|
||||
ns, // specular exponent
|
||||
ni, // optical density (1.0=no refraction, glass=1.5)
|
||||
sharpness, // reflection sharpness
|
||||
tf[3], // transmission filter
|
||||
d; // dissolve factor (1.0 = opaque)
|
||||
|
||||
int illum;
|
||||
};
|
||||
|
||||
struct tag {
|
||||
|
||||
static tag * parseTag(char const * stream);
|
||||
|
||||
std::string genTag() const;
|
||||
|
||||
std::string name;
|
||||
std::vector<int> intargs;
|
||||
std::vector<float> floatargs;
|
||||
std::vector<std::string> stringargs;
|
||||
};
|
||||
|
||||
static Shape * parseObj(ShapeDesc const & shapeDesc, bool parsemtl=false);
|
||||
static Shape * parseObj(char const * shapeString, Scheme shapeScheme,
|
||||
bool isLeftHanded=false, bool parsemtl=false);
|
||||
|
||||
void parseMtllib(char const * stream);
|
||||
|
||||
std::string genShape(char const * name) const;
|
||||
|
||||
std::string genObj() const;
|
||||
|
||||
std::string genRIB() const;
|
||||
|
||||
Shape() : scheme(kCatmark), isLeftHanded(false) { }
|
||||
|
||||
~Shape();
|
||||
|
||||
int GetNumVertices() const { return (int)verts.size()/3; }
|
||||
|
||||
int GetNumFaces() const { return (int)nvertsPerFace.size(); }
|
||||
|
||||
bool HasUV() const { return ! (uvs.empty() || faceuvs.empty()); }
|
||||
|
||||
int GetFVarWidth() const { return HasUV() ? 2 : 0; }
|
||||
|
||||
std::vector<float> verts;
|
||||
std::vector<float> uvs;
|
||||
std::vector<float> normals;
|
||||
std::vector<int> nvertsPerFace;
|
||||
std::vector<int> faceverts;
|
||||
std::vector<int> faceuvs;
|
||||
std::vector<int> facenormals;
|
||||
std::vector<tag *> tags;
|
||||
Scheme scheme;
|
||||
bool isLeftHanded;
|
||||
|
||||
char FindMaterial(char const * name) {
|
||||
for (int i=0; i<(int)mtls.size(); ++i) {
|
||||
if (mtls[i]->name==name) {
|
||||
return (char) i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string mtllib;
|
||||
std::vector<unsigned short> mtlbind;
|
||||
std::vector<material *> mtls;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endif /* SHAPE_UTILS_H */
|
||||
Reference in New Issue
Block a user