-
Notifications
You must be signed in to change notification settings - Fork 0
/
CMdl.cpp
executable file
·646 lines (523 loc) · 20 KB
/
CMdl.cpp
1
/* CMdl.cpp Author: Tom Naughton Description: based on code by Scott Gilroy, converted to C++, added exporting*//****************************************************************************** File: mdl.c Author: Scott Gilroy Project: Modelook, Quake model viewer Last Modified: June 10, 1998-------------------------------------------------------------------------------©1998 Scott GilroyMDL loading and drawing functions. These functions are based primarily onthe Quake Specs v3.4 found at http://www.gamers.org/dEngine/quake/spec/quake-spec34Source code for id Software's Quake utilities was also used for reference, andcan be found at ftp://ftp.idsoftware.com/idstuff/source/qutils.zipAlso of help was Brian Martin's <[email protected]> MedDle source code,which can be found at http://meddle.telefragged.com/******************************************************************************/#include <stdlib.h>#include <math.h>#include <string.h>#include <glut.h>#include <agl.h>#include "CPakRatApp.h"#include "CPreferences.h"#include "CMdl.h"#include "CModelInstance.h"#include "CPakStream.h"#include "CGLImage.h"#include "CPcx.h"#include "utilities.h"CMdl::CMdl(CResourceManager *resources) : C3DModel(resources){ _mdl = nil; _data = nil;}CMdl::~CMdl(){ dprintf("~CMdl()\n"); // throw away model if (_mdl) { CMemoryTracker::safeFree(_mdl); } if (_data) { CMemoryTracker::safeFree(_data); } }Boolean CMdl::init(CPakStream *inItem){ long baseSkin; // offset in the file to the skins long baseVerts; // offset to the skin vertices long baseTri; // offset to the triangles long baseFrames; // offset to the frames long isSkinGroup; // flag for skin groups long numSkinFrames; // frames for a skin group int i; // iterator int currFrame = 0; // read in all the data _glName = nextGLName(); _dataSize = inItem->getSize(); _data = (char*)CMemoryTracker::safeAlloc(1, _dataSize, "mdl data"); if (!_data) goto fail; if(!inItem->getBytes(_dataSize, (char*)_data)) goto fail; char *p = _data; _mdl = (mdl_t*)CMemoryTracker::safeAlloc(1, sizeof(mdl_t), "mdl_t"); if (!_mdl) goto fail; _mdl->header = (mdl_header_t*)p; _mdl->header->version = swapLong(_mdl->header->version); _mdl->header->scale[0] = swapFloat(_mdl->header->scale[0]); _mdl->header->scale[1] = swapFloat(_mdl->header->scale[1]); _mdl->header->scale[2] = swapFloat(_mdl->header->scale[2]); _mdl->header->origin[0] = swapFloat(_mdl->header->origin[0]); _mdl->header->origin[1] = swapFloat(_mdl->header->origin[1]); _mdl->header->origin[2] = swapFloat(_mdl->header->origin[2]); _mdl->header->radius = swapLong(_mdl->header->radius); _mdl->header->offsets[0] = swapFloat(_mdl->header->offsets[0]); _mdl->header->offsets[1] = swapFloat(_mdl->header->offsets[1]); _mdl->header->offsets[2] = swapFloat(_mdl->header->scale[2]); _mdl->header->numskins = swapLong(_mdl->header->numskins); _mdl->header->skinwidth = swapLong(_mdl->header->skinwidth); _mdl->header->skinheight = swapLong(_mdl->header->skinheight); _mdl->header->numverts = swapLong(_mdl->header->numverts); _mdl->header->numtris = swapLong(_mdl->header->numtris); _mdl->header->numframes = swapLong(_mdl->header->numframes); _mdl->header->synctype = swapLong(_mdl->header->synctype); _mdl->header->size = swapLong(_mdl->header->size); // check the tag if(_mdl->header->tag != HEADER_MDL) { dprintf("OpenMdlFile: file is not a mdl file because tag is: %X\n", _mdl->header->tag); goto fail; } // check the version if(_mdl->header->version != MDL_VERSION) { dprintf("OpenMdlFile: file is not correct version because version is: %d\n", _mdl->header->version); goto fail; } // figure out the offsets baseSkin = sizeof(mdl_header_t); baseVerts = baseSkin; // start here and then add the size of each skin p = _data + baseSkin; UInt32 skipLength; for (i = 0; i < _mdl->header->numskins; i++) { isSkinGroup = swapLong(nextLong(p)); if (isSkinGroup == 0) { skipLength = 4 + _mdl->header->skinwidth * _mdl->header->skinheight; baseVerts += skipLength; p += skipLength - 4; } else { dprintf("this has never been tested.\n"); #if debS Debugger(); #endif numSkinFrames = swapLong(nextLong(p)); skipLength = sizeof(long) * 2 + ( sizeof(float) + (_mdl->header->skinwidth * _mdl->header->skinheight)) * numSkinFrames; baseVerts + skipLength; p += skipLength - 4; } } baseTri = baseVerts + _mdl->header->numverts * sizeof(stvert_t); baseFrames = baseTri + _mdl->header->numtris * sizeof(itriangle_t); // The Skins (FIXME - skin data is wasting space) p = _data + baseSkin; UInt32 skinSize = (4 + _mdl->header->skinwidth * _mdl->header->skinheight); for(i = 0; i < _mdl->header->numskins ; i++) { CGLImage *texture = loadSkin(p, skinSize); p += skinSize; if (texture) { // texture->uploadGLImage(); addTexture(texture); dprintf("loaded texture %d!\n", i); } } // swap the texture coordinates _mdl->texCoord = (stvert_t *) (_data + baseVerts); for(i = 0; i < _mdl->header->numverts; i++) { _mdl->texCoord[i].onseam = swapLong(_mdl->texCoord[i].onseam); _mdl->texCoord[i].s = swapLong(_mdl->texCoord[i].s); _mdl->texCoord[i].t = swapLong(_mdl->texCoord[i].t); } // swap the triangles _mdl->triangles = (itriangle_t*) (_data + baseTri); for(i = 0; i < _mdl->header->numtris; i++) { _mdl->triangles[i].facesfront = swapLong(_mdl->triangles[i].facesfront); _mdl->triangles[i].vertices[0] = swapLong(_mdl->triangles[i].vertices[0]); _mdl->triangles[i].vertices[1] = swapLong(_mdl->triangles[i].vertices[1]); _mdl->triangles[i].vertices[2] = swapLong(_mdl->triangles[i].vertices[2]); } // find the frames _mdl->frameSize = sizeof(simpleframe_t) + sizeof(trivertx_t) * (_mdl->header->numverts - 1); _mdl->frames = (simpleframe_t*) (_data + baseFrames); return true;fail: return false;}CGLImage *CMdl::loadSkin(char *p, UInt32 dataSize){#pragma unused (dataSize) CPreferences *prefs = gApplication->preferences(); long skinGroup; long skinWidth = _mdl->header->skinwidth; long skinHeight = _mdl->header->skinheight; long skinSize = skinWidth * skinHeight; CGLImage *glImage = nil; // check the type skinGroup = swapLong(nextLong(p)); if(skinGroup != 0) { dprintf("Animated skins are not yet implemented"); return 0; } string paletteName = prefs->valueForKey("palette"); RGB *palette; if (paletteName == "hexenII") { palette = (RGB*)hexenPalette; } else { palette = (RGB*)quakePalette; } glImage = CreateTextureFromSkin((UInt8*)p, (RGB*)palette, skinWidth, skinHeight); return glImage;}CGLImage *CMdl::CreateTextureFromSkin(unsigned char *skin, RGB *palette, int skinWidth, int skinHeight){ long skinSize = skinWidth * skinHeight; CPcx *pcximage = new CPcx(); pcximage->initImageFromPCXWithPalette((char*)skin, skinSize, skinWidth, skinHeight, (unsigned char*) palette, false); pcximage->uploadGLImage(0, 0); return pcximage;}string CMdl::frameName(SInt16 framenum){ if (framenum < frameCount()) { simpleframe_t *frame = (simpleframe_t *) ((char*)_mdl->frames + _mdl->frameSize * framenum); return string(frame->name); } else { return string("outofrange"); }}SInt16 CMdl::frameCount() { return _mdl->header->numframes; }UInt32 CMdl::meshNum(){ return 1;}void CMdl::DrawTextureMesh (renderingAttributes_t *rendering, CGLImage *texture){ float x,y,z; int *elems = (int*)gShaderArrays.elems; float *texvecs = (float*)gShaderArrays.tex_st; int elem = 0; Rect bounds = texture->bounds(); glPushMatrix (); x= 0.5; y= 0.5; z= 0.0; if (rendering->_renderTexturePreview) { glDisable( GL_LIGHTING ); glEnable( GL_TEXTURE_2D ); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(-x, y, z); glTexCoord2f(1.0f, 0.0f); glVertex3f( x, y, z); glTexCoord2f(1.0f, 1.0f); glVertex3f( x, -y, z); glTexCoord2f(0.0f, 1.0f); glVertex3f(-x, -y, z); glEnd(); if (rendering->_textureMap) { if (rendering->_textureMap->NextSize(bounds.right - bounds.left, bounds.bottom - bounds.top)) rendering->_pickedImage = texture; } } if (rendering->_renderTextureCoordinates) { glDisable( GL_LIGHTING ); glDisable( GL_TEXTURE_2D ); glEnable(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); glColor3f(1,1,1); if (rendering->_textureMap) rendering->_textureMap->BeginMap(); for(int tri = 0; tri < _mdl->header->numtris; tri++) { if (rendering->_textureMap) rendering->_textureMap->BeginTriangle(); glBegin( GL_LINE_LOOP ); for(int corner = 0; corner < 3; corner++) { float s = _mdl->texCoord[_mdl->triangles[tri].vertices[corner]].s; float t = _mdl->texCoord[_mdl->triangles[tri].vertices[corner]].t; if( (_mdl->texCoord[_mdl->triangles[tri].vertices[corner]].onseam) && (!_mdl->triangles[tri].facesfront)) { s += _mdl->header->skinwidth / 2; } x = (float) s / _mdl->header->skinwidth; y = (float) t / _mdl->header->skinheight; if (rendering->_textureMap) rendering->_textureMap->AddVertex(x,y); x = x - 0.5; y = -y + 0.5; z = 0.0; glVertex3f(x ,y ,z); } glEnd(); if (rendering->_textureMap) rendering->_textureMap->EndTriangle(); } } glPopMatrix (); glColor4f(1,1,1,1);}void CMdl::Draw(CModelInstance *instance, renderingAttributes_t *rendering){ int s,t; // texture coordinates on skin (0 to skinwidth) float texel[2]; // texture coord in texture space (0,0 to 1,1) Vec3 normal; // current vertex normal int tri; // triangle iterator int corner; // triangle corner iterator int dim; // vector dimension iterator Vec3 position; // current vertex position float interpSet[4]; // set of 4 floats for interpolating (position or normals) simpleframe_t *currFrame = (simpleframe_t *) ((char*)_mdl->frames + _mdl->frameSize * instance->_currentFrame); simpleframe_t *nextFrame = (simpleframe_t *) ((char*)_mdl->frames + _mdl->frameSize * instance->_nextFrame); Boolean remeshing = rendering->_showNormals; CGLImage *glImage = nil; if (rendering->_textured && instance->_textureIndex >= 0 && _textureCount > instance->_textureIndex) { glImage = (*_textures)[instance->_textureIndex]; if (glImage) { glEnable( GL_TEXTURE_2D ); glImage->bindTexture(); if ((rendering->_renderTextureCoordinates || rendering->_renderTexturePreview) && _glName == rendering->_pickedName) DrawTextureMesh(rendering, glImage); if (rendering->_pickedName == _glName) rendering->_pickedImage = glImage; } } /* if ((rendering->_renderTextureCoordinates || rendering->_renderTexturePreview)) //&& _glName == rendering->_pickedName) DrawTextureMesh(rendering);*/ if (!rendering->_renderOpaque) return; glPushMatrix(); glDepthMask( GL_TRUE); glDisable( GL_BLEND ); glRotatef( 90.0f, 1.0f , 0.0f , 0.0f ); glRotatef( 90.0f, 0.0f , 1.0f , 0.0f ); if (!(rendering->_renderTextureCoordinates || rendering->_renderTexturePreview) && rendering->_pickShader && _glName) glPushName (_glName); if (rendering->_lighting) glEnable( GL_LIGHTING ); else glDisable( GL_LIGHTING ); if (instance->_interpolationFraction > 1.0) instance->_interpolationFraction = 1.0; for(tri = 0; tri < _mdl->header->numtris; tri++) // tri is which triangle { glBegin(GL_TRIANGLES); // 3 verticies per triangle; corner is which corner of triangle tri // reverse the order so that the triangles are facing outwards for(corner = 0; corner < 3; corner++) { // dim is dimension x,y,z for(dim = 0; dim < 3; dim++) { /* The formula for calculating positions is: vec3_t position[i] = ( scale[i] * packedposition[i] ) + origin[i] */ // get the packed position according to interpolation method if (instance->_interpolationFraction != 0.0f) { interpSet[2] = currFrame->vertex[ _mdl->triangles[tri].vertices[corner] ].packedposition[dim]; interpSet[3] = nextFrame->vertex[ _mdl->triangles[tri].vertices[corner] ].packedposition[dim]; position[dim] = Interpolate(interpSet, instance->_interpolationFraction, INTERP_LINEAR); interpSet[2] = avertexnormals[currFrame->vertex[ _mdl->triangles[tri].vertices[corner] ].lightnormalindex][dim]; interpSet[3] = avertexnormals[nextFrame->vertex[ _mdl->triangles[tri].vertices[corner] ].lightnormalindex][dim]; normal[dim] = Interpolate(interpSet, instance->_interpolationFraction, INTERP_LINEAR); } else { position[dim] = currFrame->vertex[ _mdl->triangles[tri].vertices[corner] ].packedposition[dim]; normal[dim] = avertexnormals[currFrame->vertex[ _mdl->triangles[tri].vertices[corner] ].lightnormalindex][dim]; } // scale and translate position[dim] = ( _mdl->header->scale[dim] * position[dim] ) + _mdl->header->origin[dim]; } // texture coordinates are if(rendering->_textured) { s = _mdl->texCoord[_mdl->triangles[tri].vertices[corner]].s; t = _mdl->texCoord[_mdl->triangles[tri].vertices[corner]].t; if( (_mdl->texCoord[_mdl->triangles[tri].vertices[corner]].onseam) && (!_mdl->triangles[tri].facesfront)) { s += _mdl->header->skinwidth / 2; } texel[0] = (float) s / _mdl->header->skinwidth; texel[1] = (float) t / _mdl->header->skinheight; glTexCoord2f(texel[0], texel[1]); } glNormal3f(normal[1], normal[2], normal[0]); glVertex3f(position[1], position[2], position[0]); } glEnd(); } if ( !(rendering->_renderTextureCoordinates || rendering->_renderTexturePreview) && rendering->_pickShader && _glName) glPopName (); glPopMatrix();}#pragma mark -Boolean CMdl::canExportFormat(ExportFormatT format){ switch (format) { case WAVEFRONT_OBJ_FORMAT: case AUTOCAD_DXF_FORMAT: return true; } return false;}void CMdl::dxfExportMesh(CModelInstance *instance, LFileStream *file, Mat4 transform, int meshnum){#pragma unused (meshnum) Vec3 normal; // current vertex normal int tri; // triangle iterator int dim; // vector dimension iterator SInt32 length; Vec3 position; // current vertex position float interpSet[4]; // set of 4 floats for interpolating (position or normals) simpleframe_t *currFrame = (simpleframe_t *) ((char*)_mdl->frames + _mdl->frameSize * instance->_currentFrame); simpleframe_t *nextFrame = (simpleframe_t *) ((char*)_mdl->frames + _mdl->frameSize * instance->_nextFrame); char str[100]; if (instance->_interpolationFraction > 1.0) instance->_interpolationFraction = 1.0; for(tri = 0; tri < _mdl->header->numtris; tri++) // tri is which triangle { char *facedef = "0\r\n3DFACE\r\n8\r\n1\r\n"; length = strlen(facedef); file->PutBytes(facedef,length); for(int v = 0; v < 4; v++) { // fourth vertex is same as third int corner = v; if (v == 3) corner = 2; // dim is dimension x,y,z for(dim = 0; dim < 3; dim++) { /* The formula for calculating positions is: vec3_t position[i] = ( scale[i] * packedposition[i] ) + origin[i] */ // get the packed position according to interpolation method if (instance->_interpolationFraction != 0.0f) { interpSet[2] = currFrame->vertex[ _mdl->triangles[tri].vertices[corner] ].packedposition[dim]; interpSet[3] = nextFrame->vertex[ _mdl->triangles[tri].vertices[corner] ].packedposition[dim]; position[dim] = Interpolate(interpSet, instance->_interpolationFraction, INTERP_LINEAR); interpSet[2] = avertexnormals[currFrame->vertex[ _mdl->triangles[tri].vertices[corner] ].lightnormalindex][dim]; interpSet[3] = avertexnormals[nextFrame->vertex[ _mdl->triangles[tri].vertices[corner] ].lightnormalindex][dim]; normal[dim] = Interpolate(interpSet, instance->_interpolationFraction, INTERP_LINEAR); } else { position[dim] = currFrame->vertex[ _mdl->triangles[tri].vertices[corner] ].packedposition[dim]; normal[dim] = avertexnormals[currFrame->vertex[ _mdl->triangles[tri].vertices[corner] ].lightnormalindex][dim]; } Vec3 tempVec = position; position = transform * tempVec; // scale and translate position[dim] = ( _mdl->header->scale[dim] * position[dim] ) + _mdl->header->origin[dim]; } sprintf(str, "1%d\r\n%f\r\n", v, position[0]); length = strlen(str); file->PutBytes(str,length); sprintf(str, "2%d\r\n%f\r\n", v, position[1]); length = strlen(str); file->PutBytes(str,length); sprintf(str, "3%d\r\n%f\r\n", v, position[2]); length = strlen(str); file->PutBytes(str,length); } }}void CMdl::objExportMeshVertexData(CModelInstance *instance, LFileStream *file, Mat4 transform, int meshnum) {#pragma unused (meshnum) int s,t; // texture coordinates on skin (0 to skinwidth) float texel[2]; // texture coord in texture space (0,0 to 1,1) Vec3 normal; // current vertex normal int dim; // vector dimension iterator Vec3 position; // current vertex position SInt32 length; float interpSet[4]; // set of 4 floats for interpolating (position or normals) simpleframe_t *currFrame = (simpleframe_t *) ((char*)_mdl->frames + _mdl->frameSize * instance->_currentFrame); simpleframe_t *nextFrame = (simpleframe_t *) ((char*)_mdl->frames + _mdl->frameSize * instance->_nextFrame); CGLImage *glImage = nil; char str[100]; if (instance->_interpolationFraction > 1.0) instance->_interpolationFraction = 1.0; for(int vert = 0; vert < _mdl->header->numverts; vert++) // vert is which vertex { // dim is dimension x,y,z for(dim = 0; dim < 3; dim++) { /* The formula for calculating positions is: vec3_t position[i] = ( scale[i] * packedposition[i] ) + origin[i] */ // get the packed position according to interpolation method if (instance->_interpolationFraction != 0.0f) { interpSet[2] = currFrame->vertex[ vert ].packedposition[dim]; interpSet[3] = nextFrame->vertex[ vert ].packedposition[dim]; position[dim] = Interpolate(interpSet, instance->_interpolationFraction, INTERP_LINEAR); interpSet[2] = avertexnormals[currFrame->vertex[ vert ].lightnormalindex][dim]; interpSet[3] = avertexnormals[nextFrame->vertex[ vert ].lightnormalindex][dim]; normal[dim] = Interpolate(interpSet, instance->_interpolationFraction, INTERP_LINEAR); } else { position[dim] = currFrame->vertex[ vert ].packedposition[dim]; normal[dim] = avertexnormals[currFrame->vertex[ vert ].lightnormalindex][dim]; } // scale and translate position[dim] = ( _mdl->header->scale[dim] * position[dim] ) + _mdl->header->origin[dim]; } Vec3 tempVec = position; position = transform * tempVec; //write vertex sprintf(str, "v %f %f %f\n", position[1], position[2], position[0]); length = strlen(str); file->PutBytes(str,length); //write texture coord. s = _mdl->texCoord[vert].s; t = _mdl->texCoord[vert].t; /* FIXME - hmmm, don't know what to do about this... if( (_mdl->texCoord[_mdl->triangles[tri].vertices[corner]].onseam) && (!_mdl->triangles[tri].facesfront)) { s += _mdl->header->skinwidth / 2; } */ texel[0] = (float) s / _mdl->header->skinwidth; texel[1] = (float) t / _mdl->header->skinheight; sprintf(str, "vt %f %f\n", texel[0], texel[1]); length = strlen(str); file->PutBytes(str,length); //write vertex normal sprintf(str, "vn %f %f %f\n", normal[1], normal[2], normal[0]); length = strlen(str); file->PutBytes(str,length); }} void CMdl::objExportMeshElementData(LFileStream *file, int meshnum, int &vertexCount, int &meshCount){#pragma unused (meshnum, vertexCount, meshCount) char str[100]; SInt32 length; // FIXME mesh names should be uniqued (in the case of three headed models etc.) sprintf(str, "g %s\ns %d\nbevel off\nc_interp off\nd_interp off\n", "mdl", 0); length = strlen(str); file->PutBytes(str,length); for(int tri = 0; tri < _mdl->header->numtris; tri++) // tri is which triangle { int a = _mdl->triangles[tri].vertices[0] + 1; int b = _mdl->triangles[tri].vertices[1] + 1; int c = _mdl->triangles[tri].vertices[2] + 1; sprintf(str, "f %d/%d/%d %d/%d/%d %d/%d/%d\n",a,a,a,b,b,b,c,c,c); length = strlen(str); file->PutBytes(str,length); }}