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

📄 charcontrol.cpp

📁 wowmodelview魔兽世界的模型查看工具。下了看看吧
💻 CPP
📖 第 1 页 / 共 5 页
字号:
							} catch (ItemVisualEffectDB::NotFound) {}
						}
					} catch (ItemVisualDB::NotFound) {}
				}

			} else {
				cd.equipment[slot] = 0; // no such model? :(
			}

		} catch (ItemDisplayDB::NotFound) {}
	}
}

void CharControl::RefreshCreatureItem(int slot)
{
	// delete all attachments in that slot
	canvas->root->delSlot(slot);

	int itemnum = cd.equipment[slot];
	if (itemnum!=0) {
		// load new model(s)
		int id1=-1;
		string path;
		//float sc = 1.0f;

		if (slot == CS_HAND_LEFT) 
			id1 = 2;
		else if (slot == CS_HAND_RIGHT) 
			id1 = 1;
		else 
			return;

		if (slot==CS_HAND_LEFT || slot==CS_HAND_RIGHT) {
			if (items.get(itemnum).type == IT_SHIELD) {
				path = "Item\\ObjectComponents\\Shield\\";
				id1 = 0;
			} else {
				path = "Item\\ObjectComponents\\Weapon\\";
			}
		}

		try {
			const ItemRecord &item = items.get(itemnum);
			ItemDisplayDB::Record r = itemdb.getById(item.model);

			GLuint tex;
			string mp;
			bool succ = false;
			Attachment *att = NULL;
			Model *m = NULL;

			if (id1>=0) {
				mp = path + r.getString(ItemDisplayDB::Model);

				if (mp.length()) {
					att = canvas->root->addChild(mp.c_str(), id1, slot);
					if (att) {
						m = static_cast<Model*>(att->model);
						if (m->ok) {
							mp = path + r.getString(ItemDisplayDB::Skin);
							mp.append(".blp");
							tex = texturemanager.add(mp);
							m->replaceTextures[2] = tex;
							succ = true;
						}
					}
				}
			}

			if (succ) {
				// okay, see if we have any glowy effects
				int visualid = r.getInt(ItemDisplayDB::Visuals);
				
				if (visualid == 0) {
					if ((modelViewer->enchants->RHandEnchant > -1) && (slot == CS_HAND_RIGHT)) {
						visualid = modelViewer->enchants->RHandEnchant;
					} else if ((modelViewer->enchants->LHandEnchant > -1) && (slot == CS_HAND_LEFT)) {
						visualid = modelViewer->enchants->LHandEnchant;
					}
				}

				if (m == NULL)
					m = static_cast<Model*>(att->model);

				if (visualid > 0) {
					try {
						ItemVisualDB::Record vis = visualdb.getById(visualid);
						for (int i=0; i<5; i++) {
							// try all five visual slots
							int effectid = vis.getInt(ItemVisualDB::Effect1 + i);
							if (effectid==0 || m->attLookup[i]<0) continue;

							try {
								ItemVisualEffectDB::Record eff = effectdb.getById(effectid);
								const char *filename = eff.getString(ItemVisualEffectDB::Model);

								att->addChild(filename, i, -1);

							} catch (ItemVisualEffectDB::NotFound) {}
						}
					} catch (ItemVisualDB::NotFound) {}
				}

			} else {
				cd.equipment[slot] = 0; // no such model? :(
			}

		} catch (ItemDisplayDB::NotFound) {}
	}
}

std::string CharControl::makeItemTexture(int region, const char *name)
{
	// just return an empty filename
	if (!name || !strlen(name)) return "";

	// try gender-specific version first
	std::string fn = regionPaths[region];
	fn += name;
	fn += "_";
	fn += cd.gender ? "F" : "M";
	fn += ".blp";
	if (MPQFile::exists(fn.c_str())) return fn;

	// try unisex version
	fn[fn.length()-5] = 'U';
	return fn;
}

void CharTexture::compose(TextureID tex)
{
	// if we only have one texture then don't bother with compositing
	if (components.size()==1) {
		Texture temp(components[0].name);
		texturemanager.LoadBLP(tex, &temp);
		return;
	}

	std::sort(components.begin(), components.end());
	unsigned char destbuf[256*256*4], tempbuf[256*256*4];
	memset(destbuf, 0, 256*256*4);

	for (std::vector<CharTextureComponent>::iterator it = components.begin(); it != components.end(); ++it) {
		CharTextureComponent &comp = *it;
		const CharRegionCoords &coords = regions[comp.region];
		TextureID temptex = texturemanager.add(comp.name);
		Texture &tex = *((Texture*)texturemanager.items[temptex]);

		tex.getPixels(tempbuf);

		// blit the texture region over the original

		//assert(tex.w==coords.xsize && tex.h==coords.ysize);
		if (tex.w==coords.xsize && tex.h==coords.ysize) {
			for (int y=0, dy=coords.ypos; y<tex.h; y++,dy++) {
				for (int x=0, dx=coords.xpos; x<tex.w; x++,dx++) {
					unsigned char *src = tempbuf + y*tex.w*4 + x*4;
					unsigned char *dest = destbuf + dy*256*4 + dx*4;

					// this is slow and ugly but I don't care
					float r = src[3] / 255.0f;
					float ir = 1.0f - r;
					// zomg RGBA?
					dest[0] = (unsigned char)(dest[0]*ir + src[0]*r);
					dest[1] = (unsigned char)(dest[1]*ir + src[1]*r);
					dest[2] = (unsigned char)(dest[2]*ir + src[2]*r);
					dest[3] = 255;
				}
			}
		}

		texturemanager.del(temptex);
	}

	// good, upload this to video
	glBindTexture(GL_TEXTURE_2D, tex);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, destbuf);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);}

