⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wmo.cpp

📁 wowmodelview魔兽世界的模型查看工具。下了看看吧
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "wmo.h"
#include "util.h"
//#include "world.h"
//#include "liquid.h"


using namespace std;

WMO::WMO(std::string name): ManagedItem(name)
{
	MPQFile f(name.c_str());
	ok = !f.isEof();
	if (!ok) {
		//gLog("Error loading WMO %s\n", name.c_str());
		return;
	}

	//gLog("Loading WMO %s\n", name.c_str());

	char fourcc[5];
	size_t size;
	float ff[3];

	char *ddnames;
	groupnames = 0;

	skybox = 0;
	doodadset = -1;
	includeDefaultDoodads = true;

	char *texbuf=0;

	while (!f.isEof()) {
		f.read(fourcc,4);
		f.read(&size, 4);

		flipcc(fourcc);
		fourcc[4] = 0;

		size_t nextpos = f.getPos() + size;

		if (!strcmp(fourcc,"MOHD")) {
			unsigned int col;
			// header
			f.read(&nTextures, 4);
			f.read(&nGroups, 4);
			f.read(&nP, 4);
			f.read(&nLights, 4);
			f.read(&nModels, 4);
			f.read(&nDoodads, 4);
			f.read(&nDoodadSets, 4);
			f.read(&col, 4);
			f.read(&nX, 4);
			f.read(ff,12);
			v1 = Vec3D(ff[0],ff[1],ff[2]);
			f.read(ff,12);
			v2 = Vec3D(ff[0],ff[1],ff[2]);

			groups = new WMOGroup[nGroups];
			mat = new WMOMaterial[nTextures];

		}
		else if (!strcmp(fourcc,"MOTX")) {
			// textures
			texbuf = new char[size];
			f.read(texbuf, size);
		}
		else if (!strcmp(fourcc,"MOMT")) {
			// materials
			//WMOMaterialBlock bl;

			for (int i=0; i<nTextures; i++) {
				WMOMaterial *m = &mat[i];
				f.read(m, 0x40);

				string texpath(texbuf+m->nameStart);
				fixname(texpath);

				m->tex = texturemanager.add(texpath);
				textures.push_back(texpath);
								// need repeat turned on				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
				/*
				// material logging
				gLog("Material %d:\t%d\t%d\t%d\t%X\t%d\t%X\t%d\t%f\t%f",
					i, m->flags, m->d1, m->transparent, m->col1, m->d3, m->col2, m->d4, m->f1, m->f2);
				for (int j=0; j<5; j++) gLog("\t%d", m->dx[j]);
				gLog("\t - %s\n", texpath.c_str());
				*/

			}
		}
		else if (!strcmp(fourcc,"MOGN")) {
			groupnames = new char[size];
			memcpy(groupnames,f.getPointer(),size);
			
			//groupnames = (char*)f.getPointer();
		}
		else if (!strcmp(fourcc,"MOGI")) {
			// group info - important information! ^_^
			for (int i=0; i<nGroups; i++) {
				groups[i].init(this, f, i, groupnames);

			}
		}
		else if (!strcmp(fourcc,"MOLT")) {
			// Lights?
			for (int i=0; i<nLights; i++) {
				WMOLight l;
				l.init(f);
				lights.push_back(l);
			}
		}
		else if (!strcmp(fourcc,"MODN")) {
			// models ...
			// MMID would be relative offsets for MMDX filenames
			if (size) {

				ddnames = (char*)f.getPointer();
				fixnamen(ddnames, size);

				char *p=ddnames,*end=p+size;
				
				while (p<end) {
					string path(p);
					p+=strlen(p)+1;
					while ((p<end) && (*p==0)) p++;

					//gWorld->modelmanager.add(path);
					models.push_back(path);
				}
				f.seekRelative((int)size);
			}
		}
		else if (!strcmp(fourcc,"MODS")) {
			for (int i=0; i<nDoodadSets; i++) {
				WMODoodadSet dds;
				f.read(&dds, 32);
				doodadsets.push_back(dds);
			}
		}
		else if (!strcmp(fourcc,"MODD")) {
			nModels = (int)size / 0x28;
			for (int i=0; i<nModels; i++) {
				int ofs;
				f.read(&ofs,4);
				//Model *m = (Model*)gWorld->modelmanager.items[gWorld->modelmanager.get(ddnames + ofs)];
				WMOModelInstance mi;
				mi.init(ddnames+ofs, f);
				modelis.push_back(mi);
			}

		}
		else if (!strcmp(fourcc,"MOSB")) {
			if (size>4) {
				string path = (char*)f.getPointer();
				fixname(path);
				if (path.length()) {
					//gLog("SKYBOX:\n");

					//sbid = gWorld->modelmanager.add(path);
					//skybox = (Model*)gWorld->modelmanager.items[sbid];

					/*if (!skybox->ok) {
						gWorld->modelmanager.del(sbid);
						skybox = 0;
					}
					*/

				}
			}
		}
		else if (!strcmp(fourcc,"MOPV")) {
			WMOPV p;
			for (int i=0; i<nP; i++) {
				f.read(ff,12);
				p.a = Vec3D(ff[0],ff[2],-ff[1]);
				f.read(ff,12);
				p.b = Vec3D(ff[0],ff[2],-ff[1]);
				f.read(ff,12);
				p.c = Vec3D(ff[0],ff[2],-ff[1]);
				f.read(ff,12);
				p.d = Vec3D(ff[0],ff[2],-ff[1]);
				pvs.push_back(p);
			}
		}
		else if (!strcmp(fourcc,"MOPR")) {
			int nn = (int)size / 8;
			WMOPR *pr = (WMOPR*)f.getPointer();
			for (int i=0; i<nn; i++) {
				prs.push_back(*pr++);
			}
		}
		else if (!strcmp(fourcc,"MFOG")) {
			int nfogs = (int)size / 0x30;
			for (int i=0; i<nfogs; i++) {
				WMOFog fog;
				fog.init(f);
				fogs.push_back(fog);
			}
		}

		f.seek((int)nextpos);
	}

	f.close();
	delete[] texbuf;

	//for (int i=0; i<nGroups; i++) groups[i].initDisplayList();

}

