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

📄 wmo.cpp

📁 wowmodelview魔兽世界的模型查看工具。下了看看吧
💻 CPP
📖 第 1 页 / 共 2 页
字号:
}

struct WMOGroupHeader {
    int nameStart, nameStart2, flags;
	float box1[3], box2[3];
	short portalStart, portalCount;
	short batches[4];
	uint8 fogs[4];
	int32 unk1, id, unk2, unk3;
};

void WMOGroup::initDisplayList()
{
	Vec3D *vertices, *normals;
	Vec2D *texcoords;
	unsigned short *indices;
	unsigned short *materials;
	WMOBatch *batches;
	int nBatches;

	WMOGroupHeader gh;

	short *useLights = 0;
	int nLR = 0;

	// open group file
	char temp[256];
	strcpy(temp, wmo->name.c_str());
    temp[wmo->name.length()-4] = 0;

	char fname[256];
	sprintf(fname,"%s_%03d.wmo",temp, num);

	MPQFile gf(fname);
    gf.seek(0x14);

	// read header
	gf.read(&gh, sizeof(WMOGroupHeader));
	WMOFog &wf = wmo->fogs[gh.fogs[0]];
	if (wf.r2 <= 0) fog = -1; // default outdoor fog..?
	else fog = gh.fogs[0];

	name = string(wmo->groupnames + gh.nameStart);
	desc = string(wmo->groupnames + gh.nameStart2);

	b1 = Vec3D(gh.box1[0], gh.box1[2], -gh.box1[1]);
	b2 = Vec3D(gh.box2[0], gh.box2[2], -gh.box2[1]);

	gf.seek(0x58); // first chunk
	char fourcc[5];
	size_t size;

	unsigned int *cv;
	hascv = false;

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

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

		size_t nextpos = gf.getPos() + size;

		// why copy stuff when I can just map it from memory ^_^

		if (!strcmp(fourcc,"MOPY")) {
			// materials per triangle
			nTriangles = (int)size / 2;
			materials = (unsigned short*)gf.getPointer();
		}
		else if (!strcmp(fourcc,"MOVI")) {
			// indices
			indices =  (unsigned short*)gf.getPointer();
		}
		else if (!strcmp(fourcc,"MOVT")) {
			nVertices = (int)size / 12;
			// let's hope it's padded to 12 bytes, not 16...
			vertices =  (Vec3D*)gf.getPointer();
			vmin = Vec3D( 9999999.0f, 9999999.0f, 9999999.0f);
			vmax = Vec3D(-9999999.0f,-9999999.0f,-9999999.0f);
			rad = 0;
			for (int i=0; i<nVertices; i++) {
				Vec3D v(vertices[i].x, vertices[i].z, -vertices[i].y);
				if (v.x < vmin.x) vmin.x = v.x;
				if (v.y < vmin.y) vmin.y = v.y;
				if (v.z < vmin.z) vmin.z = v.z;
				if (v.x > vmax.x) vmax.x = v.x;
				if (v.y > vmax.y) vmax.y = v.y;
				if (v.z > vmax.z) vmax.z = v.z;
			}
			center = (vmax + vmin) * 0.5f;
			rad = (vmax-center).length();
		}
		else if (!strcmp(fourcc,"MONR")) {
			normals =  (Vec3D*)gf.getPointer();
		}
		else if (!strcmp(fourcc,"MOTV")) {
			texcoords =  (Vec2D*)gf.getPointer();
		}
		else if (!strcmp(fourcc,"MOLR")) {
			nLR = (int)size / 2;
			useLights =  (short*)gf.getPointer();
		}
		else if (!strcmp(fourcc,"MODR")) {
			if (ddr) delete ddr;
			nDoodads = (int)size / 2;
			ddr = new short[nDoodads];
			gf.read(ddr,size);
		}
		else if (!strcmp(fourcc,"MOBA")) {
			nBatches = (int)size / 24;
			batches = (WMOBatch*)gf.getPointer();

			/*
			// batch logging
			gLog("\nWMO group #%d - %s\nVertices: %d\nTriangles: %d\nIndices: %d\nBatches: %d\n",
				this->num, this->name.c_str(), nVertices, nTriangles, nTriangles*3, nBatches);
			WMOBatch *ba = batches;
			for (int i=0; i<nBatches; i++) {
				gLog("Batch %d:\t", i);

				for (int j=0; j<12; j++) {
					if ((j%4)==0 && j!=0) gLog("| ");
					gLog("%d\t", ba[i].bytes[j]);
				}

				gLog("| %d\t%d\t| %d\t%d\t", ba[i].indexStart, ba[i].indexCount, ba[i].vertexStart, ba[i].vertexEnd);
				gLog("%d\t%d\t%s\n", ba[i].flags, ba[i].texture, wmo->textures[ba[i].texture].c_str());

			}
			int l = nBatches-1;
			gLog("Max index: %d\n", ba[l].indexStart + ba[l].indexCount);
			*/

		}
		else if (!strcmp(fourcc,"MOCV")) {
			//gLog("CV: %d\n", size);
			hascv = true;
			cv = (unsigned int*)gf.getPointer();
		}
		else if (!strcmp(fourcc,"MLIQ")) {
			// liquids
			WMOLiquidHeader hlq;
			gf.read(&hlq, 0x1E);

			//gLog("WMO Liquid: %dx%d, %dx%d, (%f,%f,%f) %d\n", hlq.X, hlq.Y, hlq.A, hlq.B, hlq.pos.x, hlq.pos.y, hlq.pos.z, hlq.type);

			//lq = new Liquid(hlq.A, hlq.B, Vec3D(hlq.pos.x, hlq.pos.z, -hlq.pos.y));
			//lq->initFromWMO(gf, wmo->mat[hlq.type], (flags&0x2000)!=0);
		}

		// TODO: figure out/use MFOG ?

 		gf.seek((int)nextpos);
	}

	// ok, make a display list

	indoor = (flags&8192)!=0;
	//gLog("Lighting: %s %X\n\n", indoor?"Indoor":"Outdoor", flags);

	initLighting(nLR,useLights);

	dl = glGenLists(1);
	glNewList(dl, GL_COMPILE);
	glDisable(GL_BLEND);

	glColor4f(1,1,1,1);

	/*
	float xr=0,xg=0,xb=0;
	if (flags & 0x0040) xr = 1;
	if (flags & 0x2000) xg = 1;
	if (flags & 0x8000) xb = 1;
	glColor4f(xr,xg,xb,1);
	*/

	// assume that texturing is on, for unit 1

	for (int b=0; b<nBatches; b++) {
		WMOBatch *batch = &batches[b];
		WMOMaterial *mat = &wmo->mat[batch->texture];

        // setup texture
		glBindTexture(GL_TEXTURE_2D, mat->tex);

		bool atest = (mat->transparent) != 0;

		if (atest) {
			glEnable(GL_ALPHA_TEST);
			float aval = 0;
            if (mat->flags & 0x80) aval = 0.3f;
			if (mat->flags & 0x01) aval = 0.0f;
			glAlphaFunc(GL_GREATER, aval);
		}

		if (mat->flags & 0x04) glDisable(GL_CULL_FACE);
		else glEnable(GL_CULL_FACE);

		/*
		float fr,fg,fb;
		fr = rand()/(float)RAND_MAX;
		fg = rand()/(float)RAND_MAX;
		fb = rand()/(float)RAND_MAX;
		glColor4f(fr,fg,fb,1);
		*/

		bool overbright = ((mat->flags & 0x10) && !hascv);
		if (overbright) {
			// TODO: use emissive color from the WMO Material instead of 1,1,1,1
			GLfloat em[4] = {1,1,1,1};
			glMaterialfv(GL_FRONT, GL_EMISSION, em);
		}

		// render
		glBegin(GL_TRIANGLES);
		for (int t=0, i=batch->indexStart; t<batch->indexCount; t++,i++) {
			int a = indices[i];
			if (indoor && hascv) {
	            setGLColor(cv[a]);
			}
			glNormal3f(normals[a].x, normals[a].z, -normals[a].y);
			glTexCoord2fv(texcoords[a]);
			glVertex3f(vertices[a].x, vertices[a].z, -vertices[a].y);
		}
		glEnd();

		if (overbright) {
			GLfloat em[4] = {0,0,0,1};
			glMaterialfv(GL_FRONT, GL_EMISSION, em);
		}

		if (atest) {
			glDisable(GL_ALPHA_TEST);
		}
	}

	glColor4f(1,1,1,1);
	glEnable(GL_CULL_FACE);

	glEndList();

	gf.close();

	// hmm
	indoor = false;

	ok = true;
}


