void Sky::init(MPQFile &f) { int addr = (int)f.getPos(); int ll[18]; int buf[64]; for (int k=0; k<4; k++) { if (k==0 || k==2) { f.seek(addr + k * 0x15f0); f.read(ll, 18*4); for (int i=0; i<18; i++) { f.read(buf,64*4); int *p=buf; int idx = (k/2)*18 + i; if (ll[i]==0) mmin[idx] = -1; else { mmin[idx] = *p; for (int l=0; l<ll[i]; l++) { SkyColor sc; sc.init(p[0],p[1]); p+=2; colorRows[idx].push_back(sc); } } } } } f.seek(addr + 4 * 0x15f0); }
void Replay::load( const std::string& filename ) { filename_ = filename; MPQArchive archive; // Sanity check isValid_ = true; if ( !archive.load( filename ) ) { std::cerr << "Error loading MPQ file " << filename << "." << std::endl; isValid_ = false; return; } MPQFile* infoFile = archive.getFile( "replay.info" ); const MPQFile* gameFile = archive.getFile( "replay.game.events" ); const MPQFile* syncFile = archive.getFile( "replay.sync.events" ); const MPQFile* messageFile = archive.getFile( "replay.message.events" ); const MPQFile* saveFile = archive.getFile( "save.jpg" ); info_.load ( infoFile->getFileContent(), infoFile->getFileSize()); gameEvents_.load ( gameFile->getFileContent(), gameFile->getFileSize() ); syncEvents_.load ( syncFile->getFileContent(), syncFile->getFileSize() ); messageEvents_.load( messageFile->getFileContent(), messageFile->getFileSize() ); imageSize_ = saveFile->getFileSize(); imageBuffer_ = new uint8_t[imageSize_]; std::copy( saveFile->getFileContent(), saveFile->getFileContent()+imageSize_, imageBuffer_ ); delete infoFile; delete gameFile; delete syncFile; delete messageFile; delete saveFile; }
void WMOGroup::init(WMO *wmo, MPQFile &f, int num, char *names) { this->wmo = wmo; this->num = num; // extract group info from f f.read(&flags,4); float ff[3]; f.read(ff,12); v1 = Vec3D(ff[0],ff[1],ff[2]); f.read(ff,12); v2 = Vec3D(ff[0],ff[1],ff[2]); int nameOfs; f.read(&nameOfs,4); // TODO: get proper name from group header and/or dbc? if (nameOfs > 0) { name = string(names + nameOfs); } else name = "(no name)"; ddr = 0; nDoodads = 0; lq = 0; }
void ParticleSystem::init(const MPQFile& f, const ModelParticleEmitterDef &mta, int *globals) { speed.init(mta.EmissionSpeed, f, globals); variation.init(mta.SpeedVariation, f, globals); spread.init(mta.VerticalRange, f, globals); lat.init(mta.HorizontalRange, f, globals); gravity.init(mta.Gravity, f, globals); lifespan.init(mta.Lifespan, f, globals); rate.init(mta.EmissionRate, f, globals); areal.init(mta.EmissionAreaLength, f, globals); areaw.init(mta.EmissionAreaWidth, f, globals); deacceleration.init(mta.Gravity2, f, globals); enabled.init(mta.en, f, globals); Vec3D colors2[3]; memcpy(colors2, f.getBuffer() + mta.p.colors.ofsKeys, sizeof(Vec3D) * 3); for (size_t i = 0; i<3; ++i) { float opacity = *reinterpret_cast<int16_t*>(f.getBuffer() + mta.p.opacity.ofsKeys + i * 2); colors[i] = Vec4D(colors2[i].x / 255.0f, colors2[i].y / 255.0f, colors2[i].z / 255.0f, opacity / 32767.0f); sizes[i] = (*reinterpret_cast<float*>(f.getBuffer() + mta.p.sizes.ofsKeys + i * 4))*mta.p.scales[i]; } mid = 0.5; slowdown = mta.p.slowdown; rotation = mta.p.rotation; pos = fixCoordSystem(mta.pos); _texture = model->_textures[mta.texture]; blend = mta.blend; rows = mta.rows; cols = mta.cols; type = mta.ParticleType; //order = mta.s2; order = mta.ParticleType>0 ? -1 : 0; parent = model->bones + mta.bone; switch (mta.EmitterType) { case 1: emitter = new PlaneParticleEmitter(this); break; case 2: emitter = new SphereParticleEmitter(this); break; } //transform = mta.flags & 1024; billboard = !(mta.flags & 4096); manim = mtime = 0; rem = 0; tofs = misc::frand(); // init tiles for (int i = 0; i<rows*cols; ++i) { TexCoordSet tc; initTile(tc.tc, i); tiles.push_back(tc); } }
ModelInstance::ModelInstance(MPQFile& f, string& ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile, int coreNumber) { float ff[3]; f.read(&id, 4); f.read(ff, 12); pos = fixCoords(Vec3D(ff[0], ff[1], ff[2])); f.read(ff, 12); rot = Vec3D(ff[0], ff[1], ff[2]); if (coreNumber == CLIENT_TBC || coreNumber == CLIENT_WOTLK) { uint16 fFlags; // dummy var f.read(&scaleOthers, 2); f.read(&fFlags, 2); // unknown but flag 1 is used for biodome in Outland, currently this value is not used sc = scaleOthers / 1024.0f; // scale factor - divide by 1024. why not just use a float? } if (coreNumber == CLIENT_CLASSIC) { f.read(&scaleZeroOnly,4); // The above three lines introduced a regression bug in Mangos Zero, is Fine for other cores. sc = scaleZeroOnly / 1024.0f; // scale factor - divide by 1024. why not just use a float? } char tempname[512]; sprintf(tempname, "%s/%s", szWorkDirWmo, ModelInstName.c_str()); FILE* input; input = fopen(tempname, "r+b"); if (!input) { //printf("ModelInstance::ModelInstance couldn't open %s\n", tempname); return; } fseek(input, 8, SEEK_SET); // get the correct no of vertices int nVertices; size_t file_read = fread(&nVertices, sizeof(int), 1, input); fclose(input); if (nVertices == 0 || file_read <= 0) { return; } uint16 adtId = 0;// not used for models uint32 flags = MOD_M2; if (tileX == 65 && tileY == 65) { flags |= MOD_WORLDSPAWN; } //write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, name fwrite(&mapID, sizeof(uint32), 1, pDirfile); fwrite(&tileX, sizeof(uint32), 1, pDirfile); fwrite(&tileY, sizeof(uint32), 1, pDirfile); fwrite(&flags, sizeof(uint32), 1, pDirfile); fwrite(&adtId, sizeof(uint16), 1, pDirfile); fwrite(&id, sizeof(uint32), 1, pDirfile); fwrite(&pos, sizeof(float), 3, pDirfile); fwrite(&rot, sizeof(float), 3, pDirfile); fwrite(&sc, sizeof(float), 1, pDirfile); uint32 nlen = ModelInstName.length(); fwrite(&nlen, sizeof(uint32), 1, pDirfile); fwrite(ModelInstName.c_str(), sizeof(char), nlen, pDirfile); }
ModelInstance::ModelInstance(MPQFile& f, const char* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile) { float ff[3]; f.read(&id, 4); f.read(ff, 12); pos = fixCoords(Vec3D(ff[0], ff[1], ff[2])); f.read(ff, 12); rot = Vec3D(ff[0], ff[1], ff[2]); uint16 dummyFlags; // dummy var f.read(&scale, 2); f.read(&dummyFlags, 2); // unknown but flag 1 is used for biodome in Outland, currently this value is not used // scale factor - divide by 1024. blizzard devs must be on crack, why not just use a float? sc = scale / 1024.0f; char tempname[512]; sprintf(tempname, "%s/%s", szWorkDirWmo, ModelInstName); FILE* input = fopen(tempname, "r+b"); if (!input) { //printf("ModelInstance::ModelInstance couldn't open %s\n", tempname); return; } fseek(input, 8, SEEK_SET); // get the correct no of vertices int nVertices; int count = fread(&nVertices, sizeof (int), 1, input); fclose(input); if (count != 1 || nVertices == 0) return; uint16 adtId = 0; // not used for models uint32 flags = MOD_M2; if (tileX == 65 && tileY == 65) flags |= MOD_WORLDSPAWN; // write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, name fwrite(&mapID, sizeof(uint32), 1, pDirfile); fwrite(&tileX, sizeof(uint32), 1, pDirfile); fwrite(&tileY, sizeof(uint32), 1, pDirfile); fwrite(&flags, sizeof(uint32), 1, pDirfile); fwrite(&adtId, sizeof(uint16), 1, pDirfile); fwrite(&id, sizeof(uint32), 1, pDirfile); fwrite(&pos, sizeof(float), 3, pDirfile); fwrite(&rot, sizeof(float), 3, pDirfile); fwrite(&sc, sizeof(float), 1, pDirfile); uint32 nlen = strlen(ModelInstName); fwrite(&nlen, sizeof(uint32), 1, pDirfile); fwrite(ModelInstName, sizeof(char), nlen, pDirfile); }
ModelInstance::ModelInstance(Model *m, MPQFile &f) : model (m) { float ff[3]; f.read(&d1, 4); f.read(ff,12); pos = Vec3D(ff[0],ff[1],ff[2]); f.read(ff,12); dir = Vec3D(ff[0],ff[1],ff[2]); f.read(&scale,4); // scale factor - divide by 1024. blizzard devs must be on crack, why not just use a float? sc = scale / 1024.0f; }
ModelInstance::ModelInstance(MPQFile &f,const char* ModelInstName,const char*MapName, FILE *pDirfile) { float ff[3]; f.read(&d1, 4); f.read(ff,12); pos = Vec3D(ff[0],ff[1],ff[2]); f.read(ff,12); rot = Vec3D(ff[0],ff[1],ff[2]); f.read(&scale,4); // scale factor - divide by 1024. blizzard devs must be on crack, why not just use a float? sc = scale / 1024.0f; char tempname[512]; sprintf(tempname, ".\\buildings\\%s", ModelInstName); FILE *input; input = fopen(tempname, "r+b"); if(!input) { return; } fseek(input, 8, SEEK_SET); // get the correct no of vertices int nVertices; fread(&nVertices, sizeof (int), 1, input); fclose(input); if(nVertices == 0) { return; } if(pDirfile) { int realx1 = (int) ((float) pos.x / 533.333333f); int realy1 = (int) ((float) pos.z / 533.333333f); int realx2 = (int) ((float) pos.x / 533.333333f); int realy2 = (int) ((float) pos.z / 533.333333f); fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f %f %d %d %d,%d %d\n", MapName, ModelInstName, (float) pos.x, (float) pos.y, (float) pos.z, (float) rot.x, (float) rot.y, (float) rot.z, sc, nVertices, realx1, realy1, realx2, realy2 ); } }
void ModelInstance::init2(Model *m, MPQFile &f) { model = m; float ff[3],temp; f.read(ff,12); pos = Vec3D(ff[0],ff[1],ff[2]); temp = pos.z; pos.z = -pos.y; pos.y = temp; f.read(&w,4); f.read(ff,12); dir = Vec3D(ff[0],ff[1],ff[2]); f.read(&sc,4); f.read(&d1,4); lcol = Vec3D(((d1&0xff0000)>>16) / 255.0f, ((d1&0x00ff00)>>8) / 255.0f, (d1&0x0000ff) / 255.0f); }
void RibbonEmitter::init(const MPQFile &f, ModelRibbonEmitterDef &mta, int *globals) { color.init(mta.color, f, globals); opacity.init(mta.opacity, f, globals); above.init(mta.above, f, globals); below.init(mta.below, f, globals); parent = model->bones + mta.bone; uint32_t *texlist = reinterpret_cast<uint32_t*>(f.getBuffer() + mta.ofsTextures); // just use the first texture for now; most models I've checked only had one _texture = model->_textures[texlist[0]]; tpos = pos = fixCoordSystem(mta.pos); //! \todo figure out actual correct way to calculate length // in BFD, res is 60 and len is 0.6, the trails are very short (too long here) // in CoT, res and len are like 10 but the trails are supposed to be much longer (too short here) numsegs = (int)mta.res; seglen = mta.length; length = mta.res * seglen; // create first segment RibbonSegment rs; rs.pos = tpos; rs.len = 0; segs.push_back(rs); }
void ModelInstance::init2(Model *m, MPQFile &f) { // MODD model = m; float ff[3],temp; f.read(ff,12); // Position (X,Z,-Y) pos = Vec3D(ff[0],ff[1],ff[2]); temp = pos.z; pos.z = -pos.y; pos.y = temp; f.read(&w,4); // W component of the orientation quaternion f.read(ff,12); // X, Y, Z components of the orientaton quaternion dir = Vec3D(ff[0],ff[1],ff[2]); f.read(&sc,4); // Scale factor unsigned int d1; f.read(&d1,4); // (B,G,R,A) Lightning-color. lcol = fromARGB(d1); }
void WMOLight::init(MPQFile &f) { char type[4]; f.read(&type,4); f.read(&color,4); f.read(pos, 12); f.read(&intensity, 4); f.read(unk, 4*5); f.read(&r,4); pos = Vec3D(pos.x, pos.z, -pos.y); // rgb? bgr? hm float fa = ((color & 0xff000000) >> 24) / 255.0f; float fr = ((color & 0x00ff0000) >> 16) / 255.0f; float fg = ((color & 0x0000ff00) >> 8) / 255.0f; float fb = ((color & 0x000000ff) ) / 255.0f; fcolor = Vec4D(fr,fg,fb,fa); fcolor *= intensity; fcolor.w = 1.0f; /* // light logging gLog("Light %08x @ (%4.2f,%4.2f,%4.2f)\t %4.2f, %4.2f, %4.2f, %4.2f, %4.2f, %4.2f, %4.2f\t(%d,%d,%d,%d)\n", color, pos.x, pos.y, pos.z, intensity, unk[0], unk[1], unk[2], unk[3], unk[4], r, type[0], type[1], type[2], type[3]); */ }
Sky::Sky(MPQFile &f) { lightinfo li; f.read(&li, 64); pos = Vec3D(li.fa/skymul, li.fb/skymul, li.fc/skymul); r1 = li.fd / skymul; r2 = li.fe / skymul; strcpy(name,li.name); for (int i=0; i<36; i++) mmin[i] = -2; global = (li.ia==-1); }
void Model::initStatic(MPQFile &f) { origVertices = (ModelVertex*)(f.getBuffer() + header.ofsVertices); initCommon(f); dlist = glGenLists(1); glNewList(dlist, GL_COMPILE); drawModel(); glEndList(); // clean up vertices, indices etc delete[] vertices; delete[] normals; delete[] indices; if (colors) delete[] colors; if (transparency) delete[] transparency; }
void Model::initCommon(MPQFile &f) { // assume: origVertices already set if (!animGeometry) { vertices = new Vec3D[header.nVertices]; normals = new Vec3D[header.nVertices]; } //Vec3D vmin = Vec3D( 9999999.0f, 9999999.0f, 9999999.0f); //Vec3D vmax = Vec3D(-9999999.0f,-9999999.0f,-9999999.0f); // vertices, normals for (size_t i=0; i<header.nVertices; i++) { origVertices[i].pos = fixCoordSystem(origVertices[i].pos); origVertices[i].normal = fixCoordSystem(origVertices[i].normal); if (!animGeometry) { vertices[i] = origVertices[i].pos; normals[i] = origVertices[i].normal.normalize(); } float len = origVertices[i].pos.lengthSquared(); if (len > rad){ rad = len; } /* if (origVertices[i].pos.x < vmin.x) vmin.x = origVertices[i].pos.x; if (origVertices[i].pos.y < vmin.y) vmin.y = origVertices[i].pos.y; if (origVertices[i].pos.z < vmin.z) vmin.z = origVertices[i].pos.z; if (origVertices[i].pos.x > vmax.x) vmax.x = origVertices[i].pos.x; if (origVertices[i].pos.y > vmax.y) vmax.y = origVertices[i].pos.y; if (origVertices[i].pos.z > vmax.z) vmax.z = origVertices[i].pos.z; */ } rad = sqrtf(rad); //rad = std::max(vmin.length(),vmax.length()); // textures ModelTextureDef *texdef = (ModelTextureDef*)(f.getBuffer() + header.ofsTextures); if (header.nTextures) { textures = new TextureID[header.nTextures]; for (size_t i=0; i<header.nTextures; i++) { char texname[256]; if (texdef[i].type == 0) { strncpy(texname, f.getBuffer() + texdef[i].nameOfs, texdef[i].nameLen); texname[texdef[i].nameLen] = 0; std::string path(texname); fixname(path); textures[i] = video.textures.add(texname); } else { // special texture - only on characters and such... textures[i] = 0; } } } // init colors if (header.nColors) { colors = new ModelColor[header.nColors]; ModelColorDef *colorDefs = (ModelColorDef*)(f.getBuffer() + header.ofsColors); for (size_t i=0; i<header.nColors; i++) colors[i].init(f, colorDefs[i], globalSequences); } // init transparency int16 *transLookup = (int16*)(f.getBuffer() + header.ofsTransparencyLookup); if (header.nTransparency) { transparency = new ModelTransparency[header.nTransparency]; ModelTransDef *trDefs = (ModelTransDef*)(f.getBuffer() + header.ofsTransparency); for (size_t i=0; i<header.nTransparency; i++) transparency[i].init(f, trDefs[i], globalSequences); } // just use the first LOD/view // indices - allocate space, too ModelView *view = (ModelView*)(f.getBuffer() + header.ofsViews); uint16 *indexLookup = (uint16*)(f.getBuffer() + view->ofsIndex); uint16 *triangles = (uint16*)(f.getBuffer() + view->ofsTris); nIndices = view->nTris; indices = new uint16[nIndices]; for (size_t i = 0; i<nIndices; i++) { indices[i] = indexLookup[triangles[i]]; } // render ops ModelGeoset *ops = (ModelGeoset*)(f.getBuffer() + view->ofsSub); ModelTexUnit *tex = (ModelTexUnit*)(f.getBuffer() + view->ofsTex); ModelRenderFlags *renderFlags = (ModelRenderFlags*)(f.getBuffer() + header.ofsTexFlags); uint16 *texlookup = (uint16*)(f.getBuffer() + header.ofsTexLookup); uint16 *texanimlookup = (uint16*)(f.getBuffer() + header.ofsTexAnimLookup); int16 *texunitlookup = (int16*)(f.getBuffer() + header.ofsTexUnitLookup); /* for (size_t i = 0; i<view->nSub; i++) { ModelRenderPass pass; pass.usetex2 = false; pass.indexStart = ops[i].istart; pass.indexCount = ops[i].icount; // textures for (size_t j = 0; j<view->nTex; j++) { if (tex[j].op==i) { TextureID texid = textures[texlookup[tex[j].textureid]]; if (tex[j].texunit==0) { pass.texture = texid; // TODO: figure out these flags properly -_- ModelRenderFlags &rf = renderFlags[tex[j].flagsIndex]; //pass.useenvmap = (rf.flags2 & 6)==6; //pass.useenvmap = rf.blend == 6; // ??? pass.useenvmap = texunitlookup[tex[j].texunit] == -1; pass.blendmode = rf.blend; pass.color = tex[j].colorIndex; pass.opacity = transLookup[tex[j].transid]; pass.cull = (rf.flags & 4)==0 && rf.blend==0; pass.unlit = (rf.flags & 3)!=0; pass.nozwrite = pass.blendmode >= 2; //(rf.flags & 16)!=0; pass.trans = pass.blendmode != 0; pass.p = ops[i].v.x; if (animTextures) { if (tex[j].flags & 16) { pass.texanim = -1; // no texture animation } else { pass.texanim = texanimlookup[tex[j].texanimid]; } } else { pass.texanim = -1; // no texture animation } } else if (tex[j].texunit==1) { pass.texture2 = texid; //pass.usetex2 = true; } } } passes.push_back(pass); } */ for (size_t j = 0; j<view->nTex; j++) { ModelRenderPass pass; pass.usetex2 = false; pass.texture2 = 0; size_t geoset = tex[j].op; pass.indexStart = ops[geoset].istart; pass.indexCount = ops[geoset].icount; pass.vertexStart = ops[geoset].vstart; pass.vertexEnd = pass.vertexStart + ops[geoset].vcount; pass.order = tex[j].order; TextureID texid = textures[texlookup[tex[j].textureid]]; pass.texture = texid; // TODO: figure out these flags properly -_- ModelRenderFlags &rf = renderFlags[tex[j].flagsIndex]; pass.useenvmap = texunitlookup[tex[j].texunit] == -1; pass.blendmode = rf.blend; pass.color = tex[j].colorIndex; pass.opacity = transLookup[tex[j].transid]; pass.cull = (rf.flags & 4)==0 && rf.blend==0; pass.unlit = (rf.flags & 3)!=0; pass.nozwrite = pass.blendmode >= 2; //(rf.flags & 16)!=0; pass.trans = pass.blendmode != 0; pass.p = ops[geoset].v.x; if (animTextures) { if (tex[j].flags & 16) { pass.texanim = -1; // no texture animation } else { pass.texanim = texanimlookup[tex[j].texanimid]; } } else { pass.texanim = -1; // no texture animation } passes.push_back(pass); } // transparent parts come later std::sort(passes.begin(), passes.end()); // zomg done }
void OutdoorLightStats::init(MPQFile &f) { float h,m; f.seekRelative(4); f.read(&h,4); f.seekRelative(4); f.read(&m,4); f.seekRelative(4); f.read(&dayIntensity,4); f.seekRelative(4); f.read(&dayColor.x,4); f.seekRelative(4); f.read(&dayColor.y,4); f.seekRelative(4); f.read(&dayColor.z,4); f.seekRelative(4); f.read(&dayDir.x,4); f.seekRelative(4); f.read(&dayDir.y,4); f.seekRelative(4); f.read(&dayDir.z,4); f.seekRelative(4); f.read(&nightIntensity, 4); f.seekRelative(4); f.read(&nightColor.x,4); f.seekRelative(4); f.read(&nightColor.y,4); f.seekRelative(4); f.read(&nightColor.z,4); f.seekRelative(4); f.read(&nightDir.x,4); f.seekRelative(4); f.read(&nightDir.y,4); f.seekRelative(4); f.read(&nightDir.z,4); f.seekRelative(4); f.read(&ambientIntensity, 4); f.seekRelative(4); f.read(&ambientColor.x,4); f.seekRelative(4); f.read(&ambientColor.y,4); f.seekRelative(4); f.read(&ambientColor.z,4); f.seekRelative(4); f.read(&fogDepth, 4); f.seekRelative(4); f.read(&fogIntensity, 4); f.seekRelative(4); f.read(&fogColor.x,4); f.seekRelative(4); f.read(&fogColor.y,4); f.seekRelative(4); f.read(&fogColor.z,4); time = (int)h * 60 * 2 + (int)m * 2; // HACK: make day & night intensity exclusive; set day intensity to 1.0 if (dayIntensity > 0) { dayIntensity = 1.0f; nightIntensity = 0.0f; } }
ModelInstance::ModelInstance(MPQFile &f, const char* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE *pDirfile) { float ff[3]; f.read(&id, 4); f.read(ff, 12); pos = fixCoords(Vec3D(ff[0], ff[1], ff[2])); f.read(ff, 12); rot = Vec3D(ff[0], ff[1], ff[2]); f.read(&scale, 4); // scale factor - divide by 1024. blizzard devs must be on crack, why not just use a float? sc = scale / 1024.0f; char tempname[512]; sprintf(tempname, "%s/%s", szWorkDirWmo, ModelInstName); FILE *input; input = fopen(tempname, "r+b"); if (!input) { //printf("ModelInstance::ModelInstance couldn't open %s\n", tempname); return; } fseek(input, 8, SEEK_SET); // get the correct no of vertices int nVertices; fread(&nVertices, sizeof (int), 1, input); fclose(input); if (nVertices == 0) return; uint16 adtId = 0;// not used for models uint32 flags = MOD_M2; if (tileX == 65 && tileY == 65) flags |= MOD_WORLDSPAWN; //write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, name fwrite(&mapID, sizeof(uint32), 1, pDirfile); fwrite(&tileX, sizeof(uint32), 1, pDirfile); fwrite(&tileY, sizeof(uint32), 1, pDirfile); fwrite(&flags, sizeof(uint32), 1, pDirfile); fwrite(&adtId, sizeof(uint16), 1, pDirfile); fwrite(&id, sizeof(uint32), 1, pDirfile); fwrite(&pos, sizeof(float), 3, pDirfile); fwrite(&rot, sizeof(float), 3, pDirfile); fwrite(&sc, sizeof(float), 1, pDirfile); uint32 nlen=strlen(ModelInstName); fwrite(&nlen, sizeof(uint32), 1, pDirfile); fwrite(ModelInstName, sizeof(char), nlen, pDirfile); /* int realx1 = (int) ((float) pos.x / 533.333333f); int realy1 = (int) ((float) pos.z / 533.333333f); int realx2 = (int) ((float) pos.x / 533.333333f); int realy2 = (int) ((float) pos.z / 533.333333f); fprintf(pDirfile, "%s/%s %f, %f, %f_%f, %f, %f %f %d %d %d, %d %d\n", MapName, ModelInstName, (float) pos.x, (float) pos.y, (float) pos.z, (float) rot.x, (float) rot.y, (float) rot.z, sc, nVertices, realx1, realy1, realx2, realy2 ); */ }
void MapTile::saveTile() { Log << "Saving ADT \"" << mFilename << "\"." << std::endl; LogDebug << "CHANGED FLAG " << changed << std::endl; int lID; // This is a global counting variable. Do not store something in here you need later. // Collect some information we need later. // Check which doodads and WMOs are on this ADT. Vec3D lTileExtents[2]; unsigned int UID(0); std::map<int, WMOInstance> lObjectInstances; std::map<int, ModelInstance> lModelInstances; lTileExtents[0] = Vec3D(this->xbase, 0.0f, this->zbase); lTileExtents[1] = Vec3D(this->xbase + TILESIZE, 0.0f, this->zbase + TILESIZE); UID += mPositionX * 10000000; UID += mPositionZ * 100000; for (std::map<int, WMOInstance>::iterator it = gWorld->mWMOInstances.begin(); it != gWorld->mWMOInstances.end(); ++it) { if (!it->second.isInsideTile(lTileExtents)) continue; if (!it->second.hasUIDLock()) { it->second.mUniqueID = UID++; it->second.lockUID(); } lObjectInstances[it->second.mUniqueID] = it->second; } for (std::map<int, ModelInstance>::iterator it = gWorld->mModelInstances.begin(); it != gWorld->mModelInstances.end(); ++it) { if (!it->second.isInsideTile(lTileExtents)) continue; if (!it->second.hasUIDLock()) { it->second.d1 = UID++; it->second.lockUID(); } lModelInstances[it->second.d1] = it->second; } filenameOffsetThing nullyThing = { 0, 0 }; std::map<std::string, filenameOffsetThing> lModels; for (std::map<int, ModelInstance>::iterator it = lModelInstances.begin(); it != lModelInstances.end(); ++it) if (lModels.find(it->second.model->_filename) == lModels.end()) lModels.insert(std::pair<std::string, filenameOffsetThing>(it->second.model->_filename, nullyThing)); lID = 0; for (std::map<std::string, filenameOffsetThing>::iterator it = lModels.begin(); it != lModels.end(); ++it) it->second.nameID = lID++; std::map<std::string, filenameOffsetThing> lObjects; for (std::map<int, WMOInstance>::iterator it = lObjectInstances.begin(); it != lObjectInstances.end(); ++it) if (lObjects.find(it->second.wmo->_filename) == lObjects.end()) lObjects.insert(std::pair<std::string, filenameOffsetThing>((it->second.wmo->_filename), nullyThing)); lID = 0; for (std::map<std::string, filenameOffsetThing>::iterator it = lObjects.begin(); it != lObjects.end(); ++it) it->second.nameID = lID++; // Check which textures are on this ADT. std::map<std::string, int> lTextures; for (int i = 0; i < 16; ++i) for (int j = 0; j < 16; ++j) for (size_t tex = 0; tex < mChunks[i][j]->textureSet->num(); tex++) if (lTextures.find(mChunks[i][j]->textureSet->filename(tex)) == lTextures.end()) lTextures.insert(std::pair<std::string, int>(mChunks[i][j]->textureSet->filename(tex), -1)); lID = 0; for (std::map<std::string, int>::iterator it = lTextures.begin(); it != lTextures.end(); ++it) it->second = lID++; // Now write the file. sExtendableArray *lADTFile = new sExtendableArray(); int lCurrentPosition = 0; // MVER lADTFile->Extend(8 + 0x4); SetChunkHeader(*lADTFile, lCurrentPosition, 'MVER', 4); // MVER data *(lADTFile->GetPointer<int>(8)) = 18; lCurrentPosition += 8 + 0x4; // MHDR int lMHDR_Position = lCurrentPosition; lADTFile->Extend(8 + 0x40); SetChunkHeader(*lADTFile, lCurrentPosition, 'MHDR', 0x40); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->flags = mFlags; lCurrentPosition += 8 + 0x40; // MCIN int lMCIN_Position = lCurrentPosition; lADTFile->Extend(8 + 256 * 0x10); SetChunkHeader(*lADTFile, lCurrentPosition, 'MCIN', 256 * 0x10); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mcin = lCurrentPosition - 0x14; lCurrentPosition += 8 + 256 * 0x10; // MTEX int lMTEX_Position = lCurrentPosition; lADTFile->Extend(8 + 0); // We don't yet know how big this will be. SetChunkHeader(*lADTFile, lCurrentPosition, 'MTEX'); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mtex = lCurrentPosition - 0x14; lCurrentPosition += 8 + 0; // MTEX data for (std::map<std::string, int>::iterator it = lTextures.begin(); it != lTextures.end(); ++it) { lADTFile->Insert(lCurrentPosition, it->first.size() + 1, it->first.c_str()); lCurrentPosition += it->first.size() + 1; lADTFile->GetPointer<sChunkHeader>(lMTEX_Position)->mSize += it->first.size() + 1; LogDebug << "Added texture \"" << it->first << "\"." << std::endl; } // MMDX int lMMDX_Position = lCurrentPosition; lADTFile->Extend(8 + 0); // We don't yet know how big this will be. SetChunkHeader(*lADTFile, lCurrentPosition, 'MMDX'); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mmdx = lCurrentPosition - 0x14; lCurrentPosition += 8 + 0; // MMDX data for (std::map<std::string, filenameOffsetThing>::iterator it = lModels.begin(); it != lModels.end(); ++it) { it->second.filenamePosition = lADTFile->GetPointer<sChunkHeader>(lMMDX_Position)->mSize; lADTFile->Insert(lCurrentPosition, it->first.size() + 1, it->first.c_str()); lCurrentPosition += it->first.size() + 1; lADTFile->GetPointer<sChunkHeader>(lMMDX_Position)->mSize += it->first.size() + 1; LogDebug << "Added model \"" << it->first << "\"." << std::endl; } // MMID int lMMID_Size = 4 * lModels.size(); lADTFile->Extend(8 + lMMID_Size); SetChunkHeader(*lADTFile, lCurrentPosition, 'MMID', lMMID_Size); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mmid = lCurrentPosition - 0x14; // MMID data int * lMMID_Data = lADTFile->GetPointer<int>(lCurrentPosition + 8); lID = 0; for (std::map<std::string, filenameOffsetThing>::iterator it = lModels.begin(); it != lModels.end(); ++it) lMMID_Data[lID++] = it->second.filenamePosition; lCurrentPosition += 8 + lMMID_Size; // MWMO int lMWMO_Position = lCurrentPosition; lADTFile->Extend(8 + 0); // We don't yet know how big this will be. SetChunkHeader(*lADTFile, lCurrentPosition, 'MWMO'); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mwmo = lCurrentPosition - 0x14; lCurrentPosition += 8 + 0; // MWMO data for (std::map<std::string, filenameOffsetThing>::iterator it = lObjects.begin(); it != lObjects.end(); ++it) { it->second.filenamePosition = lADTFile->GetPointer<sChunkHeader>(lMWMO_Position)->mSize; lADTFile->Insert(lCurrentPosition, it->first.size() + 1, it->first.c_str()); lCurrentPosition += it->first.size() + 1; lADTFile->GetPointer<sChunkHeader>(lMWMO_Position)->mSize += it->first.size() + 1; LogDebug << "Added object \"" << it->first << "\"." << std::endl; } // MWID int lMWID_Size = 4 * lObjects.size(); lADTFile->Extend(8 + lMWID_Size); SetChunkHeader(*lADTFile, lCurrentPosition, 'MWID', lMWID_Size); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mwid = lCurrentPosition - 0x14; // MWID data int * lMWID_Data = lADTFile->GetPointer<int>(lCurrentPosition + 8); lID = 0; for (std::map<std::string, filenameOffsetThing>::iterator it = lObjects.begin(); it != lObjects.end(); ++it) lMWID_Data[lID++] = it->second.filenamePosition; lCurrentPosition += 8 + lMWID_Size; // MDDF int lMDDF_Size = 0x24 * lModelInstances.size(); lADTFile->Extend(8 + lMDDF_Size); SetChunkHeader(*lADTFile, lCurrentPosition, 'MDDF', lMDDF_Size); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mddf = lCurrentPosition - 0x14; // MDDF data ENTRY_MDDF* lMDDF_Data = lADTFile->GetPointer<ENTRY_MDDF>(lCurrentPosition + 8); lID = 0; for (std::map<int, ModelInstance>::iterator it = lModelInstances.begin(); it != lModelInstances.end(); ++it) { std::map<std::string, filenameOffsetThing>::iterator lMyFilenameThingey = lModels.find(it->second.model->_filename); if (lMyFilenameThingey == lModels.end()) { LogError << "There is a problem with saving the doodads. We have a doodad that somehow changed the name during the saving function. However this got produced, you can get a reward from schlumpf by pasting him this line." << std::endl; return; } lMDDF_Data[lID].nameID = lMyFilenameThingey->second.nameID; lMDDF_Data[lID].uniqueID = it->second.d1; lMDDF_Data[lID].pos[0] = it->second.pos.x; lMDDF_Data[lID].pos[1] = it->second.pos.y; lMDDF_Data[lID].pos[2] = it->second.pos.z; lMDDF_Data[lID].rot[0] = it->second.dir.x; lMDDF_Data[lID].rot[1] = it->second.dir.y; lMDDF_Data[lID].rot[2] = it->second.dir.z; lMDDF_Data[lID].scale = (uint16_t)(it->second.sc * 1024); lMDDF_Data[lID].flags = 0; lID++; } lCurrentPosition += 8 + lMDDF_Size; LogDebug << "Added " << lID << " doodads to MDDF" << std::endl; // MODF int lMODF_Size = 0x40 * lObjectInstances.size(); lADTFile->Extend(8 + lMODF_Size); SetChunkHeader(*lADTFile, lCurrentPosition, 'MODF', lMODF_Size); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->modf = lCurrentPosition - 0x14; // MODF data ENTRY_MODF *lMODF_Data = lADTFile->GetPointer<ENTRY_MODF>(lCurrentPosition + 8); lID = 0; for (std::map<int, WMOInstance>::iterator it = lObjectInstances.begin(); it != lObjectInstances.end(); ++it) { std::map<std::string, filenameOffsetThing>::iterator lMyFilenameThingey = lObjects.find(it->second.wmo->_filename); if (lMyFilenameThingey == lObjects.end()) { LogError << "There is a problem with saving the objects. We have an object that somehow changed the name during the saving function. However this got produced, you can get a reward from schlumpf by pasting him this line." << std::endl; return; } lMODF_Data[lID].nameID = lMyFilenameThingey->second.nameID; lMODF_Data[lID].uniqueID = it->second.mUniqueID; lMODF_Data[lID].pos[0] = it->second.pos.x; lMODF_Data[lID].pos[1] = it->second.pos.y; lMODF_Data[lID].pos[2] = it->second.pos.z; lMODF_Data[lID].rot[0] = it->second.dir.x; lMODF_Data[lID].rot[1] = it->second.dir.y; lMODF_Data[lID].rot[2] = it->second.dir.z; lMODF_Data[lID].extents[0][0] = it->second.extents[0].x; lMODF_Data[lID].extents[0][1] = it->second.extents[0].y; lMODF_Data[lID].extents[0][2] = it->second.extents[0].z; lMODF_Data[lID].extents[1][0] = it->second.extents[1].x; lMODF_Data[lID].extents[1][1] = it->second.extents[1].y; lMODF_Data[lID].extents[1][2] = it->second.extents[1].z; lMODF_Data[lID].flags = it->second.mFlags; lMODF_Data[lID].doodadSet = it->second.doodadset; lMODF_Data[lID].nameSet = it->second.mNameset; lMODF_Data[lID].unknown = it->second.mUnknown; lID++; } LogDebug << "Added " << lID << " wmos to MODF" << std::endl; lCurrentPosition += 8 + lMODF_Size; //MH2O Water->saveToFile(*lADTFile, lMHDR_Position, lCurrentPosition); // MCNK for (int y = 0; y < 16; ++y) { for (int x = 0; x < 16; ++x) { mChunks[y][x]->save(*lADTFile, lCurrentPosition, lMCIN_Position, lTextures, lObjectInstances, lModelInstances); } } // MFBO if (mFlags & 1) { size_t chunkSize = sizeof(int16_t) * 9 * 2; lADTFile->Extend(8 + chunkSize); SetChunkHeader(*lADTFile, lCurrentPosition, 'MFBO', chunkSize); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mfbo = lCurrentPosition - 0x14; int16_t *lMFBO_Data = lADTFile->GetPointer<int16_t>(lCurrentPosition + 8); lID = 0; for (int i = 0; i < 9; ++i) lMFBO_Data[lID++] = (int16_t)mMinimumValues[i * 3 + 1]; for (int i = 0; i < 9; ++i) lMFBO_Data[lID++] = (int16_t)mMaximumValues[i * 3 + 1]; lCurrentPosition += 8 + chunkSize; } //! \todo Do not do bullshit here in MTFX. #if 0 if (!mTextureEffects.empty()) { //! \todo check if nTexEffects == nTextures, correct order etc. lADTFile->Extend(8 + 4 * mTextureEffects.size()); SetChunkHeader(*lADTFile, lCurrentPosition, 'MTFX', 4 * mTextureEffects.size()); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mtfx = lCurrentPosition - 0x14; uint32_t* lMTFX_Data = lADTFile->GetPointer<uint32_t>(lCurrentPosition + 8); lID = 0; //they should be in the correct order... for (std::vector<int>::iterator it = mTextureEffects.begin(); it != mTextureEffects.end(); ++it) { lMTFX_Data[lID] = *it; ++lID; } lCurrentPosition += 8 + sizeof(uint32_t) * mTextureEffects.size(); } #endif lADTFile->Extend(lCurrentPosition - lADTFile->mSize); // cleaning unused nulls at the end of file MPQFile *f = new MPQFile(mFilename); f->setBuffer(lADTFile->GetPointer<char>(), lADTFile->mSize); f->SaveFile(); f->close(); gWorld->mapIndex->markOnDisc(this->mPositionX, this->mPositionZ, true); lObjectInstances.clear(); lModelInstances.clear(); lModels.clear(); delete f; }
void Model::initAnimated(MPQFile &f) { origVertices = new ModelVertex[header.nVertices]; memcpy(origVertices, f.getBuffer() + header.ofsVertices, header.nVertices * sizeof(ModelVertex)); glGenBuffersARB(1,&vbuf); glGenBuffersARB(1,&tbuf); const size_t size = header.nVertices * sizeof(float); vbufsize = 3 * size; initCommon(f); if (header.nAnimations > 0) { anims = new ModelAnimation[header.nAnimations]; memcpy(anims, f.getBuffer() + header.ofsAnimations, header.nAnimations * sizeof(ModelAnimation)); animfiles = new MPQFile[header.nAnimations]; char tempname[256]; for(size_t i=0; i<header.nAnimations; i++) { sprintf(tempname, "%s%04d-%02d.anim", fullname.c_str(), anims[i].animID, anims[i].subAnimID); if (MPQFile::getSize(tempname) > 0) { animfiles[i].openFile(tempname); } } } if (animBones) { // init bones... bones = new Bone[header.nBones]; ModelBoneDef *mb = (ModelBoneDef*)(f.getBuffer() + header.ofsBones); for (size_t i=0; i<header.nBones; i++) { bones[i].init(f, mb[i], globalSequences, animfiles); } } if (!animGeometry) { glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbuf); glBufferDataARB(GL_ARRAY_BUFFER_ARB, vbufsize, vertices, GL_STATIC_DRAW_ARB); glGenBuffersARB(1,&nbuf); glBindBufferARB(GL_ARRAY_BUFFER_ARB, nbuf); glBufferDataARB(GL_ARRAY_BUFFER_ARB, vbufsize, normals, GL_STATIC_DRAW_ARB); delete[] vertices; delete[] normals; } Vec2D *texcoords = new Vec2D[header.nVertices]; for (size_t i=0; i<header.nVertices; i++) texcoords[i] = origVertices[i].texcoords; glBindBufferARB(GL_ARRAY_BUFFER_ARB, tbuf); glBufferDataARB(GL_ARRAY_BUFFER_ARB, 2*size, texcoords, GL_STATIC_DRAW_ARB); delete[] texcoords; if (animTextures) { texAnims = new TextureAnim[header.nTexAnims]; ModelTexAnimDef *ta = (ModelTexAnimDef*)(f.getBuffer() + header.ofsTexAnims); for (size_t i=0; i<header.nTexAnims; i++) { texAnims[i].init(f, ta[i], globalSequences); } } // particle systems if (header.nParticleEmitters) { ModelParticleEmitterDef *pdefs = (ModelParticleEmitterDef *)(f.getBuffer() + header.ofsParticleEmitters); particleSystems = new ParticleSystem[header.nParticleEmitters]; for (size_t i=0; i<header.nParticleEmitters; i++) { particleSystems[i].model = this; particleSystems[i].init(f, pdefs[i], globalSequences); } } // ribbons if (header.nRibbonEmitters) { ModelRibbonEmitterDef *rdefs = (ModelRibbonEmitterDef *)(f.getBuffer() + header.ofsRibbonEmitters); ribbons = new RibbonEmitter[header.nRibbonEmitters]; for (size_t i=0; i<header.nRibbonEmitters; i++) { ribbons[i].model = this; ribbons[i].init(f, rdefs[i], globalSequences); } } // just use the first camera, meh if (header.nCameras>0) { ModelCameraDef *camDefs = (ModelCameraDef*)(f.getBuffer() + header.ofsCameras); cam.init(f, camDefs[0], globalSequences); } // init lights if (header.nLights) { lights = new ModelLight[header.nLights]; ModelLightDef *lDefs = (ModelLightDef*)(f.getBuffer() + header.ofsLights); for (size_t i=0; i<header.nLights; i++) lights[i].init(f, lDefs[i], globalSequences); } animcalc = false; }
void Model::initCommon(MPQFile &f) { // assume: origVertices already set if (!animGeometry) { vertices = new Vec3D[header.nVertices]; normals = new Vec3D[header.nVertices]; } //Vec3D vmin = Vec3D( 9999999.0f, 9999999.0f, 9999999.0f); //Vec3D vmax = Vec3D(-9999999.0f,-9999999.0f,-9999999.0f); // vertices, normals for (size_t i=0; i<header.nVertices; i++) { origVertices[i].pos = fixCoordSystem(origVertices[i].pos); origVertices[i].normal = fixCoordSystem(origVertices[i].normal); if (!animGeometry) { vertices[i] = origVertices[i].pos; normals[i] = origVertices[i].normal.normalize(); } float len = origVertices[i].pos.lengthSquared(); if (len > rad){ rad = len; } /* if (origVertices[i].pos.x < vmin.x) vmin.x = origVertices[i].pos.x; if (origVertices[i].pos.y < vmin.y) vmin.y = origVertices[i].pos.y; if (origVertices[i].pos.z < vmin.z) vmin.z = origVertices[i].pos.z; if (origVertices[i].pos.x > vmax.x) vmax.x = origVertices[i].pos.x; if (origVertices[i].pos.y > vmax.y) vmax.y = origVertices[i].pos.y; if (origVertices[i].pos.z > vmax.z) vmax.z = origVertices[i].pos.z; */ } rad = sqrtf(rad); //rad = std::max(vmin.length(),vmax.length()); // textures ModelTextureDef *texdef = (ModelTextureDef*)(f.getBuffer() + header.ofsTextures); if (header.nTextures) { textures = new TextureID[header.nTextures]; char texname[256]; for (size_t i=0; i<header.nTextures; i++) { // Error check if (i > TEXTURE_MAX-1) { gLog("Error: Model Texture %d over %d", header.nTextures, TEXTURE_MAX); break; } if (texdef[i].type == 0) { strncpy(texname, (const char*)(f.getBuffer() + texdef[i].nameOfs), texdef[i].nameLen); texname[texdef[i].nameLen] = 0; textures[i] = video.textures.add(texname); } else { // special texture - only on characters and such... textures[i] = 0; specialTextures[i] = texdef[i].type; if (texdef[i].type < TEXTURE_MAX) useReplaceTextures[texdef[i].type] = true; if (texdef[i].type == 3) { // a fix for weapons with type-3 textures. replaceTextures[texdef[i].type] = video.textures.add("Item\\ObjectComponents\\Weapon\\ArmorReflect4.BLP"); } } } } // init colors if (header.nColors) { colors = new ModelColor[header.nColors]; ModelColorDef *colorDefs = (ModelColorDef*)(f.getBuffer() + header.ofsColors); for (size_t i=0; i<header.nColors; i++) colors[i].init(f, colorDefs[i], globalSequences); } // init transparency int16 *transLookup = (int16*)(f.getBuffer() + header.ofsTransparencyLookup); if (header.nTransparency) { transparency = new ModelTransparency[header.nTransparency]; ModelTransDef *trDefs = (ModelTransDef*)(f.getBuffer() + header.ofsTransparency); for (size_t i=0; i<header.nTransparency; i++) transparency[i].init(f, trDefs[i], globalSequences); } // just use the first LOD/view if (header.nViews > 0) { // indices - allocate space, too std::string lodname = fullname.substr(0, fullname.length()-3); fullname = lodname; lodname.append("00.skin"); MPQFile g(lodname.c_str()); if (g.isEof()) { gLog("Error: loading lod [%s]\n", lodname.c_str()); g.close(); return; } ModelView *view = (ModelView*)(g.getBuffer()); uint16 *indexLookup = (uint16*)(g.getBuffer() + view->ofsIndex); uint16 *triangles = (uint16*)(g.getBuffer() + view->ofsTris); nIndices = view->nTris; indices = new uint16[nIndices]; for (size_t i = 0; i<nIndices; i++) { indices[i] = indexLookup[triangles[i]]; } // render ops ModelGeoset *ops = (ModelGeoset*)(g.getBuffer() + view->ofsSub); ModelTexUnit *tex = (ModelTexUnit*)(g.getBuffer() + view->ofsTex); ModelRenderFlags *renderFlags = (ModelRenderFlags*)(f.getBuffer() + header.ofsTexFlags); uint16 *texlookup = (uint16*)(f.getBuffer() + header.ofsTexLookup); uint16 *texanimlookup = (uint16*)(f.getBuffer() + header.ofsTexAnimLookup); int16 *texunitlookup = (int16*)(f.getBuffer() + header.ofsTexUnitLookup); showGeosets = new bool[view->nSub]; for (size_t i=0; i<view->nSub; i++) { showGeosets[i] = true; } for (size_t j = 0; j<view->nTex; j++) { ModelRenderPass pass; pass.usetex2 = false; pass.useEnvMap = false; pass.cull = false; pass.trans = false; pass.unlit = false; pass.noZWrite = false; pass.billboard = false; size_t geoset = tex[j].op; pass.geoset = (int)geoset; pass.indexStart = ops[geoset].istart; pass.indexCount = ops[geoset].icount; pass.vertexStart = ops[geoset].vstart; pass.vertexEnd = pass.vertexStart + ops[geoset].vcount; pass.order = tex[j].shading; //TextureID texid = textures[texlookup[tex[j].textureid]]; //pass.texture = texid; pass.tex = texlookup[tex[j].textureid]; // TODO: figure out these flags properly -_- ModelRenderFlags &rf = renderFlags[tex[j].flagsIndex]; pass.blendmode = rf.blend; pass.color = tex[j].colorIndex; pass.opacity = transLookup[tex[j].transid]; pass.unlit = (rf.flags & RENDERFLAGS_UNLIT)!=0; pass.cull = (rf.flags & RENDERFLAGS_TWOSIDED)==0 && rf.blend==0; pass.billboard = (rf.flags & RENDERFLAGS_BILLBOARD) != 0; pass.useEnvMap = (texunitlookup[tex[j].texunit] == -1) && pass.billboard && rf.blend>2; pass.noZWrite = (rf.flags & RENDERFLAGS_ZBUFFERED) != 0; // ToDo: Work out the correct way to get the true/false of transparency pass.trans = (pass.blendmode>0) && (pass.opacity>0); // Transparency - not the correct way to get transparency pass.p = ops[geoset].BoundingBox[0].x; // Texture flags pass.swrap = (texdef[pass.tex].flags & TEXTURE_WRAPX) != 0; // Texture wrap X pass.twrap = (texdef[pass.tex].flags & TEXTURE_WRAPY) != 0; // Texture wrap Y if (animTextures) { if (tex[j].flags & TEXTUREUNIT_STATIC) { pass.texanim = -1; // no texture animation } else { pass.texanim = texanimlookup[tex[j].texanimid]; } } else { pass.texanim = -1; // no texture animation } passes.push_back(pass); } g.close(); // transparent parts come later std::sort(passes.begin(), passes.end()); } // zomg done }
WMOInstance::WMOInstance(MPQFile &f,const char* WmoInstName,const char*MapName, FILE *pDirfile) { pos = Vec3D(0,0,0); float ff[3]; f.read(&id, 4); f.read(ff,12); pos = Vec3D(ff[0],ff[1],ff[2]); f.read(ff,12); rot = Vec3D(ff[0],ff[1],ff[2]); f.read(ff,12); pos2 = Vec3D(ff[0],ff[1],ff[2]); f.read(ff,12); pos3 = Vec3D(ff[0],ff[1],ff[2]); f.read(&d2,4); f.read(&d3,4); doodadset = (d2 & 0xFFFF0000) >> 16; int realx1 = (int) ((float) pos2.x / 533.333333f); int realy1 = (int) ((float) pos2.z / 533.333333f); int realx2 = (int) ((float) pos3.x / 533.333333f); int realy2 = (int) ((float) pos3.z / 533.333333f); if(realx1 < 0) { realx1 +=20; realx2+=20; } if(realy1 < 0) { realy1 +=20; realy2+=20; } // hack to prevent neg. values //-----------add_in _dir_file---------------- char tempname[512]; // const char dirname[] = "buildings\\dir"; sprintf(tempname, "buildings\\%s", WmoInstName); FILE *input; input = fopen(tempname, "r+b"); if(!input) { return; } fseek(input, 8, SEEK_SET); // get the correct no of vertices int nVertices; fread(&nVertices, sizeof (int), 1, input); fclose(input); if(nVertices == 0) { return; } /* FILE *dirfile; dirfile = fopen(dirname, "ab"); if(!dirfile) { printf("Can't open dirfile!'%s'\n"); return; } */ float x,z; x = pos.x; z = pos.z; if(x==0 && z == 0) { x = 533.33333f*32; z = 533.33333f*32; } fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f 1.0 %d %d %d,%d %d\n", MapName, WmoInstName, (float) x, (float) pos.y, (float) z, (float) rot.x, (float) rot.y, (float) rot.z, nVertices, realx1, realy1, realx2, realy2 ); // fclose(dirfile); }
inline void LoadMapChunk(MPQFile & mf, chunk*_chunk) { float h; uint32 fourcc; uint32 size; MapChunkHeader header; mf.seekRelative(4); mf.read(&size, 4); size_t lastpos = mf.getPos() + size; mf.read(&header, 0x80); _chunk->area_id =header.areaid ; _chunk->flag =0; float xbase = header.xpos; float ybase = header.ypos; float zbase = header.zpos; zbase = TILESIZE*32-zbase; xbase = TILESIZE*32-xbase; if(wmoc.x >xbase)wmoc.x =xbase; if(wmoc.z >zbase)wmoc.z =zbase; int chunkflags = header.flags; float zmin=999999999.0f; float zmax=-999999999.0f; //must be there, bl!zz uses some crazy format int nTextures; while (mf.getPos() < lastpos) { mf.read(&fourcc,4); mf.read(&size, 4); //if(size!=580) // printf("\n sz=%d",size); size_t nextpos = mf.getPos() + size; if(fourcc==0x4d435654) // MCVT { for (int j=0; j<17; j++) for (int i=0; i<((j%2)?8:9); i++) { mf.read(&h,4); float z=h+ybase; if (j%2) { if(isHole(header.holes,i,j)) _chunk->v8[i][j/2] = -1000; else _chunk->v8[i][j/2] = z; } else { if(isHole(header.holes,i,j)) _chunk->v9[i][j/2] = -1000; else _chunk->v9[i][j/2] = z; } if(z>zmax)zmax=z; //if(z<zmin)zmin=z; } } else if(fourcc==0x4d434e52) // MCNR { nextpos = mf.getPos() + 0x1C0; // size fix } else if(fourcc==0x4d434c51) // MCLQ { // liquid / water level //bool haswater; char fcc1[5]; mf.read(fcc1,4); flipcc(fcc1); fcc1[4]=0; if (!strcmp(fcc1,"MCSE")) { for(int i=0;i<9;i++) for(int j=0;j<9;j++) _chunk->waterlevel[i][j]=-999999; // no liquid/water } else { float maxheight; mf.read(&maxheight, 4); for(int j=0;j<9;j++) for(int i=0;i<9;i++) { mf.read(&h, 4); mf.read(&h, 4); if(h > maxheight) _chunk->waterlevel[i][j]=-999999; else _chunk->waterlevel[i][j]=h; } if(chunkflags & 4 || chunkflags & 8) _chunk->flag |=1; if(chunkflags & 16) _chunk->flag |=2; } break; } else if (fourcc==0x4d434c59) // MCLY { // texture info nTextures = (int)size; } else if (fourcc==0x4d43414c) // MCAL { if (nTextures<=0) continue; } mf.seek(nextpos); } }
LiquidModelInstance::LiquidModelInstance(MPQFile &f, uint32 base_pos, uint32 tileID, MH20_Header* header, uint32 mapID, uint32 tileX, uint32 tileY, FILE *pDirfile) : Info(false) { memset(&LiqHeader, 0, sizeof(LiquidHeader)); LiqHeader.layerCount = header->layerCount; if(header->ofsInformation == 0) { Info = false; return; } #ifdef _DEBUG printf("Information offset: %i\n", header->ofsInformation); #endif f.seek(header->ofsInformation+base_pos); f.read(&LiqHeader.info, sizeof(MH20_Information)); #ifdef _DEBUG if(LiqHeader.info.LiquidType != 2) // Skip oceans { printf("Liquid Data Dump:\n"); printf("Flags: %08i |\n", LiqHeader.info.flags); // printf("Height %08i |\n", LiqHeader.info.height); // printf("Level1 %08f |\n", LiqHeader.info.heightLevel1); // printf("Level2 %08f |\n", LiqHeader.info.heightLevel2); printf("LType: %08i |\n", LiqHeader.info.LiquidType); printf("Width: %08i |\n", LiqHeader.info.width); printf("xOfset %08i |\n", LiqHeader.info.xOffset); printf("yOfset %08i |\n", LiqHeader.info.yOffset); WaitForInput(); } #endif uint16* buff = new uint16[3]; buff[0] = buff[1] = buff[2] = 0; if(LiqHeader.info.ofsHeightmap > 0) { #ifdef _DEBUG printf("Height Map Offset: %i\n", LiqHeader.info.ofsHeightmap); #endif f.seek(LiqHeader.info.ofsHeightmap+base_pos); f.read(&LiqHeader.heightMap.heightMap, sizeof(float)*2); f.read(&LiqHeader.heightMap.transparency, sizeof(char)*2); buff[0] = sizeof(LiqHeader.heightMap); } if(LiqHeader.info.ofsMask2 > 0) { #ifdef _DEBUG printf("Mask Offset: %i\n", LiqHeader.info.ofsMask2); #endif f.seek(LiqHeader.info.ofsMask2+base_pos); f.read(&LiqHeader.Mask2, sizeof(uint8)); buff[1] = sizeof(uint8); } if(header->ofsRender > 0) { #ifdef _DEBUG printf("Render offset: %i\n", header->ofsRender); #endif f.seek(header->ofsRender+base_pos); f.read(&LiqHeader.Render, sizeof(uint64)); buff[2] = sizeof(uint64); } fwrite(&LiqHeader.layerCount, sizeof(uint32), 1, pDirfile); fwrite(&LiqHeader.info, sizeof(MH20_Information), 1, pDirfile); fwrite(&buff[0], sizeof(uint16), 1, pDirfile); if(buff[0]) fwrite(&LiqHeader.heightMap, sizeof(MH2O_HeightMapData), 1, pDirfile); fwrite(&buff[1], sizeof(uint16), 1, pDirfile); if(buff[1]) fwrite(&LiqHeader.Mask2, sizeof(uint8), 1, pDirfile); fwrite(&buff[2], sizeof(uint16), 1, pDirfile); if(buff[2]) fwrite(&LiqHeader.Render, sizeof(uint64), 1, pDirfile); }
bool Model::isAnimated(MPQFile &f) { // see if we have any animated bones ModelBoneDef *bo = (ModelBoneDef*)(f.getBuffer() + header.ofsBones); animGeometry = false; animBones = false; ind = false; ModelVertex *verts = (ModelVertex*)(f.getBuffer() + header.ofsVertices); for (size_t i=0; i<header.nVertices && !animGeometry; i++) { for (size_t b=0; b<4; b++) { if (verts[i].weights[b]>0) { ModelBoneDef &bb = bo[verts[i].bones[b]]; if (bb.translation.type || bb.rotation.type || bb.scaling.type || (bb.flags&8)) { if (bb.flags&8) { // if we have billboarding, the model will need per-instance animation ind = true; } animGeometry = true; break; } } } } if (animGeometry) animBones = true; else { for (size_t i=0; i<header.nBones; i++) { ModelBoneDef &bb = bo[i]; if (bb.translation.type || bb.rotation.type || bb.scaling.type) { animBones = true; break; } } } animTextures = header.nTexAnims > 0; bool animMisc = header.nCameras>0 || // why waste time, pretty much all models with cameras need animation header.nLights>0 || // same here header.nParticleEmitters>0 || header.nRibbonEmitters>0; if (animMisc) animBones = true; // animated colors if (header.nColors) { ModelColorDef *cols = (ModelColorDef*)(f.getBuffer() + header.ofsColors); for (size_t i=0; i<header.nColors; i++) { if (cols[i].color.type!=0 || cols[i].opacity.type!=0) { animMisc = true; break; } } } // animated opacity if (header.nTransparency && !animMisc) { ModelTransDef *trs = (ModelTransDef*)(f.getBuffer() + header.ofsTransparency); for (size_t i=0; i<header.nTransparency; i++) { if (trs[i].trans.type!=0) { animMisc = true; break; } } } // guess not... return animGeometry || animTextures || animMisc; }
inline void LoadMapChunk(MPQFile &mf, chunk *_chunk) { float h; uint32 fourcc; uint32 size; MapChunkHeader header; mf.seekRelative(4); mf.read(&size, 4); size_t lastpos = mf.getPos() + size; mf.read(&header, 0x80); // what if header size got changed? _chunk->area_id = header.areaid; float xbase = header.xpos; float ybase = header.ypos; float zbase = header.zpos; zbase = TILESIZE * 32 - zbase; xbase = TILESIZE * 32 - xbase; if(wmoc.x > xbase) wmoc.x = xbase; if(wmoc.z > zbase) wmoc.z = zbase; int chunkflags = header.flags; //printf("LMC: flags %X\n", chunkflags); float zmin = 999999999.0f; float zmax = -999999999.0f; // must be there, bl!zz uses some crazy format while (mf.getPos() < lastpos) { mf.read(&fourcc, 4); mf.read(&size, 4); size_t nextpos = mf.getPos() + size; if(fourcc == 0x4d435654) // MCVT { for (int j = 0; j < 17; ++j) { for (int i = 0; i < ((j % 2) ? 8 : 9); ++i) { mf.read(&h, 4); float z = h + ybase; if (j % 2) { if(isHole(header.holes, i, j)) _chunk->v8[i][j / 2] = -1000; else _chunk->v8[i][j / 2] = z; } else { if(isHole(header.holes, i, j)) _chunk->v9[i][j / 2] = -1000; else _chunk->v9[i][j / 2] = z; } if(z > zmax) zmax = z; //if(z < zmin) zmin = z; } } } else if(fourcc == 0x4d434e52) // MCNR { nextpos = mf.getPos() + 0x1C0; // size fix } else if(fourcc == 0x4d434c51) // MCLQ { // liquid / water level char fcc1[5]; mf.read(fcc1, 4); flipcc(fcc1); fcc1[4] = 0; float *ChunkLiqHeight = new float[81]; if (!strcmp(fcc1, "MCSE")) { for(int j = 0; j < 81; ++j) { ChunkLiqHeight[j] = -999999; // no liquid/water } } else { float maxheight; mf.read(&maxheight, 4); for(int j = 0; j < 81; ++j) { LiqData liq; mf.read(&liq, 8); if(liq.height > maxheight) ChunkLiqHeight[j] = -999999; else ChunkLiqHeight[j] = h; } if(chunkflags & 4 || chunkflags & 8) MapLiqFlag[chunk_num] |= 1; // water if(chunkflags & 16) MapLiqFlag[chunk_num] |= 2; // magma/slime } if(!(chunk_num % 16)) m = 1024 * (chunk_num / 16); k = m + (chunk_num % 16) * 8; for(int p = 0; p < 72; p += 9) { for(int s = 0; s < 8; ++s) { MapLiqHeight[k] = ChunkLiqHeight[p + s]; ++k; } k = k + 120; } delete []ChunkLiqHeight; break; } mf.seek(nextpos); } }
WMOInstance::WMOInstance(MPQFile& f, const char* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile) { pos = Vec3D(0, 0, 0); float ff[3]; f.read(&id, 4); f.read(ff, 12); pos = Vec3D(ff[0], ff[1], ff[2]); f.read(ff, 12); rot = Vec3D(ff[0], ff[1], ff[2]); f.read(ff, 12); pos2 = Vec3D(ff[0], ff[1], ff[2]); f.read(ff, 12); pos3 = Vec3D(ff[0], ff[1], ff[2]); f.read(&d2, 4); uint16 trash, adtId; f.read(&adtId, 2); f.read(&trash, 2); //-----------add_in _dir_file---------------- char tempname[512]; sprintf(tempname, "%s/%s", szWorkDirWmo, WmoInstName); FILE* input; input = fopen(tempname, "r+b"); if (!input) { printf("WMOInstance::WMOInstance: couldn't open %s\n", tempname); return; } fseek(input, 8, SEEK_SET); // get the correct no of vertices int nVertices; fread(&nVertices, sizeof(int), 1, input); fclose(input); if (nVertices == 0) return; float x, z; x = pos.x; z = pos.z; if (x == 0 && z == 0) { pos.x = 533.33333f * 32; pos.z = 533.33333f * 32; } pos = fixCoords(pos); pos2 = fixCoords(pos2); pos3 = fixCoords(pos3); float scale = 1.0f; uint32 flags = MOD_HAS_BOUND; if (tileX == 65 && tileY == 65) flags |= MOD_WORLDSPAWN; //write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name fwrite(&mapID, sizeof(uint32), 1, pDirfile); fwrite(&tileX, sizeof(uint32), 1, pDirfile); fwrite(&tileY, sizeof(uint32), 1, pDirfile); fwrite(&flags, sizeof(uint32), 1, pDirfile); fwrite(&adtId, sizeof(uint16), 1, pDirfile); fwrite(&id, sizeof(uint32), 1, pDirfile); fwrite(&pos, sizeof(float), 3, pDirfile); fwrite(&rot, sizeof(float), 3, pDirfile); fwrite(&scale, sizeof(float), 1, pDirfile); fwrite(&pos2, sizeof(float), 3, pDirfile); fwrite(&pos3, sizeof(float), 3, pDirfile); uint32 nlen = strlen(WmoInstName); fwrite(&nlen, sizeof(uint32), 1, pDirfile); fwrite(WmoInstName, sizeof(char), nlen, pDirfile); /* fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f 1.0 %d %d %d,%d %d\n", MapName, WmoInstName, (float) x, (float) pos.y, (float) z, (float) rot.x, (float) rot.y, (float) rot.z, nVertices, realx1, realy1, realx2, realy2 ); */ // fclose(dirfile); }
Application::Application(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MPQInit(); instance = this; resources = NULL; imageLibrary = NULL; dotaLibrary = NULL; mainWindow = NULL; cache = NULL; hInstance = _hInstance; _loaded = false; root = String::getPath(getAppPath()); cfg.read(); warLoader = new MPQLoader("Custom_V1"); warLoader->loadArchive(String::buildFullName(cfg.warPath, "war3.mpq")); warLoader->loadArchive(String::buildFullName(cfg.warPath, "war3x.mpq")); warLoader->loadArchive(String::buildFullName(cfg.warPath, "war3xlocal.mpq")); warLoader->loadArchive(String::buildFullName(cfg.warPath, "war3patch.mpq")); if (logCommand(lpCmdLine)) return; ScriptType::initTypes(); UpdateDialog::init(hInstance); INITCOMMONCONTROLSEX iccex; iccex.dwSize = sizeof iccex; iccex.dwICC = ICC_STANDARD_CLASSES | ICC_PROGRESS_CLASS | ICC_BAR_CLASSES | ICC_TREEVIEW_CLASSES | ICC_LISTVIEW_CLASSES | ICC_TAB_CLASSES | ICC_UPDOWN_CLASS | ICC_DATE_CLASSES; InitCommonControlsEx(&iccex); LoadLibrary("Riched20.dll"); OleInitialize(NULL); String path = String::getPath(getAppPath()); String resPath = String::buildFullName(path, "resources.mpq"); String patchPath = String::buildFullName(path, "install.mpq"); File* tOpen = File::open(resPath, File::READ); if (tOpen == NULL) { tOpen = File::open(patchPath, File::READ); if (tOpen) { delete tOpen; MoveFile(patchPath, resPath); } } else delete tOpen; resources = MPQArchive::open(resPath); MPQArchive* patch = MPQArchive::open(patchPath, File::READ); if (patch) { for (uint32 i = 0; i < patch->getHashSize(); i++) { char const* name = patch->getFileName(i); if (name) { MPQFile* source = patch->openFile(i, File::READ); if (source) { MPQFile* dest = resources->openFile(name, File::REWRITE); if (dest) { static uint8 buf[1024]; while (int length = source->read(buf, sizeof buf)) dest->write(buf, length); delete dest; } delete source; } } } delete patch; DeleteFile(patchPath); } imageLibrary = new ImageLibrary(resources); cache = new CacheManager(); dotaLibrary = new DotaLibrary(); #if 0 File* dlog = File::open("diff.txt", File::REWRITE); for (int pt = 0; pt < 120; pt++) { String prev = ""; bool different = false; for (int ver = 1; ver <= 80 && !different; ver++) { Dota* dota = dotaLibrary->getDota(makeVersion(6, ver)); if (dota) { Dota::Hero* hero = dota->getHero(pt); if (hero) { if (prev == "") prev = hero->name; else if (prev.icompare(hero->name)) different = true; } } } if (different) { dlog->printf(" Pt=%d\r\n", pt); prev = ""; for (int ver = 1; ver <= 80; ver++) { Dota* dota = dotaLibrary->getDota(makeVersion(6, ver)); if (dota) { Dota::Hero* hero = dota->getHero(pt); if (hero) { if (prev.icompare(hero->name)) { dlog->printf("6.%02d = %s\r\n", ver, hero->name); prev = hero->name; } } } } } } delete dlog; #endif #if 0 dotaLibrary->getDota(parseVersion("6.79e"), "K:\\Progs\\DotAReplay\\maps\\DotA v6.79e.w3x"); WIN32_FIND_DATA data; String enumPath = "K:\\Progs\\DotAReplay\\maps"; HANDLE hFind = FindFirstFile(String::buildFullName(enumPath, "*"), &data); BOOL success = (hFind != INVALID_HANDLE_VALUE); while (success) { String file(data.cFileName); if (String::getExtension(file).icompare(".w3x") == 0) { file.toLower(); Array<String> sub; if (file.rfind("dota{{_| }allstars}?{_| }v(\\d)\\.(\\d\\d)([b-z]?)[^b-z]", 0, &sub) >= 0) { int major = sub[1].toInt(); int minor = sub[2].toInt(); int build = 0; if (!sub[3].isEmpty()) build = int(sub[3][0] - 'a'); uint32 version = makeVersion(major, minor, build); dotaLibrary->getDota(version, String::buildFullName(enumPath, file)); } } success = FindNextFile(hFind, &data); } FindClose(hFind); #endif mainWindow = new MainWnd(); mainWindow->postLoad(); _loaded = true; if (lpCmdLine[0]) { COPYDATASTRUCT cd; cd.dwData = MAINWND_OPEN_REPLAY; cd.cbData = strlen(lpCmdLine) + 1; cd.lpData = lpCmdLine; PostMessage(getMainWindow(), WM_COPYDATA_FAKE, NULL, (LPARAM) &cd); } }