class DPLRenderer; #include #include "VGCDivLoader.h" using namespace std; hash_map VGCDivLoader::mMaterials; hash_map VGCDivLoader::mTextures; hash_map VGCDivLoader::mRamps; hash_map VGCDivLoader::mObjects; VGCDivLoader::VGCDivLoader() { //Initialize header to defaults mHeaderInfo.precision = PRECISION_32BIT; mHeaderInfo.scale = 1; mHeaderInfo.type = TYPE_GEOMETRY; mHeaderInfo.unit = UNIT_INCHES; //Initialize surface props to defaults mMasterProps.b_material_type = 2; mMasterProps.b_material_name = 0; mMasterProps.decal_offset = 0; mMasterProps.drawmode = 0; mMasterProps.drawmode_width = 1; mMasterProps.f_material_type = 2; mMasterProps.f_material_name = 0; mMasterProps.faceted = 0; mMasterProps.locks = 0; mMasterProps.name = 0; mMasterProps.plane = 0; mMasterProps.specialInst = 0; mMasterProps.vertex_mask = 0; mMasterProps.isImmune = false; mMasterProps.drawSpheres = false; if (mTextures.find("NULL") == mTextures.end()) { DivTexture *tex = new DivTexture; memset(tex,0,sizeof(DivTexture)); tex->name = new char[5]; strcpy_s(tex->name,5,"NULL"); tex->texBuffer = new TexBuffer; tex->texBuffer->height = 1; tex->texBuffer->width = 1; tex->texBuffer->m_buffer = new RGBA*[1]; tex->texBuffer->m_buffer[0] = new RGBA; tex->texBuffer->m_buffer[0]->r = 255; tex->texBuffer->m_buffer[0]->g = 255; tex->texBuffer->m_buffer[0]->b = 255; tex->texBuffer->m_buffer[0]->a = 255; mTextures.insert(std::pair(string("NULL"),tex)); } } VGCDivLoader::~VGCDivLoader() { delete[] mMasterProps.b_material_name; delete[] mMasterProps.name; delete[] mMasterProps.f_material_name; } void VGCDivLoader::parse(LPDIRECT3DDEVICE9 device, char *fileName) { const char BIZ_IDSTR[] = "DIV-BIZ2"; const char VTX_IDSTR[] = "DIV-VTX2"; FILE file; FILE *mFile = &file; if (fopen_s(&mFile, fileName, "rb") != 0) return; char id[8]; fread(&id, 8, 1, mFile); //Compare first 8 bits to make sure it's a biz2 file if (strncmp(id,"DIV-BIZ2",8) != 0) { fclose(mFile); return; } BIZ_IDENTITIES ident; unsigned int len; while(!feof(mFile)) { //Retrieve ID and length of upcoming block getBlock(mFile, ident, len); switch(ident) { case HEADER: parseHeader(mFile, len); break; case TRAILER: //Output code here fclose(mFile); return; case TEXTURE: //This should be a geometry file fseek(mFile,len,SEEK_CUR); break; case MATERIAL: //This should be a geometry file fseek(mFile,len,SEEK_CUR); break; case RAMP: //This should be a geometry file fseek(mFile,len,SEEK_CUR); break; case OBJECT: parseObject(mFile, len, fileName); break; default: //Unknown! Skip it if (!feof(mFile)) { fseek(mFile,len,SEEK_CUR); } break; } } fclose(mFile); } void VGCDivLoader::parseHeader(FILE *file, unsigned int len) { //Set identifiable header props BIZ_IDENTITIES ident; unsigned int nlen; while(len > 0) { len -= getBlock(file, ident,nlen); len -= nlen; switch(ident) { case HDR_VERSION: fread(&mHeaderInfo.verMajor,1,1,file); fread(&mHeaderInfo.verMinor,1,1,file); break; case HDR_DATE: fread(&mHeaderInfo.dateDay,1,1,file); fread(&mHeaderInfo.dateMon,1,1,file); fread(&mHeaderInfo.dateYear,1,1,file); break; case HDR_TIME: fread(&mHeaderInfo.timeHour,1,1,file); fread(&mHeaderInfo.timeMin,1,1,file); break; case HDR_SCALE: fread(&mHeaderInfo.scale,floatSize(),1,file); break; case HDR_PRECISION: char precision; fread(&precision,1,1,file); mHeaderInfo.precision = (FloatPrecision)precision; if (mHeaderInfo.precision == PRECISION_64BIT) { //Don't believe we have any 64 bit files, so fuck it MessageBox(NULL,_T("PANIC 64 BIT"),_T("OH NOES"),MB_OK); std::cout << "PANIC: 64 BIT PRECISION." << std::endl; std::cin.get(); exit(1); } break; case HDR_FILETYPE: char type; fread(&type,1,1,file); mHeaderInfo.type = (FileType)type; break; case HDR_UNIT: char unit; fread(&unit,1,1,file); mHeaderInfo.unit = (Unit)unit; break; default: cout << "UNKNOWN HEADER ENTRY " << ident << endl; } } } TexBuffer *VGCDivLoader::LoadVTXFile(char *fileName, DivTexture *tex) { int len = strlen(fileName) + 5; char *fullFileName = new char[len]; strcpy_s(fullFileName, len, fileName); strcat_s(fullFileName, len, ".VTX"); FILE *texFile; if (fopen_s(&texFile, fullFileName, "rb") != 0) { delete [] fullFileName; return NULL; } delete [] fullFileName; char id[8]; fread(id, 1, 8, texFile); if (strncmp(id, "DIV-VTX2", 8) != 0) { fclose(texFile); return NULL; } unsigned int blen; BIZ_IDENTITIES ident; while(!feof(texFile)) { //Retrieve ID and length of upcoming block getBlock(texFile, ident, blen); switch(ident) { case HEADER: fseek(texFile, blen, SEEK_CUR); break; case VTX_TEX: tex->texBuffer = new TexBuffer; unsigned int nlen; while(blen > 0) { blen -= getBlock(texFile, ident, nlen); blen -= nlen; unsigned char pixelWidth; unsigned char colorSettings; switch(ident) { case VTX_COLOR: fread(&colorSettings, 1, 1, texFile); break; case VTX_SIZE: fread(&pixelWidth, 1, 1, texFile); break; case VTX_DIMENSIONS: fread(&tex->texBuffer->width, 4, 1, texFile); fread(&tex->texBuffer->height, 4, 1, texFile); break; default: if (ident >= 0x68 && ident == 0x68 + colorSettings) { int dataPoints = 1; if (colorSettings & 0x01) { dataPoints++; } if (colorSettings & 0x02) { dataPoints += 2; } int sampleSize = 1; if (pixelWidth != 0x01) { MessageBox(NULL, _T("PANIC: UNEXPECTED SAMPLE SIZE FOR TEX"), _T("PROBLEM"), MB_OK); } int tLen = nlen / (dataPoints * sampleSize); tex->texBuffer->m_buffer = new RGBA*[tex->texBuffer->height]; for (int i=0; i < tex->texBuffer->height; i++) { tex->texBuffer->m_buffer[i] = new RGBA[tex->texBuffer->width]; for (int j=0; j< tex->texBuffer->width; j++) { fread(&tex->texBuffer->m_buffer[i][j].r, 1, 1, texFile); if (colorSettings & 0x02) { fread(&tex->texBuffer->m_buffer[i][j].g, 1, 1, texFile); fread(&tex->texBuffer->m_buffer[i][j].b, 1, 1, texFile); } else { tex->texBuffer->m_buffer[i][j].g = tex->texBuffer->m_buffer[i][i].r; tex->texBuffer->m_buffer[i][j].b = tex->texBuffer->m_buffer[i][i].r; } if (colorSettings & 0x01) { fread(&tex->texBuffer->m_buffer[i][j].a, 1, 1, texFile); } else { tex->texBuffer->m_buffer[i][j].a = 255; } } } } else { if (ident >= 0x68) { MessageBox(NULL, _T("BAD TEX INFO"), _T("PROBLEMS"), MB_OK); } else { MessageBox(NULL, _T("UNKNOWN TAG IN VTX"), _T("PROBLEM"), MB_OK); } fseek(texFile, nlen, SEEK_CUR); } } } break; case TRAILER: fclose(texFile); return tex->texBuffer; break; default: MessageBox(NULL, _T("UNKNOWN VTX INFO"), _T("PROBLEM"), MB_OK); fseek(texFile, blen, SEEK_CUR); break; } } fclose(texFile); return tex->texBuffer;; } unsigned char getBSLData(int channel, int value) { int shift = (channel + (((channel + 1) % 2) * 2)) * 4; int mask = 0xF0 << shift; return (unsigned char)((value & mask) >> shift); } TexBuffer *VGCDivLoader::LoadBSLFile(char *fileName, char channelIndex, DivTexture *tex) { int len = strlen(fileName) + 5; char *fullFileName = new char[len]; strcpy_s(fullFileName, len, fileName); strcat_s(fullFileName, len, ".BSL"); FILE *texFile; if (fopen_s(&texFile, fullFileName, "rb") != 0) { delete [] fullFileName; return NULL; } char id[8]; fread(id, 1, 8, texFile); delete [] fullFileName; if (strncmp(id, "DIV-BSL2", 8) != 0) { fclose(texFile); return NULL; } int width, height, depth, nTextures; fread(&width, 4, 1, texFile); fread(&height, 4, 1, texFile); fread(&depth, 4, 1, texFile); fseek(texFile, 4, SEEK_CUR); fread(&nTextures, 4, 1, texFile); int usefulChannel = channelIndex; for (int i=0; i < nTextures; i++) { int header, channel; fread(&header, 4, 1, texFile); fread(&channel, 4, 1, texFile); char *chanName = new char[header-4]; fread(chanName, 1, header - 4, texFile); delete [] chanName; } tex->texBuffer = new TexBuffer; tex->texBuffer->height = height; tex->texBuffer->width = width; tex->texBuffer->m_buffer = new RGBA*[height]; for (int i=0; i texBuffer->m_buffer[i] = new RGBA[width]; for (int j=0; j < width; j++) { int val; fread(&val, 4, 1, texFile); if (usefulChannel < 6) { unsigned char color = getBSLData(usefulChannel,val); tex->texBuffer->m_buffer[i][j].a = 255; tex->texBuffer->m_buffer[i][j].r = color; tex->texBuffer->m_buffer[i][j].g = color; tex->texBuffer->m_buffer[i][j].b = color; } else { if (usefulChannel == 8) { tex->texBuffer->m_buffer[i][j].a = getBSLData(2, val); } else { tex->texBuffer->m_buffer[i][j].a = 255; } tex->texBuffer->m_buffer[i][j].r = getBSLData(5, val); tex->texBuffer->m_buffer[i][j].g = getBSLData(4, val); tex->texBuffer->m_buffer[i][j].b = getBSLData(3, val); } } } return tex->texBuffer; } void VGCDivLoader::parseTexture(FILE *file, unsigned int len) { BIZ_IDENTITIES ident; unsigned int nlen; DivTexture *texture = new DivTexture; memset(texture,0,sizeof(DivTexture)); texture->alpha = 255; char *texMapName = NULL; char channelIndex = 0; while(len > 0) { len -= getBlock(file, ident,nlen); len -= nlen; char *fileName; //Name of tex raster file char *ran; //Temp place for strings switch(ident) { case GEN_NAME: { texture->name = new char[nlen]; fread(texture->name, 1, nlen, file); break; } case GEN_SCOPE: fseek(file,1,SEEK_CUR); break; case TEX_MAP: texMapName = new char[nlen]; fread(texMapName,1,nlen,file); break; case TEX_MINIFY: fread(&texture->minify,1,1,file); break; case TEX_MAGNIFY: fread(&texture->magnify,1,1,file); break; case TEX_ALPHA: fread(&texture->alpha,1,1,file); break; case TEX_WRAP_U: fread(&texture->wrap_u,1,1,file); break; case TEX_WRAP_V: fread(&texture->wrap_v, 1, 1, file); break; case TEX_DETAIL: fread(&texture->detail_type, 1, 1, file); if (nlen > 1) { texture->detail_name = new char[nlen - 1]; fread(texture->detail_name, 1, nlen - 1, file); } break; case TEX_BSL_CHANNEL: //This is the channel index being loaded for a BSL file fread(&channelIndex, 1, 1, file); break; case SRF_SPECIAL: { char *pos; //Awesome ran = new char[nlen]; fread(ran,1,nlen,file); if ((pos = strstr(ran,"SCROLL")) != NULL) { float startu,startv,endu,endv; sscanf(pos, "SCROLL %f %f %f %f",&startu, &startv, &endu, &endv); texture->doScroll = true; texture->scrollU = endu; texture->scrollV = endv; } delete [] ran; break; } default: MessageBox(NULL,_T("UNKNOWN TEXTURE ENTRY"),_T("PROBLEM"),MB_OK); if (!feof(file)) { fseek(file, nlen, SEEK_CUR); } } } //Load up the texture buffer //Try to load as a BSL first if ((texture->texBuffer = LoadBSLFile(texMapName, channelIndex, texture)) == NULL) { //If that didn't work, do VTX texture->texBuffer = LoadVTXFile(texMapName, texture); } delete [] texMapName; if (texture->name == NULL) { delete [] texture->name; if (texture->detail_name != NULL) { delete [] texture->detail_name; } if (texture->texBuffer != NULL) { delete texture->texBuffer; } delete texture; fseek(file,len,SEEK_CUR); } else { //Add material mTextures.insert(pair(string(texture->name),texture)); } } bool VGCDivLoader::parseMaterial(FILE *file, unsigned int len, char *filename) { BIZ_IDENTITIES ident; unsigned int nlen; DivMaterial *material = new DivMaterial; memset(material,0,sizeof(DivMaterial)); material->amb_b = 1; material->amb_g = 1; material->amb_r = 1; material->dif_b = 1; material->dif_g = 1; material->dif_r = 1; material->emi_b = 0; material->emi_g = 0; material->emi_r = 0; material->spe_b = 0; material->spe_g = 0; material->spe_p = 1; material->spe_r = 0; material->opa_b = 1; material->opa_g = 1; material->opa_r = 1; material->isImmune = false; while(len > 0) { len -= getBlock(file, ident, nlen); len -= nlen; char *ran; //Temp place for strings switch(ident) { case GEN_NAME: material->name = new char[nlen]; fread(material->name, 1, nlen, file); break; case GEN_SCOPE: fseek(file,1,SEEK_CUR); break; case MAT_TEXTURE: fread(&material->tex_type, 1, 1, file); if (nlen > 1) { material->tex_name = new char[nlen - 1]; fread(material->tex_name, 1, nlen - 1, file); } //Precaching textures moves the file offset, so: /*loc = ftell(file); precacheTexture(material->tex_name,file); fseek(file,loc,SEEK_SET);*/ //We don't precache textures anymore- they should be local, so screw it break; case MAT_ENVIRONMENT: //Anyone know what this is for? fread(&material->env_type, 1, 1, file); material->env_name = new char[nlen - 1]; fread(material->env_name, 1, nlen - 1, file); break; case MAT_AMBIENT: fread(&material->amb_r, floatSize(), 1, file); fread(&material->amb_g, floatSize(), 1, file); fread(&material->amb_b, floatSize(), 1, file); break; case MAT_DIFFUSE: fread(&material->dif_r, floatSize(), 1, file); fread(&material->dif_g, floatSize(), 1, file); fread(&material->dif_b, floatSize(), 1, file); break; case MAT_SPECULAR: fread(&material->spe_r, floatSize(), 1, file); fread(&material->spe_g, floatSize(), 1, file); fread(&material->spe_b, floatSize(), 1, file); fread(&material->spe_p, floatSize(), 1, file); break; case MAT_EMISSIVE: fread(&material->emi_r, floatSize(), 1, file); fread(&material->emi_g, floatSize(), 1, file); fread(&material->emi_b, floatSize(), 1, file); break; case MAT_OPACITY: fread(&material->opa_r, floatSize(), 1, file); fread(&material->opa_g, floatSize(), 1, file); fread(&material->opa_b, floatSize(), 1, file); break; case MAT_RAMP: material->ramp_name = new char[nlen]; fread(material->ramp_name, 1, nlen, file); break; case SRF_SPECIAL: { //Awesome! ran = new char[nlen]; fread(ran,1,nlen,file); char *immuneParam = strstr(ran, "IMMUNE"); if (immuneParam != NULL) { material->isImmune = true; } delete [] ran; break; } default: MessageBox(NULL,_T("UNKNOWN MATERIAL ENTRY"),_T("PROBLEM"),MB_OK); if (!feof(file)) { fseek(file, nlen, SEEK_CUR); } } } if (material->name == NULL) { //This material is nameless? if (material->env_name) { delete [] material->env_name; } if (material->tex_name) { delete [] material->tex_name; } if (material->ramp_name) { delete [] material->ramp_name; } delete material; return false; } else { //If there's no material, set it to null. if (material->tex_type != 2) { if (material->tex_name != NULL) { delete [] material->tex_name; } material->tex_type = 2; material->tex_name = new char[5]; strcpy_s(material->tex_name, 5, "NULL"); } //Add material string fullMatName = string(filename); fullMatName += string(":"); fullMatName += string(material->name); mMaterials.insert(pair(fullMatName,material)); return true; } } void VGCDivLoader::precacheMaterial(char *name) { FILE *matFile = NULL; //Get material file name char *colon = strstr(name, ":"); int len = colon - name; char *fname = new char[(len + 5)]; char *matFileName = new char[len + 1]; strncpy(matFileName,name,len); matFileName[len] = 0; strncpy(fname, name, len); fname[len] = 0; strcat_s(fname,len + 5, ".BMF"); //Get actual material name int matNameLen = strlen(name) - len; char *mname = new char[matNameLen]; strcpy_s(mname, matNameLen, colon + 1); if (mMaterials.find(string(name)) != mMaterials.end()) { //Already precached return; } //Open the BMF file int fullDirLen = strlen(fname) + 1; char *fulldir = new char[fullDirLen]; strcpy_s(fulldir, fullDirLen, fname); delete [] fname; if (fopen_s(&matFile,fulldir,"rb") != 0) { MessageBox(NULL,_T("PANIC MAT FILE FAILED TO OPEN"),_T("SHIT"),MB_OK); } delete [] fulldir; //Parse the file char id[8]; fread(&id, 8, 1, matFile); //Compare first 8 bits to make sure it's a biz2 file if (strncmp(id,"DIV-BIZ2",8) != 0) { fclose(matFile); MessageBox(NULL, _T("PANIC MAT FILE WAS NOT MAT FILE"),_T("Oh no"),MB_OK); } unsigned int blen; BIZ_IDENTITIES ident; bool done = false; while(!feof(matFile)) { //Retrieve ID and length of upcoming block getBlock(matFile, ident, blen); switch(ident) { case MATERIAL: //This is the only relevant thing right now parseMaterial(matFile, blen,matFileName); break; case RAMP: parseRamp(matFile,blen); break; case TEXTURE: parseTexture(matFile, blen); break; default: if (!feof(matFile)) { fseek(matFile,blen,SEEK_CUR); } } } delete [] mname; delete [] matFileName; } void VGCDivLoader::parseRamp(FILE *file, unsigned int len) { BIZ_IDENTITIES ident; unsigned int nlen; DivRamp *ramp = new DivRamp; memset(ramp, 0, sizeof(DivRamp)); char *name; while(len > 0) { len -= getBlock(file, ident, nlen); len -= nlen; switch(ident) { case GEN_NAME: name = new char[nlen]; fread(name, 1, nlen, file); if (mRamps.find(string(name)) != mRamps.end()) { delete [] name; delete ramp; fseek(file,len,SEEK_CUR); return; } break; case GEN_SCOPE: if (nlen > 0) { fseek(file, nlen, SEEK_CUR); } break; case RMP_DATA: fread(&ramp->r1, floatSize(), 1, file); fread(&ramp->g1, floatSize(), 1, file); fread(&ramp->b1, floatSize(), 1, file); fread(&ramp->r2, floatSize(), 1, file); fread(&ramp->g2, floatSize(), 1, file); fread(&ramp->b2, floatSize(), 1, file); break; default: MessageBox(NULL, _T("UNRECOGNIZED RAMP BLOCK"), _T("PROBLEM"), MB_OK); if (nlen > 0) { fseek(file, nlen, SEEK_CUR); } break; } } mRamps[string(name)] = ramp; delete [] name; } void VGCDivLoader::parseObject(FILE *file, unsigned int len, char *fileName) { BIZ_IDENTITIES ident; unsigned int nlen; DivObject *obj = new DivObject; obj->objName = new char[strlen(fileName) + 1]; strcpy_s(obj->objName, strlen(fileName) + 1, fileName); while(len > 0) { len -= getBlock(file, ident,nlen); len -= nlen; switch(ident) { //Set the master set of surface props case GEN_NAME: case SRF_F_MATERIAL: case SRF_B_MATERIAL: case SRF_PLANE: case SRF_DRAWMODE: case SRF_DECAL: case SRF_FACETED: case SRF_VERTEX: case SRF_SPECIAL: case SRF_LOCK: parseSurface(file, ident,nlen,mMasterProps); break; case LOD: parseLOD(obj, file, nlen); break; case PATCH: parsePatch(obj, file, nlen); break; } } VGCDivLoader::mObjects.insert(std::pair(string(obj->objName), obj)); } void VGCDivLoader::parseLOD(DivObject *obj, FILE *file, unsigned int len) { //LOD's are only relevant if it's the closest LOD level, //and the only relevant part are the patches BIZ_IDENTITIES ident; unsigned int nlen; bool parse = false; while(len > 0) { len -= getBlock(file, ident,nlen); len -= nlen; switch(ident) { case LOD_DISTANCE: float in, out; fread(&in,floatSize(),1,file); fread(&out,floatSize(),1,file); if (in < 5.0f) { //Don't even bother if this isn't a seriously close-up LOD parse = true; } break; case PATCH: if (parse) { //If this is the right LOD, parse patches parsePatch(obj, file, nlen); } else { fseek(file,nlen,SEEK_CUR); } break; default: fseek(file,nlen,SEEK_CUR); } } } void VGCDivLoader::parsePatch(DivObject *obj, FILE *file, unsigned int len) { BIZ_IDENTITIES ident; unsigned int nlen; bool parse = false; DivPatch *patch = new DivPatch; patch->surface = mMasterProps; int *indices; DivVertex *verts; while(len > 0) { len -= getBlock(file, ident,nlen); len -= nlen; int n; switch(ident) { case GEN_NAME: case SRF_F_MATERIAL: case SRF_B_MATERIAL: case SRF_PLANE: case SRF_DRAWMODE: case SRF_DECAL: case SRF_FACETED: case SRF_VERTEX: case SRF_SPECIAL: case SRF_LOCK: //Edit our patch's surface props parseSurface(file, ident,nlen,patch->surface); break; case POLYGON: case POLYSTRIP: //Polystrip is a tri fan. Incidentally, we're treating //>3 sided polys like tri fans nlen = 0; while (!(ident & 0x80)) { //Poly lists are the only relevant blocks if (nlen > 0) { fseek(file,nlen,SEEK_CUR); } getBlock(file, ident,nlen); } //Parse list of polys verts = parseVList(file, nlen,(unsigned char)(ident & 0x7F),n); indices = new int[n]; for (int i=0; i 0) { fseek(file,nlen,SEEK_CUR); } getBlock(file, ident,nlen); } verts = parseVList(file, nlen,(unsigned char)(ident & 0x7F),n); indices = new int[n]; for (int i=0; isurface.drawSpheres = true; vector verts; while (nlen > 0) { nlen -= getBlock(file, inident, inlen); nlen -= inlen; if (inident == SPHERE) { for (int i=0; i < (inlen/(floatSize()*4)); i++) { float x,y,z,radius; fread(&x,floatSize(),1,file); fread(&y,floatSize(),1,file); fread(&z,floatSize(),1,file); fread(&radius,floatSize(),1,file); DivVertex vert; vert.x = x * this->mHeaderInfo.scale; vert.y = y * this->mHeaderInfo.scale; vert.z = z * this->mHeaderInfo.scale; vert.mask = 0; verts.insert(verts.end(),vert); } } else if (inlen > 0) { fseek(file,nlen,SEEK_CUR); } } for (int i=0; i < verts.size(); i++) { getVertex(verts[i], obj); } //setupDrawOps(props); break; } case LINE_LIST: //Ignore these fseek(file,nlen,SEEK_CUR); break; case TEXT: //Ignore these fseek(file,nlen,SEEK_CUR); break; default: cout << "UNKNOWN PATCH VAR " << ident << endl; } } obj->patches.insert(obj->patches.end(), patch); } void VGCDivLoader::parseSurface(FILE *file, BIZ_IDENTITIES ident, unsigned int len, SurfaceProps &props) { //These are really straightforward- just move the value //from the file to the SurfaceProps struct switch(ident) { case GEN_NAME: props.name = new char[len]; fread(props.name,1,len,file); break; case SRF_F_MATERIAL: fread(&props.f_material_type,1,1,file); props.faceted |= 0x02; if (len > 1) { props.f_material_name = new char[len-1]; fread(props.f_material_name,1,len-1,file); precacheMaterial(props.f_material_name); } break; case SRF_B_MATERIAL: fread(&props.b_material_type,1,1,file); props.faceted |= 0x01; if (len > 1) { props.b_material_name = new char[len-1]; fread(props.b_material_name,1,len-1,file); precacheMaterial(props.b_material_name); } break; case SRF_PLANE: fread(&props.plane,1,1,file); break; case SRF_DRAWMODE: fread(&props.drawmode,1,1,file); fread(&props.drawmode_width,1,1,file); break; case SRF_DECAL: fread(&props.decal_offset,4,1,file); break; case SRF_FACETED: fread(&props.faceted,1,1,file); break; case SRF_VERTEX: fread(&props.vertex_mask,1,1,file); break; case SRF_SPECIAL: props.specialInst = new char[len]; fread(props.specialInst,1,len,file); break; case SRF_LOCK: fread(&props.locks,1,1,file); break; default: cout << "UNKNOWN SURFACE VAR " << ident << endl; } } void VGCDivLoader::parsePMesh(FILE *file, unsigned int len, DivPatch *patch, DivObject *obj) { //PMeshes are a list of vertices, and a list of vertex indices //The pmeshes default to 3 side per poly, but can be set different BIZ_IDENTITIES ident; unsigned int nlen; bool parse = false; std::vector conLists; DivVertex *vertList; while(len > 0) { len -= getBlock(file, ident,nlen); len -= nlen; ConList *list; switch(ident) { case PMESH_CONLIST: //old conlists are tris only list = new ConList; list->sideCount = 3; list->numIndices = nlen / 4; list->indices = new int[list->numIndices]; fread(list->indices,4,list->numIndices,file); conLists.insert(conLists.begin(),list); break; case PMESH_CONLIST_NEW: //Newer ones specify the sideage of the polys list = new ConList; fread(&list->sideCount,1,1,file); list->numIndices = (nlen-1) / 4; list->indices = new int[list->numIndices]; fread(list->indices,4,list->numIndices,file); conLists.insert(conLists.begin(),list); break; default: if (ident & 0x80) { //Read in verts like normal int n; vertList = parseVList(file, nlen,(unsigned char)(ident & 0x7F), n); } else { cout << "UNKNOWN PMESH VAR " << ident << endl; fseek(file,nlen,SEEK_CUR); } } } while(!conLists.empty()) { //For each connection list, add polygons from the conlist //and destroy the connection list ConList *list = *conLists.begin(); //Replace local vertex indexes with global ones for (int i=0; i < list->numIndices; i++) { list->indices[i] = getVertex(vertList[list->indices[i]], obj); } //Add the individual polygons for (int i=0; i < list->numIndices; i += list->sideCount) { addPolygon(list->indices + i,list->sideCount, patch); } delete [] list->indices; delete list; conLists.erase(conLists.begin()); } delete [] vertList; } DivVertex *VGCDivLoader::parseVList(FILE *file, unsigned int len, unsigned char mask, int &n) { //The passed-in mask is the format of the vertices, and //determines the in-file structure //Figure out the size-per-vertex int size = floatSize() * 3; if (mask & 0x01) { //Normals size += floatSize() * 3; } if (mask & 0x02) { //RGB size += floatSize() * 4; } else if (mask & 0x04) { //Luminance size += floatSize() * 2; } if (mask & 0x08) { //2D Tex size += floatSize() * 2; } else if (mask & 0x10) { //3D Tex size += floatSize() * 3; } //Use the size-per-vertex to derive the number of vertices n = len / size; DivVertex *buffer = new DivVertex[n]; //Read in each vertex for (int i=0; i < n; i++) { buffer[i].mask = mask; fread(&buffer[i].x,floatSize(),1,file); fread(&buffer[i].y,floatSize(),1,file); fread(&buffer[i].z,floatSize(),1,file); //buffer[i].z = -buffer[i].z; buffer[i].x *= this->mHeaderInfo.scale; buffer[i].y *= this->mHeaderInfo.scale; buffer[i].z *= this->mHeaderInfo.scale; if (mask & 0x01) { //Normals fread(&buffer[i].Nx,floatSize(),1,file); fread(&buffer[i].Ny,floatSize(),1,file); fread(&buffer[i].Nz,floatSize(),1,file); } else { buffer[i].Nx = 0; buffer[i].Ny = 0; buffer[i].Nz = 0; } if (mask & 0x02) { //RGB fread(&buffer[i].r,floatSize(),1,file); fread(&buffer[i].g,floatSize(),1,file); fread(&buffer[i].b,floatSize(),1,file); } if (mask & 0x04) { //Luminance fread(&buffer[i].l,floatSize(),1,file); } if (mask & 0x06) { //RGB or Luminance fread(&buffer[i].a,floatSize(),1,file); } if (mask & 0x18) { //2D or 3D texture fread(&buffer[i].u,floatSize(),1,file); //buffer[i].u = 1.0f - buffer[i].u; fread(&buffer[i].v,floatSize(),1,file); } if (mask & 0x10) { //3D texture fread(&buffer[i].w,floatSize(),1,file); } } return buffer; } int VGCDivLoader::getBlock(FILE *file, BIZ_IDENTITIES &id, unsigned int &len) { //BIZ_IDENTTAG is ryan's structure that mimics the in-file structure //of the first two bytes of a block BIZ_IDENTTAG ident; fread(&ident,sizeof(BIZ_IDENTTAG),1,file); //Get ID value int idVal = ident.identity; idVal = (ident.configBit)?(idVal+2000):idVal; id = (BIZ_IDENTITIES)idVal; //Get File Length if (ident.headerSize == 2) { fread(&len,4,1,file); return 6; } else if (ident.headerSize == 1) { unsigned short size; fread(&size,2,1,file); len = size; return 4; } else { unsigned char size; fread(&size,1,1,file); len = size; return 3; } } int VGCDivLoader::floatSize() { return 4; } int VGCDivLoader::getVertex(DivVertex vert, DivObject *obj) { //Try and find vertices, if the vertex doesn't exist, add it std::vector::iterator it = obj->vertices.begin(); int i=0; while(it != obj->vertices.end() && memcmp(&(*it),&vert,sizeof(DivVertex)) != 0) {++it; ++i;} if (it == obj->vertices.end()) { obj->vertices.insert(obj->vertices.end(),vert); } //Return the vertex's index in the VGCDivLoader's vertex list return i; } void VGCDivLoader::addPolygon(int *indices, int numIndices, DivPatch *patch) { //Break the polygon down into a triangle fan and add it to the tris char facets = patch->surface.faceted; for (int i=0; i < numIndices - 2; i++) { if (facets & 0x02) { Triangle tri; tri.indices[2] = indices[0]; tri.indices[1] = indices[i+1]; tri.indices[0] = indices[i+2]; patch->frontTriangles.insert(patch->frontTriangles.end(),tri); } if (facets & 0x01) { Triangle tri; tri.indices[0] = indices[0]; tri.indices[1] = indices[i+1]; tri.indices[2] = indices[i+2]; patch->backTriangles.insert(patch->backTriangles.end(),tri); } } }