//models.cpp //3d model drawing code #include #include #include #include #include #include "fileio.h" #include "gamemem.h" #include "vectors.h" #include "entities.h" #include "textures.h" #include "renderframe.h" #include "environment.h" #include "transparency.h" #include "config.h" #include "modeltypes.h" #include "models.h" #include "stencil.h" #include "network.h" #include "mVertex.h" //#define __USEDISPLAYLISTS #ifndef __TARGET_TOOLAPP #define __USEVERTEXARRAYS #endif typedef struct{ void *next; tFileRef model; } tModelList; tModelList *gModelList=NULL; #define kShadowZoom 0.99 //When a model is loaded it won't neccesaryly have the correct //file reference IDs for the texture files, as file reference IDs //are redefined each time at application startup. //this function inserts the correct file reference IDs for a model's //textures based on file names. void ModelInsertTextureRefs(tFileRef modelRef) { tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data; tVector3 *vertices=(tVector3*)&modelData->data; tVector3 *normals=vertices+modelData->vertexCount; tVector2 *texels=(tVector2*)(normals+modelData->normalCount); tFaceData *faces=(tFaceData*)(texels+modelData->texelCount); tMaterial *materials=(tMaterial*)(faces+modelData->faceCount); if(modelData->modelFlags&kFlagMultiTextureFlag) materials=(tMaterial*)((tFaceDataMT*)faces+modelData->faceCount); for(int i=0;imaterialCount;i++) materials[i].m.texRef=FileGetReference(materials[i].texName); } void StoreFaceVertices(tVector3 *vertices,tVector3 *normals,tVector2 *texels,tFaceData *faces,int i,tVertexArrayElement *store,int mt) { if(mt) if(((tFaceDataMT*)faces)[i].vertices->normal!=-1) for(int vertex=0;vertex<3;vertex++){ if(((tFaceDataMT*)faces)[i].vertices->texel!=-1) store[0][vertex].texel=texels[((tFaceDataMT*)faces)[i].vertices[vertex].texel]; else store[0][vertex].texel=Vector(0,0); if(((tFaceDataMT*)faces)[i].vertices->texel2!=-1) store[0][vertex].texel2=texels[((tFaceDataMT*)faces)[i].vertices[vertex].texel2]; else store[0][vertex].texel2=Vector(0,0); store[0][vertex].normal=normals[((tFaceDataMT*)faces)[i].vertices[vertex].normal]; store[0][vertex].vertex=vertices[((tFaceDataMT*)faces)[i].vertices[vertex].vertex]; } else{ //otherwise, calculate a normal. tVector3 *a=vertices+(((tFaceDataMT*)faces)[i].vertices[0].vertex); tVector3 *b=vertices+(((tFaceDataMT*)faces)[i].vertices[1].vertex); tVector3 *c=vertices+(((tFaceDataMT*)faces)[i].vertices[2].vertex); tVector3 n=!((*b-*a)%(*c-*a)); for(int vertex=0;vertex<3;vertex++) { if(((tFaceDataMT*)faces)[i].vertices->texel!=-1) store[0][vertex].texel=texels[((tFaceDataMT*)faces)[i].vertices[vertex].texel]; else store[0][vertex].texel=Vector(0,0); if(((tFaceDataMT*)faces)[i].vertices->texel2!=-1) store[0][vertex].texel2=texels[((tFaceDataMT*)faces)[i].vertices[vertex].texel2]; else store[0][vertex].texel2=Vector(0,0); store[0][vertex].normal=n; store[0][vertex].vertex=vertices[((tFaceDataMT*)faces)[i].vertices[vertex].vertex]; } } else if(faces[i].vertices->normal!=-1) for(int vertex=0;vertex<3;vertex++){ if(faces[i].vertices->texel!=-1) store[0][vertex].texel=texels[faces[i].vertices[vertex].texel]; else store[0][vertex].texel=Vector(0,0); store[0][vertex].normal=normals[faces[i].vertices[vertex].normal]; store[0][vertex].vertex=vertices[faces[i].vertices[vertex].vertex]; } else{ //otherwise, calculate a normal. tVector3 *a=vertices+(faces[i].vertices[0].vertex); tVector3 *b=vertices+(faces[i].vertices[1].vertex); tVector3 *c=vertices+(faces[i].vertices[2].vertex); tVector3 n=!((*b-*a)%(*c-*a)); for(int vertex=0;vertex<3;vertex++) { if(faces[i].vertices->texel!=-1) store[0][vertex].texel=texels[faces[i].vertices[vertex].texel]; else store[0][vertex].texel=Vector(0,0); store[0][vertex].normal=n; store[0][vertex].vertex=vertices[faces[i].vertices[vertex].vertex]; } } } void ModelInitArrays(tFileRef modelRef) { tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data; int mt=modelData->modelFlags&kFlagMultiTextureFlag; tVector3 *vertices=(tVector3*)&modelData->data; tVector3 *normals=vertices+modelData->vertexCount; tVector2 *texels=(tVector2*)(normals+modelData->normalCount); tFaceData *faces=(tFaceData*)(texels+modelData->texelCount); tFaceDataMT *facesMT=(tFaceDataMT*)(texels+modelData->texelCount); tMaterial *materials=(tMaterial*)(faces+modelData->faceCount); if(mt) materials=(tMaterial*)(facesMT+modelData->faceCount); int matCount=mt?modelData->materialCount/2:modelData->materialCount; ((tModel*)gFileTable[modelRef].parsedData)->indices=(tMaterialArrayIndices*)MemoryAllocateZeroedBlock(sizeof(tMaterialArrayIndices)*matCount); tMaterialArrayIndices *indices=((tModel*)gFileTable[modelRef].parsedData)->indices; ((tModel*)gFileTable[modelRef].parsedData)->array=(tVertexArrayElement*)MemoryAllocateBlock(sizeof(tVertexArrayElement)*modelData->faceCount); tVertexArrayElement *array=((tModel*)gFileTable[modelRef].parsedData)->array; //arrays are indexed starting with 1, so we shift all arrays //down by one index. vertices--; normals--; texels--; materials--; //for each face for(int i=0;ifaceCount;i++) { int mat=mt?facesMT[i].material:faces[i].material; int faceMaterial=mat&kMaterialMask; if(faceMaterial!=-1&&faceMaterial!=0) if((!(materials[faceMaterial].m.flags&kMaterialUseAlphaChannel))||mat&kDisableTransparencyFlag) indices[faceMaterial-1].num++; else indices[faceMaterial-1].numTransparent++; } int arrayVertexCount=0; for(int material=1;material<=matCount;material++) { indices[material-1].start=arrayVertexCount; for(int i=0;ifaceCount;i++) { int mat=mt?facesMT[i].material:faces[i].material; int faceMaterial=mat&kMaterialMask; if(material==faceMaterial) if((!(materials[faceMaterial].m.flags&kMaterialUseAlphaChannel))||mat&kDisableTransparencyFlag) StoreFaceVertices(vertices,normals,texels,faces,i,array+arrayVertexCount++,mt); } for(int i=0;ifaceCount;i++) { int mat=mt?facesMT[i].material:faces[i].material; int faceMaterial=mat&kMaterialMask; if(material==faceMaterial) if(materials[faceMaterial].m.flags&kMaterialUseAlphaChannel&&!(mat&kDisableTransparencyFlag)) StoreFaceVertices(vertices,normals,texels,faces,i,array+arrayVertexCount++,mt); } } glGenVertexArraysAPPLE(1,&(((tModel*)gFileTable[modelRef].parsedData)->arrayRef)); glBindVertexArrayAPPLE(((tModel*)gFileTable[modelRef].parsedData)->arrayRef); glInterleavedArrays(GL_T2F_N3F_V3F,sizeof(tVertexArrayVertex),array); if(mt){ glClientActiveTextureARB(GL_TEXTURE1_ARB); glTexCoordPointer(2,GL_FLOAT,sizeof(tVertexArrayVertex),((char*)array)+sizeof(tVector2)+2*sizeof(tVector3)); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTextureARB(GL_TEXTURE0_ARB); } } enum{ kModeDrawNormal, kModeDrawEverythingSolid, kModeDrawOnlyTransparent, kModeDrawOnlyTransparentSolid, kModeDrawOnlySolid, kModeDrawEverythingGhosted }; void ModelAddGhostedArrays(tFileRef modelRef,int textureSet) { tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data; tVector3 *vertices=(tVector3*)&modelData->data; tVector3 *normals=vertices+modelData->vertexCount; tVector2 *texels=(tVector2*)(normals+modelData->normalCount); tFaceData *faces=(tFaceData*)(texels+modelData->texelCount); tMaterial *materials=(tMaterial*)(faces+modelData->faceCount); tMaterialArrayIndices *indices=((tModel*)gFileTable[modelRef].parsedData)->indices; tVertexArrayElement *array=((tModel*)gFileTable[modelRef].parsedData)->array; //arrays are indexed starting with 1, so we shift all arrays //down by one index. materials--; for(int i=0;imaterialCount;i++) for(int j=indices[i].start;jmat=&(materials+i+1)->m; p->ghost=true; p->textureSet=textureSet; for(int v=0;v<3;v++) { p->v[v]=array[j][v]; p->v[v].vertex=p->v[v].vertex*gTransformDir+gTransformPos; } } } void ModelAddTransparentArrays(tFileRef modelRef,int textureSet) { tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data; tVector3 *vertices=(tVector3*)&modelData->data; tVector3 *normals=vertices+modelData->vertexCount; tVector2 *texels=(tVector2*)(normals+modelData->normalCount); tFaceData *faces=(tFaceData*)(texels+modelData->texelCount); tMaterial *materials=(tMaterial*)(faces+modelData->faceCount); tMaterialArrayIndices *indices=((tModel*)gFileTable[modelRef].parsedData)->indices; tVertexArrayElement *array=((tModel*)gFileTable[modelRef].parsedData)->array; //arrays are indexed starting with 1, so we shift all arrays //down by one index. materials--; for(int i=0;imaterialCount;i++) for(int j=indices[i].start+indices[i].num;jmat=&(materials+i+1)->m; p->textureSet=textureSet; for(int v=0;v<3;v++) { p->v[v]=array[j][v]; p->v[v].normal=p->v[v].normal*gTransformDir; p->v[v].vertex=p->v[v].vertex*gTransformDir+gTransformPos; } } } void ModelDrawArrays(tFileRef modelRef,int mode,int textureSet) { tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data; int mt=modelData->modelFlags&kFlagMultiTextureFlag; tVector3 *vertices=(tVector3*)&modelData->data; tVector3 *normals=vertices+modelData->vertexCount; tVector2 *texels=(tVector2*)(normals+modelData->normalCount); tFaceData *faces=(tFaceData*)(texels+modelData->texelCount); tFaceDataMT *facesMT=(tFaceDataMT*)(texels+modelData->texelCount); tMaterial *materials=(tMaterial*)(faces+modelData->faceCount); if(mt) materials=(tMaterial*)(facesMT+modelData->faceCount); int matCount=mt?modelData->materialCount/2:modelData->materialCount; tMaterialArrayIndices *indices=((tModel*)gFileTable[modelRef].parsedData)->indices; //arrays are indexed starting with 1, so we shift all arrays //down by one index. materials--; glBindVertexArrayAPPLE(((tModel*)gFileTable[modelRef].parsedData)->arrayRef); //glInterleavedArrays(GL_T2F_N3F_V3F,0,((tModel*)gFileTable[modelRef].parsedData)->array); //glLockArraysEXT(0,modelData->faceCount*3); /* if(TexturesSelectTextureUnit(1)) { glTexCoordPointer(2,GL_FLOAT,sizeof(tVertexArrayVertex),((char*)((tModel*)gFileTable[modelRef].parsedData)->array)+sizeof(tVector2)+2*sizeof(tVector3)); glEnableClientState(GL_TEXTURE_COORD_ARRAY); TexturesSelectTextureUnit(0); } glTexCoordPointer(2,GL_FLOAT,sizeof(tVertexArrayVertex),((char*)((tModel*)gFileTable[modelRef].parsedData)->array)); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glNormalPointer(GL_FLOAT,sizeof(tVertexArrayVertex),((char*)((tModel*)gFileTable[modelRef].parsedData)->array)+sizeof(tVector2)); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3,GL_FLOAT,sizeof(tVertexArrayVertex),((char*)((tModel*)gFileTable[modelRef].parsedData)->array)+sizeof(tVector2)+sizeof(tVector3)); glEnableClientState(GL_VERTEX_ARRAY);*/ if(mode!=kModeDrawOnlyTransparent) for(int i=0;im),(&(materials+i+1+matCount)->m),textureSet); else UseMaterial((&(materials+i+1)->m),false,textureSet); glDrawArrays(GL_TRIANGLES,start*3,num*3); } //glUnlockArraysEXT(); if((mode==kModeDrawNormal||mode==kModeDrawOnlyTransparent)&&!mt) ModelAddTransparentArrays(modelRef,textureSet); } void ModelCompileDisplayList(tFileRef modelRef); void ModelCalcClipInfo(tFileRef modelRef) { tVector3 minv=Vector(INFINITY,INFINITY,INFINITY); tVector3 maxv=Vector(-INFINITY,-INFINITY,-INFINITY); tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data; tVector3 *vertices=(tVector3*)&modelData->data; for(int i=0;ivertexCount;i++) { if(vertices[i].xmaxv.x)maxv.x=vertices[i].x; if(vertices[i].y>maxv.y)maxv.y=vertices[i].y; if(vertices[i].z>maxv.z)maxv.z=vertices[i].z; } if(modelData->vertexCount) { ((tModel*)gFileTable[modelRef].parsedData)->center=(minv+maxv)*0.5; ((tModel*)gFileTable[modelRef].parsedData)->centerMaxExtends=~(minv-((tModel*)gFileTable[modelRef].parsedData)->center); } else { ((tModel*)gFileTable[modelRef].parsedData)->center=Vector(0,0,0); ((tModel*)gFileTable[modelRef].parsedData)->centerMaxExtends=0; } } void ModelSwitchEndianess(tFileRef modelRef) { tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data; S32Swap(modelData->vertexCount); S32Swap(modelData->normalCount); S32Swap(modelData->faceCount); S32Swap(modelData->materialCount); S32Swap(modelData->modelFlags); S32Swap(modelData->texelCount); S32Swap(*((SInt32*)(&modelData->maxExtends))); int mt=modelData->modelFlags&kFlagMultiTextureFlag; tVector3 *vertices=(tVector3*)&modelData->data; tVector3 *normals=vertices+modelData->vertexCount; tVector2 *texels=(tVector2*)(normals+modelData->normalCount); tFaceData *faces=(tFaceData*)(texels+modelData->texelCount); tFaceDataMT *facesMT=(tFaceDataMT*)(texels+modelData->texelCount); tMaterial *materials=(tMaterial*)(faces+modelData->faceCount); if(mt) materials=(tMaterial*)(facesMT+modelData->faceCount); for(int i=0;ivertexCount;i++) { S32Swap(*((SInt32*)(&(vertices[i].x)))); S32Swap(*((SInt32*)(&(vertices[i].y)))); S32Swap(*((SInt32*)(&(vertices[i].z)))); } for(int i=0;inormalCount;i++) { S32Swap(*((SInt32*)(&(normals[i].x)))); S32Swap(*((SInt32*)(&(normals[i].y)))); S32Swap(*((SInt32*)(&(normals[i].z)))); } for(int i=0;itexelCount;i++) { S32Swap(*((SInt32*)(&(texels[i].x)))); S32Swap(*((SInt32*)(&(texels[i].y)))); } if(mt) for(int i=0;ifaceCount;i++) { S32Swap(facesMT[i].material); for(int j=0;j<3;j++) { S32Swap(facesMT[i].vertices[j].vertex); S32Swap(facesMT[i].vertices[j].normal); S32Swap(facesMT[i].vertices[j].texel); S32Swap(facesMT[i].vertices[j].texel2); S32Swap(facesMT[i].vertices[j].neighbor); } } else for(int i=0;ifaceCount;i++) { S32Swap(faces[i].material); for(int j=0;j<3;j++) { S32Swap(faces[i].vertices[j].vertex); S32Swap(faces[i].vertices[j].normal); S32Swap(faces[i].vertices[j].texel); S32Swap(faces[i].vertices[j].neighbor); } } for(int i=0;imaterialCount;i++) { S32Swap(materials[i].m.flags); S32Swap(*((SInt32*)(&(materials[i].m.shininess)))); S32Swap(*((SInt32*)(&(materials[i].m.specular.x)))); S32Swap(*((SInt32*)(&(materials[i].m.specular.y)))); S32Swap(*((SInt32*)(&(materials[i].m.specular.z)))); S32Swap(*((SInt32*)(&(materials[i].m.ambient.x)))); S32Swap(*((SInt32*)(&(materials[i].m.ambient.y)))); S32Swap(*((SInt32*)(&(materials[i].m.ambient.z)))); S32Swap(*((SInt32*)(&(materials[i].m.diffuse.x)))); S32Swap(*((SInt32*)(&(materials[i].m.diffuse.y)))); S32Swap(*((SInt32*)(&(materials[i].m.diffuse.z)))); } } //Load a model from disk void ModelLoad(tFileRef modelRef) { gFileTable[modelRef].parsedData=MemoryAllocateBlock(sizeof(tModel)); ((tModel*)gFileTable[modelRef].parsedData)->data=(tModelData*)FileGetDataPtr(modelRef); #if TARGET_RT_LITTLE_ENDIAN ModelSwitchEndianess(modelRef); #endif ModelInsertTextureRefs(modelRef); #ifdef __USEVERTEXARRAYS ModelInitArrays(modelRef); #endif #ifdef __USEDISPLAYLISTS ModelCompileDisplayList(modelRef); #endif gFileTable[modelRef].parsed=true; ModelCalcClipInfo(modelRef); tModelList *modelList=gModelList; gModelList=(tModelList*)MemoryAllocateBlock(sizeof(tModelList)); gModelList->next=(void*)modelList; gModelList->model=modelRef; } tVector3 ModelGetCenter(tFileRef modelRef) { if(!gFileTable[modelRef].parsed) ModelLoad(modelRef); return ((tModel*)gFileTable[modelRef].parsedData)->center; } float ModelGetCenterMaxExtends(tFileRef modelRef) { if(!gFileTable[modelRef].parsed) ModelLoad(modelRef); return ((tModel*)gFileTable[modelRef].parsedData)->centerMaxExtends; } //Dispose all data structures associated with a model. void ModelDispose(tFileRef modelRef) { MemoryFreeBlock(((tModel*)gFileTable[modelRef].parsedData)->data); MemoryFreeBlock(((tModel*)gFileTable[modelRef].parsedData)->indices); MemoryFreeBlock(((tModel*)gFileTable[modelRef].parsedData)->array); if(gFileTable[modelRef].data!=((tModel*)gFileTable[modelRef].parsedData)->data) MemoryFreeBlock(gFileTable[modelRef].data); #ifdef __USEDISPLAYLISTS glDeleteLists(((tModel*)gFileTable[modelRef].parsedData)->ref,1); #endif glDeleteVertexArraysAPPLE(1,&((tModel*)gFileTable[modelRef].parsedData)->arrayRef); MemoryFreeBlock(((tModel*)gFileTable[modelRef].parsedData)); gFileTable[modelRef].parsed=false; gFileTable[modelRef].loaded=false; } void ModelsUnloadAll() { while(gModelList!=NULL) { tModelList *next=(tModelList*)gModelList->next; ModelDispose(gModelList->model); MemoryFreeBlock(gModelList); gModelList=next; } } //return the maximum extends of a model. (the distance from //the furthest vertex from center). float ModelGetMaxExtends(tFileRef modelRef) { if(!gFileTable[modelRef].parsed) ModelLoad(modelRef); if(!gFileTable[modelRef].parsed) return 0; tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data; if(!modelData->maxExtends) { tVector3 *vertices=(tVector3*)&modelData->data; tVector3 maxExtends=Vector(0,0,0); for(int i=0;ivertexCount;i++) { if(fabs(vertices[i].x)>maxExtends.x)maxExtends.x=fabs(vertices[i].x); if(fabs(vertices[i].y)>maxExtends.y)maxExtends.y=fabs(vertices[i].y); if(fabs(vertices[i].z)>maxExtends.z)maxExtends.z=fabs(vertices[i].z); } modelData->maxExtends=~maxExtends; } return modelData->maxExtends; } //Draw a model void ModelDraw(tFileRef modelRef,int mode,int textureSet) { tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data; tVector3 *vertices=(tVector3*)&modelData->data; tVector3 *normals=vertices+modelData->vertexCount; tVector2 *texels=(tVector2*)(normals+modelData->normalCount); tFaceData *faces=(tFaceData*)(texels+modelData->texelCount); tMaterial *materials=(tMaterial*)(faces+modelData->faceCount); //arrays are indexed starting with 1, so we shift all arrays //down by one index. vertices--; normals--; texels--; materials--; int material=-1;//currently used material int transparent; //for each face for(int i=0;ifaceCount;i++) { int faceMaterial=faces[i].material&kMaterialMask; //check if the material is the same as we were using if(faceMaterial!=material){ //if not, change material transparent=UseMaterial(&((materials+faceMaterial)->m),false,textureSet); if(mode==kModeDrawEverythingSolid) transparent=false; material=faceMaterial; } //if the face isn't transparent, draw it int drawTransparent=transparent&&!(faces[i].material&kDisableTransparencyFlag); if(!drawTransparent||(drawTransparent&&mode==kModeDrawOnlyTransparentSolid)) { if(mode!=kModeDrawOnlyTransparent) { glBegin(GL_TRIANGLES); //do we have a normal? if(faces[i].vertices->normal!=-1) for(int vertex=0;vertex<3;vertex++){ if(faces[i].vertices->texel!=-1) glTexCoord2fv(&texels[faces[i].vertices[vertex].texel].x); glNormal3fv(&normals[faces[i].vertices[vertex].normal].x); glVertex3fv(&vertices[faces[i].vertices[vertex].vertex].x); } else{ //otherwise, calculate a normal. tVector3 *a=vertices+(faces[i].vertices[0].vertex); tVector3 *b=vertices+(faces[i].vertices[1].vertex); tVector3 *c=vertices+(faces[i].vertices[2].vertex); tVector3 n=!((*b-*a)%(*c-*a)); glNormal3fv(&n.x); for(int vertex=0;vertex<3;vertex++) { if(faces[i].vertices->texel!=-1) glTexCoord2fv(&texels[faces[i].vertices[vertex].texel].x); glVertex3fv(&vertices[faces[i].vertices[vertex].vertex].x); } } glEnd(); } } //if the face is transparent, add it to the list of transparent faces else if(mode!=kModeDrawOnlySolid) if(tTransparentPoly *p=GetNextTransparentPoly(false)){ if(faces[i].vertices->normal!=-1) for(int vertex=0;vertex<3;vertex++){ if(faces[i].vertices->texel!=-1) p->v[vertex].texel=texels[faces[i].vertices[vertex].texel]; else p->v[vertex].texel=Vector(0,0); p->v[vertex].normal=normals[faces[i].vertices[vertex].normal]*gTransformDir; p->v[vertex].vertex=vertices[faces[i].vertices[vertex].vertex]*gTransformDir+gTransformPos; } else{ tVector3 *a=vertices+(faces[i].vertices[0].vertex); tVector3 *b=vertices+(faces[i].vertices[1].vertex); tVector3 *c=vertices+(faces[i].vertices[2].vertex); tVector3 n=!((*b-*a)%(*c-*a)); for(int vertex=0;vertex<3;vertex++) { if(faces[vertex].vertices->texel!=-1) p->v[vertex].texel=texels[faces[i].vertices[vertex].texel]; else p->v[vertex].texel=Vector(0,0); p->v[vertex].normal=n*gTransformDir; p->v[vertex].vertex=vertices[faces[i].vertices[vertex].vertex]*gTransformDir+gTransformPos; } } p->mat=&(materials+faces[i].material)->m; p->textureSet=textureSet; } } } void ModelDrawMultiTextured(tFileRef modelRef,int textureSet) { tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data; tVector3 *vertices=(tVector3*)&modelData->data; tVector3 *normals=vertices+modelData->vertexCount; tVector2 *texels=(tVector2*)(normals+modelData->normalCount); tFaceDataMT *faces=(tFaceDataMT*)(texels+modelData->texelCount); tMaterial *materials=(tMaterial*)(faces+modelData->faceCount); //arrays are indexed starting with 1, so we shift all arrays //down by one index. vertices--; normals--; texels--; materials--; int material=-1;//currently used material //for each face for(int i=0;ifaceCount;i++) { int faceMaterial=faces[i].material&kMaterialMask; //check if the material is the same as we were using if(faceMaterial!=material){ //if not, change material UseMaterial2(&((materials+faceMaterial)->m),&((materials+faceMaterial+modelData->materialCount/2)->m),textureSet); material=faceMaterial; } glBegin(GL_TRIANGLES); //do we have a normal? if(faces[i].vertices->normal!=-1) for(int vertex=0;vertex<3;vertex++){ if(faces[i].vertices->texel!=-1) glTexCoord2fv(&texels[faces[i].vertices[vertex].texel].x); if(faces[i].vertices->texel2!=-1) glMultiTexCoord2fv(GL_TEXTURE1,&texels[faces[i].vertices[vertex].texel2].x); glNormal3fv(&normals[faces[i].vertices[vertex].normal].x); glVertex3fv(&vertices[faces[i].vertices[vertex].vertex].x); } else{ //otherwise, calculate a normal. tVector3 *a=vertices+(faces[i].vertices[0].vertex); tVector3 *b=vertices+(faces[i].vertices[1].vertex); tVector3 *c=vertices+(faces[i].vertices[2].vertex); tVector3 n=!((*b-*a)%(*c-*a)); glNormal3fv(&n.x); for(int vertex=0;vertex<3;vertex++) { if(faces[i].vertices->texel!=-1) glTexCoord2fv(&texels[faces[i].vertices[vertex].texel].x); if(faces[i].vertices->texel2!=-1) glMultiTexCoord2fv(GL_TEXTURE1,&texels[faces[i].vertices[vertex].texel2].x); glVertex3fv(&vertices[faces[i].vertices[vertex].vertex].x); } } glEnd(); } } void ModelLoadTextures(tFileRef modelRef) { tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data; tVector3 *vertices=(tVector3*)&modelData->data; tVector3 *normals=vertices+modelData->vertexCount; tVector2 *texels=(tVector2*)(normals+modelData->normalCount); tFaceData *faces=(tFaceData*)(texels+modelData->texelCount); tMaterial *materials=(tMaterial*)(faces+modelData->faceCount); for(int i=0;imaterialCount;i++) UseMaterial(&((materials+i)->m),false,0); } void ModelCompileDisplayList(tFileRef modelRef) { //create an OpenGL display list for a model ((tModel*)gFileTable[modelRef].parsedData)->ref=glGenLists(1); ModelLoadTextures(modelRef); glNewList(((tModel*)gFileTable[modelRef].parsedData)->ref,GL_COMPILE); #ifdef __USEVERTEXARRAYS ModelDrawArrays(modelRef,kModeDrawOnlySolid,0); #else ModelDraw(modelRef,kModeDrawOnlySolid,0); #endif glEndList(); } void ModelShadowPassZFail(tFileRef modelRef,tVector3 shadowVector,char *faceSide) { tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data; tVector3 *vertices=(tVector3*)&modelData->data; tVector3 *normals=vertices+modelData->vertexCount; tVector2 *texels=(tVector2*)(normals+modelData->normalCount); vertices--; tFaceData *faces=(tFaceData*)(texels+modelData->texelCount); tMaterial *materials=(tMaterial*)(faces+modelData->faceCount); materials--; tVector3 sw=0.05*!shadowVector; for(int i=0;ifaceCount;i++) if(!((materials+(faces[i].material&kMaterialMask))->m.flags&kMaterialDisableShadow)) if(modelData->modelFlags&kFlagShadowFlag) { for(int n=0;n<3;n++) if(faces[i].vertices[n].neighbor<=-1) { glBegin(GL_TRIANGLE_STRIP); mVertex3fv((vertices[faces[i].vertices[n].vertex]*gStencilZoom-sw)); mVertex3fv((vertices[faces[i].vertices[(n+1)%3].vertex]*gStencilZoom-sw)); mVertex3fv((vertices[faces[i].vertices[n].vertex]*gStencilZoom-shadowVector)); mVertex3fv((vertices[faces[i].vertices[(n+1)%3].vertex]*gStencilZoom-shadowVector)); glEnd(); #ifdef __POLYCOUNT gPolyCount+=2; #endif } if(faceSide[i]||1) { glBegin(GL_TRIANGLES); for(int j=2;j>=0;j--) mVertex3fv((vertices[faces[i].vertices[j].vertex]*gStencilZoom-sw)); for(int j=0;j<=2;j++) mVertex3fv((vertices[faces[i].vertices[j].vertex]*gStencilZoom-shadowVector)); glEnd(); } else { glBegin(GL_TRIANGLES); for(int j=2;j>=0;j--) mVertex3fv((vertices[faces[i].vertices[j].vertex]*gStencilZoom-shadowVector)); for(int j=0;j<=2;j++) mVertex3fv((vertices[faces[i].vertices[j].vertex]*gStencilZoom-sw)); glEnd(); } } else if(faceSide[i]) { for(int n=0;n<3;n++) if(faces[i].vertices[n].neighbor!=-1) { if(faceSide[faces[i].vertices[n].neighbor]!=faceSide[i]) { glBegin(GL_TRIANGLE_STRIP); mVertex3fv((vertices[faces[i].vertices[n].vertex]*(kShadowZoom*gStencilZoom))); mVertex3fv((vertices[faces[i].vertices[(n+1)%3].vertex]*(kShadowZoom*gStencilZoom))); mVertex3fv((vertices[faces[i].vertices[n].vertex]*(kShadowZoom*gStencilZoom)-shadowVector)); mVertex3fv((vertices[faces[i].vertices[(n+1)%3].vertex]*(kShadowZoom*gStencilZoom)-shadowVector)); glEnd(); #ifdef __POLYCOUNT gPolyCount+=2; #endif } } glBegin(GL_TRIANGLES); for(int j=2;j>=0;j--) mVertex3fv((vertices[faces[i].vertices[j].vertex]*(kShadowZoom*gStencilZoom))); glEnd(); } else { glBegin(GL_TRIANGLES); for(int j=2;j>=0;j--) mVertex3fv((vertices[faces[i].vertices[j].vertex]*(kShadowZoom*gStencilZoom)-shadowVector)); glEnd(); } #ifdef __POLYCOUNT gPolyCount+=modelData->faceCount; #endif } void ModelShadowPassZPass(tFileRef modelRef,tVector3 shadowVector,char *faceSide) { tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data; tVector3 *vertices=(tVector3*)&modelData->data; tVector3 *normals=vertices+modelData->vertexCount; tVector2 *texels=(tVector2*)(normals+modelData->normalCount); vertices--; tFaceData *faces=(tFaceData*)(texels+modelData->texelCount); tMaterial *materials=(tMaterial*)(faces+modelData->faceCount); materials--; if(modelData->modelFlags&kFlagShadowFlag) { tVector3 sw=0.05*!shadowVector; for(int i=0;ifaceCount;i++) if(!((materials+(faces[i].material&kMaterialMask))->m.flags&kMaterialDisableShadow)) { for(int n=0;n<3;n++) if(faces[i].vertices[n].neighbor==-1) { glBegin(GL_TRIANGLE_STRIP); mVertex3fv((vertices[faces[i].vertices[n].vertex]*gStencilZoom-sw)); mVertex3fv((vertices[faces[i].vertices[(n+1)%3].vertex]*gStencilZoom-sw)); mVertex3fv((vertices[faces[i].vertices[n].vertex]*gStencilZoom-shadowVector)); mVertex3fv((vertices[faces[i].vertices[(n+1)%3].vertex]*gStencilZoom-shadowVector)); glEnd(); #ifdef __POLYCOUNT gPolyCount+=2; #endif } } } else for(int i=0;ifaceCount;i++) if(!((materials+(faces[i].material&kMaterialMask))->m.flags&kMaterialDisableShadow)) if(faceSide[i]||(modelData->modelFlags&kFlagShadowFlag)) for(int n=0;n<3;n++) if(faces[i].vertices[n].neighbor!=-1) if(faceSide[faces[i].vertices[n].neighbor]!=faceSide[i]) { glBegin(GL_TRIANGLE_STRIP); mVertex3fv((vertices[faces[i].vertices[n].vertex]*(kShadowZoom*gStencilZoom))); mVertex3fv((vertices[faces[i].vertices[(n+1)%3].vertex]*(kShadowZoom*gStencilZoom))); mVertex3fv((vertices[faces[i].vertices[n].vertex]*(kShadowZoom*gStencilZoom)-shadowVector)); mVertex3fv((vertices[faces[i].vertices[(n+1)%3].vertex]*(kShadowZoom*gStencilZoom)-shadowVector)); glEnd(); #ifdef __POLYCOUNT gPolyCount+=2; #endif } } //for each face of a model, calculate whether it faces the light or not. //return the results in the array faceSide void CalcFaceSides(tFileRef modelRef,tVector3 lightDir,char **faceSide) { tModelData *modelData=((tModel*)gFileTable[modelRef].parsedData)->data; tVector3 *vertices=(tVector3*)&modelData->data; tVector3 *normals=vertices+modelData->vertexCount; tVector2 *texels=(tVector2*)(normals+modelData->normalCount); vertices--; tFaceData *faces=(tFaceData*)(texels+modelData->texelCount); *faceSide=(char*)MemoryAllocateBlock(sizeof(char)*modelData->faceCount+10); for(int i=0;ifaceCount;i++){ tVector3 *a=vertices+(faces[i].vertices[0].vertex); tVector3 *b=vertices+(faces[i].vertices[1].vertex); tVector3 *c=vertices+(faces[i].vertices[2].vertex); //calculate a normal to the face tVector3 n=((*b-*a)%(*c-*a)); //use dot product to determine if the face faces the light (*faceSide)[i]=n*lightDir>0; } } //Draw the shadow of a model //Uses s stencil buffer-based shadow volume algorithm void ModelCastShadow(tFileRef modelRef,float shadowLength) { tVector3 lightDir=gEnvironment->lightDir; if(gMapEnv) if(!VectorZero(gMapEnv->lightDir)) lightDir=gMapEnv->lightDir; tMatrix3 tr; MatrixTranspose(gTransformDir,tr); lightDir=lightDir*tr; char *faceSide; CalcFaceSides(modelRef,lightDir,&faceSide); //disable actual drawing glDisable(GL_LIGHTING); glDisable(GL_FOG); glDepthMask(GL_FALSE); glColorMask(0, 0, 0, 0); //enable stencil buffer drawing glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 0, 0xffffffff); tVector3 lightNormal1=!((gTransformPos-gCameraEntity->pos)%lightDir); tVector3 lightNormal2=lightNormal1%lightDir; tVector3 shadowVector=lightDir*shadowLength; //is the camera possibly in the shadow volume? if(-lightNormal2*(gTransformPos-gCameraEntity->pos)ref); #ifdef __USEVERTEXARRAYS ModelDrawArrays(modelRef,allowTransparency?kModeDrawOnlyTransparent:kModeDrawOnlyTransparentSolid,textureSet); #else ModelDraw(modelRef,allowTransparency?kModeDrawOnlyTransparent:kModeDrawOnlyTransparentSolid,textureSet); #endif #else #ifdef __USEVERTEXARRAYS if(allowTransparency==kTransparencyGhost) ModelAddGhostedArrays(modelRef,textureSet); else ModelDrawArrays(modelRef,allowTransparency?kModeDrawNormal:kModeDrawEverythingSolid,textureSet); #else if((((tModel*)gFileTable[modelRef].parsedData)->data)->modelFlags&kFlagMultiTextureFlag) ModelDrawMultiTextured(modelRef,textureSet); else ModelDraw(modelRef,allowTransparency?kModeDrawNormal:kModeDrawEverythingSolid,textureSet); #endif #endif #ifdef __POLYCOUNT gPolyCount+=((tModelData*)((tModel*)gFileTable[modelRef].parsedData)->data)->faceCount; #endif if(TexturesSelectTextureUnit(1)){ glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_3D); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); TexturesSelectTextureUnit(0); } } //draw a model's shadow void DrawModelShadow(tFileRef modelRef,float shadowLength) { if(!gFileTable[modelRef].parsed) ModelLoad(modelRef); if(!gFileTable[modelRef].parsed) return; if((((tModel*)gFileTable[modelRef].parsedData)->data)->modelFlags&kFlagMultiTextureFlag) return; if(shadowLength>0) ModelCastShadow(modelRef,shadowLength); }