WMO::~WMO()
{
	if (ok) {
		//gLog("Unloading WMO %s\n", name.c_str());
		delete[] groups;

		for (vector<string>::iterator it = textures.begin(); it != textures.end(); ++it) {
            texturemanager.delbyname(*it);
		}

		/*
		for (vector<string>::iterator it = models.begin(); it != models.end(); ++it) {
			//gWorld->modelmanager.delbyname(*it);
		}
		*/

		delete[] mat;

		/*
		if (skybox) {
			delete skybox;
			//gWorld->modelmanager.del(sbid);
		}
		*/

		loadedModels.clear();
		delete groupnames;
	}
}

void WMO::loadGroup(int id)
{
	if (id==-1) {
		for (int i=0; i<nGroups; i++) {
			groups[i].initDisplayList();
			groups[i].visible = true;
		}
	}
	else if (id>=0 && id<nGroups) {
		groups[id].initDisplayList();
		for (int i=0; i<nGroups; i++) {
			groups[i].visible = (i==id);
			if (i!=id) groups[i].cleanup();
		}
	}
	updateModels();
}

void WMO::showDoodadSet(int id)
{
	doodadset = id;
	updateModels();
}

void WMO::updateModels()
{
	// 1. look for visible models that aren't loaded
	for (int i=0; i<nGroups; i++) if (groups[i].visible) groups[i].updateModels(true);
	// 2. unload unused models
	for (int i=0; i<nGroups; i++) if (!groups[i].visible) groups[i].updateModels(false);
}

void WMO::update(int dt)
{
	loadedModels.resetAnim();
	loadedModels.updateEmitters(dt/1000.0f);
}