void CharDetails::reset()
{
	skinColor = 0;
	faceType = 0;
	hairColor = 0;
	hairStyle = 0;
	facialHair = 0;

	showUnderwear = true;
	showHair = true;
	showFacialHair = true;
	showEars = true;

	for (int i=0; i<NUM_CHAR_SLOTS; i++) {
		equipment[i] = 0;
	}
}


bool correctType(int type, int slot)
{
	if (type == IT_ALL) 
		return true;

	switch (slot) {
	case CS_HEAD:		return (type == IT_HEAD);
	case CS_NECK:		return (type == IT_NECK);
	case CS_SHOULDER:	return (type == IT_SHOULDER);
	case CS_SHIRT:		return (type == IT_SHIRT);
	case CS_CHEST:		return (type == IT_CHEST || type == IT_ROBE);
	case CS_BELT:		return (type == IT_BELT);
	case CS_PANTS:		return (type == IT_PANTS);
	case CS_BOOTS:		return (type == IT_BOOTS);
	case CS_BRACERS:	return (type == IT_BRACERS);
	case CS_GLOVES:		return (type == IT_GLOVES);
	//case CS_HAND_RIGHT:	return (type == IT_1HANDED || type == IT_GUN || type == IT_2HANDED || type == IT_CLAW || type == IT_DAGGER);
	//case CS_HAND_LEFT:	return (type == IT_1HANDED || type == IT_SHIELD || type == IT_DAGGER || type == IT_BOW);
	case CS_HAND_RIGHT:	return (type == IT_1HANDED || type == IT_GUN || type == IT_THROWN || type == IT_2HANDED || type == IT_CLAW || type == IT_DAGGER);
	case CS_HAND_LEFT:	return (type == IT_1HANDED || type == IT_BOW || type == IT_2HANDED || type == IT_SHIELD || type == IT_CLAW || type == IT_DAGGER || type == IT_OFFHAND);
	case CS_CAPE:		return (type == IT_CAPE);
	case CS_TABARD:		return (type == IT_TABARD);
	}
	return false;
}


void CharControl::ClearItemDialog()
{
	if (itemDialog) {
		itemDialog->Show(FALSE);
		delete itemDialog;
		itemDialog = 0;
	}
}

void CharControl::selectItem(int slot, int current, const wxChar *caption)
{
	ClearItemDialog();

	numbers.clear();
	choices.Clear();

	// collect all items for this slot, making note of the occurring subclasses
	set<pair<int,int> > subclassesFound;
	
	int sel=0, ord=0;
	for (std::vector<ItemRecord>::iterator it = items.items.begin(); it != items.items.end(); ++it) {
		if (correctType(it->type, slot)) {
			choices.Add(wxString(it->name, *wxConvCurrent));
			numbers.push_back(it->id);
			if (it->id == (unsigned int)current) sel = ord;
			ord++;

			if (it->itemclass > 0) 
				subclassesFound.insert(pair<int,int>(it->itemclass,it->subclass));
		}
	}

	// make category list
	cats.clear();
	catnames.clear();

	map<pair<int,int>, int> subclasslookup;
	for (ItemSubClassDB::Iterator it=subclassdb.begin(); it != subclassdb.end(); ++it) {
		int cl = it->getInt(ItemSubClassDB::ClassID);
		int scl = it->getInt(ItemSubClassDB::SubClassID);
		// only add the subclass if it was found in the itemlist
		if (cl>0 && subclassesFound.find(pair<int,int>(cl,scl)) != subclassesFound.end()) {
			
			// Used to go through the 'string fields' looking for the one with data.
			wxString str;
			for (int i = ItemSubClassDB::Name; i<18; i++)
			{
				str = wxString(it->getString(i), *wxConvCurrent);
				if (!str.IsEmpty()) {
					//p.name = str.fn_str();
					break;
				}
			}
			//string str = it->getString(ItemSubClassDB::Name);

			int hands = it->getInt(ItemSubClassDB::Hands);
			if (hands > 0) {
				char buf[16];
				sprintf(buf, " (%d-handed)", hands);
				str.append(buf);
			}
			catnames.Add(str.c_str());
			subclasslookup[pair<int,int>(cl,scl)] = (int)catnames.size()-1;
		}
	}

	if (subclassesFound.size() > 1) {
		// build category list
		for (size_t i=0; i<numbers.size(); i++) {
			ItemRecord r = items.get(numbers[i]);
			cats.push_back(subclasslookup[pair<int,int>(r.itemclass, r.subclass)]);
		}

		itemDialog = new CategoryChoiceDialog(this, UPDATE_ITEM, canvas->GetParent(), _T("Choose an item"), caption, choices, cats, catnames);
	} else {
		itemDialog = new FilteredChoiceDialog(this, UPDATE_ITEM, canvas->GetParent(), _T("Choose an item"), caption, choices);
	}

	itemDialog->SetSelection(sel);

	wxSize s = itemDialog->GetSize();
	const int w = 250;
	if (s.GetWidth() > w) {
		itemDialog->SetSizeHints(w,-1,-1,-1,-1,-1);
		itemDialog->SetSize(w, -1);
	}

	itemDialog->Move(itemDialog->GetParent()->GetPosition() + wxPoint(4,64));
	itemDialog->Show();
	choosingSlot = slot;
}