void WMOGroup::initLighting(int nLR, short *useLights)
{
	dl_light = 0;
	// "real" lighting?
	if ((flags&0x2000) && hascv) {

		Vec3D dirmin(1,1,1);
		float lenmin;
		int lmin;

		for (int i=0; i<nDoodads; i++) {
			lenmin = 999999.0f*999999.0f;
			lmin = 0;
			WMOModelInstance &mi = wmo->modelis[ddr[i]];
			for (int j=0; j<wmo->nLights; j++) {
				WMOLight &l = wmo->lights[j];
				Vec3D dir = l.pos - mi.pos;
				float ll = dir.lengthSquared();
				if (ll < lenmin) {
					lenmin = ll;
					dirmin = dir;
					lmin = j;
				}
			}
			mi.light = lmin;
			mi.ldir = dirmin;
		}

		outdoorLights = false;
	} else {
		outdoorLights = true;
	}
}

void WMOGroup::draw()
{
	if (!ok) {
		visible = false;
		return;
	}

	visible = true;

	if (hascv) {
		glDisable(GL_LIGHTING);
	}
	//setupFog();

	glCallList(dl);

	if (hascv) {
		glEnable(GL_LIGHTING);
	}
}

void WMOGroup::drawDoodads(int doodadset)
{
	if (!visible) return;
	if (nDoodads==0) return;
	if (doodadset<0) return;

	//setupFog();

	/*
	float xr=0,xg=0,xb=0;
	if (flags & 0x0040) xr = 1;
	//if (flags & 0x0008) xg = 1;
	if (flags & 0x8000) xb = 1;
	glColor4f(xr,xg,xb,1);
	*/

	// draw doodads
	glColor4f(1,1,1,1);
	for (int i=0; i<nDoodads; i++) {
		short dd = ddr[i];
		
		bool inSet;
		if (doodadset==-1) {
			inSet = false;
		} else {
			inSet = ( ((dd >= wmo->doodadsets[doodadset].start) && (dd < (wmo->doodadsets[doodadset].start+wmo->doodadsets[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 (!outdoorLights) {
				glDisable(GL_LIGHT0);
				WMOLight::setupOnce(GL_LIGHT2, mi.ldir, mi.lcol);
			} else {
				glEnable(GL_LIGHT0);
			}

			wmo->modelis[dd].draw();
		}
	}

	glDisable(GL_LIGHT2);

	glColor4f(1,1,1,1);

}

void WMOGroup::drawLiquid()
{
	if (!visible) return;

	/*

	// draw liquid
	// TODO: culling for liquid boundingbox or something
	if (lq) {
		setupFog();
		if (outdoorLights) {
			//gWorld->outdoorLights(true);
		} else {
			// TODO: setup some kind of indoor lighting... ?
			//gWorld->outdoorLights(false);
			glEnable(GL_LIGHT2);
			glLightfv(GL_LIGHT2, GL_AMBIENT, Vec4D(0.1f,0.1f,0.1f,1));
			glLightfv(GL_LIGHT2, GL_DIFFUSE, Vec4D(0.8f,0.8f,0.8f,1));
			glLightfv(GL_LIGHT2, GL_POSITION, Vec4D(0,1,0,0));
		}
		glDisable(GL_BLEND);
		glDisable(GL_ALPHA_TEST);
		glDepthMask(GL_TRUE);
		glColor4f(1,1,1,1);
		lq->draw();
		glDisable(GL_LIGHT2);
	}

	*/
}

void WMOGroup::setupFog()
{
	/*
	if (outdoorLights || fog==-1) {
		gWorld->setupFog();
	} else {
		wmo->fogs[fog].setup();
	}
	*/
}



WMOGroup::~WMOGroup()
{
	cleanup();
	if (ddr) delete ddr;
}

void WMOGroup::cleanup()
{
	if (dl) glDeleteLists(dl, 1);
	dl = 0;
	if (dl_light) glDeleteLists(dl_light, 1);
	dl_light = 0;
	//if (lq) delete lq; lq = 0;
	ok = false;
}

void WMOFog::init(MPQFile &f)
{
	f.read(this, 0x30);
	color = Vec4D( ((color1 & 0x00FF0000) >> 16)/255.0f, ((color1 & 0x0000FF00) >> 8)/255.0f,
					(color1 & 0x000000FF)/255.0f, ((color1 & 0xFF000000) >> 24)/255.0f);
	float temp;
	temp = pos.y;
	pos.y = pos.z;
	pos.z = -temp;
	fogstart = fogstart * fogend;
}

void WMOFog::setup()
{
	/*
	if (gWorld->drawfog) {
		glFogfv(GL_FOG_COLOR, color);
		glFogf(GL_FOG_START, fogstart);
		glFogf(GL_FOG_END, fogend);

		glEnable(GL_FOG);
	} else {
		glDisable(GL_FOG);
	}
	*/
}

/*

int WMOManager::add(std::string name)
{
	int id;
	if (names.find(name) != names.end()) {
		id = names[name];
		items[id]->addref();
		//gLog("Loading WMO %s [already loaded]\n",name.c_str());
		return id;
	}

	// load new
	WMO *wmo = new WMO(name);
	id = nextID();
    do_add(name, id, wmo);
    return id;
}



WMOInstance::WMOInstance(WMO *wmo, MPQFile &f) : wmo (wmo)
{
	float ff[3];
    f.read(&id, 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(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;

	//gLog("WMO instance: %s (%d, %d)\n", wmo->name.c_str(), d2, d3);
}

void WMOInstance::draw()
{
	if (ids.find(id) != ids.end()) return;
	ids.insert(id);

	glPushMatrix();
	glTranslatef(pos.x, pos.y, pos.z);

	float rot = -90.0f + dir.y;

	// TODO: replace this with a single transform matrix calculated at load time

	glRotatef(dir.y - 90.0f, 0, 1, 0);
	glRotatef(-dir.x, 0, 0, 1);
	glRotatef(dir.z, 1, 0, 0);

	wmo->draw(doodadset,pos,-rot);

	glPopMatrix();
}

void WMOInstance::reset()
{
    ids.clear();
}

std::set<int> WMOInstance::ids;

*/

void WMOModelInstance::init(char *fname, MPQFile &f){	filename = fname;	model = 0;	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 glQuaternionRotate(const Vec3D& vdir, float w){	Matrix m;	Quaternion q(vdir, w);	m.quaternionRotate(q);	glMultMatrixf(m);}void WMOModelInstance::draw(){	if (!model) return;	glPushMatrix();	glTranslatef(pos.x, pos.y, pos.z);	Vec3D vdir(-dir.z,dir.x,dir.y);	glQuaternionRotate(vdir,w);	glScalef(sc,-sc,-sc);	model->draw();	glPopMatrix();}void WMOModelInstance::loadModel(ModelManager &mm)
{
    model = (Model*)mm.items[mm.add(filename)];
	model->isWMO = true;
}

void WMOModelInstance::unloadModel(ModelManager &mm)
{
	mm.delbyname(filename);
	model = 0;
}

⌨️ 快捷键说明

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