void WMOGroup::updateModels(bool load)
{
	if (!ddr || !ok || nDoodads==0) 
		return;

	for (int i=0; i<nDoodads; i++) {
		short dd = ddr[i];

		bool inSet;

		if (wmo->doodadset==-1) {
			inSet = false;
		} else {
			inSet = ( ((dd >= wmo->doodadsets[wmo->doodadset].start) && (dd < (wmo->doodadsets[wmo->doodadset].start+wmo->doodadsets[wmo->doodadset].size)))
			|| ( wmo->includeDefaultDoodads && (dd >= wmo->doodadsets[0].start) && ((dd < (wmo->doodadsets[0].start+wmo->doodadsets[0].size) )) ) );
		}

		if (inSet) {
			WMOModelInstance &mi = wmo->modelis[dd];

			if (load && !mi.model) 
				mi.loadModel(wmo->loadedModels);
			else if (!load && mi.model) 
				mi.unloadModel(wmo->loadedModels);
		}
	}
}

void WMO::draw()
{
	if (!ok) return;

	for (int i=0; i<nGroups; i++) {
		groups[i].draw();
	}

	for (int i=0; i<nGroups; i++) {
		groups[i].drawDoodads(doodadset);
	}

	for (int i=0; i<nGroups; i++) {
		groups[i].drawLiquid();
	}

	/*
	// draw light placeholders
	glDisable(GL_LIGHTING);
	glDisable(GL_CULL_FACE);
	glDisable(GL_TEXTURE_2D);
	glBegin(GL_TRIANGLES);
	for (int i=0; i<nLights; i++) {
		glColor4fv(lights[i].fcolor);
		glVertex3fv(lights[i].pos);
		glVertex3fv(lights[i].pos + Vec3D(-0.5f,1,0));
		glVertex3fv(lights[i].pos + Vec3D(0.5f,1,0));
	}
	glEnd();
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_CULL_FACE);
	glEnable(GL_LIGHTING);
	glColor4f(1,1,1,1);
	*/

	/*
	// draw fog positions..?
	glDisable(GL_LIGHTING);
	glDisable(GL_TEXTURE_2D);
	for (size_t i=0; i<fogs.size(); i++) {
		WMOFog &fog = fogs[i];
		glColor4f(1,1,1,1);
		glBegin(GL_LINE_LOOP);
		glVertex3fv(fog.pos);
		glVertex3fv(fog.pos + Vec3D(fog.rad1, 5, -fog.rad2));
		glVertex3fv(fog.pos + Vec3D(fog.rad1, 5, fog.rad2));
		glVertex3fv(fog.pos + Vec3D(-fog.rad1, 5, fog.rad2));
		glVertex3fv(fog.pos + Vec3D(-fog.rad1, 5, -fog.rad2));
		glEnd();
	}
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_LIGHTING);
	*/

	/*
	// draw group boundingboxes
	glDisable(GL_LIGHTING);
	glDisable(GL_TEXTURE_2D);
	for (int i=0; i<nGroups; i++) {
		WMOGroup &g = groups[i];
		float fc[2] = {1,0};
		glColor4f(fc[i%2],fc[(i/2)%2],fc[(i/3)%2],1);
		glBegin(GL_LINE_LOOP);

		glVertex3f(g.b1.x, g.b1.y, g.b1.z);
		glVertex3f(g.b1.x, g.b2.y, g.b1.z);
		glVertex3f(g.b2.x, g.b2.y, g.b1.z);
		glVertex3f(g.b2.x, g.b1.y, g.b1.z);

		glVertex3f(g.b2.x, g.b1.y, g.b2.z);
		glVertex3f(g.b2.x, g.b2.y, g.b2.z);
		glVertex3f(g.b1.x, g.b2.y, g.b2.z);
		glVertex3f(g.b1.x, g.b1.y, g.b2.z);

		glEnd();
	}
	// draw portal relations
	glBegin(GL_LINES);
	for (size_t i=0; i<prs.size(); i++) {
		WMOPR &pr = prs[i];
		WMOPV &pv = pvs[pr.portal];
		if (pr.dir>0) glColor4f(1,0,0,1);
		else glColor4f(0,0,1,1);
		Vec3D pc = (pv.a+pv.b+pv.c+pv.d)*0.25f;
		Vec3D gc = (groups[pr.group].b1 + groups[pr.group].b2)*0.5f;
		glVertex3fv(pc);
		glVertex3fv(gc);
	}
	glEnd();
	glColor4f(1,1,1,1);
	// draw portals
	for (int i=0; i<nP; i++) {
		glBegin(GL_LINE_STRIP);
		glVertex3fv(pvs[i].d);
		glVertex3fv(pvs[i].c);
		glVertex3fv(pvs[i].b);
		glVertex3fv(pvs[i].a);
		glEnd();
	}
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_LIGHTING);
	*/
}

