# HG changeset patch # User Matti Hamalainen # Date 1576325331 -7200 # Node ID 7b138613e2fc9218a054f5243f462e5a5e2c326b # Parent f645e38e31576e1d6c964dc8c2beea9176eddee4 Rename dmmodel.* to dmscene.* diff -r f645e38e3157 -r 7b138613e2fc Makefile.gen --- a/Makefile.gen Thu Dec 12 17:51:53 2019 +0200 +++ b/Makefile.gen Sat Dec 14 14:08:51 2019 +0200 @@ -44,10 +44,10 @@ $(COMPILE_CXX_OBJ) -$(BINPATH)gldragon$(BINEXT): $(addprefix $(OBJPATH), gldragon.o dmmodel.o dmutil.o) +$(BINPATH)gldragon$(BINEXT): $(addprefix $(OBJPATH), gldragon.o dmscene.o dmutil.o) $(LINK_CXX_BIN) $(LDFLAGS) $(SDL_LDFLAGS) $(GL_LDFLAGS) -$(BINPATH)ply2bin$(BINEXT): $(addprefix $(OBJPATH), ply2bin.o dmmodel.o dmutil.o) +$(BINPATH)ply2bin$(BINEXT): $(addprefix $(OBJPATH), ply2bin.o dmscene.o dmutil.o) $(LINK_CXX_BIN) $(LDFLAGS) $(TOOL_LDFLAGS) diff -r f645e38e3157 -r 7b138613e2fc dmmodel.cpp --- a/dmmodel.cpp Thu Dec 12 17:51:53 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,811 +0,0 @@ -// -// GLDragon - OpenGL PLY model viewer / simple benchmark -// -- Scene and model handling + PLY file parsing -// Programmed and designed by Matti 'ccr' Hämäläinen -// (C) Copyright 2019 Tecnic Software productions (TNSP) -// -// See file "COPYING" for license information. -// -#include "dmmodel.h" -#include - - -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(&tmpS8), 1); - pval.v_int = tmpS8; - break; - - case PLY_TYPE_UINT8: - info.file.read(reinterpret_cast(&tmpU8), 1); - pval.v_uint = tmpU8; - break; - - case PLY_TYPE_INT16: - info.file.read(reinterpret_cast(&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(&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(&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(&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(&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 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 tokens, const size_t offs, DMVector3 &vec) -{ - if (tokens.size() == offs + 1) - { - vec.x = vec.y = vec.z = std::stof(tokens[offs]); - } - else - if (tokens.size() == offs + 3) - { - vec.x = std::stof(tokens[offs]); - vec.y = std::stof(tokens[offs + 1]); - vec.z = std::stof(tokens[offs + 2]); - } - else - { - return dmSyntaxError(info, - "Expected 1/3 value vector for '"+ *info.key +"'"); - } - - return true; -} - - -bool dmParseVector(DMTextFileInfo &info, const std::vector tokens, const size_t offs, DMVector4 &vec) -{ - if (tokens.size() == offs + 1) - { - vec.p.x = vec.p.y = vec.p.z = std::stof(tokens[offs]); - } - else - if (tokens.size() == offs + 3 || tokens.size() == offs + 4) - { - vec.p.x = std::stof(tokens[offs]); - vec.p.y = std::stof(tokens[offs + 1]); - vec.p.z = std::stof(tokens[offs + 2]); - - if (tokens.size() == offs + 4) - vec.p.w = std::stof(tokens[offs + 3]); - } - else - { - return dmSyntaxError(info, - "Expected 1/3/4 value vector for '"+ *info.key +"'"); - } - - return true; -} - - -bool DMSimpleScene::loadInfo(const std::string &filename) -{ - DMTextFileInfo info; - DMModel *model = 0; - DMLight *light = 0; - DMVector4 *ppos = 0, *ppointAt = 0; - DMMaterial *pmat = 0; - - 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 scene data 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; - } - - while (info.state >= 0) - { - // Read one line - if (!dmReadLine(info)) - { - info.state = -1; - break; - } - - // Skip empty lines and comments - if (info.line.empty() || - info.line[0] == '#' || - info.line[0] == ';') - continue; - - // Split key and values - std::vector tokens = dmStrSplit(info.line); - std::string key = tokens[0]; - info.key = &key; - - if (key == "model") - { - DMModel newmodel; - if (tokens.size() != 2) - { - return dmSyntaxError(info, - "Keyword model expects a filename argument"); - } - - models.push_back(newmodel); - model = &models.back(); - model->modelFile = tokens[1]; - pmat = &model->material; - info.state = 1; - } - else - if (info.state == 1 && (key == "shaderfile")) - { - if (tokens.size() != 3) - { - return dmSyntaxError(info, - "Keyword shaderfile expects shader type (fs, vs) and filename arguments"); - } - - std::string - &shtype = tokens[1], - &shfile = tokens[2]; - - if (shtype == "fs") - model->fragShaderFile = shfile; - else - if (shtype == "vs") - model->vertShaderFile = shfile; - else - { - return dmSyntaxError(info, - "Invalid shaderfile type '"+ shtype +"'"); - } - } - else - if (info.state == 1 && (key == "translate" || key == "rotate" || key == "scale")) - { - DMVector3 vec; - - if (!dmParseVector(info, tokens, 1, vec)) - return false; - - if (!model) - return false; - - if (key == "translate") - { - model->translate = vec; - model->translateSet = true; - } - else - if (key == "rotate") - { - model->rotate = vec; - model->rotateSet = true; - } - else - if (key == "scale") - { - model->scale = vec; - model->scaleSet = true; - } - } - else - if (info.state == 1 && key == "shininess") - { - if (tokens.size() != 2) - { - return dmSyntaxError(info, - "Expected argument for shininess"); - } - - model->material.shininess = std::stoi(tokens[1], 0, 0); - } - else - if (key == "light") - { - DMLight newlight; - - if (lights.size() >= 4) - { - return dmTextError(info, - "Too many lights defined (max 4)"); - } - - lights.push_back(newlight); - light = &lights.back(); - ppos = &light->position; - ppointAt = &light->pointAt; - pmat = &light->color; - info.state = 2; - } - else - if ((info.state == 1 || info.state == 2) && - (key == "ambient" || key == "diffuse" || key == "specular")) - { - DMVector4 val; - val.c.a = 1.0f; - - if (!dmParseVector(info, tokens, 1, val)) - return false; - - if (key == "ambient") - pmat->ambient = val; - else - if (key == "diffuse") - pmat->diffuse = val; - else - if (key == "specular") - pmat->specular = val; - } - else - if (key == "camera") - { - info.state = 3; - - ppos = &camera.position; - ppointAt = &camera.pointAt; - } - else - if ((info.state == 3 || info.state == 2) && - (key == "position" || key == "pos" || key == "point_at")) - { - DMVector4 vec; - vec.p.w = 0; - - if (!dmParseVector(info, tokens, 1, vec)) - return false; - - if (key == "position" || key == "pos") - *ppos = vec; - else - if (key == "point_at") - *ppointAt = vec; - } - else - { - return dmSyntaxError(info, - "Unexpected key '"+ key +"'"); - } - } - - return true; -} diff -r f645e38e3157 -r 7b138613e2fc dmmodel.h --- a/dmmodel.h Thu Dec 12 17:51:53 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,220 +0,0 @@ -// -// GLDragon - OpenGL PLY model viewer / simple benchmark -// -- Scene and model handling + PLY file parsing -// Programmed and designed by Matti 'ccr' Hämäläinen -// (C) Copyright 2019 Tecnic Software productions (TNSP) -// -// See file "COPYING" for license information. -// -#ifndef DMMODEL_H -#define DMMODEL_H 1 - -#include "dmutil.h" -#include -#include -#include - - -#define PLY_PROP_VERTEX_INDICES "vertex_indices" -#define PLY_ELEM_FACE "face" -#define PLY_ELEM_VERTEX "vertex" - - -enum DMPLYFormat -{ - PLY_FMT_UNKNOWN, - PLY_FMT_ASCII, - PLY_FMT_BIN_LE, - PLY_FMT_BIN_BE -}; - - -enum DMPLYPropType -{ - PLY_TYPE_NONE, - PLY_TYPE_LIST, - - PLY_TYPE_UINT8, - PLY_TYPE_INT8, - PLY_TYPE_INT16, - PLY_TYPE_UINT16, - PLY_TYPE_INT32, - PLY_TYPE_UINT32, - PLY_TYPE_FLOAT, - PLY_TYPE_DOUBLE -}; - - -/* Structures - */ -union DMPLYPropValue -{ - double v_double; - float v_float; - unsigned int v_uint; - int v_int; -}; - - -struct DMPLYFileProperty -{ - std::string name; - DMPLYPropType - type, - list_num_type, - list_values_type; - - DMPLYPropValue value, list_num_value; - std::vector list_values; -}; - - -struct DMPLYFileElement -{ - int value; - std::string name; - - std::unordered_map prop_map; - std::vector properties; - - DMPLYFileProperty *checkProp(const std::string &prop) - { - if (prop_map.count(prop)) - return &prop_map[prop]; - else - return 0; - } -}; - - -struct DMTextFileInfo -{ - int nline, state; - std::string filename; - std::string line; - std::ifstream file; - std::string *key; -}; - - -struct DMPLYFileInfo : DMTextFileInfo -{ - DMPLYFormat format; - - std::unordered_map elem_map; - std::vector elements; - DMPLYFileElement *element; - - DMPLYFileInfo() - { - element = 0; - format = PLY_FMT_UNKNOWN; - } - - DMPLYFileElement *checkElem(const std::string &elem) - { - if (elem_map.count(elem)) - return &elem_map[elem]; - else - return 0; - } -}; - - -struct DMVector3 -{ - float x, y, z; -}; - - -union DMVector4 -{ - struct { float x, y, z, w; } p; - struct { float r, g, b, a; } c; - float values[4]; -}; - - -struct DMMaterial -{ - DMVector4 ambient, diffuse, specular; - int shininess; -}; - - -struct DMModel -{ - int nvertices, nfaces; - std::vector vertices, normals; - std::vector faces; - - DMMaterial material; - DMVector3 translate, scale, rotate; - bool translateSet, scaleSet, rotateSet; - - unsigned int id_prog, id_fs, id_vs; - - std::string - modelFile, - fragShaderFile, vertShaderFile, - fragShaderStr, vertShaderStr; - - bool loadFromPLY(const std::string &filename); - bool loadFromPLY(const std::string &filename, DMPLYFileInfo &info); - - DMModel() - { - nfaces = nvertices = 0; - - translate.x = translate.y = translate.z = 0; - rotate.x = rotate.y = rotate.z = 0; - scale.x = scale.y = scale.z = 0; - translateSet = rotateSet = scaleSet = false; - - material.diffuse.c.r = material.diffuse.p.z = 0.56471f; - material.diffuse.c.g = 0.5f; - material.diffuse.c.a = 1.0f; - - material.specular.c.r = material.specular.c.g = material.specular.c.b = 0.8f; - material.specular.c.a = 1.0f; - - material.shininess = 96; - } -}; - - -struct DMLight -{ - DMMaterial color; - DMVector4 position, pointAt; - - DMLight() - { - color.ambient.c.r = color.ambient.c.g = color.ambient.p.z = 0.2f; color.ambient.c.a = 1.0f; - color.diffuse.c.r = color.diffuse.c.g = color.diffuse.p.z = 0.8f; color.diffuse.c.a = 1.0f; - color.specular.c.r = color.specular.c.g = color.specular.p.z = 0.5f; color.specular.c.a = 1.0f; - - position.p.x = 10.0f; - position.p.y = 10.0f; - position.p.z = 0.0f; - position.p.w = 0.0f; - } -}; - - -struct DMCamera -{ - DMVector4 position, pointAt; -}; - - -struct DMSimpleScene -{ - DMCamera camera; - std::vector lights; - std::vector models; - - bool loadInfo(const std::string &filename); -}; - -#endif diff -r f645e38e3157 -r 7b138613e2fc dmscene.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmscene.cpp Sat Dec 14 14:08:51 2019 +0200 @@ -0,0 +1,811 @@ +// +// GLDragon - OpenGL PLY model viewer / simple benchmark +// -- Scene and model handling + PLY file parsing +// Programmed and designed by Matti 'ccr' Hämäläinen +// (C) Copyright 2019 Tecnic Software productions (TNSP) +// +// See file "COPYING" for license information. +// +#include "dmscene.h" +#include + + +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(&tmpS8), 1); + pval.v_int = tmpS8; + break; + + case PLY_TYPE_UINT8: + info.file.read(reinterpret_cast(&tmpU8), 1); + pval.v_uint = tmpU8; + break; + + case PLY_TYPE_INT16: + info.file.read(reinterpret_cast(&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(&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(&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(&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(&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 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 tokens, const size_t offs, DMVector3 &vec) +{ + if (tokens.size() == offs + 1) + { + vec.x = vec.y = vec.z = std::stof(tokens[offs]); + } + else + if (tokens.size() == offs + 3) + { + vec.x = std::stof(tokens[offs]); + vec.y = std::stof(tokens[offs + 1]); + vec.z = std::stof(tokens[offs + 2]); + } + else + { + return dmSyntaxError(info, + "Expected 1/3 value vector for '"+ *info.key +"'"); + } + + return true; +} + + +bool dmParseVector(DMTextFileInfo &info, const std::vector tokens, const size_t offs, DMVector4 &vec) +{ + if (tokens.size() == offs + 1) + { + vec.p.x = vec.p.y = vec.p.z = std::stof(tokens[offs]); + } + else + if (tokens.size() == offs + 3 || tokens.size() == offs + 4) + { + vec.p.x = std::stof(tokens[offs]); + vec.p.y = std::stof(tokens[offs + 1]); + vec.p.z = std::stof(tokens[offs + 2]); + + if (tokens.size() == offs + 4) + vec.p.w = std::stof(tokens[offs + 3]); + } + else + { + return dmSyntaxError(info, + "Expected 1/3/4 value vector for '"+ *info.key +"'"); + } + + return true; +} + + +bool DMSimpleScene::loadInfo(const std::string &filename) +{ + DMTextFileInfo info; + DMModel *model = 0; + DMLight *light = 0; + DMVector4 *ppos = 0, *ppointAt = 0; + DMMaterial *pmat = 0; + + 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 scene data 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; + } + + while (info.state >= 0) + { + // Read one line + if (!dmReadLine(info)) + { + info.state = -1; + break; + } + + // Skip empty lines and comments + if (info.line.empty() || + info.line[0] == '#' || + info.line[0] == ';') + continue; + + // Split key and values + std::vector tokens = dmStrSplit(info.line); + std::string key = tokens[0]; + info.key = &key; + + if (key == "model") + { + DMModel newmodel; + if (tokens.size() != 2) + { + return dmSyntaxError(info, + "Keyword model expects a filename argument"); + } + + models.push_back(newmodel); + model = &models.back(); + model->modelFile = tokens[1]; + pmat = &model->material; + info.state = 1; + } + else + if (info.state == 1 && (key == "shaderfile")) + { + if (tokens.size() != 3) + { + return dmSyntaxError(info, + "Keyword shaderfile expects shader type (fs, vs) and filename arguments"); + } + + std::string + &shtype = tokens[1], + &shfile = tokens[2]; + + if (shtype == "fs") + model->fragShaderFile = shfile; + else + if (shtype == "vs") + model->vertShaderFile = shfile; + else + { + return dmSyntaxError(info, + "Invalid shaderfile type '"+ shtype +"'"); + } + } + else + if (info.state == 1 && (key == "translate" || key == "rotate" || key == "scale")) + { + DMVector3 vec; + + if (!dmParseVector(info, tokens, 1, vec)) + return false; + + if (!model) + return false; + + if (key == "translate") + { + model->translate = vec; + model->translateSet = true; + } + else + if (key == "rotate") + { + model->rotate = vec; + model->rotateSet = true; + } + else + if (key == "scale") + { + model->scale = vec; + model->scaleSet = true; + } + } + else + if (info.state == 1 && key == "shininess") + { + if (tokens.size() != 2) + { + return dmSyntaxError(info, + "Expected argument for shininess"); + } + + model->material.shininess = std::stoi(tokens[1], 0, 0); + } + else + if (key == "light") + { + DMLight newlight; + + if (lights.size() >= 4) + { + return dmTextError(info, + "Too many lights defined (max 4)"); + } + + lights.push_back(newlight); + light = &lights.back(); + ppos = &light->position; + ppointAt = &light->pointAt; + pmat = &light->color; + info.state = 2; + } + else + if ((info.state == 1 || info.state == 2) && + (key == "ambient" || key == "diffuse" || key == "specular")) + { + DMVector4 val; + val.c.a = 1.0f; + + if (!dmParseVector(info, tokens, 1, val)) + return false; + + if (key == "ambient") + pmat->ambient = val; + else + if (key == "diffuse") + pmat->diffuse = val; + else + if (key == "specular") + pmat->specular = val; + } + else + if (key == "camera") + { + info.state = 3; + + ppos = &camera.position; + ppointAt = &camera.pointAt; + } + else + if ((info.state == 3 || info.state == 2) && + (key == "position" || key == "pos" || key == "point_at")) + { + DMVector4 vec; + vec.p.w = 0; + + if (!dmParseVector(info, tokens, 1, vec)) + return false; + + if (key == "position" || key == "pos") + *ppos = vec; + else + if (key == "point_at") + *ppointAt = vec; + } + else + { + return dmSyntaxError(info, + "Unexpected key '"+ key +"'"); + } + } + + return true; +} diff -r f645e38e3157 -r 7b138613e2fc dmscene.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmscene.h Sat Dec 14 14:08:51 2019 +0200 @@ -0,0 +1,220 @@ +// +// GLDragon - OpenGL PLY model viewer / simple benchmark +// -- Scene and model handling + PLY file parsing +// Programmed and designed by Matti 'ccr' Hämäläinen +// (C) Copyright 2019 Tecnic Software productions (TNSP) +// +// See file "COPYING" for license information. +// +#ifndef DMSCENE_H +#define DMSCENE_H 1 + +#include "dmutil.h" +#include +#include +#include + + +#define PLY_PROP_VERTEX_INDICES "vertex_indices" +#define PLY_ELEM_FACE "face" +#define PLY_ELEM_VERTEX "vertex" + + +enum DMPLYFormat +{ + PLY_FMT_UNKNOWN, + PLY_FMT_ASCII, + PLY_FMT_BIN_LE, + PLY_FMT_BIN_BE +}; + + +enum DMPLYPropType +{ + PLY_TYPE_NONE, + PLY_TYPE_LIST, + + PLY_TYPE_UINT8, + PLY_TYPE_INT8, + PLY_TYPE_INT16, + PLY_TYPE_UINT16, + PLY_TYPE_INT32, + PLY_TYPE_UINT32, + PLY_TYPE_FLOAT, + PLY_TYPE_DOUBLE +}; + + +/* Structures + */ +union DMPLYPropValue +{ + double v_double; + float v_float; + unsigned int v_uint; + int v_int; +}; + + +struct DMPLYFileProperty +{ + std::string name; + DMPLYPropType + type, + list_num_type, + list_values_type; + + DMPLYPropValue value, list_num_value; + std::vector list_values; +}; + + +struct DMPLYFileElement +{ + int value; + std::string name; + + std::unordered_map prop_map; + std::vector properties; + + DMPLYFileProperty *checkProp(const std::string &prop) + { + if (prop_map.count(prop)) + return &prop_map[prop]; + else + return 0; + } +}; + + +struct DMTextFileInfo +{ + int nline, state; + std::string filename; + std::string line; + std::ifstream file; + std::string *key; +}; + + +struct DMPLYFileInfo : DMTextFileInfo +{ + DMPLYFormat format; + + std::unordered_map elem_map; + std::vector elements; + DMPLYFileElement *element; + + DMPLYFileInfo() + { + element = 0; + format = PLY_FMT_UNKNOWN; + } + + DMPLYFileElement *checkElem(const std::string &elem) + { + if (elem_map.count(elem)) + return &elem_map[elem]; + else + return 0; + } +}; + + +struct DMVector3 +{ + float x, y, z; +}; + + +union DMVector4 +{ + struct { float x, y, z, w; } p; + struct { float r, g, b, a; } c; + float values[4]; +}; + + +struct DMMaterial +{ + DMVector4 ambient, diffuse, specular; + int shininess; +}; + + +struct DMModel +{ + int nvertices, nfaces; + std::vector vertices, normals; + std::vector faces; + + DMMaterial material; + DMVector3 translate, scale, rotate; + bool translateSet, scaleSet, rotateSet; + + unsigned int id_prog, id_fs, id_vs; + + std::string + modelFile, + fragShaderFile, vertShaderFile, + fragShaderStr, vertShaderStr; + + bool loadFromPLY(const std::string &filename); + bool loadFromPLY(const std::string &filename, DMPLYFileInfo &info); + + DMModel() + { + nfaces = nvertices = 0; + + translate.x = translate.y = translate.z = 0; + rotate.x = rotate.y = rotate.z = 0; + scale.x = scale.y = scale.z = 0; + translateSet = rotateSet = scaleSet = false; + + material.diffuse.c.r = material.diffuse.p.z = 0.56471f; + material.diffuse.c.g = 0.5f; + material.diffuse.c.a = 1.0f; + + material.specular.c.r = material.specular.c.g = material.specular.c.b = 0.8f; + material.specular.c.a = 1.0f; + + material.shininess = 96; + } +}; + + +struct DMLight +{ + DMMaterial color; + DMVector4 position, pointAt; + + DMLight() + { + color.ambient.c.r = color.ambient.c.g = color.ambient.p.z = 0.2f; color.ambient.c.a = 1.0f; + color.diffuse.c.r = color.diffuse.c.g = color.diffuse.p.z = 0.8f; color.diffuse.c.a = 1.0f; + color.specular.c.r = color.specular.c.g = color.specular.p.z = 0.5f; color.specular.c.a = 1.0f; + + position.p.x = 10.0f; + position.p.y = 10.0f; + position.p.z = 0.0f; + position.p.w = 0.0f; + } +}; + + +struct DMCamera +{ + DMVector4 position, pointAt; +}; + + +struct DMSimpleScene +{ + DMCamera camera; + std::vector lights; + std::vector models; + + bool loadInfo(const std::string &filename); +}; + +#endif diff -r f645e38e3157 -r 7b138613e2fc gldragon.cpp --- a/gldragon.cpp Thu Dec 12 17:51:53 2019 +0200 +++ b/gldragon.cpp Sat Dec 14 14:08:51 2019 +0200 @@ -12,7 +12,7 @@ #include #include "dmutil.h" -#include "dmmodel.h" +#include "dmscene.h" /* Default settings etc. constants diff -r f645e38e3157 -r 7b138613e2fc ply2bin.cpp --- a/ply2bin.cpp Thu Dec 12 17:51:53 2019 +0200 +++ b/ply2bin.cpp Sat Dec 14 14:08:51 2019 +0200 @@ -12,7 +12,7 @@ #define SDL_main main #include "dmutil.h" -#include "dmmodel.h" +#include "dmscene.h" bool dmFWriteFloatLE(FILE *fh, const float val)