Exemple #1
0
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);
}
Exemple #2
0
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;
}
Exemple #3
0
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;
}
Exemple #4
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);
	}
}
Exemple #5
0
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);

}
Exemple #6
0
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);
}
Exemple #7
0
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;
}
Exemple #8
0
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
            );
    }
}
Exemple #9
0
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);
}
Exemple #10
0
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);
}
Exemple #11
0
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);
}
Exemple #12
0
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]);
	*/
}
Exemple #13
0
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);
}
Exemple #14
0
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;
}
Exemple #15
0
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
}
Exemple #16
0
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;
	}
}
Exemple #17
0
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
        ); */
}
Exemple #18
0
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;
}
Exemple #19
0
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;
}
Exemple #20
0
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
}
Exemple #21
0
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);
}
Exemple #22
0
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);
    }
}
Exemple #23
0
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);
}
Exemple #24
0
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;
}
Exemple #25
0
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);
    }
}
Exemple #26
0
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);
    }
}