# HG changeset patch # User Matti Hamalainen # Date 1574384632 -7200 # Node ID 1404dfcee7b89ec8f327c4194910150a4d21a518 # Parent 294c4c7943b55baa8ec4ebf68453fe07cae6bb68 More work on scenefile and model loading support. Can now load PLY models and simple scene definition files. Converted dragon mesh to binary PLY format. diff -r 294c4c7943b5 -r 1404dfcee7b8 Makefile --- a/Makefile Fri Nov 22 00:14:16 2019 +0200 +++ b/Makefile Fri Nov 22 03:03:52 2019 +0200 @@ -18,7 +18,8 @@ %.o: %.cpp $(CXX) $(CFLAGS) -c -o $@ $< -glxdragon$(BINEXT): glxdragon.o + +glxdragon$(BINEXT): glxdragon.o dmmodel.o dmutil.o $(CXX) -o $@ $+ $(LDFLAGS) clean: diff -r 294c4c7943b5 -r 1404dfcee7b8 dmmodel.cpp --- a/dmmodel.cpp Fri Nov 22 00:14:16 2019 +0200 +++ b/dmmodel.cpp Fri Nov 22 03:03:52 2019 +0200 @@ -2,6 +2,7 @@ // // #include "dmmodel.h" +#include static bool dmError(DMTextFileInfo &info, const std::string &msg) @@ -139,7 +140,10 @@ // Read one line if (!dmReadLine(info)) - return false; + { + return dmError(info, + "Unexpected end of file"); + } // Skip empty lines if (info.line.empty()) @@ -166,71 +170,53 @@ bool dmPLYReadPropertyValueBIN(DMPLYFileInfo &info, const DMPLYPropType ptype, DMPLYPropValue &pval) { - uint8_t tmp[8]; + 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(&tmp), 1); - pval.v_int = (int8_t) tmp[0]; + info.file.read(reinterpret_cast(&tmpS8), 1); + pval.v_int = tmpS8; break; case PLY_TYPE_UINT8: - info.file.read(reinterpret_cast(&tmp), 1); - pval.v_uint = (uint8_t) tmp[0]; + info.file.read(reinterpret_cast(&tmpU8), 1); + pval.v_uint = tmpU8; break; case PLY_TYPE_INT16: - info.file.read(reinterpret_cast(&tmp), 2); - tmpS16 = - (tmp[0] << 8) | - (tmp[1]); + 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(&tmp), 2); - tmpU16 = - (tmp[0] << 8) | - (tmp[1]); + 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(&tmp), 4); - tmpS32 = - (tmp[0] << 24) | - (tmp[1] << 16) | - (tmp[2] << 8) | - (tmp[3]); - + 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(&tmp), 4); - tmpU32 = - (tmp[3] << 24) | - (tmp[2] << 16) | - (tmp[1] << 8) | - (tmp[0]); - + 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(&tmp), 4); - tmpU32 = - (tmp[0] << 24) | - (tmp[1] << 16) | - (tmp[2] << 8) | - (tmp[3]); - - pval.v_uint = tmpU32; + info.file.read(reinterpret_cast(&tmpFloat), 4); + pval.v_float = (info.format == PLY_FMT_BIN_LE) ? SDL_SwapFloatLE(tmpFloat) : SDL_SwapFloatBE(tmpFloat); break; default: @@ -548,7 +534,7 @@ else if (element->name == PLY_ELEM_VERTEX) { - DMVertex vert; + 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; @@ -559,7 +545,7 @@ element->checkProp("ny") && element->checkProp("nz")) { - DMVertex normal; + 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; @@ -578,9 +564,91 @@ } +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) +{ + vec.w = 1.0f; + + if (tokens.size() == offs + 1) + { + vec.x = vec.y = vec.z = std::stof(tokens[offs]); + } + else + if (tokens.size() == offs + 3 || tokens.size() == offs + 4) + { + vec.x = std::stof(tokens[offs]); + vec.y = std::stof(tokens[offs + 1]); + vec.z = std::stof(tokens[offs + 2]); + + if (tokens.size() == offs + 4) + vec.w = std::stof(tokens[offs + 3]); + } + else + { + return dmSyntaxError(info, + "Expected 1/3/4 value vector for '"+ *info.key +"'"); + } + + return true; +} + + +bool dmParseColor(DMTextFileInfo &info, const std::vector tokens, const size_t offs, DMColor &color) +{ + color.alpha = 0xff; + + if (tokens.size() == offs + 1) + { + color.r = color.g = color.b = std::stoi(tokens[offs], 0, 0); + } + else + if (tokens.size() == offs + 3 || tokens.size() == offs + 4) + { + color.r = std::stoi(tokens[offs], 0, 0); + color.g = std::stoi(tokens[offs + 1], 0, 0); + color.b = std::stoi(tokens[offs + 2], 0, 0); + + if (tokens.size() == offs + 4) + color.alpha = std::stoi(tokens[offs + 3], 0, 0); + } + else + { + return dmSyntaxError(info, + "Expected color values or [] for '"+ *info.key +"'"); + } + + return true; +} + + bool DMSimpleScene::loadInfo(const std::string &filename) { DMTextFileInfo info; + DMModel *model = 0; + DMLight *light = 0; + DMVector3 *ppos = 0, *ppointAt = 0; info.filename = filename; info.nline = info.state = 0; @@ -613,88 +681,103 @@ // Split key and values std::vector tokens = dmStrSplit(info.line); - std::string &key = tokens[0]; + std::string key = tokens[0]; + info.key = &key; - if (key == "color") + if (key == "model") { - DMColor color; - color.alpha = 0xff; - - if (tokens.size() == 2) + DMModel newmodel; + if (tokens.size() != 2) { - color.r = color.g = color.b = std::stoi(tokens[1], 0, 0); - } - else - if (tokens.size() == 4 || tokens.size() == 5) - { - color.r = std::stoi(tokens[1], 0, 0); - color.g = std::stoi(tokens[2], 0, 0); - color.b = std::stoi(tokens[3], 0, 0); - - if (tokens.size() == 5) - color.alpha = std::stoi(tokens[4], 0, 0); - } - else - { - return dmSyntaxError(info, - "Expected color values or []"); + return dmError(info, + "Keyword model expects a filename argument"); } - model.color = color; + models.push_back(newmodel); + model = &models.back(); + model->modelFile = tokens[1]; + info.state = 1; } else - if (key == "translate" || key == "rotate" || key == "scale" || - key == "camera_pos" || key == "camera_at") + if (info.state == 1 && key == "color") { - DMVertex vec; + if (!dmParseColor(info, tokens, 1, model->color)) + return false; + } + else + if (info.state == 1 && (key == "translate" || key == "rotate" || key == "scale")) + { + DMVector3 vec; - if (tokens.size() == 2) - { - vec.x = vec.y = vec.z = std::stof(tokens[1]); - } - else - if (tokens.size() == 4) - { - vec.x = std::stof(tokens[1]); - vec.y = std::stof(tokens[2]); - vec.z = std::stof(tokens[3]); - } - else - { - return dmSyntaxError(info, - "Expected vector value for '"+ key +"'"); - } + if (!dmParseVector(info, tokens, 1, vec)) + return false; + + if (!model) + return false; if (key == "translate") - model.translate = vec; + model->translate = vec; else if (key == "rotate") - model.rotate = vec; + model->rotate = vec; else if (key == "scale") - model.scale = vec; - else - if (key == "camera_pos") - camera.pos = vec; - else - if (key == "camera_at") - camera.lookAt = vec; + model->scale = vec; } else if (key == "light") { - if (tokens.size() == 4) + DMLight newlight; + + if (lights.size() >= 4) { - DMVertex pos; - pos.x = std::stof(tokens[1]); - pos.y = std::stof(tokens[2]); - pos.z = std::stof(tokens[3]); + printf("ERROR: Too many lights defined.\n"); + return false; } + lights.push_back(newlight); + light = &lights.back(); + ppos = &light->pos; + ppointAt = &light->pointAt; + info.state = 2; + } + else + if (info.state == 2 && (key == "ambient" || key == "diffuse" || key == "specular")) + { + DMVector4 val; + + if (!dmParseVector(info, tokens, 1, val)) + return false; + + if (key == "ambient") + light->ambient = val; else - { - return dmSyntaxError(info, - "Expected light definition as "); - } + if (key == "diffuse") + light->diffuse = val; + else + if (key == "specular") + light->specular = val; + } + else + if (key == "camera") + { + info.state = 3; + + ppos = &camera.pos; + ppointAt = &camera.pointAt; + } + else + if ((info.state == 3 || info.state == 2) && (key == "pos" || key == "point_at")) + { + DMVector3 vec; + + if (!dmParseVector(info, tokens, 1, vec)) + return false; + + if (key == "pos") + *ppos = vec; + else + if (key == "point_at") + *ppointAt = vec; } else { @@ -703,7 +786,5 @@ } } - model.printInfo(); - return true; } diff -r 294c4c7943b5 -r 1404dfcee7b8 dmmodel.h --- a/dmmodel.h Fri Nov 22 00:14:16 2019 +0200 +++ b/dmmodel.h Fri Nov 22 03:03:52 2019 +0200 @@ -88,6 +88,7 @@ std::string filename; std::string line; std::ifstream file; + std::string *key; }; @@ -121,23 +122,34 @@ }; -struct DMVertex +struct DMVector3 { float x, y, z; }; +struct DMVector4 +{ + float x, y, z, w; +}; + + struct DMModel { int nvertices, nfaces; - std::vector vertices, normals; + std::vector vertices, normals; std::vector faces; DMColor color; - DMVertex translate, scale, rotate; + DMVector3 translate, scale, rotate; 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); @@ -155,6 +167,8 @@ DMModel() { + nfaces = nvertices = 0; + translate.x = translate.y = translate.z = 0; rotate.x = rotate.y = rotate.z = 0; scale.x = scale.y = scale.z = 1; @@ -164,22 +178,22 @@ struct DMLight { - DMVertex pos; - float ambient[4], diffuse[4], specular[4]; + DMVector3 pos, pointAt; + DMVector4 ambient, diffuse, specular; }; struct DMCamera { - DMVertex pos, lookAt; + DMVector3 pos, pointAt; }; struct DMSimpleScene { - DMModel model; DMCamera camera; std::vector lights; + std::vector models; bool loadInfo(const std::string &filename); }; diff -r 294c4c7943b5 -r 1404dfcee7b8 dmutil.cpp --- a/dmutil.cpp Fri Nov 22 00:14:16 2019 +0200 +++ b/dmutil.cpp Fri Nov 22 03:03:52 2019 +0200 @@ -73,6 +73,13 @@ } +std::string dmGetPath(const std::string &path) +{ + size_t dirsep = path.find_last_of("/\\"); + return (dirsep != std::string::npos) ? path.substr(0, dirsep + 1) : ""; +} + + bool dmReadText(const std::string &filename, std::string &buf, const int maxSize) { std::ifstream in(filename.c_str(), std::fstream::in); diff -r 294c4c7943b5 -r 1404dfcee7b8 dmutil.h --- a/dmutil.h Fri Nov 22 00:14:16 2019 +0200 +++ b/dmutil.h Fri Nov 22 03:03:52 2019 +0200 @@ -10,16 +10,18 @@ #include -#define SET_WHITESPACE "\t\n\v\f\r " +#define DMUTIL_WHITESPACE "\t\n\v\f\r " -std::string dmStrLTrim(const std::string& str, const std::string& delim = SET_WHITESPACE); -std::string dmStrRTrim(const std::string& str, const std::string& delim = SET_WHITESPACE); -std::string dmStrTrim(const std::string& str, const std::string& delim = SET_WHITESPACE); +std::string dmStrLTrim(const std::string& str, const std::string& delim = DMUTIL_WHITESPACE); +std::string dmStrRTrim(const std::string& str, const std::string& delim = DMUTIL_WHITESPACE); +std::string dmStrTrim(const std::string& str, const std::string& delim = DMUTIL_WHITESPACE); -std::vector dmStrSplit(const std::string& str, const std::string& delim = SET_WHITESPACE); +std::vector dmStrSplit(const std::string& str, const std::string& delim = DMUTIL_WHITESPACE); std::string dmStrJoin(const std::vector &list, const std::string &delim); +std::string dmGetPath(const std::string &path); + bool dmReadText(const std::string &filename, std::string &buf, const int maxSize); bool dmFileExists(const std::string &filename, std::ios_base::openmode mode = std::ios_base::in); diff -r 294c4c7943b5 -r 1404dfcee7b8 dragon.frag --- a/dragon.frag Fri Nov 22 00:14:16 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -void main() -{ -gl_FragColor = vec4( - gl_FragCoord.x * 0.1, - gl_FragCoord.y * 0.001, - 0.0, - 1.0); -}; - diff -r 294c4c7943b5 -r 1404dfcee7b8 dragon.info --- a/dragon.info Fri Nov 22 00:14:16 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ - - - -v:100139 - -f:200198 diff -r 294c4c7943b5 -r 1404dfcee7b8 dragon.mesh Binary file dragon.mesh has changed diff -r 294c4c7943b5 -r 1404dfcee7b8 dragon.ply Binary file dragon.ply has changed diff -r 294c4c7943b5 -r 1404dfcee7b8 dragon.scene --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dragon.scene Fri Nov 22 03:03:52 2019 +0200 @@ -0,0 +1,1 @@ +model dragon.ply diff -r 294c4c7943b5 -r 1404dfcee7b8 dragon.vert --- a/dragon.vert Fri Nov 22 00:14:16 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -void main() -{ -gl_Position = ftransform(); -} diff -r 294c4c7943b5 -r 1404dfcee7b8 glxdragon.cpp --- a/glxdragon.cpp Fri Nov 22 00:14:16 2019 +0200 +++ b/glxdragon.cpp Fri Nov 22 03:03:52 2019 +0200 @@ -33,11 +33,8 @@ #include #include -#include -#include -#include -#include -#include +#include "dmutil.h" +#include "dmmodel.h" /* Default settings etc. constants @@ -48,19 +45,6 @@ #define SET_MAX_SHADER_SIZE (128 * 1024) -/* Structures - */ -struct Mesh -{ - int nvertices, nfaces; - - std::vector vertices; - std::vector faces; - - GLuint id_prog, id_fs, id_vs; -}; - - /* Options */ bool optUseShaders = false; @@ -68,7 +52,6 @@ optHeight = SET_DEF_HEIGHT, optVSyncMode = 1; -std::string optModelPrefix = "dragon"; /* Globals @@ -77,6 +60,8 @@ SDL_GLContext dmGLContext = NULL; +/* Helpers + */ bool dmInitSDLGL(const int width, const int height, const char *title) { int ret; @@ -169,7 +154,6 @@ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - // Enable back face culling glEnable(GL_CULL_FACE); @@ -179,6 +163,9 @@ // Enable the depth buffer glEnable(GL_DEPTH_TEST); + // Enable normal rescaling + glEnable(GL_RESCALE_NORMAL); + // Setup depth buffer glClearDepth(1.0f); @@ -196,14 +183,14 @@ } -void dmDrawModelVA(const Mesh &mesh) +void dmDrawModel(const DMModel &model) { int maxIndices; if (optUseShaders) { // Enable shader program - glUseProgram(mesh.id_prog); + glUseProgram(model.id_prog); } else { @@ -215,15 +202,26 @@ // Render the model glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &maxIndices); - glVertexPointer(3, GL_FLOAT, 3 * 4 * 2, &mesh.vertices[0]); - glNormalPointer( GL_FLOAT, 3 * 4 * 2, &mesh.vertices[3]); + glPushMatrix(); + + // Add transforms + glScalef(model.scale.x, model.scale.y, model.scale.z); + glTranslatef(model.translate.x, model.translate.y, model.translate. z); + glRotatef(model.rotate.x, 1.0f, 0.0f, 0.0f); + glRotatef(model.rotate.y, 0.0f, 1.0f, 0.0f); + glRotatef(model.rotate.z, 0.0f, 0.0f, 1.0f); - for (int n = 0; n < mesh.nfaces; n += maxIndices) + glVertexPointer(3, GL_FLOAT, 0, &model.vertices[0]); + glNormalPointer( GL_FLOAT, 0, &model.normals[0]); + + for (int n = 0; n < model.nfaces; n += maxIndices) { - const int count = std::min(maxIndices, mesh.nfaces - n); - glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_INT, &mesh.faces[n * 3]); + const int count = std::min(maxIndices, model.nfaces - n); + glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_INT, &model.faces[n * 3]); } + glPopMatrix(); + // Restore if (optUseShaders) { @@ -232,7 +230,7 @@ } -void dmDrawBackground() +void dmDrawScene(const DMSimpleScene &scene) { glClear(GL_DEPTH_BUFFER_BIT); @@ -270,136 +268,10 @@ glPopMatrix(); glEnable(GL_DEPTH_TEST); -} - -bool dmReadText(const std::string &filename, std::string &buf, const int maxSize) -{ - std::ifstream in(filename.c_str()); - - if (!in.is_open()) - { - printf("ERROR: Unable to open file '%s'.\n", - filename.c_str()); - return false; - } - - in.seekg(0, std::ios::end); - - if (in.tellg() > maxSize) - { - printf("ERROR: File '%s' is too large.\n", - filename.c_str()); - return false; - } - - buf.reserve(in.tellg()); - in.seekg(0, std::ios::beg); - - buf.assign((std::istreambuf_iterator(in)), std::istreambuf_iterator()); - - return true; -} - - -bool dmLoadMesh(const std::string &filename, const std::string &infofilename, Mesh &mesh) -{ - std::ifstream info(infofilename.c_str()); - int required = 0, nline = 0; - - printf("INFO: Trying to read mesh meta from '%s'.\n", - infofilename.c_str()); - - if (!info.is_open()) - { - printf("ERROR: Unable to open file '%s'.\n", - infofilename.c_str()); - return false; - } - - while (required != 0x03) - { - std::string tmp; - int value; - char key; - - // Read one line - if (!std::getline(info, tmp)) - { - printf("ERROR: Could not read from file '%s'.\n", - infofilename.c_str()); - return false; - } - - nline++; - - // Skip empty lines and comments - if (tmp.empty() || tmp.substr(0, 1) == "#") - continue; - - if (sscanf(tmp.c_str(), "%c:%d", &key, &value) != 2) - { - printf("ERROR: Syntax error in '%s' line #%d\n'%s'\n", - infofilename.c_str(), - nline, - tmp.c_str()); - return false; - } - - switch (key) - { - case 'v': - mesh.nvertices = value; - required |= 0x01; - break; - - case 'f': - mesh.nfaces = value; - required |= 0x02; - break; - - default: - printf("ERROR: Syntax error in '%s' line #%d\nUnknown key value '%c'.\n", - infofilename.c_str(), - nline, - key); - break; - } - } - - if (mesh.nvertices < 3 || mesh.nfaces < 1) - { - printf("ERROR: Invalid nvertices (%d) and/or nfaces (%d) in '%s'.\n", - mesh.nvertices, mesh.nfaces, - infofilename.c_str()); - return false; - } - - printf("INFO: %d vertices, %d faces\n", mesh.nvertices, mesh.nfaces); - printf("INFO: Trying to read mesh data from '%s'.\n", - filename.c_str()); - - std::ifstream in(filename.c_str(), std::ios::binary); - - if (!in.is_open()) - { - printf("ERROR: Unable to open file '%s'.\n", - filename.c_str()); - return false; - } - - mesh.vertices.resize(mesh.nvertices * 6); - in.read(reinterpret_cast(&mesh.vertices[0]), mesh.nvertices * 6 * 4); - - mesh.faces.resize(mesh.nfaces * 3); - - for (int i = 0; i < mesh.nfaces; i++) - { - in.seekg(1, std::ios::cur); - in.read(reinterpret_cast(&mesh.faces[i * 3]), 3 * 4); - } - - return true; + // Draw models + for (const DMModel &model : scene.models) + dmDrawModel(model); } @@ -415,22 +287,25 @@ } -void dmLinkMeshShaders(Mesh &mesh) +void dmLinkModelShaders(DMModel &model) { - mesh.id_prog = glCreateProgram(); - glAttachShader(mesh.id_prog, mesh.id_fs); - glAttachShader(mesh.id_prog, mesh.id_vs); - glLinkProgram(mesh.id_prog); + model.id_prog = glCreateProgram(); + glAttachShader(model.id_prog, model.id_fs); + glAttachShader(model.id_prog, model.id_vs); + glLinkProgram(model.id_prog); } int main(int argc, char *argv[]) { - std::string modelVertStr, modelFragStr; - Mesh modelMesh; - bool exitFlag = false, optShowHelp = false; int startTime, cycleStart, cycleFrames = 0, totalFrames = 0; double totalTime; + bool + exitFlag = false, + optShowHelp = false, + optSetInputFilename = false; + std::string optInputFilename = "dragon.scene", basePath; + DMSimpleScene scene; // Check commandline argument for enabling shaders for (int narg = 1; narg < argc; narg++) @@ -469,7 +344,6 @@ { case 'w': optWidth = atoi(opt + 1); break; case 'h': optHeight = atoi(opt + 1); break; - case 'm': optModelPrefix = std::string(opt + 1); break; case 'v': optVSyncMode = atoi(opt + 1); break; } break; @@ -479,20 +353,36 @@ goto exit; } } + else + { + if (optSetInputFilename) + { + printf("ERROR: Please specify only one scene file.\n"); + goto exit; + } + + optSetInputFilename = true; + optInputFilename = std::string(arg); + if (optInputFilename.empty()) + { + printf("ERROR: Invalid input filename.\n"); + goto exit; + } + + } } if (optShowHelp) { printf( - "Usage: %s [options]\n" + "Usage: %s [options] []\n" "-? Show this help\n" "-g Use GLSL shader instead of basic OpenGL lighting\n" "-w Window width (default %d)\n" "-h Window height (default %d)\n" - "-m Set model filenames prefix. Using \"-mfoo\" will\n" - " specify \"foo.mesh\", \"foo.frag\", \"foo.vert\".\n" "-v<1-3> Set vsync mode: 1 = no vsync, 2 = vsync, 3 = adaptive\n" - " Default is no vsync.\n" + " Default is no vsync. Using vsync will result in FPS being\n" + " approx whatever your monitor refresh rate is.\n" "\n", argv[0], SET_DEF_WIDTH, SET_DEF_HEIGHT @@ -508,33 +398,53 @@ goto exit; } - if (optModelPrefix.empty()) + // Load the scene + if (!scene.loadInfo(optInputFilename)) + goto exit; + + if (scene.models.size() == 0) { - printf("Model file prefix empty.\n"); + printf("ERROR: Scenefile '%s' contains no models.\n", + optInputFilename.c_str()); goto exit; } - if (!dmLoadMesh(optModelPrefix + ".mesh", optModelPrefix + ".info", modelMesh)) - goto exit; + printf("INFO: Loading %ld model(s) ..\n", + scene.models.size()); - if (optUseShaders) + basePath = dmGetPath(optInputFilename); + printf("INFO: Model base path '%s'\n", basePath.c_str()); + + for (DMModel &model : scene.models) { - // Read shader files - if (!dmReadText(optModelPrefix + ".frag", modelFragStr, SET_MAX_SHADER_SIZE) || - !dmReadText(optModelPrefix + ".vert", modelVertStr, SET_MAX_SHADER_SIZE)) + if (!model.loadFromPLY(basePath + model.modelFile)) goto exit; + + if (optUseShaders) + { + std::string + fragFile = model.fragShaderFile.empty() ? "shader.frag" : basePath + model.fragShaderFile, + vertFile = model.vertShaderFile.empty() ? "shader.vert" : basePath + model.vertShaderFile; + + if (!dmReadText(fragFile, model.fragShaderStr, SET_MAX_SHADER_SIZE) || + !dmReadText(vertFile, model.vertShaderStr, SET_MAX_SHADER_SIZE)) + goto exit; + } } // Initialize SDL + OpenGL - if (!dmInitSDLGL(optWidth, optHeight, "GLXDragon2")) + if (!dmInitSDLGL(optWidth, optHeight, "GLDragon")) goto exit; // According to our mode .. if (optUseShaders) { - modelMesh.id_fs = dmCompileShader(GL_FRAGMENT_SHADER, modelFragStr); - modelMesh.id_vs = dmCompileShader(GL_VERTEX_SHADER, modelVertStr); - dmLinkMeshShaders(modelMesh); + for (DMModel &model : scene.models) + { + model.id_fs = dmCompileShader(GL_FRAGMENT_SHADER, model.fragShaderStr); + model.id_vs = dmCompileShader(GL_VERTEX_SHADER, model.vertShaderStr); + dmLinkModelShaders(model); + } } else { @@ -591,8 +501,7 @@ } // Render the next frame - dmDrawBackground(); - dmDrawModelVA(modelMesh); + dmDrawScene(scene); // Draw the current frame SDL_GL_SwapWindow(dmWindow); diff -r 294c4c7943b5 -r 1404dfcee7b8 shader.frag --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/shader.frag Fri Nov 22 03:03:52 2019 +0200 @@ -0,0 +1,9 @@ +void main() +{ +gl_FragColor = vec4( + gl_FragCoord.x * 0.1, + gl_FragCoord.y * 0.001, + 0.0, + 1.0); +}; + diff -r 294c4c7943b5 -r 1404dfcee7b8 shader.vert --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/shader.vert Fri Nov 22 03:03:52 2019 +0200 @@ -0,0 +1,4 @@ +void main() +{ +gl_Position = ftransform(); +}