Redline/source/models.cpp

998 lines
34 KiB
C++
Raw Normal View History

//models.cpp
//3d model drawing code
#include <stdio.h>
#include <string.h>
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#include <math.h>
#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"
2016-04-02 15:18:11 +00:00
#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;i<modelData->materialCount;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;i<modelData->faceCount;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;i<modelData->faceCount;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;i<modelData->faceCount;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;i<modelData->materialCount;i++)
for(int j=indices[i].start;j<indices[i].start+indices[i].num+indices[i].numTransparent;j++)
if(tTransparentPoly *p=GetNextTransparentPoly(false))
{
p->mat=&(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;i<modelData->materialCount;i++)
for(int j=indices[i].start+indices[i].num;j<indices[i].start+indices[i].num+indices[i].numTransparent;j++)
if(tTransparentPoly *p=GetNextTransparentPoly(false))
{
p->mat=&(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;i<matCount;i++)
{
int start=indices[i].start;
if(mode==kModeDrawOnlyTransparentSolid)
start+=indices[i].num;
int num;
if(mode==kModeDrawNormal||mode==kModeDrawOnlySolid)
num=indices[i].num;
else if(mode==kModeDrawOnlyTransparentSolid)
num=indices[i].numTransparent;
else if(mode==kModeDrawEverythingSolid)
num=indices[i].num+indices[i].numTransparent;
if(mt)
UseMaterial2((&(materials+i+1)->m),(&(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;i<modelData->vertexCount;i++)
{
if(vertices[i].x<minv.x)minv.x=vertices[i].x;
if(vertices[i].y<minv.y)minv.y=vertices[i].y;
if(vertices[i].z<minv.z)minv.z=vertices[i].z;
if(vertices[i].x>maxv.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;i<modelData->vertexCount;i++)
{
S32Swap(*((SInt32*)(&(vertices[i].x))));
S32Swap(*((SInt32*)(&(vertices[i].y))));
S32Swap(*((SInt32*)(&(vertices[i].z))));
}
for(int i=0;i<modelData->normalCount;i++)
{
S32Swap(*((SInt32*)(&(normals[i].x))));
S32Swap(*((SInt32*)(&(normals[i].y))));
S32Swap(*((SInt32*)(&(normals[i].z))));
}
for(int i=0;i<modelData->texelCount;i++)
{
S32Swap(*((SInt32*)(&(texels[i].x))));
S32Swap(*((SInt32*)(&(texels[i].y))));
}
if(mt)
for(int i=0;i<modelData->faceCount;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;i<modelData->faceCount;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;i<modelData->materialCount;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;i<modelData->vertexCount;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;i<modelData->faceCount;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;i<modelData->faceCount;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;i<modelData->materialCount;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;i<modelData->faceCount;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);
2016-04-02 15:18:11 +00:00
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--)
2016-04-02 15:18:11 +00:00
mVertex3fv((vertices[faces[i].vertices[j].vertex]*gStencilZoom-sw));
for(int j=0;j<=2;j++)
2016-04-02 15:18:11 +00:00
mVertex3fv((vertices[faces[i].vertices[j].vertex]*gStencilZoom-shadowVector));
glEnd();
}
else
{
glBegin(GL_TRIANGLES);
for(int j=2;j>=0;j--)
2016-04-02 15:18:11 +00:00
mVertex3fv((vertices[faces[i].vertices[j].vertex]*gStencilZoom-shadowVector));
for(int j=0;j<=2;j++)
2016-04-02 15:18:11 +00:00
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);
2016-04-02 15:18:11 +00:00
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--)
2016-04-02 15:18:11 +00:00
mVertex3fv((vertices[faces[i].vertices[j].vertex]*(kShadowZoom*gStencilZoom)));
glEnd();
}
else
{
glBegin(GL_TRIANGLES);
for(int j=2;j>=0;j--)
2016-04-02 15:18:11 +00:00
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;i<modelData->faceCount;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);
2016-04-02 15:18:11 +00:00
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;i<modelData->faceCount;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);
2016-04-02 15:18:11 +00:00
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;i<modelData->faceCount;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)<ModelGetMaxExtends(modelRef)+shadowLength)
{
//if the camera is possibly inside the shadow volume,
//we have to use zFail rendering, as normal zPass rendering
//won't work if the camera is inside the shadow volume.
glFrontFace(GL_CW);
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
ModelShadowPassZFail(modelRef,shadowVector,faceSide);
glFrontFace(GL_CCW);
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
ModelShadowPassZFail(modelRef,shadowVector,faceSide);
}
else
{//zPass Rendering
glFrontFace(GL_CCW);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
ModelShadowPassZPass(modelRef,shadowVector,faceSide);
glFrontFace(GL_CW);
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
ModelShadowPassZPass(modelRef,shadowVector,faceSide);
}
MemoryFreeBlock(faceSide);
glDepthMask(GL_TRUE);
glColorMask(1, 1, 1, 1);
}
//draw a model
void DrawModel(tFileRef modelRef,int allowTransparency,int textureSet)
{
if(!gFileTable[modelRef].parsed)
ModelLoad(modelRef);
if(!gFileTable[modelRef].parsed)
return;
#ifdef __USEDISPLAYLISTS
glCallList(((tModel*)gFileTable[modelRef].parsedData)->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);
}