Mercurial > hg > forks > gldragon
view dmply.cpp @ 107:2b30217a3c39 default tip
Fix verbose build echos.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Thu, 29 Feb 2024 21:48:47 +0200 |
parents | 03aa729a9e90 |
children |
line wrap: on
line source
// // GLDragon - OpenGL PLY model viewer / simple benchmark // -- PLY file parsing // Programmed and designed by Matti 'ccr' Hämäläinen <ccr@tnsp.org> // (C) Copyright 2019 Tecnic Software productions (TNSP) // // See file "COPYING" for license information. // #include "dmply.h" #include <SDL_endian.h> static DMPLYPropType dmPLYParsePropType(const std::string &name) { if (name == "list") return PLY_TYPE_LIST; else if (name == "float" || name == "float32") return PLY_TYPE_FLOAT; else if (name == "double" || name == "float64") return PLY_TYPE_DOUBLE; else if (name == "uchar" || name == "uint8") return PLY_TYPE_UINT8; else if (name == "int16") return PLY_TYPE_INT16; else if (name == "uint16") return PLY_TYPE_UINT16; else if (name == "int" || name == "int32") return PLY_TYPE_INT32; else if (name == "uint" || name == "uint32") return PLY_TYPE_UINT32; else return PLY_TYPE_NONE; } static bool dmPLYParsePropertyValueASCII(DMPLYFileInfo &info, const DMPLYPropType ptype, DMPLYPropValue &pval, size_t &pos) { size_t len = 0; std::string val = info.line.substr(pos); switch (ptype) { case PLY_TYPE_INT8: case PLY_TYPE_INT16: case PLY_TYPE_INT32: pval.v_int = std::stoi(val, &len); break; case PLY_TYPE_UINT8: case PLY_TYPE_UINT16: case PLY_TYPE_UINT32: pval.v_uint = std::stoi(val, &len); break; case PLY_TYPE_FLOAT: pval.v_float = std::stof(val, &len); break; case PLY_TYPE_DOUBLE: pval.v_double = std::stod(val, &len); break; default: return info.textError( "Internal error, unimplemented PLY property type"); } pos += len; return true; } static bool dmPLYParsePropertyASCII(DMPLYFileInfo &info, DMPLYFileProperty &prop, size_t &pos) { switch (prop.type) { case PLY_TYPE_LIST: prop.list_values.clear(); if (!dmPLYParsePropertyValueASCII(info, prop.list_num_type, prop.list_num_value, pos)) return false; for (unsigned int n = 0; n < prop.list_num_value.v_uint; n++) { DMPLYPropValue pval; if (!dmPLYParsePropertyValueASCII(info, prop.list_values_type, pval, pos)) return false; prop.list_values.push_back(pval); } if (prop.list_values.size() != prop.list_num_value.v_uint) { return info.syntaxError( "Number of property list '"+ prop.name +" values not equal to number specified"); } return true; default: return dmPLYParsePropertyValueASCII(info, prop.type, prop.value, pos); } } static bool dmPLYParseElementASCII(DMPLYFileInfo &info, DMPLYFileElement &element) { size_t nprop = 0, pos = 0; // Read one line if (!info.readLine()) { return info.textError( "Unexpected end of file"); } // Skip empty lines if (info.line.empty()) return true; // Parse the properties for (auto const prop : element.properties) { if (!dmPLYParsePropertyASCII(info, *prop, pos)) return false; nprop++; } if (nprop != element.properties.size()) { return info.syntaxError( "Expected N properties, got different number"); } return true; } bool dmPLYReadPropertyValueBIN(DMPLYFileInfo &info, const DMPLYPropType ptype, DMPLYPropValue &pval) { uint8_t tmpU8; int8_t tmpS8; uint16_t tmpU16; int16_t tmpS16; uint32_t tmpU32; int32_t tmpS32; float tmpFloat; switch (ptype) { case PLY_TYPE_INT8: info.file.read(reinterpret_cast<char *>(&tmpS8), 1); pval.v_int = tmpS8; break; case PLY_TYPE_UINT8: info.file.read(reinterpret_cast<char *>(&tmpU8), 1); pval.v_uint = tmpU8; break; case PLY_TYPE_INT16: info.file.read(reinterpret_cast<char *>(&tmpS16), 2); tmpS16 = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapLE16(tmpS16) : SDL_SwapBE16(tmpS16); pval.v_int = tmpS16; break; case PLY_TYPE_UINT16: info.file.read(reinterpret_cast<char *>(&tmpU16), 2); tmpU16 = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapLE16(tmpU16) : SDL_SwapBE16(tmpU16); pval.v_uint = tmpU16; break; case PLY_TYPE_INT32: info.file.read(reinterpret_cast<char *>(&tmpS32), 4); tmpS32 = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapLE32(tmpS32) : SDL_SwapBE32(tmpS32); pval.v_int = tmpS32; break; case PLY_TYPE_UINT32: info.file.read(reinterpret_cast<char *>(&tmpU32), 4); tmpU32 = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapLE32(tmpU32) : SDL_SwapBE32(tmpU32); pval.v_uint = tmpU32; break; case PLY_TYPE_FLOAT: info.file.read(reinterpret_cast<char *>(&tmpFloat), 4); pval.v_float = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapFloatLE(tmpFloat) : SDL_SwapFloatBE(tmpFloat); break; default: return info.textError( "Internal error, unimplemented PLY property type"); } return true; } bool dmPLYReadPropertyBIN(DMPLYFileInfo &info, DMPLYFileProperty &prop) { switch (prop.type) { case PLY_TYPE_LIST: prop.list_values.clear(); if (!dmPLYReadPropertyValueBIN(info, prop.list_num_type, prop.list_num_value)) return false; for (unsigned int n = 0; n < prop.list_num_value.v_uint; n++) { DMPLYPropValue pval; if (!dmPLYReadPropertyValueBIN(info, prop.list_values_type, pval)) return false; prop.list_values.push_back(pval); } if (prop.list_values.size() != prop.list_num_value.v_uint) { return info.syntaxError( "Number of property list '"+ prop.name +" values not equal to number specified"); } return true; default: return dmPLYReadPropertyValueBIN(info, prop.type, prop.value); } } bool dmPLYReadElementBIN(DMPLYFileInfo &info, DMPLYFileElement &element) { size_t nprop = 0; for (auto const prop : element.properties) { if (!dmPLYReadPropertyBIN(info, *prop)) return false; nprop++; } if (nprop != element.properties.size()) { return info.syntaxError( "Expected N properties, got different number"); } return true; } bool dmLoadFromPLY(DMModel &model, const std::string &filename) { DMPLYFileInfo info; return dmLoadFromPLY(model, filename, info); } bool dmLoadFromPLY(DMModel &model, const std::string &filename, DMPLYFileInfo &info) { info.filename = filename; info.nline = info.state = 0; info.file.open(info.filename.c_str(), std::fstream::in | std::fstream::binary); dmMsg("Trying to read mesh from '%s'.\n", info.filename.c_str()); if (!info.file.is_open()) { dmError("Unable to open file '%s'.\n", info.filename.c_str()); return false; } // Parse the PLY header while (info.state >= 0) { // Read one line if (!info.readLine()) return false; // Skip empty lines if (info.line.empty()) continue; // Split key and value std::vector<std::string> tokens = dmStrSplit(info.line); std::string &key = tokens[0]; if (info.state == 0 && key == "ply") { info.state = 1; } else if (info.state > 0 && key == "end_header") { info.state = -1; } else if (info.state == 1 && key == "format") { if (tokens.size() < 3) { return info.syntaxError( "Expected value for format"); } info.format = PLY_FMT_UNKNOWN; if (tokens[1] == "ascii") info.format = PLY_FMT_ASCII; else if (tokens[1] == "binary_little_endian") info.format = PLY_FMT_BIN_LE; else if (tokens[1] == "binary_big_endian") info.format = PLY_FMT_BIN_BE; if (info.format == PLY_FMT_UNKNOWN || tokens[2] != "1.0") { dmError("Unknown or unsupported PLY file format '%s'.\n", (tokens[1] +" "+ tokens[2]).c_str()); return false; } info.state = 2; } else if ((info.state == 2 || info.state == 3) && key == "element") { if (tokens.size() < 3) { return info.syntaxError( "Expected a value for element key"); } std::string &el_name = tokens[1], &el_value = tokens[2]; if (info.elem_map.count(el_name)) { return info.syntaxError( "Element '"+ el_name +"' has already been defined"); } DMPLYFileElement &elem = info.elem_map[el_name]; info.element = &elem; info.elements.push_back(&elem); elem.name = el_name; elem.value = std::stoi(el_value); info.state = 3; } else if (info.state == 3 && key == "property") { if (tokens.size() < 3) { return info.syntaxError( "Expected value for property"); } const std::string &pr_name = tokens.back(), &pr_typename = tokens.at(1); if (!info.element) { // Should not happen return info.syntaxError( "No element defined for property '"+ pr_name +"'?"); } // Check if this property has been already defined if (info.element->prop_map.count(pr_name)) { return info.syntaxError( "Element '"+ info.element->name + "' already has property '"+ pr_name +"' defined?"); } // Parse property information DMPLYPropType pr_type = dmPLYParsePropType(pr_typename); if (pr_type == PLY_TYPE_NONE) { return info.syntaxError( "Invalid or unsupported property type '"+ pr_typename +"'"); } DMPLYFileProperty &prop = info.element->prop_map[pr_name]; info.element->properties.push_back(&prop); prop.name = pr_name; prop.type = pr_type; if (pr_type == PLY_TYPE_LIST) { // List is a special case if (tokens.size() < 5) { return info.syntaxError( "Expected more values for a list property (num_type, val_type, name)"); } prop.list_num_type = dmPLYParsePropType(tokens.at(2)); prop.list_values_type = dmPLYParsePropType(tokens.at(3)); if (prop.list_num_type == PLY_TYPE_NONE || prop.list_values_type == PLY_TYPE_NONE) { return info.syntaxError( "Invalid or unsupported property type(s)"); } } } else if (info.state > 0 // && (key == "comment" || key == "obj_info") ) { // Ignore comments // .. and unknown keys } else { return info.syntaxError( "Unexpected key '"+ key +"'"); } } // Check header data DMPLYFileElement *elem; DMPLYFileProperty *prop; if (info.state != -1 || (elem = info.checkElem(PLY_ELEM_FACE)) == 0 || (prop = elem->checkProp(PLY_PROP_VERTEX_INDICES)) == 0 || prop->type != PLY_TYPE_LIST || (elem = info.checkElem(PLY_ELEM_VERTEX)) == 0 || (prop = elem->checkProp("x")) == 0 || prop->type != PLY_TYPE_FLOAT || (prop = elem->checkProp("y")) == 0 || prop->type != PLY_TYPE_FLOAT || (prop = elem->checkProp("z")) == 0 || prop->type != PLY_TYPE_FLOAT ) { dmError("PLY file did not contain expected information.\n"); return false; } model.nvertices = info.elem_map[PLY_ELEM_VERTEX].value; model.nfaces = info.elem_map[PLY_ELEM_FACE].value; if (model.nvertices < 3 || model.nfaces < 1) { dmError("Invalid nvertices (%d) and/or nfaces (%d).\n", model.nvertices, model.nfaces); return false; } dmMsg("Should have %d vertices, %d faces\n", model.nvertices, model.nfaces); // Pre-allocate space model.vertices.reserve(model.nvertices); model.normals.reserve(model.nvertices); model.faces.reserve(model.nfaces * 3); // Read the actual data (in order of the elements) for (auto *element : info.elements) for (int n = 0; n < element->value; n++) { switch (info.format) { case PLY_FMT_ASCII: if (!dmPLYParseElementASCII(info, *element)) return false; break; default: if (!dmPLYReadElementBIN(info, *element)) return false; break; } // Check for specific elements if (element->name == PLY_ELEM_FACE) { DMPLYFileProperty &prop = element->prop_map[PLY_PROP_VERTEX_INDICES]; if (prop.list_num_value.v_uint != 3) { return info.syntaxError( "Expected 3 vertices per face"); } for (unsigned int n = 0; n < prop.list_num_value.v_uint; n++) { model.faces.push_back(prop.list_values[n].v_uint); } } else if (element->name == PLY_ELEM_VERTEX) { DMVector3 vert; vert.x = element->prop_map["x"].value.v_float; vert.y = element->prop_map["y"].value.v_float; vert.z = element->prop_map["z"].value.v_float; model.vertices.push_back(vert); if (element->checkProp("nx") && element->checkProp("ny") && element->checkProp("nz")) { DMVector3 normal; normal.x = element->prop_map["nx"].value.v_float; normal.y = element->prop_map["ny"].value.v_float; normal.z = element->prop_map["nz"].value.v_float; model.normals.push_back(normal); } } } dmMsg("Found %ld vertices, %ld normals, %ld faces\n", model.vertices.size(), model.normals.size(), model.faces.size() / 3); return true; }