Mercurial > hg > forks > gldragon
diff dmscene.cpp @ 70:03aa729a9e90
Refactor PLY file parsing from dmscene.* to dmply.* and some helper functions into dmutil.h
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 16 Dec 2019 07:51:05 +0200 |
parents | 7b138613e2fc |
children |
line wrap: on
line diff
--- a/dmscene.cpp Mon Dec 16 06:51:40 2019 +0200 +++ b/dmscene.cpp Mon Dec 16 07:51:05 2019 +0200 @@ -1,572 +1,12 @@ // // GLDragon - OpenGL PLY model viewer / simple benchmark -// -- Scene and model handling + PLY file parsing +// -- Scene file handling // 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 "dmscene.h" -#include <SDL_endian.h> - - -static bool dmTextError(DMTextFileInfo &info, const std::string &msg) -{ - dmError("%s on line #%d: %s\n", - msg.c_str(), info.nline, info.line.c_str()); - return false; -} - - -static bool dmSyntaxError(DMTextFileInfo &info, const std::string &msg) -{ - dmError("Syntax error on line #%d: %s\n", - info.nline, msg.c_str()); - return false; -} - - -static bool dmReadLine(DMTextFileInfo &info) -{ - if (!std::getline(info.file, info.line)) - return false; - - info.nline++; - - info.line = dmStrTrim(info.line); - - return true; -} - - -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 dmTextError(info, - "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 dmSyntaxError(info, - "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 (!dmReadLine(info)) - { - return dmTextError(info, - "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 dmSyntaxError(info, - "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 dmTextError(info, - "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 dmSyntaxError(info, - "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 dmSyntaxError(info, - "Expected N properties, got different number"); - } - - return true; -} - - -bool DMModel::loadFromPLY(const std::string &filename) -{ - DMPLYFileInfo info; - - return loadFromPLY(filename, info); -} - - -bool DMModel::loadFromPLY(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 (!dmReadLine(info)) - 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 dmSyntaxError(info, - "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 dmSyntaxError(info, - "Expected a value for element key"); - } - - std::string &el_name = tokens[1], &el_value = tokens[2]; - - if (info.elem_map.count(el_name)) - { - return dmSyntaxError(info, - "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 dmSyntaxError(info, - "Expected value for property"); - } - - const std::string - &pr_name = tokens.back(), - &pr_typename = tokens.at(1); - - if (!info.element) - { - // Should not happen - return dmSyntaxError(info, - "No element defined for property '"+ pr_name +"'?"); - } - - // Check if this property has been already defined - if (info.element->prop_map.count(pr_name)) - { - return dmSyntaxError(info, - "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 dmSyntaxError(info, - "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 dmSyntaxError(info, - "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 dmSyntaxError(info, - "Invalid or unsupported property type(s)"); - } - } - } - else - if (info.state > 0 // && (key == "comment" || key == "obj_info") - ) - { - // Ignore comments - // .. and unknown keys - } - else - { - return dmSyntaxError(info, - "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; - } - - nvertices = info.elem_map[PLY_ELEM_VERTEX].value; - nfaces = info.elem_map[PLY_ELEM_FACE].value; - - - if (nvertices < 3 || nfaces < 1) - { - dmError("Invalid nvertices (%d) and/or nfaces (%d).\n", - nvertices, nfaces); - return false; - } - - dmMsg("Should have %d vertices, %d faces\n", - nvertices, nfaces); - - // Pre-allocate space - vertices.reserve(nvertices); - normals.reserve(nvertices); - faces.reserve(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 dmSyntaxError(info, - "Expected 3 vertices per face"); - } - - for (unsigned int n = 0; n < prop.list_num_value.v_uint; n++) - { - 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; - - 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; - - normals.push_back(normal); - } - } - } - - dmMsg("Found %ld vertices, %ld normals, %ld faces\n", - vertices.size(), - normals.size(), - faces.size() / 3); - - return true; -} bool dmParseVector(DMTextFileInfo &info, const std::vector<std::string> tokens, const size_t offs, DMVector3 &vec) @@ -584,7 +24,7 @@ } else { - return dmSyntaxError(info, + return info.syntaxError( "Expected 1/3 value vector for '"+ *info.key +"'"); } @@ -610,7 +50,7 @@ } else { - return dmSyntaxError(info, + return info.syntaxError( "Expected 1/3/4 value vector for '"+ *info.key +"'"); } @@ -643,7 +83,7 @@ while (info.state >= 0) { // Read one line - if (!dmReadLine(info)) + if (!info.readLine()) { info.state = -1; break; @@ -665,7 +105,7 @@ DMModel newmodel; if (tokens.size() != 2) { - return dmSyntaxError(info, + return info.syntaxError( "Keyword model expects a filename argument"); } @@ -680,7 +120,7 @@ { if (tokens.size() != 3) { - return dmSyntaxError(info, + return info.syntaxError( "Keyword shaderfile expects shader type (fs, vs) and filename arguments"); } @@ -695,7 +135,7 @@ model->vertShaderFile = shfile; else { - return dmSyntaxError(info, + return info.syntaxError( "Invalid shaderfile type '"+ shtype +"'"); } } @@ -733,7 +173,7 @@ { if (tokens.size() != 2) { - return dmSyntaxError(info, + return info.syntaxError( "Expected argument for shininess"); } @@ -746,7 +186,7 @@ if (lights.size() >= 4) { - return dmTextError(info, + return info.textError( "Too many lights defined (max 4)"); } @@ -802,7 +242,7 @@ } else { - return dmSyntaxError(info, + return info.syntaxError( "Unexpected key '"+ key +"'"); } }