/*
struct NumStringPair {
	int id;
	string name;

	const bool operator< (const NumStringPair &p) const {
		return name < p.name;
	}
};
*/

void CharControl::selectSet()
{
	ClearItemDialog();

	std::vector<NumStringPair> items;

	for (ItemSetDB::Iterator it = sets.begin(); it != sets.end(); ++it) {
		int id = it->getUInt(ItemSetDB::SetID);
		if (sets.available(id)) {
			NumStringPair p;
			p.id = id;
			
			// Used to go through the 'string fields' looking for the one with data.
			for (int i = ItemSetDB::Name; i<9; i++)
			{
				//wxString str = wxString(it->getString(i), *wxConvCurrent);
				wxString str(wxCSConv("iso-8859-1").cWC2WX(wxConvUTF8.cMB2WC(it->getString(i))));
				if (!str.IsEmpty()) {
					p.name = str.fn_str();
					break;
				}
			}
			//p.name = it->getString(ItemSetDB::Name);

			items.push_back(p);
		}
	}

	std::sort(items.begin(), items.end());
	numbers.clear();
	choices.Clear();
	for (std::vector<NumStringPair>::iterator it = items.begin(); it != items.end(); ++it) {
		//choices.Add(wxString(it->name.c_str(), *wxConvCurrent));
		choices.Add(wxString(it->name.c_str(), *wxConvCurrent));
		numbers.push_back(it->id);
	}

	itemDialog = new FilteredChoiceDialog(this, UPDATE_SET, canvas->GetParent(), _("Choose an item set"), _("Item sets"), choices);
	itemDialog->Move(itemDialog->GetParent()->GetPosition() + wxPoint(4,64));
	itemDialog->Show();
}

void CharControl::selectStart()
{
	ClearItemDialog();

	numbers.clear();
	choices.Clear();

	for (StartOutfitDB::Iterator it = start.begin(); it != start.end(); ++it) {
		if ((it->getByte(StartOutfitDB::Race) == cd.race) && (it->getByte(StartOutfitDB::Gender) == cd.gender)) {
			try {
				CharClassesDB::Record r = classdb.getById(it->getByte(StartOutfitDB::Class));

				for (int i = CharClassesDB::Name; i<13; i++)
				{
					//wxString str = wxString(r.getString(i), *wxConvCurrent);
					wxString str(wxCSConv("iso-8859-1").cWC2WX(wxConvUTF8.cMB2WC(r.getString(i))));
					if (!str.IsEmpty()) {
						choices.Add(str);
						numbers.push_back(it->getUInt(StartOutfitDB::StartOutfitID));
						break;
					}
				}
			} catch (CharClassesDB::NotFound) {}
		}
	}

	itemDialog = new ChoiceDialog(this, UPDATE_START, canvas->GetParent(), _T("Choose a class"), _T("Classes"), choices);
	itemDialog->Move(itemDialog->GetParent()->GetPosition() + wxPoint(4,64));
	itemDialog->Show();
}

bool filterCreatures(string fn)
{
	wxString tmp(fn);
	tmp.LowerCase();
	const size_t len = tmp.Length();
	if (len < 4) return false;
	return (tmp[0]=='c' && tmp[1]=='r' && tmp[len-1]=='2' && tmp[len-2]=='m');
}

vector<wxString> creaturemodels;
vector<bool> ridablelist;

// TODO: Add an equivilant working version of this function for Linux / Mac OS X
void CharControl::selectMount()
{
#ifdef _WIN32
	ClearItemDialog();

⌨️ 快捷键说明

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