/*! * Load shape levels recursively * \param ppFileData Pointer to the data (usualy read from a file) * \param FileDataEnd ??? * \param nlevels Number of levels to load * \return pointer to iFSDShape structure (or NULL on error) * \pre ppFileData loaded * \post s allocated */ static iIMDShape *_imd_load_level(const QString &filename, const char **ppFileData, const char *FileDataEnd, int nlevels, int pieVersion, int level) { const char *pFileData = *ppFileData; char buffer[PATH_MAX] = {'\0'}; int cnt = 0, n = 0, i; iIMDShape *s = nullptr; float dummy; if (nlevels == 0) { return nullptr; } i = sscanf(pFileData, "%255s %n", buffer, &cnt); ASSERT_OR_RETURN(nullptr, i == 1, "Bad directive following LEVEL"); s = new iIMDShape; // Optionally load and ignore deprecated MATERIALS directive if (strcmp(buffer, "MATERIALS") == 0) { i = sscanf(pFileData, "%255s %f %f %f %f %f %f %f %f %f %f%n", buffer, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &cnt); ASSERT_OR_RETURN(nullptr, i == 11, "Bad MATERIALS directive"); debug(LOG_WARNING, "MATERIALS directive no longer supported!"); pFileData += cnt; } else if (strcmp(buffer, "SHADERS") == 0) { char vertex[PATH_MAX], fragment[PATH_MAX]; if (sscanf(pFileData, "%255s %255s %255s%n", buffer, vertex, fragment, &cnt) != 3) { debug(LOG_ERROR, "%s shader corrupt: %s", filename.toUtf8().constData(), buffer); return nullptr; } std::vector<std::string> uniform_names { "colour", "teamcolour", "stretch", "tcmask", "fogEnabled", "normalmap", "specularmap", "ecmEffect", "alphaTest", "graphicsCycle", "ModelViewProjectionMatrix" }; s->shaderProgram = pie_LoadShader(filename.toUtf8().constData(), vertex, fragment, uniform_names); pFileData += cnt; } if (sscanf(pFileData, "%255s %d%n", buffer, &s->npoints, &cnt) != 2) { debug(LOG_ERROR, "_imd_load_level(2): file corrupt"); return nullptr; } pFileData += cnt; // load points ASSERT_OR_RETURN(nullptr, strcmp(buffer, "POINTS") == 0, "Expecting 'POINTS' directive, got: %s", buffer); _imd_load_points(&pFileData, s); if (sscanf(pFileData, "%255s %d%n", buffer, &s->npolys, &cnt) != 2) { debug(LOG_ERROR, "_imd_load_level(3): file corrupt"); return nullptr; } pFileData += cnt; ASSERT_OR_RETURN(nullptr, strcmp(buffer, "POLYGONS") == 0, "Expecting 'POLYGONS' directive, got: %s", buffer); _imd_load_polys(filename, &pFileData, s, pieVersion); // optional stuff : levels, object animations, connectors s->objanimframes = 0; while (!AtEndOfFile(pFileData, FileDataEnd)) // check for end of file (give or take white space) { // Scans in the line ... if we don't get 2 parameters then quit if (sscanf(pFileData, "%255s %d%n", buffer, &n, &cnt) != 2) { break; } pFileData += cnt; if (strcmp(buffer, "LEVEL") == 0) // check for next level { debug(LOG_3D, "imd[_load_level] = npoints %d, npolys %d", s->npoints, s->npolys); s->next = _imd_load_level(filename, &pFileData, FileDataEnd, nlevels - 1, pieVersion, level + 1); } else if (strcmp(buffer, "CONNECTORS") == 0) { //load connector stuff s->nconnectors = n; _imd_load_connectors(&pFileData, s); } else if (strcmp(buffer, "ANIMOBJECT") == 0) { s->objanimtime = n; if (sscanf(pFileData, "%d %d%n", &s->objanimcycles, &s->objanimframes, &cnt) != 2) { debug(LOG_ERROR, "%s bad ANIMOBJ: %s", filename.toUtf8().constData(), pFileData); return nullptr; } pFileData += cnt; s->objanimdata.resize(s->objanimframes); for (int i = 0; i < s->objanimframes; i++) { int frame; Vector3i pos, rot; if (sscanf(pFileData, "%d %d %d %d %d %d %d %f %f %f%n", &frame, &pos.x, &pos.y, &pos.z, &rot.x, &rot.y, &rot.z, &s->objanimdata[i].scale.x, &s->objanimdata[i].scale.y, &s->objanimdata[i].scale.z, &cnt) != 10) { debug(LOG_ERROR, "%s: Invalid object animation level %d, line %d, frame %d", filename.toUtf8().constData(), level, i, frame); } ASSERT(frame == i, "%s: Invalid frame enumeration object animation (level %d) %d: %d", filename.toUtf8().constData(), level, i, frame); s->objanimdata[i].pos.x = pos.x / INT_SCALE; s->objanimdata[i].pos.y = pos.z / INT_SCALE; s->objanimdata[i].pos.z = pos.y / INT_SCALE; s->objanimdata[i].rot.pitch = -(rot.x * DEG_1 / INT_SCALE); s->objanimdata[i].rot.direction = -(rot.z * DEG_1 / INT_SCALE); s->objanimdata[i].rot.roll = -(rot.y * DEG_1 / INT_SCALE); pFileData += cnt; } } else { debug(LOG_ERROR, "(_load_level) unexpected directive %s %d", buffer, n); break; } } // FINALLY, massage the data into what can stream directly to OpenGL glGenBuffers(VBO_COUNT, s->buffers); vertexCount = 0; for (int k = 0; k < MAX(1, s->numFrames); k++) { // Go through all polygons for each frame for (unsigned i = 0; i < s->npolys; i++) { const iIMDPoly *pPolys = &s->polys[i]; // Do we already have the vertex data for this polygon? indices.append(addVertex(s, 0, pPolys, k)); indices.append(addVertex(s, 1, pPolys, k)); indices.append(addVertex(s, 2, pPolys, k)); } } glBindBuffer(GL_ARRAY_BUFFER, s->buffers[VBO_VERTEX]); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), vertices.constData(), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, s->buffers[VBO_NORMAL]); glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(GLfloat), normals.constData(), GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->buffers[VBO_INDEX]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint16_t), indices.constData(), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, s->buffers[VBO_TEXCOORD]); glBufferData(GL_ARRAY_BUFFER, texcoords.size() * sizeof(GLfloat), texcoords.constData(), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); // unbind indices.resize(0); vertices.resize(0); texcoords.resize(0); normals.resize(0); *ppFileData = pFileData; return s; }
/*! * Load shape levels recursively * \param ppFileData Pointer to the data (usualy read from a file) * \param FileDataEnd ??? * \param nlevels Number of levels to load * \return pointer to iFSDShape structure (or NULL on error) * \pre ppFileData loaded * \post s allocated */ static iIMDShape *_imd_load_level(const char **ppFileData, const char *FileDataEnd, int nlevels, int pieVersion) { const char *pFileName = GetLastResourceFilename(); // Last loaded filename const char *pFileData = *ppFileData; char buffer[PATH_MAX] = {'\0'}; int cnt = 0, n = 0, i; iIMDShape *s = NULL; float dummy; if (nlevels == 0) { return NULL; } i = sscanf(pFileData, "%255s %n", buffer, &cnt); ASSERT_OR_RETURN(NULL, i == 1, "Bad directive following LEVEL"); s = new iIMDShape; // Optionally load and ignore deprecated MATERIALS directive if (strcmp(buffer, "MATERIALS") == 0) { i = sscanf(pFileData, "%255s %f %f %f %f %f %f %f %f %f %f%n", buffer, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &cnt); ASSERT_OR_RETURN(NULL, i == 11, "Bad MATERIALS directive"); debug(LOG_WARNING, "MATERIALS directive no longer supported!"); pFileData += cnt; } else if (strcmp(buffer, "SHADERS") == 0) { char vertex[PATH_MAX], fragment[PATH_MAX]; if (sscanf(pFileData, "%255s %255s %255s%n", buffer, vertex, fragment, &cnt) != 3) { debug(LOG_ERROR, "%s shader corrupt: %s", pFileName, buffer); return NULL; } s->shaderProgram = pie_LoadShader(pFileName, vertex, fragment); pFileData += cnt; } if (sscanf(pFileData, "%255s %d%n", buffer, &s->npoints, &cnt) != 2) { debug(LOG_ERROR, "_imd_load_level(2): file corrupt"); return NULL; } pFileData += cnt; // load points ASSERT_OR_RETURN(NULL, strcmp(buffer, "POINTS") == 0, "Expecting 'POINTS' directive, got: %s", buffer); _imd_load_points(&pFileData, s); if (sscanf(pFileData, "%255s %d%n", buffer, &s->npolys, &cnt) != 2) { debug(LOG_ERROR, "_imd_load_level(3): file corrupt"); return NULL; } pFileData += cnt; ASSERT_OR_RETURN(NULL, strcmp(buffer, "POLYGONS") == 0, "Expecting 'POLYGONS' directive, got: %s", buffer); _imd_load_polys(&pFileData, s, pieVersion); // NOW load optional stuff while (!AtEndOfFile(pFileData, FileDataEnd)) // check for end of file (give or take white space) { // Scans in the line ... if we don't get 2 parameters then quit if (sscanf(pFileData, "%255s %d%n", buffer, &n, &cnt) != 2) { break; } pFileData += cnt; if (strcmp(buffer, "LEVEL") == 0) // check for next level { debug(LOG_3D, "imd[_load_level] = npoints %d, npolys %d", s->npoints, s->npolys); s->next = _imd_load_level(&pFileData, FileDataEnd, nlevels - 1, pieVersion); } else if (strcmp(buffer, "CONNECTORS") == 0) { //load connector stuff s->nconnectors = n; _imd_load_connectors(&pFileData, s); } else { debug(LOG_ERROR, "(_load_level) unexpected directive %s %d", buffer, n); break; } } // FINALLY, massage the data into what can stream directly to OpenGL glGenBuffers(VBO_COUNT, s->buffers); vertexCount = 0; for (int k = 0; k < MAX(1, s->numFrames); k++) { // Go through all polygons for each frame for (int i = 0; i < s->npolys; i++) { const iIMDPoly *pPolys = &s->polys[i]; // Do we already have the vertex data for this polygon? indices.append(addVertex(s, 0, pPolys, k)); indices.append(addVertex(s, 1, pPolys, k)); indices.append(addVertex(s, 2, pPolys, k)); } } glBindBuffer(GL_ARRAY_BUFFER, s->buffers[VBO_VERTEX]); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), vertices.constData(), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, s->buffers[VBO_NORMAL]); glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(GLfloat), normals.constData(), GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->buffers[VBO_INDEX]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint16_t), indices.constData(), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, s->buffers[VBO_TEXCOORD]); glBufferData(GL_ARRAY_BUFFER, texcoords.size() * sizeof(GLfloat), texcoords.constData(), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); // unbind indices.resize(0); vertices.resize(0); texcoords.resize(0); normals.resize(0); *ppFileData = pFileData; return s; }
/*! * Load shape levels recursively * \param ppFileData Pointer to the data (usualy read from a file) * \param FileDataEnd ??? * \param nlevels Number of levels to load * \return pointer to iFSDShape structure (or NULL on error) * \pre ppFileData loaded * \post s allocated */ static iIMDShape *_imd_load_level(const char **ppFileData, const char *FileDataEnd, int nlevels) { const char *pFileData = *ppFileData; char buffer[MAX_PATH] = {'\0'}; int cnt = 0, n = 0; iIMDShape *s = NULL; if (nlevels == 0) return NULL; s = (iIMDShape*)malloc(sizeof(iIMDShape)); if (s == NULL) { /* Failed to allocate memory for s */ fprintf(stderr, "_imd_load_level: Memory allocation error\n"); return NULL; } s->nconnectors = 0; // Default number of connectors must be 0 s->npoints = 0; s->npolys = 0; s->points = NULL; s->polys = NULL; s->connectors = NULL; s->next = NULL; s->shadowEdgeList = NULL; s->nShadowEdges = 0; s->texpage = iV_TEX_INVALID; if (sscanf(pFileData, "%s %d%n", buffer, &s->npoints, &cnt) != 2) { fprintf(stderr, "_imd_load_level(2): file corrupt\n"); return NULL; } pFileData += cnt; // load points if (strcmp(buffer, "POINTS") != 0) { fprintf(stderr, "_imd_load_level: expecting 'POINTS' directive, got: %s", buffer); return NULL; } if (s->npoints > iV_IMD_MAX_POINTS) { fprintf(stderr, "_imd_load_level: too many points in IMD\n"); return NULL; } _imd_load_points( &pFileData, s ); if (sscanf(pFileData, "%s %d%n", buffer, &s->npolys, &cnt) != 2) { fprintf(stderr, "_imd_load_level(3): file corrupt\n"); return NULL; } pFileData += cnt; if (strcmp(buffer, "POLYGONS") != 0) { fprintf(stderr,"_imd_load_level: expecting 'POLYGONS' directive\n"); return NULL; } _imd_load_polys( &pFileData, s ); // NOW load optional stuff while (!AtEndOfFile(pFileData, FileDataEnd)) // check for end of file (give or take white space) { // Scans in the line ... if we don't get 2 parameters then quit if (sscanf(pFileData, "%s %d%n", buffer, &n, &cnt) != 2) { break; } pFileData += cnt; // check for next level ... or might be a BSP - This should handle an imd if it has a BSP tree attached to it // might be "BSP" or "LEVEL" if (strcmp(buffer, "LEVEL") == 0) { fprintf(stderr, "imd[_load_level] = npoints %d, npolys %d\n", s->npoints, s->npolys); s->next = _imd_load_level(&pFileData, FileDataEnd, nlevels - 1); } else if (strcmp(buffer, "CONNECTORS") == 0) { //load connector stuff s->nconnectors = n; _imd_load_connectors( &pFileData, s ); } else { fprintf(stderr, "(_load_level) unexpected directive %s %d", buffer, n); break; } } *ppFileData = pFileData; return s; }
/*! * Load shape levels recursively * \param ppFileData Pointer to the data (usualy read from a file) * \param FileDataEnd ??? * \param nlevels Number of levels to load * \return pointer to iFSDShape structure (or NULL on error) * \pre ppFileData loaded * \post s allocated */ static iIMDShape *_imd_load_level(const char **ppFileData, const char *FileDataEnd, int nlevels, int pieVersion) { const char *pTmp, *pFileData = *ppFileData; char buffer[PATH_MAX] = {'\0'}; int cnt = 0, n = 0, i; iIMDShape *s = NULL; if (nlevels == 0) { return NULL; } // Load optional MATERIALS directive pTmp = pFileData; // remember position i = sscanf(pFileData, "%255s %n", buffer, &cnt); ASSERT_OR_RETURN(NULL, i == 1, "Bad directive following LEVEL"); s = new iIMDShape; if (strcmp(buffer, "MATERIALS") == 0) { i = sscanf(pFileData, "%255s %f %f %f %f %f %f %f %f %f %f%n", buffer, &s->material[LIGHT_AMBIENT][0], &s->material[LIGHT_AMBIENT][1], &s->material[LIGHT_AMBIENT][2], &s->material[LIGHT_DIFFUSE][0], &s->material[LIGHT_DIFFUSE][1], &s->material[LIGHT_DIFFUSE][2], &s->material[LIGHT_SPECULAR][0], &s->material[LIGHT_SPECULAR][1], &s->material[LIGHT_SPECULAR][2], &s->shininess, &cnt); ASSERT_OR_RETURN(NULL, i == 11, "Bad MATERIALS directive"); pFileData += cnt; } else // use defaults { pFileData = pTmp; } if (sscanf(pFileData, "%255s %d%n", buffer, &s->npoints, &cnt) != 2) { debug(LOG_ERROR, "_imd_load_level(2): file corrupt"); return NULL; } pFileData += cnt; // load points ASSERT_OR_RETURN(NULL, strcmp(buffer, "POINTS") == 0, "Expecting 'POINTS' directive, got: %s", buffer); _imd_load_points( &pFileData, s ); if (sscanf(pFileData, "%255s %d%n", buffer, &s->npolys, &cnt) != 2) { debug(LOG_ERROR, "_imd_load_level(3): file corrupt"); return NULL; } pFileData += cnt; ASSERT_OR_RETURN(NULL, strcmp(buffer, "POLYGONS") == 0, "Expecting 'POLYGONS' directive, got: %s", buffer); _imd_load_polys( &pFileData, s, pieVersion); // NOW load optional stuff while (!AtEndOfFile(pFileData, FileDataEnd)) // check for end of file (give or take white space) { // Scans in the line ... if we don't get 2 parameters then quit if (sscanf(pFileData, "%255s %d%n", buffer, &n, &cnt) != 2) { break; } pFileData += cnt; // check for next level ... or might be a BSP - This should handle an imd if it has a BSP tree attached to it // might be "BSP" or "LEVEL" if (strcmp(buffer, "LEVEL") == 0) { debug(LOG_3D, "imd[_load_level] = npoints %d, npolys %d", s->npoints, s->npolys); s->next = _imd_load_level(&pFileData, FileDataEnd, nlevels - 1, pieVersion); } else if (strcmp(buffer, "CONNECTORS") == 0) { //load connector stuff s->nconnectors = n; _imd_load_connectors( &pFileData, s ); } else { debug(LOG_ERROR, "(_load_level) unexpected directive %s %d", buffer, n); break; } } // FINALLY, massage the data into what can stream directly to OpenGL glGenBuffers(VBO_COUNT, s->buffers); vertexCount = 0; for (int k = 0; k < MAX(1, s->numFrames); k++) { // Go through all polygons for each frame for (int i = 0; i < s->npolys; i++) { const iIMDPoly *pPolys = &s->polys[i]; // Do we already have the vertex data for this polygon? indices.append(addVertex(s, 0, pPolys, k)); indices.append(addVertex(s, 1, pPolys, k)); indices.append(addVertex(s, 2, pPolys, k)); } } glBindBuffer(GL_ARRAY_BUFFER, s->buffers[VBO_VERTEX]); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), vertices.constData(), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, s->buffers[VBO_NORMAL]); glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(GLfloat), normals.constData(), GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->buffers[VBO_INDEX]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint16_t), indices.constData(), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, s->buffers[VBO_TEXCOORD]); glBufferData(GL_ARRAY_BUFFER, texcoords.size() * sizeof(GLfloat), texcoords.constData(), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); // unbind indices.resize(0); vertices.resize(0); texcoords.resize(0); normals.resize(0); *ppFileData = pFileData; return s; }
/*! * Load shape levels recursively * \param ppFileData Pointer to the data (usualy read from a file) * \param FileDataEnd ??? * \param nlevels Number of levels to load * \return pointer to iFSDShape structure (or NULL on error) * \pre ppFileData loaded * \post s allocated */ static iIMDShape *_imd_load_level(const char **ppFileData, const char *FileDataEnd, int nlevels, int pieVersion) { const char *pTmp, *pFileData = *ppFileData; char buffer[PATH_MAX] = {'\0'}; int cnt = 0, n = 0, i; iIMDShape *s = NULL; if (nlevels == 0) { return NULL; } // Load optional MATERIALS directive pTmp = pFileData; // remember position i = sscanf(pFileData, "%255s %n", buffer, &cnt); ASSERT_OR_RETURN(NULL, i == 1, "Bad directive following LEVEL"); s = (iIMDShape*)malloc(sizeof(iIMDShape)); if (s == NULL) { /* Failed to allocate memory for s */ debug(LOG_ERROR, "_imd_load_level: Memory allocation error"); return NULL; } s->flags = 0; s->nconnectors = 0; // Default number of connectors must be 0 s->npoints = 0; s->npolys = 0; s->points = NULL; s->polys = NULL; s->connectors = NULL; s->next = NULL; s->shadowEdgeList = NULL; s->nShadowEdges = 0; s->texpage = iV_TEX_INVALID; s->tcmaskpage = iV_TEX_INVALID; s->normalpage = iV_TEX_INVALID; memset(s->material, 0, sizeof(s->material)); s->material[LIGHT_AMBIENT][3] = 1.0f; s->material[LIGHT_DIFFUSE][3] = 1.0f; s->material[LIGHT_SPECULAR][3] = 1.0f; if (strcmp(buffer, "MATERIALS") == 0) { i = sscanf(pFileData, "%255s %f %f %f %f %f %f %f %f %f %f%n", buffer, &s->material[LIGHT_AMBIENT][0], &s->material[LIGHT_AMBIENT][1], &s->material[LIGHT_AMBIENT][2], &s->material[LIGHT_DIFFUSE][0], &s->material[LIGHT_DIFFUSE][1], &s->material[LIGHT_DIFFUSE][2], &s->material[LIGHT_SPECULAR][0], &s->material[LIGHT_SPECULAR][1], &s->material[LIGHT_SPECULAR][2], &s->shininess, &cnt); ASSERT_OR_RETURN(NULL, i == 11, "Bad MATERIALS directive"); pFileData += cnt; } else { // Set default values s->material[LIGHT_AMBIENT][0] = 1.0f; s->material[LIGHT_AMBIENT][1] = 1.0f; s->material[LIGHT_AMBIENT][2] = 1.0f; s->material[LIGHT_DIFFUSE][0] = 1.0f; s->material[LIGHT_DIFFUSE][1] = 1.0f; s->material[LIGHT_DIFFUSE][2] = 1.0f; s->material[LIGHT_SPECULAR][0] = 1.0f; s->material[LIGHT_SPECULAR][1] = 1.0f; s->material[LIGHT_SPECULAR][2] = 1.0f; s->shininess = 10; pFileData = pTmp; } if (sscanf(pFileData, "%255s %d%n", buffer, &s->npoints, &cnt) != 2) { debug(LOG_ERROR, "_imd_load_level(2): file corrupt"); return NULL; } pFileData += cnt; // load points ASSERT_OR_RETURN(NULL, strcmp(buffer, "POINTS") == 0, "Expecting 'POINTS' directive, got: %s", buffer); _imd_load_points( &pFileData, s ); if (sscanf(pFileData, "%255s %d%n", buffer, &s->npolys, &cnt) != 2) { debug(LOG_ERROR, "_imd_load_level(3): file corrupt"); return NULL; } pFileData += cnt; ASSERT_OR_RETURN(NULL, strcmp(buffer, "POLYGONS") == 0, "Expecting 'POLYGONS' directive, got: %s", buffer); _imd_load_polys( &pFileData, s, pieVersion); // NOW load optional stuff while (!AtEndOfFile(pFileData, FileDataEnd)) // check for end of file (give or take white space) { // Scans in the line ... if we don't get 2 parameters then quit if (sscanf(pFileData, "%255s %d%n", buffer, &n, &cnt) != 2) { break; } pFileData += cnt; // check for next level ... or might be a BSP - This should handle an imd if it has a BSP tree attached to it // might be "BSP" or "LEVEL" if (strcmp(buffer, "LEVEL") == 0) { debug(LOG_3D, "imd[_load_level] = npoints %d, npolys %d", s->npoints, s->npolys); s->next = _imd_load_level(&pFileData, FileDataEnd, nlevels - 1, pieVersion); } else if (strcmp(buffer, "CONNECTORS") == 0) { //load connector stuff s->nconnectors = n; _imd_load_connectors( &pFileData, s ); } else { debug(LOG_ERROR, "(_load_level) unexpected directive %s %d", buffer, n); break; } } *ppFileData = pFileData; return s; }