/* Copyright (C) 2006 Parallel Realities This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "modelLoader.h" void createDisplayListFromSimpleModel(char *filename, SimpleModel *model) { if (!engine->loadData(filename)) { graphics->showErrorAndExit(ERR_FILE, filename); } char *token = strtok((char*)engine->dataBuffer, "\n"); int numberOfPoints = atoi(token); if ((numberOfPoints % 3) != 0) { graphics->showErrorAndExit("ERROR - loadSimpleModel() - Incorrect format! Must be divisible by 3!!"); } float x[3], y[3], z[3], u[3], v[3]; model->data = glGenLists(1); glNewList(model->data, GL_COMPILE); { for (int i = 0 ; i < numberOfPoints ; i += 3) { for (int j = 0 ; j < 3 ; j++) { token = strtok(NULL, "\n"); sscanf(token, "%f %f %f %f %f", &x[j], &y[j], &z[j], &u[j], &v[j]); } glBegin(GL_TRIANGLES); { glTexCoord2f(u[0], v[0]); glVertex3f(x[0], y[0], z[0]); glTexCoord2f(u[1], v[1]); glVertex3f(x[1], y[1], z[1]); glTexCoord2f(u[2], v[2]); glVertex3f(x[2], y[2], z[2]); } glEnd(); } } glEndList(); } void createDisplayListFromProperties(char *filename, SimpleModel *model) { List *list = loadProperties(filename, true); Vector bbMins, bbMaxs; Vector position, scale, size; float radius; GLColor color, rotation; String texture; model->data = glGenLists(1); //model->name = filename; glNewList(model->data, GL_COMPILE); { for (Properties *props = (Properties*)list->getFirstElement() ; props != NULL ; props = (Properties*)props->next) { glPushMatrix(); { position = props->getVector("position"); scale = props->getVector("scale"); color = props->getColor("color"); rotation = props->getColor("rotate"); // we're using a GLColor here because it can hold four values ;) if (rotation.color[0] != 1) { glRotatef(rotation.color[0], rotation.color[1], rotation.color[2], rotation.color[3]); } if ((scale.x != 0 ) && (scale.y != 0) && (scale.z != 0)) { glScalef(scale.x, scale.y, scale.z); } glTranslatef(position.x, position.y, position.z); glColor4fv(color.color); if (props->name == "Sphere") { radius = props->getFloat("radius", 1); gluSphere(graphics->quadric, radius, 16, 16); } else if (props->name == "Box") { size = props->getVector("size"); drawBox(position, size.x, size.y, size.z, 1); } else if (props->name == "Cone") { gluCylinder(graphics->quadric, props->getFloat("bottomRadius", 0), props->getFloat("topRadius", 1), props->getFloat("height", 0), 12, 1); } } glPopMatrix(); } } glEndList(); } SimpleModel *loadSimpleModel(char *filename, int type) { debug(("loadSimpleModel() - %s\n", filename)); SimpleModel *simpleModel = new SimpleModel(); switch (type) { case MDL_RAW: createDisplayListFromSimpleModel(filename, simpleModel); break; case MDL_PRIMITIVE: createDisplayListFromProperties(filename, simpleModel); break; } return simpleModel; } MD2Model *loadMD2Model(char *filename) { debug(("loadMD2Model() - %s\n", filename)); char name[255], lastName[255], *buffer, *bufferIndex; int i, j, k, frame; long fileSize; FILE *fp; tMd2AliasFrame *frameIndex; Object currentFrame; MD2 md2; Animation animation; tMd2Header *headerIndex; tMd2Skin *skinIndex; tMd2TexCoord *textureIndex; tMd2Face *triangleIndex; MD2Model *model = new MD2Model(); if (pak->getFileLocation(filename) == FILE_NOT_FOUND) { graphics->showErrorAndExit("Failed to open MD2: %s\n", filename); } fp = fopen(pak->getFileName(), "rb"); fseek(fp, 0, SEEK_END); fileSize = ftell(fp); fseek(fp, 0, SEEK_SET); buffer = (char *)malloc(fileSize); fread(buffer, fileSize, 1, fp); headerIndex = (tMd2Header *)buffer; md2.m_Header = *headerIndex; md2.m_Header.version = SDL_SwapLE32(md2.m_Header.version); md2.m_Header.magic = SDL_SwapLE32(md2.m_Header.magic); md2.m_Header.skinWidth = SDL_SwapLE32(md2.m_Header.skinWidth); md2.m_Header.skinHeight = SDL_SwapLE32(md2.m_Header.skinHeight); md2.m_Header.frameSize = SDL_SwapLE32(md2.m_Header.frameSize); md2.m_Header.numSkins = SDL_SwapLE32(md2.m_Header.numSkins); md2.m_Header.numVertices = SDL_SwapLE32(md2.m_Header.numVertices); md2.m_Header.numTexCoords = SDL_SwapLE32(md2.m_Header.numTexCoords); md2.m_Header.numTriangles = SDL_SwapLE32(md2.m_Header.numTriangles); md2.m_Header.numGlCommands = SDL_SwapLE32(md2.m_Header.numGlCommands); md2.m_Header.numFrames = SDL_SwapLE32(md2.m_Header.numFrames); md2.m_Header.offsetSkins = SDL_SwapLE32(md2.m_Header.offsetSkins); md2.m_Header.offsetTexCoords = SDL_SwapLE32(md2.m_Header.offsetTexCoords); md2.m_Header.offsetTriangles = SDL_SwapLE32(md2.m_Header.offsetTriangles); md2.m_Header.offsetFrames = SDL_SwapLE32(md2.m_Header.offsetFrames); md2.m_Header.offsetGlCommands = SDL_SwapLE32(md2.m_Header.offsetGlCommands); md2.m_Header.offsetEnd = SDL_SwapLE32(md2.m_Header.offsetEnd); if (md2.m_Header.version != 8) /* MUST be version 8 for MD2 */ { fclose(fp); graphics->showErrorAndExit("Incorrect version of MD2, expected 8, found %d\n", md2.m_Header.version); } /* Allocate memory for the md2 */ md2.m_pSkins = (tMd2Skin *)malloc(sizeof(tMd2Skin) * md2.m_Header.numSkins); md2.m_pTexCoords = (tMd2TexCoord *)malloc(sizeof(tMd2TexCoord) * md2.m_Header.numTexCoords); md2.m_pTriangles = (tMd2Face *)malloc(sizeof(tMd2Face) * md2.m_Header.numTriangles); md2.m_pFrames = (tMd2Frame *)malloc(sizeof(tMd2Frame) * md2.m_Header.numFrames); if (md2.m_pSkins == NULL || md2.m_pTexCoords == NULL || md2.m_pTriangles == NULL || md2.m_pFrames == NULL) { fclose(fp); graphics->showErrorAndExit("Ran out of memory while loading md2: %s\n", filename); } /* Seek to and read the skin. Only the first one for the moment */ bufferIndex = buffer; bufferIndex += md2.m_Header.offsetSkins; skinIndex = (tMd2Skin *)bufferIndex; for (i=0;ishowErrorAndExit("Ran out of memory while creating frames for md2: %s\n", filename); } /* Copy the name of the animation to the frame */ strcpy(md2.m_pFrames[i].strName, frameIndex->name); /* Assign scale and translations. MD2 swap the Y and Z, so switch them back, and negate the Z */ for (j=0;jaliasVertices[j].vertex[0]) * SDL_SwapLE32(frameIndex->scale[0]) + SDL_SwapLE32(frameIndex->translate[0]); md2.m_pFrames[i].pVertices[j].vertex[2] = -1 * SDL_SwapLE32(frameIndex->aliasVertices[j].vertex[1]) * SDL_SwapLE32(frameIndex->scale[1]) - SDL_SwapLE32(frameIndex->translate[1]); md2.m_pFrames[i].pVertices[j].vertex[1] = SDL_SwapLE32(frameIndex->aliasVertices[j].vertex[2]) * SDL_SwapLE32(frameIndex->scale[2]) + SDL_SwapLE32(frameIndex->translate[2]); } bufferIndex = (char *)frameIndex; bufferIndex += md2.m_Header.frameSize; frameIndex = (tMd2AliasFrame *)bufferIndex; } free(buffer); fclose(fp); model->frameCount = md2.m_Header.numFrames; strcpy(lastName, ""); k = 0; /* Get all the animation frame names */ for (i=0;iframeCount;i++) { strcpy(name, md2.m_pFrames[i].strName); /* Extract the frame number from the animation frame name */ for (j=strlen(name)-1;j>=0;j--) { if (!isdigit(name[j])) { name[j + 1] = '\0'; break; } } if (strcmp(name, lastName) != 0) { strcpy(lastName, name); k++; } } /* Allocate the required memory for the animations */ model->animation = (Animation *)malloc(sizeof(Animation) * k); if (model->animation == NULL) { fclose(fp); graphics->showErrorAndExit("Ran out of memory while creating animations for md2: %s\n", filename); } model->animCount = k; /* Now go back and add the frames to the relevant animations */ strcpy(lastName, ""); k = 0; for (i=0;iframeCount;i++) { strcpy(name, md2.m_pFrames[i].strName); /* Extract the frame number from the animation frame name */ for (j=strlen(name)-1;j>=0;j--) { if (!isdigit(name[j])) { frame = atoi(strrchr(name, name[j + 1])); name[j + 1] = '\0'; break; } } /* Check if this frame name is not the same as the last name or it's the very last frame */ if (strcmp(name, lastName) != 0 || i == model->frameCount - 1) { /* If this is not the very first frame or it's the very last frame, add it to the list */ if (strlen(lastName) != 0 || i == model->frameCount - 1) { animation.end = i - 1; model->animation[k++] = animation; /* Set the new animation's start to i */ strcpy(animation.name, name); animation.start = i; } /* Otherwise, create the animation */ else { strcpy(animation.name, name); animation.start = i; } } /* Set the last name to the current name */ strcpy(lastName, name); } /* Now place all the information into the model */ model->frame = (Object *)malloc(sizeof(Object) * model->frameCount); for (i=0;iframeCount;i++) { currentFrame.vertexCount = md2.m_Header.numVertices; currentFrame.textureCoordCount = md2.m_Header.numTexCoords; currentFrame.faceCount = md2.m_Header.numTriangles; currentFrame.verts = (Vector*)malloc(sizeof(Vector) * currentFrame.vertexCount); if (currentFrame.verts == NULL) { fclose(fp); graphics->showErrorAndExit("Ran out of memory while creating model for %s\n", filename); } for (j=0;jshowErrorAndExit("Ran out of memory while creating model textures for %s\n", filename); } /* Assign the uv coordinates. Scale the u and v down from 0-256 to 0-1 and invert the v */ for (j=0;jframe[i] = currentFrame; } /* Free all the information */ if (md2.m_pSkins != NULL) { free(md2.m_pSkins); } if (md2.m_pTexCoords != NULL) { free(md2.m_pTexCoords); } if (md2.m_pTriangles != NULL) { free(md2.m_pTriangles); } if (md2.m_pFrames != NULL) { free(md2.m_pFrames); } return model; }