private WhModel LoadWhCharacterModel(WhRace race, WhGender gender, string[] itemIds) { var gathererItems = WhDataLoader.LoadItemsFromGatherer(itemIds); var options = new WhViewerOptions() { Cls = WhClass.WARRIOR, Hd = true }; if (gathererItems != null) { options.Items = gathererItems .Select((x, i) => new WhViewerOptions.Item() { Slot = x.Value.OtherData.SlotBak, Id = x.Value.OtherData.DisplayId, // Пока так, когда узнать откуда взять этот id - надо тоже прописать VisualId = null }) .ToArray(); } var characterModel = new WhModel( options, WhModelInfo.CreateForCharacter(race, gender), 0); WhDefferedList.Execute(); characterModel.EmulateDraw(false); return(characterModel); }
private WowBone[] MakeBoneHierarchyFromWhModel(WhModel whModel) { if (whModel.Bones == null || whModel.Bones.Length == 0) { return(null); } // Формируем начальный массив всех костей и задаем абсолютные позиции для всех костей (прописываем их временно в локальную позицию) var wowBones = whModel.Bones .Select(x => new WowBone() { Index = Convert.ToByte(x.Index), Id = x.Id, LocalPosition = Vec3.Scale(Vec3.ConvertPositionFromWh(x.Pivot), _scale) }) .ToArray(); // Прописываем иерархию родители/дети для всех костей for (int boneIdx = 0; boneIdx < wowBones.Length; boneIdx++) { var wowBone = wowBones[boneIdx]; var whBone = whModel.Bones[boneIdx]; // Если у текущей кости есть родительская кость if (whBone.Parent >= 0) { wowBone.ParentBone = wowBones[whBone.Parent]; wowBone.ParentBone.ChildBones.Add(wowBone); } } return(wowBones); }
public WhBone(WhModel model, int index, BinaryReader r) { Model = model; Index = index; KeyId = r.ReadInt32(); Flags = r.ReadUInt32(); Parent = r.ReadInt16(); Mesh = r.ReadUInt16(); Id = r.ReadUInt32(); Pivot = new Vec3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); Translation = WhAnimatedVec3.ReadSet(r); Rotation = WhAnimatedQuat.ReadSet(r); Scale = WhAnimatedVec3.ReadSet(r); Hidden = false; Updated = false; // Не стал делать //self.transformedPivot = vec3.create(); //self.matrix = mat4.create(); //self.tmpVec = vec3.create(); //self.tmpQuat = quat.create(); //self.tmpMat = mat4.create(); // Я сделал. -1 значит что эта переменная будет игнорироваться при Update модели IndexInParentModel = -1; }
private WowMeshWithMaterials MakeMeshFromWhModel(WhModel whModel) { var mesh = new WowMeshWithMaterials(); mesh.Vertices = whModel.Vertices.Select(x => MakeVertexFromWhVertex(x)).ToArray(); mesh.Submeshes = new List <WowSubmeshWithMaterials>(); foreach (var whTexUnit in whModel.SortedTexUnits) { if (!whTexUnit.Show) { continue; } var triangles = ConvertTrianglesFromWh(whModel.Indices .Skip(whTexUnit.Mesh.IndexStart) .Take(whTexUnit.Mesh.IndexCount) .ToArray()); var material = MakeMaterialFromWhTexUnit(whTexUnit); var submesh = new WowSubmeshWithMaterials(mesh, triangles, material); mesh.Submeshes.Add(submesh); } mesh.RemoveUnusedVertices(); return(mesh); }
private void AddAdditionalMeshToCharacterObject(WowObject characterObject, WhModel whModel) { var itemObject = new WowObject() { Parent = characterObject, GlobalPosition = new Vec3(0, 0, 0), }; // На этот раз добавляем не в MainMesh а делаем дополнительный меш, таким образом этот меш будет исползовать те же кости что и основной characterObject.Meshes.Add(MakeMeshFromWhModel(whModel)); }
public WhItemVisual(WhModel model, int id) { Model = model; Models = null; Loaded = false; if (id != 0) { Load(id); } }
private WhModel LoadWhCharacterModel(WhViewerOptions opts) { var characterModel = new WhModel( opts, opts.Model, 0); WhDefferedList.Execute(); characterModel.EmulateDraw(false); return(characterModel); }
public WhMaterial(WhModel model, int index, BinaryReader r) { Model = model; Index = index; Type = r.ReadInt32(); Flags = r.ReadUInt32(); Filename = r.ReadUInt32(); Texture = null; Load(); }
// ToDo: так как тут идет ссылка на Bitmap, который IDispossable, возможно стоит этот класс тоже сделать IDispossable (у js варианта есть destroy метод) // ToDo: незнаю пока какого типа index, пока будет int (возможно он не используется, тогда убрать его вообще) // Иногда сюда присваивается значение из енума Region, а иногда 0 или 1 (которые по энаму региона явно ничего не значат), то есть видмо разное может означать этот индекс public WhTexture(WhModel model, int index, uint file) { Model = model; Index = index; // url формировать и сохранять тут не буду, т.к. он нафиг не нужен // также не буду добавлять alphaimg, mergedimg и текстуры, так как по сути это все одно и то же (= Img) Img = null; Loaded = false; WhDefferedList.Add(() => LoadAndHandle_Texture(file)); }
//tmpColor //tmpVec //tmpQuat public void Setup(WhModel model) { Model = model; Mesh = model.Meshes[MeshIndex]; MeshId = Mesh.Id; WhRenderFlag.ComputeFlags(this); // На момент теста эта штука была undefined, так что думаю можно это не использовать //window.MeshLoadFilter && window.MeshLoadFilter(self); //var program = ZamModelViewer.Wow.ShaderTool.GetWowProgram(self.shaderId, self.opcount, self.renderFlag); //self.program = program; for (int i = 0; i < Opcount; i++) { if (MaterialIndex > -1 && MaterialIndex < model.MaterialLookup.Length) { var matIdx = model.MaterialLookup[MaterialIndex + i]; if (matIdx > -1 && matIdx < model.Materials.Length) { Material.Insert(i, model.Materials[matIdx]); } } // if (self.textureAnimIndex > -1 && self.textureAnimIndex < model.textureAnimLookup.length) { // var animIdx = model.textureAnimLookup[self.textureAnimIndex + i]; // if (animIdx > -1 && model.textureAnims && animIdx < model.textureAnims.length) { // self.textureAnim.splice(i, 0, model.textureAnims[animIdx]) // } else { // self.textureAnim.splice(i, 0, null) // } // } } //if (self.flip) { // self.material = self.material.reverse(); // self.textureAnim = self.textureAnim.reverse() //} //if (model.colors && self.colorIndex > -1 && self.colorIndex < model.colors.length) { // self.color = model.colors[self.colorIndex] //} //if (self.alphaIndex > -1 && self.alphaIndex < model.alphaLookup.length) { // var alphaIdx = model.alphaLookup[self.alphaIndex]; // if (alphaIdx > -1 && alphaIdx < model.alphas.length) { // self.alpha = model.alphas[alphaIdx] // } //} }
public WhItem(WhModel model, WhSlot slot, int id, WhRace race, WhGender gender) { Model = model; Slot = slot; UniqueSlot = WhGlobal.UniqueSlots[slot]; SortValue = WhGlobal.SlotOrder[slot]; Models = null; Textures = null; GeosetGroup = null; Flags = 0; Loaded = false; Visual = null; Visualid = 0; if (id != 0) { Load(id, race, gender); } }
public WowObject BuildFromCharacterWhModel(WhModel whCharacterModel) { // ToDo: Смотреть как работает, Wow.Model.draw, // по сути в зависимости от алгоритма отрисовки идет и алгоритм построения объектов для дальнейшей отрисовки (то что тут происодит) // Сам перс var characterObject = new WowObject(); // Добавляем MainMesh characterObject.Meshes.Add(MakeMeshFromWhModel(whCharacterModel)); characterObject.Bones = MakeBoneHierarchyFromWhModel(whCharacterModel); characterObject.OptimizeBones(); TranslateBonePositionsFromGlobalToLocal(characterObject); // Рога if (whCharacterModel.HornsModel != null) { AddAdditionalMeshToCharacterObject(characterObject, whCharacterModel.HornsModel); } // Маунт if (whCharacterModel.Mount != null) { // ToDo: хз че тут делать, создать его вообще отдельно? //var mountObject = new WowObject() //{ // Parent = characterObject //}; //// MainMesh (не факт что я вообще тут правильно делаю, т.к. еще не тестил) //mountObject.Meshes.Add(MakeMeshFromWhModel(whCharacterModel.Mount)); //characterObject.Children.Add(mountObject); } // Итемы foreach (var whItemInSlot in whCharacterModel.Items) { var whItem = whItemInSlot.Value; if (whItem?.Models == null) { continue; } foreach (var whItemModel in whItem.Models) { if (whItemModel?.Model == null) { continue; } if (whItemModel.Bone > -1 && whItemModel.Bone < whCharacterModel.Bones.Length) { var itemPosition = Vec3.Scale(Vec3.ConvertPositionFromWh(whItemModel.Attachment.Position), _scale); var itemObject = new WowObject() { Parent = characterObject, GlobalPosition = itemPosition, }; // MainMesh - по сути он использоваться будет тлолько в AttachedWowObjects кости itemObject.Meshes.Add(MakeMeshFromWhModel(whItemModel.Model)); // Если у итема есть кость, к которой можно прикрепиться if (itemObject.Parent != null && whItemModel.Attachment.Bone >= 0) { var parentAttachmentBone = itemObject.Parent.Bones[whItemModel.Attachment.Bone]; var whParentAttachmentBone = whItemModel.Model.Parent.Bones[whItemModel.Attachment.Bone]; // записываем объект этого итема в кость, к которой крепимся(у родительского объекта) parentAttachmentBone.AttachedWowObjects.Add(itemObject); // меняем данные о костях в вершинах так итема так, чтобы при привязке к скелету родителя этот итем двигался вместе с костью // (при этом в иерархии объектов он не будет в ноде кости, а будет на том же уровне что и родительский объект, к скелету которого мы привязываем итем) itemObject.MainMesh.ApplyTransform( whParentAttachmentBone.LastUpdatedTranslation, whParentAttachmentBone.LastUpdatedRotation, whParentAttachmentBone.LastUpdatedScale); var eachVertexItemBoneIndexes = new ByteVec4((byte)parentAttachmentBone.Index, 0, 0, 0); var eachVertexItemBoneWeights = new Vec4(1, 0, 0, 0); foreach (var vertex in itemObject.MainMesh.Vertices) { vertex.BoneIndexes = eachVertexItemBoneIndexes; vertex.BoneWeights = eachVertexItemBoneWeights; } } if (whItem.Visual?.Models != null && whItemModel.Model.Loaded) { foreach (var visual in whItem.Visual.Models) { if (visual != null) { var visualPosition = Vec3.Scale(Vec3.ConvertPositionFromWh(visual.Attachment.Position), _scale); var visualObject = new WowObject() { Parent = characterObject, GlobalPosition = visualPosition }; // MainMesh (не факт что я вообще тут правильно делаю, т.к. еще не тестил) visualObject.Meshes.Add(MakeMeshFromWhModel(visual.Model)); } } } } else if (whItemModel.Bone == -1) { AddAdditionalMeshToCharacterObject(characterObject, whItemModel.Model); } } } foreach (var collection in whCharacterModel.CollectionModels.Values) { if (collection == null) { continue; } AddAdditionalMeshToCharacterObject(characterObject, collection); } return(characterObject); }
public void LoadMeta(WhJsonMeta meta) { Flags = meta.Item.Flags; Slot = meta.Item.InventoryType; ItemClass = meta.Item.ItemClass; ItemSubClass = meta.Item.ItemSubClass; if (meta.ComponentTextures != null) { Textures = new List <WhItemTexture>(); foreach (var componentTexture in meta.ComponentTextures) { var region = componentTexture.Key; var texFile = SelectBestTexture(meta, componentTexture.Value, Model.Gender, Model.Class, Model.Race); WhItemTexture texture = null; if (texFile != 0) { texture = new WhItemTexture() { Region = region, Gender = Model.Gender, File = texFile, Texture = null }; if (region != WhRegion.Base) { texture.Texture = new WhTexture(Model, (int)region, texFile); } else if (Slot == WhSlot.CAPE) { Model.TextureOverrides[2] = new WhTexture(Model, 2, texFile); } } Textures.Add(texture); } } GeosetGroup = meta.Item.GeosetGroup; if (Slot == WhSlot.HEAD) { var gender = Model.Gender; var hideGeoset = gender == WhGender.MALE ? meta.Item.HideGeosetMale : meta.Item.HideGeosetFemale; if (gender == WhGender.MALE) { HideGeosetMale = meta.Item.HideGeosetMale; } else { HideGeosetFemale = meta.Item.HideGeosetFemale; } } if (Slot == WhSlot.SHOULDER) { Models = new List <WhItemModel>() { null, null } } ; else if (WhGlobal.SlotType[Slot] != WhType.ARMOR) { Models = new List <WhItemModel>() { null } } ; if (Models != null) { for (int i = 0; i < Models.Count; i++) { var model = new WhItemModel() { Race = Race, Gender = Gender, Bone = -1, Attachment = null, Model = null }; var modelInfo = new WhModelInfo() { Type = WhGlobal.SlotType[Slot], Id = Id.ToString(), Parent = Model }; if (Slot == WhSlot.SHOULDER) { modelInfo.Shoulder = i + 1; } model.Model = new WhModel(Model.Opts, modelInfo, i, true); model.Model.LoadMeta(meta, modelInfo.Type); Models[i] = model; } } if (Slot == WhSlot.BELT && meta.Model != 0) { var model = new WhItemModel() { Race = WhRace.Undefined2, Gender = WhGender.MALE, Bone = -1, Attachment = null, Model = null }; var modelInfo = new WhModelInfo() { Type = WhGlobal.SlotType[Slot], Id = Id.ToString(), Parent = Model }; model.Model = new WhModel(Model.Opts, modelInfo, 0, true); model.Model.LoadMeta(meta, WhType.ARMOR); Models = new List <WhItemModel>() { model }; } if (Slot == WhSlot.SHIRT || Slot == WhSlot.CHEST || Slot == WhSlot.ROBE || Slot == WhSlot.BELT || Slot == WhSlot.PANTS || Slot == WhSlot.HANDS || Slot == WhSlot.BOOTS || Slot == WhSlot.HEAD) { int componentIndex = 0; if (Slot == WhSlot.HEAD) { componentIndex = 1; } if (meta.ComponentModels != null && meta.ComponentModels.ContainsKey(componentIndex.ToString())) { var modelId = meta.ComponentModels[componentIndex.ToString()]; if (modelId != 0 && meta.ModelFiles.ContainsKey(modelId)) { var modelInfo = new WhModelInfo() { Type = WhGlobal.SlotType[Slot], Id = Id.ToString(), Parent = Model }; var model = new WhModel(Model.Opts, modelInfo, 0, true); model.Meta = meta; model.IsDirty = true; var race = WhRace.HUMAN; var gender = WhGender.MALE; var cls = WhClass.WARRIOR; if (Model != null) { race = Model.Race; gender = Model.Gender; cls = Model.Class; } var modelFile = model.SelectBestModel(modelId, gender, cls, race); if (modelFile != 0) { if (Model != null) { if (!Model.CollectionModels.ContainsKey(modelFile)) { Model.CollectionModels[modelFile] = model; CollectionModel = model; model._Load(WhType.PATH, modelFile.ToString()); } else { CollectionModel = Model.CollectionModels[modelFile]; } } else { model._Load(WhType.PATH, modelFile.ToString()); } if (meta.Textures != null) { foreach (var texturePair in meta.Textures) { model.TextureOverrides[texturePair.Key] = new WhTexture(model, texturePair.Key, texturePair.Value); } } } } } } if (Slot == WhSlot.PANTS && GeosetGroup[2] > 0) { SortValue += 2; } if (Visualid != 0) { Visual = new WhItemVisual(Models[0].Model, Visualid); } Loaded = true; Model.UpdateMeshes(); }