void WMO::drawSkybox()
{
	if (skybox) {
		// TODO: only draw sky if we are "inside" the WMO... ?

		// We need to clear the depth buffer, because the skybox model can (will?)
		// require it *. This is inefficient - is there a better way to do this?
		// * planets in front of "space" in Caverns of Time
		//glClear(GL_DEPTH_BUFFER_BIT);

		// update: skybox models seem to have an explicit renderop ordering!
		// that saves us the depth buffer clear and the depth testing, too

		/*
		glDisable(GL_CULL_FACE);
		glDisable(GL_DEPTH_TEST);
		glPushMatrix();
		Vec3D o = gWorld->camera;
		glTranslatef(o.x, o.y, o.z);
		const float sc = 2.0f;
		glScalef(sc,sc,sc);
        skybox->draw();
		glPopMatrix();
		gWorld->hadSky = true;
		glEnable(GL_DEPTH_TEST);
		*/
	}
}

/*
void WMO::drawPortals()
{
	// not used ;)
	glBegin(GL_QUADS);
	for (int i=0; i<nP; i++) {
		glVertex3fv(pvs[i].d);
		glVertex3fv(pvs[i].c);
		glVertex3fv(pvs[i].b);
		glVertex3fv(pvs[i].a);
	}
	glEnd();
}
*/

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]);
	*/
}

void WMOLight::setup(GLint light)
{
	// not used right now -_-

	GLfloat LightAmbient[] = {0, 0, 0, 1.0f};
	GLfloat LightPosition[] = {pos.x, pos.y, pos.z, 0.0f};

	glLightfv(light, GL_AMBIENT, LightAmbient);
	glLightfv(light, GL_DIFFUSE, fcolor);
	glLightfv(light, GL_POSITION,LightPosition);

	glEnable(light);
}

void WMOLight::setupOnce(GLint light, Vec3D dir, Vec3D lcol)
{
	Vec4D position(dir, 0);
	//Vec4D position(0,1,0,0);

	Vec4D ambient = Vec4D(lcol * 0.3f, 1);
	//Vec4D ambient = Vec4D(0.101961f, 0.062776f, 0, 1);
	Vec4D diffuse = Vec4D(lcol, 1);
	//Vec4D diffuse = Vec4D(0.439216f, 0.266667f, 0, 1);

	glLightfv(light, GL_AMBIENT, ambient);
	glLightfv(light, GL_DIFFUSE, diffuse);
	glLightfv(light, GL_POSITION,position);

	glEnable(light);
}



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;

	ok = false;
	visible = false;
}


struct WMOBatch {
	signed char bytes[12];
	unsigned int indexStart;
	unsigned short indexCount, vertexStart, vertexEnd;
	unsigned char flags, texture;
};

void setGLColor(unsigned int col)
{
	//glColor4ubv((GLubyte*)(&col));
	GLubyte r,g,b,a;
	a = (col & 0xFF000000) >> 24;
	r = (col & 0x00FF0000) >> 16;
	g = (col & 0x0000FF00) >> 8;
	b = (col & 0x000000FF);
    glColor4ub(r,g,b,1);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -