Merge branch 'master' of github.com:syoyo/tinyobjloader
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
//
|
||||
// Stiches multiple .obj files into one .obj.
|
||||
//
|
||||
|
||||
#define TINYOBJLOADER_IMPLEMENTATION
|
||||
#include "../../tiny_obj_loader.h"
|
||||
#include "obj_writer.h"
|
||||
|
||||
@@ -11,27 +13,59 @@
|
||||
|
||||
typedef std::vector<tinyobj::shape_t> Shape;
|
||||
typedef std::vector<tinyobj::material_t> Material;
|
||||
typedef tinyobj::attrib_t Attribute;
|
||||
|
||||
void
|
||||
StichObjs(
|
||||
tinyobj::attrib_t& out_attribute,
|
||||
std::vector<tinyobj::shape_t>& out_shape,
|
||||
std::vector<tinyobj::material_t>& out_material,
|
||||
const std::vector<Attribute>& attributes,
|
||||
const std::vector<Shape>& shapes,
|
||||
const std::vector<Material>& materials)
|
||||
{
|
||||
int numShapes = 0;
|
||||
for (size_t i = 0; i < shapes.size(); i++) {
|
||||
numShapes += (int)shapes[i].size();
|
||||
// The amount of attributes, shape-vectors and material-vecotrs should be the same.
|
||||
if(attributes.size() != shapes.size() && attributes.size() != materials.size()){
|
||||
std::cerr << "Size of attributes, shapes and Materials don't fit!" << attributes.size() << " " << shapes.size() <<" " << materials.size() << std::endl;;
|
||||
exit(1);
|
||||
}
|
||||
int num_shapes = 0;
|
||||
// 4 values (vertices, normals, texcoords, colors)
|
||||
std::vector<int> num_attributes(4, 0);
|
||||
int num_materials = 0;
|
||||
for(int i = 0; i < shapes.size(); i++){
|
||||
num_shapes += shapes[i].size();
|
||||
}
|
||||
for(int i = 0; i < attributes.size(); i++){
|
||||
num_attributes[0] += attributes[i].vertices.size();
|
||||
num_attributes[1] += attributes[i].normals.size();
|
||||
num_attributes[2] += attributes[i].texcoords.size();
|
||||
num_attributes[3] += attributes[i].colors.size();
|
||||
}
|
||||
for(int i = 0; i < materials.size(); i++){
|
||||
num_materials += materials[i].size();
|
||||
}
|
||||
|
||||
printf("Total # of shapes = %d\n", numShapes);
|
||||
int materialIdOffset = 0;
|
||||
// More performant, than push_back
|
||||
out_attribute.vertices.resize(num_attributes[0]);
|
||||
out_attribute.normals.resize(num_attributes[1]);
|
||||
out_attribute.texcoords.resize(num_attributes[2]);
|
||||
out_attribute.colors.resize(num_attributes[3]);
|
||||
out_shape.resize(num_shapes);
|
||||
out_material.resize(num_materials);
|
||||
|
||||
size_t face_offset = 0;
|
||||
int material_id_offset = 0;
|
||||
int shape_id_offset = 0;
|
||||
int vertex_idx_offset = 0;
|
||||
int normal_idx_offset = 0;
|
||||
int texcoord_idx_offset = 0;
|
||||
int color_idx_offset = 0;
|
||||
|
||||
// shapes.size() = attributes.size() = materials.size()
|
||||
for (size_t i = 0; i < shapes.size(); i++) {
|
||||
|
||||
// Copy shapes
|
||||
for (size_t k = 0; k < shapes[i].size(); k++) {
|
||||
|
||||
std::string new_name = shapes[i][k].name;
|
||||
// Add suffix
|
||||
char buf[1024];
|
||||
@@ -39,36 +73,51 @@ StichObjs(
|
||||
new_name += std::string(buf);
|
||||
|
||||
printf("shape[%ld][%ld].name = %s\n", i, k, shapes[i][k].name.c_str());
|
||||
assert((shapes[i][k].mesh.indices.size() % 3) == 0);
|
||||
assert((shapes[i][k].mesh.positions.size() % 3) == 0);
|
||||
|
||||
tinyobj::shape_t new_shape = shapes[i][k];
|
||||
// Add offset.
|
||||
// Add material offset.
|
||||
for(size_t f = 0; f < new_shape.mesh.material_ids.size(); f++) {
|
||||
new_shape.mesh.material_ids[f] += materialIdOffset;
|
||||
new_shape.mesh.material_ids[f] += material_id_offset;
|
||||
}
|
||||
// Add indices offset.
|
||||
for(size_t f = 0; f < new_shape.mesh.indices.size(); f++){
|
||||
tinyobj::index_t& ref = new_shape.mesh.indices[f];
|
||||
if(ref.vertex_index > -1){
|
||||
ref.vertex_index += vertex_idx_offset;
|
||||
}
|
||||
if(ref.normal_index > -1){
|
||||
ref.normal_index += normal_idx_offset;
|
||||
}
|
||||
if(ref.texcoord_index > -1){
|
||||
ref.texcoord_index += texcoord_idx_offset;
|
||||
}
|
||||
}
|
||||
|
||||
new_shape.name = new_name;
|
||||
printf("shape[%ld][%ld].new_name = %s\n", i, k, new_shape.name.c_str());
|
||||
|
||||
out_shape.push_back(new_shape);
|
||||
out_shape[shape_id_offset++] = new_shape;
|
||||
}
|
||||
|
||||
materialIdOffset += materials[i].size();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < materials.size(); i++) {
|
||||
// Copy materials
|
||||
for (size_t k = 0; k < materials[i].size(); k++) {
|
||||
out_material.push_back(materials[i][k]);
|
||||
out_material[material_id_offset++] = materials[i][k];
|
||||
}
|
||||
|
||||
// Copy attributes (3 floats per vertex, 3 floats per normal, 2 floats per texture-coordinate, 3 floats per color)
|
||||
// You could also include a check here, if the sizes are dividable by 3 (resp. 2), but it's safe to simply assume, they do.
|
||||
std::copy(attributes[i].vertices.begin(), attributes[i].vertices.end(), out_attribute.vertices.begin() + vertex_idx_offset * 3);
|
||||
vertex_idx_offset += attributes[i].vertices.size() / 3;
|
||||
std::copy(attributes[i].normals.begin(), attributes[i].normals.end(), out_attribute.normals.begin() + normal_idx_offset * 3);
|
||||
normal_idx_offset += attributes[i].normals.size() / 3;
|
||||
std::copy(attributes[i].texcoords.begin(), attributes[i].texcoords.end(), out_attribute.texcoords.begin() + texcoord_idx_offset * 2);
|
||||
texcoord_idx_offset += attributes[i].texcoords.size() / 2;
|
||||
std::copy(attributes[i].colors.begin(), attributes[i].colors.end(), out_attribute.colors.begin() + color_idx_offset);
|
||||
color_idx_offset += attributes[i].colors.size();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
main(
|
||||
int argc,
|
||||
char **argv)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
printf("Usage: obj_sticher input0.obj input1.obj ... output.obj\n");
|
||||
@@ -78,16 +127,15 @@ main(
|
||||
int num_objfiles = argc - 2;
|
||||
std::string out_filename = std::string(argv[argc-1]); // last element
|
||||
|
||||
std::vector<Shape> shapes;
|
||||
std::vector<Material> materials;
|
||||
shapes.resize(num_objfiles);
|
||||
materials.resize(num_objfiles);
|
||||
std::vector<Attribute> attributes(num_objfiles);
|
||||
std::vector<Shape> shapes(num_objfiles);
|
||||
std::vector<Material> materials(num_objfiles);
|
||||
|
||||
for (int i = 0; i < num_objfiles; i++) {
|
||||
std::cout << "Loading " << argv[i+1] << " ... " << std::flush;
|
||||
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(shapes[i], materials[i], err, argv[i+1]);
|
||||
bool ret = tinyobj::LoadObj(&attributes[i], &shapes[i], &materials[i], &err, argv[i+1]);
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
@@ -98,12 +146,13 @@ main(
|
||||
std::cout << "DONE." << std::endl;
|
||||
}
|
||||
|
||||
std::vector<tinyobj::shape_t> out_shape;
|
||||
std::vector<tinyobj::material_t> out_material;
|
||||
StichObjs(out_shape, out_material, shapes, materials);
|
||||
Attribute out_attribute;
|
||||
Shape out_shape;
|
||||
Material out_material;
|
||||
StichObjs(out_attribute, out_shape, out_material, attributes, shapes, materials);
|
||||
|
||||
bool coordTransform = true;
|
||||
bool ret = WriteObj(out_filename, out_shape, out_material, coordTransform);
|
||||
bool ret = WriteObj(out_filename, out_attribute, out_shape, out_material, coordTransform);
|
||||
assert(ret);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -30,6 +30,8 @@ bool WriteMat(const std::string& filename, const std::vector<tinyobj::material_t
|
||||
fprintf(fp, "Ke %f %f %f\n", mat.emission[0], mat.emission[1], mat.emission[2]);
|
||||
fprintf(fp, "Ns %f\n", mat.shininess);
|
||||
fprintf(fp, "Ni %f\n", mat.ior);
|
||||
fprintf(fp, "illum %d\n", mat.illum);
|
||||
fprintf(fp, "\n");
|
||||
// @todo { texture }
|
||||
}
|
||||
|
||||
@@ -38,7 +40,7 @@ bool WriteMat(const std::string& filename, const std::vector<tinyobj::material_t
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials, bool coordTransform) {
|
||||
bool WriteObj(const std::string& filename, const tinyobj::attrib_t& attributes, const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials, bool coordTransform) {
|
||||
FILE* fp = fopen(filename.c_str(), "w");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "Failed to open file [ %s ] for write.\n", filename.c_str());
|
||||
@@ -48,17 +50,53 @@ bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>&
|
||||
std::string basename = GetFileBasename(filename);
|
||||
std::string material_filename = basename + ".mtl";
|
||||
|
||||
int v_offset = 0;
|
||||
int vn_offset = 0;
|
||||
int vt_offset = 0;
|
||||
int prev_material_id = -1;
|
||||
|
||||
fprintf(fp, "mtllib %s\n", material_filename.c_str());
|
||||
fprintf(fp, "mtllib %s\n\n", material_filename.c_str());
|
||||
|
||||
// facevarying vtx
|
||||
for (size_t k = 0; k < attributes.vertices.size(); k+=3) {
|
||||
if (coordTransform) {
|
||||
fprintf(fp, "v %f %f %f\n",
|
||||
attributes.vertices[k + 0],
|
||||
attributes.vertices[k + 2],
|
||||
-attributes.vertices[k + 1]);
|
||||
} else {
|
||||
fprintf(fp, "v %f %f %f\n",
|
||||
attributes.vertices[k + 0],
|
||||
attributes.vertices[k + 1],
|
||||
attributes.vertices[k + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fp, "\n");
|
||||
|
||||
// facevarying normal
|
||||
for (size_t k = 0; k < attributes.normals.size(); k += 3) {
|
||||
if (coordTransform) {
|
||||
fprintf(fp, "vn %f %f %f\n",
|
||||
attributes.normals[k + 0],
|
||||
attributes.normals[k + 2],
|
||||
-attributes.normals[k + 1]);
|
||||
} else {
|
||||
fprintf(fp, "vn %f %f %f\n",
|
||||
attributes.normals[k + 0],
|
||||
attributes.normals[k + 1],
|
||||
attributes.normals[k + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fp, "\n");
|
||||
|
||||
// facevarying texcoord
|
||||
for (size_t k = 0; k < attributes.texcoords.size(); k += 2) {
|
||||
fprintf(fp, "vt %f %f\n",
|
||||
attributes.texcoords[k + 0],
|
||||
attributes.texcoords[k + 1]);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < shapes.size(); i++) {
|
||||
|
||||
bool has_vn = false;
|
||||
bool has_vt = false;
|
||||
fprintf(fp, "\n");
|
||||
|
||||
if (shapes[i].name.empty()) {
|
||||
fprintf(fp, "g Unknown\n");
|
||||
@@ -66,101 +104,53 @@ bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>&
|
||||
fprintf(fp, "g %s\n", shapes[i].name.c_str());
|
||||
}
|
||||
|
||||
//if (!shapes[i].material.name.empty()) {
|
||||
// fprintf(fp, "usemtl %s\n", shapes[i].material.name.c_str());
|
||||
//}
|
||||
|
||||
// facevarying vtx
|
||||
for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
int idx = shapes[i].mesh.indices[3*k+j];
|
||||
if (coordTransform) {
|
||||
fprintf(fp, "v %f %f %f\n",
|
||||
shapes[i].mesh.positions[3*idx+0],
|
||||
shapes[i].mesh.positions[3*idx+2],
|
||||
-shapes[i].mesh.positions[3*idx+1]);
|
||||
} else {
|
||||
fprintf(fp, "v %f %f %f\n",
|
||||
shapes[i].mesh.positions[3*idx+0],
|
||||
shapes[i].mesh.positions[3*idx+1],
|
||||
shapes[i].mesh.positions[3*idx+2]);
|
||||
bool has_vn = false;
|
||||
bool has_vt = false;
|
||||
// Assumes normals and textures are set shape-wise.
|
||||
if(shapes[i].mesh.indices.size() > 0){
|
||||
has_vn = shapes[i].mesh.indices[0].normal_index != -1;
|
||||
has_vt = shapes[i].mesh.indices[0].texcoord_index != -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// facevarying normal
|
||||
if (shapes[i].mesh.normals.size() > 0) {
|
||||
for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
int idx = shapes[i].mesh.indices[3*k+j];
|
||||
if (coordTransform) {
|
||||
fprintf(fp, "vn %f %f %f\n",
|
||||
shapes[i].mesh.normals[3*idx+0],
|
||||
shapes[i].mesh.normals[3*idx+2],
|
||||
-shapes[i].mesh.normals[3*idx+1]);
|
||||
} else {
|
||||
fprintf(fp, "vn %f %f %f\n",
|
||||
shapes[i].mesh.normals[3*idx+0],
|
||||
shapes[i].mesh.normals[3*idx+1],
|
||||
shapes[i].mesh.normals[3*idx+2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shapes[i].mesh.normals.size() > 0) has_vn = true;
|
||||
|
||||
// facevarying texcoord
|
||||
if (shapes[i].mesh.texcoords.size() > 0) {
|
||||
for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
int idx = shapes[i].mesh.indices[3*k+j];
|
||||
fprintf(fp, "vt %f %f\n",
|
||||
shapes[i].mesh.texcoords[2*idx+0],
|
||||
shapes[i].mesh.texcoords[2*idx+1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shapes[i].mesh.texcoords.size() > 0) has_vt = true;
|
||||
|
||||
// face
|
||||
for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) {
|
||||
|
||||
// Face index is 1-base.
|
||||
//int v0 = shapes[i].mesh.indices[3*k+0] + 1 + v_offset;
|
||||
//int v1 = shapes[i].mesh.indices[3*k+1] + 1 + v_offset;
|
||||
//int v2 = shapes[i].mesh.indices[3*k+2] + 1 + v_offset;
|
||||
int v0 = (3*k + 0) + 1 + v_offset;
|
||||
int v1 = (3*k + 1) + 1 + v_offset;
|
||||
int v2 = (3*k + 2) + 1 + v_offset;
|
||||
|
||||
int vt0 = (3*k + 0) + 1 + vt_offset;
|
||||
int vt1 = (3*k + 1) + 1 + vt_offset;
|
||||
int vt2 = (3*k + 2) + 1 + vt_offset;
|
||||
|
||||
int material_id = shapes[i].mesh.material_ids[k];
|
||||
int face_index = 0;
|
||||
for (size_t k = 0; k < shapes[i].mesh.indices.size(); k += shapes[i].mesh.num_face_vertices[face_index++]) {
|
||||
// Check Materials
|
||||
int material_id = shapes[i].mesh.material_ids[face_index];
|
||||
if (material_id != prev_material_id) {
|
||||
std::string material_name = materials[material_id].name;
|
||||
fprintf(fp, "usemtl %s\n", material_name.c_str());
|
||||
prev_material_id = material_id;
|
||||
}
|
||||
|
||||
unsigned char v_per_f = shapes[i].mesh.num_face_vertices[face_index];
|
||||
// Imperformant, but if you want to have variable vertices per face, you need some kind of a dynamic loop.
|
||||
fprintf(fp, "f");
|
||||
for(int l = 0; l < v_per_f; l++){
|
||||
const tinyobj::index_t& ref = shapes[i].mesh.indices[k + l];
|
||||
if(has_vn && has_vt){
|
||||
fprintf(fp, "f %d/%d/%d %d/%d/%d %d/%d/%d\n",
|
||||
v0, vt0, v0, v1, vt1, v1, v2, vt2, v2);
|
||||
} else if (has_vn && !has_vt) {
|
||||
fprintf(fp, "f %d//%d %d//%d %d//%d\n", v0, v0, v1, v1, v2, v2);
|
||||
} else if (!has_vn && has_vt) {
|
||||
fprintf(fp, "f %d/%d %d/%d %d/%d\n", v0, v0, v1, v1, v2, v2);
|
||||
} else {
|
||||
fprintf(fp, "f %d %d %d\n", v0, v1, v2);
|
||||
// v0/t0/vn0
|
||||
fprintf(fp, " %d/%d/%d", ref.vertex_index + 1, ref.texcoord_index + 1, ref.normal_index + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(has_vn && !has_vt){
|
||||
// v0//vn0
|
||||
fprintf(fp, " %d//%d", ref.vertex_index + 1, ref.normal_index + 1);
|
||||
continue;
|
||||
}
|
||||
if(!has_vn && has_vt){
|
||||
// v0/vt0
|
||||
fprintf(fp, " %d/%d", ref.vertex_index + 1, ref.texcoord_index + 1);
|
||||
continue;
|
||||
}
|
||||
if(!has_vn && !has_vt){
|
||||
// v0 v1 v2
|
||||
fprintf(fp, " %d", ref.vertex_index + 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
v_offset += shapes[i].mesh.indices.size();
|
||||
//vn_offset += shapes[i].mesh.normals.size() / 3;
|
||||
vt_offset += shapes[i].mesh.texcoords.size() / 2;
|
||||
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "../../tiny_obj_loader.h"
|
||||
|
||||
extern bool WriteObj(const std::string& filename, const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials, bool coordTransform = false);
|
||||
|
||||
extern bool WriteObj(const std::string& filename, const tinyobj::attrib_t& attributes, const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials, bool coordTransform = false);
|
||||
|
||||
#endif // __OBJ_WRITER_H__
|
||||
|
||||
@@ -1523,7 +1523,6 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes,
|
||||
size_t t_count = t_offsets[t];
|
||||
size_t f_count = f_offsets[t];
|
||||
size_t face_count = face_offsets[t];
|
||||
int material_id = -1; // -1 = default unknown material.
|
||||
|
||||
for (size_t i = 0; i < commands[t].size(); i++) {
|
||||
if (commands[t][i].type == COMMAND_EMPTY) {
|
||||
|
||||
24
models/invalid-face-definition.mtl
Normal file
24
models/invalid-face-definition.mtl
Normal file
@@ -0,0 +1,24 @@
|
||||
newmtl white
|
||||
Ka 0 0 0
|
||||
Kd 1 1 1
|
||||
Ks 0 0 0
|
||||
|
||||
newmtl red
|
||||
Ka 0 0 0
|
||||
Kd 1 0 0
|
||||
Ks 0 0 0
|
||||
|
||||
newmtl green
|
||||
Ka 0 0 0
|
||||
Kd 0 1 0
|
||||
Ks 0 0 0
|
||||
|
||||
newmtl blue
|
||||
Ka 0 0 0
|
||||
Kd 0 0 1
|
||||
Ks 0 0 0
|
||||
|
||||
newmtl light
|
||||
Ka 20 20 20
|
||||
Kd 1 1 1
|
||||
Ks 0 0 0
|
||||
18
models/invalid-face-definition.obj
Normal file
18
models/invalid-face-definition.obj
Normal file
@@ -0,0 +1,18 @@
|
||||
mtllib invalid-face-definition.mtl
|
||||
|
||||
v 0.000000 2.000000 2.000000
|
||||
v 0.000000 0.000000 2.000000
|
||||
v 2.000000 0.000000 2.000000
|
||||
v 2.000000 2.000000 2.000000
|
||||
v 0.000000 2.000000 0.000000
|
||||
v 0.000000 0.000000 0.000000
|
||||
v 2.000000 0.000000 0.000000
|
||||
v 2.000000 2.000000 0.000000
|
||||
# 8 vertices
|
||||
|
||||
g front cube
|
||||
usemtl white
|
||||
f 1
|
||||
g back cube
|
||||
# expects white material
|
||||
f 8 7
|
||||
@@ -751,6 +751,24 @@ TEST_CASE("smoothing-group", "[Issue162]") {
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("invalid-face-definition", "[face]") {
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/invalid-face-definition.obj", gMtlBasePath);
|
||||
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << "[face] " << err << std::endl;
|
||||
}
|
||||
|
||||
REQUIRE(true == ret);
|
||||
REQUIRE(1 == shapes.size());
|
||||
REQUIRE(0 == shapes[0].mesh.indices.size());
|
||||
}
|
||||
|
||||
#if 0
|
||||
int
|
||||
main(
|
||||
|
||||
@@ -1028,6 +1028,11 @@ static bool exportFaceGroupToShape(shape_t *shape,
|
||||
for (size_t i = 0; i < faceGroup.size(); i++) {
|
||||
const face_t &face = faceGroup[i];
|
||||
|
||||
if (face.vertex_indices.size() < 3) {
|
||||
// Face must have 3+ vertices.
|
||||
continue;
|
||||
}
|
||||
|
||||
vertex_index_t i0 = face.vertex_indices[0];
|
||||
vertex_index_t i1(-1);
|
||||
vertex_index_t i2 = face.vertex_indices[1];
|
||||
|
||||
Reference in New Issue
Block a user