From 4930716d55d23c069371edb5b283b57f94631dc9 Mon Sep 17 00:00:00 2001 From: ousnius Date: Mon, 9 Nov 2015 21:51:29 +0100 Subject: [PATCH 01/64] Initial adjustments for FO4 --- BodySlide.rc | Bin 5148 -> 5148 bytes BodySlideApp.cpp | 10 +++- Config.xml | 122 ++++++----------------------------------- OutfitProject.cpp | 1 + OutfitStudio.h | 15 ++--- ShapeProperties.cpp | 1 + res/BodyslideFrame.xrc | 3 +- 7 files changed, 34 insertions(+), 118 deletions(-) diff --git a/BodySlide.rc b/BodySlide.rc index 470725e771608008956994d2b5a91c9aca447af2..5fe873e77a41ffa243aa9dbaacf4319f97102d77 100644 GIT binary patch delta 74 zcmbQEF-K#=94<~{1|0?i5T3l0OB2D{e4UG#8OYTGN&@j@Mgi%`7x=_Bi|{>RLzCtu(b+bqKOgb^XU I87RyG094Qp#{d8T diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index 727fde94..25bcba55 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -93,6 +93,7 @@ bool BodySlideApp::OnInit() { case FO3: gameName.Append("Fallout 3"); break; case FONV: gameName.Append("Fallout New Vegas"); break; case SKYRIM: gameName.Append("Skyrim"); break; + case FO4: gameName.Append("Fallout 4"); break; default: gameName.Append("Invalid"); } wxLogMessage(gameName); @@ -752,7 +753,7 @@ void BodySlideApp::RebuildPreviewMeshes() { } void BodySlideApp::SetDefaultConfig() { - Config.SetDefaultValue("TargetGame", 2); + Config.SetDefaultValue("TargetGame", 3); targetGame = Config.GetIntValue("TargetGame"); Config.SetDefaultValue("ShapeDataPath", wxGetCwd().ToStdString() + "\\ShapeData"); @@ -783,6 +784,12 @@ void BodySlideApp::SetDefaultConfig() { gameKey = "SOFTWARE\\Bethesda Softworks\\Skyrim"; gameValueKey = "Installed Path"; break; + case FO4: + Config.SetDefaultValue("Anim/DefaultSkeletonReference", "res\\skeleton_fo4.nif"); + Config.SetDefaultValue("Anim/SkeletonRootName", "NPC"); + gameKey = "SOFTWARE\\Bethesda Softworks\\Fallout4"; + gameValueKey = "Installed Path"; + break; default: Config.SetDefaultValue("Anim/DefaultSkeletonReference", "res\\skeleton_female.nif"); Config.SetDefaultValue("Anim/SkeletonRootName", "NPC"); @@ -2311,6 +2318,7 @@ void BodySlideFrame::OnChooseTargetGame(wxCommandEvent& event) { choiceSkeletonRoot->SetStringSelection("Bip01"); break; case SKYRIM: + case FO4: default: choiceSkeletonRoot->SetStringSelection("NPC"); break; diff --git a/Config.xml b/Config.xml index 84294871..32d5418f 100644 --- a/Config.xml +++ b/Config.xml @@ -1,141 +1,51 @@ - - - 2 + + + 3 true - true - 3 + true + 3 CBBE Body - CBBE Curvy + CBBE - CBAdvanced - + CBBE + - - - - + 0 100 false - + Object - + 80 55 45 45 - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - res\skeleton_female_xpmse.nif + res\skeleton_fo4.nif NPC - + diff --git a/OutfitProject.cpp b/OutfitProject.cpp index 437820fd..d9f06487 100644 --- a/OutfitProject.cpp +++ b/OutfitProject.cpp @@ -415,6 +415,7 @@ int OutfitProject::AddShapeFromObjFile(const string& fileName, const string& sha nifShaderPP->textureSetRef = blank.AddBlock((NiObject*)nifTexset, "BSShaderTextureSet"); break; case SKYRIM: + case FO4: default: nifShader = new BSLightingShaderProperty(workNif.hdr); shaderID = blank.AddBlock((NiObject*)nifShader, "BSLightingShaderProperty"); diff --git a/OutfitStudio.h b/OutfitStudio.h index 0ca029fe..d189c874 100644 --- a/OutfitStudio.h +++ b/OutfitStudio.h @@ -18,16 +18,6 @@ along with this program. If not, see . #pragma once -#ifndef FO3 -#define FO3 0 -#endif -#ifndef FONV -#define FONV 1 -#endif -#ifndef SKYRIM -#define SKYRIM 2 -#endif - #include "stdafx.h" #include "wxStateButton.h" #include "GLSurface.h" @@ -50,6 +40,11 @@ along with this program. If not, see . #include +enum TargetGame { + FO3, FONV, SKYRIM, FO4 +}; + + class ShapeItemData : public wxTreeItemData { public: NifFile* refFile; diff --git a/ShapeProperties.cpp b/ShapeProperties.cpp index e5df3970..a4a7165b 100644 --- a/ShapeProperties.cpp +++ b/ShapeProperties.cpp @@ -202,6 +202,7 @@ void ShapeProperties::AddShader() { break; } case SKYRIM: + case FO4: default: { BSLightingShaderProperty* shader = new BSLightingShaderProperty(nif->hdr); geom->propertiesRef1 = nif->AddBlock(shader, "BSLightingShaderProperty"); diff --git a/res/BodyslideFrame.xrc b/res/BodyslideFrame.xrc index 7a382da7..ac0738e8 100644 --- a/res/BodyslideFrame.xrc +++ b/res/BodyslideFrame.xrc @@ -4,7 +4,7 @@ 800,750 #404040 - Caliente's BodySlide + BodySlide 0 wxVERTICAL @@ -236,6 +236,7 @@ wxALIGN_CENTER|wxALL 5 + 1 #c8c8c8 Builds a TRI file alongside the low and high weight meshes for accessing the sliders in-game. Requires the RaceMenu mod and matching plugin/scripts for the collection of sliders. From 63e277076931b8300cf3c805f8e2a4e6f300da8c Mon Sep 17 00:00:00 2001 From: ousnius Date: Tue, 10 Nov 2015 00:03:26 +0100 Subject: [PATCH 02/64] Loading exportInfo3 in header --- BodySlideApp.cpp | 3 +++ NifBlock.cpp | 4 ++++ NifFile.h | 3 ++- res/BodyslideFrame.xrc | 1 - 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index 25bcba55..74b8dd5e 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -1582,6 +1582,9 @@ BodySlideFrame::BodySlideFrame(BodySlideApp* app, const wxSize &size) : delayLoa wxButton* btnAbout = (wxButton*)FindWindowByName("btnAbout"); if (btnAbout) btnAbout->SetBitmap(wxArtProvider::GetBitmap(wxART_INFORMATION, wxART_OTHER, wxSize(15, 15))); + + if (app->targetGame != SKYRIM) + XRCCTRL(*this, "cbRaceMenu", wxCheckBox)->Show(false); } void BodySlideFrame::OnLinkClicked(wxHtmlLinkEvent& link) { diff --git a/NifBlock.cpp b/NifBlock.cpp index 49416c49..7adfadd9 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -96,6 +96,10 @@ void NiHeader::Get(fstream& file) { creator.Get(file, 1); exportInfo1.Get(file, 1); exportInfo2.Get(file, 1); + + if (userVersion2 >= 130) + exportInfo3.Get(file, 1); + file.read((char*)&numBlockTypes, 2); for (int i = 0; i < numBlockTypes; i++) blockTypes.push_back(NiString(file, 4)); diff --git a/NifFile.h b/NifFile.h index 4fe3500b..4eb52c8f 100644 --- a/NifFile.h +++ b/NifFile.h @@ -224,7 +224,7 @@ class NiHeader : public NiObject { /* Maximum supported */ // Version: 20.2.0.7 // User Version: 12 - // User Version 2: 83 + // User Version 2: 130 char verStr[0x26]; byte version1; @@ -240,6 +240,7 @@ class NiHeader : public NiObject { NiString creator; NiString exportInfo1; NiString exportInfo2; + NiString exportInfo3; ushort numBlockTypes; vector blockTypes; vector blockIndex; diff --git a/res/BodyslideFrame.xrc b/res/BodyslideFrame.xrc index ac0738e8..21d11929 100644 --- a/res/BodyslideFrame.xrc +++ b/res/BodyslideFrame.xrc @@ -236,7 +236,6 @@ wxALIGN_CENTER|wxALL 5 - 1 #c8c8c8 Builds a TRI file alongside the low and high weight meshes for accessing the sliders in-game. Requires the RaceMenu mod and matching plugin/scripts for the collection of sliders. From c13e3220a5274a8671b7102e44f0629509f4dd67 Mon Sep 17 00:00:00 2001 From: ousnius Date: Thu, 12 Nov 2015 00:41:14 +0100 Subject: [PATCH 03/64] Update for BA2, now using zlib --- .gitmodules | 3 + BodySlide.vcxproj | 1 + BodySlide.vcxproj.filters | 3 + FSBSA.cpp | 413 +++++++++++++++++++++++++++----------- FSBSA.h | 160 +++++++++++++-- FSManager.cpp | 5 +- Log.cpp | 6 + Log.h | 6 + zlib | 1 + 9 files changed, 468 insertions(+), 130 deletions(-) create mode 100644 .gitmodules create mode 160000 zlib diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..c4668cc7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "zlib"] + path = zlib + url = https://github.com/madler/zlib diff --git a/BodySlide.vcxproj b/BodySlide.vcxproj index 5b14a64f..e32499b6 100644 --- a/BodySlide.vcxproj +++ b/BodySlide.vcxproj @@ -147,6 +147,7 @@ + diff --git a/BodySlide.vcxproj.filters b/BodySlide.vcxproj.filters index 9e1e98f6..92cdd6b1 100644 --- a/BodySlide.vcxproj.filters +++ b/BodySlide.vcxproj.filters @@ -215,6 +215,9 @@ Header Files + + Header Files + diff --git a/FSBSA.cpp b/FSBSA.cpp index 2993b899..4ee54be8 100644 --- a/FSBSA.cpp +++ b/FSBSA.cpp @@ -31,101 +31,21 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***** END LICENCE BLOCK *****/ #include "FSBSA.h" +#include "DDS.h" +#include "zlib\zlib.h" + #include -#include -#include #pragma warning (disable : 4389) -/* Default header data */ -#define MW_BSAHEADER_FILEID 0x00000100 //!< Magic for Morrowind BSA -#define OB_BSAHEADER_FILEID 0x00415342 //!< Magic for Oblivion BSA, the literal string "BSA\0". -#define OB_BSAHEADER_VERSION 0x67 //!< Version number of an Oblivion BSA -#define F3_BSAHEADER_VERSION 0x68 //!< Version number of a Fallout 3 BSA - -/* Archive flags */ -#define OB_BSAARCHIVE_PATHNAMES 0x0001 //!< Whether the BSA has names for paths -#define OB_BSAARCHIVE_FILENAMES 0x0002 //!< Whether the BSA has names for files -#define OB_BSAARCHIVE_COMPRESSFILES 0x0004 //!< Whether the files are compressed -#define F3_BSAARCHIVE_PREFIXFULLFILENAMES 0x0100 //!< Whether the name is prefixed to the data? - -/* File flags */ -#define OB_BSAFILE_NIF 0x0001 //!< Set when the BSA contains NIF files -#define OB_BSAFILE_DDS 0x0002 //!< Set when the BSA contains DDS files -#define OB_BSAFILE_XML 0x0004 //!< Set when the BSA contains XML files -#define OB_BSAFILE_WAV 0x0008 //!< Set when the BSA contains WAV files -#define OB_BSAFILE_MP3 0x0010 //!< Set when the BSA contains MP3 files -#define OB_BSAFILE_TXT 0x0020 //!< Set when the BSA contains TXT files -#define OB_BSAFILE_HTML 0x0020 //!< Set when the BSA contains HTML files -#define OB_BSAFILE_BAT 0x0020 //!< Set when the BSA contains BAT files -#define OB_BSAFILE_SCC 0x0020 //!< Set when the BSA contains SCC files -#define OB_BSAFILE_SPT 0x0040 //!< Set when the BSA contains SPT files -#define OB_BSAFILE_TEX 0x0080 //!< Set when the BSA contains TEX files -#define OB_BSAFILE_FNT 0x0080 //!< Set when the BSA contains FNT files -#define OB_BSAFILE_CTL 0x0100 //!< Set when the BSA contains CTL files - -/* Bitmasks for the size field in the header */ -#define OB_BSAFILE_SIZEMASK 0x3fffffff //!< Bit mask with OBBSAFileInfo::sizeFlags to get the size of the file - -/* Record flags */ -#define OB_BSAFILE_FLAG_COMPRESS 0xC0000000 //!< Bit mask with OBBSAFileInfo::sizeFlags to get the compression status - -//! \file bsa.cpp OBBSAHeader / \link OBBSAFileInfo FileInfo\endlink / \link OBBSAFolderInfo FolderInfo\endlink; MWBSAHeader, MWBSAFileSizeOffset - -//! The header of an Oblivion BSA. -/*! - * Follows OB_BSAHEADER_FILEID and OB_BSAHEADER_VERSION. - */ -struct OBBSAHeader { - wxUint32 FolderRecordOffset; //!< Offset of beginning of folder records - wxUint32 ArchiveFlags; //!< Archive flags - wxUint32 FolderCount; //!< Total number of folder records (OBBSAFolderInfo) - wxUint32 FileCount; //!< Total number of file records (OBBSAFileInfo) - wxUint32 FolderNameLength; //!< Total length of folder names - wxUint32 FileNameLength; //!< Total length of file names - wxUint32 FileFlags; //!< File flags - - //friend QDebug operator<<(QDebug dbg, const OBBSAHeader & head) - //{ - // return dbg << "BSAHeader:" - // << "\n folder offset" << head.FolderRecordOffset - // << "\n archive flags" << head.ArchiveFlags - // << "\n folder Count" << head.FolderCount - // << "\n file Count" << head.FileCount - // << "\n folder name length" << head.FolderNameLength - // << "\n file name length" << head.FileNameLength - // << "\n file flags" << head.FileFlags; - //} -}; - -//! Info for a file inside an Oblivion BSA -struct OBBSAFileInfo { - wxUint64 hash; //!< Hash of the filename - wxUint32 sizeFlags; //!< Size of the data, possibly with OB_BSAFILE_FLAG_COMPRESS set - wxUint32 offset; //!< Offset to raw file data -}; - -//! Info for a folder inside an Oblivion BSA -struct OBBSAFolderInfo { - wxUint64 hash; //!< Hash of the folder name - wxUint32 fileCount; //!< Number of files in folder - wxUint32 offset; //!< Offset to name of this folder -}; - -//! The header of a Morrowind BSA -struct MWBSAHeader { - wxUint32 HashOffset; //!< Offset of hash table minus header size (12) - wxUint32 FileCount; //!< Number of files in the archive -}; - -//! The file size and offset of an entry in a Morrowind BSA -struct MWBSAFileSizeOffset { - wxUint32 size; //!< The size of the file - wxUint32 offset; //!< The offset of the file -}; wxUint32 BSA::BSAFile::size() const { - return sizeFlags & OB_BSAFILE_SIZEMASK; + if (sizeFlags > 0) { + // Skyrim and earlier + return sizeFlags & OB_BSAFILE_SIZEMASK; + } + + return (packedLength == 0) ? unpackedLength : packedLength; } bool BSA::BSAFile::compressed() const { @@ -154,6 +74,58 @@ static bool BSAReadSizedString(wxFile &bsa, wxString &s) { } } +wxMemoryBuffer gUncompress(const wxMemoryBuffer &data) { + if (data.GetBufSize() <= 4) { + //qWarning("gUncompress: Input data is truncated"); + return wxMemoryBuffer(); + } + + wxMemoryBuffer result; + + int ret; + z_stream strm; + static const int CHUNK_SIZE = 1024; + char out[CHUNK_SIZE]; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = data.GetBufSize(); + + char *dataPtr = static_cast(data.GetData()); + strm.next_in = (Bytef*)(dataPtr + 4); + + ret = inflateInit2(&strm, 15 + 32); // gzip decoding + if (ret != Z_OK) + return wxMemoryBuffer(); + + // run inflate() + do { + strm.avail_out = CHUNK_SIZE; + strm.next_out = (Bytef*)(out); + + ret = inflate(&strm, Z_NO_FLUSH); + //Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered + + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; // and fall through + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return wxMemoryBuffer(); + } + + result.AppendData(out, CHUNK_SIZE - strm.avail_out); + } while (strm.avail_out == 0); + + // clean up and return + inflateEnd(&strm); + return result; +} + + BSA::BSA(const wxString &filename) : FSArchiveFile(), bsa(filename), bsaInfo(filename), status("initialized") { bsaPath = bsaInfo.GetPathWithSep() + bsaInfo.GetFullName(); bsaBase = bsaInfo.GetPath(); @@ -173,7 +145,13 @@ bool BSA::canOpen(const wxString &fn) { return false; //qDebug() << "Magic:" << QString::number( magic, 16 ); - if (magic == OB_BSAHEADER_FILEID) { + if (magic == F4_BSAHEADER_FILEID) { + if (f.Read((char *)&version, sizeof(version)) != 4) + return false; + + return version == F4_BSAHEADER_VERSION; + } + else if (magic == OB_BSAHEADER_FILEID) { if (f.Read((char *)& version, sizeof(version)) != 4) return false; @@ -198,8 +176,85 @@ bool BSA::open() { bsa.Read((char*)&magic, sizeof(magic)); - if (magic == OB_BSAHEADER_FILEID) - { + if (magic == F4_BSAHEADER_FILEID) { + bsa.Read((char*)&version, sizeof(version)); + + if (version != F4_BSAHEADER_VERSION) + throw wxString("file version"); + + F4BSAHeader header; + if (bsa.Read((char *)&header, sizeof(header)) != sizeof(header)) + throw wxString("header size"); + + numFiles = header.numFiles; + + std::vector filepaths; + if (bsa.Seek(header.nameTableOffset)) { + for (wxUint32 i = 0; i < header.numFiles; i++) { + wxUint16 length; + bsa.Read((char*)&length, 2); + + wxMemoryBuffer strdata(length); + bsa.Read(strdata.GetData(), length); + + wxString filepath(strdata, strdata.GetBufSize()); + filepaths.push_back(filepath); + } + } + + + wxString h(header.type, 4); + if (h == "GNRL") { + // General BA2 Format + if (bsa.Seek(sizeof(header) + 8)) { + for (wxUint32 i = 0; i < header.numFiles; i++) { + F4GeneralInfo finfo; + bsa.Read((char*)&finfo, 36); + + wxString fullpath = filepaths[i]; + fullpath.Replace("\\", "/"); + + wxString filename = fullpath.AfterLast('/'); + wxString folderName = fullpath.BeforeLast('/'); + + BSAFolder * folder = insertFolder(folderName); + + insertFile(folder, filename, finfo.packedSize, finfo.unpackedSize, finfo.offset); + } + } + } + else if (h == "DX10") { + // Texture BA2 Format + if (bsa.Seek(sizeof(header) + 8)) { + for (wxUint32 i = 0; i < header.numFiles; i++) { + F4Tex tex; + bsa.Read((char*)&tex.header, 24); + + std::vector texChunks; + for (wxUint32 j = 0; j < tex.header.numChunks; j++) { + F4TexChunk texChunk; + bsa.Read((char*)&texChunk, 24); + texChunks.push_back(texChunk); + } + + tex.chunks = texChunks; + + wxString fullpath = filepaths[i]; + fullpath.Replace("\\", "/"); + + wxString filename = fullpath.AfterLast('/'); + wxString folderName = fullpath.BeforeLast('/'); + + BSAFolder * folder = insertFolder(folderName); + + F4TexChunk chunk = tex.chunks[0]; + insertFile(folder, filename, chunk.packedSize, chunk.unpackedSize, chunk.offset, tex); + } + } + } + } + // From NifSkope + else if (magic == OB_BSAHEADER_FILEID) { bsa.Read((char*)&version, sizeof(version)); if (version != OB_BSAHEADER_VERSION && version != F3_BSAHEADER_VERSION) @@ -210,6 +265,7 @@ bool BSA::open() { if (bsa.Read((char *)& header, sizeof(header)) != sizeof(header)) throw wxString("header size"); + numFiles = header.FileCount; //qWarning() << bsaName << header; if ((header.ArchiveFlags & OB_BSAARCHIVE_PATHNAMES) == 0 || (header.ArchiveFlags & OB_BSAARCHIVE_FILENAMES) == 0) @@ -288,7 +344,7 @@ bool BSA::open() { if (bsa.Read((char *)& header, sizeof(header)) != sizeof(header)) throw wxString("header"); - + numFiles = header.FileCount; compressToggle = false; namePrefix = false; @@ -358,9 +414,20 @@ void BSA::close() { wxInt64 BSA::fileSize(const wxString & fn) const { // note: lazy size count (not accurate for compressed files) - if (const BSAFile *file = getFile(fn)) - return file->size(); + if (const BSAFile * file = getFile(fn)) { + if (file->sizeFlags > 0) + return file->size(); + + wxUint64 size = file->unpackedLength; + + if (file->tex.chunks.size()) { + for (int i = 1; i < file->tex.chunks.size(); i++) { + size += file->tex.chunks[i].unpackedSize; + } + } + return size; + } return 0; } @@ -379,29 +446,136 @@ bool BSA::fileContents(const wxString &fn, wxMemoryBuffer &content) { ok = bsa.Seek(file->offset + 1 + len); } - content.SetBufSize(filesz); - - if (ok != wxInvalidOffset && bsa.Read(content.GetData(), filesz) == filesz) { - char *dataPtr = static_cast(content.GetData()); + if (file->tex.chunks.size()) { + // Fill DDS Header for BA2 + DDS_HEADER ddsHeader = { 0 }; + + ddsHeader.dwSize = sizeof(ddsHeader); + ddsHeader.dwHeaderFlags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_LINEARSIZE | DDS_HEADER_FLAGS_MIPMAP; + ddsHeader.dwHeight = file->tex.header.height; + ddsHeader.dwWidth = file->tex.header.width; + ddsHeader.dwMipMapCount = file->tex.header.numMips; + ddsHeader.ddspf.dwSize = sizeof(DDS_PIXELFORMAT); + ddsHeader.dwSurfaceFlags = DDS_SURFACE_FLAGS_TEXTURE | DDS_SURFACE_FLAGS_MIPMAP; + + bool ok = true; + + switch (file->tex.header.format) { + case DXGI_FORMAT_BC1_UNORM: + ddsHeader.ddspf.dwFlags = DDS_FOURCC; + ddsHeader.ddspf.dwFourCC = MAKEFOURCC('D', 'X', 'T', '1'); + ddsHeader.dwPitchOrLinearSize = file->tex.header.width * file->tex.header.height / 2; // 4bpp + break; + + case DXGI_FORMAT_BC2_UNORM: + ddsHeader.ddspf.dwFlags = DDS_FOURCC; + ddsHeader.ddspf.dwFourCC = MAKEFOURCC('D', 'X', 'T', '3'); + ddsHeader.dwPitchOrLinearSize = file->tex.header.width * file->tex.header.height; // 8bpp + break; + + case DXGI_FORMAT_BC3_UNORM: + ddsHeader.ddspf.dwFlags = DDS_FOURCC; + ddsHeader.ddspf.dwFourCC = MAKEFOURCC('D', 'X', 'T', '5'); + ddsHeader.dwPitchOrLinearSize = file->tex.header.width * file->tex.header.height; // 8bpp + break; + + case DXGI_FORMAT_BC5_UNORM: + // Incorrect + ddsHeader.ddspf.dwFlags = DDS_FOURCC; + ddsHeader.ddspf.dwFourCC = MAKEFOURCC('A', 'T', 'I', '2'); + //ddsHeader.ddspf.dwFourCC = MAKEFOURCC('D', 'X', 'T', '5'); + ddsHeader.dwPitchOrLinearSize = file->tex.header.width * file->tex.header.height; // 8bpp + break; + + case DXGI_FORMAT_BC7_UNORM: + // Incorrect + ddsHeader.ddspf.dwFlags = DDS_FOURCC; + ddsHeader.ddspf.dwFourCC = MAKEFOURCC('B', 'C', '7', '\0'); + ddsHeader.dwPitchOrLinearSize = file->tex.header.width * file->tex.header.height; // 8bpp + break; + + case DXGI_FORMAT_B8G8R8A8_UNORM: + ddsHeader.ddspf.dwFlags = DDS_RGBA; + ddsHeader.ddspf.dwRGBBitCount = 32; + ddsHeader.ddspf.dwRBitMask = 0x00FF0000; + ddsHeader.ddspf.dwGBitMask = 0x0000FF00; + ddsHeader.ddspf.dwBBitMask = 0x000000FF; + ddsHeader.ddspf.dwABitMask = 0xFF000000; + ddsHeader.dwPitchOrLinearSize = file->tex.header.width * file->tex.header.height * 4; // 32bpp + break; + + case DXGI_FORMAT_R8_UNORM: + ddsHeader.ddspf.dwFlags = DDS_RGB; + ddsHeader.ddspf.dwRGBBitCount = 8; + ddsHeader.ddspf.dwRBitMask = 0xFF; + ddsHeader.dwPitchOrLinearSize = file->tex.header.width * file->tex.header.height; // 8bpp + break; + + default: + ok = false; + break; + } - if (file->compressed() ^ compressToggle) { - wxMemoryInputStream memInStream(dataPtr + 4, filesz); - wxMemoryOutputStream memOutStream; - wxZlibInputStream* zOutput = new wxZlibInputStream(memInStream); - zOutput->Read(memOutStream); - delete zOutput; + char buf[sizeof(ddsHeader)]; + memcpy(buf, &ddsHeader, sizeof(ddsHeader)); - size_t streamSize = memOutStream.GetSize(); - content.SetBufSize(streamSize); - content.SetDataLen(streamSize); - size_t numCopied = memOutStream.CopyTo(content.GetData(), streamSize); + // Append DDS Header + wxString dds = "DDS "; + content.SetBufSize(sizeof(ddsHeader) + 4); + content.AppendData(dds.data(), 4); + content.AppendData(buf, sizeof(ddsHeader)); + } - if (numCopied != streamSize) - return false; + wxMemoryBuffer firstChunk; + firstChunk.SetBufSize(filesz); + if (ok != wxInvalidOffset && bsa.Read(firstChunk.GetData(), filesz) == filesz) { + if (file->sizeFlags > 0) { + // BSA + if (file->compressed() ^ compressToggle) { + firstChunk = gUncompress(firstChunk); + content.AppendData(firstChunk, firstChunk.GetBufSize()); + } + } + else if (file->packedLength > 0) { + // BA2 + firstChunk = gUncompress(firstChunk); + content.AppendData(firstChunk, firstChunk.GetBufSize()); } - else - content.SetDataLen(filesz); + if (file->tex.chunks.size()) { + // Start at 2nd chunk for BA2 + for (int i = 1; i < file->tex.chunks.size(); i++) { + F4TexChunk chunk = file->tex.chunks[i]; + if (bsa.Seek(chunk.offset)) { + wxMemoryBuffer chunkData; + + if (chunk.packedSize > 0) { + chunkData.SetBufSize(chunk.packedSize); + if (bsa.Read(chunkData.GetData(), chunk.packedSize) == chunk.packedSize) + chunkData = gUncompress(chunkData); + + if (chunkData.GetBufSize() != chunk.unpackedSize) { + //qCritical() << "Size does not match at " << chunk.offset; + return false; + } + + } + else { + chunkData.SetBufSize(chunk.unpackedSize); + if (!(bsa.Read(chunkData.GetData(), chunk.unpackedSize) == chunk.unpackedSize)) { + //qCritical() << "Size does not match at " << chunk.offset; + return false; + } + } + + content.AppendData(chunkData.GetData(), chunkData.GetBufSize()); + } + else { + //qCritical() << "Seek error"; + return false; + } + } + } return true; } } @@ -457,6 +631,19 @@ BSA::BSAFile *BSA::insertFile(BSAFolder *folder, wxString name, wxUint32 sizeFla return file; } +BSA::BSAFile *BSA::insertFile(BSAFolder *folder, wxString name, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, F4Tex dds) { + name = name.Lower(); + + BSAFile * file = new BSAFile; + file->tex = dds; + file->packedLength = packed; + file->unpackedLength = unpacked; + file->offset = offset; + folder->files[name.ToStdString()] = file; + + return file; +} + const BSA::BSAFolder *BSA::getFolder(wxString fn) const { if (fn.IsEmpty()) { return &root; diff --git a/FSBSA.h b/FSBSA.h index 3ea063aa..f35211bd 100644 --- a/FSBSA.h +++ b/FSBSA.h @@ -30,8 +30,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***** END LICENCE BLOCK *****/ -#ifndef BSA_H -#define BSA_H +#pragma once #include "FSEngine.h" @@ -42,16 +41,132 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -//! \file bsa.h BSA file, BSAIterator - -//! A Bethesda Software Archive file +/* Default header data */ +#define MW_BSAHEADER_FILEID 0x00000100 //!< Magic for Morrowind BSA +#define OB_BSAHEADER_FILEID 0x00415342 //!< Magic for Oblivion BSA, the literal string "BSA\0". +#define F4_BSAHEADER_FILEID 0x58445442 //!< Magic for Fallout 4 BA2, the literal string "BTDX". +#define OB_BSAHEADER_VERSION 0x67 //!< Version number of an Oblivion BSA +#define F3_BSAHEADER_VERSION 0x68 //!< Version number of a Fallout 3 BSA +#define F4_BSAHEADER_VERSION 0x01 //!< Version number of a Fallout 4 BA2 + +/* Archive flags */ +#define OB_BSAARCHIVE_PATHNAMES 0x0001 //!< Whether the BSA has names for paths +#define OB_BSAARCHIVE_FILENAMES 0x0002 //!< Whether the BSA has names for files +#define OB_BSAARCHIVE_COMPRESSFILES 0x0004 //!< Whether the files are compressed +#define F3_BSAARCHIVE_PREFIXFULLFILENAMES 0x0100 //!< Whether the name is prefixed to the data? + +/* File flags */ +#define OB_BSAFILE_NIF 0x0001 //!< Set when the BSA contains NIF files +#define OB_BSAFILE_DDS 0x0002 //!< Set when the BSA contains DDS files +#define OB_BSAFILE_XML 0x0004 //!< Set when the BSA contains XML files +#define OB_BSAFILE_WAV 0x0008 //!< Set when the BSA contains WAV files +#define OB_BSAFILE_MP3 0x0010 //!< Set when the BSA contains MP3 files +#define OB_BSAFILE_TXT 0x0020 //!< Set when the BSA contains TXT files +#define OB_BSAFILE_HTML 0x0020 //!< Set when the BSA contains HTML files +#define OB_BSAFILE_BAT 0x0020 //!< Set when the BSA contains BAT files +#define OB_BSAFILE_SCC 0x0020 //!< Set when the BSA contains SCC files +#define OB_BSAFILE_SPT 0x0040 //!< Set when the BSA contains SPT files +#define OB_BSAFILE_TEX 0x0080 //!< Set when the BSA contains TEX files +#define OB_BSAFILE_FNT 0x0080 //!< Set when the BSA contains FNT files +#define OB_BSAFILE_CTL 0x0100 //!< Set when the BSA contains CTL files + +/* Bitmasks for the size field in the header */ +#define OB_BSAFILE_SIZEMASK 0x3fffffff //!< Bit mask with OBBSAFileInfo::sizeFlags to get the size of the file + +/* Record flags */ +#define OB_BSAFILE_FLAG_COMPRESS 0xC0000000 //!< Bit mask with OBBSAFileInfo::sizeFlags to get the compression status + +//! The header of an Oblivion BSA. /*! - * See The UESP for descriptions of the - * Morrowind format and the - * Oblivion format. - * - * \sa MWBSAHeader, MWBSAFileSizeOffset, OBBSAHeader, OBBSAFileInfo, OBBSAFolderInfo - */ +* Follows OB_BSAHEADER_FILEID and OB_BSAHEADER_VERSION. +*/ +struct OBBSAHeader { + wxUint32 FolderRecordOffset; //!< Offset of beginning of folder records + wxUint32 ArchiveFlags; //!< Archive flags + wxUint32 FolderCount; //!< Total number of folder records (OBBSAFolderInfo) + wxUint32 FileCount; //!< Total number of file records (OBBSAFileInfo) + wxUint32 FolderNameLength; //!< Total length of folder names + wxUint32 FileNameLength; //!< Total length of file names + wxUint32 FileFlags; //!< File flags +}; + +//! Info for a file inside an Oblivion BSA +struct OBBSAFileInfo { + wxUint64 hash; //!< Hash of the filename + wxUint32 sizeFlags; //!< Size of the data, possibly with OB_BSAFILE_FLAG_COMPRESS set + wxUint32 offset; //!< Offset to raw file data +}; + +//! Info for a folder inside an Oblivion BSA +struct OBBSAFolderInfo { + wxUint64 hash; //!< Hash of the folder name + wxUint32 fileCount; //!< Number of files in folder + wxUint32 offset; //!< Offset to name of this folder +}; + +//! The header of a Morrowind BSA +struct MWBSAHeader { + wxUint32 HashOffset; //!< Offset of hash table minus header size (12) + wxUint32 FileCount; //!< Number of files in the archive +}; + +//! The file size and offset of an entry in a Morrowind BSA +struct MWBSAFileSizeOffset { + wxUint32 size; //!< The size of the file + wxUint32 offset; //!< The offset of the file +}; + +#pragma pack(push, 4) +struct F4BSAHeader { + char type[4]; //!< 08 GNRL=General, DX10=Textures + wxUint32 numFiles; //!< 0C + wxUint64 nameTableOffset; //!< 10 - relative to start of file +}; + +// 24 +struct F4GeneralInfo { + wxUint32 unk00; //!< 00 - hash? + char ext[4]; //!< 04 - extension + wxUint32 unk08; //!< 08 - hash? + wxUint32 unk0C; //!< 0C - flags? 00100100 + wxUint64 offset; //!< 10 - relative to start of file + wxUint32 packedSize; //!< 18 - packed length (zlib) + wxUint32 unpackedSize; //!< 1C - unpacked length + wxUint32 unk20; //!< 20 - BAADF00D +}; +#pragma pack(pop) + +// 18 +struct F4TexInfo { + wxUint32 nameHash; //!< 00 + char ext[4]; //!< 04 + wxUint32 dirHash; //!< 08 + wxUint8 unk0C; //!< 0C + wxUint8 numChunks; //!< 0D + wxUint16 chunkHeaderSize; //!< 0E - size of one chunk header + wxUint16 width; //!< 10 + wxUint16 height; //!< 12 + wxUint8 numMips; //!< 14 + wxUint8 format; //!< 15 - DXGI_FORMAT + wxUint16 unk16; //!< 16 - 0800 +}; + +// 18 +struct F4TexChunk { + wxUint64 offset; //!< 00 + wxUint32 packedSize; //!< 08 + wxUint32 unpackedSize; //!< 0C + wxUint16 startMip; //!< 10 + wxUint16 endMip; //!< 12 + wxUint32 unk14; //!< 14 - BAADFOOD +}; + +struct F4Tex { + F4TexInfo header; + std::vector chunks; +}; + + class BSA final : public FSArchiveFile { public: //! Constructor; creates a %BSA from the given file path. @@ -78,6 +193,7 @@ class BSA final : public FSArchiveFile { bool hasFile(const wxString&) const override final; //! Returns the size of the file per BSAFile::size(). wxInt64 fileSize(const wxString&) const override final; + //! Returns the contents of the specified file /*! * \param fn The filename to get the contents for @@ -97,17 +213,29 @@ class BSA final : public FSArchiveFile { //! Returns BSA::status. wxString statusText() const { return status; } + //! Returns BSA::numFiles. + wxUint64 fileCount() const { return numFiles; } + protected: //! A file inside a BSA struct BSAFile { - wxUint32 sizeFlags; //!< The size of the file in the BSA - wxUint32 offset; //!< The offset of the file in the BSA + // Skyrim and earlier + wxUint32 sizeFlags = 0; //!< The size of the file in the BSA + + // Fallout 4 + wxUint32 packedLength = 0; + wxUint32 unpackedLength = 0; + + wxUint64 offset; //!< The offset of the file in the BSA //! The size of the file inside the BSA wxUint32 size() const; + //! Whether the file is compressed inside the BSA bool compressed() const; + + F4Tex tex; }; //! A folder inside a BSA @@ -135,6 +263,7 @@ class BSA final : public FSArchiveFile { BSAFolder *insertFolder(wxString name); //! Inserts a file into the structure of a %BSA BSAFile *insertFile(BSAFolder *folder, wxString name, wxUint32 sizeFlags, wxUint32 offset); + BSAFile *insertFile(BSAFolder *folder, wxString name, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, F4Tex dds = F4Tex()); //! Gets the specified folder, or the root folder if not found const BSAFolder *getFolder(wxString fn) const; @@ -164,10 +293,11 @@ class BSA final : public FSArchiveFile { //! Error string for exception handling wxString status; + //! Number of files + wxUint64 numFiles; + //! Whether the %BSA is compressed bool compressToggle; //! Whether Fallout 3 names are prefixed with an extra string bool namePrefix; }; - -#endif diff --git a/FSManager.cpp b/FSManager.cpp index 1eb548a9..13ebdfab 100644 --- a/FSManager.cpp +++ b/FSManager.cpp @@ -88,10 +88,11 @@ wxArrayString FSManager::autodetectArchives() { wxString path = Config["GameDataPath"]; if (!path.IsEmpty()) { wxArrayString files; - wxDir::GetAllFiles(path, &files, "*.bsa", wxDIR_FILES); + wxDir::GetAllFiles(path, &files, wxEmptyString, wxDIR_FILES); for (auto &file : files) - list.Add(file); + if (file.EndsWith(".bsa") || file.EndsWith(".ba2")) + list.Add(file); } return list; diff --git a/Log.cpp b/Log.cpp index 1fa47d3c..21b2dcb4 100644 --- a/Log.cpp +++ b/Log.cpp @@ -1,3 +1,9 @@ +/* +BodySlide and Outfit Studio +Copyright (C) 2015 Caliente & ousnius +See the included LICENSE file +*/ + #include "Log.h" #include "BodySlideApp.h" diff --git a/Log.h b/Log.h index c56f0971..0c17fe5f 100644 --- a/Log.h +++ b/Log.h @@ -1,3 +1,9 @@ +/* +BodySlide and Outfit Studio +Copyright (C) 2015 Caliente & ousnius +See the included LICENSE file +*/ + #pragma once #include #include diff --git a/zlib b/zlib new file mode 160000 index 00000000..50893291 --- /dev/null +++ b/zlib @@ -0,0 +1 @@ +Subproject commit 50893291621658f355bc5b4d450a8d06a563053d From 28583b297d2777edbac1aea90300f6a1da3c16a1 Mon Sep 17 00:00:00 2001 From: ousnius Date: Thu, 12 Nov 2015 00:42:17 +0100 Subject: [PATCH 04/64] Added missing DDS.h --- DDS.h | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 DDS.h diff --git a/DDS.h b/DDS.h new file mode 100644 index 00000000..58a55ad0 --- /dev/null +++ b/DDS.h @@ -0,0 +1,112 @@ +//-------------------------------------------------------------------------------------- +// dds.h +// +// This header defines constants and structures that are useful when parsing +// DDS files. DDS files were originally designed to use several structures +// and constants that are native to DirectDraw and are defined in ddraw.h, +// such as DDSURFACEDESC2 and DDSCAPS2. This file defines similar +// (compatible) constants and structures so that one can use DDS files +// without needing to include ddraw.h. +//-------------------------------------------------------------------------------------- + +#pragma once + +#include +#include + +#pragma pack(push,1) + +#define DDS_MAGIC 0x20534444 // "DDS " + +struct DDS_PIXELFORMAT +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwFourCC; + DWORD dwRGBBitCount; + DWORD dwRBitMask; + DWORD dwGBitMask; + DWORD dwBBitMask; + DWORD dwABitMask; +}; + +#define DDS_FOURCC 0x00000004 // DDPF_FOURCC +#define DDS_RGB 0x00000040 // DDPF_RGB +#define DDS_RGBA 0x00000041 // DDPF_RGB | DDPF_ALPHAPIXELS +#define DDS_LUMINANCE 0x00020000 // DDPF_LUMINANCE +#define DDS_ALPHA 0x00000002 // DDPF_ALPHA + +const DDS_PIXELFORMAT DDSPF_DXT1 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 }; + +const DDS_PIXELFORMAT DDSPF_DXT2 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','2'), 0, 0, 0, 0, 0 }; + +const DDS_PIXELFORMAT DDSPF_DXT3 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0 }; + +const DDS_PIXELFORMAT DDSPF_DXT4 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','4'), 0, 0, 0, 0, 0 }; + +const DDS_PIXELFORMAT DDSPF_DXT5 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0 }; + +const DDS_PIXELFORMAT DDSPF_A8R8G8B8 = + { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }; + +const DDS_PIXELFORMAT DDSPF_A1R5G5B5 = + { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000 }; + +const DDS_PIXELFORMAT DDSPF_A4R4G4B4 = + { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000 }; + +const DDS_PIXELFORMAT DDSPF_R8G8B8 = + { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 }; + +const DDS_PIXELFORMAT DDSPF_R5G6B5 = + { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000 }; + +// This indicates the DDS_HEADER_DXT10 extension is present (the format is in dxgiFormat) +const DDS_PIXELFORMAT DDSPF_DX10 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }; + +#define DDS_HEADER_FLAGS_TEXTURE 0x00001007 // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT +#define DDS_HEADER_FLAGS_MIPMAP 0x00020000 // DDSD_MIPMAPCOUNT +#define DDS_HEADER_FLAGS_VOLUME 0x00800000 // DDSD_DEPTH +#define DDS_HEADER_FLAGS_PITCH 0x00000008 // DDSD_PITCH +#define DDS_HEADER_FLAGS_LINEARSIZE 0x00080000 // DDSD_LINEARSIZE + +#define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE +#define DDS_SURFACE_FLAGS_MIPMAP 0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP +#define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX + +#define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX +#define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX +#define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY +#define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY +#define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ +#define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ + +#define DDS_CUBEMAP_ALLFACES ( DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX |\ + DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY |\ + DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ ) + +#define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME + +typedef struct +{ + DWORD dwSize; + DWORD dwHeaderFlags; + DWORD dwHeight; + DWORD dwWidth; + DWORD dwPitchOrLinearSize; + DWORD dwDepth; // only if DDS_HEADER_FLAGS_VOLUME is set in dwHeaderFlags + DWORD dwMipMapCount; + DWORD dwReserved1[11]; + DDS_PIXELFORMAT ddspf; + DWORD dwSurfaceFlags; + DWORD dwCubemapFlags; + DWORD dwReserved2[3]; +} DDS_HEADER; + +#pragma pack(pop) From d32faf1acdacde1fff022e3a2bd38bc314ca928c Mon Sep 17 00:00:00 2001 From: ousnius Date: Thu, 12 Nov 2015 14:57:47 +0100 Subject: [PATCH 05/64] Add FO4 target game selection to settings --- res/BodyslideFrame.xrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/BodyslideFrame.xrc b/res/BodyslideFrame.xrc index 21d11929..296c3484 100644 --- a/res/BodyslideFrame.xrc +++ b/res/BodyslideFrame.xrc @@ -770,11 +770,12 @@ 5 Choose the target game you want to use the program for here. - 2 + 3 Fallout 3 Fallout New Vegas Skyrim + Fallout 4 From 1b60d4deb8c5599cc49bd04bf330e9aa6fedcf31 Mon Sep 17 00:00:00 2001 From: ousnius Date: Thu, 12 Nov 2015 20:50:16 +0100 Subject: [PATCH 06/64] std::string in FSBSA Performance improvements. --- FSBSA.cpp | 177 ++++++++++++++++++++++++--------------------- FSBSA.h | 42 +++++------ FSEngine.cpp | 2 +- FSEngine.h | 22 +++--- FSManager.cpp | 15 ++-- FSManager.h | 3 +- ResourceLoader.cpp | 4 +- 7 files changed, 139 insertions(+), 126 deletions(-) diff --git a/FSBSA.cpp b/FSBSA.cpp index 4ee54be8..80b5dedc 100644 --- a/FSBSA.cpp +++ b/FSBSA.cpp @@ -35,6 +35,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "zlib\zlib.h" #include +#include #pragma warning (disable : 4389) @@ -53,7 +54,7 @@ bool BSA::BSAFile::compressed() const { } //! Reads a foldername sized string (length + null-terminated string) from the BSA -static bool BSAReadSizedString(wxFile &bsa, wxString &s) { +static bool BSAReadSizedString(wxFile &bsa, std::string &s) { //qDebug() << "BSA is at" << bsa.pos(); wxUint8 len; if (bsa.Read((char *)&len, 1) != 1) { @@ -126,7 +127,7 @@ wxMemoryBuffer gUncompress(const wxMemoryBuffer &data) { } -BSA::BSA(const wxString &filename) : FSArchiveFile(), bsa(filename), bsaInfo(filename), status("initialized") { +BSA::BSA(const std::string &filename) : FSArchiveFile(), bsa(filename), bsaInfo(filename), status("initialized") { bsaPath = bsaInfo.GetPathWithSep() + bsaInfo.GetFullName(); bsaBase = bsaInfo.GetPath(); bsaName = bsaInfo.GetFullName(); @@ -136,7 +137,7 @@ BSA::~BSA() { close(); } -bool BSA::canOpen(const wxString &fn) { +bool BSA::canOpen(const std::string &fn) { wxFile f(fn); if (f.IsOpened()) { wxUint32 magic, version; @@ -170,7 +171,7 @@ bool BSA::open() { try { bsa.Open(bsaPath); if (!bsa.IsOpened()) - throw wxString("file open"); + throw std::string("file open"); wxUint32 magic, version; @@ -180,15 +181,15 @@ bool BSA::open() { bsa.Read((char*)&version, sizeof(version)); if (version != F4_BSAHEADER_VERSION) - throw wxString("file version"); + throw std::string("file version"); F4BSAHeader header; if (bsa.Read((char *)&header, sizeof(header)) != sizeof(header)) - throw wxString("header size"); + throw std::string("header size"); numFiles = header.numFiles; - std::vector filepaths; + std::vector filepaths; if (bsa.Seek(header.nameTableOffset)) { for (wxUint32 i = 0; i < header.numFiles; i++) { wxUint16 length; @@ -197,13 +198,13 @@ bool BSA::open() { wxMemoryBuffer strdata(length); bsa.Read(strdata.GetData(), length); - wxString filepath(strdata, strdata.GetBufSize()); + std::string filepath(strdata, strdata.GetBufSize()); filepaths.push_back(filepath); } } - wxString h(header.type, 4); + std::string h(header.type, 4); if (h == "GNRL") { // General BA2 Format if (bsa.Seek(sizeof(header) + 8)) { @@ -211,14 +212,17 @@ bool BSA::open() { F4GeneralInfo finfo; bsa.Read((char*)&finfo, 36); - wxString fullpath = filepaths[i]; - fullpath.Replace("\\", "/"); + std::string fullpath = filepaths[i]; + std::replace(fullpath.begin(), fullpath.end(), '\\', '/'); - wxString filename = fullpath.AfterLast('/'); - wxString folderName = fullpath.BeforeLast('/'); + std::string folderName; + int p = fullpath.find_last_of('/'); + if (p >= 0) + folderName = fullpath.substr(0, p); - BSAFolder * folder = insertFolder(folderName); + std::string filename = fullpath.substr(p + 1); + BSAFolder *folder = insertFolder(folderName); insertFile(folder, filename, finfo.packedSize, finfo.unpackedSize, finfo.offset); } } @@ -239,13 +243,17 @@ bool BSA::open() { tex.chunks = texChunks; - wxString fullpath = filepaths[i]; - fullpath.Replace("\\", "/"); + std::string fullpath = filepaths[i]; + std::replace(fullpath.begin(), fullpath.end(), '\\', '/'); - wxString filename = fullpath.AfterLast('/'); - wxString folderName = fullpath.BeforeLast('/'); + std::string folderName; + int p = fullpath.find_last_of('/'); + if (p >= 0) + folderName = fullpath.substr(0, p); - BSAFolder * folder = insertFolder(folderName); + std::string filename = fullpath.substr(p + 1); + + BSAFolder *folder = insertFolder(folderName); F4TexChunk chunk = tex.chunks[0]; insertFile(folder, filename, chunk.packedSize, chunk.unpackedSize, chunk.offset, tex); @@ -258,18 +266,18 @@ bool BSA::open() { bsa.Read((char*)&version, sizeof(version)); if (version != OB_BSAHEADER_VERSION && version != F3_BSAHEADER_VERSION) - throw wxString("file version"); + throw std::string("file version"); OBBSAHeader header; if (bsa.Read((char *)& header, sizeof(header)) != sizeof(header)) - throw wxString("header size"); + throw std::string("header size"); numFiles = header.FileCount; //qWarning() << bsaName << header; if ((header.ArchiveFlags & OB_BSAARCHIVE_PATHNAMES) == 0 || (header.ArchiveFlags & OB_BSAARCHIVE_FILENAMES) == 0) - throw wxString("header flags"); + throw std::string("header flags"); compressToggle = (header.ArchiveFlags & OB_BSAARCHIVE_COMPRESSFILES) != 0; @@ -279,22 +287,22 @@ bool BSA::open() { namePrefix = false; if (bsa.Seek(header.FolderRecordOffset + header.FolderNameLength + header.FolderCount * (1 + sizeof(OBBSAFolderInfo)) + header.FileCount * sizeof(OBBSAFileInfo)) == wxInvalidOffset) - throw wxString("file name seek"); + throw std::string("file name seek"); wxMemoryBuffer fileNames(header.FileNameLength); if (bsa.Read(fileNames.GetData(), header.FileNameLength) != header.FileNameLength) - throw wxString("file name read"); + throw std::string("file name read"); wxUint32 fileNameIndex = 0; //qDebug() << bsa.pos() - header.FileNameLength << fileNames; if (bsa.Seek(header.FolderRecordOffset) == wxInvalidOffset) - throw wxString("folder info seek"); + throw std::string("folder info seek"); std::vector folderInfos(header.FolderCount); if (bsa.Read((char *)folderInfos.data(), header.FolderCount * sizeof(OBBSAFolderInfo)) != header.FolderCount * sizeof(OBBSAFolderInfo)) - throw wxString("folder info read"); + throw std::string("folder info read"); wxUint32 totalFileCount = 0; @@ -307,28 +315,28 @@ bool BSA::open() { */ - wxString folderName; - if (!BSAReadSizedString(bsa, folderName) || folderName.IsEmpty()) { + std::string folderName; + if (!BSAReadSizedString(bsa, folderName) || folderName.empty()) { //qDebug() << "folderName" << folderName; - throw wxString("folder name read"); + throw std::string("folder name read"); } // qDebug() << folderName; - BSAFolder * folder = insertFolder(folderName); + BSAFolder *folder = insertFolder(folderName); wxUint32 fcnt = folderInfo.fileCount; totalFileCount += fcnt; std::vector fileInfos(fcnt); if (bsa.Read((char *)fileInfos.data(), fcnt * sizeof(OBBSAFileInfo)) != fcnt * sizeof(OBBSAFileInfo)) - throw wxString("file info read"); + throw std::string("file info read"); for (const OBBSAFileInfo fileInfo : fileInfos) { if (fileNameIndex >= header.FileNameLength) - throw wxString("file name size"); + throw std::string("file name size"); - wxString fileName = static_cast(fileNames.GetData()) + fileNameIndex; + std::string fileName = static_cast(fileNames.GetData()) + fileNameIndex; fileNameIndex += fileName.length() + 1; insertFile(folder, fileName, fileInfo.sizeFlags, fileInfo.offset); @@ -336,13 +344,13 @@ bool BSA::open() { } if (totalFileCount != header.FileCount) - throw wxString("file count"); + throw std::string("file count"); } else if (magic == MW_BSAHEADER_FILEID) { MWBSAHeader header; if (bsa.Read((char *)& header, sizeof(header)) != sizeof(header)) - throw wxString("header"); + throw std::string("header"); numFiles = header.FileCount; compressToggle = false; @@ -354,30 +362,30 @@ bool BSA::open() { // file size/offset table std::vector sizeOffset(header.FileCount); if (bsa.Read((char *)sizeOffset.data(), header.FileCount * sizeof(MWBSAFileSizeOffset)) != header.FileCount * sizeof(MWBSAFileSizeOffset)) - throw wxString("file size/offset"); + throw std::string("file size/offset"); // filename offset table std::vector nameOffset(header.FileCount); if (bsa.Read((char *)nameOffset.data(), header.FileCount * sizeof(wxUint32)) != header.FileCount * sizeof(wxUint32)) - throw wxString("file name offset"); + throw std::string("file name offset"); // filenames. size is given by ( HashOffset - ( 8 * number of file/size offsets) - ( 4 * number of filenames) ) // i.e. ( HashOffset - ( 12 * number of files ) ) wxMemoryBuffer fileNames; fileNames.SetBufSize(header.HashOffset - 12 * header.FileCount); if (bsa.Read((char *)fileNames.GetData(), header.HashOffset - 12 * header.FileCount) != header.HashOffset - 12 * header.FileCount) - throw wxString("file names"); + throw std::string("file names"); // table of 8 bytes of hash values follow, but we don't need to know what they are // file data follows that, which is fetched by fileContents for (wxUint32 c = 0; c < header.FileCount; c++) { - wxString fname = static_cast(fileNames.GetData()) + nameOffset[c]; - wxString dname; - int x = fname.Last('\\'); + std::string fname = static_cast(fileNames.GetData()) + nameOffset[c]; + std::string dname; + int x = fname.find_last_of('\\'); if (x > 0) { - dname = fname.Left(x); - fname = fname.Remove(0, x + 1); + dname = fname.substr(0, x); + fname.erase(0, x + 1); } // qDebug() << "inserting" << dname << fname; @@ -386,9 +394,9 @@ bool BSA::open() { } } else - throw wxString("file magic"); + throw std::string("file magic"); } - catch (wxString e) { + catch (std::string e) { status = e; return false; } @@ -412,7 +420,7 @@ void BSA::close() { folders.clear(); } -wxInt64 BSA::fileSize(const wxString & fn) const { +wxInt64 BSA::fileSize(const std::string & fn) const { // note: lazy size count (not accurate for compressed files) if (const BSAFile * file = getFile(fn)) { if (file->sizeFlags > 0) @@ -431,7 +439,7 @@ wxInt64 BSA::fileSize(const wxString & fn) const { return 0; } -bool BSA::fileContents(const wxString &fn, wxMemoryBuffer &content) { +bool BSA::fileContents(const std::string &fn, wxMemoryBuffer &content) { //qDebug() << "entering fileContents for" << fn; if (const BSAFile *file = getFile(fn)) { wxMutexLocker lock(bsaMutex); @@ -520,7 +528,7 @@ bool BSA::fileContents(const wxString &fn, wxMemoryBuffer &content) { memcpy(buf, &ddsHeader, sizeof(ddsHeader)); // Append DDS Header - wxString dds = "DDS "; + std::string dds = "DDS "; content.SetBufSize(sizeof(ddsHeader) + 4); content.AppendData(dds.data(), 4); content.AppendData(buf, sizeof(ddsHeader)); @@ -583,75 +591,77 @@ bool BSA::fileContents(const wxString &fn, wxMemoryBuffer &content) { return false; } -wxString BSA::absoluteFilePath(const wxString &fn) const { +std::string BSA::absoluteFilePath(const std::string &fn) const { if (hasFile(fn)) { wxFileName fileInfo(fn); - return fileInfo.GetPath(true) + fileInfo.GetName(); + return (fileInfo.GetPath(true) + fileInfo.GetName()).ToStdString(); } - return wxString(); + return std::string(); } -BSA::BSAFolder *BSA::insertFolder(wxString name) { - if (name.IsEmpty()) +BSA::BSAFolder *BSA::insertFolder(std::string name) { + if (name.empty()) return &root; - name.Replace("\\", "/"); - name = name.Lower(); + std::replace(name.begin(), name.end(), '\\', '/'); + std::transform(name.begin(), name.end(), name.begin(), ::tolower); - BSAFolder *folder = folders[name.ToStdString()]; + BSAFolder *folder = folders[name]; if (!folder) { // qDebug() << "inserting" << name; folder = new BSAFolder; - folders[name.ToStdString()] = folder; + folders[name] = folder; - int p = name.Last('/'); + int p = name.find_last_of('/'); if (p >= 0) { - folder->parent = insertFolder(name.Left(p)); - folder->parent->children[name.Right(name.length() - p - 1).ToStdString()] = folder; + folder->parent = insertFolder(name.substr(0, p)); + folder->parent->children[name.substr(p + 1)] = folder; } else { folder->parent = &root; - root.children[name.ToStdString()] = folder; + root.children[name] = folder; } } return folder; } -BSA::BSAFile *BSA::insertFile(BSAFolder *folder, wxString name, wxUint32 sizeFlags, wxUint32 offset) { - name = name.Lower(); +BSA::BSAFile *BSA::insertFile(BSAFolder *folder, std::string name, wxUint32 sizeFlags, wxUint32 offset) { + std::transform(name.begin(), name.end(), name.begin(), ::tolower); BSAFile *file = new BSAFile; file->sizeFlags = sizeFlags; file->offset = offset; - folder->files[name.ToStdString()] = file; + folder->files[name] = file; return file; } -BSA::BSAFile *BSA::insertFile(BSAFolder *folder, wxString name, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, F4Tex dds) { - name = name.Lower(); +BSA::BSAFile *BSA::insertFile(BSAFolder *folder, std::string name, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, F4Tex dds) { + std::transform(name.begin(), name.end(), name.begin(), ::tolower); - BSAFile * file = new BSAFile; + BSAFile *file = new BSAFile; file->tex = dds; file->packedLength = packed; file->unpackedLength = unpacked; file->offset = offset; - folder->files[name.ToStdString()] = file; + folder->files[name] = file; return file; } -const BSA::BSAFolder *BSA::getFolder(wxString fn) const { - if (fn.IsEmpty()) { +const BSA::BSAFolder *BSA::getFolder(std::string fn) const { + std::transform(fn.begin(), fn.end(), fn.begin(), ::tolower); + + if (fn.empty()) { return &root; } else { - auto it = folders.find(fn.Lower().ToStdString()); + auto it = folders.find(fn); if (it != folders.end()) { - BSA::BSAFolder* folder = it->second; + BSA::BSAFolder *folder = it->second; if (folder) return folder; } @@ -660,22 +670,23 @@ const BSA::BSAFolder *BSA::getFolder(wxString fn) const { return nullptr; } -const BSA::BSAFile *BSA::getFile(wxString fn) const { - wxString folderName; - wxString fileName = fn.Lower(); - int p = fileName.Last('/'); +const BSA::BSAFile *BSA::getFile(std::string fn) const { + std::transform(fn.begin(), fn.end(), fn.begin(), ::tolower); + + std::string folderName; + int p = fn.find_last_of('/'); if (p >= 0) { - folderName = fileName.Left(p); - fileName = fileName.Right(fileName.length() - p - 1); + folderName = fn.substr(0, p); + fn = fn.substr(p + 1); } // TODO: Multiple matches occur and user has no say which version gets loaded // When it comes to the AUTO feature, should give preference to certain BSAs // or take the newest and or highest quality version. if (const BSAFolder *folder = getFolder(folderName)) { - auto it = folder->files.find(fileName.ToStdString()); + auto it = folder->files.find(fn); if (it != folder->files.end()) { - BSA::BSAFile* file = it->second; + BSA::BSAFile *file = it->second; if (file) return file; } @@ -684,15 +695,15 @@ const BSA::BSAFile *BSA::getFile(wxString fn) const { return nullptr; } -bool BSA::hasFile(const wxString &fn) const { +bool BSA::hasFile(const std::string &fn) const { return getFile(fn) != nullptr; } -bool BSA::hasFolder(const wxString &fn) const { +bool BSA::hasFolder(const std::string &fn) const { return getFolder(fn) != nullptr; } -wxDateTime BSA::fileTime(const wxString&) const { +wxDateTime BSA::fileTime(const std::string&) const { wxDateTime created; bsaInfo.GetTimes(nullptr, nullptr, &created); return created; diff --git a/FSBSA.h b/FSBSA.h index f35211bd..3b2018a4 100644 --- a/FSBSA.h +++ b/FSBSA.h @@ -170,7 +170,7 @@ struct F4Tex { class BSA final : public FSArchiveFile { public: //! Constructor; creates a %BSA from the given file path. - BSA(const wxString &filePath); + BSA(const std::string &filePath); //! Destructor; closes the file. ~BSA(); @@ -180,19 +180,19 @@ class BSA final : public FSArchiveFile { void close() override final; //! Returns BSA::bsaPath. - wxString path() const override final { return bsaPath; } + std::string path() const override final { return bsaPath; } //! Returns BSA::bsaBase. - wxString base() const override final { return bsaBase; } + std::string base() const override final { return bsaBase; } //! Returns BSA::bsaName. - wxString name() const override final { return bsaName; } + std::string name() const override final { return bsaName; } //! Whether the specified folder exists or not - bool hasFolder(const wxString&) const override final; + bool hasFolder(const std::string&) const override final; //! Whether the specified file exists or not - bool hasFile(const wxString&) const override final; + bool hasFile(const std::string&) const override final; //! Returns the size of the file per BSAFile::size(). - wxInt64 fileSize(const wxString&) const override final; + wxInt64 fileSize(const std::string&) const override final; //! Returns the contents of the specified file /*! @@ -200,18 +200,18 @@ class BSA final : public FSArchiveFile { * \param content Reference to the byte array that holds the file contents * \return True if successful */ - bool fileContents(const wxString&, wxMemoryBuffer&) override final; + bool fileContents(const std::string&, wxMemoryBuffer&) override final; //! See QFileInfo::created(). - wxDateTime fileTime(const wxString&) const override final; + wxDateTime fileTime(const std::string&) const override final; //! See QFileInfo::absoluteFilePath(). - wxString absoluteFilePath(const wxString&) const override final; + std::string absoluteFilePath(const std::string&) const override final; //! Whether the given file can be opened as a %BSA or not - static bool canOpen(const wxString&); + static bool canOpen(const std::string&); //! Returns BSA::status. - wxString statusText() const { return status; } + std::string statusText() const { return status; } //! Returns BSA::numFiles. wxUint64 fileCount() const { return numFiles; } @@ -260,15 +260,15 @@ class BSA final : public FSArchiveFile { }; //! Recursive function to generate the tree structure of folders inside a %BSA - BSAFolder *insertFolder(wxString name); + BSAFolder *insertFolder(std::string name); //! Inserts a file into the structure of a %BSA - BSAFile *insertFile(BSAFolder *folder, wxString name, wxUint32 sizeFlags, wxUint32 offset); - BSAFile *insertFile(BSAFolder *folder, wxString name, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, F4Tex dds = F4Tex()); + BSAFile *insertFile(BSAFolder *folder, std::string name, wxUint32 sizeFlags, wxUint32 offset); + BSAFile *insertFile(BSAFolder *folder, std::string name, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, F4Tex dds = F4Tex()); //! Gets the specified folder, or the root folder if not found - const BSAFolder *getFolder(wxString fn) const; + const BSAFolder *getFolder(std::string fn) const; //! Gets the specified file, or null if not found - const BSAFile *getFile(wxString fn) const; + const BSAFile *getFile(std::string fn) const; //! The %BSA file wxFile bsa; @@ -279,11 +279,11 @@ class BSA final : public FSArchiveFile { wxMutex bsaMutex; //! The absolute name of the file, e.g. "d:/temp/test.bsa" - wxString bsaPath; + std::string bsaPath; //! The base path of the file, e.g. "d:/temp" - wxString bsaBase; + std::string bsaBase; //! The name of the file, e.g. "test.bsa" - wxString bsaName; + std::string bsaName; //! Map of folders inside a %BSA std::unordered_map folders; @@ -291,7 +291,7 @@ class BSA final : public FSArchiveFile { BSAFolder root; //! Error string for exception handling - wxString status; + std::string status; //! Number of files wxUint64 numFiles; diff --git a/FSEngine.cpp b/FSEngine.cpp index 4fb0aa6f..9e2909f4 100644 --- a/FSEngine.cpp +++ b/FSEngine.cpp @@ -36,7 +36,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //! \file fsengine.cpp File system engine implementations -FSArchiveHandler * FSArchiveHandler::openArchive(const wxString &fn) { +FSArchiveHandler *FSArchiveHandler::openArchive(const std::string &fn) { if (BSA::canOpen(fn)) { BSA *bsa = new BSA(fn); if (bsa->open()) { diff --git a/FSEngine.h b/FSEngine.h index 92d0b9d1..61f2c374 100644 --- a/FSEngine.h +++ b/FSEngine.h @@ -43,7 +43,7 @@ class FSArchiveHandler { public: //! Opens a BSA for the specified file - static FSArchiveHandler *openArchive(const wxString&); + static FSArchiveHandler *openArchive(const std::string&); public: //! Constructor @@ -51,7 +51,7 @@ class FSArchiveHandler //! Destructor ~FSArchiveHandler(); - FSArchiveFile * getArchive() { return archive; } + FSArchiveFile *getArchive() { return archive; } protected: class FSArchiveFile *archive; @@ -69,17 +69,17 @@ class FSArchiveFile virtual bool open() = 0; virtual void close() = 0; - virtual wxString base() const = 0; - virtual wxString name() const = 0; - virtual wxString path() const = 0; + virtual std::string base() const = 0; + virtual std::string name() const = 0; + virtual std::string path() const = 0; - virtual bool hasFolder(const wxString&) const = 0; - virtual bool hasFile(const wxString&) const = 0; - virtual wxInt64 fileSize(const wxString&) const = 0; - virtual bool fileContents(const wxString&, wxMemoryBuffer&) = 0; - virtual wxString absoluteFilePath(const wxString&) const = 0; + virtual bool hasFolder(const std::string&) const = 0; + virtual bool hasFile(const std::string&) const = 0; + virtual wxInt64 fileSize(const std::string&) const = 0; + virtual bool fileContents(const std::string&, wxMemoryBuffer&) = 0; + virtual std::string absoluteFilePath(const std::string&) const = 0; - virtual wxDateTime fileTime(const wxString&) const = 0; + virtual wxDateTime fileTime(const std::string&) const = 0; protected: //! A reference counter for an implicitly shared class diff --git a/FSManager.cpp b/FSManager.cpp index 13ebdfab..8529e079 100644 --- a/FSManager.cpp +++ b/FSManager.cpp @@ -35,6 +35,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FSEngine.h" #include "FSBSA.h" #include "ConfigurationManager.h" + #include @@ -64,12 +65,12 @@ std::list FSManager::archiveList() { } FSManager::FSManager() { - wxArrayString list; + std::vector list; list = autodetectArchives(); for (auto &an : list) { if (FSArchiveHandler *a = FSArchiveHandler::openArchive(an)) - archives[an.ToStdString()] = a; + archives[an] = a; } } @@ -80,19 +81,19 @@ FSManager::~FSManager() { archives.clear(); } -wxArrayString FSManager::autodetectArchives() { - wxArrayString list; +std::vector FSManager::autodetectArchives() { + std::vector list; if (Config["GameDataPath"].empty()) return list; - wxString path = Config["GameDataPath"]; - if (!path.IsEmpty()) { + std::string path = Config["GameDataPath"]; + if (!path.empty()) { wxArrayString files; wxDir::GetAllFiles(path, &files, wxEmptyString, wxDIR_FILES); for (auto &file : files) if (file.EndsWith(".bsa") || file.EndsWith(".ba2")) - list.Add(file); + list.push_back(file.ToStdString()); } return list; diff --git a/FSManager.h b/FSManager.h index 3eb32be2..d04f1390 100644 --- a/FSManager.h +++ b/FSManager.h @@ -33,6 +33,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include +#include #include #include @@ -59,5 +60,5 @@ class FSManager { std::map archives; //! Builds a list of global BSAs on Windows platforms - static wxArrayString autodetectArchives(); + static std::vector autodetectArchives(); }; diff --git a/ResourceLoader.cpp b/ResourceLoader.cpp index ed64627b..b687ac5c 100644 --- a/ResourceLoader.cpp +++ b/ResourceLoader.cpp @@ -56,9 +56,9 @@ GLMaterial* ResourceLoader::AddMaterial(const string& textureFile, const string& texFile.Replace("\\", "/"); for (FSArchiveFile *archive : FSManager::archiveList()) { if (archive) { - if (archive->hasFile(texFile)) { + if (archive->hasFile(texFile.ToStdString())) { wxMemoryBuffer outData; - archive->fileContents(texFile, outData); + archive->fileContents(texFile.ToStdString(), outData); if (!outData.IsEmpty()) { data = outData; From 89e1418fe97e87e11aa0c8d1bc3dcbcce312a867 Mon Sep 17 00:00:00 2001 From: ousnius Date: Fri, 13 Nov 2015 01:05:46 +0100 Subject: [PATCH 07/64] Loading FO4 diffuse textures from BA2 should be working now --- FSBSA.cpp | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/FSBSA.cpp b/FSBSA.cpp index 80b5dedc..9919ad37 100644 --- a/FSBSA.cpp +++ b/FSBSA.cpp @@ -75,9 +75,9 @@ static bool BSAReadSizedString(wxFile &bsa, std::string &s) { } } -wxMemoryBuffer gUncompress(const wxMemoryBuffer &data) { +wxMemoryBuffer gUncompress(const wxMemoryBuffer &data, int skip = 0) { if (data.GetBufSize() <= 4) { - //qWarning("gUncompress: Input data is truncated"); + // Input data is truncated return wxMemoryBuffer(); } @@ -94,8 +94,7 @@ wxMemoryBuffer gUncompress(const wxMemoryBuffer &data) { strm.opaque = Z_NULL; strm.avail_in = data.GetBufSize(); - char *dataPtr = static_cast(data.GetData()); - strm.next_in = (Bytef*)(dataPtr + 4); + strm.next_in = (Bytef*)(data + skip); ret = inflateInit2(&strm, 15 + 32); // gzip decoding if (ret != Z_OK) @@ -118,6 +117,7 @@ wxMemoryBuffer gUncompress(const wxMemoryBuffer &data) { return wxMemoryBuffer(); } + result.SetBufSize(result.GetBufSize() + CHUNK_SIZE - strm.avail_out); result.AppendData(out, CHUNK_SIZE - strm.avail_out); } while (strm.avail_out == 0); @@ -145,7 +145,6 @@ bool BSA::canOpen(const std::string &fn) { if (f.Read((char *)& magic, sizeof(magic)) != 4) return false; - //qDebug() << "Magic:" << QString::number( magic, 16 ); if (magic == F4_BSAHEADER_FILEID) { if (f.Read((char *)&version, sizeof(version)) != 4) return false; @@ -188,6 +187,7 @@ bool BSA::open() { throw std::string("header size"); numFiles = header.numFiles; + namePrefix = false; std::vector filepaths; if (bsa.Seek(header.nameTableOffset)) { @@ -274,7 +274,6 @@ bool BSA::open() { throw std::string("header size"); numFiles = header.FileCount; - //qWarning() << bsaName << header; if ((header.ArchiveFlags & OB_BSAARCHIVE_PATHNAMES) == 0 || (header.ArchiveFlags & OB_BSAARCHIVE_FILENAMES) == 0) throw std::string("header flags"); @@ -295,8 +294,6 @@ bool BSA::open() { wxUint32 fileNameIndex = 0; - //qDebug() << bsa.pos() - header.FileNameLength << fileNames; - if (bsa.Seek(header.FolderRecordOffset) == wxInvalidOffset) throw std::string("folder info seek"); @@ -316,12 +313,8 @@ bool BSA::open() { std::string folderName; - if (!BSAReadSizedString(bsa, folderName) || folderName.empty()) { - //qDebug() << "folderName" << folderName; + if (!BSAReadSizedString(bsa, folderName) || folderName.empty()) throw std::string("folder name read"); - } - - // qDebug() << folderName; BSAFolder *folder = insertFolder(folderName); @@ -388,8 +381,6 @@ bool BSA::open() { fname.erase(0, x + 1); } - // qDebug() << "inserting" << dname << fname; - insertFile(insertFolder(dname), fname, sizeOffset[c].size, dataOffset + sizeOffset[c].offset); } } @@ -440,7 +431,6 @@ wxInt64 BSA::fileSize(const std::string & fn) const { } bool BSA::fileContents(const std::string &fn, wxMemoryBuffer &content) { - //qDebug() << "entering fileContents for" << fn; if (const BSAFile *file = getFile(fn)) { wxMutexLocker lock(bsaMutex); if (bsa.Seek(file->offset)) { @@ -540,13 +530,15 @@ bool BSA::fileContents(const std::string &fn, wxMemoryBuffer &content) { if (file->sizeFlags > 0) { // BSA if (file->compressed() ^ compressToggle) { - firstChunk = gUncompress(firstChunk); + firstChunk = gUncompress(firstChunk, 4); + content.SetBufSize(content.GetBufSize() + firstChunk.GetBufSize()); content.AppendData(firstChunk, firstChunk.GetBufSize()); } } else if (file->packedLength > 0) { // BA2 firstChunk = gUncompress(firstChunk); + content.SetBufSize(content.GetBufSize() + firstChunk.GetBufSize()); content.AppendData(firstChunk, firstChunk.GetBufSize()); } @@ -562,8 +554,8 @@ bool BSA::fileContents(const std::string &fn, wxMemoryBuffer &content) { if (bsa.Read(chunkData.GetData(), chunk.packedSize) == chunk.packedSize) chunkData = gUncompress(chunkData); - if (chunkData.GetBufSize() != chunk.unpackedSize) { - //qCritical() << "Size does not match at " << chunk.offset; + if (chunkData.GetDataLen() != chunk.unpackedSize) { + // Size does not match at chunk.offset return false; } @@ -571,15 +563,16 @@ bool BSA::fileContents(const std::string &fn, wxMemoryBuffer &content) { else { chunkData.SetBufSize(chunk.unpackedSize); if (!(bsa.Read(chunkData.GetData(), chunk.unpackedSize) == chunk.unpackedSize)) { - //qCritical() << "Size does not match at " << chunk.offset; + // Size does not match at chunk.offset return false; } } - + + content.SetBufSize(content.GetBufSize() + chunkData.GetBufSize()); content.AppendData(chunkData.GetData(), chunkData.GetBufSize()); } else { - //qCritical() << "Seek error"; + // Seek error return false; } } @@ -609,8 +602,6 @@ BSA::BSAFolder *BSA::insertFolder(std::string name) { BSAFolder *folder = folders[name]; if (!folder) { - // qDebug() << "inserting" << name; - folder = new BSAFolder; folders[name] = folder; From 575100c12e8f3d3f7c4fb83183e91f3e711f76ba Mon Sep 17 00:00:00 2001 From: ousnius Date: Fri, 13 Nov 2015 18:56:59 +0100 Subject: [PATCH 08/64] Fixed BSA/BA2 buffer sizes Moved auto detection out of FSManager. --- FSBSA.cpp | 50 +++++++++++++++++++++++++++++++++++++--------- FSBSA.h | 7 +++++++ FSEngine.h | 4 ++++ FSManager.cpp | 37 ++++++++++------------------------ FSManager.h | 7 ++++--- ResourceLoader.cpp | 15 ++++++++++++++ 6 files changed, 82 insertions(+), 38 deletions(-) diff --git a/FSBSA.cpp b/FSBSA.cpp index 9919ad37..8d2a9b70 100644 --- a/FSBSA.cpp +++ b/FSBSA.cpp @@ -32,7 +32,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FSBSA.h" #include "DDS.h" -#include "zlib\zlib.h" +#include "zlib/zlib.h" #include #include @@ -117,7 +117,6 @@ wxMemoryBuffer gUncompress(const wxMemoryBuffer &data, int skip = 0) { return wxMemoryBuffer(); } - result.SetBufSize(result.GetBufSize() + CHUNK_SIZE - strm.avail_out); result.AppendData(out, CHUNK_SIZE - strm.avail_out); } while (strm.avail_out == 0); @@ -430,6 +429,24 @@ wxInt64 BSA::fileSize(const std::string & fn) const { return 0; } +void BSA::addFilesOfFolders(const std::string &folderName, std::vector &tree) const { + if (const BSAFolder *folder = getFolder(folderName)) { + tree.push_back(folderName); + for (auto &child : folder->children) { + addFilesOfFolders(folderName + "/" + child.first, tree); + } + for (auto &file : folder->files) { + tree.push_back(folderName + "/" + file.first); + } + } +} + +void BSA::fileTree(std::vector &tree) const { + tree.push_back(name()); + for (auto &folder : root.children) + addFilesOfFolders(folder.first, tree); +} + bool BSA::fileContents(const std::string &fn, wxMemoryBuffer &content) { if (const BSAFile *file = getFile(fn)) { wxMutexLocker lock(bsaMutex); @@ -519,7 +536,6 @@ bool BSA::fileContents(const std::string &fn, wxMemoryBuffer &content) { // Append DDS Header std::string dds = "DDS "; - content.SetBufSize(sizeof(ddsHeader) + 4); content.AppendData(dds.data(), 4); content.AppendData(buf, sizeof(ddsHeader)); } @@ -531,15 +547,13 @@ bool BSA::fileContents(const std::string &fn, wxMemoryBuffer &content) { // BSA if (file->compressed() ^ compressToggle) { firstChunk = gUncompress(firstChunk, 4); - content.SetBufSize(content.GetBufSize() + firstChunk.GetBufSize()); - content.AppendData(firstChunk, firstChunk.GetBufSize()); + content.AppendData(firstChunk, firstChunk.GetDataLen()); } } else if (file->packedLength > 0) { // BA2 firstChunk = gUncompress(firstChunk); - content.SetBufSize(content.GetBufSize() + firstChunk.GetBufSize()); - content.AppendData(firstChunk, firstChunk.GetBufSize()); + content.AppendData(firstChunk, firstChunk.GetDataLen()); } if (file->tex.chunks.size()) { @@ -568,8 +582,7 @@ bool BSA::fileContents(const std::string &fn, wxMemoryBuffer &content) { } } - content.SetBufSize(content.GetBufSize() + chunkData.GetBufSize()); - content.AppendData(chunkData.GetData(), chunkData.GetBufSize()); + content.AppendData(chunkData.GetData(), chunkData.GetDataLen()); } else { // Seek error @@ -584,6 +597,25 @@ bool BSA::fileContents(const std::string &fn, wxMemoryBuffer &content) { return false; } +bool BSA::exportFile(const std::string &fn, const std::string &target) { + wxMemoryBuffer content; + if (!fileContents(fn, content)) + return false; + + if (content.IsEmpty()) + return false; + + wxFile file(target, wxFile::write); + if (file.Error()) + return false; + + if (file.Write(content.GetData(), content.GetDataLen()) != content.GetDataLen()) + return false; + + file.Close(); + return true; +} + std::string BSA::absoluteFilePath(const std::string &fn) const { if (hasFile(fn)) { wxFileName fileInfo(fn); diff --git a/FSBSA.h b/FSBSA.h index 3b2018a4..3a34d5cf 100644 --- a/FSBSA.h +++ b/FSBSA.h @@ -193,6 +193,10 @@ class BSA final : public FSArchiveFile { bool hasFile(const std::string&) const override final; //! Returns the size of the file per BSAFile::size(). wxInt64 fileSize(const std::string&) const override final; + //! Add all files of the folder to the map + void addFilesOfFolders(const std::string&, std::vector&) const override final; + //! Returns the entire file tree of the BSA + void fileTree(std::vector&) const override final; //! Returns the contents of the specified file /*! @@ -202,6 +206,9 @@ class BSA final : public FSArchiveFile { */ bool fileContents(const std::string&, wxMemoryBuffer&) override final; + //! Writes the contents to the specified file + bool exportFile(const std::string&, const std::string&) override final; + //! See QFileInfo::created(). wxDateTime fileTime(const std::string&) const override final; //! See QFileInfo::absoluteFilePath(). diff --git a/FSEngine.h b/FSEngine.h index 61f2c374..c617500a 100644 --- a/FSEngine.h +++ b/FSEngine.h @@ -36,6 +36,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include //! Provides a way to register an FSArchiveEngine with the application. @@ -76,7 +77,10 @@ class FSArchiveFile virtual bool hasFolder(const std::string&) const = 0; virtual bool hasFile(const std::string&) const = 0; virtual wxInt64 fileSize(const std::string&) const = 0; + virtual void addFilesOfFolders(const std::string&, std::vector&) const = 0; + virtual void fileTree(std::vector&) const = 0; virtual bool fileContents(const std::string&, wxMemoryBuffer&) = 0; + virtual bool exportFile(const std::string&, const std::string&) = 0; virtual std::string absoluteFilePath(const std::string&) const = 0; virtual wxDateTime fileTime(const std::string&) const = 0; diff --git a/FSManager.cpp b/FSManager.cpp index 8529e079..ee14fd00 100644 --- a/FSManager.cpp +++ b/FSManager.cpp @@ -34,7 +34,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FSManager.h" #include "FSEngine.h" #include "FSBSA.h" -#include "ConfigurationManager.h" #include @@ -48,6 +47,10 @@ FSManager* FSManager::get() { return theFSManager; } +bool FSManager::exists() { + return theFSManager != nullptr; +} + void FSManager::del() { if (theFSManager) { delete theFSManager; @@ -64,37 +67,19 @@ std::list FSManager::archiveList() { return archives; } -FSManager::FSManager() { - std::vector list; - list = autodetectArchives(); - - for (auto &an : list) { - if (FSArchiveHandler *a = FSArchiveHandler::openArchive(an)) - archives[an] = a; +void FSManager::addArchives(const std::vector& archiveList) { + for (auto &archive : archiveList) { + if (FSArchiveHandler *a = FSArchiveHandler::openArchive(archive)) + get()->archives[archive] = a; } } +FSManager::FSManager() { +} + FSManager::~FSManager() { for (auto &it : archives) delete it.second; archives.clear(); } - -std::vector FSManager::autodetectArchives() { - std::vector list; - if (Config["GameDataPath"].empty()) - return list; - - std::string path = Config["GameDataPath"]; - if (!path.empty()) { - wxArrayString files; - wxDir::GetAllFiles(path, &files, wxEmptyString, wxDIR_FILES); - - for (auto &file : files) - if (file.EndsWith(".bsa") || file.EndsWith(".ba2")) - list.push_back(file.ToStdString()); - } - - return list; -} diff --git a/FSManager.h b/FSManager.h index d04f1390..20887687 100644 --- a/FSManager.h +++ b/FSManager.h @@ -46,10 +46,14 @@ class FSManager { public: //! Gets the global file system manager static FSManager *get(); + //! Returns if the file manager exists already + static bool exists(); //! Deletes the global file system manager static void del(); //! Gets the list of globally registered BSA files static std::list archiveList(); + //! Adds archives to the global list + static void addArchives(const std::vector&); protected: //! Constructor @@ -58,7 +62,4 @@ class FSManager { ~FSManager(); std::map archives; - - //! Builds a list of global BSAs on Windows platforms - static std::vector autodetectArchives(); }; diff --git a/ResourceLoader.cpp b/ResourceLoader.cpp index b687ac5c..460a2cf4 100644 --- a/ResourceLoader.cpp +++ b/ResourceLoader.cpp @@ -17,6 +17,8 @@ See the included LICENSE file #pragma comment (lib, "SOIL.lib") #endif +#include + using std::string; size_t ResourceLoader::MatKeyHash::operator()(const MaterialKey& key) const { @@ -50,6 +52,19 @@ GLMaterial* ResourceLoader::AddMaterial(const string& textureFile, const string& return nullptr; } + // Auto-detect archives + if (!FSManager::exists()) { + wxArrayString files; + wxDir::GetAllFiles(Config["GameDataPath"], &files, wxEmptyString, wxDIR_FILES); + + vector archives; + for (auto &file : files) + if (file.EndsWith(".bsa") || file.EndsWith(".ba2")) + archives.push_back(file.ToStdString()); + + FSManager::addArchives(archives); + } + wxMemoryBuffer data; wxString texFile = textureFile; texFile.Replace(Config["GameDataPath"], ""); From fd1cedb1c09d8c2bf12650c37b087992c617ba2d Mon Sep 17 00:00:00 2001 From: ousnius Date: Sun, 15 Nov 2015 00:26:53 +0100 Subject: [PATCH 09/64] Added skeleton and root selection --- BodySlideApp.cpp | 8 +++++--- Config.xml | 4 +--- res/BodyslideFrame.xrc | 1 + res/skeleton_fo4.nif | Bin 0 -> 46367 bytes 4 files changed, 7 insertions(+), 6 deletions(-) create mode 100644 res/skeleton_fo4.nif diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index 74b8dd5e..14c67b0c 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -786,13 +786,13 @@ void BodySlideApp::SetDefaultConfig() { break; case FO4: Config.SetDefaultValue("Anim/DefaultSkeletonReference", "res\\skeleton_fo4.nif"); - Config.SetDefaultValue("Anim/SkeletonRootName", "NPC"); + Config.SetDefaultValue("Anim/SkeletonRootName", "Root"); gameKey = "SOFTWARE\\Bethesda Softworks\\Fallout4"; gameValueKey = "Installed Path"; break; default: Config.SetDefaultValue("Anim/DefaultSkeletonReference", "res\\skeleton_female.nif"); - Config.SetDefaultValue("Anim/SkeletonRootName", "NPC"); + Config.SetDefaultValue("Anim/SkeletonRootName", "Root"); } Config.SetDefaultValue("ReferenceTemplates", ""); @@ -2321,9 +2321,11 @@ void BodySlideFrame::OnChooseTargetGame(wxCommandEvent& event) { choiceSkeletonRoot->SetStringSelection("Bip01"); break; case SKYRIM: + choiceSkeletonRoot->SetStringSelection("NPC"); + break; case FO4: default: - choiceSkeletonRoot->SetStringSelection("NPC"); + choiceSkeletonRoot->SetStringSelection("Root"); break; } } diff --git a/Config.xml b/Config.xml index 32d5418f..c826d9a4 100644 --- a/Config.xml +++ b/Config.xml @@ -42,9 +42,7 @@ res\skeleton_fo4.nif - NPC - - + Root diff --git a/res/BodyslideFrame.xrc b/res/BodyslideFrame.xrc index 296c3484..fdd84bf4 100644 --- a/res/BodyslideFrame.xrc +++ b/res/BodyslideFrame.xrc @@ -933,6 +933,7 @@ The root node name of the reference skeleton. Can differ from game to game. 0 + Root NPC Bip01 diff --git a/res/skeleton_fo4.nif b/res/skeleton_fo4.nif new file mode 100644 index 0000000000000000000000000000000000000000..353044f2d3484379e53161aa3e80257328fb193f GIT binary patch literal 46367 zcmeHw30#y__y5BxC@Q#RuH=fO$iB_Y^9%^4rbf6{D4?RC2nd)vjQg&nW^O5JnWDL{ z%WPy;YPg$eE|I0FDN>r6n)5&3JM#>~4Cq_EZ@>5b{5yUQ=bm%VJ@-EMoVz^tKHw{{ zJX`&T)3^K|!mKWf*?cCKq+8=ZhS2k^a}94(Gr* z)~af1Q?Fzy`PXZywSrnRs<%tzL~6&?_04UFd%ULfi;zZ z%)FiEddN4|5pDjbo<(efSdYm6JE_=Tq7Ovd;KjUb8ZMBFd<><*Bj(P~z@AGKQ-~9x zIH!3eC5*Nqo~ANJLK*215rUx?Iv_Ne%~s?ju5WZ?!iZjRi79cZ$m`oTZcOyR*1$;#Y3W{685fzHoDP#cUh9WhGa@eW?S!v32NoeaErF^`R9yF+E+(hoG;i0M0NJ zh>VL(Wu?&j10s6&5BD;ryfH!cpv5npbs)Tl3%tz* zKFpc0(JMA-R8?+5(wMkZFO%|mfk}D2z{jkJw|Nn7^CI5nMSRSQ_?Q>*F)!k4Uc}eD zh_87OKl37f=0*H`5Mo2(VpEcn`o@h;$KVS|N*J$S<@@jhm}H%dn&q>MS|Ee+cvh2siT<~xlKgtRUyXY zMl%EAlP4yQic1ykWA^ADH*y?kukesC1XHiL*ioz$n4YmC0!B zQWeIg(yACVl~#o@lbWnL2yHVN3vF{5ixy)OEJE8%y(+Y;GE768Nvnd48AoU{xp`<~ zLXWIkND;DZ8fK-?OMOFA<6_hFYZLfL6CNS0*JgA302*6(WW9(z1~Y@0WrIRoTu|wN zl!T->eTTvf(+-VGOq{}sz>Gn|xNI0p={o>Tt)YNdw6Orfp$EOKrN&}?)Tdkx?r>gUH`U(VNNFWBK?CKUe7`&j;DPFWi!AWL0fEkcj4&mh4$8j zIs!DIIw*wa^9liFVG9f7RzleRoDi}qP=s>a-Vlz9AykB-UOYUysA@BUXN>4Zk&>L+ zH!*I^LTx9ZV9<9ms|~z%MdX4d_R?R0?|wTRI09UQ)>5+)~|Q#V_ir%8FWp>)KM2lB9=IdO4V4e1ck<+R zPkn`rhkL5p>Z!DKpOBE1pT1t|`ZO~@Y&3emoGie|K?)mqVi!FHUdr(n27p%)5jtJw zPV&)ajw2JgOcoI_XX#E==1dv0h_>8glh=b60Rd$Pl!kb zh;_6~3J8dLscYcsQwu3dN_}m(z6DgTw&d6^zNo`W&kMQ7e#u8ZWN0fQ47NHEqArE8 z^;`_iv*qPOoJ&jLXgY?VC!_NXJh^FHzDj)jxM*)rFJBKY56^C?UYw3ZY|kGZJu)#i zEiH-0XIgYLq?AX&T}g?W5Km(Y(b4HsQjA6QFDTDbn;-RSzkzp@})yK z&Y51=X*!Tn{`1_u@x)_KHluxbY)sIymm=zep5?CrupBB`!)n zW-91S=O^4w*X0*Un3Q5TR>5fqz1Vyd!-PFzQ_?0T#tn#%O^M_DU1t=LRMez-ER9ZV z=sbs&;m*jKAU7g8Eg_xGY^t*RCDWk`7aVi*b>#O=7@v?HH>wx*2UR-E#D!y@JSCOb z0pjUWwMVY4U$JZvD#ZLh%DYfO!dlCVc13D#UzBsY7D5Z5A8%#dS5~3R%tRFH(Wt=^ z+4Aaqt=vEM{^>soj(_5%mJ#yL`1ogh{7d7*Fb|iW2<5V#gmBzZp5s~w)0%kjr`kQ{ z>wVo`0>oUc8?%0`ZQ4Zpv}z&uPkFYE{nLN{#LqwD=MT&uR$TD1k+Kub!ow7X5PdlvnHQ)QTel*uV8*sgA z%PIH;PfL2#RG+Fz&(QUo9?F5J?{MrBb^i|+3Sr9byme{Q0_+-&I2uYB*zZq7KX4BHth ze9>aAI{oGm*$Ou|Va~{l>aBEI@$B00w*Kt?JZI?7&W8RB7u@*AyZWg+Rc_>mMl4WU z9~>nMk#rHV-)f`TJXZ4D`s}H`UDTh-TKaQ7_2*gY%Wn+*8Rs^LR~-0SvTD#=na9xf z(obR?1#kDC_;=ns%>R_r?78*Tq53-ZUcsMTGqT3`T=d%d5a0*jY-j#!<@&wv+{y9bZ`$S>>nopH7y?|n^(Lz?ebeW@Gqy;i zyUxEaNamO4{<>z3^wK?F?YZ~XsE9tdK1ZtW{KD4!vi3u2tZ#e3r*h!AAFWt@iRov2 z4=hblbuHL0Y-_em`r476(pFD>wYLuSRN<88dGS)0>Z2nn{&Gg+@S4VZ{ix8;74_PL ztRlpCuuEH^8TqP2{hl^o=sf8QY12j1l^qu)3A^mnvdoga=Z=SZRNt0ggL6vhlA>w+_(mgz_V+^gI!*RGw>~GT?~zW& z%a$yvvA*HMCiVEe>()@KZd*f9-$#v{wYPV+=cDed5KcDM>m9)5u!fZ)>HH6%5`tH$h{mTsYH`99ll-Bd*w4N`1#(EC>IBnI@`S7#a@6`Rc?^n$| zit~S+!`i=$=Hq2FA77>Um?)Fg^xUvd^Ay>)NbD+g9FTlZ=GxJ>KEd0Ib+KGQx<>UFdOaG-mg+U#FQ zY|6j4cChMVZ+-hOybvv0kl96e;Nq%DYE}DskN&~AxQ=dv9OzD^Hv3_T!J3x-yVWn8 z+$SS-?qI-VepRr$koe^(zV(Af&ul+V>2-8g?_gWI{mRG^-#6wyk+}T4joFHz^{zFo zceiQ1YyXV(4(-S3zmDzz9O$&aw)Xe(2;?{ZzDqssQ+@j#zB$D&tY{?M?=hKwL;7t0 z;yO*oHRK%VBB3_>%E%yoMfWK6u%uGf{;z00JVf(h1DX%7J!3vZ`*D?}quVeCa&&F> z!=r*UNn}6PV80oy&z)#}{+QNh#WU7t*vA!>j;qh^M{2X*az4ZZ!Pw4X?#{X_@aPdGedKLPvfri;G%qC28m z?SJ)c)54_*{Z)m!i>&>*w7#a&`ud30*D23fUtu422s*k&a3Dw2)_$Au^@J;B-^u2$ zSj+71|0+m0<$a%*_t>pI_UJ*a`ytrJEufCRQgfh*x;FcXiS&CRr2C*QAfJ1zYBTn1U^Hz+3`b=72E-Tjqe+fvx`qfPdjj z_zgaSKhXE^8Tt;sKwqI>&&3$EmHl%hst$oAZ+?D8N~1&&`6dg`tH6JJr$q8-VhiQYWDi4u@~Iz~zL-yaV&sue{X=73p%othbseyS`*wCR)9Xnfldb6~%va4fbZEwsL)r=JW@@lk8_GkTde&{K__kFwE)?e8-FL#KF=hrf{DW6JPg$^fd;x-C&N9zsp}iTVD9nAIHYm?pALb^WiU%M?U-o{gXju!6*-Zi9GV*FX)T;@R!IV zAO50cl8q&F=*OfBD#|ucy9_)VQ>TK;N+{1bzDhl2s*$e;g+Mlq;|o4DJd>#KKQq3z z&kFZy+ia{i;&>m8uN)J;jAHOTitF5|`tj9_#*fHjd?Eig8ehnVzmPBT@RwNr@?`z^ z63c^!zr^z3;V-c~c=)U7gbFFZ$lcgHB4V2G$R>! zvaNxii0=d*b%ToVca5)%QOp1IeCSwqiN8H?La}>?ok8$d`h}Cy8?W3C$_OcDca!qR zUrJ-0C-2V~u^DTJFuL<)zC&@ZlI*0i{qWa`m&#cFrIO4nxTEA}@`r=f(tukrgZC33OuRsR(eSk!OGuxMA=1}+{e46eXdx=(_Equw)n4-*>&Dp zvgDi{<`z?427jftUT(~Xzf5=;{Dtyf9k&LfJp5(C%iu5Qi}~=E2`@9B4=0c=`W9;t zs6DmIz_U5fyW`es^WkRyRcJEdAC+1)TU3I4_-lCh zW&ULG*kI(tUom+{rQTHj(52Hs@K+&~zt_;A?7=O;Mlhifis`A+Gxy)Z-x4ZK`-8af!ZqhFp{u;WXm6TJIvV8cnltmg;O;-R4yL;pVQmUFCkw0-T}pa(&tH^`D^n# z-YR!0`vb{-|2n56GE1%@UQ4`&_+WXi3Uj;>{;u)W`|a+3dVjd~bTj^Fvt_ECxBAdr zqYy-X>8(CAmnekS*EZ*~!ZxUqY$7qY82KeOk!(Kvu6|QvKKv!}$cMjBzUiq7sMR{ls!=mw{*VVdGPoQp|gh0V38mr~QQp3W01I=SO-r zt>KwOg}-e+{43*2{YG~_f`S99R4{1{BLFKz4T^P@$yGysPE>~LLjzla9 zn}a?1v2SdY)!QA-=EJO0uG09`N|q0QEz0iBC+)~)`S6$X6nAO-JLSs4r%!|7uV1LV zhRTnUJ4x7n<7-!`+dE2@4}V>t@&~9q^5HMfv9~nc8tcc`ru5d*7i5!5rUY4)+$X=p zC?b`_2NNGmymnm2r@^GplRg_?juGCf4pg=?$?8-r4({-sTtmE;cn$F-T-oRUC*y0w zmbd@(d>Hg(1|NNEelG3j_hCG(TKHJnr{j1dZ@cWi^yq}PCEHTkviWe=`V9V#fyaD^ z{JY6*gOLw^A^)U-hrh(~t*8wAC6)&de~IP6!(U=~@bFi~&bHp-nE5TaZHaL(P+O@^ z@Cv<5p+ynX^kd1_rBnUj zujGkesxnT@kuHC~1>;pgCsc1um?=%_Vavvs?Gabm^6Bd&XWz1A{#teBnCgpF3t2w= zwPyNDGFe?E%ZI;;4dpZL+c1CGQ~9M-zS(6PHomf`{O432`S8~|Dleh($cMkwHr@Ec zuj}uQCr9*FB@ZYnOiP&NhcTz=XInzNKk@80Ydmk+l#srL^qIfDDGQVyp|Tp1*>ENP z5B*!JiPsX(6JHq6;(NCKi9Y+g{IxQ0;Gg!_T(>Fwpn&0dr~9q&g1=shzbD=FcD#{a z)uvMVlAmMAAumVfufly(_y@jv9`hmcFLiSaMn3$7{5l?b9{v)``+GSue~IP6V?Gqi zgNMJw^5EgGr#b=i8yjEex;Yx>L&y%3j-js=m;(cdCw6SRemF9)|ivWLWb2XA5XVI}1|-&@7<;V{#hFp z#@Eo?LW$oHJC+ZB**vi2BRbi!eE6$xy>MO{FpbTJ%0*WsvO|Mp2X=Q>$+l(+i}OAS zCSFavlz44Qu$z+fHKfnR*MinIDxZr}g{z;2X=Z-&hT1LAQA50zc%FFKi7`L@pX}$G z{sn(EE^H#Lyzrvx+Mt)I?F!*>Y8^gljib76SaXU!+6y;w;5|>&QD39%>y2Gy5- z@M=TVlg9nn``5J#b@=0+PAnh(+J4AU+U}Su%ZI;Cz2v}Oxll*_#hHdu_-knA2GYc- z4OMN9+OhYqLpSU2Go?-}AO1R2SXX-Ui7U&8zh;aK*Ie_~_y4(I8`a|3gVZITcb2A+ zzwS-$q9k5Myoz{jmgm7>(&tH^`S*>_u1K1no2qTsDx42l^M-oC9yclR0`VH+Wj~B@ zGI^i=d-jLoSQaVuSvBZ7C{vi;bgXpE`7CwaFEWLBSKm?Zjd7K==$xrNdq<)ILVnY= z1D$VJ!py{p+NrNa@lBWW{Nfu)LixO3W#fCV)VRpg1gj=ip)?P0E9%bE5b{UM z`Z8Z44}kAEIWCa!(18_o?S-21tw`lSvA5>#=x;5`(;UHh65{!YSOBau=#YMx>Il`_ z$Ma>&Db4y!RH=!Y`x9fxQtw}taonXQ8A4p>BiXGFGyE=obhLodYRDoMX#G4Y`V{~n z7wd`oVVG=Y(L=+2hU5NQ{0V;$TKL1%pS9)d{h3SUb1lk0&!6UfZ|Ug8ER-=Fas(+}b@s}8U zu%8kUyxs$#`n)Pxm2Z&BE~WdwEn|Ww(7oTgbut78>kMJ<+TYcs*9S@i*ZnR7Le3Qm z*gtZoTl~ns{)Tl)f45I*zhXIl8bSCk0OmFQT%w=X@SS}<&9B-gAM5Yw%)ib0qx~c{ z!91R+AO6yObG*rP;qWwX&8}f}d}eR`-IvllWF1#O%|DVi%m)a$SkM0ar?S)i8u_-T zxJH})TjKez&NmU025Sia?eh(F(O-&ZZi%~ut5_4PqVdr4!VJNca6z!GhLg8dW(V2w zK*+iLPqDw|gtkBObNfFGcKdoEb^KS} z%M?y2R!dvP*%#d1Ha?%yD#)x>O!AGJRmTqqxj6n`$Z?_m>YhjAKd+|#Y7AjD_-pf1 zHB-b??H?6#mU+}UXt+t0s~bA$K0)h>s~*;>-*8_Ly~|JeltMuAJSa9_sFhb-^ZES@`5nwrrQAm5OPN+ zZ|0vY^3SImqSd{lg4ny*|B`=xyS&_@|1lql{+WK>)gu3|`savEyf7yAoQ7Mpb>C;< zOZ+L#L)QBIy28M&HvT}!#rfRaKYbo%3U^+grYh`vF<_V^z@O4m$leNQRXF;$3q?T4 z#qtxDZ00l4qtp%~UZrx4-GWR# z|73s`2>A(_4_gmBCeFtGCZFCzX&-9opTDvm(B4K%?>K1de{z4r`hm{Lg&Wi_z)IF% zbf!an1%#}&{^Dk(DHX@Ul>(Ljeq}#lAfa?wbAc<`AW<%Bt_4EQop_7B@1pau3A6dP zPM75&4KSZ?{@eR&qkX2ZFC!OwTb~V-=C~N@zfxb^N03|wWb#raiwE|QCO^LXVXSa! z<(C@H^-9qfl;+A$6>(hWfZwS+$$21?b8&3EE4Nk3=-Ut<&bJ=xGxPpxY+_rV{7>x% z&DYPG&yW7q{UDt+YKvm){M+Ye>I3TcKYzaQN_JP7v@}!eyltTL;;Qvhr+PDlXxsL( z5>-=;y>n9@2>HVxdM6|pYCoU$gV}y`Mp)zg{8!=`eS|Z*|K#}3PRf-bnS^7!(_$VJ&O-5`8KcaAQ~Zv7RN0i`+I%;FU9cOumC#O zY8?$=>4)hF|*{_b-AoVO1$6~HAVg9kEeL^{#--)y-0rqz3-&FyHj#+m|W&CFT`Vo|Knmy{cPF~ zz@MDr!@P^jy|tXepWYRs0!IGUUeiB!x`lm@I`d(l+T&dK#{3fPLq{KBP5yjYXk2sk z?Mgoj{iZZO)0feR;R3$baLr>!AFV2XzIr<8->N|$zyF&>=t}5G7tXi~+)KYKEGL>p zlVt?ah!<&>M6|Mnej-)0q~G<5q!taJ{}+d-oM+YK^q;U zJ=>CfL%Q6RY&6l!v)a-B;bTb4J5YH;y0RmcX{y)B?o9R#>4+|5-;m~BCi~6wI(xg4 zeM36NgY46PIfZ(i>A_MA=~DVK?Svtn;zRbE>vdfH$i5+cg1k~`NGs@i6@9?kPZ1Pv zNOSliz>v-+udXqqE)CC_s6!pnR9PyCD z7Y>Fr`rO%&hQFE{((sF`A&vfbGo;~PPeU4h3^b(SFS#KNzw|Ps(f<*KH2Qg{Aq{`U z7}D@dyde$$rWn%j<77h`{+di}NBb2Ni=GmF`UKHHleF9H{bpqNH1i)qhbefn)8h)2LG{Jn0`PYx07y5`Cry50pT@xpz#UWz@!9Y$rL#Bbd3;~1)6r7I z{$@opqHuG2Lbw>Ntw#ueo}rF_r{8`Tw0-w!xpm15t>Oc({e9dWG^MTDs86^|6prj! z!3X!V=3CgT;#*uz)uJBQuqAXNq~(ZfLP*OAt5d=LYK9eY$OVWs-9Lc8RGb??Ws7G& znju{Fc`WOmdRFD{`&iw;B|~`2`b6;2ac8BOGtLH2yn!8~Lcm|!upvZCT?iWy!mhp+ zv;i6bu@=Y0I;v$&5pY$r>-?m=5!wdMC)AmdBZVbj(A`{QL-jA0Hp*s&uTig}dpy+A zkjkUQ&V;B*Z@mts(31esy6ipo5Z6_2OSs~Yk^^H02)o{N))rR|QI@~yEYu%2K;ZUX z^UrDGEy?bAujE6v>(zS%Hbjq#wxsdjsvf;^PF?a=4$X%O!IN9(XQMdge?qsm0DLp9 zqM(lASm8O{Z5k)=c9ku(7$DlpNK6eWYrR_=an_xAs5|$*pDlOH|Fmv{!PXB24&1TA zv%2psY~iT^qOGSdbW*qd=(u`gu)bXTW0Gfv!(QJQG+e`8X(%5zwT&AdG>L&JnE0z zLX-kTTa*mYQPgkUeY*5SP=>ZmdXD7U#7f!yleblg^(G3~y)pCylQ1 z=R1wm4t)B9tT)}}1=0;(o3HE3B0t@xzT&@&{^o@~>RXaBqP`U&YSLSGq!gYAAX?w~ zt~*(`rM-V}Kd^-P(bmTl z^>^y;))t?{-$JABO?At?an^lRw>(#0w$j&{E2R~u(!v({7$DkuvZtf^;s?jo8o9n* zG|S|1oP+N}osMjx9S^B}4rJ${g)Q_RK(rP5fTDiOadph(m)Xd^t;@`%IWzZ$F4JJ^ zTt1ByN}nT})t?bw0f@G&)*lTiC0p`If7}*43lMGTIq@gzC8rw!{NA>D+1^d&?J{gB zjJ8Tg)RAA^-$>Tsx3bdE!0Fm|pU#xJukhgW<6lyLxhqw8>x<2r(Hq@0gU)Qxq*Nqn zVGr#c|H-3zd0wFOxT!H%;sM-S3iyGkA^f$=>RZzE2aDE?djXE(GxJ zWUc3K%}cIktF7LY(H7XaW!9xccA?I!*V?>8=`NN1+fbL|8EalMNr!XA4+61W+}>1q zly`{IHP)u6Rig|c@YhG`i$$RYL}lPtSzq$&(5#+cWX~UsGa{=m(z^N4D|zx?6Fg0&BN=cjGBz~)Un3AO>K z$(?W+;c~((Le#9U$&ONnZJx2FJAK=RbWgC`Of?pM$?K^t! z&-tq_tT)CvwtHCfyAlo|j3%5%IG=C<;X=Yigo_E65H2M|tMsjKpcHl>0P%T`2dxeH zCC6IZ^WixmrvGt`e9%GV*hXWuuldc_wCOcbxW46ztW}E`;f;4z@MXzgu$cm7F~fEv z97H&numd4Lv|ILWFY3n_f5`4E94iDR&D8uL+ob8SdnWIcI!VyneMw#FxQXxC$3v}r zA&sJeertzxVYfTsYlH&{QHQ?ucy7a%*jP(*?Q*JR1I_8>{wJ=#DV$N;Xurx=sO9%< z1m&=|gdcKc%J)7VAyc&YRpmkFRH((1?7;J0g#8Ioo4$qyltOd>#OJtn{-B&wloWB< zl46vuTN;w- zEmsIh8yb6We>BTG#kWx|Y&et6)aco{M620E-_R7w^&;#`i1-4CcE4bD9Rn#2iW|_4 zfgjxxNVB`Dv&VOll_oe!*MF8NTAMpL)*I!)Qc zmHhj~@!F2gAwto?&O+&yu4=KTtjGq!1aS%wpJry-C^@G%Og%Ke_!bu+oY?IpoDbct zZn4N)J7s);5b2k!I_4iCn|^(n?Dcw8Jr8?SNPIOi+Dj^YQO?QBY3=+V!20)LLYpss z=e?Wvl4+Ve)!da27dY4N3Z=?!YTG5Bt3KIRWe;t_cms%STUWPIp8EPl{+rKSLZgae^`3%yTK9>Agy5bzvYYK5$~ec(s$^&VDvz>gTM!|l8X($R+$BWLmAeOW zit?h}E2KhYyKchgQHu(RYQguJ-LufjeX-w1d$&-7og zruf}H7Args_?iE4!684Q8t`G8^8F_$w)(B8EG#s&2OAg<0MXWihIi$;kJ|{nd~WjZ z-U=6<&VET4vTlxSOPzLFuj8S@-Ulvx*78oWh?6ZeC%?w;km^SO+J;v{j5mO2ugj%y zIp^sY$jRFm_xJJ=+8zuP*59+2-1sz5JCpc#M>{EJYeJRW^ihR{CL;>=@Op`H3lQzK ztK&p*@*=t1p-{GbfbdF3XJK{TE6N!iowaWh@7r?j{xvx*C7Gk11m~LAgAI&OfM{#W zxe9sn0eO6+d$HE~ZC>cRv!k#r)}7C3@UpfrE>OtL=XuVH-h`Eznz--TeYAkGXd68^ z8zH9lhR=1EbI$hUS6z|+h}MGp_1?moj8K1~TJSMGy9-mheO8$Da++~95$(yz5Jo2e zGR#gr-R}xqX$C!OynkS)!9qs3lQ4Pz?E<1&@Q*VB{M_38=6AqBzlRfj0UH?M0MXWm zBhSbKe=gL#=@C*I)WBO<{;j8Q;zn;i?n;36?Kxe9sQ2FFpR8FVby~PeQ+hYOnqNc7 z4#q4%w3jS2lyh_J$ggLM28YUoGb6eRd%2)sqT08JU%qA6{!v#$OY9q@?SE|I2lQPJ zLX25}Xz#k@E2=XA@$S2`u!GRzw;sZVj#eeDe(Ry#MLf4|a>3A(9|omB3(DXT-Jvxmnm+0s2ZeY2p$h^N;`c|b`l=4 znGt1S1LGAS+R}64PlfOr=bD$qDe_+DTxo(-2<7y!@RE{s*czrz-0YQVq4 zmf;A8>rM6$XNtvHa;F^~G~A>WvNP71+V4NyCtL3oqbf+=qrRS*p?&N;U#;!8QFXq< z9Cg=m)%zap!Rmx3*TcHCYjMcO^&zC24a%<_UnL#v)({ndqGO)w-ec;hB97UqbKcJs z7A|m*S;`j3@<~rZdi@Q0N6X5XUNp&iRh8xUlU}TejQy`4BpYWU!*2wc*KwyJiIrVX zdV`Jj7BIcHNH)|Uqi1C@(|Ylj>QV0&(hD=_sgz3oGm^QGte-(fZRS5A*()RypZD^m zOEt8mf>)AW9}|1jRRY><+7{|70eY{Kp4es=7Z<_2-gRqVWMxg;+^$_ai?Y;LLNVEk zFlnEUkB@-9Ur4f01ga${c|vWP2+XV#}fO!Qn_PFmDEc+giCvUO|E zTlj;=8#DTvP(tlPtjP@R+nICILhnvRglsK}{`WlPA4kQI_Tn3q6&xrA57$FSWMNqj!8J ztKL`btJDT%;-)QvV{xWEMzoaS;&r-b+wS)sqnCnxwv>)$Y`#! zkPRN>XCa$BDZoOuZf%f-Or?}q$Sz-!S;#1?EM)E4g<8mHjI$VpotcGw3b=O z)~%glQC6j#W}$ca(hLh3t%DXa7nhk9vUcreS;%~RW?RT;4YiOB9yHfNHfHoZ3)$pJ z^DShw{#wY^tzBp#+nKY-LZ(tKwvf@K!b0Zb zv(iEq9=6ItMtcSe*_hF*Eo74?y=Ng?xL}Qi4Et`ZGp1_*tx=pUAtF1O}~22Q0TB!!@Qq|H5G#rYh3q@@>ad_8Vk zK!18Ik7%{GUD&{x6F{`}fhtN9G0K|HoTj%$<#GIkH!8zh71Hd5o8;Bsvcwk;(N-f( zl%~-#E56SaL%W`6y(@LP{IDn5T$HWLRr(U|OVoJMin3@=9sD2=ZB2;})pFdYbc!^q z2xT{pYg52q+wPs^+s1Fe)l8vt{tc;PNvk}fD)7)jS@d@V;Q&H8AwabGS;|#8-FecR zu9VsI%?bAIdN;(U-Ky@ngMP~t+)5HuOV)(u5tV{BwfQ>Pi6jgm1c){(mS<|X%qyz< z?@eL8s7L)~&3XFPXZ@%U?&>yy&;M1o$)f*4^`?xr)Mq}TFT7qY=F;2J%dkRlAY1jg zHNJOrnXIfmSME!EK2eMQ!<#)oY*&*$J9z#~FHJ`1DE1sqimN+ZIYq96;u|_fR|xjp z-hAS{iPGUmb-&^~5+K^TyE{{p;(SH*FjN1G4|S>?wsb2b*J(SU>_eT9Pdwcm;h3|! zEu3otL|adF-RaPvZ@?4X;-J3N$Md<7DxqtefVL5ppu@{WL>;mM3e{LVcq)$>En+FICSm6 zVh7JTl*;3*_zl8ggu@Ak5bDovohXI3ae!FMz121pK&8}6*@X?iO%?JlZ06UkJ{dq% z1O8f!Yta_Z@*>+d?;A(%n^YcA{T5*qA!^gt(2!C%NdSm7{HEI(v{6??ZFHgoL7b9A z)7azalq8zX4NrBty~O9ydp{lURreLn4FIC8ac72WhkUt`;)iZR>4OeBPtfkB+d-lv zjF#?YzWVK)RzCE&ru@avloIE$f~|DE#^#lY!t^~?)L%7=(e7QdLK8Tp z`n^mH*_lH)m#{w}K(sqx3GQVoX|9PWa#=D~n74kWCdFwJzw7c${>r#XLe$QeWZ7SB z)V#ULLuTWuzn6)n@`$Gqgc*dh31bNL-mXij*9ZY(E$@AbdztezqQ(|i{`#iy(`Fm( z3i_R<^A~J{4ddSu!jh$uCvU{5y#pUg>(TExp*KcSdBoEw!Wo39OjQMGbL;(+M$m0z{kM zKfq>lict--*>|Fww|k5B-qQzmVfQjpx{n#_-7c4?h0W1qXBuH7AwabG9kUrk?fj*v zA>GL|raKuA`t6S8hC7)JpJi%QeVS_4^q}A5*sH&j8AIhA3F8UJ5hf8%AWSEmL^zpn z3gJ{j)T{3$XG&pp0f@Et-f~3v;r-3pE55h2`E)0fL3c7Pk~6#u-N~GxJDGLG@q(Lk zh&K0NXKlIJolFAR8OW?v*}IZHO3r=oau65OEwG7IfUu43WPSYa2a^ALA3Dc|}B zDZ9z)E%{t(ekU{7%+{3#mGV=AFY=cUx|F)molHF4$uzAfmhGlHnV0EK#=mEd`bN8l z>iZ6xrRH}siDYYtnZ0*CLgd`=tYS_fHQvb-ezU+|ypyrHBJq!U@!f(xpKPXCsA@FR z491No9BO87{kdC0X}5TatSG+fLlF<3@Kf8y>i5VwQJOhn;M}pEA3X zNhV8}y8)uT-QR`F<-e?@XYCU(knUh!q&u0<@7gQBr#qQ>#QVfKNh(#L67Ec#zxka^ z3faLL01)kMa&(d_f@T+UrMZPK(;dtRx|69_@QP#&-N}q1erl(=K|klTRA$FNDKWp3 z!CC?kZOyw_A>SC6$M@=3EZ|P2kN!?Zv)ynfvn!w1a4&n7JSoZK&F^GV$qrUPfM`#$ z&|S{8SxL`&J|K|pV7kzqOsk({g+#UBS48ab@44-uztiH`1*U$0U(*P&ngT?7O}gC` zoUbk_=H!El#5>xcQO;nQjFf5v2C40=}zX}WQw`6 z0P#*{qHR!#cqdcmqg_FJZiEJ}c1a5|zms{JY+>dHi0$hod?hFnKQH1+Un;_#%!_m< zWAA1a+)})g8Jp^N^6ZEEBb+|pZ+<6(`5YkH(j5C*zRV`N^w2C{K9}xfMwGHU88y3; zsqj!ar)6k2KDeoJ`#w|4jjetsgS7%6+R}64PmG=Hz1;7aJBWI+KDXj>6*h`4bgkfR z?gOkhfPaTAtSo?khb_$P0MXXPK~b6)gKhXXn@rW<8E)y0`+EK^_z-1r)wtbbcjEIN zq*(7Xe@3h*0MVA;sVI$Oe``K1NpH)6o0_kn-4{_`lzn2&c@ytrYlGjJsXiBBRRV~% z0zQe-xGuEfS6$KDs?=%o?mW%RBg)f9PcwapG9LC&7B;ZP07P5%=R&kxY283B zJCb4+ZyIBA?aH*d8Moi^cB8kcb164fFWP_VO;ieAw1rhYlW-Ox))|0ka~gZQY7j`@ zs1PcI$Udj?UGCKLogQ}5w-4>~KX`kr)T`1ZpQsAFsZ9mhnMsIM7$Dlbk({Y{bnc3( zMLzr6xk7iYJg*5S_wnM&*)uwDS@}-%yF)}-e~LC?18WUHwAJq`db>K2Qp|0?!=5?C zfy;H|S`=hC>SMJzy`2*8N7Q2ez&ZmEZQX0NgP;0(xaPyvqqL~=w5=ld@srHlqqYhb z_s*PKf!*(!-b9W2c$9?=>@onNt+<~uH1>-xsZynSzq-;+m{UCHLevlw^aieYNMj6d z;niaVYYafN)sU+Uth72*XwA*pkGHD_^+u|=zVVWvq58M0qNm%HNvlUHzgwLnDKdMz z!ukRbZKV%=D9?K5qD=naw5rbjDT1|&v&Ju?n`X6DeO^LuR~Lm!)sM%!^A75dCD*;G zzg^ksO&M*CzGfG)tz9Q=&ZBI({LC3u|AQ^mE=u~Fp_j{~&O~2JYAuWXDpQ;B)fuV$ zQke?RiFUvYc4PptU1P}BRI*j)adxS^=jYOs$xl?fj?zx_$v0BXkxap^?E`5H+1h;e zj8t*4OloQ?Rd32@tGslvE}0-cBPrw+8vM*a#G$?du(K)JlpLX*;L6+erjQ|c0}SkngiPtgki&0^A&f}gbV#s z_^dNwylK1A&1@Btt%pKSZFyW`sWaJHM7E|BCJST9mYQs(4qL6ceJ4%(uz!js%FGtl zCxF;r+N}3fF7pbt&ZP-OPbntCE)J7=y;$r;R0aO#r(^dW-noCD{ed`(H$tpU0MXXd zYhTFE96CuczrkzF-RZ*0m96=1Pu}$=ssUf{(u5J0HfoOC`?iQE4_;clslc8)7x1g@PN8|+Pu80<+M>70Ku1pD=a6#M zAG%gFcC5JURz%r&q+5_2@I>9sZDEHG5ZhH=v`p^V(T;aYXB?R9n#Pi@0zUe(7o z-f{qodAl-Th~Qm9d=EjV0Y#?ymz;XADg=5N%C6@q;5hFspRer3HxX`YX0(=}mDPh{A)_p~@F}xk9kxS9bh^~btco2I;qyctZsU5thrwbUxmn#N24~j2TK=D-yD859| z=PzKCqKQ#_Wdb?AEYa(iF^Vrp^yMlTrE2MES-p(nixBYm3Ir5iet_a@4^VvJ0ZO-( zjN(fU@c4QI6klwB;wueMe3=1?uQ5RJ1qLX36ck@tfa2>4P<&AVimxa@@#O?4Jr|?+ zLIOO#iU7rz5TN+_0Tf?6fZ{6$P<+_{imw?!>0Fahe6;|6;etbq;_C$P_#y!mUm<|v z%L7n+Z2*cd3_$T!0VuvC0L9k>p!i|{6kiE|;>!R~>SsA9z5oEltv@Jk`ayBK4~iRo zP~75!;^rO{xAma7p$EmSJScABL2>&IiW_%O+_HnxTEZy#kx|^BLylW>P~4P*;&vPq zH{zhU1qa2=Hz;nqL2<(kid$_^++>5|_8Js7)}ZvbjN)b*JZ_^waRUvCTW3(*G=t)H z85B3lptwZ_#mzA&#usQDb>u(e1^xHWctJe;GhY4~FNlMG)|Y?Q7sSC|U0-NgHiKrnMM$xa+{|)o-zj1jxdqAu*y{sn zrPdH(t>L(fp_EpbASJ7TNvmtun`0<~mf~r(MJ=`8CLIaUi!JxZ)oL(2?FR9K~I z^{P6QucQZXrU&sPj4(m-^0V8Y@o|hF*8>m1z4+0cy&}^uZv2S2RPMN={~}Qoo-}bh zm$)eTn5m$5dfa$!@q{78Buq+)h@X;{Ffwhxlr$2DQOmf#(I3UItRAr`X%iFU2E@mv z#IdkrO{xBLRUEp&(2Z3>eV5kAKTp4wd{bMLcIB*foIw9LE9<^8{r}OSA1`K#^uKYK zORDqqaG4BA+=h?^SalV~C5&vKI@@ADUqcp&%%i(zEmP^I6u;feLwL9BbK-T9X*T_( z1-Ti&m$T=(S~cf-p^J==Qtt@$LRI}g9S^5ADuin}kAewHvcBnoHXHeteU8wX5#vk5 zdkv=fsudggBiTk;l$r3^I{{h|mvkCwJ literal 0 HcmV?d00001 From d5f7dfe577a85559f6aa40fea199bd0d2afbcb45 Mon Sep 17 00:00:00 2001 From: ousnius Date: Sun, 15 Nov 2015 03:42:23 +0100 Subject: [PATCH 10/64] Fixed BA2 texture width/height order --- FSBSA.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FSBSA.h b/FSBSA.h index 3a34d5cf..1e6e109a 100644 --- a/FSBSA.h +++ b/FSBSA.h @@ -144,8 +144,8 @@ struct F4TexInfo { wxUint8 unk0C; //!< 0C wxUint8 numChunks; //!< 0D wxUint16 chunkHeaderSize; //!< 0E - size of one chunk header - wxUint16 width; //!< 10 - wxUint16 height; //!< 12 + wxUint16 height; //!< 10 + wxUint16 width; //!< 12 wxUint8 numMips; //!< 14 wxUint8 format; //!< 15 - DXGI_FORMAT wxUint16 unk16; //!< 16 - 0800 From ee43b9ba73cefc2d0c2da6fa2c8d072fbc9aa5e4 Mon Sep 17 00:00:00 2001 From: Caliente Date: Tue, 17 Nov 2015 14:13:21 -0500 Subject: [PATCH 11/64] Fallout4 nif mesh loading functionality --- BodySlide.vcxproj | 4 + BodySlide.vcxproj.filters | 8 + GLSurface.cpp | 74 ++++- GLSurface.h | 3 +- NifBlock.cpp | 539 ++++++++++++++++++++++++++++++--- NifFile.cpp | 616 ++++++++++++++++++++++++++++++-------- NifFile.h | 111 ++++++- ObjFile.cpp | 73 +++++ ObjFile.h | 1 + Object3d.cpp | 46 +++ Object3d.h | 3 + OutfitProject.cpp | 10 +- 12 files changed, 1303 insertions(+), 185 deletions(-) create mode 100644 Object3d.cpp diff --git a/BodySlide.vcxproj b/BodySlide.vcxproj index e32499b6..5a3eb215 100644 --- a/BodySlide.vcxproj +++ b/BodySlide.vcxproj @@ -123,6 +123,7 @@ + @@ -186,6 +187,9 @@ + + + diff --git a/BodySlide.vcxproj.filters b/BodySlide.vcxproj.filters index 92cdd6b1..0e2ca32b 100644 --- a/BodySlide.vcxproj.filters +++ b/BodySlide.vcxproj.filters @@ -111,6 +111,9 @@ Source Files + + Source Files + @@ -229,4 +232,9 @@ Resource Files + + + Resource Files + + \ No newline at end of file diff --git a/GLSurface.cpp b/GLSurface.cpp index 18d38bee..d8a5d2bd 100644 --- a/GLSurface.cpp +++ b/GLSurface.cpp @@ -1167,6 +1167,7 @@ void GLSurface::AddMeshFromNif(NifFile* nif, string shapeName, Vector3* color, b nif->GetVertsForShape(shapeName, nifVerts); nif->GetTrisForShape(shapeName, &nifTris); + const vector* nifNorms = nullptr; const vector* nifUvs = nif->GetUvsForShape(shapeName); @@ -1198,6 +1199,9 @@ void GLSurface::AddMeshFromNif(NifFile* nif, string shapeName, Vector3* color, b m->verts[i].x = (nifVerts)[i].x / -10.0f; m->verts[i].z = (nifVerts)[i].y / 10.0f; m->verts[i].y = (nifVerts)[i].z / 10.0f; + //m->verts[i].x = (nifVerts)[i].x / 10.0f; + //m->verts[i].y = (nifVerts)[i].y / 10.0f; + //m->verts[i].z = (nifVerts)[i].z / 10.0f; m->verts[i].indexRef = i; } @@ -1275,6 +1279,17 @@ void GLSurface::AddMeshFromNif(NifFile* nif, string shapeName, Vector3* color, b } } + //nifNorms = nif->GetNormalsForShape(shapeName); + //m->ColorFill(Vector3(0, 0, 0)); + //for (int i = 0; i < m->nVerts; i++) { + + // m->vcolors[i].y = m->verts[i].nx * m->verts[i].nz; //Vector3(m->verts[i].nx, m->verts[i].ny, m->verts[i].nz).dot(Vector3(0, 0, 1.0)); // + //m->vcolors[i].y = (*nifNorms)[i].y; + //} + + //AddVisNorms(m,nifNorms,"fileNorms",Vector3(1.0f,0,0)); + //AddVisNorms(m, NULL, "CalcNorms", Vector3(0, 0, 1.0f)); + m->CreateBVH(); m->CreateKDTree(); @@ -1465,15 +1480,68 @@ int GLSurface::AddVisRay(Vector3& start, Vector3& direction, float length) { } return overlays.size() - 1; } +int GLSurface::AddVisNorms(const mesh* src, const vector* normals, const string& name, const Vector3 color ) { + int visMesh = GetOverlayID(name); + if (visMesh >= 0) { + delete overlays[visMesh]; + overlays.erase(overlays.begin() + visMesh); + visMesh = 0; + } -int GLSurface::AddVisPoint(const Vector3& p, const string& name) { + mesh* mv = new mesh(); + mv->nVerts = src->nVerts*2; + mv->nEdges = src->nVerts; + + mv->verts = new Vertex[mv->nVerts]; + mv->edges = new Edge[mv->nEdges]; + + int mvi = 0; + + for (int i = 0; i < mv->nEdges; i++) { + mv->verts[mvi] = src->verts[i]; + if (normals != NULL) { + mv->verts[mvi + 1].x = src->verts[i].x + (*normals)[i].x*.1; + mv->verts[mvi + 1].y = src->verts[i].y + (*normals)[i].y*.1; + mv->verts[mvi + 1].z = src->verts[i].z + (*normals)[i].z*.1; + + } + else { + mv->verts[mvi + 1].x = src->verts[i].x + src->verts[i].nx*.1; + mv->verts[mvi + 1].y = src->verts[i].y + src->verts[i].ny*.1; + mv->verts[mvi + 1].z = src->verts[i].z + src->verts[i].nz*.1; + + } + mv->edges[i].p1 = mvi; + mv->edges[i].p2 = mvi + 1; + mvi += 2; + } + + mv->rendermode = RenderMode::UnlitWire; + mv->color = color; // Vector3(1.0, 0.0, 1.0f); + + mv->shapeName = name; + + namedOverlays[mv->shapeName] = overlays.size(); + overlays.push_back(mv); + return overlays.size() - 1; + +} + + + +int GLSurface::AddVisPoint(const Vector3& p, const string& name, const Vector3* color ) { mesh* m; int pmesh = GetOverlayID(name); if (pmesh >= 0) { m = overlays[pmesh]; m->verts[0] = p; - - m->color = Vector3(0.0f, 1.0f, 1.0f); + if (color != nullptr) { + m->color = (*color); + } + else { + m->color = Vector3(0.0f, 1.0f, 1.0f); + + } m->bVisible = true; return pmesh; } diff --git a/GLSurface.h b/GLSurface.h index ae3f9436..1667e17c 100644 --- a/GLSurface.h +++ b/GLSurface.h @@ -249,8 +249,9 @@ class GLSurface { int AddVisCircle(const Vector3& center, const Vector3& normal, float radius, const string& name = "RingMesh"); int AddVis3dRing(const Vector3& center, const Vector3& normal, float holeRadius, float ringRadius, const Vector3& color, const string& name = "XRotateMesh"); int AddVis3dArrow(const Vector3& origin, const Vector3& direction, float stemRadius, float pointRadius, float length, const Vector3& color, const string& name = "XMoveMesh"); - int AddVisPoint(const Vector3& p, const string& name = "PointMesh"); + int AddVisPoint(const Vector3& p, const string& name = "PointMesh", const Vector3* color = nullptr); int AddVisTri(const Vector3& p1, const Vector3& p2, const Vector3& p3, const string& name = "TriMesh"); + int AddVisNorms(const mesh* src, const vector* normals = NULL, const string& name = "MeshNorms", const Vector3 color = { 1.0f, 0.0f, 1.0f }); int AddVisFacets(vector& triIDs, const string& name = "TriMesh"); int AddVisFacetsInSphere(Vector3& origin, float radius, const string& name = "SphereFIntersect"); diff --git a/NifBlock.cpp b/NifBlock.cpp index 7adfadd9..b66c881c 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -134,6 +134,9 @@ void NiHeader::Put(fstream& file) { creator.Put(file, 1); exportInfo1.Put(file, 1); exportInfo2.Put(file, 1); + if (userVersion2 >= 130) { + exportInfo3.Put(file, 1); + } file.write((char*)&numBlockTypes, 2); for (int i = 0; i < numBlockTypes; i++) blockTypes[i].Put(file, 4); @@ -489,10 +492,12 @@ void NiNode::Get(fstream& file) { children.push_back(intData); } - file.read((char*)&numEffects, 4); - for (int i = 0; i < numEffects; i++) { - file.read((char*)&intData, 4); - effects.push_back(intData); + if (header->userVersion == 12 && header->userVersion2 < 130) { + file.read((char*)&numEffects, 4); + for (int i = 0; i < numEffects; i++) { + file.read((char*)&intData, 4); + effects.push_back(intData); + } } } @@ -503,9 +508,11 @@ void NiNode::Put(fstream& file) { for (int i = 0; i < numChildren; i++) file.write((char*)&children[i], 4); - file.write((char*)&numEffects, 4); - for (int i = 0; i < numEffects; i++) - file.write((char*)&effects[i], 4); + if (header->userVersion == 12 && header->userVersion2 < 130) { + file.write((char*)&numEffects, 4); + for (int i = 0; i < numEffects; i++) + file.write((char*)&effects[i], 4); + } } void NiNode::notifyBlockDelete(int blockID) { @@ -551,10 +558,336 @@ void NiNode::notifyBlockSwap(int blockIndexLo, int blockIndexHi) { int NiNode::CalcBlockSize() { NiAVObject::CalcBlockSize(); - blockSize += 8; + blockSize += 4; blockSize += numChildren * 4; - blockSize += numEffects * 4; + if (header->userVersion == 12 && header->userVersion2 < 130) { + blockSize += 4; + blockSize += numEffects * 4; + } + return blockSize; +} + +BSTriShape::BSTriShape(fstream& file, NiHeader& hdr, int blockindex) { + NiAVObject::Init(); + blockType = BSTRISHAPE; + header = &hdr; + blockSize = header->blockSizes[blockindex]; + Get(file); +} + +void BSTriShape::Get(fstream& file) { + int intData; + short shortData; + // The order of definition deviates slightly from previous versions, so can't directly use the super Get... instead + // that code is duplicated here and the super super get is called. + NiObjectNET::Get(file); + + file.read((char*)&flags, 2); + + file.read((char*)&unkShort1, 2); + + file.read((char*)&translation.x, 4); + file.read((char*)&translation.y, 4); + file.read((char*)&translation.z, 4); + + for (int i = 0; i < 3; i++) { + file.read((char*)&rotation[i].x, 4); + file.read((char*)&rotation[i].y, 4); + file.read((char*)&rotation[i].z, 4); + } + + file.read((char*)&scale, 4); + + file.read((char*)&collisionRef, 4); + + for (int i = 0; i < 4; i++) { + file.read((char*)&unkProps[i], 4); + } + + file.read((char*)&skinInstanceRef, 4); + file.read((char*)&shaderPropertyRef, 4); + + file.read((char*)&unkRef, 4); + for (int i = 0; i < 8; i++) { + file.read((char*)&vertFlags[i], 1); + } + + + file.read((char*)&numTris, 4); + file.read((char*)&numverts, 2); + + file.read((char*)&datasize, 4); + vertRecSize = (datasize - (numTris * 6)) / numverts; + + + vertData.resize(numverts); + for (int i = 0; i < numverts; i++) { + file.read((char*)&shortData, 2); + vertData[i].vert.x = h2float(shortData); + file.read((char*)&shortData, 2); + vertData[i].vert.y = h2float(shortData); + file.read((char*)&shortData, 2); + vertData[i].vert.z = h2float(shortData); + + file.read((char*)&shortData, 2); + vertData[i].dotNormal = h2float(shortData); + + file.read((char*)&shortData, 2); + vertData[i].uv.u = h2float(shortData); + file.read((char*)&shortData, 2); + vertData[i].uv.v = h2float(shortData); + + if (vertFlags[6] & 0x1) { + file.read((char*)vertData[i].normalData, 8); + } + + if (vertFlags[6] & 0x2) { + file.read((char*)&vertData[i].colorData, 4); + } + + if (vertFlags[6] & 0x4) { + for (int j = 0; j < 4; j++) { + file.read((char*)&shortData, 2); + vertData[i].weights[j] = h2float(shortData); + } + for (int j = 0; j < 4; j++) { + file.read((char*)&vertData[i].weightBones[j], 1); + } + } + } + + + triangles.resize(numTris); + for (int i = 0; i < numTris; i++) { + file.read((char*)&triangles[i].p1, 2); + file.read((char*)&triangles[i].p2, 2); + file.read((char*)&triangles[i].p3, 2); + } + + +} + + +void BSTriShape::Put(fstream& file) { + short shortData; + // The order of definition deviates slightly from previous versions, so can't directly use the super Get... instead + // that code is duplicated here and the super super get is called. + NiObjectNET::Put(file); + + file.write((char*)&flags, 2); + + + file.write((char*)&unkShort1, 2); + + file.write((char*)&translation.x, 4); + file.write((char*)&translation.y, 4); + file.write((char*)&translation.z, 4); + + for (int i = 0; i < 3; i++) { + file.write((char*)&rotation[i].x, 4); + file.write((char*)&rotation[i].y, 4); + file.write((char*)&rotation[i].z, 4); + } + + file.write((char*)&scale, 4); + + file.write((char*)&collisionRef, 4); + + for (int i = 0; i < 4; i++) { + file.write((char*)&unkProps[i], 4); + } + + file.write((char*)&skinInstanceRef, 4); + file.write((char*)&shaderPropertyRef, 4); + + file.write((char*)&unkRef, 4); + for (int i = 0; i < 8; i++) { + file.write((char*)&vertFlags[i], 1); + } + + file.write((char*)&numTris, 4); + file.write((char*)&numverts, 2); + + file.write((char*)&datasize, 4); + + for (int i = 0; i < numverts; i++) { + + shortData = float2h(vertData[i].vert.x); + file.write((char*)&shortData, 2); + + shortData = float2h(vertData[i].vert.y); + file.write((char*)&shortData, 2); + + + shortData = float2h(vertData[i].vert.z); + file.write((char*)&shortData, 2); + + shortData = float2h(vertData[i].dotNormal); + file.write((char*)&shortData, 2); + + shortData = float2h(vertData[i].uv.u); + file.write((char*)&shortData, 2); + + + shortData = float2h(vertData[i].uv.v); + file.write((char*)&shortData, 2); + + if (vertFlags[6] & 0x1) { + file.write((char*)vertData[i].normalData, 8); + // file.write((char*)&vertData[i].normals[0], 4); + // file.write((char*)&vertData[i].normals[1], 4); + } + + if (vertFlags[6] & 0x2) { + file.write((char*)&vertData[i].colorData, 4); + } + if (vertFlags[6] & 0x4) { + for (int j = 0; j < 4; j++) { + shortData = float2h(vertData[i].weights[j]); + file.write((char*)&shortData, 2); + } + for (int j = 0; j < 4; j++) { + file.write((char*)&vertData[i].weightBones[j], 1); + } + } + } + + for (int i = 0; i < numTris; i++) { + file.write((char*)&triangles[i].p1, 2); + file.write((char*)&triangles[i].p2, 2); + file.write((char*)&triangles[i].p3, 2); + } + +} + +void BSTriShape::notifyBlockDelete(int blockID) { + NiObjectNET::notifyBlockDelete(blockID); + + +} + +void BSTriShape::notifyBlockSwap(int blockIndexLo, int blockIndexHi) { + + NiObjectNET::notifyBlockSwap(blockIndexLo, blockIndexHi); + +} + +int BSTriShape::CalcBlockSize() { + blockSize = 118 + 6 * numTris + 32 * numverts; + + return blockSize; + +} + + +const vector* BSTriShape::GetRawVerts() { + rawverts.clear(); + rawverts.resize(numverts); + for (int i = 0; i < numverts; i++) { + rawverts[i] = vertData[i].vert; + } + + return &rawverts; +} + + +const vector* BSTriShape::GetNormalData() { + rawnorms.clear(); + rawnorms.resize(numverts); + for (int i = 0; i < numverts; i++) { + + float q1 = (((float)vertData[i].normalData[0])/255.0f) *2.0f - 1.0f; + float q2 = (((float)vertData[i].normalData[1])/255.0f) *2.0f - 1.0f; + float q3 = (((float)vertData[i].normalData[2])/255.0f) *2.0f - 1.0f; + + float x = q1; + float y = q2; + float z = q3; + + rawnorms[i].x = -x; + rawnorms[i].z = y; + rawnorms[i].y = z; + + } + + return &rawnorms; +} + +const vector* BSTriShape::GetTangentData() { + rawtangents.clear(); + rawtangents.resize(numverts); + for (int i = 0; i < numverts; i++) { + float q6 = (((float)vertData[i].normalData[4]) / 255.0f) *2.0f - 1.0f; + float q7 = (((float)vertData[i].normalData[5]) / 255.0f) *2.0f - 1.0f; + float q8 = (((float)vertData[i].normalData[6]) / 255.0f) *2.0f - 1.0f; + + float x = q6; + float y = q7; + float z = q8; + + rawtangents[i].x = -x; + rawtangents[i].z = y; + rawtangents[i].y = z; + } + return &rawtangents; +} + +const vector* BSTriShape::GetUVData() { + rawuvs.clear(); + rawuvs.resize(numverts); + for (int i = 0; i < numverts; i++) { + rawuvs[i] = vertData[i].uv; + } + + return &rawuvs; + +} + + + +BSSubIndexTriShape::BSSubIndexTriShape(fstream& file, NiHeader& hdr, int blockindex) : +BSTriShape(file, hdr, blockindex) +{ + blockType = BSSUBINDEXTRISHAPE; + Get(file); +} + +void BSSubIndexTriShape::Get(fstream& file) { + vertRecSize = (datasize - (numTris * 6)) / numverts; + szMysteryBlob = blockSize - (vertRecSize * numverts + 6 * numTris + 118); + + /// LETS LEAK SOME MEMORY! temporary until we figure out the hunk of data at the end of this block + MysteryBlob = new char[szMysteryBlob]; + file.read((char*)MysteryBlob, szMysteryBlob); +} + + +void BSSubIndexTriShape::Put(fstream& file) { + BSTriShape::Put(file); + + file.write((char*)MysteryBlob, szMysteryBlob); + + + +} + +void BSSubIndexTriShape::notifyBlockDelete(int blockID) { + NiObjectNET::notifyBlockDelete(blockID); + + +} + +void BSSubIndexTriShape::notifyBlockSwap(int blockIndexLo, int blockIndexHi) { + + NiObjectNET::notifyBlockSwap(blockIndexLo, blockIndexHi); + +} + +int BSSubIndexTriShape::CalcBlockSize() { + blockSize = 118 + 6 * numTris + 32 * numverts + szMysteryBlob; + return blockSize; + } @@ -2925,6 +3258,9 @@ void BSLightingShaderProperty::Get(fstream& file) { file.read((char*)&emissiveColor.y, 4); file.read((char*)&emissiveColor.z, 4); file.read((char*)&emissiveMultiple, 4); + if (header->userVersion == 12 && header->userVersion2 >= 130) { + file.read((char*)&wetMaterialNameRef, 4); + } file.read((char*)&textureClampMode, 4); file.read((char*)&alpha, 4); file.read((char*)&refractionStrength, 4); @@ -2934,12 +3270,19 @@ void BSLightingShaderProperty::Get(fstream& file) { file.read((char*)&specularColor.z, 4); file.read((char*)&specularStrength, 4); file.read((char*)&lightingEffect1, 4); - file.read((char*)&lightingEffect2, 4); + + if (header->userVersion == 12 && header->userVersion2 < 130) { + file.read((char*)&lightingEffect2, 4); + } + else if (header->userVersion == 12 && header->userVersion2 >= 130) { + file.read((char*)&unk1,4); + file.read((char*)&unk2, 4); + } if (skyrimShaderType == 1) { file.read((char*)&environmentMapScale, 4); } - else if (skyrimShaderType == 5) { + else if (skyrimShaderType == 5 && header->userVersion2 < 130) { file.read((char*)&skinTintColor.x, 4); file.read((char*)&skinTintColor.y, 4); file.read((char*)&skinTintColor.z, 4); @@ -2975,6 +3318,21 @@ void BSLightingShaderProperty::Get(fstream& file) { file.read((char*)&eyeRightReflectionCenter.y, 4); file.read((char*)&eyeRightReflectionCenter.z, 4); } + + if (header->userVersion2 >= 130) { + for (int i = 0; i < 8; i++) { + file.read((char*)&unk[i], 4); + } + } + if (skyrimShaderType==1 && header->userVersion2 >= 130) { + for (int i = 0; i < 2; i++) { + file.read((char*)&pad[i], 1); + } + }if (skyrimShaderType == 5 && header->userVersion2 >= 130) { + for (int i = 0; i < 16; i++) { + file.read((char*)&pad[i], 1); + } + } } void BSLightingShaderProperty::Put(fstream& file) { @@ -2995,6 +3353,9 @@ void BSLightingShaderProperty::Put(fstream& file) { file.write((char*)&emissiveColor.y, 4); file.write((char*)&emissiveColor.z, 4); file.write((char*)&emissiveMultiple, 4); + if (header->userVersion == 12 && header->userVersion2 >= 130) { + file.write((char*)&wetMaterialNameRef, 4); + } file.write((char*)&textureClampMode, 4); file.write((char*)&alpha, 4); file.write((char*)&refractionStrength, 4); @@ -3004,12 +3365,19 @@ void BSLightingShaderProperty::Put(fstream& file) { file.write((char*)&specularColor.z, 4); file.write((char*)&specularStrength, 4); file.write((char*)&lightingEffect1, 4); - file.write((char*)&lightingEffect2, 4); + + if (header->userVersion == 12 && header->userVersion2 < 130) { + file.write((char*)&lightingEffect2, 4); + } + else if (header->userVersion == 12 && header->userVersion2 >= 130) { + file.write((char*)&unk1, 4); + file.write((char*)&unk2, 4); + } if (skyrimShaderType == 1) { file.write((char*)&environmentMapScale, 4); } - else if (skyrimShaderType == 5) { + else if (skyrimShaderType == 5 && header->userVersion2 < 130) { file.write((char*)&skinTintColor.x, 4); file.write((char*)&skinTintColor.y, 4); file.write((char*)&skinTintColor.z, 4); @@ -3045,6 +3413,23 @@ void BSLightingShaderProperty::Put(fstream& file) { file.write((char*)&eyeRightReflectionCenter.y, 4); file.write((char*)&eyeRightReflectionCenter.z, 4); } + + + if (header->userVersion2 >= 130) { + for (int i = 0; i < 8; i++) { + file.write((char*)&unk[i], 4); + } + } + if (skyrimShaderType == 1 && header->userVersion2 >= 130) { + for (int i = 0; i < 2; i++) { + file.write((char*)&pad[i], 1); + } + }if (skyrimShaderType == 5 && header->userVersion2 >= 130) { + for (int i = 0; i < 16; i++) { + file.write((char*)&pad[i], 1); + } + } + } void BSLightingShaderProperty::notifyBlockDelete(int blockID) { @@ -3142,22 +3527,46 @@ int BSLightingShaderProperty::CalcBlockSize() { if (header->userVersion == 12) blockSize += 8; - blockSize += 76; + blockSize += 72; - if (skyrimShaderType == 1) - blockSize += 4; - else if (skyrimShaderType == 5) + if (header->userVersion == 12 && header->userVersion2 >= 130) { blockSize += 12; - else if (skyrimShaderType == 6) + } + + if (header->userVersion == 12 && header->userVersion2 < 130) { + blockSize += 4; + } + + if (skyrimShaderType == 1) { + blockSize += 4; + } + else if (skyrimShaderType == 5) { + if (header->userVersion2 < 130) { + blockSize += 12; + } + } + else if (skyrimShaderType == 6) { blockSize += 12; - else if (skyrimShaderType == 7) + }else if (skyrimShaderType == 7){ blockSize += 8; - else if (skyrimShaderType == 11) + }else if (skyrimShaderType == 11){ blockSize += 20; - else if (skyrimShaderType == 14) + }else if (skyrimShaderType == 14){ blockSize += 16; - else if (skyrimShaderType == 16) + }else if (skyrimShaderType == 16){ blockSize += 28; + } + + if (header->userVersion2 >= 130) { + blockSize += 32; + } + + if (skyrimShaderType == 1 && header->userVersion2 >= 130) { + blockSize += 2; + } + if (skyrimShaderType == 5 && header->userVersion2 >= 130) { + blockSize += 16; + } return blockSize; } @@ -3271,15 +3680,28 @@ void BSEffectShaderProperty::Get(fstream& file) { file.read((char*)&uvScale.v, 4); sourceTexture = NiString(file, 4, false); file.read((char*)&textureClampMode, 4); + if (header->userVersion == 12 && header->userVersion2 < 130) { + file.read((char*)&falloffStartAngle, 4); + file.read((char*)&falloffStopAngle, 4); + file.read((char*)&falloffStartOpacity, 4); + file.read((char*)&falloffStopOpacity, 4); + file.read((char*)&emissiveColor, 16); + file.read((char*)&emissiveMultiple, 4); + file.read((char*)&softFalloffDepth, 4); + greyscaleTexture = NiString(file, 4, false); + } + if (header->userVersion == 12 && header->userVersion2 >= 130) { + for (int i = 0; i < 11; i++) { + file.read((char*)&unkdata[i], 4); + } + emissiveTex = NiString(file, 4, false); + normalTex = NiString(file,4,false); + specularTex = NiString(file,4,false); + for (int i = 0; i < 3; i++) { + file.read((char*)&unkdata2[i], 4); + } + } - file.read((char*)&falloffStartAngle, 4); - file.read((char*)&falloffStopAngle, 4); - file.read((char*)&falloffStartOpacity, 4); - file.read((char*)&falloffStopOpacity, 4); - file.read((char*)&emissiveColor, 16); - file.read((char*)&emissiveMultiple, 4); - file.read((char*)&softFalloffDepth, 4); - greyscaleTexture = NiString(file, 4, false); } void BSEffectShaderProperty::Put(fstream& file) { @@ -3294,14 +3716,27 @@ void BSEffectShaderProperty::Put(fstream& file) { sourceTexture.Put(file, 4); file.write((char*)&textureClampMode, 4); - file.write((char*)&falloffStartAngle, 4); - file.write((char*)&falloffStopAngle, 4); - file.write((char*)&falloffStartOpacity, 4); - file.write((char*)&falloffStopOpacity, 4); - file.write((char*)&emissiveColor, 16); - file.write((char*)&emissiveMultiple, 4); - file.write((char*)&softFalloffDepth, 4); - greyscaleTexture.Put(file, 4); + if (header->userVersion == 12 && header->userVersion2 < 130) { + file.write((char*)&falloffStartAngle, 4); + file.write((char*)&falloffStopAngle, 4); + file.write((char*)&falloffStartOpacity, 4); + file.write((char*)&falloffStopOpacity, 4); + file.write((char*)&emissiveColor, 16); + file.write((char*)&emissiveMultiple, 4); + file.write((char*)&softFalloffDepth, 4); + greyscaleTexture.Put(file, 4); + } + if (header->userVersion == 12 && header->userVersion2 >= 130) { + for (int i = 0; i < 11; i++) { + file.write((char*)&unkdata[i], 4); + } + emissiveTex.Put(file, 4); + normalTex.Put(file, 4); + specularTex.Put(file, 4); + for (int i = 0; i < 3; i++) { + file.write((char*)&unkdata2[i], 4); + } + } } void BSEffectShaderProperty::notifyBlockDelete(int blockID) { @@ -3577,17 +4012,39 @@ NiAlphaProperty::NiAlphaProperty(fstream& file, NiHeader& hdr) { } void NiAlphaProperty::Get(fstream& file) { - NiProperty::Get(file); + if (header->userVersion == 12 && header->userVersion2 < 130) { + NiProperty::Get(file); + } + + if (header->userVersion == 12 && header->userVersion2 >= 130) { + file.read((char*)&unkRef, 4); + } + file.read((char*)&flags, 2); - file.read((char*)&threshold, 1); + file.read((char*)&threshold, 1); + if (header->userVersion == 12 && header->userVersion2 >= 130) { + file.read((char*)&unk1, 4); + file.read((char*)&unk2, 4); + } } void NiAlphaProperty::Put(fstream& file) { - NiProperty::Put(file); + if (header->userVersion == 12 && header->userVersion2 < 130) { + NiProperty::Put(file); + } + + if (header->userVersion == 12 && header->userVersion2 >= 130) { + file.write((char*)&unkRef, 4); + } + file.write((char*)&flags, 2); file.write((char*)&threshold, 1); + if (header->userVersion == 12 && header->userVersion2 >= 130) { + file.write((char*)&unk1, 4); + file.write((char*)&unk2, 4); + } } void NiAlphaProperty::notifyBlockDelete(int blockID) { diff --git a/NifFile.cpp b/NifFile.cpp index c0d1b83a..145c6ce3 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -38,8 +38,40 @@ NiTriBasedGeom* NifFile::geomForName(const string& name, int dupIndex) { } return nullptr; } +BSTriShape* NifFile::geomForNameF4(const string& name, int dupIndex) { + int numFound = 0; + for (auto& block : blocks) { + ushort type = block->blockType; + if (type == BSSUBINDEXTRISHAPE || type == BSTRISHAPE) { + BSTriShape* geom = dynamic_cast(block); + if (geom && !name.compare(geom->name)) { + if (numFound >= dupIndex) + return geom; + numFound++; + } + } + } + return nullptr; +} + +NiAVObject* NifFile::avObjectForName(const string& name, int dupIndex) { + int numFound = 0; + for (auto& block : blocks) { + ushort type = block->blockType; + if (type == NITRISHAPE || type == NITRISTRIPS || type == BSSUBINDEXTRISHAPE || type == BSTRISHAPE) { + NiAVObject* avo = dynamic_cast(block); + if (avo && !name.compare(avo->name)) { + if (numFound >= dupIndex) + return avo; + numFound++; + } + } + } + return nullptr; +} int NifFile::shapeDataIdForName(const string& name, int& outBlockType) { + int i = 0; for (auto& block : blocks) { ushort type = block->blockType; if (type == NITRISHAPE || type == NITRISTRIPS) { @@ -50,6 +82,14 @@ int NifFile::shapeDataIdForName(const string& name, int& outBlockType) { return geom->dataRef; } } + else if (type == BSSUBINDEXTRISHAPE|| type == BSTRISHAPE) { + BSTriShape* geom = dynamic_cast(block); + outBlockType = type; + if (geom && !name.compare(geom->name)) { + return i; + } + } + i++; } return -1; } @@ -64,6 +104,12 @@ int NifFile::shapeIdForName(const string& name) { if (geom && !name.compare(geom->name)) return id; } + else if (type == BSSUBINDEXTRISHAPE || type == BSTRISHAPE) { + BSTriShape* geom = dynamic_cast(block); + if (geom && !name.compare(geom->name)) { + return id; + } + } } return -1; } @@ -205,6 +251,12 @@ void NifFile::CopyFrom(NifFile& other) { case BSEFFECTSHADERPROPERTYFLOATCONTROLLER: blockCopy = new BSEffectShaderPropertyFloatController((*(BSEffectShaderPropertyFloatController*)other.blocks[i])); break; + case BSTRISHAPE: + blockCopy = new BSTriShape((*(BSTriShape*)other.blocks[i])); + break; + case BSSUBINDEXTRISHAPE: + blockCopy = new BSSubIndexTriShape((*(BSSubIndexTriShape*)other.blocks[i])); + break; } if (blockCopy) { @@ -302,6 +354,10 @@ int NifFile::Load(const string& filename) { block = (NiObject*) new BSEffectShaderPropertyColorController(file, hdr); else if (!thisBlockTypeStr.compare("BSEffectShaderPropertyFloatController")) block = (NiObject*) new BSEffectShaderPropertyFloatController(file, hdr); + else if (!thisBlockTypeStr.compare("BSSubIndexTriShape")) + block = (NiObject*) new BSSubIndexTriShape(file, hdr, i); + else if (!thisBlockTypeStr.compare("BSTriShape")) + block = (NiObject*) new BSTriShape(file, hdr, i); else { hasUnknown = true; block = (NiObject*) new NiUnknown(file, hdr.blockSizes[i]); @@ -530,14 +586,40 @@ int NifFile::AddStringExtraData(const string& shapeName, const string& name, con return strExtraDataId; } +NiShader* NifFile::GetShaderF4(const string& shapeName) { + int prop1 = -1; + + BSTriShape* geom = geomForNameF4(shapeName); + if (geom) + prop1 = geom->shaderPropertyRef; + else { + return nullptr; + } + + if (prop1 != -1) { + NiShader* shader = dynamic_cast(blocks[prop1]); + if (shader) { + ushort type = shader->blockType; + if (type == BSLIGHTINGSHADERPROPERTY || + type == BSEFFECTSHADERPROPERTY || + type == BSSHADERPPLIGHTINGPROPERTY) + return shader; + } + } + + return nullptr; +} + NiShader* NifFile::GetShader(const string& shapeName) { int prop1 = -1; NiTriBasedGeom* geom = geomForName(shapeName); if (geom) prop1 = geom->propertiesRef1; - else - return nullptr; + else { + return NifFile::GetShaderF4(shapeName); + + } if (prop1 != -1) { NiShader* shader = dynamic_cast(blocks[prop1]); @@ -668,7 +750,9 @@ void NifFile::TrimTexturePaths() { tFile = regex_replace(tFile, regex("/+|\\\\+"), "\\"); // Replace multiple slashes or forward slashes with one backslash tFile = regex_replace(tFile, regex("^\\\\+", regex_constants::icase), ""); // Remove all backslashes from the front tFile = regex_replace(tFile, regex(".*?Data\\\\", regex_constants::icase), ""); // Remove everything before and including the data path root - tFile = regex_replace(tFile, regex("^(?!^textures\\\\)", regex_constants::icase), "textures\\"); // Add textures root path if not existing + if (hdr.userVersion == 12 && hdr.userVersion2 < 130) { + tFile = regex_replace(tFile, regex("^(?!^textures\\\\)", regex_constants::icase), "textures\\"); // Add textures root path if not existing + } SetTextureForShape(s, tFile, i); } } @@ -1164,14 +1248,21 @@ int NifFile::Save(const string& filename) { return 0; } + +int NifFile::GetShapeType(const string& shapeName) { + int type; + shapeDataIdForName(shapeName, type); + return type; +} + int NifFile::GetShapeList(vector& outList) { outList.clear(); for (auto& block : blocks) { ushort type = block->blockType; - if (type == NITRISHAPE || type == NITRISTRIPS) { - NiTriBasedGeom* geom = dynamic_cast(block); - if (geom) - outList.push_back(geom->name); + if (type == NITRISHAPE || type == NITRISTRIPS || type == BSSUBINDEXTRISHAPE || type==BSTRISHAPE) { + NiAVObject* avo = dynamic_cast(block); + if (avo) + outList.push_back(avo->name); } } return outList.size(); @@ -1180,7 +1271,7 @@ int NifFile::GetShapeList(vector& outList) { void NifFile::RenameShape(const string& oldName, const string& newName) { uint strID; - NiTriBasedGeom* geom = geomForName(oldName); + NiAVObject* geom = avObjectForName(oldName); if (geom) { strID = geom->nameRef; geom->name = newName; @@ -1199,9 +1290,9 @@ void NifFile::RenameDuplicateShape(const string& dupedShape) { int dupCount = 1; char buf[10]; - NiTriBasedGeom* geom = geomForName(dupedShape); + NiAVObject* geom = avObjectForName(dupedShape); if (geom) { - while ((geom = geomForName(dupedShape, 1)) != nullptr) { + while ((geom = avObjectForName(dupedShape, 1)) != nullptr) { _snprintf(buf, 10, "_%d", dupCount); while (FindStringId(geom->name + buf) != -1) { dupCount++; @@ -1279,8 +1370,14 @@ int NifFile::GetShapeBoneList(const string& shapeName, vector& outList) outList.clear(); NiTriBasedGeom* geom = geomForName(shapeName); - if (geom) + if (geom) { skinRef = geom->skinInstanceRef; + } + else { + BSTriShape* siTriShape = geomForNameF4(shapeName); + skinRef = siTriShape->skinInstanceRef; + } + if (skinRef == -1) return 0; @@ -1305,8 +1402,14 @@ int NifFile::GetShapeBoneIDList(const string& shapeName, vector& outList) { outList.clear(); NiTriBasedGeom* geom = geomForName(shapeName); - if (geom) + if (geom) { skinRef = geom->skinInstanceRef; + } + else { + BSTriShape* siTriShape = geomForNameF4(shapeName); + skinRef = siTriShape->skinInstanceRef; + } + if (skinRef == -1) return 0; @@ -1327,8 +1430,14 @@ void NifFile::SetShapeBoneIDList(const string& shapeName, vector& inList) { int skinRef = -1; NiTriBasedGeom* geom = geomForName(shapeName); - if (geom) + if (geom) { skinRef = geom->skinInstanceRef; + } + else { + BSTriShape* siTriShape = geomForNameF4(shapeName); + skinRef = siTriShape->skinInstanceRef; + } + if (skinRef == -1) return; @@ -1362,8 +1471,13 @@ int NifFile::GetShapeBoneWeights(const string& shapeName, int boneIndex, unorder outWeights.clear(); NiTriBasedGeom* geom = geomForName(shapeName); - if (geom) + if (geom) { skinRef = geom->skinInstanceRef; + } + else { + BSTriShape* siTriShape = geomForNameF4(shapeName); + skinRef = siTriShape->skinInstanceRef; + } if (skinRef == -1) return 0; @@ -1400,8 +1514,13 @@ bool NifFile::SetShapeBoneTransform(const string& shapeName, int boneIndex, Skin int skinRef = -1; NiTriBasedGeom* geom = geomForName(shapeName); - if (geom) + if (geom) { skinRef = geom->skinInstanceRef; + } + else { + BSTriShape* siTriShape = geomForNameF4(shapeName); + skinRef = siTriShape->skinInstanceRef; + } if (skinRef == -1) return false; @@ -1433,8 +1552,13 @@ bool NifFile::GetShapeBoneTransform(const string& shapeName, int boneIndex, Skin int skinRef = -1; NiTriBasedGeom* geom = geomForName(shapeName); - if (geom) + if (geom) { skinRef = geom->skinInstanceRef; + } + else { + BSTriShape* siTriShape = geomForNameF4(shapeName); + skinRef = siTriShape->skinInstanceRef; + } if (skinRef == -1) return false; @@ -1471,6 +1595,12 @@ void NifFile::UpdateShapeBoneID(const string& shapeName, int oldID, int newID) { NiTriBasedGeom* geom = geomForName(shapeName); if (geom) skinRef = geom->skinInstanceRef; + else { + BSTriShape* siTriShape = geomForNameF4(shapeName); + if (siTriShape) { + //NOT IMPLEMENTED; + } + } if (skinRef == -1) return; @@ -1493,6 +1623,12 @@ void NifFile::SetShapeBoneWeights(const string& shapeName, int boneIndex, unorde NiTriBasedGeom* geom = geomForName(shapeName); if (geom) skinRef = geom->skinInstanceRef; + else { + BSTriShape* siTriShape = geomForNameF4(shapeName); + if (siTriShape) { + //NOT IMPLEMENTED; + } + } if (skinRef == -1) return; @@ -1523,30 +1659,38 @@ const vector* NifFile::GetRawVertsForShape(const string& shapeName) { int dataRef = shapeDataIdForName(shapeName, bType); if (dataRef == -1) return nullptr; - - NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); - return &geomData->vertices; + if (bType == NITRISHAPEDATA || bType == NITRISTRIPSDATA) { + NiTriBasedGeomData* geomData = static_cast(blocks[dataRef]); + return &geomData->vertices; + } + else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + BSTriShape* siTriShape = static_cast(blocks[dataRef]); + return siTriShape->GetRawVerts(); + } } bool NifFile::GetTrisForShape(const string& shapeName, vector* outTris) { - NiTriBasedGeom* geom = geomForName(shapeName); - if (!geom) - return false; - - int dataRef = geom->dataRef; - if (dataRef == -1 || dataRef >= hdr.numBlocks) + int bType; + int dataID = shapeDataIdForName(shapeName, bType); + if (dataID == -1) return false; - if (geom->blockType == NITRISHAPE) { - NiTriShapeData* shapeData = (NiTriShapeData*)(blocks[dataRef]); + if (bType == NITRISHAPE) { + NiTriShapeData* shapeData = static_cast(blocks[dataID]); *outTris = shapeData->triangles; return true; } - else if (geom->blockType == NITRISTRIPS) { - NiTriStripsData* stripsData = (NiTriStripsData*)(blocks[dataRef]); + else if (bType == NITRISTRIPS) { + NiTriStripsData* stripsData = static_cast(blocks[dataID]); stripsData->StripsToTris(outTris); return true; } + else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + BSTriShape* shapeData = static_cast(blocks[dataID]); + *outTris = shapeData->triangles; + return true; + + } return false; } @@ -1566,6 +1710,12 @@ const vector* NifFile::GetNormalsForShape(const string& shapeName) { if (stripsData->hasNormals) return &stripsData->normals; } + else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + // NOT IMPLEMENTED + BSTriShape* shapeData = (BSTriShape*)(blocks[dataID]); + return shapeData->GetNormalData(); + + } return nullptr; } @@ -1585,6 +1735,11 @@ const vector* NifFile::GetUvsForShape(const string& shapeName) { if (stripsData->numUVSets > 0) return &stripsData->uvSets; } + else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + BSTriShape* shapeData = (BSTriShape*)(blocks[dataID]); + return shapeData->GetUVData(); + + } return nullptr; } @@ -1604,6 +1759,12 @@ bool NifFile::GetUvsForShape(const string& shapeName, vector& outUvs) { outUvs.assign(stripsData->uvSets.begin(), stripsData->uvSets.end()); return true; } + else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + const vector* uvdata = GetUvsForShape(shapeName); + outUvs.assign(uvdata->begin(), uvdata->end()); + return true; + + } return false; } @@ -1617,9 +1778,12 @@ const vector>* NifFile::GetSeamVertsForShape(const string& shapeName //NiTriShapeData* shapeData = (NiTriShapeData*)blocks[dataID]; // dosomthin } - else { + else if (bType == NITRISTRIPSDATA) { //NiTriStripsData* stripsData = (NiTriStripsData*)blocks[dataID]; // dosomthin + } + else if (bType == BSSUBINDEXTRISHAPE|| bType == BSTRISHAPE) { + } return nullptr; } @@ -1633,17 +1797,24 @@ bool NifFile::GetVertsForShape(const string& shapeName, vector& outVert return false; if (bType == NITRISHAPEDATA) { - NiTriShapeData* shapeData = (NiTriShapeData*)blocks[dataRef]; + NiTriShapeData* shapeData = static_cast(blocks[dataRef]); for (auto &v : shapeData->vertices) outVerts.push_back(v); return true; } else if (bType == NITRISTRIPSDATA) { - NiTriStripsData* stripsData = (NiTriStripsData*)blocks[dataRef]; + NiTriStripsData* stripsData = static_cast(blocks[dataRef]); for (auto &v : stripsData->vertices) outVerts.push_back(v); return true; } + else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + BSTriShape* siTriShape = static_cast(blocks[dataRef]); + for (auto &v : siTriShape->vertData) + outVerts.push_back(v.vert); + return true; + + } return false; } @@ -1654,15 +1825,20 @@ int NifFile::GetVertCountForShape(const string& shapeName) { return -1; if (bType == NITRISHAPEDATA) { - NiTriShapeData* shapeData = (NiTriShapeData*)blocks[dataID]; + NiTriShapeData* shapeData = static_cast(blocks[dataID]); if (shapeData) return shapeData->numVertices; } else if (bType == NITRISTRIPSDATA) { - NiTriStripsData* stripsData = (NiTriStripsData*)blocks[dataID]; + NiTriStripsData* stripsData = static_cast(blocks[dataID]); if (stripsData) return stripsData->numVertices; } + else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + BSTriShape* siTriShape = static_cast(blocks[dataID]); + return siTriShape->numverts; + + } return -1; } @@ -1673,7 +1849,7 @@ void NifFile::SetVertsForShape(const string& shapeName, const vector& v return; if (bType == NITRISHAPEDATA) { - NiTriShapeData* shapeData = (NiTriShapeData*)blocks[dataID]; + NiTriShapeData* shapeData = static_cast(blocks[dataID]); if (verts.size() != shapeData->vertices.size()) return; @@ -1681,13 +1857,23 @@ void NifFile::SetVertsForShape(const string& shapeName, const vector& v shapeData->vertices[i] = verts[i]; } else if (bType == NITRISTRIPSDATA) { - NiTriStripsData* stripsData = (NiTriStripsData*)blocks[dataID]; + NiTriStripsData* stripsData = static_cast(blocks[dataID]); if (verts.size() != stripsData->vertices.size()) return; for (int i = 0; i < stripsData->vertices.size(); i++) stripsData->vertices[i] = verts[i]; } + else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + BSTriShape* siTriShape = static_cast(blocks[dataID]); + if (verts.size() != siTriShape->numverts) { + return; + } + for (int i = 0; i < siTriShape->numverts; i++) { + siTriShape->vertData[i].vert = verts[i]; + } + + } } void NifFile::SetUvsForShape(const string& shapeName, const vector& uvs) { @@ -1697,18 +1883,28 @@ void NifFile::SetUvsForShape(const string& shapeName, const vector& uvs return; if (bType == NITRISHAPEDATA) { - NiTriShapeData* shapeData = (NiTriShapeData*)blocks[dataID]; + NiTriShapeData* shapeData = static_cast(blocks[dataID]); if (uvs.size() != shapeData->vertices.size()) return; shapeData->uvSets.assign(uvs.begin(), uvs.end()); } else if (bType == NITRISTRIPSDATA) { - NiTriStripsData* stripsData = (NiTriStripsData*)blocks[dataID]; + NiTriStripsData* stripsData = static_cast(blocks[dataID]); if (uvs.size() != stripsData->vertices.size()) return; stripsData->uvSets.assign(uvs.begin(), uvs.end()); + } if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + BSTriShape* siTriShape = static_cast(blocks[dataID]); + if (uvs.size() != siTriShape->numverts) { + return; + } + + for (int i = 0; i < siTriShape->numverts; i++) { + //// VALIDATE LATER for now don't touch the data. + // siTriShape->vertData[i].uv = uvs[i]; + } } } @@ -1738,6 +1934,9 @@ void NifFile::SetNormalsForShape(const string& shapeName, const vector& stripsData->numUVSets |= 1; hdr.blockSizes[dataID] = stripsData->CalcBlockSize(); } + if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + //// Fix later after discovering how fo4 stores normals + } } void NifFile::CalcTangentsForShape(const string& shapeName) { @@ -1756,16 +1955,19 @@ void NifFile::CalcTangentsForShape(const string& shapeName) { stripsData->CalcTangentSpace(); hdr.blockSizes[dataID] = stripsData->CalcBlockSize(); } + if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + //// Fix later after discovering how fo4 stores tangents + } } void NifFile::ClearShapeTransform(const string& shapeName) { - NiTriBasedGeom* geom = geomForName(shapeName); - if (geom) { - geom->translation.Zero(); - geom->scale = 1.0f; - geom->rotation[0] = Vector3(1.0f, 0.0f, 0.0f); - geom->rotation[1] = Vector3(0.0f, 1.0f, 0.0f); - geom->rotation[2] = Vector3(0.0f, 0.0f, 1.0f); + NiAVObject* avo = avObjectForName(shapeName); + if (avo) { + avo->translation.Zero(); + avo->scale = 1.0f; + avo->rotation[0] = Vector3(1.0f, 0.0f, 0.0f); + avo->rotation[1] = Vector3(0.0f, 1.0f, 0.0f); + avo->rotation[2] = Vector3(0.0f, 0.0f, 1.0f); } } @@ -1781,13 +1983,13 @@ void NifFile::GetShapeTransform(const string& shapeName, Matrix4& outTransform) } SkinTransform xFormShape; - NiTriBasedGeom* geom = geomForName(shapeName); - if (geom) { - xFormShape.translation = geom->translation; - xFormShape.scale = geom->scale; - xFormShape.rotation[0] = geom->rotation[0]; - xFormShape.rotation[1] = geom->rotation[1]; - xFormShape.rotation[2] = geom->rotation[2]; + NiAVObject* avo = avObjectForName(shapeName); + if (avo) { + xFormShape.translation = avo->translation; + xFormShape.scale = avo->scale; + xFormShape.rotation[0] = avo->rotation[0]; + xFormShape.rotation[1] = avo->rotation[1]; + xFormShape.rotation[2] = avo->rotation[2]; } Matrix4 matRoot = xFormRoot.ToMatrix(); @@ -1835,9 +2037,9 @@ void NifFile::SetRootScale(const float& newScale) { } void NifFile::GetShapeTranslation(const string& shapeName, Vector3& outVec) { - NiTriBasedGeom* geom = geomForName(shapeName); - if (geom) - outVec = geom->translation; + NiAVObject* avo = avObjectForName(shapeName); + if (avo) + outVec = avo->translation; NiNode* root = dynamic_cast(blocks[0]); if (root) @@ -1848,21 +2050,21 @@ void NifFile::GetShapeTranslation(const string& shapeName, Vector3& outVec) { } void NifFile::SetShapeTranslation(const string& shapeName, const Vector3& newTrans) { - NiTriBasedGeom* geom = geomForName(shapeName); - if (geom) - geom->translation = newTrans; + NiAVObject* avo = avObjectForName(shapeName); + if (avo) + avo->translation = newTrans; } void NifFile::GetShapeScale(const string& shapeName, float& outScale) { - NiTriBasedGeom* geom = geomForName(shapeName); - if (geom) - outScale = geom->scale; + NiAVObject* avo = avObjectForName(shapeName); + if (avo) + outScale = avo->scale; } void NifFile::SetShapeScale(const string& shapeName, const float& newScale) { - NiTriBasedGeom* geom = geomForName(shapeName); - if (geom) - geom->scale = newScale; + NiAVObject* avo = avObjectForName(shapeName); + if (avo) + avo->scale = newScale; } void NifFile::ApplyShapeTranslation(const string& shapeName, const Vector3& offset) { @@ -1871,18 +2073,30 @@ void NifFile::ApplyShapeTranslation(const string& shapeName, const Vector3& offs if (dataRef == -1) return; - NiTriBasedGeom* geom = geomForName(shapeName); - if (!geom) - return; + if (bType == NITRISHAPEDATA || bType == NITRISTRIPSDATA) { + NiTriBasedGeom* geom = geomForName(shapeName); + if (!geom) + return; - NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); - if (!geomData) - return; + NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); + if (!geomData) + return; - for (int i = 0; i < geomData->vertices.size(); i++) - geomData->vertices[i] += geom->translation + offset; + for (int i = 0; i < geomData->vertices.size(); i++) + geomData->vertices[i] += geom->translation + offset; + + geom->translation = Vector3(0.0f, 0.0f, 0.0f); + } + else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + BSTriShape* geom = dynamic_cast(blocks[dataRef]); + if (!geom) + return; + + for (int i = 0; i < geom->numverts; i++) + geom->vertData[i].vert += geom->translation + offset; - geom->translation = Vector3(0.0f, 0.0f, 0.0f); + geom->translation = Vector3(0.0f, 0.0f, 0.0f); + } } void NifFile::MoveVertex(const string& shapeName, const Vector3& pos, const int& id) { @@ -1891,9 +2105,17 @@ void NifFile::MoveVertex(const string& shapeName, const Vector3& pos, const int& if (dataRef == -1) return; - NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); - if (geomData && geomData->numVertices > id) - geomData->vertices[id] = pos; + + if (bType == NITRISHAPEDATA || bType == NITRISTRIPSDATA) { + NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); + if (geomData && geomData->numVertices > id) + geomData->vertices[id] = pos; + } + else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + BSTriShape* geom = dynamic_cast(blocks[dataRef]); + if (geom && geom->numverts > id) + geom->vertData[id].vert = pos; + } } void NifFile::OffsetShape(const string& shapeName, const Vector3& offset, unordered_map* mask) { @@ -1902,23 +2124,45 @@ void NifFile::OffsetShape(const string& shapeName, const Vector3& offset, unorde if (dataRef == -1) return; - NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); - if (!geomData) - return; + if (bType == NITRISHAPEDATA || bType == NITRISTRIPSDATA) { + NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); + if (!geomData) + return; - for (int i = 0; i < geomData->vertices.size(); i++) { - if (mask) { - float maskFactor = 1.0f; - Vector3 diff = offset; - if (mask->find(i) != mask->end()) { - maskFactor = 1.0f - (*mask)[i]; - diff *= maskFactor; + for (int i = 0; i < geomData->vertices.size(); i++) { + if (mask) { + float maskFactor = 1.0f; + Vector3 diff = offset; + if (mask->find(i) != mask->end()) { + maskFactor = 1.0f - (*mask)[i]; + diff *= maskFactor; + } + geomData->vertices[i] += diff; } - geomData->vertices[i] += diff; + else + geomData->vertices[i] += offset; } - else - geomData->vertices[i] += offset; } + else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + BSTriShape* geomData = dynamic_cast(blocks[dataRef]); + if (!geomData) + return; + + for (int i = 0; i < geomData->numverts; i++) { + if (mask) { + float maskFactor = 1.0f; + Vector3 diff = offset; + if (mask->find(i) != mask->end()) { + maskFactor = 1.0f - (*mask)[i]; + diff *= maskFactor; + } + geomData->vertData[i].vert += diff; + } + else + geomData->vertData[i].vert += offset; + } + } + } void NifFile::ScaleShape(const string& shapeName, const float& scale, unordered_map* mask) { @@ -1927,29 +2171,56 @@ void NifFile::ScaleShape(const string& shapeName, const float& scale, unordered_ if (dataRef == -1) return; - NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); - if (!geomData) - return; - Vector3 root; GetRootTranslation(root); - unordered_map diff; - for (int i = 0; i < geomData->vertices.size(); i++) { - Vector3 target = geomData->vertices[i] - root; - target *= scale; - diff[i] = geomData->vertices[i] - target; - - if (mask) { - float maskFactor = 1.0f; - if (mask->find(i) != mask->end()) { - maskFactor = 1.0f - (*mask)[i]; - diff[i] *= maskFactor; - target = geomData->vertices[i] - root + diff[i]; + if (bType == NITRISHAPEDATA || bType == NITRISTRIPSDATA) { + NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); + if (!geomData) + return; + + + unordered_map diff; + for (int i = 0; i < geomData->vertices.size(); i++) { + Vector3 target = geomData->vertices[i] - root; + target *= scale; + diff[i] = geomData->vertices[i] - target; + + if (mask) { + float maskFactor = 1.0f; + if (mask->find(i) != mask->end()) { + maskFactor = 1.0f - (*mask)[i]; + diff[i] *= maskFactor; + target = geomData->vertices[i] - root + diff[i]; + } } + geomData->vertices[i] = target; + } + } + else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + BSTriShape* geomData = dynamic_cast(blocks[dataRef]); + if (!geomData) + return; + + + unordered_map diff; + for (int i = 0; i < geomData->numverts; i++) { + Vector3 target = geomData->vertData[i].vert - root; + target *= scale; + diff[i] = geomData->vertData[i].vert - target; + + if (mask) { + float maskFactor = 1.0f; + if (mask->find(i) != mask->end()) { + maskFactor = 1.0f - (*mask)[i]; + diff[i] *= maskFactor; + target = geomData->vertData[i].vert - root + diff[i]; + } + } + geomData->vertData[i].vert = target; } - geomData->vertices[i] = target; } + } void NifFile::RotateShape(const string& shapeName, const Vector3& angle, unordered_map* mask) { @@ -1958,33 +2229,63 @@ void NifFile::RotateShape(const string& shapeName, const Vector3& angle, unorder if (dataRef == -1) return; - NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); - if (!geomData) - return; - Vector3 root; GetRootTranslation(root); + if (bType == NITRISHAPEDATA || bType == NITRISTRIPSDATA) { + NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); + if (!geomData) + return; + + + unordered_map diff; + for (int i = 0; i < geomData->vertices.size(); i++) { + Vector3 target = geomData->vertices[i] - root; + Matrix4 mat; + mat.Rotate(angle.x * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f)); + mat.Rotate(angle.y * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f)); + mat.Rotate(angle.z * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f)); + target = mat * target; + diff[i] = geomData->vertices[i] - target; + + if (mask) { + float maskFactor = 1.0f; + if (mask->find(i) != mask->end()) { + maskFactor = 1.0f - (*mask)[i]; + diff[i] *= maskFactor; + target = geomData->vertices[i] - root + diff[i]; + } + } + geomData->vertices[i] = target; + } + } + else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + BSTriShape* geomData = dynamic_cast(blocks[dataRef]); + if (!geomData) + return; + - unordered_map diff; - for (int i = 0; i < geomData->vertices.size(); i++) { - Vector3 target = geomData->vertices[i] - root; - Matrix4 mat; - mat.Rotate(angle.x * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f)); - mat.Rotate(angle.y * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f)); - mat.Rotate(angle.z * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f)); - target = mat * target; - diff[i] = geomData->vertices[i] - target; - - if (mask) { - float maskFactor = 1.0f; - if (mask->find(i) != mask->end()) { - maskFactor = 1.0f - (*mask)[i]; - diff[i] *= maskFactor; - target = geomData->vertices[i] - root + diff[i]; + unordered_map diff; + for (int i = 0; i < geomData->numverts ; i++) { + Vector3 target = geomData->vertData[i].vert - root; + Matrix4 mat; + mat.Rotate(angle.x * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f)); + mat.Rotate(angle.y * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f)); + mat.Rotate(angle.z * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f)); + target = mat * target; + diff[i] = geomData->vertData[i].vert - target; + + if (mask) { + float maskFactor = 1.0f; + if (mask->find(i) != mask->end()) { + maskFactor = 1.0f - (*mask)[i]; + diff[i] *= maskFactor; + target = geomData->vertData[i].vert - root + diff[i]; + } } + geomData->vertData[i].vert = target; } - geomData->vertices[i] = target; } + } bool NifFile::GetAlphaForShape(const string& shapeName, ushort& outFlags, byte& outThreshold) { @@ -2003,6 +2304,12 @@ bool NifFile::GetAlphaForShape(const string& shapeName, ushort& outFlags, byte& } } } + else { + BSTriShape* siTriShape = geomForNameF4(shapeName); + if (siTriShape) { + //alphaRef = siTriShape->unkRef; + } + } if (alphaRef == -1) return false; @@ -2057,6 +2364,12 @@ void NifFile::SetAlphaForShape(const string& shapeName, ushort flags, ushort thr hdr.blockIndex.push_back(alphaBlockTypeId); } } + else { + BSTriShape* siTriShape = geomForNameF4(shapeName); + if (siTriShape) { + //alphaRef = siTriShape->unkRef; + } + } if (alphaRef == -1) return; @@ -2107,10 +2420,18 @@ void NifFile::DeleteShape(const string& shapeName) { for (int i = 0; i < geom->numExtraData; i++) DeleteBlock(geom->extraDataRef[i]); + + int shapeID = shapeIdForName(shapeName); + DeleteBlock(shapeID); + } + else { + // Not IMplemented + BSTriShape* siTriShape = geomForNameF4(shapeName); + if (siTriShape) { + + } } - int shapeID = shapeIdForName(shapeName); - DeleteBlock(shapeID); } void NifFile::DeleteShader(const string& shapeName) { @@ -2147,6 +2468,13 @@ void NifFile::DeleteShader(const string& shapeName) { } } } + else { + // Not IMplemented + BSTriShape* siTriShape = geomForNameF4(shapeName); + if (siTriShape) { + //alphaRef = siTriShape->unkRef; + } + } } void NifFile::DeleteAlpha(const string& shapeName) { @@ -2170,6 +2498,13 @@ void NifFile::DeleteAlpha(const string& shapeName) { } } } + else { + // Not IMplemented + BSTriShape* siTriShape = geomForNameF4(shapeName); + if (siTriShape) { + //alphaRef = siTriShape->unkRef; + } + } } void NifFile::DeleteVertsForShape(const string& shapeName, const vector& indices) { @@ -2197,6 +2532,13 @@ void NifFile::DeleteVertsForShape(const string& shapeName, const vector& } } } + else { + // Not IMplemented + BSTriShape* siTriShape = geomForNameF4(shapeName); + if (siTriShape) { + //alphaRef = siTriShape->unkRef; + } + } if (skinRef == -1) return; @@ -2256,7 +2598,16 @@ int NifFile::ShapeDiff(const string& baseShapeName, const string& targetShape, u void NifFile::UpdateSkinPartitions(const string& shapeName) { int skinRef = -1; NiTriBasedGeom* geom = geomForName(shapeName); - skinRef = geom->skinInstanceRef; + if (geom) { + skinRef = geom->skinInstanceRef; + } + else { + // Not IMplemented + BSTriShape* siTriShape = geomForNameF4(shapeName); + if (siTriShape) { + //alphaRef = siTriShape->unkRef; + } + } if (skinRef == -1) return; @@ -2372,6 +2723,11 @@ void NifFile::BuildSkinPartitions(const string& shapeName, int maxBonesPerPartit if (dataRef == -1) return; + if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + // NOT IMPLEMENTED + return; + } + NiTriBasedGeom* geom = geomForName(shapeName); if (!geom) return; diff --git a/NifFile.h b/NifFile.h index 4eb52c8f..e0b5db3c 100644 --- a/NifFile.h +++ b/NifFile.h @@ -48,7 +48,9 @@ enum BlockType { BSLIGHTINGSHADERPROPERTYCOLORCONTROLLER, BSLIGHTINGSHADERPROPERTYFLOATCONTROLLER, BSEFFECTSHADERPROPERTYCOLORCONTROLLER, - BSEFFECTSHADERPROPERTYFLOATCONTROLLER + BSEFFECTSHADERPROPERTYFLOATCONTROLLER, + BSTRISHAPE, + BSSUBINDEXTRISHAPE }; struct VertexWeight { @@ -261,6 +263,7 @@ class NiHeader : public NiObject { void Put(fstream& file); }; + class NiObjectNET : public NiObject { public: uint skyrimShaderType; // BSLightingShaderProperty && User Version >= 12 @@ -327,6 +330,76 @@ class NiNode : public NiAVObject { int CalcBlockSize(); }; +// Fallout 4 trishape and trishape data for non-skinned meshes. uses half floats for vertices. +class BSTriShape : public NiAVObject{ +public: + + class TSVertData { + public: + Vector3 vert; // Stored half-float, convert! + float dotNormal; // maybe the dotproduct of the vert normal and the z axis? + Vector2 uv; // Stored as half-float, convert! + byte normalData[8]; // only if flags[6] & 0x1 is true? some kind of packed normal data ? + //uint normals[2]; + byte colorData[4]; // only if flags[6] & 0x2 is true + float weights[4]; // stored in half-float, convert! + byte weightBones[4]; + }; + + uint unkProps[4]; + uint skinInstanceRef; + uint shaderPropertyRef; + int unkRef; + + // flags for vert data look to be stored in here. byte 0 or byte 6 specifically look promising . + // using byte 6 currently, bit 3 indicating sub index data, bit 2 indicating the presence of color data. bit 1 indicating presence of normal data + byte vertFlags[8]; + uint numTris; + ushort numverts; + uint datasize; + uint vertRecSize; // size of vertex structure calculated with (datasize - (numtris*6)) / numverts; + + vector rawverts; // filled by GetRawVerts function and returned. + vector rawnorms; // filled by GetNormalData function and returned. + vector rawtangents; // filled by GetTangentData function and returned. + vector rawuvs; // filled by GetUVData function and returned. + + vector vertData; + vector triangles; + + BSTriShape(fstream& file, NiHeader& hdr, int blockindex); + virtual void Get(fstream& file); + virtual void Put(fstream& file); + virtual void notifyBlockDelete(int blockID); + virtual void notifyBlockSwap(int blockIndexLo, int blockIndexHi); + virtual int CalcBlockSize(); + + const vector* GetRawVerts(); + const vector* GetNormalData(); + const vector* GetTangentData(); + const vector* GetUVData(); + +}; + + +// Fallout 4 trishape and trishape data for skinned meshes. uses half floats for vertices. +class BSSubIndexTriShape : public BSTriShape { +public: + + + int szMysteryBlob; + char* MysteryBlob; + + //Blockindex is a temporary measure to enable us to see the total size of the block during loading ... not all fields are known yet + BSSubIndexTriShape(fstream& file, NiHeader& hdr, int blockindex); + virtual void Get(fstream& file); + virtual void Put(fstream& file); + virtual void notifyBlockDelete(int blockID); + virtual void notifyBlockSwap(int blockIndexLo, int blockIndexHi); + virtual int CalcBlockSize(); + +}; + class NiGeometry : public NiAVObject { public: int dataRef; @@ -793,6 +866,7 @@ class BSLightingShaderProperty : public NiShader { Vector3 emissiveColor; float emissiveMultiple; + uint wetMaterialNameRef; uint textureClampMode; float alpha; float refractionStrength; @@ -800,11 +874,14 @@ class BSLightingShaderProperty : public NiShader { Vector3 specularColor; float specularStrength; float lightingEffect1; - float lightingEffect2; + float lightingEffect2; // User version == 12, userversion2 < 130 + uint unk1; // user version == 12, userversion2 >= 130 + uint unk2; // user version == 12, userversion2 >= 130 + float environmentMapScale; - Vector3 skinTintColor; - Vector3 hairTintColor; + Vector3 skinTintColor; + Vector3 hairTintColor; float maxPasses; float scale; float parallaxInnerLayerThickness; @@ -812,9 +889,12 @@ class BSLightingShaderProperty : public NiShader { Vector2 parallaxInnerLayerTextureScale; float parallaxEnvmapStrength; Color4 sparkleParameters; - float eyeCubemapScale; - Vector3 eyeLeftReflectionCenter; - Vector3 eyeRightReflectionCenter; + float eyeCubemapScale; + Vector3 eyeLeftReflectionCenter; + Vector3 eyeRightReflectionCenter; + + float unk[8]; // unkown shader float params in shadertype 5 for fallout4 + byte pad[16]; // up to 16 bytes of uknown padding. clearly this isn't the right format. BSLightingShaderProperty(NiHeader& hdr); BSLightingShaderProperty(fstream& file, NiHeader& hdr); @@ -868,7 +948,7 @@ class BSEffectShaderProperty : public NiShader { Vector2 uvScale; NiString sourceTexture; uint textureClampMode; - float falloffStartAngle; + float falloffStartAngle; // userversion2 < 130 float falloffStopAngle; float falloffStartOpacity; float falloffStopOpacity; @@ -877,6 +957,13 @@ class BSEffectShaderProperty : public NiShader { float softFalloffDepth; NiString greyscaleTexture; + //userversion2 >= 130 + float unkdata[11]; + NiString emissiveTex; + NiString normalTex; + NiString specularTex; + float unkdata2[3]; + BSEffectShaderProperty(NiHeader& hdr); BSEffectShaderProperty(fstream& file, NiHeader& hdr); @@ -945,6 +1032,10 @@ class NiAlphaProperty : public NiProperty { ushort flags; byte threshold; + uint unkRef; + uint unk1; + uint unk2; + NiAlphaProperty(NiHeader& hdr); NiAlphaProperty(fstream& file, NiHeader& hdr); @@ -1096,8 +1187,11 @@ class NifFile int AddOrFindStringId(const string& str); NiTriBasedGeom* geomForName(const string& name, int dupIndex = 0); + BSTriShape* geomForNameF4(const string& name, int dupIndex = 0); + NiAVObject* avObjectForName(const string& name, int dupIndex = 0); NiShader* GetShader(const string& shapeName); + NiShader* GetShaderF4(const string& shapeName); bool IsShaderSkin(const string& shapeName); NiMaterialProperty* GetMaterialProperty(const string& shapeName); @@ -1109,6 +1203,7 @@ class NifFile void CopyShader(const string& shapeDest, int srcShaderRef, NifFile& srcNif, bool addAlpha, int propRef1, int propRef2); void CopyGeometry(const string& shapeDest, NifFile& srcNif, const string& srcShape); + int GetShapeType(const string& shapeName); int GetShapeList(vector& outList); void RenameShape(const string& oldName, const string& newName); void RenameDuplicateShape(const string& dupedShape); diff --git a/ObjFile.cpp b/ObjFile.cpp index 068e595d..27015dee 100644 --- a/ObjFile.cpp +++ b/ObjFile.cpp @@ -30,6 +30,79 @@ int ObjFile::AddGroup(const string& name, const vector& verts, const ve return 0; } +int ObjFile::LoadSimple(const string &inFn, const string& groupName){ + fstream base(inFn.c_str(), ios_base::in | ios_base::binary); + if (base.fail()) + return 1; + + ObjData* di = new ObjData(); + + string dump; + Vector3 v; + Vector2 uv; + Triangle t; + string curgrp; + string facept1; + string facept2; + string facept3; + string facept4; + size_t pos; + int ft[4]; + vector verts; + vector uvs; + vector tris; + bool readgroup = true; + + while (!base.eof()) { + base >> dump; + if (dump.compare("v") == 0) { + base >> v.x >> v.y >> v.z; + di->verts.push_back(v); + } + else if (dump.compare("g") == 0 || dump.compare("o") == 0) { + base >> curgrp; + + if (di->name != "") { + data[di->name] = di; + di = new ObjData; + } + + di->name = curgrp; + objGroups.push_back(curgrp); + + if (groupName.length() > 0) { + if (curgrp.compare(groupName) == 0) + readgroup = true; + else + readgroup = false; + } + } + else if (dump.compare("vt") == 0) { + base >> uv.u >> uv.v; + uv.v = 1.0f - uv.v; + di->uvs.push_back(uv); + } + else if (dump.compare("f") == 0) { + base >> facept1 >> facept2 >> facept3; + pos = facept1.find('/'); + t.p1 = atoi(facept1.c_str()) - 1; + ft[0] = atoi(facept1.substr(pos + 1).c_str()) - 1; + pos = facept2.find('/'); + t.p1 = atoi(facept2.c_str()) - 1; + ft[1] = atoi(facept2.substr(pos + 1).c_str()) - 1; + pos = facept3.find('/'); + t.p1 = atoi(facept3.c_str()) - 1; + ft[2] = atoi(facept3.substr(pos + 1).c_str()) - 1; + + di->tris.push_back(t); + } + + } + data[di->name] = di; + base.close(); + return 0; +} + int ObjFile::LoadForNif(const string &inFn, const string& groupName) { fstream base(inFn.c_str(), ios_base::in | ios_base::binary); if (base.fail()) diff --git a/ObjFile.h b/ObjFile.h index 5519ec0d..cd0537c9 100644 --- a/ObjFile.h +++ b/ObjFile.h @@ -43,6 +43,7 @@ class ObjFile { void SetScale(const Vector3& inScale) { scale = inScale; } void SetOffset(const Vector3& inOffset) { offset = inOffset; } + int LoadSimple(const string& inFn, const string& groupName = ""); int LoadForNif(const string& inFn, const string& groupName = ""); int LoadForNif(fstream& base, const string& groupName = ""); diff --git a/Object3d.cpp b/Object3d.cpp new file mode 100644 index 00000000..72dbe945 --- /dev/null +++ b/Object3d.cpp @@ -0,0 +1,46 @@ +#include "object3d.h" + +float h2float(const unsigned short in) { + float ret; + unsigned int t1; + unsigned int t2; + unsigned int t3; + + t1 = in & 0x7fff; + t2 = in & 0x8000; + t3 = in & 0x7c00; + + t1 <<= 13; + t2 <<= 16; + + t1 += 0x38000000; + t1 = (t3 == 0 ? 0 : t1); + t1 |= t2; + + *((unsigned int*)&ret) = t1; + + return ret; + +} + +unsigned short float2h(const float in) { + unsigned short ret; + + unsigned int c = *((unsigned int*)&in); + + unsigned int t1, t2, t3; + t1 = c & 0x7fffffff; + t2 = c & 0x80000000; + t3 = c & 0x7f800000; + + t1 >>= 13; + t2 >>= 16; + t1 -= 0x1c000; + + t1 = (t3 < 0x38800000 ? 0 : t1); + t1 = (t3 > 0x8e000000 ? 0x7bff : t1); + + t1 |= t2; + ret = t1; + return ret; +} diff --git a/Object3d.h b/Object3d.h index e563740b..20417fbb 100644 --- a/Object3d.h +++ b/Object3d.h @@ -28,6 +28,9 @@ typedef unsigned char byte; typedef unsigned short ushort; typedef unsigned int uint; +float h2float(const unsigned short in); +unsigned short float2h(const float in); + struct Vertex; struct Vector2 { diff --git a/OutfitProject.cpp b/OutfitProject.cpp index 7d1a6752..463a376f 100644 --- a/OutfitProject.cpp +++ b/OutfitProject.cpp @@ -670,9 +670,15 @@ void OutfitProject::SetSliderFromBSD(const string& sliderName, const string& sha bool OutfitProject::SetSliderFromOBJ(const string& sliderName, const string& shapeName, const string& fileName) { string target = ShapeToTarget(shapeName); - + int type= workNif.GetShapeType(shapeName); ObjFile obj; - obj.LoadForNif(fileName); + if (type == BSSUBINDEXTRISHAPE) { + obj.LoadSimple(fileName); + } + else { + obj.LoadForNif(fileName); + + } vector groupNames; obj.GetGroupList(groupNames); From b47f40cf75475c6cd830a3e4b2635924db2b1c9d Mon Sep 17 00:00:00 2001 From: ousnius Date: Tue, 17 Nov 2015 23:39:06 +0100 Subject: [PATCH 12/64] Return nullptr path --- NifFile.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/NifFile.cpp b/NifFile.cpp index 145c6ce3..922d7ebb 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -1667,6 +1667,7 @@ const vector* NifFile::GetRawVertsForShape(const string& shapeName) { BSTriShape* siTriShape = static_cast(blocks[dataRef]); return siTriShape->GetRawVerts(); } + return nullptr; } bool NifFile::GetTrisForShape(const string& shapeName, vector* outTris) { From 0e449b2a436e424e11f0cd3346892ec9c35c9c90 Mon Sep 17 00:00:00 2001 From: Caliente Date: Wed, 18 Nov 2015 03:24:56 -0500 Subject: [PATCH 13/64] --Additions to the settings dialog; improved UI, saving game paths for multiple games, and selecting which data files to scan during BSA scanning, plus defaults for these --Ba2 scanning speed performance improvement --- BodySlideApp.cpp | 127 ++++++++++++++++++++++++++++++++++++-- BodySlideApp.h | 3 + Config.xml | 32 +++++----- ConfigurationManager.h | 9 +++ FSBSA.cpp | 120 ++++++++++++++++++++++++++---------- FSBSA.h | 2 + res/BodyslideFrame.xrc | 134 +++++++++++++++++++++++++---------------- 7 files changed, 327 insertions(+), 100 deletions(-) diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index 14c67b0c..e0a5a42f 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -762,6 +762,16 @@ void BodySlideApp::SetDefaultConfig() { Config.SetDefaultValue("LogLevel", "3"); Config.SetDefaultValue("SelectedPreset", ""); Config.SetDefaultValue("SelectedOutfit", ""); + Config.SetDefaultValue("GameRegKey/Fallout3", "Software\\Bethesda Softworks\\Fallout3"); + Config.SetDefaultValue("GameRegVal/Fallout3", "Installed Path"); + Config.SetDefaultValue("GameRegKey/FalloutNewVegas", "Software\\Bethesda Softworks\\FalloutNV"); + Config.SetDefaultValue("GameRegVal/FalloutNewVegas", "Installed Path"); + Config.SetDefaultValue("GameRegKey/Skyrim", "Software\\Bethesda Softworks\\Skyrim"); + Config.SetDefaultValue("GameRegVal/Skyrim", "Installed Path"); + Config.SetDefaultValue("GameRegKey/Fallout4", "Software\\Bethesda Softworks\\Fallout4"); + Config.SetDefaultValue("GameRegVal/Fallout4", "Installed Path"); + Config.SetDefaultValue("GameRegKey/Skyrim", "Software\\Bethesda Softworks\\Skyrim"); + Config.SetDefaultValue("GameRegVal/Skyrim", "Installed Path"); wxString gameKey; wxString gameValueKey; @@ -838,6 +848,42 @@ void BodySlideApp::SetDefaultConfig() { wxLogMessage("Game data path in config: %s", Config["GameDataPath"]); } +wxString BodySlideApp::GetGameDataPath(TargetGame gameID) { + wxString dataPath; + wxString gamestr; + switch (gameID) { + case FO3: + gamestr = "Fallout3"; + break; + case FONV: + gamestr = "FalloutNewVegas"; + break; + case SKYRIM: + gamestr = "Skyrim"; + break; + case FO4: + gamestr = "Fallout4"; + break; + default: break; + } + wxString gkey = "GameRegKey/" + gamestr; + wxString gval = "GameRegVal/" + gamestr; + wxString cust = "GameDataPaths/" + gamestr; + + if (Config.Exists(cust.ToStdString()) && Config[cust.ToStdString()].length() > 0) { + dataPath = Config[cust.ToStdString()]; + } + else { + wxRegKey key(wxRegKey::HKLM, Config[gkey]); + if (key.Exists()) { + if (key.HasValues() && key.QueryValue(Config[gval], dataPath)) { + dataPath.Append("Data\\"); + } + } + } + return dataPath; +} + void BodySlideApp::LoadAllCategories() { wxLogMessage("Loading all slider categories..."); cCollection.LoadCategories("SliderCategories"); @@ -2315,7 +2361,8 @@ void BodySlideFrame::OnChooseTargetGame(wxCommandEvent& event) { wxChoice* choiceTargetGame = (wxChoice*)event.GetEventObject(); wxWindow* parent = choiceTargetGame->GetGrandParent(); wxChoice* choiceSkeletonRoot = XRCCTRL(*parent, "choiceSkeletonRoot", wxChoice); - switch (choiceTargetGame->GetSelection()) { + TargetGame targ = (TargetGame)choiceTargetGame->GetSelection(); + switch (targ) { case FO3: case FONV: choiceSkeletonRoot->SetStringSelection("Bip01"); @@ -2328,6 +2375,62 @@ void BodySlideFrame::OnChooseTargetGame(wxCommandEvent& event) { choiceSkeletonRoot->SetStringSelection("Root"); break; } + + wxCheckListBox* dataFileList = XRCCTRL(*parent, "DataFileList", wxCheckListBox); + wxString dataDir = app->GetGameDataPath(targ); + + wxDirPickerCtrl* dpGameDataPath = XRCCTRL(*parent, "dpGameDataPath", wxDirPickerCtrl); + dpGameDataPath->SetPath(dataDir); + + SettingsFillDataFiles(dataFileList, dataDir, targ); + +} + +void BodySlideFrame::SettingsFillDataFiles(wxCheckListBox* dataFileList, wxString& dataDir, int targetGame) { + dataFileList->Clear(); + + string cp = "GameDataFiles"; + + switch (targetGame) { + case FO3: + cp += "/Fallout3"; + break; + case FONV: + cp += "/FalloutNewVegas"; + break; + case SKYRIM: + cp += "/Skyrim"; + break; + case FO4: + cp += "/Fallout4"; + break; + + } + + wxString activatedFiles = Config.GetString(cp); + + + wxStringTokenizer tokenizer(activatedFiles, ";"); + std::map fsearch; + while (tokenizer.HasMoreTokens()) { + wxString val = tokenizer.GetNextToken().Trim(false); + val = val.Trim(); + std::transform(val.begin(), val.end(), val.begin(), ::tolower); + fsearch[val] = true; + } + + wxArrayString files; + wxDir::GetAllFiles(dataDir, &files, wxT("*.ba2"), wxDIR_FILES); + wxDir::GetAllFiles(dataDir, &files, wxT("*.bsa"), wxDIR_FILES); + for (auto& f : files) { + f = f.AfterLast('\\'); + dataFileList->Insert(f, dataFileList->GetCount()); + std::transform(f.begin(), f.end(), f.begin(), ::tolower); + if (fsearch.find(f) != fsearch.end()) { + dataFileList->Check(dataFileList->GetCount() - 1); + } + } + } void BodySlideFrame::OnSettings(wxCommandEvent& WXUNUSED(event)) { @@ -2354,17 +2457,33 @@ void BodySlideFrame::OnSettings(wxCommandEvent& WXUNUSED(event)) { wxChoice* choiceSkeletonRoot = XRCCTRL(*settings, "choiceSkeletonRoot", wxChoice); choiceSkeletonRoot->SetStringSelection(Config["Anim/SkeletonRootName"]); - + + wxCheckListBox* dataFileList = XRCCTRL(*settings, "DataFileList", wxCheckListBox); + SettingsFillDataFiles(dataFileList, gameDataPath, Config.GetIntValue("TargetGame")); + settings->Bind(wxEVT_CHOICE, &BodySlideFrame::OnChooseTargetGame, this); if (settings->ShowModal() == wxID_OK) { - Config.SetValue("TargetGame", choiceTargetGame->GetSelection()); - + TargetGame targ = (TargetGame)choiceTargetGame->GetSelection(); + Config.SetValue("TargetGame",targ); + wxString TargetGames[4] = { "Fallout3", "FalloutNewVegas", "Skyrim", "Fallout4" }; if (!dpGameDataPath->GetPath().IsEmpty()) { wxFileName gameDataDir = dpGameDataPath->GetDirName(); Config.SetValue("GameDataPath", gameDataDir.GetFullPath().ToStdString()); + Config.SetValue("GameDataPaths/" + TargetGames[targ].ToStdString(), gameDataDir.GetFullPath().ToStdString()); FSManager::del(); + } + wxArrayInt items; + wxString selectedfiles; + dataFileList->GetCheckedItems(items); + for (auto i : items) { + selectedfiles += dataFileList->GetString(i) + "; "; + } + selectedfiles = selectedfiles.BeforeLast(';'); + + Config.SetValue("GameDataFiles/" + TargetGames[targ].ToStdString(), selectedfiles.ToStdString()); + Config.SetValue("BSATextureScan", cbBSATextures->IsChecked() ? "true" : "false"); Config.SetValue("Input/LeftMousePan", cbLeftMousePan->IsChecked() ? "true" : "false"); diff --git a/BodySlideApp.h b/BodySlideApp.h index 7febf46f..9cb7e79d 100644 --- a/BodySlideApp.h +++ b/BodySlideApp.h @@ -41,6 +41,7 @@ along with this program. If not, see . #include #include #include +#include #include #include @@ -100,6 +101,7 @@ class BodySlideApp : public wxApp { int targetGame; void SetDefaultConfig(); + wxString GetGameDataPath(TargetGame gameID); void LoadData(); void CharHook(wxKeyEvent& event) { wxWindow* w = (wxWindow*)event.GetEventObject(); @@ -308,6 +310,7 @@ class BodySlideFrame : public wxFrame { void OnBatchBuildContext(wxMouseEvent& event); void OnBatchBuildSelect(wxCommandEvent& event); void OnOutfitStudio(wxCommandEvent& event); + void SettingsFillDataFiles(wxCheckListBox* dataFileList, wxString& dataDir, int targetGame); void OnSettings(wxCommandEvent& event); void OnChooseTargetGame(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); diff --git a/Config.xml b/Config.xml index c826d9a4..49f9f7d0 100644 --- a/Config.xml +++ b/Config.xml @@ -6,6 +6,16 @@ 3 true true + + + + Skyrim - Textures.bsa + Fallout4 - Textures1.ba2; Fallout4 - Textures2.ba2; Fallout4 - Textures3.ba2; Fallout4 - Textures4.ba2; Fallout4 - Textures5.ba2; Fallout4 - Textures6.ba2; Fallout4 - Textures7.ba2; Fallout4 - Textures8.ba2; Fallout4 - Textures9.ba2 + + + + + 3 CBBE Body CBBE @@ -13,8 +23,7 @@ This information is used by BodySlide for choosing what presets to display for outfits. If the attribute "includeInBuild" is true, batch building the specified groups will also build unassigned outfits. --> - CBBE - + CBBE @@ -22,31 +31,26 @@ 0 100 - false - + false - Object - + Object 80 55 45 - 45 - + 45 - - + res\skeleton_fo4.nif - Root - + Root - - + + diff --git a/ConfigurationManager.h b/ConfigurationManager.h index 22305941..d365dc9f 100644 --- a/ConfigurationManager.h +++ b/ConfigurationManager.h @@ -10,6 +10,7 @@ See the included LICENSE file #include #include +#include using namespace std; using namespace tinyxml2; @@ -108,9 +109,17 @@ class ConfigurationManager int GetValueArray(const string& containerName, const string& arrayName, vector& outValues); int GetValueAttributeArray(const string& containerName, const string& arrayName, const string& attributeName, vector& outValues); + string operator [] (const char* inName) + { + return GetString(string(inName)); + } + string operator [] (const string& inName) { return GetString(inName); } + wxString operator [] (const wxString& inName) { + return GetString(inName.ToStdString()); + } }; extern ConfigurationManager Config; diff --git a/FSBSA.cpp b/FSBSA.cpp index 8d2a9b70..0d87f497 100644 --- a/FSBSA.cpp +++ b/FSBSA.cpp @@ -188,47 +188,69 @@ bool BSA::open() { numFiles = header.numFiles; namePrefix = false; - std::vector filepaths; + char* superbuffer = new char[numFiles * (MAX_PATH + 2) + 1]; + std::vector path_sizes (numFiles*2); + if (bsa.Seek(header.nameTableOffset)) { + bsa.Read(superbuffer, numFiles*(MAX_PATH + 2)); + size_t cursor=0; + size_t n = 0; for (wxUint32 i = 0; i < header.numFiles; i++) { - wxUint16 length; - bsa.Read((char*)&length, 2); + if (cursor > numFiles*(MAX_PATH + 2) + 1) { + __debugbreak(); + } + unsigned short len; + len = *(unsigned short*)&superbuffer[cursor]; + cursor += 2; + path_sizes[n++] = cursor; + cursor += len; + path_sizes[n++] = cursor; + + //wxUint16 length; + //bsa.Read((char*)&length, 2); - wxMemoryBuffer strdata(length); - bsa.Read(strdata.GetData(), length); + //wxMemoryBuffer strdata(length); + //bsa.Read(strdata.GetData(), length); - std::string filepath(strdata, strdata.GetBufSize()); - filepaths.push_back(filepath); + //std::string filepath(strdata, strdata.GetBufSize()); + //filepaths.push_back(filepath); } } - + std::replace(superbuffer, superbuffer + numFiles*(MAX_PATH + 2), '\\', '/'); std::string h(header.type, 4); if (h == "GNRL") { // General BA2 Format if (bsa.Seek(sizeof(header) + 8)) { + F4GeneralInfo* finfo = new F4GeneralInfo[header.numFiles]; + bsa.Read(finfo, 36 * numFiles); + size_t n = 0; for (wxUint32 i = 0; i < header.numFiles; i++) { - F4GeneralInfo finfo; - bsa.Read((char*)&finfo, 36); + //F4GeneralInfo finfo; + //bsa.Read((char*)&finfo, 36); + insertFile(superbuffer + path_sizes[n], path_sizes[n + 1]-path_sizes[n], finfo[i].packedSize, finfo[i].unpackedSize, finfo[i].offset); + n += 2; - std::string fullpath = filepaths[i]; - std::replace(fullpath.begin(), fullpath.end(), '\\', '/'); + //std::string fullpath = filepaths[i]; + //std::replace(fullpath.begin(), fullpath.end(), '\\', '/'); - std::string folderName; - int p = fullpath.find_last_of('/'); - if (p >= 0) - folderName = fullpath.substr(0, p); + //std::string folderName; + ///int p = fullpath.find_last_of('/'); + //if (p >= 0) + // folderName = fullpath.substr(0, p); - std::string filename = fullpath.substr(p + 1); + //std::string filename = fullpath.substr(p + 1); - BSAFolder *folder = insertFolder(folderName); - insertFile(folder, filename, finfo.packedSize, finfo.unpackedSize, finfo.offset); + //BSAFolder *folder = insertFolder(folderName); + //insertFile(folder, filename, finfo.packedSize, finfo.unpackedSize, finfo.offset); } + delete[]finfo; } } else if (h == "DX10") { // Texture BA2 Format if (bsa.Seek(sizeof(header) + 8)) { + size_t n = 0; for (wxUint32 i = 0; i < header.numFiles; i++) { F4Tex tex; bsa.Read((char*)&tex.header, 24); @@ -242,23 +264,13 @@ bool BSA::open() { tex.chunks = texChunks; - std::string fullpath = filepaths[i]; - std::replace(fullpath.begin(), fullpath.end(), '\\', '/'); - - std::string folderName; - int p = fullpath.find_last_of('/'); - if (p >= 0) - folderName = fullpath.substr(0, p); - - std::string filename = fullpath.substr(p + 1); - - BSAFolder *folder = insertFolder(folderName); F4TexChunk chunk = tex.chunks[0]; - insertFile(folder, filename, chunk.packedSize, chunk.unpackedSize, chunk.offset, tex); + insertFile(superbuffer + path_sizes[n], path_sizes[n + 1]- path_sizes[n], chunk.packedSize, chunk.unpackedSize, chunk.offset, &tex); } } } + delete[]superbuffer; } // From NifSkope else if (magic == OB_BSAHEADER_FILEID) { @@ -651,6 +663,27 @@ BSA::BSAFolder *BSA::insertFolder(std::string name) { return folder; } +BSA::BSAFolder* BSA::insertFolder( char* folder, int szFn) { + auto loc = folders.find(std::string(folder, folder + szFn - 1)); + if (loc != folders.end()) { + return loc->second; + } + + BSAFolder* fldr = new BSAFolder(); + folders[std::string(folder, folder + szFn)] = fldr; + + for (int p = szFn - 1; p >= 0; p--) { + if (folder[p] == '/') { + fldr->parent = insertFolder(folder, p); + fldr->parent->children[std::string(folder + p + 1,szFn-p-1)] = fldr; + return fldr; + } + } + fldr->parent = &root; + root.children[std::string(folder, folder + szFn)] = fldr; + return fldr; +} + BSA::BSAFile *BSA::insertFile(BSAFolder *folder, std::string name, wxUint32 sizeFlags, wxUint32 offset) { std::transform(name.begin(), name.end(), name.begin(), ::tolower); @@ -675,6 +708,31 @@ BSA::BSAFile *BSA::insertFile(BSAFolder *folder, std::string name, wxUint32 pack return file; } +BSA::BSAFile* BSA::insertFile(char* filename, int szFn, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, F4Tex* dds) { + std::transform(filename, filename+szFn-1, filename, ::tolower); + //int p; + //for (p = szFn - 1; p >= 0; p--) { + // if (filename[p] == '/') + // break; + //} + //BSAFolder* folder; + //if (p > -1) + // folder = insertFolder(filename, p); + //else + // folder = &root; + + BSAFile *file = new BSAFile; + if (dds) { + file->tex = *dds; + } + file->packedLength = packed; + file->unpackedLength = unpacked; + file->offset = offset; + //folder->files[name] = file; + root.files.emplace(std::string(filename, filename + szFn), file); + return nullptr; +} + const BSA::BSAFolder *BSA::getFolder(std::string fn) const { std::transform(fn.begin(), fn.end(), fn.begin(), ::tolower); diff --git a/FSBSA.h b/FSBSA.h index 1e6e109a..a45cde7a 100644 --- a/FSBSA.h +++ b/FSBSA.h @@ -268,9 +268,11 @@ class BSA final : public FSArchiveFile { //! Recursive function to generate the tree structure of folders inside a %BSA BSAFolder *insertFolder(std::string name); + BSAFolder *insertFolder( char* folder, int szFn); //! Inserts a file into the structure of a %BSA BSAFile *insertFile(BSAFolder *folder, std::string name, wxUint32 sizeFlags, wxUint32 offset); BSAFile *insertFile(BSAFolder *folder, std::string name, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, F4Tex dds = F4Tex()); + BSAFile *insertFile(char* filename, int szFn, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, F4Tex* dds = nullptr); //! Gets the specified folder, or the root folder if not found const BSAFolder *getFolder(std::string fn) const; diff --git a/res/BodyslideFrame.xrc b/res/BodyslideFrame.xrc index fdd84bf4..27eea393 100644 --- a/res/BodyslideFrame.xrc +++ b/res/BodyslideFrame.xrc @@ -735,8 +735,8 @@ - - + + 475,400 Settings 1 @@ -756,10 +756,11 @@ wxHORIZONTAL - + wxALIGN_CENTER_VERTICAL|wxALL 5 + 100,-1 -1 @@ -788,10 +789,11 @@ wxHORIZONTAL - + wxALIGN_CENTER_VERTICAL|wxALL 5 + 100,-1 -1 @@ -801,7 +803,7 @@ wxALIGN_CENTER_VERTICAL|wxALL 5 - + ,90,90,-1,70,0 Select the data path of the game... Data path to load textures from and build to. @@ -812,62 +814,90 @@ - - wxALL|wxEXPAND + + wxEXPAND 5 - - wxVERTICAL - + + wxHORIZONTAL wxALL|wxEXPAND - 5 - - wxHORIZONTAL + 2 + + 160,-1 + wxVERTICAL + - - wxALIGN_CENTER_VERTICAL|wxALL - 5 - - - -1 + + wxALL|wxEXPAND + 2 + + wxHORIZONTAL + + + wxALIGN_CENTER_VERTICAL|wxALIGN_TOP|wxALL|wxBOTTOM + 5 + + 100,-1 + + -1 + + + + + wxALIGN_CENTER_VERTICAL|wxALIGN_TOP|wxALL + 5 + + Enables/disables scanning BSAs in the game data folder for textures to load. + + 1 + + - - wxALIGN_CENTER_VERTICAL|wxALL - 5 - - Enables/disables scanning BSAs in the game data folder for textures to load. - - 1 + + wxALL|wxEXPAND + 2 + + wxHORIZONTAL + + + wxALIGN_CENTER_VERTICAL|wxALL + 5 + + 100,-1 + + -1 + + + + + wxALIGN_CENTER_VERTICAL|wxALL + 5 + + Enables/disables panning the camera with the left mouse button. + + 0 + + - + wxALL|wxEXPAND - 5 - - wxHORIZONTAL + 2 + + wxVERTICAL + - wxALIGN_CENTER_VERTICAL|wxALL + wxALL|wxEXPAND 5 - - - -1 - - - - - wxALIGN_CENTER_VERTICAL|wxALL - 5 - - Enables/disables panning the camera with the left mouse button. - - 0 + + @@ -888,10 +918,11 @@ wxHORIZONTAL - + wxALIGN_CENTER_VERTICAL|wxALL 5 + 100,-1 -1 @@ -901,7 +932,7 @@ wxALIGN_CENTER_VERTICAL|wxALL 5 - + ,90,90,-1,70,0 Select a reference skeleton .nif file... *.nif @@ -917,10 +948,11 @@ wxHORIZONTAL - + wxALIGN_CENTER_VERTICAL|wxALL 5 + 100,-1 -1 @@ -944,14 +976,14 @@ - - wxALL|wxEXPAND + + wxEXPAND 5 - 0,0 + 0,20 - wxALL|wxEXPAND + wxALIGN_BOTTOM|wxALL|wxEXPAND 5 From 159944a654aac0a556a8b3f7c309d3e3eab35c25 Mon Sep 17 00:00:00 2001 From: ousnius Date: Wed, 18 Nov 2015 17:40:37 +0100 Subject: [PATCH 14/64] Config clean-up, pre-FO4 NIF fix --- BodySlideApp.cpp | 66 ++++++++++++++++++++++++------------------------ Config.xml | 14 ++++------ FSBSA.cpp | 2 +- NifFile.cpp | 4 +-- 4 files changed, 41 insertions(+), 45 deletions(-) diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index e0a5a42f..d124c48b 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -762,16 +762,15 @@ void BodySlideApp::SetDefaultConfig() { Config.SetDefaultValue("LogLevel", "3"); Config.SetDefaultValue("SelectedPreset", ""); Config.SetDefaultValue("SelectedOutfit", ""); - Config.SetDefaultValue("GameRegKey/Fallout3", "Software\\Bethesda Softworks\\Fallout3"); - Config.SetDefaultValue("GameRegVal/Fallout3", "Installed Path"); - Config.SetDefaultValue("GameRegKey/FalloutNewVegas", "Software\\Bethesda Softworks\\FalloutNV"); - Config.SetDefaultValue("GameRegVal/FalloutNewVegas", "Installed Path"); - Config.SetDefaultValue("GameRegKey/Skyrim", "Software\\Bethesda Softworks\\Skyrim"); - Config.SetDefaultValue("GameRegVal/Skyrim", "Installed Path"); - Config.SetDefaultValue("GameRegKey/Fallout4", "Software\\Bethesda Softworks\\Fallout4"); - Config.SetDefaultValue("GameRegVal/Fallout4", "Installed Path"); - Config.SetDefaultValue("GameRegKey/Skyrim", "Software\\Bethesda Softworks\\Skyrim"); - Config.SetDefaultValue("GameRegVal/Skyrim", "Installed Path"); + + Config.SetDefaultValue("GameRegKey/Fallout3", "Software\\Bethesda Softworks\\Fallout3"); + Config.SetDefaultValue("GameRegVal/Fallout3", "Installed Path"); + Config.SetDefaultValue("GameRegKey/FalloutNewVegas", "Software\\Bethesda Softworks\\FalloutNV"); + Config.SetDefaultValue("GameRegVal/FalloutNewVegas", "Installed Path"); + Config.SetDefaultValue("GameRegKey/Skyrim", "Software\\Bethesda Softworks\\Skyrim"); + Config.SetDefaultValue("GameRegVal/Skyrim", "Installed Path"); + Config.SetDefaultValue("GameRegKey/Fallout4", "Software\\Bethesda Softworks\\Fallout4"); + Config.SetDefaultValue("GameRegVal/Fallout4", "Installed Path"); wxString gameKey; wxString gameValueKey; @@ -779,26 +778,26 @@ void BodySlideApp::SetDefaultConfig() { case FO3: Config.SetDefaultValue("Anim/DefaultSkeletonReference", "res\\skeleton_female_fo3nv.nif"); Config.SetDefaultValue("Anim/SkeletonRootName", "Bip"); - gameKey = "SOFTWARE\\Bethesda Softworks\\Fallout3"; - gameValueKey = "Installed Path"; + gameKey = Config["GameRegKey/Fallout3"]; + gameValueKey = Config["GameRegVal/Fallout3"]; break; case FONV: Config.SetDefaultValue("Anim/DefaultSkeletonReference", "res\\skeleton_female_fo3nv.nif"); Config.SetDefaultValue("Anim/SkeletonRootName", "Bip"); - gameKey = "SOFTWARE\\Bethesda Softworks\\FalloutNV"; - gameValueKey = "Installed Path"; + gameKey = Config["GameRegKey/FalloutNewVegas"]; + gameValueKey = Config["GameRegVal/FalloutNewVegas"]; break; case SKYRIM: Config.SetDefaultValue("Anim/DefaultSkeletonReference", "res\\skeleton_female_xpmse.nif"); Config.SetDefaultValue("Anim/SkeletonRootName", "NPC"); - gameKey = "SOFTWARE\\Bethesda Softworks\\Skyrim"; - gameValueKey = "Installed Path"; + gameKey = Config["GameRegKey/Skyrim"]; + gameValueKey = Config["GameRegVal/Skyrim"]; break; case FO4: Config.SetDefaultValue("Anim/DefaultSkeletonReference", "res\\skeleton_fo4.nif"); Config.SetDefaultValue("Anim/SkeletonRootName", "Root"); - gameKey = "SOFTWARE\\Bethesda Softworks\\Fallout4"; - gameValueKey = "Installed Path"; + gameKey = Config["GameRegKey/Fallout4"]; + gameValueKey = Config["GameRegVal/Fallout4"]; break; default: Config.SetDefaultValue("Anim/DefaultSkeletonReference", "res\\skeleton_female.nif"); @@ -823,7 +822,7 @@ void BodySlideApp::SetDefaultConfig() { Config.SetDefaultValue("OutfitStudioFrame.x", 100); Config.SetDefaultValue("OutfitStudioFrame.y", 100); - if (!Config.Exists("GameDataPath")) { + if (Config["GameDataPath"].empty()) { wxRegKey key(wxRegKey::HKLM, gameKey); if (key.Exists()) { wxString installPath; @@ -870,8 +869,8 @@ wxString BodySlideApp::GetGameDataPath(TargetGame gameID) { wxString gval = "GameRegVal/" + gamestr; wxString cust = "GameDataPaths/" + gamestr; - if (Config.Exists(cust.ToStdString()) && Config[cust.ToStdString()].length() > 0) { - dataPath = Config[cust.ToStdString()]; + if (!Config[cust].IsEmpty()) { + dataPath = Config[cust]; } else { wxRegKey key(wxRegKey::HKLM, Config[gkey]); @@ -1099,7 +1098,7 @@ int BodySlideApp::BuildBodies(bool localPath, bool clean, bool tri) { outFileNameSmall = outFileNameBig = activeSet.GetOutputFile(); } else { - if (!Config.Exists("GameDataPath")) { + if (Config["GameDataPath"].empty()) { if (Config["WarnMissingGamePath"] == "true") { int ret = wxMessageBox("WARNING: Game data path not configured. Would you like to show BodySlide where it is?", "Game not found", wxYES_NO | wxCANCEL | wxICON_EXCLAMATION); if (ret != wxYES) { @@ -1314,7 +1313,7 @@ int BodySlideApp::BuildListBodies(const vector& outfitList, mapClear(); - string cp = "GameDataFiles"; + wxString cp = "GameDataFiles"; switch (targetGame) { case FO3: @@ -2404,14 +2403,12 @@ void BodySlideFrame::SettingsFillDataFiles(wxCheckListBox* dataFileList, wxStrin case FO4: cp += "/Fallout4"; break; - } - wxString activatedFiles = Config.GetString(cp); - + wxString activatedFiles = Config[cp]; wxStringTokenizer tokenizer(activatedFiles, ";"); - std::map fsearch; + map fsearch; while (tokenizer.HasMoreTokens()) { wxString val = tokenizer.GetNextToken().Trim(false); val = val.Trim(); @@ -2420,8 +2417,8 @@ void BodySlideFrame::SettingsFillDataFiles(wxCheckListBox* dataFileList, wxStrin } wxArrayString files; - wxDir::GetAllFiles(dataDir, &files, wxT("*.ba2"), wxDIR_FILES); - wxDir::GetAllFiles(dataDir, &files, wxT("*.bsa"), wxDIR_FILES); + wxDir::GetAllFiles(dataDir, &files, "*.ba2", wxDIR_FILES); + wxDir::GetAllFiles(dataDir, &files, "*.bsa", wxDIR_FILES); for (auto& f : files) { f = f.AfterLast('\\'); dataFileList->Insert(f, dataFileList->GetCount()); @@ -2430,7 +2427,6 @@ void BodySlideFrame::SettingsFillDataFiles(wxCheckListBox* dataFileList, wxStrin dataFileList->Check(dataFileList->GetCount() - 1); } } - } void BodySlideFrame::OnSettings(wxCommandEvent& WXUNUSED(event)) { @@ -2469,11 +2465,15 @@ void BodySlideFrame::OnSettings(wxCommandEvent& WXUNUSED(event)) { wxString TargetGames[4] = { "Fallout3", "FalloutNewVegas", "Skyrim", "Fallout4" }; if (!dpGameDataPath->GetPath().IsEmpty()) { wxFileName gameDataDir = dpGameDataPath->GetDirName(); - Config.SetValue("GameDataPath", gameDataDir.GetFullPath().ToStdString()); + + wxString currentPath = app->GetGameDataPath(targ); + if (currentPath != dpGameDataPath->GetPath()) + Config.SetValue("GameDataPath", gameDataDir.GetFullPath().ToStdString()); + Config.SetValue("GameDataPaths/" + TargetGames[targ].ToStdString(), gameDataDir.GetFullPath().ToStdString()); FSManager::del(); - } + wxArrayInt items; wxString selectedfiles; dataFileList->GetCheckedItems(items); diff --git a/Config.xml b/Config.xml index 49f9f7d0..7207e35e 100644 --- a/Config.xml +++ b/Config.xml @@ -1,14 +1,10 @@ - - - 3 true true - - + Fallout - Textures.bsa + Fallout - Textures.bsa; Fallout - Textures2.bsa Skyrim - Textures.bsa Fallout4 - Textures1.ba2; Fallout4 - Textures2.ba2; Fallout4 - Textures3.ba2; Fallout4 - Textures4.ba2; Fallout4 - Textures5.ba2; Fallout4 - Textures6.ba2; Fallout4 - Textures7.ba2; Fallout4 - Textures8.ba2; Fallout4 - Textures9.ba2 @@ -16,6 +12,9 @@ + + + 3 CBBE Body CBBE @@ -48,9 +47,6 @@ res\skeleton_fo4.nif Root - - - diff --git a/FSBSA.cpp b/FSBSA.cpp index 0d87f497..6180e1ad 100644 --- a/FSBSA.cpp +++ b/FSBSA.cpp @@ -37,7 +37,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#pragma warning (disable : 4389) +#pragma warning (disable : 4389 4018) wxUint32 BSA::BSAFile::size() const { diff --git a/NifFile.cpp b/NifFile.cpp index 922d7ebb..5f05f663 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -1676,12 +1676,12 @@ bool NifFile::GetTrisForShape(const string& shapeName, vector* outTris if (dataID == -1) return false; - if (bType == NITRISHAPE) { + if (bType == NITRISHAPEDATA) { NiTriShapeData* shapeData = static_cast(blocks[dataID]); *outTris = shapeData->triangles; return true; } - else if (bType == NITRISTRIPS) { + else if (bType == NITRISTRIPSDATA) { NiTriStripsData* stripsData = static_cast(blocks[dataID]); stripsData->StripsToTris(outTris); return true; From 2b5b4f1c9a9a1e4d856e2c3a81cd9912e380770d Mon Sep 17 00:00:00 2001 From: Caliente Date: Fri, 20 Nov 2015 16:40:29 -0500 Subject: [PATCH 15/64] - game support settings fixes - Texture loading support from ba2s - Fo4 skinning data support - bugfixes --- Anim.cpp | 17 ++- Anim.h | 24 +++++ BodySlideApp.cpp | 17 ++- Config.xml | 20 ++-- FSBSA.cpp | 12 ++- NifBlock.cpp | 233 +++++++++++++++++++++++++++++++++++++++-- NifFile.cpp | 255 ++++++++++++++++++++++++++++++++++++++------- NifFile.h | 84 ++++++++++++++- OutfitStudio.cpp | 31 +++--- ResourceLoader.cpp | 53 +++++++++- ResourceLoader.h | 4 + 11 files changed, 661 insertions(+), 89 deletions(-) diff --git a/Anim.cpp b/Anim.cpp index f62973e3..8a161b85 100644 --- a/Anim.cpp +++ b/Anim.cpp @@ -224,6 +224,9 @@ void AnimInfo::WriteToNif(NifFile* nif, bool synchBoneIDs, const string& shapeEx SkinTransform xForm; for (auto &shapeBoneList : shapeBones) { + int stype = nif->GetShapeType(shapeBoneList.first); + bool bIsFo4 = (stype == BSTRISHAPE || stype == BSSUBINDEXTRISHAPE); + unordered_map vertWeights; for (auto &boneName : shapeBoneList.second) { if (!AnimSkeleton::getInstance().GetBoneTransform(boneName, xForm)) continue; @@ -232,9 +235,21 @@ void AnimInfo::WriteToNif(NifFile* nif, bool synchBoneIDs, const string& shapeEx int bid = GetShapeBoneIndex(shapeBoneList.first, boneName); AnimWeight& bw = shapeSkinning[shapeBoneList.first].boneWeights[bid]; + if (bIsFo4) { + for (auto vw : bw.weights) { + vertWeights[vw.first].Add(bid, vw.second); + } + } if (AnimSkeleton::getInstance().GetSkinTransform(boneName, xForm)) { nif->SetShapeBoneTransform(shapeBoneList.first, bid, xForm, bw.bSphereOffset, bw.bSphereRadius); - nif->SetShapeBoneWeights(shapeBoneList.first, bid, bw.weights); + if (!bIsFo4) { + nif->SetShapeBoneWeights(shapeBoneList.first, bid, bw.weights); + } + } + } + if (bIsFo4) { + for (auto vid : vertWeights) { + nif->SetShapeVertWeights(shapeBoneList.first, vid.first, vid.second.boneIds, vid.second.weights); } } } diff --git a/Anim.h b/Anim.h index 77c61b22..e860f7e4 100644 --- a/Anim.h +++ b/Anim.h @@ -15,6 +15,30 @@ See the included LICENSE file using namespace std; +struct vertexBoneWeights { + vector boneIds; + vector weights; + + vertexBoneWeights () { + } + + void Add (int inboneid, float inweight) { + if (inweight == 0) return; + + for (int i; i < weights.size(); ++i) { + if (inweight < weights[i]) + continue; + weights.insert(weights.begin() + i, inweight); + boneIds.insert(boneIds.begin() + i, inboneid); + return; + } + weights.push_back(inweight); + boneIds.push_back(inboneid); + + + } +}; + class AnimBone { public: string boneName; // bone names are node names in the nif file diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index d124c48b..526f6ac1 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -73,7 +73,7 @@ bool BodySlideApp::OnInit() { Config.LoadConfig(); logger.Initialize(); - wxHandleFatalExceptions(); + //wxHandleFatalExceptions(); wxLogMessage("Initializing BodySlide..."); wxInitAllImageHandlers(); @@ -2423,7 +2423,7 @@ void BodySlideFrame::SettingsFillDataFiles(wxCheckListBox* dataFileList, wxStrin f = f.AfterLast('\\'); dataFileList->Insert(f, dataFileList->GetCount()); std::transform(f.begin(), f.end(), f.begin(), ::tolower); - if (fsearch.find(f) != fsearch.end()) { + if (fsearch.find(f) == fsearch.end()) { dataFileList->Check(dataFileList->GetCount() - 1); } } @@ -2465,20 +2465,17 @@ void BodySlideFrame::OnSettings(wxCommandEvent& WXUNUSED(event)) { wxString TargetGames[4] = { "Fallout3", "FalloutNewVegas", "Skyrim", "Fallout4" }; if (!dpGameDataPath->GetPath().IsEmpty()) { wxFileName gameDataDir = dpGameDataPath->GetDirName(); - - wxString currentPath = app->GetGameDataPath(targ); - if (currentPath != dpGameDataPath->GetPath()) - Config.SetValue("GameDataPath", gameDataDir.GetFullPath().ToStdString()); - + Config.SetValue("GameDataPath", gameDataDir.GetFullPath().ToStdString()); Config.SetValue("GameDataPaths/" + TargetGames[targ].ToStdString(), gameDataDir.GetFullPath().ToStdString()); FSManager::del(); } wxArrayInt items; wxString selectedfiles; - dataFileList->GetCheckedItems(items); - for (auto i : items) { - selectedfiles += dataFileList->GetString(i) + "; "; + for (int i = 0; i < dataFileList->GetCount(); i++) { + if (!dataFileList->IsChecked(i)) { + selectedfiles += dataFileList->GetString(i) + "; "; + } } selectedfiles = selectedfiles.BeforeLast(';'); diff --git a/Config.xml b/Config.xml index 7207e35e..1e7c6e2d 100644 --- a/Config.xml +++ b/Config.xml @@ -1,20 +1,21 @@ - 3 + + + + 2 true true - Fallout - Textures.bsa - Fallout - Textures.bsa; Fallout - Textures2.bsa - Skyrim - Textures.bsa - Fallout4 - Textures1.ba2; Fallout4 - Textures2.ba2; Fallout4 - Textures3.ba2; Fallout4 - Textures4.ba2; Fallout4 - Textures5.ba2; Fallout4 - Textures6.ba2; Fallout4 - Textures7.ba2; Fallout4 - Textures8.ba2; Fallout4 - Textures9.ba2 + + + Skyrim - Animations.bsa; Skyrim - Interface.bsa; Skyrim - Meshes.bsa; Skyrim - Misc.bsa; Skyrim - Shaders.bsa; Skyrim - Sounds.bsa; Skyrim - Voices.bsa; Skyrim - VoicesExtra.bsa; + Fallout4 - Animations.ba2; Fallout4 - Interface.ba2; Fallout4 - Materials.ba2; Fallout4 - Meshes.ba2; Fallout4 - MeshesExtra.ba2; Fallout4 - Misc.ba2; Fallout4 - Shaders.ba2; Fallout4 - Sounds.ba2; Fallout4 - Startup.ba2; Fallout4 - Voices.ba2 - - - 3 CBBE Body CBBE @@ -46,7 +47,8 @@ res\skeleton_fo4.nif - Root + NPC + diff --git a/FSBSA.cpp b/FSBSA.cpp index 6180e1ad..4891f0e3 100644 --- a/FSBSA.cpp +++ b/FSBSA.cpp @@ -266,7 +266,8 @@ bool BSA::open() { F4TexChunk chunk = tex.chunks[0]; - insertFile(superbuffer + path_sizes[n], path_sizes[n + 1]- path_sizes[n], chunk.packedSize, chunk.unpackedSize, chunk.offset, &tex); + insertFile(superbuffer + path_sizes[n], path_sizes[n + 1] - path_sizes[n], chunk.packedSize, chunk.unpackedSize, chunk.offset, &tex); + n += 2; } } } @@ -664,7 +665,7 @@ BSA::BSAFolder *BSA::insertFolder(std::string name) { } BSA::BSAFolder* BSA::insertFolder( char* folder, int szFn) { - auto loc = folders.find(std::string(folder, folder + szFn - 1)); + auto loc = folders.find(std::string(folder, folder + szFn)); if (loc != folders.end()) { return loc->second; } @@ -709,7 +710,7 @@ BSA::BSAFile *BSA::insertFile(BSAFolder *folder, std::string name, wxUint32 pack } BSA::BSAFile* BSA::insertFile(char* filename, int szFn, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, F4Tex* dds) { - std::transform(filename, filename+szFn-1, filename, ::tolower); + std::transform(filename, filename+szFn, filename, ::tolower); //int p; //for (p = szFn - 1; p >= 0; p--) { // if (filename[p] == '/') @@ -754,6 +755,11 @@ const BSA::BSAFolder *BSA::getFolder(std::string fn) const { const BSA::BSAFile *BSA::getFile(std::string fn) const { std::transform(fn.begin(), fn.end(), fn.begin(), ::tolower); + auto earlyfile = root.files.find(fn); + if (earlyfile != root.files.end()) { + return earlyfile->second; + } + std::string folderName; int p = fn.find_last_of('/'); if (p >= 0) { diff --git a/NifBlock.cpp b/NifBlock.cpp index b66c881c..536a8861 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -853,27 +853,91 @@ BSTriShape(file, hdr, blockindex) } void BSSubIndexTriShape::Get(fstream& file) { - vertRecSize = (datasize - (numTris * 6)) / numverts; - szMysteryBlob = blockSize - (vertRecSize * numverts + 6 * numTris + 118); - /// LETS LEAK SOME MEMORY! temporary until we figure out the hunk of data at the end of this block - MysteryBlob = new char[szMysteryBlob]; - file.read((char*)MysteryBlob, szMysteryBlob); + + file.read((char*)&numtris2, 4); + file.read((char*)&numSubIndexRecordA, 4); + file.read((char*)&numSubIndexRecordB, 4); + + subIndexRecordsA.resize(numSubIndexRecordB * 4); + for (int i = 0; i < numSubIndexRecordB * 4; i++) { + file.read((char*)&subIndexRecordsA[i], 4); + } + + if (numSubIndexRecordB > numSubIndexRecordA) { + file.read((char*)&numSubIndexRecordA_2, 4); + file.read((char*)&numSubIndexRecordB_2, 4); + + sequence.resize(numSubIndexRecordA); + for (int i = 0; i < numSubIndexRecordA; i++) { + file.read((char*)&sequence[i], 4); + } + + subIndexRecordsB.resize(numSubIndexRecordB); + for (int i = 0; i < numSubIndexRecordB; i++) { + file.read((char*)&subIndexRecordsB[i].unk1, 4); + file.read((char*)&subIndexRecordsB[i].unk2, 4); + file.read((char*)&subIndexRecordsB[i].numExtra, 4); + subIndexRecordsB[i].extraData.resize(subIndexRecordsB[i].numExtra); + for (int j = 0; j < subIndexRecordsB[i].numExtra; j++) { + file.read((char*)&subIndexRecordsB[i].extraData[j], 4); + } + + } + + ssfFile.Get(file, 2); + } + } void BSSubIndexTriShape::Put(fstream& file) { BSTriShape::Put(file); - file.write((char*)MysteryBlob, szMysteryBlob); + file.write((char*)&numtris2, 4); + file.write((char*)&numSubIndexRecordA, 4); + file.write((char*)&numSubIndexRecordB, 4); + + for (int i = 0; i < numSubIndexRecordB * 4; i++) { + file.write((char*)&subIndexRecordsA[i], 4); + } + if (numSubIndexRecordB > numSubIndexRecordA) { + file.write((char*)&numSubIndexRecordA_2, 4); + file.write((char*)&numSubIndexRecordB_2, 4); + for (int i = 0; i < numSubIndexRecordA; i++) { + file.write((char*)&sequence[i], 4); + } + + for (int i = 0; i < numSubIndexRecordB; i++) { + file.write((char*)&subIndexRecordsB[i].unk1, 4); + file.write((char*)&subIndexRecordsB[i].unk2, 4); + file.write((char*)&subIndexRecordsB[i].numExtra, 4); + + for (int j = 0; j < subIndexRecordsB[i].numExtra; j++) { + file.write((char*)&subIndexRecordsB[i].extraData[j], 4); + } + + } + + ssfFile.Put(file, 2); + } } void BSSubIndexTriShape::notifyBlockDelete(int blockID) { NiObjectNET::notifyBlockDelete(blockID); + if (skinInstanceRef == blockID) + skinInstanceRef = -1; + else if (skinInstanceRef > blockID) + skinInstanceRef--; + + if (shaderPropertyRef == blockID) + shaderPropertyRef = -1; + else if (shaderPropertyRef > blockID) + shaderPropertyRef--; } @@ -884,7 +948,19 @@ void BSSubIndexTriShape::notifyBlockSwap(int blockIndexLo, int blockIndexHi) { } int BSSubIndexTriShape::CalcBlockSize() { - blockSize = 118 + 6 * numTris + 32 * numverts + szMysteryBlob; + BSTriShape::CalcBlockSize(); + blockSize += 12; // tris and first record counts + blockSize += numSubIndexRecordB * 4 * 4; // sub inex record arrayA + + if (numSubIndexRecordB > numSubIndexRecordA) { + blockSize += 8; // second index accounts + blockSize += numSubIndexRecordA * 4; // sequence array + for (int i = 0; i < numSubIndexRecordA; i++) { // sub index recordsb + blockSize += 12; // unknown data per record + blockSize += 4 * subIndexRecordsB[i].numExtra; // extra data per record. + } + } + return blockSize; @@ -2124,6 +2200,149 @@ int BSDismemberSkinInstance::CalcBlockSize() { } + +BSSkinInstance::BSSkinInstance(NiHeader& hdr) { + Init(); + + header = &hdr; + blockType = BSSKININSTANCE; +} + +BSSkinInstance::BSSkinInstance(fstream& file, NiHeader& hdr) { + Init(); + + header = &hdr; + blockType = BSSKININSTANCE; + + Get(file); +} + +void BSSkinInstance::Init() { + NiObject::Init(); + + numBones = 0; +} + +void BSSkinInstance::Get(fstream& file) { + NiObject::Get(file); + uint intData; + + file.read((char*)&unk, 4); + file.read((char*)&boneDataRef, 4); + file.read((char*)&numBones, 4); + for (int i=0; i < numBones; i++) { + file.read((char*)&intData, 4); + bones.push_back(intData); + } + + file.read((char*)&numVertices, 4); + if (numVertices > 0) + __debugbreak; // Found a skin instance with vertices figure out how much data goes here! + +} + +void BSSkinInstance::Put(fstream& file) { + NiObject::Put(file); + + file.write((char*)&unk, 4); + file.write((char*)&boneDataRef, 4); + file.write((char*)&numBones, 4); + for (int i = 0; i < numBones; i++) + file.write((char*)&bones[i], 4); + file.write((char*)&numVertices, 4); + +} + +void BSSkinInstance::notifyBlockDelete(int blockID) { + NiObject::notifyBlockDelete(blockID); + + int boneIndex = -1; + if (boneDataRef == blockID) + boneDataRef = -1; + else if (boneDataRef > blockID) + boneDataRef--; + + for (int i = 0; i < numBones; i++) { + if (bones[i] == blockID) { + bones.erase(bones.begin() + i); + boneIndex = i; + i--; + numBones--; + } + else if (bones[i] > blockID) + bones[i]--; + } +} + +void BSSkinInstance::notifyBlockSwap(int blockIndexLo, int blockIndexHi) { + NiObject::notifyBlockSwap(blockIndexLo, blockIndexHi); + + if (boneDataRef == blockIndexLo) + boneDataRef = blockIndexHi; + else if (boneDataRef == blockIndexHi) + boneDataRef = blockIndexLo; + + for (int i = 0; i < numBones; i++) { + if (bones[i] == blockIndexLo) + bones[i] = blockIndexHi; + else if (bones[i] == blockIndexHi) + bones[i] = blockIndexLo; + } +} + +BSSkinBoneData::BSSkinBoneData(NiHeader& hdr) { + NiObject::Init(); + + header = &hdr; + blockType = BSBONEDATA; +} + +BSSkinBoneData::BSSkinBoneData(fstream& file, NiHeader& hdr) { + NiObject::Init(); + + header = &hdr; + blockType = BSBONEDATA; + Get(file); +} + +void BSSkinBoneData::Get(fstream& file) { + NiObject::Get(file); + + file.read((char*)&nBones, 4); + + BoneData boneData; + for (int i = 0; i < nBones; i++) { + + file.read((char*)&boneData.boundSphereOffset, 12); + file.read((char*)&boneData.boundSphereRadius, 4); + file.read((char*)&boneData.boneTransform, 52); + + boneXforms.push_back(boneData); + } +} + +void BSSkinBoneData::Put(fstream& file) { + NiObject::Put(file); + + file.write((char*)&nBones, 4); + + for (int i = 0; i < nBones; i++) { + + file.read((char*)&boneXforms[i].boundSphereOffset, 12); + file.read((char*)&boneXforms[i].boundSphereRadius, 4); + file.read((char*)&boneXforms[i].boneTransform, 52); + } +} + + +int BSSkinInstance::CalcBlockSize() { + NiObject::CalcBlockSize(); + + blockSize += 16; + blockSize += numBones * 4; + return blockSize; +} + NiSkinData::NiSkinData(NiHeader& hdr) { NiObject::Init(); diff --git a/NifFile.cpp b/NifFile.cpp index 5f05f663..9656aeec 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -141,6 +141,16 @@ int NifFile::nodeIdForName(const string& name) { int NifFile::shapeBoneIndex(const string& shapeName, const string& boneName) { int skinRef = -1; + BSTriShape* bsTriShape = geomForNameF4(shapeName); + if (bsTriShape) { + NiBoneContainer* bonelist = (NiBoneContainer*)blocks[bsTriShape->skinInstanceRef]; + for (int i = 0; ibones.size();i++) { + if (bonelist->bones[i] > -1 && ((NiNode*)blocks[bonelist->bones[i]])->name == boneName) { + return i; + } + } + } + NiTriBasedGeom* geom = geomForName(shapeName); if (geom) skinRef = geom->skinInstanceRef; @@ -257,6 +267,12 @@ void NifFile::CopyFrom(NifFile& other) { case BSSUBINDEXTRISHAPE: blockCopy = new BSSubIndexTriShape((*(BSSubIndexTriShape*)other.blocks[i])); break; + case BSSKININSTANCE: + blockCopy = new BSSkinInstance(*(BSSkinInstance*)other.blocks[i]); + break; + case BSBONEDATA: + blockCopy = new BSSkinBoneData(*(BSSkinBoneData*)other.blocks[i]); + break; } if (blockCopy) { @@ -338,8 +354,8 @@ int NifFile::Load(const string& filename) { block = (NiObject*) new NiMaterialProperty(file, hdr); else if (!thisBlockTypeStr.compare("NiStencilProperty")) block = (NiObject*) new NiStencilProperty(file, hdr); - else if (!thisBlockTypeStr.compare("BSEffectShaderProperty")) - block = (NiObject*) new BSEffectShaderProperty(file, hdr); + //else if (!thisBlockTypeStr.compare("BSEffectShaderProperty")) + // block = (NiObject*) new BSEffectShaderProperty(file, hdr); else if (!thisBlockTypeStr.compare("NiFloatInterpolator")) block = (NiObject*) new NiFloatInterpolator(file, hdr); else if (!thisBlockTypeStr.compare("NiTransformInterpolator")) @@ -358,6 +374,10 @@ int NifFile::Load(const string& filename) { block = (NiObject*) new BSSubIndexTriShape(file, hdr, i); else if (!thisBlockTypeStr.compare("BSTriShape")) block = (NiObject*) new BSTriShape(file, hdr, i); + else if (!thisBlockTypeStr.compare("BSSkin::Instance")) + block = (NiObject*) new BSSkinInstance(file, hdr); + else if (!thisBlockTypeStr.compare("BSSkin::BoneData")) + block = (NiObject*) new BSSkinBoneData(file, hdr); else { hasUnknown = true; block = (NiObject*) new NiUnknown(file, hdr.blockSizes[i]); @@ -750,9 +770,7 @@ void NifFile::TrimTexturePaths() { tFile = regex_replace(tFile, regex("/+|\\\\+"), "\\"); // Replace multiple slashes or forward slashes with one backslash tFile = regex_replace(tFile, regex("^\\\\+", regex_constants::icase), ""); // Remove all backslashes from the front tFile = regex_replace(tFile, regex(".*?Data\\\\", regex_constants::icase), ""); // Remove everything before and including the data path root - if (hdr.userVersion == 12 && hdr.userVersion2 < 130) { - tFile = regex_replace(tFile, regex("^(?!^textures\\\\)", regex_constants::icase), "textures\\"); // Add textures root path if not existing - } + tFile = regex_replace(tFile, regex("^(?!^textures\\\\)", regex_constants::icase), "textures\\"); // Add textures root path if not existing} SetTextureForShape(s, tFile, i); } } @@ -990,8 +1008,18 @@ int NifFile::CopyNamedNode(string& nodeName, NifFile& srcNif) { void NifFile::CopyGeometry(const string& shapeDest, NifFile& srcNif, const string& srcShape) { NiTriBasedGeom* srcGeom = srcNif.geomForName(srcShape); - if (!srcGeom) - return; + if (srcGeom) { + CopyGeometry(shapeDest, srcNif, srcShape, srcGeom); + } + else { + BSTriShape* srcGeom = srcNif.geomForNameF4(srcShape); + CopyGeometry(shapeDest, srcNif, srcShape, srcGeom); + } + + +} + +void NifFile::CopyGeometry(const string& shapeDest, NifFile& srcNif, const string& srcShape, NiTriBasedGeom* srcGeom) { bool skipSkinInst = false; if (srcGeom->skinInstanceRef == -1) @@ -1225,6 +1253,93 @@ void NifFile::CopyGeometry(const string& shapeDest, NifFile& srcNif, const strin hdr.blockSizes[0] = rootNode->CalcBlockSize(); } +void NifFile::CopyGeometry(const string& shapeDest, NifFile& srcNif, const string& srcShape, BSTriShape* srcGeom) { + BSTriShape* destGeom = nullptr; + NiNode* rootNode = (NiNode*)blocks[0]; + int newBlockSize; + if (srcGeom->blockType == BSSUBINDEXTRISHAPE) { + BSSubIndexTriShape* shape = (BSSubIndexTriShape*)srcGeom; + BSSubIndexTriShape* destShape = new BSSubIndexTriShape(*shape); + newBlockSize = destShape->CalcBlockSize(); + destGeom = dynamic_cast(destShape); + } + else { + BSTriShape* destShape = (BSTriShape*)srcGeom; + newBlockSize = destShape->CalcBlockSize(); + destGeom = new BSTriShape(*destShape); + + } + destGeom->header = &hdr; + destGeom->nameRef = AddOrFindStringId(shapeDest); + destGeom->name = shapeDest; + + blocks.push_back(destGeom); + rootNode->children.push_back(hdr.numBlocks); + rootNode->numChildren++; + hdr.numBlocks++; + hdr.blockSizes.push_back(newBlockSize); + hdr.blockIndex.push_back(AddOrFindBlockTypeId(srcNif.hdr.blockTypes[srcNif.hdr.blockIndex[srcNif.shapeIdForName(srcShape)]].str)); + + bool skipSkinInst = true; + BSSkinInstance* newSkinInst = nullptr; + if (srcGeom->skinInstanceRef != -1) { + skipSkinInst = false; + newSkinInst = new BSSkinInstance(*(BSSkinInstance*)srcNif.GetBlock(srcGeom->skinInstanceRef)); + hdr.blockSizes.push_back(newSkinInst->CalcBlockSize()); + hdr.blockIndex.push_back(AddOrFindBlockTypeId(srcNif.hdr.blockTypes[srcNif.hdr.blockIndex[srcGeom->skinInstanceRef]].str)); + blocks.push_back(newSkinInst); + destGeom->skinInstanceRef = hdr.numBlocks; + hdr.numBlocks++; + if (newSkinInst->boneDataRef != -1) { + BSSkinBoneData* newBoneData = new BSSkinBoneData(*(BSSkinBoneData*)srcNif.GetBlock(newSkinInst->boneDataRef)); + hdr.blockSizes.push_back(newBoneData->CalcBlockSize()); + hdr.blockIndex.push_back(AddOrFindBlockTypeId(srcNif.hdr.blockTypes[srcNif.hdr.blockIndex[newSkinInst->boneDataRef]].str)); + blocks.push_back(newBoneData); + newSkinInst->boneDataRef = hdr.numBlocks; + hdr.numBlocks++; + } + } + + if (srcGeom->shaderPropertyRef != -1) { + BSLightingShaderProperty * bsShader = new BSLightingShaderProperty(*(BSLightingShaderProperty*)srcNif.GetBlock(srcGeom->shaderPropertyRef)); + blocks.push_back(bsShader); + destGeom->shaderPropertyRef = hdr.numBlocks; + hdr.numBlocks++; + hdr.blockSizes.push_back(bsShader->CalcBlockSize()); + hdr.blockIndex.push_back(AddOrFindBlockTypeId(srcNif.hdr.blockTypes[srcNif.hdr.blockIndex[srcGeom->shaderPropertyRef]].str)); + + if (bsShader->textureSetRef) { + BSShaderTextureSet* bsTexSet = new BSShaderTextureSet(*(BSShaderTextureSet*)srcNif.GetBlock(bsShader->textureSetRef)); + blocks.push_back(bsTexSet); + hdr.blockSizes.push_back(bsTexSet->CalcBlockSize()); + hdr.blockIndex.push_back(AddOrFindBlockTypeId(srcNif.hdr.blockTypes[srcNif.hdr.blockIndex[bsShader->textureSetRef]].str)); + bsShader->textureSetRef = hdr.numBlocks; + hdr.numBlocks++; + } + + } + + vector srcBoneList; + if (!skipSkinInst) { + srcNif.GetShapeBoneList(srcShape, srcBoneList); + newSkinInst->bones.clear(); + } + + int bonePtr; + for (auto &boneName : srcBoneList) { + bonePtr = nodeIdForName(boneName); + if (bonePtr == -1) { + bonePtr = CopyNamedNode(boneName, srcNif); + rootNode->children.push_back(bonePtr); + rootNode->numChildren++; + } + newSkinInst->bones.push_back(bonePtr); + } + + hdr.blockSizes[0] = rootNode->CalcBlockSize(); + +} + int NifFile::Save(const string& filename) { fstream file(filename.c_str(), ios_base::out | ios_base::binary); if (file.is_open()) { @@ -1375,14 +1490,16 @@ int NifFile::GetShapeBoneList(const string& shapeName, vector& outList) } else { BSTriShape* siTriShape = geomForNameF4(shapeName); - skinRef = siTriShape->skinInstanceRef; + if (siTriShape) { + skinRef = siTriShape->skinInstanceRef; + } } if (skinRef == -1) return 0; - NiSkinInstance* skinInst = dynamic_cast(blocks[skinRef]); + NiBoneContainer* skinInst = dynamic_cast(blocks[skinRef]); if (!skinInst) return 0; @@ -1407,14 +1524,16 @@ int NifFile::GetShapeBoneIDList(const string& shapeName, vector& outList) { } else { BSTriShape* siTriShape = geomForNameF4(shapeName); - skinRef = siTriShape->skinInstanceRef; + if (siTriShape) { + skinRef = siTriShape->skinInstanceRef; + } } if (skinRef == -1) return 0; - NiSkinInstance* skinInst = dynamic_cast(blocks[skinRef]); + NiBoneContainer* skinInst = dynamic_cast(blocks[skinRef]); if (!skinInst) return 0; @@ -1435,34 +1554,38 @@ void NifFile::SetShapeBoneIDList(const string& shapeName, vector& inList) { } else { BSTriShape* siTriShape = geomForNameF4(shapeName); - skinRef = siTriShape->skinInstanceRef; + if (siTriShape) { + skinRef = siTriShape->skinInstanceRef; + } } - if (skinRef == -1) return; - NiSkinInstance* skinInst = dynamic_cast(blocks[skinRef]); - if (!skinInst) + NiBoneContainer* boneCont = dynamic_cast(blocks[skinRef]); + if (!boneCont) return; - skinInst->bones.clear(); - skinInst->numBones = 0; + boneCont->bones.clear(); + boneCont->numBones = 0; for (int i = 0; i < inList.size(); i++) { - skinInst->bones.push_back(inList[i]); - skinInst->numBones++; + boneCont->bones.push_back(inList[i]); + boneCont->numBones++; } - hdr.blockSizes[skinRef] = skinInst->CalcBlockSize(); + hdr.blockSizes[skinRef] = boneCont->CalcBlockSize(); - NiSkinData* skinData = (NiSkinData*)blocks[skinInst->dataRef]; - int nBonesToAdd = skinInst->bones.size() - skinData->numBones; - if (nBonesToAdd > 0) { - for (int i = 0; i < nBonesToAdd; i++) { - skinData->bones.emplace_back(); - skinData->bones.back().numVertices = 0; - skinData->numBones++; + NiSkinInstance* skinInst = dynamic_cast(boneCont); + if (skinInst) { + NiSkinData* skinData = (NiSkinData*)blocks[skinInst->dataRef]; + int nBonesToAdd = skinInst->bones.size() - skinData->numBones; + if (nBonesToAdd > 0) { + for (int i = 0; i < nBonesToAdd; i++) { + skinData->bones.emplace_back(); + skinData->bones.back().numVertices = 0; + skinData->numBones++; + } + hdr.blockSizes[skinInst->dataRef] = skinData->CalcBlockSize(); } - hdr.blockSizes[skinInst->dataRef] = skinData->CalcBlockSize(); } } @@ -1476,7 +1599,17 @@ int NifFile::GetShapeBoneWeights(const string& shapeName, int boneIndex, unorder } else { BSTriShape* siTriShape = geomForNameF4(shapeName); - skinRef = siTriShape->skinInstanceRef; + if (siTriShape) { + + for (int vid = 0; vid < siTriShape->numverts; vid++) { + for (int i = 0; i < 4; i++) + if (siTriShape->vertData[vid].weightBones[i] == boneIndex && siTriShape->vertData[vid].weights[i] != 0) { + outWeights[vid] = siTriShape->vertData[vid].weights[i]; + } + } + return outWeights.size(); + } + } if (skinRef == -1) @@ -1519,7 +1652,9 @@ bool NifFile::SetShapeBoneTransform(const string& shapeName, int boneIndex, Skin } else { BSTriShape* siTriShape = geomForNameF4(shapeName); - skinRef = siTriShape->skinInstanceRef; + if (siTriShape) { + skinRef = siTriShape->skinInstanceRef; + } } if (skinRef == -1) @@ -1557,7 +1692,25 @@ bool NifFile::GetShapeBoneTransform(const string& shapeName, int boneIndex, Skin } else { BSTriShape* siTriShape = geomForNameF4(shapeName); - skinRef = siTriShape->skinInstanceRef; + if (siTriShape) { + skinRef = siTriShape->skinInstanceRef; + if (skinRef != -1) { + int dataref = dynamic_cast(blocks[skinRef])->boneDataRef; + if (dataref != -1) { + if (boneIndex == -1) { + // overall skin transform not found in fo4 meshes :( + return false; + } + BSSkinBoneData* bd = dynamic_cast(blocks[dataref]); + outXform = bd->boneXforms[boneIndex].boneTransform; + outSphereOffset = bd->boneXforms[boneIndex].boundSphereOffset; + outSphereRadius = bd->boneXforms[boneIndex].boundSphereRadius; + + return true; + } + + } + } } if (skinRef == -1) @@ -1598,7 +1751,13 @@ void NifFile::UpdateShapeBoneID(const string& shapeName, int oldID, int newID) { else { BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { - //NOT IMPLEMENTED; + skinRef = siTriShape->skinInstanceRef; + if (skinRef != -1) { + for (auto& b : dynamic_cast(blocks[skinRef])->bones) { + if (b == oldID) + b = newID; + } + } } } @@ -1625,9 +1784,7 @@ void NifFile::SetShapeBoneWeights(const string& shapeName, int boneIndex, unorde skinRef = geom->skinInstanceRef; else { BSTriShape* siTriShape = geomForNameF4(shapeName); - if (siTriShape) { - //NOT IMPLEMENTED; - } + // NOT Implemented. use SetShapeVertWeights instead. } if (skinRef == -1) @@ -1654,6 +1811,23 @@ void NifFile::SetShapeBoneWeights(const string& shapeName, int boneIndex, unorde hdr.blockSizes[skinInst->dataRef] = skinData->CalcBlockSize(); } +void NifFile::SetShapeVertWeights(const string& shapeName, int vertIndex, vector& boneids, vector& weights) { + + BSTriShape* trishape = geomForNameF4(shapeName); + if (!trishape) { + return; + } + + memset(trishape->vertData[vertIndex].weights, 0, sizeof(float)* 4); + memset(trishape->vertData[vertIndex].weightBones, 0, sizeof(unsigned char) * 4); + + for (int i= 0; i <4; i++) { + trishape->vertData[vertIndex].weightBones[i] = boneids[i]; + trishape->vertData[vertIndex].weights[i] = weights[i]; + } + +} + const vector* NifFile::GetRawVertsForShape(const string& shapeName) { int bType; int dataRef = shapeDataIdForName(shapeName, bType); @@ -2429,7 +2603,12 @@ void NifFile::DeleteShape(const string& shapeName) { // Not IMplemented BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { - + int shapeID = shapeIdForName(shapeName); + DeleteBlock(((BSLightingShaderProperty*)GetBlock(siTriShape->shaderPropertyRef))->textureSetRef); + DeleteBlock(siTriShape->shaderPropertyRef); + DeleteBlock(((BSSkinInstance*)GetBlock(siTriShape->skinInstanceRef))->boneDataRef); + DeleteBlock(siTriShape->skinInstanceRef); + DeleteBlock(shapeID); } } @@ -2473,7 +2652,9 @@ void NifFile::DeleteShader(const string& shapeName) { // Not IMplemented BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { - //alphaRef = siTriShape->unkRef; + if (siTriShape->skinInstanceRef != -1) { + + } } } } diff --git a/NifFile.h b/NifFile.h index e0b5db3c..352cde87 100644 --- a/NifFile.h +++ b/NifFile.h @@ -37,6 +37,8 @@ enum BlockType { NITRISTRIPS, NITRISTRIPSDATA, NISKININSTANCE, + BSSKININSTANCE, + BSBONEDATA, NISTRINGEXTRADATA, BSSHADERPPLIGHTINGPROPERTY, NIMATERIALPROPERTY, @@ -385,10 +387,28 @@ class BSTriShape : public NiAVObject{ // Fallout 4 trishape and trishape data for skinned meshes. uses half floats for vertices. class BSSubIndexTriShape : public BSTriShape { public: + uint numtris2; + uint numSubIndexRecordA; + uint numSubIndexRecordB; + vector subIndexRecordsA; + + uint numSubIndexRecordA_2; + uint numSubIndexRecordB_2; - int szMysteryBlob; - char* MysteryBlob; + vector sequence; + + class subIndexRecordB { + public: + uint unk1; + uint unk2; + uint numExtra; + vector extraData; + }; + + vector subIndexRecordsB; + + NiString ssfFile; //Blockindex is a temporary measure to enable us to see the total size of the block during loading ... not all fields are known yet BSSubIndexTriShape(fstream& file, NiHeader& hdr, int blockindex); @@ -546,13 +566,17 @@ class NiTriStripsData : public NiTriBasedGeomData { int CalcBlockSize(); }; -class NiSkinInstance : public NiObject { +class NiBoneContainer : public NiObject { +public: + uint numBones; + vector bones; +}; + +class NiSkinInstance : public NiBoneContainer { public: int dataRef; int skinPartitionRef; int skeletonRootRef; - uint numBones; - vector bones; NiSkinInstance() { }; NiSkinInstance(NiHeader& hdr); @@ -586,6 +610,53 @@ class BSDismemberSkinInstance : public NiSkinInstance { int CalcBlockSize(); }; +class BSSkinInstance : public NiBoneContainer { +public: + uint unk; + uint boneDataRef; + ushort numVertices; + vector vertexWeights; + + + BSSkinInstance() : unk(0), boneDataRef(0), numVertices(0) { numBones = 0; }; + BSSkinInstance(NiHeader& hdr); + BSSkinInstance(fstream& file, NiHeader& hdr); + + virtual void Init(); + virtual void Get(fstream& file); + virtual void Put(fstream& file); + virtual void notifyBlockDelete(int blockID); + virtual void notifyBlockSwap(int blockIndexLo, int blockIndexHi); + virtual int CalcBlockSize(); +}; + +class BSSkinBoneData : public NiObject { +public: + uint nBones; + class BoneData { + public: + Vector3 boundSphereOffset; + float boundSphereRadius; + SkinTransform boneTransform; + + BoneData() { + boneTransform.scale = 1.0f; + boundSphereRadius = 0.0f; + } + int CalcSize() { + return (70); + } + }; + vector boneXforms; + + BSSkinBoneData() : nBones(0) { }; + BSSkinBoneData(NiHeader& hdr); + BSSkinBoneData(fstream& file, NiHeader& hdr); + + virtual void Get(fstream& file); + virtual void Put(fstream& file); +}; + class NiSkinData : public NiObject { public: class BoneData { @@ -1202,6 +1273,8 @@ class NifFile int CopyNamedNode(string& nodeName, NifFile& srcNif); void CopyShader(const string& shapeDest, int srcShaderRef, NifFile& srcNif, bool addAlpha, int propRef1, int propRef2); void CopyGeometry(const string& shapeDest, NifFile& srcNif, const string& srcShape); + void CopyGeometry(const string& shapeDest, NifFile& srcNif, const string& srcShape, NiTriBasedGeom* geom); + void CopyGeometry(const string& shapeDest, NifFile& srcNif, const string& srcShape, BSTriShape* geom); int GetShapeType(const string& shapeName); int GetShapeList(vector& outList); @@ -1226,6 +1299,7 @@ class NifFile bool GetShapeBoneTransform(const string& shapeName, int boneIndex, SkinTransform& outXform, Vector3& outSphereOffset, float& outSphereRadius); void UpdateShapeBoneID(const string& shapeName, int oldID, int newID); void SetShapeBoneWeights(const string& shapeName, int boneIndex, unordered_map& inWeights); + void SetShapeVertWeights(const string& shapeName, int vertIndex, vector& boneids, vector& weights); const vector* GetRawVertsForShape(const string& shapeName); bool GetTrisForShape(const string& shapeName, vector* outTris); diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index cbdb5677..c74354d0 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -1035,21 +1035,27 @@ void OutfitStudio::OnLoadOutfit(wxCommandEvent& WXUNUSED(event)) { vector oldShapes; project->GetShapes(oldShapes); - for (auto &s : oldShapes) - if (!project->IsBaseShape(s)) + for (auto &s : oldShapes) { + if (!project->IsBaseShape(s)) { glView->DeleteMesh(s); + } + } UpdateProgress(1.0f, "Loading outfit..."); int ret = 0; if (XRCCTRL(dlg, "npWorkNif", wxRadioButton)->GetValue() == true) { - if (!XRCCTRL(dlg, "npWorkAdd", wxCheckBox)->IsChecked()) + project->ClearOutfit(); + if (!XRCCTRL(dlg, "npWorkAdd", wxCheckBox)->IsChecked()) { ret = project->AddNif(XRCCTRL(dlg, "npNifFilename", wxFilePickerCtrl)->GetPath().ToStdString(), true, outfitName); - else + } + else { ret = project->AddNif(XRCCTRL(dlg, "npNifFilename", wxFilePickerCtrl)->GetPath().ToStdString(), false); + } } - else if (XRCCTRL(dlg, "npWorkObj", wxRadioButton)->GetValue() == true) + else if (XRCCTRL(dlg, "npWorkObj", wxRadioButton)->GetValue() == true) { ret = project->AddShapeFromObjFile(XRCCTRL(dlg, "npObjFilename", wxFilePickerCtrl)->GetPath().ToStdString(), outfitName); + } else project->ClearOutfit(); @@ -1059,13 +1065,14 @@ void OutfitStudio::OnLoadOutfit(wxCommandEvent& WXUNUSED(event)) { return; } - if (XRCCTRL(dlg, "npTexAuto", wxRadioButton)->GetValue() == true) - project->SetTextures("_AUTO_"); - else if (XRCCTRL(dlg, "npTexDefault", wxRadioButton)->GetValue() == true) - project->SetTexturesDefault(XRCCTRL(dlg, "npDefaultTexChoice", wxChoice)->GetStringSelection().ToStdString()); - else + if (XRCCTRL(dlg, "npTexAuto", wxRadioButton)->GetValue() == true) { + project->SetTextures("_AUTO_"); + } else if (XRCCTRL(dlg, "npTexDefault", wxRadioButton)->GetValue() == true) { + project->SetTexturesDefault(XRCCTRL(dlg, "npDefaultTexChoice", wxChoice)->GetStringSelection().ToStdString()); + } else { project->SetTextures(XRCCTRL(dlg, "npTexFilename", wxFilePickerCtrl)->GetPath().ToStdString()); - + + } wxLogMessage("Creating outfit..."); UpdateProgress(50.0f, "Creating outfit..."); RefreshGUIFromProj(); @@ -1714,7 +1721,7 @@ void OutfitStudio::OnBoneSelect(wxTreeEvent& event) { if (!project->IsBaseShape(activeItem->shapeName)) { project->GetWorkAnim()->GetWeights(activeItem->shapeName, activeBone, boneWeights); mesh* workMesh = glView->GetMesh(activeItem->shapeName); - workMesh->ColorChannelFill(1, 0.0f); + //workMesh->ColorChannelFill(1, 0.0f); for (auto &bw : boneWeights) workMesh->vcolors[bw.first].y = bw.second; diff --git a/ResourceLoader.cpp b/ResourceLoader.cpp index 460a2cf4..cdd0019b 100644 --- a/ResourceLoader.cpp +++ b/ResourceLoader.cpp @@ -18,6 +18,8 @@ See the included LICENSE file #endif #include +#include +#include using std::string; @@ -32,6 +34,48 @@ ResourceLoader::ResourceLoader() { ResourceLoader::~ResourceLoader() { } +void ResourceLoader::GetArchiveFiles(vector& outList) { + string cp = "GameDataFiles"; + int targ = Config.GetIntValue("TargetGame"); + + switch (targ) { + case 0: + cp += "/Fallout3"; + break; + case 1: + cp += "/FalloutNewVegas"; + break; + case 2: + cp += "/Skyrim"; + break; + case 3: + cp += "/Fallout4"; + break; + } + + wxString activatedFiles = Config[cp]; + + wxStringTokenizer tokenizer(activatedFiles, ";"); + map fsearch; + while (tokenizer.HasMoreTokens()) { + wxString val = tokenizer.GetNextToken().Trim(false); + val = val.Trim(); + std::transform(val.begin(), val.end(), val.begin(), ::tolower); + fsearch[val] = true; + } + wxString dataDir = Config["GameDataPath"]; + wxArrayString files; + wxDir::GetAllFiles(dataDir, &files, "*.ba2", wxDIR_FILES); + wxDir::GetAllFiles(dataDir, &files, "*.bsa", wxDIR_FILES); + for (auto& f : files) { + f = f.AfterLast('\\'); + std::transform(f.begin(), f.end(), f.begin(), ::tolower); + if (fsearch.find(f) == fsearch.end()) { + outList.push_back(dataDir.ToStdString() + f.ToStdString()); + } + } +} + GLMaterial* ResourceLoader::AddMaterial(const string& textureFile, const string& vShaderFile, const string& fShaderFile) { MaterialKey key(textureFile, vShaderFile, fShaderFile); auto it = materials.find(key); @@ -54,13 +98,12 @@ GLMaterial* ResourceLoader::AddMaterial(const string& textureFile, const string& // Auto-detect archives if (!FSManager::exists()) { - wxArrayString files; - wxDir::GetAllFiles(Config["GameDataPath"], &files, wxEmptyString, wxDIR_FILES); + vector fileList; + GetArchiveFiles(fileList); vector archives; - for (auto &file : files) - if (file.EndsWith(".bsa") || file.EndsWith(".ba2")) - archives.push_back(file.ToStdString()); + for (auto &file : fileList) + archives.push_back(file); FSManager::addArchives(archives); } diff --git a/ResourceLoader.h b/ResourceLoader.h index 3b2c843f..f3098615 100644 --- a/ResourceLoader.h +++ b/ResourceLoader.h @@ -8,6 +8,7 @@ See the included LICENSE file #include #include +#include #include using namespace std; @@ -19,10 +20,13 @@ class ResourceLoader { ResourceLoader(); virtual ~ResourceLoader(); + void GetArchiveFiles(vector& outList); + GLMaterial* AddMaterial(const string& textureFile, const string& vShaderFile, const string& fShaderFile); + void Cleanup(); private: From 521c600a7d84a3f25e8c5c3f306cb04527cb9e7e Mon Sep 17 00:00:00 2001 From: ousnius Date: Sat, 21 Nov 2015 03:18:53 +0100 Subject: [PATCH 16/64] Fixed compiler warnings, cleaned up BSTriShape deletion --- Anim.h | 10 ++++------ Config.xml | 15 +++++++-------- NifBlock.cpp | 7 +++---- NifFile.cpp | 22 ++++++++++++++-------- OutfitStudio.cpp | 9 +++++---- ResourceLoader.cpp | 13 +++++-------- ResourceLoader.h | 1 - 7 files changed, 38 insertions(+), 39 deletions(-) diff --git a/Anim.h b/Anim.h index e860f7e4..1005822e 100644 --- a/Anim.h +++ b/Anim.h @@ -19,23 +19,21 @@ struct vertexBoneWeights { vector boneIds; vector weights; - vertexBoneWeights () { + vertexBoneWeights() { } - void Add (int inboneid, float inweight) { + void Add(int inboneid, float inweight) { if (inweight == 0) return; - for (int i; i < weights.size(); ++i) { + for (int i = 0; i < weights.size(); ++i) { if (inweight < weights[i]) continue; weights.insert(weights.begin() + i, inweight); boneIds.insert(boneIds.begin() + i, inboneid); return; - } + } weights.push_back(inweight); boneIds.push_back(inboneid); - - } }; diff --git a/Config.xml b/Config.xml index 1e7c6e2d..92539cb7 100644 --- a/Config.xml +++ b/Config.xml @@ -1,21 +1,21 @@ - - - - 2 + + 3 true true - Skyrim - Animations.bsa; Skyrim - Interface.bsa; Skyrim - Meshes.bsa; Skyrim - Misc.bsa; Skyrim - Shaders.bsa; Skyrim - Sounds.bsa; Skyrim - Voices.bsa; Skyrim - VoicesExtra.bsa; + Skyrim - Animations.bsa; Skyrim - Interface.bsa; Skyrim - Meshes.bsa; Skyrim - Misc.bsa; Skyrim - Shaders.bsa; Skyrim - Sounds.bsa; Skyrim - Voices.bsa; Skyrim - VoicesExtra.bsa Fallout4 - Animations.ba2; Fallout4 - Interface.ba2; Fallout4 - Materials.ba2; Fallout4 - Meshes.ba2; Fallout4 - MeshesExtra.ba2; Fallout4 - Misc.ba2; Fallout4 - Shaders.ba2; Fallout4 - Sounds.ba2; Fallout4 - Startup.ba2; Fallout4 - Voices.ba2 + + + 3 CBBE Body CBBE @@ -47,8 +47,7 @@ res\skeleton_fo4.nif - NPC - + Root diff --git a/NifBlock.cpp b/NifBlock.cpp index 536a8861..858933a2 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -576,7 +576,6 @@ BSTriShape::BSTriShape(fstream& file, NiHeader& hdr, int blockindex) { } void BSTriShape::Get(fstream& file) { - int intData; short shortData; // The order of definition deviates slightly from previous versions, so can't directly use the super Get... instead // that code is duplicated here and the super super get is called. @@ -930,12 +929,12 @@ void BSSubIndexTriShape::notifyBlockDelete(int blockID) { NiObjectNET::notifyBlockDelete(blockID); if (skinInstanceRef == blockID) - skinInstanceRef = -1; + skinInstanceRef = 0xFFFFFFFF; else if (skinInstanceRef > blockID) skinInstanceRef--; if (shaderPropertyRef == blockID) - shaderPropertyRef = -1; + shaderPropertyRef = 0xFFFFFFFF; else if (shaderPropertyRef > blockID) shaderPropertyRef--; @@ -2258,7 +2257,7 @@ void BSSkinInstance::notifyBlockDelete(int blockID) { int boneIndex = -1; if (boneDataRef == blockID) - boneDataRef = -1; + boneDataRef = 0xFFFFFFFF; else if (boneDataRef > blockID) boneDataRef--; diff --git a/NifFile.cpp b/NifFile.cpp index 9656aeec..c0b0d07b 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -1783,7 +1783,7 @@ void NifFile::SetShapeBoneWeights(const string& shapeName, int boneIndex, unorde if (geom) skinRef = geom->skinInstanceRef; else { - BSTriShape* siTriShape = geomForNameF4(shapeName); + // BSTriShape* siTriShape = geomForNameF4(shapeName); // NOT Implemented. use SetShapeVertWeights instead. } @@ -2595,23 +2595,29 @@ void NifFile::DeleteShape(const string& shapeName) { for (int i = 0; i < geom->numExtraData; i++) DeleteBlock(geom->extraDataRef[i]); - + int shapeID = shapeIdForName(shapeName); DeleteBlock(shapeID); } else { - // Not IMplemented BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { + NiShader* shader = dynamic_cast(GetBlock(siTriShape->shaderPropertyRef)); + if (shader) { + DeleteBlock(shader->GetTextureSetRef()); + DeleteBlock(siTriShape->shaderPropertyRef); + } + + BSSkinInstance* bsSkinInst = dynamic_cast(GetBlock(siTriShape->skinInstanceRef)); + if (bsSkinInst) { + DeleteBlock(bsSkinInst->boneDataRef); + DeleteBlock(siTriShape->skinInstanceRef); + } + int shapeID = shapeIdForName(shapeName); - DeleteBlock(((BSLightingShaderProperty*)GetBlock(siTriShape->shaderPropertyRef))->textureSetRef); - DeleteBlock(siTriShape->shaderPropertyRef); - DeleteBlock(((BSSkinInstance*)GetBlock(siTriShape->skinInstanceRef))->boneDataRef); - DeleteBlock(siTriShape->skinInstanceRef); DeleteBlock(shapeID); } } - } void NifFile::DeleteShader(const string& shapeName) { diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index c74354d0..9d3ec3cb 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -1721,10 +1721,11 @@ void OutfitStudio::OnBoneSelect(wxTreeEvent& event) { if (!project->IsBaseShape(activeItem->shapeName)) { project->GetWorkAnim()->GetWeights(activeItem->shapeName, activeBone, boneWeights); mesh* workMesh = glView->GetMesh(activeItem->shapeName); - //workMesh->ColorChannelFill(1, 0.0f); - - for (auto &bw : boneWeights) - workMesh->vcolors[bw.first].y = bw.second; + if (workMesh) { + workMesh->ColorChannelFill(1, 0.0f); + for (auto &bw : boneWeights) + workMesh->vcolors[bw.first].y = bw.second; + } } boneWeights.clear(); diff --git a/ResourceLoader.cpp b/ResourceLoader.cpp index cdd0019b..131e66c0 100644 --- a/ResourceLoader.cpp +++ b/ResourceLoader.cpp @@ -21,11 +21,9 @@ See the included LICENSE file #include #include -using std::string; - size_t ResourceLoader::MatKeyHash::operator()(const MaterialKey& key) const { - std::hash strHash; - return (strHash(std::get<0>(key)) ^ strHash(std::get<1>(key)) ^ strHash(std::get<2>(key))); + hash strHash; + return (strHash(get<0>(key)) ^ strHash(get<1>(key)) ^ strHash(get<2>(key))); } ResourceLoader::ResourceLoader() { @@ -59,17 +57,16 @@ void ResourceLoader::GetArchiveFiles(vector& outList) { map fsearch; while (tokenizer.HasMoreTokens()) { wxString val = tokenizer.GetNextToken().Trim(false); - val = val.Trim(); - std::transform(val.begin(), val.end(), val.begin(), ::tolower); + val = val.Trim().MakeLower(); fsearch[val] = true; } + wxString dataDir = Config["GameDataPath"]; wxArrayString files; wxDir::GetAllFiles(dataDir, &files, "*.ba2", wxDIR_FILES); wxDir::GetAllFiles(dataDir, &files, "*.bsa", wxDIR_FILES); for (auto& f : files) { - f = f.AfterLast('\\'); - std::transform(f.begin(), f.end(), f.begin(), ::tolower); + f = f.AfterLast('\\').MakeLower(); if (fsearch.find(f) == fsearch.end()) { outList.push_back(dataDir.ToStdString() + f.ToStdString()); } diff --git a/ResourceLoader.h b/ResourceLoader.h index f3098615..1104f51f 100644 --- a/ResourceLoader.h +++ b/ResourceLoader.h @@ -8,7 +8,6 @@ See the included LICENSE file #include #include -#include #include using namespace std; From bf767e626c5eb41dcd77a59a7f45ff0a482428a0 Mon Sep 17 00:00:00 2001 From: Caliente Date: Sat, 21 Nov 2015 02:50:35 -0500 Subject: [PATCH 17/64] Further bugfixes and cleanup --- Anim.h | 10 ++++++---- NifBlock.cpp | 46 ++++++++++++++++++++++++++++++++-------------- NifFile.cpp | 2 +- NifFile.h | 7 +++++-- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/Anim.h b/Anim.h index 1005822e..2d4f6c78 100644 --- a/Anim.h +++ b/Anim.h @@ -19,21 +19,23 @@ struct vertexBoneWeights { vector boneIds; vector weights; - vertexBoneWeights() { + vertexBoneWeights () { } - void Add(int inboneid, float inweight) { + void Add (int inboneid, float inweight) { if (inweight == 0) return; - for (int i = 0; i < weights.size(); ++i) { + for (int i=0; i < weights.size(); ++i) { if (inweight < weights[i]) continue; weights.insert(weights.begin() + i, inweight); boneIds.insert(boneIds.begin() + i, inboneid); return; - } + } weights.push_back(inweight); boneIds.push_back(inboneid); + + } }; diff --git a/NifBlock.cpp b/NifBlock.cpp index 858933a2..41c13305 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -637,7 +637,16 @@ void BSTriShape::Get(fstream& file) { vertData[i].uv.v = h2float(shortData); if (vertFlags[6] & 0x1) { - file.read((char*)vertData[i].normalData, 8); + for (int j = 0; j < 3; j++) { + file.read((char*)&vertData[i].normal[j], 1); + } + + file.read((char*)&vertData[i].unk1, 1); + + for (int j = 0; j < 3; j++) { + file.read((char*)&vertData[i].tangent[j], 1); + } + file.read((char*)&vertData[i].unk2, 1); } if (vertFlags[6] & 0x2) { @@ -732,9 +741,17 @@ void BSTriShape::Put(fstream& file) { file.write((char*)&shortData, 2); if (vertFlags[6] & 0x1) { - file.write((char*)vertData[i].normalData, 8); - // file.write((char*)&vertData[i].normals[0], 4); - // file.write((char*)&vertData[i].normals[1], 4); + for (int j = 0; j < 3; j++) { + file.write((char*)&vertData[i].normal[j], 1); + } + + file.write((char*)&vertData[i].unk1, 1); + + for (int j = 0; j < 3; j++) { + file.write((char*)&vertData[i].tangent[j], 1); + } + + file.write((char*)&vertData[i].unk2, 1); } if (vertFlags[6] & 0x2) { @@ -795,9 +812,9 @@ const vector* BSTriShape::GetNormalData() { rawnorms.resize(numverts); for (int i = 0; i < numverts; i++) { - float q1 = (((float)vertData[i].normalData[0])/255.0f) *2.0f - 1.0f; - float q2 = (((float)vertData[i].normalData[1])/255.0f) *2.0f - 1.0f; - float q3 = (((float)vertData[i].normalData[2])/255.0f) *2.0f - 1.0f; + float q1 = (((float)vertData[i].normal[0])/255.0f) *2.0f - 1.0f; + float q2 = (((float)vertData[i].normal[1])/255.0f) *2.0f - 1.0f; + float q3 = (((float)vertData[i].normal[2])/255.0f) *2.0f - 1.0f; float x = q1; float y = q2; @@ -816,9 +833,9 @@ const vector* BSTriShape::GetTangentData() { rawtangents.clear(); rawtangents.resize(numverts); for (int i = 0; i < numverts; i++) { - float q6 = (((float)vertData[i].normalData[4]) / 255.0f) *2.0f - 1.0f; - float q7 = (((float)vertData[i].normalData[5]) / 255.0f) *2.0f - 1.0f; - float q8 = (((float)vertData[i].normalData[6]) / 255.0f) *2.0f - 1.0f; + float q6 = (((float)vertData[i].tangent[0]) / 255.0f) *2.0f - 1.0f; + float q7 = (((float)vertData[i].tangent[1]) / 255.0f) *2.0f - 1.0f; + float q8 = (((float)vertData[i].tangent[2]) / 255.0f) *2.0f - 1.0f; float x = q6; float y = q7; @@ -2246,8 +2263,9 @@ void BSSkinInstance::Put(fstream& file) { file.write((char*)&unk, 4); file.write((char*)&boneDataRef, 4); file.write((char*)&numBones, 4); - for (int i = 0; i < numBones; i++) + for (int i = 0; i < numBones; i++) { file.write((char*)&bones[i], 4); + } file.write((char*)&numVertices, 4); } @@ -2327,9 +2345,9 @@ void BSSkinBoneData::Put(fstream& file) { for (int i = 0; i < nBones; i++) { - file.read((char*)&boneXforms[i].boundSphereOffset, 12); - file.read((char*)&boneXforms[i].boundSphereRadius, 4); - file.read((char*)&boneXforms[i].boneTransform, 52); + file.write((char*)&boneXforms[i].boundSphereOffset, 12); + file.write((char*)&boneXforms[i].boundSphereRadius, 4); + file.write((char*)&boneXforms[i].boneTransform, 52); } } diff --git a/NifFile.cpp b/NifFile.cpp index c0b0d07b..56f1f52d 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -1821,7 +1821,7 @@ void NifFile::SetShapeVertWeights(const string& shapeName, int vertIndex, vector memset(trishape->vertData[vertIndex].weights, 0, sizeof(float)* 4); memset(trishape->vertData[vertIndex].weightBones, 0, sizeof(unsigned char) * 4); - for (int i= 0; i <4; i++) { + for (int i= 0; i vertData[vertIndex].weightBones[i] = boneids[i]; trishape->vertData[vertIndex].weights[i] = weights[i]; } diff --git a/NifFile.h b/NifFile.h index 352cde87..67492759 100644 --- a/NifFile.h +++ b/NifFile.h @@ -341,7 +341,10 @@ class BSTriShape : public NiAVObject{ Vector3 vert; // Stored half-float, convert! float dotNormal; // maybe the dotproduct of the vert normal and the z axis? Vector2 uv; // Stored as half-float, convert! - byte normalData[8]; // only if flags[6] & 0x1 is true? some kind of packed normal data ? + byte normal[3]; + byte unk1; + byte tangent[3]; // only if flags[6] & 0x1 is true? some kind of packed normal data ? + byte unk2; //uint normals[2]; byte colorData[4]; // only if flags[6] & 0x2 is true float weights[4]; // stored in half-float, convert! @@ -614,7 +617,7 @@ class BSSkinInstance : public NiBoneContainer { public: uint unk; uint boneDataRef; - ushort numVertices; + uint numVertices; vector vertexWeights; From 2925fef339f4b18429c20dfd470e0e513ddfdc36 Mon Sep 17 00:00:00 2001 From: ousnius Date: Sat, 21 Nov 2015 21:20:00 +0100 Subject: [PATCH 18/64] Added zlib license to about text --- res/BodyslideFrame.xrc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/res/BodyslideFrame.xrc b/res/BodyslideFrame.xrc index 27eea393..b195a50b 100644 --- a/res/BodyslideFrame.xrc +++ b/res/BodyslideFrame.xrc @@ -1053,7 +1053,17 @@ notice, this list of conditions and the following disclaimer in the
documenta used to endorse or promote products derived from this software
without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


+ +zlib

Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler

+This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.

+Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:

+1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.

+2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.

+3. This notice may not be removed or altered from any source
distribution.

+Jean-loup Gailly Mark Adler
+jloup@gzip.org madler@alumni.caltech.edu
+The data format used by the zlib library is described by RFCs (Request for Comments)
1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format),
rfc1951 (deflate format) and rfc1952 (gzip format).
]]>
From 3fc6b2837096f99b7fa0605068032c39075fb2ee Mon Sep 17 00:00:00 2001 From: ousnius Date: Wed, 25 Nov 2015 22:49:43 +0100 Subject: [PATCH 19/64] Fixed NIF version bugs --- NifBlock.cpp | 73 ++++++++++++++++++++++++++++------------------------ NifFile.h | 3 +-- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/NifBlock.cpp b/NifBlock.cpp index 41c13305..d443f94b 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -33,19 +33,6 @@ int NiObject::CalcBlockSize() { return blockSize; } -bool NiObject::VerCheck(int v1, int v2, int v3, int v4, bool equal) { - if (equal) { - if (header->version4 == v1 && header->version3 == v2 && header->version2 == v3 && header->version1 == v4) - return true; - } - else { - if (header->version4 >= v1 && header->version3 >= v2 && header->version2 >= v3 && header->version1 >= v4) - return true; - } - - return false; -} - NiHeader::NiHeader() { header = this; @@ -79,6 +66,19 @@ void NiHeader::SetVersion(const byte& v1, const byte& v2, const byte& v3, const userVersion2 = userVer2; } +bool NiHeader::VerCheck(int v1, int v2, int v3, int v4, bool equal) { + if (equal) { + if (version4 == v1 && version3 == v2 && version2 == v3 && version1 == v4) + return true; + } + else { + if (version4 >= v1 && version3 >= v2 && version2 >= v3 && version1 >= v4) + return true; + } + + return false; +} + void NiHeader::Get(fstream& file) { file.read(verStr, 38); if (_strnicmp(verStr, "Gamebryo", 8) != 0) { @@ -492,7 +492,7 @@ void NiNode::Get(fstream& file) { children.push_back(intData); } - if (header->userVersion == 12 && header->userVersion2 < 130) { + if (header->userVersion <= 12 && header->userVersion2 < 130) { file.read((char*)&numEffects, 4); for (int i = 0; i < numEffects; i++) { file.read((char*)&intData, 4); @@ -508,7 +508,7 @@ void NiNode::Put(fstream& file) { for (int i = 0; i < numChildren; i++) file.write((char*)&children[i], 4); - if (header->userVersion == 12 && header->userVersion2 < 130) { + if (header->userVersion <= 12 && header->userVersion2 < 130) { file.write((char*)&numEffects, 4); for (int i = 0; i < numEffects; i++) file.write((char*)&effects[i], 4); @@ -560,7 +560,7 @@ int NiNode::CalcBlockSize() { blockSize += 4; blockSize += numChildren * 4; - if (header->userVersion == 12 && header->userVersion2 < 130) { + if (header->userVersion <= 12 && header->userVersion2 < 130) { blockSize += 4; blockSize += numEffects * 4; } @@ -3507,11 +3507,11 @@ void BSLightingShaderProperty::Get(fstream& file) { file.read((char*)&specularStrength, 4); file.read((char*)&lightingEffect1, 4); - if (header->userVersion == 12 && header->userVersion2 < 130) { + if (header->userVersion <= 12 && header->userVersion2 < 130) { file.read((char*)&lightingEffect2, 4); } else if (header->userVersion == 12 && header->userVersion2 >= 130) { - file.read((char*)&unk1,4); + file.read((char*)&unk1, 4); file.read((char*)&unk2, 4); } @@ -3560,11 +3560,12 @@ void BSLightingShaderProperty::Get(fstream& file) { file.read((char*)&unk[i], 4); } } - if (skyrimShaderType==1 && header->userVersion2 >= 130) { + if (skyrimShaderType == 1 && header->userVersion2 >= 130) { for (int i = 0; i < 2; i++) { file.read((char*)&pad[i], 1); } - }if (skyrimShaderType == 5 && header->userVersion2 >= 130) { + } + if (skyrimShaderType == 5 && header->userVersion2 >= 130) { for (int i = 0; i < 16; i++) { file.read((char*)&pad[i], 1); } @@ -3602,7 +3603,7 @@ void BSLightingShaderProperty::Put(fstream& file) { file.write((char*)&specularStrength, 4); file.write((char*)&lightingEffect1, 4); - if (header->userVersion == 12 && header->userVersion2 < 130) { + if (header->userVersion <= 12 && header->userVersion2 < 130) { file.write((char*)&lightingEffect2, 4); } else if (header->userVersion == 12 && header->userVersion2 >= 130) { @@ -3660,12 +3661,12 @@ void BSLightingShaderProperty::Put(fstream& file) { for (int i = 0; i < 2; i++) { file.write((char*)&pad[i], 1); } - }if (skyrimShaderType == 5 && header->userVersion2 >= 130) { + } + if (skyrimShaderType == 5 && header->userVersion2 >= 130) { for (int i = 0; i < 16; i++) { file.write((char*)&pad[i], 1); } } - } void BSLightingShaderProperty::notifyBlockDelete(int blockID) { @@ -3767,9 +3768,9 @@ int BSLightingShaderProperty::CalcBlockSize() { if (header->userVersion == 12 && header->userVersion2 >= 130) { blockSize += 12; - } - - if (header->userVersion == 12 && header->userVersion2 < 130) { + } + + if (header->userVersion <= 12 && header->userVersion2 < 130) { blockSize += 4; } @@ -3783,13 +3784,17 @@ int BSLightingShaderProperty::CalcBlockSize() { } else if (skyrimShaderType == 6) { blockSize += 12; - }else if (skyrimShaderType == 7){ + } + else if (skyrimShaderType == 7){ blockSize += 8; - }else if (skyrimShaderType == 11){ + } + else if (skyrimShaderType == 11){ blockSize += 20; - }else if (skyrimShaderType == 14){ + } + else if (skyrimShaderType == 14){ blockSize += 16; - }else if (skyrimShaderType == 16){ + } + else if (skyrimShaderType == 16){ blockSize += 28; } @@ -3916,7 +3921,7 @@ void BSEffectShaderProperty::Get(fstream& file) { file.read((char*)&uvScale.v, 4); sourceTexture = NiString(file, 4, false); file.read((char*)&textureClampMode, 4); - if (header->userVersion == 12 && header->userVersion2 < 130) { + if (header->userVersion <= 12 && header->userVersion2 < 130) { file.read((char*)&falloffStartAngle, 4); file.read((char*)&falloffStopAngle, 4); file.read((char*)&falloffStartOpacity, 4); @@ -3952,7 +3957,7 @@ void BSEffectShaderProperty::Put(fstream& file) { sourceTexture.Put(file, 4); file.write((char*)&textureClampMode, 4); - if (header->userVersion == 12 && header->userVersion2 < 130) { + if (header->userVersion <= 12 && header->userVersion2 < 130) { file.write((char*)&falloffStartAngle, 4); file.write((char*)&falloffStopAngle, 4); file.write((char*)&falloffStartOpacity, 4); @@ -4248,7 +4253,7 @@ NiAlphaProperty::NiAlphaProperty(fstream& file, NiHeader& hdr) { } void NiAlphaProperty::Get(fstream& file) { - if (header->userVersion == 12 && header->userVersion2 < 130) { + if (header->userVersion <= 12 && header->userVersion2 < 130) { NiProperty::Get(file); } @@ -4266,7 +4271,7 @@ void NiAlphaProperty::Get(fstream& file) { } void NiAlphaProperty::Put(fstream& file) { - if (header->userVersion == 12 && header->userVersion2 < 130) { + if (header->userVersion <= 12 && header->userVersion2 < 130) { NiProperty::Put(file); } diff --git a/NifFile.h b/NifFile.h index 67492759..d1b56e9a 100644 --- a/NifFile.h +++ b/NifFile.h @@ -214,8 +214,6 @@ class NiObject { virtual void Put(fstream& file); virtual int CalcBlockSize(); - - virtual bool VerCheck(int v1, int v2, int v3, int v4, bool equal = false); }; class NiHeader : public NiObject { @@ -260,6 +258,7 @@ class NiHeader : public NiObject { NiHeader(); void Clear(); void SetVersion(const byte& v1, const byte& v2, const byte& v3, const byte& v4, const uint& userVer, const uint& userVer2); + bool VerCheck(int v1, int v2, int v3, int v4, bool equal = false); void Get(fstream& file); void Put(fstream& file); From 49a8cb593e150ad835ce031f86d50b1a538b6420 Mon Sep 17 00:00:00 2001 From: ousnius Date: Sun, 29 Nov 2015 05:52:26 +0100 Subject: [PATCH 20/64] Fixed skeleton root selection in settings --- BodySlideApp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index 526f6ac1..8837bae5 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -2457,7 +2457,7 @@ void BodySlideFrame::OnSettings(wxCommandEvent& WXUNUSED(event)) { wxCheckListBox* dataFileList = XRCCTRL(*settings, "DataFileList", wxCheckListBox); SettingsFillDataFiles(dataFileList, gameDataPath, Config.GetIntValue("TargetGame")); - settings->Bind(wxEVT_CHOICE, &BodySlideFrame::OnChooseTargetGame, this); + choiceTargetGame->Bind(wxEVT_CHOICE, &BodySlideFrame::OnChooseTargetGame, this); if (settings->ShowModal() == wxID_OK) { TargetGame targ = (TargetGame)choiceTargetGame->GetSelection(); From e81850e9f5d1a7ca31686ac69b3b8dc62a5f4ba8 Mon Sep 17 00:00:00 2001 From: ousnius Date: Tue, 1 Dec 2015 20:23:25 +0100 Subject: [PATCH 21/64] Split up slider header files, clean-up --- Automorph.cpp | 15 - Automorph.h | 3 +- BodySlide.vcxproj | 4 + BodySlide.vcxproj.filters | 12 + OutfitProject.cpp | 2 +- OutfitStudio.h | 1 + SliderData.cpp | 562 +------------------------------------- SliderData.h | 297 +------------------- SliderManager.cpp | 49 +--- SliderManager.h | 29 +- SliderPresets.cpp | 218 +++++++++++++++ SliderPresets.h | 34 +++ SliderSet.cpp | 352 ++++++++++++++++++++++++ SliderSet.h | 258 +++++++++++++++++ 14 files changed, 901 insertions(+), 935 deletions(-) create mode 100644 SliderPresets.cpp create mode 100644 SliderPresets.h create mode 100644 SliderSet.cpp create mode 100644 SliderSet.h diff --git a/Automorph.cpp b/Automorph.cpp index 3f87ef61..c8fd83d7 100644 --- a/Automorph.cpp +++ b/Automorph.cpp @@ -111,21 +111,6 @@ void Automorph::SetRef(NifFile& ref, const string& refShape) { refTree = new kd_tree(morphRef->verts, morphRef->nVerts); } -int Automorph::InitRefDiffData(const string &srcFileName, const string &dataSetName, const string &baseDataPath) { - SliderSetFile srcSliderSetFile; - srcSliderSetFile.Open(srcFileName); - - SliderSet srcSet; - if (srcSliderSetFile.GetSet(dataSetName, srcSet)) - return 1; - - srcSet.SetBaseDataPath(baseDataPath); - srcSet.LoadSetDiffData(__srcDiffData); - srcDiffData = &__srcDiffData; - - return 0; -} - void Automorph::LinkRefDiffData(DiffDataSets* diffData) { srcDiffData = diffData; } diff --git a/Automorph.h b/Automorph.h index e1a7ff02..172c8f6c 100644 --- a/Automorph.h +++ b/Automorph.h @@ -10,7 +10,7 @@ See the included LICENSE file #include "NifFile.h" #include "KDMatcher.h" #include "Mesh.h" -#include "SliderData.h" +#include "SliderSet.h" #include "DiffData.h" #include "ObjFile.h" @@ -65,7 +65,6 @@ class Automorph { void SetRef(NifFile& Ref, const string& refShape = "BaseShape"); - int InitRefDiffData(const string& srcFileName, const string& dataSetName, const string& baseDataPath); void LinkRefDiffData(DiffDataSets* diffData); void UnlinkRefDiffData(); diff --git a/BodySlide.vcxproj b/BodySlide.vcxproj index 5a3eb215..8abcb1a8 100644 --- a/BodySlide.vcxproj +++ b/BodySlide.vcxproj @@ -135,6 +135,8 @@ + + Create Create @@ -174,6 +176,8 @@ + + diff --git a/BodySlide.vcxproj.filters b/BodySlide.vcxproj.filters index 0e2ca32b..3e041ba9 100644 --- a/BodySlide.vcxproj.filters +++ b/BodySlide.vcxproj.filters @@ -114,6 +114,12 @@ Source Files + + Source Files + + + Source Files + @@ -221,6 +227,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/OutfitProject.cpp b/OutfitProject.cpp index 463a376f..ff679e73 100644 --- a/OutfitProject.cpp +++ b/OutfitProject.cpp @@ -94,7 +94,7 @@ string OutfitProject::Save(const string& strFileName, owner->UpdateProgress(prog); for (int i = 0; i < activeSet.size(); i++) { id = outSet.CopySlider(&activeSet[i]); - outSet[id].ClearDataFiles(); + outSet[id].Clear(); if (copyRef && !baseShape.empty()) { targ = ShapeToTarget(baseShape); targSlider = activeSet[i].TargetDataName(targ); diff --git a/OutfitStudio.h b/OutfitStudio.h index d189c874..a9ca46f9 100644 --- a/OutfitStudio.h +++ b/OutfitStudio.h @@ -22,6 +22,7 @@ along with this program. If not, see . #include "wxStateButton.h" #include "GLSurface.h" #include "SliderData.h" +#include "SliderPresets.h" #include "ObjFile.h" #include "TweakBrush.h" #include "Automorph.h" diff --git a/SliderData.cpp b/SliderData.cpp index 41afe3d9..620b3a63 100644 --- a/SliderData.cpp +++ b/SliderData.cpp @@ -6,6 +6,8 @@ See the included LICENSE file #include "SliderData.h" +#include + SliderData::SliderData(const string& inName) { name = inName; bClamp = false; @@ -20,6 +22,9 @@ SliderData::SliderData(const string& inName) { defSmallValue = 0; } +SliderData::~SliderData() { +} + SliderData::SliderData(XMLElement* element) { LoadSliderData(element); } @@ -86,562 +91,5 @@ int SliderData::LoadSliderData(XMLElement* element) { if (numDatafiles == 0) return 1; - float reqval; - string reqslider; - XMLElement* requirement = element->FirstChildElement("require"); - while (requirement) { - reqval = requirement->FloatAttribute("value"); - reqslider = requirement->Attribute("slidername"); - requirements[reqslider] = reqval; - requirement = requirement->NextSiblingElement("require"); - } - return 0; -} - -SliderData::~SliderData() { -} - -SliderSet::SliderSet() { - genWeights = true; -} - -SliderSet::SliderSet(XMLElement* element) { - LoadSliderSet(element); -} - -SliderSet::~SliderSet() { -} - -void SliderSet::DeleteSlider(const string& setName) { - for (int i = 0; i < sliders.size(); i++) { - if (sliders[i].name == setName) { - sliders.erase(sliders.begin() + i); - return; - } - } -} - -int SliderSet::CreateSlider(const string& setName) { - sliders.emplace_back(setName); - return sliders.size() - 1; -} - -int SliderSet::CopySlider(SliderData* other) { - sliders.emplace_back(other->name); - SliderData* ms = &sliders.back(); - ms->bClamp = other->bClamp; - ms->bHidden = other->bHidden; - ms->bInvert = other->bInvert; - ms->bZap = other->bZap; - ms->defBigValue = other->defBigValue; - ms->defSmallValue = other->defSmallValue; - ms->dataFiles = other->dataFiles; - return sliders.size() - 1; -} - -int SliderSet::LoadSliderSet(XMLElement* element) { - name = element->Attribute("name"); - XMLElement* tmpElement; - tmpElement = element->FirstChildElement("SetFolder"); - if (tmpElement) - datafolder = tmpElement->GetText(); - tmpElement = element->FirstChildElement("SourceFile"); - if (tmpElement) - inputfile = tmpElement->GetText(); - tmpElement = element->FirstChildElement("OutputPath"); - if (tmpElement) - outputpath = tmpElement->GetText(); - - genWeights = true; - tmpElement = element->FirstChildElement("OutputFile"); - if (tmpElement) { - outputfile = tmpElement->GetText(); - if (tmpElement->Attribute("GenWeights")) { - string gw = tmpElement->Attribute("GenWeights"); - if (_strnicmp(gw.c_str(), "false", 5) == 0) { - genWeights = false; - } - } - } - - XMLElement* shapeName = element->FirstChildElement("BaseShapeName"); - while (shapeName) { - if (shapeName->Attribute("DataFolder")) - targetdatafolders[shapeName->Attribute("target")] = shapeName->Attribute("DataFolder"); - else - targetdatafolders[shapeName->Attribute("target")] = datafolder; - - targetshapenames[shapeName->Attribute("target")] = shapeName->GetText(); - shapeName = shapeName->NextSiblingElement("BaseShapeName"); - } - - XMLElement* sliderEntry = element->FirstChildElement("Slider"); - SliderData tmpSlider; - while (sliderEntry) { - tmpSlider.Clear(); - if (tmpSlider.LoadSliderData(sliderEntry) == 0) - sliders.push_back(tmpSlider); - - sliderEntry = sliderEntry->NextSiblingElement("Slider"); - } - return 0; -} - -void SliderSet::LoadSetDiffData(DiffDataSets& inDataStorage) { - string fullfilepath; - DiffDataFile f; - for (int i = 0; i < sliders.size(); i++) { - for (int j = 0; j < sliders[i].dataFiles.size(); j++) { - f = sliders[i].dataFiles[j]; - fullfilepath = baseDataPath + "\\"; - if (f.bLocal) - fullfilepath += datafolder + "\\"; - else - fullfilepath += targetdatafolders[f.targetName] + "\\"; - - fullfilepath += f.fileName; - inDataStorage.LoadSet(f.dataName, f.targetName, fullfilepath); - } - } -} - -void SliderSet::WriteSliderSet(XMLElement* sliderSetElement) { - sliderSetElement->DeleteChildren(); - sliderSetElement->SetAttribute("name", name.c_str()); - - XMLElement* newElement = sliderSetElement->GetDocument()->NewElement("SetFolder"); - XMLText* newText = sliderSetElement->GetDocument()->NewText(datafolder.c_str()); - sliderSetElement->InsertEndChild(newElement)->ToElement()->InsertEndChild(newText); - - newElement = sliderSetElement->GetDocument()->NewElement("SourceFile"); - newText = sliderSetElement->GetDocument()->NewText(inputfile.c_str()); - sliderSetElement->InsertEndChild(newElement)->ToElement()->InsertEndChild(newText); - - newElement = sliderSetElement->GetDocument()->NewElement("OutputPath"); - newText = sliderSetElement->GetDocument()->NewText(outputpath.c_str()); - sliderSetElement->InsertEndChild(newElement)->ToElement()->InsertEndChild(newText); - - newElement = sliderSetElement->GetDocument()->NewElement("OutputFile"); - XMLElement* outputFileElement = sliderSetElement->InsertEndChild(newElement)->ToElement(); - - if (!genWeights) - outputFileElement->SetAttribute("GenWeights", "false"); - - newText = sliderSetElement->GetDocument()->NewText(outputfile.c_str()); - outputFileElement->InsertEndChild(newText); - - XMLElement* baseShapeElement; - XMLElement* sliderElement; - XMLElement* dataFileElement; - - for (auto &tsn : targetshapenames) { - newElement = sliderSetElement->GetDocument()->NewElement("BaseShapeName"); - baseShapeElement = sliderSetElement->InsertEndChild(newElement)->ToElement(); - baseShapeElement->SetAttribute("target", tsn.first.c_str()); - if (targetdatafolders.find(tsn.first) != targetdatafolders.end()) - baseShapeElement->SetAttribute("DataFolder", targetdatafolders[tsn.first].c_str()); - - newText = sliderSetElement->GetDocument()->NewText(tsn.second.c_str()); - baseShapeElement->InsertEndChild(newText); - } - - for (auto &slider : sliders) { - if (slider.dataFiles.size() == 0) - continue; - - newElement = sliderSetElement->GetDocument()->NewElement("Slider"); - sliderElement = sliderSetElement->InsertEndChild(newElement)->ToElement(); - sliderElement->SetAttribute("name", slider.name.c_str()); - sliderElement->SetAttribute("invert", (slider.bInvert) ? "true" : "false"); - sliderElement->SetAttribute("small", (int)slider.defSmallValue); - sliderElement->SetAttribute("big", (int)slider.defBigValue); - if (slider.bHidden) - sliderElement->SetAttribute("hidden", "true"); - if (slider.bClamp) - sliderElement->SetAttribute("clamp", "true"); - if (slider.bZap) - sliderElement->SetAttribute("zap", "true"); - if (slider.bUV) - sliderElement->SetAttribute("uv", "true"); - for (auto &df : slider.dataFiles) { - newElement = sliderSetElement->GetDocument()->NewElement("datafile"); - dataFileElement = sliderElement->InsertEndChild(newElement)->ToElement(); - dataFileElement->SetAttribute("name", df.dataName.c_str()); - dataFileElement->SetAttribute("target", df.targetName.c_str()); - if (df.bLocal) { - dataFileElement->SetAttribute("local", "true"); - } - - // Hack! Force these clamp bsd's to use the new ones that don't include the CBBE offset. - // this is here in order to allow older slider sets to be opened by Outfit Studio and saved without - // telling the user about the offset. (OS clears out the offset naturally when loading the files, so everything lines up - // except for these old seam clamps.) - string fn = df.fileName; - if (fn == "LockSeamLo.bsd") - fn = "LockSeamLo2.bsd"; - if (fn == "LockSeamHi.bsd") - fn = "LockSeamHi2.bsd"; - if (fn == "NH_LockSeamLo.bsd") - fn = "NH_LockSeamLo2.bsd"; - if (fn == "NH_LockSeamHi.bsd") - fn = "NH_LockSeamHi2.bsd"; - - newText = sliderSetElement->GetDocument()->NewText(fn.c_str()); - dataFileElement->InsertEndChild(newText); - } - } -} - -string SliderSet::GetInputFileName() { - string o; - o = baseDataPath + "\\"; - o += datafolder + "\\"; - o += inputfile; - return o; -} - -string SliderSet::GetOutputFilePath() { - return outputpath + "\\" + outputfile; -} - -bool SliderSet::GenWeights() { - return genWeights; -} - -SliderSetFile::SliderSetFile(const string& srcFileName) :error(0) { - Open(srcFileName); -} - -void SliderSetFile::Open(const string& srcFileName) { - XMLElement* setElement; - string setname; - fileName = srcFileName; - error = doc.LoadFile(srcFileName.c_str()); - if (error) - return; - - root = doc.FirstChildElement("SliderSetInfo"); - if (!root) { - error = 100; - return; - } - - setElement = root->FirstChildElement("SliderSet"); - while (setElement) { - setname = setElement->Attribute("name"); - setsInFile[setname] = setElement; - setsOrder.push_back(setname); - setElement = setElement->NextSiblingElement("SliderSet"); - } -} - -void SliderSetFile::New(const string& newFileName) { - error = 0; - fileName = newFileName; - doc.Clear(); - - XMLElement* rootElement = doc.NewElement("SliderSetInfo"); - doc.InsertEndChild(rootElement); - root = doc.FirstChildElement("SliderSetInfo"); -} - -int SliderSetFile::GetSetNames(vector &outSetNames, bool append) { - if (!append) - outSetNames.clear(); - - for (auto &xmlit : setsInFile) - outSetNames.push_back(xmlit.first); - - return outSetNames.size(); -} - -int SliderSetFile::GetSetNamesUnsorted(vector &outSetNames, bool append) { - if (!append) { - outSetNames.clear(); - outSetNames.assign(setsOrder.begin(), setsOrder.end()); - } - else - outSetNames.insert(outSetNames.end(), setsOrder.begin(), setsOrder.end()); - - return outSetNames.size(); -} - -bool SliderSetFile::HasSet(const string &querySetName) { - return (setsInFile.find(querySetName) != setsInFile.end()); -} - -void SliderSetFile::SetShapes(const string& set, vector& outShapeNames) { - if (!HasSet(set)) - return; - - XMLElement* setElement = setsInFile[set]; - XMLElement* shapeElement = setElement->FirstChildElement("BaseShapeName"); - while (shapeElement) { - outShapeNames.push_back(shapeElement->GetText()); - shapeElement = shapeElement->NextSiblingElement("BaseShapeName"); - } -} - -void SliderSetFile::SetTargets(const string& set, vector& outTargetNames) { - if (!HasSet(set)) - return; - - XMLElement* setElement = setsInFile[set]; - XMLElement* shapeElement = setElement->FirstChildElement("BaseShapeName"); - while (shapeElement) { - outTargetNames.push_back(shapeElement->Attribute("target")); - shapeElement = shapeElement->NextSiblingElement("BaseShapeName"); - } -} - -int SliderSetFile::GetSet(const string &setName, SliderSet &outSliderSet) { - XMLElement* setPtr; - if (!HasSet(setName)) - return 1; - - setPtr = setsInFile[setName]; - - int ret; - ret = outSliderSet.LoadSliderSet(setPtr); - - return ret; -} - -int SliderSetFile::GetAllSets(vector &outAppendSets) { - int err; - SliderSet tmpSet; - for (auto &xmlit : setsInFile) { - err = tmpSet.LoadSliderSet(xmlit.second); - if (err) - return err; - outAppendSets.push_back(tmpSet); - } - return 0; -} - -int SliderSetFile::UpdateSet(SliderSet &inSliderSet) { - XMLElement* setPtr; - string setName; - setName = inSliderSet.GetName(); - if (HasSet(setName)) { - setPtr = setsInFile[setName]; - } - else { - XMLElement* tmpElement = doc.NewElement("SliderSet"); - tmpElement->SetAttribute("name", setName.c_str()); - setPtr = root->InsertEndChild(tmpElement)->ToElement(); - } - inSliderSet.WriteSliderSet(setPtr); - - return 0; -} - -int SliderSetFile::Save() { - return doc.SaveFile(fileName.c_str()) == XML_SUCCESS; -} - -void PresetCollection::Clear() { - namedSliderPresets.clear(); -} - -void PresetCollection::GetPresetNames(vector& outNames) { - for (auto &it : namedSliderPresets) - outNames.push_back(it.first); -} - -void PresetCollection::SetSliderPreset(const string& set, const string& slider, float big, float small) { - map newPreset; - SliderPreset sp; - if (namedSliderPresets.find(set) == namedSliderPresets.end()) { - sp.big = sp.small = -10000.0f; - if (big > -10000.0f) - sp.big = big; - if (small > -10000.0f) - sp.small = small; - newPreset[slider] = sp; - namedSliderPresets[set] = newPreset; - - } - else { - if (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end()) { - sp.big = sp.small = -10000.0f; - if (big > -10000.0f) - sp.big = big; - if (small > -10000.0f) - sp.small = small; - namedSliderPresets[set][slider] = sp; - } - else { - if (big > -10000.0f) { - namedSliderPresets[set][slider].big = big; - } - if (small > -10000.0f) { - namedSliderPresets[set][slider].small = small; - } - } - } -} - -bool PresetCollection::GetSliderExists(const string& set, const string& slider) { - if (namedSliderPresets.find(set) == namedSliderPresets.end()) - return false; - if (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end()) - return false; - - return true; -} - -bool PresetCollection::GetBigPreset(const string& set, const string& slider, float& big) { - float b; - if (namedSliderPresets.find(set) == namedSliderPresets.end()) - return false; - if (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end()) - return false; - b = namedSliderPresets[set][slider].big; - if (b > -10000.0f) { - big = b; - return true; - } - return false; -} - -bool PresetCollection::GetSmallPreset(const string& set, const string& slider, float& small) { - float b; - if (namedSliderPresets.find(set) == namedSliderPresets.end()) - return false; - if (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end()) - return false; - b = namedSliderPresets[set][slider].small; - if (b > -10000.0f) { - small = b; - return true; - } - return false; -} - -bool PresetCollection::LoadPresets(const string& basePath, const string& sliderSet, vector& groupFilter, bool allPresets) { - XMLDoc doc; - XMLElement* root; - XMLElement* element; - XMLElement* g; - XMLElement* setSlider; - - string presetName, sliderName, applyTo; - float o, b, s; - - wxArrayString files; - wxDir::GetAllFiles(basePath, &files, "*.xml"); - - for (auto &file : files) { - if (doc.LoadFile(file) != XML_SUCCESS) - continue; - - root = doc.FirstChildElement("SliderPresets"); - if (!root) - continue; - - element = root->FirstChildElement("Preset"); - while (element) { - bool skip = true; - g = element->FirstChildElement("Group"); - while (g) { - for (int i = 0; i < groupFilter.size(); i++) { - if (g->Attribute("name") == groupFilter[i]) { - skip = false; - break; - } - } - g = g->NextSiblingElement("Group"); - } - if (element->Attribute("set") == sliderSet || allPresets) - skip = false; - - if (skip) { - element = element->NextSiblingElement("Preset"); - continue; - } - - presetName = element->Attribute("name"); - setSlider = element->FirstChildElement("SetSlider"); - while (setSlider) { - sliderName = setSlider->Attribute("name"); - applyTo = setSlider->Attribute("size"); - o = setSlider->FloatAttribute("value") / 100.0f; - s = b = -10000.0f; - if (applyTo == "small") - s = o; - else if (applyTo == "big") - b = o; - else if (applyTo == "both") - s = b = o; - - SetSliderPreset(presetName, sliderName, b, s); - setSlider = setSlider->NextSiblingElement("SetSlider"); - } - element = element->NextSiblingElement("Preset"); - } - } - - return 0; -} - -int PresetCollection::SavePreset(const string& filePath, const string& presetName, const string& sliderSetName, vector& assignGroups) { - if (namedSliderPresets.find(presetName) == namedSliderPresets.end()) - return -1; - - XMLElement* newElement = nullptr; - XMLDoc outDoc; - XMLNode* slidersNode; - XMLElement* presetElem; - if (outDoc.LoadFile(filePath.c_str()) == XML_SUCCESS) { - // File exists - merge data. - slidersNode = outDoc.FirstChildElement("SliderPresets"); - presetElem = slidersNode->FirstChildElement("Preset"); - while (presetElem) { - // Replace preset if found in file. - if (_stricmp(presetElem->Attribute("name"), presetName.c_str()) == 0) { - XMLElement* tmpElem = presetElem; - presetElem = presetElem->NextSiblingElement("Preset"); - slidersNode->DeleteChild(tmpElem); - } - else - presetElem = presetElem->NextSiblingElement("Preset"); - } - } - else { - newElement = outDoc.NewElement("SliderPresets"); - slidersNode = outDoc.InsertEndChild(newElement); - } - - newElement = outDoc.NewElement("Preset"); - presetElem = slidersNode->InsertEndChild(newElement)->ToElement(); - presetElem->SetAttribute("name", presetName.c_str()); - presetElem->SetAttribute("set", sliderSetName.c_str()); - - XMLElement* sliderElem; - for (int i = 0; i < assignGroups.size(); i++){ - newElement = outDoc.NewElement("Group"); - sliderElem = presetElem->InsertEndChild(newElement)->ToElement(); - sliderElem->SetAttribute("name", assignGroups[i].c_str()); - } - for (auto &p : namedSliderPresets[presetName]) { - if (p.second.big > -10000.0f) { - newElement = outDoc.NewElement("SetSlider"); - sliderElem = presetElem->InsertEndChild(newElement)->ToElement(); - sliderElem->SetAttribute("name", p.first.c_str()); - sliderElem->SetAttribute("size", "big"); - sliderElem->SetAttribute("value", (int)(p.second.big * 100.0f)); - } - if (p.second.small > -10000.0f) { - newElement = outDoc.NewElement("SetSlider"); - sliderElem = presetElem->InsertEndChild(newElement)->ToElement(); - sliderElem->SetAttribute("name", p.first.c_str()); - sliderElem->SetAttribute("size", "small"); - sliderElem->SetAttribute("value", (int)(p.second.small * 100.0f)); - } - } - if (outDoc.SaveFile(filePath.c_str()) != XML_SUCCESS) - return outDoc.ErrorID(); - return 0; } diff --git a/SliderData.h b/SliderData.h index 95a77eb9..c2741fdf 100644 --- a/SliderData.h +++ b/SliderData.h @@ -9,7 +9,6 @@ See the included LICENSE file #include "tinyxml2.h" #include "DiffData.h" -#include #include #include @@ -26,19 +25,6 @@ struct DiffDataFile { } }; -class TextureVariant { -public: - // int is the texture channel to change, string is the texture file name. - // If there is no '\' in the texture file name, it assumes no change in texture path. - unordered_map tOverride; -}; - -class TextureVariantCollection { -public: - // Texture variants organized by shape name. - unordered_map shapeTexVariants; -}; - class SliderData { public: @@ -51,12 +37,11 @@ class SliderData float defSmallValue; float defBigValue; - // Outfit studio values + // Outfit Studio values float curValue; // Current slider value. bool bShow; // On to enable this slider when deforming verts. vector dataFiles; - map requirements; SliderData(const string& inName = ""); SliderData(XMLElement* element); @@ -100,286 +85,6 @@ class SliderData void Clear() { dataFiles.clear(); - requirements.clear(); - } - void ClearDataFiles() { - dataFiles.clear(); } int LoadSliderData(XMLElement* srcdata); }; - - -#define LOADSS_REFERENCE 1 // Excludes targets from slider set that are referenced. -#define LOADSS_DIRECT 2 // Excludes targets from slider set that are referenced. - -class SliderSet -{ - string name; - string baseDataPath; // Base data path - from application configuration. - string datafolder; // Default data folder specified for a slider set (overridden by target data folders, usually). - string inputfile; - string outputpath; - string outputfile; - bool genWeights; // Generate both low and high weight meshes on output. - map targetshapenames; // Target names mapped to nif file shape names. - map targetdatafolders; - - vector sliders; - - // Texture variants by variant name. - unordered_map texVariants; - - SliderData Empty; - -public: - SliderSet(); - SliderSet(XMLElement* sliderSetSource); - ~SliderSet(); - - void SetName(const string& newName) { - name = newName; - } - void SetDataFolder(const string& newDataFolder) { - datafolder = newDataFolder; - } - void SetInputFile(const string& newInputFile) { - inputfile = newInputFile; - } - void SetOutputPath(const string& newOutputpath) { - outputpath = newOutputpath; - } - void SetOutputFile(const string& newOutputFile) { - outputfile = newOutputFile; - } - void SetGenWeights(bool inGenWeights) { - genWeights = inGenWeights; - } - - int GetTargetShapeCount() { - return targetshapenames.size(); - } - - void Clear() { - targetshapenames.clear(); - targetdatafolders.clear(); - sliders.clear(); - } - - - void SetBaseDataPath(const string& inPath) { - baseDataPath = inPath; - } - - int LoadSliderSet(XMLElement* sliderSetSource); - void LoadSetDiffData(DiffDataSets& inDataStorage); - - // Add an empty set. - int CreateSlider(const string& setName); - - int CopySlider(SliderData* other); - - void WriteSliderSet(XMLElement* sliderSetElement); - - void DeleteSlider(const string& setName); - - string GetName() { - return name; - } - - string GetInputFileName(); - string GetOutputPath() { - return outputpath; - } - string GetOutputFile() { - return outputfile; - } - string GetOutputFilePath(); - string GetDefaultDataFolder() { - return datafolder; - } - bool GenWeights(); - - // Gets the target names in the targetdatafolders map - these are the shapes with non-local or referenced data. - // Use TargetToShape to get the NIF file shape name. - void GetReferencedTargets(vector &outTargets) { - for (auto &tdf : targetdatafolders) - if (tdf.second != datafolder) - outTargets.push_back(tdf.first); - } - - string TargetToShape(const string& targetName) { - if (targetshapenames.find(targetName) != targetshapenames.end()) - return targetshapenames[targetName]; - - return ""; - } - - // Adds a shape target and also ensures that any diff data in the set knows about the shape target. - void LinkShapeTarget(const string& shapeName, const string& targetName) { - targetshapenames[targetName] = shapeName; - for (auto &&s : sliders) - for (auto &df : s.dataFiles) - df.targetName = targetName; - } - - void ClearTargets(const string& oldTarget) { - targetshapenames.erase(oldTarget); - targetdatafolders.erase(oldTarget); - } - - void Retarget(const string& oldTarget, const string& newTarget) { - for (auto &s : sliders) - for (auto &df : s.dataFiles) - if (df.targetName == oldTarget) - df.targetName = newTarget; - } - - void AddShapeTarget(const string& shapeName, const string& targetName) { - targetshapenames[targetName] = shapeName; - } - - void RenameShape(const string& shapeName, const string& newShapeName) { - for (auto& tsn : targetshapenames) - if (tsn.second == shapeName) - tsn.second = newShapeName; - } - - void AddTargetDataFolder(const string& targetName, const string& datafolder) { - targetdatafolders[targetName] = datafolder; - } - - map::iterator TargetShapesBegin() { - return targetshapenames.begin(); - } - map::iterator TargetShapesEnd() { - return targetshapenames.end(); - } - - string ShapeToDataName(int index, const string& shapeName) { - for (auto &tsn : targetshapenames) - if (tsn.second == shapeName) - return sliders[index].TargetDataName(tsn.first); - - return ""; - } - - string ShapeToTarget(const string& shapeName) { - for (auto &tsn : targetshapenames) - if (tsn.second == shapeName) - return tsn.first; - - return ""; - } - - string ShapeToDataFolder(const string& shapeName) { - string t = ShapeToTarget(shapeName); - if (targetdatafolders.find(t) != targetdatafolders.end()) - return targetdatafolders[t]; - else - return datafolder; - } - - size_t size() { - return sliders.size(); - } - - SliderData& operator [] (int idx) { - return sliders[idx]; - } - - SliderData& operator [] (const string& sliderName) { - for (int i = 0; i < sliders.size(); i++) - if (sliders[i].name == sliderName) - return sliders[i]; - - return Empty; // Err... sorry... this is bad, but I really like returning references. - } - - bool SliderExists(const string& sliderName) { - for (int i = 0; i < sliders.size(); i++) - if (sliders[i].name == sliderName) - return true; - - return false; - } -}; - -/* Does not manage set information, just provides an interface for loading/saving to specfic set files. - information is maintained in the tinyxml document object, and sets can be retrieved and added/updated to that - document while the slidersetfile object exists. -*/ -class SliderSetFile { - XMLDoc doc; - XMLElement* root; - map setsInFile; - vector setsOrder; - int error; - -public: - string fileName; - SliderSetFile() : error(0) { } - SliderSetFile(const string& srcFileName); - ~SliderSetFile() { } - - bool fail() { - return error != 0; - } - int GetError() { - return error; - } - - // Loads the XML document and identifies included slider set names. On a failure, sets the internal error value. - void Open(const string& srcFileName); - - // Creates a new empty slider set document structure, ready to add new slider sets to. - void New(const string& newFileName); - - // Changes the internal file name. The xml file isn't saved until the save() function is used. Note the original - // file name is not changed. This method allows you to save a slider set as a new file without altering the original. - void Rename(const string& newFileName); - // Returns a list of all the slider sets found in the slider set file. - int GetSetNames(vector& outSetNames, bool append = true); - // Returns a list of all the slider sets found in the slider set file in the order they appear. - int GetSetNamesUnsorted(vector& outSetNames, bool append = true); - // Returns true if the set name exists. - bool HasSet(const string& querySetName); - - void SetShapes(const string& set, vector& outShapeNames); - void SetTargets(const string& set, vector& outTargetNames); - - // Adds all of the slider sets in the file to the supplied slider set vector. Does not clear the vector before doing so. - int GetAllSets(vector& outAppendSets); - // Gets a single slider set from the XML document based on the name. - int GetSet(const string& setName, SliderSet& outSliderSet); - // Updates a slider set in the xml document with the provided set's information. - // If the set does not already exist in the file (based on name) the set is added. - int UpdateSet(SliderSet& inSliderSet); - - // Writes the xml file using the internal fileName (use Rename() to change the name). - int Save(); -}; - - -#undef small - -class SliderPreset { -public: - float big; - float small; -}; - -class PresetCollection { - map> namedSliderPresets; -public: - - void Clear(); - - void GetPresetNames(vector& outNames); - void SetSliderPreset(const string& set, const string& slider, float big = -10000.0f, float small = -10000.0f); - bool GetSliderExists(const string& set, const string& slider); - bool GetBigPreset(const string& set, const string& slider, float& big); - bool GetSmallPreset(const string& set, const string& slider, float& small); - bool LoadPresets(const string& basePath, const string& sliderSet, vector& groupFilter, bool allPresets = false); - - int SavePreset(const string& filePath, const string& presetName, const string& sliderSetName, vector& assignGroups); -}; diff --git a/SliderManager.cpp b/SliderManager.cpp index 550c7abc..bd9a49c7 100644 --- a/SliderManager.cpp +++ b/SliderManager.cpp @@ -6,7 +6,6 @@ See the included LICENSE file #include "SliderManager.h" - SliderManager::SliderManager() { mSliderCount = 0; bNeedReload = true; @@ -37,9 +36,6 @@ void SliderManager::AddSlidersInSet(SliderSet& inSet, bool hideAll) { for (int j = 0; j < inSet[i].dataFiles.size(); j++) AddSliderLink(inSet[i].name, inSet[i].dataFiles[j].dataName); - - for (auto &reqIter : inSet[i].requirements) - AddSliderTrigger(reqIter.first, inSet[i].name, reqIter.second, 0); } } @@ -49,8 +45,8 @@ void SliderManager::AddSlider(const string& name, bool invert, const string& dat if (dataSetName.length() > 0) s.linkedDataSets.push_back(dataSetName); - s.value = 0; - s.defValue = 0; + s.value = 0.0f; + s.defValue = 0.0f; s.invert = invert; s.zap = false; s.clamp = false; @@ -148,45 +144,16 @@ void SliderManager::AddSliderLink(const string& slider, const string& dataSetNam slidersSmall[i].linkedDataSets.push_back(dataSetName); } -void SliderManager::AddSliderTrigger(const string& slider, const string& targetSlider, float triggerVal, uint triggerType) { - int targetIdx = -1; - int sliderIdx = -1; - SliderNotifyTrigger trigger; - trigger.triggerValue = triggerVal; - trigger.triggerType = triggerType; - for (int i = 0; i < slidersBig.size(); i++) { - if (slidersBig[i].name == slider) - sliderIdx = i; - if (slidersBig[i].name == targetSlider) - targetIdx = i; - } - if (sliderIdx >= 0 && targetIdx >= 0) { - trigger.targetSlider = slidersBig[targetIdx].name; - slidersBig[sliderIdx].triggers.push_back(trigger); - } - sliderIdx = -1; targetIdx = -1; - for (int i = 0; i < slidersSmall.size(); i++) { - if (slidersSmall[i].name == slider) - sliderIdx = i; - if (slidersSmall[i].name == targetSlider) - targetIdx = i; - } - if (sliderIdx >= 0 && targetIdx >= 0){ - trigger.targetSlider = slidersSmall[targetIdx].name; - slidersSmall[sliderIdx].triggers.push_back(trigger); - } -} - float SliderManager::GetSlider(const string& slider, bool isSmall) { if (!isSmall) { for (int i = 0; i < slidersBig.size(); i++) if (slidersBig[i].name == slider) - return slidersBig[i].Get(); + return slidersBig[i].value; } else { for (int i = 0; i < slidersSmall.size(); i++) if (slidersSmall[i].name == slider) - return slidersSmall[i].Get(); + return slidersSmall[i].value; } return 0.0f; } @@ -200,7 +167,7 @@ void SliderManager::SetSlider(const string& slider, bool isSmall, float val) { if (val > 0.0f) val = 1.0f; } - slidersBig[i].Set(val); + slidersBig[i].value = val; return; } } @@ -213,7 +180,7 @@ void SliderManager::SetSlider(const string& slider, bool isSmall, float val) { if (val > 0.0f) val = 1.0f; } - slidersSmall[i].Set(val); + slidersSmall[i].value = val; return; } } @@ -263,13 +230,13 @@ void SliderManager::InitializeSliders(const string& presetName) { if (!presetCollection.GetBigPreset(presetName, slidersBig[i].name, ps)) ps = slidersBig[i].defValue; - slidersBig[i].Set(ps); + slidersBig[i].value = ps; } for (int i = 0; i < slidersSmall.size(); i++) { if (!presetCollection.GetSmallPreset(presetName, slidersSmall[i].name, ps)) ps = slidersSmall[i].defValue; - slidersSmall[i].Set(ps); + slidersSmall[i].value = ps; } } diff --git a/SliderManager.h b/SliderManager.h index c11dadfe..fc661ff9 100644 --- a/SliderManager.h +++ b/SliderManager.h @@ -6,22 +6,11 @@ See the included LICENSE file #pragma once -#include "stdafx.h" -#include "NifFile.h" -#include "DiffData.h" -#include "SliderData.h" - -#include +#include "SliderSet.h" +#include "SliderPresets.h" using namespace std; -class SliderNotifyTrigger { -public: - float triggerValue; - ushort triggerType; - string targetSlider; -}; - class Slider { public: string name; @@ -33,14 +22,6 @@ class Slider { float defValue; float value; vector linkedDataSets; - vector triggers; - - float Get() { - return value; - } - void Set(float val) { - value = val; - } }; class SliderManager { @@ -101,7 +82,6 @@ class SliderManager { void SetSliderDefaults(const string& slider, float bigVal, float smallVal); void SetClampSlider(const string& slider); void AddSliderLink(const string& slider, const string& dataSetName); - void AddSliderTrigger(const string& slider, const string& targetSlider, float triggerVal, uint triggerType); float GetSlider(const string& slider, bool isSmall); void SetSlider(const string& slider, bool isSmall, float val); @@ -115,7 +95,10 @@ class SliderManager { void FlagReload(bool needReload) { bNeedReload = needReload; } - bool NeedReload() { return bNeedReload; } + + bool NeedReload() { + return bNeedReload; + } void GetSmallSliderList(vector& names); void GetBigSliderList(vector& names); diff --git a/SliderPresets.cpp b/SliderPresets.cpp new file mode 100644 index 00000000..6904cdb4 --- /dev/null +++ b/SliderPresets.cpp @@ -0,0 +1,218 @@ +/* +BodySlide and Outfit Studio +Copyright (C) 2015 Caliente & ousnius +See the included LICENSE file +*/ + +#include "tinyxml2.h" +#include "SliderPresets.h" + +#include + +using namespace tinyxml2; + +void PresetCollection::Clear() { + namedSliderPresets.clear(); +} + +void PresetCollection::GetPresetNames(vector& outNames) { + for (auto &it : namedSliderPresets) + outNames.push_back(it.first); +} + +void PresetCollection::SetSliderPreset(const string& set, const string& slider, float big, float small) { + map newPreset; + SliderPreset sp; + if (namedSliderPresets.find(set) == namedSliderPresets.end()) { + sp.big = sp.small = -10000.0f; + if (big > -10000.0f) + sp.big = big; + if (small > -10000.0f) + sp.small = small; + newPreset[slider] = sp; + namedSliderPresets[set] = newPreset; + + } + else { + if (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end()) { + sp.big = sp.small = -10000.0f; + if (big > -10000.0f) + sp.big = big; + if (small > -10000.0f) + sp.small = small; + namedSliderPresets[set][slider] = sp; + } + else { + if (big > -10000.0f) { + namedSliderPresets[set][slider].big = big; + } + if (small > -10000.0f) { + namedSliderPresets[set][slider].small = small; + } + } + } +} + +bool PresetCollection::GetSliderExists(const string& set, const string& slider) { + if (namedSliderPresets.find(set) == namedSliderPresets.end()) + return false; + if (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end()) + return false; + + return true; +} + +bool PresetCollection::GetBigPreset(const string& set, const string& slider, float& big) { + float b; + if (namedSliderPresets.find(set) == namedSliderPresets.end()) + return false; + if (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end()) + return false; + b = namedSliderPresets[set][slider].big; + if (b > -10000.0f) { + big = b; + return true; + } + return false; +} + +bool PresetCollection::GetSmallPreset(const string& set, const string& slider, float& small) { + float b; + if (namedSliderPresets.find(set) == namedSliderPresets.end()) + return false; + if (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end()) + return false; + b = namedSliderPresets[set][slider].small; + if (b > -10000.0f) { + small = b; + return true; + } + return false; +} + +bool PresetCollection::LoadPresets(const string& basePath, const string& sliderSet, vector& groupFilter, bool allPresets) { + XMLDoc doc; + XMLElement* root; + XMLElement* element; + XMLElement* g; + XMLElement* setSlider; + + string presetName, sliderName, applyTo; + float o, b, s; + + wxArrayString files; + wxDir::GetAllFiles(basePath, &files, "*.xml"); + + for (auto &file : files) { + if (doc.LoadFile(file) != XML_SUCCESS) + continue; + + root = doc.FirstChildElement("SliderPresets"); + if (!root) + continue; + + element = root->FirstChildElement("Preset"); + while (element) { + bool skip = true; + g = element->FirstChildElement("Group"); + while (g) { + for (auto &filter : groupFilter) { + if (g->Attribute("name") == filter) { + skip = false; + break; + } + } + g = g->NextSiblingElement("Group"); + } + if (element->Attribute("set") == sliderSet || allPresets) + skip = false; + + if (skip) { + element = element->NextSiblingElement("Preset"); + continue; + } + + presetName = element->Attribute("name"); + setSlider = element->FirstChildElement("SetSlider"); + while (setSlider) { + sliderName = setSlider->Attribute("name"); + applyTo = setSlider->Attribute("size"); + o = setSlider->FloatAttribute("value") / 100.0f; + s = b = -10000.0f; + if (applyTo == "small") + s = o; + else if (applyTo == "big") + b = o; + else if (applyTo == "both") + s = b = o; + + SetSliderPreset(presetName, sliderName, b, s); + setSlider = setSlider->NextSiblingElement("SetSlider"); + } + element = element->NextSiblingElement("Preset"); + } + } + + return 0; +} + +int PresetCollection::SavePreset(const string& filePath, const string& presetName, const string& sliderSetName, vector& assignGroups) { + if (namedSliderPresets.find(presetName) == namedSliderPresets.end()) + return -1; + + XMLElement* newElement = nullptr; + XMLDoc outDoc; + XMLNode* slidersNode; + XMLElement* presetElem; + if (outDoc.LoadFile(filePath.c_str()) == XML_SUCCESS) { + // File exists - merge data. + slidersNode = outDoc.FirstChildElement("SliderPresets"); + presetElem = slidersNode->FirstChildElement("Preset"); + while (presetElem) { + // Replace preset if found in file. + if (_stricmp(presetElem->Attribute("name"), presetName.c_str()) == 0) { + XMLElement* tmpElem = presetElem; + presetElem = presetElem->NextSiblingElement("Preset"); + slidersNode->DeleteChild(tmpElem); + } + else + presetElem = presetElem->NextSiblingElement("Preset"); + } + } + else { + newElement = outDoc.NewElement("SliderPresets"); + slidersNode = outDoc.InsertEndChild(newElement); + } + + newElement = outDoc.NewElement("Preset"); + presetElem = slidersNode->InsertEndChild(newElement)->ToElement(); + presetElem->SetAttribute("name", presetName.c_str()); + presetElem->SetAttribute("set", sliderSetName.c_str()); + + XMLElement* sliderElem; + for (auto &group : assignGroups) { + newElement = outDoc.NewElement("Group"); + sliderElem = presetElem->InsertEndChild(newElement)->ToElement(); + sliderElem->SetAttribute("name", group.c_str()); + } + for (auto &p : namedSliderPresets[presetName]) { + if (p.second.big > -10000.0f) { + newElement = outDoc.NewElement("SetSlider"); + sliderElem = presetElem->InsertEndChild(newElement)->ToElement(); + sliderElem->SetAttribute("name", p.first.c_str()); + sliderElem->SetAttribute("size", "big"); + sliderElem->SetAttribute("value", (int)(p.second.big * 100.0f)); + } + if (p.second.small > -10000.0f) { + newElement = outDoc.NewElement("SetSlider"); + sliderElem = presetElem->InsertEndChild(newElement)->ToElement(); + sliderElem->SetAttribute("name", p.first.c_str()); + sliderElem->SetAttribute("size", "small"); + sliderElem->SetAttribute("value", (int)(p.second.small * 100.0f)); + } + } + if (outDoc.SaveFile(filePath.c_str()) != XML_SUCCESS) + return outDoc.ErrorID(); + + return 0; +} \ No newline at end of file diff --git a/SliderPresets.h b/SliderPresets.h new file mode 100644 index 00000000..7c0c391b --- /dev/null +++ b/SliderPresets.h @@ -0,0 +1,34 @@ +/* +BodySlide and Outfit Studio +Copyright (C) 2015 Caliente & ousnius +See the included LICENSE file +*/ + +#pragma once + +#include +#include + +using namespace std; + +class SliderPreset { +public: + float big; + float small; +}; + +class PresetCollection { + map> namedSliderPresets; +public: + + void Clear(); + + void GetPresetNames(vector& outNames); + void SetSliderPreset(const string& set, const string& slider, float big = -10000.0f, float small = -10000.0f); + bool GetSliderExists(const string& set, const string& slider); + bool GetBigPreset(const string& set, const string& slider, float& big); + bool GetSmallPreset(const string& set, const string& slider, float& small); + bool LoadPresets(const string& basePath, const string& sliderSet, vector& groupFilter, bool allPresets = false); + + int SavePreset(const string& filePath, const string& presetName, const string& sliderSetName, vector& assignGroups); +}; diff --git a/SliderSet.cpp b/SliderSet.cpp new file mode 100644 index 00000000..07c848e6 --- /dev/null +++ b/SliderSet.cpp @@ -0,0 +1,352 @@ +/* +BodySlide and Outfit Studio +Copyright (C) 2015 Caliente & ousnius +See the included LICENSE file +*/ + +#include "SliderSet.h" + +SliderSet::SliderSet() { + genWeights = true; +} + +SliderSet::SliderSet(XMLElement* element) { + LoadSliderSet(element); +} + +SliderSet::~SliderSet() { +} + +void SliderSet::DeleteSlider(const string& setName) { + for (int i = 0; i < sliders.size(); i++) { + if (sliders[i].name == setName) { + sliders.erase(sliders.begin() + i); + return; + } + } +} + +int SliderSet::CreateSlider(const string& setName) { + sliders.emplace_back(setName); + return sliders.size() - 1; +} + +int SliderSet::CopySlider(SliderData* other) { + sliders.emplace_back(other->name); + SliderData* ms = &sliders.back(); + ms->bClamp = other->bClamp; + ms->bHidden = other->bHidden; + ms->bInvert = other->bInvert; + ms->bZap = other->bZap; + ms->defBigValue = other->defBigValue; + ms->defSmallValue = other->defSmallValue; + ms->dataFiles = other->dataFiles; + return sliders.size() - 1; +} + +int SliderSet::LoadSliderSet(XMLElement* element) { + name = element->Attribute("name"); + XMLElement* tmpElement; + tmpElement = element->FirstChildElement("SetFolder"); + if (tmpElement) + datafolder = tmpElement->GetText(); + tmpElement = element->FirstChildElement("SourceFile"); + if (tmpElement) + inputfile = tmpElement->GetText(); + tmpElement = element->FirstChildElement("OutputPath"); + if (tmpElement) + outputpath = tmpElement->GetText(); + + genWeights = true; + tmpElement = element->FirstChildElement("OutputFile"); + if (tmpElement) { + outputfile = tmpElement->GetText(); + if (tmpElement->Attribute("GenWeights")) { + string gw = tmpElement->Attribute("GenWeights"); + if (_strnicmp(gw.c_str(), "false", 5) == 0) { + genWeights = false; + } + } + } + + XMLElement* shapeName = element->FirstChildElement("BaseShapeName"); + while (shapeName) { + if (shapeName->Attribute("DataFolder")) + targetdatafolders[shapeName->Attribute("target")] = shapeName->Attribute("DataFolder"); + else + targetdatafolders[shapeName->Attribute("target")] = datafolder; + + targetshapenames[shapeName->Attribute("target")] = shapeName->GetText(); + shapeName = shapeName->NextSiblingElement("BaseShapeName"); + } + + XMLElement* sliderEntry = element->FirstChildElement("Slider"); + SliderData tmpSlider; + while (sliderEntry) { + tmpSlider.Clear(); + if (tmpSlider.LoadSliderData(sliderEntry) == 0) + sliders.push_back(tmpSlider); + + sliderEntry = sliderEntry->NextSiblingElement("Slider"); + } + return 0; +} + +void SliderSet::LoadSetDiffData(DiffDataSets& inDataStorage) { + string fullfilepath; + DiffDataFile f; + for (int i = 0; i < sliders.size(); i++) { + for (int j = 0; j < sliders[i].dataFiles.size(); j++) { + f = sliders[i].dataFiles[j]; + fullfilepath = baseDataPath + "\\"; + if (f.bLocal) + fullfilepath += datafolder + "\\"; + else + fullfilepath += targetdatafolders[f.targetName] + "\\"; + + fullfilepath += f.fileName; + inDataStorage.LoadSet(f.dataName, f.targetName, fullfilepath); + } + } +} + +void SliderSet::WriteSliderSet(XMLElement* sliderSetElement) { + sliderSetElement->DeleteChildren(); + sliderSetElement->SetAttribute("name", name.c_str()); + + XMLElement* newElement = sliderSetElement->GetDocument()->NewElement("SetFolder"); + XMLText* newText = sliderSetElement->GetDocument()->NewText(datafolder.c_str()); + sliderSetElement->InsertEndChild(newElement)->ToElement()->InsertEndChild(newText); + + newElement = sliderSetElement->GetDocument()->NewElement("SourceFile"); + newText = sliderSetElement->GetDocument()->NewText(inputfile.c_str()); + sliderSetElement->InsertEndChild(newElement)->ToElement()->InsertEndChild(newText); + + newElement = sliderSetElement->GetDocument()->NewElement("OutputPath"); + newText = sliderSetElement->GetDocument()->NewText(outputpath.c_str()); + sliderSetElement->InsertEndChild(newElement)->ToElement()->InsertEndChild(newText); + + newElement = sliderSetElement->GetDocument()->NewElement("OutputFile"); + XMLElement* outputFileElement = sliderSetElement->InsertEndChild(newElement)->ToElement(); + + if (!genWeights) + outputFileElement->SetAttribute("GenWeights", "false"); + + newText = sliderSetElement->GetDocument()->NewText(outputfile.c_str()); + outputFileElement->InsertEndChild(newText); + + XMLElement* baseShapeElement; + XMLElement* sliderElement; + XMLElement* dataFileElement; + + for (auto &tsn : targetshapenames) { + newElement = sliderSetElement->GetDocument()->NewElement("BaseShapeName"); + baseShapeElement = sliderSetElement->InsertEndChild(newElement)->ToElement(); + baseShapeElement->SetAttribute("target", tsn.first.c_str()); + if (targetdatafolders.find(tsn.first) != targetdatafolders.end()) + baseShapeElement->SetAttribute("DataFolder", targetdatafolders[tsn.first].c_str()); + + newText = sliderSetElement->GetDocument()->NewText(tsn.second.c_str()); + baseShapeElement->InsertEndChild(newText); + } + + for (auto &slider : sliders) { + if (slider.dataFiles.size() == 0) + continue; + + newElement = sliderSetElement->GetDocument()->NewElement("Slider"); + sliderElement = sliderSetElement->InsertEndChild(newElement)->ToElement(); + sliderElement->SetAttribute("name", slider.name.c_str()); + sliderElement->SetAttribute("invert", (slider.bInvert) ? "true" : "false"); + sliderElement->SetAttribute("small", (int)slider.defSmallValue); + sliderElement->SetAttribute("big", (int)slider.defBigValue); + if (slider.bHidden) + sliderElement->SetAttribute("hidden", "true"); + if (slider.bClamp) + sliderElement->SetAttribute("clamp", "true"); + if (slider.bZap) + sliderElement->SetAttribute("zap", "true"); + if (slider.bUV) + sliderElement->SetAttribute("uv", "true"); + for (auto &df : slider.dataFiles) { + newElement = sliderSetElement->GetDocument()->NewElement("datafile"); + dataFileElement = sliderElement->InsertEndChild(newElement)->ToElement(); + dataFileElement->SetAttribute("name", df.dataName.c_str()); + dataFileElement->SetAttribute("target", df.targetName.c_str()); + if (df.bLocal) { + dataFileElement->SetAttribute("local", "true"); + } + + // Hack! Force these clamp bsd's to use the new ones that don't include the CBBE offset. + // this is here in order to allow older slider sets to be opened by Outfit Studio and saved without + // telling the user about the offset. (OS clears out the offset naturally when loading the files, so everything lines up + // except for these old seam clamps.) + string fn = df.fileName; + if (fn == "LockSeamLo.bsd") + fn = "LockSeamLo2.bsd"; + if (fn == "LockSeamHi.bsd") + fn = "LockSeamHi2.bsd"; + if (fn == "NH_LockSeamLo.bsd") + fn = "NH_LockSeamLo2.bsd"; + if (fn == "NH_LockSeamHi.bsd") + fn = "NH_LockSeamHi2.bsd"; + + newText = sliderSetElement->GetDocument()->NewText(fn.c_str()); + dataFileElement->InsertEndChild(newText); + } + } +} + +string SliderSet::GetInputFileName() { + string o; + o = baseDataPath + "\\"; + o += datafolder + "\\"; + o += inputfile; + return o; +} + +string SliderSet::GetOutputFilePath() { + return outputpath + "\\" + outputfile; +} + +bool SliderSet::GenWeights() { + return genWeights; +} + +SliderSetFile::SliderSetFile(const string& srcFileName) :error(0) { + Open(srcFileName); +} + +void SliderSetFile::Open(const string& srcFileName) { + fileName = srcFileName; + error = doc.LoadFile(srcFileName.c_str()); + if (error) + return; + + root = doc.FirstChildElement("SliderSetInfo"); + if (!root) { + error = 100; + return; + } + + version = root->IntAttribute("Version"); + + XMLElement* setElement; + string setname; + setElement = root->FirstChildElement("SliderSet"); + while (setElement) { + setname = setElement->Attribute("name"); + setsInFile[setname] = setElement; + setsOrder.push_back(setname); + setElement = setElement->NextSiblingElement("SliderSet"); + } +} + +void SliderSetFile::New(const string& newFileName) { + version = 1; // Most recent + error = 0; + fileName = newFileName; + doc.Clear(); + + XMLElement* rootElement = doc.NewElement("SliderSetInfo"); + if (version > 0) + rootElement->SetAttribute("Version", version); + + doc.InsertEndChild(rootElement); + root = doc.FirstChildElement("SliderSetInfo"); +} + +int SliderSetFile::GetSetNames(vector &outSetNames, bool append) { + if (!append) + outSetNames.clear(); + + for (auto &xmlit : setsInFile) + outSetNames.push_back(xmlit.first); + + return outSetNames.size(); +} + +int SliderSetFile::GetSetNamesUnsorted(vector &outSetNames, bool append) { + if (!append) { + outSetNames.clear(); + outSetNames.assign(setsOrder.begin(), setsOrder.end()); + } + else + outSetNames.insert(outSetNames.end(), setsOrder.begin(), setsOrder.end()); + + return outSetNames.size(); +} + +bool SliderSetFile::HasSet(const string &querySetName) { + return (setsInFile.find(querySetName) != setsInFile.end()); +} + +void SliderSetFile::SetShapes(const string& set, vector& outShapeNames) { + if (!HasSet(set)) + return; + + XMLElement* setElement = setsInFile[set]; + XMLElement* shapeElement = setElement->FirstChildElement("BaseShapeName"); + while (shapeElement) { + outShapeNames.push_back(shapeElement->GetText()); + shapeElement = shapeElement->NextSiblingElement("BaseShapeName"); + } +} + +void SliderSetFile::SetTargets(const string& set, vector& outTargetNames) { + if (!HasSet(set)) + return; + + XMLElement* setElement = setsInFile[set]; + XMLElement* shapeElement = setElement->FirstChildElement("BaseShapeName"); + while (shapeElement) { + outTargetNames.push_back(shapeElement->Attribute("target")); + shapeElement = shapeElement->NextSiblingElement("BaseShapeName"); + } +} + +int SliderSetFile::GetSet(const string &setName, SliderSet &outSliderSet) { + XMLElement* setPtr; + if (!HasSet(setName)) + return 1; + + setPtr = setsInFile[setName]; + + int ret; + ret = outSliderSet.LoadSliderSet(setPtr); + + return ret; +} + +int SliderSetFile::GetAllSets(vector &outAppendSets) { + int err; + SliderSet tmpSet; + for (auto &xmlit : setsInFile) { + err = tmpSet.LoadSliderSet(xmlit.second); + if (err) + return err; + outAppendSets.push_back(tmpSet); + } + return 0; +} + +int SliderSetFile::UpdateSet(SliderSet &inSliderSet) { + XMLElement* setPtr; + string setName; + setName = inSliderSet.GetName(); + if (HasSet(setName)) { + setPtr = setsInFile[setName]; + } + else { + XMLElement* tmpElement = doc.NewElement("SliderSet"); + tmpElement->SetAttribute("name", setName.c_str()); + setPtr = root->InsertEndChild(tmpElement)->ToElement(); + } + inSliderSet.WriteSliderSet(setPtr); + + return 0; +} + +int SliderSetFile::Save() { + return doc.SaveFile(fileName.c_str()) == XML_SUCCESS; +} diff --git a/SliderSet.h b/SliderSet.h new file mode 100644 index 00000000..d60697cb --- /dev/null +++ b/SliderSet.h @@ -0,0 +1,258 @@ +/* +BodySlide and Outfit Studio +Copyright (C) 2015 Caliente & ousnius +See the included LICENSE file +*/ + +#pragma once + +#include "tinyxml2.h" +#include "SliderData.h" + +using namespace std; +using namespace tinyxml2; + +class SliderSet +{ + string name; + string baseDataPath; // Base data path - from application configuration. + string datafolder; // Default data folder specified for a slider set (overridden by target data folders, usually). + string inputfile; + string outputpath; + string outputfile; + bool genWeights; // Generate both low and high weight meshes on output. + map targetshapenames; // Target names mapped to nif file shape names. + map targetdatafolders; + + vector sliders; + + SliderData Empty; + +public: + SliderSet(); + SliderSet(XMLElement* sliderSetSource); + ~SliderSet(); + + void SetName(const string& newName) { + name = newName; + } + void SetDataFolder(const string& newDataFolder) { + datafolder = newDataFolder; + } + void SetInputFile(const string& newInputFile) { + inputfile = newInputFile; + } + void SetOutputPath(const string& newOutputpath) { + outputpath = newOutputpath; + } + void SetOutputFile(const string& newOutputFile) { + outputfile = newOutputFile; + } + void SetGenWeights(bool inGenWeights) { + genWeights = inGenWeights; + } + + int GetTargetShapeCount() { + return targetshapenames.size(); + } + + void Clear() { + targetshapenames.clear(); + targetdatafolders.clear(); + sliders.clear(); + } + + + void SetBaseDataPath(const string& inPath) { + baseDataPath = inPath; + } + + int LoadSliderSet(XMLElement* sliderSetSource); + void LoadSetDiffData(DiffDataSets& inDataStorage); + + // Add an empty set. + int CreateSlider(const string& setName); + + int CopySlider(SliderData* other); + + void WriteSliderSet(XMLElement* sliderSetElement); + + void DeleteSlider(const string& setName); + + string GetName() { + return name; + } + + string GetInputFileName(); + string GetOutputPath() { + return outputpath; + } + string GetOutputFile() { + return outputfile; + } + string GetOutputFilePath(); + string GetDefaultDataFolder() { + return datafolder; + } + bool GenWeights(); + + // Gets the target names in the targetdatafolders map - these are the shapes with non-local or referenced data. + // Use TargetToShape to get the NIF file shape name. + void GetReferencedTargets(vector &outTargets) { + for (auto &tdf : targetdatafolders) + if (tdf.second != datafolder) + outTargets.push_back(tdf.first); + } + + string TargetToShape(const string& targetName) { + if (targetshapenames.find(targetName) != targetshapenames.end()) + return targetshapenames[targetName]; + + return ""; + } + + // Adds a shape target and also ensures that any diff data in the set knows about the shape target. + void LinkShapeTarget(const string& shapeName, const string& targetName) { + targetshapenames[targetName] = shapeName; + for (auto &&s : sliders) + for (auto &df : s.dataFiles) + df.targetName = targetName; + } + + void ClearTargets(const string& oldTarget) { + targetshapenames.erase(oldTarget); + targetdatafolders.erase(oldTarget); + } + + void Retarget(const string& oldTarget, const string& newTarget) { + for (auto &s : sliders) + for (auto &df : s.dataFiles) + if (df.targetName == oldTarget) + df.targetName = newTarget; + } + + void AddShapeTarget(const string& shapeName, const string& targetName) { + targetshapenames[targetName] = shapeName; + } + + void RenameShape(const string& shapeName, const string& newShapeName) { + for (auto& tsn : targetshapenames) + if (tsn.second == shapeName) + tsn.second = newShapeName; + } + + void AddTargetDataFolder(const string& targetName, const string& datafolder) { + targetdatafolders[targetName] = datafolder; + } + + map::iterator TargetShapesBegin() { + return targetshapenames.begin(); + } + map::iterator TargetShapesEnd() { + return targetshapenames.end(); + } + + string ShapeToDataName(int index, const string& shapeName) { + for (auto &tsn : targetshapenames) + if (tsn.second == shapeName) + return sliders[index].TargetDataName(tsn.first); + + return ""; + } + + string ShapeToTarget(const string& shapeName) { + for (auto &tsn : targetshapenames) + if (tsn.second == shapeName) + return tsn.first; + + return ""; + } + + string ShapeToDataFolder(const string& shapeName) { + string t = ShapeToTarget(shapeName); + if (targetdatafolders.find(t) != targetdatafolders.end()) + return targetdatafolders[t]; + else + return datafolder; + } + + size_t size() { + return sliders.size(); + } + + SliderData& operator [] (int idx) { + return sliders[idx]; + } + + SliderData& operator [] (const string& sliderName) { + for (int i = 0; i < sliders.size(); i++) + if (sliders[i].name == sliderName) + return sliders[i]; + + return Empty; // Err... sorry... this is bad, but I really like returning references. + } + + bool SliderExists(const string& sliderName) { + for (int i = 0; i < sliders.size(); i++) + if (sliders[i].name == sliderName) + return true; + + return false; + } +}; + +/* Does not manage set information, just provides an interface for loading/saving to specfic set files. +information is maintained in the tinyxml document object, and sets can be retrieved and added/updated to that +document while the slidersetfile object exists. +*/ +class SliderSetFile { + XMLDoc doc; + XMLElement* root; + map setsInFile; + vector setsOrder; + int version; + int error; + +public: + string fileName; + SliderSetFile() : error(0) { } + SliderSetFile(const string& srcFileName); + ~SliderSetFile() { } + + bool fail() { + return error != 0; + } + int GetError() { + return error; + } + + // Loads the XML document and identifies included slider set names. On a failure, sets the internal error value. + void Open(const string& srcFileName); + + // Creates a new empty slider set document structure, ready to add new slider sets to. + void New(const string& newFileName); + + // Changes the internal file name. The xml file isn't saved until the save() function is used. Note the original + // file name is not changed. This method allows you to save a slider set as a new file without altering the original. + void Rename(const string& newFileName); + // Returns a list of all the slider sets found in the slider set file. + int GetSetNames(vector& outSetNames, bool append = true); + // Returns a list of all the slider sets found in the slider set file in the order they appear. + int GetSetNamesUnsorted(vector& outSetNames, bool append = true); + // Returns true if the set name exists. + bool HasSet(const string& querySetName); + + void SetShapes(const string& set, vector& outShapeNames); + void SetTargets(const string& set, vector& outTargetNames); + + // Adds all of the slider sets in the file to the supplied slider set vector. Does not clear the vector before doing so. + int GetAllSets(vector& outAppendSets); + // Gets a single slider set from the XML document based on the name. + int GetSet(const string& setName, SliderSet& outSliderSet); + // Updates a slider set in the xml document with the provided set's information. + // If the set does not already exist in the file (based on name) the set is added. + int UpdateSet(SliderSet& inSliderSet); + + // Writes the xml file using the internal fileName (use Rename() to change the name). + int Save(); +}; From 431ce05c5664ca8a1e7a9b22a47ffc4508041b8b Mon Sep 17 00:00:00 2001 From: ousnius Date: Fri, 4 Dec 2015 00:54:19 +0100 Subject: [PATCH 22/64] New file formats: .osp and .osd .osp format is the slider set XML with a few minor changes and adjustments for the .osd format. Can do file association now. .osd format are the BSD files merged into one bigger file. Everything is fully backwards-compatible. New saving only happens as .osp and .osd. Slider properties dialog still needs a value for the "default" slider value, not just the "small" and "big" defaults. --- Automorph.cpp | 10 ---- Automorph.h | 3 +- DiffData.cpp | 136 +++++++++++++++++++++++++++++++++++++++++-- DiffData.h | 19 ++++++ OutfitProject.cpp | 63 +++++++++++++------- OutfitStudio.cpp | 21 ++++--- SliderData.cpp | 39 ++++++++----- SliderData.h | 12 ++-- SliderSet.cpp | 132 +++++++++++++++++++++-------------------- SliderSet.h | 9 --- res/outfitStudio.xrc | 18 +++--- 11 files changed, 312 insertions(+), 150 deletions(-) diff --git a/Automorph.cpp b/Automorph.cpp index c8fd83d7..2930f3b2 100644 --- a/Automorph.cpp +++ b/Automorph.cpp @@ -27,16 +27,6 @@ Automorph::~Automorph() { ClearSourceShapes(); } -Automorph::Automorph(NifFile &ref, const string& refShape) { - morphRef = nullptr; - refTree = nullptr; - srcDiffData = nullptr; - bEnableMask = true; - proximity_radius = 10.0f; - max_prox_points = 5.0f; - SetRef(ref, refShape); -} - void Automorph::ClearSourceShapes() { for (auto &shapes : sourceShapes) { if (foreignShapes.find(shapes.first) != foreignShapes.end()) diff --git a/Automorph.h b/Automorph.h index 172c8f6c..6c17e086 100644 --- a/Automorph.h +++ b/Automorph.h @@ -48,7 +48,6 @@ class Automorph { int minCount; Automorph(); - Automorph(NifFile& ref, const string& refShape = "BaseShape"); ~Automorph(); void ClearResultDiff() { @@ -63,7 +62,7 @@ class Automorph { bEnableMask = enable; } - void SetRef(NifFile& Ref, const string& refShape = "BaseShape"); + void SetRef(NifFile& Ref, const string& refShape); void LinkRefDiffData(DiffDataSets* diffData); void UnlinkRefDiffData(); diff --git a/DiffData.cpp b/DiffData.cpp index 3f113a5f..924a8034 100644 --- a/DiffData.cpp +++ b/DiffData.cpp @@ -8,6 +8,96 @@ See the included LICENSE file #include +OSDataFile::OSDataFile() { + header = 'OSD\0'; + version = 1; + dataCount = 0; +} + +OSDataFile::~OSDataFile() { +} + +int OSDataFile::Read(const string& fileName) { + ifstream file(fileName, ios_base::binary); + if (!file) + return 1; + + file.read((char*)&header, 4); + if (header != 'OSD\0') + return 2; + + file.read((char*)&version, 4); + file.read((char*)&dataCount, 4); + + byte nameLength; + string dataName; + ushort diffSize; + for (int i = 0; i < dataCount; ++i) { + file.read((char*)&nameLength, 1); + dataName.resize(nameLength, ' '); + file.read((char*)&dataName.front(), nameLength); + + ushort index; + Vector3 diff; + unordered_map diffs; + file.read((char*)&diffSize, 2); + for (int j = 0; j < diffSize; ++j) { + file.read((char*)&index, 2); + file.read((char*)&diff, sizeof(Vector3)); + diffs[index] = diff; + } + + dataDiffs[dataName] = diffs; + } + + return 0; +} + +int OSDataFile::Write(const string& fileName) { + ofstream file(fileName, ios_base::binary); + if (!file) + return 1; + + file.write((char*)&header, 4); + file.write((char*)&version, 4); + file.write((char*)&dataCount, 4); + + byte nameLength; + ushort diffSize; + for (auto &diffs : dataDiffs) { + nameLength = diffs.first.length(); + file.write((char*)&nameLength, 1); + file.write(diffs.first.c_str(), nameLength); + + diffSize = diffs.second.size(); + file.write((char*)&diffSize, 2); + for (auto &diff : diffs.second) { + file.write((char*)&diff.first, 2); + file.write((char*)&diff.second, sizeof(Vector3)); + } + } + + return 0; +} + +void OSDataFile::GetDataDiff(const string& dataName, unordered_map& outDataDiff) { + outDataDiff.clear(); + + auto it = dataDiffs.find(dataName); + if (it != dataDiffs.end()) + outDataDiff = dataDiffs[dataName]; +} + +void OSDataFile::SetDataDiff(const string& dataName, unordered_map& inDataDiff) { + auto it = dataDiffs.find(dataName); + if (it != dataDiffs.end()) + dataDiffs.erase(dataName); + + dataDiffs[dataName] = inDataDiff; + dataCount++; +} + + int DiffDataSets::LoadSet(const string& name, const string& target, unordered_map& inDiffData) { if (namedSet.find(name) != namedSet.end()) namedSet.erase(name); @@ -19,8 +109,8 @@ int DiffDataSets::LoadSet(const string& name, const string& target, unordered_ma } int DiffDataSets::LoadSet(const string& name, const string& target, const string& fromFile) { - fstream inFile(fromFile.c_str(), ios_base::in | ios_base::binary); - if (!inFile.is_open()) + ifstream inFile(fromFile, ios_base::binary); + if (!inFile) return 1; int sz; @@ -44,15 +134,31 @@ int DiffDataSets::LoadSet(const string& name, const string& target, const string return 0; } +int DiffDataSets::LoadData(const map>& osdNames) { + for (auto &osd : osdNames) { + OSDataFile osdFile; + if (osdFile.Read(osd.first)) + continue; + + for (auto &dataNames : osd.second) { + unordered_map diff; + osdFile.GetDataDiff(dataNames.first, diff); + LoadSet(dataNames.first, dataNames.second, diff); + } + } + + return 0; +} + int DiffDataSets::SaveSet(const string& name, const string& target, const string& toFile) { unordered_map* data = &namedSet[name]; if (!TargetMatch(name, target)) - return 1; - - fstream outFile(toFile.c_str(), ios_base::out | ios_base::binary); - if (!outFile.is_open()) return 2; + ofstream outFile(toFile, ios_base::binary); + if (!outFile) + return 1; + int sz = data->size(); outFile.write((char*)&sz, sizeof(int)); for (auto resultIt = data->begin(); resultIt != data->end(); ++resultIt) { @@ -62,6 +168,24 @@ int DiffDataSets::SaveSet(const string& name, const string& target, const string return 0; } +int DiffDataSets::SaveData(const map>& osdNames) { + for (auto &osd : osdNames) { + OSDataFile osdFile; + for (auto &dataNames : osd.second) { + unordered_map* data = &namedSet[dataNames.first]; + if (!TargetMatch(dataNames.first, dataNames.second)) + continue; + + osdFile.SetDataDiff(dataNames.first, *data); + } + + if (!osdFile.Write(osd.first)) + continue; + } + + return 0; +} + void DiffDataSets::RenameSet(const string& oldName, const string& newName) { if (namedSet.find(oldName) != namedSet.end()) { namedSet.emplace(newName, namedSet[oldName]); diff --git a/DiffData.h b/DiffData.h index c08ebc01..33976895 100644 --- a/DiffData.h +++ b/DiffData.h @@ -14,6 +14,23 @@ See the included LICENSE file using namespace std; +class OSDataFile { + uint header; + uint version; + uint dataCount; + map> dataDiffs; + +public: + OSDataFile(); + ~OSDataFile(); + + int Read(const string& fileName); + int Write(const string& fileName); + + void GetDataDiff(const string& dataName, unordered_map& outDataDiff); + void SetDataDiff(const string& dataName, unordered_map& inDataDiff); +}; + class DiffDataSets { map> namedSet; map dataTargets; @@ -22,7 +39,9 @@ class DiffDataSets { inline bool TargetMatch(const string& set, const string& target); int LoadSet(const string& name, const string& target, unordered_map& inDiffData); int LoadSet(const string& name, const string& target, const string& fromFile); + int LoadData(const map>& osdNames); int SaveSet(const string& name, const string& target, const string& toFile); + int SaveData(const map>& osdNames); void RenameSet(const string& oldName, const string& newName); void DeepRename(const string& oldName, const string& newName); void AddEmptySet(const string& name, const string& target); diff --git a/OutfitProject.cpp b/OutfitProject.cpp index ff679e73..c6acff79 100644 --- a/OutfitProject.cpp +++ b/OutfitProject.cpp @@ -14,7 +14,10 @@ OutfitProject::OutfitProject(ConfigurationManager& inConfig, OutfitStudio* inOwn LoadSkeletonReference(defSkelFile); mCopyRef = true; - mGenWeights = true; + if (owner->targetGame == SKYRIM) + mGenWeights = true; + else + mGenWeights = false; } OutfitProject::~OutfitProject() { @@ -85,9 +88,13 @@ string OutfitProject::Save(const string& strFileName, int id; string targ; string targSlider; - string targSliderFile; + string targSliderData; + + string osdFileName = baseFile.substr(0, baseFile.find_last_of('.')) + ".osd"; string saveDataPath = "ShapeData\\" + strDataDir; - string saveFileName; + + DiffDataSets osdDiffs; + map> osdNames; prog = 10.0f; step = 50.0f / activeSet.size(); @@ -98,15 +105,19 @@ string OutfitProject::Save(const string& strFileName, if (copyRef && !baseShape.empty()) { targ = ShapeToTarget(baseShape); targSlider = activeSet[i].TargetDataName(targ); - targSliderFile = activeSet[i].DataFileName(targSlider); if (baseDiffData.GetDiffSet(targSlider) && baseDiffData.GetDiffSet(targSlider)->size() > 0) { if (activeSet[i].IsLocalData(targSlider)) { - outSet[id].AddDataFile(targ, targSlider, targSliderFile); - saveFileName = saveDataPath + "\\" + targSliderFile; - baseDiffData.SaveSet(targSlider, targ, saveFileName); + targSliderData = osdFileName + "\\" + activeSet[i].DataFileName(targSlider); + outSet[id].AddDataFile(targ, targSlider, targSliderData); + + unordered_map* diff = baseDiffData.GetDiffSet(targSlider); + osdDiffs.LoadSet(targSlider, targ, *diff); + osdNames[saveDataPath + "\\" + osdFileName][targSlider] = targ; + } + else { + targSliderData = activeSet[i].DataFileName(targSlider); + outSet[id].AddDataFile(targ, targSlider, targSliderData, false); } - else - outSet[id].AddDataFile(targ, targSlider, targSliderFile, false); } } @@ -119,20 +130,28 @@ string OutfitProject::Save(const string& strFileName, if (targSlider.empty()) targSlider = targ + outSet[i].name; - targSliderFile = targSlider + ".bsd"; if (morpher.GetResultDiffSize(s, activeSet[i].name) > 0) { string shapeDataFolder = activeSet.ShapeToDataFolder(s); if (shapeDataFolder == activeSet.GetDefaultDataFolder() || activeSet[i].IsLocalData(targSlider)) { - outSet[i].AddDataFile(targ, targSlider, targSliderFile); - saveFileName = saveDataPath + "\\" + targSliderFile; - morpher.SaveResultDiff(s, activeSet[i].name, saveFileName); + targSliderData = osdFileName + "\\" + targSlider; + outSet[i].AddDataFile(targ, targSlider, targSliderData); + + unordered_map diff; + morpher.GetRawResultDiff(s, activeSet[i].name, diff); + osdDiffs.LoadSet(targSlider, targ, diff); + osdNames[saveDataPath + "\\" + osdFileName][targSlider] = targ; + } + else { + targSliderData = activeSet[i].DataFileName(targSlider); + outSet[i].AddDataFile(targ, targSlider, targSliderData, false); } - else - outSet[i].AddDataFile(targ, targSlider, targSliderFile, false); } } owner->UpdateProgress(prog += step, "Calculating slider data..."); } + + osdDiffs.SaveData(osdNames); + prog = 60.0f; owner->UpdateProgress(prog, "Creating slider set file..."); @@ -168,7 +187,7 @@ string OutfitProject::Save(const string& strFileName, owner->UpdateProgress(70.0f, "Saving NIF file..."); - saveFileName = saveDataPath + "\\" + baseFile; + string saveFileName = saveDataPath + "\\" + baseFile; if (workNif.IsValid()) { NifFile clone(workNif); @@ -279,7 +298,7 @@ void OutfitProject::AddEmptySlider(const string& newName) { string target = ShapeToTarget(baseShape); string shapeAbbrev = NameAbbreviate(baseShape); string shapeSlider = target + sliderAbbrev; - activeSet[sliderID].AddDataFile(target, shapeSlider, shapeSlider + ".bsd"); + activeSet[sliderID].AddDataFile(target, shapeSlider, shapeSlider); activeSet.AddShapeTarget(baseShape, target); baseDiffData.AddEmptySet(shapeSlider, target); } @@ -302,7 +321,7 @@ void OutfitProject::AddZapSlider(const string& newName, unordered_mapGetPath(); wxString refShape = XRCCTRL(wiz, "npRefShapeName", wxChoice)->GetStringSelection(); - if (fileName.EndsWith(".xml")) { + if (fileName.EndsWith(".osp") || fileName.EndsWith(".xml")) { wxString sliderSetName = XRCCTRL(wiz, "npSliderSetName", wxChoice)->GetStringSelection(); wxLogMessage("Loading reference '%s' from set '%s' of file '%s'...", refShape, sliderSetName, fileName); @@ -790,7 +790,7 @@ void OutfitStudio::OnNewProject(wxCommandEvent& WXUNUSED(event)) { } void OutfitStudio::OnLoadProject(wxCommandEvent& WXUNUSED(event)) { - wxFileDialog loadProjectDialog(this, "Select a slider set to load", "SliderSets", wxEmptyString, "Slider Set Files (*.xml)|*.xml", wxFD_FILE_MUST_EXIST); + wxFileDialog loadProjectDialog(this, "Select a slider set to load", "SliderSets", wxEmptyString, "Slider Set Files (*.osp;*.xml)|*.osp;*.xml", wxFD_FILE_MUST_EXIST); if (loadProjectDialog.ShowModal() == wxID_CANCEL) return; @@ -945,7 +945,7 @@ void OutfitStudio::OnLoadReference(wxCommandEvent& WXUNUSED(event)) { wxString fileName = XRCCTRL(dlg, "npSliderSetFile", wxFilePickerCtrl)->GetPath(); wxString refShape = XRCCTRL(dlg, "npRefShapeName", wxChoice)->GetStringSelection(); - if (fileName.EndsWith(".xml")) { + if (fileName.EndsWith(".osp") || fileName.EndsWith(".xml")) { wxString sliderSetName = XRCCTRL(dlg, "npSliderSetName", wxChoice)->GetStringSelection(); wxLogMessage("Loading reference '%s' from set '%s' of file '%s'...", refShape, sliderSetName, fileName); @@ -1116,7 +1116,10 @@ void OutfitStudio::ClearProject() { project->mBaseFile = ""; project->mGamePath = ""; project->mGameFile = ""; - project->mGenWeights = true; + if (targetGame == SKYRIM) + project->mGenWeights = true; + else + project->mGenWeights = false; project->mCopyRef = true; glView->DestroyOverlays(); @@ -1193,7 +1196,7 @@ void OutfitStudio::OnSSSNameCopy(wxCommandEvent& event) { string copyStr = XRCCTRL(*win, "sssName", wxTextCtrl)->GetValue(); copyStr = project->NameAbbreviate(copyStr); - string defSliderSetFile = copyStr + ".xml"; + string defSliderSetFile = copyStr + ".osp"; string defShapeDataDir = copyStr; string defOutputFile = copyStr + ".nif"; @@ -1300,7 +1303,7 @@ void OutfitStudio::OnSaveSliderSetAs(wxCommandEvent& WXUNUSED(event)) { if (!project->mFileName.empty()) XRCCTRL(dlg, "sssSliderSetFile", wxFilePickerCtrl)->SetPath(project->mFileName); else - XRCCTRL(dlg, "sssSliderSetFile", wxFilePickerCtrl)->SetPath(sssName + ".xml"); + XRCCTRL(dlg, "sssSliderSetFile", wxFilePickerCtrl)->SetPath(sssName + ".osp"); if (!project->mDataDir.empty()) XRCCTRL(dlg, "sssShapeDataFolder", wxDirPickerCtrl)->SetPath(project->mDataDir); @@ -1351,8 +1354,8 @@ void OutfitStudio::OnSaveSliderSetAs(wxCommandEvent& WXUNUSED(event)) { wxMessageBox("Invalid or no slider set file specified! Please try again.", "Error", wxOK | wxICON_ERROR); return; } - if (strFileName.substr(strFileName.length() - 4, strFileName.length()) != ".xml") - strFileName.append(".xml"); + if (strFileName.substr(strFileName.length() - 4, strFileName.length()) != ".osp") + strFileName.append(".osp"); strOutfitName = XRCCTRL(dlg, "sssName", wxTextCtrl)->GetValue(); if (strOutfitName.empty()) { @@ -3696,7 +3699,7 @@ void OutfitStudio::OnNPWizChangeSliderSetFile(wxFileDirPickerEvent& event) { setNameChoice->Clear(); refShapeChoice->Clear(); - if (fn.rfind(".xml") != string::npos) { + if (fn.rfind(".osp") != string::npos || fn.rfind(".xml") != string::npos) { SliderSetFile ssf(fn); if (ssf.fail()) return; diff --git a/SliderData.cpp b/SliderData.cpp index 620b3a63..7df92d50 100644 --- a/SliderData.cpp +++ b/SliderData.cpp @@ -25,15 +25,16 @@ SliderData::SliderData(const string& inName) { SliderData::~SliderData() { } -SliderData::SliderData(XMLElement* element) { - LoadSliderData(element); -} - -int SliderData::LoadSliderData(XMLElement* element) { +int SliderData::LoadSliderData(XMLElement* element, bool genWeights) { //Outfit Studio state values, not saved in XML. curValue = 0; bShow = false; - int numDatafiles = 0; + int numData = 0; + + XMLElement *root = element->Parent()->Parent()->ToElement(); + int version = root->IntAttribute("version"); + + string dataFileStr = version >= 1 ? "Data" : "datafile"; name = element->Attribute("name"); if (element->Attribute("invert")) @@ -46,10 +47,17 @@ int SliderData::LoadSliderData(XMLElement* element) { else bUV = false; - float b = element->FloatAttribute("big"); - float s = element->FloatAttribute("small"); - defBigValue = b; - defSmallValue = s; + if (genWeights) { + float b = element->FloatAttribute("big"); + float s = element->FloatAttribute("small"); + defBigValue = b; + defSmallValue = s; + } + else { + float defValue = element->FloatAttribute("default"); + defBigValue = defValue; + defSmallValue = defValue; + } if (element->Attribute("hidden")) bHidden = (_strnicmp(element->Attribute("hidden"), "true", 4) == 0); @@ -66,9 +74,10 @@ int SliderData::LoadSliderData(XMLElement* element) { else bClamp = false; - DiffDataFile tmpDataFile; - XMLElement* datafile = element->FirstChildElement("datafile"); + DiffInfo tmpDataFile; + XMLElement* datafile = element->FirstChildElement(dataFileStr.c_str()); while (datafile) { + datafile->SetName("Data"); tmpDataFile.targetName = datafile->Attribute("target"); if (datafile->Attribute("local")) @@ -85,10 +94,10 @@ int SliderData::LoadSliderData(XMLElement* element) { dataFiles.push_back(tmpDataFile); - datafile = datafile->NextSiblingElement("datafile"); - numDatafiles++; + datafile = datafile->NextSiblingElement(dataFileStr.c_str()); + numData++; } - if (numDatafiles == 0) + if (numData == 0) return 1; return 0; diff --git a/SliderData.h b/SliderData.h index c2741fdf..14c7681b 100644 --- a/SliderData.h +++ b/SliderData.h @@ -15,18 +15,17 @@ See the included LICENSE file using namespace std; using namespace tinyxml2; -struct DiffDataFile { +struct DiffInfo { bool bLocal; // Local files use the slider set's directory for path info. Otherwise, it uses the target's data path. string dataName; // Alias for the data. string targetName; // Shape affected by the data. string fileName; // File name not including path. - DiffDataFile(bool l = false, const string& dn = "", const string& tn = "", const string& fn = "") + DiffInfo(bool l = false, const string& dn = "", const string& tn = "", const string& fn = "") : bLocal(l), dataName(dn), targetName(tn), fileName(fn) { } }; -class SliderData -{ +class SliderData { public: string name; bool bHidden; @@ -41,7 +40,7 @@ class SliderData float curValue; // Current slider value. bool bShow; // On to enable this slider when deforming verts. - vector dataFiles; + vector dataFiles; SliderData(const string& inName = ""); SliderData(XMLElement* element); @@ -86,5 +85,6 @@ class SliderData void Clear() { dataFiles.clear(); } - int LoadSliderData(XMLElement* srcdata); + + int LoadSliderData(XMLElement* srcdata, bool genWeights); }; diff --git a/SliderSet.cpp b/SliderSet.cpp index 07c848e6..586163fd 100644 --- a/SliderSet.cpp +++ b/SliderSet.cpp @@ -7,15 +7,15 @@ See the included LICENSE file #include "SliderSet.h" SliderSet::SliderSet() { - genWeights = true; +} + +SliderSet::~SliderSet() { } SliderSet::SliderSet(XMLElement* element) { LoadSliderSet(element); } -SliderSet::~SliderSet() { -} void SliderSet::DeleteSlider(const string& setName) { for (int i = 0; i < sliders.size(); i++) { @@ -45,14 +45,24 @@ int SliderSet::CopySlider(SliderData* other) { } int SliderSet::LoadSliderSet(XMLElement* element) { + XMLElement *root = element->Parent()->ToElement(); + int version = root->IntAttribute("version"); + + string shapeStr = version >= 1 ? "Shape" : "BaseShapeName"; + string dataFolderStr = version >= 1 ? "DataFolder" : "SetFolder"; + name = element->Attribute("name"); - XMLElement* tmpElement; - tmpElement = element->FirstChildElement("SetFolder"); - if (tmpElement) + + XMLElement* tmpElement = element->FirstChildElement(dataFolderStr.c_str()); + if (tmpElement) { + tmpElement->SetName("DataFolder"); datafolder = tmpElement->GetText(); + } + tmpElement = element->FirstChildElement("SourceFile"); if (tmpElement) inputfile = tmpElement->GetText(); + tmpElement = element->FirstChildElement("OutputPath"); if (tmpElement) outputpath = tmpElement->GetText(); @@ -69,22 +79,23 @@ int SliderSet::LoadSliderSet(XMLElement* element) { } } - XMLElement* shapeName = element->FirstChildElement("BaseShapeName"); + XMLElement* shapeName = element->FirstChildElement(shapeStr.c_str()); while (shapeName) { + shapeName->SetName("Shape"); if (shapeName->Attribute("DataFolder")) targetdatafolders[shapeName->Attribute("target")] = shapeName->Attribute("DataFolder"); else targetdatafolders[shapeName->Attribute("target")] = datafolder; targetshapenames[shapeName->Attribute("target")] = shapeName->GetText(); - shapeName = shapeName->NextSiblingElement("BaseShapeName"); + shapeName = shapeName->NextSiblingElement(shapeStr.c_str()); } - XMLElement* sliderEntry = element->FirstChildElement("Slider"); SliderData tmpSlider; + XMLElement* sliderEntry = element->FirstChildElement("Slider"); while (sliderEntry) { tmpSlider.Clear(); - if (tmpSlider.LoadSliderData(sliderEntry) == 0) + if (tmpSlider.LoadSliderData(sliderEntry, genWeights) == 0) sliders.push_back(tmpSlider); sliderEntry = sliderEntry->NextSiblingElement("Slider"); @@ -93,28 +104,47 @@ int SliderSet::LoadSliderSet(XMLElement* element) { } void SliderSet::LoadSetDiffData(DiffDataSets& inDataStorage) { - string fullfilepath; - DiffDataFile f; - for (int i = 0; i < sliders.size(); i++) { - for (int j = 0; j < sliders[i].dataFiles.size(); j++) { - f = sliders[i].dataFiles[j]; - fullfilepath = baseDataPath + "\\"; - if (f.bLocal) - fullfilepath += datafolder + "\\"; + map> osdNames; + + for (auto &slider : sliders) { + for (auto &ddf : slider.dataFiles) { + string fullFilePath = baseDataPath + "\\"; + if (ddf.bLocal) + fullFilePath += datafolder + "\\"; else - fullfilepath += targetdatafolders[f.targetName] + "\\"; + fullFilePath += targetdatafolders[ddf.targetName] + "\\"; + + fullFilePath += ddf.fileName; - fullfilepath += f.fileName; - inDataStorage.LoadSet(f.dataName, f.targetName, fullfilepath); + // BSD format + if (ddf.fileName.compare(ddf.fileName.size() - 4, ddf.fileName.size(), ".bsd") == 0) { + inDataStorage.LoadSet(ddf.dataName, ddf.targetName, fullFilePath); + } + // OSD format + else { + // Split file name to get file and data name in it + int split = fullFilePath.find_last_of('\\'); + if (split < 0) + continue; + + string dataName = fullFilePath.substr(split + 1); + string fileName = fullFilePath.substr(0, split); + + // Cache data locations + osdNames[fileName][dataName] = ddf.targetName; + } } } + + // Load from cached data locations at once + inDataStorage.LoadData(osdNames); } void SliderSet::WriteSliderSet(XMLElement* sliderSetElement) { sliderSetElement->DeleteChildren(); sliderSetElement->SetAttribute("name", name.c_str()); - XMLElement* newElement = sliderSetElement->GetDocument()->NewElement("SetFolder"); + XMLElement* newElement = sliderSetElement->GetDocument()->NewElement("DataFolder"); XMLText* newText = sliderSetElement->GetDocument()->NewText(datafolder.c_str()); sliderSetElement->InsertEndChild(newElement)->ToElement()->InsertEndChild(newText); @@ -129,8 +159,7 @@ void SliderSet::WriteSliderSet(XMLElement* sliderSetElement) { newElement = sliderSetElement->GetDocument()->NewElement("OutputFile"); XMLElement* outputFileElement = sliderSetElement->InsertEndChild(newElement)->ToElement(); - if (!genWeights) - outputFileElement->SetAttribute("GenWeights", "false"); + outputFileElement->SetAttribute("GenWeights", genWeights ? "true" : "false"); newText = sliderSetElement->GetDocument()->NewText(outputfile.c_str()); outputFileElement->InsertEndChild(newText); @@ -140,7 +169,7 @@ void SliderSet::WriteSliderSet(XMLElement* sliderSetElement) { XMLElement* dataFileElement; for (auto &tsn : targetshapenames) { - newElement = sliderSetElement->GetDocument()->NewElement("BaseShapeName"); + newElement = sliderSetElement->GetDocument()->NewElement("Shape"); baseShapeElement = sliderSetElement->InsertEndChild(newElement)->ToElement(); baseShapeElement->SetAttribute("target", tsn.first.c_str()); if (targetdatafolders.find(tsn.first) != targetdatafolders.end()) @@ -157,9 +186,15 @@ void SliderSet::WriteSliderSet(XMLElement* sliderSetElement) { newElement = sliderSetElement->GetDocument()->NewElement("Slider"); sliderElement = sliderSetElement->InsertEndChild(newElement)->ToElement(); sliderElement->SetAttribute("name", slider.name.c_str()); - sliderElement->SetAttribute("invert", (slider.bInvert) ? "true" : "false"); - sliderElement->SetAttribute("small", (int)slider.defSmallValue); - sliderElement->SetAttribute("big", (int)slider.defBigValue); + sliderElement->SetAttribute("invert", slider.bInvert ? "true" : "false"); + + if (genWeights) { + sliderElement->SetAttribute("small", (int)slider.defSmallValue); + sliderElement->SetAttribute("big", (int)slider.defBigValue); + } + else + sliderElement->SetAttribute("default", (int)slider.defSmallValue); + if (slider.bHidden) sliderElement->SetAttribute("hidden", "true"); if (slider.bClamp) @@ -169,29 +204,14 @@ void SliderSet::WriteSliderSet(XMLElement* sliderSetElement) { if (slider.bUV) sliderElement->SetAttribute("uv", "true"); for (auto &df : slider.dataFiles) { - newElement = sliderSetElement->GetDocument()->NewElement("datafile"); + newElement = sliderSetElement->GetDocument()->NewElement("Data"); dataFileElement = sliderElement->InsertEndChild(newElement)->ToElement(); dataFileElement->SetAttribute("name", df.dataName.c_str()); dataFileElement->SetAttribute("target", df.targetName.c_str()); - if (df.bLocal) { + if (df.bLocal) dataFileElement->SetAttribute("local", "true"); - } - // Hack! Force these clamp bsd's to use the new ones that don't include the CBBE offset. - // this is here in order to allow older slider sets to be opened by Outfit Studio and saved without - // telling the user about the offset. (OS clears out the offset naturally when loading the files, so everything lines up - // except for these old seam clamps.) - string fn = df.fileName; - if (fn == "LockSeamLo.bsd") - fn = "LockSeamLo2.bsd"; - if (fn == "LockSeamHi.bsd") - fn = "LockSeamHi2.bsd"; - if (fn == "NH_LockSeamLo.bsd") - fn = "NH_LockSeamLo2.bsd"; - if (fn == "NH_LockSeamHi.bsd") - fn = "NH_LockSeamHi2.bsd"; - - newText = sliderSetElement->GetDocument()->NewText(fn.c_str()); + newText = sliderSetElement->GetDocument()->NewText(df.fileName.c_str()); dataFileElement->InsertEndChild(newText); } } @@ -229,7 +249,7 @@ void SliderSetFile::Open(const string& srcFileName) { return; } - version = root->IntAttribute("Version"); + version = root->IntAttribute("version"); XMLElement* setElement; string setname; @@ -250,7 +270,7 @@ void SliderSetFile::New(const string& newFileName) { XMLElement* rootElement = doc.NewElement("SliderSetInfo"); if (version > 0) - rootElement->SetAttribute("Version", version); + rootElement->SetAttribute("version", version); doc.InsertEndChild(rootElement); root = doc.FirstChildElement("SliderSetInfo"); @@ -286,22 +306,10 @@ void SliderSetFile::SetShapes(const string& set, vector& outShapeNames) return; XMLElement* setElement = setsInFile[set]; - XMLElement* shapeElement = setElement->FirstChildElement("BaseShapeName"); + XMLElement* shapeElement = setElement->FirstChildElement("Shape"); while (shapeElement) { outShapeNames.push_back(shapeElement->GetText()); - shapeElement = shapeElement->NextSiblingElement("BaseShapeName"); - } -} - -void SliderSetFile::SetTargets(const string& set, vector& outTargetNames) { - if (!HasSet(set)) - return; - - XMLElement* setElement = setsInFile[set]; - XMLElement* shapeElement = setElement->FirstChildElement("BaseShapeName"); - while (shapeElement) { - outTargetNames.push_back(shapeElement->Attribute("target")); - shapeElement = shapeElement->NextSiblingElement("BaseShapeName"); + shapeElement = shapeElement->NextSiblingElement("Shape"); } } diff --git a/SliderSet.h b/SliderSet.h index d60697cb..1a294d21 100644 --- a/SliderSet.h +++ b/SliderSet.h @@ -111,14 +111,6 @@ class SliderSet return ""; } - // Adds a shape target and also ensures that any diff data in the set knows about the shape target. - void LinkShapeTarget(const string& shapeName, const string& targetName) { - targetshapenames[targetName] = shapeName; - for (auto &&s : sliders) - for (auto &df : s.dataFiles) - df.targetName = targetName; - } - void ClearTargets(const string& oldTarget) { targetshapenames.erase(oldTarget); targetdatafolders.erase(oldTarget); @@ -243,7 +235,6 @@ class SliderSetFile { bool HasSet(const string& querySetName); void SetShapes(const string& set, vector& outShapeNames); - void SetTargets(const string& set, vector& outTargetNames); // Adds all of the slider sets in the file to the supplied slider set vector. Does not clear the vector before doing so. int GetAllSets(vector& outAppendSets); diff --git a/res/outfitStudio.xrc b/res/outfitStudio.xrc index 3e7132c5..2e92eb39 100644 --- a/res/outfitStudio.xrc +++ b/res/outfitStudio.xrc @@ -1666,7 +1666,7 @@ wxALIGN_CENTER_VERTICAL|wxALL 5 - + -1
@@ -1676,8 +1676,8 @@ 5 - Select a slider set XML file, or a Reference NIF file - *.xml;*.nif + Select a project file, or a reference NIF file + *.osp;*.xml;*.nif
@@ -2277,7 +2277,7 @@ wxALIGN_CENTER_VERTICAL|wxALL 5 - + -1
@@ -2287,8 +2287,8 @@ 5 - Select a slider set XML file, or a Reference NIF file - *.xml;*.nif + Select a project file, or a reference NIF file + *.osp;*.xml;*.nif
@@ -3114,9 +3114,9 @@ 5 - The slider set definition .XML file - Select slider set XML file name - *.xml + The .osp slider set project file + Select slider set .osp file name + *.osp
From b06a74d243ab401e35b042178c935e284913fcdb Mon Sep 17 00:00:00 2001 From: ousnius Date: Fri, 4 Dec 2015 13:37:04 +0100 Subject: [PATCH 23/64] Fixed 431ce05, added largest anisotropy condition --- BodySlideApp.cpp | 1 + GLSurface.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index 8837bae5..792f63b7 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -261,6 +261,7 @@ int BodySlideApp::LoadSliderSets() { outfitNameOrder.clear(); wxArrayString files; + wxDir::GetAllFiles("SliderSets", &files, "*.osp"); wxDir::GetAllFiles("SliderSets", &files, "*.xml"); for (auto &file : files) { diff --git a/GLSurface.cpp b/GLSurface.cpp index d8a5d2bd..912c6d5b 100644 --- a/GLSurface.cpp +++ b/GLSurface.cpp @@ -421,7 +421,8 @@ int GLSurface::Initialize(wxGLCanvas* can, wxGLContext* ctx) { void GLSurface::InitGLExtensions() { bUseAF = IsExtensionSupported("GL_EXT_texture_filter_anisotropic"); - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largestAF); + if (bUseAF) + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largestAF); glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glEnableVertexAttribArray"); glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer"); From 92497a956706190e58e93ac6c58765c9fc7f79e9 Mon Sep 17 00:00:00 2001 From: ousnius Date: Fri, 4 Dec 2015 20:41:20 +0100 Subject: [PATCH 24/64] Fixed cubemap file contents Unused in BS/OS as of now. --- FSBSA.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/FSBSA.cpp b/FSBSA.cpp index 4891f0e3..2434d12d 100644 --- a/FSBSA.cpp +++ b/FSBSA.cpp @@ -486,6 +486,9 @@ bool BSA::fileContents(const std::string &fn, wxMemoryBuffer &content) { ddsHeader.ddspf.dwSize = sizeof(DDS_PIXELFORMAT); ddsHeader.dwSurfaceFlags = DDS_SURFACE_FLAGS_TEXTURE | DDS_SURFACE_FLAGS_MIPMAP; + if (file->tex.header.unk16 == 2049) + ddsHeader.dwCubemapFlags = DDS_CUBEMAP_ALLFACES; + bool ok = true; switch (file->tex.header.format) { From 8a06a2a91519111b03a88e3e2099bb9dd421d29a Mon Sep 17 00:00:00 2001 From: ousnius Date: Sat, 5 Dec 2015 21:14:10 +0100 Subject: [PATCH 25/64] Cleanup, wxHandleFatalExceptions() in release only --- Anim.cpp | 1 + BodySlide.vcxproj | 2 -- BodySlideApp.cpp | 7 ++++++- DDS.h | 2 +- GLShader.h | 2 ++ Mesh.h | 3 --- NifBlock.cpp | 6 +----- NifFile.cpp | 2 -- ObjFile.h | 1 + Object3d.cpp | 22 ++++++++++------------ Object3d.h | 12 ++++-------- OutfitProject.cpp | 2 ++ SliderManager.cpp | 2 -- stdafx.h | 3 --- wxStateButton.h | 3 +-- 15 files changed, 29 insertions(+), 41 deletions(-) diff --git a/Anim.cpp b/Anim.cpp index 8a161b85..8a1db86e 100644 --- a/Anim.cpp +++ b/Anim.cpp @@ -4,6 +4,7 @@ Copyright (C) 2015 Caliente & ousnius See the included LICENSE file */ +#include "stdafx.h" #include "Anim.h" bool AnimInfo::AddShapeBone(const string& shape, AnimBone& boneDataRef) { diff --git a/BodySlide.vcxproj b/BodySlide.vcxproj index 8abcb1a8..47620933 100644 --- a/BodySlide.vcxproj +++ b/BodySlide.vcxproj @@ -61,7 +61,6 @@ false EnableFastChecks MultiThreadedDebug - Level4 true @@ -85,7 +84,6 @@ MultiThreaded - Level4 true None diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index 792f63b7..f36631d6 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -73,9 +73,12 @@ bool BodySlideApp::OnInit() { Config.LoadConfig(); logger.Initialize(); - //wxHandleFatalExceptions(); wxLogMessage("Initializing BodySlide..."); +#ifdef NDEBUG + wxHandleFatalExceptions(); +#endif + wxInitAllImageHandlers(); preview = nullptr; @@ -323,6 +326,8 @@ void BodySlideApp::ActivateOutfit(const string& outfitName) { } void BodySlideApp::ActivatePreset(const string &presetName) { + wxLogMessage("Applying preset '%s' to sliders.", presetName); + Config.SetValue("SelectedPreset", presetName); sliderManager.InitializeSliders(presetName); Slider* slider = nullptr; diff --git a/DDS.h b/DDS.h index 58a55ad0..a34cbb4f 100644 --- a/DDS.h +++ b/DDS.h @@ -11,7 +11,7 @@ #pragma once -#include +#include "stdafx.h" #include #pragma pack(push,1) diff --git a/GLShader.h b/GLShader.h index 174d5a08..baec87d8 100644 --- a/GLShader.h +++ b/GLShader.h @@ -6,11 +6,13 @@ See the included LICENSE file #pragma once +#include "stdafx.h" #include "Object3d.h" #include #include #include +#include #include #define GLSHADER_PASSTHROUGH "__PASSTHRU__" // Specifies the basic "do nothing" shader. diff --git a/Mesh.h b/Mesh.h index e6938c4c..1f4cbf97 100644 --- a/Mesh.h +++ b/Mesh.h @@ -52,9 +52,6 @@ class mesh { shared_ptr bvh; kd_tree* kdtree; - GLuint VboBufName; - GLuint IboBufName; - bool bBuffersLoaded; bool bVisible; bool smoothSeamNormals; diff --git a/NifBlock.cpp b/NifBlock.cpp index d443f94b..16c07e10 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -2246,15 +2246,12 @@ void BSSkinInstance::Get(fstream& file) { file.read((char*)&unk, 4); file.read((char*)&boneDataRef, 4); file.read((char*)&numBones, 4); - for (int i=0; i < numBones; i++) { + for (int i = 0; i < numBones; i++) { file.read((char*)&intData, 4); bones.push_back(intData); } file.read((char*)&numVertices, 4); - if (numVertices > 0) - __debugbreak; // Found a skin instance with vertices figure out how much data goes here! - } void BSSkinInstance::Put(fstream& file) { @@ -2267,7 +2264,6 @@ void BSSkinInstance::Put(fstream& file) { file.write((char*)&bones[i], 4); } file.write((char*)&numVertices, 4); - } void BSSkinInstance::notifyBlockDelete(int blockID) { diff --git a/NifFile.cpp b/NifFile.cpp index 56f1f52d..16e8ba30 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -1397,8 +1397,6 @@ void NifFile::RenameShape(const string& oldName, const string& newName) { hdr.strings[strID].str = newName; if (hdr.maxStringLen < newName.length()) hdr.maxStringLen = newName.length(); - - wxLogMessage("Renamed shape '%s' to '%s' in file '%s'.", oldName, newName, fileName); } void NifFile::RenameDuplicateShape(const string& dupedShape) { diff --git a/ObjFile.h b/ObjFile.h index cd0537c9..e5d80797 100644 --- a/ObjFile.h +++ b/ObjFile.h @@ -10,6 +10,7 @@ See the included LICENSE file #include #include #include +#include using namespace std; diff --git a/Object3d.cpp b/Object3d.cpp index 72dbe945..57e6466a 100644 --- a/Object3d.cpp +++ b/Object3d.cpp @@ -1,10 +1,10 @@ -#include "object3d.h" +#include "Object3d.h" -float h2float(const unsigned short in) { +float h2float(const ushort& in) { float ret; - unsigned int t1; - unsigned int t2; - unsigned int t3; + uint t1; + uint t2; + uint t3; t1 = in & 0x7fff; t2 = in & 0x8000; @@ -17,18 +17,16 @@ float h2float(const unsigned short in) { t1 = (t3 == 0 ? 0 : t1); t1 |= t2; - *((unsigned int*)&ret) = t1; - + *((uint*)&ret) = t1; return ret; - } -unsigned short float2h(const float in) { - unsigned short ret; +unsigned short float2h(const float& in) { + ushort ret; - unsigned int c = *((unsigned int*)&in); + uint c = *((uint*)&in); - unsigned int t1, t2, t3; + uint t1, t2, t3; t1 = c & 0x7fffffff; t2 = c & 0x80000000; t3 = c & 0x7f800000; diff --git a/Object3d.h b/Object3d.h index 20417fbb..8b432b48 100644 --- a/Object3d.h +++ b/Object3d.h @@ -6,18 +6,14 @@ See the included LICENSE file #pragma once -#include "stdafx.h" - -#include -#include -#include -#include #include #include #include using namespace std; +#pragma warning (disable : 4018 4244 4389) + #ifndef EPSILON #define EPSILON (1.0E-4) #endif @@ -28,8 +24,8 @@ typedef unsigned char byte; typedef unsigned short ushort; typedef unsigned int uint; -float h2float(const unsigned short in); -unsigned short float2h(const float in); +float h2float(const ushort& in); +ushort float2h(const float& in); struct Vertex; diff --git a/OutfitProject.cpp b/OutfitProject.cpp index c6acff79..ceca1b15 100644 --- a/OutfitProject.cpp +++ b/OutfitProject.cpp @@ -1710,6 +1710,8 @@ void OutfitProject::RenameShape(const string& shapeName, const string& newShapeN shapeDirty.erase(shapeName); shapeDirty[newShapeName] = true; } + + wxLogMessage("Renamed shape '%s' to '%s'.", shapeName, newShapeName); } void OutfitProject::UpdateNifNormals(NifFile* nif, const vector& shapeMeshes) { diff --git a/SliderManager.cpp b/SliderManager.cpp index bd9a49c7..b52aeaab 100644 --- a/SliderManager.cpp +++ b/SliderManager.cpp @@ -223,8 +223,6 @@ float SliderManager::GetSmallPresetValue(const string& presetName, const string& } void SliderManager::InitializeSliders(const string& presetName) { - wxLogMessage("Applying preset '%s' to sliders.", presetName); - float ps; for (int i = 0; i < slidersBig.size(); i++) { if (!presetCollection.GetBigPreset(presetName, slidersBig[i].name, ps)) diff --git a/stdafx.h b/stdafx.h index 2c362aef..ce55f4bf 100644 --- a/stdafx.h +++ b/stdafx.h @@ -7,6 +7,3 @@ #include #include "resource.h" - -#define MSG_PREVIEWCLOSING WM_USER+42 -#define MSG_BIGPREVIEWCLOSING WM_USER+43 diff --git a/wxStateButton.h b/wxStateButton.h index 0ab9b7de..e2468ee6 100644 --- a/wxStateButton.h +++ b/wxStateButton.h @@ -6,8 +6,7 @@ See the included LICENSE file #pragma once -#include - +#include "stdafx.h" class wxStateButton : public wxButton { bool m_bChecked; From 26850c66f5d260514f269bc6f5161bf2c32db9c4 Mon Sep 17 00:00:00 2001 From: ousnius Date: Sun, 6 Dec 2015 15:37:22 +0100 Subject: [PATCH 26/64] Fixed wxLogError in LoadProject --- OutfitStudio.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index 94c9c39b..5b24b9ad 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -836,12 +836,12 @@ void OutfitStudio::OnLoadProject(wxCommandEvent& WXUNUSED(event)) { int error = project->OutfitFromSliderSet(file, outfit); if (error) { EndProgress(); - wxLogError("Failed to create project (%d)!", outfit, file, error); + wxLogError("Failed to create project (%d)!", error); wxMessageBox(wxString::Format("Failed to create project '%s' from file '%s' (%d)!", outfit, file, error), "Slider Set Error", wxICON_ERROR); RefreshGUIFromProj(); return; } - + string shape = project->GetBaseShape(); wxLogMessage("Loading reference shape '%s'...", shape); UpdateProgress(50.0f, wxString::Format("Loading reference shape '%s'...", shape)); From 37d7944fac9da041ac724168be9b9248dd5b731e Mon Sep 17 00:00:00 2001 From: ousnius Date: Sun, 6 Dec 2015 16:46:25 +0100 Subject: [PATCH 27/64] Added support for dropping NIFs into Outfit Studio --- OutfitProject.cpp | 2 + OutfitStudio.cpp | 137 +++++++++++++++++----------------------------- OutfitStudio.h | 13 ++++- 3 files changed, 63 insertions(+), 89 deletions(-) diff --git a/OutfitProject.cpp b/OutfitProject.cpp index ceca1b15..81949fcf 100644 --- a/OutfitProject.cpp +++ b/OutfitProject.cpp @@ -1460,6 +1460,8 @@ int OutfitProject::AddNif(const string& fileName, bool clear, const string& inOu if (!inOutfitName.empty()) outfitName = inOutfitName; + else if (outfitName.empty()) + outfitName = "New Outfit"; if (clear) { size_t fnpos = fileName.rfind("\\"); diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index 5b24b9ad..6d3f131e 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -296,6 +296,8 @@ OutfitStudio::OutfitStudio(wxWindow* parent, const wxPoint& pos, const wxSize& s if (splitterRight) splitterRight->SetSashPosition(200); + SetDropTarget(new DnDFile(this)); + wxLogMessage("Outfit Studio loaded."); } @@ -750,28 +752,6 @@ void OutfitStudio::OnNewProject(wxCommandEvent& WXUNUSED(event)) { RefreshGUIFromProj(); - wxTreeItemId itemToSelect; - wxTreeItemIdValue cookie; - if (outfitRoot.IsOk()) - itemToSelect = outfitShapes->GetFirstChild(outfitRoot, cookie); - - if (itemToSelect.IsOk()) { - activeItem = (ShapeItemData*)outfitShapes->GetItemData(itemToSelect); - if (activeItem) - glView->SetActiveShape(activeItem->shapeName); - else - glView->SetActiveShape(""); - - outfitShapes->UnselectAll(); - outfitShapes->SelectItem(itemToSelect); - } - else - activeItem = nullptr; - - selectedItems.clear(); - if (activeItem) - selectedItems.push_back(activeItem); - wxLogMessage("Creating %d slider(s)...", project->SliderCount()); UpdateProgress(90.0f, wxString::Format("Creating %d slider(s)...", project->SliderCount())); StartSubProgress(90.0f, 99.0f); @@ -864,28 +844,6 @@ void OutfitStudio::OnLoadProject(wxCommandEvent& WXUNUSED(event)) { UpdateProgress(80, "Creating outfit..."); RefreshGUIFromProj(); - wxTreeItemId itemToSelect; - wxTreeItemIdValue cookie; - if (outfitRoot.IsOk()) - itemToSelect = outfitShapes->GetFirstChild(outfitRoot, cookie); - - if (itemToSelect.IsOk()) { - activeItem = (ShapeItemData*)outfitShapes->GetItemData(itemToSelect); - if (activeItem) - glView->SetActiveShape(activeItem->shapeName); - else - glView->SetActiveShape(""); - - outfitShapes->UnselectAll(); - outfitShapes->SelectItem(itemToSelect); - } - else - activeItem = nullptr; - - selectedItems.clear(); - if (activeItem) - selectedItems.push_back(activeItem); - wxLogMessage("Creating %d slider(s)...", project->SliderCount()); UpdateProgress(90.0f, wxString::Format("Creating %d slider(s)...", project->SliderCount())); StartSubProgress(90.0f, 99.0f); @@ -983,28 +941,6 @@ void OutfitStudio::OnLoadReference(wxCommandEvent& WXUNUSED(event)) { UpdateProgress(99.0f, "Applying slider effects..."); ApplySliders(); - wxTreeItemId itemToSelect; - wxTreeItemIdValue cookie; - if (outfitRoot.IsOk()) - itemToSelect = outfitShapes->GetFirstChild(outfitRoot, cookie); - - if (itemToSelect.IsOk()) { - activeItem = (ShapeItemData*)outfitShapes->GetItemData(itemToSelect); - if (activeItem) - glView->SetActiveShape(activeItem->shapeName); - else - glView->SetActiveShape(""); - - outfitShapes->UnselectAll(); - outfitShapes->SelectItem(itemToSelect); - } - else - activeItem = nullptr; - - selectedItems.clear(); - if (activeItem) - selectedItems.push_back(activeItem); - wxLogMessage("Reference loaded."); UpdateProgress(100.0f, "Finished"); EndProgress(); @@ -1077,28 +1013,6 @@ void OutfitStudio::OnLoadOutfit(wxCommandEvent& WXUNUSED(event)) { UpdateProgress(50.0f, "Creating outfit..."); RefreshGUIFromProj(); - wxTreeItemId itemToSelect; - wxTreeItemIdValue cookie; - if (outfitRoot.IsOk()) - itemToSelect = outfitShapes->GetFirstChild(outfitRoot, cookie); - - if (itemToSelect.IsOk()) { - activeItem = (ShapeItemData*)outfitShapes->GetItemData(itemToSelect); - if (activeItem) - glView->SetActiveShape(activeItem->shapeName); - else - glView->SetActiveShape(""); - - outfitShapes->UnselectAll(); - outfitShapes->SelectItem(itemToSelect); - } - else - activeItem = nullptr; - - selectedItems.clear(); - if (activeItem) - selectedItems.push_back(activeItem); - wxLogMessage("Outfit loaded."); UpdateProgress(100.0f, "Finished"); EndProgress(); @@ -1134,6 +1048,28 @@ void OutfitStudio::RenameProject(const string& projectName) { void OutfitStudio::RefreshGUIFromProj() { WorkingGUIFromProj(); AnimationGUIFromProj(); + + wxTreeItemId itemToSelect; + wxTreeItemIdValue cookie; + if (outfitRoot.IsOk()) + itemToSelect = outfitShapes->GetFirstChild(outfitRoot, cookie); + + if (itemToSelect.IsOk()) { + activeItem = (ShapeItemData*)outfitShapes->GetItemData(itemToSelect); + if (activeItem) + glView->SetActiveShape(activeItem->shapeName); + else + glView->SetActiveShape(""); + + outfitShapes->UnselectAll(); + outfitShapes->SelectItem(itemToSelect); + } + else + activeItem = nullptr; + + selectedItems.clear(); + if (activeItem) + selectedItems.push_back(activeItem); } void OutfitStudio::AnimationGUIFromProj() { @@ -4608,6 +4544,31 @@ void wxGLPanel::OnRightUp(wxMouseEvent& WXUNUSED(event)) { rbuttonDown = false; } +bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames) { + if (owner) { + wxString inputFile; + if (fileNames.GetCount() > 0) + inputFile = fileNames.Item(0); + + if (!inputFile.IsEmpty() && inputFile.MakeLower().EndsWith(".nif")) { + owner->StartProgress("Adding NIF file..."); + owner->UpdateProgress(1.0f, "Adding NIF file..."); + owner->project->AddNif(inputFile.ToStdString(), false); + owner->project->SetTextures("_AUTO_"); + + owner->UpdateProgress(60.0f, "Refreshing GUI..."); + owner->RefreshGUIFromProj(); + + owner->UpdateProgress(100.0f, "Finished."); + owner->EndProgress(); + } + } + else + return false; + + return true; +} + void OutfitStudio::OnNewProject2FP_NIF(wxFileDirPickerEvent& event) { wxWindow* win = ((wxDialog*)event.GetEventObject())->GetParent(); XRCCTRL((*win), "npWorkNif", wxRadioButton)->SetValue(true); diff --git a/OutfitStudio.h b/OutfitStudio.h index a9ca46f9..c9bedfbb 100644 --- a/OutfitStudio.h +++ b/OutfitStudio.h @@ -475,6 +475,8 @@ class OutfitStudio : public wxFrame { void ActiveShapeUpdated(TweakStroke* refStroke, bool bIsUndo = false, bool setWeights = true); void UpdateActiveShapeUI(); + void RefreshGUIFromProj(); + string GetActiveBone(); bool NotifyStrokeStarting(); @@ -645,7 +647,6 @@ class OutfitStudio : public wxFrame { void ClearProject(); void RenameProject(const string& projectName); - void RefreshGUIFromProj(); void AnimationGUIFromProj(); void WorkingGUIFromProj(); @@ -878,3 +879,13 @@ class OutfitStudio : public wxFrame { DECLARE_EVENT_TABLE() }; + +class DnDFile : public wxFileDropTarget { +public: + DnDFile(OutfitStudio *pOwner = nullptr) { owner = pOwner; } + + virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& fileNames); + +private: + OutfitStudio *owner; +}; From a0d0715c5649282f855b09fea2cb7cad784f6277 Mon Sep 17 00:00:00 2001 From: ousnius Date: Sun, 6 Dec 2015 19:22:51 +0100 Subject: [PATCH 28/64] Added support for dropping BSD & OBJ files as sliders into OS --- OutfitStudio.cpp | 252 +++++++++++++++++++++++++++++++---------------- OutfitStudio.h | 64 +++++++----- 2 files changed, 209 insertions(+), 107 deletions(-) diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index 6d3f131e..7f1cf096 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -361,6 +361,9 @@ void OutfitStudio::CreateSetSliders() { createSliderGUI(project->GetSliderName(i), i, sliderScroll, rootSz); } + if (!sliderScroll->GetDropTarget()) + sliderScroll->SetDropTarget(new DnDSliderFile(this)); + sliderScroll->Thaw(); sliderScroll->FitInside(); @@ -430,6 +433,31 @@ void OutfitStudio::createSliderGUI(const string& name, int id, wxScrolledWindow* sliderDisplays[name] = d; } +string OutfitStudio::NewSlider() { + string namebase = "NewSlider"; + char thename[256]; + _snprintf_s(thename, 256, 256, "%s", namebase.c_str()); + int count = 1; + + while (sliderDisplays.find(thename) != sliderDisplays.end()) + _snprintf_s(thename, 256, 256, "%s%d", namebase.c_str(), count++); + + string finalName = wxGetTextFromUser("Enter a name for the new slider:", "Create New Slider", thename, this); + if (finalName.empty()) + return finalName; + + finalName = project->NameAbbreviate(finalName); + wxLogMessage("Creating new slider '%s'.", finalName); + + createSliderGUI(finalName, project->SliderCount(), sliderScroll, sliderScroll->GetSizer()); + + project->AddEmptySlider(finalName); + ShowSliderEffect(finalName); + sliderScroll->FitInside(); + + return finalName; +} + void OutfitStudio::SetSliderValue(int index, int val) { string name = project->GetSliderName(index); project->SliderValue(index) = val / 100.0f; @@ -602,8 +630,70 @@ void OutfitStudio::SetClean(const string& shapeName) { project->Clean(shapeName); } -// Slider edit states - enable/disable menu items. -void OutfitStudio::EnterSliderEdit() { +void OutfitStudio::EnterSliderEdit(const string& sliderName) { + if (IsDirty(activeItem->shapeName)) { + int response = wxMessageBox("You have unsaved changes to the base mesh shape, do you wish to apply the changes? If you select NO, the changes will be lost.", wxMessageBoxCaptionStr, wxYES_NO | wxCANCEL, this); + if (response == wxCANCEL) + return; + + if (response == wxYES) { + vector shapes; + project->GetShapes(shapes); + + for (auto &s : shapes) { + UpdateShapeSource(s); + project->RefreshMorphShape(s); + } + } + if (response == wxNO) + project->Clean(); + } + + bEditSlider = true; + activeSlider = sliderName; + SliderDisplay* d = sliderDisplays[activeSlider]; + d->slider->SetValue(100); + SetSliderValue(activeSlider, 100); + + if (d->sliderNameCheck->Get3StateValue() == wxCheckBoxState::wxCHK_UNCHECKED) { + d->sliderNameCheck->Set3StateValue(wxCheckBoxState::wxCHK_CHECKED); + ShowSliderEffect(d->sliderID - 2000, true); + } + + d->sliderNameCheck->Enable(false); + d->slider->SetFocus(); + d->btnMinus->Show(); + d->btnPlus->Show(); + d->sliderPane->Layout(); + glView->GetStrokeManager()->PushBVH(); + glView->SetStrokeManager(&d->sliderStrokes); + MenuEnterSliderEdit(); + + HighlightSlider(activeSlider); + ApplySliders(); +} + +void OutfitStudio::ExitSliderEdit() { + SliderDisplay* d = sliderDisplays[activeSlider]; + d->sliderNameCheck->Enable(true); + d->slider->SetValue(0); + SetSliderValue(activeSlider, 0); + ShowSliderEffect(activeSlider, true); + d->slider->SetFocus(); + d->btnMinus->Hide(); + d->btnPlus->Hide(); + d->sliderPane->Layout(); + activeSlider.clear(); + bEditSlider = false; + glView->GetStrokeManager()->PushBVH(); + glView->SetStrokeManager(nullptr); + MenuExitSliderEdit(); + + HighlightSlider(activeSlider); + ApplySliders(); +} + +void OutfitStudio::MenuEnterSliderEdit() { wxMenuBar* menu = GetMenuBar(); menu->Enable(XRCID("menuImportSlider"), true); menu->Enable(XRCID("menuExportSlider"), true); @@ -613,7 +703,7 @@ void OutfitStudio::EnterSliderEdit() { menu->Enable(XRCID("sliderProperties"), true); } -void OutfitStudio::ExitSliderEdit() { +void OutfitStudio::MenuExitSliderEdit() { wxMenuBar* menu = GetMenuBar(); menu->Enable(XRCID("menuImportSlider"), false); menu->Enable(XRCID("menuExportSlider"), false); @@ -1951,64 +2041,10 @@ void OutfitStudio::OnClickSliderButton(wxCommandEvent& event) { return; } - bEditSlider = false; - - if (activeSlider != clickedName) { - if (IsDirty(activeItem->shapeName)) { - int response = wxMessageBox("You have unsaved changes to the base mesh shape, do you wish to apply the changes? If you select NO, the changes will be lost.", wxMessageBoxCaptionStr, wxYES_NO | wxCANCEL, this); - if (response == wxCANCEL) - return; - - if (response == wxYES) { - vector shapes; - project->GetShapes(shapes); - - for (auto &s : shapes) { - UpdateShapeSource(s); - project->RefreshMorphShape(s); - } - } - if (response == wxNO) - project->Clean(); - } - - bEditSlider = true; - activeSlider = clickedName; - SliderDisplay* d = sliderDisplays[activeSlider]; - d->slider->SetValue(100); - SetSliderValue(activeSlider, 100); - - if (d->sliderNameCheck->Get3StateValue() == wxCheckBoxState::wxCHK_UNCHECKED) { - d->sliderNameCheck->Set3StateValue(wxCheckBoxState::wxCHK_CHECKED); - ShowSliderEffect(d->sliderID - 2000, true); - } - d->sliderNameCheck->Enable(false); - d->slider->SetFocus(); - d->btnMinus->Show(); - d->btnPlus->Show(); - d->sliderPane->Layout(); - glView->GetStrokeManager()->PushBVH(); - glView->SetStrokeManager(&d->sliderStrokes); - EnterSliderEdit(); - } - else { - SliderDisplay* d = sliderDisplays[activeSlider]; - d->sliderNameCheck->Enable(true); - d->slider->SetValue(0); - SetSliderValue(activeSlider, 0); - ShowSliderEffect(activeSlider, true); - d->slider->SetFocus(); - d->btnMinus->Hide(); - d->btnPlus->Hide(); - d->sliderPane->Layout(); - activeSlider = ""; - glView->GetStrokeManager()->PushBVH(); - glView->SetStrokeManager(nullptr); + if (activeSlider != clickedName) + EnterSliderEdit(clickedName); + else ExitSliderEdit(); - } - - HighlightSlider(activeSlider); - ApplySliders(); } void OutfitStudio::OnReadoutChange(wxCommandEvent& event){ @@ -2445,7 +2481,7 @@ void OutfitStudio::OnSliderImportTRI(wxCommandEvent& WXUNUSED(event)) { sliderDisplays.erase(e); glView->SetStrokeManager(nullptr); - ExitSliderEdit(); + MenuExitSliderEdit(); sliderScroll->FitInside(); activeSlider = ""; @@ -2610,26 +2646,7 @@ void OutfitStudio::OnClearSlider(wxCommandEvent& WXUNUSED(event)) { } void OutfitStudio::OnNewSlider(wxCommandEvent& WXUNUSED(event)) { - string namebase = "NewSlider"; - char thename[256]; - _snprintf_s(thename, 256, 256, "%s", namebase.c_str()); - int count = 1; - - while (sliderDisplays.find(thename) != sliderDisplays.end()) - _snprintf_s(thename, 256, 256, "%s%d", namebase.c_str(), count++); - - string finalName = wxGetTextFromUser("Enter a name for the new slider:", "Create New Slider", thename, this); - if (finalName.empty()) - return; - - finalName = project->NameAbbreviate(finalName); - wxLogMessage("Creating new slider '%s'.", finalName); - - createSliderGUI(finalName, project->SliderCount(), sliderScroll, sliderScroll->GetSizer()); - - project->AddEmptySlider(finalName); - ShowSliderEffect(finalName); - sliderScroll->FitInside(); + NewSlider(); } void OutfitStudio::OnNewZapSlider(wxCommandEvent& WXUNUSED(event)) { @@ -2725,7 +2742,7 @@ void OutfitStudio::OnDeleteSlider(wxCommandEvent& WXUNUSED(event)) { sd->sliderStrokes.Clear(); sd->slider->SetFocus(); glView->SetStrokeManager(nullptr); - ExitSliderEdit(); + MenuExitSliderEdit(); sd->btnSliderEdit->Destroy(); sd->slider->Destroy(); @@ -4544,13 +4561,14 @@ void wxGLPanel::OnRightUp(wxMouseEvent& WXUNUSED(event)) { rbuttonDown = false; } + bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames) { if (owner) { wxString inputFile; if (fileNames.GetCount() > 0) inputFile = fileNames.Item(0); - if (!inputFile.IsEmpty() && inputFile.MakeLower().EndsWith(".nif")) { + if (inputFile.MakeLower().EndsWith(".nif")) { owner->StartProgress("Adding NIF file..."); owner->UpdateProgress(1.0f, "Adding NIF file..."); owner->project->AddNif(inputFile.ToStdString(), false); @@ -4569,6 +4587,74 @@ bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames) { return true; } +bool DnDSliderFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames) { + if (owner) { + wxString inputFile; + if (fileNames.GetCount() > 0) + inputFile = fileNames.Item(0); + + bool isBSD = inputFile.MakeLower().EndsWith(".bsd"); + bool isOBJ = inputFile.MakeLower().EndsWith(".obj"); + if (isBSD || isOBJ) { + if (!owner->activeItem) { + wxMessageBox("There is no shape selected!", "Error"); + return false; + } + + if (lastResult == wxDragCopy) + targetSlider = owner->NewSlider(); + + if (targetSlider.empty()) + return false; + + owner->StartProgress("Loading slider file..."); + owner->UpdateProgress(1.0f, "Loading slider file..."); + + if (isBSD) + owner->project->SetSliderFromBSD(targetSlider, owner->activeItem->shapeName, inputFile.ToStdString()); + else if (isOBJ) + owner->project->SetSliderFromOBJ(targetSlider, owner->activeItem->shapeName, inputFile.ToStdString()); + else + return false; + + if (owner->activeSlider != targetSlider) + owner->EnterSliderEdit(targetSlider); + + targetSlider.clear(); + + owner->UpdateProgress(100.0f, "Finished."); + owner->EndProgress(); + } + } + else + return false; + + return true; +} + +wxDragResult DnDSliderFile::OnDragOver(wxCoord x, wxCoord y, wxDragResult defResult) { + lastResult = defResult; + + if (owner) { + for (auto &child : owner->sliderDisplays) { + if (child.second->sliderPane->HitTest(x, y) == wxHT_WINDOW_INSIDE) { + targetSlider = child.first; + lastResult = wxDragMove; + break; + } + } + + if (targetSlider.empty()) + if (owner->sliderScroll->HitTest(x, y) == wxHT_WINDOW_INSIDE) + lastResult = wxDragCopy; + } + else + lastResult = wxDragCancel; + + return lastResult; +} + + void OutfitStudio::OnNewProject2FP_NIF(wxFileDirPickerEvent& event) { wxWindow* win = ((wxDialog*)event.GetEventObject())->GetParent(); XRCCTRL((*win), "npWorkNif", wxRadioButton)->SetValue(true); diff --git a/OutfitStudio.h b/OutfitStudio.h index c9bedfbb..c90c7fd7 100644 --- a/OutfitStudio.h +++ b/OutfitStudio.h @@ -456,8 +456,32 @@ class OutfitStudio : public wxFrame { ConfigurationManager& appConfig; + class SliderDisplay { + public: + bool hilite; + wxPanel* sliderPane; + wxBoxSizer* paneSz; + + int sliderNameCheckID; + int sliderID; + + wxBitmapButton* btnSliderEdit; + wxButton* btnMinus; + wxButton* btnPlus; + wxCheckBox* sliderNameCheck; + wxStaticText* sliderName; + wxSlider* slider; + wxTextCtrl* sliderReadout; + + TweakUndo sliderStrokes; // This probably shouldn't be here, but it's a convenient location to store undo info. + }; + + map sliderDisplays; + void CreateSetSliders(); + string NewSlider(); + void SetSliderValue(int index, int val); void SetSliderValue(const string& name, int val); @@ -485,9 +509,10 @@ class OutfitStudio : public wxFrame { bool IsDirty(const string& shapeName); void SetClean(const string& shapeName); - // Slider edit states - enable/disable menu items - void EnterSliderEdit(); + void EnterSliderEdit(const string& sliderName); void ExitSliderEdit(); + void MenuEnterSliderEdit(); + void MenuExitSliderEdit(); void ToggleBrushPane() { wxCollapsiblePane* brushPane = (wxCollapsiblePane*)FindWindowByName("brushPane"); @@ -613,33 +638,11 @@ class OutfitStudio : public wxFrame { } private: - class SliderDisplay { - public: - bool hilite; - wxPanel* sliderPane; - wxBoxSizer* paneSz; - - int sliderNameCheckID; - int sliderID; - - wxBitmapButton* btnSliderEdit; - wxButton* btnMinus; - wxButton* btnPlus; - wxCheckBox* sliderNameCheck; - wxStaticText* sliderName; - wxSlider* slider; - wxTextCtrl* sliderReadout; - - TweakUndo sliderStrokes; // This probably shouldn't be here, but it's a convenient location to store undo info. - }; - bool previousMirror; Vector3 previewMove; float previewScale; Vector3 previewRotation; - map sliderDisplays; - void createSliderGUI(const string& name, int id, wxScrolledWindow* wnd, wxSizer* rootSz); void HighlightSlider(const string& name); void ZeroSliders(); @@ -889,3 +892,16 @@ class DnDFile : public wxFileDropTarget { private: OutfitStudio *owner; }; + +class DnDSliderFile : public wxFileDropTarget { +public: + DnDSliderFile(OutfitStudio *pOwner = nullptr) { owner = pOwner; } + + virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& fileNames); + virtual wxDragResult OnDragOver(wxCoord x, wxCoord y, wxDragResult defResult); + +private: + OutfitStudio *owner; + wxDragResult lastResult; + string targetSlider; +}; From 5ae797412f7e76eaf55279d3a687abfcb3950e2f Mon Sep 17 00:00:00 2001 From: ousnius Date: Sun, 6 Dec 2015 19:44:34 +0100 Subject: [PATCH 29/64] Fixed selection bugs of a0d0715 --- OutfitStudio.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index 7f1cf096..8f9ab54b 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -4633,11 +4633,15 @@ bool DnDSliderFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames } wxDragResult DnDSliderFile::OnDragOver(wxCoord x, wxCoord y, wxDragResult defResult) { + targetSlider.clear(); lastResult = defResult; + if (defResult == wxDragCopy) + return lastResult; + if (owner) { for (auto &child : owner->sliderDisplays) { - if (child.second->sliderPane->HitTest(x, y) == wxHT_WINDOW_INSIDE) { + if (child.second->sliderPane->GetRect().Contains(x, y)) { targetSlider = child.first; lastResult = wxDragMove; break; From cc57a0234233855de62004679dc6e84ec5302132 Mon Sep 17 00:00:00 2001 From: ousnius Date: Sun, 6 Dec 2015 20:08:00 +0100 Subject: [PATCH 30/64] Fixed update case when dropping slider file --- OutfitStudio.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index 8f9ab54b..9b852739 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -4617,9 +4617,7 @@ bool DnDSliderFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames else return false; - if (owner->activeSlider != targetSlider) - owner->EnterSliderEdit(targetSlider); - + owner->EnterSliderEdit(targetSlider); targetSlider.clear(); owner->UpdateProgress(100.0f, "Finished."); From eaf4c8998c1414884d3671f5cd7badc17b73dfa8 Mon Sep 17 00:00:00 2001 From: ousnius Date: Mon, 7 Dec 2015 11:11:54 +0100 Subject: [PATCH 31/64] Added x64 build configuration, updated to SOIL2 --- BodySlide.sln | 6 + BodySlide.vcxproj | 106 ++++- GLSurface.cpp | 7 - ResourceLoader.cpp | 16 +- SOIL.lib | Bin 411952 -> 0 bytes SOIL.obj | Bin 56645 -> 0 bytes SOIL.h => SOIL2.h | 928 ++++++++++++++++++++++------------------- SOIL2.lib | Bin 0 -> 259208 bytes SOIL2_d.lib | Bin 0 -> 577092 bytes SOIL2_d.pdb | Bin 0 -> 151552 bytes SOIL2_x64.lib | Bin 0 -> 464630 bytes SOIL2_x64_d.lib | Bin 0 -> 715478 bytes SOIL2_x64_d.pdb | Bin 0 -> 159744 bytes SOIL_d.lib | Bin 281448 -> 0 bytes image_DXT.obj | Bin 22599 -> 0 bytes image_helper.obj | Bin 15868 -> 0 bytes res/BodyslideFrame.xrc | 3 +- stb_image_aug.obj | Bin 179335 -> 0 bytes 18 files changed, 615 insertions(+), 451 deletions(-) delete mode 100644 SOIL.lib delete mode 100644 SOIL.obj rename SOIL.h => SOIL2.h (84%) create mode 100644 SOIL2.lib create mode 100644 SOIL2_d.lib create mode 100644 SOIL2_d.pdb create mode 100644 SOIL2_x64.lib create mode 100644 SOIL2_x64_d.lib create mode 100644 SOIL2_x64_d.pdb delete mode 100644 SOIL_d.lib delete mode 100644 image_DXT.obj delete mode 100644 image_helper.obj delete mode 100644 stb_image_aug.obj diff --git a/BodySlide.sln b/BodySlide.sln index d2dc41b8..af58e869 100644 --- a/BodySlide.sln +++ b/BodySlide.sln @@ -8,15 +8,21 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {F7E444AD-893D-4E93-8897-AF050C1C6A48}.Debug|Win32.ActiveCfg = Debug|Win32 {F7E444AD-893D-4E93-8897-AF050C1C6A48}.Debug|Win32.Build.0 = Debug|Win32 {F7E444AD-893D-4E93-8897-AF050C1C6A48}.Debug|Win32.Deploy.0 = Debug|Win32 + {F7E444AD-893D-4E93-8897-AF050C1C6A48}.Debug|x64.ActiveCfg = Debug|x64 + {F7E444AD-893D-4E93-8897-AF050C1C6A48}.Debug|x64.Build.0 = Debug|x64 {F7E444AD-893D-4E93-8897-AF050C1C6A48}.Release|Win32.ActiveCfg = Release|Win32 {F7E444AD-893D-4E93-8897-AF050C1C6A48}.Release|Win32.Build.0 = Release|Win32 {F7E444AD-893D-4E93-8897-AF050C1C6A48}.Release|Win32.Deploy.0 = Release|Win32 + {F7E444AD-893D-4E93-8897-AF050C1C6A48}.Release|x64.ActiveCfg = Release|x64 + {F7E444AD-893D-4E93-8897-AF050C1C6A48}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/BodySlide.vcxproj b/BodySlide.vcxproj index 47620933..211b60b7 100644 --- a/BodySlide.vcxproj +++ b/BodySlide.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {F7E444AD-893D-4E93-8897-AF050C1C6A48} @@ -24,34 +32,65 @@ false false + + Application + v120 + Unicode + true + false + false + Application v120 Unicode + + Application + v120 + Unicode + + + + + + + <_ProjectFileVersion>11.0.61030.0 - $(SolutionDir)$(Configuration)\ - $(Configuration)\ + $(Configuration)\$(Platform)\ $(ProjectName) Debug false + $(SolutionDir)$(Configuration)\$(Platform)\ + + + $(ProjectName) $(Platform) Debug + false + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ - $(SolutionDir)$(Configuration)\ - $(Configuration)\ + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ + false + + false + $(ProjectName) $(Platform) + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ @@ -65,11 +104,31 @@ true - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL_d.lib;%(AdditionalDependencies) + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_d.lib;%(AdditionalDependencies) ..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) true Windows - MachineX86 + false + libcmt.lib + RequireAdministrator + + + + + Disabled + ..\wxWidgets\include\msvc;..\wxWidgets\include;%(AdditionalIncludeDirectories) + WIN64;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level4 + true + + + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_x64_d.lib;%(AdditionalDependencies) + ..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) + true + Windows false libcmt.lib RequireAdministrator @@ -80,7 +139,7 @@ MaxSpeed true ..\wxWidgets\include\msvc;..\wxWidgets\include;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreaded @@ -89,7 +148,7 @@ None - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL.lib;%(AdditionalDependencies) + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2.lib;%(AdditionalDependencies) ..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) false @@ -98,7 +157,34 @@ Windows true true - MachineX86 + + + RequireAdministrator + + + + + MaxSpeed + true + ..\wxWidgets\include\msvc;..\wxWidgets\include;%(AdditionalIncludeDirectories) + WIN64;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level4 + true + None + + + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_x64.lib;%(AdditionalDependencies) + ..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) + false + + + false + Windows + true + true RequireAdministrator @@ -137,7 +223,9 @@ Create + Create Create + Create diff --git a/GLSurface.cpp b/GLSurface.cpp index 912c6d5b..0026d5b7 100644 --- a/GLSurface.cpp +++ b/GLSurface.cpp @@ -10,13 +10,6 @@ See the included LICENSE file #include #include -#ifdef _DEBUG -#pragma comment (lib, "SOIL_d.lib") -#else -#pragma comment (lib, "SOIL.lib") -#endif -#include "SOIL.h" - PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr; PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray = nullptr; PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = nullptr; diff --git a/ResourceLoader.cpp b/ResourceLoader.cpp index 131e66c0..c4018804 100644 --- a/ResourceLoader.cpp +++ b/ResourceLoader.cpp @@ -10,11 +10,19 @@ See the included LICENSE file #include "FSManager.h" #include "FSEngine.h" -#include "SOIL.h" -#ifdef _DEBUG -#pragma comment (lib, "SOIL_d.lib") +#include "SOIL2.h" +#ifdef NDEBUG + #ifdef _WIN32 + #pragma comment (lib, "SOIL2.lib") + #elif _WIN64 + #pragma comment (lib, "SOIL2_x64.lib") + #endif #else -#pragma comment (lib, "SOIL.lib") + #ifdef _WIN32 + #pragma comment (lib, "SOIL2_d.lib") + #elif _WIN64 + #pragma comment (lib, "SOIL2_x64_d.lib") + #endif #endif #include diff --git a/SOIL.lib b/SOIL.lib deleted file mode 100644 index dc14dd9d671e65b5f34832307b5056d7773ad207..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 411952 zcmeEv2VfM{_V>(YLqbSG2%x~0Y(iKVV37m@O8~RUrne0cPyt;-3JHcJrckVFL+oN# zEZ7_Nf~%sUKFdSYXYcJj3w8yc&&u~Z_s*T2*=#~t-{0^5eFkQB_RcB4bMCoy?%qkC zRo7YHd|<)>4&z_e)TxtaOq-saJ>8f-S^YXa$DPeD4^NOJ=_yIdee18|e}NBTR(&n~ zb@c6n*s149dvx58BE|0h$jkG4J^snrB~_Kh1qIcfl}qw6^YcBDNG~s}De-g~6Q>mW zDhi7WOG`X?ncm8S^KuLiy`HSBtgt&3`4uH4<<*|N8Ha>%O)o1d_m&nE zmU))cHRRZ|m4+dDgZIv}#NaBf~s%ksLVjYhFvPfbaFRYifXFhpB3 zuP`EQk*BD%rmCW%w8%5Rt!_zcV_r^odtOd^M`K%FPE!lM>wQ~L>hTs=l@xnR3qju1 z)6vo1+1&`^8I-2>&gFI8;SA-)B?Xn06<$xVZ*En7ZC++!^_1+q8B1Ea{hh6i{?4UK z!gQ2*%B#Eu)x{N+@Je3JRB{PE@JR>1o{B%Cq6$wzRaHq*MM;&XjJX7Mz>wCuPPm8J z)X-Sp-Vmm%(o>V4Ur|}(#RYi?sPb|e8auk1;jON`oHoijH%~V>qRLZJ<3mK%_@K82 z3RZVO4I>Y^WlCPo+{z*&&MHrNVR3b_udu|kps{nchLGnY;?i4IuV!#&AtK6KZshlQ ziVI4Ms`HDAJQPn6RJxgSk%w)qtHXIq3ae|1D~qc82c5+w7!0oQR8>{`yp=vg7mFp~ zofZVj+>(O4oci|G_D%#%??NI`PuqHyFKGlm!d~B8 z*Vfk93NN&1jFp~hZ%t8tIZQ>-C`4saGdI7mEWg@oEM`@n(#o>(>heOLt_lpRenI0a zqq2y~JzUl_LkOZuDJiZht@0Izq=i@aRVW{Yr3F4zq@w(?T2Wt!sy)8a!u-OL;)0MI z7GHWIpQk#%vZSQ2yx8OGLG44XSl+n29d(7Ctj1GVT2ufZ)_BS&irea1^Ku$HJCVDL z%-`Bx*MJft`MbK8wD^}S?_eomU;Ry;?aTdC&qut$_3CbQH+FT0le07fWqo@a3TL;U z)$w(0ONH=;hAuq_@wFES;|+sox)lyWOEXfk>fT>?aBY@`ref;l?tC-qwq zqnc{q>}WIiLwxPUZ@ke zKdQB5iC?Wdmh?0=Y2fuYme;kSrisA8Z}^w?p!x1^i#5B(Z_n^A!7jL%!<^A%Qk=K0Dh(XzI+bhp&C0#O*H z*HctoR#}{nCa;6aTV*lXQO4;4e1Kd!zn4ODJrijCp7tU3y`U+ zx~ZzI??Gj_ysjghzM?F@qM)i0-SkR-^#YB&v$4J#4N~~9rp!}OT~u9NUCgY7u^L04 z@_m*0H6`f2Fay=j`%2bjL(c`EB4Da6ud1o8_Evl5)vai0TZ%zLGsX-mFSQ-vnNaTW z79s}XITaj?xfcS3O#|wytIx z1fpEmb<=Re5SUfy(G|fN7@KI?^jy@lYO7lwHtIywRF;<`Lea4l81-BYEz6-6%DRl& z&^0W`FYr}VB6|g&&Ng0gM6|BPQ(RF{P*|K_f!PRyL+a}~>Xx*$wsd2lK%qQ&{6Et@f6b*7%C_ z4I-LPH8dX6_0VAgZ`N-Aqg z%W90Vx3saXu@hygS1f3p7_L_4SLJ&PibMo;!HdQ+ScSoMWko&=tDawpSmO1Iq1aS= z$_vUWN-I$ambUiMdRKd@G5v?mL8VX?p=*L^w3?!dN^}ZTWf5ympQo&o6=w<=xZTt@4nI8F17jqB9eIOO2~Ok|V&=ghup6A9wqc6J~|LtS0xx$sD9d%{|7Z zGDM%AIgUb_yHllR389u&^4B*v)*s==?4BQa%w|t8VRB>-CT3}Zz#nQHMQU}8FH*AV z$_Naw1v#VkIt}-Eeqnm16SW&!CYH?@JG8g7mPG6mOMc9=7SX^JpA9W5@_Qv@!=lzY zO!X{T-HkDZn1=y5aUJ4q_bv^kvahN%2@?u!4d_U(Vmc)M@|F(7xo{pE4Xc5v3ahT2 z=k<5hHPKM!$j)vIbbC7dIy%W;Ij;x;*=UbVm2@%j%UdupBARe29L7l&!yUs63*G5K zY2=BmEp3hdd9{T_3ql6zrkjN2JThQAO#_7}^~o4*_8xyy3b^=KREr{iT^B3Pd;MfL zd-62#WY>&GyKm)6($}kEr1Pf6N+~zQ(xYBU4*O@4=pRp|&(Oi|i2Iz1Q;IvprN1A3 zm-B>V3+Z}(E+bqHmt>Y=@J~?p{~05h*+1eCSF(Xyq?(Y*G5xvc80|^o|5r~K|MXde z|4SZm?#pDxUOyDwtJx1cUD^9*sCzqMvM zo1QH5{241}_IXltUzgl?|C&wR?QH7*)ytChV4ipPOPBs9=YscenbiMP6UOSZ_&;j# zRzGuRdoTz1*W`6yQ^$Qy<^Ml3d2O8keg)jwUqO(rJS_Z{eR(7 z&hUq)2ZTLh+}&?SXNVt>Iu1{m+t`Zr=Z%ZeSg4O|>w1<>YG1NU5_hP7Xh`7CLz^30 zI~qG9+`z+AmU@7ug+I;g3su(S$3Nd$fl2$yE;Kqkrxt&Q48-%<0`ZN1YIKdO zv>Q*2Hc1OBw6E+!qw89&-3Xp0Nse}-VvVk0iAMLJSCZcRPj5On)J2cOvAD1^H^ZB| zxQ2e0Q@7kvjFc|NxK-|H%Hpb)`p)*Q_NH#ff|jnHx>m=$?w*F0c1KqBq{)jHco#2e zX$4OtWO*8SP?JLBN$>=;Q(l>+x& zDcKN#BNikDcI_Gwh?OP!9M8@Z*m)v52jbbC)Wxy&xr=*PzBI6WY0&az1<&Fxp2aL* zH1oQ6zR*uPm$o`sQFmZ5dms7IETzaVUwrwn^*>+f-}%tRTg$I%n3d`$%@D|fj8tB!AIe*Zu^8!V;JbiR->Z0T*72xN@ z%?!KupsT;xm=^nT^(%!_$}ae3YU+yAC`I#SS4?<9{jIMI^If&&j*I7Av*BOGZ>Fvv z9;NWsmgOzoJYI(FI%>nzd(($YSB(H%jsh347965^O%aD(ofB2^d?U>d)W7^vC zwMU-*W$LG+qD0Qu&oSZdnOme2XZ`TWw%RR??;pK&aq4H$3a{%z<<-rEuS&8`&wBUU z3+_t1d$hvg7W~$m3155q{J;SpO}c%~tq%>}_U-YLQhy-f|CO4v#ZSLJ zqz)EUZ@0d-Y1={0I@g+K4qq9#>iI&GG~Y5N;=TkY4v@@p%!ccwcqveZ{thj)TBOlp zRqh`BET2gk#-&uLQdVkGy!-USU?y`MmpNaRxxy-}*xdvt<4)$>t5xne)HP(IGzk$hgaP#t2^Ip?r_O*KoY`?-pq;e~Ls+EUmBD{OOWZUeX?}d5t7zswQVjX@vci7>k*!UaYE~6=I3Jl~W|9g&I@8yK^vB zL$;+(r(xHBrNgM3lB-9L@#>+8^Hw~+;GtuNUs(OdB`>^al2(ru0TW?csz_E|qA~Q^ z5{r?C^)feVCYFAq5m*O+=Z(h2C*yJQU;;C_ zIYpAwEpoEcA~i~D4Bf*v046czQ>>cWm{?~`#OX$`R)f_v!4fkO*m6~!^u$yW zwpT56G3LgS)d8r9!$3GjaCyqt7CJC$@M;^c(R0Yl$Ol(#3!nMrb1lH8gkpPVFL zoFw0oBtM=czm+6^l_bX|%Ri5jQ^R%2$xS+)O`366z)M$>B55X0?XrYy(NX2zW}l}kgTQyahg3?lKe1! zz@kLe!jP=1R9O)=S`o361z}f{u%kUV{RCnAHK&+JQu3_^ZiF|Fwrk;(>xg4uK2B4> zKN-OaqBl!fCx7P+VqNLmi05=iu zjl_Eocv(sL9(qsi&CB;~(evI+y!&}^dR6f50Pm?PZ?ETvdfr=z_Y~s&5xgmcc_(;J z@6Fp=@2$l9G4YOs1&sFx@D8=2bk|{XBv!6YjEiB_0YTeH3`K=F%>)A~5tEc`5!46@ zNf5sc;@gP$DI)F!v9mNKMoP}GN=qBN-CE7m3cA~gZetNnTR?ZF9$zgmqE@f}2*RD#n0JP{a6#9Ki;iOcPgPBg{PQCmt~2-3TV^n_BJ=7MxQ43iHUAScgcVzZ_hAlyx~N0;GrA!yS|;qeTsDcQql zr({cOOuW_|4r}fq+U#OeXZSs{;rd5f)*_{rjG&2vY?9h->$jw+lU0KJ`M zT?-NOO|$q`bEuTKp|haj0pgfbjnjX?5x5|xG$l561l6XCt>zVgmS>Sdv8=Hl z3WY&pZ(5Agef#0`uvD629-y%!pb?iVkawjPDO3tI33DLfL6UH%AE!JJH%#cvzdCJ_(Ge+7H4U}a3eS$BhHss;8bD5!%Y+;Dfv2^)Y4Fo z?bFzuiY(I$1&b#^uS@%*o|y<;_ge~WE} z_|MaY3!Z?UCyCd6CQjqP8#vkoZgaWK6tJ1Dvzd0-Vv=2U36GHKu>+F8Dfr3peN6zu>`geW$0NbOT7-;g076C~Nv7>K zv&$|YYnPLsGD>1yNrREklAxvsahjw^QX@=^-EK4eXp2HARAH;R$Hk>9>Pr8Y!^hE0j z)Q5;A(^Gc&Q@gywE}PS2OPV|-O)g85m!+B4rJ0hGlKAj|31%undpL?NGj-EnA`REQ zi_@ZPNm80qVogJ>^4c^xd6(LK(ImiYyt7B+gqMl$lJ{`>9(*&vr*`(xzo*XL_Hb^) zT3aEBI_6R&|+t6z@SvUfd-iFZrY@*Le-Njdl`HK&5It1PRoMx0%_H_ zxRP=tsf5+ZlNddk491`pz%N1m29eMC7fusEJ_=2SJkB8}Pj^U1MQ#k^;N>@o=__J7 z6ik5?sG4G8SYs$p0&_E%4Sl(tQ1lk@-2DYkKTLx)4A*jpgpOn@ZME5@h2_6N{5BCE z_a#ng(|u z^~BdW-3YG01FW3|eque>fp)e7TRdqTCg^#OIJ&;asmjeti^-f$y%-Z}(2E?VNa`0q;q=N3oO~oT4jD4t0l{&{JAh7p(qVea5tIChz}V9!wyQvk z*c<4FB=P_}+6$aP1Ilkum&nvBKt8N=$mfzsQ}VAu7~2altf3%aACZ)2&5%-w!6Y@{ zh?AIRW@d6+x83b{nw2g!wEGQmQXuDJ zk`tE*Ifr22nuGdHwt;$+T5k1QANJZEQPd(sA?Fj4Gdl@#UW1(G<`i=bZ+vG#+9Q2R z)9SSGknt(WXc`O|mtnz;r5RoHO^I?c<`UQpkRFS=`=Y2twuAd~;!Z_pDDXA7JwPCn z?&l+Lhi}m+3?UF-keKcv5OcCel9mF5&XCvp6BYr}mn3Y%PzaltufueHI_n3rt);cT z%z&793DlXu@D;I{hJ)>Ku#HAA$sY6uFG-j9PB^qhXjlx=!0>Bgdym+D0h=3a=tj|a zZ+*Jy>U2}`CW@xU?q)5JGN9`lV)}VMFfGH#y@HK%o`xd6sS;^2c4l1Q`IdNEM}SB6 z;_BZ6XsE(ETGYitdAT!P-jp7jyd*;_(%qePZC&W1(h49=|76Jej%2Nz0$F9HxT0YX z2FXWdsMV6c1N+%_W1AdNw@d-g_r&x3H1K%Ja5WIMfY~hidTfYuL55mz$N)Y!rVcV^ zfPV+^UosQ?7tl!ab9B&S_Qz=Okwoegu$pcZdW@5-X4a#H^U1Cac9=Hw{B-$}bouFY zc}a$RREB(CM$7{lrpGc&aie1sN1KxOA5Fy!T6rG_((|BjCn*5%(QIIB`H(wEfDvyqb1rvn^bGzLgnIT;y8CPIBo*RVyc@lr+|rq za%)WTsj5oBDWZjUwWyEt3$Y)47=Z?RmI3s!FuOHeLIlvil8np!1bQB36I9T|jmhig zmZiXagy6h}={@D}gz7 zrzJkanwVoX7g^)Vts@c3C@1HQHeWH?eEn$ii=$&-9c_ATwCTOkrtK&jD|L=COnl3! zl5`>|`sQRP8okI6pO~bk_&hI+SwDZN_KRmBvrZy0`D-BNZHO6*elhi@AAqAzjwnFn zl`3K?M4U__CY%ZpZHqAxrgn%)#95h=*p^t!D+;hvh$CYyI7S|dtMw?}EW{>RV`f?h zB;T!S7QDSfYz+y>IRgTEAix-6XJyLC7l%s_uyy6)RFbjaOvrcT*6| zMR~iHIEI`Bj`YKDRflRYHjY)Jrb*U;IaEXj%(G(V%9MPK4nVK0JB{R=a5dyu>J3?k zCkvEyo5Ps<$hy->%*)q6%*zlXvhG$Ga7RP|!UwvnJA*`Qz7`^y8bVn|BF2xAXwU3k zb;Fs&aqo5D7}6+7He?)XdpY@CRiohPon?pxDNuhs7``;r7b1bBH7FMsR!sjzB%;Z(@^K%Nv(LtrccDVm;OYydc(&F- zd7-MP~V`>{?O5UbJ)hi#*CE>5#4dJF1Lq6i!5ar`%Va$Ex<2n*E?p}y_5Mo3= z7Q(8xA_@?W(dFZLBqH@bh^Sf?%109M>=-`#8D7VqPaFg92giTFF$?)ja%(Zgqnv7iT7vXeF(h9Kp+Vpal{xW zcDEnVh{;xUeqjMh;6=o134(XOR!OQyA0DV<6q@j;lu~Xi_d7YHHlyG;)NQO=rYrSmRODKN=IW zV@%9wr)jLy&vMEOohYF?Pm>7|qKh8bT}GOYeI1(Sb%&xW1p;!y1>l#T z>MIyT2cKGq^(0{F8xZh`PQYpiNQops>qJo_bvg0Qc@w;=dkoJVbCPL}ABBXTJI02~ z(eHUFpwI)uD@fcEZ$aD?%q@$ShHOa~%f~zvcFY;f77@8>Nl62u4J6{hw;|#^od~jK z$XJQ}#LBG&&oX4x)kJ^SJD@*pB_bUWCodl$CtFnFrWG3Xa!_AG)Yb2TdK;(%8(63f z85@^eBIp@8211AcCk5s$dEjFpoQSBd={EvxXR7)?VLSgs=$^M_#h z8Z3b$(Ul(xt{wPr)_tXh~WapE4+xKk9_K z!^g^(j5Q@^szbHV&&$;kNzGTwy@(Z&$>_iBuZM_TAw`Y}pdN@Fcvy-{cJ zHsXJW_$M95${R*!zp0$Pep)S_${r2I+lldb zFXJwf@zJl4u@N!?|CUKgX)GoWdr49EJr&P{VkP_q$e_DP#hF>S(>R2X&tnrOw zabu{osYbnr7#>dm!=@8)wVFC-@u;iOEt_YJYq6SQ#>tj(vU8j~eVi%Tp^K$HDo?8W z?j@neI3VTzNIor8;X!}AbZdGseqJdBa-k31ceBYP4U%q5r;)T2aKIshq>+hi9;gSsL&qTL z=vch}4YL#tc>dPX*3=HNS>TnWbW3Kh#X^`-GvijE!z@WA=^967170oQ#}md*l8b7^(=2J%Ntfc!xot09Xq`-`VW{Iw}-VqkMX8i83RaQ=g7{(e*s zeqkg@J%gk%4lxxC*`I+TUW&2K^X6Ccm&63-K_1Irh+POvvE+NV10;Hc0C3!?(X%+4CpNF)_}6Th)w(tTilU zfR!=@UmMuhX~`^)IB=xqvDAiGdIyc4+-hD9PqCH^%O7~iEd|DRnLpBPI&JaN%_vBC zi9(~UD8Zqnv63IpMd+81ypm@#iE24Pi%eOHCn*s69)!kA!xHD!7L z!Ya8{9a`QD1>W}=mTyKO4)CBx!UXD0OJ-|!v-;|$HL+@Dc;L!Lqi5@5SKt*wD3CzF z3+UBq0bPP$NJlK6CTW8sQ!PrmQhW?@J8(EftYjVmmr?bgd8`vCKV&G^QUryCk4cJ6 z&r~Pq{Zu>Dwbf&70~J4qlr9C9P>2nZu88%wwDYi_f@A&;bpicm6ZIv}mlCA@6Ix7C ztu1p2cGgBoB_V|bt${%sB%K(GD5V&t+zm8R>cI(;e?^!2Q$2sZKU64UA@LI?@hZ*c zkYjWv$4h2j(&#tB=pREYD`~V*^A9{T_yQ!~MTWsndr-Hw2& zTS3#Poyek41syAyze+`8-r0tX(7c=pw4Va4`AAWOv3e<%`({7f`waKurC1JBt*b&% zO_KRnszR}Z!BB@%>EBLL8}}!T-R&Xw9EOtiUJ>PnUJI@)x)>NcxV#66=zr z?m^PmtgfOMO&=sR$F9T+4Dpj+7G15~KST#1`sF+|D68sJ-|gAn#$BAWu2*43Di2l$yiTZZ~I$sCb_)kFG{HxdHB zVFHg4&EfJTqB-nf*>?-Fud8Q?F5}ROI8vnL?Rf8*Xrru<^Bv^C|DjUA%NH*L0f&tC z0OjCgP|D_uhq8>X$BVdxw-+KGzGouhMrY==@HeHPF{IaL<`tBC^78l!6)_{PYu|=b z*_aM~iq!8dna$a)yxQ=$Aa-;W$8TXZsYzO&o|#7y5iPtaWv>dL6dqeTE%Btq%Cy8w zcfc#`VMwpA9)R$?P2AOajXDL#sZ9@+5_%;7FD8j_NxZa?7ZV)^ZIu2Ln*5{KY8>v( z-L?0;GxD!EIQwcTz*|t0bZ2@dD}8KT2u4GAHyh8EShA@L`7FoYlpcF?y6Kj5`Sx`A zj&xa;c5p|sB5!o0c`J$vUslKqCiP!-vb^iDp%Ua>6RyEW8hS{BlmJj@WF=WPOL6$k zq!bg=xdc~>a5ap-m)OzW?x5<>!G>&c(n{PKSH?COz`Il&?M)86>(s&Cwd0^#YNDgP z)1khJ6Oz7%@L2Pt2R}P74)Ez3B_J;jO$l9ZdoIxvhng&uzQQWSB;);?Bv|ck#!0hm zQcRNi`eg^bxD$eFZIWz4571f`RN4!OlKo)KBCG`#xCx zOjAGcq>-f`uYN*6oYX_g5XvSQ%H(()n2nML;-G&}E+^m^f@1^@2ab_AQgIBzVa5@Q zBN4|?9HVfg;~0lyG7bet1`Z33VK|a-48Q?{XUyI1a!u9mjz< z;Lv?P;-qPIL=EMfgDu|d;v~|#nmO*?5 zh{yLs%wB=p*x+bx#8a7WFl+$BC?3LiEs=x0s+z)FUC9s{K%P-27wkqpeC1EFo! zA7qsNAOrOW8LK}u9dXjt3;+oyfh0tDhde`GA#ac;M&d}vk%c24M;(s93940F)K64= zBs_3}`YD_EcR5D=M3qAK5y8b=8ZA|xSHB_$x|(xsS$ zY81^n2M_Q&85ePq82Ti21LCCnGB5~SfcN#N#fL2^aEueLV5UO+07&c*V=U`oh4(QK zjgCNs-kth}a0j|IjSv?%T8bHdF#a5@2g0PXW(W5YanBh+iuwv~m4kJn<7nYvs2t<9 zjo`ENhF2UsBgVr1*+8RWbIyxU#5<0?~F5S^FZwTk1hlJ4T90 z)hd>Gg?z6V+&Ba`(&yvdY#lVpLls7g;P84vY8>&da*fUpx`}!^{yJ|W6EE|2w6qym z8o**98B~!rG-Be#(bB~%cT*CSw}2vzY2oP*Ft?-tO*`H;uh!zAY6F#%sPNi!^aLE5 z$3rg*3=uyE;>6K;;?3a+;2-UjVg`khkTMo2nm6zkEzL?7ZtP#|n_HD%J9|ntx!2!G z3v20B&2dsT-PQYmSk*QCane-WHM|!eZa65?GDd0gO9k@mOgBJxVS^o;v*k6BtdEhS( z{N;haJn)wX{_?Q?1QSyHA(qNzI&{&`8FdTjyhx1Q4aQh(qgn^P}ug_G+M6qw>j9wn*Gd+_)^3ww5 zlns*45%@i%E6&olGU6IDZ=UmogksmW1lQIC*Ru(gz9I8`vePGz^~vL$|449dOPILE z`)#~5Wlceb*_2J!6+T&UzLelRIAQaed^~~}fH8XT9|?48KAonl@tzbf;qoL$a2t|O zaNzm`M{sMxnu4DBID*e2^=cx%I=(U+G9Yn0lz|bNgpLWpmlALj$v)y#&`g39h#iTyLo6PBEJDUSw0=(V6m=X385nQyA0_p=m0h z;w!Kw&nJ7FUnMxVN6eah=htCb^Hs>6;C5V} zMEQZd`BZ1n$C^R^)ET7aO#!qS^Tr$eTFaX+VQ?V~#%DhU?3MPYJFc z6I?$exOS)}R~WPB7o9mj>CE|2XU-3rIXiUbu>AQQa4P{9pDJ7`b#h=7W~O*a4P1%h z?K4eBYJtzRD4EI@E0uJa8nKx5V;wOCCPFwYoSahZnv~+2n8J%$z=dRIe9Gpvr{rVB zD;1+jDY%}GBREl9Rp#SsZdMA!OaeWi<9gpb&9EHDu{;4RTLh5fkv0Vdjm_VANd1;N9pNgRWS<-(B*N^Kc^snXm zUx5B?DXy&o!f7gmz$u6T24kCm5!@=SbPjou0G-YO;W`RHXK_HU0MJVU&DjFYNdnDF z5iq<;7|!7sa2*AP^Eie#f#G$5;e3JN34!7D2pHZX3>R<=xQ+tD#T>(X!0?X1aEXec zo#n_o5%j-L`Y+}BaUF&J%enr4LjQ+C{}rnK02WE{sQ54fhJO);D>(*SM}gsLj^Q(4 z_(Wj1M#WIaeDFyG{o6_ZwOl{0qtJgl*Z&pte;E45zZLp7tNO7`gqjE6M!>LxFg(IB;5rHnTR4WFfZ@j!*AD{5<0_01%nd&Z2*Dr3 zm9BF5nZP{3!QeUyFwbx>(vV`;?ByAL)MNzqCrGhFs2#x(j1gCrtTBlvEH7{@ zxQ+tLOB_oQunZdF8Yr;5Ojt&!?ioc`1`R4?)y!i4Ts_fMp|hFfIsu5AvXO$Qtis z@xk;VNM!wyY(x~@-9dL9S~82QG%{o-ZlJ4#>nIHQ5kk;y8wW$2LtL4{5PG`=>n+_b zDkGCKtFLnxQ+tQuN;sIfF=kuzo}@BU^zP>g8oUQ|97q**HP%F$F^`t zHuO&x`b|h<-Z)iwV{!xxQwT#0NRcVHjsn8~j$t}5mWS&lUO;RsCH|e{KZ*vq^sv*N^Kc^y3HFln43HpC|MWQS}GT5P6Un0Yd>{ zNaYxC9R-Gw977o}ln4x?1cnm?h7wjTQDh}HkYMAOa>8KY7;qg01_#G52N-+;L%NEA zk0E>!^v@;z8C*ZEqtHKw>pvL!7YuRL3J6XWLTC)JzyKpyYxv4XcZU$Fu^bhyqd+y0 zqpAZczkuWtkWLagL)FywFyxQ+sY zn`3ALhE{=L2GX2A4(7vcthtnetr0M^6NX%l0oPGr$m1A}0)|yXTq^_&55f3Vg~3Ms zs|+xLD-2(Ggd9z%@;NG8M}ex4qY41kaRO2i(pVj?4RMZ(fZ+tfP|PvlItmPB9K$KV zaFW1Ku43TByptm6UqkvUxPDwmp??n7e=hW&E%eV-_46Ut*%9=wBmMKZeq2YP{}8T! zJ@j8H^eAjsj5|NAx!!dSZxci$K(lWaBvN z33NxrIBQD;NKX-@4h{*|Q9$b9kX`_!Z9`mJ1*8=O$uM!a%>W~~)$o-&>P14elB2?P z6sV5ks9p!ESBJP>7O0Nyh3ZuUjNr?LuN>7Igz6ZM3fEDfI-a9?AE@3P;(A-43J@y8 zIPhI<9QbwwKpzmG6F4ATM*(Op2lN#HeId}ChBT^a`8e#02>QP!{ik#NxQ;^qSzQ13 z(EqK_f3~Whk3+wWpnnJHKZonbbrkw9;rioKi(La!UFKAElHgJ#L&atIa3-W0$AN=V z`8d#=N+Uh3>nH|;>%kKokjjRNgNQ`jxSVbzPzvj14oroDE0BiK2Ck#9;W`LGZ`%PI z?5QrRu;F?nvj$Te0@_KrhB#<7eC45@PN;6+sBj$xsyjKV0-*8;NOuWH+BnP;0fUz? z+|4oIItmQ;aSSEEP$V$iuVUb1(V__YOG*DGt{>M?=zoywuY~?`q5mOOKOYB{N6=qI z`XA={aUF&JN4fqv(C-uaA5-;*#$mn)80Hd&EgS=`qrmVa$FKkxY6XVBsTlZJv^IkN zgGm2VTtBW={p^8PkdIs{lNx{Zp^vIe&$yPx&4C5fj5y+*(1V~N^kSFLsE*l1rQy~Z- zajo}ovCnkbaLvPXIoxMjA4;LiA)IDE{t&X#XZm!M#zB{OZn_BLyYX*FDSW@0gS)=|N93q7>Yr&I1|i%&ip7UOf@vW4Uy z2l-A*u`AQURUGe3w*)hp7O^rQ5J2{`$YD=($3iW8a0%78-gni3b08P$&q*wHjZ@VJ z&PAGYv4slJ4(UYK0$atYO!A`S8{qg&3& z7G^PfB%hmQQL-&+k~|nCsY1!J1SeZ?MO2Oq_Y@1(aRe?0t8+r=PO8~F4lg5ESu5x5Q)$}~%@IXBy)OtI9)AngW~9(4kihcLW161_>mbrcbB zCxjpZauES@EH0nLRb_EiSX^ZyOYXvbXRXEgUF_yH-c1fEfbBsg=X?vRq=IE|={2;v z0u>gl-o&iF8!SM44?cpmAlT%XagYTe&KJ*A68|FN|2DpoJC&b#h3DN6pF59o<6f{U z;9FpE79~RW2D}4tHbvtc%5?Tn!w2DFR8pn8uFzd`0MNFHA>2TVc>?#5QCnaUt>(!k zp?Wf+xSzl;fSe6f)CHzZNQK9NFA9%i6K?W&5j@^taV@d94!5`tv$z%uk3WR_K=3d= zoTell#>IfMiJT2n+|A^p%|w#~nvi!IH190YdEs!~^<-)eEDCHED2%UKQhchcWxagGNa9#vs8WGYAd z9)74k9%F@bD+w+YhRxNaa@j#1){{|msls6O0FQ1;VqbZHYhT+C?~hUI^;kR}#8O#i zG5#FXu$uLGG8i^Fm+Bjwc8k(sQIpgLr`-}l*FTmMZ+{~}1IS)4zQ+I=jYPLMt(NU5S;{BLC3X9VeV zi}R~J@X{Hq5!gs-HLN+n+YKZI);UknHwR}~l(Q{rlG+@cWeJ|5Zw}6(Ou}0ZSaZPc^llC$ z)Z=eZJ$|>^9Q0RQ&n1E1^e@m1fp3z)`$WU=-w2HF$S3Doa?iFX=TH-I@g4-oIzs2AUk*$Fl>l--$Tmq<_yW1M~wny z@nM=8t}MvSFw~CR8m&6y25DcpY~=U`)>%g0F`MvW4N18tEDrnWoC&^U@FCA3BZ@pv zg%ITVame#67T2Q|*Jg|BA&V<$acvUWj#pezw&UFslCkv)YB{8>LS=b`WfX}~KgB;{`w=aUw6E!B?u;gm;zgdQy@MnX&QN#H_I zJVk0pkzvN5U<$d~AUDkr6x>2B3b>KlS1wy06wEpcS@+al1qI`?f)7D~>nMUE6G9La zS0N~#v$*~)0>Me98~QKLX<7PrxJX0*n?-w`oHd@K!F3d9CUG>k0?i8o$^iuBrM@cv z7XYSLDy5b-HL8A5_lU)lmqWAm9|Ds^)WyG_h}-=F(G9 zP0eQPX?igSq{=In;LGGK=A3_!bMTH6$|_t(;hY%|f~>k7&UsZhXC^^2OfkI5OymYI z0Iw5(JPrWYQ2?ms08Rjae=`8i@8RQe4;nK3eVb>Ng8#N)eQhjTWD9%$6O}qVxgdK_ zhPt1)x*g%_eln>0B`S4uxVlrJ?pLmErzQ9+DG=uT9+mvLT>j~hzl+QN!4ll1moHnR z$(?pCf2g(CHN@%~Y*n91bs#x7*t*915uQrrcc-AE`>7*11PPlQsQUO+^N}DzehrHX zKo19C0f3QK*Zx-5aDibZVHh5UfzMWJ5LO#$h5_eij^O@a`rLtEl49CgtEi7Ml8)$2 z8XRebtu$`Hu1y->(cpuX)~KvJ4nh!>8L-kJ?8DxASWF&fA0C#Vs>!s{;}qJ($~ngB zd__N39+AOV^PEV6$Edb+@8S;>c>R|N=(|0PVaat*&_>&ZtidUzQgK-^2ErZvmkb@OC zc&ut2X0u4 z>nNyaGHis<&~r2BFLde8t4v;#mX9%MFoJcWW5SE-Ttc}`H%c?D$Tx~&Qm zc$HD1S_v>&yf6=@P^?hgqyYN0Z8c`W3|$t8hmY42 z+}Wad#t-b9!^Fa77Qw!O!^U+K8Fn*=?E&lq1?*c0c7YYP=pyGp1MGqxa`~+UyTFQt z2$Wwb1N-IxY^L%V-J}3X6n=dPLQrQchF=$2T?boT3xr=^CLjw$ zg-~S<9xSc{7r{iciM(wKE~HfcB|afkpC3y8d4(gybrcBkUL8W%0)$Jgu12e?-s-Be zy8HqsUYkSX{5Sc>+xQ696Q*DtozvWH)}Wu|AO_(Z;&Yb~FuZI=QrfIjXgv$nBJbh5 zbGg-N9f1)!_U#C)qA=lN8Y$e(!KLhj0s=p3gP>3s?tN0ZoT(5CLONOCeLzwTt7bS5 zWW2g+=0l<|tb$l!#oazvK``(ifr&-kzi^>Im9v$1Uih+@RaRxSRZUW-rB_*lt;{9N zh>38El;J*#Vf>g794%a=lBp&$2by`*g?gT!5XUiA)nX$D^H?tqylF<_xj`WlZ|06Q z%{-PN_=>DJ0ahGg4Kl?cov>vRnF8*{+3KWs}GaUwkqdDGFgo}H3m`C zP%FUXvyCR7+lR^h#b8D5IacLd4c&KyZe1Vf&a*1#?;f2NVCNapUC;-*KRUq9w<;HC z_IywFT-b*_7g?2ycW;jtU>6zfx#WMuo`?aat5rgUQq(G_GcL9&muN27K`ywo4;Nf! zRn|vxftrbGz-cbH%;<#N4Mxm>BlI=&QQxkcy)Y((HS@W$qm7?{=ee?u_gl9Xw;Pr4qY4gF?Zr z8Kh$gRUkSgp+t?PBKHofa;N5lpU4Myg+?kr<9lr^I-bsBt+UW8#Vwo@W}m=52hBc( zeJ0L6jeQQ8eHQy1I(r@a95(wx_BnF)73_1=?5o+Qb@rv~Gkx~;>@#Eb&FpjZ?AxrB z3hU+KU4s%h5C$p-pr)2ZQVb+dB4`&0=VWhvt}N=j$5cAR_oE zMhlOr8#<=BpFlhs#&q|v!Gt=d+vC9;o`yff{WuUhlqakl3uUG}$o;g{`G}gr$3f3n z6IUhjhp_f|Fx8^lCx z){A(~s%*15d6FvPIcsn;6Y&V0Gu+QJ-o%ibR1Ms*oR$SS`^^Qb^tB%g?xg2MY@0vs z!oFD9K!(Z(8@RHaZ?q?MAGCYSQfz38zTgie)GT(!Ndhno)3#Za=dJ8#6v>2?TfiV@ zxL>rY8Qhn8hCCQ8M1g2904Oh7QIh^{Rkrd7NI_aZF@^jcLa=!p@}&e1QLd*V6%#f}kPi0#(k z+f2kebk1;p!FcW9b$-cM16mRJUMnKpL#l4>Y%V2Kx+Wv?gF9IKhYEzTq+n`BJmUTU zkGL_Z!*`HMgYw{)R(uN)V2Tg3L|CDvou>7 z_`ZBIhLn9D$u~Q!P)2d2`Nj!aWrsD4T=mUPL2mHPSYp|^XTD)5jJ_EMc2=_~B*9)Se!QejM3)Gu&K}R zPasU=ZK~V&(-5{3s&kw!F?XU(aoN-)wcJd!1;^RoZDLKya8I%UDeaev=c{_o18mA< zo0_C@9$*V9#2L)Av26i`81cglDur1j?i7d%W`O8-2WbgNv3MmhJ-k;D%Q;-XI=Lp~ z;5U41<~w^0O{Pt@DOon;gUhB&vaznxn!dya$EyZ$fvQs=1XySvR_6qrWk@@n(!!i~ z2GWEJWM0!vu_;r-Trfp-0drouJI6+k@@d0Wy}6Zm0Ts+$o6g+@TJ9kZGdO|3@@@y1 zX=heFv*xQXqb9>CtT=O_Y3^xE_c>r!+_rs^FoW{y+;IK)4)CX?hv$`vCPGzDvJ9Mf zaz;9eY({!TuG^+CVe3d3vyU7k)7Ye2=70x|cF(jK`*pKye3G6$2pvmcXxmt2rj3ae5gdB9JT7l`b|7~qtZjntXw$%eZhufm5*KdXp)a&J_*GomEehcZZWG3EutsbS6uoWR8QX;#I;tOj-Xi<>Jl#LJ?^odMo?Pr?1hUvSF z^v$suAEQT>D5TNezQH*{n&fcLWs>fodt23K9cUG+n}UbvPxSuL9J1GzI2MRC3llJp#x z2#*t-c=p?P=)0dl#3)q;jT))QoDu0WDs4(Nq25FcCIuEm(GQ@lh!HP`AYKl#x#o+I zc@)V|@fiQ0J%xkwLm|@(6&n1*YzR8O1;G_GIm^irEN7>)EeM{131iWXARRwOBh8+@Rdx>vgCaVy38bK#)PtTiD(bkDtz+=k?BjR7Vy0beJJ3+1Q#kxl))$}OWGG2 zm1P?$%T}9fnW!vj|7T|h@00{vMb#pQdW*CLG%|xWd=4(_qZ;Lm8Sc)odX&?L>d_w{ zL;=x}HoYiAIn>|KDi;b0u7hWvz^ThVQ7Zr47f#MEGU8_D zY_6khu2nYI3Xyxma38vc z9LI#rn*PQjCy-6FFR`+Q1&h9Wj}btC_2_x`o_Fn6LFGE#+BOSeJkiEAA`CgwYY8a> z!Nvo6oaA&#-&M1cgp+KlF?2g{Zw_lPu1^mhry7##rZE}aq~*xGV;DSaXZGKuP} zu>3n_H~B{!BnQt@&8B5nXYV%uoTM3KXWBxHgS8F`ZIJ9dLwC!}8yx@~N4n0`bfvk^ zVel0Lguu550*CutTkh!;EaOSpxi;1M6wy_jfMkp&*4Y#;gLYH~P4EnoE{JHKWYxva z9wEXwMWRjHYwkA&6+_!As0^8N0E42eBeaw0Iz~Co7Cc#)>B*R})}}C9vT&F3nvZx` zS;!^^lY;9g%J(z~LHWKA<@>RIG$gXnW=0`2=nvDl7(v^#C*7m$1yp z)$X&X%y3`IWbj4s7me=DO16x?DJ9Ic_>{vN>f zwDJnd=^HHr*h%ZKHrj$Wh#-m2aNo|{-wh@3G3_WDyp`!E598sUS~*NcjiAj9;7P?D zHXT{Yo{^2%Gcw1Xk&W9kvdMc!=I)1#W&~+dTj!m6qbY>dc@yEA;4LgeaYMJLQY-1S z{IlDn&8HkquD%HjJITwOfj?3UB{KhqCo*q`Co$ukzygziCawl-)N4s{>ugnO-ed0Eg!EWaz z(!y_k+hFG2M@a-TBa{f8uh`v)X5QV~%tRi4&U*~E*tD*=^^h%iH?#ge<{Xaa5kn%M z>vleD3*N&h@6}OmHYBQ)KoY7|B9t|qIqYskbAUM{Btr4m31N353PIk6gs@W6XZ*0c z5rrTELPA&}?NbQ58&L=%nfqDqy`b=(-uVdE-Z_FW>+SppZ9JrdL6##dHeXED0vp-D z1hMp|F?v%29-d{gSo&KIEgjBc;8^5;vZsO;(1JFC1`!slZ-s9H1IlD z$HU5Ni05P@4+}ZY^DxuH1I(!B6eAC-D|_*T=~-jsVU;xJ+068?7-F?)2-~Sf9#$}W z@r3E2t%x68r1UBqxDfk!T2R#2>o-)iiOZDVaF zZLjWp*`~9GY!$Nw>PXJ{ik@IV1cH}r!Izo4UZHcZM(#yh@TJgg3Jyaf_YZNK$zZqj zjhq1Tm(-7PlzBk0s(v(A|SlsnFVi#2-teaFmJ$J+%7%ZR|Q(V zvB=im9zb^VHug1JkY#=FRptSfhq}f9W-~!7UDp`ES|*F7>ly-7(SM+ zYYYJNHI@M^%-CIhV*tqfb|}E~jR73Oz%xEwV*sBpb6C2rG0@_b8_R2LK-L!lo~T8a zo)XT`l?JUbIG>8*>uSv|$!cTpMtH)T;R$brC7^=2fGVh)BMcBQe&#FdZ=%_x*O|+B zhLep$5@;5HuZ)M33yo4(w6fkspHf)y36pY>QA%imu2ISx3=5CQ2v{yQN?~If9h87#3D|B4Jr? zl)@^%{-s31ayg`+L3+-nY~u}*`o@auqnfJt08%kku^m$tpNbiZ50Qq@`iNkEiU3ug zPHT^OwGk{Ub2QK5aDQpTE68nqlCu?R5$|d;ILQ|_JUC|4HlK4V{|OYzmo^B;ehIu> z+)Cvl1Wf-dT&#rq7hz|zv`Gp!JLGVG#Y>_#JM=j<_8*gyuWZUUwn$8A?r(|c6Aov` zhvC!Wn5bD)h^YB7jPhZzIzSKN0g=ca9+(q|>vsc}meIlAsJ4X4P*_;CXB&hhj@6+t+6ZV63EQ>D!W{hyON6j_ z&RpGx9hcPb)>Pae-Ul{Xm`S%kiHJm^ce%~N&*WH{-}wC$0$-a(B6N2 zWdTubJiu9rI?j&ed}g~6YiG;(Y;-d=SGFrAJ6j-Tr-Yc?L3V}LVQKgdUI+h3$HzQp z5)V_>D&(fxm7#VuNiDaj_F$474%55gCjLN{$6khe7;||B6PKtLH{7o5XLs@>RorlU zFfm-*bw+XfGjW+rT(Vx=2)i=U?&L|TxDobXaxZcEIy}QYiisNoaZZaNhqMZti$GL_ z4M*XsaSTO@9);De*z8W8q@u9egDK%CLgm0hw@A9yD$@@B!g+QEPholn>-D7B6^Gr) zlTX(L*~q3q9#f&v^Knf9qtjSGx3RTpR2}ys2tmi)WiNJ3u)7qy`a7RuBtvTnK7tb{ z2xd-Z8B>Y`WhwzG!&N`OtC&PI6-1pwSCze}r%~C&R!OWJGU{rgo=((0qBd+Er`W}a zUq7%WhnO91w|#d&YDl!(9t?>IXal1?Q6xrfb08;_3k>x<5$*4-_nzI?3OyPZxqk$+rjd1XoO^yI{9mi-@bhKF{gVx3*rpQfOC`)YjH(4|;@T zPlmgQJiM4thRoOX*#(GH)(^*eCXHEL-7J294A1ivqX%P6gSuVUy3V)5C7)gl8zG1N-8YIL_kF|-`Ff>w57vmU2#z^+ zW$td{qYXloIf#!+ofWzB>`JX&O;Y1yo;_G8gku5veCCFBLRS&G!@HDwQ+zr|LY2L@ z5E{COr>{qX2tR49wJY;^V001}4~!uqFuITyatBr;EnpD4iPWi%xgWqF6sk}Y?u^$3 zwmLKx&NGalD`y6dV7tO`uG|Bh zfl&Xi53GlTV_ij94++ECx17H5u4Z_ZgQ-9rh3l}0S!h=lg+^yD>tcRQFRq$BgJ082qh?R%*EEYfd#b%s$s%RzL+zn6_tnW?D*ZbLbsh1tqAUqF|2KoFnG6qN12{&N=7QASz}t=bUrK zoKXJvJ=N7+-7~Yhxc9ry&-1WdbL!+eb*j3my1SuKCa={KEEDL_;7rx@%tpr4V*rw8 z8IDCkZ7F8yr5vfA$m#}#ayOQ#PXH54e742JXB#u?IT0{ubP_J!4w->`o2oMqGwPlU zk}yGOk5@9&xhKI$4>NiwIi(g8<{oj8+q!d0RWSymsn`*QMVj0I7K5Ey)Xp6x=It0q zr$RZkQ%ksmNxIxg8{c5DOpK;BO%1tVmrl8!My|Uc-EXfOSucd_+M;%Ai9k`h-?b&& zo|0?IbA#O_P)`R(Z;#Ay*RkKvAjw{{MRF!c@SumS^xiFMpOy#|DZO_~xMxP`#P4{N zgMK{=oNS|#TRS0zlarMT28~`(2=^dgC)kfH&IXIJFgph&wO>nlpBA+*GExW9onXAx zt)zv|CGq%Fe08LZzV8nAGVu`25xQzi>b8A6rU(0X8Z75g!Tr0epk8Z86pUsnT~#o( zR6zv~=v2Y;so()A1(Rhi312p+J|rZqYtqLBAjA-{TZ`JgMH1hI0CXjFun%Ikeqg7n zT}0J@mU@|c^=`qWeDUnbKd4jrms0*g5^_4xOUPXYC^9+9-N@uuf(bJD;mG8Nw)h8| zWPTM*II<-?IFq)*c@Q|}mh3%#X z^l^jZI&#Dj?5x*GD1(R5PCg@o?r`Qikcmv8s8FnQbuU%Z4F}S4HOEriJf^6-o6pI z;Y8!e#$0f6OY*axKRZ}D5NS728mJP#>J+Zom=1h1u*P~5bV?Oq`IHuQYD)x)#)DH@ z!U@zx)4IWFGGg6A9g`@vmIMVkH3I0xz4(JA`Ws@m&IW@OWY(Wya2psP{hZpOPSfe< z4swj+nnyLqH&%GSjPhr8>chLhPMwKSKINdZTGZJY2c2acl=U`cxxqQ&ue)c%Ts>l@ zvtGIn=&9E|v(1wl>DHuo>M`3nm)-l`ZZOIP=aI#IV9{ArhQLwhwWxDjyra9&4JOZq zR(ii7Jlb>`Gp=_rLNz(P6I@^?-wwk%A(F&Z49;&+7jzm{Q|N^AyDTK?x3OVnKF~$O zl9^j@(QL}3HzLC>Y*80=YS{fW?7}V!(fbXZ1bJ68OltFj)1HevRd*`Yy%=lO<+EGV zIXZ(p$cQ`C#1N(^msn%JB-Ux9($IF?YYwsUOEM_*u%Jl;*ib#naR70HOEaooRxw~b zLZO#tGtuQO>WWMzy1e5|bfsjXM`>gi!zT&x@EE$K7+lqY*~jdYn<3{hnsQZ_86@5d zkJa+8Zo!17tMU_aBmZ&AznZOnMT@#pxB62Vhg@X#mbJ}>bb1EuvKUQNGiXm|&~A#+ z#DnZn$u{US8RXkyWZ{`cel~*~?}1z4mIR^gqgV&_Y1uTbZ>(95&(G=M<++T!cnjZ> zmjtrSFE*owyi|QG?*+)qjJDUbsB1GZeoeg_c4P6FR=n@C$?C4^7DXq&}v!Tl}(B+|g=36e7mpXEW_UY`XtSu*noQ9ek zyWIFh3~mvRmZzHEo^8c(BI{_(m-U-cZ;&4J4w#tEC}*YcqU;uRQ`{N*F-fQ!qs~ar z;W*RHLi#R9)31Q+q9?Q$MH$?xM&GM>Z#Jx{dZY0^7+}l#rWSRx-m?CH`c?e`j_gjz zIR7Du_?okiQBXH@dBo8gbhRH?2FH)?&n>-lMxV?Ve?Ea8U1eMKcIi`E)KtE8C6Lg zA^ruJ-hC}NP_NIbKg_d_niA207jT(z>Q}P7&&=A|-{2lVYnYi;rS8b@X0CX*0fd5z+Wii<-u^sOQhd^8GDpDt|WMCzi%6$4DbpI_8nAV;VuJG*rj6xT}fm z8x+dji0fWpg1CMhas8+X>Sn;8?;N;NMT0Td#eA?oF+~R-O;=kYG zziT2VkNWU^gv@2l`Yp&`P#af^M!6fJOIq|#5dA}o|9y-9ZHxbPi~pq&y%_2tYY@@A zU$kE(e9FJJsNY&5P_+8@D-M`3l)~@%*A0HBnhK=hm!iC`g$MQiGhNvjeqF69KL6Yl ze%oQa41f*#ul~HBJXKQutwsH=hpxpF`Pz9uQ>!HaMZ2Ng4d*RIuZ;DYoDqJ5u7XMGV_QVo7`+VL5=qItNaWm~w(;2{)@3tWGC1DD;SKB!ZD(f<&+|62XFwzkuV<=lJtDet#!AY`PZe(W+}x zg9WS}pOaV|MR5Nr{n!E~-9tPZ&Qk?F_GnW$Uq{u|9d6t-I?+bEX%QxibpVwZSq}x3 zb37;NJKa*mOhm>cGHITbejMYi${Y`^)(72KZ&5oB6dYA_3`pmJf)g$(y-{561|{+O z2B7s?oKPefMaB}CHciu3hOKdOt@=1&j7yA*aifG`MXGMr7V6ogb&_UkmcLEb&<3+N ztjWQ``r7j7Ys)(R(vI&t{t}L_Okdjy_3+WwMDtdZ(1@NmT-i~96M>=`%gRo;qJ+lM z{Obm-jP-4VbS0a#?5M$xr$G^E*$Gz?(q%R2DkS|6NJAx^FJdgUO&XQ05DgDYSU541 z9ay?yd9b5aanLM*qgr*dY@2Y_9$kU*wgVI%MY$Uu-Iex^_11z%M>_s+$6v$ohdTah zj^AdSx*Jd+Zg*mOqioNNcGNmf1d2Q}+6hOAXNGIftSkL(572t+IpJ#Ba=}Ph9?uK< z>Gvepwb$_rFnWD?Pp!aSWHQzX*XWc$>5Kk~-@ zT3`xxfaaEh9SB%BhT`KTqv&mon>k~31@ZCP&&?f}DP_^FyoIA;kX~t_XtjkS3tb0+ zuiDHB*RRHUE3lS|i1pSEd}FcR#!)fIV!e%KeK1*X<%AnlW4$d{OGU(bI|u%=Sa0vB z7-X^DUb8-gthaT-HVFbD!=I=_YA>M!)|r9uP&zNcO-A6zY#aBmG_KXrwH-F@;c47t z@IBhFK!aMlTdCj_FhMHV6{%on z)AvsW3<6JMmAAX??mZl}rxSsqzQ2bP?oMsPo#ABt28(3T+zs}URB$?2SqRp~xzMsv z;%6E4BB?wE9PBOBXMj4rWSq$Akd?K9nk*TgIorBqj+UGS2GS|cMnUcEbk#7u@Tv{l zR}4Gn-x_AIN(?)9HVmt}2z;I~?0g!wFNdQ&9krK^whLISqZ4({; z7{{OB`0b8=go(WCP>;yF0he%M)CZ8PT2FS8pH0Q!BuAa>q!;N=ci@PcpQ)e3q4P#? zRVO*&5t%@hykJuFEkMF5p0#SF(WBM3GaU96>-`UQ?I;~6dbFOT-F7>Lp5b^WL>6c} zDs

jr|6TJL!R}qC}#yjZScu6P{rFgInCQXy08_{Y2@m`W6|my8$bo?I=OGMdS-rG7Xop-Z^%PxX4i#I}s>K5f?e(Ig%nyr z+VT;aLOryAt=BMTz6ugNYId=sF2S$~z#9N~=R28%BstrP63YGsU!lV1ek~}YD}qY9 zSIt&$LO^)FOl(_k`EO<*YX1(HD{?*0q;{OEF5ls(I~@V7zCThsK5IFaNLxK{Sp>Edgqe9(KkgRqfk9@NxyMoWW`>!2GQ-S$BK&;{4?7xWJ|M?3{oSYJLN(+jMjO+O-$u+w3;3_IskF6h^_Pv^E; zf{?_t>~|#n`CIRxakBXP|ho;`c%@MVj=pTBLEh{ydElrR&5;mZ7miU!-Z0K|p3P zR=jpN56PkLnm44}&&=>;n(gcj6vdbuJY(Mseg&@Ten(!s@HNX*9Gqgg*HQO5GKKht zQj-~CA($$j`xapD0SAFePs^%n^gdLyO6-a6NSrh& z@+2k`;-qu4A`&cj%ZXr#jHpU(x-(Vb1Cr)+%-)@pnsLl z0xK55smJ5w^*5jy?>^zECo|rCqGRtqiN<%=FS$X^+JVg4>hyUpm2xXjRonxV1jjlIp@ST-yQ!|$A8)J zUv&KE&APyxsE5$GaPj7ep4fhkDd&0UbuS-XyEo^(r8_;WHph~96FE0&j(4Il_DvGK z&Jk1c)T`nPki)?*Tjdv%GT5RX2ghe5#^!lZ4_Wh3|IZ!ohaNED-dtV#nlQoJaA7EQMJ{|Bie5qcui&G5sHe&EgCzVM zHTULPzkpMCa#L&nDYah!)#?k!`^C&%q-fvYyDo^TkNc|j>|7f{rhE@J9DT6K8 z$07AA8^r}rH~{5tIKTrFIG_RD=yzlBVt|4FAbnA|cz-$GWWGSTiU$!uN8~k%UdCg_jFG zYA&PJ4L9Jsq%76L|6?r?efbTXhOSL1?`L(5mu8;JNMiM zn$T`uL0gC8siJeUP0KT@8k*2<0a|UAgo>hbw*(B%MY$W!-3CnH+@;{$C3F7b#=rjo zIR3Eb_V@w!>)`%?oosOvFr(@5e&Le*-Pl`nTbjD(2~WgVZUS$72tlJ~$x0>b+C`s(`+Gv8gWlkVHbNR3Y2?^%^V-oRssWJ)BRdD$Eu zESFWxy2XxJ<16c9?R$aESg+O6sk~}Vt(J>G(dzN4xv-VK3RmP`HyA=^?F~||Ef+2i z=D3j+1el<=_TpnPgvh-Ft<&tvtL4;?oXlMI(L7j3^ApVYHgaD}!RXZ4(41O5qu|g; zK{CQ?o7SLy`+-siLwWU_T0;vQPl1CibAh;jrHJ7SI zgXt#I!UqB;Oj^LaBxzDUahZHUDHN(Dk8$%b-j(ITgEFMs;{Z1jTP10k0#l?1Q?tQ2 z&6Ld)w@-9uH#GUI<{`wbiW00%PaaA&L_29jd1HUQW;jP77?n$}ucr?32c$m?^lDU2 zt(~*|kkiH-Z}~w~OCh7j z0IDh@5rjWUDB?^*eH@NQfiBZuM(5NznOGSex!d%YbtPCPP}B7~=rG32qp93_Y|>zi zP##0d^>d6g0mu4r1~E;mu{r%%j~UWI!_9m6rH4u1*IR16;%`+==8M?M%Q-Z-A#*f59euXFpi z%<%aMXHOJPK|zhH(yYS7P@hWl9zf>{&()Y54JF;^WX}>VibS*~W@AIQA)a1r}js>|c4{PsCGt(Gst!C4Am;g=nRdkok5eQfPn(i!8wbK_M&+kOTFeL=gsOH@eO0`tozfVHH}7{KSG(BM$y`7 zlzz~T@*g0|!8s5N#sBg_^xK1g!EY#cBZwXb6Zq{&`0enVf2i@>BLG9hqZE5+6~D0w zF(El7<2H?&xa~2}D!nP#EKMe29U?8&QWo8n}xZ# z8yqXq{sgML3AUK_B$*qMXby)AZa6-fHZW?P2^3*k=czPG)H;G@5(C?lu^^Tl z4_A@|+Sz_jgGy$L&!eD@&3Q+sbHDgl=DF2emCF1tfCCbP74il)00 zDfLC_dNd8RHBKfiVi-j0i2?^=H<(1imq1uPo~4(m@1$J$xSTp3={htdwYg=CC3{E`5O#(2xc$rxV)J09a-g933Ld>ucmfUefwZ=_MG zwfCDuv6Sgrd%p!L^jEZfH~Qb%5i~xB`Vq*zvus*!zjclF zV~V~Y7oI86c?$nFglF+m3@)T@pJ?U`p@#nWGpc++PD#zDtT`j+%>u=8O@jo<1aJqXW$f`0pHDtA56a_<1};9MuJ?N_Bl1b#I{=dCSnvb z|ANeuhS6?~khIzCd3b$%Oz~x!LOat?h<#a#uRuW$>Bmq-y{`d6 zy~UdRiL3_7x+SM>t`sM2v!ZkxF>T2S{rAS1;Qo6v(i%aBU7Oo-N}Jh)-vIZ}m!7y} z{NV(5iEQ1nBD)u`)Ll9FUA$HgubDxq8CBjLIq%Y3%qGd{#_Mws>9T4V!QDAh9|(u6 zzJFbN4>+VcVugpyB(OJi1DDz{(caW7H%%SIMIUg94dChWdpd3Wz7!0!J9FOU)l4(S z&q?F4(_x}6aZi9fA5f=^uZmdH__?UVy_FH6b7&HPb`A~iWca(meVtl3H@V+ei~Ai> zFJdCGdVm${#UM<_dMGp%*0fH}275nBo}5#lzrB`xF+)PXsWEd9vOmeEGO`%2^()~| z@BlmP0907I>fV}k9|$u)^u3gHqVm+766$$CJ+6nkjhyCXxv6|zPF=6>CFdicL7~5N zBl`^m6J)<>$bJu+?6)9b5V(-OEUYh!=*yz|;^5*vosJ}0-a}mdpkzm#R|suq|BWXu zInqAURoeQPE>F5=E9si5%8Wj74?7B=6D?9}wey%|SG`vIq_tLC1i@JEDIFrxsmjmg z)bqIr6wNxH%Y{!dAj4;MbiW`uy+kEntW;9J|Jrtp>8&0qp3HfVM*Jimc&InECaafg zUZg0!ToXP1uo$Qj70>6?3py$Wk=@Esx^IrsJ&eUk60s4VCVQN=ev}{G`m#1r#`}jE zV~c}Wy`1x=Tebtd1i`Q7!s%k~)AIKj{%vrB*Tn24DfRXAAZg@;)vWeG5YJwh!jJHE zGGsg9{_9ODvov`=VU)pggS~Ji*eOpe1N8FSIrV1FV&w$yh%D_rnuu=yW5L1VLO;uN}rfQ&7eLttPZmpETcfxb{FO#B*t9w;- zb)VSPgUO_ZtGl4+DioXbX&Zoep#>C$Ti<3-tx8B^`PH0yjXzhz&njV^3qI^gsjBfon z%YSw9*HAsr5+l|C6k`a=-55hgfCfWg0O>dRWVgrCH7=473Ue(BXG z_=atCCyL|GmN~^V4%Lqd0%VWO@dvA;O}xZx#2rI-%A%;mkNAg=rai? z(LTGZ!;REbCRz`CENL2_mNuKUmoaG!?GM2)v)uK8fjIpxr@p6eHo(ughmFGz^;0hV z+GNZoH~5)Y8=|6?0qI3i+jWWV<)3m&7;QvGU*^DzN+l=u>>)|t%QQtebwEU5+QU}d zvo|I;91YRjl5={sxh2N|W1N`VCg2u+C1cQ+#sTeIGMh6O{Mu2k{hTh^6x8ZhI~cfO zV7{Sg7|IMYX>n_jycqn}sf^7i<2PG|eUny0Mrs!OJ5}ABZnJOPLLsdP{nkIMzAi>? zK?VNEso$ld{U$`{5Dq?u0TvDt<1G8pm42zAb~1Qv3FZ~#nzN39`0>lF(wNbzfMq{0 z_2R_Vz?4XnsfgIH4M50DD0d?>Z3iaEOf!+0{xq3sd%(PZa_Ro?r!`|Wd1D76&dP=V zm?%p=ahhiQ*cpfk1G)Qe3hVOdRPvOKBcIQ}dvWXY=}p4Cy@p1hhj!*m{-sUuA1tHCrff8M;BPcuEZ(!ulR)dCp_^IH;}d@wNY z^++Izb9-o&7s#uDn)@N(j@W3l1ue^N15sxP*;W!BxR9=5%Nt|{9K%iJWuQbYu_?=MV zjQbKoc{0F=6cY28V=@tFT{4fpt~Vg(!p*2We{c%06)NnRGfCTX2x*z^Hn9~k!A+VW zHF@^4ww+3jekDhJAJ(ISTg7yFsVv9S$Z@GW)-jjPD{bWIG;&%^hcA<5aRyl|0~Ts& z#^0GFzq%&*vRU%8NWLuEOTqht$l+{2u=`xhhmLfELSB^!KL>F7Pv>fBw{wZwpiu5c zuD$?F&>vSpe=O(yAn&h~_gBdK%bAXOA?m~Bq|;G+v^B5-05kYxj2_xAN+U&+fDF>b zX{2a3KqG}KMWN40SUn=i-e1+Y>}pg(&^1(T&FuS)SJ&#{)x(*+n`?m{t|@*s zFBKkzaN&l~Q2Mz%g4$mPEHx_cjnt7O)7o%VP+gJBtX5u6@fuA}ZBuCB5bB}3F&(at zsoy}FRU&Wpx3>`_^u()?0a#Jd%EG@hnjuL0Iap6}#f>y(7}WZ?IT(|VN|83!JUN2c z>&T{IZ=#`NjG-2W<&2wwgZrlq@=8m+h3YRjP-mhgu!U2}A6iE1Gq(b{!o9Z%N3{W6 zeLKqy3U2R4pxgx}2$Tm9D4XQ{jq?6D6D4<}1_6XEKkVSO&kJXVn~1}pq8_c<>xSr5 z8EzEE^f+m1py0spfaml)Is8sC9h;y8b8cZ=LtI%=?=gbtj_|f~HXG?d{;( zS~SW8-~9<%6nr*X_@8RQHcn?vl3W;g=Dx4j9zo#=}P64`dBX{D_| zY8=X(upLPr1W9?9yb}6{@Ppy5&jDDC&%D2T-rv=@ z_c7E!%Hz0r`(|$a5T1C4# zP3CxpwjN?^wJ?SM_nCsb?G*Auj;O>MOBm}+hM z25D-xsqT&Kac?{VVoh&6&NS!=^u?QrY`gii(pKZ>-Z+sYZ-JzIQeFxD+xU_6#))}# z5>eg(6dne8H$40!n83qlV(N3caqLfkf&b6AcxT6s#c{(Sc-uGklILflJ{{&JUxw2+ z48J5KbaGcneg#Q*c7Ec-bKRl*Q$CBf{RSv(L%AEa{Rt+p?L63ajrZ^qum>d38xX0!26D7w5x^qVO2sjL+^+!GA!R{shrEmOs1;6O!Z}K@LIXg3B_? z5|=Yp%n_dR$$S==tIP7`OY-Vc+;&O=8OlU0wRPBYhi_2shHvHt6Zqy{_~!1se`nsm z-FRp|)OcY&yqzY8ck*vTcsDQc8KL=!GFiMf_Yh)*f-4lVO%tDJUVxZWDlmm>8gn2q z@2|krf;s7mc`gXdaI#38!oT@oYCigXfBai?8H(ESee~!;piw{*f-pjRAg|3!&=w{d zz#=sPF9I+;4o=UeE1-O=n|I=&eh5baBwpE zdZSB(XY%1w5@iNKKf)V6MzfpDU3&qjFu6#I=WL2(H^K}PCE&!X?H+zu3KV5toq0(~ zRq+W>cY6KK60H>X4>`-fOipO&8TMk;1j&0KT3^icjnql4C)tvNK&)QOhmYjJIed{S&}$!6mnZWW|ibNBWYQZy#=p5YrMu& zesAa1JNXC{CDpg{;j_|s(u8jCuDEHrSkb}n31E5h!-=!VdLhx)4}wY4v`^Ad?xg5t zyZ0F|E0Dv--QlnzIeaqP93zPnZOPReTf+USMSle*YKmk?xVzyPWJl9GNUv`H>865B=%=>xoy*$4~|Gtji zHhti|zU^cA-O%=lTpQaym1|SmXL9Y)_Jv$~wtbl&t;DFoWZ1L(PF}r>g)xNTDgZ?3 zN-|?E_$pRdxF!h zw3srCdR72OsUPy;bf!mX%Gz`8ktYevLhy&J>;Hk6-fY*F4^t@?&28 zlt*}c%Y3pXz42SuyzzTp{qf)R#_wrw{F(K}UwJh%VFn;xT@+}Rz6 zW@8L!bXAiJm({td-ZjCtHeJ>Os&=94^>kIQ|E|k=x~Z<$oORh8uIim}*&G>{_4z+> zS*jUo$D*VRGwk(tRUi7dm#dm%|Bj-6`*zL0bGmA-|E_=MO#654tbhBts(;46{WAU? z@bCPa8p2a^lxp6THSZ3G_f8w6V(9PhssU_{xm-1O+#I9X9P@UqIp%ZK{QuqNm@nNN z3uK#PpsNZxgGLsvy~=3JGhcNcY4OYGfs;a$w>zRi2z z$RzPwne^4Q&5&z-+i!AhX!}R5jcq;TM!u=7uUvby%`4ZQZ40}jl}shZkYSHGv9x!i)^7yzZZ*0_tiYKc_inh3KdScCMUVm#FxR&%PBojuA_tpYeo zEuId5C9?tGyK1RS0Qi{zSbDYtK;H)}<*KFGU`x1aNj8}0!eg7zW6N~SW6Qc~x&OV# zmQ8zX`K-rQaMg+#kFAjL*h;hQu`1I!Y0TQwxfNZt61}^etCo+wyD7c9a@V{YxT^Jk z@7*Bn-E!8ugI%>s#=CS*W9|AtA_mV z-MU)ZtwXbJUENh{WZb%X#;wEtPuyyfoL*R}8Pln8bPZPxV;c-{)zG*NHfI|Q?^+v- zaMj5FeH)BOx51j(HdxD5YiHVEtxOw?`gd)R8f(*2$0{D5-Kk>@7NhM|qqSW%icL1s zRcppgwgsDPovt<6x~^L9f8S*5rkiX`w#n9a)dra+TR+oeWB*-~b**2dy2S>r8cQFq z=c+NWkGG_c$92ue8@g(v|GkelO#67_tdBQw)utIAZ<6uxX8+E|sczBP6tpW*zNxD= zV+(BLs*U3o*a|IxDX8aqC70`zp57~JQ*y0uTSl%8Z7a*Qv29hkHnk0xYmc^d?1Sx0gdN>*dmu!Q7RBq37SP)3G23Fhka8!RwY38i z@1*Pjtau8(7k-4>xG9q{S<$n#tzwcYwfc>l)KMn$^0AocvB`ZQ4_1?7 zL%d?VAAq>;*v(bDyYfYX@dPxM_i&ZAaDV*HSh%OF_R3heXU4+4#lizX+bv^)eO!w^ z@lgDPOqe*MO0AQoZ|KmORcc9(&TwGbjAU+1H^-j^I|x{6A2;%F@u zcGFLYq_%($rL&F$kpkM0ZbTaQ-brL9(&%5D_dZ5K@&tg#dWYE^_E=XD5)_jLyF>>umi7O_H+`}FjgU2V*GHt=5luJk3lf@KnhaT4sWD6OpcP z$Cj^j)m3h!6DAo*Eb2<>EjLr_H7<_qP33vHy7m%J%uxmFIfz`m7?y@mDG{%D>YPaTR88*Za|Rd@})PISAS)i+7;4iv%kPF%DK zt#@P+dnNa~NDefuDczlHFyo=uJ3D1?HyPaNM&6Jh5hm%Ai)mjWHY)JVD*@Z_?UduK!tucj$A>B!YAQKC zXh&YsZ-R$ycoJc)(_Hm%hI3_8JwVRW-0)l%_Y$p-NUwenFsrvj@79YOvq4_8&hcz~ zJ?}!2W^U3ilb0^Zn)oUAhrm%X5h8ww#X7N~hXqZJFxt?>GB zEML#kbd==Xz0VNiNolNSQS_?i()PN>I=l?xsZPZ`M`l2~xOz@*#8(oLJ|X^jAchxn z_DlmCn<~WSg6W+~dx6rXW69;jE3SGq6N#@x;Z`9Z?~7u${19BK#H7`Zoy0=H z9rO`+As@Z&D(&!(@w>vod`YOdwomIDotpj$I4Gc1I8Vty&P%DTUNMJW5rHz=t0CA_~yQ4fW|2T_o=e$c5G zz9R$R+x_ChD*ZxpuIw1>$KR93hi-TQQ(i?|HG~%uUJO1GHD>@BG(S*VsbC|bCw=1L z2B?CVmF;y%hQ-=dvYHsB`5&puC$9ReQ*Az{M}Go(bl-*7z4CbIXReZ(pIP&WN9;oZ1f)gdfZOsCnq`t4w>OmX2he{tFHG%D$=7i7#Rl-`M^NJV~Ozli(wJ z8pS8LKF{IY{=K>2Yg+jSPXF%#wTw>W=7L;i^jnT4xFM*KdV3OS->k|p>I zTQqt=F}zwQxoNfrmMR8t;HsM=mB%!%3W?h8ctNTjMCiERQtt+oaj#!NBA=l}eIx31 z$8I7OJ9bYL)OXTjdZ7qNGcHLt#hYqoWT%94kY+|@?8qY=CIo-%)cw85=0}@NPP~Wb zqoe1bm%t6Z_q~fiM>l~#@c}yN`?8l>)w4iF#|J8&h_?F&?CL|i5+W@trSfk&87FHH zeW~GZZhE;WVPUnXj>1tEe_g4)5%;D!slypH6S~AbCJcYM8i~IfbNnf{9>JfkLis%2 zh6I1O>QA=$Tx6L9AYWbrHzj~%+|u056n$>cm1nx@4>IZ3WhO$dW|F8si0~Ab9%YtF z)?O$_tHCi?+Uk2|=1hmS8UWtI13lWYC|}}^Zv8vk76Twn{cWuOhYHL?1-5my0?T%! z0EWjZGG=9E%u5-wT=kD}cwK?{Y<_?%JZcS8Kv^J-619S~nsN9*qDb3IvlfE-g2gnV zka|P0Al0caU>`%9xI#xJ>Ukc$jcHaDV;c%kb0Kh~bp5^;83-1pkcNWf_(fQ*E7Xej zbc^x%XDi-yWhUMijpUj6EmUX$NHR~3!kVa+i&B)cnh?IpQWsa9a&o_nfxCyaMG3ed z@kr9EAhzI7H09CLw=|D|y`%Y#epU5i31PC{T~&C$G~u9xu%Tm#&1piF5GL!}RVCJ? z36~&YY8kR`0S#*&kd@Y35;)>b9|hH;;H?;auW<^7-HLHQ`l3z^VDwQ=-p#WVDD|MQ zG@124*}D#V>iFEc__uxB&|zz}y)S*Geb~Cg*J}Gtm$_ovc9Sj-A2)hT+mpIHcHIre zw>^h_b-5p37EEg|{&Cn_j$)h2SGnqHSKiyTJOK>~26kiRd?hf!%J~9?5&nDyf1ZNh zzu?bZ@aHT<8|*7nuLWTtH{0R_9RM26SuhLTRfD=UjZ-zzm(w^!8Q3zi1`}t#0=lDw zvD@ktlAm}qv8AA#LOK9W=jS020GgBj%W3IQCeZRgcBWOpRkakbWuTKrnMp&Wu=Pcf zgn>2^?2v7Pg7mF6kisRF{aSAsBx4t?+6B{Ai%knkkx>@cWN^r#ni+P8mhA03}H7|fhj^_cR6WzcoWgIj8$GLDSIn(j6k2( zF}V^`!iL}pn^EqD&6|J;Y#s@lhZOu(3;rqvzg+MGWAmn{hpf%0|FA-hFEIyDwBk$5 zn}Z}Ah8lc{d3cnNwf3u1`z=tdh8Mgw3UGMj7x@zNkk~J)CiaJ`Smm-+)&k%g`%BDQ zQrpy*m~Av>hOMaF8sKBT#4I{(4JbT{ayLA>9hktQ%fh4U7yR`K{yGJJRKZ`X;Eyy; z-5w}VVh3E(U)EhKwtXaYGhfynS2d(|By~EZ){n{8vs|=}RUVa;y>Y3K8p}r62|VEd zl)K@8-M|D67z+n%Xe{0xF!0|)U-rbs+q97W67z;oE&C%feFky9J9AWjZMb`2L6+%m1{3<9tum$X#=XbdM;?!28pwepjIbJr0QLK zQryKY3DU(c0#SH;+{Gs{>MjNh4nnyb4!Rsn;Go^%ppy#z3C2fP01OdV;*##-C&gX- z1gndmYB}L5(xg0KYNf-RLe;MZ4pc|E8>(LqCQ$thbmP;E-ZxPASvr)A!*2vEJgpEd z{o-c-Y^m2T-8+-&+yo4Db|FE++CY6>Avg#5TX6gFs~X;Ey3Duk4`a8xnPlgr$neJ5 zLU67jlMj7HWb(3pA-jcS=UQa_3c-1X1P9GxNlme&TS;=BMbcCV&Nn1DaU7F0#3Z+o zyp%7ePNMr*jQmj5Ext$~z6vDIOI1}&O0Wca1g6W2{fj<&!$QwH1%!}5p&~T{4LV3 zI&L$bagTJETpgodf-waci5S^J?j!Mk2?Oqa)WW4Gcf+L*f(cxDHC%dS!N0uVUuqot z5NaT08ZO>->CW&7VBzI#VA_rEgk4|oE-h$C^Lzj?upb3d`G$hB>gH#ax`E0+Mz+@$ z!b{1;bh0P3tnf-3_#}Yprb2j~k%#xX-7NRyPuVXuVq024U%J~;KBf`3=RzoX#aR`72zu6+^pko6KS-W20n z1g3Yt{bQ>A;{odjNMF_*ULl8vOcgBm9l{9a(zuDRe7(xFJ=t{nkR`$VLxHyBo*qFh^Fx}rW8ys7(xzFU`Q{0wC3&4Tw>p*FFJlh3K;W2X6W2>7i` zi@w)+i+(|QpnJSvHBz!}7QZf{u4trwNvTPLYFyf*-{6?7;R#sb!ka;?80r!3D>6wU z*9kt9VEH;_(Lgu&h_3twP~?&DDP!tfjg&V~{_^OUPO9GmO?`xwy7I>brTKkF%164; zlfI|mM-2aZr}fi9@)J9XpA^)m8Rvf4xpQYwqfa^z&(!h*b*vd$#Q3pOjGsEi__v{`6 zhAAf6v-HD#Xv%uR^*GuNa13uCTuatx@uGgx2sn;v{ZLSvZv7o-U0v<=He-bn1AUWJpGdvB?-b94+Iz{Y5#Hn3CoD+!Q z6i%DN`}x-ielF-zIMw{-*2mny)2r%M7VQV1?8x>zEB{$ge-$E7bb{{BLO9Lj#lCJZla5-XW8USz3TkFSJh><^@jZ^;N!5aK z(pB)y%D)M9$Sa-PbrzEB-k`r>54;@k)ZfVN>SL1S$t)Rb^uA5_fVs_*1G|m-#F-u) zToT+vOM-t2y1?GqSin#4D^QImqY5*k6ag&HDk#AyMHpG3JftB6Y8DxJM4Md5JihoO z1zY+i`)*AZG#PiRKI6C;Scj7_HNLF5wZ531yqObfx-00v$cG@mxxrjw%91qY!6at&mz-%C?}DRq4mIyJ%;8eMCKv0_ zL#JGps>y|iNV=-a(%_Pe%b4WPU95ex#D2XD2o#X2dV#%4OQuisSQ98>)C?ImjGAM zatOrgpY}}~U~+bURTNad7-hLAC)Ka0nM6GXac$Tpy*ueq_T#Oqf!*x$O8U6XYskOi zm1G^8*HH43F+tqm1a5~W6DieISErjm6OYXG4c0J{X<#QP7RxOR&oxL^ETWZ@CTn(T zXOl3;=Ceo9VgJer)f;E{zv5NBaYp(V}W8%JH(b z086LRC)mrY=Ek*wi#)twQ7xqN@F)Tr%U)6G;d(TgEoSvYZ;<^%**_Mye=K4DSknIC z+dr1FejsYrp}3{fuyqMrCJkGUuug`Hss@h%VG@u7onTq!aRz;3)u@hNkFY)n%gYtj zvQ|9zbAsg!dG$^alW#!s6^bgx*OMOw&~of9V`)&0Y(6fl^NN!9HYADmOZ@!zMu6c~ zVx^*5(b5yQiYp7r#^fZoG;ud~f}p7Hbp*s4MFGj}5MPMRgPpSk6wP=o5ES1e(IS34 za#O%mpaW_%mRBySm5Sjq?BT7gqRHmeL}UbmBl#?dZms2_8l0JPb~c}bCRy(mEB)mgB78Wb!p}8z*0AR zu!aD(2Ou-u9$r)<%tRuZm<;d2L}H}y+X4L0^gB|Hz8eUaHq!w6*~L!h&pTD)U_U|G zDTke_aj>7`?3BYU;1DH0yu?J$R(2(9&8Y7%ej7R%L*q_u52L$LFMEhtD;{EWqD@bE z!ZqnXb91sgh}Bv}Jfb8qbpdwsh0vV-=4UIN}5ETQ>6xR@zgHQTZIr!xY-5fLsyN5~+uSX^4Kh&-Y* zN*`8@HjdhNwpcG2GaM9`G;7H(Y1aGA7HdCdsN#}lE!if`dOTQrV~Tn$BW?XsG43O10iI}8B8562~w0yiwGjWQ{4!%kBmT~puN z4K^0$M}VuhiSa|lZC5gjZqlA>0y%C$Frr4Mo{uDhO=AYh9aeJ3CK4Mp?;4Yt8qC|p z=G5)o=0&wdrU!4{X%CLryTO)X^ikA#Y%$!VNGswS2z_g1Zc(b&hMRUoGpu@bIJSu8 z1xAt_44DA&m>6$SR9ota@zDhIC~s6$8|!#DhJZ#i`a~4e2E}O2ZmX!E&B+B@i8aRo zhl_3LbMMs}f`f3?$)r@sx}c;L=_68#7qaYw?#Dx5l&$m{n-gqf0>D~-o9OmKwYKpd&swdn6$^mi=!+ZX+9i_ya&XQ3WVcs4HHp2Zr6nYTqaRUBqM z2PEO1sKH_8y>NfQr%SZ{w94CC zWi0?W_F?ApsBP*nvyH};wezXm9^hjRGmB0a01A(y+zpRj3?}gC8Sv=AMgPE}zkku+ zujub%JbDT0p~0oNqz~%t19i-i_`{0H3fpDGyboh1l&x!Dn}g@Uv5yY4e6hb(-Y+S8 zhMD&Mq4fUc;0a4n?uMmTg9$7>29_RI^p7q2M;HC0ivE#B|8QgMH9YiYv5(F0lU zu$7ODEjS#Sn$x!@SY}^GnzY%+#YD#@=7mRF<)f0aXP9ZTC(-Qd!4qbq+zqpD1rwNk za&d%zqOtQfz`*}@>YRF`$ca$MoXBP1-9d~~i?xwVx4#pJ;i)uOMxJ7Dn!ZQZ=Mrhm zUBFPM6}!ak?liYtaC$Le-jM!@=WOlTInqCSr+@b0Pim+iq&$U+-9yDrFM6r>E@T~X zFOWLMxQ`gAX?>PQ*eQ?6onlPs5JPK* zaFbTTJG#!Y8m(XY=fL#O9Din-g2M8<(+3`h9`-6ei1#;I=O5RjPsr%QuUL|7er}f zKxj#jlgraV6rRs&>1O9Lnx6&?4nnyb4tgF;;GlEipo@$Cg~mrO01Oc?;*w5}7sr|I zLb%GL$IC1yyhNIm2TZM~ekoOd88}cKzcu-l92d)jL1yi3G8x`6l|5%27R zI`0$lt}bx=fQWZ@0r5j3-qQudkBE407Z5)t;(c8(<`W`@T|oQ{h={e%i9ZExk$Q^w z3tjo8zI;WThje=_HUZNa$xw208iDJpgBz-Y8#7?2@ij$EONYcaggu;weM{IQ0*jY- zzXvS5)eO1Kh2T+kq8Wg4YyAgO+$t2!{g5Fzn*T_c4#1epPk_no!Y?SOM~iTx3cXpag&1ur`mo}9V;St8UQB-C!SSbx zYC2Wu3p}bY7p~s*mi5i?nZvos>RK&BI2sxKP=P(0r;F+-vg#kPn#aOVd>gZySE$s} zB$*FoZ*nnnkVGuhZP=uhZj$xo%*$E^k~p;_b2IIg8(TZAF&r17PTKR&Qt-m~O|uuR z;Bk9R9u9G*WR<;x_`2nq7|qQ+s_B{|?bv9VzYcFys?mYb6!6D)@suzk8C|b~d9y=SNpY2jNc#$qBf(c#V;TqmXtl%ZW7mMJ72%ko{ z@9{l`bT~C5fohPJQ@_VRvMoc+6Rb0Kdy5OSK$lxt9)=^Oi-X@TH2ka<$r>Nd7MxZE4-oZkwX_)3F&BqPiqYfj;0N0VY zdJiUedMz!A)<}2ZQGL64O^{=0_1&U+PcN;mML^H;`$Z)#TRRdnn%A_x9~9Mx8GS!U z^cbJ$`w{hBCt|cNu9f6S&k5NGB{Phpz06?_?f)2HmLS=X8z&UWu0J%F)~-siNkWl0yF-di6N(OwMr{VH z@+Y)nbClEx&r`WM?R2M-xG2$O5tP~i=z=# zWAqyCV(=H0J3mtH z0!p5V%`%L@!hTP~ zE(Hu*secyLUwSL`G6H&(e<`Y8^;YWT1aK?$N)*&j#b`>ZZ^LuJKXk!WsA5B3jcfWK ze|)#agZ#j_#&Ely+=TcB5@FR0>tR^w!W!1yqN0o|YzX^5S=kU3;M^bdU4^Vg%^LCEqRixsu;f@)s%j3mIb{1q#GHMiWvyl8eL^ECfx>lKWzo*^iSZZFVsxauf5y zoK&w&ZdUc5BIA7t!&p2`lfU)3`RnwYIf=Fax9V^+tr z;5+&uc?nSLG@VcSyt6JT6(Mn4hbzcJv{9nh#TfUUu zEm{hSXLpOVlG#LcdXqagJ4Fiw}@1Iw`lpOi3fz11j(asgD6~% z)w1QX3?1|iU}#U2yWyY@zy$62FdVc}$zQ?v=tF=Z;v-zrp}SHXg)6{SCUjdZCwxqr zlm|?$s2))DPk;l}QSOH7pMwchABIp|z2pxm`Ky-vRZ4!@*zg7FA?r(h`AT2D)|YSe z<$GMxkz1}FxnrpH3}UC=6fur=*L+jNa1#9lA~mLz-ha+Y!BhPk68Yx}37d8<;WtXy zu#{T4Wk2gF{kpnE2+(?^UMmJx9(i$ zS=4#6lDBTDw)>4Db$y}nI$c0)Bx33$fNeajz=p&&)VYb6sg~TnbDjHvNNv-B=O_Uu z8g`(B{uL5->0H9Rl(0j(C2RYqYV$5Yx%L|VY|<~(P5K<^*X+Pard9Jm4A(T_h0mPr zO1HTrPc_V*ox80BBDHJDTd$Pf_h5T8h3im8Q@E~Ns%<5B)MP#Mdpse#cPTBs<0oXL zgD*zupc_%rq9RGgPM_Sx&R~3rljZ<`R10YW-M5;ka|3o~uykz)FMIA_5RUcM(qpKw zFYjMc2b3a^ocE2X+tLpysY6Si21U{jDTQlOdN_iA-QciNc#wED7KZPl(neW*W1&utcVl4(isAPF z{YA-PqsoVt)L|uAl3yL7v21mCNoiGv(Tq`+CNOO{VCu+HILemZE}D-Z`sh;ne2?v1 z(^MmY7>+j1Yv=PaPH>d)SPNBH#-318N0l-tZg8}qjM8FglXeEQ8co=!h{D{LtplJs zHUb6{g?L@SB2RUoC%nW!SdUz7ZxJ|#z|rEA`jwyqVe11nZjSP?B{h+qYXkmlE+1D? zM`w*F2FHsYV}Sz9jS^qZA#75I?$u}aHzi`$8Jhv9PBhLqNtDxE`_IewI80I?uTcU)Y-Zp?hVoC zhv$@(R%KtBk?Du~RjPMxNu8Hb@7#=f=hN}yK^keN%dI&xp$yB4@v4P?3@_ zVZIi6N!)rY!OYM;1b!$b>KeTq-~<<$2+%iaGMXF)G<8u)R$z``8R`u|%l+IOTx?1@ zF`KM)B(YGps$l8C#MHG@=qkEGR5le8SfRDCgdYtkrsYti8`JXRzy#CsXK_byP07Ei zQl+Qk1)4>G@y+OW%T}kCgmrCI7*a zKegmfDfyu>_5z?l+=VnDwWu;BwjhM2=FaqS%j}CtlQ#R2m}pvJUihF@o|=?B!%Um~ z7|p&IJYhD<-7x!VFoD@m;ZF7mW9Kzg_UV%MOeyoqylYVb!Pk+-dsYVg=)B5vCG~tM z0!1ego-2how-K%Zy3Gr z0}T8_>hNx6S?UcaoL!chOvKc(l!fKJZJ9NNnD3O*mKg*yBHT};>dR8^Mvfa0S`uVg zYAT4rcUUbBdW#Nv05CWRjuqWZk#Df>0zHe%}+rSQ`duqECZ#&{~>3z;K44chPnFrCpH>6Cc@ zSLlqSXNdht)CqC>gZHgD!I#45IV$mWM@oE?nO@r(Mml{%-#-sd<*!Rhe!RdRUl9Bv zN-~vwiITo7!CjrZ=4BE!mOn2k;qfYdM%Kn==v*Q_-5qr1TpawV&aFA|9#2-)`Z2|6#6|{LLc)@?~KO{SC0m&2;ZkxKbRJ8 z$OnJW6(11#Ep&ZIA4!Jy^b2V$(dqLGVt`ef-dva32CF)KTtZiiUg57LXoeLAqjvL< zraGJ=)!Kdty~=-<)F0xakN%yOwj9Iw<1{PLzKLUyrE?XNsz1?gsDNG$(d zQaT>LjO7phN4)YmQeMiI|He#YpEQ3Ac`}LP#1l!gB#+m(_3%j0(AFf^#X}W4(EPJTA+@D0fK%`txDY2nG zSlr{S?mT*@Z*w#k zBNhV#zLLB`6>Ea!XJ4^-s2J$xp|=L$RU&XQ`_H@-J-_GeumGeFsB7OklHQv)xxj}1 z{>Z0%X=Zuzkz=bD)$uMMZX&!}sBA>x?t!Apt)42g&E~Id>nhc39X$KCEK(A|}C@x()Tb zxg?0=M{DvxQ2-D0(%TTB2+;DIG!G2I_|jwi5XM9DM)ZfIZA%m+x>8WH+dAA!ezw=O z^FtcLJT+YU>taA2>n$pJ=sZ*&;i-{c1d46~M|k0))Lbj#25SoKAfa8vrd`WZYeRVf zMYL;q;UYpSD!IWZp;e$oSS*fUe(GU+cN7{=9i32%pYKW8*O75Ky25}GR(?>o;V3l`mPmS{AjcQ8~ z(4#!kQ)_xMAzqq*#`3zJ8YYGZe#XsXGH%{LIIcjBj+dTq z+rBUnwjvR8T|iukhzoWBab+Nej)~cZTV2Z907#l{xqyr;q=~YM*1+H;u8)0_e zK+vs9*n$If&@I6U{{jdxc|IsQv9=m8$`aE&J!ROK?=R;^SfL9k@9kj!O z5#ky^)b7wdITvi?WnO?A+aoW)t*u~sY}<_9sDAuF#(B|x7`5NXiwreu&s%s1^Gu$K zvrdwk@EVBt%{3#)XbWiGqQgS`T;9r4TYC{G${AaEVT*|?Y(Z`#0X34|va=05xF$Jn zo5?WS3Hn+@U#J7;nmwVlffz32A$H=COk%khY%h#PlhMLmV6={w$R-vB{i1MO7x1xO z-nMxMPwnVMpvdMOyf9CjEmhoLC#J^rsGyEA6QL^tQ4(a6c2siD5-v&cY{+tR zd0S6y$DbSVXRq?sp4vud;*9|qn~I0>?w;BsGy3eFiH$wUYZH*x$Pba9^{AjdjKAF9 z)?-k$@kEBVhIm}Ihmi6fp4wCEyD1ImQC{Cu8|aZ^Gip)0qe9QkNz$m+rOsQT9BS!U z7BQ3Xt%%W}Fd^^8vdDkH1UD`RozU+yMbdXMNTn^QVDclRm)hs2W1+K`M8NK&TJ~&-^`F><|SoX%Hni}zq%XpB4he5&4Zd}gr%BNHE{*-)% zh^@SF(Tpq`o#0F_a&&y-asWA;$s3o`JS992q7sKQakQS*^*OWg#bM+Jy4f@Qa8Pw} z<6>JAoHzT59YMuFcNo28-MAb{(MQ&p%mW+#!;OnA-3;dK(tXmKIz(`?gM?W}wU3dNf5JQNvdI#>G~^n0qXU!+j8(xN$jx;bAH! zvSL47aim=_i52@xg(N;ha01mhP@*<|hwaIP9hDvag`Jkx6dp+4a+^{g-=^4;fm6w% z-3yO`#LJrFIl`ILLKLPFxO=(QOMXUoFV}eLTIsZB19_}BQFM#$Uas@h^HNvF9Z-n+)bXkSq~W(5zwQ2y{B%_L&n7fG?s7m)HR~VrTCq( z|29wEp0WS7jQw{A?PZ|#j?YYMY&}i;UrxkHT|m5oh!eVicqI_SWjF^1?~! zpA*c_=(gfcPu(SIUqf2$S`y3ppsW^YhGtTCZ5l0E9@c^k+I49(YZ@gA7_{rtXvy|K zdTNvMUNrf;0i+czeItQUoEbOYM3^1Qh=`j3D@&Z+f|5+eZ$&}f>A}y^Kg_MfZKUqV z_vTjOb|8jgobFb+;O^|Lgzk|DT)CA52~s`rSl7x}%_r8sZ)xhDTSM=07Nm?jxgPy1*#Z z66yZbG=DPSW4#k>n;-JjG%o^0Hb3NrC(vd~6*qX8sbmTj)RAps! z^VGw7{(L`JV4DAkr?gEERI2o-ryk3w^k_Ae9;ZqV&W=i*^o8iYq3P5fK&4=(_AK%fco$kW8x}=A3gpa}KAEo_e0A zo;l~7&Uoe=@c*r@>Ynh-1K#<2U;L~+(-pd^y1Kf$r)Qprs3MZPk@)=!*D}TMnG2Ny zK0+8y4%dGoZGHkwkT#FNBlxG%`6tr($I|&n()ovV+WaKokl-m4{-^8@V`9*UYM!Nx zMGnj7fWH#? zn$h$XSEIs9p6eIf>$GOZefkDz`Z9PzQ(XTEO6=if=^-_n}C zPJ(}uF7YDYTad8m%-I_tfp~ACD0~7096kFikR$Fl82uW)3xlZoF=_V}$aA3kG>vW$ zyQwdberW9Wfoq?_d!FleJl8A$TJs)Fdz+N<9ZmD1QD*WE3I8eh=%Z;$rgu>bi{tuF zSp45$0*l9B@t@QAAJh5o)A?`H`LEOYFSXG>1PX-s2!;PV&eulwFCm*gkMo` z|B(9G5dG*e%=ez_Z{6#(X2wJ6SL%vSz!PfY`cJ6+A25O1eKXtT%QE?RCLhh@olM@! zRLe=ku(no&v zwc}nJW<0*iGmzse@Pyj9{u65d1SU{>4XC|(Cf`3pk4DpLW(up5bQ@x(wp7ZMZjIlA z=Nne<914Q{A(+HVnsjY?LS`;N4ZXih?mPv;4g6EW{mQ}(hH&d;^6O;sgOq&G{Wm~z zLogZc#h8}mW03f|i2GR_~(H()QZNx2-3gLI6tj>%}kqNEUa5FrEjo?gr zJrGT-qFIb~4{#O1x3s=3v()dpQOW`%@h0;;vOzk7IyDgta;>rR6!2AF(6EW~NO0b0 z6`Yr))(CLkD1*9U&i>{VlGz?DQ;!J?p^`Wx$!3tGW)+g4Cj*ky7#H<%_DiCWsQ1H! zD1ka4MBWmp>xQ6eBS%QJ@zjw~T$!I`jNwLgCwh|hy7>uf9JS*r2swc(oKQ$*(#Z^+ zP#90{(w*F@T9u=>8m`JQTa8rZCR=Tm**T}&rHlw8U8XX9Y4#?zZX7c-H@_T3UduH-8GWp#z`CT*l zU9_5mNQ_y^&X)Ncqx%^j0Tq4Mkty8oI=U24ZEfP&z&!QulCFa~fYw7%*qywZdfck2 zX{LT$p9tnCg5PQJm!6#|?5UA#^)Og{w0qAyv#E)~9QuEe{jt9=A5c6PR!u0dyE2za0ZfO1X|5~7SX*=}>8q)35j8oSn%rJ|dOrCyGgV^Y zfBLkuJRRC&xz+uDfstNJ(-uaJM?rNUHVt{k^^jy4l5q)LWpTyE+Wa6TehwAW(@oxv zJ2;a&BqLSQaR+A#P1?eds+vQI)d*0g>sBo@t322h;R+CW= z+jXl&s&u4`Y;~Brk8ZUDlacbqjX~%cu+=rar1mDH_W$*O-4sl7y&1eH)}G0AaDp@T z4>eRcfZRi!plZ-*A*9?4#F&9wGP%}_dM~PmDx6&1pPG2K0253+XJFzvEt5YblRqhw zKOvJpE|WhdlRqkxKQfbFn#muo=bkM|gR?S$rQ_Ko=B3HP;fQ2KOUJE1QaDRRz?yT^ zz~34*P-q+Cb#5koTKGIYp1{6&`dl#il75{65$80|H8V#&)`PUro4||%^YlcjJy2p~ zH^s~fbUXjV`*98I8%F!xjM>R9ciwXnya8Blc-JKqBMvx85pWJx5Y*7 zoQznCAB-f`>jY<#k8VeJP7c?9B5&FeOwifY{kF?rmC0X`$zPtyUz*8Ztb2DSz|+@e z3YU^X>KtQ41vvMISf>C3((KH|R4#TQvNJM#1aKiNOHt0ENc3M{tgERoM`Dh;oGpth zC6Wea^~G3yQQX>CCLswT(ZaRF$YFl;6r4qysxKzeMfy6K%@i^%CPaKV$WP0h7QH`pXkut!2}(;5jyntO#aqP{^m^n#!UWt z-J#Q|XYR}tZY7aP8@qgcy;VO0Fvzh7p#(dxtZ*k$;E@*_YF(n$mCAgDo7oEJnj7_% znCp*syXgpj_oWNm5w7`_G-`QwyQd?RR;pHnK}U!%p&fC3up{oEj@T0hKu6$OI>NaN z)z-Ai-spgft!c^L71p$k`_CR&Q8sAJs(ATiySzNI`haz9+gk1NfkP&4yV}}i*6Py~ z(G>K>D~O~oiT$VgcavX2`}!CF={7l8^O~BW_=T}o(d;g{*D|XldObiiE%*8=h^8lN z-UtxwntNjvM9E~$n*pNTb8lw+zfc#{>EL9|TLGf!Ij-Rs-$=_Dus6#8&GD&s_JW}Y z4aQ4RV(7i6+54nF$oM~E^ft^Lcw1~=|IV%lBmExv9PeT8mwrEke)N32NCRc;%q;PS z*atikCJZciIMbB0f8l)ssnP!~5ELU=|GU^ZMK6Kg#6)EjFm1W;gh^*gg_* zx(ok?DfG_br>>%nel0abiTMe{oDDHi{_kSWg_vJsKzy0Wf1b&ICX&uef2&-?E__ZB z(onD?eF~qMo5GiL*@pr2Q4V#|u%+-VRm=YsXl_?|$M?Y>q+(mIUDwKIqj&M<2 zB?^7KC`(-wR})gew|%pWu>O!5P;yq+^v`03J{HxqPkp@0gxrWlAtp{yR~XNU3dmK@fXL+Ck(lnU z6I|{Td5XEay=Yiy?yhAFD8T(hmpcu{V(zX37#5nlYg7XYa6ifAUhd=W^OBQYtbPWo zwCR9iEE{6JXh4QjT<-mY+(S&~+)TR6P^dG^DqEbSHV;K5c9=AuEdk0f%I0;fGYK9BE3V5WAkc=%{xz; zXjzjXkBf?MMct$xxT*c-^M(BY#aZw&7)vpNS;r)`imxrg`%j3#09^NmRdwF>3y*#c8TG`y7tlBfWmMWZFH2Wv=-QF9)1gYF$q;l(J^Xp{gMcAnH2fVtwf3PHk2rC=i;v@3hSt}(2(%V zSUSnZo&?qa>oL(#-A<^_8L0T&>i!=KzXPp{hAcS*yAyRVaWb1rv55;*f#;Qf%Eb48 z2~3=ZiL0~uDsAF>Nr0TP<^T+G^)}UgsDm8$6KDim9|MJrQm8JGL2GCKhfC#75FRSG z((6_axKwT~O9<)-he+WkRgmhM4XA7X33BS%hg>%9EJA}kUZjX&u67sg(oOI@oiJ14 z!)_b?Y&f=xHk?1+#=qP)+^k0ht5viS`QvRo;%Y*&#nA?Uwt=D~8stxTEf1r)W(FU@v4YN7rZcpHr-0dm1X}`N^6P0RO zi&nDfm~pqK-8TI0wyJK@CjJ9$Jma?EcQ?(Wlpb1!KhVarZX14g)3zwphPLG&XyZAw zL3vqT1ugM7ox0>r>QYuZuN$HAIz}x@U7mMU@OzpsLw^BSNN_f!xbz~fr>C>t$!cUa zw^3HAWU?BWEoAj1g2`$WQNBc!C|{;FM{^L?@%a_18 ze}d}t=E_0zmRIkms6&r^#>IcQ_<|6(&K5Q;F@dZ3)B_C}Zxp%9%obShm&9=!FGn{D zn(5WU(T!gQ8sPX9arEsWZ6#Y^TS~cwY=v!2ePFi2z9zcyJW9Y)Qk5+TN9QHqxG1h> zg)O}(-?}KSB89EIDBt~I0k`o9_`S>8wL-xs;14c}8-)D={^+8(G1M>MFD^=O#tquX zbV5{2=SpTkWCzdw)UPgge*|=dg=<>FLUVVOGN1tW-(2oxrWZ*7&E4%4!$Na+?O{Lx z?kimGo~?|MM)9^AVwm9W&F?OEcj;N$C|>R%h6!@FY~$Z<$Pw-#M)7hFF-(xV1Mbt) z<2;khxCz`wEHxop7)L%$%rQ$%qFE|JlqjPl-((#L3Y%-Z&>6`LUaUTGGXS;dzcsiR$i2KZDVyFywbPpzVDZir+OKlk$4dah zsjvsRT{#!Yn&x7T8RFQiW!TwJk{*zHUNJ?MDCTJyChLSP=eCd2d;a#7Q7UU%igLZ%e|P62xPFQ15YoJDFi?!rO;rt(i}uWgFa6+?j|ny(jz^T_hccv(uijzHVQY z4U9Hl2%AKl_S7>5enY-1>)ytyYdW*JuHx~q1E_MH*>r8Vg*~=#b)@MXo6LoMsWD^0 z9ZBNdvVqV3)Dn)$YB>&?I6VdEIGV3Cl%4Vg+1$dcRLMEz1=+%Z#DUwYs#!!f+L=gE z?xI*6;AOEmn_H4ibCs}IoGl!nSj?pVSJfOuEN~P_vDgh|`cTDz6-giFxdGztgwV@% z!bf>l+~_@>Fb*%qh#8DMfZ=w9U0HJkiLfVXNsGOS-uq+oWZg0~dCZ`tLCCbR50ON& z{0!#^Ji|!~W_mhPsHf@s0t>ItF3skS@OT1Vrd~$P?vt3 zWV2N;U%&TjTqNduV zsSaxDFmF>XD)TZ;&DTwJQBy}{r>755<3q;z(b?QFS*emidUUpMh#I7a@gO~xTJDyX zd#L5(WP~ZH8QGE85EifT^}f(*Hn3yH<^pOXeXv)&maJ= zGwzsd?%1q)!Qf!3NQ_&O%^j3gA67Vwn%|q+tvQLr>cu@d$l)l{CoA>L(~u(w*PSUU zYfd4Gr9!dHrNF0Gc$PX6b?VoWmg6FK3OZCmtU?%fYBqOTAnKkfQMV}RsH!=gT02Tw zJDOTM!|PS9uXDU5b2;w(ehd+u=_T;Ep$hZ?f@48YI79cFT~%`ywSSzne>}HOH0Dc6 zC!kKfYjPqka%W`=XL_j5ChC)f`edR$Q(4zgpQ5QxCF--Y{-5Jgf-u8q;bh{=kKTeS zgVTsh*|^iPxzn@C@~2Zp9BrRLY){JKvjz*ZxkXv^rO7i17#Vj?Hm8z^vv5nDe-27X zB23DEF6ul(!_835=sk}x_EN5NE-8DyaJ!%sr5Q{Y0z=7j5iWA)X8%Y6bTLr>yX>P# zddjDQ*~lft_K#;HmjOMHjhvs&T@c7d&JScG7m|4{CsLGGP>bGq+#{#Qr`@RJ`fb#M z>ZXY77!p!A3v!8Fj$YzbvV@=WR$_Q!aW!<1C~^_$c8%zEEtUQ;e{nWKmYOW?t?;%zw z??suuCaY&M9Z=b6ymQojKn%wU)*^ZvxASuNdk6MWb6VE>QJ}lY zb(J*=YL^Ab*t)sHbA7veoz~1)(|bt&|9~en#r2=i^h+>-rZH&xa5n#7Hvd32e}6WA zpVss%z|q#%B>!XCzzd#x(6@c?g6Dk@RK0Tx#k8ShWDdC-;uPw_ba_<6imM-;T{Da z{m~yK(+{YHMRENnEcy$Wz@h_T(U-IN7qj{2v-xMU`KPn_C$&+31qy`t4Tb;JoTrWM zPeL~RYR+pOM_NHNen)!Q5WVOz%=4b>XWi?xX2y>6Ds{#0;0d*HEowWP#ZX;GZvygV z11_gV?5F!yTDINaw(TeSTD9A?ced7bTgxL>BpS6+RP z(F3%vj2vLq?qeMtgEN$&Unki1hN#)wQ`6spjsIx~?pNUDL_m%(UV$Gm;D^G%PaE(P z0WdrgHTzfrelHk;X9EPPxmOMNr7-YY2K;&$_)*wVe- zw%sR;U`<0XAPl^&0S^iTR~m2yH)oW>&w4?r^^1sXCxyBl$t`U-Y6_0(BvG@Su7T^q zO>>5Eni(56we9L6rXUz;2sQ`e)55^}81S9}ux-ykjd#o|ezOb#ev+p+0L(SurZ8~30k?#K4>I6IfwpaXK^Vc| zhTzaJ@NxrQ8U{YafKLnqpKrkDgn_Rx;LF0m_Zsls0DJ9d+l4TKhYZ03ia_RMGlcIC zBYN5pJyF!kV_^g@8-f>#2%ZZgc-s)Xp$IUCb4bUSe=UsQb3^cH82B3l{xS^QXP^#b z@qsEPnK3^>jrk~Q{nL)^l%vi+=KG>1Fy>Q+@leIs9VfP3QN$Euev%;=9|qpRfVT|; zPc`73!oa&5@U$@SUIsiP4E&7&e+lr^x<$nk`{w{)V%O;nyr>H4jT*vp*U~0#TB`(g zBLLGo>pj$zcPZ*&gPB_0WaI{6bFkIrYmRa_g);&;mP$CYgRRcS?ge!%wX-|hTWh`2>SYfgjeP_YY5{QV=){}h%taw{wIk3$BBN&N_mWw zM@xB>l*_raml^$!D4~CE3H=WZ)BoTw{g=Q~8{2&DwP>(4t7rCXpYv`cb~&=xF2|R& z%cY{nMaH8qD51xBCGr@mE{J9kT?Lpz}oOFen8J%h_?O|ZgGhi}| zqJPAW46m>-mm9OAOE(bW5g_J?FB3)#={EufyUm8-7*34{w3+Z6YxLc?!t#f?(cvuY zElnevhhf;xRu$F~p9b~>L$Y-^$wWos$c)+pRkkxElfp^1FKT6qA=x3EWanTj&K_ch z8HRMXpc$rxbUH;C+nyTMiW(;S8+QAG+BbRZU14EI&XcU{Sz%$)G!-;NVmDW;g`SSY zZ>msJs8ESi?D~o|DY1%QC-7?pevQDd7Wh>Hzf#~=2>dSszg*y#3H(xl zUn1~}1%8phFBJF%0zY5i=L!5=fuAGrvju*Zz|R!;83I3D;HL@vRDqu&@RJ38lE6Bk-dIew4tM3;aldFBAAufgd68!x<^2(?A(n!uXNJ zj2~IV_)e#csy1<_x#)i$=1mopa(eb<8!IT?^iwjDhfoEv@H!3sTk5S*MB7alJC zWBudd|HUKGr`ZUxC)rrBC)ilA$Jtns$Ha(_iV+_XBmPT__^^}@h%xVmF*)oN5E_HI z{vFD|X873l?aIKOid#$C>|Pn`tXa41{4Hq2`zoyVp6-qwZ&E*=2ETJpg*C6pjAR!K z-*3eN-*6fIip%&HQhqM*PsKu?h=o2D3w+Q@C?U&U<;FszFOklxTHN=|Z$ubU=MM8E+V61LH3>uIJnQ7m4 zMhx*enC;|-1P5-E*Ty`6#}A>5#xUp)n@$8(30RL1B~Dw%sB^mz13%O1trnmLY+}YHqj~^Hq}`89G#NnTmKMatbq#p3G(BBq>ki z(m57Ahm98J80opAx#yha47U$A_Bm8K%4`oF41?8qH<8F$ZF>o-8;YwJ4GGReYp9fH zLAYv5f$sA}XIap`N1_uvu4y|*fTnpi_E}t)hJzjN_i{UO!Vs&|>-To#IMjHlqWz;V z-MM0_bHr3E!J}QQM4D&0xjzj3%{y#HJl-8JJ*87L!$cJ zxf*hKDwPy!&(4nB1pNB$#!g?*L14NErXJ(zBRf_YVs&idtGNR;ew^FjBL14&QM0j+ z>P}GkYyOIw(LS8Np>==Ft>ELYxeHXA`l#*()hJ)hy{PfGbqn}-aX2!+64W;O0=WCM zjXsAOpKj5ogW5))32GaC9#lRFqR*nnr%CkXptjMcg4#x31eH(Q=u1Iuqpt?FjXoLB z7SZra9tF-9JPMru$Y}daM%yQ5w0#&JDLzFj))5r*Fzl_QT1|axhR|1GMDa*jcBo1T z$}&=>xl9b_vVS#~{Zd0!O3^PlRHYRCDu=3+qVG_y?>mI+`&Mv$+4@{xwjS4)t;_ZC zb+|shHrK}oaeZ_xu8*$C_0fS`@05#NXo%u-Ssy9OxJ)FZjB^=}3IC|@j|hK9_}jwY z68=Ald4DwK{cZ@Y!9!-~6+^6rUN4UPu4YOTWbMdrGGFPeIP$YUbU2Y;B~~p{QKAf$~5|yQHC&JC@qK#(2lG=l*6uRuHR69b`)7{s4o+8B5Mrg z*{4MN{fGJ!CAa-Pb{}kysU?-pQ2O>S@87R~f4l!M2<97s{i`6Ex2As?JiL~>$T>jD z{ke?IqA#^i@Zn|{!?t-@)mysPAFR}yUMYbEN zwg6(=3jJiEpCt4Xg?@t2Zz=R!2>s?vAE^=eW^%u&l$&trjK&i(_05B7o{jDbF38DU2aN6MR)B* zsaLYwc?J~u!xbXM5QZ5r7Hyf7lubK7re^^?^40LL{z_s;m(DEe}R&7U2zaRw7$;2 zjk7qsdkzl_3g?Jme;o#9o?MHzt!?K>_<3z>ol0Kycyg8vwdNF6E)8^}(~JK1rr5T# ze5h~DNDkrqQ=uF_{s1c){Rfwk`^8{?7lYj^2Du0IWU#++y>pk;7r38m1{zVOIolaT)j%48b;w6shg`(zRdT7P^88c+04 z%cy>pd?cW}l8*%RtyGzpQ&y=mB0E;8H&dL-pb4!?*Mv&k6+v;034bju?$4#fjaT}_ zwVebi+WdQd)C(8}YNxb+r7wd(9}E}eszteBqFhpxt1!x~SESrJLFEQf>t6pbeX*v3 zg!%{0>3ICZ(-%kxy?tRj5XHaLao{MyMGKFoEm^JT7OYlu9IF-CT-2=*bvNUBdlT^H zVKCaOrs}edf@lKL=DA#TvLnV)a}`XUYA6Qr1fS0dhZ6 z%KfB%UoIoNhy|vK1$Gt->;wz&Vt@Ne9I7CSlvyw&3_H!ng~gwWh62J8?6wu=GV#DJ}0zmH(p;|`%O#7y$ zm-s~05y~HHi;r6MGNAal)uEN4D~DtKk=AyOtHc%>?UeIlG3{jt%y#4~(htnn(&ZT3MD{^LKV7Yl7>E9*C%mPc^=RlLRBWEjbHI37f z*N$DJhKJdQdl;x#CSW^~fVZ1L%UY<3o|egWqEJj{C+?ylIIG>eM~Ve?+>YNXA;HTg zp;p@fJ{S%}&hiSnmxJ|7CA#;865acp@Z`8AXV#yoq*Z*t5uU0nI(b3)!K=zx%8-8_ ztM(3#wtCNob&ytmB;NM{#N&s4@0Aemof6``6(-&rVdA|8@k$@^`%r`zyYeBwf5QR8 z4jb9u8*_eJLf)@S$oplOyq|~3`&nhtiIh(ex=S5J`=PX%?VpXfKZf_wFTtVrt8z+r z)^L7X34150oy$rV$-H7EGDng$ZHKysoij|+N#7F{b*gA11Klub&1&v8S-46+MkHw~ zz)ZVD5#Kw>&lmSfs+2S~BdJo+=&oEwc42sAD#If?C;9o~6v5j`@U|Dc?F4UI#*0jn z`iW9MLF&g#{Wem+HP_oU(12ZjQ|Q;D_RLN0uyIoDbLcm=WbE<$KRW4)p6^neaU5qW zCV?Tyo|AcNWEp_i$lp8}NDH?}7C(U;m-GihXG_S{xTqVEkRC-4*YO-V)rO18kCA6_ znlTNnd$J4)dAp$vZx!Ox9{wiiailYs?P@n0d(8GL_=QpsnDdkTpt2*$4=US}{GhT8 zl$?gm3!_xe?UqO@i;Um&_`S-uyTXWVXR(sm#Cphata!pPQXVZme3bO?a_(X0NQOJh zr0rg`%~R|l{-&r4ZTq04rH(a9XS3RPFy^`|_1$8Jv2=A}_mjl$S1Cele-V#jVx;t?jDsWJ3$miJg3=Upk^5%J!V@=Yn< zkn(jYUz73`E}a*p8()xad`{p`bA99~u8%w^;pHDj-TT7Sb)0{32*7FQrtUelysLTy z4e~WPbl{~iY&JO$D?KR$bXf|lK9s;HeF?>O9u@!5hHxJ7hns}+U~-9yBHS3olHT_* zhND*RM{xazl4$6Oq&25rj$R9+g!4dB#A|3=(%iJ9u8Blg6J#XZKa*(tF_5+RT+MbK zM_r&JxOboN4<$+?UkU^%O4p+3wx7i8KT7$7l;2DFt#rpX(j8yO{pWK38ROX>nr?VM ztQ&0S6By60w(Wde$_2p9Em+S4a6o-GxHT$G|6P?UaDj-Hjvjt+KxQuQj_amju zOSz%IH{dcdLdu+!S%GKdKFy^wJjK&fb&98_VJS5|IaLBracK{QygUsIPFWpwon4K! z(vxn+V%zJbLT7_Y7{0lU9@(29gV!iiR`=o#?|CBfclDoIEZbY5NzVSqt)$7Cl-0P% zzlSk4WwncUn%ra))FBJ?r2qU*_?R$>;fcG8opu#FOp|ho*ke0mkICTN)2-SIEG;IY zU)!3yoAG`UMJm$X$TL1wlyh#KD$bLu5NXIoc7O#u(VVBO?Un2*5&dX&y+-+pD3tHm z`x*o8T~fw9i{+S6QV!UqS?tgxcBn@ioDkMQ+o08JQCF1vlTNn1e@G|o$DQPVYlYwY zvYm!f+Cr*>S(?Zak#4b+JtAd?>8-YsmS`!q#N3jWu$|7Z9+_WCM(z>kc#-Q^k!!iJ z-m(zu9Z}kPy&={+bY<2%s+43{W}j~S|U#PJw$8-&x=`& z$VC$5E|eg5fdsj8jCyB=Gd>?0dV)g2IXBhO)`Zcb=FBq8nK;yJotNU-;a;)cJt(p3 zWZ!9e^>!toXL#L;p7V{jo0a|sgT_=r^`Ivr{S6h~HAD+fC?p6}o9cw~NqC6}l-x zx0BHAD0Djr-S$GaozQJ7bd!Z{lF&^Qx(PxzUg)+Fx~+w7E1}y`=(Z5LaYDDb(A5at zWJ&h9 z7|uq}L6(&8OA5bA;Wt$H4H147!f&w1vA)o)Cv@uy-8w?Iw$Kd{y0wIEpwO)$bOVHL zb)j2L==uv?KcOoZy1qi!N9f9gE+KSrp^FJ!ROli?=LnrGbe7Ql&Z9EEBE|mq8;{zu zUwPD){lf6X&s?AQiR%+T3f&Jv_r1`4Cv@Km-8Vw_wa|SfbYC)E>^~{)pU?0~1thW2 zPkA^;KjAX*G2Jus7z6jPFDcZF% z7?f+-(U&PPYr)}1Z;Xq+h-gYnX8+KrHP z94qP^BkCR{@Z|zOQsB!N?kp9x4}#j9i7i6Q$T^KenWS?;l{e{BkN&$AZew?M@oC@A zDqk|MO>$_MNe&L0(JG#pERGUp`$4>B9 z!Eh&Fz+r?K%`J0r#O8E;)WE%0G<^Crre~|KPDZk`0 z_Bn^-_<#65@tMFsmHSVm{E+)J@o(~*FqdyRb| z@hamdUKYBSxGZ~7@Lv%8=LP>c!GBiDXN2x)DWBpp_9VBPctYfTT;zR>`NSU;{6_@; zUxNRz)IY>!;z23@DfJIX`41`Ym-0R-@0Ic%DgP$r-BR8qWkJe2r2MOtw@G=cl(%ph zyN>0HUd^dO^eRaet^^!*j{F6B()QcstY_ph8Ecm^y>khd_8Ay!yc#~WD*U0gqvsRU~rQ&iTP{c5ztfITu*%^jd-^Mx9-ScPF}PyF2UJ zuqQ?UWVKe(an5uj0B@C9bSg-lsK?iZFpQjwsseM#dEifvm}+Im)YHsaEH}p48_)Szv&w4#|H$v1lOmHoA z_1>)pJAQo?9@BRCj#*;fN~pOE&n(p(#xogRAWmZ3Pa(vSu^ro)~6h4VC3k6wPoM8IBUJ=nUg~r&7wHT-xgn z)2=sYSh(x0IgFyDncw(%_Zq`|hcdWw^HqnuTNaTD|x{7d@ukRxCCVqVdEyzJzF7 zmk@2sFww?^iB<#ANQna0jH9&Ji-84wtf5+~iO+$T9t(VWGPqhoL&~&4A@b$YtUB9}`scD8-wcwSt|s zK_&4=7wLbZVSRkD{>QFF|C7R6fd1!-zUN4Jwv=Z{d8U+SaA}_g0eIM)JdAQaS1oNJ`9tEI6k4E1GDE%;>o5~wt%dA52; zWs=#8h6Ns%3YqyfZ1%haj|4RzHjL5v*8rE>sEO7!-x=I8A*tCgJb{i^wS z`d(Zg-IMF1dvLw8JJXl##${p`#!F0Pyu{9o7u!kjb`-qr1#dgS+g9)b+*HaIGF@b#lxs*ifXmqGTt-(D`u;-SPw2}8Kf$FFlhT&* zck!bYC?QwmH@=Vk%KjGnh5aq|^Dus_^P|AO=Q92+)5X4#`md$_D=EK}`Y*VQelF#I zr2LG_$fr_%BIO5CzR#uep4`7H_wPvgs+6xt`LdKRN%;&)3R;iL{bO9(1&kLCR(~xq zN8DCoj<_Xkj<_joj<`Vu5|c;JZUYVdyN6k=h}E8)??DXN4qw{k+zTWX1We|7|1jTH zFFsBH6zrsW_&kId+S1%nyP&bNyBXiyY4N>;o1`|PjnJdAKpUwkv;+jjmr z%v#vo;7jdrE`FHRUDw&D73f%U#5PHx5?pQ?1^D^>2>F_C_tX7ukp*kdepH;oGOtcM9kCdE=wpN$OL=S?zoYXHaA@9Nx^7e$u z+Z877e33|&8~WRQ2Uk-L7RZy3W*lQgI;w<7N0tz2X_!cdhlzApby0GB2t2yf8OCG7 zMRiU`uT$(kP3Edor94IIPv(33M5x5E{5Zv_DB_-kYVUZ58O}0hI3wJC=T`f+%53NC zFez>499YpaI>7oO!}@|^JDj%?J6s&r0=$0(>ly!r=lJ-~k~{n)xx@D|_kSmI|F>N4 ze8Y6HudDej(yyfaQpzv5jDA+lA3*vPUs|T%_zBm?KbG<%DL>>g_CDjs-edg4yWD=_ z9d1AIHn$&pi`!4UDeyN0{yM|suZeuGa2b7B%9o`6MJZp9@;QM&%Vp#l<{NpM`9_`+ zy`NyX^O%&6O8JPC|B~_{l;mFzO8HN&x35D7a^ikidAillQ!mgA)4P3e&jdq>kmLLvVA^*qsqX{isC5ms z>f~;*viDZ|5+;)#xk(Z>3ZEBSw|aHL6s$5RJN_yrXnH8p;C%&EZQ$wMK0>7vNSNb) zfKQS8_`XsR`%!9ri4@WaJMk+Nq_6XMas`_A`wdsCOuNr;Jt7ms!{`0j@bGy*GCXA7 zw}*$!`@gSr-Y*{>GVk{tUSi%~7xMDFzjg_E*D4|Jz%Y3Sgvq;_NEDd&*Bc%_@28DO z)g?r#Dj`xbOr)V75EWS9?oUFm+|6Q!u-#6rVjUiZpGPUIDHb% zGc!-2rqxqyPvuU-0~7Cd!}*E#q$1RvjqjN$V|%ciQ`gqk*iwwXqk;LPm^M6gnY{zs zg_haP?cSMNNApFHD=;UirI}g@;*MuQCJu ziV|ITIg3idNZjKGF_(sQ;l*KHcp(Br=?4whgoXL5ONIG6Ol-KlguJ(wkoV>=d2bAp z_xkXFc4v5Wu^%)dJy1fV`%8#)UzkYugo$*waYnP3Tv$mUd?;Mh$TQsQk*7H@M4sZn z5P6aVgZ-%ShKIw4-4ns_^BC}&o7(ESdpgx=3?3`$C$DJJ+J4a(=lNn4o?VFwFNLdM zziJr19NtZD1m~UC!Z_g*oaijiP{pa1&tMhWsQy%}^09=wk5EsGmJhk!e$R;Tc8CJ% zoU{GraNpS+y%G7oF@gyyAHX>*{17xh-0q+O3|V4nwSbI9rHn}Fa2ff1xLQC)Rt#4Q zNar`{*a?nowKpjkK{74p_Cg){RrSg4<{%1Ra|eck=B#*YU%ISHlu4TC5r#6OU}A!`b7<1*}2=F?C$ZpEk{cg=xDn%7;_7BRWn1 z`p2F49wkxe8`E^&u}}ZL>JQ&m?)wnCUEc@Ujr#tR-L>oicBj7o5cvH9|GU8NV|e0T zh9~Y}c>Hd@kKZNt1;&rv&iJw0P}1tAyW`%+I+(%8R7Dknx=h7~eTt>QCn~a+;KpHtvoMj=Q6RA7%`-V7JX`AkO1 z#}JM8dp|58+6N^>doN71cfv$_3!;@?c6=g&^GuJrB68h7H(v_JfmH)EE7KS$1~wGe>4*^^E;W4ncvFj zsn&?PB1BY*0rUXAUnYEuY#>DCG<0>}zH)=}HQbvXV%Z$7j@m>F8z| zPMJqaIb6zWE+eT7r_9L=r_7ZZKHoDmqY_fP!kBHn41eHKl3UK`*MU5(*tRyyV6Gk% zCZ=A6r%5R{-=S^Vji_oFrTbX5TWe5Nji@e33!H5SW0q}wt?F#Zo)p%q?d&Lmi&K+? z@kqQkqcZ8lVQh##hqB^*4q?Un9Gp>^c;Xl^Jloz|ySK-k_EfIzshAOTxZPpAhGw-UG%f6k0n{|BHdwt&xcTQ~ zthu#~ZQjj%+iA@BQe4NW&sZJs3X0beOC8-%r-~hCR>qp8ULy1Z@S|{c>4^Hmd&TKU9S0Bd^^OlU@ zH>G?-%GafQjZ6Dg$juwWFR8$9VkYl{Ai}+CG<#dRMnc$cL~>qWWI;1@kk^k7E6l7D%oOog|X0jE49!%*;QF+h~FOAHwcxRM1(w}M4pXA zo{`dn8%hsuAU&8d@>Q=?zN%Hqm-Wl%I3rAdaZFHi7rj?TV(9(8v z4Eod8QBZc0C_7PU!O?AM1M<>$?ru_}z1> zpnGl^bkEI0ZDc!J6uBo{b8^sNu+A;$YT9$SnY%o4leoZ*Tpzsw)&o3xJzFn&ow&-i zj2FF{tsA{c;8!xd>;d7zzxj^`w&+y2(40p~EerHR0 z7MF?Bh3{#?_f)2fpTh9iNnG|lk@5PTz<7O+7demR`m$rVzU*kOPaGxumrHr1l*^=C zD&-Me#t&jX@g>YBzL@z$7jb=bA=gJ2aDAkU=^~w6I`gG$m$FsLc~Uk@*(7D7l(V?B zcZE0e^f(n=A9kj43VXRH{PJY5V>V=gwtY5afwpZnbZd5xEY2&}HF*#BI?fE=n3B=0 z-lkj1-hP08h~P(=v)1IjXW(nft<8ZG&j*5+{}V-UmwX*GBc+ z<#{l?7q=G7d2FW^cJv-(#7|fOl|Klj&U*It;?+ZJz#eV&o(O9>&U6uhQ+)a9gpjrS}Msoj4e@{+dHk zNLOqf%#? zuE`dkO`=myG$r!1Xy1b|#QSY`ml#8Z5@YC&urYLd*ciGMgT*rhb!vLA8d^pBZO-E| zydQyRyt(yo3DF)bA=(3BqTL@R+I+7$|`#J+Gyy(#v z1F?MT*dWX5b!bSs|KQ9x-PznWyPbaTtEax(8oAAcJ&J0_j|X380Jt%)_3eQ%FiF9v zJt%F|NAO2RE?=!|K(}fjX5ll(iY}(#TZG zuZXFyUi9mu`HhGS>^~@CmEqp9AQ^E$n^e~qby2+QqU*@6Fsf6oaFyan{#-o_OABX-N^;bT|IRz$*%66hUWI<=rJQl z&0J7Fv$?IlrKh2BW_@ROL*wkOk#nqXV4KzAYxjdZ{qa{>Mtx!rgpAe%`J+CfYlv;F z4jk&+0VtK9cyMWE_2Lc`+%*HZk96AA-EF)G7J{n z3XR*>9%zFf@pXCH)=ic{oI$uI+ z9*%&ep0OYRf{%_4JpD zsGfW3zcw@Gd%7AsyJj{twl(Ab?e#sajcwgsGyP+I%&5^DQ*fBuSPxiNb8AOSW3s)Y zv8|~k*-S^(lP%4&I_o+Y&&2O0&qP!BSPUItuj^@Y-U@vX3GyIVVEx7D>aTIKK}1S)5u$BId-gct2%toLUkW>+`jDD0!6cLC@!;hR7Yw`bIT&UN10)4Td5r6d*7tkxDukLZuhp+u}OtZmZ zZ=Z#GZw#MD_u$o{@dnxhY5pVL15uKlUHpjECiv|dU%ZIsPU>A4^gP(@)~o!0=!l+p64nBtU#Rg`b4T)OG%`eHJ=(O)Ng~HsUn2AeY5LH4a1PS= zR{RtjO@wky@gKH1MAM;N;zsWC-uF}aD8vfJ?TdDJE##I8AP(u{bahI z%aQ&tv}akf>+oeF<*U7P@2KzUtNX+0KB^9t0ko%}mFUcv^*QI`Xcd~X*AeFK}&{H}eE))wm8(=Yu=AK>+9 z7_Lb#g%=tr=5{nTDdW?{c%6fsplQIH`hjdUeto}f$BQjb7C2nytMcAAW!@wUTlABK zVkx?h;+VaTB4v0?uCM!9-SfS818~I7d%qTTbG-NK;unl-@f4v!=1SsSfqg8^FNuvV zeO+xW9OI?M28_9<(YqlpY*p`(=Z|t8pWVX~l6GXs9=vsW)L+x+lxN9q>w2!;(vE_DhP|7B=Kaqmyu5 zVUfSo;>Ww$zo>5J`l=2;7S462pzi!l>gxW$Et2+L*LS1*cs%x$9 zk$HhEe3hwlt$UrRTWBnPld0q0J_EAcrs~w!s+3h}Jf1$51_@<7^Z{g+o7y>B>glT} zBu^4`=Z|fz>zoHPk2hUBwyhoMYNNOA^09Ol027noor$)u8r$C408*{nonx_wM{jD@ zsxM{HPirfgsO`Uv?QU;qhxIX5)<%H;VNSXa&ygc zY5Jtdb%oGhsqx^UghL*x#x`Xkbd4K5e_f+-Weq|)&@Yga9`vW%pb~-7x(;=u`}HWb zT!g2t1DO%=q0#5sE^6H*^fzl7@S^ymdEKh7Av<(Aj#Uucy9};tqwz9|JEYxo;C@8leto)!{1kPR{2u#iAGzPO;VIF z=Vg2rT}3FXXdg?hui*G~v^FxSA>K^pn(^aRzdWRQN`I35^&i;&O{v>BcK=$9rvqkMq1z<0lvg>TPd)OUFz z#=6#G^}~L8gjZOLJKDS060~M|Ovys>KpS3p8o|uofvzD-U{pU28XDCXU>lD#Bz;sb z$xeW_iY~p@VQ-0BPl1MLpVqYSO2VfRg({WFkj3e~SKYgwr?WZjdCv>47c?)=h+EmJ z|0SV&S<^|@M&3Oaf4WDxorv|S;J>Ev;gyt;(x}%v4{vy2L{BgsJ>Jr=kzwnSCEip= z-@xL$^YM7iBx?`=rpYEgT?(U18_!9W~ z-$$#5SOh)r6>z8r&Qm?W^Wqn{cjr~x`iAad@o!P;IL)KQg?(>eZY=Ico(ekB(c7zf z&8Frxz#yviv$XMx;lmz4vb;+$j6&@JzX|RNjf*x2$J++c5x$qs#)L@nI4HFqyjH|X zK!HUyOriwwC4cbqidb>MPiTCKY-o=n8S*9-+4TLxfi)S}eN`T}RZvkj01f@?Cp`OW zo)Y0m7qTJAp#NOGV%F+HH$c-#9#JJWP&A+?8sbCVJy2-Y)HHyxE!^CO5(s6d&=JO; zH>Dw_t}w>R(;Rh}k9ev0In_n^_g_?Q>7dis1%Lgo3@-=M=Td$A;Gguv6Xc(tU~`04 z3>_dK8^gbSHpVRXRe4od#KrGRD6S|;M)dy>t=Gij^#%2H1%K?;%+N{t!5NH1EVtA+ zB%EsXW-_8S+Qh9>>Cq)?1=@rj^odf^BLYF)zH|2os&BmI>Gq&JFzJ5m>Quo>pgFJeZOvU^oR*mrAT=VzjdK#Z}r$5r2 zY(cr+7DBgWfKIgo9Fv6v=(ZNRZ8V+7kCOrUl^@Fvv2LGaq6}k_@R{u419~+c(7dt( zy~al4L)l66ngzczvXPtsd-d8u`0l9rdNL%^UE}KvX^P3fgtDWA7m-M z`wav4g9GMQ6=) zO-?Xd_%~@9u^r)Q*|}dGt66a8YFv?>aLLZv*4htR1i!TeK1o1*qw(7XzeD4Xum|=5 zj+TYw@%~YspzmEieXLI5)1~>0u?NC0)RP#E?=8K2c>ZI#2nSbIkMLWd`FZ+a-GKkW z6knBVyMx+0u3Q?2dhB^FBrZYx3e-=a zw_7|g+M|ReoaL~P{+IkCdzAklKV50ArL%W<=vrHk$BJb2_}WK7#-s5^5u|)iZwA${ za8g}I*JxRLkd5Bk%)PxfR5owKbK?cbS4>*x?tj8V${)jyw-*F-z zG7LNw?kjt;Bn{Sx3#ZmKHS0ZBEn(18lve~ig(Td8Ulmt5mG+3e)OTE6k0Ni_l};m0 z>)aXJBz2vNxeF(+n5;hQ@79q=Ol|I%TG!!v+>y{CiTd5eD%z@K{hh6@UFnBgwrlTf zt&{Z{Y29LVk+D@CNb()*p{E|8=lU3{&I!QP|9UNVV5zjzy_InmUz<)kQjcTFg>fAj zltfA6ZoG;$I!BlFz))MA{W%5rY6oj}U2_XQ7lM7Ox-NYD26Lf;PeD*=B$?Ld`w_TT z`23uIc4s4=pi5qn2aMtg$3NRT1H8+tnC?v7PG@5imX!Duog6VCFOqyh<&zYf^&ey> zeiWx@o;sWOtjH0EI9Z^1?c(J% zo6mBXvl*iIo*_8;yocs9TI1j(EPVpOdniQPmTcp-?WG=DT&Cq?dSi1s$HIN(;j09M zy`<0J8;UQ_rPysEz9RdTnlA~3S8Q5PG}X1@d(5C;2@akVU~3@+hZuklu`9{PgJbwe zpVJN~8$H&8M{8NsZLG$vrwxS%E9f>1o~MrTT;Qo^Dq5F=&@MgA>A|~|bY4i0J6apm zx2tb0*3OoAqG|RAjcYcQN2sy88|vMzL%odQJ5WEXr@5t}R&N@j9T`9L?4+r)eW5%( zs_kj(s+)~{BCQ8KFX4}^xcn|f9eybt`%H))^^MI72w&Qw=MnO87Il2tYfpL}Qs07Y zY|>Nun4Uj0H`I6Y$#n3MdfKmtt!m|Im63j>YQN zmmBy~2pn&eeMoK`@u#4_%}7SHFjc3_UK2u z@B2)eHAxL>q+%qaf=l01-{42B>)LucYSj}ykL_vKT!m<58P;6)pNZiL76{}X9%c?O zc(9N7fQj=4<_oLFjwVJbJatyjH(!|8?84poLiD7a`B}}~osIYsYF8t|1IZ|UOS{Q{ zVPGhrrN>1A;~6`r-a%-5n)XANz}ag&OT8Z)08kpZavf#5nWNz_oIik=o}o4Y)`ZzBpLl1+Tq#an{YgL+s1 zF7~8-O8UKH$UVERrv+Q$uD&EY%Sp75Ut%upQ8u*Ks>~ z`r4)*jC%FJ0ldZMX}_ujKII+iBpj{tD8H$KJ*af&ZI>zf36-mBBm!I;(<#vVnf=G(|)2p)r-z*Y^z`FjSIB@#{Q>2@Qi+xzNfu2?q6ar z^SsDI`&{T_+5|Q2nOH&Sfl#4&nmD0xJU(mUgogRTgsZoS6NKl62_uJz69z6}f@~wP zfb2aBKV?Yd${u19{^cuAXSU@4m! zc(Kh$R{|SdgSr`Dh;ACTGTr<*p}KW+HI&v(154><;NiLvxTJ0d7^0hotxPvRPN;4w z_td@~^kogyN8`yigX6*ANF0#gvA-3^n={$Z-`<(=nT-o?_gVYD@K|VnER9~w; z-salFtnUnhTABIs1LNxkhnR4OX?@IC@!=qbNv>knhz9Om0V=zwcO+;XOmmJ|AIrVF zMvhxUF)lUVN}K{eaUyT&ISLni?KPn~vR-<{iPIJywMy zX$fB39c|V;BRGEv!5OnLe{n}p!LKy#CYuIv#ot2sLLHp_(K(;kk;Vp@!i*V_-T1r) zdgFxjv&xgmKlPvFN_sD6Q%^sS)%~pbdFE#`PiPpo<@#`2WT1ncU(4FAwyhmsbVMwm zdmHy%J+myj#=8@>J@6g6j^Mg(L6fSF;#%i71dA~YUO_*i%6#G)M{3I_Ce(R)^54xN zw>gd4h}Ws}EQ30yy4NP5AZ*sD-Pv)VrRTPNu$@fLN)xzN&&0=tJ!|H7`tTYu&*QYu z?yr(Pz{sGjz?b&?4x~N5(C6zd&VX`!>gGG0n5Y_bkw!bTl^vi)t!yH9#7qNs5>8R zb6-Mnc~@(D)L$%bn%1hfs1S+phApa{9q>Q>?@lZHHCp9<;UM-5JRjH*eEMTlY)B&n z-a+;!@8~7ZhUb`*kur->7CpPZr5&$}nVFyxby)s1QIbn~>Y1sXaJw2C=TW2qZ`!#w zyoDc~7{WqFEyBvj>L@dP(u7?&AaayZ_v+_bIMS$lSxS*j67Vw1A=!6_KK_tkc!dTG z7YdV*?6Apn@SvzM(}qn%PC7FQKHrKl|Y)lpHp6pOe2t zt%XwQ`fFKWypfOg!#uA&yBwn)RnA_XzQ#CGZ*&`^l2IzY_TJLB_`5@$kjf*9cD;&C)FVAt5jxZkPTc(SedqE@n?UERTBd4k__ATxUPut<$ z;YC1?sQ%awe8$7pmqU7O`zFkqvsK0d9GP)xN23;lwWA$}A~5aaOgEn;X_ZE$iFAc*l_??(OxpG818Eq zbS>=YLUHx7Fm zo@%TjeWxdUnr8+)7uI+A+F6J?*#|Lr^aM&hcJhqp^-$M>pV?7%Lu}}Sd!?V)tb+Ko zH_Z0N06K|5detMX^gbg?1*smD|Aq&`Z0p86_vR@FIG7gSwbwQSgl z!|thmxw>}~jPA%91Cyz$@e?|_dzO}+Qg(6K-^;!%`?l=6vLlj5g6r|glar?<&rF_^ zJU4lM@}lIW$;*>hCa+0eo4hW0ee%ZS&Bax^dQdg#~N?o10CUtG<`qT}n8&fx@Zb{vix;=GA>dw?%sk>8uOWl*Y zH+5g?@2UG!|42QM`e*7vSn1)^BdJGWt0z-Wr=CeYn|dzwLh8lT%c)mVuccm3y^(q| z^;YU_Sn}P}2e9TRsn1gXfla@FRliMrm-;^SL+Z!WPpMy0zou5CeoysQ9Z|KkYFX8h zRYz4FU3E;=u~o-aoltdR)yY+-{6F@-J3gvnegEtxkVp!!fC5sMC9bTnl+Z$GNj8Oq zBpZ_e_Rs=EN+JopxD+EQNUj&3QuAg1MxPEp0+x5Ha57(crBd#S~mv&v&mA)Ni@ zcHPi*bJv@@-rDuEu1iw3q}-ZvU&@}8hf?;YJe~4v%5y0%q#TAvy_xcE%KIrFrhJt0 zP0IHvKc<`@)B4w^U%%di1`JG19cayUI{WnQJzxMx`}FDCzfT{Qjm5j9M~>LELfhaAKNywv z=RJwrUf)@C$EJVW=W>@ln)jehYn2$Mv8?MJ85N8T zUb_rfBO?@`NoO^VX6=GD?`H19-wJ>wmN?;gGW$@o7$6-Dzj zZ_Ws07nS3pO!MYe|Hq-=DW}9c+BfLD(n>s&tF1gwV5=T~AtX*zd9x??wa%&dK;pc#o_);2 zXJ$=5&nUx-Pc3XeUG~+NWuKpN*TSd2A3gAcGe2^if5IGVaezeSL~Mw zN8@|E2l7vL+A5NXnqV62`!Ed{M8$Zi2AzC4`ajcCvs;Gr+ zZN=cnXS6tLQ_}f+HV$*Vp5quBE%V?(NG)t9o!Rf5XYL#D!2OO>r)vB6p6R$JTJAVB z1V1}2jKAXYQGs6X_q_AWoewrY_|3&V9rquN`BD2#(92;E!E{N=_*432l_mDC-ud{% zW}7c{JkVIC)2n7suEF=KcgK(YsrK2Ac8=)U=IXw0zw6K&%eS_saspQD__bFaHr2wG zb$6K@F{(Osq zz6Wo;`}!x_#5h{To#>ok_%^<3$BzOA?QzzmtJcl@Xq$7u-24SMzV&0Vqjh6B^Gu?; z+KB@1SHtJ*NZJu4P7cE~~|ED7_zL9t*&#IcJT<@7hO(!?qdfn$|Z`if`_Fd1P zMEqW)pV4+}gk8k-x7myXnRcb6t%eK0PYz5a(_E-FQT6IR-vo^GSr)ig~);S(Ixv^X&*i^yx z&e8X@ed$)$w0RjnTz^5r!Yz(PZKGqGCfJrv+WK|Ro?}}4lCkiy)`RbB?`Yq?k!-Q} zfRhQPYrnX2?-vQTta*BB`5Sl4Xjkee>d;80Q|qR4#Vd!;KF+0!mOWLQvwq{)O$B}1 zyz6-LXubHTvxr=M&5$tLxDE`qul3AdTHgHOB^SNh&r#8-kuat16S$==3{Z4>zb)?$ zdwb;h1^2|J|NZp~9b-?JGmy$@iG5cv-P^UpC7btt`EKuwUtVug*mb3&p!12s1yihy z`Tk&~f%NrXzy0{VL$^8tUp=^TVSju-@kd?`b<+nStE*!pV;iFY4P5O<}9k)70H-_b`x~gdwC%ygAZEIe-{EvIu z{Mi2R^^<%*I;J#+DSpUxVo>*6CXM@~`TnzOSDjVXrler(caBRN!xJ|$f-Tk!$^vio z`n~(Krzan%N&Rz9w?lm|b?j~o<4INHG2belBlZsdYVN~V^t^jr#;ZSFvhQuj6OG|1 z4!fzT!mrvJ?cZt0zAHXF?`!Ay=Tg^?zOwEDN5`&>Xn(k=)v3N*VoTXG>7{{ZTwC>C zpZhMm$&u0+rg+RzqhKcOPx|EZ2j;EZUh=3nrY`Y!$Lhv#tf~e-HS8U>9o}+5{3ZFV zUV8fF?pyoc>-fAeENkb@z>$E4F%R9c`mq6jZ@#2$^}&m0bsPVfqvEti7*m{XgNGec zD<>+(PoFgZ{fxMW64M7w82@t9%4Em<#xOPp6Zv4wbgbdm|2BNwBYj@l`$Ny$HnnZG z$T92mMu4uxzC4bSRe=AsJ^As%rZFY%mIZU~2+VuMk=v~iOyy&E#dAc$;oMh#e9KYt z(<|@Y-(<}I#~M!~cuMVSs__K3a`Lzd^T1tsME)lerj+?h$5zf6J7CQFot8Kri%x)r zb*B$KlP|gV%+pd{-T8X;$~V#-SDeuZ?BdvT6YiB?UOnoh35Wk|eQ?D;lRhol@3^}$ zJTI&suMFH&Yf^gZ4K>d!>UZAjnZujk(BkQQ_1${FV1!RqgNw1bEK`sGSg&RzjWpoiFpfh9{aHRlZj8CGu-iG zW7wjf)m2WftFFNdHIwPQViv#TNY!mamdC7ImE7&d-&a4|$?<1nc&qUtjQPKIcj}V& z`|=0ppTD%j8@1CnI2^qjVGm{LaWyqqc-7%ob&U3k!^;&|uBJ+kql?r}Ar|7}9wJ!#p0b8H)SqPTV9rqo+>ziM$ znf%)IXZ+2#*73I!W{ZU#vChW}MXCjhw)B7d>38A|Z(P0Oyl!Xqc*1c(W7eQpNt+AM z!M_~xK0Eo7kM{NU#`U{;K}$#XtVXJD+=lfL>R-NM=3T7{?*DS&g>Q8low9MKrlFW z!(DfO)UwGk$8F^&%2R^mA;yB^D=*}AKY78wpJ=<|;rT;44c+g!YHA}m;&r7;!%GF% z=9@lyloe)WOP4o7Vxm;$BRJO8P}M9IsqM(09jzL}5Zq?s_-di|H`8BTym#f}OFxNT`pvQwp8Ts35BW7>#JFYlkmTDlLF+F^{KBr(oUGI95-rbOPqVIs9dqA z{p$F)-@0Mfxyx^U(owzeL~(-Q^a*nXyd|ybtH1hr&Bs@^E%>1D@P?g^OBOeR8{eCp zfY()weVVJUnVmFy_ol4h-W~mY#aHjOcU;#Ph*i_43y6z;tM2q{?1ULTpFQ{NF+&zy z=BRHB#L3gnn=Bs$UAVTUX2Cz)D}P;G^})jZO|NzA#P8%l>Hos%^3_#R%Z&^&%M5><9R7J8mmsLnvO@&qDQqpGXKVY_jYNcZE1U3pYxxc;W!vQ zd$C>D=VYG@5}f5vx_qL zK!13DemPl%5p#a!#NjEKnHl`Wt5{o0=V@BtYP@7(vul@H>ic{dh503Uc|{{L@@L?{ z#j1(J`%fA-wQ_j>5!t0kicigl_vcfTs!3Iq1~=D@+i)gJfJal>@Ou5D7KT|x86ykx zeEC`6Y;xoeiVg3N7mLA>uWJnNKMjXKSm1S#4DU7=9~^S3YYxwnO9XUTK7!83ln#cKYH;;hUp|H#6u20_YiDI;Nak}U5t zSoX89gt{ZLGjn`}#Up|&vE?#(8Z@_HrvAhGh&k zcz>M5Y_RMqQSvi?woay%WnqRttHf8B2XC=p6D=e9D_Ut5TBiS$akIg5oWZfXuM;lNa2HIsu*}KM@aGkljL0v^$;ibCIpkG`K}ej2fP2LV zt_Dk=MESmfve?2h%b$^5SWu9kIkL#oVen0L<&4@X)#!Q?vHqJuSG4+4*vNCHm0?jv zabAuO|E(jBg(2U|ucK=Rohxj-Ee~bqACZHGEy`~gA4f25o*kXt3=6yBjN-zP7!`90 z!`dVWCd|nKmfBeb8M#?SC79nZ67cQ1V3YD2NsLzFhm|Z)+DXfQWmtZ*m05m9aY0c@ zaj~yBqio!4jDKj%DPU=gBYYh{WYTOadHrbc+G62V1Xs%}%JgOBC|tD|F|9LhqOAOr zQTd6G%Ei9Ik(oJ}8O5UtF=a=LjbU}4w$#ne$|%ao9Fdn*l$U`spyY%)y#E|}cwIGI zvz9N+OD~oCc!o>%k$8SH@H}tfiH=j4nd{3h$`AE&eq{g;AKriJjOsb)Jwl%NxTWEq z^Qx6+W`?gQr=)OXZjr<(KZ*&qAD;9L?=Myy=tow=IVDhjf5RUBmW3%SHqtjDyCA=0 zWJY!s-%Q4EUBga}`ESzj{$+j3eMWP_95brx44fH~m|?gWnNyVSFUTut5T9Zug#cp1!^IaCmRL_^73OE<=M`r~ z;)8~weH7ndp9<^XEjI*buB^urS1sSv+z?QAtsDK{!Kp7`fgFY8EzL=7)0fWn)UtD)NyNCU_It zad0ZIazZD=gqMZsnVgD8ACpm72P+R{l$V!Xl2d>wKFnI|1Nbhp#$u%~Mx#O*jV#V7 zE-ua$D-Nq}f6eH83nR2&c0o~gp5Hez+(>*~oeMKey%n{6>n2!`g|**!3q!1{{Mk8q z=kkhoKwk9?wzS8W9VPm%oiBmcvI0@fjw0^3$O-mjm>5Hp#@uqJW{e7h0PWl{^ zJ|jsRg9m_>#vAGo5Z6SbfNl_QKP&Xd36g;&sNi_2w_QulH7W!pSSmcg3cFe1QL{op zhz2;mX}PV5of7y}s4gVnwBSGtK8TPi_(N0(tFVU^4zR*-v%=_59Z*9lkqQwHvPKyN zEb#Cf4ggw=S6H4d}JLuQS!AzI+as++`;fM?+D6#}~8>JJlAWrz+Tf>hZUhZgw;5}8qH5b zu*s%qsb_c)++wmW@2Hj6EJ>`M!x+bv~*-&#HIg8@0fTs4A7J z3ajeFqb(e6mp8L|R*hMC5h@>Im(De`=AZXmnl!x-*{#&gUw0e7!SPjHH0q9j$?Nf#z89(^6a7v5VrW3Fi zZwoM}yAr`E*hREuGZ@bx`Ikt>*yN00em0oDLFQBOSzBNjPL2<((WbO$5+CIJ%WCku z1lzo}D;ZFbUC7|psy#Ud5E|AX`HU;)P2f+sX1Vdm61vaf|Kp%flpZ6p6 zF>VA*LsfwFyJY?F`3OGd)H>8YrNv3{G*we7)Rd-bN)6&WE7nc9p=;+RtUcKksf!_` zL0!f};0F}A1mAiFW^)MlLtyiG>T+~}lx5=%tv&h6NUh}79}eCS?^l`1RYKOsl=b@p z1mAFiIN1ifC5(hDo9PU8(;1ow4TVPtf!x2fbH~-rJyLseuSi`(MK`GO6u|h5Fm^9R zu#Lm~sesW`!Z6z~9ENB}0fPu^L}25_sy&(TrTZ8s?Xe4l0x@l{2OaQp3cvF*1amlG z-wfe#CkbaQyb4U&wy|d0+QLL~-_@Qxq#=>UeTXTG=kk9^S<9|M;5$Rpx#G1_@kUOq7%JFjp8?XZSbN9S2);t?#3?PXAY{Lh+KTroXN;RxVNp9A!&Y$l znq1TwqFc)5bfOcvvaS`o=oqy z3^8KULaUFF!{Y`R>3gz2_z;4cemJTK-6Gb-LDB3CcJ9*Ilj)z~j6&VqV7d!Te<0IQ z`w-;z$7v=&9P0~Z%FR1_GBuD)g#`?BSdvotPr&F$GWvZ#0(=##1vXLnrio(EX0VYh zBt}*4-`TnGW>02QN~S#i!T6zZalQ~|BXYh4oPQ$c?;k@@HxM%*T+EiwUXZ-htUe9D zM2o{XYH_rvX|g$JkzZJK@c{%|Q8jr=3u6jNW>=MxCyGrcIWh4BcI!cHYB=YS$G?)* zcVx8-tOA2$VgEL8(dP6{;iq&_yXm4fv!$Dfo*MK&?i<><0churot;~3c5aE;xrt@x z=98V8mqPWCgUJ-moXL>(>OY+~8{`>m~ zPQe&d4k-m37Y0i&=xhRF;7(Do8I7jF`PO`7w1&?OS5xI^NaH;@{936s4&x)lMPb_tH#pb)X`1#wpcMp zbV2!g$WG8w<3<(wQM;tP6o;?GYmX}|T)W}a>4{adGqGw?{A{Q)Db6<{6Vx>c+JKHF zK>2D15F{@LY`E}(+HI!-@u5Qp-3!OiW>0d@CbYZcdAKtJIHPz z8GD;?HkD%00dTemTg+-*F{&)5v?9}2oRW+^@Z}UD zl8SY8>Y;OIOwCcHlv?bAKNSzU;;d)_ZCQv*A6H{7#7d5n45M? z5i-m2i%JS}tWvfKM9)EQ4wZ8MAB>ZcZPVBvQ>KjLDUC<%*qS{y77kixZ^xd{oKXGpqL7^4GFh_2wvEXmBuFATOqxfZw$WJ(s78k+bC17oV<3F&D1;_@wnCShl2VOpy#1Be;InRctY){-Q39``J{U|9;xWD@Xp`g0 zM)*rH*0qG^aQGZQudY(loUvU0;iPK$iwa_a!p7k-oLCdcG3Z5byGOK3RooakqFj`q zjg8A5gCUKocTLbv7rtNO_v4t0z`ZbaELWE%W24Q__Eq~PhdA19!FLceE2$9flvn8U z7qL5+_Y%)A<7#*_C*Th#%3` z0#6XxU5g>h@`8_LdG$PGJtg$%9J&z6FD@(RlnowF3xltPzG6Wmx^296e@OpOZ{C#V zl;mWVTbE_AfVnrW#25hs{N48i?ZPH=@IfSgvjd|?EN`^5;5}Le=3~s&ri1erdY_@u z_MOD$z(3QTZXkP>McK{FWBXJ~C7{}KEaMG>I>1kK#{dp@4eUknK^F7AT$@#cJ7jhX zb(bi|6?UBGK@_h&p|rIu_);xP5H3C+R5W75;BuqTpP5~eonM;c!@O)R)-tqM-VMqF z1eeCaAOS3O1HVAnAt7vE2&15BeQ1$9EINX$G<&@EsG<&znKWN;%(TPci`Bw>`uGXP z!u$moFJ5~{)fS+|x}YpGH;0Qui<|%`^$ml`v#2jxqkOwity%Wux-V#3=LS6Jecv-x4+oY!EioLyZt5of3+ zXqV!GCn2L*Z5nUj`2#k%&&H2a^V}9Z&K8?I@FF#3b0V_wjaHcRr*=MnsTx@-iZTm$ zg{Edtf(3Y=VbgePBnF#^o2v%Knt1J0kcUr?#r|Tnq`6q5nxo^&^3TDvhw&^y3mD5V zwic1g!EY^W60be1nj+Zb<$1UtFsDhbSa?e)FgAEs*#OQ2t+!aS$h#b@Tiy|u((0|^ zwY^HJa22j5LYiN*#d6al(X}%@&KJ!j2q?6H|=kl6Mc5OZtT6QY;vGBN->&b;ib?@g}m9uQod| zjyUCu%}(`R^F)wx(_4$_ph($tPE6=dz6w(76zirqjk~8>Oy}Zir&%7{F>o3$A%hwB zvbC5_5zLG?ixoTWKwIF+P2M1Digxl{J8O|_VA zhEF(4)&7mseBIW`w{2^9E-rqABu?WVs}_?SvLk_P?z)O>%S?)F?!#&^r!@QuEXuh> ztHmT)-)%)M_iVM8_Sm6T!#mzt?G=1w6(roz)nXhL67eeP87SgDFI!9;^(Wt%a*nHY zj+@~$4gtjdEIR;5xf`s-_~d(|&bn%+dTTV2S~T)t=kzMPEiz-WV#W9Oz->5qasSui zPr*H9XYh4Vka36D;=>j)^%5wExP#m=sA@5mJf~{Z855o6 z>xqEKO;;_(c&*PV-#TJvf`_Tm^gaR(TKR>MObq-$}_&kYoc8J4r`|Nj1G zf&W?He-`+k1^#D&|5@OF7Wkh9{%3&`v4G!xUK77f^Y=}fk!=g$lXoN^ zlEiyKz~myM@MKX47Pe%+{Y^>p7H9|?v8|QN?d-R=ilapYO_|@`T3mGw#J0Fm^E(57 z9+$0HDKH)@`LZ(ikholLI(GT6`DF`CK%Sl+SMOWm>`|ZP(t4~|+7-dFWr#AB~m(?=NE;}_?8tXR@2MEj8xKU<1NItuapi3}M3Oo;a@@rxmoiWXRkG>5}lw9ryy7e&}$m$ep&qWJh{z|am?wgna&IcFdT`=`jc zm^tl{2p|DpJ2_sd+bA7ZfD6o>2p!wSdrwh1UPdX@@p2|i9otzIxx!MUIZm+_t+W)` zMUkoFDp3?4|E$o+4iQ%xIUb=kbzIFH>bM38=y+;$I$j4Z(6J?S>=f_qpmf|oDb#Tz z6Q+)xtcq;16loY}ElqsArN}OdOdU6iBCC!!7&+Zd9k(!tI^Ku`baa|J+VkSY$gb%Q z4&S5W$J`ybRUf0 zTc0&c3&i0`gZ@H1(xdR-ARI;NLSL4KVJB-=`eCxa1bmN zIn9i|)|Wj$r&+!4GGOFrXMoIZCP5|=WL`4`Qc?osWfqVH%>a@=*#(eDtHFU*4y*%q zIb+}zP$V1bL&q?$7$)Yl7Un%AG1uEB(c3Cf4HL+wMFYbiI-@?*p|?pyIEtxOiS@oK zoxpjevruN+Gm)R(HW8TSqavUp-8g#+P-`Tpt^m~~(c4*pT8nI|t*~`e*t!7GviKeV zp$UYYalHmp9S|aeIFUAIn-t=_O5#L13Y^;{&Yr;8Bhh8<@hC{r3DFlx z_ryf~0svd*?0wymwa!$`qa#t&4@KoMNc5Mr2C&woM4@mo6$YI?F%jV?Go_E^b%Mx{ zEYVKu;7@|iIjAzxGnq=JftSq71bzAh<_)4ey9eng6wd_{C_W8}Uzq5fq7=_VHbmqj z@>C1O3y^frNYtl9Dn1fLLh(XbtBAE~!W5rjDlSs`g}k;4#U)EaaZ&0VRGsL#h)Vjw zOSje#`cG$33B}qyNJpXnTrh$D^P&ITMDJ{+|2$+v!~#T~MMD3DNV*p$>a(H$)ol2y z%!XftBBB3cS?glfS{$bTLQ{W{(&zFzQRpvO8v2V;=b%N2o{OpE67bSRo=|)N^OjPc z-Gg)#imwC{D83wuFHQ6Yl;W$94H2smc`g--uR+pXpQr~S8-6W{gyQRDt*cmTMVR9C zrs5){FXeTTP+YP!6c?q=L6;_aE~ApyfR`@vgyNSl?^?>UdytMo@hxBi#aBY{%aztQ zA`kp;LgZO3w7wZh_mzqI<&n*O3yOr++hncnthFXg>nlyIMXE1!wn=Z791W#Kp>xpc zM9*3(xC5+oO9i3&Dwf_|_QK)_|m_YTbq53+d`flWb|NV$O>xJqMAnCp~QC}CS zx{e~D`W{*9LDsr1O!aF`)kR9E9wXXYax_#Ih0a0i6FnQK;9juOEfs|7*RW(Ch1xwx zN1^&tU;@=|fa=#LdN(TVpGG!BJd4P)RcQYllI|N5^^K9*A4HMR{&`vJ5Nq8Oru~hk z_Sc&!$;;4N5I6^IP4wJM?Op^EUE~Rkw=nM|3bK2UjzZ&izyuoafX3Ssy|*Zh-$gb= zypPDUQ)v7FlJ46R^;;q}{t!h%qSQHPXQJnC zRPs~s(nX$7{5Ix&MtOD*(#KHzFK_uSIaz4_Mq;k9imOKkxUWDYW@8Ul>s-w7LadbB zZzTdG)<>MjF9TWnn}l;YQhG2r~w%JL;JK|6dT(FpmsW0jhLn}1%kz{1>xbs4uK z>V4NZwccE!$^C$j6CwTMsH7j3(my{g>E_b#3kv?i6m0(;)=*3AKBvH#_O?mEoNJiV zm_>K<&cZbPl5)MNNk&_>L>^4v3Xyw2lAfAW?_2NeeRs=iovBM(*06nAqevf+gsV*a zPwx*Tfi}nkWTc~Lsg7WRmKp>&0~MUk$OHc_h}?sd^nsCZTqx29n{d(zrz`RR2k9u_ z^Z*mU$pD;TN!}p}QBTSn0vsEh`Y?)3UDxtDCk@jJCFz-z-&@K@ItuxNr2JgS&rb4Y zDfxpbKTFEb4v{~E^7ANvsFaU%6!LSV`~t`yp@iol5B&2HxeJr@5rDDD+56ru8=a}k zyR@Vc3Q(jMCgCa*|IIsAZAq~MG~9{7(zm60>@^jUQV&8S9iHyct<5l(#KH#Bq<;1 zDCAd5`R76YIZ58Ll>Cb*|12s0oDlglDgS)Rua)wVjzazdDSs^FU!a69LLT^EjL1Dc zNxuLvwm5s=mwAIT6{9`9BY+}(d=jq2t@=2^S%N$?2hvf%xeQFu9F>4GLBY8KdEmba zk$ZBIJ|Pm$l_=6Dn{Xx(&T8ZV4$@J;xeiPKXByyKnB<+J5N)KqDZp{1Q@@a6Q?Jcj zCA?!3O46rO{`FEm(ox9YCgsnB{F)^13?=_o%AX2s5?d=X2MIfQdR^3WVeM*(L)n4mcp z0M0xG=Mm(A|6_>Ui<0ztk#Kmvk-o@;vygBeM;_oH9R-}{!31!Y0!|>wyI3K5f$|mu z$2zATpx9JyZ?N0Eh?4YWl>d^Hk8~9B-<0xKKz@Cace#@PHsvpu^6Nw7|C91Bqx^TI ze59k0|E-k267nxs!oNoz`2UE=ePxnl~~ zD+I~N1OFC?+?$g0^}w=;Sk}TYoL}&thG~g%eUmxSZ6qcK@_-5HC@`H0CUDlRz_caF zyIH~NNO_w9X0riC-y)_P15PItr{6>noh1mQqX2Qb1hE|;Zczw4$OHfGh}=7p^jm;s z3$d(&VK}rJQ%(<*>pRRb{#Ii0A`gZ^Itok!zyyZ56PWHu^4_jsrBUAP0CS}QM!!Rh zv<93(C{F)7L8MC%NJjx8OM(v!URD_CWecR#?aGr;J&7-S4Mnh#*Eu5J*P> zVjP$N#KQowPa&9qJa@mOz39C7q?1oQ_5sdz!oe_uJJ9vmpARPskITFir!19d3GLKkRTCqHH3@itUWxm9M zbQD;YNh~h|%S%b#7ZjXJ2qyz@;$pObht2d-5*nljn{5;V{RN=g8Emx;a^IjH)zV)f zxJxBCq@w`0MuK|_;ND2`zNWyfBe+~ExHm$Uc| zw&|yUvWty~i40wD6T04VR~Ic4LHZZOa)-o%bQDOC@x@EqpGG{ZG7&;7V^p zEI&vrNJoL?cZsDvu(VZJ{v?)4E0(s$z;Y_F9FbU%jsi9Ae3nSdfka zi(g_X0G1I7%bCP-j}^;^V_+FcETs|)(otYJS7IpzmXc&|v4V3x;Vd;AD38rll8grF z!DbT=PK$x=>0qnj1rgprU4UxoWdv6t!66+5xG56cIRJN7vUjuscOk*8u!1`)6x`?r z!A&K&a|v#m1c!7K;ATm1;{k4LviAZ7ZVtgcXazSm6x;<3f}2Zl69{ge1c!7K;8sg; zQvhy~LbjI3LT0^5fbwi`{1mfZ@NKLrqFE==ARPsojS|fapqZx7Tu(G1^WL;$qNygD z%@PgLQJ~o-(bNIWOoirFq6wM#W*!sGETY*V(I6cKn!6;Lg+Mbu**jMOx`%*5=Dzs= zWPO!xF0RFkXmZJ7On&#GUiu=U+bz){9R<3565Vp3Tbk?*D0B}KUC89OGz?v!L3EE0 z-6cf#s6>Z!6zHCn=vD&V<;mU^3f)1X3z_{c4@0-2L3Ga(-72CxB+(&lpbL54yv&8& zq>$&$pNJgmGwBz)hSR(*a;!9M(n<5k$-(E=9Yv1yN%r~(8t;(sS}%wkYppjUa-JE+ zT8r8SWpy7Oj&NW^&caO6w8#6zh{Ow^zcZ&XPu9ITV!b)5eXh5*z4xN_#vM#gWa}5T z$FfeZWylv094FzmRV=(`^F8KXAix3>=_nj!ffT+F!soa5&Q-z}BHO*Vy*{_S>{>qD z?4{Ntndq%UdjSxW7$B||A*zF@J4x$8+}_aLp@uc$+?33e1TvI&;rtUByM zly}VamUdJxq99K%?O5+SBsDs{-gi?xb&E+g5MLQe5etg1K+Aaowt7*hzdDpA9yDJE zX%0&hh0-K~<{OhH`yYa4Z759(&|G8EK%%ff>BP4KxYl%_3czB6gE-xf4i zhthNajno`!$+o&Kl)?#$@4+Rr&W4@z&jgbVp(H5=ldM_Y6qC)MKwFOLsM@kIoo5@E zpykG)_|cz~qkJ%8uR%3d3E* zFu}win_jO(#$jTRZGU$tk!*W?a>shKdnyAq>^&0bg;4>0Py($6(CHn$Qx(dG2ww3bqDa;Wvq6 zO;kASMPm563OLp(948@9Un_91^EbmKhRLg=k~3Gzd9b5+&64^AtS>gU4SBKgM?BQ3 z_x zQ-W7L{r1(tt6qNl=fSJq_~Q07vtA#+eSYvN)o-75x>?rOZ_n*!UiI_a*LcjU{(k#o z!K(p&`xR%HWdr^8yMtG0_(nH)H3&KcuhRYY_q&_*2K(**=w)6F@!Nk4UJdoz{|sIY z^V=Q0P0HbZd#B)4#)+;_*<69wP8D97Gc4EZ8)htzUPm4lO!C3oT<(MThHUm*EK9oobqeAkf zL{bJMXAblFhk1(>n6C(?$^f&NV9p%Ise2Ry-48H_3GA>_FA4+pwFFik6|kQqurUBO zN@>q7toj5RP#^M4vm%d$y8pL$>>3L;4aL5WD9tXBW2I@1j{`z!Qbf-0@*RA^XJ!P=y%98zN6<8HLe4^k?Lvjy z%7qG$Zf7!3?68OyIX8)%2PO+Tk(1WjWOA!uvTmv$Uhc2)eD7Mg60d6bDhk&WU=4QWMHxIJ3;WZAQ%X*MJv=V7BzW=7T<}ZXU*#_ ze)}?<=`OC9Ga*jq5GmH&g(K8i){wo9^*N5LcN$D~KRD!icO&%P!{9Ci(t2*c4J)8- zZXG#p63DlqxQ`QS$34n7+=uYE_pq2px#Kx<9nMJSxXUUefLXu6HVP&J4apT~g(NAoLz!@F;_a5lEBt4Of(u4JyjoK}E?%DN1fZMTHViBg=2=2PH)67)tzgn+}B* zhrut``yxW`AqEE-Jc~eTfx&aQ-UG0bv|PrYQ@7QiYWfnBcm1BBl97`(&a zZ3b^5kfs?Kt}w}i3bS5NVKN9ROioH+G7Ks#+W2E+`E7+zMx@k;B71V6y%-r}PY>K+ zjtwrq-M5DI(C;}qbj96_^*Y6GKd7#GVvoFNcrHr6|i%4o}H|%i*XD>@Lp2FcDY+emeQ#I&CImwP!IYk`d%*{Ce=5tq9fY2f%F z-aW%iO;;&B94UAZ>g9xEaG|=ku4%QXW6g@~BCU=<1k>?@J* zkdYj1b%H1C&S|rd0*loKtF>gsqv_o|1s|$mXbo(JYA`0!gt!hQq9v^6x(b;>(ltnU z45rs2jSA~!be)VgAd-#C-!_zudy~<)fxbx^Y$kmo@Lod~!KTN#DAuN@xee3nG`LFB zC_f=!hz)DV9~Xz%F@pmyGU4q_ZAW7mejitH+f! z%NChsmsw!S)fQdrUc}NLE=BboORZCFU^fbbo)7>5YH&|Tc)|lncqr7pguySX&91V; zXzp0iPnM%p_LF61YN<-;RNLC4jefF6h~~;cCwJ+~mmviN52B3N_agoaU*0F!U{nz; zYG|+@nL>j{knoUch}k-)T`uK3iek!n46&O(o+Xz!JLx}cH|2FyOQorpN-N+{-te&l zLUQ^QAo5U%Rj$2r+Dc?W-s6VcCn%RcoEEj*Cxu+Fei{i6#dwGT8P6aC(X%poPDTe2 zxi0~MyK!BZ?u||^jy9r~t28}98RsvJ7Se?e5m8tdjx_I!pwfvO0<8`H67tc7Me|3| zh2I7nbm16`B)Q&eAjW$YgS8A+GgyVd=)&)S7IuACM(@e!14KG28Y3WP#m%?^-G?Zl zt9>R3KbH}2Biz@6!p&ctltbyAM&Cl0!aQj(6KR4`mL?o!X`-SrLkGowfwxZHsFHRA zVo3iIc|^gx6ICYcxL%fjgM2Y(ev5>Ml|(oCo>zt_0S`0noh(X*ob_G*cT?NL=7+`3a4$(lozHE44%Y=OiKu>yajH-vkK|8*=X&o3X74TrcQUwx!R-uoFxbxE76vyVFnTFZ=z^^~$*8l8y2uE>?8UOK zGD?xrX)tR1ulP8<9y(ESYH!z(5oT*l9?3Sj!j(2wsi@Pa*{tgA7)K$?6p3 z9er^<1SAm#8j4IIiRZ6*45k@KgLkHkvSj2#z*9^-4Y>vG#^oeff`o^)BHZFx$?8mlRT)_w+bzmL z65$r3kSV6yF-Uj}re`4ym}krA92uR9==j{?WDq;<5M*oP=4xG0DI)nRpsRlgvP-kW_<&$6$I9(ttTrMzu1kLv(yja?1aa zlguWfzjTs0pb}0p4+#%FBFsr%kd~Z}Vmiq}a*fhS)Z`rIB#Xh?>Je~~7l|j-Ntgv3 z7aMp2#M6+IEJ1;2x}`{XSS!Lw4ogyXdEg*>)Np3`@ zkaQCg9)s!4NCW0AGTJ7i?TC)gN!tA%Imr$p`pc2zHc*L?WG50HdPJC$ye2Jq2a4$= zcam$APNEj?VNS9OtgRjaCwZNCLY;(Jz;Ty>=WgO@$Vu)&foQsWk?^oqgp<4}S?xAh z-A`7>c9I7`65%8|GKHiEk?1_sVFWjP@fsJ|}7af8->O5Yb;c$)lhWPI3SV z4?RLTiP#D;?w%ee6%NFpRin6peFJQ81M9*7o$LJt%)CD__<_N948CFT6@z~<_?*F~ z3_fP?A%piByvyL94BkRu+}^$g?r4{{W%N%Oy(^>lWc0p_K9JFeGWrOSPCnc=lAhFg zP#nfJonj&~i6SDCAR{uVLqsN3v}C3=g&+^50s6;4!k+jEV(G5@Y07qq(98m?<%FURn8kVKg7Ph<*7 z8Xkap45l_d47CODbH|KgWE6|YeFX9wdE?8zrEYfF#Z;R5E927mDoyjNv{G9cT|RVd zN z6LXKj^i-q)uY-&_%BT~f<8zpXZ;7oAW3->RC2qXKIEm;l9i|JYM3?A_gonNo<~}W@ zB~wt$MsXuXbh?bXA&S<0II}4CQA2x}` zzFGdyyU$=E`b+m20xID?!;tXMSHj$5hKcykq=R{?!zUDav!w_2y>qt zh_U(#+~;H>4Rs%80a`AIi8PPc8giczC=iXBkA#P{BHX8~WL03WDkQ68yH62FBHX7K znL<(t5*~x;nMea(sf@~GRF3HQ+^6B&=>NR?j3%PLbe}Px67F+05+3?WnESMomOKZ= zY?Sj5BRXG37a)q(eYnZ6QzZ`v5fl9c~Y9u`L73DtS*4wzVTSF?l zM_fg5>%9qVaO?dgHcWH99?0^Z&fqi#T^V#iVBAP=1}&_7gN(Kya`!>0Xd?9z;#TD9 ztYdvt+ZWfUcoWL#MK`miX!?FA2)m8F1%<&z?=EX@L#8mvtw?ytPA695ZUQfm^p|uy zP)rGbLoBd0@M@(^ye48)7ins&?t~O{wNWMSa_$5_ow|Z7ZGe>ZcSF`)mNL;m2Ijkw zFC6tABs{DnG}z56!Yy<6MrarhFM6jB#HA+7|{bV(q*(qMi0v9Aw)V`lnrCy=CH+f)3n| zGl^Dzj7%GTv0#X-b^sI<|2Qc{=V)N(_bR+Sj(6)2wv{544154Fj&1rR>z()4ud4ZKrbUxNcsm79)sztNb6J?im*mgot8i% z)|r-pl*}^-VpX9mgIcelI@Nm}arls~6oC1RHy+<0l|Y^e)?q&NCJG}kzlBVJ`JYI5 z2nfR7K^oD!GI|e@9OOn~<5a#E_aNUYGsiZ(=42h)RCgB5s?!Cat{4Fg)kWG+S)@%( zxHDh1X^)1+7;_4;#j0>TQw}8P22DuEf z8Dt?aX0Pv20ml15Mn58Qm!nizUd>)VBUfh~>rU)wT%+PIC}WHN%9^4r$DkmrEq_B{ zuq}&a&3_|PwB;X2c*ssC;Na|amZbX=#gq`kFU@dfx{R725=a|({ZY8O=m-T*i53;PbJfa=d}x@_zs|;_>QDJ+Pu~Yg%RRABU1?Jf`rFl=Rz9X zy2>a8k=qYJ5f2tP4j8`gE=5{Sc4wNY5|z@A)k}!NL zrm0BlRA2QvomRmGCcg1VkxNrW5UUDh8Pw{F>Qt{E;_yj8DG;3a`jhHt6W;(7MqnO@ zOo4e25*`AAuymvm4VKXmL~=w7oA}Iu5EGwuAXNQbPJC<==qQFuLv@ihY$DR8CLt5w zFbWQv_)JQ3;u{VsHK$zi+-7>KqUi&(a815?5{ z6h^e|cw}NqF!)U1RctyN(!*vFtzJo{4NnOdOYxIHLGhDGd9*2E3JN2{S0PgfnTmwR zU^fkEo&K(TMrRMe1qQSLQsmN95yYxOSq2o-QJrXJAU^6)RgJ<3G&RT+Xl5eep(rIq z2}wy?f?P1K1qFrFA$Hf2(!i)Dg;^}9GtlBQZ}H`KU^a4bLf}&5dkju<3{G5T;W!VtmprB`+k!Ok}zX@v<1cS;04GfqlHYU^Uh- z;#i%74l?kWTh=W8gf~7D#aEQ_L(j!zGY14Z2PqJ!mG;Fbh!_@@gT`|Sg79I11!2QN zJ+h!lfP4@yp`go<7h;a3%)LCAD_6bCh3pj;o=W{#p?>-mDDtdC;3g3{8p9I{bmq|j z#=v6MRTiMrl1(N?TiDIE zaHXvQEg)QKKv;oTXM3_`Ohe&(O0o2oBcnMLm?|2*Du_}+umhSJP8~ONNyQJ4@T1ww zAf-G$oeFpepgazlmou|zI_>G9VaoX-=#|8C9E0xQwWtC5)u3lPuR-j&M&_+W+HBnb zp8+WET8EPKb&~2T*0@%tuMVlfZC_R68cU69S!2Ddu|A{*ACjvY*I8<8V2$f!jg28S z_yK~dvB^^7de+z=Yitgw!6&Jz#toJlTUcYGtih97f|~Q;nX0kXQsXA1%bN&0xM{{A zXlxpVZk0WhteDCfO5jWt52az5DjQ0JF*Rx^K{7RFC{0r6G0b`kn4>+m$!NQbZk5pv z8Qq3RbpB(#t)jDg8h5M|6EMHh;M&G0&^d&tv@za@b(-P$5ozV=p|`uY0}$pbjxZjM zA7b#ngDArmb!K&QQFkY(6biAZGZs64Cri6WTt%^{)4>Ldx*=jww++y|H#6AEU<-rI z3^pM!)^iV{0?hxAjP}ZCpN#e+YRKfr@!2^=D?1Z`N)rgZ0snR4QE9?bX`S z2KO?!o53yycQUvGfdS(^)Q7U~%jg3{?nh8crDp>-^u8EL~cSMj$cjz1CI7TGM6?I=zhc*6KWLti6s;jQSviNFeW{PGLIqo z7i3YB-&jcr2^{(3$Pp#z-=dO-l|c6guVT}mCJRHwKMfXIELeyYN+aPzuMp3x8whE~UDk&yNrhyeQ}l+cvT5F<+9rTcl53BBbK z;}9-AFCZ`rjKvKLbP_`m(%WN|ey+3^kqw542LB|)?w2g|x}j0f63UsANqU&1hOx-n z7NZ2k9K9xw8Y^=jWL0G^WoD_#%P8`^fA^ZwkAMA5^9O(fPmkIxvUzJ zdops%3er=U*(99}?P2SQE!(!tq<^a{hwR4q`emnpLEYb`oi2*x+VRM{p9-ok(~n#wtBNA?3I)?ei+sqcA0aR;5-Tmj0t5*i&xSGj4Qq1Zzn5IF+esZ%~;_ZP^c75RGtJoPV7z}$a@ z=Z-|K=PTsutN>EgNnL4QBLnpc4X#C2uJ)D&*J9+NDapZORPdAKw`56aWNDywrF|z^ zmKZG0BufR!WLYX%l7q*nP>!r{fX+cbG$6y7_C4#d2-rs%g2qtLkI0Kyc^Na0Vjin7 zH@NaT3v9skY#E(HrlsaY_Bc1Q42{KvWf)YXDce|d-59SXA5rp`)17!?zy=&od0{t} zYKjO>iW5l1Y+cDTH_s-rh<>HCRjyIV0s>L^Rly__h>3nO5*}Js^olB8(esqEnEp8E z7v@HI>CedZun1~gh|2WR>4*`{K;-@nML}nE|2yOoMAeeE22q5_v_B=^i%>|uGZn*d z$|g#yT2KhB>X7iTdL-f_lIbji>1;A3tZ+(`=^Vv$E}62r`*+f-eoPh77fkwjagN)PscH zvVzQNO|yto$QrjAU8$t6rgVyNKTHVs(wM=G>NP0US%5scJZ37pgtQhVgtQK^`(bms zd5Y5wE1-}6D1JUiyrm&d*SiX&LgTBE@Q{z#&5$SZJX|Yo5 zdgM{;29_DB4{jpMHX3D{5PMFNdDkOt?mPreY8Sjq-;9#!h17_%)VSGF;}+IPlr^@6)QGp#*lwwDE7F*)h|x_Ix$xkH7<-0NL8k0O z37n~zp#;QK>`)3S^cd>xpg8Wv=-h*`H1F*wuzH;{AuS0NVc(r7p`GtwRqoNayM?Y> zlpFtzEJy&c0$As?WXa-AgT*dV7)>Q8#KGUT&S}jh-CYLVJ&4Ucqrf-If=zWVO0aZm z0eX*7X}3}7{*X%FTPi&uDtTB5dg#33*83hLJVYqQ)Q5OQmECtOmg}WMoEQy{=K!Vl zjLa3&UQ`M9+m_%E^xOTQ2s4R8qIei3wCbaX5j{p$tx+UjfiMS?17y&U#ZH!N9yi!L zsp`A8i7|l>p8_wjBejx%u;4qP;X%yaCXA=R9yigafS1RR{IntYSyS?^|Ayq}gk%pT z!%PQprPE9t<2TQk>{q+Uc72uYs+gdyUhbmPNbp)t zBJ@kNU~u&((#C8k((FEP2f9I!cuz1>j97;uH{3VcK}yg!UM5A@L}Ni^yfOI?P{H!; zQPpGU`zo^NI>dJY_m=<5g2i&-!wzZaLL#a_9RF|VI z?M%h3Rti`AZ35udv}G_qHAL}uK!IoHR0;6kFhxt)=#mSUn* zY=hX%)!5f0a+1hsw1$YjAyF3)9d$uQG4P96ovfG;V_euX>~F!wlL7)ELnmO6o}}P) z8RU*EGf;I&I}K$X5(eFV-%vuxze|vR5Tpl1VZ-&GWYExX-CeRdVz99_5t`c(2{sXOlW?WeXkzg8%FJfS zB%lPuh!SO#B%@?R4GrFki5$EM6^^L)$_`{v<<^K1wUN=uGCBoO`0!?N?c*B1|5A5MZpYHSEioK( zglh+i@;DE*f(Gq*)ik{qbu{|RsmP*^9T6kyB%{tUaw7Wwtz#ErIHry+P?R_IP%CJ_ z-z^D_(ds$GY0MR4w9y?K8h+g*VwhzJz@#l{V26#PPf#y9j$f`)($gbZ-5Uja=f6x?B0iJ z8M9tbWYINxA4T->0q=7>wT}usm9>uvye}v)hZ8uk_Q#cV4v$SpOO+)9P(p16l4C>7 z;ISC;|FQSpfl*cI|M0ytlMqTWV^qWjGXY0O4bsGrwGcvpKuBT|KolKA5+D+ikV3PK zqSysom~pVQ{v$(?|k@9+I<(absb>E}7mdG0yq zHeV)37HtW)KNI%^T6dqEfQr87ts}#V#!3r|fu)7}Zi$W#Tx#(Ql>NXhR!#e(5~JvJ z|BVAI)$s?AK2W?jfHCE&i2%`%NhqV^fe^M@aFD)SUP_GHiAfTQ*|rMhj6R&a1|6s6Qr*HcFakUeyC0w{DWLnTIW(P{iiyAyF;lB1xF)EZqE|lok{n1TdU)eylZ%#4 z?x#~zS|Zi12Bk`*XMie6dmzl2PtK(AzL>}^eMqDiKnxNoAAZL7$)TpOi9Zeespn4| zKPrc=11$pNLKM*>0FD-%Ne_ulM1H*`Nq*gCis8x>Ey41X@=`|>oI0WgCL`?~$m3@I zMNpHZ8Y<97&zL|v&PD%D)n&Co|Tea?rQRX5!Zl}V~} zcGEF9hH-ZQ$8NflX7%1pcYy@mbSxNSiu-QGeUITz0GrlL_X@rk`Jm`N92sL|HytT4 zNz(aZ;;0YZ^ccjTo0uA=6rKjrg{Sc6B>tSppVj<14nL}!9tQ&qdrB66lEu@qcm_q1 zTyU|-Rs|Ez!BLXZ(m>Rb859^H8EKHrPJI4km;}-o=ed3@j$_mVv;GVV*g=0mNekqR z(D^~$@9`qkAYjgiqL?z|C4ihJVsZ0(Y2wSku$`}!~aqs z(gyGcLTvG6z{C{ahl=kb!*_X4zK;c8jC?TS6C7zH#930s@Ta8m#l%q`hW%F%gJI8; z^_0T(P^m`u*MLXM`NS7)ow5=?u!D$ZE_8&sm|$*{rd&yb`(Vm{q$$VK6lKK^043>P zevA)U?}TviHPS6VN}b}U4?2C>qWM)&F{SVph%Vf~pBwpeJ%6snk1{3zT69Pjis&5x zs~A!*P$2ZqbZ8Etccnx7OF;us)c11i!Xou_}Wvbp^8BUBCug~?ga2FyU);3I@TpQMGQDUe`G+94#)6 zgoTER`yh~CUvcy9O7*IdgJu$G9s~`2U}yA=@KBat=b2J+J>ZnwZX}ab-im8#<|^!D@Fl4YG(~?yiAI+J zMn_DcOq~P8PKIvBRAO|lGd4^kR1Y?HU)p#wKngEc!l%20JMSKv;S_GRA}RnCce~6) zB}QSCJ<>oKMP2*$)}Q38lDZHu=gNTViadw;|}B@1IRnd|GT%O%DJGYaR-y{JqbGm z^;A!6ble~`j~Lw(IXW5+1+@5W$$J>(yf5oV|u7E*z;=LNOAw_t#d z0w=6zL@c5O{umw%AR2lsO6{(q&p`lKLg9`_DI4(* zAky5m8ps}vH~~P>h!atXQCzAKeC|;X@HLcd8sWs8M2u;K6LT_U`(tbbY&?Z@I&r0+ zr1j1zJ zFM)&DvjC%(wPgAyV8U^F#}vc4is5`GgLzBD?*&7Q3=nz&X`_!Rsq#UF z;;$)eBYsi{`M41gNfINjl58o;NYOW_K-4;=_Cl06ya+|~TQca3P20(+1o#H%He5{7 z??|eWdNL#FB_K^wDg@CFc0tj zC@EJ`3MpJtuF_JjrWCTsUQ`BYk*N$6MBj2B@ftE_71O6Nx=V!lwFLT$zbBCK2D^99OC(a)$r+C7wp@?Mn5I~0-f zk54b4B1OMQ>iZOR5@qyPz|sfq{Xoz=sRfbK*=D(?HGx!Ky>Kj$lI*fI9*gz|sFWsZ zkvgg#0>Weq8z16AdmaXi?Ru1@8NbM#e6rF9nwTFy0-Z)ho)9kP!y0-|EQ!s zhBBH(N^PuWF)iZ5Z~A)7;~>vW>4oV^dyGy?dLn})Cw-EJIkZ0s9=zFv?TxV=;>{*c z0SNc}NfuAb;u#d_clqcBB8t=RWa1PVvBW49BSP#Ds?;UwD&vW|A(jaXqXH>VMWq;s zjO{yx(bFz3|7Jo(Ib+?(zXdR=}_#5nWHY(lD7oZn68qrRe z_7aX#F{Vx){n&;a{FvZVmn(_T(ULlO^p~PurYMMf1tp4CQA7ujL7zO-NyD5oUL(ao zQs{F=I>p~Wk)#aOe4HwBrLxz7p|ZbgE%c6gi0=(R>vDj86O|ZQlGKxuk|(9SrKG$~ zDWq^oc}Gimk5b5DMru&Ylc zTqVO)=9?{zX4PU5tjetPXx4q{8PK1?D2%-jniW&+{R|*_{d3yuY%l#L9vSWmWa+j$ zVLkou4~T%IFJ$pgS$v72w=v=EizF?90q#Mv+2-SnqTo`SNs!Pqkf=W*}infvBHUY*K+Wml2(@tUeh@x#Jg%21~1W=~k zl|{k~cNnJ6FtRdmd*5N0&YcZzGc+=(!2`C0+uT2x z&OK0=6{A^jP%e&=+&EWSvFEm(#N+`(7X~wF^SnDSU0Y~NxXrC?>D*gw3AedxEuA|b z+~|NI>;ToMtpQ@Awx!_hfe_K)ypL~iPnAg$iu1eb8FL?By2kCcfH`Ahhin0J#qb9~3ZUBY?pof#V1y1c&4I_syCXV`WQ6>s8xF$7OT$Bkz zZ{bk>?8KiP@T0EB>Q132eo+O#`twb2iX{6fI#U$^k#w4UnYJNw) z5mb|QV_lNE#klFYyxbQ|s$0p*bU&FA4_;?Qn!`ZrH3?UTj+e8J8{a_raLcVX?K=xk%5yz zm85oxQ~oL_8V3NZF9VW}m`YJZYD%qR8W5r-(@}{jt{JFF|{#`s#BXHHLZhS*Gkw!-|TaA8wgNVw7`GqBuwvb7gTb3K^Brhx;QBe2phjcSS5j z_XV>U`Ozr8bq>r81);>Az=-pQf0(??$vu=4#N|yq`#r4acT(da5K4`QqKwiemEYto zBZmQslhl5ojVXq>VyJgAnB~ZP!4M+@gf{SqnZ5~?7~80uE$%qjM^Y^yl`kfa`rznh zh=HT|raJBD#Q-ITyBs}H>TDq~3~NP+qD>aV+BKu z44_T$h~aWPDlzty?mQ7L2S}>br1HhYQ6Iu(4a6W^_#SB;E++$&+}RZ_l~U&^B!*$9 zp+s@IEY6U{nX))b7H7+1Eeg-Rtb@eg92vD>@{~5~zmf)YX@BrOvBJ48yKLiQ-yWT!+Hb!-sPD1N8sqZtO@P9~ zhk-Vx7&a(|TgVUxLYg#&&)9Rua2wz#ZkNR!vba+gccBnG(W1JC)=a(?=YVlMJIt32 zxV-=;0Eoc?S_yjv3{rlQst6ud)QB21yb2th^cICi(=C4+P^{~lKpRsG?(^ zVuqo>tY(pyj2c6MiNhi<8H00hCKh&VlVjB`YF^M)+Sc9LW#K!6G$>*f*mi!7HM_p0 zyUD_r25CdY8ZIo{(eQ4ck#{@8Yb)NZ1#j5!4$a8Bli_vieF?nMcYn>X;xp@4xJ_7=&m=*)%B2vVDHL!6-jmw*V^u z8JAnz_F=L_p?U*jOFs-=;u23y4P*17&{zi+A1)~>X*DQ!!Pwj;c>E%NZSR@CaL z=vbxb7^UcFrRYebXoZ)eWtp0_jcV3Wp4v`P+D=y5PEy)VG}?~$(w4}iO}A~0r?$09 z+u2InSxVa(M%$?#{?aWt(^KY!O6EEx^8zLFd?WLmUS$5>Q|47l=9Nn36-wsiM&>16 zUb$$HRaf7!unC#T3>j_wdQU|+D@7ZWqMMYW8;qiBy%b&DON(ywQe?lO1m^l|-402}Bd?fRa4Gj+d;XK$oS0|J)xmImkcSnPBz;34^Y<#XtHpf#c{;YNg zDmJ|P^uqf)Pu>#4yT1ePm$Gep-`os|XnUQArWyg0y#!3!tbiFtz%&o*cT_E}(85n( z%YA71R%m&(;hotF?}47Ya|~~t1MiozZM!Cu;XCV=A8G^~>?Po!%?hYD0uJ-Aewb?c zd@Wo>k}V=>f#GfFg?FJR?-Ij%gadC*UW+mrZq8txMnJolfY!|lSZ)M#c~~D&EnlI9 zr%n{;^P>#!%3gSn_T*h{coPo1IdL76$#9u-q5KphV2zi66E-X03?txF59{?fKT`{L zjq~#j?>P><8LMY!Qf|iTMMl5{9?JDlyI2c%4Yex`@8u4>87`M*Qf`LJbwZqyuk)=H5)oP0&1Q1U&4a zJgW1_Q-}*P+xA~GS-pog=Pe`P?_L7_wpjrm83FHm z33zw20{&qHeCpBCQQFXrhV0AU$i6pZ-}Oee$&mf5tv-Q%<0&U%+dpQqdT(t`zdU^= z59Fz{wNrpEFT)wt2nZShgS-R`*sOqUjez{To^y#}ZRn1MY)Efp5koe#H?o)^i)yRY z;?d^faYQDo576d}HUdU^3D|S90wx#%^?MqbY zPM&Y*<2zf`ZEY=%h1!82vh72+NX`*P&O*?)G}X6uw@>Y8>uxWtZ*6F5(Uw?vHL~K@cf~|3CC@b z+|!NRQxG2=&21gcT`RdrR=wCPWSz7{vd%WL&e$UQ^9=pkEuw!A^xR++JC#%R*8`z+ zf2+M=zSFTL`YQ}kIf%O2ojbZR`ln`Qt~1OBf@nc2azI*eR|%mFK$y)B8Pzj0OFhU) zot2sBFhg|6{??K<=eDH`nz@;I8x3#${+W9;o>{;mBcLfWQHvpJ&P;Rzh~$p&wfkEu z(sHG}&q|FQx3cH7XpIQGF)K67&LSdJA|c*)x@~DWccX5_r?hn}sW(X>VkNjsY}Vi>E1FVgD zQVMW}p5V0~7YMhtNcGa%KMG_|YabEt4Aw&P%fM^RF9_P|mbQlG)&*_4ZE(oR!XeKK zbO!y;3S>|He-`iz`fcAU0-ecQuL^7rZ+#4~w)q1opr^Oq6NvQ2z+bX4?+A2;#=Iqv zJsb0efM;k7&gR{?HZ>HXGv z3GQg>?re(ll-1qQ6fd9bqG%F~ZP;jxH{b$6Yf}p(=setI+YJKW+|txqzr>mBr5)s2HM#CaT+lheEcr)?{mQ7+t(QW(M2zRO?CSu_eP_4u)YHD7%$i%gPFClz+ zb7L2-YRPa1IM<&Wz#p#|oDRJ7*J-A9s;Qk~YHLKzZ~JkbIOVxxQ1|fMQ3UtuxmA*) zv!T8P-ffF7sYkAHcy5IdT)(&}K5cSMe1S?24uWNZAhTY9B4YC06pN8Q7r=MvnjL)Qw%%%OM|@$8NLQQw}9jJSB_H6|B+S#`V#>}0)f%sMN)~1E=1sEcZ9%bgS z?HeV&y{*$5e?9RlGxJ|7@frEACVoX`{wpOu13x3~Zc=zfT#^Wnh`Wz)&xpI17>|g% zhj5RG6T??zNXA}3WXiPPY`;H@*T%|t94cyz$DIvqCsW(OV7E80A*MFiV7E1}ZA>lS zV7D@`kg4SvY_5j+2ASFbgY9o%{X~uNn5|*m6^ zm+_c61$~`PX@W6xr%e&~%$+uw_{>9k zQVQ+pZ$0CxBG#)%>xl5^(OSXa>d_j4JbUy&Vmx}Zn(!^_(X5L=yEQjVvo18Xb*6TK zsr}y6&eyfTIjH4h@#PP!MQtnA`kjrM=W3x`z*sRku*1tw$ z{U>Uy{{)To9gmuvhaYEZ2~lG_9;;!2V?>RycQk4;_KreL#@>;r30r(C1s!6~UW%HI zvo_Q{;%o`Qy~f#M!I(LYnu&LIqnWfXBqr632Hr%t=|%%?Ah@x1#>b#~8>dxdPLkiFc+&@C8NIbb4H1aeK%z;VD1oJ=~gxhdDcU3TCk zg2ZakfKDN(xzPY9Iysg2gPti5zCd!(rqn%bVGwui1|?W${mC~9IH1$Hqt zeyKx_sGT*Pe|km`Ol><;8?0;od|k^5nOacS0(rXT&(*cSAk;*@3Jf&00jAbp z*ZkS2iQMGRLQUi*AHNMCGlA1ovHD|suK1MYBJMo zL{0kTD+Bvd!+f8kHk5hN_nD~i%*W3Zi*st=6V$fh*){89)P%gOk5CixvOYvjWUjym zsL7oDzM*^1(7kKu-qCdaH&K(`cmp-*jn`3=-uRoYWxtA=(3|}VYC>=J%cx1cFKBGw zuNoV8USoZKK}~w&Xk=6gcd?1xbshL-d8?*~z5z7jii4U3u@7RNiA zS2e|(TDzCHw(agGVOu+PL0ZhtUMfMze2M+P`@G0jwqrT1FCc>G9uoCT7k3fdYr43D z6rO4QHex)|#Vv&QOcxsn_DmPH?+?UzFul+rTE6C6{8(EJL@F_ALD@YL}2%OjkvC+CG8gO@sT%% zhIvl1{eKr+P6is4E&c?-7bIwHS{_eznm#r8|DkcF;}i;(;y*j^FA{V#b=EIwZ)p-& zjU+*WJHb@{lO$;D#`0i3vi#z>>wM_{MQiZT{Y9dei57Jow9F6tQ)>vOHYBKLun_88r%`~+NU9+d6rst<+sC#9VQo@a| z&1A8JV8>Nu>=7S8kb9ecKZ2T<)Gx#)zQ~M@9s1u9$L+@q7eC4cud^F{(+FyBUeVMN z_i(uFn?ZbM{j#Pw`ntQtTb}1<1`IdPn_ziG*nzD&Ft(W zh}TZ@s|!jh#fSy^u^^DGI!4#*BT>_>T1f%Dv}!r=8C%s&Y=%~K66f8jr9@?3Lbs*R z9!r{|i0!S(mw`Yw`4UsR*wijGwRNWUds92#)Xp`vb3~1Ew6z*$pMjd5pPYue*NNJ; zPa!7dJjWn9i5TrT2mD0Bdyd-G1ZNnJ#}U`dcs!GM@4=LTCT2T^Zi9~I?C4>$?0f6)I^%i;v2&xZ$Q)a3rYoTGqc!?O(bU_y#p0CBU~Z3MqlFQIn^EuQZ*XFVPfw zeP4(gruhEP4eT>r^M7J$AL*KpuSb>Ee}I}?`n+#y@9CQVZPerx|1H$S6yN^_YEtjt zbpSCWq0iHaIfrc^jhdS~z&8@y>)iZ$Qe@6Me4)HTd*q$F ziREm<^AvU`v7A)PTM0M|5|ir32zPI)+^YpG=x%9IGb%Hmz}%kbh6O#hHf$eX^JmqL ztt(Y$We3+iTIiDc=GLAmspXg0++T288>GU((!;Jr!}QgPP3Rz6XiuZf(G0 zl*qZAoXMu9nyEwqh#a;D4AD?06US zAt6=Fpt&w|8TbHkjucm{P-aQEUk{d_K%fJBw}52k3jt(}Z%Pm~ zAKwQcYBnGJcZ;zDe5HYfy`Fe|VWd&==>_OH5aVEe=A_mwYKZc`i zeY0`k06g;#k^vZ?x{lMYplNr|_%%(Qo$mvjTdCbB2j=C3SX!3P$^wisvNbLAECojE z$3 z!RuFk8Ej}I+^66}9B_oLq2D15uIYDjz}Xfpf2adan>9R~g6E@CEk40VKewY!Zx-+v zejc8p3x$Ev{JUtl@-v^+YX_b(*zfGCT>+zv-83!y92OYq=iO6qVFMrJBR|_q8}?NE zg(0@UK*}!;3IqFb=ojm$rz()VFP7ozl}@5g$=_<4;$!1+Av=6?~|en6#%1c zn4sax20pn*UZ)MeQ!@6|w6K9Pv<>^G;KBwz)<=H!7j2lR_)AiBq2a)28%i}?*}w<* z$m_JBOv#v{X<-9pXd9*(xQh8T;78w0H*j}+R%rP2tZi}CgTvMFFJ4z2FDCklO)TJFe9a;vMVDvTf=fK$d(wdUPF6K`onSxM!r z>iE=}s#(=WhzqLhsL`^NPdR@1r+wNFo~r{5eKbqcPV&@SQd(C&yQHohE-0<4tSdXH zPHOH6SGwnDc~d;)IelARSzA|9Sz4BAi}t$4D4BD$Ox2!)ah%?sLjYrY=4sjiS@{L% zRhe5=-KMW)eW(xhDgON2ZT;3^;IXWVw$_DHFd-Fh|JX=)T)?ZFIy!M%coQD%`Su$D zKU~5)_=HLm`)_;}s4ZW;fXh${So?OjawDs;u&aLI{-TX82-`L(YcQ!Bis!X=v@PtY zUlQhWyEDAoilXtcdCM`AZCldzd04~!BE*Iw%xL(h`6Sr9Y zd>`9uIXknuro5`Ayl!rMTKUvz7V&s-u45n>d}US5%#sRtjWmcuFPe&~IhMftz47Ih zvr8(l9_o#zv}#sm9eZrxq<-6Gp?A7q@glUuHHNiW?4LQ~JW=Q<;blH0LobgJUicDT zpkJk*XER3daF&b@K6Mh14`PXU;qxLnt_P|t0q4_Gc#%xz2dz}RG1fy?4X*g(2_vP0 z4?%6?@t72C;9cVla^(PcaWUxi zzunxv-11zBm}-F>dUGbdiE&Gx={XktrR(&OuCvX$&Nk{g+aT&u@0?RMNu`*wN$5=G z0AHv}^9-=Xd5ez|>HNs7v5d!{TdwI;?jap*P0{+Sm5O$irp>qWIX+0swy+H;dcSoP zk0JYLl)`R@Y-e8M8SYp`oA97zyHj#~*71sVwWh^+aw+W4^UD)8-18j6`vF>-_!LRJ zv#X=Kp-VWe2NWKp?I&qjJJ|UcT~-7!%DHNPz)!{>AAg~39CenJWt{>T`A*e*p6A}K zMO?e2bUF<2Mw$LRUCZ@6k4few^Tk6lJ%qa8s(oi_dArMTeg=-YRFsd|$Z>uaU;#^U zGp^uQA3E)9K}&j$`&4T->(`oI&j(AI8#>xL+ZJ?%mo;~G*SCZ_ySf{j+rp#Aj2ty@ zS%Wz}G<0+|HZADH*@4*)V{I+$IR}5ka@Z&SZQEg20sb)G+&FNsosX_E>lOAF|JZkO z-4d|Q2QT~X_b5fYsy^o$hZiBtpW+KsAo_fr;=54uW!qwEO4*DL{<~PwT%u_Zvtht> z%w9(L3DCd0o!=jD-tVSuWJw#-|5CR1x7I89SES^N@lG2_$8kz+S1G!yHJ!sx@D==+ z6H0H_b(&WBka(wU%X&Cs;t;c3Tv@VLOv#|z9-cB=O2burtU zYG*$yscgMp>sNVM(=jiypB_|n4{17wUAqZ8?#$3iCh zIa4n9hm!e)=5_ST_H3Usr^5(fIrI-n^Yxi-zz!)@sKk*O-?xNcw*WyL{N`7&*|9z)yS23gzer$ohHU{hR2DM=R+H% zoWG@FXD`Ye<24WE6&|(a&#i>i;Y2Yfg+CZeJTLD_8HxMV3WHF~YFsYn;c7)dSO74& zzLT>N!g2`1i|k5E66 z`keqTX=z_n@4#_IjLhN7hKKaO@RqEIk1#VJJVo2lIS=piY{qX}L-!Iaz&q!;XFg*_ zjULOT^ASxAz;!nBj;OG_PcJMkYKL2z=Xcb1ten@`f%%cR?WA!9*Uf5X)DQOM;O_t! zIdHa|>Cp%DcPXw|jaI8I!su_p#yDW~H#+hlr~ib%n_&GiT+^Z+_yPmdH^AYG(3bcD zGq-`tzM0TJFfqV(TR5|RVRM7S8d{hhB_blkE1dcEp88GEF%qhq zyBZc%byPIBHr00s;VC>LVscYEo(xUF7!5O<+h^9d%SW*pZCPkV81Ne97421ezryOQ z=KVWUZG&98kP1P<=|%zaEu{O_;Nw3|0Tp#)ZWHe_F!IJV~>vk)4<)m z#%a8{4ObH7icwVM_{4bU=B^m;i8IyMl(X14-{T@IXSN7falQmb921Y%;m+qFvn3pF`3`S{ ztqd)xG-J$b*J(>v8J%5Nd*~ggt)X`t{E2a-W<@;H>DdmiV8J|VFiK|5?NFv?PGor3 zSr=Pl=B!SBE*J4*U!k2E@J)@|p^x=_)L zOwonf0oP};Q7O34Gn(|!vlmM08N*}f8LR1bu*GiVaP(UZR^cTLxYweisYv9oG+brd zlqS3q$c5vTk~w&@OjAu0cCxW!KZPG&4nA2rVmJ?&)`yw zT&GrNb4ArET9gO^?$b2B(>r?^T<5#lz9A@#7rr(m2KD!c9rj2c(f{a4AO9 zF5Pc6^~+_ysP-D)3k2*_aP3=wrC$}?_)a1?23>vw*!aw}pFp-<$ zPVETkW3yw!e5i92$F|N-vpBYuU9(ZIttzj;13&eR@v5m6`VM>Dkh^QlMK#GM=wcMaIn#a%>HFqMul#nimf48e zK|_~JD_qSw!muP)+Xm~dy zRpSc_4Dl4P$?YjxH2|Dc4%n~f_Ca_{3x|J0yIIQ(B3#%6AUsX_FI0khKf<&1rbr64)!s8LY6xzX`Q1~Tntv&FoVdDuBFIQ`jce2&M z2U$j^h@~!i@N|XKZ9EbDXX8DF;>j1Ka}8kU0oH;WWHlXO>j3L^z)lA266jWb>+Vo1 z&QkziudXr0#aa-Ni)(9G`S?x+PXD{l^1gs3Le3i{BLlk-r$Np+7@>P&iOHxmD-Jc& zlX=r4pZT;4ABDOXIaA zQ()cHNoYCSWZ5a(O4~{oLbHVXQt(upN^u*^)QU2CZGJy-m7OE)EO_1AjloA!3sbyK zKZ<)x=8W4SQgkVFnDzhv{T^FqTXPFG1$fo*Y}mgRe}|(j0}}_UXuzHB<+arnC3A5* z(UkJ3@!Hao%8K&JvUpX^JJ}jS2FUqLe zoSt&r&Qw!TQVKOD61SWuKC8OAtOiC_OrBC+Q!DN?p zRW+q$@mY{Hb_{kd`)!MBg5nOBbK&vLFmuSy8MhfC5h;DTKWSlOvxmc7_ zNNCxa2aTbC2M`yG2F4EaGzd62~TOskTh4pBk znpyGMFB``97owC#Q-@k%a~BJ@@HZ`HCOAglWmVm_ys2Xr_LHmeoCNPe6Y*{1{vrjh zZ0ph}9s34X-dfK$DK`mU`cpjka#!;bJmoHAIpF23%dh}%WS^w&npzLL;>RavHe zoX#qnT}Rs%q+;!Q==F#-hfJk1bJTgzs`&eVo~;{1w!Q&vxDkJajB&Msqp#%)H|5F! zG0V^uC%n%31x;dn)W~ZRa`#hCe+lP2jdP%YwOj#HbFiGWIV9(0gRJFdw#Jz(K)#z{ zkN$_bp}0TE5M`WgXAiywe4MZB!ublW>Ns*sZOQDic-`D;{7fy;dEb^Xkit!xS*>v@ z&!lje4v2Oioa+DEpwFZKQ#{a>x$E6zdd%Donanwy3Fws+uh(;O+tkse)^g|#Oj&q6 zg=3{!j}^7@V*hD+)pv6_8xi({-dv+s`G>pNSSaG*5y(^H?L){|*us5Gahax5@G5%l z;xFLkHU~YguP(Pg$>PSCp9fM&R^1wJfrkH4nFyqm~5K1@g%@Su2poW z;yAvnb9p;n<=nL(-Vkqr47Iy>9dIJ|a;J+nDL8l1MS7`~FM!thHe1klwBl(Rk=M=r zams(0{JpoMy}Tbmw6~m#>oH<3F)-ot>$xvxm*q1{rk06$YHhr{qN=iDuE@qdD-Abx z%%t+Vnz93DVVgm1YJNN~f#D zJ>3`yWtDX`bE~T`jgT2Hkl-3KO=evU?u4IQHfh$>$t86q#`c;x=G3*kGkj*r^eP;U zkuun>G@Rhca>L7UBd~z84K?w}Wff(0Ws~DHJzh~(Ikj#Yyv&g+@w4knCRLP8Eva@< z5N}(mF=ANHEIBA%I*HLk+$JHrykcfq-L$I7@mkE^k59roSvKeCE~@ky)Y4V^MeC>ZZP zTY~p!wKcdiST`PIY~UNJ#R)SdgLkWN3r=UXGjS~JQkjN#<(SOn+DLCls7naCX7D1&QIe3{Sic z2LD$1TZbbB!`qj3b+67@n{!UixjE}|uE@DE=j)vBa{iTbTzGZ(gz%d1Y2h=%XNK2? z&k3I&{(bm@@VfAY;ful-hc5|V8on%id3b&Jittt8>%%vP?+D);elYxK_{s2d;pf9I zgkK838va}Ot?*|s*F>(3To<`Ma%1GC$jy;kBDY0ukK7TtGjdnt?#Mlndn5Nn z?vFeWc_{L5Bh@_yvQ$VZV+BA-S+k9-mNXXMMs*O85pZzJDD{uTLmo6pkrkD%#XDImOw)^Be= z(Sa6KLDM*2)TzX851f!rLmLL{HEwL!`ET^Naib=T-)GF2eVov6c=V`I@Y0$2xe^Cflm8e|N+Ovx)f-!yZ>#joB|5Uu@VWGSA2!-rFe`=yP$qVk{9 z;e^oLd#1Z{Ku9`EIh}O%pgB5?ZlV>MC>p99Pr94ok+<1Pj(>(uIiDzsI*qqtJN_9u z)d56}sKgFvCOXv#q|4gIvTmEhTI!#Xr#ga|Y4G~pi&HeLkq+K2WW3@YnvUXv(&Bko zM2csrrZ}FZnrZHxpDpj5uXWrzKf83^{N~nq4P!<&wzL$4dDBQC_h=iNTdcwb7DRIS z-8pZvxEXD-xf#tZO5BVF-STF%T6r^C6=ug%E5c%O7_R7XGuoo27JNi{WP?>WwUg0f z6*jhYT7`40aaLi~Lj27i1Jp{ZuxuK@GwX0rYZXpu`#(1ccLGVfXO~Wxr*7a-H_Ry; z+vXnu&5atjtYP$+Q6t;YKZWADT1OM#3Res{OWM0&YIS3C{lb~uT?mL#u76WXt*zGh z|9;OHn@f9Z490xEmALyd>juQ%klDFNFGCVpBFzlhoylg%9^!XT@tepInEZKJcxdkb ze*03cb5)BMSs}aik?EiQ`=r~R{>$*#UEkU*_vY{O|AXQNC_ZrdpT-Sn>;Kr)k%yif z+aqsG{*6=&_x5;9aEou)s^`vZ$bSEUKfbs90Xy{Dbn%3}r*3#-dj3s)m5eneuEccU zj-ZvDO38*9&wseMA=Gtn^x2KWH|BKbZ|JL%Wq4VJc&H_0uZ{oiiPq3T7v~;&|3&-f zzh0JqLtllb9+?T*{SO@X&NKInzwh4s9T!`Fc<8|VPx~sprFjV+;S|o_X49(mM`^3qek$lrHhA7cjJSXv}R zm(IE3s|~}lUaEX~^4Rk8z8aS|IM3=_+R=sARAglZ!j_d7iqX8Dm2tTGo|uYZz0IFO zww1Ry%SxLSud%au0!VBaR*K= ziM=Jq>a5;(s$d4g9uA_W0C1oYRF{`9f< zITueF?6`=nIz7vKXT_=K2J-DZ4nO$*t(B;Pr2+eeV0Pa5DQ2-BqxOUGVif5Z8hIm` zf5OZou?ucU5zUm$TZiyYk=90D_msQj>;Rg&Be-rN*Ri+@Gr>EJRxAqn?e7QKd6#9S z?>oD6Z6MbxCHQH>>@QJBLw(@eI%MZv*MpVsy-V47GkI^Ail6&&-b_@I*AL#od1Mc~ zio0DK7A@>-Uf61#oE5-^oRtW{v|GRy_yovBE8B5Pghtsw-AdH^gScK=(QYsSU~VI( zI#)3<^zaG~2d*uTnmy`cBqkX7Zo5q~$y(oWnm z5bqZu*eEY+0`jITo<7Yf8Ej$Dyw#QvLeeHDwcNNX4G0 zSS9!=zKS*^qz$O|!G_h+hU;L%HQI&~lnuuU{nvQtzn=O}l=@NcgZ`7H{#&4bLvG=X z+JsY-35gT68#ZV&k~iv_!y&iQpi`wmsQ1C3Go(Rx!l2u=HD_vTR%>f+_psqE+HjV% z0rfuEaE`R$KG<-Nw&7fD!(-ZpdpvAN(uVV-4XF3Qh6|((55a~9v<>T&4Q(PY9`Mlr zF!f(3^`qVg{g+7ne}w)=wEjz#{=_NT2akBz@EC2lOxl2YA8fcn+VB)?ctYE7rLv)3 z_}~c-{ePnVtE7I^`=I|8ssAs~|BTjutJ1%f(Ep5w{%5KGHmM)=KInf?>VEppni!-f}W!^6@B)cat=qtb@I!G>3J3t!e|{85=PM7ZHqZ9?*8U2`Od*J;dS z(iqhHV9cMSG4H^bw{i>L(8fFsaP)n3_Q>Mdt- z=edQSYFl2SE#E8m@a}}<=ean=&B9;uQxE6-lLoyk4MM#S27M$A+6aTb($;(o7|*cH zB67a+(Eknfex6!VcW zh$v#eC3X|1N~vkeuWZP7KwzqbdLJ6{J%nJ|)-P{LVOCzDKTl2D{sXX>E#0D%QC1%8 z5z{umt~oM6P96;UK^la59}N0g8Z-z74bay7qO4ggdUk+^{#@$+Rq98*5BhCfuYg0g zg8rb^?*mMD<0S2kpob0lw80NjbPDQyupwL8Fc>y$qiyJ?Y&cZ-U>gtp+fjdx)Q@@} z^beH!cZB}!wf;d$f2YvDy@&pts6SWgN4*dF`3@@dK^XdnYW-U&{fX0b9}M-dAwnDY z%0=`6>V2?bduhXNupz2#*g@N1)(}xKTroB+v5*k!m>6x?QQCldA8ZIq8%Du~k=llc zvO%sPMtbNUP5lK@Kk9wZzl+qr5A^SyS2$Li5LG6m))0HU%t(%P9m>^R5v|%)T7`Na ztlCprH4#?ruT3h{Cau=dvA>56CA49rv;p-#*f3VwFby_L(Kd|JHawzgCY0+Y75$b)gs8w2YH7vR^uW-G# zs10EEI_t{3)H-Xuhe_Aaq;_c%>U}V&TbgtWOxloFc%wFH8BKC+9By!#k-X7$C>?bx zty(UvLcI@Gt&&#V1FP=JE4)Knbz~2#?sA!tyu)=Ut-6<19VM+oy$@C$E3JAMRy~+k zc)zwPL91Nrzz6g6I`DoEgZ@B+j*|wV-UowDmInO=20f##IR!9gTDcB;#zX(J)PJhf zk9r^UpCR?X0R7Kv{bwruavl1-hyE9-|17B=^*-odC-r{<{U7BOexOab5MZdd2u1X> zJoh^AbF~iqz-^db3|J~hD!m%Oc(V&wBc$9!EAdI z+VD$W;ZM2^*8uEZ0{-H%IQf(7P=-3LSJ;VbrB$f+!K&M&RgvJ7!eK$RD!pBsWY%HB zf?OB7=iddi;SOm7>V2@`ZfQdlHjL0V+@oxeYta!N`gf)Nd!>HV`=I}RsecdXk7@l6 zDE)FB81vA-C-pxl^`qVg{eO`9M?wEct^X0FKeY}U>0!fY+VH5f0rfuE@VK;LZ`d$a z+wg?4L9Ru|dgvcd{ZC5$s4M;AQrf`ZdP#}b-v(oVEY6xzSRX8m2MZ4k79J8ToEt2h z6D*vijM}cs9#UoRSY_{2W$#>N4^7SqA_sB+*##3?g2}n=!?-^532eRl@DP0{c*m|O zU7cekX9ce~TlsWy0$B}D@~QCdQ*Ho6d&!@M#0 znNhqX7;6nGkj?hah%E^w7qTX$6%@6h3A>|Jdq&$8MrcSj1+fdErLsE3CaDp(Y4V9PP4m$vF@M(DYLtR z$pu20aAQHyGMGIEW{-_7R~Tt_qtonh(G|hu@^rKJuCj}gD}*o;KeYTvSPpszOj_Qr z%AOEAGDt;&%W3)VqN`MUBws+1_>v;J;6Av#%HFp&y2#nSqk^%cg9@bDcT_OBNSGuT z3yO|G`}RZo4u~ELP8~|`B9v5@Osuj?fKw5hTt#N|e7+sn&9X*anSV}Lbd@kRC4jLg zJ>s7mNCS)h1(^PV(UWkoJ6(ZnmM@bYDS2~(Cs)~JJp>D{E3ajgpJuS=Sr{xM(-=Ob z%AVT0{4H!on%r{qHOH3hu__xrsz}QGpoWx)&46l!idPv3KH0memL-p+o9FI%e16y( zgC7W+S(j6MbTD>IunrMdS(jbh9gHmta^O_e1&UjPv9=&n&4I!OlYVM2H$fWu@3KGB z?mVR3RY<#M1Pf0K7M>C;JSkXsVz6*^u<$sQb`Pzx53924tL*tzc0-ljm|U%bjcIpX zFnOZ;@Fe%)aU!M4bUKXWr-+p50G#G#I3smfbU`q-4kMunBVi%iEz|B<04<^~nqwCP zqh|-DK}jJ8sZfl$Bcf}SWl14W!xtydcF4aFl3E~q38V?5n}qoUUbrT>)!kB;6Dl#W+`V=!6Z zmae3dl7$a_O6iEAn_yMqc+kMI#A=ijDq>9;B5m|5iHQ?HQr91}yw4(blhP;st3`|0 z98t7^qSq+VoY~Smfm7X)Ci-M8nmbvs4Z-M*!Q}PAgE#P3C-%e{6m?B7c_X1h=KyWp znLyP>uXFay&B53$K?PDhb8|3xT}p02(XBM}EWvuMll8V>?Dk+(f)wj*!Q{1qRTx%K zbO%|_CM(Ld$}leQaR0eLs8OxFDI!#BP@Sg~sPKWW?)BB6Xz3< zU3_^kwq9h!#P10R6kigIT`IC-;sO9f2Z+qb43Stz8ea_c|2{h=)Cj0Slt5N%TlC znWP(Z>|7&p*U92~6v?}Z7Y!_!@OUtJulrDNr?7WAQ*6;=!Pw*U#|@Cf*tiKLX=O5f zfT#@sF^S=ObBOoHkjNf(M&A>`*pop8QqlKBF!`{yA;HH~3yPkiq+6Ae+fYUyO%bWy zeke%qBp(z7X2n9ro`hMc`N+F%a8#Be^0`iuiQ8#up!msP>?zstcT&+K!dhE;QTSn? zKcwRJZd&AS&(p!!Gi;BfXESERo>sO>PfG^}Btf8{=+A81J(PsT|j3Dt#uHpA~F!m0+{$+?|^t_6a zZQdk2{{~U70VIas>!`%u4knF2|FEKWN%42Z{07VDo6gXCFBp42s6c+&H6!+3F!?5H zvK7*J46l+dKSKEf%6n7EdkbasLv6C;61|j)L`IrUOmCC?qn_lpn_LHGmw9mzhq`G4Lh%zwF8HaGf(kzasfpJ<0uP)*&2tj{chD zU#kfFLiAelOHsHZ>>JSi7ZD~TN`bvZ*mqvS9sbD>8vm5$e$B!i8vphZ=x|u_s~`up z^1*++s2%=tsZR>6Nuks|PJVzG#N+3|*gs@E{z!m7_9=tsXVmFYIp+{b?-!zdG1U8T zy6KOZ2TnKVBfEbeEc{on@Y`VFMxEUU014fLWRWY2JQT@q=`%6p3nu&$O#aJ#_`N>oqbs}r9E|DJxIJ+LRY!-*n>R4R&*d{9qv zM>cYX+#Vp`@}L>SI7#-GK{KFd&=h(}b2QW4+ftek;|`j=yu>)#>m^1Q z!yUidSL2qT9GOVpm<&`@kxC@Mi}AviRY9HNc$7ZinQ+*D=UG?Ync zj3G+1Mqb$1iPuU3$!%GTD2h-GP>JmoO72GfqS3@HP;3iPI;|1A8yGF}@rIqS zB9U4dYtkH1lWoHN?CWzX^!2^OBCW5P`bLLpqkE_(NEvE`j0wfYhJd2AHZ7VF8xulo#k5Cr2pu}M-ifB)g)6w>07VR zH;nCM9N&}C-W=mnGVarp(PI`Q2Ak2?LB_b133Ol4Q*ldCB8qo|K9XM*l5SQuoyTY!`?CND6?Haycj+o=>Gf zNlLEty_u8@b*f&Ww52*QCB{q$WbP8~OKtC2yo`x$J!p|h6Sl8(Ta=20-(b9!~pWWT|pqqf{45h=Y}#PbzrmtoX;C2)gCnUY07OzB8;XsSN&Pqg zMChb4-SMRH#gO&-kke0t5ajghkkiXTg{7gwl2G9RI;WojBqHHV6w&FS1&I3r~^xvZrs|Y2_ z$X`@R+y#nl9ZH8a;YYs0jC;pbq~$87SA}BL zA)rLR(4rZ!s!(#8ZX0s?fwb^qW#OeLaduOMS>PsY@6%fNUg8S8p7rba~u#;eFUJCv*urq;?l?Kp7e>8llOouHj9 zX&nbn+G|N$9!d%-lf<#d5wOD1!Flp*KTPaDimOGI3>rzFH4EK?XT1=Jn@RH5DK+J~ z<8_i30B4fF9+b&cSERCY((tAy`IHQmgyu=v)dMYv4fIJ5X52x~*yu_1olgBCH zMz{T`Q2Gt_-}HZGzX+7yWd8=Y{i%rl4ffyse`ddk+TUdVEpGc$1M4@~e;e(eo_4yq z9YCCJszb2@<>}@Q08*zLk%aFgjW33}I^Br-3KMq$JkxK7a)(*AoonL{FQ}V~SIJp^ zyzb7nN^E-|AO|@hxxQ?_eU)KYFVJhq5CFqOfxh0Lukk|PYS0_f(6)UeAan6@JeRz? z3NNrS$}3;nP`Kj4La%%C6fLjTF2pYTFIYtYYlpQOds~p^1c_tKMlj@lEGG5x@`MXFNSXn!&hGD z?+yApFZ8bl{gYH@8iiQ^8uddDCfjG_S@Cj)rHw$1AW(gqKs7}}5V{D{oID-ZSs-`2 z*AGaKNXj(~1H91r1|9T5Z)eckc%gSP=rLN^)od@ppn zK`-$_A8F7lywE2a^zmNkOAY!Wpq+lS?R8!Z*BFK?1;ZK>?Q#gO_hP!$Fm33eUo`0Fz0jW;^hZ*i@j{6h^B?qJvVETe z<{tB(0g^W6t)L$BzX-vpabnv)^$?0AQD7K`1wBr6yBhQeFZ7-U9rHquHt3OF=UrpEZ9rsjouxYvw~JzNAp65XuMI_%Jtd4rl8fh zk`n`4&O>b9!k`6!tpKD$5Kj;NX5n&?A7&x-WZ`9tX$47D;w06#Qhy@qm1_0v1tuFAjL95#ZxE=rx zx~mzcu4qhbgYjhNT!Vp2xF&#F-Qiwc!Lt5A7Hh04swksOLz|Ss!B*xBwpoEhK&ui+0wB z$P5mEbe^5{RnV%(EAY_|ptZtw*4I6Sf0-`)pXtKCa0`deb3)=|9OxGkC*weNNSus) zSs`&U4%iBBDf}ko^Iw(Ee^EaFS^4}2sgP+pA?7Q-?ErQ( z-u59m@WTbjim4ZYpiP57!^sQr9XV5Q2KBZ z-Af+ZyQ95wdbV4L(=(B_@byd>L;Fm-@#zH*Z;bHrMnPt86ncAOWX}fKzCF@iv?l=0 zQ_gZ^*1mtC&W6whG_A7Ui@SqKT9zn;il#4)k%x|B53*X z3n%SFNa7!9SyFDcqUFahoV3*2g+HfUBoZN)AHYbb<=W9ni$o=8`ArN#JHXE8xtVfP zbhd?zA?WyZ4@DRH|JwT!@TjV@|9kIDl1ai6qLAFUa1(KK)ImVO5UGS+1Vo7&ijE;0 zBiYOXNVN_wsI|6O>V~X}xKyRqYQ0(oMAYhMwboj-wRQcpY84e}T`K?Id(M0AGIJBq zX`ko&Kab&I&b{w`-t(Sw&%Lw!EXe2##aK-AOGrj9qIe`-7x9bZexZRRUxEK%0=`lD zQLz(`7+6w-A3|mkeu{Pa+zeHcjMvs8O0Wv=H8UixszEZCJ zAT=(Jd>}S22)d@ADFb*T1Y{=1O||8~$&f#Wbwy!2tUIgiNwk5UCi(7AU(HGaO6RWlG z{%z40&p@vB1by*XU<|#4tAqE?K|$o?6AwT8u33PS^8Pt;9`wZ(^EBoGdxVR!)>pkKY7JrtXB_v{RV2(So zHQpPTuI8q-Z%ux=cz$u##_N-9!uEcvulTpQ z^yx|G{Hpb+u6;jQQT(%#Y;7-WN90|NLzAt|n5esMsryrC$H|4eewvze#}nVL!d25e zaO~K`gzChw5mRPNpFDp2@zo3GjvX>?Ts1vS4C|q_x6qSB+&^nTS!n`RWbFdRXjd5U z3e&I^G9OtQ03Q#*OEuQU)c*n?GAFMiN53FP@9d*5E7ms`>tpsZG}GwU;X*k|>{x8M zv1$*;+ba?y5qI<2cCz>4P`sRj%Xcbdz@D+7kN!rf-tU5710#I~J|+XzN8zQSA6_mX z10iYP9oRVEbaw4?lU<39+SVrAsWM0-q3nJ_`tOXxOaB3yb`W48wSJeH8gSp~7GdNl zc=JeqO44_X$4e`uk021q^UYAdpGbwu%1Q}PPihzC^KW zYBx}DE$u)81~g-H8zASCtqqBqlO|3&#Zf;S>YtJNmlN?)h^;ixrKWL%srP%MRD^)XKAnk)6KgmQ z`OIJ0!2Q4WPqOj;Y`m-*h?g&bWf?MlVjB0r#ye>?YMa~V)$;oR%EoE1@h`IR;at4@ zs01&gV8g(s?SY*3u6cMbq8{(xBwHKXz&a1o;bp~IV_kDwCykeQbdWj*dtfT zbre1(-2hzRbD>2R{W6b3TkHLnorn{yCIEfBLC z8tdA+TX92~x>A_m>>_`G5b*UjEJ{pQwQN&B~0zf-|Ec~s_ zSx}3S?<7a<*uWQR+bDtz_szwLWZT^CM%9PS$WI$Ev@so|GrB|ii7>e-Cn5WgAfwBu z$3sfA#DY#5DEjbJE&TR+9S{@!bKwDVX>GMI4DXt+q3xGvh+l-#c zE~m6oEp-Bz*AlZ+z@h@4HV-*W;Zag*99Y*8>)N~kbkpmFZ(9{#%Uo4_H$W}CIxiFU zbcN7(h|7c0lW_7wx93<8@n>qG(89S|UjOgFQAIw!d-*N{-(}#t41AY??=tXR2ENO{ zcNzE=8Tf|asDLnCfiHyv!t_RfqOQdMRkBs!s2~$K>S{-bz)?x%8$+Fvl7c$DI}eBj zdGR~)yili0^E^5Y=i^J zggPA?!B@D%uLFoLJc)0^kB=aR6dsx2t1LMFcHf*7Fj z`Ddt89B1L5p-yMO|FlSastO?!>U5e4!=9>+JQ!xjQ$P%LisLK-VyM$u2~(GPz(%pisLL|V5rkm5yQzUhUFM2`YuyyD<-AD@j5vmhSMkphC0P@7BMi?=^Vsx zx{ARMb$WV$|1-%yL!II{3;zstS_}UPvcu6vtVF#89V~BBYBW@g*uG0d@LOo(JmmVi5-Y zG{zEjB%w~1QY;L0isLL|VW`t95z7^k_+=`VKOptdYdJmmgd~2{H-eQ+d~^M>faLs$ z0%E9B9A^;_L!B-|KtEQ|_@PdJ9N_U1UiuZYC2S0Q+zPFF{wt9fVy)ae=m=mmbw^-f?4#701!u0UY}>U2$nuv<_} z&d-#5ib1wlJ7lpPLCcyu5br#Q~S zKSQ1Nga1Ct|18ddggWgL;J-ilXQ)#gXW^frPEGhPQT|V7{}Sr7B*1?e`9DMEAIDkv zKO06+0|&r=x$&LXPCvV2ZPR5khW6IE2-2RZ7Cs>T&LS#?Iz1Cnosl1(t)fa%RKEMbGxF7a;Ou~a&Z2;pKnd$VjP6Vq8I||^m3vIsME`+4-9pR<1G5H zUgmH$`mi!TzC!ik7LdgS^KP}JTIq|}Ug0~HrM`xu+5k;d7LK!silI(7BdSMKNSRQl zj|9Z9g<|-ni~+}4#K2Ie+YrN66@wq@bZdbB$H_lKo#HqP{}0NMc?$lYRQ@00VUbX$ zPX_pZn*1}=DUP%7&rqk&!v8bM|7P~@LY+Pn5W{m6!xlLPIL;!5$7Bv(Kn%~T7`AZ? z66*B%0RMj^|Bp-mIA;G0b!zMYm){tp!+|r6&s+)}4wxxq2F(;2eP$X{@T32%L5F*P zQ@B)8N?nYJge}QdAnk1FAK#=v4=w?jz=VKfO7l${EM5V2^zhR0-SP|m_LlxQJ{kX6 z5KG8%Yx;!o_@W_*RRS&QQrN+?!|}IEw}^3sE@G@2Fgad1AU4fVM zBLS~+kRu1kAn7Y@cI5ySq?AOE*L#9IdH`~8Bn%-)9DB#4?@VKUv6Eps+0`X%#NbahE|NXf%A2q}wtw5o(y=*RYm>^2Tp zS@sPeUvG)-+1Hh*PG1A+Iuc$Nna)@!hrk&W;Ys;8)LvZz`{HL>SE7T5AsJ}D-H1_! zMxd{EqOW(9#BVE!Zzzec=k6Zi@5&v)UAfKEl?_f;)_b}lLcI%~jzp+vdkJ-Sd+BgR?{#<_`ukh-_lc7DwvzbPlK7UA_$Kc1 zH2?5C;pxscPj|L@y0gXU&L&TH#P~dgaHk_&v}#__EJ~H(;jvuA`UTFUUOGTfqr=gG zCj9pA_R{!=rST6+^^_;6MGahf^T8KzMuUh6#756{qs^(%2V(lOBVg0sfv?BSqIg0qGd} z`QPf;=cTr5uTc0LT=^yV(iOibrxKkm{V$KN;2R}P3g0Be}*sqbJ zlaTzAS?eT6D@ETiVa-!8QoBlHBz!7_PYVC21x`VY$V1FOI2JHWFmjnb9$O$*bfTx~6=Jsj-n3tBvAvugl@|j4gbF zYg;s=XZ5ISi*&f_ znoH%QI}@x9YYQgYw_6HnB}rl>>A*@-V8$b6JlBke&A4I8mE@e6`h1}J0@Qb=-WuK8 z6g4bX>F7XlqVtm779Hea0@l|qFlhq23N!T%0Q&-=*AAQLfapZUXw$TFeW$!i8758Y z!NiaF`0iI33JT6oTjm3j;SFk~Na7DN2|96t(2{NVrj zBz<9QACu#DgB18Mz{hjrR22LI@VKss{7G>v=(GSt`{FqsR~NSOD#Eq74x=*~938o)ZYr!&(^@r6Fv{;0~ya zlI0(=|5NRS#CVs{yu0b0uHaV~QNH{^?Bq)b1%bQ14gaPO+G7^^c9p=#z<_)H~zZwld z;oBX^xoiLPj_iRHOAr38`>*-y)vZ7vE~q-pjKxg>m3#vw8UtdB?2CC^HPnn9o;FBB zd5}b5Ra6e6FYXm9MLD;PUc!HtLqNkzf@t=zq$`y1u-^X*D;)$SENY4<3uh9Z!n z4>x1OWcSw)AyO4HV~3bx8m$F^%H9?QE%PzljEzXE`{7*ooR1?YAL~dJ?M=djuk4RB zV;9%F8o;j0s2;w82;#LGQ#yl=3P8^l&8?d&IPbL` zJQ7UjE&Fs25pt`_%~*vg zps9XIgmBgVW^Ax2pgQh#9lBT3)UQa)h~dim?ROff2Vn%ejSH~b7;na_&G<29e2f{d z;@w7ykd@J8!c#^=7|LiKkqv<%N2hyMqIMvu%_MNVM*zByf@Y7;*omaJf)4g$ zve`ybV`#~v!NbkaEYm*5cgnkxD&CcVU+v?&r`VO8XvSvI2tE$8G=fi{_3ln467xwA zMY^BDLF`12LF`gaB8jJ2{eRGMU)63U^^DSfmb6bYqcdeL+&J_?=i2x@WHkvZ*YTk}Wg)I_Iv#-i#JGj^)UB;J#pV%k$Ei!y|Y%G0RV zFOn+SKM50)y(VUxvD3|{B(aIvraf7h5TjR7c?OwyiA}tMHaf>+0X)Kdj-DxKysbIQ za{>VZbCzL=1=5hg9Z;Dd%Y^Vu!3pT*v$#m4w3BUuWftr4YdDA{I6yWg!aShzY%=yb z8+!vSLXtxxyW<#p6Fgz;Ei!gCwlz~d{i&)oV{=U=@t&mCw5N)UoJFq{m38FmZFcp) z)JBi>ny5Ep4JMP=M7?PrD@>dzO*E2;ci6m))3_Kf7p>dgF4iMzxV!Y{(5!$KHMU`1O$!dAH4-JQw++t%dyNgb-hb> z(QCv$QXu7sNw3?&1@R?j86Lngc+H0h3>V7=Gu9|CmLGvYrDTgDk-Lp1Gd3@+mYTSh zMEzG(CaILRlPcPed+97jo>YQ&U!Uw=F?g@=>FyOh)#2HF?byAdC#xRC&!C9B%`;<3 znYW!ph*ZrrV|DU^{7(>QTH9j6%0!-H#^$HZ>vMQsb0V85kpwnPiTqrc@J;I$GuE0m z6fORtXd??>u!S$t_B7dg9SXvt-i>1LP!MAEZWM!u;_KZj1`ow9C}JpD%~+cp3jCxB z4aIyj)+~p@03rGg@9k#O-fkN2?T(XsJ9;>i!cPmQFQV;c?A)|$w|laUEnNp?JBKvU z=AyMH$t|7S(fHRXMI->O!BosZWFiPJQZ!_S^TVKeW-OE;H6G`&2}P+^W;f*co!0 zI)Dh_s#DF_X>yxNzvameBZlKFwy6U0yC!d?hhfEW7CAW(Mv#-AASYLu@hi>v z6=wW0m6j-&_7&nzAtO%Fec-p(}S|NTkX&lp_p{^&2{v z3|+MwLn4K)AuTAP7z`nK%d$$|;V^>a-GJm>XU4BFMCAX>nXN7FqoL zfP!b7 zRCjkjDZVG8G{=zUx;@m)2rbaQKeX?WgEg5BJV^09ghqJl(VO;AGb6M>`~J`bZ2Qfb z4gv=>!@(Z(y_$Nk{@Xg(gC2|{2e)K82#hVG2YcXPJRIQCeybU~OO>fe=f!}rRyksM}(E9VC1m23C+ zK-_A3D&!kv^<2LtH!N9e-yo|UeoJoPY-!K4+C^E|gRBbp_&vy~0EFLztS|LxtLOPGWs%hzULzzxyp>cQ@-UrlBkbG2L?ghR?@}AfP{rs+Oxrod`w#*G8oCkcXnujl7cBLU zM=W*Uzur0qxbB=~=W;|VQXnyGFxf49kF1~Q$hxKNk@XY9#_Sxmr2bOIeXneOC7b(X zbH8kUjRs>D7@{rnAa?!KA)T(TX&cROU@ttHq9=ixDgplZJ*t8ctU6nD@d1keLDRPB zqN9j5h&9oBMZwGW&#E?=vCXC;$=j7prhTufs-lX@EmScNk|x@R(4zT`Y#x@)BeK~f zo6TsVzv(q|(!MM#@dP?>S1j%&dd*{ooxr`Rw9{)=GYkc8U)hk8<1Of^{ToWK{UE(o zR6a_%dK6^J)mBObhCoQDA$SbLlX9xInz2WjBZp{6YISU$z{{F0mOrzs+pf+8mV4-r-0 z6!CW~`4A;iZT+8RNgwg|AgUtfo9=C9?D4cB-sUM{ytDcQCHHyKMEe4nz0Vbp8)Wwq z^BR^fB*B>ll20p(AqNX{JAjE5M%uG8=!TN8>_TIry`10KHdn5PRB;J!MAkPw(oU zjnc{S7tQz!X8d`zL;W{6@ba~6cF9JgPxI?39ZmFaBJo;J`%UKeypfdpJ#HjfpFY{$ z(|*>VFkV9#nVaR;gQ$o+Oe$|Uk$XS6%VY{zlI43EOr|&`S$=AP$rPR>J0H-=B^USb z4zm$EO#20QA89{N1w~aI{R{0kcSNFpmaTY$Dgs^mMO4sQ_i={U`PhF}TNL^1Tg=Zw z^l_w!5T z1WWbzOXUVj;g|ir*~|-;A|yb(TO#iWl5|J#s;Ccl>5}6lsqT8>rMioWpvtt1PeRju z1E46{HsrE^x3^&uHxSh#xL{xkd zO75}f3q`p4yk*ATmRFyBK(JqRmJT_q3XN*DZxE+*-Xy<8d%)qCJ$X zzV9hY&<+C)OSwZRR$xg5LS<;XLTlW1oiiQ)BeC;*%3T2M&HyGkM{0q`|u;6Xut1F9RQdX0)_uCGy1t{e=N2pq8gl05|4H$ z4iO7-a3bVuqB})@Wp}E+GGqTXnZzGb{mQg=sxim2fv>4{W|1b^8no=o5lVlKWdDn_ zhg9w&#gka^WV8si7hM(PDUd`FYh|%ry@`ukR{L{uRZ*#z!PTkk>NIlYq$DUzShZpwU8wSK7{_F!}UQa$X!>ikkY?7`~&Qa$X!8X*<^rzo%@mE|U)eF2(S>o&i= zYcRdJDKaR>Pwpw4i}yUpt16XCTa{533zhk+)F^XCwhL7nrV2=sCffOE(KM6e+_GM3 z&QnA(2>T0KrNjOQA}wSmrwo(X&Mm`O(MaUcmxA4;PxZA8qFgcdKh-1(xeKSALk3)y zXQ6B-RYynI@5&ic8KI7y3m$c>(=|^)=&pRIz^y0ggajh4Kwe>}K&{DLFeAQ9(T#&x zq>M)_q}JyJ#1B`6%3|R%v5i_p1S9sDvp$Povq+r>@{EwaF;8LK-wAA{+1lkffai{A zx;9SN?*QdA52de>8`8%|l)~5uv4N~Ef#ItKdy2!J7{or_VNXkA>-tnsW~bY$aTHES zQxNV>bJ!;bvCnkarw6g;I_yLcyUAhK2eF$Sb~1>4uETB(VlQ&o-C%qBt?QjZ3Ku#G z=SzhUCq6}p=(@f*NNK5~gl~zad07&q@FPdz3aOy8mo8nuEJ)#MN8!go>}wtN@*wsq zhrL3&b2^1}2A#S-LrFK*fHsxNQb(bdqfm|2piEX2lrGBjR>$yqY1k=KUB4;AC=~8= z6mAb<-{Y|F4r1T$upLE#U1lygXVh%j#u%8KH|H)y$kjB>a z=Rxt#d13E0N8!~p1;KvTVZR;3{)fYUFNpoQ!`_+ZTi164DeQ6-z6xT8^VM>s=Lf7- z{T+6nAa@f~|G}zue>iSVZ3KJcLaYA9KQ|)pJj}1~f-cg#C;bm%& z!YPhIO@_jWK?-L%3TFs~rJgxIJ4m6~QAh@{&vn?XLF~&M_9fDtlZA0&&R>+Fq#IX& z=AZMIgOWDq*Eoh(3d8O^(e)J>Mlt8NI0}yhu^)HXTZ7n7JM1Te*v~oaXM)&&blA@a zu^;QN>Uv9mEit2Z(FB1&xzyn0xLemZfl<@d0SH8OA=nEK&cqx&dVtcd9MFUIC@^X| z2tZM3mn!X*B})4SU`0-D>i|-)k}KCzB&X}wft4B4HJ~CUKYTMudv z@xk8%j=%dLcLMMw1q>;ts9a0!C%S%b&tC5d^t!QUuexD_*;7^?1TP~iPdQOOL8_Tq z*#>fY@W_h{ek+(gq-+aVnJL=@YL6*1c9rgrVh9;ubNdyyUvm2e+7S4k%X9sc(!rXc z_tkZMd#P4m+g0ls(?djdKLm*EyxP{*hUQMH2D!P!?&E_}ZC*pNX`ZMNhx%TrwlG=W zHP0vdZmHIo1UPAJ3jkQ1`j)dpH+Gh41Pe=Ot*YG0wJzP*A?Ye8E>BC8=V#Zjegw-8XZc|)e>lqzWqO?HhcW$7wsQ#EiLsr7B|Y~bQ;b}0RJJ)4 zQZA=l%H>#6E;LxuL;Fj5Xg^6e_K|vqiIzsVRG#a7Of|v@IJHu@`)M^deI46sb2* z<_Ea44Vd80qNp4FP3;^HfeS3$H>Yo|o_he|tM^8y=N@QkExsh=4gtk0(>G82i}cO! zTOj`D^_9nHQMcV(KV4iuom^KPOh1?D?UJ6~Ch7UDlAhnf^35zipXJYC`6SEFWBDeg zH!{6}>Gf= zU)L`Ll)Q%^_I1mkuZi%k68dS2>XpJq8u1EYCyjWSh}PLmlJU@OJTY$NiLpUW41I;; z^g2_kPj)oabtT&fY+P*|<*oWPrqLf(P+&9>i^O5W|nL z+*WQMW%(^EznSGX@oM;pOHeJ7~hvEJ?=q*Wa-N>E5?L@D|1<5HJ zqW3inJr$6g6$~j#;*dFHM)A|PyvWm z9*1&6;q5$FA94GkY(wwyp#7Z(?Oh(UcbNY+^WS3rn>>?Wa%S?2=xWf;N$hs@7j`qm z&qF(N^F~YF>oQYqjg6gjGw1Z%FkW>>r$~?so1y;EaYH z!yPFTJMvJtOx!7iLS^DkA!L+^JB6?=`C*OQT|C@h^Kk#0hx;oY?$4az{*;msuu+!7 z{c*3uO~d-Rsnt5eA+od6KWc{Yr87R2GRu}6pJtimFTk#=ZEi@=Etyjmy7A8*vi~o5 zbTUsVQnN$kIHyeOOi!X7&Mni@iO6dotw3C;G_A0oPM<&$yUP>{U=#!$!;#o=B3G!-!A<3+RbO#f&kfZX)*L+*}h7) zKrhx|kLmc>eIj1vNqsU2x;mLDOgG*l{OkP^+s&Jo_qJWqNTA ztdt{1L3l_2~&Dn1yI$F3XkO@jcsZ znJbi!j<*3-4mSkN=TW4Eim$e|-*$~y7;Xo<$=+9v0`2$u9(uzR;X(rJ_Em{$dq;rhGNVIab3=M1trvm>&8f;;N(K;hsspJOf#gyvNIH#FP z|H&rVren%_6`jNO(MpF`HYG>7C(GYsxnt7gLU2I#$Un(dv)ni(HzKH7=!qad;iDzT zJ(X3{FEo(iqy8O6{lm`-%F2;Z*DtK0r-`U_8dai&wfcpVQ68N<(nO08t*yIb!US0n zMC$|EtSRHiC%fd6SEXM>bWms1cFyLuG*$!#I*5IkcYx^oQmu2Z0P8mQ{T{<#A{n!cS}QSSLYo6nlNJ6 z@FQpuIR`h4opU;qE$z(>R$F^RYg4n8Y^iN(u$q%|J8C=5o735Wm4hgW`bAytnlTyi zO~HRrji>nYJ)yR}bGRqBly9Pq@X#pV7|7GS`4jnWK=cdn#E{k|O4fOzp$OBfL{vmtl~9Do$_L#}HBmL3DjsvY6-JeCLb9uF z-pr2a*xJ^12;(lFDq>q-2Y=j;i>4k3Nk+A?8>gWOX`Z)n7_Hb?L01WP{)e<#EMKGKF_$gK(_9`#bJ=r_wHN1d zmzZhG&`xDrrv=!mCS6Y~v`*1~ibbwjA?*y-pQH4#PC^g8Le6+?B)=qIjegL7w=cLN zvHsagAF-1@^#%DBeIZ@voNdw$R{RH#?0aq2v&{x&lXWQXj$T?EO{_Cd=^zf}7bFo! zHOHaO72hI0U+L+(LUi?C#YX3JrEdYhaDQFwNLq2+S-YSiAy*1Kgv8vYyj4g(?FQ=F zS{F2Qbg>AY-w_1B9>|O&8TLbCqwLI0b|pG$Tbml>_=q@&-_bNT0qY}2jYMBqk8(lu z%F4=wctl8CT4ACxJ{mK+3G41^z?%W;jxB{YVT|s<7l8QO0C@0(-AajE}suQF_$qP%Av1zhCguVMv>Shrce)oF(wktb&0NI z3oaq_rXt1YC&?J$Yl*Uncr3yV(*J|vq ziQe2?OGDf4tcrbzE@A?a_XgjG_aY$=;ik5Z^VkmgY!~$AQ zeYAxRkt!b~P@hFP>P&c%!^lR2S#>coQ1h3)w4M^|G44?bOc^xOb9ysdZ^>f|+#e^F(4@-}KC2VO^(BpRWEbwaw_f>t`Hjh+FK#Ron%jHRByy(HF$++*5PE z==n)YTYV#qO)2g`Lxbo^LgwEmALk9sS!r#s)>)U9-)-GvZMB}UzOb$=pB5^%%B#D& zFOIB@Y>sS??1+38Sz=vcU1t5zy2@H+Ew`?*R#+>oHPGB(-EQ4s-D%xr-ED1zjr*+o ztzTQV^^o-&>k(^{wZ(c=*nQ6Wz4Zs{1?!L2i`Gll%hoH_U#wTHzgn+ZuUl_eZ(46# z|7*Q#{oQ)cdf)oM`q26ukz87SW%;u58_EZzZbX;*SJRR|G+BS&>esYg_;z+kt8Q$l z?HW34*wwn0l9ZwK^j^+_2I?(6I|}J1W^{aLU9x#dW0Rm8Lgow-_5BH%re;B-omfae zw!kNV6Cs1^7yY4zAyX)hy)QxrZ?4lHjY3FYF;AR$UW82Nd4iHFWZuH!?f(-p^>YO= R53eD8Czc8SAH`7c{{ZuOg#Z8m diff --git a/SOIL.obj b/SOIL.obj deleted file mode 100644 index 71f3e6e48cf1b2a46b04fed6aa0c7b792aff84be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56645 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 diff --git a/SOIL.h b/SOIL2.h similarity index 84% rename from SOIL.h rename to SOIL2.h index e19a86a7..37facf8c 100644 --- a/SOIL.h +++ b/SOIL2.h @@ -1,430 +1,498 @@ -/** - @mainpage SOIL - - Jonathan Dummer - 2007-07-26-10.36 - - Simple OpenGL Image Library - - A tiny c library for uploading images as - textures into OpenGL. Also saving and - loading of images is supported. - - I'm using Sean's Tool Box image loader as a base: - http://www.nothings.org/ - - I'm upgrading it to load TGA and DDS files, and a direct - path for loading DDS files straight into OpenGL textures, - when applicable. - - Image Formats: - - BMP load & save - - TGA load & save - - DDS load & save - - PNG load - - JPG load - - OpenGL Texture Features: - - resample to power-of-two sizes - - MIPmap generation - - compressed texture S3TC formats (if supported) - - can pre-multiply alpha for you, for better compositing - - can flip image about the y-axis (except pre-compressed DDS files) - - Thanks to: - * Sean Barret - for the awesome stb_image - * Dan Venkitachalam - for finding some non-compliant DDS files, and patching some explicit casts - * everybody at gamedev.net -**/ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -/** - The format of images that may be loaded (force_channels). - SOIL_LOAD_AUTO leaves the image in whatever format it was found. - SOIL_LOAD_L forces the image to load as Luminous (greyscale) - SOIL_LOAD_LA forces the image to load as Luminous with Alpha - SOIL_LOAD_RGB forces the image to load as Red Green Blue - SOIL_LOAD_RGBA forces the image to load as Red Green Blue Alpha -**/ -enum -{ - SOIL_LOAD_AUTO = 0, - SOIL_LOAD_L = 1, - SOIL_LOAD_LA = 2, - SOIL_LOAD_RGB = 3, - SOIL_LOAD_RGBA = 4 -}; - -/** - Passed in as reuse_texture_ID, will cause SOIL to - register a new texture ID using glGenTextures(). - If the value passed into reuse_texture_ID > 0 then - SOIL will just re-use that texture ID (great for - reloading image assets in-game!) -**/ -enum -{ - SOIL_CREATE_NEW_ID = 0 -}; - -/** - flags you can pass into SOIL_load_OGL_texture() - and SOIL_create_OGL_texture(). - (note that if SOIL_FLAG_DDS_LOAD_DIRECT is used - the rest of the flags with the exception of - SOIL_FLAG_TEXTURE_REPEATS will be ignored while - loading already-compressed DDS files.) - - SOIL_FLAG_POWER_OF_TWO: force the image to be POT - SOIL_FLAG_MIPMAPS: generate mipmaps for the texture - SOIL_FLAG_TEXTURE_REPEATS: otherwise will clamp - SOIL_FLAG_MULTIPLY_ALPHA: for using (GL_ONE,GL_ONE_MINUS_SRC_ALPHA) blending - SOIL_FLAG_INVERT_Y: flip the image vertically - SOIL_FLAG_COMPRESS_TO_DXT: if the card can display them, will convert RGB to DXT1, RGBA to DXT5 - SOIL_FLAG_DDS_LOAD_DIRECT: will load DDS files directly without _ANY_ additional processing - SOIL_FLAG_NTSC_SAFE_RGB: clamps RGB components to the range [16,235] - SOIL_FLAG_CoCg_Y: Google YCoCg; RGB=>CoYCg, RGBA=>CoCgAY - SOIL_FLAG_TEXTURE_RECTANGE: uses ARB_texture_rectangle ; pixel indexed & no repeat or MIPmaps or cubemaps -**/ -enum -{ - SOIL_FLAG_POWER_OF_TWO = 1, - SOIL_FLAG_MIPMAPS = 2, - SOIL_FLAG_TEXTURE_REPEATS = 4, - SOIL_FLAG_MULTIPLY_ALPHA = 8, - SOIL_FLAG_INVERT_Y = 16, - SOIL_FLAG_COMPRESS_TO_DXT = 32, - SOIL_FLAG_DDS_LOAD_DIRECT = 64, - SOIL_FLAG_NTSC_SAFE_RGB = 128, - SOIL_FLAG_CoCg_Y = 256, - SOIL_FLAG_TEXTURE_RECTANGLE = 512 -}; - -/** - The types of images that may be saved. - (TGA supports uncompressed RGB / RGBA) - (BMP supports uncompressed RGB) - (DDS supports DXT1 and DXT5) -**/ -enum -{ - SOIL_SAVE_TYPE_TGA = 0, - SOIL_SAVE_TYPE_BMP = 1, - SOIL_SAVE_TYPE_DDS = 2 -}; - -/** - Defines the order of faces in a DDS cubemap. - I recommend that you use the same order in single - image cubemap files, so they will be interchangeable - with DDS cubemaps when using SOIL. -**/ -#define SOIL_DDS_CUBEMAP_FACE_ORDER "EWUDNS" - -/** - The types of internal fake HDR representations - - SOIL_HDR_RGBE: RGB * pow( 2.0, A - 128.0 ) - SOIL_HDR_RGBdivA: RGB / A - SOIL_HDR_RGBdivA2: RGB / (A*A) -**/ -enum -{ - SOIL_HDR_RGBE = 0, - SOIL_HDR_RGBdivA = 1, - SOIL_HDR_RGBdivA2 = 2 -}; - -/** - Loads an image from disk into an OpenGL texture. - \param filename the name of the file to upload as a texture - \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_load_OGL_texture - ( - const char *filename, - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Loads 6 images from disk into an OpenGL cubemap texture. - \param x_pos_file the name of the file to upload as the +x cube face - \param x_neg_file the name of the file to upload as the -x cube face - \param y_pos_file the name of the file to upload as the +y cube face - \param y_neg_file the name of the file to upload as the -y cube face - \param z_pos_file the name of the file to upload as the +z cube face - \param z_neg_file the name of the file to upload as the -z cube face - \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_load_OGL_cubemap - ( - const char *x_pos_file, - const char *x_neg_file, - const char *y_pos_file, - const char *y_neg_file, - const char *z_pos_file, - const char *z_neg_file, - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Loads 1 image from disk and splits it into an OpenGL cubemap texture. - \param filename the name of the file to upload as a texture - \param face_order the order of the faces in the file, any combination of NSWEUD, for North, South, Up, etc. - \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_load_OGL_single_cubemap - ( - const char *filename, - const char face_order[6], - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Loads an HDR image from disk into an OpenGL texture. - \param filename the name of the file to upload as a texture - \param fake_HDR_format SOIL_HDR_RGBE, SOIL_HDR_RGBdivA, SOIL_HDR_RGBdivA2 - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_load_OGL_HDR_texture - ( - const char *filename, - int fake_HDR_format, - int rescale_to_max, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Loads an image from RAM into an OpenGL texture. - \param buffer the image data in RAM just as if it were still in a file - \param buffer_length the size of the buffer in bytes - \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_load_OGL_texture_from_memory - ( - const unsigned char *const buffer, - int buffer_length, - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Loads 6 images from memory into an OpenGL cubemap texture. - \param x_pos_buffer the image data in RAM to upload as the +x cube face - \param x_pos_buffer_length the size of the above buffer - \param x_neg_buffer the image data in RAM to upload as the +x cube face - \param x_neg_buffer_length the size of the above buffer - \param y_pos_buffer the image data in RAM to upload as the +x cube face - \param y_pos_buffer_length the size of the above buffer - \param y_neg_buffer the image data in RAM to upload as the +x cube face - \param y_neg_buffer_length the size of the above buffer - \param z_pos_buffer the image data in RAM to upload as the +x cube face - \param z_pos_buffer_length the size of the above buffer - \param z_neg_buffer the image data in RAM to upload as the +x cube face - \param z_neg_buffer_length the size of the above buffer - \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_load_OGL_cubemap_from_memory - ( - const unsigned char *const x_pos_buffer, - int x_pos_buffer_length, - const unsigned char *const x_neg_buffer, - int x_neg_buffer_length, - const unsigned char *const y_pos_buffer, - int y_pos_buffer_length, - const unsigned char *const y_neg_buffer, - int y_neg_buffer_length, - const unsigned char *const z_pos_buffer, - int z_pos_buffer_length, - const unsigned char *const z_neg_buffer, - int z_neg_buffer_length, - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Loads 1 image from RAM and splits it into an OpenGL cubemap texture. - \param buffer the image data in RAM just as if it were still in a file - \param buffer_length the size of the buffer in bytes - \param face_order the order of the faces in the file, any combination of NSWEUD, for North, South, Up, etc. - \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_load_OGL_single_cubemap_from_memory - ( - const unsigned char *const buffer, - int buffer_length, - const char face_order[6], - int force_channels, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Creates a 2D OpenGL texture from raw image data. Note that the raw data is - _NOT_ freed after the upload (so the user can load various versions). - \param data the raw data to be uploaded as an OpenGL texture - \param width the width of the image in pixels - \param height the height of the image in pixels - \param channels the number of channels: 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_create_OGL_texture - ( - const unsigned char *const data, - int width, int height, int channels, - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Creates an OpenGL cubemap texture by splitting up 1 image into 6 parts. - \param data the raw data to be uploaded as an OpenGL texture - \param width the width of the image in pixels - \param height the height of the image in pixels - \param channels the number of channels: 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA - \param face_order the order of the faces in the file, and combination of NSWEUD, for North, South, Up, etc. - \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) - \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT - \return 0-failed, otherwise returns the OpenGL texture handle -**/ -unsigned int - SOIL_create_OGL_single_cubemap - ( - const unsigned char *const data, - int width, int height, int channels, - const char face_order[6], - unsigned int reuse_texture_ID, - unsigned int flags - ); - -/** - Captures the OpenGL window (RGB) and saves it to disk - \return 0 if it failed, otherwise returns 1 -**/ -int - SOIL_save_screenshot - ( - const char *filename, - int image_type, - int x, int y, - int width, int height - ); - -/** - Loads an image from disk into an array of unsigned chars. - Note that *channels return the original channel count of the - image. If force_channels was other than SOIL_LOAD_AUTO, - the resulting image has force_channels, but *channels may be - different (if the original image had a different channel - count). - \return 0 if failed, otherwise returns 1 -**/ -unsigned char* - SOIL_load_image - ( - const char *filename, - int *width, int *height, int *channels, - int force_channels - ); - -/** - Loads an image from memory into an array of unsigned chars. - Note that *channels return the original channel count of the - image. If force_channels was other than SOIL_LOAD_AUTO, - the resulting image has force_channels, but *channels may be - different (if the original image had a different channel - count). - \return 0 if failed, otherwise returns 1 -**/ -unsigned char* - SOIL_load_image_from_memory - ( - const unsigned char *const buffer, - int buffer_length, - int *width, int *height, int *channels, - int force_channels - ); - -/** - Saves an image from an array of unsigned chars (RGBA) to disk - \return 0 if failed, otherwise returns 1 -**/ -int - SOIL_save_image - ( - const char *filename, - int image_type, - int width, int height, int channels, - const unsigned char *const data - ); - -/** - Frees the image data (note, this is just C's "free()"...this function is - present mostly so C++ programmers don't forget to use "free()" and call - "delete []" instead [8^) -**/ -void - SOIL_free_image_data - ( - unsigned char *img_data - ); - -/** - This function resturn a pointer to a string describing the last thing - that happened inside SOIL. It can be used to determine why an image - failed to load. -**/ -const char* - SOIL_last_result - ( - void - ); - - -#ifdef __cplusplus -} -#endif +/** + @mainpage SOIL2 + + Fork by Martin Lucas Golini + + Original author Jonathan Dummer + 2007-07-26-10.36 + + Simple OpenGL Image Library 2 + + A tiny c library for uploading images as + textures into OpenGL. Also saving and + loading of images is supported. + + I'm using Sean's Tool Box image loader as a base: + http://www.nothings.org/ + + I'm upgrading it to load TGA and DDS files, and a direct + path for loading DDS files straight into OpenGL textures, + when applicable. + + Image Formats: + - BMP load & save + - TGA load & save + - DDS load & save + - PNG load & save + - JPG load + - PSD load + - HDR load + - PIC load + + OpenGL Texture Features: + - resample to power-of-two sizes + - MIPmap generation + - compressed texture S3TC formats (if supported) + - can pre-multiply alpha for you, for better compositing + - can flip image about the y-axis (except pre-compressed DDS files) + + Thanks to: + * Sean Barret - for the awesome stb_image + * Dan Venkitachalam - for finding some non-compliant DDS files, and patching some explicit casts + * everybody at gamedev.net +**/ + +#ifndef HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY +#define HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY + +#ifdef __cplusplus +extern "C" { +#endif + +/** + The format of images that may be loaded (force_channels). + SOIL_LOAD_AUTO leaves the image in whatever format it was found. + SOIL_LOAD_L forces the image to load as Luminous (greyscale) + SOIL_LOAD_LA forces the image to load as Luminous with Alpha + SOIL_LOAD_RGB forces the image to load as Red Green Blue + SOIL_LOAD_RGBA forces the image to load as Red Green Blue Alpha +**/ +enum +{ + SOIL_LOAD_AUTO = 0, + SOIL_LOAD_L = 1, + SOIL_LOAD_LA = 2, + SOIL_LOAD_RGB = 3, + SOIL_LOAD_RGBA = 4 +}; + +/** + Passed in as reuse_texture_ID, will cause SOIL to + register a new texture ID using glGenTextures(). + If the value passed into reuse_texture_ID > 0 then + SOIL will just re-use that texture ID (great for + reloading image assets in-game!) +**/ +enum +{ + SOIL_CREATE_NEW_ID = 0 +}; + +/** + flags you can pass into SOIL_load_OGL_texture() + and SOIL_create_OGL_texture(). + (note that if SOIL_FLAG_DDS_LOAD_DIRECT is used + the rest of the flags with the exception of + SOIL_FLAG_TEXTURE_REPEATS will be ignored while + loading already-compressed DDS files.) + + SOIL_FLAG_POWER_OF_TWO: force the image to be POT + SOIL_FLAG_MIPMAPS: generate mipmaps for the texture + SOIL_FLAG_TEXTURE_REPEATS: otherwise will clamp + SOIL_FLAG_MULTIPLY_ALPHA: for using (GL_ONE,GL_ONE_MINUS_SRC_ALPHA) blending + SOIL_FLAG_INVERT_Y: flip the image vertically + SOIL_FLAG_COMPRESS_TO_DXT: if the card can display them, will convert RGB to DXT1, RGBA to DXT5 + SOIL_FLAG_DDS_LOAD_DIRECT: will load DDS files directly without _ANY_ additional processing ( if supported ) + SOIL_FLAG_NTSC_SAFE_RGB: clamps RGB components to the range [16,235] + SOIL_FLAG_CoCg_Y: Google YCoCg; RGB=>CoYCg, RGBA=>CoCgAY + SOIL_FLAG_TEXTURE_RECTANGE: uses ARB_texture_rectangle ; pixel indexed & no repeat or MIPmaps or cubemaps + SOIL_FLAG_PVR_LOAD_DIRECT: will load PVR files directly without _ANY_ additional processing ( if supported ) +**/ +enum +{ + SOIL_FLAG_POWER_OF_TWO = 1, + SOIL_FLAG_MIPMAPS = 2, + SOIL_FLAG_TEXTURE_REPEATS = 4, + SOIL_FLAG_MULTIPLY_ALPHA = 8, + SOIL_FLAG_INVERT_Y = 16, + SOIL_FLAG_COMPRESS_TO_DXT = 32, + SOIL_FLAG_DDS_LOAD_DIRECT = 64, + SOIL_FLAG_NTSC_SAFE_RGB = 128, + SOIL_FLAG_CoCg_Y = 256, + SOIL_FLAG_TEXTURE_RECTANGLE = 512, + SOIL_FLAG_PVR_LOAD_DIRECT = 1024, + SOIL_FLAG_ETC1_LOAD_DIRECT = 2048, + SOIL_FLAG_GL_MIPMAPS = 4096 +}; + +/** + The types of images that may be saved. + (TGA supports uncompressed RGB / RGBA) + (BMP supports uncompressed RGB) + (DDS supports DXT1 and DXT5) + (PNG supports RGB / RGBA) +**/ +enum +{ + SOIL_SAVE_TYPE_TGA = 0, + SOIL_SAVE_TYPE_BMP = 1, + SOIL_SAVE_TYPE_PNG = 2, + SOIL_SAVE_TYPE_DDS = 3 +}; + +/** + Defines the order of faces in a DDS cubemap. + I recommend that you use the same order in single + image cubemap files, so they will be interchangeable + with DDS cubemaps when using SOIL. +**/ +#define SOIL_DDS_CUBEMAP_FACE_ORDER "EWUDNS" + +/** + The types of internal fake HDR representations + + SOIL_HDR_RGBE: RGB * pow( 2.0, A - 128.0 ) + SOIL_HDR_RGBdivA: RGB / A + SOIL_HDR_RGBdivA2: RGB / (A*A) +**/ +enum +{ + SOIL_HDR_RGBE = 0, + SOIL_HDR_RGBdivA = 1, + SOIL_HDR_RGBdivA2 = 2 +}; + +/** + Loads an image from disk into an OpenGL texture. + \param filename the name of the file to upload as a texture + \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA + \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) + \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT + \return 0-failed, otherwise returns the OpenGL texture handle +**/ +unsigned int + SOIL_load_OGL_texture + ( + const char *filename, + int force_channels, + unsigned int reuse_texture_ID, + unsigned int flags + ); + +/** + Loads 6 images from disk into an OpenGL cubemap texture. + \param x_pos_file the name of the file to upload as the +x cube face + \param x_neg_file the name of the file to upload as the -x cube face + \param y_pos_file the name of the file to upload as the +y cube face + \param y_neg_file the name of the file to upload as the -y cube face + \param z_pos_file the name of the file to upload as the +z cube face + \param z_neg_file the name of the file to upload as the -z cube face + \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA + \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) + \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT + \return 0-failed, otherwise returns the OpenGL texture handle +**/ +unsigned int + SOIL_load_OGL_cubemap + ( + const char *x_pos_file, + const char *x_neg_file, + const char *y_pos_file, + const char *y_neg_file, + const char *z_pos_file, + const char *z_neg_file, + int force_channels, + unsigned int reuse_texture_ID, + unsigned int flags + ); + +/** + Loads 1 image from disk and splits it into an OpenGL cubemap texture. + \param filename the name of the file to upload as a texture + \param face_order the order of the faces in the file, any combination of NSWEUD, for North, South, Up, etc. + \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA + \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) + \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT + \return 0-failed, otherwise returns the OpenGL texture handle +**/ +unsigned int + SOIL_load_OGL_single_cubemap + ( + const char *filename, + const char face_order[6], + int force_channels, + unsigned int reuse_texture_ID, + unsigned int flags + ); + +/** + Loads an HDR image from disk into an OpenGL texture. + \param filename the name of the file to upload as a texture + \param fake_HDR_format SOIL_HDR_RGBE, SOIL_HDR_RGBdivA, SOIL_HDR_RGBdivA2 + \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) + \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT + \return 0-failed, otherwise returns the OpenGL texture handle +**/ +unsigned int + SOIL_load_OGL_HDR_texture + ( + const char *filename, + int fake_HDR_format, + int rescale_to_max, + unsigned int reuse_texture_ID, + unsigned int flags + ); + +/** + Loads an image from RAM into an OpenGL texture. + \param buffer the image data in RAM just as if it were still in a file + \param buffer_length the size of the buffer in bytes + \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA + \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) + \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT + \return 0-failed, otherwise returns the OpenGL texture handle +**/ +unsigned int + SOIL_load_OGL_texture_from_memory + ( + const unsigned char *const buffer, + int buffer_length, + int force_channels, + unsigned int reuse_texture_ID, + unsigned int flags + ); + +/** + Loads 6 images from memory into an OpenGL cubemap texture. + \param x_pos_buffer the image data in RAM to upload as the +x cube face + \param x_pos_buffer_length the size of the above buffer + \param x_neg_buffer the image data in RAM to upload as the +x cube face + \param x_neg_buffer_length the size of the above buffer + \param y_pos_buffer the image data in RAM to upload as the +x cube face + \param y_pos_buffer_length the size of the above buffer + \param y_neg_buffer the image data in RAM to upload as the +x cube face + \param y_neg_buffer_length the size of the above buffer + \param z_pos_buffer the image data in RAM to upload as the +x cube face + \param z_pos_buffer_length the size of the above buffer + \param z_neg_buffer the image data in RAM to upload as the +x cube face + \param z_neg_buffer_length the size of the above buffer + \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA + \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) + \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT + \return 0-failed, otherwise returns the OpenGL texture handle +**/ +unsigned int + SOIL_load_OGL_cubemap_from_memory + ( + const unsigned char *const x_pos_buffer, + int x_pos_buffer_length, + const unsigned char *const x_neg_buffer, + int x_neg_buffer_length, + const unsigned char *const y_pos_buffer, + int y_pos_buffer_length, + const unsigned char *const y_neg_buffer, + int y_neg_buffer_length, + const unsigned char *const z_pos_buffer, + int z_pos_buffer_length, + const unsigned char *const z_neg_buffer, + int z_neg_buffer_length, + int force_channels, + unsigned int reuse_texture_ID, + unsigned int flags + ); + +/** + Loads 1 image from RAM and splits it into an OpenGL cubemap texture. + \param buffer the image data in RAM just as if it were still in a file + \param buffer_length the size of the buffer in bytes + \param face_order the order of the faces in the file, any combination of NSWEUD, for North, South, Up, etc. + \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA + \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) + \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT + \return 0-failed, otherwise returns the OpenGL texture handle +**/ +unsigned int + SOIL_load_OGL_single_cubemap_from_memory + ( + const unsigned char *const buffer, + int buffer_length, + const char face_order[6], + int force_channels, + unsigned int reuse_texture_ID, + unsigned int flags + ); + +/** + Creates a 2D OpenGL texture from raw image data. Note that the raw data is + _NOT_ freed after the upload (so the user can load various versions). + \param data the raw data to be uploaded as an OpenGL texture + \param width the pointer of the width of the image in pixels ( if the texture size change, width will be overrided with the new width ) + \param height the pointer of the height of the image in pixels ( if the texture size change, height will be overrided with the new height ) + \param channels the number of channels: 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA + \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) + \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT + \return 0-failed, otherwise returns the OpenGL texture handle +**/ +unsigned int + SOIL_create_OGL_texture + ( + const unsigned char *const data, + int *width, int *height, int channels, + unsigned int reuse_texture_ID, + unsigned int flags + ); + +/** + Creates an OpenGL cubemap texture by splitting up 1 image into 6 parts. + \param data the raw data to be uploaded as an OpenGL texture + \param width the width of the image in pixels + \param height the height of the image in pixels + \param channels the number of channels: 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA + \param face_order the order of the faces in the file, and combination of NSWEUD, for North, South, Up, etc. + \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) + \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT + \return 0-failed, otherwise returns the OpenGL texture handle +**/ +unsigned int + SOIL_create_OGL_single_cubemap + ( + const unsigned char *const data, + int width, int height, int channels, + const char face_order[6], + unsigned int reuse_texture_ID, + unsigned int flags + ); + +/** + Captures the OpenGL window (RGB) and saves it to disk + \return 0 if it failed, otherwise returns 1 +**/ +int + SOIL_save_screenshot + ( + const char *filename, + int image_type, + int x, int y, + int width, int height + ); + +/** + Loads an image from disk into an array of unsigned chars. + Note that *channels return the original channel count of the + image. If force_channels was other than SOIL_LOAD_AUTO, + the resulting image has force_channels, but *channels may be + different (if the original image had a different channel + count). + \return 0 if failed, otherwise returns 1 +**/ +unsigned char* + SOIL_load_image + ( + const char *filename, + int *width, int *height, int *channels, + int force_channels + ); + +/** + Loads an image from memory into an array of unsigned chars. + Note that *channels return the original channel count of the + image. If force_channels was other than SOIL_LOAD_AUTO, + the resulting image has force_channels, but *channels may be + different (if the original image had a different channel + count). + \return 0 if failed, otherwise returns 1 +**/ +unsigned char* + SOIL_load_image_from_memory + ( + const unsigned char *const buffer, + int buffer_length, + int *width, int *height, int *channels, + int force_channels + ); + +/** + Saves an image from an array of unsigned chars (RGBA) to disk + \return 0 if failed, otherwise returns 1 +**/ +int + SOIL_save_image + ( + const char *filename, + int image_type, + int width, int height, int channels, + const unsigned char *const data + ); + +/** + Frees the image data (note, this is just C's "free()"...this function is + present mostly so C++ programmers don't forget to use "free()" and call + "delete []" instead [8^) +**/ +void + SOIL_free_image_data + ( + unsigned char *img_data + ); + +/** + This function resturn a pointer to a string describing the last thing + that happened inside SOIL. It can be used to determine why an image + failed to load. +**/ +const char* + SOIL_last_result + ( + void + ); + +/** @return The address of the GL function proc, or NULL if the function is not found. */ +void * + SOIL_GL_GetProcAddress + ( + const char *proc + ); + +/** @return 1 if an OpenGL extension is supported for the current context, 0 otherwise. */ +int + SOIL_GL_ExtensionSupported + ( + const char *extension + ); + +/** Loads the DDS texture directly to the GPU memory ( if supported ) */ +unsigned int SOIL_direct_load_DDS( + const char *filename, + unsigned int reuse_texture_ID, + int flags, + int loading_as_cubemap ); + +/** Loads the DDS texture directly to the GPU memory ( if supported ) */ +unsigned int SOIL_direct_load_DDS_from_memory( + const unsigned char *const buffer, + int buffer_length, + unsigned int reuse_texture_ID, + int flags, + int loading_as_cubemap ); + +/** Loads the PVR texture directly to the GPU memory ( if supported ) */ +unsigned int SOIL_direct_load_PVR( + const char *filename, + unsigned int reuse_texture_ID, + int flags, + int loading_as_cubemap ); + +/** Loads the PVR texture directly to the GPU memory ( if supported ) */ +unsigned int SOIL_direct_load_PVR_from_memory( + const unsigned char *const buffer, + int buffer_length, + unsigned int reuse_texture_ID, + int flags, + int loading_as_cubemap ); + +/** Loads the PVR texture directly to the GPU memory ( if supported ) */ +unsigned int SOIL_direct_load_ETC1(const char *filename, + unsigned int reuse_texture_ID, + int flags ); + +/** Loads the PVR texture directly to the GPU memory ( if supported ) */ +unsigned int SOIL_direct_load_ETC1_from_memory(const unsigned char *const buffer, + int buffer_length, + unsigned int reuse_texture_ID, + int flags ); + +#ifdef __cplusplus +} +#endif + +#endif /* HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY */ diff --git a/SOIL2.lib b/SOIL2.lib new file mode 100644 index 0000000000000000000000000000000000000000..96a5c15c4f2987bbd6cd8b649bd66f74075566e3 GIT binary patch literal 259208 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 literal 0 HcmV?d00001 diff --git a/SOIL2_d.lib b/SOIL2_d.lib new file mode 100644 index 0000000000000000000000000000000000000000..82510c6ec41a2da7e8d0fda9a7bbd2901c467d90 GIT binary patch literal 577092 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�N=`ZW`=B(GX8303il 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Ξq5lic8TaYyPS4OyHyHit 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

JYfw7uC=hK(M<}$@5)_iuTCI3x*6IZm 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 z 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 z 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 literal 0 HcmV?d00001 diff --git a/SOIL2_d.pdb b/SOIL2_d.pdb new file mode 100644 index 0000000000000000000000000000000000000000..1f06e7dd4e1f7f585f360fcb0e55a7cbe66a35b0 GIT binary patch literal 151552 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¬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 literal 0 HcmV?d00001 diff --git a/SOIL2_x64.lib b/SOIL2_x64.lib new file mode 100644 index 0000000000000000000000000000000000000000..8e4140d70e4f5a0a49a4b49520100daae8d75ea7 GIT binary patch literal 464630 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®)9g#Aay-I}q4Xs;v&?-khuE5R(Vllhu{S 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⋙)mB`~ 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 z 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

d!u#HXCQo$vPt!%^7Vd7$#= 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

ke({J3uxm9vnnI0w*O&xfvI^FTu~a|l%5iWe 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%0A@0aV%$+KWNj5J|1T6p02i~ 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 &Z`MBWe+iF;E2c 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 z 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 AX#fBK diff --git a/image_DXT.obj b/image_DXT.obj deleted file mode 100644 index c509acc1bfb28a3b0ef504f7a9a86389df0fa8db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22599 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 aDFyYsxa;1p=PHtx+VX{|`Bm4O^#1`@66ON{ diff --git a/image_helper.obj b/image_helper.obj deleted file mode 100644 index b3b402a7336d932ff705b68277a1008bed062d78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15868 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 diff --git a/res/BodyslideFrame.xrc b/res/BodyslideFrame.xrc index b195a50b..747b4355 100644 --- a/res/BodyslideFrame.xrc +++ b/res/BodyslideFrame.xrc @@ -1037,7 +1037,8 @@ along with this program. If not, see htt wxWidgets

wxWindows License
http://www.wxwidgets.org/


OpenGL
http://www.opengl.org/


-Simple OpenGL Image Libary (SOIL)
Public Domain
http://lonesock.net/soil.html



+ +Simple OpenGL Image Libary 2 (SOIL2)
Public Domain
https://bitbucket.org/SpartanJ/soil2
http://lonesock.net/soil.html



TinyXML-2

zlib License
Original code by Lee Thomason (http://www.grinninglizard.com/)

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.

diff --git a/stb_image_aug.obj b/stb_image_aug.obj deleted file mode 100644 index c004968f9df7db7415376e2145d2c74fcfed16bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 179335 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

S3$R~Ux>eS#r6kWT};&%Wx<^#}fE6;i3% zzWzY6O4sNQDDRmZs4k6%T$DoYmjv+?UvADev{{NH8zVlHLhi|J zmQ59bt6N6?{G%42W}CGxsm)5r$+lUQJjD*XYV-k=cF8T=W?fF5SH9*#wOLm}wOLoe zA@FJ_InIN}!fT+b$LHZM6|-%YtH-I@EX7fIiI1m{XNopUk4WLRU#Q#PW+e*3zS9l& zT9ijuU#|)D^*Y##>+|7Aczp_e-QG6qDM!AnK>v?xvz`y+^#WA=ei5q8dMSmxO7K_v z9@alNy} z+N{^0+N^a@ZPx2hZPpu5a(ol2%~}s#J>K3n>*W;k{BLiwE)MkdQm8g-4pf_USqgpK z-ZtwsN51Ae31{hs`pzlbA05R0Wpjgf1oFBQs(#-E)n?tDLSEZzS2v`PS3)2EZ_QtQ z*wDADA4AFg6DWJ|DRk|C)`DuzB0Rp`opX&1G`@YAqmT1GOK}uN-}$|>HMy4;@HqGm zoDMg@v*Ei?vUm@=^4;EcYh4QY{-?HE_fqfGZrumfZru;nZmoc7w^l;w=>t&h)`QTM z=k~T+Z>5lD!cJ7b)B2N4Yt2d5?Ne>t?~l(9K8s$epY=RcyR{ao-FhK~zHYC4-`<*h zWe*a21N>LX_vJvouLkmcEs*cJ6!O(tPwZ0l+>7S7>j&qux2JKq>s%B^VPYJ4j(p3b z1+j`s)<8>%`GWqpcTcfR{e12cM371)_D-l?gI~t8tkd%|Ih2OHz;mwW?|pI=+zY>X zFbiG-`$EYZH^KtW7eM9fX6V-S?d?PT(~(tPUd8|Valht5 zr5~L+Mn9OZFv+9<2)a_^4i{U|E3i3l9p`a`&E6gAOo7bB@dqe-liVgwA8Z3 zdnw64G7PulU#0ou{%@eh{r`f})lE?2{%@hi{p_1z#{J(zSGL>RKmB$qvi-j>?ss+i zXXGoL{spRk`YTksza@p-x3~ZFX$rajr}Up(JwApyul^H#Bh!Bx2YYf(pVai9SX*i2 zh%TG{6ZW=-9&c~^{;w4B{BP?&x%&D^ps)Xg>OXx3)qnatg}(BslX0@)a%$geL7l68 z*Z5&?Z&*60c8a4g4LNcW^8LN9ptWm_UQNpGR#a+3qZIp=>E4+fdcJK_XjjembM!Uh zYSZKVuVztMwiB#^J43Y<_23d%A3g;eK)x;Z*h0wc z-O~ta&z{EcMA!tL0@I=7))cyBvF8r{`%)`XcWp!);<;s^II^|epUs2#!??7>wi~7_ z+Sv=q43))zKd~%SuG>%+;eEXBB4JPaiBtK0rV{0JI!a$BX~Qp-&$-9}r+^COC#7?> zCuec&OM(vsW zBpcnQvm+bDQJ7&IRSDTdDzl@d{{Cc&UDMT+j-P4i`G8Px-QO+u^GUm&c>!z&X-`c5 zZ8lUoE{1Nos}CY)Q{(Er#w+_ec~czez1sZAiM*-YtA0c0x0W?yCzTiLbbp

+l@X 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 Date: Mon, 7 Dec 2015 16:28:01 +0100 Subject: [PATCH 32/64] Container size() (size_t) warnings --- Object3d.h | 2 +- tinyxml2.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Object3d.h b/Object3d.h index 8b432b48..7c1004d1 100644 --- a/Object3d.h +++ b/Object3d.h @@ -12,7 +12,7 @@ See the included LICENSE file using namespace std; -#pragma warning (disable : 4018 4244 4389) +#pragma warning (disable : 4018 4244 4267 4389) #ifndef EPSILON #define EPSILON (1.0E-4) diff --git a/tinyxml2.cpp b/tinyxml2.cpp index bdf7d007..69b9324f 100644 --- a/tinyxml2.cpp +++ b/tinyxml2.cpp @@ -2083,7 +2083,11 @@ void XMLPrinter::PrintString( const char* p, bool restricted ) while ( p < q ) { const size_t delta = q - p; // %.*s accepts type int as "precision" +#ifdef _WIN64 + const int toPrint = ( LLONG_MAX < delta || delta > INT_MAX ) ? INT_MAX : (const int)delta; +#else const int toPrint = ( INT_MAX < delta ) ? INT_MAX : delta; +#endif Print( "%.*s", toPrint, p ); p += toPrint; } From 3618805e6c4b97c92a9a83a30a9dee85d123d867 Mon Sep 17 00:00:00 2001 From: Caliente Date: Tue, 8 Dec 2015 14:11:55 -0500 Subject: [PATCH 33/64] Such change much wow FBX import export, massive fallout 4 support improvements --- Anim.cpp | 120 +++- Anim.h | 22 +- BodySlide.vcxproj | 17 +- BodySlide.vcxproj.filters | 9 + BodySlide.vcxproj.filters.orig | 263 +++++++++ BodySlide.vcxproj.orig | 304 +++++++++++ BodySlideApp.cpp | 1 + FBXWrangler.cpp | 465 ++++++++++++++++ FBXWrangler.h | 71 +++ GLSurface.cpp | 33 +- Mesh.cpp | 4 + NifBlock.cpp | 566 +++++++++++++++++-- NifFile.cpp | 135 ++++- NifFile.h | 103 +++- ObjFile.cpp | 218 +++++++- ObjFile.h | 4 + Object3d.h | 38 ++ OutfitProject.cpp | 391 ++++++++++--- OutfitProject.h | 10 +- OutfitStudio.cpp | 241 ++++++-- OutfitStudio.h | 45 +- OutfitStudio.h.orig | 968 +++++++++++++++++++++++++++++++++ res/GameObjectBlank.nif | Bin 0 -> 1968 bytes res/outfitStudio.xrc | 12 + targetver.h | 6 +- 25 files changed, 3803 insertions(+), 243 deletions(-) create mode 100644 BodySlide.vcxproj.filters.orig create mode 100644 BodySlide.vcxproj.orig create mode 100644 FBXWrangler.cpp create mode 100644 FBXWrangler.h create mode 100644 OutfitStudio.h.orig create mode 100644 res/GameObjectBlank.nif diff --git a/Anim.cpp b/Anim.cpp index 8a1db86e..8edcce18 100644 --- a/Anim.cpp +++ b/Anim.cpp @@ -12,6 +12,7 @@ bool AnimInfo::AddShapeBone(const string& shape, AnimBone& boneDataRef) { if (!bone.compare(boneDataRef.boneName)) return false; + shapeSkinning[shape].boneNames[boneDataRef.boneName] = shapeBones.size(); shapeBones[shape].push_back(boneDataRef.boneName); AnimSkeleton::getInstance().RefBone(boneDataRef.boneName); return true; @@ -101,8 +102,20 @@ bool AnimInfo::LoadFromNif(NifFile* nif, const string& shape, bool newRefNif) { cstm.rot.Set(r); cstm.localRot = cstm.rot; cstm.localTrans = cstm.trans; + AnimSkeleton::getInstance().RefBone(bn); } + AnimBone* bonePtr = AnimSkeleton::getInstance().GetBonePtr(bn); + if (bonePtr && !bonePtr->hasSkinXform) { + SkinTransform shapeskinxform; + Vector3 offs; + float rad; + if (nif->GetShapeBoneTransform(shape, bn, shapeskinxform, offs, rad)) { + bonePtr->skinRot.Set(shapeskinxform.rotation); + bonePtr->skinTrans = shapeskinxform.translation; + bonePtr->hasSkinXform = true; + } + } shapeBones[shape].push_back(bn); BoneIndices.push_back(slot++); } @@ -154,6 +167,64 @@ void AnimInfo::SetShapeBoneXForm(const string& shape, const string& boneName, Sk return; shapeSkinning[shape].boneWeights[b].xform = stransform; + +} + +bool AnimInfo::CalcShapeSkinBounds(const string& shape) { + if (!refNif || !refNif->IsValid()) { // check for existence of reference nif + return false; + } + if (shapeSkinning.find(shape) == shapeSkinning.end()) { // Check for shape in skinning data + return false; + } + vector verts; + refNif->GetVertsForShape(shape, verts); + if (verts.size() == 0) // check for empty shape + return false; + + for (auto bn : shapeSkinning[shape].boneNames) { + Vector3 a(FLT_MAX, FLT_MAX, FLT_MAX); + Vector3 b(-FLT_MAX, -FLT_MAX, -FLT_MAX); + for (auto &w : shapeSkinning[shape].boneWeights[bn.second].weights) { + if (w.first > verts.size()) { // incoming weights have a larger set of possible verts. + return false; + } + Vector3 v = verts[w.first]; + a.x = min(a.x, v.x); + a.y = min(a.y, v.y); + a.z = min(a.z, v.z); + b.x = max(b.x, v.x); + b.y = max(b.y, v.y); + b.z = max(b.z, v.z); + } + + Vector3 tot = (a + b) / 2.0f; + float d = 0.0f; + for (auto &w : shapeSkinning[shape].boneWeights[bn.second].weights) { + Vector3 v = verts[w.first]; + d = max(d, tot.DistanceTo(v)); + } + + Matrix4 mat; + Vector3 trans; + + AnimBone* xformRef = AnimSkeleton::getInstance().GetBonePtr(bn.first); + if (xformRef->hasSkinXform) { + mat = xformRef->skinRot; + trans = xformRef->skinTrans; + } + else { + // Just FYI, I have no idea if the transform here is even slightly appropriate. + mat = shapeSkinning[shape].boneWeights[bn.second].xform.ToMatrix(); + } + + tot = mat * tot; + tot = tot + trans; + shapeSkinning[shape].boneWeights[bn.second].bSphereOffset = tot; + shapeSkinning[shape].boneWeights[bn.second].bSphereRadius = d; + + } + return true; } void AnimInfo::SetWeights(const string& shape, const string& boneName, unordered_map& inVertWeights) { @@ -168,9 +239,16 @@ void AnimInfo::SetWeights(const string& shape, const string& boneName, unordered vector verts; refNif->GetVertsForShape(shape, verts); + if (verts.size() == 0) // early out for when the reference nif doesn't contain a matching shape for the incoming weights. + return; + + Vector3 a(FLT_MAX, FLT_MAX, FLT_MAX); Vector3 b(-FLT_MAX, -FLT_MAX, -FLT_MAX); for (auto &w : inVertWeights) { + if (w.first > verts.size()) { // incoming weights have a larger set of possible verts. + return; + } Vector3 v = verts[w.first]; a.x = min(a.x, v.x); a.y = min(a.y, v.y); @@ -192,6 +270,8 @@ void AnimInfo::SetWeights(const string& shape, const string& boneName, unordered shapeSkinning[shape].boneWeights[bid].bSphereOffset = tot; shapeSkinning[shape].boneWeights[bid].bSphereRadius = d; } + // Got all the way here, bounds calculation has been done. + shapeSkinning[shape].bNeedsBoundsCalc = false; } void AnimInfo::WriteToNif(NifFile* nif, bool synchBoneIDs, const string& shapeException) { @@ -225,8 +305,15 @@ void AnimInfo::WriteToNif(NifFile* nif, bool synchBoneIDs, const string& shapeEx SkinTransform xForm; for (auto &shapeBoneList : shapeBones) { + if (shapeBoneList.first == shapeException) + continue; int stype = nif->GetShapeType(shapeBoneList.first); bool bIsFo4 = (stype == BSTRISHAPE || stype == BSSUBINDEXTRISHAPE); + + if (shapeSkinning[shapeBoneList.first].bNeedsBoundsCalc) { + CalcShapeSkinBounds(shapeBoneList.first); + } + unordered_map vertWeights; for (auto &boneName : shapeBoneList.second) { if (!AnimSkeleton::getInstance().GetBoneTransform(boneName, xForm)) @@ -240,10 +327,23 @@ void AnimInfo::WriteToNif(NifFile* nif, bool synchBoneIDs, const string& shapeEx for (auto vw : bw.weights) { vertWeights[vw.first].Add(bid, vw.second); } + AnimBone* bptr = AnimSkeleton::getInstance().GetBonePtr(boneName); + if (!bptr->hasSkinXform) { + wxMessageBox("Warning: Bone information incomplete, exported data will not contain correct BSBoneData entries! Be sure to Load a reference nif prior to export.", "Export warning"); + nif->SetShapeBoneTransform(shapeBoneList.first, bid, bw.xform, bw.bSphereOffset, bw.bSphereRadius); + } + else { + SkinTransform st; + st.rotation[0] = Vector3(bptr->skinRot[0], bptr->skinRot[1], bptr->skinRot[2]); + st.rotation[1] = Vector3(bptr->skinRot[4], bptr->skinRot[5], bptr->skinRot[6]); + st.rotation[2] = Vector3(bptr->skinRot[8], bptr->skinRot[9], bptr->skinRot[10]); + st.translation = bptr->skinTrans; + nif->SetShapeBoneTransform(shapeBoneList.first, bid,st, bw.bSphereOffset, bw.bSphereRadius); + } } - if (AnimSkeleton::getInstance().GetSkinTransform(boneName, xForm)) { - nif->SetShapeBoneTransform(shapeBoneList.first, bid, xForm, bw.bSphereOffset, bw.bSphereRadius); - if (!bIsFo4) { + else { + if (AnimSkeleton::getInstance().GetSkinTransform(boneName, xForm)) { + nif->SetShapeBoneTransform(shapeBoneList.first, bid, xForm, bw.bSphereOffset, bw.bSphereRadius); nif->SetShapeBoneWeights(shapeBoneList.first, bid, bw.weights); } } @@ -252,6 +352,7 @@ void AnimInfo::WriteToNif(NifFile* nif, bool synchBoneIDs, const string& shapeEx for (auto vid : vertWeights) { nif->SetShapeVertWeights(shapeBoneList.first, vid.first, vid.second.boneIds, vid.second.weights); } + } } } @@ -282,11 +383,7 @@ AnimBone& AnimBone::LoadFromNif(NifFile* skeletonNif, int srcBlock, AnimBone* in order = -1; refCount = 0; - vector m33; - m33.push_back(node->rotation[0]); - m33.push_back(node->rotation[1]); - m33.push_back(node->rotation[2]); - localRot.Set(m33); + localRot.Set(node->rotation); localTrans = node->translation; scale = node->scale; @@ -313,8 +410,7 @@ AnimBone& AnimBone::LoadFromNif(NifFile* skeletonNif, int srcBlock, AnimBone* in } int AnimSkeleton::LoadFromNif(const string& fileName) { - NifFile nif; - int error = nif.Load(fileName); + int error = refSkeletonNif.Load(fileName); if (error) { wxLogError("Failed to load skeleton '%s'!", fileName); wxMessageBox(wxString::Format("Failed to load skeleton '%s'!", fileName)); @@ -322,7 +418,7 @@ int AnimSkeleton::LoadFromNif(const string& fileName) { } rootBone = Config.GetCString("Anim/SkeletonRootName"); - int nodeID = nif.GetNodeID(rootBone); + int nodeID = refSkeletonNif.GetNodeID(rootBone); if (nodeID == -1) { wxLogError("Root '%s' not found in skeleton '%s'!", rootBone, fileName); wxMessageBox(wxString::Format("Root '%s' not found in skeleton '%s'!", rootBone, fileName)); @@ -332,7 +428,7 @@ int AnimSkeleton::LoadFromNif(const string& fileName) { if (isValid) allBones.clear(); - AddBone(rootBone).LoadFromNif(&nif, nodeID, nullptr); + AddBone(rootBone).LoadFromNif(&refSkeletonNif, nodeID, nullptr); isValid = true; wxLogMessage("Loaded skeleton '%s' with root '%s'.", fileName, rootBone); return 0; diff --git a/Anim.h b/Anim.h index 2d4f6c78..2397a807 100644 --- a/Anim.h +++ b/Anim.h @@ -54,18 +54,24 @@ class AnimBone { Matrix4 localRot; // rotation offset from parent bone. Vector3 localTrans; // offset from parent bone + bool hasSkinXform; + Matrix4 skinRot; // skinning rotation transform (NOT node transform + Vector3 skinTrans; // skinning translation transform (NOT node transform + int refCount; // reference count of this bone AnimBone() { boneName = "bogus"; boneID = -1; order = -1; isValidBone = false; + hasSkinXform = false; } AnimBone(const string& bn, int bid, int ord) : boneName(bn), boneID(bid), order(ord) { refCount = 0; parent = nullptr; isValidBone = true; + hasSkinXform = false; } AnimBone& LoadFromNif(NifFile* skeletonNif, int srcBlock, AnimBone* parent = nullptr); }; @@ -96,10 +102,18 @@ class AnimWeight { class AnimSkin { public: unordered_map boneWeights; - AnimSkin() { } - AnimSkin(NifFile* loadFromFile, const string& shape, const vector& BoneIndices) { - for (auto &i : BoneIndices) + unordered_map boneNames; + bool bNeedsBoundsCalc; + AnimSkin() : bNeedsBoundsCalc(true) { } + AnimSkin(NifFile* loadFromFile, const string& shape, const vector& BoneIndices) : bNeedsBoundsCalc(true) { + vector idList; + loadFromFile->GetShapeBoneIDList(shape, idList); + for (auto &i : BoneIndices) { boneWeights[i] = AnimWeight(loadFromFile, shape, i); + NiNode* node = (NiNode*)loadFromFile->GetBlock(idList[i]); + boneNames[node->name] = i; + } + bNeedsBoundsCalc = false; } void VertexBones(ushort queryvert, vector& outbones, vector& outWeights) { float wresult; @@ -159,6 +173,7 @@ class AnimInfo { void GetBoneXForm(const string& boneName, SkinTransform& stransform); void SetWeights(const string& shape, const string& boneName, unordered_map& inVertWeights); void SetShapeBoneXForm(const string& shape, const string& boneName, SkinTransform& stransform); + bool CalcShapeSkinBounds(const string& shape); void WriteToNif(NifFile* nif, bool synchBoneIDs = true, const string& shapeException = ""); void RenameShape(const string& shapeName, const string& newShapeName); @@ -174,6 +189,7 @@ class AnimSkeleton { bool allowCustom; public: + NifFile refSkeletonNif; static AnimSkeleton& getInstance() { static AnimSkeleton instance; return instance; diff --git a/BodySlide.vcxproj b/BodySlide.vcxproj index 211b60b7..e1618c92 100644 --- a/BodySlide.vcxproj +++ b/BodySlide.vcxproj @@ -95,7 +95,7 @@ Disabled - ..\wxWidgets\include\msvc;..\wxWidgets\include;%(AdditionalIncludeDirectories) + ..\wxWidgets\include\msvc;..\wxWidgets\include;..\libraries\fbx\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false EnableFastChecks @@ -104,13 +104,13 @@ true - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_d.lib;%(AdditionalDependencies) - ..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_d.lib;libfbxsdk.lib;%(AdditionalDependencies) + ..\libraries\fbx\lib\vs2013\x86\debug;..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) true Windows false libcmt.lib - RequireAdministrator + AsInvoker @@ -138,7 +138,7 @@ MaxSpeed true - ..\wxWidgets\include\msvc;..\wxWidgets\include;%(AdditionalIncludeDirectories) + ..\wxWidgets\include\msvc;..\wxWidgets\include;..\libraries\fbx\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreaded @@ -148,8 +148,8 @@ None - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2.lib;%(AdditionalDependencies) - ..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2.lib;libfbxsdk.lib;%(AdditionalDependencies) + ..\libraries\fbx\lib\vs2013\x86\release;..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) false @@ -195,6 +195,7 @@ + @@ -237,6 +238,7 @@ + @@ -279,6 +281,7 @@ + diff --git a/BodySlide.vcxproj.filters b/BodySlide.vcxproj.filters index 3e041ba9..0fe17932 100644 --- a/BodySlide.vcxproj.filters +++ b/BodySlide.vcxproj.filters @@ -120,6 +120,9 @@ Source Files + + Source Files + @@ -233,6 +236,9 @@ Header Files + + Header Files + @@ -248,5 +254,8 @@ Resource Files + + Resource Files + \ No newline at end of file diff --git a/BodySlide.vcxproj.filters.orig b/BodySlide.vcxproj.filters.orig new file mode 100644 index 00000000..73aac139 --- /dev/null +++ b/BodySlide.vcxproj.filters.orig @@ -0,0 +1,263 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + +<<<<<<< Updated upstream + + Source Files + + +======= + +>>>>>>> Stashed changes + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + +<<<<<<< Updated upstream + + Header Files + + +======= + +>>>>>>> Stashed changes + Header Files + + + + + Resource Files + + + + + Resource Files + + + + + Resource Files + + + Resource Files + + + \ No newline at end of file diff --git a/BodySlide.vcxproj.orig b/BodySlide.vcxproj.orig new file mode 100644 index 00000000..0ad7afae --- /dev/null +++ b/BodySlide.vcxproj.orig @@ -0,0 +1,304 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F7E444AD-893D-4E93-8897-AF050C1C6A48} + BodySlide + Win32Proj + + + + Application + v120 + Unicode + true + false + false + + + Application + v120 + Unicode + true + false + false + + + Application + v120 + Unicode + + + Application + v120 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.61030.0 + + + $(Configuration)\$(Platform)\ + $(ProjectName) Debug + false + $(SolutionDir)$(Configuration)\$(Platform)\ + + + $(ProjectName) $(Platform) Debug + false + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ + + + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ + false + + + false + $(ProjectName) $(Platform) + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ + + + + Disabled + ..\wxWidgets\include\msvc;..\wxWidgets\include;..\libraries\fbx\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level4 + true + + +<<<<<<< Updated upstream + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_d.lib;%(AdditionalDependencies) + ..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) +======= + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;libfbxsdk.lib;SOIL_d.lib;%(AdditionalDependencies) + ..\libraries\fbx\lib\vs2013\x86\debug;..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) +>>>>>>> Stashed changes + true + Windows + false + libcmt.lib + RequireAdministrator + + + + + Disabled + ..\wxWidgets\include\msvc;..\wxWidgets\include;%(AdditionalIncludeDirectories) + WIN64;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebug + Level4 + true + + + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_x64_d.lib;%(AdditionalDependencies) + ..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) + true + Windows + false + libcmt.lib + RequireAdministrator + + + + + MaxSpeed + true +<<<<<<< Updated upstream + ..\wxWidgets\include\msvc;..\wxWidgets\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) +======= + ..\wxWidgets\include\msvc;..\wxWidgets\include;..\libraries\fbx\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) +>>>>>>> Stashed changes + MultiThreaded + + + Level4 + true + None + + +<<<<<<< Updated upstream + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2.lib;%(AdditionalDependencies) + ..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) +======= + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;libfbxsdk.lib;SOIL.lib;%(AdditionalDependencies) + ..\libraries\fbx\lib\vs2013\x86\release;..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) +>>>>>>> Stashed changes + false + + + false + Windows + true + true + + + RequireAdministrator + + + + + MaxSpeed + true + ..\wxWidgets\include\msvc;..\wxWidgets\include;%(AdditionalIncludeDirectories) + WIN64;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + Level4 + true + None + + + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_x64.lib;%(AdditionalDependencies) + ..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) + false + + + false + Windows + true + true + + + RequireAdministrator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index f36631d6..386fe81d 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -81,6 +81,7 @@ bool BodySlideApp::OnInit() { wxInitAllImageHandlers(); + preview = nullptr; sliderView = nullptr; previewBaseNif = nullptr; diff --git a/FBXWrangler.cpp b/FBXWrangler.cpp new file mode 100644 index 00000000..d5285139 --- /dev/null +++ b/FBXWrangler.cpp @@ -0,0 +1,465 @@ +#include "FBXWrangler.h" +#include "NifFile.h" + + +FBXWrangler::FBXWrangler(): pSdkManager(nullptr), pCurrentScene(nullptr) { + + pSdkManager = FbxManager::Create(); + + FbxIOSettings* ios = FbxIOSettings::Create(pSdkManager, IOSROOT); + pSdkManager->SetIOSettings(ios); + +} + + +FBXWrangler::~FBXWrangler() +{ + if (pCurrentScene) + CloseScene(); + + if (pSdkManager) + pSdkManager->Destroy(); +} + +void FBXWrangler::NewScene() { + if (pCurrentScene) + CloseScene(); + pCurrentScene = FbxScene::Create(pSdkManager, "OutfitStudioScene"); +} + +void FBXWrangler::CloseScene() { + if (pCurrentScene) + pCurrentScene->Destroy(); + + pCurrentScene = nullptr; +} + +void FBXWrangler::AddMesh(mesh* m) { + FbxMesh* lm = FbxMesh::Create(pSdkManager, m->shapeName.c_str()); + + FbxGeometryElementNormal* normElem = lm->CreateElementNormal(); + normElem->SetMappingMode(FbxLayerElement::eByControlPoint); + normElem->SetReferenceMode(FbxLayerElement::eDirect); + + FbxGeometryElementUV* lUVDiffuseElement = lm->CreateElementUV(string(m->shapeName+"UV").c_str()); + lUVDiffuseElement->SetMappingMode(FbxGeometryElement::eByControlPoint); + lUVDiffuseElement->SetReferenceMode(FbxGeometryElement::eDirect); + + lm->InitControlPoints(m->nVerts); + FbxVector4* cp = lm->GetControlPoints(); + + for (int i = 0; i < m->nVerts; i++) { + cp[i] = FbxVector4(m->verts[i].x, m->verts[i].y, m->verts[i].z); + normElem->GetDirectArray().Add(FbxVector4(m->verts[i].nx, m->verts[i].ny, m->verts[i].nz)); + lUVDiffuseElement->GetDirectArray().Add(FbxVector2(m->texcoord[i].u, m->texcoord[i].v)); + } + + + for (int i = 0; i < m->nTris; i++) { + lm->BeginPolygon(); + lm->AddPolygon(m->tris[i].p1); + lm->AddPolygon(m->tris[i].p2); + lm->AddPolygon(m->tris[i].p3); + lm->EndPolygon(); + } + + FbxNode* rootNode = pCurrentScene->GetRootNode(); + + FbxNode* mNode = FbxNode::Create(pSdkManager,m->shapeName.c_str() ); + + rootNode->AddChild(mNode); + + mNode->SetNodeAttribute(lm); + + mNode->LclScaling.Set(FbxVector4(1.0, 1.0, 1.0)); + mNode->LclTranslation.Set(FbxVector4(0.0, 0.0, 0.0)); + +} + +void FBXWrangler::AddGeometry(const string& shapeName, const vector* verts, const vector* norms, vector* tris, const vector* uvs) { + + FbxMesh* lm = FbxMesh::Create(pSdkManager, shapeName.c_str()); + + FbxGeometryElementNormal* normElem = lm->CreateElementNormal(); + normElem->SetMappingMode(FbxLayerElement::eByControlPoint); + normElem->SetReferenceMode(FbxLayerElement::eDirect); + + FbxGeometryElementUV* lUVDiffuseElement = lm->CreateElementUV(string(shapeName+"UV").c_str()); + lUVDiffuseElement->SetMappingMode(FbxGeometryElement::eByControlPoint); + lUVDiffuseElement->SetReferenceMode(FbxGeometryElement::eDirect); + + lm->InitControlPoints(verts->size()); + FbxVector4* cp = lm->GetControlPoints(); + + for (int i = 0; i < verts->size(); i++) { + cp[i] = FbxVector4((*verts)[i].x, (*verts)[i].y, (*verts)[i].z); + normElem->GetDirectArray().Add(FbxVector4((*norms)[i].x, (*norms)[i].y, (*norms)[i].z)); + lUVDiffuseElement->GetDirectArray().Add(FbxVector2((*uvs)[i].u, (*uvs)[i].v)); + } + + + for (auto t:(*tris)) { + lm->BeginPolygon(); + lm->AddPolygon(t.p1); + lm->AddPolygon(t.p2); + lm->AddPolygon(t.p3); + lm->EndPolygon(); + } + + FbxNode* rootNode = pCurrentScene->GetRootNode(); + + FbxNode* mNode = FbxNode::Create(pSdkManager,shapeName.c_str() ); + + rootNode->AddChild(mNode); + + mNode->SetNodeAttribute(lm); + + // For Blender import + //mNode->LclScaling.Set(FbxVector4(0.1, 0.1, 0.1)); + //mNode->LclTranslation.Set(FbxVector4(0.0, 0.0, 0.0)); + + // For Maya Import + mNode->LclScaling.Set(FbxVector4(1,1,1)); + mNode->LclRotation.Set(FbxVector4(-90, 0, 0)); + mNode->LclTranslation.Set(FbxVector4(0, 120, 0)); + +} + +void FBXWrangler::AddSkeleton(NifFile* skeletonNif) { + + string skelName = "NifSkeleton"; + + FbxSkeleton* skelly = FbxSkeleton::Create(pCurrentScene, skelName.c_str()); + skelly->SetSkeletonType(FbxSkeleton::eRoot); + FbxNode* skellynode = FbxNode::Create(pCurrentScene, skelName.c_str()); + skellynode->SetNodeAttribute(skelly); + //skellynode->SetRotationOrder(FbxNode::eSourcePivot, eEulerZYX); + skellynode->LclTranslation.Set(FbxVector4(0.0, 0.0, 0.0)); + //skellynode->LclRotation.Set(FbxVector4(0.0, 0.0, 0.0)); + + float rx, ry, rz; + + NiNode* root = (NiNode*)skeletonNif->GetBlock(skeletonNif->GetNodeID("Root")); + NiNode* COM = (NiNode*)skeletonNif->GetBlock(skeletonNif->GetNodeID("COM")); + + FbxNode* parentNode = skellynode; + if (root) { + FbxSkeleton* rootbone = FbxSkeleton::Create(pCurrentScene, root->name.c_str()); + rootbone->SetSkeletonType(FbxSkeleton::eLimbNode); + rootbone->Size.Set(1.0f); + FbxNode* rootboneNode = FbxNode::Create(pCurrentScene, root->name.c_str()); + rootboneNode->SetNodeAttribute(rootbone); + root->rotToEulerDegrees(rx, ry, rz); + rootboneNode->LclRotation.Set(FbxVector4(rx, ry, rz)); + rootboneNode->LclTranslation.Set(FbxVector4(root->translation.x, root->translation.y, root->translation.z)); + //rootboneNode->SetRotationOrder(FbxNode::eSourcePivot, eEulerZYX); + parentNode->AddChild(rootboneNode); + parentNode = rootboneNode; + } + + if (COM) { + FbxSkeleton* COMBone = FbxSkeleton::Create(pCurrentScene, COM->name.c_str()); + COMBone->SetSkeletonType(FbxSkeleton::eLimbNode); + COMBone->Size.Set(1.0f); + FbxNode* COMBoneNode = FbxNode::Create(pCurrentScene, COM->name.c_str()); + COMBoneNode->SetNodeAttribute(COMBone); + COM->rotToEulerDegrees(rx, ry, rz); + COMBoneNode->LclRotation.Set(FbxVector4(rx, ry, rz)); + COMBoneNode->LclTranslation.Set(FbxVector4(COM->translation.y, COM->translation.z, COM->translation.x)); + //COMBoneNode->SetRotationOrder(FbxNode::eSourcePivot, eEulerZYX); + parentNode->AddChild(COMBoneNode); + parentNode = COMBoneNode; + + } + + NiNode* top = COM; + // likely a mesh nif with non hierarchical bone nodes + if (!COM) { + top = (NiNode*)skeletonNif->GetBlock(0); + } + + vector boneNodes = skeletonNif->GetChildren(top); + for (auto bn:boneNodes) { + parentNode->AddChild(AddLimb(skeletonNif, bn)); + } + + + pCurrentScene->GetRootNode()->AddChild(skellynode); + +} + +FbxNode* FBXWrangler::AddLimb(NifFile* skeletonNif, NiNode* nifBone) { + + float rx, ry, rz; + static map boneNames; + if (boneNames.find(nifBone->name) == boneNames.end()) { + boneNames[nifBone->name] = 1; + } + else { + boneNames[nifBone->name]++; + } + + Vector3 myTranslation = nifBone->translation; + FbxSkeleton* myBone = FbxSkeleton::Create(pCurrentScene, nifBone->name.c_str()); + myBone->SetSkeletonType(FbxSkeleton::eLimbNode); + myBone->Size.Set(1.0f); + FbxNode* myNode = FbxNode::Create(pCurrentScene, nifBone->name.c_str()); + myNode->SetNodeAttribute(myBone); + nifBone->rotToEulerDegrees(rx, ry, rz); + myNode->LclRotation.Set(FbxVector4(rx, ry, rz)); + myNode->LclTranslation.Set(FbxVector4(myTranslation.x, myTranslation.y, myTranslation.z)); + //myNode->SetRotationOrder(FbxNode::eSourcePivot, eEulerZYX); + + vector boneNodes = skeletonNif->GetChildren(nifBone); + for (auto bn:boneNodes) { + myNode->AddChild(AddLimb(skeletonNif, bn)); + } + + + return myNode; +} + +void FBXWrangler::AddNif(NifFile* meshNif, const string& shapeName, bool addSkeleton) { + + if (addSkeleton) { + AddSkeleton(meshNif); + } + + vector shapeList; + + meshNif->GetShapeList(shapeList); + for (auto s : shapeList) { + if (shapeName == "" || s == shapeName) { + vector tris; + if (meshNif->GetTrisForShape(s, &tris)) { + const vector* verts = meshNif->GetRawVertsForShape(s); + const vector* norms = meshNif->GetNormalsForShape(s,false); + const vector* uvs = meshNif->GetUvsForShape(s); + AddGeometry(s, verts, norms, &tris, uvs); + } + } + } + +} + +void FBXWrangler::AddSkinning(AnimInfo* anim, const string& shapeName) { + FbxNode* rootNode = pCurrentScene->GetRootNode(); + FbxNode* skelNode = rootNode->FindChild("NifSkeleton"); + if (!skelNode) + return; + + for (auto shapeskin : anim->shapeSkinning) { + if (shapeName != "" && shapeskin.first != shapeName) { + continue; + } + string curShape = shapeskin.first; + auto askin = shapeskin.second; + + // FbxPose* bindPose = FbxPose::Create(pCurrentScene, "BindPose"); + // bindPose->SetIsBindPose(true); + FbxNode* shapeNode = rootNode->FindChild(curShape.c_str()); + if (shapeNode) { + // bindPose->Add(shapeNode, shapeNode->EvaluateGlobalTransform()); + } + + + FbxSkin* skin = FbxSkin::Create(pCurrentScene, string(curShape + "_sk").c_str()); + unordered_map outWeights; + + for (auto bn : anim->shapeBones[curShape]) { + FbxNode* jointNode = skelNode->FindChild(bn.c_str()); + if (jointNode) { + FbxCluster* aCluster = FbxCluster::Create(pCurrentScene, string(bn + "_sk").c_str()); + aCluster->SetLink(jointNode); + aCluster->SetLinkMode(FbxCluster::eTotalOne); + int bi = anim->GetShapeBoneIndex(curShape, bn); + anim->GetWeights(curShape, bn, outWeights); + //for (auto vw : askin.boneWeights[bi].weights) { + for (auto vw: outWeights) { + aCluster->AddControlPointIndex(vw.first, vw.second); + } + FbxMatrix xforMat = jointNode->EvaluateGlobalTransform(); + // bindPose->Add(jointNode, xforMat); + skin->AddCluster(aCluster); + } + } + + ((FbxMesh*)shapeNode->GetNodeAttribute())->AddDeformer(skin); + } +// pCurrentScene->AddPose(bindPose); +} + +bool FBXWrangler::ExportScene(const std::string& fileName) { + + int lMajor, lMinor, lRevision; + + FbxExporter* iExporter = FbxExporter::Create(pSdkManager, ""); + + if (iExporter->Initialize(fileName.c_str(), -1, pSdkManager->GetIOSettings()) == false) { + iExporter->Destroy(); + return false; + } + + FbxManager::GetFileFormatVersion(lMajor, lMinor, lRevision); + + auto ios = (pSdkManager->GetIOSettings()); + + // Export options determine what kind of data is to be imported. + // The default (except for the option eEXPORT_TEXTURE_AS_EMBEDDED) + // is true, but here we set the options explicitly. + ios->SetBoolProp(EXP_FBX_MATERIAL, true); + ios->SetBoolProp(EXP_FBX_TEXTURE, true); + ios->SetBoolProp(EXP_FBX_EMBEDDED, false); + ios->SetBoolProp(EXP_FBX_SHAPE, true); + ios->SetBoolProp(EXP_FBX_GOBO, true); + ios->SetBoolProp(EXP_FBX_ANIMATION, true); + ios->SetBoolProp(EXP_FBX_GLOBAL_SETTINGS, true); + + iExporter->SetFileExportVersion(FBX_2014_00_COMPATIBLE); + + pSdkManager->CreateMissingBindPoses(pCurrentScene); + + FbxAxisSystem axis (FbxAxisSystem::eMax); + axis.ConvertScene(pCurrentScene); + + // Export the scene. + bool status = iExporter->Export(pCurrentScene); + + // Destroy the exporter. + iExporter->Destroy(); + + return status; + +} + +bool FBXWrangler::ImportScene(const std::string& filenName) { + + FbxIOSettings* ios = pSdkManager->GetIOSettings(); + ios->SetBoolProp(IMP_FBX_MATERIAL, true); + ios->SetBoolProp(IMP_FBX_TEXTURE, true); + ios->SetBoolProp(IMP_FBX_LINK, false); + ios->SetBoolProp(IMP_FBX_SHAPE, true); + ios->SetBoolProp(IMP_FBX_GOBO, true); + ios->SetBoolProp(IMP_FBX_ANIMATION, true); + ios->SetBoolProp(IMP_FBX_GLOBAL_SETTINGS, true); + + + FbxImporter* iImporter = FbxImporter::Create(pSdkManager, ""); + + if (iImporter->Initialize(filenName.c_str(), -1, ios) == false) { + iImporter->Destroy(); + return false; + } + + NewScene(); + + bool status = iImporter->Import(pCurrentScene); + + iImporter->Destroy(); + + if (!status) + return false; + + return LoadMeshes(); + +} + +bool FBXWrangler::LoadMeshes() { + if (!pCurrentScene) + return false; + + FbxNode* root = pCurrentScene->GetRootNode(); + + for (int i = 0; i < root->GetChildCount(); i++) { + FbxNode* c = root->GetChild(i); + + if (c->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eMesh) { + FBXShape meshData; + FbxMesh* m = (FbxMesh*)c->GetNodeAttribute(); + + if (!m->IsTriangleMesh()) { + FbxGeometryConverter converter(pSdkManager); + m = (FbxMesh*)converter.Triangulate((FbxNodeAttribute*)m, true); + } + + meshData.name = c->GetName(); + meshData.numverts = m->GetControlPointsCount(); + meshData.numtris = m->GetPolygonCount(); + + for (int v = 0; v < meshData.numverts; v++) { + FbxVector4 vert = m->GetControlPointAt(v); + meshData.verts.emplace_back(vert.mData[0], vert.mData[1], vert.mData[2]); + if (m->GetElementUVCount() && m->GetElementUV(0)->GetMappingMode() == FbxGeometryElement::eByControlPoint) { + int uindex = v; + if (m->GetElementUV(0)->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { + uindex = m->GetElementUV(0)->GetIndexArray().GetAt(v); + } + meshData.uvs.emplace_back(m->GetElementUV(0)->GetDirectArray().GetAt(uindex).mData[0], + m->GetElementUV(0)->GetDirectArray().GetAt(uindex).mData[1]); + } + + if (m->GetElementNormalCount() && m->GetElementNormal(0)->GetMappingMode() == FbxGeometryElement::eByControlPoint) { + meshData.normals.emplace_back(m->GetElementNormal(0)->GetDirectArray().GetAt(v).mData[0], + m->GetElementNormal(0)->GetDirectArray().GetAt(v).mData[1], + m->GetElementNormal(0)->GetDirectArray().GetAt(v).mData[2]); + } + } + + int p1, p2, p3;const char* uvn = m->GetElementUV(0)->GetName(); + meshData.uvs.resize(meshData.numverts); + FbxVector2 uv; + bool hasuv; + + for (int t = 0; t < meshData.numtris; t++) { + if (m->GetPolygonSize(t) != 3) + continue; + + p1 = m->GetPolygonVertex(t, 0); + p2 = m->GetPolygonVertex(t, 1); + p3 = m->GetPolygonVertex(t, 2); + meshData.tris.emplace_back(p1,p2,p3); + + if (m->GetElementUVCount() && m->GetElementUV(0)->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) { + + m->GetPolygonVertexUV(t, 0, uvn, uv, hasuv); + meshData.uvs[p1] = Vector2(uv.mData[0], uv.mData[1]); + + m->GetPolygonVertexUV(t, 1, uvn, uv, hasuv); + meshData.uvs[p2] = Vector2(uv.mData[0], uv.mData[1]); + + m->GetPolygonVertexUV(t, 2, uvn, uv, hasuv); + meshData.uvs[p3] = Vector2(uv.mData[0], uv.mData[1]); + + } + + } + + for (int iskin = 0; iskin < m->GetDeformerCount(FbxDeformer::eSkin); iskin++) { + FbxSkin* skin = (FbxSkin*)m->GetDeformer(iskin,FbxDeformer::eSkin); + + for (int icluster = 0; icluster < skin->GetClusterCount(); icluster++) { + FbxCluster* cluster = skin->GetCluster(icluster); + if (!cluster->GetLink()) + continue; + string bn = cluster->GetLink()->GetName(); + meshData.boneNames.insert(bn); + for (int iv = 0; iv < cluster->GetControlPointIndicesCount(); iv++) { + int v = cluster->GetControlPointIndices()[iv]; + float w = cluster->GetControlPointWeights()[iv]; + meshData.boneSkin[bn].add(v, w); + } + } + + } + + + + inShapes[meshData.name] = meshData; + + } + + } + + return true; + +} diff --git a/FBXWrangler.h b/FBXWrangler.h new file mode 100644 index 00000000..09d4d511 --- /dev/null +++ b/FBXWrangler.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include +#include "mesh.h" +#include "NifFile.h" +#include "Anim.h" + + +class FBXShape { +public: + class FBXSkin { + public: + unordered_map vertweights; + void add(ushort vert, float wt) { + vertweights[vert] = wt; + } + }; + string name; + int numverts; + int numtris; + vector verts; + vector tris; + vector uvs; + vector normals; + + unordered_map boneSkin; + set boneNames; + +}; + +class FBXWrangler +{ + FbxManager* pSdkManager; + FbxScene* pCurrentScene; + + map inShapes; +public: + FBXWrangler(); + ~FBXWrangler(); + void GetShapeNames(vector& outNames) { + for (auto is : inShapes) { + outNames.push_back(is.first); + } + } + + FBXShape* InShape(const string& shapeName) { + return &(inShapes[shapeName]); + } + + void NewScene(); + + void CloseScene(); + + void AddMesh(mesh * m); + void AddSkeleton(NifFile* skeletonNif); + // Recursively add bones to the skeleton in a depth-first manner + FbxNode* AddLimb(NifFile* skeletonNif, NiNode* nifBone); + + void AddNif(NifFile* meshNif, const string& shapeName = "", bool addSkeleton=true); + void AddSkinning(AnimInfo* anim, const string& shapeName = ""); + void AddGeometry(const string& name, const vector* verts, const vector* norms, vector* tris, const vector* uvs); + + bool ExportScene(const std::string& fileName); + + bool ImportScene(const std::string& filenName); + + bool LoadMeshes(); + +}; + diff --git a/GLSurface.cpp b/GLSurface.cpp index 0026d5b7..421aff04 100644 --- a/GLSurface.cpp +++ b/GLSurface.cpp @@ -1164,6 +1164,7 @@ void GLSurface::AddMeshFromNif(NifFile* nif, string shapeName, Vector3* color, b const vector* nifNorms = nullptr; const vector* nifUvs = nif->GetUvsForShape(shapeName); + nifNorms = nif->GetNormalsForShape(shapeName, false); mesh* m = new mesh(); @@ -1178,7 +1179,7 @@ void GLSurface::AddMeshFromNif(NifFile* nif, string shapeName, Vector3* color, b } m->shapeName = shapeName; - m->smoothSeamNormals = smoothNormalSeams; + m->smoothSeamNormals = false; // smoothNormalSeams; m->nVerts = nifVerts.size(); m->verts = new Vertex[m->nVerts]; @@ -1193,9 +1194,9 @@ void GLSurface::AddMeshFromNif(NifFile* nif, string shapeName, Vector3* color, b m->verts[i].x = (nifVerts)[i].x / -10.0f; m->verts[i].z = (nifVerts)[i].y / 10.0f; m->verts[i].y = (nifVerts)[i].z / 10.0f; - //m->verts[i].x = (nifVerts)[i].x / 10.0f; - //m->verts[i].y = (nifVerts)[i].y / 10.0f; - //m->verts[i].z = (nifVerts)[i].z / 10.0f; + /*m->verts[i].x = (nifVerts)[i].x / 10.0f; + m->verts[i].y = (nifVerts)[i].y / 10.0f; + m->verts[i].z = (nifVerts)[i].z / 10.0f;*/ m->verts[i].indexRef = i; } @@ -1271,9 +1272,33 @@ void GLSurface::AddMeshFromNif(NifFile* nif, string shapeName, Vector3* color, b m->verts[i].nz = (*nifNorms)[i].y; m->verts[i].ny = (*nifNorms)[i].z; } + + // virtually Weld verts across uv seams + kd_matcher matcher(m->verts, m->nVerts); + for (int i = 0; i < matcher.matches.size(); i++) { + Vertex* a = matcher.matches[i].first; + Vertex* b = matcher.matches[i].second; + m->weldVerts[a->indexRef].push_back(b->indexRef); + m->weldVerts[b->indexRef].push_back(a->indexRef); + } } //nifNorms = nif->GetNormalsForShape(shapeName); + //const vector* tans = nif->GetTangentsForShape(shapeName); + //const vector* bits = nif->GetBitangentsForShape(shapeName); + //AddVisNorms(m, nifNorms, "Norms", Vector3(0.0f, 0, 1.0f)); + //AddVisNorms(m, tans, "tans", Vector3(0.0f, 1.0f, 0.0f)); + //AddVisNorms(m, bits, "bits", Vector3(1.0f, 0.0f, 0.0f)); + // + //vector * n; + //vector * b; + //vector * t; + + //nif->CalcTangentsForShape(shapeName, &n, &t, &b); + //AddVisNorms(m, n, "Norms", Vector3(0.0f, 0, 1.0f)); + //AddVisNorms(m, t, "tans", Vector3(0.0f, 1.0f, 0.0f)); + //AddVisNorms(m, b, "bits2", Vector3(0.0f, 1.0f, 1.0f)); + //m->ColorFill(Vector3(0, 0, 0)); //for (int i = 0; i < m->nVerts; i++) { diff --git a/Mesh.cpp b/Mesh.cpp index ba4c1593..23d54940 100644 --- a/Mesh.cpp +++ b/Mesh.cpp @@ -298,6 +298,10 @@ void mesh::SmoothNormals() { Vector3 tn; for (int v = 0; v < nVerts; v++) { norm.x = norm.y = norm.z = 0.0f; + if (!smoothSeamNormals && weldVerts.find(v)!= weldVerts.end()) { + // if smooth seams is off, don't update seam normals to preserve continuity for normal mapping + continue; + } for (auto &t : vertTris[v]) { tris[t].trinormal(verts, &tn); norm += tn; diff --git a/NifBlock.cpp b/NifBlock.cpp index 16c07e10..6c241b11 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -41,6 +41,9 @@ NiHeader::NiHeader() { numStrings = 0; blocks = nullptr; blockType = NIHEADER; + exportInfo1.outputNull = true; + exportInfo2.outputNull = true; + exportInfo3.outputNull = true; } void NiHeader::Clear() { @@ -86,7 +89,7 @@ void NiHeader::Get(fstream& file) { return; } - //file >> unk1; + //file >> bitangentY; unk1 = 10; file >> version1 >> version2 >> version3 >> version4; file >> endian; @@ -139,7 +142,7 @@ void NiHeader::Put(fstream& file) { } file.write((char*)&numBlockTypes, 2); for (int i = 0; i < numBlockTypes; i++) - blockTypes[i].Put(file, 4); + blockTypes[i].Put(file, 4,false); for (int i = 0; i < numBlocks; i++) file.write((char*)&blockIndex[i], 2); @@ -150,7 +153,7 @@ void NiHeader::Put(fstream& file) { file.write((char*)&numStrings, 4); file.write((char*)&maxStringLen, 4); for (int i = 0; i < numStrings; i++) - strings[i].Put(file, 4); + strings[i].Put(file, 4,false); file.write((char*)&unkInt2, 4); } @@ -165,28 +168,32 @@ NiString::NiString(fstream& file, int szSize, bool wantNullOutput) { Get(file, szSize); } -void NiString::Put(fstream& file, int szSize) { +void NiString::Put(fstream& file, int szSize, bool wantNullOutput) { if (szSize == 1) { byte smSize = str.length(); - if (!smSize && outputNull) - smSize = 1; + //if (!smSize && outputNull) + if (wantNullOutput) + smSize += 1; file.write((char*)&smSize, 1); } else if (szSize == 2) { ushort medSize = str.length(); - if (!medSize && outputNull) - medSize = 1; + //if (!medSize && outputNull) + if (wantNullOutput) + medSize += 1; file.write((char*)&medSize, 2); } else if (szSize == 4) { uint bigSize = str.length(); - if (!bigSize && outputNull) - bigSize = 1; + //if (!bigSize && outputNull) + if (wantNullOutput) + bigSize += 1; file.write((char*)&bigSize, 4); } file.write(str.c_str(), str.length()); - if (str.length() == 0 && outputNull) + //if (str.length() == 0 && outputNull) + if (wantNullOutput) file.put(0); } @@ -567,12 +574,40 @@ int NiNode::CalcBlockSize() { return blockSize; } -BSTriShape::BSTriShape(fstream& file, NiHeader& hdr, int blockindex) { +BSTriShape::BSTriShape(NiHeader& hdr) { + NiAVObject::Init(); + blockType = BSTRISHAPE; + header = &hdr; + + memset(unkProps, 0, sizeof(float)* 4); + skinInstanceRef = 0xFFFFFFFF; + shaderPropertyRef = 0xFFFFFFFF; + alphaPropertyRef = 0xFFFFFFFF; + + // flags for vert data look to be stored in here. byte 0 or byte 6 specifically look promising . + // using byte 6 currently, bit 3 indicating sub index data, bit 2 indicating the presence of color data. bit 1 indicating presence of normal data + vertFlags[0] = 0x5; + vertFlags[1] = 0x2; + vertFlags[2] = 0x43; + vertFlags[3] = 0x50; + vertFlags[4] = 0x0; + vertFlags[5] = 0xB0; + vertFlags[6] = 0x1; + vertFlags[7] = 0x0; + numTris = 0; + numverts = 0; + datasize = 0; + vertRecSize = 20; // size of vertex structure calculated with (datasize - (numtris*6)) / numverts; + + CalcBlockSize(); +} + +BSTriShape::BSTriShape(fstream& file, NiHeader& hdr) { NiAVObject::Init(); blockType = BSTRISHAPE; header = &hdr; - blockSize = header->blockSizes[blockindex]; Get(file); + CalcBlockSize(); } void BSTriShape::Get(fstream& file) { @@ -606,7 +641,7 @@ void BSTriShape::Get(fstream& file) { file.read((char*)&skinInstanceRef, 4); file.read((char*)&shaderPropertyRef, 4); - file.read((char*)&unkRef, 4); + file.read((char*)&alphaPropertyRef, 4); for (int i = 0; i < 8; i++) { file.read((char*)&vertFlags[i], 1); } @@ -629,7 +664,7 @@ void BSTriShape::Get(fstream& file) { vertData[i].vert.z = h2float(shortData); file.read((char*)&shortData, 2); - vertData[i].dotNormal = h2float(shortData); + vertData[i].bitangentX = h2float(shortData); file.read((char*)&shortData, 2); vertData[i].uv.u = h2float(shortData); @@ -641,12 +676,12 @@ void BSTriShape::Get(fstream& file) { file.read((char*)&vertData[i].normal[j], 1); } - file.read((char*)&vertData[i].unk1, 1); + file.read((char*)&vertData[i].bitangentY, 1); for (int j = 0; j < 3; j++) { file.read((char*)&vertData[i].tangent[j], 1); } - file.read((char*)&vertData[i].unk2, 1); + file.read((char*)&vertData[i].bitangentZ, 1); } if (vertFlags[6] & 0x2) { @@ -708,7 +743,7 @@ void BSTriShape::Put(fstream& file) { file.write((char*)&skinInstanceRef, 4); file.write((char*)&shaderPropertyRef, 4); - file.write((char*)&unkRef, 4); + file.write((char*)&alphaPropertyRef, 4); for (int i = 0; i < 8; i++) { file.write((char*)&vertFlags[i], 1); } @@ -730,7 +765,7 @@ void BSTriShape::Put(fstream& file) { shortData = float2h(vertData[i].vert.z); file.write((char*)&shortData, 2); - shortData = float2h(vertData[i].dotNormal); + shortData = float2h(vertData[i].bitangentX); file.write((char*)&shortData, 2); shortData = float2h(vertData[i].uv.u); @@ -745,13 +780,13 @@ void BSTriShape::Put(fstream& file) { file.write((char*)&vertData[i].normal[j], 1); } - file.write((char*)&vertData[i].unk1, 1); + file.write((char*)&vertData[i].bitangentY, 1); for (int j = 0; j < 3; j++) { file.write((char*)&vertData[i].tangent[j], 1); } - file.write((char*)&vertData[i].unk2, 1); + file.write((char*)&vertData[i].bitangentZ, 1); } if (vertFlags[6] & 0x2) { @@ -779,24 +814,57 @@ void BSTriShape::Put(fstream& file) { void BSTriShape::notifyBlockDelete(int blockID) { NiObjectNET::notifyBlockDelete(blockID); + if (skinInstanceRef == blockID) + skinInstanceRef = 0xFFFFFFFF; + else if (skinInstanceRef > blockID) + skinInstanceRef--; + + if (shaderPropertyRef == blockID) + shaderPropertyRef = 0xFFFFFFFF; + else if (shaderPropertyRef > blockID) + shaderPropertyRef--; + } void BSTriShape::notifyBlockSwap(int blockIndexLo, int blockIndexHi) { NiObjectNET::notifyBlockSwap(blockIndexLo, blockIndexHi); + if (skinInstanceRef == blockIndexLo) + skinInstanceRef = blockIndexHi; + else if (skinInstanceRef == blockIndexHi) + skinInstanceRef = blockIndexLo; + if (shaderPropertyRef == blockIndexLo) + shaderPropertyRef = blockIndexHi; + else if (shaderPropertyRef == blockIndexHi) + shaderPropertyRef = blockIndexLo; } int BSTriShape::CalcBlockSize() { - blockSize = 118 + 6 * numTris + 32 * numverts; + blockSize = 118 + 6 * numTris; + + int vdataSize = 12; + if (vertFlags[6] & 0x1) { //normals + vdataSize += 8; + } + + if (vertFlags[6] & 0x2) { //colors + vdataSize += 4; + } + + if (vertFlags[6] & 0x4) { //skinning + vdataSize += 12; + + } + blockSize += vdataSize * numverts; return blockSize; } -const vector* BSTriShape::GetRawVerts() { +const vector* BSTriShape::GetRawVerts(bool xform) { rawverts.clear(); rawverts.resize(numverts); for (int i = 0; i < numverts; i++) { @@ -807,7 +875,7 @@ const vector* BSTriShape::GetRawVerts() { } -const vector* BSTriShape::GetNormalData() { +const vector* BSTriShape::GetNormalData(bool xform) { rawnorms.clear(); rawnorms.resize(numverts); for (int i = 0; i < numverts; i++) { @@ -820,34 +888,70 @@ const vector* BSTriShape::GetNormalData() { float y = q2; float z = q3; - rawnorms[i].x = -x; - rawnorms[i].z = y; - rawnorms[i].y = z; + if (xform) { + rawnorms[i].x = -x; + rawnorms[i].z = y; + rawnorms[i].y = z; + } + else { + rawnorms[i].x = x; + rawnorms[i].z = z; + rawnorms[i].y = y; + } } return &rawnorms; } -const vector* BSTriShape::GetTangentData() { +const vector* BSTriShape::GetTangentData(bool xform) { rawtangents.clear(); rawtangents.resize(numverts); for (int i = 0; i < numverts; i++) { float q6 = (((float)vertData[i].tangent[0]) / 255.0f) *2.0f - 1.0f; float q7 = (((float)vertData[i].tangent[1]) / 255.0f) *2.0f - 1.0f; float q8 = (((float)vertData[i].tangent[2]) / 255.0f) *2.0f - 1.0f; - float x = q6; float y = q7; float z = q8; - rawtangents[i].x = -x; - rawtangents[i].z = y; - rawtangents[i].y = z; + if (xform) { + rawtangents[i].x = -x; + rawtangents[i].z = y; + rawtangents[i].y = z; + } + else { + rawtangents[i].x = x; + rawtangents[i].z = z; + rawtangents[i].y = y; + } } return &rawtangents; } +const vector* BSTriShape::GetBitangentData(bool xform) { + rawBitangents.clear(); + rawBitangents.resize(numverts); + for (int i = 0; i < numverts; i++) { + float x = (vertData[i].bitangentX); + float y = (((float)vertData[i].bitangentY) / 255.0f) *2.0f - 1.0f; + float z = (((float)vertData[i].bitangentZ) / 255.0f) *2.0f - 1.0f; + + + if (xform) { + rawBitangents[i].x = -x; + rawBitangents[i].z = y; + rawBitangents[i].y = z; + } + else { + rawBitangents[i].x = x; + rawBitangents[i].z = z; + rawBitangents[i].y = y; + } + } + return &rawBitangents; +} + const vector* BSTriShape::GetUVData() { rawuvs.clear(); rawuvs.resize(numverts); @@ -859,13 +963,304 @@ const vector* BSTriShape::GetUVData() { } +void BSTriShape::calcTangentSpace(vector** outNorms, vector** outTangents, vector** outBitangents, bool transform) { + + GetNormalData(false); + + vector tan1; + vector tan2; + tan1.resize(numverts); + tan2.resize(numverts); + + + for (int i = 0; i < triangles.size(); i++) { + int i1 = triangles[i].p1; + int i2 = triangles[i].p2; + int i3 = triangles[i].p3; + + Vector3 v1 = vertData[i1].vert; + Vector3 v2 = vertData[i2].vert; + Vector3 v3 = vertData[i3].vert; + + Vector2 w1 = vertData[i1].uv; + Vector2 w2 = vertData[i2].uv; + Vector2 w3 = vertData[i3].uv; + + float x1 = v2.x - v1.x; + float x2 = v3.x - v1.x; + float y1 = v2.y - v1.y; + float y2 = v3.y - v1.y; + float z1 = v2.z - v1.z; + float z2 = v3.z - v1.z; + + float s1 = w2.u - w1.u; + float s2 = w3.u - w1.u; + float t1 = w2.v - w1.v; + float t2 = w3.v - w1.v; + + float r = (s1 * t2 - s2 * t1); + r = (r >= 0.0f ? +1.0f : -1.0f); + + Vector3 sdir = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); + Vector3 tdir = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); + + tan1[i1] += tdir; + tan1[i2] += tdir; + tan1[i3] += tdir; + + tan2[i1] += sdir; + tan2[i2] += sdir; + tan2[i3] += sdir; + } + + rawBitangents.resize(numverts); + rawtangents.resize(numverts); + + for (int i = 0; i < numverts; i++) { + Vector3 n = rawnorms[i]; + + rawtangents[i] = tan1[i]; + rawBitangents[i] = tan2[i]; + + if (rawtangents[i].IsZero() || rawBitangents[i].IsZero()) { + rawtangents[i].x = rawnorms[i].y; rawtangents[i].y = rawnorms[i].z; rawtangents[i].z = rawnorms[i].x; + rawBitangents[i] = rawnorms[i].cross(rawtangents[i]); + } + else { + rawtangents[i].Normalize(); + rawtangents[i] = (rawtangents[i] - rawnorms[i] * rawnorms[i].dot(rawtangents[i])); + rawtangents[i].Normalize(); + + rawBitangents[i].Normalize(); + + rawBitangents[i] = (rawBitangents[i] - rawnorms[i] * rawnorms[i].dot(rawBitangents[i])); + rawBitangents[i] = (rawBitangents[i] - rawtangents[i] * rawtangents[i].dot(rawBitangents[i])); + + rawBitangents[i].Normalize(); + + + } + + + //rawBitangents[i] = tan1[i] ; + //rawBitangents[i].Normalize(); + + //rawtangents[i] = rawBitangents[i].cross(rawnorms[i]); + //rawtangents[i].Normalize(); + + + + float tmp; + if (transform) { + rawnorms[i].x = -rawnorms[i].x; + tmp = rawnorms[i].y; + rawnorms[i].y = rawnorms[i].z; + rawnorms[i].z = tmp; + + + rawBitangents[i].x = -rawBitangents[i].x; + tmp = rawBitangents[i].y; + rawBitangents[i].y = rawBitangents[i].z; + rawBitangents[i].z = tmp; + + rawtangents[i].x = -rawtangents[i].x; + tmp = rawtangents[i].y; + rawtangents[i].y = rawtangents[i].z; + rawtangents[i].z = tmp; + } + + } + if (outNorms) + *outNorms = &rawnorms; + if (outTangents) + *outTangents = &rawtangents; + if (outBitangents) + *outBitangents = &rawBitangents; + + + +} + +void BSTriShape::setNormals(const vector& inNorms) { + rawnorms.clear(); + rawnorms.resize(numverts); + for (int i = 0;i < numverts; i++) { + rawnorms[i] = inNorms[i]; + vertData[i].normal[0] = (unsigned char)round((((inNorms[i].x + 1.0f) /2.0f )*255.0f)); + vertData[i].normal[1] = (unsigned char)round((((inNorms[i].y + 1.0f) / 2.0f)*255.0f));; + vertData[i].normal[2] = (unsigned char)round((((inNorms[i].z + 1.0f) / 2.0f)*255.0f));; + + } + +} + +void BSTriShape::SetTangentData() { + if (rawnorms.empty()) { + GetNormalData(false); + } + vector tan1; + vector tan2; + tan1.resize(numverts); + tan2.resize(numverts); -BSSubIndexTriShape::BSSubIndexTriShape(fstream& file, NiHeader& hdr, int blockindex) : -BSTriShape(file, hdr, blockindex) + + for (int i = 0; i < triangles.size(); i++) { + int i1 = triangles[i].p1; + int i2 = triangles[i].p2; + int i3 = triangles[i].p3; + + Vector3 v1 = vertData[i1].vert; + Vector3 v2 = vertData[i2].vert; + Vector3 v3 = vertData[i3].vert; + + Vector2 w1 = vertData[i1].uv; + Vector2 w2 = vertData[i2].uv; + Vector2 w3 = vertData[i3].uv; + + float x1 = v2.x - v1.x; + float x2 = v3.x - v1.x; + float y1 = v2.y - v1.y; + float y2 = v3.y - v1.y; + float z1 = v2.z - v1.z; + float z2 = v3.z - v1.z; + + float s1 = w2.u - w1.u; + float s2 = w3.u - w1.u; + float t1 = w2.v - w1.v; + float t2 = w3.v - w1.v; + + float r = (s1 * t2 - s2 * t1); + r = (r >= 0.0f ? +1.0f : -1.0f); + + Vector3 sdir = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); + Vector3 tdir = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); + + sdir.Normalize(); + tdir.Normalize(); + + tan1[i1] += tdir; + tan1[i2] += tdir; + tan1[i3] += tdir; + + tan2[i1] += sdir; + tan2[i2] += sdir; + tan2[i3] += sdir; + } + + rawBitangents.resize(numverts); + rawtangents.resize(numverts); + + for (int i = 0; i < numverts; i++) { + + rawtangents[i] = tan1[i]; + rawBitangents[i] = tan2[i]; + + if (rawtangents[i].IsZero() || rawBitangents[i].IsZero()) { + rawtangents[i].x = rawnorms[i].y; rawtangents[i].y = rawnorms[i].z; rawtangents[i].z = rawnorms[i].x; + rawBitangents[i] = rawnorms[i].cross(rawtangents[i]); + } + else { + rawtangents[i].Normalize(); + rawtangents[i] = (rawtangents[i] - rawnorms[i] * rawnorms[i].dot(rawtangents[i])); + rawtangents[i].Normalize(); + + rawBitangents[i].Normalize(); + + rawBitangents[i] = (rawBitangents[i] - rawnorms[i] * rawnorms[i].dot(rawBitangents[i])); + rawBitangents[i] = (rawBitangents[i] - rawtangents[i] * rawtangents[i].dot(rawBitangents[i])); + + rawBitangents[i].Normalize(); + + + } + + + ///* Old wrong way */ + //rawBitangents[i] = tan1[i]; + //rawBitangents[i].Normalize(); + + //rawtangents[i] = rawBitangents[i].cross(rawnorms[i]); + //rawtangents[i].Normalize(); + + + + vertData[i].tangent[0] = (unsigned char)round((((rawtangents[i].x + 1.0f) / 2.0f)*255.0f)); + vertData[i].tangent[1] = (unsigned char)round((((rawtangents[i].y + 1.0f) / 2.0f)*255.0f));; + vertData[i].tangent[2] = (unsigned char)round((((rawtangents[i].z + 1.0f) / 2.0f)*255.0f));; + + vertData[i].bitangentX = rawBitangents[i].x; + vertData[i].bitangentY = (unsigned char)round((((rawBitangents[i].y + 1.0f) / 2.0f)*255.0f)); + vertData[i].bitangentZ = (unsigned char)round((((rawBitangents[i].z + 1.0f) / 2.0f)*255.0f)); + + } + + + + +} + +void BSTriShape::Create(vector* verts, vector* tris, vector* uvs, vector* normals) { + unkShort1 = 0; //from AVObject -- zero for these blocks. + numverts = verts->size(); + numTris = tris->size(); + vertData.resize(verts->size()); + for (int i = 0; i < numverts; i++) { + vertData[i].vert = (*verts)[i]; + vertData[i].uv = (*uvs)[i]; + + vertData[i].bitangentX = 0.0f; + vertData[i].bitangentY = 0; + vertData[i].bitangentZ = 0; + vertData[i].normal[0] = vertData[i].normal[1] = vertData[i].normal[2] = 0; + memset(vertData[i].colorData, 255, 4); + memset(vertData[i].weights, 0, sizeof(float)* 4); + memset(vertData[i].weightBones, 0, 4); + + } + if (normals) { + setNormals((*normals)); + calcTangentSpace(NULL, NULL, NULL); + } + vertRecSize = 12; + if (vertFlags[6] & 0x1) { //normals + vertRecSize += 8; + } + + if (vertFlags[6] & 0x2) { //colors + vertRecSize += 4; + } + + if (vertFlags[6] & 0x4) { //skinning + vertRecSize += 12; + } + datasize = 6 * numTris + numverts * vertRecSize; + + triangles.resize(numTris); + for (int i = 0; i < numTris; i++) { + triangles[i] = (*tris)[i]; + } + + CalcBlockSize(); + +} + +BSSubIndexTriShape::BSSubIndexTriShape(NiHeader& hdr) : BSTriShape(hdr) { + blockType = BSSUBINDEXTRISHAPE; + numtris2 = 0; + numSubIndexRecordA = 0; + numSubIndexRecordB = 0; + numSubIndexRecordA_2 = 0; + numSubIndexRecordB_2 = 0; + CalcBlockSize(); +} + +BSSubIndexTriShape::BSSubIndexTriShape(fstream& file, NiHeader& hdr) : +BSTriShape(file, hdr) { blockType = BSSUBINDEXTRISHAPE; Get(file); + CalcBlockSize(); } void BSSubIndexTriShape::Get(fstream& file) { @@ -937,29 +1332,21 @@ void BSSubIndexTriShape::Put(fstream& file) { } - ssfFile.Put(file, 2); + ssfFile.Put(file, 2,false); } } void BSSubIndexTriShape::notifyBlockDelete(int blockID) { - NiObjectNET::notifyBlockDelete(blockID); + BSTriShape::notifyBlockDelete(blockID); - if (skinInstanceRef == blockID) - skinInstanceRef = 0xFFFFFFFF; - else if (skinInstanceRef > blockID) - skinInstanceRef--; - if (shaderPropertyRef == blockID) - shaderPropertyRef = 0xFFFFFFFF; - else if (shaderPropertyRef > blockID) - shaderPropertyRef--; } void BSSubIndexTriShape::notifyBlockSwap(int blockIndexLo, int blockIndexHi) { - NiObjectNET::notifyBlockSwap(blockIndexLo, blockIndexHi); + BSTriShape::notifyBlockSwap(blockIndexLo, blockIndexHi); } @@ -971,17 +1358,50 @@ int BSSubIndexTriShape::CalcBlockSize() { if (numSubIndexRecordB > numSubIndexRecordA) { blockSize += 8; // second index accounts blockSize += numSubIndexRecordA * 4; // sequence array - for (int i = 0; i < numSubIndexRecordA; i++) { // sub index recordsb + for (int i = 0; i < numSubIndexRecordB; i++) { // sub index recordsb blockSize += 12; // unknown data per record blockSize += 4 * subIndexRecordsB[i].numExtra; // extra data per record. } - } + blockSize += 2; + blockSize += ssfFile.str.length(); + } return blockSize; } +void BSSubIndexTriShape::Create(vector* verts, vector* tris, vector* uvs, vector* normals) { + BSTriShape::Create(verts, tris, uvs, normals); + + vertFlags[0] = 8; + vertFlags[6] = 5; + + numtris2 = numTris; + numSubIndexRecordA = 0; + numSubIndexRecordB = 0; + numSubIndexRecordA_2 = 0; + numSubIndexRecordB_2 = 0; + + numSubIndexRecordA = numSubIndexRecordB = 4; + + subIndexRecordsA.resize(4 * 32); + int n = 0; + for (int i = 0; i < 3; i++) { + subIndexRecordsA[n++] = 0x0; + subIndexRecordsA[n++] = 0x0; + subIndexRecordsA[n++] = 0xFFFFFFFF; + subIndexRecordsA[n++] = 0x0; + } + + subIndexRecordsA[n++] = 0x0; + subIndexRecordsA[n++] = numTris; + subIndexRecordsA[n++] = 0xFFFFFFFF; + subIndexRecordsA[n++] = 0x0; + + CalcBlockSize(); + +} void NiGeometry::Init() { NiAVObject::Init(); @@ -2236,7 +2656,10 @@ BSSkinInstance::BSSkinInstance(fstream& file, NiHeader& hdr) { void BSSkinInstance::Init() { NiObject::Init(); + unk = 0; + boneDataRef = 0xFFFFFFFF; numBones = 0; + numVertices = 0; } void BSSkinInstance::Get(fstream& file) { @@ -2305,7 +2728,7 @@ void BSSkinInstance::notifyBlockSwap(int blockIndexLo, int blockIndexHi) { BSSkinBoneData::BSSkinBoneData(NiHeader& hdr) { NiObject::Init(); - + nBones = 0; header = &hdr; blockType = BSBONEDATA; } @@ -2313,6 +2736,7 @@ BSSkinBoneData::BSSkinBoneData(NiHeader& hdr) { BSSkinBoneData::BSSkinBoneData(fstream& file, NiHeader& hdr) { NiObject::Init(); + nBones = 0; header = &hdr; blockType = BSBONEDATA; Get(file); @@ -2347,6 +2771,12 @@ void BSSkinBoneData::Put(fstream& file) { } } +int BSSkinBoneData::CalcBlockSize() { + NiObject::CalcBlockSize(); + blockSize += 68 * nBones; + blockSize += 4; + return blockSize; +} int BSSkinInstance::CalcBlockSize() { NiObject::CalcBlockSize(); @@ -3413,19 +3843,30 @@ BSLightingShaderProperty::BSLightingShaderProperty(NiHeader& hdr) { header = &hdr; blockType = BSLIGHTINGSHADERPROPERTY; - shaderFlags1 = 0x82400303; - shaderFlags2 = 0x8001; + if (hdr.userVersion == 12 && hdr.userVersion2 >= 120) { + shaderFlags1 = 0x80600203; + shaderFlags2 = 0x81; + } + else { + shaderFlags1 = 0x82400303; + shaderFlags2 = 0x8001; + } uvOffset.u = 0.0f; uvOffset.v = 0.0f; uvScale.u = 1.0f; uvScale.v = 1.0f; textureSetRef = -1; + emissiveColor.Zero(); emissiveMultiple = 1.0f; textureClampMode = 3; alpha = 1.0f; refractionStrength = 0.0f; - glossiness = 20.0f; + if (hdr.userVersion == 12 && hdr.userVersion2 >= 120) { + glossiness = 1.0f; + } else { + glossiness = 20.0f; + } specularColor = Vector3(1.0f, 1.0f, 1.0f); specularStrength = 1.0f; lightingEffect1 = 0.3f; @@ -3444,6 +3885,21 @@ BSLightingShaderProperty::BSLightingShaderProperty(NiHeader& hdr) { sparkleParameters.b = 0.0f; sparkleParameters.a = 0.0f; eyeCubemapScale = 1.0f; + + unk1 = 0x7F7FFFFF; + unk2 = 0x3D4CCCCD; + + unk[0] = 1.0f; + unk[1] = 5.0f; + unk[2] = 0.6f; + unk[3] = 1.4f; + unk[4] = 0.2f; + unk[5] = 1.0f; + unk[6] = 1.6; + unk[7] = 0; + + memset(pad, 0, 16); + } BSLightingShaderProperty::BSLightingShaderProperty(fstream& file, NiHeader& hdr) { @@ -3685,7 +4141,7 @@ void BSLightingShaderProperty::notifyBlockSwap(int blockIndexLo, int blockIndexH } bool BSLightingShaderProperty::IsSkin() { - return (shaderFlags1 & (1 << 21)) != 0; + return (header->userVersion2 < 130 && shaderFlags1 & (1 << 21)) != 0; } bool BSLightingShaderProperty::IsDoubleSided() { @@ -4183,7 +4639,9 @@ BSShaderTextureSet::BSShaderTextureSet(NiHeader& hdr) { header = &hdr; blockType = BSSHADERTEXTURESET; - if (header->userVersion == 12) + if (header->userVersion == 12 && header->userVersion2 >= 130) + numTextures = 10; + else if (header->userVersion == 12) numTextures = 9; else numTextures = 6; @@ -4214,7 +4672,7 @@ void BSShaderTextureSet::Put(fstream& file) { file.write((char*)&numTextures, 4); for (int i = 0; i < numTextures; i++) - textures[i].Put(file, 4); + textures[i].Put(file, 4, false); } int BSShaderTextureSet::CalcBlockSize() { diff --git a/NifFile.cpp b/NifFile.cpp index 16e8ba30..b0778c01 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -371,9 +371,9 @@ int NifFile::Load(const string& filename) { else if (!thisBlockTypeStr.compare("BSEffectShaderPropertyFloatController")) block = (NiObject*) new BSEffectShaderPropertyFloatController(file, hdr); else if (!thisBlockTypeStr.compare("BSSubIndexTriShape")) - block = (NiObject*) new BSSubIndexTriShape(file, hdr, i); + block = (NiObject*) new BSSubIndexTriShape(file, hdr); else if (!thisBlockTypeStr.compare("BSTriShape")) - block = (NiObject*) new BSTriShape(file, hdr, i); + block = (NiObject*) new BSTriShape(file, hdr); else if (!thisBlockTypeStr.compare("BSSkin::Instance")) block = (NiObject*) new BSSkinInstance(file, hdr); else if (!thisBlockTypeStr.compare("BSSkin::BoneData")) @@ -1316,6 +1316,13 @@ void NifFile::CopyGeometry(const string& shapeDest, NifFile& srcNif, const strin bsShader->textureSetRef = hdr.numBlocks; hdr.numBlocks++; } + if (bsShader->nameRef != -1) { + bsShader->name = srcNif.hdr.strings[bsShader->nameRef].str; + bsShader->nameRef = AddOrFindStringId(bsShader->name); + } + if (bsShader->wetMaterialNameRef != -1) { + bsShader->wetMaterialNameRef = AddOrFindStringId(srcNif.hdr.strings[bsShader->wetMaterialNameRef].str); + } } @@ -1429,7 +1436,9 @@ void NifFile::SetNodeName(int blockID, const string& newName) { if (hdr.maxStringLen < newName.length()) hdr.maxStringLen = newName.length(); } - + + + int NifFile::GetNodeID(const string& nodeName) { int id = -1; for (auto& block : blocks) { @@ -1545,7 +1554,7 @@ int NifFile::GetShapeBoneIDList(const string& shapeName, vector& outList) { void NifFile::SetShapeBoneIDList(const string& shapeName, vector& inList) { int skinRef = -1; - + BSSkinBoneData* boneData = nullptr; NiTriBasedGeom* geom = geomForName(shapeName); if (geom) { skinRef = geom->skinInstanceRef; @@ -1554,6 +1563,11 @@ void NifFile::SetShapeBoneIDList(const string& shapeName, vector& inList) { BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { skinRef = siTriShape->skinInstanceRef; + BSSkinInstance * tmpskin = dynamic_cast(blocks[skinRef]); + if (tmpskin) { + boneData = dynamic_cast(blocks[tmpskin->boneDataRef]); + + } } } @@ -1566,9 +1580,20 @@ void NifFile::SetShapeBoneIDList(const string& shapeName, vector& inList) { boneCont->bones.clear(); boneCont->numBones = 0; + bool feedBoneData = false; + if (boneData && boneData->nBones != inList.size()) { // bone data array, clear it out if it doesn't match size + boneData->nBones = 0; + boneData->boneXforms.clear(); + feedBoneData = true; + } for (int i = 0; i < inList.size(); i++) { boneCont->bones.push_back(inList[i]); boneCont->numBones++; + if (boneData && feedBoneData) { + boneData->boneXforms.emplace_back(); + boneData->nBones++; + boneData->CalcBlockSize(); + } } hdr.blockSizes[skinRef] = boneCont->CalcBlockSize(); @@ -1652,6 +1677,16 @@ bool NifFile::SetShapeBoneTransform(const string& shapeName, int boneIndex, Skin BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { skinRef = siTriShape->skinInstanceRef; + if (skinRef == -1) { + return false; + } + BSSkinInstance * tmpskin = dynamic_cast(blocks[skinRef]); + if (tmpskin && boneIndex!=-1) { + BSSkinBoneData* bsskin = dynamic_cast(blocks[tmpskin->boneDataRef]); + bsskin->boneXforms[boneIndex].boundSphereOffset = inSphereOffset; + bsskin->boneXforms[boneIndex].boundSphereRadius = inSphereRadius; + bsskin->boneXforms[boneIndex].boneTransform = inXform; + } } } @@ -1819,9 +1854,17 @@ void NifFile::SetShapeVertWeights(const string& shapeName, int vertIndex, vector memset(trishape->vertData[vertIndex].weights, 0, sizeof(float)* 4); memset(trishape->vertData[vertIndex].weightBones, 0, sizeof(unsigned char) * 4); - for (int i= 0; i vertData[vertIndex].weightBones[i] = boneids[i]; - trishape->vertData[vertIndex].weights[i] = weights[i]; + trishape->vertData[vertIndex].weights[i] = weights[i] / sum; } } @@ -1867,7 +1910,7 @@ bool NifFile::GetTrisForShape(const string& shapeName, vector* outTris return false; } -const vector* NifFile::GetNormalsForShape(const string& shapeName) { +const vector* NifFile::GetNormalsForShape(const string& shapeName, bool transform) { int bType; int dataID = shapeDataIdForName(shapeName, bType); if (dataID == -1) @@ -1886,7 +1929,49 @@ const vector* NifFile::GetNormalsForShape(const string& shapeName) { else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { // NOT IMPLEMENTED BSTriShape* shapeData = (BSTriShape*)(blocks[dataID]); - return shapeData->GetNormalData(); + return shapeData->GetNormalData(transform); + + } + return nullptr; +} + +const vector* NifFile::GetTangentsForShape(const string& shapeName, bool transform) { + int bType; + int dataID = shapeDataIdForName(shapeName, bType); + if (dataID == -1) + return nullptr; + + if (bType == NITRISHAPEDATA) { + return nullptr; + } + else if (bType == NITRISTRIPSDATA) { + return nullptr; + } + else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + // NOT IMPLEMENTED + BSTriShape* shapeData = (BSTriShape*)(blocks[dataID]); + return shapeData->GetTangentData(transform); + + } + return nullptr; +} + +const vector* NifFile::GetBitangentsForShape(const string& shapeName, bool transform) { + int bType; + int dataID = shapeDataIdForName(shapeName, bType); + if (dataID == -1) + return nullptr; + + if (bType == NITRISHAPEDATA) { + return nullptr; + } + else if (bType == NITRISTRIPSDATA) { + return nullptr; + } + else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + // NOT IMPLEMENTED + BSTriShape* shapeData = (BSTriShape*)(blocks[dataID]); + return shapeData->GetBitangentData(transform); } return nullptr; @@ -2108,7 +2193,8 @@ void NifFile::SetNormalsForShape(const string& shapeName, const vector& hdr.blockSizes[dataID] = stripsData->CalcBlockSize(); } if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - //// Fix later after discovering how fo4 stores normals + BSTriShape* shape = (BSTriShape*)blocks[dataID]; + shape->setNormals(norms); } } @@ -2129,10 +2215,29 @@ void NifFile::CalcTangentsForShape(const string& shapeName) { hdr.blockSizes[dataID] = stripsData->CalcBlockSize(); } if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - //// Fix later after discovering how fo4 stores tangents + BSTriShape* shape = (BSTriShape*)blocks[dataID]; + shape->SetTangentData(); } } +void NifFile::CalcTangentsForShape(const string& shapeName, vector** outNormals, vector** outTagents, vector** outBitangents, bool transform) { + int bType; + int dataID = shapeDataIdForName(shapeName, bType); + if (dataID == -1) + return; + + if (bType == NITRISHAPEDATA) { + return; + } + else if (bType == NITRISTRIPSDATA) { + return; + } + if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + BSTriShape* shape = (BSTriShape*)blocks[dataID]; + shape->calcTangentSpace(outNormals, outTagents, outBitangents, transform); + } +} + void NifFile::ClearShapeTransform(const string& shapeName) { NiAVObject* avo = avObjectForName(shapeName); if (avo) { @@ -2480,7 +2585,7 @@ bool NifFile::GetAlphaForShape(const string& shapeName, ushort& outFlags, byte& else { BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { - //alphaRef = siTriShape->unkRef; + //alphaRef = siTriShape->alphaPropertyRef; } } @@ -2540,7 +2645,7 @@ void NifFile::SetAlphaForShape(const string& shapeName, ushort flags, ushort thr else { BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { - //alphaRef = siTriShape->unkRef; + //alphaRef = siTriShape->alphaPropertyRef; } } @@ -2688,7 +2793,7 @@ void NifFile::DeleteAlpha(const string& shapeName) { // Not IMplemented BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { - //alphaRef = siTriShape->unkRef; + //alphaRef = siTriShape->alphaPropertyRef; } } } @@ -2722,7 +2827,7 @@ void NifFile::DeleteVertsForShape(const string& shapeName, const vector& // Not IMplemented BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { - //alphaRef = siTriShape->unkRef; + //alphaRef = siTriShape->alphaPropertyRef; } } @@ -2791,7 +2896,7 @@ void NifFile::UpdateSkinPartitions(const string& shapeName) { // Not IMplemented BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { - //alphaRef = siTriShape->unkRef; + //alphaRef = siTriShape->alphaPropertyRef; } } diff --git a/NifFile.h b/NifFile.h index d1b56e9a..fa0d73b3 100644 --- a/NifFile.h +++ b/NifFile.h @@ -190,7 +190,7 @@ class NiString { bool outputNull; NiString(bool wantOutputNull = true); NiString(fstream& file, int szSize, bool wantNullOutput = true); - void Put(fstream& file, int szSize); + void Put(fstream& file, int szSize, bool wantNullOutput = true); void Get(fstream& file, int szSize); }; @@ -301,6 +301,36 @@ class NiAVObject : public NiObjectNET { virtual void notifyBlockDelete(int blockID); virtual void notifyBlockSwap(int blockIndexLo, int blockIndexHi); virtual int CalcBlockSize(); + + bool rotToEulerDegrees(float &Y, float& P, float& R) { + float rx, ry, rz; + bool canRot = false; + if (rotation[0].z < 1.0) + { + if (rotation[0].z > -1.0) + { + rx = atan2(-rotation[1].z, rotation[2].z); + ry = asin(rotation[0].z); + rz = atan2(-rotation[0].y, rotation[0].x); + canRot = true; + } + else { + rx = -atan2(-rotation[1].x, rotation[1].y); + ry = -PI / 2; + rz = 0.0f; + } + } + else { + rx = atan2(rotation[1].x, rotation[1].y); + ry = PI / 2; + rz = 0.0f; + } + + Y = rx * 180 / PI; + P = ry * 180 / PI; + R = rz * 180 / PI; + return canRot; + } }; class NiProperty : public NiObjectNET { @@ -338,13 +368,13 @@ class BSTriShape : public NiAVObject{ class TSVertData { public: Vector3 vert; // Stored half-float, convert! - float dotNormal; // maybe the dotproduct of the vert normal and the z axis? + float bitangentX; // maybe the dotproduct of the vert normal and the z axis? Vector2 uv; // Stored as half-float, convert! byte normal[3]; - byte unk1; + byte bitangentY; byte tangent[3]; // only if flags[6] & 0x1 is true? some kind of packed normal data ? - byte unk2; - //uint normals[2]; + byte bitangentZ; + byte colorData[4]; // only if flags[6] & 0x2 is true float weights[4]; // stored in half-float, convert! byte weightBones[4]; @@ -353,7 +383,7 @@ class BSTriShape : public NiAVObject{ uint unkProps[4]; uint skinInstanceRef; uint shaderPropertyRef; - int unkRef; + uint alphaPropertyRef; // flags for vert data look to be stored in here. byte 0 or byte 6 specifically look promising . // using byte 6 currently, bit 3 indicating sub index data, bit 2 indicating the presence of color data. bit 1 indicating presence of normal data @@ -365,24 +395,29 @@ class BSTriShape : public NiAVObject{ vector rawverts; // filled by GetRawVerts function and returned. vector rawnorms; // filled by GetNormalData function and returned. - vector rawtangents; // filled by GetTangentData function and returned. + vector rawtangents; // filled by calcTangentSpace function and returned. + vector rawBitangents; // filled in calcTangentSpace vector rawuvs; // filled by GetUVData function and returned. vector vertData; vector triangles; - - BSTriShape(fstream& file, NiHeader& hdr, int blockindex); + BSTriShape(NiHeader& hdr); + BSTriShape(fstream& file, NiHeader& hdr); virtual void Get(fstream& file); virtual void Put(fstream& file); virtual void notifyBlockDelete(int blockID); virtual void notifyBlockSwap(int blockIndexLo, int blockIndexHi); virtual int CalcBlockSize(); - const vector* GetRawVerts(); - const vector* GetNormalData(); - const vector* GetTangentData(); + const vector* GetRawVerts(bool xform = true); + const vector* GetNormalData(bool xform = true); + const vector* GetTangentData(bool xform = true); + const vector* GetBitangentData(bool xform = true); const vector* GetUVData(); - + void calcTangentSpace(vector** outNorms = nullptr, vector** outTangents = nullptr, vector** outBitangents = nullptr, bool transform = true); + void setNormals(const vector& inNorms); + void SetTangentData(); + virtual void Create(vector* verts, vector* tris, vector* uvs, vector* normals = nullptr); }; @@ -412,14 +447,14 @@ class BSSubIndexTriShape : public BSTriShape { NiString ssfFile; - //Blockindex is a temporary measure to enable us to see the total size of the block during loading ... not all fields are known yet - BSSubIndexTriShape(fstream& file, NiHeader& hdr, int blockindex); + BSSubIndexTriShape(NiHeader& hdr); + BSSubIndexTriShape(fstream& file, NiHeader& hdr); virtual void Get(fstream& file); virtual void Put(fstream& file); virtual void notifyBlockDelete(int blockID); virtual void notifyBlockSwap(int blockIndexLo, int blockIndexHi); virtual int CalcBlockSize(); - + virtual void Create(vector* verts, vector* tris, vector* uvs, vector* normals=nullptr); }; class NiGeometry : public NiAVObject { @@ -646,7 +681,7 @@ class BSSkinBoneData : public NiObject { boundSphereRadius = 0.0f; } int CalcSize() { - return (70); + return (68); } }; vector boneXforms; @@ -657,6 +692,7 @@ class BSSkinBoneData : public NiObject { virtual void Get(fstream& file); virtual void Put(fstream& file); + virtual int CalcBlockSize(); }; class NiSkinData : public NiObject { @@ -969,6 +1005,8 @@ class BSLightingShaderProperty : public NiShader { float unk[8]; // unkown shader float params in shadertype 5 for fallout4 byte pad[16]; // up to 16 bytes of uknown padding. clearly this isn't the right format. + + BSLightingShaderProperty(NiHeader& hdr); BSLightingShaderProperty(fstream& file, NiHeader& hdr); @@ -1220,7 +1258,6 @@ class NifFile NifFile(); NifFile(NifFile& other); ~NifFile(); - NiHeader hdr; void CopyFrom(NifFile& other); @@ -1284,6 +1321,10 @@ class NifFile void RenameDuplicateShape(const string& dupedShape); void SetNodeName(int blockID, const string& newName); + /// GetChildren of a node ... templatized to allow any particular type to be queried. useful for walking a node tree + template + vector GetChildren(NiNode* parent); + int GetNodeID(const string& nodeName); bool GetNodeTransform(const string& nodeName, vector& outRot, Vector3& outTrans, float& outScale); bool SetNodeTransform(const string& nodeName, SkinTransform& inXform); @@ -1305,7 +1346,9 @@ class NifFile const vector* GetRawVertsForShape(const string& shapeName); bool GetTrisForShape(const string& shapeName, vector* outTris); - const vector* GetNormalsForShape(const string& shapeName); + const vector* GetNormalsForShape(const string& shapeName, bool transform = true); + const vector* GetTangentsForShape(const string& shapeName, bool transform = true); + const vector* GetBitangentsForShape(const string& shapeName, bool transform = true); const vector* GetUvsForShape(const string& shapeName); bool GetUvsForShape(const string& shapeName, vector& outUvs); const vector>* GetSeamVertsForShape(const string& shapeName); @@ -1315,6 +1358,7 @@ class NifFile void SetUvsForShape(const string& shapeName, const vector& uvs); void SetNormalsForShape(const string& shapeName, const vector& norms); void CalcTangentsForShape(const string& shapeName); + void CalcTangentsForShape(const string& shapeName, vector** outNormals, vector** outTagents, vector** outBitangents, bool transform = true); void ClearShapeTransform(const string& shapeName); void GetShapeTransform(const string& shapeName, Matrix4& outTransform); @@ -1353,3 +1397,24 @@ class NifFile // Maintains the number of and makeup of skin partitions, but updates the weighting values void UpdateSkinPartitions(const string& shapeName); }; + +template +vector NifFile::GetChildren(NiNode* parent) { + vector result; + T* n; + if (parent == nullptr) { + n = dynamic_cast(blocks[0]); + if (n) + result.push_back(n); + return result; + } + + for (int i = 0; i < parent->children.size(); i++) { + n = dynamic_cast(blocks[parent->children[i]]); + if (n) { + result.push_back(n); + } + } + + return result; +} diff --git a/ObjFile.cpp b/ObjFile.cpp index 27015dee..60373de5 100644 --- a/ObjFile.cpp +++ b/ObjFile.cpp @@ -30,6 +30,21 @@ int ObjFile::AddGroup(const string& name, const vector& verts, const ve return 0; } + +int ObjFile::AddGroup(const string& name, const vector& verts, const vector& faces, const vector& uvs) { + if (name.empty() || verts.empty()) + return 1; + + ObjData* newData = new ObjData(); + newData->name = name; + newData->verts = verts; + newData->faces = faces; + newData->uvs = uvs; + + data[name] = newData; + return 0; +} + int ObjFile::LoadSimple(const string &inFn, const string& groupName){ fstream base(inFn.c_str(), ios_base::in | ios_base::binary); if (base.fail()) @@ -53,8 +68,8 @@ int ObjFile::LoadSimple(const string &inFn, const string& groupName){ vector tris; bool readgroup = true; + base >> dump; while (!base.eof()) { - base >> dump; if (dump.compare("v") == 0) { base >> v.x >> v.y >> v.z; di->verts.push_back(v); @@ -88,14 +103,15 @@ int ObjFile::LoadSimple(const string &inFn, const string& groupName){ t.p1 = atoi(facept1.c_str()) - 1; ft[0] = atoi(facept1.substr(pos + 1).c_str()) - 1; pos = facept2.find('/'); - t.p1 = atoi(facept2.c_str()) - 1; + t.p2 = atoi(facept2.c_str()) - 1; ft[1] = atoi(facept2.substr(pos + 1).c_str()) - 1; pos = facept3.find('/'); - t.p1 = atoi(facept3.c_str()) - 1; + t.p3 = atoi(facept3.c_str()) - 1; ft[2] = atoi(facept3.substr(pos + 1).c_str()) - 1; di->tris.push_back(t); } + base >> dump; } data[di->name] = di; @@ -152,7 +168,7 @@ int ObjFile::LoadForNif(fstream &base, const string& groupName) { base >> v.x >> v.y >> v.z; verts.push_back(v); } - else if (dump.compare("g") == 0 || dump.compare("o") == 0) { + else if (dump.compare("g") == 0 || dump.compare("o") == 0 || dump.compare("s")==0) { base >> curgrp; if (di->name != "") { @@ -269,6 +285,177 @@ int ObjFile::LoadForNif(fstream &base, const string& groupName) { return 0; } +int ObjFile::LoadVertOrderMap(const string &inFn, map& outMap, vector& origFaces, vector& origUVs, const string& groupName) { + fstream base(inFn.c_str(), ios_base::in | ios_base::binary); + if (base.fail()) + return 1; + + LoadVertOrderMap(base,outMap, origFaces, origUVs, groupName); + base.close(); + return 0; +} + +int ObjFile::LoadVertOrderMap(fstream &base, map& outMap, vector& origFaces, vector& origUVs, const string& groupName) { + ObjData* di = new ObjData(); + + Vector3 v; + Vector2 uv; + Vector2 uv2; + Triangle t; + + string dump; + string curgrp; + string facept1; + string facept2; + string facept3; + string facept4; + int f[4]; + int ft[4]; + int nPoints = 0; + int v_idx[4]; + + vector verts; + vector uvs; + vector tris; + size_t pos; + map> vertMap; + map>::iterator savedVert; + + bool gotface = false; + bool readgroup = true; + + while (!base.eof()) { + if (!gotface) + base >> dump; + else + gotface = false; + + if (dump.compare("v") == 0) { + base >> v.x >> v.y >> v.z; + verts.push_back(v); + } + else if (dump.compare("g") == 0 || dump.compare("o") == 0) { + base >> curgrp; + + if (di->name != "") { + data[di->name] = di; + di = new ObjData; + } + + di->name = curgrp; + objGroups.push_back(curgrp); + + if (groupName.length() > 0) { + if (curgrp.compare(groupName) == 0) + readgroup = true; + else + readgroup = false; + } + } + else if (dump.compare("vt") == 0) { + base >> uv.u >> uv.v; + uv.v = 1.0f - uv.v; + uvs.push_back(uv); + origUVs.push_back(uv); + } + else if (dump.compare("f") == 0) { + base >> facept1 >> facept2 >> facept3; + pos = facept1.find('/'); + f[0] = atoi(facept1.c_str()) - 1; + ft[0] = atoi(facept1.substr(pos + 1).c_str()) - 1; + pos = facept2.find('/'); + f[1] = atoi(facept2.c_str()) - 1; + ft[1] = atoi(facept2.substr(pos + 1).c_str()) - 1; + pos = facept3.find('/'); + f[2] = atoi(facept3.c_str()) - 1; + ft[2] = atoi(facept3.substr(pos + 1).c_str()) - 1; + base >> facept4; + + if (facept4 == "f") { + gotface = true; + dump = "f"; + nPoints = 3; + } + else if (facept4 == "g") { + gotface = true; + dump = "g"; + nPoints = 3; + } + else if (facept4 == "s") { + gotface = true; + dump = "s"; + nPoints = 3; + } + else if (facept4.length() > 0) { + pos = facept4.find('/'); + if (pos == string::npos) { + gotface = true; + dump = "f"; + nPoints = 3; + } + else { + f[3] = atoi(facept4.c_str()) - 1; + ft[3] = atoi(facept4.substr(pos + 1).c_str()) - 1; + nPoints = 4; + } + } + + if (f[0] == -1 || f[1] == -1 || f[2] == -1) + continue; + + origFaces.emplace_back(nPoints, f, ft); + + if (!readgroup) + continue; + + for (int i = 0; i < nPoints; i++) { + v_idx[i] = di->verts.size(); + if ((savedVert = vertMap.find(f[i])) != vertMap.end()) { + for (int j = 0; j < savedVert->second.size(); j++) { + if (savedVert->second[j].uv == ft[i]) + v_idx[i] = savedVert->second[j].v; + else if (uvs.size() > 0) { + uv = uvs[ft[i]]; + uv2 = uvs[savedVert->second[j].uv]; + if (fabs(uv.u - uv2.u) > uvDupThreshold) { + v_idx[i] = v_idx[i]; + continue; + } + else if (fabs(uv.v - uv2.v) > uvDupThreshold) { + v_idx[i] = v_idx[i]; + continue; + } + v_idx[i] = savedVert->second[j].v; + } + } + } + + if (v_idx[i] == di->verts.size()) { + vertMap[f[i]].push_back(VertUV(v_idx[i], ft[i])); + outMap[f[i]] = di->verts.size(); + di->verts.push_back(verts[f[i]]); + if (uvs.size() > 0) { + di->uvs.push_back(uvs[ft[i]]); + } + } + } + t.p1 = v_idx[0]; + t.p2 = v_idx[1]; + t.p3 = v_idx[2]; + di->tris.push_back(t); + if (nPoints == 4) { + t.p1 = v_idx[0]; + t.p2 = v_idx[2]; + t.p3 = v_idx[3]; + di->tris.push_back(t); + } + } + } + //data[di->name] = di; + delete di; + return 0; +} + int ObjFile::Load(const string &inFn, const string& groupName) { ifstream base(inFn.c_str(), ios_base::binary); if (base.is_open()) @@ -482,11 +669,24 @@ int ObjFile::Save(const string &fileName) { file << "vt " << d.second->uvs[i].u << " " << (1.0f - d.second->uvs[i].v) << endl; file << endl; - for (int i = 0; i < d.second->tris.size(); i++) { - file << "f " << d.second->tris[i].p1 + 1 << "/" << d.second->tris[i].p1 + 1 << " " - << d.second->tris[i].p2 + 1 << "/" << d.second->tris[i].p2 + 1 << " " - << d.second->tris[i].p3 + 1 << "/" << d.second->tris[i].p3 + 1 - << endl; + if (d.second->faces.size() > 0) { + for (int i = 0; i < d.second->faces.size(); i++) { + file << "f " << d.second->faces[i].p1 + 1 << "/" << d.second->faces[i].uv1 + 1 << " " + << d.second->faces[i].p2 + 1 << "/" << d.second->faces[i].uv2 + 1 << " " + << d.second->faces[i].p3 + 1 << "/" << d.second->faces[i].uv3 + 1; + if (d.second->faces[i].nPoints == 4) { + file << " " << d.second->faces[i].p4 + 1 << "/" << d.second->faces[i].uv4 + 1; + } + file << endl; + } + } + else { + for (int i = 0; i < d.second->tris.size(); i++) { + file << "f " << d.second->tris[i].p1 + 1 << "/" << d.second->tris[i].p1 + 1 << " " + << d.second->tris[i].p2 + 1 << "/" << d.second->tris[i].p2 + 1 << " " + << d.second->tris[i].p3 + 1 << "/" << d.second->tris[i].p3 + 1 + << endl; + } } file << endl; } diff --git a/ObjFile.h b/ObjFile.h index e5d80797..9822d8ca 100644 --- a/ObjFile.h +++ b/ObjFile.h @@ -25,6 +25,7 @@ struct ObjData { vector verts; vector tris; vector uvs; + vector faces; // only for quad support during special output operations. }; class ObjFile { @@ -40,6 +41,7 @@ class ObjFile { ~ObjFile(); int AddGroup(const string& name, const vector& verts, const vector& tris, const vector& uvs); + int AddGroup(const string& name, const vector& verts, const vector& faces, const vector& uvs); void SetScale(const Vector3& inScale) { scale = inScale; } void SetOffset(const Vector3& inOffset) { offset = inOffset; } @@ -48,6 +50,8 @@ class ObjFile { int LoadForNif(const string& inFn, const string& groupName = ""); int LoadForNif(fstream& base, const string& groupName = ""); + int LoadVertOrderMap(const string& inFn, map& outMap, vector& origFaces, vector& origUVs, const string& groupName = ""); + int LoadVertOrderMap(fstream& base, map& outMap, vector& origFaces, vector& origUVs, const string& groupName = ""); int Load(const string& inFn, const string& groupName = ""); int Load(ifstream& base, const string& groupName = ""); diff --git a/Object3d.h b/Object3d.h index 7c1004d1..81be5c74 100644 --- a/Object3d.h +++ b/Object3d.h @@ -32,6 +32,13 @@ struct Vertex; struct Vector2 { float u; float v; + Vector2() { + u = v = 0.0f; + } + Vector2(float U, float V) { + u = U; + v = V; + } }; struct Vector3 { @@ -310,6 +317,13 @@ class Matrix4 { Set(mat33); } + void Set(Vector3 mat33[3]) { + m[0] = mat33[0].x; m[1] = mat33[0].y; m[2] = mat33[0].z; m[3] = 0; + m[4] = mat33[1].x; m[5] = mat33[1].y; m[6] = mat33[1].z; m[7] = 0; + m[8] = mat33[2].x; m[9] = mat33[2].y; m[10] = mat33[2].z; m[11] = 0; + m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; + } + void Set(vector& mat33) { m[0] = mat33[0].x; m[1] = mat33[0].y; m[2] = mat33[0].z; m[3] = 0; m[4] = mat33[1].x; m[5] = mat33[1].y; m[6] = mat33[1].z; m[7] = 0; @@ -688,6 +702,30 @@ namespace std { }; } +struct Face { + byte nPoints; + ushort p1; + ushort uv1; + ushort p2; + ushort uv2; + ushort p3; + ushort uv3; + ushort p4; + ushort uv4; + + Face(int npts = 0, int* points=nullptr, int* tc = nullptr) { + nPoints = npts; + if (npts<3) + return; + p1 = points[0]; p2 = points[1]; p3 = points[2]; + uv1 = tc[0]; uv2 = tc[1]; uv3 = tc[2]; + if (npts == 4) { + p4 = points[3]; + uv4 = tc[3]; + } + } +}; + struct IntersectResult; struct AABB { diff --git a/OutfitProject.cpp b/OutfitProject.cpp index 81949fcf..789fae15 100644 --- a/OutfitProject.cpp +++ b/OutfitProject.cpp @@ -361,72 +361,116 @@ void OutfitProject::AddCombinedSlider(const string& newName) { } } -int OutfitProject::AddShapeFromObjFile(const string& fileName, const string& shapeName, const string& mergeShape) { +int OutfitProject::AddShapeFromObjFile(const string& fileName, string& shapeName, const string& mergeShape) { ObjFile obj; obj.SetScale(Vector3(10.0f, 10.0f, 10.0f)); + + //Config.SetValue("StaticMeshMode", "True"); + //obj.LoadSimple(fileName); + if (obj.LoadForNif(fileName)) { wxLogError("Could not load OBJ file '%s'!", fileName); wxMessageBox(wxString::Format("Could not load OBJ file '%s'!", fileName), "OBJ Error", wxICON_ERROR); return 1; } + vector objGroupNames; + obj.GetGroupList(objGroupNames); + for (int i = 0; i < objGroupNames.size(); i++) { + vector v; + vector t; + vector uv; + if (!obj.CopyDataForIndex(i, &v, &t, &uv)) { + wxLogError("Could not copy data from OBJ file '%s'!", fileName); + wxMessageBox(wxString::Format("Could not copy data from OBJ file '%s'!", fileName), "OBJ Error", wxICON_ERROR); + return 3; + } + // skip zero size groups. + if (v.size() == 0) + continue; - vector v; - vector t; - vector uv; - if (!obj.CopyDataForIndex(0, &v, &t, &uv)) { - wxLogError("Could not copy data from OBJ file '%s'!", fileName); - wxMessageBox(wxString::Format("Could not copy data from OBJ file '%s'!", fileName), "OBJ Error", wxICON_ERROR); - return 3; + string useShapeName = objGroupNames[i]; + + if (mergeShape != "") { + vector shapeVerts; + workNif.GetVertsForShape(mergeShape, shapeVerts); + if (shapeVerts.size() == v.size()) { + int r = wxMessageBox("The vertex count of the selected .obj file matches the currently selected outfit shape. Do you wish to update the current shape? (click No to create a new shape)", "Merge or New", wxYES_NO | wxICON_QUESTION); + if (r == wxYES) { + wxLogMessage("Updated shape '%s' using '%s'.", mergeShape, fileName); + workNif.SetVertsForShape(mergeShape, v); + return 101; + } + } + useShapeName = wxGetTextFromUser("Please specify a name for the new shape", "New Shape Name", useShapeName); + if (useShapeName == "") + return 100; + } + + int ret = CreateNifShapeFromData(useShapeName, v, t, uv); } - string useShapeName = shapeName; + return 0; +} + - if (mergeShape != "") { - vector shapeVerts; - workNif.GetVertsForShape(mergeShape, shapeVerts); - if (shapeVerts.size() == v.size()) { - int r = wxMessageBox("The vertex count of the selected .obj file matches the currently selected outfit shape. Do you wish to update the current shape? (click No to create a new shape)", "Merge or New", wxYES_NO | wxICON_QUESTION); - if (r == wxYES) { - wxLogMessage("Updated shape '%s' using '%s'.", mergeShape, fileName); - workNif.SetVertsForShape(mergeShape, v); - return 101; - } - } - useShapeName = wxGetTextFromUser("Please specify a name for the new shape", "New Shape Name"); - if (useShapeName == "") - return 100; +int OutfitProject::CreateNifShapeFromData(const string& shapeName, vector& v, vector& t, vector& uv, vector* norms) { + if (norms == nullptr) + owner->setShapeImporting(shapeName, true); + + bool staticMode = (Config.GetString("StaticMeshMode") == "True"); + + string blankSkel = "res\\SkeletonBlank.nif"; + string defaultName = "New Outfit"; + if (staticMode) { + blankSkel = "res\\GameObjectBlank.nif"; + defaultName = "New Object"; + } + else if (owner->targetGame == FO4) { + blankSkel = "res\\SkeletonBlank_fo4.nif"; } + NifFile blank; - blank.Load("res\\SkeletonBlank.nif"); + blank.Load(blankSkel); if (!blank.IsValid()) { - wxLogError("Could not load 'SkeletonBlank.nif' for OBJ file."); - wxMessageBox("Could not load 'SkeletonBlank.nif' for OBJ file.", "OBJ Error", wxICON_ERROR); + wxLogError("Could not load 'SkeletonBlank.nif' for importing data file."); + wxMessageBox("Could not load 'SkeletonBlank.nif' for importing data file.", "import data Error", wxICON_ERROR); return 2; } if (!workNif.IsValid()) - AddNif("res\\SkeletonBlank.nif", true, "New Outfit"); - - NiTriShapeData* nifShapeData = new NiTriShapeData(workNif.hdr); - nifShapeData->Create(&v, &t, &uv); - int shapeID = blank.AddBlock((NiObject*)nifShapeData, "NiTriShapeData"); + AddNif(blankSkel, true, defaultName); + + if (owner->targetGame != FO4) { + NiTriShapeData* nifShapeData = new NiTriShapeData(workNif.hdr); + nifShapeData->Create(&v, &t, &uv); + if (norms) { + nifShapeData->normals = (*norms); + nifShapeData->hasNormals = true; + } + int shapeID = blank.AddBlock((NiObject*)nifShapeData, "NiTriShapeData"); - NiSkinData* nifSkinData = new NiSkinData(workNif.hdr); - int skinID = blank.AddBlock((NiObject*)nifSkinData, "NiSkinData"); + int dismemberID = -1; + if (!staticMode){ + NiSkinData* nifSkinData = new NiSkinData(workNif.hdr); + int skinID = blank.AddBlock((NiObject*)nifSkinData, "NiSkinData"); - NiSkinPartition* nifSkinPartition = new NiSkinPartition(workNif.hdr); - int partID = blank.AddBlock((NiObject*)nifSkinPartition, "NiSkinPartition"); + NiSkinPartition* nifSkinPartition = new NiSkinPartition(workNif.hdr); + int partID = blank.AddBlock((NiObject*)nifSkinPartition, "NiSkinPartition"); - BSDismemberSkinInstance* nifDismemberInst = new BSDismemberSkinInstance(workNif.hdr); - int dismemberID = blank.AddBlock((NiObject*)nifDismemberInst, "BSDismemberSkinInstance"); + BSDismemberSkinInstance* nifDismemberInst = new BSDismemberSkinInstance(workNif.hdr); + dismemberID = blank.AddBlock((NiObject*)nifDismemberInst, "BSDismemberSkinInstance"); + nifDismemberInst->dataRef = skinID; + nifDismemberInst->skinPartitionRef = partID; + nifDismemberInst->skeletonRootRef = 0; + } - BSShaderTextureSet* nifTexset = new BSShaderTextureSet(workNif.hdr); + BSShaderTextureSet* nifTexset = new BSShaderTextureSet(workNif.hdr); - int shaderID; - BSLightingShaderProperty* nifShader = nullptr; - BSShaderPPLightingProperty* nifShaderPP = nullptr; - switch (owner->targetGame) { + int shaderID; + BSLightingShaderProperty* nifShader = nullptr; + BSShaderPPLightingProperty* nifShaderPP = nullptr; + switch (owner->targetGame) { case FO3: case FONV: nifShaderPP = new BSShaderPPLightingProperty(workNif.hdr); @@ -439,23 +483,65 @@ int OutfitProject::AddShapeFromObjFile(const string& fileName, const string& sha nifShader = new BSLightingShaderProperty(workNif.hdr); shaderID = blank.AddBlock((NiObject*)nifShader, "BSLightingShaderProperty"); nifShader->textureSetRef = blank.AddBlock((NiObject*)nifTexset, "BSShaderTextureSet"); + } + + NiTriShape* nifTriShape = new NiTriShape(workNif.hdr); + blank.AddBlock((NiObject*)nifTriShape, "NiTriShape"); + nifTriShape->propertiesRef1 = shaderID; + + int nameID = blank.AddOrFindStringId(shapeName); + nifTriShape->dataRef = shapeID; + nifTriShape->skinInstanceRef = dismemberID; + nifTriShape->nameRef = nameID; + nifTriShape->name = shapeName; } + else { + BSTriShape* triShapeBase; + string shaderName = "Materials\\actors\\Character\\BaseHumanFemale\\basehumanFemaleskin.bgsm"; + string wetShaderName = "template/SkinTemplate_Wet.bgsm"; + if (staticMode) { + triShapeBase = new BSTriShape(workNif.hdr); + triShapeBase->Create(&v, &t, &uv, norms); + blank.AddBlock((NiObject*)triShapeBase, "BSTriShape"); + shaderName = "Materials\\Clothes\\Hats\\WigGO.BGSM"; + wetShaderName = ""; + + } else { + BSSubIndexTriShape* nifBSTriShape = new BSSubIndexTriShape(workNif.hdr); + nifBSTriShape->Create(&v, &t, &uv, norms); + nifBSTriShape->ssfFile = "Meshes\\Actors\\Character\\CharacterAssets\\FemaleBody.ssf"; + blank.AddBlock((NiObject*)nifBSTriShape, "BSSubIndexTriShape"); + + BSSkinInstance* nifBSSkinInstance = new BSSkinInstance(workNif.hdr); + int skinID = blank.AddBlock((NiObject*)nifBSSkinInstance, "BSSkin::Instance"); + + BSSkinBoneData* nifBoneData = new BSSkinBoneData(workNif.hdr); + int boneID = blank.AddBlock((NiObject*)nifBoneData, "BSSkin::BoneData"); + nifBSSkinInstance->boneDataRef = boneID; + nifBSTriShape->skinInstanceRef = skinID; + triShapeBase = nifBSTriShape; + } + + BSShaderTextureSet* nifTexset = new BSShaderTextureSet(workNif.hdr); + + int shaderID; + BSLightingShaderProperty* nifShader = new BSLightingShaderProperty(workNif.hdr); + nifShader->nameRef = blank.AddOrFindStringId(shaderName); + nifShader->name = shaderName; + nifShader->wetMaterialNameRef = blank.AddOrFindStringId(wetShaderName); + shaderID = blank.AddBlock((NiObject*)nifShader, "BSLightingShaderProperty"); + nifShader->textureSetRef = blank.AddBlock((NiObject*)nifTexset, "BSShaderTextureSet"); + + int nameID = blank.AddOrFindStringId(shapeName); + triShapeBase->shaderPropertyRef = shaderID; + triShapeBase->nameRef = nameID; + triShapeBase->name = shapeName; - NiTriShape* nifTriShape = new NiTriShape(workNif.hdr); - blank.AddBlock((NiObject*)nifTriShape, "NiTriShape"); - nifDismemberInst->dataRef = skinID; - nifDismemberInst->skinPartitionRef = partID; - nifDismemberInst->skeletonRootRef = 0; - nifTriShape->propertiesRef1 = shaderID; - int nameID = blank.AddOrFindStringId(useShapeName); - nifTriShape->dataRef = shapeID; - nifTriShape->skinInstanceRef = dismemberID; - nifTriShape->nameRef = nameID; - nifTriShape->name = useShapeName; + } - workNif.CopyGeometry(useShapeName, blank, useShapeName); - SetTexture(useShapeName, "_AUTO_"); + workNif.CopyGeometry(shapeName, blank, shapeName); + SetTexture(shapeName, "_AUTO_"); return 0; } @@ -664,9 +750,24 @@ int OutfitProject::SaveSliderOBJ(const string& sliderName, const string& shapeNa else morpher.ApplyResultToVerts(sliderName, target, &outVerts); + + string mapfn = wxFileSelector("Choose vertex map source .obj", wxEmptyString, wxEmptyString, ".obj", "*.obj", wxFD_OPEN | wxFD_FILE_MUST_EXIST, owner); + if (mapfn.empty()) + return 1; + + map orderMap; + vector origFaces; + vector origUvs; + ObjFile orderFile; + orderFile.LoadVertOrderMap(mapfn, orderMap, origFaces, origUvs); + vector swizzleverts(orderMap.size()); + for (int i = 0; i < orderMap.size(); i++) { + swizzleverts[i] = outVerts[orderMap[i]]; + } ObjFile obj; obj.SetScale(Vector3(0.1f, 0.1f, 0.1f)); - obj.AddGroup(shapeName, outVerts, tris, *uvs); + obj.AddGroup(shapeName, swizzleverts, origFaces, origUvs); + //obj.AddGroup(shapeName, outVerts, tris, *uvs); if (obj.Save(fileName)) return 1; @@ -692,7 +793,8 @@ bool OutfitProject::SetSliderFromOBJ(const string& sliderName, const string& sha int type= workNif.GetShapeType(shapeName); ObjFile obj; if (type == BSSUBINDEXTRISHAPE) { - obj.LoadSimple(fileName); + obj.LoadForNif(fileName); + // obj.LoadSimple(fileName); } else { obj.LoadForNif(fileName); @@ -731,6 +833,48 @@ bool OutfitProject::SetSliderFromOBJ(const string& sliderName, const string& sha return true; } +bool OutfitProject::SetSliderFromFBX(const string& sliderName, const string& shapeName, const string& fileName) { + string target = ShapeToTarget(shapeName); + int type = workNif.GetShapeType(shapeName); + + FBXWrangler fbxw; + string invalidBones; + + bool result = fbxw.ImportScene(fileName); + if (!result) + return 1; + vectorshapes; + fbxw.GetShapeNames(shapes); + bool found = false; + for (auto s : shapes) { + if (s == shapeName) { + found = true; + } + } + if (!found) { + return false; + } + FBXShape* shape = fbxw.InShape(shapeName); + + + unordered_map diff; + if (IsBaseShape(shapeName)) { + if (workNif.CalcShapeDiff(shapeName, &shape->verts, diff, 1.0f)) + return false; + + string sliderData = activeSet[sliderName].TargetDataName(target); + baseDiffData.LoadSet(sliderData, target, diff); + } + else { + if (workNif.CalcShapeDiff(shapeName, &shape->verts, diff, 1.0f)) + return false; + + morpher.SetResultDiff(target, sliderName, diff); + } + return true; + +} + void OutfitProject::SetSliderFromTRI(const string& sliderName, const string& shapeName, unordered_map& diff) { string target = ShapeToTarget(shapeName); if (IsBaseShape(shapeName)) { @@ -959,8 +1103,8 @@ void OutfitProject::CopyBoneWeights(const string& destShape, unordered_mapUpdateProgress(prog); - for (auto &bone : *boneList) { - string wtSet = bone + "_WT_"; + for (auto &boneName : *boneList) { + string wtSet = boneName + "_WT_"; morpher.GenerateResultDiff(destShape, wtSet, wtSet); unordered_map diffResult; @@ -970,7 +1114,7 @@ void OutfitProject::CopyBoneWeights(const string& destShape, unordered_map 0) { AnimBone boneRef; - AnimSkeleton::getInstance().GetBone(bone, boneRef); + AnimSkeleton::getInstance().GetBone(boneName, boneRef); if (workAnim.AddShapeBone(destShape, boneRef)) { - SkinTransform xForm; - workAnim.GetBoneXForm(bone, xForm); - workAnim.SetShapeBoneXForm(destShape, bone, xForm); + if (owner->targetGame == FO4) { + // Fallout 4 bone transforms are stored in a bonedata structure per shape versus the node transform in the skeleton data. + SkinTransform xForm; + Vector3 sphereOffset; + float sphereRadius; + workNif.GetShapeBoneTransform(baseShape, boneName, xForm, sphereOffset, sphereRadius); + + workAnim.SetShapeBoneXForm(destShape, boneName, xForm); + } + else { + SkinTransform xForm; + workAnim.GetBoneXForm(boneName, xForm); + workAnim.SetShapeBoneXForm(destShape, boneName, xForm); + + } } } - workAnim.SetWeights(destShape, bone, weights); + workAnim.SetWeights(destShape, boneName, weights); owner->UpdateProgress(prog += step, "Copying bone weights..."); } @@ -1045,9 +1201,21 @@ void OutfitProject::TransferSelectedWeights(const string& destShape, unordered_m AnimBone boneRef; AnimSkeleton::getInstance().GetBone(boneName, boneRef); if (workAnim.AddShapeBone(destShape, boneRef)) { - SkinTransform xForm; - workAnim.GetBoneXForm(boneName, xForm); - workAnim.SetShapeBoneXForm(destShape, boneName, xForm); + if (owner->targetGame == FO4) { + // Fallout 4 bone transforms are stored in a bonedata structure per shape versus the node transform in the skeleton data. + SkinTransform xForm; + Vector3 sphereOffset; + float sphereRadius; + workNif.GetShapeBoneTransform(baseShape, boneName, xForm, sphereOffset, sphereRadius); + + workAnim.SetShapeBoneXForm(destShape, boneName, xForm); + } + else { + SkinTransform xForm; + workAnim.GetBoneXForm(boneName, xForm); + workAnim.SetShapeBoneXForm(destShape, boneName, xForm); + + } } workAnim.SetWeights(destShape, boneName, weights); @@ -1552,8 +1720,9 @@ int OutfitProject::AddNif(const string& fileName, bool clear, const string& inOu AutoOffset(nif); nif.GetShapeList(nifShapes); - if (nifShapes.empty()) - return 0; + // don't want to exit here -- this function is used to generate a blank nif when an outfit is loaded from an .obj + //if (nifShapes.empty()) + // return 0; if (workNif.IsValid()) { for (auto &s : nifShapes) { @@ -1775,6 +1944,88 @@ int OutfitProject::SaveOutfitNif(const string& fileName, const vector& mo return clone.Save(fileName); } +int OutfitProject::ImportShapeFBX(const string& fileName, const string& shapeName, const string& mergeShape) { + FBXWrangler fbxw; + string invalidBones; + + bool result = fbxw.ImportScene(fileName); + if (!result) + return 1; + vectorshapes; + fbxw.GetShapeNames(shapes); + for (int i = 0; i < shapes.size(); i++) { + FBXShape* shape = fbxw.InShape(shapes[i]); + + string useShapeName = shapes[i]; + + if (mergeShape != "") { + vector shapeVerts; + workNif.GetVertsForShape(mergeShape, shapeVerts); + if (shapeVerts.size() == shape->numverts) { + int r = wxMessageBox("The vertex count of the selected .fbx file matches the currently selected outfit shape. Do you wish to update the current shape? (click No to create a new shape)", "Merge or New", wxYES_NO | wxICON_QUESTION); + if (r == wxYES) { + r = wxMessageBox("Update Vertex Positions?", "Vertex Position Update", wxYES_NO | wxICON_QUESTION); + if (r == wxYES) { + workNif.SetVertsForShape(mergeShape, shape->verts); + } + r = wxMessageBox("Update Animation Weighting?", "Animation Weight Update", wxYES_NO | wxICON_QUESTION); + if (r == wxYES) { + for (auto &bn : shape->boneNames) { + workAnim.SetWeights(mergeShape, bn, shape->boneSkin[bn].vertweights); + } + } + return 101; + } + } + useShapeName = wxGetTextFromUser("Please specify a name for the new shape", "New Shape Name", useShapeName); + if (useShapeName == "") + return 100; + } + + + int slot = 0; + for (auto &bn : shape->boneNames) { + if (!AnimSkeleton::getInstance().RefBone(bn)) { + // no bone reference exist for this bone name. + AnimBone& cstm = AnimSkeleton::getInstance().AddBone(bn, true); + if (!cstm.isValidBone) + invalidBones += bn + "\n"; + // using default transformation data, needs to be set up later somehow.... + AnimSkeleton::getInstance().RefBone(bn); + } + workAnim.shapeBones[useShapeName].push_back(bn); + workAnim.shapeSkinning[useShapeName].boneNames[bn] = slot; + workAnim.SetWeights(useShapeName, bn, shape->boneSkin[bn].vertweights); + // workAnim.shapeSkinning[useShapeName].boneWeights[slot].weights = shape->boneSkin[bn].vertweights; + slot++; + } + + CreateNifShapeFromData(shapes[i], shape->verts, shape->tris, shape->uvs, &shape->normals); + } + return 0; +} + +int OutfitProject::ExportShapeFBX(const string& fileName, const string& shapeName) { + FBXWrangler fbxw; + fbxw.NewScene(); + /*if (shapeName != "") { + vector tris; + workNif.GetTrisForShape(shapeName, &tris); + const vector* verts = workNif.GetRawVertsForShape(shapeName); + const vector* norms = workNif.GetNormalsForShape(shapeName); + const vector* uvs = workNif.GetUvsForShape(shapeName); + fbxw.AddGeometry(shapeName, verts, norms, &tris, uvs); + }*/ + + fbxw.AddSkeleton(&AnimSkeleton::getInstance().refSkeletonNif); + fbxw.AddNif(&workNif, shapeName, false); + fbxw.AddSkinning(&workAnim, shapeName); + //fbxw.AddNif(&AnimSkeleton::getInstance().refSkeletonNif); + //fbxw.AddSkeleton(); + + return fbxw.ExportScene(fileName); +} + int OutfitProject::ExportShapeObj(const string& fileName, const string& shapeName, Vector3 scale, Vector3 offset) { vector tris; workNif.GetTrisForShape(shapeName, &tris); diff --git a/OutfitProject.h b/OutfitProject.h index 7a584b24..fb04cacd 100644 --- a/OutfitProject.h +++ b/OutfitProject.h @@ -15,6 +15,7 @@ See the included LICENSE file #include "OutfitStudio.h" #include "ConfigurationManager.h" #include "Anim.h" +#include #include #include @@ -51,7 +52,6 @@ class OutfitProject { // inOwner is meant to provide access to OutfitStudio for the purposes of reporting process status only. OutfitProject(ConfigurationManager& inConfig, OutfitStudio* inOwner = nullptr); ~OutfitProject(); - string mFileName; string mOutfitName; string mDataDir; @@ -102,7 +102,10 @@ class OutfitProject { void AddZapSlider(const string& newName, unordered_map& verts, const string& shapeName); void AddCombinedSlider(const string& newName); - int AddShapeFromObjFile(const string& fileName, const string& shapeName, const string& mergeShape = ""); + // AddShapeFromObjFile - shapeName is modified during a successful import to reflect the name of the news hape. + int AddShapeFromObjFile(const string& fileName, string& shapeName, const string& mergeShape = ""); + + int CreateNifShapeFromData(const string& shapeName, vector& v, vector& t, vector& uv, vector* norms = nullptr); // Slider data can have a separate name from the shape target. string SliderShapeDataName(int index, const string& shapeName); @@ -122,6 +125,7 @@ class OutfitProject { void SetSliderFromBSD(const string& sliderName, const string& shapeName, const string& fileName); bool SetSliderFromOBJ(const string& sliderName, const string& shapeName, const string& fileName); + bool SetSliderFromFBX(const string& sliderName, const string& shapeName, const string& fileName); void SetSliderFromTRI(const string& sliderName, const string& shapeName, unordered_map& diff); int SaveSliderBSD(const string& sliderName, const string& shapeName, const string& fileName); int SaveSliderOBJ(const string& sliderName, const string& shapeName, const string& fileName); @@ -224,6 +228,8 @@ class OutfitProject { void UpdateNifNormals(NifFile* nif, const vector& shapemeshes); int SaveOutfitNif(const string& fileName, const vector& modMeshes, bool writeNormals, bool withRef = false); + int ImportShapeFBX(const string& fileName, const string& shapeName = "", const string& mergeShape = ""); + int ExportShapeFBX(const string& fileName, const string& shapeName = ""); int ExportShapeObj(const string& fileName, const string& shapeName, Vector3 scale = Vector3(1.0f, 1.0f, 1.0f), Vector3 offset = Vector3()); /* Creates an abbreviated name for use in data file identifiers. Mostly removes spaces and other special characters. */ diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index 9b852739..0975ef53 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -57,6 +57,7 @@ BEGIN_EVENT_TABLE(OutfitStudio, wxFrame) EVT_MENU(XRCID("sliderConformAll"), OutfitStudio::OnSliderConformAll) EVT_MENU(XRCID("sliderImportBSD"), OutfitStudio::OnSliderImportBSD) EVT_MENU(XRCID("sliderImportOBJ"), OutfitStudio::OnSliderImportOBJ) + EVT_MENU(XRCID("sliderImportFBX"), OutfitStudio::OnSliderImportFBX) EVT_MENU(XRCID("sliderImportTRI"), OutfitStudio::OnSliderImportTRI) EVT_MENU(XRCID("sliderExportBSD"), OutfitStudio::OnSliderExportBSD) EVT_MENU(XRCID("sliderExportOBJ"), OutfitStudio::OnSliderExportOBJ) @@ -105,6 +106,8 @@ BEGIN_EVENT_TABLE(OutfitStudio, wxFrame) EVT_MENU(XRCID("importShape"), OutfitStudio::OnImportShape) EVT_MENU(XRCID("exportShape"), OutfitStudio::OnExportShape) + EVT_MENU(XRCID("importFBX"), OutfitStudio::OnImportFBX) + EVT_MENU(XRCID("exportFBX"), OutfitStudio::OnExportFBX) EVT_MENU(XRCID("moveShape"), OutfitStudio::OnMoveShape) EVT_MENU(XRCID("scaleShape"), OutfitStudio::OnScaleShape) EVT_MENU(XRCID("rotateShape"), OutfitStudio::OnRotateShape) @@ -142,13 +145,14 @@ BEGIN_EVENT_TABLE(OutfitStudio, wxFrame) EVT_SLIDER(XRCID("lightBrightnessSlider2"), OutfitStudio::OnUpdateLights) EVT_SLIDER(XRCID("lightBrightnessSlider3"), OutfitStudio::OnUpdateLights) EVT_BUTTON(XRCID("lightReset"), OutfitStudio::OnResetLights) + + EVT_DROP_FILES(OutfitStudio::OnDropFiles) EVT_MOVE_END(OutfitStudio::OnMoveWindow) EVT_SIZE(OutfitStudio::OnSetSize) END_EVENT_TABLE() - // ---------------------------------------------------------------------------- // OutfitStudio frame // ---------------------------------------------------------------------------- @@ -184,6 +188,19 @@ OutfitStudio::OutfitStudio(wxWindow* parent, const wxPoint& pos, const wxSize& s statusBar->SetStatusWidths(3, statusWidths); statusBar->SetStatusText("Ready!"); } + +/* + HWND h = this->GetHandle(); + bool ret = ChangeWindowsMessageFilterEX(h, WM_DROPFILES, MSGFLT_ADD); + if (!ret) { + wxMessageBox("blargh"); + } + ret = ChangeWindowMessageFilterEX(h,WM_COPYDATA, MSGFLT_ADD); + ret = ChangeWindowMessageFilterEX(h,WM_COPY, MSGFLT_ADD); + ret = ChangeWindowMessageFilterEX(h,WM_MOVE, MSGFLT_ADD); + ret = ChangeWindowMessageFilterEX(h,0x0049, MSGFLT_ADD); +*/ + this->DragAcceptFiles(true); toolBar = (wxToolBar*)FindWindowByName("toolbar"); if (toolBar) { @@ -225,6 +242,10 @@ OutfitStudio::OutfitStudio(wxWindow* parent, const wxPoint& pos, const wxSize& s if (outfitShapes) { outfitShapes->AssignStateImageList(visStateImages); shapesRoot = outfitShapes->AddRoot("Shapes"); + + outfitShapes->DragAcceptFiles(true); + outfitShapes->Bind(wxEVT_DROP_FILES, wxDropFilesEventHandler(OutfitStudio::OnDropFiles), this); + } outfitBones = (wxTreeCtrl*)FindWindowByName("outfitBones"); @@ -433,18 +454,27 @@ void OutfitStudio::createSliderGUI(const string& name, int id, wxScrolledWindow* sliderDisplays[name] = d; } -string OutfitStudio::NewSlider() { +string OutfitStudio::NewSlider(const string& suggestedName, bool skipPrompt) { string namebase = "NewSlider"; + if (suggestedName != "") + { + namebase = suggestedName; + } char thename[256]; _snprintf_s(thename, 256, 256, "%s", namebase.c_str()); int count = 1; while (sliderDisplays.find(thename) != sliderDisplays.end()) _snprintf_s(thename, 256, 256, "%s%d", namebase.c_str(), count++); - - string finalName = wxGetTextFromUser("Enter a name for the new slider:", "Create New Slider", thename, this); - if (finalName.empty()) - return finalName; + string finalName; + if (!skipPrompt) { + string finalName = wxGetTextFromUser("Enter a name for the new slider:", "Create New Slider", thename, this); + if (finalName.empty()) + return finalName; + } + else { + finalName = thename; + } finalName = project->NameAbbreviate(finalName); wxLogMessage("Creating new slider '%s'.", finalName); @@ -1199,7 +1229,12 @@ void OutfitStudio::WorkingGUIFromProj() { for (auto &shape : shapes) { glView->DeleteMesh(shape); - glView->AddMeshFromNif(project->GetWorkNif(), shape); + glView->AddMeshFromNif(project->GetWorkNif(), shape, shapeIsImporting(shape)); + if (shapeIsImporting(shape)) { + vector updateshape; + updateshape.push_back(glView->GetMesh(shape)); + project->UpdateNifNormals(project->GetWorkNif(), updateshape); + } glView->SetMeshTexture(shape, project->GetShapeTexture(shape), project->GetWorkNif()->IsShaderSkin(shape)); if (outfitShapes) { subItem = outfitShapes->AppendItem(outfitRoot, shape); @@ -2516,6 +2551,30 @@ void OutfitStudio::OnSliderImportTRI(wxCommandEvent& WXUNUSED(event)) { wxMessageBox(wxString::Format("Added morphs for the following shapes:\n\n%s", addedMorphs), "TRI Import"); } +void OutfitStudio::OnSliderImportFBX(wxCommandEvent& event) { + if (!activeItem) { + wxMessageBox("There is no shape selected!", "Error"); + return; + } + if (!bEditSlider) { + wxMessageBox("There is no slider in edit mode to import data to!", "Error"); + return; + } + + string fn = wxFileSelector("Import .fbx file for slider calculation", wxEmptyString, wxEmptyString, ".fbx", "*.fbx", wxFD_FILE_MUST_EXIST, this); + if (fn.empty()) + return; + + wxLogMessage("Importing slider to '%s' for shape '%s' from FBX file '%s'...", activeSlider, activeItem->shapeName, fn); + if (!project->SetSliderFromFBX(activeSlider, activeItem->shapeName, fn)) { + wxLogError("Vertex count of .obj file mesh does not match currently selected shape!"); + wxMessageBox("Vertex count of .obj file mesh does not match currently selected shape!", "Error", wxICON_ERROR); + return; + } + + ApplySliders(); +} + void OutfitStudio::OnSliderExportBSD(wxCommandEvent& WXUNUSED(event)) { if (!activeItem) { wxMessageBox("There is no shape selected!", "Error"); @@ -2571,6 +2630,7 @@ void OutfitStudio::OnSliderExportOBJ(wxCommandEvent& WXUNUSED(event)) { } } else { + /* string fn = wxFileSelector("Export .obj slider data", wxEmptyString, wxEmptyString, ".obj", "*.obj", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this); if (fn.empty()) return; @@ -2580,6 +2640,20 @@ void OutfitStudio::OnSliderExportOBJ(wxCommandEvent& WXUNUSED(event)) { wxLogError("Failed to export OBJ file '%s'!", fn); wxMessageBox("Failed to export OBJ file!", "Error", wxICON_ERROR); } + */ + // TEMPORARY bulk slider export + string dir = wxDirSelector("Export .obj slider data to directory", wxEmptyString, wxDD_DIR_MUST_EXIST, wxDefaultPosition, this); + vector sliderNames; + project->GetSliderList(sliderNames); + + for (auto s : sliderNames) { + statusBar->SetStatusText("Exporting " + s); + string fn = dir; + fn += "\\" + s + ".obj"; + project->SaveSliderOBJ(s, activeItem->shapeName, fn); + + } + statusBar->SetStatusText("Ready!"); } ApplySliders(); @@ -2902,11 +2976,13 @@ void OutfitStudio::OnImportShape(wxCommandEvent& WXUNUSED(event)) { wxLogMessage("Importing shape from OBJ file '%s'...", fn); + string shapeName = "New Shape"; + int ret; if (activeItem) - ret = project->AddShapeFromObjFile(fn, "New Shape", activeItem->shapeName); + ret = project->AddShapeFromObjFile(fn, shapeName, activeItem->shapeName); else - ret = project->AddShapeFromObjFile(fn, "New Shape"); + ret = project->AddShapeFromObjFile(fn, shapeName); if (ret == 101) { // User chose to merge shapes vector v; @@ -2920,6 +2996,9 @@ void OutfitStudio::OnImportShape(wxCommandEvent& WXUNUSED(event)) { wxLogMessage("Imported shape."); WorkingGUIFromProj(); + + finishImporting(); + glView->Refresh(); } @@ -2954,6 +3033,59 @@ void OutfitStudio::OnExportShape(wxCommandEvent& WXUNUSED(event)) { } } +void OutfitStudio::OnImportFBX(wxCommandEvent& event) { + string fn = wxFileSelector("Import .fbx file for new shape", wxEmptyString, wxEmptyString, ".fbx", "*.fbx", wxFD_FILE_MUST_EXIST, this); + if (fn.empty()) + return; + wxLogMessage("Importing shape from FBX file '%s'...", fn); + + string shapeName = "New Shape"; + + int ret; + if (activeItem) { + ret = project->ImportShapeFBX(fn, shapeName, activeItem->shapeName); + } + else { + ret = project->ImportShapeFBX(fn, shapeName); + } + if (ret == 101) { + vector v; + project->GetLiveVerts(activeItem->shapeName, v); + glView->UpdateMeshVertices(activeItem->shapeName, &v); + return; + } + if (ret) + return; + + wxLogMessage("Imported shape."); + + WorkingGUIFromProj(); + AnimationGUIFromProj(); + + finishImporting(); + + glView->Refresh(); +} + +void OutfitStudio::OnExportFBX(wxCommandEvent& event) { + string defFile = "OutfitStudioShapes.fbx"; + if (activeItem) + defFile = activeItem->shapeName + ".fbx"; + + string fn = wxFileSelector("Export .fbx file for new shape", wxEmptyString, defFile, "", "FBX Files (*.fbx)|*.fbx", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this); + if (fn.empty()) + return; + + if (activeItem){ + project->ExportShapeFBX(fn, activeItem->shapeName); + } + else { + project->ExportShapeFBX(fn, ""); + } + + +} + void OutfitStudio::OnRenameShape(wxCommandEvent& WXUNUSED(event)) { if (!activeItem) { wxMessageBox("There is no shape selected!", "Error"); @@ -3374,7 +3506,7 @@ void OutfitStudio::OnDupeShape(wxCommandEvent& WXUNUSED(event)) { mesh* curshapemesh = glView->GetMesh(activeItem->shapeName); project->DuplicateShape(activeItem->shapeName, newname, curshapemesh); - glView->AddMeshFromNif(project->GetWorkNif(), newname); + glView->AddMeshFromNif(project->GetWorkNif(), newname, false); project->SetTexture(newname, "_AUTO_"); glView->SetMeshTexture(newname, project->GetShapeTexture(newname), project->GetWorkNif()->IsShaderSkin(newname)); @@ -3642,6 +3774,24 @@ void OutfitStudio::OnShapeProperties(wxCommandEvent& WXUNUSED(event)) { prop.ShowModal(); } +void OutfitStudio::OnDropFiles(wxDropFilesEvent& event) { + if (event.GetNumberOfFiles() > 0) { + wxString* dropped = event.GetFiles(); + wxArrayString files; + for (int i = 0; i < event.GetNumberOfFiles(); i++) { + wxString name = dropped[i]; + if (wxFileExists(name)) { + if (name.EndsWith (".nif") || name.EndsWith(".obj")) + files.push_back(name); + } + } + for (auto f : files) { + wxMessageBox(f, "flie dropped"); + } + } + +} + void OutfitStudio::OnNPWizChangeSliderSetFile(wxFileDirPickerEvent& event) { string fn = event.GetPath(); vector shapes; @@ -3812,7 +3962,7 @@ void wxGLPanel::SetNotifyWindow(wxWindow* win) { notifyWindow = win; } -void wxGLPanel::AddMeshFromNif(NifFile* nif, const string& shapeName) { +void wxGLPanel::AddMeshFromNif(NifFile* nif, const string& shapeName, bool buildNormals) { vector shapeList; nif->GetShapeList(shapeList); @@ -3827,7 +3977,11 @@ void wxGLPanel::AddMeshFromNif(NifFile* nif, const string& shapeName) { gls.GetMesh(shapeList[i])->BuildTriAdjacency(); gls.GetMesh(shapeList[i])->BuildEdgeList(); gls.GetMesh(shapeList[i])->ColorFill(Vector3()); - RecalcNormals(shapeList[i]); + + // Removed -- smoothing normals here breaks fallout 4 mesh normals. meshes without normals have their normals calculated/smoothed during mesh load. + if (buildNormals) { + RecalcNormals(shapeList[i], true); + } } } @@ -4589,40 +4743,49 @@ bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames) { bool DnDSliderFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames) { if (owner) { - wxString inputFile; - if (fileNames.GetCount() > 0) - inputFile = fileNames.Item(0); - - bool isBSD = inputFile.MakeLower().EndsWith(".bsd"); - bool isOBJ = inputFile.MakeLower().EndsWith(".obj"); - if (isBSD || isOBJ) { - if (!owner->activeItem) { - wxMessageBox("There is no shape selected!", "Error"); - return false; - } + bool isMultiple = (fileNames.GetCount() > 1); + for (int i = 0; iactiveItem) { + wxMessageBox("There is no shape selected!", "Error"); + return false; + } - if (lastResult == wxDragCopy) - targetSlider = owner->NewSlider(); + if (lastResult == wxDragCopy) { + targetSlider = owner->NewSlider(dataName.ToStdString(),isMultiple); + } - if (targetSlider.empty()) - return false; + if (targetSlider.empty()) + return false; - owner->StartProgress("Loading slider file..."); - owner->UpdateProgress(1.0f, "Loading slider file..."); + owner->StartProgress("Loading slider file..."); + owner->UpdateProgress(1.0f, "Loading slider file..."); - if (isBSD) - owner->project->SetSliderFromBSD(targetSlider, owner->activeItem->shapeName, inputFile.ToStdString()); - else if (isOBJ) - owner->project->SetSliderFromOBJ(targetSlider, owner->activeItem->shapeName, inputFile.ToStdString()); - else - return false; + if (isBSD) + owner->project->SetSliderFromBSD(targetSlider, owner->activeItem->shapeName, inputFile.ToStdString()); + else if (isOBJ) + owner->project->SetSliderFromOBJ(targetSlider, owner->activeItem->shapeName, inputFile.ToStdString()); + else if (isFBX) + owner->project->SetSliderFromFBX(targetSlider, owner->activeItem->shapeName, inputFile.ToStdString()); + else + return false; - owner->EnterSliderEdit(targetSlider); - targetSlider.clear(); - owner->UpdateProgress(100.0f, "Finished."); - owner->EndProgress(); + owner->UpdateProgress(100.0f, "Finished."); + owner->EndProgress(); + } } + owner->EnterSliderEdit(targetSlider); + targetSlider.clear(); } else return false; diff --git a/OutfitStudio.h b/OutfitStudio.h index c90c7fd7..4fa2f9ea 100644 --- a/OutfitStudio.h +++ b/OutfitStudio.h @@ -26,6 +26,7 @@ along with this program. If not, see . #include "ObjFile.h" #include "TweakBrush.h" #include "Automorph.h" +#include "FBXWrangler.h" #include "OutfitProject.h" #include "ConfigurationManager.h" @@ -40,7 +41,6 @@ along with this program. If not, see . #include #include - enum TargetGame { FO3, FONV, SKYRIM, FO4 }; @@ -64,7 +64,7 @@ class wxGLPanel : public wxGLCanvas { void SetNotifyWindow(wxWindow* win); - void AddMeshFromNif(NifFile* nif, const string& shapeName); + void AddMeshFromNif(NifFile* nif, const string& shapeName, bool buildNormals); void AddExplicitMesh(vector* v, vector* t, vector* uv = nullptr, const string& shapeName = ""); void RenameShape(const string& shapeName, const string& newShapeName) { @@ -176,12 +176,15 @@ class wxGLPanel : public wxGLCanvas { m->SmoothNormals(); } - void RecalcNormals(const string& shape) { + void RecalcNormals(const string& shape, bool forceSmoothSeam = false) { mesh* m = gls.GetMesh(shape); if (!m) return; - - m->SmoothNormals(); + if (forceSmoothSeam) { + m->smoothSeamNormals = true; + m->SmoothNormals(); + m->smoothSeamNormals = false; + } } void ToggleAutoNormals() { if (bAutoNormals) @@ -480,7 +483,7 @@ class OutfitStudio : public wxFrame { void CreateSetSliders(); - string NewSlider(); + string NewSlider(const string& suggestedName = "", bool skipPrompt = false); void SetSliderValue(int index, int val); void SetSliderValue(const string& name, int val); @@ -637,12 +640,38 @@ class OutfitStudio : public wxFrame { progWnd->Update(progressVal, msg); } + + bool shapeIsImporting(const string& shapeName) { + auto ss = shapeStates.find(shapeName); + if (ss != shapeStates.end()) { + return ss->second.bIsImporting; + } + return false; + } + void setShapeImporting(const string& shapeName, bool isOn) { + shapeStates[shapeName].bIsImporting = isOn; + } + void finishImporting() { + for (auto &ss : shapeStates) { + ss.second.bIsImporting = false; + } + } + private: + class ShapeState { // metadata state of shapes by shape name + public: + TargetGame gameType; // game type source (affects block types in nif) + bool bIsImporting; // true if shape is currently in the process of being imported from .obj (lacking normals, textures, etc.) + ShapeState() : gameType(SKYRIM), bIsImporting(false) {} + }; + bool previousMirror; Vector3 previewMove; float previewScale; Vector3 previewRotation; + map shapeStates; + void createSliderGUI(const string& name, int id, wxScrolledWindow* wnd, wxSizer* rootSz); void HighlightSlider(const string& name); void ZeroSliders(); @@ -714,6 +743,7 @@ class OutfitStudio : public wxFrame { void OnSliderImportBSD(wxCommandEvent& event); void OnSliderImportOBJ(wxCommandEvent& event); void OnSliderImportTRI(wxCommandEvent& event); + void OnSliderImportFBX(wxCommandEvent& event); void OnSliderExportBSD(wxCommandEvent& event); void OnSliderExportOBJ(wxCommandEvent& event); void OnSliderExportTRI(wxCommandEvent& event); @@ -728,6 +758,8 @@ class OutfitStudio : public wxFrame { void OnImportShape(wxCommandEvent& event); void OnExportShape(wxCommandEvent& event); + void OnImportFBX(wxCommandEvent& event); + void OnExportFBX(wxCommandEvent& event); void OnEnterClose(wxKeyEvent& event); @@ -759,6 +791,7 @@ class OutfitStudio : public wxFrame { void OnMaskWeighted(wxCommandEvent& event); void OnBuildSkinPartitions(wxCommandEvent& event); void OnShapeProperties(wxCommandEvent& event); + void OnDropFiles(wxDropFilesEvent& event); void OnNPWizChangeSliderSetFile(wxFileDirPickerEvent& event); void OnNPWizChangeSetNameChoice(wxCommandEvent& event); diff --git a/OutfitStudio.h.orig b/OutfitStudio.h.orig new file mode 100644 index 00000000..ca733ff4 --- /dev/null +++ b/OutfitStudio.h.orig @@ -0,0 +1,968 @@ +/* +BodySlide and Outfit Studio +Copyright(C) 2015 Caliente & ousnius + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#pragma once + +#include "stdafx.h" +#include "wxStateButton.h" +#include "GLSurface.h" +#include "SliderData.h" +#include "SliderPresets.h" +#include "ObjFile.h" +#include "TweakBrush.h" +#include "Automorph.h" +#include "FBXWrangler.h" +#include "OutfitProject.h" +#include "ConfigurationManager.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum TargetGame { + FO3, FONV, SKYRIM, FO4 +}; + + +class ShapeItemData : public wxTreeItemData { +public: + NifFile* refFile; + string shapeName; + ShapeItemData(NifFile* inRefFile = nullptr, const string& inShapeName = "") { + refFile = inRefFile; + shapeName = inShapeName; + } +}; + + +class wxGLPanel : public wxGLCanvas { +public: + wxGLPanel(wxWindow* parent, const wxSize& size, const int* attribs); + ~wxGLPanel(); + + void SetNotifyWindow(wxWindow* win); + + void AddMeshFromNif(NifFile* nif, const string& shapeName, bool buildNormals); + void AddExplicitMesh(vector* v, vector* t, vector* uv = nullptr, const string& shapeName = ""); + + void RenameShape(const string& shapeName, const string& newShapeName) { + gls.RenameMesh(shapeName, newShapeName); + } + + void SetMeshTexture(const string& shapeName, const string& texturefile, bool isSkin = false); + + mesh* GetMesh(const string& shapeName) { + return gls.GetMesh(shapeName); + } + + void UpdateMeshVertices(const string& shapeName, vector* verts, bool updateBVH = true, bool recalcNormals = true); + void RecalculateMeshBVH(const string& shapeName); + + void ShowShape(const string& shapeName, bool show = true); + void SetActiveShape(const string& shapeName); + + TweakUndo* GetStrokeManager() { + return strokeManager; + } + void SetStrokeManager(TweakUndo* manager) { + if (!manager) + strokeManager = &baseStrokes; + else + strokeManager = manager; + } + + void SetActiveBrush(int brushID); + TweakBrush* GetActiveBrush() { + return activeBrush; + } + + bool StartBrushStroke(const wxPoint& screenPos); + void UpdateBrushStroke(const wxPoint& screenPos); + void EndBrushStroke(); + + bool StartTransform(const wxPoint& screenPos); + void UpdateTransform(const wxPoint& screenPos); + void EndTransform(); + + bool UndoStroke(); + bool RedoStroke(); + + void ShowTransformTool(bool show = true, bool updateBrush = true); + + void SetEditMode(bool on = true) { + editMode = on; + } + void ToggleEditMode() { + if (transformMode != 0) { + transformMode = 0; + editMode = true; + ShowTransformTool(false); + } + else { + editMode = false; + transformMode = 1; + ShowTransformTool(); + } + } + bool GetXMirror() { + return bXMirror; + } + void SetXMirror(bool on = true) { + bXMirror = on; + } + void ToggleXMirror() { + if (bXMirror) + bXMirror = false; + else + bXMirror = true; + } + void ToggleConnectedEdit() { + if (bConnectedEdit) + bConnectedEdit = false; + else + bConnectedEdit = true; + } + + void SetShapeGhostMode(const string& shapeName, bool on = true) { + mesh* m = gls.GetMesh(shapeName); + if (!m) return; + if (on) + m->rendermode = RenderMode::LitWire; + else + m->rendermode = RenderMode::Normal; + } + void ToggleGhostMode() { + mesh* m = gls.GetActiveMesh(); + if (!m) + return; + + if (m->rendermode == RenderMode::Normal) + m->rendermode = RenderMode::LitWire; + else if (m->rendermode == RenderMode::LitWire) + m->rendermode = RenderMode::Normal; + } + + void ToggleNormalSeamSmoothMode() { + mesh* m = gls.GetActiveMesh(); + if (!m) + return; + + if (m->smoothSeamNormals == true) + m->smoothSeamNormals = false; + else + m->smoothSeamNormals = true; + m->SmoothNormals(); + } + + void RecalcNormals(const string& shape, bool forceSmoothSeam = false) { + mesh* m = gls.GetMesh(shape); + if (!m) + return; + if (forceSmoothSeam) { + m->smoothSeamNormals = true; + m->SmoothNormals(); + m->smoothSeamNormals = false; + } + } + void ToggleAutoNormals() { + if (bAutoNormals) + bAutoNormals = false; + else + bAutoNormals = true; + } + float GetBrushSize() { + return brushSize / 3.0f; + } + void SetBrushSize(float val) { + val *= 3.0f; + brushSize = val; + gls.SetCursorSize(val); + } + + float IncBrush() { + gls.SetCursorSize(gls.GetCursorSize() + 0.010f); + brushSize += 0.010f; + LimitBrushSize(); + return brushSize; + } + float DecBrush() { + gls.SetCursorSize(gls.GetCursorSize() - 0.010f); + brushSize -= 0.010f; + LimitBrushSize(); + return brushSize; + } + void LimitBrushSize() { + if (brushSize < 0.000f) { + gls.SetCursorSize(0.000f); + brushSize = 0.000f; + } + else if (brushSize > 3.000f) { + gls.SetCursorSize(3.000f); + brushSize = 3.000f; + } + } + + float IncStr() { + if (!activeBrush) + return 0.0f; + + float str = activeBrush->getStrength(); + str += 0.010f; + activeBrush->setStrength(str); + return str; + } + float DecStr() { + if (!activeBrush) + return 0.0f; + + float str = activeBrush->getStrength(); + str -= 0.010f; + activeBrush->setStrength(str); + return str; + } + + void ShowWireframe() { + gls.ToggleWireframe(); + } + void ToggleLighting() { + gls.ToggleLighting(); + } + void ToggleTextures() { + gls.ToggleTextures(); + } + void ToggleMaskVisible() { + mesh* m = gls.GetActiveMesh(); + if (!m->vcolors) { + m->vcolors = new Vector3[m->nVerts]; + memset(m->vcolors, 0, 12 * m->nVerts); + } + gls.ToggleMask(); + } + void SetWeightVisible(bool bVisible = true) { + gls.SetWeightColors(bVisible); + } + + void ClearMask() { + mesh* m = gls.GetActiveMesh(); + if (m->vcolors) + m->ColorChannelFill(0, 0.0f); + } + + void GetActiveMask(unordered_map& mask) { + mesh* m = gls.GetActiveMesh(); + if (!m->vcolors) + return; + + for (int i = 0; i < m->nVerts; i++) { + if (m->vcolors[i].x != 0.0f) + mask[i] = m->vcolors[i].x; + } + } + + void GetActiveUnmasked(unordered_map& mask) { + mesh* m = gls.GetActiveMesh(); + if (!m->vcolors) { + for (int i = 0; i < m->nVerts; i++) + mask[i] = 0.0f; + return; + } + for (int i = 0; i < m->nVerts; i++) + if (m->vcolors[i].x == 0.0f) + mask[i] = m->vcolors[i].x; + } + + void GetShapeMask(unordered_map& mask, const string& shapeName) { + mesh* m = gls.GetMesh(shapeName); + if (!m || !m->vcolors) + return; + + for (int i = 0; i < m->nVerts; i++) { + if (m->vcolors[i].x != 0.0f) + mask[i] = m->vcolors[i].x; + } + } + + void GetShapeUnmasked(unordered_map& mask, const string& shapeName) { + mesh* m = gls.GetMesh(shapeName); + if (!m) + return; + + if (!m->vcolors) { + for (int i = 0; i < m->nVerts; i++) + mask[i] = 0.0f; + return; + } + for (int i = 0; i < m->nVerts; i++) + if (m->vcolors[i].x == 0.0f) + mask[i] = m->vcolors[i].x; + } + + void InvertMask() { + mesh* m = gls.GetActiveMesh(); + if (!m->vcolors) + m->ColorFill(Vector3(0.0f, 0.0f, 0.0f)); + for (int i = 0; i < m->nVerts; i++) + m->vcolors[i].x = 1 - m->vcolors[i].x; + } + + void DeleteMesh(const string& shape) { + gls.DeleteMesh(shape); + Refresh(); + } + void DestroyOverlays() { + gls.DeleteOverlays(); + Refresh(); + } + + void SetView(const char& type) { + gls.SetView(type); + Refresh(); + } + + void SetPerspective(const bool& enabled) { + gls.SetPerspective(enabled); + Refresh(); + } + + void SetFieldOfView(const int& fieldOfView) { + gls.SetFieldOfView(fieldOfView); + Refresh(); + } + + void UpdateLights(const int& ambient = 50, const int& brightness1 = 50, const int& brightness2 = 50, const int& brightness3 = 50) { + gls.UpdateLights(ambient, brightness1, brightness2, brightness3); + Refresh(); + } + + +private: + void OnShown(); + void OnPaint(wxPaintEvent& event); + void OnSize(wxSizeEvent& event); + + void OnMouseWheel(wxMouseEvent& event); + void OnMouseMove(wxMouseEvent& event); + + void OnMiddleDown(wxMouseEvent& event); + void OnMiddleUp(wxMouseEvent& event); + void OnLeftDown(wxMouseEvent& event); + void OnLeftUp(wxMouseEvent& event); + + void OnRightDown(wxMouseEvent& event); + void OnRightUp(wxMouseEvent& event); + + void OnKeys(wxKeyEvent& event); + void OnIdle(wxIdleEvent& event); + + void OnCaptureLost(wxMouseCaptureLostEvent& event); + + GLSurface gls; + wxGLContext* context; + + bool rbuttonDown; + bool lbuttonDown; + bool mbuttonDown; + bool isLDragging; + bool isMDragging; + bool isRDragging; + bool firstPaint{true}; + + int lastX; + int lastY; + + set BVHUpdateQueue; + + wxWindow* notifyWindow; + + float brushSize; + bool editMode; + bool transformMode; // 0 = off, 1 = move, 2 = rotate, 3 = scale + bool bMaskPaint; + bool bWeightPaint; + bool isPainting; + bool isTransforming; + bool bXMirror; + bool bAutoNormals; + bool bConnectedEdit; + + TweakBrush* activeBrush; + TweakBrush* savedBrush; + TweakBrush standardBrush; + TB_Deflate deflateBrush; + TB_Move moveBrush; + TB_Smooth smoothBrush; + TB_Mask maskBrush; + TB_Unmask UnMaskBrush; + TB_Weight weightBrush; + TB_Unweight unweightBrush; + TB_SmoothWeight smoothWeightBrush; + TB_XForm translateBrush; + + TweakStroke* activeStroke; + TweakUndo* strokeManager; + TweakUndo baseStrokes; + + Vector3 xformCenter; // Transform center for transform brushes (rotate, specifically cares about this) + + DECLARE_EVENT_TABLE() +}; + +class OutfitProject; + +class OutfitStudio : public wxFrame { +public: + OutfitStudio(wxWindow* parent, const wxPoint& pos, const wxSize& size, ConfigurationManager& inConfig); + ~OutfitStudio(); + + int targetGame; + wxGLPanel* glView = nullptr; + OutfitProject* project = nullptr; + ShapeItemData* activeItem = nullptr; + vector selectedItems; + string activeSlider; + string activeBone; + bool bEditSlider; + + wxTreeCtrl* outfitShapes; + wxTreeCtrl* outfitBones; + wxPanel* lightSettings; + wxSlider* boneScale; + wxScrolledWindow* sliderScroll; + wxStatusBar* statusBar; + wxToolBar* toolBar; + wxTreeItemId shapesRoot; + wxTreeItemId outfitRoot; + wxTreeItemId bonesRoot; + wxImageList* visStateImages; + + ConfigurationManager& appConfig; + + class SliderDisplay { + public: + bool hilite; + wxPanel* sliderPane; + wxBoxSizer* paneSz; + + int sliderNameCheckID; + int sliderID; + + wxBitmapButton* btnSliderEdit; + wxButton* btnMinus; + wxButton* btnPlus; + wxCheckBox* sliderNameCheck; + wxStaticText* sliderName; + wxSlider* slider; + wxTextCtrl* sliderReadout; + + TweakUndo sliderStrokes; // This probably shouldn't be here, but it's a convenient location to store undo info. + }; + + map sliderDisplays; + + void CreateSetSliders(); + + string NewSlider(); + + void SetSliderValue(int index, int val); + void SetSliderValue(const string& name, int val); + + void ApplySliders(bool recalcBVH = true); + + void ShowSliderEffect(int slider, bool show = true); + void ShowSliderEffect(const string& sliderName, bool show = true); + + void SelectShape(const string& shapeName); + vector GetShapeList(); + + void UpdateShapeSource(const string& shapeName); + int PromptUpdateBase(); + + void ActiveShapeUpdated(TweakStroke* refStroke, bool bIsUndo = false, bool setWeights = true); + void UpdateActiveShapeUI(); + + void RefreshGUIFromProj(); + + string GetActiveBone(); + + bool NotifyStrokeStarting(); + + bool IsDirty(); + bool IsDirty(const string& shapeName); + void SetClean(const string& shapeName); + + void EnterSliderEdit(const string& sliderName); + void ExitSliderEdit(); + void MenuEnterSliderEdit(); + void MenuExitSliderEdit(); + + void ToggleBrushPane() { + wxCollapsiblePane* brushPane = (wxCollapsiblePane*)FindWindowByName("brushPane"); + if (!brushPane) + return; + + brushPane->Collapse(!brushPane->IsCollapsed()); + + wxWindow* leftPanel = FindWindowByName("leftSplitPanel"); + if (leftPanel) + leftPanel->Layout(); + } + + void UpdateBrushPane() { + TweakBrush* brush = glView->GetActiveBrush(); + if (!brush) + return; + + wxCollapsiblePane* parent = (wxCollapsiblePane*)FindWindowByName("brushPane"); + if (!parent) + return; + + XRCCTRL(*parent, "brushSize", wxSlider)->SetValue(glView->GetBrushSize() * 1000.0f); + wxStaticText* valSize = (wxStaticText*)XRCCTRL(*parent, "valSize", wxStaticText); + wxString valSizeStr = wxString::Format("%0.3f", glView->GetBrushSize()); + valSize->SetLabel(valSizeStr); + + XRCCTRL(*parent, "brushStr", wxSlider)->SetValue(brush->getStrength() * 1000.0f); + wxStaticText* valStr = (wxStaticText*)XRCCTRL(*parent, "valStr", wxStaticText); + wxString valStrengthStr = wxString::Format("%0.3f", brush->getStrength()); + valStr->SetLabel(valStrengthStr); + + XRCCTRL(*parent, "brushFocus", wxSlider)->SetValue(brush->getFocus() * 1000.0f); + wxStaticText* valFocus = (wxStaticText*)XRCCTRL(*parent, "valFocus", wxStaticText); + wxString valFocusStr = wxString::Format("%0.3f", brush->getFocus()); + valFocus->SetLabel(valFocusStr); + + XRCCTRL(*parent, "brushSpace", wxSlider)->SetValue(brush->getSpacing() * 1000.0f); + wxStaticText* valSpace = (wxStaticText*)XRCCTRL(*parent, "valSpace", wxStaticText); + wxString valSpacingStr = wxString::Format("%0.3f", brush->getSpacing()); + valSpace->SetLabel(valSpacingStr); + } + + void CheckBrushBounds() { + TweakBrush* brush = glView->GetActiveBrush(); + if (!brush) + return; + + float size = glView->GetBrushSize(); + float strength = brush->getStrength(); + //float focus = brush->getFocus(); + //float spacing = brush->getSpacing(); + + if (size >= 1.0f) + GetMenuBar()->Enable(XRCID("btnIncreaseSize"), false); + else + GetMenuBar()->Enable(XRCID("btnIncreaseSize"), true); + + if (size <= 0.0f) + GetMenuBar()->Enable(XRCID("btnDecreaseSize"), false); + else + GetMenuBar()->Enable(XRCID("btnDecreaseSize"), true); + + if (strength >= 1.0f) + GetMenuBar()->Enable(XRCID("btnIncreaseStr"), false); + else + GetMenuBar()->Enable(XRCID("btnIncreaseStr"), true); + + if (strength <= 0.0f) + GetMenuBar()->Enable(XRCID("btnDecreaseStr"), false); + else + GetMenuBar()->Enable(XRCID("btnDecreaseStr"), true); + } + + wxProgressDialog* progWnd; + vector> progressStack; + int progressVal; + + void StartProgress(const wxString& title) { + if (progressStack.empty()) { + progWnd = new wxProgressDialog(title, "Starting...", 10000, this, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_SMOOTH | wxPD_ELAPSED_TIME); + progWnd->SetSize(400, 150); + progressVal = 0; + progressStack.emplace_back(0.0f, 10000.0f); + } + } + + void StartSubProgress(float min, float max) { + float range = progressStack.back().second - progressStack.front().first; + float mindiv = min / 100.0f; + float maxdiv = max / 100.0f; + float minoff = mindiv * range; + float maxoff = maxdiv * range; + progressStack.emplace_back(progressStack.front().first + minoff, progressStack.front().first + maxoff); + } + + void EndProgress() { + if (progressStack.empty()) + return; + + progWnd->Update(progressStack.back().second); + progressStack.pop_back(); + + if (progressStack.empty()) { + delete progWnd; + progWnd = nullptr; + } + } + + void UpdateProgress(float val, const wxString& msg = "") { + if (progressStack.empty()) + return; + + float range = progressStack.back().second - progressStack.back().first; + float div = val / 100.0f; + float offset = range * div; + + progressVal = progressStack.back().first + offset; + if (progressVal > 10000) + progressVal = 10000; + + progWnd->Update(progressVal, msg); + } + + + bool shapeIsImporting(const string& shapeName) { + auto ss = shapeStates.find(shapeName); + if (ss != shapeStates.end()) { + return ss->second.bIsImporting; + } + return false; + } + void setShapeImporting(const string& shapeName, bool isOn) { + shapeStates[shapeName].bIsImporting = isOn; + } + void finishImporting() { + for (auto &ss : shapeStates) { + ss.second.bIsImporting = false; + } + } + +private: +<<<<<<< Updated upstream +======= + class SliderDisplay { + public: + bool hilite; + wxPanel* sliderPane; + wxBoxSizer* paneSz; + + int sliderNameCheckID; + int sliderID; + + wxBitmapButton* btnSliderEdit; + wxButton* btnMinus; + wxButton* btnPlus; + wxCheckBox* sliderNameCheck; + wxStaticText* sliderName; + wxSlider* slider; + wxTextCtrl* sliderReadout; + + TweakUndo sliderStrokes; // This probably shouldn't be here, but it's a convenient location to store undo info. + }; + + class ShapeState { // metadata state of shapes by shape name + public: + TargetGame gameType; // game type source (affects block types in nif) + bool bIsImporting; // true if shape is currently in the process of being imported from .obj (lacking normals, textures, etc.) + ShapeState() : gameType(SKYRIM), bIsImporting(false) {} + }; + +>>>>>>> Stashed changes + bool previousMirror; + Vector3 previewMove; + float previewScale; + Vector3 previewRotation; + +<<<<<<< Updated upstream +======= + map sliderDisplays; + + map shapeStates; + +>>>>>>> Stashed changes + void createSliderGUI(const string& name, int id, wxScrolledWindow* wnd, wxSizer* rootSz); + void HighlightSlider(const string& name); + void ZeroSliders(); + + void ClearProject(); + void RenameProject(const string& projectName); + + void AnimationGUIFromProj(); + void WorkingGUIFromProj(); + + void OnMoveWindow(wxMoveEvent& event); + void OnSetSize(wxSizeEvent& event); + + void OnExit(wxCommandEvent& event); + void OnNewProject(wxCommandEvent& event); + void OnLoadProject(wxCommandEvent &event); + void OnLoadReference(wxCommandEvent &event); + void OnLoadOutfit(wxCommandEvent& event); + + void OnNewProject2FP_NIF(wxFileDirPickerEvent& event); + void OnNewProject2FP_OBJ(wxFileDirPickerEvent& event); + void OnNewProject2FP_Texture(wxFileDirPickerEvent& event); + void OnLoadOutfitFP_NIF(wxFileDirPickerEvent& event); + void OnLoadOutfitFP_OBJ(wxFileDirPickerEvent& event); + void OnLoadOutfitFP_Texture(wxFileDirPickerEvent& event); + + void OnSetBaseShape(wxCommandEvent &event); + void OnExportOutfitNif(wxCommandEvent &event); + void OnExportOutfitNifWithRef(wxCommandEvent &event); + void OnMakeConvRef(wxCommandEvent& event); + + void OnSSSNameCopy(wxCommandEvent& event); + void OnSSSGenWeightsTrue(wxCommandEvent& event); + void OnSSSGenWeightsFalse(wxCommandEvent& event); + void OnSaveSliderSet(wxCommandEvent &event); + void OnSaveSliderSetAs(wxCommandEvent &event); + + void OnBrushPane(wxCollapsiblePaneEvent &event); + + void OnSlider(wxScrollEvent& event); + void OnClickSliderButton(wxCommandEvent &event); + void OnReadoutChange(wxCommandEvent& event); + + void OnTabButtonClick(wxCommandEvent& event); + void OnFixedWeight(wxCommandEvent& event); + void OnSelectSliders(wxCommandEvent& event); + + void OnShapeVisToggle(wxTreeEvent& event); + void OnShapeSelect(wxTreeEvent& event); + void OnShapeContext(wxTreeEvent& event); + void OnShapeDrag(wxTreeEvent& event); + void OnShapeDrop(wxTreeEvent& event); + void OnBoneSelect(wxTreeEvent& event); + void OnBoneContext(wxTreeEvent& event); + void OnCheckTreeSel(wxTreeEvent& event); + void OnCheckBox(wxCommandEvent& event); + + void OnSelectBrush(wxCommandEvent& event); + + void OnSetView(wxCommandEvent& event); + void OnTogglePerspective(wxCommandEvent& event); + void OnFieldOfViewSlider(wxCommandEvent& event); + void OnUpdateLights(wxCommandEvent& event); + void OnResetLights(wxCommandEvent& event); + + void OnLoadPreset(wxCommandEvent& event); + void OnSliderConform(wxCommandEvent& event); + void OnSliderConformAll(wxCommandEvent& event); + void OnSliderImportBSD(wxCommandEvent& event); + void OnSliderImportOBJ(wxCommandEvent& event); + void OnSliderImportTRI(wxCommandEvent& event); + void OnSliderImportFBX(wxCommandEvent& event); + void OnSliderExportBSD(wxCommandEvent& event); + void OnSliderExportOBJ(wxCommandEvent& event); + void OnSliderExportTRI(wxCommandEvent& event); + + void OnNewSlider(wxCommandEvent& event); + void OnNewZapSlider(wxCommandEvent& event); + void OnNewCombinedSlider(wxCommandEvent& event); + void OnSliderNegate(wxCommandEvent& event); + void OnClearSlider(wxCommandEvent& event); + void OnDeleteSlider(wxCommandEvent& event); + void OnSliderProperties(wxCommandEvent& event); + + void OnImportShape(wxCommandEvent& event); + void OnExportShape(wxCommandEvent& event); + void OnImportFBX(wxCommandEvent& event); + void OnExportFBX(wxCommandEvent& event); + + void OnEnterClose(wxKeyEvent& event); + + void OnMoveShape(wxCommandEvent& event); + void OnMoveShapeOldOffset(wxCommandEvent& event); + void OnMoveShapeSlider(wxCommandEvent& event); + void OnMoveShapeText(wxCommandEvent& event); + void PreviewMove(const Vector3& changed); + + void OnScaleShape(wxCommandEvent& event); + void OnScaleShapeSlider(wxCommandEvent& event); + void OnScaleShapeText(wxCommandEvent& event); + void PreviewScale(const float& scale); + + void OnRotateShape(wxCommandEvent& event); + void OnRotateShapeSlider(wxCommandEvent& event); + void OnRotateShapeText(wxCommandEvent& event); + void PreviewRotation(const Vector3& changed); + + void OnRenameShape(wxCommandEvent& event); + void OnSetReference(wxCommandEvent& event); + void OnDupeShape(wxCommandEvent& event); + void OnDeleteShape(wxCommandEvent& event); + void OnAddBone(wxCommandEvent& event); + void OnDeleteBone(wxCommandEvent& event); + void OnCopyBoneWeight(wxCommandEvent& event); + void OnCopySelectedWeight(wxCommandEvent& event); + void OnTransferSelectedWeight(wxCommandEvent& event); + void OnMaskWeighted(wxCommandEvent& event); + void OnBuildSkinPartitions(wxCommandEvent& event); + void OnShapeProperties(wxCommandEvent& event); + void OnDropFiles(wxDropFilesEvent& event); + + void OnNPWizChangeSliderSetFile(wxFileDirPickerEvent& event); + void OnNPWizChangeSetNameChoice(wxCommandEvent& event); + + void OnBrushSettingsSlider(wxScrollEvent& event); + + void OnXMirror(wxCommandEvent& WXUNUSED(event)) { + glView->ToggleXMirror(); + } + + void OnConnectedOnly(wxCommandEvent& WXUNUSED(event)) { + glView->ToggleConnectedEdit(); + } + + void OnUndo(wxCommandEvent& WXUNUSED(event)) { + glView->UndoStroke(); + } + void OnRedo(wxCommandEvent& WXUNUSED(event)) { + glView->RedoStroke(); + } + + void OnRecalcNormals(wxCommandEvent& WXUNUSED(event)) { + glView->RecalcNormals(activeItem->shapeName); + glView->Refresh(); + } + + void OnAutoNormals(wxCommandEvent& WXUNUSED(event)) { + glView->ToggleAutoNormals(); + glView->Refresh(); + } + + void OnSmoothNormalSeams(wxCommandEvent& WXUNUSED(event)) { + glView->ToggleNormalSeamSmoothMode(); + glView->Refresh(); + } + + void OnGhostMesh(wxCommandEvent& WXUNUSED(event)) { + glView->ToggleGhostMode(); + glView->Refresh(); + } + + void OnShowWireframe(wxCommandEvent& WXUNUSED(event)) { + glView->ShowWireframe(); + glView->Refresh(); + } + + void OnEnableLighting(wxCommandEvent& WXUNUSED(event)) { + glView->ToggleLighting(); + glView->Refresh(); + } + + void OnEnableTextures(wxCommandEvent& WXUNUSED(event)) { + glView->ToggleTextures(); + glView->Refresh(); + } + + void OnShowMask(wxCommandEvent& WXUNUSED(event)) { + if (!activeItem) + return; + + glView->ToggleMaskVisible(); + glView->Refresh(); + } + + void OnIncBrush(wxCommandEvent& WXUNUSED(event)) { + if (glView->GetActiveBrush() && glView->GetBrushSize() < 1.0f) { + float v = glView->IncBrush() / 3.0f; + if (statusBar) + statusBar->SetStatusText(wxString::Format("Rad: %f", v), 2); + + CheckBrushBounds(); + UpdateBrushPane(); + } + } + void OnDecBrush(wxCommandEvent& WXUNUSED(event)) { + if (glView->GetActiveBrush() && glView->GetBrushSize() > 0.0f) { + float v = glView->DecBrush() / 3.0f; + if (statusBar) + statusBar->SetStatusText(wxString::Format("Rad: %f", v), 2); + + CheckBrushBounds(); + UpdateBrushPane(); + } + } + void OnIncStr(wxCommandEvent& WXUNUSED(event)) { + if (glView->GetActiveBrush() && glView->GetActiveBrush()->getStrength() < 1.0f) { + float v = glView->IncStr(); + if (statusBar) + statusBar->SetStatusText(wxString::Format("Str: %f", v), 2); + + CheckBrushBounds(); + UpdateBrushPane(); + } + } + void OnDecStr(wxCommandEvent& WXUNUSED(event)) { + if (glView->GetActiveBrush() && glView->GetActiveBrush()->getStrength() > 0.0f) { + float v = glView->DecStr(); + if (statusBar) + statusBar->SetStatusText(wxString::Format("Str: %f", v), 2); + + CheckBrushBounds(); + UpdateBrushPane(); + } + } + + void OnClearMask(wxCommandEvent& WXUNUSED(event)) { + if (!activeItem) + return; + + glView->ClearMask(); + glView->Refresh(); + } + + void OnInvertMask(wxCommandEvent& WXUNUSED(event)) { + if (!activeItem) + return; + + glView->InvertMask(); + glView->Refresh(); + } + + DECLARE_EVENT_TABLE() +}; + +class DnDFile : public wxFileDropTarget { +public: + DnDFile(OutfitStudio *pOwner = nullptr) { owner = pOwner; } + + virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& fileNames); + +private: + OutfitStudio *owner; +}; + +class DnDSliderFile : public wxFileDropTarget { +public: + DnDSliderFile(OutfitStudio *pOwner = nullptr) { owner = pOwner; } + + virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& fileNames); + virtual wxDragResult OnDragOver(wxCoord x, wxCoord y, wxDragResult defResult); + +private: + OutfitStudio *owner; + wxDragResult lastResult; + string targetSlider; +}; diff --git a/res/GameObjectBlank.nif b/res/GameObjectBlank.nif new file mode 100644 index 0000000000000000000000000000000000000000..8639e9036da9925aa56e60450c297c3aaa4eb1f6 GIT binary patch literal 1968 zcmb7EUuYY39RFT&P0}se3@SR>fnrjrL3EQRdh35+D)c!)gXlrhdlcjCsm%rjN*_vWq?ubeS<`ta&{KX)=Fo%G4H|e#mpB@=Q*#Ow-^YkIcQI z7u`h5o-5THqv+&oj;mJ)gM}zeFT%$)9tNI3*${YN8`D^StHPwIRm)+R(F*@Q3HWC; zL7csjy!3zTUYffFHJE?ZPVz8WizLi6yS_e~Xf${kv=fL4B(R^e13C<$R91(RL;K|+ zIXP$#QIma-0IFIvHOHx9IgYBb6+X0UK)4@xMct&TZf&uXiX`MWc-(EMJC|iuoyXC( zJGXND{54(#E=>|R(S^8+JO$?BCk-KOt*N6rSOOm(S3=2`2z zZo?ry@ONIF{Q}17;)Z*`myUk^{N||dQmpDJ{q>w>)?8~*&zH1CofZzxz5(Y^{iI?o zRb72PXTxW^hVIbbM|a=!6aCOE=Ie5Hma)w?`6rKU^a4L`>HpE&dE4d(b+_;)r769d z5<)MG{no74F#>Mu<{L|Netb*jCPO=~u{KG|e@zgrjuBofD4=jei1viUs3=4z z)DsT(L?dFz|Ga_-pYvt{UdQ-*N7^8K_U*O4bEipuSGjZOc#ZZU1Ha^*$%h6<8T=4? zfCQ`oNg#p372uK65u$dGe8jc J5#)9V{R@AYo!bBa literal 0 HcmV?d00001 diff --git a/res/outfitStudio.xrc b/res/outfitStudio.xrc index 2e92eb39..6ed1dd5a 100644 --- a/res/outfitStudio.xrc +++ b/res/outfitStudio.xrc @@ -811,6 +811,14 @@ Export the current shape as an OBJ file.

+ + + Import an FBX file as a new shape in the outfit. + + + + Export the current shape as an FBX file. + Duplicate the current shape. @@ -926,6 +934,10 @@ Import an OBJ file matching the current shape's vertex count, and calculate slider data from the difference. + + + Import an FBX file matching the current shape's vertex count, and calculate slider data from the difference. + 0
diff --git a/targetver.h b/targetver.h index ef9d80b6..a99e72d3 100644 --- a/targetver.h +++ b/targetver.h @@ -9,15 +9,15 @@ // Refer to MSDN for the latest info on corresponding values for different platforms. #ifndef WINVER // Specifies that the minimum required platform is Windows Vista. -#define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows. +#define WINVER 0x0601 // Change this to the appropriate value to target other versions of Windows. #endif #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. -#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#define _WIN32_WINNT 0x0601 // Change this to the appropriate value to target other versions of Windows. #endif #ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows Vista. -#define _WIN32_WINDOWS 0x0600 // Change this to the appropriate value to target other versions of Windows. +#define _WIN32_WINDOWS 0x0601 // Change this to the appropriate value to target other versions of Windows. #endif #ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0. From cee05b47d1de8f86ccf4a0b58a45b44fff1c1eab Mon Sep 17 00:00:00 2001 From: ousnius Date: Tue, 8 Dec 2015 23:03:25 +0100 Subject: [PATCH 34/64] Cleanup, warning fixes --- BodySlide.vcxproj | 16 +- BodySlide.vcxproj.filters.orig | 263 --------- BodySlide.vcxproj.orig | 304 ----------- FBXWrangler.cpp | 14 +- FBXWrangler.h | 2 +- NifBlock.cpp | 4 +- OutfitProject.cpp | 1 + OutfitProject.h | 1 - OutfitStudio.cpp | 6 +- OutfitStudio.h | 1 - OutfitStudio.h.orig | 968 --------------------------------- res/outfitStudio.xrc | 16 +- targetver.h | 6 +- 13 files changed, 32 insertions(+), 1570 deletions(-) delete mode 100644 BodySlide.vcxproj.filters.orig delete mode 100644 BodySlide.vcxproj.orig delete mode 100644 OutfitStudio.h.orig diff --git a/BodySlide.vcxproj b/BodySlide.vcxproj index e1618c92..9a675824 100644 --- a/BodySlide.vcxproj +++ b/BodySlide.vcxproj @@ -116,7 +116,7 @@ Disabled - ..\wxWidgets\include\msvc;..\wxWidgets\include;%(AdditionalIncludeDirectories) + ..\wxWidgets\include\msvc;..\wxWidgets\include;..\libraries\fbx\include;%(AdditionalIncludeDirectories) WIN64;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) false EnableFastChecks @@ -125,13 +125,13 @@ true - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_x64_d.lib;%(AdditionalDependencies) - ..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_x64_d.lib;libfbxsdk.lib;%(AdditionalDependencies) + ..\libraries\fbx\lib\vs2013\x64\debug;..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) true Windows false libcmt.lib - RequireAdministrator + AsInvoker @@ -166,7 +166,7 @@ MaxSpeed true - ..\wxWidgets\include\msvc;..\wxWidgets\include;%(AdditionalIncludeDirectories) + ..\wxWidgets\include\msvc;..\wxWidgets\include;..\libraries\fbx\include;%(AdditionalIncludeDirectories) WIN64;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) MultiThreaded @@ -176,8 +176,8 @@ None - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_x64.lib;%(AdditionalDependencies) - ..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_x64.lib;libfbxsdk.lib;%(AdditionalDependencies) + ..\libraries\fbx\lib\vs2013\x64\release;..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) false @@ -187,7 +187,7 @@ true - RequireAdministrator + AsInvoker diff --git a/BodySlide.vcxproj.filters.orig b/BodySlide.vcxproj.filters.orig deleted file mode 100644 index 73aac139..00000000 --- a/BodySlide.vcxproj.filters.orig +++ /dev/null @@ -1,263 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - -<<<<<<< Updated upstream - - Source Files - - -======= - ->>>>>>> Stashed changes - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - -<<<<<<< Updated upstream - - Header Files - - -======= - ->>>>>>> Stashed changes - Header Files - - - - - Resource Files - - - - - Resource Files - - - - - Resource Files - - - Resource Files - - - \ No newline at end of file diff --git a/BodySlide.vcxproj.orig b/BodySlide.vcxproj.orig deleted file mode 100644 index 0ad7afae..00000000 --- a/BodySlide.vcxproj.orig +++ /dev/null @@ -1,304 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {F7E444AD-893D-4E93-8897-AF050C1C6A48} - BodySlide - Win32Proj - - - - Application - v120 - Unicode - true - false - false - - - Application - v120 - Unicode - true - false - false - - - Application - v120 - Unicode - - - Application - v120 - Unicode - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>11.0.61030.0 - - - $(Configuration)\$(Platform)\ - $(ProjectName) Debug - false - $(SolutionDir)$(Configuration)\$(Platform)\ - - - $(ProjectName) $(Platform) Debug - false - $(SolutionDir)$(Configuration)\$(Platform)\ - $(Configuration)\$(Platform)\ - - - $(SolutionDir)$(Configuration)\$(Platform)\ - $(Configuration)\$(Platform)\ - false - - - false - $(ProjectName) $(Platform) - $(SolutionDir)$(Configuration)\$(Platform)\ - $(Configuration)\$(Platform)\ - - - - Disabled - ..\wxWidgets\include\msvc;..\wxWidgets\include;..\libraries\fbx\include;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - false - EnableFastChecks - MultiThreadedDebug - Level4 - true - - -<<<<<<< Updated upstream - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_d.lib;%(AdditionalDependencies) - ..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) -======= - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;libfbxsdk.lib;SOIL_d.lib;%(AdditionalDependencies) - ..\libraries\fbx\lib\vs2013\x86\debug;..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) ->>>>>>> Stashed changes - true - Windows - false - libcmt.lib - RequireAdministrator - - - - - Disabled - ..\wxWidgets\include\msvc;..\wxWidgets\include;%(AdditionalIncludeDirectories) - WIN64;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - false - EnableFastChecks - MultiThreadedDebug - Level4 - true - - - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_x64_d.lib;%(AdditionalDependencies) - ..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) - true - Windows - false - libcmt.lib - RequireAdministrator - - - - - MaxSpeed - true -<<<<<<< Updated upstream - ..\wxWidgets\include\msvc;..\wxWidgets\include;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) -======= - ..\wxWidgets\include\msvc;..\wxWidgets\include;..\libraries\fbx\include;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) ->>>>>>> Stashed changes - MultiThreaded - - - Level4 - true - None - - -<<<<<<< Updated upstream - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2.lib;%(AdditionalDependencies) - ..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) -======= - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;libfbxsdk.lib;SOIL.lib;%(AdditionalDependencies) - ..\libraries\fbx\lib\vs2013\x86\release;..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) ->>>>>>> Stashed changes - false - - - false - Windows - true - true - - - RequireAdministrator - - - - - MaxSpeed - true - ..\wxWidgets\include\msvc;..\wxWidgets\include;%(AdditionalIncludeDirectories) - WIN64;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - MultiThreaded - - - Level4 - true - None - - - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_x64.lib;%(AdditionalDependencies) - ..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) - false - - - false - Windows - true - true - - - RequireAdministrator - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/FBXWrangler.cpp b/FBXWrangler.cpp index d5285139..7d86dbc8 100644 --- a/FBXWrangler.cpp +++ b/FBXWrangler.cpp @@ -1,6 +1,4 @@ #include "FBXWrangler.h" -#include "NifFile.h" - FBXWrangler::FBXWrangler(): pSdkManager(nullptr), pCurrentScene(nullptr) { @@ -388,20 +386,20 @@ bool FBXWrangler::LoadMeshes() { for (int v = 0; v < meshData.numverts; v++) { FbxVector4 vert = m->GetControlPointAt(v); - meshData.verts.emplace_back(vert.mData[0], vert.mData[1], vert.mData[2]); + meshData.verts.emplace_back((float)vert.mData[0], (float)vert.mData[1], (float)vert.mData[2]); if (m->GetElementUVCount() && m->GetElementUV(0)->GetMappingMode() == FbxGeometryElement::eByControlPoint) { int uindex = v; if (m->GetElementUV(0)->GetReferenceMode() == FbxLayerElement::eIndexToDirect) { uindex = m->GetElementUV(0)->GetIndexArray().GetAt(v); } - meshData.uvs.emplace_back(m->GetElementUV(0)->GetDirectArray().GetAt(uindex).mData[0], - m->GetElementUV(0)->GetDirectArray().GetAt(uindex).mData[1]); + meshData.uvs.emplace_back((float)m->GetElementUV(0)->GetDirectArray().GetAt(uindex).mData[0], + (float)m->GetElementUV(0)->GetDirectArray().GetAt(uindex).mData[1]); } if (m->GetElementNormalCount() && m->GetElementNormal(0)->GetMappingMode() == FbxGeometryElement::eByControlPoint) { - meshData.normals.emplace_back(m->GetElementNormal(0)->GetDirectArray().GetAt(v).mData[0], - m->GetElementNormal(0)->GetDirectArray().GetAt(v).mData[1], - m->GetElementNormal(0)->GetDirectArray().GetAt(v).mData[2]); + meshData.normals.emplace_back((float)m->GetElementNormal(0)->GetDirectArray().GetAt(v).mData[0], + (float)m->GetElementNormal(0)->GetDirectArray().GetAt(v).mData[1], + (float)m->GetElementNormal(0)->GetDirectArray().GetAt(v).mData[2]); } } diff --git a/FBXWrangler.h b/FBXWrangler.h index 09d4d511..490818cb 100644 --- a/FBXWrangler.h +++ b/FBXWrangler.h @@ -2,7 +2,7 @@ #include #include -#include "mesh.h" +#include "Mesh.h" #include "NifFile.h" #include "Anim.h" diff --git a/NifBlock.cpp b/NifBlock.cpp index 6c241b11..520bc3d0 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -3895,8 +3895,8 @@ BSLightingShaderProperty::BSLightingShaderProperty(NiHeader& hdr) { unk[3] = 1.4f; unk[4] = 0.2f; unk[5] = 1.0f; - unk[6] = 1.6; - unk[7] = 0; + unk[6] = 1.6f; + unk[7] = 0.0f; memset(pad, 0, 16); diff --git a/OutfitProject.cpp b/OutfitProject.cpp index 789fae15..826737a2 100644 --- a/OutfitProject.cpp +++ b/OutfitProject.cpp @@ -6,6 +6,7 @@ See the included LICENSE file #include "OutfitProject.h" #include "TriFile.h" +#include "FBXWrangler.h" OutfitProject::OutfitProject(ConfigurationManager& inConfig, OutfitStudio* inOwner) : appConfig(inConfig) { morpherInitialized = false; diff --git a/OutfitProject.h b/OutfitProject.h index fb04cacd..6ebc9b4e 100644 --- a/OutfitProject.h +++ b/OutfitProject.h @@ -15,7 +15,6 @@ See the included LICENSE file #include "OutfitStudio.h" #include "ConfigurationManager.h" #include "Anim.h" -#include #include #include diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index 0975ef53..f53b0e41 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -2551,7 +2551,7 @@ void OutfitStudio::OnSliderImportTRI(wxCommandEvent& WXUNUSED(event)) { wxMessageBox(wxString::Format("Added morphs for the following shapes:\n\n%s", addedMorphs), "TRI Import"); } -void OutfitStudio::OnSliderImportFBX(wxCommandEvent& event) { +void OutfitStudio::OnSliderImportFBX(wxCommandEvent& WXUNUSED(event)) { if (!activeItem) { wxMessageBox("There is no shape selected!", "Error"); return; @@ -3033,7 +3033,7 @@ void OutfitStudio::OnExportShape(wxCommandEvent& WXUNUSED(event)) { } } -void OutfitStudio::OnImportFBX(wxCommandEvent& event) { +void OutfitStudio::OnImportFBX(wxCommandEvent& WXUNUSED(event)) { string fn = wxFileSelector("Import .fbx file for new shape", wxEmptyString, wxEmptyString, ".fbx", "*.fbx", wxFD_FILE_MUST_EXIST, this); if (fn.empty()) return; @@ -3067,7 +3067,7 @@ void OutfitStudio::OnImportFBX(wxCommandEvent& event) { glView->Refresh(); } -void OutfitStudio::OnExportFBX(wxCommandEvent& event) { +void OutfitStudio::OnExportFBX(wxCommandEvent& WXUNUSED(event)) { string defFile = "OutfitStudioShapes.fbx"; if (activeItem) defFile = activeItem->shapeName + ".fbx"; diff --git a/OutfitStudio.h b/OutfitStudio.h index 4fa2f9ea..841566af 100644 --- a/OutfitStudio.h +++ b/OutfitStudio.h @@ -26,7 +26,6 @@ along with this program. If not, see . #include "ObjFile.h" #include "TweakBrush.h" #include "Automorph.h" -#include "FBXWrangler.h" #include "OutfitProject.h" #include "ConfigurationManager.h" diff --git a/OutfitStudio.h.orig b/OutfitStudio.h.orig deleted file mode 100644 index ca733ff4..00000000 --- a/OutfitStudio.h.orig +++ /dev/null @@ -1,968 +0,0 @@ -/* -BodySlide and Outfit Studio -Copyright(C) 2015 Caliente & ousnius - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#pragma once - -#include "stdafx.h" -#include "wxStateButton.h" -#include "GLSurface.h" -#include "SliderData.h" -#include "SliderPresets.h" -#include "ObjFile.h" -#include "TweakBrush.h" -#include "Automorph.h" -#include "FBXWrangler.h" -#include "OutfitProject.h" -#include "ConfigurationManager.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -enum TargetGame { - FO3, FONV, SKYRIM, FO4 -}; - - -class ShapeItemData : public wxTreeItemData { -public: - NifFile* refFile; - string shapeName; - ShapeItemData(NifFile* inRefFile = nullptr, const string& inShapeName = "") { - refFile = inRefFile; - shapeName = inShapeName; - } -}; - - -class wxGLPanel : public wxGLCanvas { -public: - wxGLPanel(wxWindow* parent, const wxSize& size, const int* attribs); - ~wxGLPanel(); - - void SetNotifyWindow(wxWindow* win); - - void AddMeshFromNif(NifFile* nif, const string& shapeName, bool buildNormals); - void AddExplicitMesh(vector* v, vector* t, vector* uv = nullptr, const string& shapeName = ""); - - void RenameShape(const string& shapeName, const string& newShapeName) { - gls.RenameMesh(shapeName, newShapeName); - } - - void SetMeshTexture(const string& shapeName, const string& texturefile, bool isSkin = false); - - mesh* GetMesh(const string& shapeName) { - return gls.GetMesh(shapeName); - } - - void UpdateMeshVertices(const string& shapeName, vector* verts, bool updateBVH = true, bool recalcNormals = true); - void RecalculateMeshBVH(const string& shapeName); - - void ShowShape(const string& shapeName, bool show = true); - void SetActiveShape(const string& shapeName); - - TweakUndo* GetStrokeManager() { - return strokeManager; - } - void SetStrokeManager(TweakUndo* manager) { - if (!manager) - strokeManager = &baseStrokes; - else - strokeManager = manager; - } - - void SetActiveBrush(int brushID); - TweakBrush* GetActiveBrush() { - return activeBrush; - } - - bool StartBrushStroke(const wxPoint& screenPos); - void UpdateBrushStroke(const wxPoint& screenPos); - void EndBrushStroke(); - - bool StartTransform(const wxPoint& screenPos); - void UpdateTransform(const wxPoint& screenPos); - void EndTransform(); - - bool UndoStroke(); - bool RedoStroke(); - - void ShowTransformTool(bool show = true, bool updateBrush = true); - - void SetEditMode(bool on = true) { - editMode = on; - } - void ToggleEditMode() { - if (transformMode != 0) { - transformMode = 0; - editMode = true; - ShowTransformTool(false); - } - else { - editMode = false; - transformMode = 1; - ShowTransformTool(); - } - } - bool GetXMirror() { - return bXMirror; - } - void SetXMirror(bool on = true) { - bXMirror = on; - } - void ToggleXMirror() { - if (bXMirror) - bXMirror = false; - else - bXMirror = true; - } - void ToggleConnectedEdit() { - if (bConnectedEdit) - bConnectedEdit = false; - else - bConnectedEdit = true; - } - - void SetShapeGhostMode(const string& shapeName, bool on = true) { - mesh* m = gls.GetMesh(shapeName); - if (!m) return; - if (on) - m->rendermode = RenderMode::LitWire; - else - m->rendermode = RenderMode::Normal; - } - void ToggleGhostMode() { - mesh* m = gls.GetActiveMesh(); - if (!m) - return; - - if (m->rendermode == RenderMode::Normal) - m->rendermode = RenderMode::LitWire; - else if (m->rendermode == RenderMode::LitWire) - m->rendermode = RenderMode::Normal; - } - - void ToggleNormalSeamSmoothMode() { - mesh* m = gls.GetActiveMesh(); - if (!m) - return; - - if (m->smoothSeamNormals == true) - m->smoothSeamNormals = false; - else - m->smoothSeamNormals = true; - m->SmoothNormals(); - } - - void RecalcNormals(const string& shape, bool forceSmoothSeam = false) { - mesh* m = gls.GetMesh(shape); - if (!m) - return; - if (forceSmoothSeam) { - m->smoothSeamNormals = true; - m->SmoothNormals(); - m->smoothSeamNormals = false; - } - } - void ToggleAutoNormals() { - if (bAutoNormals) - bAutoNormals = false; - else - bAutoNormals = true; - } - float GetBrushSize() { - return brushSize / 3.0f; - } - void SetBrushSize(float val) { - val *= 3.0f; - brushSize = val; - gls.SetCursorSize(val); - } - - float IncBrush() { - gls.SetCursorSize(gls.GetCursorSize() + 0.010f); - brushSize += 0.010f; - LimitBrushSize(); - return brushSize; - } - float DecBrush() { - gls.SetCursorSize(gls.GetCursorSize() - 0.010f); - brushSize -= 0.010f; - LimitBrushSize(); - return brushSize; - } - void LimitBrushSize() { - if (brushSize < 0.000f) { - gls.SetCursorSize(0.000f); - brushSize = 0.000f; - } - else if (brushSize > 3.000f) { - gls.SetCursorSize(3.000f); - brushSize = 3.000f; - } - } - - float IncStr() { - if (!activeBrush) - return 0.0f; - - float str = activeBrush->getStrength(); - str += 0.010f; - activeBrush->setStrength(str); - return str; - } - float DecStr() { - if (!activeBrush) - return 0.0f; - - float str = activeBrush->getStrength(); - str -= 0.010f; - activeBrush->setStrength(str); - return str; - } - - void ShowWireframe() { - gls.ToggleWireframe(); - } - void ToggleLighting() { - gls.ToggleLighting(); - } - void ToggleTextures() { - gls.ToggleTextures(); - } - void ToggleMaskVisible() { - mesh* m = gls.GetActiveMesh(); - if (!m->vcolors) { - m->vcolors = new Vector3[m->nVerts]; - memset(m->vcolors, 0, 12 * m->nVerts); - } - gls.ToggleMask(); - } - void SetWeightVisible(bool bVisible = true) { - gls.SetWeightColors(bVisible); - } - - void ClearMask() { - mesh* m = gls.GetActiveMesh(); - if (m->vcolors) - m->ColorChannelFill(0, 0.0f); - } - - void GetActiveMask(unordered_map& mask) { - mesh* m = gls.GetActiveMesh(); - if (!m->vcolors) - return; - - for (int i = 0; i < m->nVerts; i++) { - if (m->vcolors[i].x != 0.0f) - mask[i] = m->vcolors[i].x; - } - } - - void GetActiveUnmasked(unordered_map& mask) { - mesh* m = gls.GetActiveMesh(); - if (!m->vcolors) { - for (int i = 0; i < m->nVerts; i++) - mask[i] = 0.0f; - return; - } - for (int i = 0; i < m->nVerts; i++) - if (m->vcolors[i].x == 0.0f) - mask[i] = m->vcolors[i].x; - } - - void GetShapeMask(unordered_map& mask, const string& shapeName) { - mesh* m = gls.GetMesh(shapeName); - if (!m || !m->vcolors) - return; - - for (int i = 0; i < m->nVerts; i++) { - if (m->vcolors[i].x != 0.0f) - mask[i] = m->vcolors[i].x; - } - } - - void GetShapeUnmasked(unordered_map& mask, const string& shapeName) { - mesh* m = gls.GetMesh(shapeName); - if (!m) - return; - - if (!m->vcolors) { - for (int i = 0; i < m->nVerts; i++) - mask[i] = 0.0f; - return; - } - for (int i = 0; i < m->nVerts; i++) - if (m->vcolors[i].x == 0.0f) - mask[i] = m->vcolors[i].x; - } - - void InvertMask() { - mesh* m = gls.GetActiveMesh(); - if (!m->vcolors) - m->ColorFill(Vector3(0.0f, 0.0f, 0.0f)); - for (int i = 0; i < m->nVerts; i++) - m->vcolors[i].x = 1 - m->vcolors[i].x; - } - - void DeleteMesh(const string& shape) { - gls.DeleteMesh(shape); - Refresh(); - } - void DestroyOverlays() { - gls.DeleteOverlays(); - Refresh(); - } - - void SetView(const char& type) { - gls.SetView(type); - Refresh(); - } - - void SetPerspective(const bool& enabled) { - gls.SetPerspective(enabled); - Refresh(); - } - - void SetFieldOfView(const int& fieldOfView) { - gls.SetFieldOfView(fieldOfView); - Refresh(); - } - - void UpdateLights(const int& ambient = 50, const int& brightness1 = 50, const int& brightness2 = 50, const int& brightness3 = 50) { - gls.UpdateLights(ambient, brightness1, brightness2, brightness3); - Refresh(); - } - - -private: - void OnShown(); - void OnPaint(wxPaintEvent& event); - void OnSize(wxSizeEvent& event); - - void OnMouseWheel(wxMouseEvent& event); - void OnMouseMove(wxMouseEvent& event); - - void OnMiddleDown(wxMouseEvent& event); - void OnMiddleUp(wxMouseEvent& event); - void OnLeftDown(wxMouseEvent& event); - void OnLeftUp(wxMouseEvent& event); - - void OnRightDown(wxMouseEvent& event); - void OnRightUp(wxMouseEvent& event); - - void OnKeys(wxKeyEvent& event); - void OnIdle(wxIdleEvent& event); - - void OnCaptureLost(wxMouseCaptureLostEvent& event); - - GLSurface gls; - wxGLContext* context; - - bool rbuttonDown; - bool lbuttonDown; - bool mbuttonDown; - bool isLDragging; - bool isMDragging; - bool isRDragging; - bool firstPaint{true}; - - int lastX; - int lastY; - - set BVHUpdateQueue; - - wxWindow* notifyWindow; - - float brushSize; - bool editMode; - bool transformMode; // 0 = off, 1 = move, 2 = rotate, 3 = scale - bool bMaskPaint; - bool bWeightPaint; - bool isPainting; - bool isTransforming; - bool bXMirror; - bool bAutoNormals; - bool bConnectedEdit; - - TweakBrush* activeBrush; - TweakBrush* savedBrush; - TweakBrush standardBrush; - TB_Deflate deflateBrush; - TB_Move moveBrush; - TB_Smooth smoothBrush; - TB_Mask maskBrush; - TB_Unmask UnMaskBrush; - TB_Weight weightBrush; - TB_Unweight unweightBrush; - TB_SmoothWeight smoothWeightBrush; - TB_XForm translateBrush; - - TweakStroke* activeStroke; - TweakUndo* strokeManager; - TweakUndo baseStrokes; - - Vector3 xformCenter; // Transform center for transform brushes (rotate, specifically cares about this) - - DECLARE_EVENT_TABLE() -}; - -class OutfitProject; - -class OutfitStudio : public wxFrame { -public: - OutfitStudio(wxWindow* parent, const wxPoint& pos, const wxSize& size, ConfigurationManager& inConfig); - ~OutfitStudio(); - - int targetGame; - wxGLPanel* glView = nullptr; - OutfitProject* project = nullptr; - ShapeItemData* activeItem = nullptr; - vector selectedItems; - string activeSlider; - string activeBone; - bool bEditSlider; - - wxTreeCtrl* outfitShapes; - wxTreeCtrl* outfitBones; - wxPanel* lightSettings; - wxSlider* boneScale; - wxScrolledWindow* sliderScroll; - wxStatusBar* statusBar; - wxToolBar* toolBar; - wxTreeItemId shapesRoot; - wxTreeItemId outfitRoot; - wxTreeItemId bonesRoot; - wxImageList* visStateImages; - - ConfigurationManager& appConfig; - - class SliderDisplay { - public: - bool hilite; - wxPanel* sliderPane; - wxBoxSizer* paneSz; - - int sliderNameCheckID; - int sliderID; - - wxBitmapButton* btnSliderEdit; - wxButton* btnMinus; - wxButton* btnPlus; - wxCheckBox* sliderNameCheck; - wxStaticText* sliderName; - wxSlider* slider; - wxTextCtrl* sliderReadout; - - TweakUndo sliderStrokes; // This probably shouldn't be here, but it's a convenient location to store undo info. - }; - - map sliderDisplays; - - void CreateSetSliders(); - - string NewSlider(); - - void SetSliderValue(int index, int val); - void SetSliderValue(const string& name, int val); - - void ApplySliders(bool recalcBVH = true); - - void ShowSliderEffect(int slider, bool show = true); - void ShowSliderEffect(const string& sliderName, bool show = true); - - void SelectShape(const string& shapeName); - vector GetShapeList(); - - void UpdateShapeSource(const string& shapeName); - int PromptUpdateBase(); - - void ActiveShapeUpdated(TweakStroke* refStroke, bool bIsUndo = false, bool setWeights = true); - void UpdateActiveShapeUI(); - - void RefreshGUIFromProj(); - - string GetActiveBone(); - - bool NotifyStrokeStarting(); - - bool IsDirty(); - bool IsDirty(const string& shapeName); - void SetClean(const string& shapeName); - - void EnterSliderEdit(const string& sliderName); - void ExitSliderEdit(); - void MenuEnterSliderEdit(); - void MenuExitSliderEdit(); - - void ToggleBrushPane() { - wxCollapsiblePane* brushPane = (wxCollapsiblePane*)FindWindowByName("brushPane"); - if (!brushPane) - return; - - brushPane->Collapse(!brushPane->IsCollapsed()); - - wxWindow* leftPanel = FindWindowByName("leftSplitPanel"); - if (leftPanel) - leftPanel->Layout(); - } - - void UpdateBrushPane() { - TweakBrush* brush = glView->GetActiveBrush(); - if (!brush) - return; - - wxCollapsiblePane* parent = (wxCollapsiblePane*)FindWindowByName("brushPane"); - if (!parent) - return; - - XRCCTRL(*parent, "brushSize", wxSlider)->SetValue(glView->GetBrushSize() * 1000.0f); - wxStaticText* valSize = (wxStaticText*)XRCCTRL(*parent, "valSize", wxStaticText); - wxString valSizeStr = wxString::Format("%0.3f", glView->GetBrushSize()); - valSize->SetLabel(valSizeStr); - - XRCCTRL(*parent, "brushStr", wxSlider)->SetValue(brush->getStrength() * 1000.0f); - wxStaticText* valStr = (wxStaticText*)XRCCTRL(*parent, "valStr", wxStaticText); - wxString valStrengthStr = wxString::Format("%0.3f", brush->getStrength()); - valStr->SetLabel(valStrengthStr); - - XRCCTRL(*parent, "brushFocus", wxSlider)->SetValue(brush->getFocus() * 1000.0f); - wxStaticText* valFocus = (wxStaticText*)XRCCTRL(*parent, "valFocus", wxStaticText); - wxString valFocusStr = wxString::Format("%0.3f", brush->getFocus()); - valFocus->SetLabel(valFocusStr); - - XRCCTRL(*parent, "brushSpace", wxSlider)->SetValue(brush->getSpacing() * 1000.0f); - wxStaticText* valSpace = (wxStaticText*)XRCCTRL(*parent, "valSpace", wxStaticText); - wxString valSpacingStr = wxString::Format("%0.3f", brush->getSpacing()); - valSpace->SetLabel(valSpacingStr); - } - - void CheckBrushBounds() { - TweakBrush* brush = glView->GetActiveBrush(); - if (!brush) - return; - - float size = glView->GetBrushSize(); - float strength = brush->getStrength(); - //float focus = brush->getFocus(); - //float spacing = brush->getSpacing(); - - if (size >= 1.0f) - GetMenuBar()->Enable(XRCID("btnIncreaseSize"), false); - else - GetMenuBar()->Enable(XRCID("btnIncreaseSize"), true); - - if (size <= 0.0f) - GetMenuBar()->Enable(XRCID("btnDecreaseSize"), false); - else - GetMenuBar()->Enable(XRCID("btnDecreaseSize"), true); - - if (strength >= 1.0f) - GetMenuBar()->Enable(XRCID("btnIncreaseStr"), false); - else - GetMenuBar()->Enable(XRCID("btnIncreaseStr"), true); - - if (strength <= 0.0f) - GetMenuBar()->Enable(XRCID("btnDecreaseStr"), false); - else - GetMenuBar()->Enable(XRCID("btnDecreaseStr"), true); - } - - wxProgressDialog* progWnd; - vector> progressStack; - int progressVal; - - void StartProgress(const wxString& title) { - if (progressStack.empty()) { - progWnd = new wxProgressDialog(title, "Starting...", 10000, this, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_SMOOTH | wxPD_ELAPSED_TIME); - progWnd->SetSize(400, 150); - progressVal = 0; - progressStack.emplace_back(0.0f, 10000.0f); - } - } - - void StartSubProgress(float min, float max) { - float range = progressStack.back().second - progressStack.front().first; - float mindiv = min / 100.0f; - float maxdiv = max / 100.0f; - float minoff = mindiv * range; - float maxoff = maxdiv * range; - progressStack.emplace_back(progressStack.front().first + minoff, progressStack.front().first + maxoff); - } - - void EndProgress() { - if (progressStack.empty()) - return; - - progWnd->Update(progressStack.back().second); - progressStack.pop_back(); - - if (progressStack.empty()) { - delete progWnd; - progWnd = nullptr; - } - } - - void UpdateProgress(float val, const wxString& msg = "") { - if (progressStack.empty()) - return; - - float range = progressStack.back().second - progressStack.back().first; - float div = val / 100.0f; - float offset = range * div; - - progressVal = progressStack.back().first + offset; - if (progressVal > 10000) - progressVal = 10000; - - progWnd->Update(progressVal, msg); - } - - - bool shapeIsImporting(const string& shapeName) { - auto ss = shapeStates.find(shapeName); - if (ss != shapeStates.end()) { - return ss->second.bIsImporting; - } - return false; - } - void setShapeImporting(const string& shapeName, bool isOn) { - shapeStates[shapeName].bIsImporting = isOn; - } - void finishImporting() { - for (auto &ss : shapeStates) { - ss.second.bIsImporting = false; - } - } - -private: -<<<<<<< Updated upstream -======= - class SliderDisplay { - public: - bool hilite; - wxPanel* sliderPane; - wxBoxSizer* paneSz; - - int sliderNameCheckID; - int sliderID; - - wxBitmapButton* btnSliderEdit; - wxButton* btnMinus; - wxButton* btnPlus; - wxCheckBox* sliderNameCheck; - wxStaticText* sliderName; - wxSlider* slider; - wxTextCtrl* sliderReadout; - - TweakUndo sliderStrokes; // This probably shouldn't be here, but it's a convenient location to store undo info. - }; - - class ShapeState { // metadata state of shapes by shape name - public: - TargetGame gameType; // game type source (affects block types in nif) - bool bIsImporting; // true if shape is currently in the process of being imported from .obj (lacking normals, textures, etc.) - ShapeState() : gameType(SKYRIM), bIsImporting(false) {} - }; - ->>>>>>> Stashed changes - bool previousMirror; - Vector3 previewMove; - float previewScale; - Vector3 previewRotation; - -<<<<<<< Updated upstream -======= - map sliderDisplays; - - map shapeStates; - ->>>>>>> Stashed changes - void createSliderGUI(const string& name, int id, wxScrolledWindow* wnd, wxSizer* rootSz); - void HighlightSlider(const string& name); - void ZeroSliders(); - - void ClearProject(); - void RenameProject(const string& projectName); - - void AnimationGUIFromProj(); - void WorkingGUIFromProj(); - - void OnMoveWindow(wxMoveEvent& event); - void OnSetSize(wxSizeEvent& event); - - void OnExit(wxCommandEvent& event); - void OnNewProject(wxCommandEvent& event); - void OnLoadProject(wxCommandEvent &event); - void OnLoadReference(wxCommandEvent &event); - void OnLoadOutfit(wxCommandEvent& event); - - void OnNewProject2FP_NIF(wxFileDirPickerEvent& event); - void OnNewProject2FP_OBJ(wxFileDirPickerEvent& event); - void OnNewProject2FP_Texture(wxFileDirPickerEvent& event); - void OnLoadOutfitFP_NIF(wxFileDirPickerEvent& event); - void OnLoadOutfitFP_OBJ(wxFileDirPickerEvent& event); - void OnLoadOutfitFP_Texture(wxFileDirPickerEvent& event); - - void OnSetBaseShape(wxCommandEvent &event); - void OnExportOutfitNif(wxCommandEvent &event); - void OnExportOutfitNifWithRef(wxCommandEvent &event); - void OnMakeConvRef(wxCommandEvent& event); - - void OnSSSNameCopy(wxCommandEvent& event); - void OnSSSGenWeightsTrue(wxCommandEvent& event); - void OnSSSGenWeightsFalse(wxCommandEvent& event); - void OnSaveSliderSet(wxCommandEvent &event); - void OnSaveSliderSetAs(wxCommandEvent &event); - - void OnBrushPane(wxCollapsiblePaneEvent &event); - - void OnSlider(wxScrollEvent& event); - void OnClickSliderButton(wxCommandEvent &event); - void OnReadoutChange(wxCommandEvent& event); - - void OnTabButtonClick(wxCommandEvent& event); - void OnFixedWeight(wxCommandEvent& event); - void OnSelectSliders(wxCommandEvent& event); - - void OnShapeVisToggle(wxTreeEvent& event); - void OnShapeSelect(wxTreeEvent& event); - void OnShapeContext(wxTreeEvent& event); - void OnShapeDrag(wxTreeEvent& event); - void OnShapeDrop(wxTreeEvent& event); - void OnBoneSelect(wxTreeEvent& event); - void OnBoneContext(wxTreeEvent& event); - void OnCheckTreeSel(wxTreeEvent& event); - void OnCheckBox(wxCommandEvent& event); - - void OnSelectBrush(wxCommandEvent& event); - - void OnSetView(wxCommandEvent& event); - void OnTogglePerspective(wxCommandEvent& event); - void OnFieldOfViewSlider(wxCommandEvent& event); - void OnUpdateLights(wxCommandEvent& event); - void OnResetLights(wxCommandEvent& event); - - void OnLoadPreset(wxCommandEvent& event); - void OnSliderConform(wxCommandEvent& event); - void OnSliderConformAll(wxCommandEvent& event); - void OnSliderImportBSD(wxCommandEvent& event); - void OnSliderImportOBJ(wxCommandEvent& event); - void OnSliderImportTRI(wxCommandEvent& event); - void OnSliderImportFBX(wxCommandEvent& event); - void OnSliderExportBSD(wxCommandEvent& event); - void OnSliderExportOBJ(wxCommandEvent& event); - void OnSliderExportTRI(wxCommandEvent& event); - - void OnNewSlider(wxCommandEvent& event); - void OnNewZapSlider(wxCommandEvent& event); - void OnNewCombinedSlider(wxCommandEvent& event); - void OnSliderNegate(wxCommandEvent& event); - void OnClearSlider(wxCommandEvent& event); - void OnDeleteSlider(wxCommandEvent& event); - void OnSliderProperties(wxCommandEvent& event); - - void OnImportShape(wxCommandEvent& event); - void OnExportShape(wxCommandEvent& event); - void OnImportFBX(wxCommandEvent& event); - void OnExportFBX(wxCommandEvent& event); - - void OnEnterClose(wxKeyEvent& event); - - void OnMoveShape(wxCommandEvent& event); - void OnMoveShapeOldOffset(wxCommandEvent& event); - void OnMoveShapeSlider(wxCommandEvent& event); - void OnMoveShapeText(wxCommandEvent& event); - void PreviewMove(const Vector3& changed); - - void OnScaleShape(wxCommandEvent& event); - void OnScaleShapeSlider(wxCommandEvent& event); - void OnScaleShapeText(wxCommandEvent& event); - void PreviewScale(const float& scale); - - void OnRotateShape(wxCommandEvent& event); - void OnRotateShapeSlider(wxCommandEvent& event); - void OnRotateShapeText(wxCommandEvent& event); - void PreviewRotation(const Vector3& changed); - - void OnRenameShape(wxCommandEvent& event); - void OnSetReference(wxCommandEvent& event); - void OnDupeShape(wxCommandEvent& event); - void OnDeleteShape(wxCommandEvent& event); - void OnAddBone(wxCommandEvent& event); - void OnDeleteBone(wxCommandEvent& event); - void OnCopyBoneWeight(wxCommandEvent& event); - void OnCopySelectedWeight(wxCommandEvent& event); - void OnTransferSelectedWeight(wxCommandEvent& event); - void OnMaskWeighted(wxCommandEvent& event); - void OnBuildSkinPartitions(wxCommandEvent& event); - void OnShapeProperties(wxCommandEvent& event); - void OnDropFiles(wxDropFilesEvent& event); - - void OnNPWizChangeSliderSetFile(wxFileDirPickerEvent& event); - void OnNPWizChangeSetNameChoice(wxCommandEvent& event); - - void OnBrushSettingsSlider(wxScrollEvent& event); - - void OnXMirror(wxCommandEvent& WXUNUSED(event)) { - glView->ToggleXMirror(); - } - - void OnConnectedOnly(wxCommandEvent& WXUNUSED(event)) { - glView->ToggleConnectedEdit(); - } - - void OnUndo(wxCommandEvent& WXUNUSED(event)) { - glView->UndoStroke(); - } - void OnRedo(wxCommandEvent& WXUNUSED(event)) { - glView->RedoStroke(); - } - - void OnRecalcNormals(wxCommandEvent& WXUNUSED(event)) { - glView->RecalcNormals(activeItem->shapeName); - glView->Refresh(); - } - - void OnAutoNormals(wxCommandEvent& WXUNUSED(event)) { - glView->ToggleAutoNormals(); - glView->Refresh(); - } - - void OnSmoothNormalSeams(wxCommandEvent& WXUNUSED(event)) { - glView->ToggleNormalSeamSmoothMode(); - glView->Refresh(); - } - - void OnGhostMesh(wxCommandEvent& WXUNUSED(event)) { - glView->ToggleGhostMode(); - glView->Refresh(); - } - - void OnShowWireframe(wxCommandEvent& WXUNUSED(event)) { - glView->ShowWireframe(); - glView->Refresh(); - } - - void OnEnableLighting(wxCommandEvent& WXUNUSED(event)) { - glView->ToggleLighting(); - glView->Refresh(); - } - - void OnEnableTextures(wxCommandEvent& WXUNUSED(event)) { - glView->ToggleTextures(); - glView->Refresh(); - } - - void OnShowMask(wxCommandEvent& WXUNUSED(event)) { - if (!activeItem) - return; - - glView->ToggleMaskVisible(); - glView->Refresh(); - } - - void OnIncBrush(wxCommandEvent& WXUNUSED(event)) { - if (glView->GetActiveBrush() && glView->GetBrushSize() < 1.0f) { - float v = glView->IncBrush() / 3.0f; - if (statusBar) - statusBar->SetStatusText(wxString::Format("Rad: %f", v), 2); - - CheckBrushBounds(); - UpdateBrushPane(); - } - } - void OnDecBrush(wxCommandEvent& WXUNUSED(event)) { - if (glView->GetActiveBrush() && glView->GetBrushSize() > 0.0f) { - float v = glView->DecBrush() / 3.0f; - if (statusBar) - statusBar->SetStatusText(wxString::Format("Rad: %f", v), 2); - - CheckBrushBounds(); - UpdateBrushPane(); - } - } - void OnIncStr(wxCommandEvent& WXUNUSED(event)) { - if (glView->GetActiveBrush() && glView->GetActiveBrush()->getStrength() < 1.0f) { - float v = glView->IncStr(); - if (statusBar) - statusBar->SetStatusText(wxString::Format("Str: %f", v), 2); - - CheckBrushBounds(); - UpdateBrushPane(); - } - } - void OnDecStr(wxCommandEvent& WXUNUSED(event)) { - if (glView->GetActiveBrush() && glView->GetActiveBrush()->getStrength() > 0.0f) { - float v = glView->DecStr(); - if (statusBar) - statusBar->SetStatusText(wxString::Format("Str: %f", v), 2); - - CheckBrushBounds(); - UpdateBrushPane(); - } - } - - void OnClearMask(wxCommandEvent& WXUNUSED(event)) { - if (!activeItem) - return; - - glView->ClearMask(); - glView->Refresh(); - } - - void OnInvertMask(wxCommandEvent& WXUNUSED(event)) { - if (!activeItem) - return; - - glView->InvertMask(); - glView->Refresh(); - } - - DECLARE_EVENT_TABLE() -}; - -class DnDFile : public wxFileDropTarget { -public: - DnDFile(OutfitStudio *pOwner = nullptr) { owner = pOwner; } - - virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& fileNames); - -private: - OutfitStudio *owner; -}; - -class DnDSliderFile : public wxFileDropTarget { -public: - DnDSliderFile(OutfitStudio *pOwner = nullptr) { owner = pOwner; } - - virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& fileNames); - virtual wxDragResult OnDragOver(wxCoord x, wxCoord y, wxDragResult defResult); - -private: - OutfitStudio *owner; - wxDragResult lastResult; - string targetSlider; -}; diff --git a/res/outfitStudio.xrc b/res/outfitStudio.xrc index 6ed1dd5a..07322403 100644 --- a/res/outfitStudio.xrc +++ b/res/outfitStudio.xrc @@ -815,10 +815,10 @@ Import an FBX file as a new shape in the outfit. - - - Export the current shape as an FBX file. - + + + Export the current shape as an FBX file. + Duplicate the current shape. @@ -934,10 +934,10 @@ Import an OBJ file matching the current shape's vertex count, and calculate slider data from the difference. - - - Import an FBX file matching the current shape's vertex count, and calculate slider data from the difference. - + + + Import an FBX file matching the current shape's vertex count, and calculate slider data from the difference. + 0
diff --git a/targetver.h b/targetver.h index a99e72d3..ef9d80b6 100644 --- a/targetver.h +++ b/targetver.h @@ -9,15 +9,15 @@ // Refer to MSDN for the latest info on corresponding values for different platforms. #ifndef WINVER // Specifies that the minimum required platform is Windows Vista. -#define WINVER 0x0601 // Change this to the appropriate value to target other versions of Windows. +#define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows. #endif #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. -#define _WIN32_WINNT 0x0601 // Change this to the appropriate value to target other versions of Windows. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. #endif #ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows Vista. -#define _WIN32_WINDOWS 0x0601 // Change this to the appropriate value to target other versions of Windows. +#define _WIN32_WINDOWS 0x0600 // Change this to the appropriate value to target other versions of Windows. #endif #ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0. From 95f52e1b9e5341ea0f0c268d936fa04fa1470aa3 Mon Sep 17 00:00:00 2001 From: ousnius Date: Tue, 8 Dec 2015 23:19:26 +0100 Subject: [PATCH 35/64] Removed unnecessary SOIL library includes --- ResourceLoader.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/ResourceLoader.cpp b/ResourceLoader.cpp index c4018804..8e237957 100644 --- a/ResourceLoader.cpp +++ b/ResourceLoader.cpp @@ -9,21 +9,7 @@ See the included LICENSE file #include "ConfigurationManager.h" #include "FSManager.h" #include "FSEngine.h" - #include "SOIL2.h" -#ifdef NDEBUG - #ifdef _WIN32 - #pragma comment (lib, "SOIL2.lib") - #elif _WIN64 - #pragma comment (lib, "SOIL2_x64.lib") - #endif -#else - #ifdef _WIN32 - #pragma comment (lib, "SOIL2_d.lib") - #elif _WIN64 - #pragma comment (lib, "SOIL2_x64_d.lib") - #endif -#endif #include #include From a699928e8f69e6ec72a579fee589a23071b93608 Mon Sep 17 00:00:00 2001 From: ousnius Date: Tue, 8 Dec 2015 23:36:56 +0100 Subject: [PATCH 36/64] Changed FBX lib to use the MT file name --- BodySlide.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BodySlide.vcxproj b/BodySlide.vcxproj index 9a675824..62e31e00 100644 --- a/BodySlide.vcxproj +++ b/BodySlide.vcxproj @@ -104,7 +104,7 @@ true - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_d.lib;libfbxsdk.lib;%(AdditionalDependencies) + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_d.lib;libfbxsdk-mt.lib;%(AdditionalDependencies) ..\libraries\fbx\lib\vs2013\x86\debug;..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) true Windows @@ -125,7 +125,7 @@ true - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_x64_d.lib;libfbxsdk.lib;%(AdditionalDependencies) + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_x64_d.lib;libfbxsdk-mt.lib;%(AdditionalDependencies) ..\libraries\fbx\lib\vs2013\x64\debug;..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) true Windows @@ -148,7 +148,7 @@ None - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2.lib;libfbxsdk.lib;%(AdditionalDependencies) + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2.lib;libfbxsdk-mt.lib;%(AdditionalDependencies) ..\libraries\fbx\lib\vs2013\x86\release;..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) false @@ -176,7 +176,7 @@ None - comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_x64.lib;libfbxsdk.lib;%(AdditionalDependencies) + comctl32.lib;rpcrt4.lib;OpenGL32.lib;glu32.lib;opengl32.lib;SOIL2_x64.lib;libfbxsdk-mt.lib;%(AdditionalDependencies) ..\libraries\fbx\lib\vs2013\x64\release;..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) false From ab728b4b7e3525e9403bff8a4df4aab377da943a Mon Sep 17 00:00:00 2001 From: ousnius Date: Tue, 8 Dec 2015 23:44:53 +0100 Subject: [PATCH 37/64] Missed manifest setting for Win32 Release --- BodySlide.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BodySlide.vcxproj b/BodySlide.vcxproj index 62e31e00..b5fea19d 100644 --- a/BodySlide.vcxproj +++ b/BodySlide.vcxproj @@ -159,7 +159,7 @@ true - RequireAdministrator + AsInvoker From ee7661119db905cc111e82d8656ebf9bb4f1e67a Mon Sep 17 00:00:00 2001 From: ousnius Date: Wed, 9 Dec 2015 20:15:06 +0100 Subject: [PATCH 38/64] Fixed local data name bugs --- Config.xml | 2 +- NifBlock.cpp | 2 +- OutfitProject.cpp | 8 +++++++- SliderSet.h | 6 ++++++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Config.xml b/Config.xml index 92539cb7..67acb11a 100644 --- a/Config.xml +++ b/Config.xml @@ -43,7 +43,7 @@ 45 - + res\skeleton_fo4.nif diff --git a/NifBlock.cpp b/NifBlock.cpp index 520bc3d0..bb563850 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -4141,7 +4141,7 @@ void BSLightingShaderProperty::notifyBlockSwap(int blockIndexLo, int blockIndexH } bool BSLightingShaderProperty::IsSkin() { - return (header->userVersion2 < 130 && shaderFlags1 & (1 << 21)) != 0; + return (shaderFlags1 & (1 << 21)) != 0; } bool BSLightingShaderProperty::IsDoubleSided() { diff --git a/OutfitProject.cpp b/OutfitProject.cpp index 826737a2..375cd3e7 100644 --- a/OutfitProject.cpp +++ b/OutfitProject.cpp @@ -90,6 +90,7 @@ string OutfitProject::Save(const string& strFileName, string targ; string targSlider; string targSliderData; + string targDataName; string osdFileName = baseFile.substr(0, baseFile.find_last_of('.')) + ".osd"; string saveDataPath = "ShapeData\\" + strDataDir; @@ -108,7 +109,10 @@ string OutfitProject::Save(const string& strFileName, targSlider = activeSet[i].TargetDataName(targ); if (baseDiffData.GetDiffSet(targSlider) && baseDiffData.GetDiffSet(targSlider)->size() > 0) { if (activeSet[i].IsLocalData(targSlider)) { - targSliderData = osdFileName + "\\" + activeSet[i].DataFileName(targSlider); + targDataName = activeSet[i].DataFileName(targSlider); + int lastIndex = targDataName.find_last_of('\\') + 1; + + targSliderData = osdFileName + "\\" + targDataName.substr(lastIndex, targDataName.length() - lastIndex); outSet[id].AddDataFile(targ, targSlider, targSliderData); unordered_map* diff = baseDiffData.GetDiffSet(targSlider); @@ -1529,6 +1533,8 @@ int OutfitProject::LoadReference(const string& fileName, const string& setName, sset.GetSet(setName, activeSet); activeSet.SetBaseDataPath(Config["ShapeDataPath"]); + activeSet.SetAllReferenced(); + string inMeshFile = activeSet.GetInputFileName(); if (!ClearRef) diff --git a/SliderSet.h b/SliderSet.h index 1a294d21..d29f0159 100644 --- a/SliderSet.h +++ b/SliderSet.h @@ -104,6 +104,12 @@ class SliderSet outTargets.push_back(tdf.first); } + void SetAllReferenced() { + for (auto &s : sliders) + for (auto &df : s.dataFiles) + df.bLocal = false; + } + string TargetToShape(const string& targetName) { if (targetshapenames.find(targetName) != targetshapenames.end()) return targetshapenames[targetName]; From a42da93753d037a08a394c7bf2227fd1722e3415 Mon Sep 17 00:00:00 2001 From: ousnius Date: Wed, 9 Dec 2015 22:25:19 +0100 Subject: [PATCH 39/64] Camera offset for FO4, BSTriShape refs to integer Added a 12.0f camera offset for skinned FO4 meshes. --- GLSurface.cpp | 11 ++++++++++- GLSurface.h | 1 + NifBlock.cpp | 12 +++++------- NifFile.cpp | 16 +++++++--------- NifFile.h | 10 +++++----- 5 files changed, 28 insertions(+), 22 deletions(-) diff --git a/GLSurface.cpp b/GLSurface.cpp index 421aff04..564f6054 100644 --- a/GLSurface.cpp +++ b/GLSurface.cpp @@ -477,6 +477,7 @@ void GLSurface::SetStartingView(const Vector3& pos, const Vector3& rot, const ui perspective = true; camPos = pos; camRot = rot; + camOffset.Zero(); vpW = vpWidth; vpH = vpHeight; mFov = fov; @@ -867,7 +868,7 @@ void GLSurface::UpdateProjection() { if (perspective) gluPerspective(mFov, aspect, 0.1, 1000); else - glOrtho(camPos.z / 2 * aspect, -camPos.z / 2 * aspect, camPos.z / 2, -camPos.z / 2, 0.1, 1000); + glOrtho((camPos.z + camOffset.z) / 2 * aspect, (-camPos.z + camOffset.z) / 2 * aspect, (camPos.z + camOffset.z) / 2, (-camPos.z + camOffset.z) / 2, 0.1, 1000); glMatrixMode(GL_MODELVIEW); } @@ -884,6 +885,7 @@ void GLSurface::RenderOneFrame() { glTranslatef(camPos.x, camPos.y, camPos.z); glRotatef(camRot.x, 1.0f, 0.0f, 0.0f); glRotatef(camRot.y, 0.0f, 1.0f, 0.0f); + glTranslatef(camOffset.x, camOffset.y, camOffset.z); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -1324,6 +1326,13 @@ void GLSurface::AddMeshFromNif(NifFile* nif, string shapeName, Vector3* color, b meshes[i]->color = Vector3(c, c, c); } } + + // Offset camera for skinned FO4 shapes + if (nif->hdr.userVersion == 12 && nif->hdr.userVersion2 == 130) { + BSTriShape* geom = nif->geomForNameF4(shapeName); + if (geom && geom->skinInstanceRef != -1) + camOffset.y = 12.0f; + } } int GLSurface::AddVisFacets(vector& ids, const string& name) { diff --git a/GLSurface.h b/GLSurface.h index 1667e17c..30f4664e 100644 --- a/GLSurface.h +++ b/GLSurface.h @@ -32,6 +32,7 @@ class GLSurface { float mFov; Vector3 camPos; Vector3 camRot; // Turntable camera emulation. + Vector3 camOffset; uint vpW; uint vpH; diff --git a/NifBlock.cpp b/NifBlock.cpp index bb563850..7e2579df 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -580,9 +580,9 @@ BSTriShape::BSTriShape(NiHeader& hdr) { header = &hdr; memset(unkProps, 0, sizeof(float)* 4); - skinInstanceRef = 0xFFFFFFFF; - shaderPropertyRef = 0xFFFFFFFF; - alphaPropertyRef = 0xFFFFFFFF; + skinInstanceRef = -1; + shaderPropertyRef = -1; + alphaPropertyRef = -1; // flags for vert data look to be stored in here. byte 0 or byte 6 specifically look promising . // using byte 6 currently, bit 3 indicating sub index data, bit 2 indicating the presence of color data. bit 1 indicating presence of normal data @@ -815,16 +815,14 @@ void BSTriShape::notifyBlockDelete(int blockID) { NiObjectNET::notifyBlockDelete(blockID); if (skinInstanceRef == blockID) - skinInstanceRef = 0xFFFFFFFF; + skinInstanceRef = -1; else if (skinInstanceRef > blockID) skinInstanceRef--; if (shaderPropertyRef == blockID) - shaderPropertyRef = 0xFFFFFFFF; + shaderPropertyRef = -1; else if (shaderPropertyRef > blockID) shaderPropertyRef--; - - } void BSTriShape::notifyBlockSwap(int blockIndexLo, int blockIndexHi) { diff --git a/NifFile.cpp b/NifFile.cpp index b0778c01..3966104e 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -1012,11 +1012,10 @@ void NifFile::CopyGeometry(const string& shapeDest, NifFile& srcNif, const strin CopyGeometry(shapeDest, srcNif, srcShape, srcGeom); } else { - BSTriShape* srcGeom = srcNif.geomForNameF4(srcShape); - CopyGeometry(shapeDest, srcNif, srcShape, srcGeom); + BSTriShape* srcGeomF4 = srcNif.geomForNameF4(srcShape); + if (srcGeomF4) + CopyGeometry(shapeDest, srcNif, srcShape, srcGeomF4); } - - } void NifFile::CopyGeometry(const string& shapeDest, NifFile& srcNif, const string& srcShape, NiTriBasedGeom* srcGeom) { @@ -1623,16 +1622,15 @@ int NifFile::GetShapeBoneWeights(const string& shapeName, int boneIndex, unorder else { BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { - for (int vid = 0; vid < siTriShape->numverts; vid++) { - for (int i = 0; i < 4; i++) - if (siTriShape->vertData[vid].weightBones[i] == boneIndex && siTriShape->vertData[vid].weights[i] != 0) { - outWeights[vid] = siTriShape->vertData[vid].weights[i]; + for (int i = 0; i < 4; i++) { + if (siTriShape->vertData[vid].weightBones[i] == boneIndex && siTriShape->vertData[vid].weights[i] != 0) { + outWeights[vid] = siTriShape->vertData[vid].weights[i]; + } } } return outWeights.size(); } - } if (skinRef == -1) diff --git a/NifFile.h b/NifFile.h index fa0d73b3..8c32b44e 100644 --- a/NifFile.h +++ b/NifFile.h @@ -381,9 +381,9 @@ class BSTriShape : public NiAVObject{ }; uint unkProps[4]; - uint skinInstanceRef; - uint shaderPropertyRef; - uint alphaPropertyRef; + int skinInstanceRef; + int shaderPropertyRef; + int alphaPropertyRef; // flags for vert data look to be stored in here. byte 0 or byte 6 specifically look promising . // using byte 6 currently, bit 3 indicating sub index data, bit 2 indicating the presence of color data. bit 1 indicating presence of normal data @@ -650,12 +650,12 @@ class BSDismemberSkinInstance : public NiSkinInstance { class BSSkinInstance : public NiBoneContainer { public: uint unk; - uint boneDataRef; + int boneDataRef; uint numVertices; vector vertexWeights; - BSSkinInstance() : unk(0), boneDataRef(0), numVertices(0) { numBones = 0; }; + BSSkinInstance() : unk(0), boneDataRef(-1), numVertices(0) { numBones = 0; }; BSSkinInstance(NiHeader& hdr); BSSkinInstance(fstream& file, NiHeader& hdr); From 3fa032bc3d47d8b4551fef9facd62284d0233ca0 Mon Sep 17 00:00:00 2001 From: ousnius Date: Thu, 10 Dec 2015 00:47:36 +0100 Subject: [PATCH 40/64] Hiding panel in preview for single-weight, not just slider --- PreviewWindow.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PreviewWindow.h b/PreviewWindow.h index acff55c5..7824c313 100644 --- a/PreviewWindow.h +++ b/PreviewWindow.h @@ -52,7 +52,8 @@ class PreviewWindow : public wxFrame wxSlider* weightSlider = (wxSlider*)FindWindowByName("weightSlider", this); if (weightSlider) { weightSlider->SetValue(weight); - weightSlider->Show(show); + weightSlider->GetParent()->Show(show); + Layout(); } } From 8a560f1b4181e0e3439383c2666b3aed6e55debe Mon Sep 17 00:00:00 2001 From: Caliente Date: Thu, 10 Dec 2015 11:32:05 -0500 Subject: [PATCH 41/64] Drag and drop files to shape window (obj, fbx in addition to nif ) --- OutfitStudio.cpp | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index f53b0e41..97e72a6f 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -468,7 +468,7 @@ string OutfitStudio::NewSlider(const string& suggestedName, bool skipPrompt) { _snprintf_s(thename, 256, 256, "%s%d", namebase.c_str(), count++); string finalName; if (!skipPrompt) { - string finalName = wxGetTextFromUser("Enter a name for the new slider:", "Create New Slider", thename, this); + finalName = wxGetTextFromUser("Enter a name for the new slider:", "Create New Slider", thename, this); if (finalName.empty()) return finalName; } @@ -4722,6 +4722,13 @@ bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames) { if (fileNames.GetCount() > 0) inputFile = fileNames.Item(0); + string mergeShapeName = ""; + if (owner->activeItem) { + mergeShapeName = owner->activeItem->shapeName; + } + wxString dataName = inputFile.AfterLast('\\'); + dataName = dataName.BeforeLast('.'); + if (inputFile.MakeLower().EndsWith(".nif")) { owner->StartProgress("Adding NIF file..."); owner->UpdateProgress(1.0f, "Adding NIF file..."); @@ -4731,6 +4738,28 @@ bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames) { owner->UpdateProgress(60.0f, "Refreshing GUI..."); owner->RefreshGUIFromProj(); + owner->UpdateProgress(100.0f, "Finished."); + owner->EndProgress(); + } else if (inputFile.MakeLower().EndsWith(".obj")) { + owner->StartProgress("Adding OBJ file..."); + owner->UpdateProgress(1.0f, "Adding NIF file..."); + owner->project->AddShapeFromObjFile(inputFile.ToStdString(), dataName.ToStdString(), mergeShapeName); + owner->project->SetTextures("_AUTO_"); + + owner->UpdateProgress(60.0f, "Refreshing GUI..."); + owner->RefreshGUIFromProj(); + + owner->UpdateProgress(100.0f, "Finished."); + owner->EndProgress(); + } else if (inputFile.MakeLower().EndsWith(".fbx")) { + owner->StartProgress("Adding FBX file..."); + owner->UpdateProgress(1.0f, "Adding NIF file..."); + owner->project->ImportShapeFBX(inputFile.ToStdString(), dataName.ToStdString(), mergeShapeName); + owner->project->SetTextures("_AUTO_"); + + owner->UpdateProgress(60.0f, "Refreshing GUI..."); + owner->RefreshGUIFromProj(); + owner->UpdateProgress(100.0f, "Finished."); owner->EndProgress(); } From c64926f5fbc92b64048014f3dbedb6e65486d17e Mon Sep 17 00:00:00 2001 From: ousnius Date: Thu, 10 Dec 2015 17:37:34 +0100 Subject: [PATCH 42/64] Removed unused drop event, fixed progress dialog text --- OutfitStudio.cpp | 38 ++++++++------------------------------ OutfitStudio.h | 1 - 2 files changed, 8 insertions(+), 31 deletions(-) diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index 97e72a6f..d011d351 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -145,8 +145,6 @@ BEGIN_EVENT_TABLE(OutfitStudio, wxFrame) EVT_SLIDER(XRCID("lightBrightnessSlider2"), OutfitStudio::OnUpdateLights) EVT_SLIDER(XRCID("lightBrightnessSlider3"), OutfitStudio::OnUpdateLights) EVT_BUTTON(XRCID("lightReset"), OutfitStudio::OnResetLights) - - EVT_DROP_FILES(OutfitStudio::OnDropFiles) EVT_MOVE_END(OutfitStudio::OnMoveWindow) EVT_SIZE(OutfitStudio::OnSetSize) @@ -242,10 +240,6 @@ OutfitStudio::OutfitStudio(wxWindow* parent, const wxPoint& pos, const wxSize& s if (outfitShapes) { outfitShapes->AssignStateImageList(visStateImages); shapesRoot = outfitShapes->AddRoot("Shapes"); - - outfitShapes->DragAcceptFiles(true); - outfitShapes->Bind(wxEVT_DROP_FILES, wxDropFilesEventHandler(OutfitStudio::OnDropFiles), this); - } outfitBones = (wxTreeCtrl*)FindWindowByName("outfitBones"); @@ -3774,24 +3768,6 @@ void OutfitStudio::OnShapeProperties(wxCommandEvent& WXUNUSED(event)) { prop.ShowModal(); } -void OutfitStudio::OnDropFiles(wxDropFilesEvent& event) { - if (event.GetNumberOfFiles() > 0) { - wxString* dropped = event.GetFiles(); - wxArrayString files; - for (int i = 0; i < event.GetNumberOfFiles(); i++) { - wxString name = dropped[i]; - if (wxFileExists(name)) { - if (name.EndsWith (".nif") || name.EndsWith(".obj")) - files.push_back(name); - } - } - for (auto f : files) { - wxMessageBox(f, "flie dropped"); - } - } - -} - void OutfitStudio::OnNPWizChangeSliderSetFile(wxFileDirPickerEvent& event) { string fn = event.GetPath(); vector shapes; @@ -4740,9 +4716,10 @@ bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames) { owner->UpdateProgress(100.0f, "Finished."); owner->EndProgress(); - } else if (inputFile.MakeLower().EndsWith(".obj")) { + } + else if (inputFile.MakeLower().EndsWith(".obj")) { owner->StartProgress("Adding OBJ file..."); - owner->UpdateProgress(1.0f, "Adding NIF file..."); + owner->UpdateProgress(1.0f, "Adding OBJ file..."); owner->project->AddShapeFromObjFile(inputFile.ToStdString(), dataName.ToStdString(), mergeShapeName); owner->project->SetTextures("_AUTO_"); @@ -4751,9 +4728,10 @@ bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames) { owner->UpdateProgress(100.0f, "Finished."); owner->EndProgress(); - } else if (inputFile.MakeLower().EndsWith(".fbx")) { + } + else if (inputFile.MakeLower().EndsWith(".fbx")) { owner->StartProgress("Adding FBX file..."); - owner->UpdateProgress(1.0f, "Adding NIF file..."); + owner->UpdateProgress(1.0f, "Adding FBX file..."); owner->project->ImportShapeFBX(inputFile.ToStdString(), dataName.ToStdString(), mergeShapeName); owner->project->SetTextures("_AUTO_"); @@ -4773,7 +4751,7 @@ bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames) { bool DnDSliderFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames) { if (owner) { bool isMultiple = (fileNames.GetCount() > 1); - for (int i = 0; iNewSlider(dataName.ToStdString(),isMultiple); + targetSlider = owner->NewSlider(dataName.ToStdString(), isMultiple); } if (targetSlider.empty()) diff --git a/OutfitStudio.h b/OutfitStudio.h index 841566af..83335c2e 100644 --- a/OutfitStudio.h +++ b/OutfitStudio.h @@ -790,7 +790,6 @@ class OutfitStudio : public wxFrame { void OnMaskWeighted(wxCommandEvent& event); void OnBuildSkinPartitions(wxCommandEvent& event); void OnShapeProperties(wxCommandEvent& event); - void OnDropFiles(wxDropFilesEvent& event); void OnNPWizChangeSliderSetFile(wxFileDirPickerEvent& event); void OnNPWizChangeSetNameChoice(wxCommandEvent& event); From 252f2f811e28affd3f8b16c71e9e9a46d4acc0e9 Mon Sep 17 00:00:00 2001 From: ousnius Date: Thu, 10 Dec 2015 21:51:34 +0100 Subject: [PATCH 43/64] Fixed registry key for x64 build --- BodySlideApp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index 386fe81d..0b93fd94 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -830,7 +830,7 @@ void BodySlideApp::SetDefaultConfig() { Config.SetDefaultValue("OutfitStudioFrame.y", 100); if (Config["GameDataPath"].empty()) { - wxRegKey key(wxRegKey::HKLM, gameKey); + wxRegKey key(wxRegKey::HKLM, gameKey, wxRegKey::WOW64ViewMode_32); if (key.Exists()) { wxString installPath; if (key.HasValues() && key.QueryValue(gameValueKey, installPath)) { @@ -880,7 +880,7 @@ wxString BodySlideApp::GetGameDataPath(TargetGame gameID) { dataPath = Config[cust]; } else { - wxRegKey key(wxRegKey::HKLM, Config[gkey]); + wxRegKey key(wxRegKey::HKLM, Config[gkey], wxRegKey::WOW64ViewMode_32); if (key.Exists()) { if (key.HasValues() && key.QueryValue(Config[gval], dataPath)) { dataPath.Append("Data\\"); From ccf62211d0542350eb76680a0aa016de282cd692 Mon Sep 17 00:00:00 2001 From: Caliente Date: Fri, 11 Dec 2015 19:11:55 -0500 Subject: [PATCH 44/64] Half float precision improvements, fixes for missing normals and crash on FBX import --- DiffData.cpp | 4 +- NifBlock.cpp | 64 +- NifFile.h | 2 +- Object3d.cpp | 3 +- Object3d.h | 13 + OutfitProject.cpp | 2 +- half.hpp | 2909 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 2964 insertions(+), 33 deletions(-) create mode 100644 half.hpp diff --git a/DiffData.cpp b/DiffData.cpp index 924a8034..bf0240a0 100644 --- a/DiffData.cpp +++ b/DiffData.cpp @@ -44,6 +44,7 @@ int OSDataFile::Read(const string& fileName) { for (int j = 0; j < diffSize; ++j) { file.read((char*)&index, 2); file.read((char*)&diff, sizeof(Vector3)); + diff.clampEpsilon(); diffs[index] = diff; } @@ -122,6 +123,7 @@ int DiffDataSets::LoadSet(const string& name, const string& target, const string for (int i = 0; i < sz; i++) { inFile.read((char*)&idx, sizeof(int)); inFile.read((char*)&v, sizeof(Vector3)); + v.clampEpsilon(); data.emplace(idx, v); } inFile.close(); @@ -299,7 +301,7 @@ void DiffDataSets::ApplyDiff(const string& set, const string& target, float perc for (auto resultIt = data->begin(); resultIt != data->end(); ++resultIt) { if (resultIt->first >= maxidx) continue; // prevent crashes. - + ushort idx = resultIt->first; (*inOutResult)[resultIt->first].x += resultIt->second.x * percent; (*inOutResult)[resultIt->first].y += resultIt->second.y * percent; (*inOutResult)[resultIt->first].z += resultIt->second.z * percent; diff --git a/NifBlock.cpp b/NifBlock.cpp index 7e2579df..1f82091e 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -511,6 +511,10 @@ void NiNode::Get(fstream& file) { void NiNode::Put(fstream& file) { NiAVObject::Put(file); + if (children.size() != numChildren) { // error somewhere else with block management :( + return; + } + file.write((char*)&numChildren, 4); for (int i = 0; i < numChildren; i++) file.write((char*)&children[i], 4); @@ -612,6 +616,7 @@ BSTriShape::BSTriShape(fstream& file, NiHeader& hdr) { void BSTriShape::Get(fstream& file) { short shortData; + half_float::half halfData; // The order of definition deviates slightly from previous versions, so can't directly use the super Get... instead // that code is duplicated here and the super super get is called. NiObjectNET::Get(file); @@ -656,20 +661,20 @@ void BSTriShape::Get(fstream& file) { vertData.resize(numverts); for (int i = 0; i < numverts; i++) { - file.read((char*)&shortData, 2); - vertData[i].vert.x = h2float(shortData); - file.read((char*)&shortData, 2); - vertData[i].vert.y = h2float(shortData); - file.read((char*)&shortData, 2); - vertData[i].vert.z = h2float(shortData); + file.read((char*)&halfData, 2); + vertData[i].vert.x = halfData;//h2float(shortData); + file.read((char*)&halfData, 2); + vertData[i].vert.y = halfData;//h2float(shortData); + file.read((char*)&halfData, 2); + vertData[i].vert.z = halfData;//h2float(shortData); - file.read((char*)&shortData, 2); - vertData[i].bitangentX = h2float(shortData); + file.read((char*)&halfData, 2); + vertData[i].bitangentX = halfData;//h2float(shortData); - file.read((char*)&shortData, 2); - vertData[i].uv.u = h2float(shortData); - file.read((char*)&shortData, 2); - vertData[i].uv.v = h2float(shortData); + file.read((char*)&halfData, 2); + vertData[i].uv.u = halfData;//h2float(shortData); + file.read((char*)&halfData, 2); + vertData[i].uv.v = halfData;//h2float(shortData); if (vertFlags[6] & 0x1) { for (int j = 0; j < 3; j++) { @@ -690,8 +695,8 @@ void BSTriShape::Get(fstream& file) { if (vertFlags[6] & 0x4) { for (int j = 0; j < 4; j++) { - file.read((char*)&shortData, 2); - vertData[i].weights[j] = h2float(shortData); + file.read((char*)&halfData, 2); + vertData[i].weights[j] = halfData;//h2float(shortData); } for (int j = 0; j < 4; j++) { file.read((char*)&vertData[i].weightBones[j], 1); @@ -713,6 +718,7 @@ void BSTriShape::Get(fstream& file) { void BSTriShape::Put(fstream& file) { short shortData; + half_float::half halfData; // The order of definition deviates slightly from previous versions, so can't directly use the super Get... instead // that code is duplicated here and the super super get is called. NiObjectNET::Put(file); @@ -755,25 +761,25 @@ void BSTriShape::Put(fstream& file) { for (int i = 0; i < numverts; i++) { - shortData = float2h(vertData[i].vert.x); - file.write((char*)&shortData, 2); + halfData = vertData[i].vert.x; + file.write((char*)&halfData, 2); - shortData = float2h(vertData[i].vert.y); - file.write((char*)&shortData, 2); + halfData = vertData[i].vert.y; + file.write((char*)&halfData, 2); - shortData = float2h(vertData[i].vert.z); - file.write((char*)&shortData, 2); + halfData = vertData[i].vert.z; + file.write((char*)&halfData, 2); - shortData = float2h(vertData[i].bitangentX); - file.write((char*)&shortData, 2); + halfData = vertData[i].bitangentX; + file.write((char*)&halfData, 2); - shortData = float2h(vertData[i].uv.u); - file.write((char*)&shortData, 2); + halfData = vertData[i].uv.u; + file.write((char*)&halfData, 2); - shortData = float2h(vertData[i].uv.v); - file.write((char*)&shortData, 2); + halfData = vertData[i].uv.v; + file.write((char*)&halfData, 2); if (vertFlags[6] & 0x1) { for (int j = 0; j < 3; j++) { @@ -794,8 +800,8 @@ void BSTriShape::Put(fstream& file) { } if (vertFlags[6] & 0x4) { for (int j = 0; j < 4; j++) { - shortData = float2h(vertData[i].weights[j]); - file.write((char*)&shortData, 2); + halfData = vertData[i].weights[j]; + file.write((char*)&halfData, 2); } for (int j = 0; j < 4; j++) { file.write((char*)&vertData[i].weightBones[j], 1); @@ -1216,7 +1222,7 @@ void BSTriShape::Create(vector* verts, vector* tris, vectorsize() == numverts) { setNormals((*normals)); calcTangentSpace(NULL, NULL, NULL); } diff --git a/NifFile.h b/NifFile.h index 8c32b44e..f9c547cd 100644 --- a/NifFile.h +++ b/NifFile.h @@ -1417,4 +1417,4 @@ vector NifFile::GetChildren(NiNode* parent) { } return result; -} +} diff --git a/Object3d.cpp b/Object3d.cpp index 57e6466a..22627693 100644 --- a/Object3d.cpp +++ b/Object3d.cpp @@ -1,5 +1,5 @@ #include "Object3d.h" - +/* float h2float(const ushort& in) { float ret; uint t1; @@ -42,3 +42,4 @@ unsigned short float2h(const float& in) { ret = t1; return ret; } +*/ \ No newline at end of file diff --git a/Object3d.h b/Object3d.h index 81be5c74..cd11cc6c 100644 --- a/Object3d.h +++ b/Object3d.h @@ -9,6 +9,7 @@ See the included LICENSE file #include #include #include +#include "half.hpp" using namespace std; @@ -24,8 +25,10 @@ typedef unsigned char byte; typedef unsigned short ushort; typedef unsigned int uint; +/* float h2float(const ushort& in); ushort float2h(const float& in); +*/ struct Vertex; @@ -172,6 +175,16 @@ struct Vector3 { B.Normalize(); return acosf(A.dot(B)); } + + void clampEpsilon() { + + if (fabs(x) < EPSILON) + x = 0.0f; + if (fabs(y) < EPSILON) + y = 0.0f; + if (fabs(z) < EPSILON) + z = 0.0f; + } }; /* Vertex structure. This contains information about a mesh vertex, including position, normal, and index diff --git a/OutfitProject.cpp b/OutfitProject.cpp index 375cd3e7..25bf8465 100644 --- a/OutfitProject.cpp +++ b/OutfitProject.cpp @@ -1924,7 +1924,7 @@ int OutfitProject::SaveOutfitNif(const string& fileName, const vector& mo clone.SetVertsForShape(m->shapeName, liveVerts); if (writeNormals) { - if (clone.IsShaderSkin(m->shapeName)) + if (clone.IsShaderSkin(m->shapeName) && owner->targetGame != FO4) continue; clone.SetNormalsForShape(m->shapeName, liveNorms); diff --git a/half.hpp b/half.hpp new file mode 100644 index 00000000..441a652b --- /dev/null +++ b/half.hpp @@ -0,0 +1,2909 @@ +// half - IEEE 754-based half-precision floating point library. +// +// Copyright (c) 2012-2013 Christian Rau +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// Version 1.11.0 + +/// \file +/// Main header file for half precision functionality. + +#ifndef HALF_HALF_HPP +#define HALF_HALF_HPP + +/// Combined gcc version number. +#define HALF_GNUC_VERSION (__GNUC__*100+__GNUC_MINOR__) + +//check C++11 language features +#if defined(__clang__) //clang + #if __has_feature(cxx_static_assert) && !defined(HALF_ENABLE_CPP11_STATIC_ASSERT) + #define HALF_ENABLE_CPP11_STATIC_ASSERT 1 + #endif + #if __has_feature(cxx_constexpr) && !defined(HALF_ENABLE_CPP11_CONSTEXPR) + #define HALF_ENABLE_CPP11_CONSTEXPR 1 + #endif + #if __has_feature(cxx_noexcept) && !defined(HALF_ENABLE_CPP11_NOEXCEPT) + #define HALF_ENABLE_CPP11_NOEXCEPT 1 + #endif + #if __has_feature(cxx_user_literals) && !defined(HALF_ENABLE_CPP11_USER_LITERALS) + #define HALF_ENABLE_CPP11_USER_LITERALS 1 + #endif + #if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) && !defined(HALF_ENABLE_CPP11_LONG_LONG) + #define HALF_ENABLE_CPP11_LONG_LONG 1 + #endif +/*#elif defined(__INTEL_COMPILER) //Intel C++ + #if __INTEL_COMPILER >= 1100 && !defined(HALF_ENABLE_CPP11_STATIC_ASSERT) ???????? + #define HALF_ENABLE_CPP11_STATIC_ASSERT 1 + #endif + #if __INTEL_COMPILER >= 1300 && !defined(HALF_ENABLE_CPP11_CONSTEXPR) ???????? + #define HALF_ENABLE_CPP11_CONSTEXPR 1 + #endif + #if __INTEL_COMPILER >= 1300 && !defined(HALF_ENABLE_CPP11_NOEXCEPT) ???????? + #define HALF_ENABLE_CPP11_NOEXCEPT 1 + #endif + #if __INTEL_COMPILER >= 1100 && !defined(HALF_ENABLE_CPP11_LONG_LONG) ???????? + #define HALF_ENABLE_CPP11_LONG_LONG 1 + #endif*/ +#elif defined(__GNUC__) //gcc + #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L + #if HALF_GNUC_VERSION >= 403 && !defined(HALF_ENABLE_CPP11_STATIC_ASSERT) + #define HALF_ENABLE_CPP11_STATIC_ASSERT 1 + #endif + #if HALF_GNUC_VERSION >= 406 && !defined(HALF_ENABLE_CPP11_CONSTEXPR) + #define HALF_ENABLE_CPP11_CONSTEXPR 1 + #endif + #if HALF_GNUC_VERSION >= 406 && !defined(HALF_ENABLE_CPP11_NOEXCEPT) + #define HALF_ENABLE_CPP11_NOEXCEPT 1 + #endif + #if HALF_GNUC_VERSION >= 407 && !defined(HALF_ENABLE_CPP11_USER_LITERALS) + #define HALF_ENABLE_CPP11_USER_LITERALS 1 + #endif + #if !defined(HALF_ENABLE_CPP11_LONG_LONG) + #define HALF_ENABLE_CPP11_LONG_LONG 1 + #endif + #endif +#elif defined(_MSC_VER) //Visual C++ + #if _MSC_VER >= 1600 && !defined(HALF_ENABLE_CPP11_STATIC_ASSERT) + #define HALF_ENABLE_CPP11_STATIC_ASSERT 1 + #endif + #if _MSC_VER >= 1310 && !defined(HALF_ENABLE_CPP11_LONG_LONG) + #define HALF_ENABLE_CPP11_LONG_LONG 1 + #endif + #define HALF_POP_WARNINGS 1 + #pragma warning(push) + #pragma warning(disable : 4099 4127 4146) //struct vs class, constant in if, negative unsigned +#endif + +//check C++11 library features +#include +#if defined(_LIBCPP_VERSION) //libc++ + #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103 + #ifndef HALF_ENABLE_CPP11_TYPE_TRAITS + #define HALF_ENABLE_CPP11_TYPE_TRAITS 1 + #endif + #ifndef HALF_ENABLE_CPP11_CSTDINT + #define HALF_ENABLE_CPP11_CSTDINT 1 + #endif + #ifndef HALF_ENABLE_CPP11_CMATH + #define HALF_ENABLE_CPP11_CMATH 1 + #endif + #ifndef HALF_ENABLE_CPP11_HASH + #define HALF_ENABLE_CPP11_HASH 1 + #endif + #endif +#elif defined(__GLIBCXX__) //libstdc++ + #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103 + #ifdef __clang__ + #if __GLIBCXX__ >= 20080606 && !defined(HALF_ENABLE_CPP11_TYPE_TRAITS) + #define HALF_ENABLE_CPP11_TYPE_TRAITS 1 + #endif + #if __GLIBCXX__ >= 20080606 && !defined(HALF_ENABLE_CPP11_CSTDINT) + #define HALF_ENABLE_CPP11_CSTDINT 1 + #endif + #if __GLIBCXX__ >= 20080606 && !defined(HALF_ENABLE_CPP11_CMATH) + #define HALF_ENABLE_CPP11_CMATH 1 + #endif + #if __GLIBCXX__ >= 20080606 && !defined(HALF_ENABLE_CPP11_HASH) + #define HALF_ENABLE_CPP11_HASH 1 + #endif + #else + #if HALF_GNUC_VERSION >= 403 && !defined(HALF_ENABLE_CPP11_CSTDINT) + #define HALF_ENABLE_CPP11_CSTDINT 1 + #endif + #if HALF_GNUC_VERSION >= 403 && !defined(HALF_ENABLE_CPP11_CMATH) + #define HALF_ENABLE_CPP11_CMATH 1 + #endif + #if HALF_GNUC_VERSION >= 403 && !defined(HALF_ENABLE_CPP11_HASH) + #define HALF_ENABLE_CPP11_HASH 1 + #endif + #endif + #endif +#elif defined(_CPPLIB_VER) //Dinkumware/Visual C++ + #if _CPPLIB_VER >= 520 + #ifndef HALF_ENABLE_CPP11_TYPE_TRAITS + #define HALF_ENABLE_CPP11_TYPE_TRAITS 1 + #endif + #ifndef HALF_ENABLE_CPP11_CSTDINT + #define HALF_ENABLE_CPP11_CSTDINT 1 + #endif + #ifndef HALF_ENABLE_CPP11_HASH + #define HALF_ENABLE_CPP11_HASH 1 + #endif + #endif + #if _CPPLIB_VER >= 610 + #ifndef HALF_ENABLE_CPP11_CMATH + #define HALF_ENABLE_CPP11_CMATH 1 + #endif + #endif +#endif +#undef HALF_GNUC_VERSION + +//support constexpr +#if HALF_ENABLE_CPP11_CONSTEXPR + #define HALF_CONSTEXPR constexpr + #define HALF_CONSTEXPR_CONST constexpr +#else + #define HALF_CONSTEXPR + #define HALF_CONSTEXPR_CONST const +#endif + +//support noexcept +#if HALF_ENABLE_CPP11_NOEXCEPT + #define HALF_NOEXCEPT noexcept + #define HALF_NOTHROW noexcept +#else + #define HALF_NOEXCEPT + #define HALF_NOTHROW throw() +#endif + +#include +#include +#include +#include +#include +#include +#if HALF_ENABLE_CPP11_TYPE_TRAITS + #include +#endif +#if HALF_ENABLE_CPP11_CSTDINT + #include +#endif +#if HALF_ENABLE_CPP11_HASH + #include +#endif + + +/// Default rounding mode. +/// This specifies the rounding mode used for all conversions between [half](\ref half_float::half)s and `float`s as well as +/// for the half_cast() if not specifying a rounding mode explicitly. It can be redefined (before including half.hpp) to one +/// of the standard rounding modes using their respective constants or the equivalent values of `std::float_round_style`: +/// +/// `std::float_round_style` | value | rounding +/// ---------------------------------|-------|------------------------- +/// `std::round_indeterminate` | -1 | fastest (default) +/// `std::round_toward_zero` | 0 | toward zero +/// `std::round_to_nearest` | 1 | to nearest +/// `std::round_toward_infinity` | 2 | toward positive infinity +/// `std::round_toward_neg_infinity` | 3 | toward negative infinity +/// +/// By default this is set to `-1` (`std::round_indeterminate`), which uses truncation (round toward zero, but with overflows +/// set to infinity) and is the fastest rounding mode possible. It can even be set to `std::numeric_limits::round_style` +/// to synchronize the rounding mode with that of the underlying single-precision implementation. +#ifndef HALF_ROUND_STYLE + #define HALF_ROUND_STYLE -1 // = std::round_indeterminate +#endif + +/// Tie-breaking behaviour for round to nearest. +/// This specifies if ties in round to nearest should be resolved by rounding to the nearest even value. By default this is +/// defined to `0` resulting in the faster but slightly more biased behaviour of rounding away from zero in half-way cases (and +/// thus equal to the round() function), but can be redefined to `1` (before including half.hpp) if more IEEE-conformant +/// behaviour is needed. +#ifndef HALF_ROUND_TIES_TO_EVEN + #define HALF_ROUND_TIES_TO_EVEN 0 // ties away from zero +#endif + +/// Value signaling overflow. +/// In correspondence with `HUGE_VAL[F|L]` from `` this symbol expands to a positive value signaling the overflow of an +/// operation, in particular it just evaluates to positive infinity. +#define HUGE_VALH std::numeric_limits::infinity() + +/// Fast half-precision fma function. +/// This symbol is only defined if the fma() function generally executes as fast as, or faster than, a separate +/// half-precision multiplication followed by an addition. Due to the internal single-precision implementation of all +/// arithmetic operations, this is in fact always the case. +#define FP_FAST_FMAH 1 + +#ifndef FP_ILOGB0 + #define FP_ILOGB0 INT_MIN +#endif +#ifndef FP_ILOGBNAN + #define FP_ILOGBNAN INT_MAX +#endif +#ifndef FP_SUBNORMAL + #define FP_SUBNORMAL 0 +#endif +#ifndef FP_ZERO + #define FP_ZERO 1 +#endif +#ifndef FP_NAN + #define FP_NAN 2 +#endif +#ifndef FP_INFINITE + #define FP_INFINITE 3 +#endif +#ifndef FP_NORMAL + #define FP_NORMAL 4 +#endif + + +/// Main namespace for half precision functionality. +/// This namespace contains all the functionality provided by the library. +namespace half_float +{ + class half; + + /// \internal + /// \brief Implementation details. + namespace detail + { + #if HALF_ENABLE_CPP11_TYPE_TRAITS + /// Conditional type. + template struct conditional : std::conditional {}; + + /// Helper for tag dispatching. + template struct bool_type : std::integral_constant {}; + using std::true_type; + using std::false_type; + + /// Type traits for floating point types. + template struct is_float : std::is_floating_point {}; + #else + /// Conditional type. + template struct conditional { typedef T type; }; + template struct conditional { typedef F type; }; + + /// Helper for tag dispatching. + template struct bool_type {}; + typedef bool_type true_type; + typedef bool_type false_type; + + /// Type traits for floating point types. + template struct is_float : false_type {}; + template struct is_float : is_float {}; + template struct is_float : is_float {}; + template struct is_float : is_float {}; + template<> struct is_float : true_type {}; + template<> struct is_float : true_type {}; + template<> struct is_float : true_type {}; + #endif + + #if HALF_ENABLE_CPP11_CSTDINT + /// Unsigned integer of (at least) 16 bits width. + typedef std::uint_least16_t uint16; + + /// Unsigned integer of (at least) 32 bits width. + typedef std::uint_least32_t uint32; + + /// Fastest signed integer capable of holding all values of type uint16. + typedef std::int_fast32_t int17; + #else + /// Unsigned integer of (at least) 16 bits width. + typedef unsigned short uint16; + + /// Unsigned integer of (at least) 32 bits width. + typedef conditional::digits>=32,unsigned int,unsigned long>::type uint32; + + /// Fastest signed integer capable of holding all values of type uint16. + typedef conditional::digits>=16,int,long>::type int17; + #endif + + /// Tag type for binary construction. + struct binary_t {}; + + /// Tag for binary construction. + HALF_CONSTEXPR_CONST binary_t binary = binary_t(); + + /// Temporary half-precision expression. + /// This class represents a half-precision expression which just stores a single-precision value internally. + struct expr + { + /// Conversion constructor. + /// \param f single-precision value to convert + explicit HALF_CONSTEXPR expr(float f) : value_(f) {} + + /// Conversion to single-precision. + /// \return single precision value representing expression value + HALF_CONSTEXPR operator float() const { return value_; } + + private: + /// Internal expression value stored in single-precision. + float value_; + }; + + /// SFINAE helper for generic half-precision functions. + /// This class template has to be specialized for each valid combination of argument types to provide a corresponding + /// `type` member equivalent to \a T. + /// \tparam T type to return + template struct enable {}; + template struct enable { typedef T type; }; + template struct enable { typedef T type; }; + template struct enable { typedef T type; }; + template struct enable { typedef T type; }; + template struct enable { typedef T type; }; + template struct enable { typedef T type; }; + template struct enable { typedef T type; }; + template struct enable { typedef T type; }; + template struct enable { typedef T type; }; + template struct enable { typedef T type; }; + template struct enable { typedef T type; }; + template struct enable { typedef T type; }; + template struct enable { typedef T type; }; + template struct enable { typedef T type; }; + + /// Return type for specialized generic 2-argument half-precision functions. + /// This class template has to be specialized for each valid combination of argument types to provide a corresponding + /// `type` member denoting the appropriate return type. + /// \tparam T first argument type + /// \tparam U first argument type + template struct result : enable {}; + template<> struct result { typedef half type; }; + + /// \name Classification helpers + /// \{ + + /// Check for infinity. + /// \tparam T argument type (builtin floating point type) + /// \param arg value to query + /// \retval true if infinity + /// \retval false else + template bool builtin_isinf(T arg) + { + #if HALF_ENABLE_CPP11_CMATH + return std::isinf(arg); + #elif defined(_MSC_VER) + return !_finite(static_cast(arg)) && !_isnan(static_cast(arg)); + #else + return arg == std::numeric_limits::infinity() || arg == -std::numeric_limits::infinity(); + #endif + } + + /// Check for NaN. + /// \tparam T argument type (builtin floating point type) + /// \param arg value to query + /// \retval true if not a number + /// \retval false else + template bool builtin_isnan(T arg) + { + #if HALF_ENABLE_CPP11_CMATH + return std::isnan(arg); + #elif defined(_MSC_VER) + return _isnan(static_cast(arg)) != 0; + #else + return arg != arg; + #endif + } + + /// Check sign. + /// \tparam T argument type (builtin floating point type) + /// \param arg value to query + /// \retval true if signbit set + /// \retval false else + template bool builtin_signbit(T arg) + { + #if HALF_ENABLE_CPP11_CMATH + return std::signbit(arg); + #else + return arg < T() || (arg == T() && T(1)/arg < T()); + #endif + } + + /// \} + /// \name Conversion + /// \{ + + /// Convert IEEE single-precision to half-precision. + /// Credit for this goes to [Jeroen van der Zijp](ftp://ftp.fox-toolkit.org/pub/fasthalffloatconversion.pdf). + /// \tparam R rounding mode to use, `std::round_indeterminate` for fastest rounding + /// \param value single-precision value + /// \return binary representation of half-precision value + template uint16 float2half_impl(float value, true_type) + { + #if HALF_ENABLE_CPP11_STATIC_ASSERT + static_assert(std::numeric_limits::is_iec559, "float to half conversion needs IEEE 754 conformant 'float' type"); + static_assert(sizeof(uint32)==sizeof(float), "float to half conversion needs unsigned integer type of exactly the size of a 'float'"); + #endif + static const uint16 base_table[512] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, + 0x0200, 0x0400, 0x0800, 0x0C00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00, + 0x4000, 0x4400, 0x4800, 0x4C00, 0x5000, 0x5400, 0x5800, 0x5C00, 0x6000, 0x6400, 0x6800, 0x6C00, 0x7000, 0x7400, 0x7800, 0x7C00, + 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, + 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, + 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, + 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, + 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, + 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, + 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, 0x7C00, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8001, 0x8002, 0x8004, 0x8008, 0x8010, 0x8020, 0x8040, 0x8080, 0x8100, + 0x8200, 0x8400, 0x8800, 0x8C00, 0x9000, 0x9400, 0x9800, 0x9C00, 0xA000, 0xA400, 0xA800, 0xAC00, 0xB000, 0xB400, 0xB800, 0xBC00, + 0xC000, 0xC400, 0xC800, 0xCC00, 0xD000, 0xD400, 0xD800, 0xDC00, 0xE000, 0xE400, 0xE800, 0xEC00, 0xF000, 0xF400, 0xF800, 0xFC00, + 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, + 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, + 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, + 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, + 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, + 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, + 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00, 0xFC00 }; + static const unsigned char shift_table[512] = { + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 13, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 13 }; + uint32 bits;// = *reinterpret_cast(&value); //violating strict aliasing! + std::memcpy(&bits, &value, sizeof(float)); + uint16 hbits = base_table[bits>>23] + static_cast((bits&0x7FFFFF)>>shift_table[bits>>23]); + if(R == std::round_to_nearest) + hbits += (((bits&0x7FFFFF)>>(shift_table[bits>>23]-1))|(((bits>>23)&0xFF)==102)) & ((hbits&0x7C00)!=0x7C00) + #if HALF_ROUND_TIES_TO_EVEN + & (((((static_cast(1)<<(shift_table[bits>>23]-1))-1)&bits)!=0)|hbits) + #endif + ; + else if(R == std::round_toward_zero) + hbits -= ((hbits&0x7FFF)==0x7C00) & ~shift_table[bits>>23]; + else if(R == std::round_toward_infinity) + hbits += ((((bits&0x7FFFFF&((static_cast(1)<<(shift_table[bits>>23]))-1))!=0)|(((bits>>23)<=102)& + ((bits>>23)!=0)))&(hbits<0x7C00)) - ((hbits==0xFC00)&((bits>>23)!=511)); + else if(R == std::round_toward_neg_infinity) + hbits += ((((bits&0x7FFFFF&((static_cast(1)<<(shift_table[bits>>23]))-1))!=0)|(((bits>>23)<=358)& + ((bits>>23)!=256)))&(hbits<0xFC00)&(hbits>>15)) - ((hbits==0x7C00)&((bits>>23)!=255)); + return hbits; + } + + /// Convert non-IEEE single-precision to half-precision. + /// \param value single-precision value + /// \return binary representation of half-precision value + template uint16 float2half_impl(float value, false_type) + { + uint16 hbits = builtin_signbit(value) << 15; + if(value == 0.0f) + return hbits; + if(builtin_isnan(value)) + return hbits | 0x7FFF; + if(builtin_isinf(value)) + return hbits | 0x7C00; + int exp; + std::frexp(value, &exp); + if(exp > 16) + { + if(R == std::round_toward_zero) + return hbits | 0x7BFF; + else if(R == std::round_toward_infinity) + return hbits | 0x7C00 - (hbits>>15); + else if(R == std::round_toward_neg_infinity) + return hbits | 0x7BFF + (hbits>>15); + return hbits | 0x7C00; + } + if(exp < -13) + value = std::ldexp(value, 24); + else + { + value = std::ldexp(value, 11-exp); + hbits |= ((exp+14)<<10); + } + int ival = static_cast(value); + hbits |= static_cast(std::abs(ival)&0x3FF); + if(R == std::round_to_nearest) + { + float diff = std::abs(value-static_cast(ival)); + #if HALF_ROUND_TIES_TO_EVEN + hbits += (diff>0.5f) | ((diff==0.5f)&hbits); + #else + hbits += diff >= 0.5f; + #endif + } + else if(R == std::round_toward_infinity) + hbits += value > static_cast(ival); + else if(R == std::round_toward_neg_infinity) + hbits += value < static_cast(ival); + return hbits; + } + + /// Convert single-precision to half-precision. + /// \param value single-precision value + /// \return binary representation of half-precision value + template uint16 float2half(float value) + { + return float2half_impl(value, bool_type::is_iec559&&sizeof(uint32)==sizeof(float)>()); + } + + /// Convert integer to half-precision floating point. + /// \tparam R rounding mode to use, `std::round_indeterminate` for fastest rounding + /// \tparam S `true` if value negative, `false` else + /// \tparam T type to convert (builtin integer type) + /// \param value non-negative integral value + /// \return binary representation of half-precision value + template uint16 int2half_impl(T value) + { + if(S) + value = -value; + uint16 bits = S << 15; + if(value > 65504) + { + if(R == std::round_toward_infinity) + bits |= 0x7C00 - S; + else if(R == std::round_toward_neg_infinity) + bits |= 0x7BFF + S; + else + bits |= 0x7BFF + (R!=std::round_toward_zero); + } + else if(value) + { + unsigned int m = value, exp = 25; + for(; m<0x400; m<<=1,--exp) ; + for(; m>0x7FF; m>>=1,++exp) ; + bits |= (exp<<10) | (m&0x3FF); + if(exp > 25) + { + if(R == std::round_to_nearest) + bits += (value>>(exp-26)) & 1 + #if HALF_ROUND_TIES_TO_EVEN + & (((((1<<(exp-26))-1)&value)!=0)|bits) + #endif + ; + else if(R == std::round_toward_infinity) + bits += ((value&((1<<(exp-25))-1))!=0) & !S; + else if(R == std::round_toward_neg_infinity) + bits += ((value&((1<<(exp-25))-1))!=0) & S; + } + } + return bits; + } + + /// Convert integer to half-precision floating point. + /// \tparam R rounding mode to use, `std::round_indeterminate` for fastest rounding + /// \tparam T type to convert (builtin integer type) + /// \param value integral value + /// \return binary representation of half-precision value + template uint16 int2half(T value) + { + return (value<0) ? int2half_impl(value) : int2half_impl(value); + } + + /// Convert half-precision to IEEE single-precision. + /// Credit for this goes to [Jeroen van der Zijp](ftp://ftp.fox-toolkit.org/pub/fasthalffloatconversion.pdf). + /// \param value binary representation of half-precision value + /// \return single-precision value + inline float half2float_impl(uint16 value, true_type) + { + #if HALF_ENABLE_CPP11_STATIC_ASSERT + static_assert(std::numeric_limits::is_iec559, "half to float conversion needs IEEE 754 conformant 'float' type"); + static_assert(sizeof(uint32)==sizeof(float), "half to float conversion needs unsigned integer type of exactly the size of a 'float'"); + #endif + static const uint32 mantissa_table[2048] = { + 0x00000000, 0x33800000, 0x34000000, 0x34400000, 0x34800000, 0x34A00000, 0x34C00000, 0x34E00000, 0x35000000, 0x35100000, 0x35200000, 0x35300000, 0x35400000, 0x35500000, 0x35600000, 0x35700000, + 0x35800000, 0x35880000, 0x35900000, 0x35980000, 0x35A00000, 0x35A80000, 0x35B00000, 0x35B80000, 0x35C00000, 0x35C80000, 0x35D00000, 0x35D80000, 0x35E00000, 0x35E80000, 0x35F00000, 0x35F80000, + 0x36000000, 0x36040000, 0x36080000, 0x360C0000, 0x36100000, 0x36140000, 0x36180000, 0x361C0000, 0x36200000, 0x36240000, 0x36280000, 0x362C0000, 0x36300000, 0x36340000, 0x36380000, 0x363C0000, + 0x36400000, 0x36440000, 0x36480000, 0x364C0000, 0x36500000, 0x36540000, 0x36580000, 0x365C0000, 0x36600000, 0x36640000, 0x36680000, 0x366C0000, 0x36700000, 0x36740000, 0x36780000, 0x367C0000, + 0x36800000, 0x36820000, 0x36840000, 0x36860000, 0x36880000, 0x368A0000, 0x368C0000, 0x368E0000, 0x36900000, 0x36920000, 0x36940000, 0x36960000, 0x36980000, 0x369A0000, 0x369C0000, 0x369E0000, + 0x36A00000, 0x36A20000, 0x36A40000, 0x36A60000, 0x36A80000, 0x36AA0000, 0x36AC0000, 0x36AE0000, 0x36B00000, 0x36B20000, 0x36B40000, 0x36B60000, 0x36B80000, 0x36BA0000, 0x36BC0000, 0x36BE0000, + 0x36C00000, 0x36C20000, 0x36C40000, 0x36C60000, 0x36C80000, 0x36CA0000, 0x36CC0000, 0x36CE0000, 0x36D00000, 0x36D20000, 0x36D40000, 0x36D60000, 0x36D80000, 0x36DA0000, 0x36DC0000, 0x36DE0000, + 0x36E00000, 0x36E20000, 0x36E40000, 0x36E60000, 0x36E80000, 0x36EA0000, 0x36EC0000, 0x36EE0000, 0x36F00000, 0x36F20000, 0x36F40000, 0x36F60000, 0x36F80000, 0x36FA0000, 0x36FC0000, 0x36FE0000, + 0x37000000, 0x37010000, 0x37020000, 0x37030000, 0x37040000, 0x37050000, 0x37060000, 0x37070000, 0x37080000, 0x37090000, 0x370A0000, 0x370B0000, 0x370C0000, 0x370D0000, 0x370E0000, 0x370F0000, + 0x37100000, 0x37110000, 0x37120000, 0x37130000, 0x37140000, 0x37150000, 0x37160000, 0x37170000, 0x37180000, 0x37190000, 0x371A0000, 0x371B0000, 0x371C0000, 0x371D0000, 0x371E0000, 0x371F0000, + 0x37200000, 0x37210000, 0x37220000, 0x37230000, 0x37240000, 0x37250000, 0x37260000, 0x37270000, 0x37280000, 0x37290000, 0x372A0000, 0x372B0000, 0x372C0000, 0x372D0000, 0x372E0000, 0x372F0000, + 0x37300000, 0x37310000, 0x37320000, 0x37330000, 0x37340000, 0x37350000, 0x37360000, 0x37370000, 0x37380000, 0x37390000, 0x373A0000, 0x373B0000, 0x373C0000, 0x373D0000, 0x373E0000, 0x373F0000, + 0x37400000, 0x37410000, 0x37420000, 0x37430000, 0x37440000, 0x37450000, 0x37460000, 0x37470000, 0x37480000, 0x37490000, 0x374A0000, 0x374B0000, 0x374C0000, 0x374D0000, 0x374E0000, 0x374F0000, + 0x37500000, 0x37510000, 0x37520000, 0x37530000, 0x37540000, 0x37550000, 0x37560000, 0x37570000, 0x37580000, 0x37590000, 0x375A0000, 0x375B0000, 0x375C0000, 0x375D0000, 0x375E0000, 0x375F0000, + 0x37600000, 0x37610000, 0x37620000, 0x37630000, 0x37640000, 0x37650000, 0x37660000, 0x37670000, 0x37680000, 0x37690000, 0x376A0000, 0x376B0000, 0x376C0000, 0x376D0000, 0x376E0000, 0x376F0000, + 0x37700000, 0x37710000, 0x37720000, 0x37730000, 0x37740000, 0x37750000, 0x37760000, 0x37770000, 0x37780000, 0x37790000, 0x377A0000, 0x377B0000, 0x377C0000, 0x377D0000, 0x377E0000, 0x377F0000, + 0x37800000, 0x37808000, 0x37810000, 0x37818000, 0x37820000, 0x37828000, 0x37830000, 0x37838000, 0x37840000, 0x37848000, 0x37850000, 0x37858000, 0x37860000, 0x37868000, 0x37870000, 0x37878000, + 0x37880000, 0x37888000, 0x37890000, 0x37898000, 0x378A0000, 0x378A8000, 0x378B0000, 0x378B8000, 0x378C0000, 0x378C8000, 0x378D0000, 0x378D8000, 0x378E0000, 0x378E8000, 0x378F0000, 0x378F8000, + 0x37900000, 0x37908000, 0x37910000, 0x37918000, 0x37920000, 0x37928000, 0x37930000, 0x37938000, 0x37940000, 0x37948000, 0x37950000, 0x37958000, 0x37960000, 0x37968000, 0x37970000, 0x37978000, + 0x37980000, 0x37988000, 0x37990000, 0x37998000, 0x379A0000, 0x379A8000, 0x379B0000, 0x379B8000, 0x379C0000, 0x379C8000, 0x379D0000, 0x379D8000, 0x379E0000, 0x379E8000, 0x379F0000, 0x379F8000, + 0x37A00000, 0x37A08000, 0x37A10000, 0x37A18000, 0x37A20000, 0x37A28000, 0x37A30000, 0x37A38000, 0x37A40000, 0x37A48000, 0x37A50000, 0x37A58000, 0x37A60000, 0x37A68000, 0x37A70000, 0x37A78000, + 0x37A80000, 0x37A88000, 0x37A90000, 0x37A98000, 0x37AA0000, 0x37AA8000, 0x37AB0000, 0x37AB8000, 0x37AC0000, 0x37AC8000, 0x37AD0000, 0x37AD8000, 0x37AE0000, 0x37AE8000, 0x37AF0000, 0x37AF8000, + 0x37B00000, 0x37B08000, 0x37B10000, 0x37B18000, 0x37B20000, 0x37B28000, 0x37B30000, 0x37B38000, 0x37B40000, 0x37B48000, 0x37B50000, 0x37B58000, 0x37B60000, 0x37B68000, 0x37B70000, 0x37B78000, + 0x37B80000, 0x37B88000, 0x37B90000, 0x37B98000, 0x37BA0000, 0x37BA8000, 0x37BB0000, 0x37BB8000, 0x37BC0000, 0x37BC8000, 0x37BD0000, 0x37BD8000, 0x37BE0000, 0x37BE8000, 0x37BF0000, 0x37BF8000, + 0x37C00000, 0x37C08000, 0x37C10000, 0x37C18000, 0x37C20000, 0x37C28000, 0x37C30000, 0x37C38000, 0x37C40000, 0x37C48000, 0x37C50000, 0x37C58000, 0x37C60000, 0x37C68000, 0x37C70000, 0x37C78000, + 0x37C80000, 0x37C88000, 0x37C90000, 0x37C98000, 0x37CA0000, 0x37CA8000, 0x37CB0000, 0x37CB8000, 0x37CC0000, 0x37CC8000, 0x37CD0000, 0x37CD8000, 0x37CE0000, 0x37CE8000, 0x37CF0000, 0x37CF8000, + 0x37D00000, 0x37D08000, 0x37D10000, 0x37D18000, 0x37D20000, 0x37D28000, 0x37D30000, 0x37D38000, 0x37D40000, 0x37D48000, 0x37D50000, 0x37D58000, 0x37D60000, 0x37D68000, 0x37D70000, 0x37D78000, + 0x37D80000, 0x37D88000, 0x37D90000, 0x37D98000, 0x37DA0000, 0x37DA8000, 0x37DB0000, 0x37DB8000, 0x37DC0000, 0x37DC8000, 0x37DD0000, 0x37DD8000, 0x37DE0000, 0x37DE8000, 0x37DF0000, 0x37DF8000, + 0x37E00000, 0x37E08000, 0x37E10000, 0x37E18000, 0x37E20000, 0x37E28000, 0x37E30000, 0x37E38000, 0x37E40000, 0x37E48000, 0x37E50000, 0x37E58000, 0x37E60000, 0x37E68000, 0x37E70000, 0x37E78000, + 0x37E80000, 0x37E88000, 0x37E90000, 0x37E98000, 0x37EA0000, 0x37EA8000, 0x37EB0000, 0x37EB8000, 0x37EC0000, 0x37EC8000, 0x37ED0000, 0x37ED8000, 0x37EE0000, 0x37EE8000, 0x37EF0000, 0x37EF8000, + 0x37F00000, 0x37F08000, 0x37F10000, 0x37F18000, 0x37F20000, 0x37F28000, 0x37F30000, 0x37F38000, 0x37F40000, 0x37F48000, 0x37F50000, 0x37F58000, 0x37F60000, 0x37F68000, 0x37F70000, 0x37F78000, + 0x37F80000, 0x37F88000, 0x37F90000, 0x37F98000, 0x37FA0000, 0x37FA8000, 0x37FB0000, 0x37FB8000, 0x37FC0000, 0x37FC8000, 0x37FD0000, 0x37FD8000, 0x37FE0000, 0x37FE8000, 0x37FF0000, 0x37FF8000, + 0x38000000, 0x38004000, 0x38008000, 0x3800C000, 0x38010000, 0x38014000, 0x38018000, 0x3801C000, 0x38020000, 0x38024000, 0x38028000, 0x3802C000, 0x38030000, 0x38034000, 0x38038000, 0x3803C000, + 0x38040000, 0x38044000, 0x38048000, 0x3804C000, 0x38050000, 0x38054000, 0x38058000, 0x3805C000, 0x38060000, 0x38064000, 0x38068000, 0x3806C000, 0x38070000, 0x38074000, 0x38078000, 0x3807C000, + 0x38080000, 0x38084000, 0x38088000, 0x3808C000, 0x38090000, 0x38094000, 0x38098000, 0x3809C000, 0x380A0000, 0x380A4000, 0x380A8000, 0x380AC000, 0x380B0000, 0x380B4000, 0x380B8000, 0x380BC000, + 0x380C0000, 0x380C4000, 0x380C8000, 0x380CC000, 0x380D0000, 0x380D4000, 0x380D8000, 0x380DC000, 0x380E0000, 0x380E4000, 0x380E8000, 0x380EC000, 0x380F0000, 0x380F4000, 0x380F8000, 0x380FC000, + 0x38100000, 0x38104000, 0x38108000, 0x3810C000, 0x38110000, 0x38114000, 0x38118000, 0x3811C000, 0x38120000, 0x38124000, 0x38128000, 0x3812C000, 0x38130000, 0x38134000, 0x38138000, 0x3813C000, + 0x38140000, 0x38144000, 0x38148000, 0x3814C000, 0x38150000, 0x38154000, 0x38158000, 0x3815C000, 0x38160000, 0x38164000, 0x38168000, 0x3816C000, 0x38170000, 0x38174000, 0x38178000, 0x3817C000, + 0x38180000, 0x38184000, 0x38188000, 0x3818C000, 0x38190000, 0x38194000, 0x38198000, 0x3819C000, 0x381A0000, 0x381A4000, 0x381A8000, 0x381AC000, 0x381B0000, 0x381B4000, 0x381B8000, 0x381BC000, + 0x381C0000, 0x381C4000, 0x381C8000, 0x381CC000, 0x381D0000, 0x381D4000, 0x381D8000, 0x381DC000, 0x381E0000, 0x381E4000, 0x381E8000, 0x381EC000, 0x381F0000, 0x381F4000, 0x381F8000, 0x381FC000, + 0x38200000, 0x38204000, 0x38208000, 0x3820C000, 0x38210000, 0x38214000, 0x38218000, 0x3821C000, 0x38220000, 0x38224000, 0x38228000, 0x3822C000, 0x38230000, 0x38234000, 0x38238000, 0x3823C000, + 0x38240000, 0x38244000, 0x38248000, 0x3824C000, 0x38250000, 0x38254000, 0x38258000, 0x3825C000, 0x38260000, 0x38264000, 0x38268000, 0x3826C000, 0x38270000, 0x38274000, 0x38278000, 0x3827C000, + 0x38280000, 0x38284000, 0x38288000, 0x3828C000, 0x38290000, 0x38294000, 0x38298000, 0x3829C000, 0x382A0000, 0x382A4000, 0x382A8000, 0x382AC000, 0x382B0000, 0x382B4000, 0x382B8000, 0x382BC000, + 0x382C0000, 0x382C4000, 0x382C8000, 0x382CC000, 0x382D0000, 0x382D4000, 0x382D8000, 0x382DC000, 0x382E0000, 0x382E4000, 0x382E8000, 0x382EC000, 0x382F0000, 0x382F4000, 0x382F8000, 0x382FC000, + 0x38300000, 0x38304000, 0x38308000, 0x3830C000, 0x38310000, 0x38314000, 0x38318000, 0x3831C000, 0x38320000, 0x38324000, 0x38328000, 0x3832C000, 0x38330000, 0x38334000, 0x38338000, 0x3833C000, + 0x38340000, 0x38344000, 0x38348000, 0x3834C000, 0x38350000, 0x38354000, 0x38358000, 0x3835C000, 0x38360000, 0x38364000, 0x38368000, 0x3836C000, 0x38370000, 0x38374000, 0x38378000, 0x3837C000, + 0x38380000, 0x38384000, 0x38388000, 0x3838C000, 0x38390000, 0x38394000, 0x38398000, 0x3839C000, 0x383A0000, 0x383A4000, 0x383A8000, 0x383AC000, 0x383B0000, 0x383B4000, 0x383B8000, 0x383BC000, + 0x383C0000, 0x383C4000, 0x383C8000, 0x383CC000, 0x383D0000, 0x383D4000, 0x383D8000, 0x383DC000, 0x383E0000, 0x383E4000, 0x383E8000, 0x383EC000, 0x383F0000, 0x383F4000, 0x383F8000, 0x383FC000, + 0x38400000, 0x38404000, 0x38408000, 0x3840C000, 0x38410000, 0x38414000, 0x38418000, 0x3841C000, 0x38420000, 0x38424000, 0x38428000, 0x3842C000, 0x38430000, 0x38434000, 0x38438000, 0x3843C000, + 0x38440000, 0x38444000, 0x38448000, 0x3844C000, 0x38450000, 0x38454000, 0x38458000, 0x3845C000, 0x38460000, 0x38464000, 0x38468000, 0x3846C000, 0x38470000, 0x38474000, 0x38478000, 0x3847C000, + 0x38480000, 0x38484000, 0x38488000, 0x3848C000, 0x38490000, 0x38494000, 0x38498000, 0x3849C000, 0x384A0000, 0x384A4000, 0x384A8000, 0x384AC000, 0x384B0000, 0x384B4000, 0x384B8000, 0x384BC000, + 0x384C0000, 0x384C4000, 0x384C8000, 0x384CC000, 0x384D0000, 0x384D4000, 0x384D8000, 0x384DC000, 0x384E0000, 0x384E4000, 0x384E8000, 0x384EC000, 0x384F0000, 0x384F4000, 0x384F8000, 0x384FC000, + 0x38500000, 0x38504000, 0x38508000, 0x3850C000, 0x38510000, 0x38514000, 0x38518000, 0x3851C000, 0x38520000, 0x38524000, 0x38528000, 0x3852C000, 0x38530000, 0x38534000, 0x38538000, 0x3853C000, + 0x38540000, 0x38544000, 0x38548000, 0x3854C000, 0x38550000, 0x38554000, 0x38558000, 0x3855C000, 0x38560000, 0x38564000, 0x38568000, 0x3856C000, 0x38570000, 0x38574000, 0x38578000, 0x3857C000, + 0x38580000, 0x38584000, 0x38588000, 0x3858C000, 0x38590000, 0x38594000, 0x38598000, 0x3859C000, 0x385A0000, 0x385A4000, 0x385A8000, 0x385AC000, 0x385B0000, 0x385B4000, 0x385B8000, 0x385BC000, + 0x385C0000, 0x385C4000, 0x385C8000, 0x385CC000, 0x385D0000, 0x385D4000, 0x385D8000, 0x385DC000, 0x385E0000, 0x385E4000, 0x385E8000, 0x385EC000, 0x385F0000, 0x385F4000, 0x385F8000, 0x385FC000, + 0x38600000, 0x38604000, 0x38608000, 0x3860C000, 0x38610000, 0x38614000, 0x38618000, 0x3861C000, 0x38620000, 0x38624000, 0x38628000, 0x3862C000, 0x38630000, 0x38634000, 0x38638000, 0x3863C000, + 0x38640000, 0x38644000, 0x38648000, 0x3864C000, 0x38650000, 0x38654000, 0x38658000, 0x3865C000, 0x38660000, 0x38664000, 0x38668000, 0x3866C000, 0x38670000, 0x38674000, 0x38678000, 0x3867C000, + 0x38680000, 0x38684000, 0x38688000, 0x3868C000, 0x38690000, 0x38694000, 0x38698000, 0x3869C000, 0x386A0000, 0x386A4000, 0x386A8000, 0x386AC000, 0x386B0000, 0x386B4000, 0x386B8000, 0x386BC000, + 0x386C0000, 0x386C4000, 0x386C8000, 0x386CC000, 0x386D0000, 0x386D4000, 0x386D8000, 0x386DC000, 0x386E0000, 0x386E4000, 0x386E8000, 0x386EC000, 0x386F0000, 0x386F4000, 0x386F8000, 0x386FC000, + 0x38700000, 0x38704000, 0x38708000, 0x3870C000, 0x38710000, 0x38714000, 0x38718000, 0x3871C000, 0x38720000, 0x38724000, 0x38728000, 0x3872C000, 0x38730000, 0x38734000, 0x38738000, 0x3873C000, + 0x38740000, 0x38744000, 0x38748000, 0x3874C000, 0x38750000, 0x38754000, 0x38758000, 0x3875C000, 0x38760000, 0x38764000, 0x38768000, 0x3876C000, 0x38770000, 0x38774000, 0x38778000, 0x3877C000, + 0x38780000, 0x38784000, 0x38788000, 0x3878C000, 0x38790000, 0x38794000, 0x38798000, 0x3879C000, 0x387A0000, 0x387A4000, 0x387A8000, 0x387AC000, 0x387B0000, 0x387B4000, 0x387B8000, 0x387BC000, + 0x387C0000, 0x387C4000, 0x387C8000, 0x387CC000, 0x387D0000, 0x387D4000, 0x387D8000, 0x387DC000, 0x387E0000, 0x387E4000, 0x387E8000, 0x387EC000, 0x387F0000, 0x387F4000, 0x387F8000, 0x387FC000, + 0x38000000, 0x38002000, 0x38004000, 0x38006000, 0x38008000, 0x3800A000, 0x3800C000, 0x3800E000, 0x38010000, 0x38012000, 0x38014000, 0x38016000, 0x38018000, 0x3801A000, 0x3801C000, 0x3801E000, + 0x38020000, 0x38022000, 0x38024000, 0x38026000, 0x38028000, 0x3802A000, 0x3802C000, 0x3802E000, 0x38030000, 0x38032000, 0x38034000, 0x38036000, 0x38038000, 0x3803A000, 0x3803C000, 0x3803E000, + 0x38040000, 0x38042000, 0x38044000, 0x38046000, 0x38048000, 0x3804A000, 0x3804C000, 0x3804E000, 0x38050000, 0x38052000, 0x38054000, 0x38056000, 0x38058000, 0x3805A000, 0x3805C000, 0x3805E000, + 0x38060000, 0x38062000, 0x38064000, 0x38066000, 0x38068000, 0x3806A000, 0x3806C000, 0x3806E000, 0x38070000, 0x38072000, 0x38074000, 0x38076000, 0x38078000, 0x3807A000, 0x3807C000, 0x3807E000, + 0x38080000, 0x38082000, 0x38084000, 0x38086000, 0x38088000, 0x3808A000, 0x3808C000, 0x3808E000, 0x38090000, 0x38092000, 0x38094000, 0x38096000, 0x38098000, 0x3809A000, 0x3809C000, 0x3809E000, + 0x380A0000, 0x380A2000, 0x380A4000, 0x380A6000, 0x380A8000, 0x380AA000, 0x380AC000, 0x380AE000, 0x380B0000, 0x380B2000, 0x380B4000, 0x380B6000, 0x380B8000, 0x380BA000, 0x380BC000, 0x380BE000, + 0x380C0000, 0x380C2000, 0x380C4000, 0x380C6000, 0x380C8000, 0x380CA000, 0x380CC000, 0x380CE000, 0x380D0000, 0x380D2000, 0x380D4000, 0x380D6000, 0x380D8000, 0x380DA000, 0x380DC000, 0x380DE000, + 0x380E0000, 0x380E2000, 0x380E4000, 0x380E6000, 0x380E8000, 0x380EA000, 0x380EC000, 0x380EE000, 0x380F0000, 0x380F2000, 0x380F4000, 0x380F6000, 0x380F8000, 0x380FA000, 0x380FC000, 0x380FE000, + 0x38100000, 0x38102000, 0x38104000, 0x38106000, 0x38108000, 0x3810A000, 0x3810C000, 0x3810E000, 0x38110000, 0x38112000, 0x38114000, 0x38116000, 0x38118000, 0x3811A000, 0x3811C000, 0x3811E000, + 0x38120000, 0x38122000, 0x38124000, 0x38126000, 0x38128000, 0x3812A000, 0x3812C000, 0x3812E000, 0x38130000, 0x38132000, 0x38134000, 0x38136000, 0x38138000, 0x3813A000, 0x3813C000, 0x3813E000, + 0x38140000, 0x38142000, 0x38144000, 0x38146000, 0x38148000, 0x3814A000, 0x3814C000, 0x3814E000, 0x38150000, 0x38152000, 0x38154000, 0x38156000, 0x38158000, 0x3815A000, 0x3815C000, 0x3815E000, + 0x38160000, 0x38162000, 0x38164000, 0x38166000, 0x38168000, 0x3816A000, 0x3816C000, 0x3816E000, 0x38170000, 0x38172000, 0x38174000, 0x38176000, 0x38178000, 0x3817A000, 0x3817C000, 0x3817E000, + 0x38180000, 0x38182000, 0x38184000, 0x38186000, 0x38188000, 0x3818A000, 0x3818C000, 0x3818E000, 0x38190000, 0x38192000, 0x38194000, 0x38196000, 0x38198000, 0x3819A000, 0x3819C000, 0x3819E000, + 0x381A0000, 0x381A2000, 0x381A4000, 0x381A6000, 0x381A8000, 0x381AA000, 0x381AC000, 0x381AE000, 0x381B0000, 0x381B2000, 0x381B4000, 0x381B6000, 0x381B8000, 0x381BA000, 0x381BC000, 0x381BE000, + 0x381C0000, 0x381C2000, 0x381C4000, 0x381C6000, 0x381C8000, 0x381CA000, 0x381CC000, 0x381CE000, 0x381D0000, 0x381D2000, 0x381D4000, 0x381D6000, 0x381D8000, 0x381DA000, 0x381DC000, 0x381DE000, + 0x381E0000, 0x381E2000, 0x381E4000, 0x381E6000, 0x381E8000, 0x381EA000, 0x381EC000, 0x381EE000, 0x381F0000, 0x381F2000, 0x381F4000, 0x381F6000, 0x381F8000, 0x381FA000, 0x381FC000, 0x381FE000, + 0x38200000, 0x38202000, 0x38204000, 0x38206000, 0x38208000, 0x3820A000, 0x3820C000, 0x3820E000, 0x38210000, 0x38212000, 0x38214000, 0x38216000, 0x38218000, 0x3821A000, 0x3821C000, 0x3821E000, + 0x38220000, 0x38222000, 0x38224000, 0x38226000, 0x38228000, 0x3822A000, 0x3822C000, 0x3822E000, 0x38230000, 0x38232000, 0x38234000, 0x38236000, 0x38238000, 0x3823A000, 0x3823C000, 0x3823E000, + 0x38240000, 0x38242000, 0x38244000, 0x38246000, 0x38248000, 0x3824A000, 0x3824C000, 0x3824E000, 0x38250000, 0x38252000, 0x38254000, 0x38256000, 0x38258000, 0x3825A000, 0x3825C000, 0x3825E000, + 0x38260000, 0x38262000, 0x38264000, 0x38266000, 0x38268000, 0x3826A000, 0x3826C000, 0x3826E000, 0x38270000, 0x38272000, 0x38274000, 0x38276000, 0x38278000, 0x3827A000, 0x3827C000, 0x3827E000, + 0x38280000, 0x38282000, 0x38284000, 0x38286000, 0x38288000, 0x3828A000, 0x3828C000, 0x3828E000, 0x38290000, 0x38292000, 0x38294000, 0x38296000, 0x38298000, 0x3829A000, 0x3829C000, 0x3829E000, + 0x382A0000, 0x382A2000, 0x382A4000, 0x382A6000, 0x382A8000, 0x382AA000, 0x382AC000, 0x382AE000, 0x382B0000, 0x382B2000, 0x382B4000, 0x382B6000, 0x382B8000, 0x382BA000, 0x382BC000, 0x382BE000, + 0x382C0000, 0x382C2000, 0x382C4000, 0x382C6000, 0x382C8000, 0x382CA000, 0x382CC000, 0x382CE000, 0x382D0000, 0x382D2000, 0x382D4000, 0x382D6000, 0x382D8000, 0x382DA000, 0x382DC000, 0x382DE000, + 0x382E0000, 0x382E2000, 0x382E4000, 0x382E6000, 0x382E8000, 0x382EA000, 0x382EC000, 0x382EE000, 0x382F0000, 0x382F2000, 0x382F4000, 0x382F6000, 0x382F8000, 0x382FA000, 0x382FC000, 0x382FE000, + 0x38300000, 0x38302000, 0x38304000, 0x38306000, 0x38308000, 0x3830A000, 0x3830C000, 0x3830E000, 0x38310000, 0x38312000, 0x38314000, 0x38316000, 0x38318000, 0x3831A000, 0x3831C000, 0x3831E000, + 0x38320000, 0x38322000, 0x38324000, 0x38326000, 0x38328000, 0x3832A000, 0x3832C000, 0x3832E000, 0x38330000, 0x38332000, 0x38334000, 0x38336000, 0x38338000, 0x3833A000, 0x3833C000, 0x3833E000, + 0x38340000, 0x38342000, 0x38344000, 0x38346000, 0x38348000, 0x3834A000, 0x3834C000, 0x3834E000, 0x38350000, 0x38352000, 0x38354000, 0x38356000, 0x38358000, 0x3835A000, 0x3835C000, 0x3835E000, + 0x38360000, 0x38362000, 0x38364000, 0x38366000, 0x38368000, 0x3836A000, 0x3836C000, 0x3836E000, 0x38370000, 0x38372000, 0x38374000, 0x38376000, 0x38378000, 0x3837A000, 0x3837C000, 0x3837E000, + 0x38380000, 0x38382000, 0x38384000, 0x38386000, 0x38388000, 0x3838A000, 0x3838C000, 0x3838E000, 0x38390000, 0x38392000, 0x38394000, 0x38396000, 0x38398000, 0x3839A000, 0x3839C000, 0x3839E000, + 0x383A0000, 0x383A2000, 0x383A4000, 0x383A6000, 0x383A8000, 0x383AA000, 0x383AC000, 0x383AE000, 0x383B0000, 0x383B2000, 0x383B4000, 0x383B6000, 0x383B8000, 0x383BA000, 0x383BC000, 0x383BE000, + 0x383C0000, 0x383C2000, 0x383C4000, 0x383C6000, 0x383C8000, 0x383CA000, 0x383CC000, 0x383CE000, 0x383D0000, 0x383D2000, 0x383D4000, 0x383D6000, 0x383D8000, 0x383DA000, 0x383DC000, 0x383DE000, + 0x383E0000, 0x383E2000, 0x383E4000, 0x383E6000, 0x383E8000, 0x383EA000, 0x383EC000, 0x383EE000, 0x383F0000, 0x383F2000, 0x383F4000, 0x383F6000, 0x383F8000, 0x383FA000, 0x383FC000, 0x383FE000, + 0x38400000, 0x38402000, 0x38404000, 0x38406000, 0x38408000, 0x3840A000, 0x3840C000, 0x3840E000, 0x38410000, 0x38412000, 0x38414000, 0x38416000, 0x38418000, 0x3841A000, 0x3841C000, 0x3841E000, + 0x38420000, 0x38422000, 0x38424000, 0x38426000, 0x38428000, 0x3842A000, 0x3842C000, 0x3842E000, 0x38430000, 0x38432000, 0x38434000, 0x38436000, 0x38438000, 0x3843A000, 0x3843C000, 0x3843E000, + 0x38440000, 0x38442000, 0x38444000, 0x38446000, 0x38448000, 0x3844A000, 0x3844C000, 0x3844E000, 0x38450000, 0x38452000, 0x38454000, 0x38456000, 0x38458000, 0x3845A000, 0x3845C000, 0x3845E000, + 0x38460000, 0x38462000, 0x38464000, 0x38466000, 0x38468000, 0x3846A000, 0x3846C000, 0x3846E000, 0x38470000, 0x38472000, 0x38474000, 0x38476000, 0x38478000, 0x3847A000, 0x3847C000, 0x3847E000, + 0x38480000, 0x38482000, 0x38484000, 0x38486000, 0x38488000, 0x3848A000, 0x3848C000, 0x3848E000, 0x38490000, 0x38492000, 0x38494000, 0x38496000, 0x38498000, 0x3849A000, 0x3849C000, 0x3849E000, + 0x384A0000, 0x384A2000, 0x384A4000, 0x384A6000, 0x384A8000, 0x384AA000, 0x384AC000, 0x384AE000, 0x384B0000, 0x384B2000, 0x384B4000, 0x384B6000, 0x384B8000, 0x384BA000, 0x384BC000, 0x384BE000, + 0x384C0000, 0x384C2000, 0x384C4000, 0x384C6000, 0x384C8000, 0x384CA000, 0x384CC000, 0x384CE000, 0x384D0000, 0x384D2000, 0x384D4000, 0x384D6000, 0x384D8000, 0x384DA000, 0x384DC000, 0x384DE000, + 0x384E0000, 0x384E2000, 0x384E4000, 0x384E6000, 0x384E8000, 0x384EA000, 0x384EC000, 0x384EE000, 0x384F0000, 0x384F2000, 0x384F4000, 0x384F6000, 0x384F8000, 0x384FA000, 0x384FC000, 0x384FE000, + 0x38500000, 0x38502000, 0x38504000, 0x38506000, 0x38508000, 0x3850A000, 0x3850C000, 0x3850E000, 0x38510000, 0x38512000, 0x38514000, 0x38516000, 0x38518000, 0x3851A000, 0x3851C000, 0x3851E000, + 0x38520000, 0x38522000, 0x38524000, 0x38526000, 0x38528000, 0x3852A000, 0x3852C000, 0x3852E000, 0x38530000, 0x38532000, 0x38534000, 0x38536000, 0x38538000, 0x3853A000, 0x3853C000, 0x3853E000, + 0x38540000, 0x38542000, 0x38544000, 0x38546000, 0x38548000, 0x3854A000, 0x3854C000, 0x3854E000, 0x38550000, 0x38552000, 0x38554000, 0x38556000, 0x38558000, 0x3855A000, 0x3855C000, 0x3855E000, + 0x38560000, 0x38562000, 0x38564000, 0x38566000, 0x38568000, 0x3856A000, 0x3856C000, 0x3856E000, 0x38570000, 0x38572000, 0x38574000, 0x38576000, 0x38578000, 0x3857A000, 0x3857C000, 0x3857E000, + 0x38580000, 0x38582000, 0x38584000, 0x38586000, 0x38588000, 0x3858A000, 0x3858C000, 0x3858E000, 0x38590000, 0x38592000, 0x38594000, 0x38596000, 0x38598000, 0x3859A000, 0x3859C000, 0x3859E000, + 0x385A0000, 0x385A2000, 0x385A4000, 0x385A6000, 0x385A8000, 0x385AA000, 0x385AC000, 0x385AE000, 0x385B0000, 0x385B2000, 0x385B4000, 0x385B6000, 0x385B8000, 0x385BA000, 0x385BC000, 0x385BE000, + 0x385C0000, 0x385C2000, 0x385C4000, 0x385C6000, 0x385C8000, 0x385CA000, 0x385CC000, 0x385CE000, 0x385D0000, 0x385D2000, 0x385D4000, 0x385D6000, 0x385D8000, 0x385DA000, 0x385DC000, 0x385DE000, + 0x385E0000, 0x385E2000, 0x385E4000, 0x385E6000, 0x385E8000, 0x385EA000, 0x385EC000, 0x385EE000, 0x385F0000, 0x385F2000, 0x385F4000, 0x385F6000, 0x385F8000, 0x385FA000, 0x385FC000, 0x385FE000, + 0x38600000, 0x38602000, 0x38604000, 0x38606000, 0x38608000, 0x3860A000, 0x3860C000, 0x3860E000, 0x38610000, 0x38612000, 0x38614000, 0x38616000, 0x38618000, 0x3861A000, 0x3861C000, 0x3861E000, + 0x38620000, 0x38622000, 0x38624000, 0x38626000, 0x38628000, 0x3862A000, 0x3862C000, 0x3862E000, 0x38630000, 0x38632000, 0x38634000, 0x38636000, 0x38638000, 0x3863A000, 0x3863C000, 0x3863E000, + 0x38640000, 0x38642000, 0x38644000, 0x38646000, 0x38648000, 0x3864A000, 0x3864C000, 0x3864E000, 0x38650000, 0x38652000, 0x38654000, 0x38656000, 0x38658000, 0x3865A000, 0x3865C000, 0x3865E000, + 0x38660000, 0x38662000, 0x38664000, 0x38666000, 0x38668000, 0x3866A000, 0x3866C000, 0x3866E000, 0x38670000, 0x38672000, 0x38674000, 0x38676000, 0x38678000, 0x3867A000, 0x3867C000, 0x3867E000, + 0x38680000, 0x38682000, 0x38684000, 0x38686000, 0x38688000, 0x3868A000, 0x3868C000, 0x3868E000, 0x38690000, 0x38692000, 0x38694000, 0x38696000, 0x38698000, 0x3869A000, 0x3869C000, 0x3869E000, + 0x386A0000, 0x386A2000, 0x386A4000, 0x386A6000, 0x386A8000, 0x386AA000, 0x386AC000, 0x386AE000, 0x386B0000, 0x386B2000, 0x386B4000, 0x386B6000, 0x386B8000, 0x386BA000, 0x386BC000, 0x386BE000, + 0x386C0000, 0x386C2000, 0x386C4000, 0x386C6000, 0x386C8000, 0x386CA000, 0x386CC000, 0x386CE000, 0x386D0000, 0x386D2000, 0x386D4000, 0x386D6000, 0x386D8000, 0x386DA000, 0x386DC000, 0x386DE000, + 0x386E0000, 0x386E2000, 0x386E4000, 0x386E6000, 0x386E8000, 0x386EA000, 0x386EC000, 0x386EE000, 0x386F0000, 0x386F2000, 0x386F4000, 0x386F6000, 0x386F8000, 0x386FA000, 0x386FC000, 0x386FE000, + 0x38700000, 0x38702000, 0x38704000, 0x38706000, 0x38708000, 0x3870A000, 0x3870C000, 0x3870E000, 0x38710000, 0x38712000, 0x38714000, 0x38716000, 0x38718000, 0x3871A000, 0x3871C000, 0x3871E000, + 0x38720000, 0x38722000, 0x38724000, 0x38726000, 0x38728000, 0x3872A000, 0x3872C000, 0x3872E000, 0x38730000, 0x38732000, 0x38734000, 0x38736000, 0x38738000, 0x3873A000, 0x3873C000, 0x3873E000, + 0x38740000, 0x38742000, 0x38744000, 0x38746000, 0x38748000, 0x3874A000, 0x3874C000, 0x3874E000, 0x38750000, 0x38752000, 0x38754000, 0x38756000, 0x38758000, 0x3875A000, 0x3875C000, 0x3875E000, + 0x38760000, 0x38762000, 0x38764000, 0x38766000, 0x38768000, 0x3876A000, 0x3876C000, 0x3876E000, 0x38770000, 0x38772000, 0x38774000, 0x38776000, 0x38778000, 0x3877A000, 0x3877C000, 0x3877E000, + 0x38780000, 0x38782000, 0x38784000, 0x38786000, 0x38788000, 0x3878A000, 0x3878C000, 0x3878E000, 0x38790000, 0x38792000, 0x38794000, 0x38796000, 0x38798000, 0x3879A000, 0x3879C000, 0x3879E000, + 0x387A0000, 0x387A2000, 0x387A4000, 0x387A6000, 0x387A8000, 0x387AA000, 0x387AC000, 0x387AE000, 0x387B0000, 0x387B2000, 0x387B4000, 0x387B6000, 0x387B8000, 0x387BA000, 0x387BC000, 0x387BE000, + 0x387C0000, 0x387C2000, 0x387C4000, 0x387C6000, 0x387C8000, 0x387CA000, 0x387CC000, 0x387CE000, 0x387D0000, 0x387D2000, 0x387D4000, 0x387D6000, 0x387D8000, 0x387DA000, 0x387DC000, 0x387DE000, + 0x387E0000, 0x387E2000, 0x387E4000, 0x387E6000, 0x387E8000, 0x387EA000, 0x387EC000, 0x387EE000, 0x387F0000, 0x387F2000, 0x387F4000, 0x387F6000, 0x387F8000, 0x387FA000, 0x387FC000, 0x387FE000 }; + static const uint32 exponent_table[64] = { + 0x00000000, 0x00800000, 0x01000000, 0x01800000, 0x02000000, 0x02800000, 0x03000000, 0x03800000, 0x04000000, 0x04800000, 0x05000000, 0x05800000, 0x06000000, 0x06800000, 0x07000000, 0x07800000, + 0x08000000, 0x08800000, 0x09000000, 0x09800000, 0x0A000000, 0x0A800000, 0x0B000000, 0x0B800000, 0x0C000000, 0x0C800000, 0x0D000000, 0x0D800000, 0x0E000000, 0x0E800000, 0x0F000000, 0x47800000, + 0x80000000, 0x80800000, 0x81000000, 0x81800000, 0x82000000, 0x82800000, 0x83000000, 0x83800000, 0x84000000, 0x84800000, 0x85000000, 0x85800000, 0x86000000, 0x86800000, 0x87000000, 0x87800000, + 0x88000000, 0x88800000, 0x89000000, 0x89800000, 0x8A000000, 0x8A800000, 0x8B000000, 0x8B800000, 0x8C000000, 0x8C800000, 0x8D000000, 0x8D800000, 0x8E000000, 0x8E800000, 0x8F000000, 0xC7800000 }; + static const unsigned short offset_table[64] = { + 0, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 0, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024 }; + uint32 bits = mantissa_table[offset_table[value>>10]+(value&0x3FF)] + exponent_table[value>>10]; +// uint32 bits = mantissa_table[(((value&0x7C00)!=0)<<10)+(value&0x3FF)] + exponent_table[value>>10]; +// return *reinterpret_cast(&bits); //violating strict aliasing! + float out; + std::memcpy(&out, &bits, sizeof(float)); + return out; + } + + /// Convert half-precision to non-IEEE single-precision. + /// \param value binary representation of half-precision value + /// \return single-precision value + inline float half2float_impl(uint16 value, false_type) + { + float out; + int abs = value & 0x7FFF; + if(abs > 0x7C00) + out = std::numeric_limits::has_quiet_NaN ? std::numeric_limits::quiet_NaN() : 0.0f; + else if(abs == 0x7C00) + out = std::numeric_limits::has_infinity ? std::numeric_limits::infinity() : std::numeric_limits::max(); + else if(abs > 0x3FF) + out = std::ldexp(static_cast((value&0x3FF)|0x400), (abs>>10)-25); + else + out = std::ldexp(static_cast(abs), -24); + return (value&0x8000) ? -out : out; + } + + /// Convert half-precision to single-precision. + /// \param value binary representation of half-precision value + /// \return single-precision value + inline float half2float(uint16 value) + { + return half2float_impl(value, bool_type::is_iec559&&sizeof(uint32)==sizeof(float)>()); + } + + /// Convert half-precision floating point to integer. + /// \tparam R rounding mode to use, `std::round_indeterminate` for fastest rounding + /// \tparam E `true` for round to even, `false` for round away from zero + /// \tparam T type to convert to (buitlin integer type with at least 16 bits precision, excluding any implicit sign bits) + /// \param value binary representation of half-precision value + /// \return integral value + template T half2int_impl(uint16 value) + { + unsigned int e = value & 0x7FFF; + if(e >= 0x7C00) + return (value&0x8000) ? std::numeric_limits::min() : std::numeric_limits::max(); + if(e < 0x3800) + { + if(R == std::round_toward_infinity) + return T(~(value>>15)&(e!=0)); + else if(R == std::round_toward_neg_infinity) + return -T(value>0x8000); + return T(); + } + int17 m = (value&0x3FF) | 0x400; + e >>= 10; + if(e < 25) + { + if(R == std::round_indeterminate || R == std::round_toward_zero) + m >>= 25 - e; + else + { + if(R == std::round_to_nearest) + m += (1<<(24-e)) - (~(m>>(25-e))&E); + else if(R == std::round_toward_infinity) + m += ((value>>15)-1) & ((1<<(25-e))-1U); + else if(R == std::round_toward_neg_infinity) + m += -(value>>15) & ((1<<(25-e))-1U); + m >>= 25 - e; + } + } + else + m <<= e - 25; +// if(std::numeric_limits::digits < 16) +// return std::min(std::max(m, static_cast(std::numeric_limits::min())), static_cast(std::numeric_limits::max())); + return static_cast((value&0x8000) ? -m : m); + } + + /// Convert half-precision floating point to integer. + /// \tparam R rounding mode to use, `std::round_indeterminate` for fastest rounding + /// \tparam T type to convert to (buitlin integer type with at least 16 bits precision, excluding any implicit sign bits) + /// \param value binary representation of half-precision value + /// \return integral value + template T half2int(uint16 value) { return half2int_impl(value); } + + /// Convert half-precision floating point to integer using round-to-nearest-away-from-zero. + /// \tparam T type to convert to (buitlin integer type with at least 16 bits precision, excluding any implicit sign bits) + /// \param value binary representation of half-precision value + /// \return integral value + template T half2int_up(uint16 value) { return half2int_impl(value); } + + /// Round half-precision number to nearest integer value. + /// \tparam R rounding mode to use, `std::round_indeterminate` for fastest rounding + /// \tparam E `true` for round to even, `false` for round away from zero + /// \param value binary representation of half-precision value + /// \return half-precision bits for nearest integral value + template uint16 round_half_impl(uint16 value) + { + unsigned int e = value & 0x7FFF; + uint16 result = value; + if(e < 0x3C00) + { + result &= 0x8000; + if(R == std::round_to_nearest) + result |= 0x3C00U & -(e>=(0x3800+E)); + else if(R == std::round_toward_infinity) + result |= 0x3C00U & -(~(value>>15)&(e!=0)); + else if(R == std::round_toward_neg_infinity) + result |= 0x3C00U & -(value>0x8000); + } + else if(e < 0x6400) + { + e = 25 - (e>>10); + unsigned int mask = (1<>e)&E); + else if(R == std::round_toward_infinity) + result += mask & ((value>>15)-1); + else if(R == std::round_toward_neg_infinity) + result += mask & -(value>>15); + result &= ~mask; + } + return result; + } + + /// Round half-precision number to nearest integer value. + /// \tparam R rounding mode to use, `std::round_indeterminate` for fastest rounding + /// \param value binary representation of half-precision value + /// \return half-precision bits for nearest integral value + template uint16 round_half(uint16 value) { return round_half_impl(value); } + + /// Round half-precision number to nearest integer value using round-to-nearest-away-from-zero. + /// \param value binary representation of half-precision value + /// \return half-precision bits for nearest integral value + inline uint16 round_half_up(uint16 value) { return round_half_impl(value); } + /// \} + + struct functions; + template struct unary_specialized; + template struct binary_specialized; + template struct half_caster; + } + + /// Half-precision floating point type. + /// This class implements an IEEE-conformant half-precision floating point type with the usual arithmetic operators and + /// conversions. It is implicitly convertible to single-precision floating point, which makes artihmetic expressions and + /// functions with mixed-type operands to be of the most precise operand type. Additionally all arithmetic operations + /// (and many mathematical functions) are carried out in single-precision internally. All conversions from single- to + /// half-precision are done using truncation (round towards zero), but temporary results inside chained arithmetic + /// expressions are kept in single-precision as long as possible (while of course still maintaining a strong half-precision type). + /// + /// According to the C++98/03 definition, the half type is not a POD type. But according to C++11's less strict and + /// extended definitions it is both a standard layout type and a trivially copyable type (even if not a POD type), which + /// means it can be standard-conformantly copied using raw binary copies. But in this context some more words about the + /// actual size of the type. Although the half is representing an IEEE 16-bit type, it does not neccessarily have to be of + /// exactly 16-bits size. But on any reasonable implementation the actual binary representation of this type will most + /// probably not ivolve any additional "magic" or padding beyond the simple binary representation of the underlying 16-bit + /// IEEE number, even if not strictly guaranteed by the standard. But even then it only has an actual size of 16 bits if + /// your C++ implementation supports an unsigned integer type of exactly 16 bits width. But this should be the case on + /// nearly any reasonable platform. + /// + /// So if your C++ implementation is not totally exotic or imposes special alignment requirements, it is a reasonable + /// assumption that the data of a half is just comprised of the 2 bytes of the underlying IEEE representation. + class half + { + friend struct detail::functions; + friend struct detail::unary_specialized; + friend struct detail::binary_specialized; + template friend struct detail::half_caster; + friend class std::numeric_limits; + #if HALF_ENABLE_CPP11_HASH + friend struct std::hash; + #endif + + public: + /// Default constructor. + /// This initializes the half to 0. Although this does not match the builtin types' default-initialization semantics + /// and may be less efficient than no initialization, it is needed to provide proper value-initialization semantics. + HALF_CONSTEXPR half() : data_() {} + + /// Copy constructor. + /// \tparam T type of concrete half expression + /// \param rhs half expression to copy from + half(detail::expr rhs) : data_(detail::float2half(rhs)) {} + + /// Conversion constructor. + /// \param rhs float to convert + explicit half(float rhs) : data_(detail::float2half(rhs)) {} + + /// Conversion to single-precision. + /// \return single precision value representing expression value + operator float() const { return detail::half2float(data_); } + + /// Assignment operator. + /// \tparam T type of concrete half expression + /// \param rhs half expression to copy from + /// \return reference to this half + half& operator=(detail::expr rhs) { return *this = static_cast(rhs); } + + /// Arithmetic assignment. + /// \tparam T type of concrete half expression + /// \param rhs half expression to add + /// \return reference to this half + template typename detail::enable::type operator+=(T rhs) { return *this += static_cast(rhs); } + + /// Arithmetic assignment. + /// \tparam T type of concrete half expression + /// \param rhs half expression to subtract + /// \return reference to this half + template typename detail::enable::type operator-=(T rhs) { return *this -= static_cast(rhs); } + + /// Arithmetic assignment. + /// \tparam T type of concrete half expression + /// \param rhs half expression to multiply with + /// \return reference to this half + template typename detail::enable::type operator*=(T rhs) { return *this *= static_cast(rhs); } + + /// Arithmetic assignment. + /// \tparam T type of concrete half expression + /// \param rhs half expression to divide by + /// \return reference to this half + template typename detail::enable::type operator/=(T rhs) { return *this /= static_cast(rhs); } + + /// Assignment operator. + /// \param rhs single-precision value to copy from + /// \return reference to this half + half& operator=(float rhs) { data_ = detail::float2half(rhs); return *this; } + + /// Arithmetic assignment. + /// \param rhs single-precision value to add + /// \return reference to this half + half& operator+=(float rhs) { data_ = detail::float2half(detail::half2float(data_)+rhs); return *this; } + + /// Arithmetic assignment. + /// \param rhs single-precision value to subtract + /// \return reference to this half + half& operator-=(float rhs) { data_ = detail::float2half(detail::half2float(data_)-rhs); return *this; } + + /// Arithmetic assignment. + /// \param rhs single-precision value to multiply with + /// \return reference to this half + half& operator*=(float rhs) { data_ = detail::float2half(detail::half2float(data_)*rhs); return *this; } + + /// Arithmetic assignment. + /// \param rhs single-precision value to divide by + /// \return reference to this half + half& operator/=(float rhs) { data_ = detail::float2half(detail::half2float(data_)/rhs); return *this; } + + /// Prefix increment. + /// \return incremented half value + half& operator++() { return *this += 1.0f; } + + /// Prefix decrement. + /// \return decremented half value + half& operator--() { return *this -= 1.0f; } + + /// Postfix increment. + /// \return non-incremented half value + half operator++(int) { half out(*this); ++*this; return out; } + + /// Postfix decrement. + /// \return non-decremented half value + half operator--(int) { half out(*this); --*this; return out; } + + private: + /// Rounding mode to use (always `std::round_indeterminate`) + static const std::float_round_style round_style = (std::float_round_style)(HALF_ROUND_STYLE); + + /// Constructor. + /// \param bits binary representation to set half to + HALF_CONSTEXPR half(detail::binary_t, detail::uint16 bits) : data_(bits) {} + + /// Internal binary representation + detail::uint16 data_; + }; + +#if HALF_ENABLE_CPP11_USER_LITERALS + /// Library-defined half-precision literals. + /// Import this namespace to enable half-precision floating point literals: + /// ~~~~{.cpp} + /// using namespace half_float::literal; + /// half_float::half = 4.2_h; + /// ~~~~ + namespace literal + { + /// Half literal. + /// While this returns an actual half-precision value, half literals can unfortunately not be constant expressions due + /// to rather involved single-to-half conversion. + /// \param value literal value + /// \return half with given value (if representable) + inline half operator "" _h(long double value) { return half(static_cast(value)); } + } +#endif + + namespace detail + { + /// Wrapper implementing unspecialized half-precision functions. + struct functions + { + /// Addition implementation. + /// \param x first operand + /// \param y second operand + /// \return Half-precision sum stored in single-precision + static expr plus(float x, float y) { return expr(x+y); } + + /// Subtraction implementation. + /// \param x first operand + /// \param y second operand + /// \return Half-precision difference stored in single-precision + static expr minus(float x, float y) { return expr(x-y); } + + /// Multiplication implementation. + /// \param x first operand + /// \param y second operand + /// \return Half-precision product stored in single-precision + static expr multiplies(float x, float y) { return expr(x*y); } + + /// Division implementation. + /// \param x first operand + /// \param y second operand + /// \return Half-precision quotient stored in single-precision + static expr divides(float x, float y) { return expr(x/y); } + + /// Output implementation. + /// \param out stream to write to + /// \param arg value to write + /// \return reference to stream + template static std::basic_ostream& write(std::basic_ostream &out, float arg) { return out << arg; } + + /// Input implementation. + /// \param in stream to read from + /// \param arg half to read into + /// \return reference to stream + template static std::basic_istream& read(std::basic_istream &in, half &arg) + { + float f; + if(in >> f) + arg = f; + return in; + } + + /// Modulo implementation. + /// \param x first operand + /// \param y second operand + /// \return Half-precision division remainder stored in single-precision + static expr fmod(float x, float y) { return expr(std::fmod(x, y)); } + + /// Remainder implementation. + /// \param x first operand + /// \param y second operand + /// \return Half-precision division remainder stored in single-precision + static expr remainder(float x, float y) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::remainder(x, y)); + #else + if(builtin_isnan(x) || builtin_isnan(y)) + return expr(std::numeric_limits::quiet_NaN()); + float ax = std::fabs(x), ay = std::fabs(y); + if(ax >= 65536.0f || ay < std::ldexp(1.0f, -24)) + return expr(std::numeric_limits::quiet_NaN()); + if(ay >= 65536.0f) + return expr(x); + if(ax == ay) + return expr(builtin_signbit(x) ? -0.0f : 0.0f); + ax = std::fmod(ax, ay+ay); + float y2 = 0.5f * ay; + if(ax > y2) + { + ax -= ay; + if(ax >= y2) + ax -= ay; + } + return expr(builtin_signbit(x) ? -ax : ax); + #endif + } + + /// Remainder implementation. + /// \param x first operand + /// \param y second operand + /// \param quo address to store quotient bits at + /// \return Half-precision division remainder stored in single-precision + static expr remquo(float x, float y, int *quo) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::remquo(x, y, quo)); + #else + if(builtin_isnan(x) || builtin_isnan(y)) + return expr(std::numeric_limits::quiet_NaN()); + bool sign = builtin_signbit(x), qsign = static_cast(sign^builtin_signbit(y)); + float ax = std::fabs(x), ay = std::fabs(y); + if(ax >= 65536.0f || ay < std::ldexp(1.0f, -24)) + return expr(std::numeric_limits::quiet_NaN()); + if(ay >= 65536.0f) + return expr(x); + if(ax == ay) + return *quo = qsign ? -1 : 1, expr(sign ? -0.0f : 0.0f); + ax = std::fmod(ax, 8.0f*ay); + int cquo = 0; + if(ax >= 4.0f * ay) + { + ax -= 4.0f * ay; + cquo += 4; + } + if(ax >= 2.0f * ay) + { + ax -= 2.0f * ay; + cquo += 2; + } + float y2 = 0.5f * ay; + if(ax > y2) + { + ax -= ay; + ++cquo; + if(ax >= y2) + { + ax -= ay; + ++cquo; + } + } + return *quo = qsign ? -cquo : cquo, expr(sign ? -ax : ax); + #endif + } + + /// Positive difference implementation. + /// \param x first operand + /// \param y second operand + /// \return Positive difference stored in single-precision + static expr fdim(float x, float y) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::fdim(x, y)); + #else + return expr((x<=y) ? 0.0f : (x-y)); + #endif + } + + /// Fused multiply-add implementation. + /// \param x first operand + /// \param y second operand + /// \param z third operand + /// \return \a x * \a y + \a z stored in single-precision + static expr fma(float x, float y, float z) + { + #if HALF_ENABLE_CPP11_CMATH && defined(FP_FAST_FMAF) + return expr(std::fma(x, y, z)); + #else + return expr(x*y+z); + #endif + } + + /// Get NaN. + /// \return Half-precision quiet NaN + static half nanh(const char*) { return half(binary, 0x7FFF); } + + /// Exponential implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr exp(float arg) { return expr(std::exp(arg)); } + + /// Exponential implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr expm1(float arg) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::expm1(arg)); + #else + return expr(static_cast(std::exp(static_cast(arg))-1.0)); + #endif + } + + /// Binary exponential implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr exp2(float arg) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::exp2(arg)); + #else + return expr(static_cast(std::exp(arg*0.69314718055994530941723212145818))); + #endif + } + + /// Logarithm implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr log(float arg) { return expr(std::log(arg)); } + + /// Common logarithm implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr log10(float arg) { return expr(std::log10(arg)); } + + /// Logarithm implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr log1p(float arg) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::log1p(arg)); + #else + return expr(static_cast(std::log(1.0+arg))); + #endif + } + + /// Binary logarithm implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr log2(float arg) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::log2(arg)); + #else + return expr(static_cast(std::log(static_cast(arg))*1.4426950408889634073599246810019)); + #endif + } + + /// Square root implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr sqrt(float arg) { return expr(std::sqrt(arg)); } + + /// Cubic root implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr cbrt(float arg) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::cbrt(arg)); + #else + if(builtin_isnan(arg) || builtin_isinf(arg)) + return expr(arg); + return expr(builtin_signbit(arg) ? -static_cast(std::pow(std::fabs(static_cast(arg)), 1.0/3.0)) : + static_cast(std::pow(static_cast(arg), 1.0/3.0))); + #endif + } + + /// Hypotenuse implementation. + /// \param x first argument + /// \param y second argument + /// \return function value stored in single-preicision + static expr hypot(float x, float y) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::hypot(x, y)); + #else + return expr((builtin_isinf(x) || builtin_isinf(y)) ? std::numeric_limits::infinity() : + static_cast(std::sqrt(static_cast(x)*x+static_cast(y)*y))); + #endif + } + + /// Power implementation. + /// \param base value to exponentiate + /// \param exp power to expontiate to + /// \return function value stored in single-preicision + static expr pow(float base, float exp) { return expr(std::pow(base, exp)); } + + /// Sine implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr sin(float arg) { return expr(std::sin(arg)); } + + /// Cosine implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr cos(float arg) { return expr(std::cos(arg)); } + + /// Tan implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr tan(float arg) { return expr(std::tan(arg)); } + + /// Arc sine implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr asin(float arg) { return expr(std::asin(arg)); } + + /// Arc cosine implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr acos(float arg) { return expr(std::acos(arg)); } + + /// Arc tangent implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr atan(float arg) { return expr(std::atan(arg)); } + + /// Arc tangent implementation. + /// \param x first argument + /// \param y second argument + /// \return function value stored in single-preicision + static expr atan2(float x, float y) { return expr(std::atan2(x, y)); } + + /// Hyperbolic sine implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr sinh(float arg) { return expr(std::sinh(arg)); } + + /// Hyperbolic cosine implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr cosh(float arg) { return expr(std::cosh(arg)); } + + /// Hyperbolic tangent implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr tanh(float arg) { return expr(std::tanh(arg)); } + + /// Hyperbolic area sine implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr asinh(float arg) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::asinh(arg)); + #else + return expr((arg==-std::numeric_limits::infinity()) ? arg : static_cast(std::log(arg+std::sqrt(arg*arg+1.0)))); + #endif + } + + /// Hyperbolic area cosine implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr acosh(float arg) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::acosh(arg)); + #else + return expr((arg<-1.0f) ? std::numeric_limits::quiet_NaN() : static_cast(std::log(arg+std::sqrt(arg*arg-1.0)))); + #endif + } + + /// Hyperbolic area tangent implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr atanh(float arg) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::atanh(arg)); + #else + return expr(static_cast(0.5*std::log((1.0+arg)/(1.0-arg)))); + #endif + } + + /// Error function implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr erf(float arg) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::erf(arg)); + #else + return expr(static_cast(erf(static_cast(arg)))); + #endif + } + + /// Complementary implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr erfc(float arg) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::erfc(arg)); + #else + return expr(static_cast(1.0-erf(static_cast(arg)))); + #endif + } + + /// Gamma logarithm implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr lgamma(float arg) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::lgamma(arg)); + #else + if(builtin_isinf(arg)) + return expr(std::numeric_limits::infinity()); + double z = static_cast(arg); + if(z < 0) + { + double i, f = std::modf(-z, &i); + if(f == 0.0) + return expr(std::numeric_limits::infinity()); + return expr(static_cast(1.1447298858494001741434273513531-std::log(std::abs(std::sin(3.1415926535897932384626433832795*f)))-lgamma(1.0-z))); + } +// if(z < 8.0) + return expr(static_cast(lgamma(static_cast(arg)))); + return expr(static_cast(0.5*(1.8378770664093454835606594728112-std::log(z))+z*(std::log(z+1.0/(12.0*z-1.0/(10.0*z)-1.0))-1.0))); + #endif + } + + /// Gamma implementation. + /// \param arg function argument + /// \return function value stored in single-preicision + static expr tgamma(float arg) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::tgamma(arg)); + #else + double z = static_cast(arg); + if(z == 0.0) + return builtin_signbit(z) ? expr(-std::numeric_limits::infinity()) : expr(std::numeric_limits::infinity()); + if(z < 0.0) + { + double i, f = std::modf(-z, &i); + if(f == 0.0) + return expr(std::numeric_limits::quiet_NaN()); + double sign = (std::fmod(i, 2.0)==0.0) ? -1.0 : 1.0; + return expr(static_cast(sign*3.1415926535897932384626433832795/(std::sin(3.1415926535897932384626433832795*f)*std::exp(lgamma(1.0-z))))); + } + if(builtin_isinf(arg)) + return expr(arg); +// if(arg < 8.0f) + return expr(static_cast(std::exp(lgamma(z)))); + return expr(static_cast(std::sqrt(6.283185307179586476925286766559/z)*std::pow(0.36787944117144232159552377016146*(z+1.0/(12.0*z-1.0/(10.0*z))), z))); + #endif + } + + /// Floor implementation. + /// \param arg value to round + /// \return rounded value + static half floor(half arg) { return half(binary, round_half(arg.data_)); } + + /// Ceiling implementation. + /// \param arg value to round + /// \return rounded value + static half ceil(half arg) { return half(binary, round_half(arg.data_)); } + + /// Truncation implementation. + /// \param arg value to round + /// \return rounded value + static half trunc(half arg) { return half(binary, round_half(arg.data_)); } + + /// Nearest integer implementation. + /// \param arg value to round + /// \return rounded value + static half round(half arg) { return half(binary, round_half_up(arg.data_)); } + + /// Nearest integer implementation. + /// \param arg value to round + /// \return rounded value + static long lround(half arg) { return detail::half2int_up(arg.data_); } + + /// Nearest integer implementation. + /// \param arg value to round + /// \return rounded value + static half rint(half arg) { return half(binary, round_half(arg.data_)); } + + /// Nearest integer implementation. + /// \param arg value to round + /// \return rounded value + static long lrint(half arg) { return detail::half2int(arg.data_); } + + #if HALF_ENABLE_CPP11_LONG_LONG + /// Nearest integer implementation. + /// \param arg value to round + /// \return rounded value + static long long llround(half arg) { return detail::half2int_up(arg.data_); } + + /// Nearest integer implementation. + /// \param arg value to round + /// \return rounded value + static long long llrint(half arg) { return detail::half2int(arg.data_); } + #endif + + /// Decompression implementation. + /// \param arg number to decompress + /// \param exp address to store exponent at + /// \return normalized significant + static half frexp(half arg, int *exp) + { + unsigned int m = arg.data_ & 0x7FFF; + if(m >= 0x7C00 || !m) + return *exp = 0, arg; + int e = m >> 10; + if(!e) + for(m<<=1; m<0x400; m<<=1,--e) ; + return *exp = e-14, half(binary, static_cast((arg.data_&0x8000)|0x3800|(m&0x3FF))); + } + + /// Decompression implementation. + /// \param arg number to decompress + /// \param iptr address to store integer part at + /// \return fractional part + static half modf(half arg, half *iptr) + { + unsigned int e = arg.data_ & 0x7C00; + if(e > 0x6000) + return *iptr = arg, (e==0x7C00&&(arg.data_&0x3FF)) ? arg : half(binary, arg.data_&0x8000); + if(e < 0x3C00) + return iptr->data_ = arg.data_ & 0x8000, arg; + e >>= 10; + unsigned int mask = (1<<(25-e)) - 1, m = arg.data_ & mask; + iptr->data_ = arg.data_ & ~mask; + if(!m) + return half(binary, arg.data_&0x8000); + for(; m<0x400; m<<=1,--e) ; + return half(binary, static_cast((arg.data_&0x8000)|(e<<10)|(m&0x3FF))); + } + + /// Scaling implementation. + /// \param arg number to scale + /// \param exp power of two to scale by + /// \return scaled number + static half scalbln(half arg, long exp) + { + long e = arg.data_ & 0x7C00; + if(e == 0x7C00) + return arg; + unsigned int m = arg.data_ & 0x3FF; + if(e >>= 10) + m |= 0x400; + else + { + if(!m) + return arg; + for(m<<=1; m<0x400; m<<=1,--e) ; + } + e += exp; + uint16 value = arg.data_ & 0x8000; + if(e > 30) + { + if(half::round_style == std::round_toward_zero) + value |= 0x7BFF; + else if(half::round_style == std::round_toward_infinity) + value |= 0x7C00 - (value>>15); + else if(half::round_style == std::round_toward_neg_infinity) + value |= 0x7BFF + (value>>15); + else + value |= 0x7C00; + } + else if(e > 0) + value |= (e<<10) | (m&0x3FF); + else if(e > -11) + { + if(half::round_style == std::round_to_nearest) + { + m += 1 << -e; + #if HALF_ROUND_TIES_TO_EVEN + m -= (m>>(1-e)) & 1; + #endif + } + else if(half::round_style == std::round_toward_infinity) + m += ((value>>15)-1) & ((1<<(1-e))-1U); + else if(half::round_style == std::round_toward_neg_infinity) + m += -(value>>15) & ((1<<(1-e))-1U); + value |= m >> (1-e); + } + else if(half::round_style == std::round_toward_infinity) + value |= ((value>>15)-1) & 1; + else if(half::round_style == std::round_toward_neg_infinity) + value |= value >> 15; + return half(binary, value); + } + + /// Exponent implementation. + /// \param arg number to query + /// \return floating point exponent + static int ilogb(half arg) + { + int exp = arg.data_ & 0x7FFF; + if(!exp) + return FP_ILOGB0; + if(exp < 0x7C00) + { + if(!(exp>>=10)) + for(unsigned int m=(arg.data_&0x3FF); m<0x200; m<<=1,--exp) ; + return exp - 15; + } + if(exp > 0x7C00) + return FP_ILOGBNAN; + return INT_MAX; + } + + /// Exponent implementation. + /// \param arg number to query + /// \return floating point exponent + static half logb(half arg) + { + int exp = arg.data_ & 0x7FFF; + if(!exp) + return half(binary, 0xFC00); + if(exp < 0x7C00) + { + if(!(exp>>=10)) + for(unsigned int m=(arg.data_&0x3FF); m<0x200; m<<=1,--exp) ; + return half(static_cast(exp-15)); + } + if(exp > 0x7C00) + return arg; + return half(binary, 0x7C00); + } + + /// Enumeration implementation. + /// \param from number to increase/decrease + /// \param to direction to enumerate into + /// \return next representable number + static half nextafter(half from, half to) + { + uint16 fabs = from.data_ & 0x7FFF, tabs = to.data_ & 0x7FFF; + if(fabs > 0x7C00) + return from; + if(tabs > 0x7C00 || from.data_ == to.data_ || !(fabs|tabs)) + return to; + if(!fabs) + return half(binary, (to.data_&0x8000)+1); + bool lt = (signbit(from) ? (static_cast(0x8000)-from.data_) : static_cast(from.data_)) < + (signbit(to) ? (static_cast(0x8000)-to.data_) : static_cast(to.data_)); + return half(binary, from.data_+(((from.data_>>15)^static_cast(lt))<<1)-1); + } + + /// Enumeration implementation. + /// \param from number to increase/decrease + /// \param to direction to enumerate into + /// \return next representable number + static half nexttoward(half from, long double to) + { + if(isnan(from)) + return from; + long double lfrom = static_cast(from); + if(builtin_isnan(to) || lfrom == to) + return half(static_cast(to)); + if(!(from.data_&0x7FFF)) + return half(binary, (static_cast(builtin_signbit(to))<<15)+1); + return half(binary, from.data_+(((from.data_>>15)^static_cast(lfrom 0x7C00) + return FP_NAN; + if(abs == 0x7C00) + return FP_INFINITE; + if(abs > 0x3FF) + return FP_NORMAL; + return abs ? FP_SUBNORMAL : FP_ZERO; + } + + /// Classification implementation. + /// \param arg value to classify + /// \retval true if finite number + /// \retval false else + static bool isfinite(half arg) { return (arg.data_&0x7C00) != 0x7C00; } + + /// Classification implementation. + /// \param arg value to classify + /// \retval true if infinite number + /// \retval false else + static bool isinf(half arg) { return (arg.data_&0x7FFF) == 0x7C00; } + + /// Classification implementation. + /// \param arg value to classify + /// \retval true if not a number + /// \retval false else + static bool isnan(half arg) { return (arg.data_&0x7FFF) > 0x7C00; } + + /// Classification implementation. + /// \param arg value to classify + /// \retval true if normal number + /// \retval false else + static bool isnormal(half arg) { return ((arg.data_&0x7C00)!=0) & ((arg.data_&0x7C00)!=0x7C00); } + + /// Sign bit implementation. + /// \param arg value to check + /// \retval true if signed + /// \retval false if unsigned + static bool signbit(half arg) { return (arg.data_&0x8000) != 0; } + + /// Comparison implementation. + /// \param x first operand + /// \param y second operand + /// \retval true if operands equal + /// \retval false else + static bool isequal(half x, half y) { return (x.data_==y.data_ || !((x.data_|y.data_)&0x7FFF)) && !isnan(x); } + + /// Comparison implementation. + /// \param x first operand + /// \param y second operand + /// \retval true if operands not equal + /// \retval false else + static bool isnotequal(half x, half y) { return (x.data_!=y.data_ && ((x.data_|y.data_)&0x7FFF)) || isnan(x); } + + /// Comparison implementation. + /// \param x first operand + /// \param y second operand + /// \retval true if \a x > \a y + /// \retval false else + static bool isgreater(half x, half y) { return !isnan(x) && !isnan(y) && ((signbit(x) ? (static_cast(0x8000)-x.data_) : + static_cast(x.data_)) > (signbit(y) ? (static_cast(0x8000)-y.data_) : static_cast(y.data_))); } + + /// Comparison implementation. + /// \param x first operand + /// \param y second operand + /// \retval true if \a x >= \a y + /// \retval false else + static bool isgreaterequal(half x, half y) { return !isnan(x) && !isnan(y) && ((signbit(x) ? (static_cast(0x8000)-x.data_) : + static_cast(x.data_)) >= (signbit(y) ? (static_cast(0x8000)-y.data_) : static_cast(y.data_))); } + + /// Comparison implementation. + /// \param x first operand + /// \param y second operand + /// \retval true if \a x < \a y + /// \retval false else + static bool isless(half x, half y) { return !isnan(x) && !isnan(y) && ((signbit(x) ? (static_cast(0x8000)-x.data_) : + static_cast(x.data_)) < (signbit(y) ? (static_cast(0x8000)-y.data_) : static_cast(y.data_))); } + + /// Comparison implementation. + /// \param x first operand + /// \param y second operand + /// \retval true if \a x <= \a y + /// \retval false else + static bool islessequal(half x, half y) { return !isnan(x) && !isnan(y) && ((signbit(x) ? (static_cast(0x8000)-x.data_) : + static_cast(x.data_)) <= (signbit(y) ? (static_cast(0x8000)-y.data_) : static_cast(y.data_))); } + + /// Comparison implementation. + /// \param x first operand + /// \param y second operand + /// \retval true neither \a x > \a y nor \a x < \a y + /// \retval false else + static bool islessgreater(half x, half y) + { + if(isnan(x) || isnan(y)) + return false; + int17 a = signbit(x) ? (static_cast(0x8000)-x.data_) : static_cast(x.data_); + int17 b = signbit(y) ? (static_cast(0x8000)-y.data_) : static_cast(y.data_); + return a < b || a > b; + } + + /// Comparison implementation. + /// \param x first operand + /// \param y second operand + /// \retval true if operand unordered + /// \retval false else + static bool isunordered(half x, half y) { return isnan(x) || isnan(y); } + + private: + static double erf(double arg) + { + if(builtin_isinf(arg)) + return (arg<0.0) ? -1.0 : 1.0; + double x2 = static_cast(arg) * static_cast(arg), ax2 = 0.147 * x2; + double value = std::sqrt(1.0-std::exp(-x2*(1.2732395447351626861510701069801+ax2)/(1.0+ax2))); + return builtin_signbit(arg) ? -value : value; + } + + static double lgamma(double arg) + { + double v = 1.0; + for(; arg<8.0; ++arg) v *= arg; + double w = 1.0 / (arg * arg); + return (((((((-0.02955065359477124183006535947712*w+0.00641025641025641025641025641026)*w+ + -0.00191752691752691752691752691753)*w+8.4175084175084175084175084175084e-4)*w+ + -5.952380952380952380952380952381e-4)*w+7.9365079365079365079365079365079e-4)*w+ + -0.00277777777777777777777777777778)*w+0.08333333333333333333333333333333)/arg + + 0.91893853320467274178032973640562 - std::log(v) - arg + (arg-0.5) * std::log(arg); + } + }; + + /// Wrapper for unary half-precision functions needing specialization for individual argument types. + /// \tparam T argument type + template struct unary_specialized + { + /// Negation implementation. + /// \param arg value to negate + /// \return negated value + static HALF_CONSTEXPR half negate(half arg) { return half(binary, arg.data_^0x8000); } + + /// Absolute value implementation. + /// \param arg function argument + /// \return absolute value + static half fabs(half arg) { return half(binary, arg.data_&0x7FFF); } + }; + template<> struct unary_specialized + { + static HALF_CONSTEXPR expr negate(float arg) { return expr(-arg); } + static expr fabs(float arg) { return expr(std::fabs(arg)); } + }; + + /// Wrapper for binary half-precision functions needing specialization for individual argument types. + /// \tparam T first argument type + /// \tparam U first argument type + template struct binary_specialized + { + /// Minimum implementation. + /// \param x first operand + /// \param y second operand + /// \return minimum value + static expr fmin(float x, float y) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::fmin(x, y)); + #else + if(builtin_isnan(x)) + return expr(y); + if(builtin_isnan(y)) + return expr(x); + return expr(std::min(x, y)); + #endif + } + + /// Maximum implementation. + /// \param x first operand + /// \param y second operand + /// \return maximum value + static expr fmax(float x, float y) + { + #if HALF_ENABLE_CPP11_CMATH + return expr(std::fmax(x, y)); + #else + if(builtin_isnan(x)) + return expr(y); + if(builtin_isnan(y)) + return expr(x); + return expr(std::max(x, y)); + #endif + } + }; + template<> struct binary_specialized + { + static half fmin(half x, half y) + { + if(functions::isnan(x)) + return y; + if(functions::isnan(y)) + return x; + return ((functions::signbit(x) ? (static_cast(0x8000)-x.data_) : static_cast(x.data_)) > + (functions::signbit(y) ? (static_cast(0x8000)-y.data_) : static_cast(y.data_))) ? y : x; + } + static half fmax(half x, half y) + { + if(functions::isnan(x)) + return y; + if(functions::isnan(y)) + return x; + return ((functions::signbit(x) ? (static_cast(0x8000)-x.data_) : static_cast(x.data_)) < + (functions::signbit(y) ? (static_cast(0x8000)-y.data_) : static_cast(y.data_))) ? y : x; + } + }; + + /// Helper class for half casts. + /// This class template has to be specialized for all valid cast argument to define an appropriate static `cast` member + /// function and a corresponding `type` member denoting its return type. + /// \tparam T destination type + /// \tparam U source type + /// \tparam R rounding mode to use + template struct half_caster {}; + template struct half_caster + { + #if HALF_ENABLE_CPP11_STATIC_ASSERT && HALF_ENABLE_CPP11_TYPE_TRAITS + static_assert(std::is_arithmetic::value, "half_cast from non-arithmetic type unsupported"); + #endif + + typedef half type; + static half cast(U arg) { return cast_impl(arg, is_float()); }; + + private: + static half cast_impl(U arg, true_type) { return half(binary, float2half(static_cast(arg))); } + static half cast_impl(U arg, false_type) { return half(binary, int2half(arg)); } + }; + template struct half_caster + { + #if HALF_ENABLE_CPP11_STATIC_ASSERT && HALF_ENABLE_CPP11_TYPE_TRAITS + static_assert(std::is_arithmetic::value, "half_cast to non-arithmetic type unsupported"); + #endif + + typedef T type; + template static T cast(U arg) { return cast_impl(arg, is_float()); } + + private: + static T cast_impl(float arg, true_type) { return static_cast(arg); } + static T cast_impl(half arg, false_type) { return half2int(arg.data_); } + }; + template struct half_caster : public half_caster {}; + template struct half_caster + { + typedef half type; + static half cast(half arg) { return arg; } + }; + template struct half_caster : public half_caster {}; + + /// \name Comparison operators + /// \{ + + /// Comparison for equality. + /// \param x first operand + /// \param y second operand + /// \retval true if operands equal + /// \retval false else + template typename enable::type operator==(T x, U y) { return functions::isequal(x, y); } + + /// Comparison for inequality. + /// \param x first operand + /// \param y second operand + /// \retval true if operands not equal + /// \retval false else + template typename enable::type operator!=(T x, U y) { return functions::isnotequal(x, y); } + + /// Comparison for less than. + /// \param x first operand + /// \param y second operand + /// \retval true if \a x less than \a y + /// \retval false else + template typename enable::type operator<(T x, U y) { return functions::isless(x, y); } + + /// Comparison for greater than. + /// \param x first operand + /// \param y second operand + /// \retval true if \a x greater than \a y + /// \retval false else + template typename enable::type operator>(T x, U y) { return functions::isgreater(x, y); } + + /// Comparison for less equal. + /// \param x first operand + /// \param y second operand + /// \retval true if \a x less equal \a y + /// \retval false else + template typename enable::type operator<=(T x, U y) { return functions::islessequal(x, y); } + + /// Comparison for greater equal. + /// \param x first operand + /// \param y second operand + /// \retval true if \a x greater equal \a y + /// \retval false else + template typename enable::type operator>=(T x, U y) { return functions::isgreaterequal(x, y); } + + /// \} + /// \name Arithmetic operators + /// \{ + + /// Add halfs. + /// \param x left operand + /// \param y right operand + /// \return sum of half expressions + template typename enable::type operator+(T x, U y) { return functions::plus(x, y); } + + /// Subtract halfs. + /// \param x left operand + /// \param y right operand + /// \return difference of half expressions + template typename enable::type operator-(T x, U y) { return functions::minus(x, y); } + + /// Multiply halfs. + /// \param x left operand + /// \param y right operand + /// \return product of half expressions + template typename enable::type operator*(T x, U y) { return functions::multiplies(x, y); } + + /// Divide halfs. + /// \param x left operand + /// \param y right operand + /// \return quotient of half expressions + template typename enable::type operator/(T x, U y) { return functions::divides(x, y); } + + /// Identity. + /// \param arg operand + /// \return uncahnged operand + template HALF_CONSTEXPR typename enable::type operator+(T arg) { return arg; } + + /// Negation. + /// \param arg operand + /// \return negated operand + template HALF_CONSTEXPR typename enable::type operator-(T arg) { return unary_specialized::negate(arg); } + + /// \} + /// \name Input and output + /// \{ + + /// Output operator. + /// \param out output stream to write into + /// \param arg half expression to write + /// \return reference to output stream + template typename enable&,T>::type + operator<<(std::basic_ostream &out, T arg) { return functions::write(out, arg); } + + /// Input operator. + /// \param in input stream to read from + /// \param arg half to read into + /// \return reference to input stream + template std::basic_istream& + operator>>(std::basic_istream &in, half &arg) { return functions::read(in, arg); } + + /// \} + /// \name Basic mathematical operations + /// \{ + + /// Absolute value. + /// \param arg operand + /// \return absolute value of \a arg +// template typename enable::type abs(T arg) { return unary_specialized::fabs(arg); } + inline half abs(half arg) { return unary_specialized::fabs(arg); } + inline expr abs(expr arg) { return unary_specialized::fabs(arg); } + + /// Absolute value. + /// \param arg operand + /// \return absolute value of \a arg +// template typename enable::type fabs(T arg) { return unary_specialized::fabs(arg); } + inline half fabs(half arg) { return unary_specialized::fabs(arg); } + inline expr fabs(expr arg) { return unary_specialized::fabs(arg); } + + /// Remainder of division. + /// \param x first operand + /// \param y second operand + /// \return remainder of floating point division. +// template typename enable::type fmod(T x, U y) { return functions::fmod(x, y); } + inline expr fmod(half x, half y) { return functions::fmod(x, y); } + inline expr fmod(half x, expr y) { return functions::fmod(x, y); } + inline expr fmod(expr x, half y) { return functions::fmod(x, y); } + inline expr fmod(expr x, expr y) { return functions::fmod(x, y); } + + /// Remainder of division. + /// \param x first operand + /// \param y second operand + /// \return remainder of floating point division. +// template typename enable::type remainder(T x, U y) { return functions::remainder(x, y); } + inline expr remainder(half x, half y) { return functions::remainder(x, y); } + inline expr remainder(half x, expr y) { return functions::remainder(x, y); } + inline expr remainder(expr x, half y) { return functions::remainder(x, y); } + inline expr remainder(expr x, expr y) { return functions::remainder(x, y); } + + /// Remainder of division. + /// \param x first operand + /// \param y second operand + /// \param quo address to store some bits of quotient at + /// \return remainder of floating point division. +// template typename enable::type remquo(T x, U y, int *quo) { return functions::remquo(x, y, quo); } + inline expr remquo(half x, half y, int *quo) { return functions::remquo(x, y, quo); } + inline expr remquo(half x, expr y, int *quo) { return functions::remquo(x, y, quo); } + inline expr remquo(expr x, half y, int *quo) { return functions::remquo(x, y, quo); } + inline expr remquo(expr x, expr y, int *quo) { return functions::remquo(x, y, quo); } + + /// Fused multiply add. + /// \param x first operand + /// \param y second operand + /// \param z third operand + /// \return ( \a x * \a y ) + \a z rounded as one operation. +// template typename enable::type fma(T x, U y, V z) { return functions::fma(x, y, z); } + inline expr fma(half x, half y, half z) { return functions::fma(x, y, z); } + inline expr fma(half x, half y, expr z) { return functions::fma(x, y, z); } + inline expr fma(half x, expr y, half z) { return functions::fma(x, y, z); } + inline expr fma(half x, expr y, expr z) { return functions::fma(x, y, z); } + inline expr fma(expr x, half y, half z) { return functions::fma(x, y, z); } + inline expr fma(expr x, half y, expr z) { return functions::fma(x, y, z); } + inline expr fma(expr x, expr y, half z) { return functions::fma(x, y, z); } + inline expr fma(expr x, expr y, expr z) { return functions::fma(x, y, z); } + + /// Maximum of half expressions. + /// \param x first operand + /// \param y second operand + /// \return maximum of operands +// template typename result::type fmax(T x, U y) { return binary_specialized::fmax(x, y); } + inline half fmax(half x, half y) { return binary_specialized::fmax(x, y); } + inline expr fmax(half x, expr y) { return binary_specialized::fmax(x, y); } + inline expr fmax(expr x, half y) { return binary_specialized::fmax(x, y); } + inline expr fmax(expr x, expr y) { return binary_specialized::fmax(x, y); } + + /// Minimum of half expressions. + /// \param x first operand + /// \param y second operand + /// \return minimum of operands +// template typename result::type fmin(T x, U y) { return binary_specialized::fmin(x, y); } + inline half fmin(half x, half y) { return binary_specialized::fmin(x, y); } + inline expr fmin(half x, expr y) { return binary_specialized::fmin(x, y); } + inline expr fmin(expr x, half y) { return binary_specialized::fmin(x, y); } + inline expr fmin(expr x, expr y) { return binary_specialized::fmin(x, y); } + + /// Positive difference. + /// \param x first operand + /// \param y second operand + /// \return \a x - \a y or 0 if difference negative +// template typename enable::type fdim(T x, U y) { return functions::fdim(x, y); } + inline expr fdim(half x, half y) { return functions::fdim(x, y); } + inline expr fdim(half x, expr y) { return functions::fdim(x, y); } + inline expr fdim(expr x, half y) { return functions::fdim(x, y); } + inline expr fdim(expr x, expr y) { return functions::fdim(x, y); } + + /// Get NaN value. + /// \param arg descriptive string (ignored) + /// \return quiet NaN + inline half nanh(const char *arg) { return functions::nanh(arg); } + + /// \} + /// \name Exponential functions + /// \{ + + /// Exponential function. + /// \param arg function argument + /// \return e raised to \a arg +// template typename enable::type exp(T arg) { return functions::exp(arg); } + inline expr exp(half arg) { return functions::exp(arg); } + inline expr exp(expr arg) { return functions::exp(arg); } + + /// Exponential minus one. + /// \param arg function argument + /// \return e raised to \a arg subtracted by 1 +// template typename enable::type expm1(T arg) { return functions::expm1(arg); } + inline expr expm1(half arg) { return functions::expm1(arg); } + inline expr expm1(expr arg) { return functions::expm1(arg); } + + /// Binary exponential. + /// \param arg function argument + /// \return 2 raised to \a arg +// template typename enable::type exp2(T arg) { return functions::exp2(arg); } + inline expr exp2(half arg) { return functions::exp2(arg); } + inline expr exp2(expr arg) { return functions::exp2(arg); } + + /// Natural logorithm. + /// \param arg function argument + /// \return logarithm of \a arg to base e +// template typename enable::type log(T arg) { return functions::log(arg); } + inline expr log(half arg) { return functions::log(arg); } + inline expr log(expr arg) { return functions::log(arg); } + + /// Common logorithm. + /// \param arg function argument + /// \return logarithm of \a arg to base 10 +// template typename enable::type log10(T arg) { return functions::log10(arg); } + inline expr log10(half arg) { return functions::log10(arg); } + inline expr log10(expr arg) { return functions::log10(arg); } + + /// Natural logorithm. + /// \param arg function argument + /// \return logarithm of \a arg plus 1 to base e +// template typename enable::type log1p(T arg) { return functions::log1p(arg); } + inline expr log1p(half arg) { return functions::log1p(arg); } + inline expr log1p(expr arg) { return functions::log1p(arg); } + + /// Binary logorithm. + /// \param arg function argument + /// \return logarithm of \a arg to base 2 +// template typename enable::type log2(T arg) { return functions::log2(arg); } + inline expr log2(half arg) { return functions::log2(arg); } + inline expr log2(expr arg) { return functions::log2(arg); } + + /// \} + /// \name Power functions + /// \{ + + /// Square root. + /// \param arg function argument + /// \return square root of \a arg +// template typename enable::type sqrt(T arg) { return functions::sqrt(arg); } + inline expr sqrt(half arg) { return functions::sqrt(arg); } + inline expr sqrt(expr arg) { return functions::sqrt(arg); } + + /// Cubic root. + /// \param arg function argument + /// \return cubic root of \a arg +// template typename enable::type cbrt(T arg) { return functions::cbrt(arg); } + inline expr cbrt(half arg) { return functions::cbrt(arg); } + inline expr cbrt(expr arg) { return functions::cbrt(arg); } + + /// Hypotenuse function. + /// \param x first argument + /// \param y second argument + /// \return square root of sum of squares without internal over- or underflows +// template typename enable::type hypot(T x, U y) { return functions::hypot(x, y); } + inline expr hypot(half x, half y) { return functions::hypot(x, y); } + inline expr hypot(half x, expr y) { return functions::hypot(x, y); } + inline expr hypot(expr x, half y) { return functions::hypot(x, y); } + inline expr hypot(expr x, expr y) { return functions::hypot(x, y); } + + /// Power function. + /// \param base first argument + /// \param exp second argument + /// \return \a base raised to \a exp +// template typename enable::type pow(T base, U exp) { return functions::pow(base, exp); } + inline expr pow(half base, half exp) { return functions::pow(base, exp); } + inline expr pow(half base, expr exp) { return functions::pow(base, exp); } + inline expr pow(expr base, half exp) { return functions::pow(base, exp); } + inline expr pow(expr base, expr exp) { return functions::pow(base, exp); } + + /// \} + /// \name Trigonometric functions + /// \{ + + /// Sine function. + /// \param arg function argument + /// \return sine value of \a arg +// template typename enable::type sin(T arg) { return functions::sin(arg); } + inline expr sin(half arg) { return functions::sin(arg); } + inline expr sin(expr arg) { return functions::sin(arg); } + + /// Cosine function. + /// \param arg function argument + /// \return cosine value of \a arg +// template typename enable::type cos(T arg) { return functions::cos(arg); } + inline expr cos(half arg) { return functions::cos(arg); } + inline expr cos(expr arg) { return functions::cos(arg); } + + /// Tangent function. + /// \param arg function argument + /// \return tangent value of \a arg +// template typename enable::type tan(T arg) { return functions::tan(arg); } + inline expr tan(half arg) { return functions::tan(arg); } + inline expr tan(expr arg) { return functions::tan(arg); } + + /// Arc sine. + /// \param arg function argument + /// \return arc sine value of \a arg +// template typename enable::type asin(T arg) { return functions::asin(arg); } + inline expr asin(half arg) { return functions::asin(arg); } + inline expr asin(expr arg) { return functions::asin(arg); } + + /// Arc cosine function. + /// \param arg function argument + /// \return arc cosine value of \a arg +// template typename enable::type acos(T arg) { return functions::acos(arg); } + inline expr acos(half arg) { return functions::acos(arg); } + inline expr acos(expr arg) { return functions::acos(arg); } + + /// Arc tangent function. + /// \param arg function argument + /// \return arc tangent value of \a arg +// template typename enable::type atan(T arg) { return functions::atan(arg); } + inline expr atan(half arg) { return functions::atan(arg); } + inline expr atan(expr arg) { return functions::atan(arg); } + + /// Arc tangent function. + /// \param x first argument + /// \param y second argument + /// \return arc tangent value +// template typename enable::type atan2(T x, U y) { return functions::atan2(x, y); } + inline expr atan2(half x, half y) { return functions::atan2(x, y); } + inline expr atan2(half x, expr y) { return functions::atan2(x, y); } + inline expr atan2(expr x, half y) { return functions::atan2(x, y); } + inline expr atan2(expr x, expr y) { return functions::atan2(x, y); } + + /// \} + /// \name Hyperbolic functions + /// \{ + + /// Hyperbolic sine. + /// \param arg function argument + /// \return hyperbolic sine value of \a arg +// template typename enable::type sinh(T arg) { return functions::sinh(arg); } + inline expr sinh(half arg) { return functions::sinh(arg); } + inline expr sinh(expr arg) { return functions::sinh(arg); } + + /// Hyperbolic cosine. + /// \param arg function argument + /// \return hyperbolic cosine value of \a arg +// template typename enable::type cosh(T arg) { return functions::cosh(arg); } + inline expr cosh(half arg) { return functions::cosh(arg); } + inline expr cosh(expr arg) { return functions::cosh(arg); } + + /// Hyperbolic tangent. + /// \param arg function argument + /// \return hyperbolic tangent value of \a arg +// template typename enable::type tanh(T arg) { return functions::tanh(arg); } + inline expr tanh(half arg) { return functions::tanh(arg); } + inline expr tanh(expr arg) { return functions::tanh(arg); } + + /// Hyperbolic area sine. + /// \param arg function argument + /// \return area sine value of \a arg +// template typename enable::type asinh(T arg) { return functions::asinh(arg); } + inline expr asinh(half arg) { return functions::asinh(arg); } + inline expr asinh(expr arg) { return functions::asinh(arg); } + + /// Hyperbolic area cosine. + /// \param arg function argument + /// \return area cosine value of \a arg +// template typename enable::type acosh(T arg) { return functions::acosh(arg); } + inline expr acosh(half arg) { return functions::acosh(arg); } + inline expr acosh(expr arg) { return functions::acosh(arg); } + + /// Hyperbolic area tangent. + /// \param arg function argument + /// \return area tangent value of \a arg +// template typename enable::type atanh(T arg) { return functions::atanh(arg); } + inline expr atanh(half arg) { return functions::atanh(arg); } + inline expr atanh(expr arg) { return functions::atanh(arg); } + + /// \} + /// \name Error and gamma functions + /// \{ + + /// Error function. + /// \param arg function argument + /// \return error function value of \a arg +// template typename enable::type erf(T arg) { return functions::erf(arg); } + inline expr erf(half arg) { return functions::erf(arg); } + inline expr erf(expr arg) { return functions::erf(arg); } + + /// Complementary error function. + /// \param arg function argument + /// \return 1 minus error function value of \a arg +// template typename enable::type erfc(T arg) { return functions::erfc(arg); } + inline expr erfc(half arg) { return functions::erfc(arg); } + inline expr erfc(expr arg) { return functions::erfc(arg); } + + /// Natural logarithm of gamma function. + /// \param arg function argument + /// \return natural logarith of gamma function for \a arg +// template typename enable::type lgamma(T arg) { return functions::lgamma(arg); } + inline expr lgamma(half arg) { return functions::lgamma(arg); } + inline expr lgamma(expr arg) { return functions::lgamma(arg); } + + /// Gamma function. + /// \param arg function argument + /// \return gamma function value of \a arg +// template typename enable::type tgamma(T arg) { return functions::tgamma(arg); } + inline expr tgamma(half arg) { return functions::tgamma(arg); } + inline expr tgamma(expr arg) { return functions::tgamma(arg); } + + /// \} + /// \name Rounding + /// \{ + + /// Nearest integer not less than half value. + /// \param arg half to round + /// \return nearest integer not less than \a arg +// template typename enable::type ceil(T arg) { return functions::ceil(arg); } + inline half ceil(half arg) { return functions::ceil(arg); } + inline half ceil(expr arg) { return functions::ceil(arg); } + + /// Nearest integer not greater than half value. + /// \param arg half to round + /// \return nearest integer not greater than \a arg +// template typename enable::type floor(T arg) { return functions::floor(arg); } + inline half floor(half arg) { return functions::floor(arg); } + inline half floor(expr arg) { return functions::floor(arg); } + + /// Nearest integer not greater in magnitude than half value. + /// \param arg half to round + /// \return nearest integer not greater in magnitude than \a arg +// template typename enable::type trunc(T arg) { return functions::trunc(arg); } + inline half trunc(half arg) { return functions::trunc(arg); } + inline half trunc(expr arg) { return functions::trunc(arg); } + + /// Nearest integer. + /// \param arg half to round + /// \return nearest integer, rounded away from zero in half-way cases +// template typename enable::type round(T arg) { return functions::round(arg); } + inline half round(half arg) { return functions::round(arg); } + inline half round(expr arg) { return functions::round(arg); } + + /// Nearest integer. + /// \param arg half to round + /// \return nearest integer, rounded away from zero in half-way cases +// template typename enable::type lround(T arg) { return functions::lround(arg); } + inline long lround(half arg) { return functions::lround(arg); } + inline long lround(expr arg) { return functions::lround(arg); } + + /// Nearest integer using half's internal rounding mode. + /// \param arg half expression to round + /// \return nearest integer using default rounding mode +// template typename enable::type nearbyint(T arg) { return functions::nearbyint(arg); } + inline half nearbyint(half arg) { return functions::rint(arg); } + inline half nearbyint(expr arg) { return functions::rint(arg); } + + /// Nearest integer using half's internal rounding mode. + /// \param arg half expression to round + /// \return nearest integer using default rounding mode +// template typename enable::type rint(T arg) { return functions::rint(arg); } + inline half rint(half arg) { return functions::rint(arg); } + inline half rint(expr arg) { return functions::rint(arg); } + + /// Nearest integer using half's internal rounding mode. + /// \param arg half expression to round + /// \return nearest integer using default rounding mode +// template typename enable::type lrint(T arg) { return functions::lrint(arg); } + inline long lrint(half arg) { return functions::lrint(arg); } + inline long lrint(expr arg) { return functions::lrint(arg); } + #if HALF_ENABLE_CPP11_LONG_LONG + /// Nearest integer. + /// \param arg half to round + /// \return nearest integer, rounded away from zero in half-way cases +// template typename enable::type llround(T arg) { return functions::llround(arg); } + inline long long llround(half arg) { return functions::llround(arg); } + inline long long llround(expr arg) { return functions::llround(arg); } + + /// Nearest integer using half's internal rounding mode. + /// \param arg half expression to round + /// \return nearest integer using default rounding mode +// template typename enable::type llrint(T arg) { return functions::llrint(arg); } + inline long long llrint(half arg) { return functions::llrint(arg); } + inline long long llrint(expr arg) { return functions::llrint(arg); } + #endif + + /// \} + /// \name Floating point manipulation + /// \{ + + /// Decompress floating point number. + /// \param arg number to decompress + /// \param exp address to store exponent at + /// \return significant in range [0.5, 1) +// template typename enable::type frexp(T arg, int *exp) { return functions::frexp(arg, exp); } + inline half frexp(half arg, int *exp) { return functions::frexp(arg, exp); } + inline half frexp(expr arg, int *exp) { return functions::frexp(arg, exp); } + + /// Multiply by power of two. + /// \param arg number to modify + /// \param exp power of two to multiply with + /// \return \a arg multplied by 2 raised to \a exp +// template typename enable::type ldexp(T arg, int exp) { return functions::scalbln(arg, exp); } + inline half ldexp(half arg, int exp) { return functions::scalbln(arg, exp); } + inline half ldexp(expr arg, int exp) { return functions::scalbln(arg, exp); } + + /// Extract integer and fractional parts. + /// \param arg number to decompress + /// \param iptr address to store integer part at + /// \return fractional part +// template typename enable::type modf(T arg, half *iptr) { return functions::modf(arg, iptr); } + inline half modf(half arg, half *iptr) { return functions::modf(arg, iptr); } + inline half modf(expr arg, half *iptr) { return functions::modf(arg, iptr); } + + /// Multiply by power of two. + /// \param arg number to modify + /// \param exp power of two to multiply with + /// \return \a arg multplied by 2 raised to \a exp +// template typename enable::type scalbn(T arg, int exp) { return functions::scalbln(arg, exp); } + inline half scalbn(half arg, int exp) { return functions::scalbln(arg, exp); } + inline half scalbn(expr arg, int exp) { return functions::scalbln(arg, exp); } + + /// Multiply by power of two. + /// \param arg number to modify + /// \param exp power of two to multiply with + /// \return \a arg multplied by 2 raised to \a exp +// template typename enable::type scalbln(T arg, long exp) { return functions::scalbln(arg, exp); } + inline half scalbln(half arg, long exp) { return functions::scalbln(arg, exp); } + inline half scalbln(expr arg, long exp) { return functions::scalbln(arg, exp); } + + /// Extract exponent. + /// \param arg number to query + /// \return floating point exponent + /// \retval FP_ILOGB0 for zero + /// \retval FP_ILOGBNAN for NaN + /// \retval MAX_INT for infinity +// template typename enable::type ilogb(T arg) { return functions::ilogb(arg); } + inline int ilogb(half arg) { return functions::ilogb(arg); } + inline int ilogb(expr arg) { return functions::ilogb(arg); } + + /// Extract exponent. + /// \param arg number to query + /// \return floating point exponent +// template typename enable::type logb(T arg) { return functions::logb(arg); } + inline half logb(half arg) { return functions::logb(arg); } + inline half logb(expr arg) { return functions::logb(arg); } + + /// Next representable value. + /// \param from value to compute next representable value for + /// \param to direction towards which to compute next value + /// \return next representable value after \a from in direction towards \a to +// template typename enable::type nextafter(T from, U to) { return functions::nextafter(from, to); } + inline half nextafter(half from, half to) { return functions::nextafter(from, to); } + inline half nextafter(half from, expr to) { return functions::nextafter(from, to); } + inline half nextafter(expr from, half to) { return functions::nextafter(from, to); } + inline half nextafter(expr from, expr to) { return functions::nextafter(from, to); } + + /// Next representable value. + /// \param from value to compute next representable value for + /// \param to direction towards which to compute next value + /// \return next representable value after \a from in direction towards \a to +// template typename enable::type nexttoward(T from, long double to) { return functions::nexttoward(from, to); } + inline half nexttoward(half from, long double to) { return functions::nexttoward(from, to); } + inline half nexttoward(expr from, long double to) { return functions::nexttoward(from, to); } + + /// Take sign. + /// \param x value to change sign for + /// \param y value to take sign from + /// \return value equal to \a x in magnitude and to \a y in sign +// template typename enable::type copysign(T x, U y) { return functions::copysign(x, y); } + inline half copysign(half x, half y) { return functions::copysign(x, y); } + inline half copysign(half x, expr y) { return functions::copysign(x, y); } + inline half copysign(expr x, half y) { return functions::copysign(x, y); } + inline half copysign(expr x, expr y) { return functions::copysign(x, y); } + + /// \} + /// \name Floating point classification + /// \{ + + + /// Classify floating point value. + /// \param arg number to classify + /// \retval FP_ZERO for positive and negative zero + /// \retval FP_SUBNORMAL for subnormal numbers + /// \retval FP_INFINITY for positive and negative infinity + /// \retval FP_NAN for NaNs + /// \retval FP_NORMAL for all other (normal) values +// template typename enable::type fpclassify(T arg) { return functions::fpclassify(arg); } + inline int fpclassify(half arg) { return functions::fpclassify(arg); } + inline int fpclassify(expr arg) { return functions::fpclassify(arg); } + + /// Check if finite number. + /// \param arg number to check + /// \retval true if neither infinity nor NaN + /// \retval false else +// template typename enable::type isfinite(T arg) { return functions::isfinite(arg); } + inline bool isfinite(half arg) { return functions::isfinite(arg); } + inline bool isfinite(expr arg) { return functions::isfinite(arg); } + + /// Check for infinity. + /// \param arg number to check + /// \retval true for positive or negative infinity + /// \retval false else +// template typename enable::type isinf(T arg) { return functions::isinf(arg); } + inline bool isinf(half arg) { return functions::isinf(arg); } + inline bool isinf(expr arg) { return functions::isinf(arg); } + + /// Check for NaN. + /// \param arg number to check + /// \retval true for NaNs + /// \retval false else +// template typename enable::type isnan(T arg) { return functions::isnan(arg); } + inline bool isnan(half arg) { return functions::isnan(arg); } + inline bool isnan(expr arg) { return functions::isnan(arg); } + + /// Check if normal number. + /// \param arg number to check + /// \retval true if normal number + /// \retval false if either subnormal, zero, infinity or NaN +// template typename enable::type isnormal(T arg) { return functions::isnormal(arg); } + inline bool isnormal(half arg) { return functions::isnormal(arg); } + inline bool isnormal(expr arg) { return functions::isnormal(arg); } + + /// Check sign. + /// \param arg number to check + /// \retval true for negative number + /// \retval false for positive number +// template typename enable::type signbit(T arg) { return functions::signbit(arg); } + inline bool signbit(half arg) { return functions::signbit(arg); } + inline bool signbit(expr arg) { return functions::signbit(arg); } + + /// \} + /// \name Comparison + /// \{ + + /// Comparison for greater than. + /// \param x first operand + /// \param y second operand + /// \retval true if \a x greater than \a y + /// \retval false else +// template typename enable::type isgreater(T x, U y) { return functions::isgreater(x, y); } + inline bool isgreater(half x, half y) { return functions::isgreater(x, y); } + inline bool isgreater(half x, expr y) { return functions::isgreater(x, y); } + inline bool isgreater(expr x, half y) { return functions::isgreater(x, y); } + inline bool isgreater(expr x, expr y) { return functions::isgreater(x, y); } + + /// Comparison for greater equal. + /// \param x first operand + /// \param y second operand + /// \retval true if \a x greater equal \a y + /// \retval false else +// template typename enable::type isgreaterequal(T x, U y) { return functions::isgreaterequal(x, y); } + inline bool isgreaterequal(half x, half y) { return functions::isgreaterequal(x, y); } + inline bool isgreaterequal(half x, expr y) { return functions::isgreaterequal(x, y); } + inline bool isgreaterequal(expr x, half y) { return functions::isgreaterequal(x, y); } + inline bool isgreaterequal(expr x, expr y) { return functions::isgreaterequal(x, y); } + + /// Comparison for less than. + /// \param x first operand + /// \param y second operand + /// \retval true if \a x less than \a y + /// \retval false else +// template typename enable::type isless(T x, U y) { return functions::isless(x, y); } + inline bool isless(half x, half y) { return functions::isless(x, y); } + inline bool isless(half x, expr y) { return functions::isless(x, y); } + inline bool isless(expr x, half y) { return functions::isless(x, y); } + inline bool isless(expr x, expr y) { return functions::isless(x, y); } + + /// Comparison for less equal. + /// \param x first operand + /// \param y second operand + /// \retval true if \a x less equal \a y + /// \retval false else +// template typename enable::type islessequal(T x, U y) { return functions::islessequal(x, y); } + inline bool islessequal(half x, half y) { return functions::islessequal(x, y); } + inline bool islessequal(half x, expr y) { return functions::islessequal(x, y); } + inline bool islessequal(expr x, half y) { return functions::islessequal(x, y); } + inline bool islessequal(expr x, expr y) { return functions::islessequal(x, y); } + + /// Comarison for less or greater. + /// \param x first operand + /// \param y second operand + /// \retval true if either less or greater + /// \retval false else +// template typename enable::type islessgreater(T x, U y) { return functions::islessgreater(x, y); } + inline bool islessgreater(half x, half y) { return functions::islessgreater(x, y); } + inline bool islessgreater(half x, expr y) { return functions::islessgreater(x, y); } + inline bool islessgreater(expr x, half y) { return functions::islessgreater(x, y); } + inline bool islessgreater(expr x, expr y) { return functions::islessgreater(x, y); } + + /// Check if unordered. + /// \param x first operand + /// \param y second operand + /// \retval true if unordered (one or two NaN operands) + /// \retval false else +// template typename enable::type isunordered(T x, U y) { return functions::isunordered(x, y); } + inline bool isunordered(half x, half y) { return functions::isunordered(x, y); } + inline bool isunordered(half x, expr y) { return functions::isunordered(x, y); } + inline bool isunordered(expr x, half y) { return functions::isunordered(x, y); } + inline bool isunordered(expr x, expr y) { return functions::isunordered(x, y); } + + /// \name Casting + /// \{ + + /// Cast to or from half-precision floating point number. + /// This casts between [half](\ref half_float::half) and any built-in arithmetic type. Floating point types are + /// converted via an explicit cast to/from `float` (using the rounding mode of the built-in single precision + /// implementation) and thus any possible warnings due to an otherwise implicit conversion to/from `float` will be + /// suppressed. Integer types are converted directly using the given rounding mode, without any roundtrip over `float` + /// that a `static_cast` would otherwise do. It uses the default rounding mode. + /// + /// Using this cast with neither of the two types being a [half](\ref half_float::half) or with any of the two types + /// not being a built-in arithmetic type (apart from [half](\ref half_float::half), of course) results in a compiler + /// error and casting between [half](\ref half_float::half)s is just a no-op. + /// \tparam T destination type (half or built-in arithmetic type) + /// \tparam U source type (half or built-in arithmetic type) + /// \param arg value to cast + /// \return \a arg converted to destination type + template typename half_caster::type half_cast(U arg) { return half_caster::cast(arg); } + + /// Cast to or from half-precision floating point number. + /// This casts between [half](\ref half_float::half) and any built-in arithmetic type. Floating point types are + /// converted via an explicit cast to/from `float` (using the rounding mode of the built-in single precision + /// implementation) and thus any possible warnings due to an otherwise implicit conversion to/from `float` will be + /// suppressed. Integer types are converted directly using the given rounding mode, without any roundtrip over `float` + /// that a `static_cast` would otherwise do. + /// + /// Using this cast with neither of the two types being a [half](\ref half_float::half) or with any of the two types + /// not being a built-in arithmetic type (apart from [half](\ref half_float::half), of course) results in a compiler + /// error and casting between [half](\ref half_float::half)s is just a no-op. + /// \tparam T destination type (half or built-in arithmetic type) + /// \tparam R rounding mode to use. + /// \tparam U source type (half or built-in arithmetic type) + /// \param arg value to cast + /// \return \a arg converted to destination type + template typename half_caster::type half_cast(U arg) + { return half_caster::cast(arg); } + /// \} + } + + using detail::operator==; + using detail::operator!=; + using detail::operator<; + using detail::operator>; + using detail::operator<=; + using detail::operator>=; + using detail::operator+; + using detail::operator-; + using detail::operator*; + using detail::operator/; + using detail::operator<<; + using detail::operator>>; + + using detail::abs; + using detail::fabs; + using detail::fmod; + using detail::remainder; + using detail::remquo; + using detail::fma; + using detail::fmax; + using detail::fmin; + using detail::fdim; + using detail::nanh; + using detail::exp; + using detail::expm1; + using detail::exp2; + using detail::log; + using detail::log10; + using detail::log1p; + using detail::log2; + using detail::sqrt; + using detail::cbrt; + using detail::hypot; + using detail::pow; + using detail::sin; + using detail::cos; + using detail::tan; + using detail::asin; + using detail::acos; + using detail::atan; + using detail::atan2; + using detail::sinh; + using detail::cosh; + using detail::tanh; + using detail::asinh; + using detail::acosh; + using detail::atanh; + using detail::erf; + using detail::erfc; + using detail::lgamma; + using detail::tgamma; + using detail::ceil; + using detail::floor; + using detail::trunc; + using detail::round; + using detail::lround; + using detail::nearbyint; + using detail::rint; + using detail::lrint; +#if HALF_ENABLE_CPP11_LONG_LONG + using detail::llround; + using detail::llrint; +#endif + using detail::frexp; + using detail::ldexp; + using detail::modf; + using detail::scalbn; + using detail::scalbln; + using detail::ilogb; + using detail::logb; + using detail::nextafter; + using detail::nexttoward; + using detail::copysign; + using detail::fpclassify; + using detail::isfinite; + using detail::isinf; + using detail::isnan; + using detail::isnormal; + using detail::signbit; + using detail::isgreater; + using detail::isgreaterequal; + using detail::isless; + using detail::islessequal; + using detail::islessgreater; + using detail::isunordered; + + using detail::half_cast; +} + + +/// Extensions to the C++ standard library. +namespace std +{ + /// Numeric limits for half-precision floats. + /// Because of the underlying single-precision implementation of many operations, it inherits some properties from + /// `std::numeric_limits`. + template<> class numeric_limits : public numeric_limits + { + public: + /// Supports signed values. + static HALF_CONSTEXPR_CONST bool is_signed = true; + + /// Is not exact. + static HALF_CONSTEXPR_CONST bool is_exact = false; + + /// Doesn't provide modulo arithmetic. + static HALF_CONSTEXPR_CONST bool is_modulo = false; + + /// IEEE conformant. + static HALF_CONSTEXPR_CONST bool is_iec559 = true; + + /// Supports infinity. + static HALF_CONSTEXPR_CONST bool has_infinity = true; + + /// Supports quiet NaNs. + static HALF_CONSTEXPR_CONST bool has_quiet_NaN = true; + + /// Supports subnormal values. + static HALF_CONSTEXPR_CONST float_denorm_style has_denorm = denorm_present; + + /// Rounding mode. + /// Due to the mix of internal single-precision computations (using the rounding mode of the underlying + /// single-precision implementation) with explicit truncation of the single-to-half conversions, the actual rounding + /// mode is indeterminate. + static HALF_CONSTEXPR_CONST float_round_style round_style = (std::numeric_limits::round_style== + half_float::half::round_style) ? half_float::half::round_style : round_indeterminate; + + /// Significant digits. + static HALF_CONSTEXPR_CONST int digits = 11; + + /// Significant decimal digits. + static HALF_CONSTEXPR_CONST int digits10 = 3; + + /// Required decimal digits to represent all possible values. + static HALF_CONSTEXPR_CONST int max_digits10 = 5; + + /// Number base. + static HALF_CONSTEXPR_CONST int radix = 2; + + /// One more than smallest exponent. + static HALF_CONSTEXPR_CONST int min_exponent = -13; + + /// Smallest normalized representable power of 10. + static HALF_CONSTEXPR_CONST int min_exponent10 = -4; + + /// One more than largest exponent + static HALF_CONSTEXPR_CONST int max_exponent = 16; + + /// Largest finitely representable power of 10. + static HALF_CONSTEXPR_CONST int max_exponent10 = 4; + + /// Smallest positive normal value. + static HALF_CONSTEXPR half_float::half min() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0x0400); } + + /// Smallest finite value. + static HALF_CONSTEXPR half_float::half lowest() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0xFBFF); } + + /// Largest finite value. + static HALF_CONSTEXPR half_float::half max() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0x7BFF); } + + /// Difference between one and next representable value. + static HALF_CONSTEXPR half_float::half epsilon() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0x1400); } + + /// Maximum rounding error. + static HALF_CONSTEXPR half_float::half round_error() HALF_NOTHROW + { return half_float::half(half_float::detail::binary, (round_style==std::round_to_nearest) ? 0x3800 : 0x3C00); } + + /// Positive infinity. + static HALF_CONSTEXPR half_float::half infinity() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0x7C00); } + + /// Quiet NaN. + static HALF_CONSTEXPR half_float::half quiet_NaN() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0x7FFF); } + + /// Signalling NaN. + static HALF_CONSTEXPR half_float::half signaling_NaN() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0x7DFF); } + + /// Smallest positive subnormal value. + static HALF_CONSTEXPR half_float::half denorm_min() HALF_NOTHROW { return half_float::half(half_float::detail::binary, 0x0001); } + }; + +#if HALF_ENABLE_CPP11_HASH + /// Hash function for half-precision floats. + /// This is only defined if C++11 `std::hash` is supported and enabled. + template<> struct hash //: unary_function + { + /// Type of function argument. + typedef half_float::half argument_type; + + /// Function return type. + typedef size_t result_type; + + /// Compute hash function. + /// \param arg half to hash + /// \return hash value + result_type operator()(argument_type arg) const + { return hash()(static_cast(arg.data_)&-(arg.data_!=0x8000)); } + }; +#endif +} + + +#undef HALF_CONSTEXPR +#undef HALF_CONSTEXPR_CONST +#undef HALF_NOEXCEPT +#undef HALF_NOTHROW +#ifdef HALF_POP_WARNINGS + #pragma warning(pop) + #undef HALF_POP_WARNINGS +#endif + +#endif From 5b4f14b4d52a612ac0d72cf753787e6a1d675f0e Mon Sep 17 00:00:00 2001 From: Caliente Date: Fri, 11 Dec 2015 19:13:11 -0500 Subject: [PATCH 45/64] Adding missing fallout4 blank skeleton nif --- res/SkeletonBlank_fo4.nif | Bin 0 -> 7166 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 res/SkeletonBlank_fo4.nif diff --git a/res/SkeletonBlank_fo4.nif b/res/SkeletonBlank_fo4.nif new file mode 100644 index 0000000000000000000000000000000000000000..5e72987cc34c245bc9f77864b88aa3a5b0e94976 GIT binary patch literal 7166 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 Date: Sat, 12 Dec 2015 16:37:25 +0100 Subject: [PATCH 46/64] Cleanup, warnings, updated about dialog, cleaned SkeletonBlank_fo4 --- BodySlide.vcxproj | 1 - BodySlide.vcxproj.filters | 3 -- DiffData.cpp | 8 ++-- FBXWrangler.cpp | 6 +++ FBXWrangler.h | 6 +++ NifBlock.cpp | 2 - Object3d.cpp | 45 ------------------ Object3d.h | 5 -- OutfitProject.cpp | 95 ++++++++++++++++++++------------------ OutfitProject.h | 4 +- OutfitStudio.cpp | 34 ++++++-------- half.hpp | 2 + res/BodyslideFrame.xrc | 26 +++++++++++ res/SkeletonBlank_fo4.nif | Bin 7166 -> 6753 bytes 14 files changed, 108 insertions(+), 129 deletions(-) delete mode 100644 Object3d.cpp diff --git a/BodySlide.vcxproj b/BodySlide.vcxproj index b5fea19d..d3f82494 100644 --- a/BodySlide.vcxproj +++ b/BodySlide.vcxproj @@ -208,7 +208,6 @@ - diff --git a/BodySlide.vcxproj.filters b/BodySlide.vcxproj.filters index 0fe17932..42e8f97a 100644 --- a/BodySlide.vcxproj.filters +++ b/BodySlide.vcxproj.filters @@ -111,9 +111,6 @@ Source Files - - Source Files - Source Files diff --git a/DiffData.cpp b/DiffData.cpp index bf0240a0..51a33c71 100644 --- a/DiffData.cpp +++ b/DiffData.cpp @@ -281,7 +281,7 @@ void DiffDataSets::ApplyUVDiff(const string& set, const string& target, float pe for (auto resultIt = data->begin(); resultIt != data->end(); ++resultIt) { if (resultIt->first >= maxidx) - continue; // prevent crashes. + continue; (*inOutResult)[resultIt->first].u += resultIt->second.x * percent; (*inOutResult)[resultIt->first].v += resultIt->second.y * percent; @@ -300,8 +300,8 @@ void DiffDataSets::ApplyDiff(const string& set, const string& target, float perc for (auto resultIt = data->begin(); resultIt != data->end(); ++resultIt) { if (resultIt->first >= maxidx) - continue; // prevent crashes. - ushort idx = resultIt->first; + continue; + (*inOutResult)[resultIt->first].x += resultIt->second.x * percent; (*inOutResult)[resultIt->first].y += resultIt->second.y * percent; (*inOutResult)[resultIt->first].z += resultIt->second.z * percent; @@ -317,7 +317,7 @@ void DiffDataSets::ApplyClamp(const string& set, const string& target, vectorbegin(); resultIt != data->end(); ++resultIt) { if (resultIt->first >= maxidx) - continue; // prevent crashes. + continue; (*inOutResult)[resultIt->first].x = resultIt->second.x; (*inOutResult)[resultIt->first].y = resultIt->second.y; diff --git a/FBXWrangler.cpp b/FBXWrangler.cpp index 7d86dbc8..2229890d 100644 --- a/FBXWrangler.cpp +++ b/FBXWrangler.cpp @@ -1,3 +1,9 @@ +/* +BodySlide and Outfit Studio +Copyright (C) 2015 Caliente & ousnius +See the included LICENSE file +*/ + #include "FBXWrangler.h" FBXWrangler::FBXWrangler(): pSdkManager(nullptr), pCurrentScene(nullptr) { diff --git a/FBXWrangler.h b/FBXWrangler.h index 490818cb..bb3b3e6c 100644 --- a/FBXWrangler.h +++ b/FBXWrangler.h @@ -1,3 +1,9 @@ +/* +BodySlide and Outfit Studio +Copyright (C) 2015 Caliente & ousnius +See the included LICENSE file +*/ + #pragma once #include diff --git a/NifBlock.cpp b/NifBlock.cpp index 1f82091e..6ef0c8c4 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -615,7 +615,6 @@ BSTriShape::BSTriShape(fstream& file, NiHeader& hdr) { } void BSTriShape::Get(fstream& file) { - short shortData; half_float::half halfData; // The order of definition deviates slightly from previous versions, so can't directly use the super Get... instead // that code is duplicated here and the super super get is called. @@ -717,7 +716,6 @@ void BSTriShape::Get(fstream& file) { void BSTriShape::Put(fstream& file) { - short shortData; half_float::half halfData; // The order of definition deviates slightly from previous versions, so can't directly use the super Get... instead // that code is duplicated here and the super super get is called. diff --git a/Object3d.cpp b/Object3d.cpp deleted file mode 100644 index 22627693..00000000 --- a/Object3d.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "Object3d.h" -/* -float h2float(const ushort& in) { - float ret; - uint t1; - uint t2; - uint t3; - - t1 = in & 0x7fff; - t2 = in & 0x8000; - t3 = in & 0x7c00; - - t1 <<= 13; - t2 <<= 16; - - t1 += 0x38000000; - t1 = (t3 == 0 ? 0 : t1); - t1 |= t2; - - *((uint*)&ret) = t1; - return ret; -} - -unsigned short float2h(const float& in) { - ushort ret; - - uint c = *((uint*)&in); - - uint t1, t2, t3; - t1 = c & 0x7fffffff; - t2 = c & 0x80000000; - t3 = c & 0x7f800000; - - t1 >>= 13; - t2 >>= 16; - t1 -= 0x1c000; - - t1 = (t3 < 0x38800000 ? 0 : t1); - t1 = (t3 > 0x8e000000 ? 0x7bff : t1); - - t1 |= t2; - ret = t1; - return ret; -} -*/ \ No newline at end of file diff --git a/Object3d.h b/Object3d.h index cd11cc6c..8ccc45c0 100644 --- a/Object3d.h +++ b/Object3d.h @@ -25,11 +25,6 @@ typedef unsigned char byte; typedef unsigned short ushort; typedef unsigned int uint; -/* -float h2float(const ushort& in); -ushort float2h(const float& in); -*/ - struct Vertex; struct Vector2 { diff --git a/OutfitProject.cpp b/OutfitProject.cpp index 25bf8465..bb89e0c7 100644 --- a/OutfitProject.cpp +++ b/OutfitProject.cpp @@ -366,12 +366,14 @@ void OutfitProject::AddCombinedSlider(const string& newName) { } } -int OutfitProject::AddShapeFromObjFile(const string& fileName, string& shapeName, const string& mergeShape) { +int OutfitProject::AddShapeFromObjFile(const string& fileName, const string& shapeName, const string& mergeShape) { ObjFile obj; obj.SetScale(Vector3(10.0f, 10.0f, 10.0f)); - //Config.SetValue("StaticMeshMode", "True"); - //obj.LoadSimple(fileName); + if (!shapeName.empty()) + outfitName = shapeName; + else if (outfitName.empty()) + outfitName = "New Outfit"; if (obj.LoadForNif(fileName)) { wxLogError("Could not load OBJ file '%s'!", fileName); @@ -389,7 +391,8 @@ int OutfitProject::AddShapeFromObjFile(const string& fileName, string& shapeName wxMessageBox(wxString::Format("Could not copy data from OBJ file '%s'!", fileName), "OBJ Error", wxICON_ERROR); return 3; } - // skip zero size groups. + + // Skip zero size groups. if (v.size() == 0) continue; @@ -411,7 +414,7 @@ int OutfitProject::AddShapeFromObjFile(const string& fileName, string& shapeName return 100; } - int ret = CreateNifShapeFromData(useShapeName, v, t, uv); + CreateNifShapeFromData(useShapeName, v, t, uv); } return 0; @@ -422,7 +425,7 @@ int OutfitProject::CreateNifShapeFromData(const string& shapeName, vectorsetShapeImporting(shapeName, true); - bool staticMode = (Config.GetString("StaticMeshMode") == "True"); + bool staticMode = Config["StaticMeshMode"] == "True"; string blankSkel = "res\\SkeletonBlank.nif"; string defaultName = "New Outfit"; @@ -430,9 +433,8 @@ int OutfitProject::CreateNifShapeFromData(const string& shapeName, vectortargetGame == FO4) { + else if (owner->targetGame == FO4) blankSkel = "res\\SkeletonBlank_fo4.nif"; - } NifFile blank; @@ -510,8 +512,8 @@ int OutfitProject::CreateNifShapeFromData(const string& shapeName, vectorCreate(&v, &t, &uv, norms); nifBSTriShape->ssfFile = "Meshes\\Actors\\Character\\CharacterAssets\\FemaleBody.ssf"; @@ -522,7 +524,7 @@ int OutfitProject::CreateNifShapeFromData(const string& shapeName, vectorboneDataRef = boneID; + nifBSSkinInstance->boneDataRef = boneID; nifBSTriShape->skinInstanceRef = skinID; triShapeBase = nifBSTriShape; } @@ -546,7 +548,7 @@ int OutfitProject::CreateNifShapeFromData(const string& shapeName, vector tris; const vector* verts = workNif.GetRawVertsForShape(shapeName); workNif.GetTrisForShape(shapeName, &tris); - const vector* uvs = workNif.GetUvsForShape(shapeName); vector outVerts = *verts; @@ -765,14 +766,14 @@ int OutfitProject::SaveSliderOBJ(const string& sliderName, const string& shapeNa vector origUvs; ObjFile orderFile; orderFile.LoadVertOrderMap(mapfn, orderMap, origFaces, origUvs); + vector swizzleverts(orderMap.size()); - for (int i = 0; i < orderMap.size(); i++) { + for (int i = 0; i < orderMap.size(); i++) swizzleverts[i] = outVerts[orderMap[i]]; - } + ObjFile obj; obj.SetScale(Vector3(0.1f, 0.1f, 0.1f)); obj.AddGroup(shapeName, swizzleverts, origFaces, origUvs); - //obj.AddGroup(shapeName, outVerts, tris, *uvs); if (obj.Save(fileName)) return 1; @@ -840,27 +841,25 @@ bool OutfitProject::SetSliderFromOBJ(const string& sliderName, const string& sha bool OutfitProject::SetSliderFromFBX(const string& sliderName, const string& shapeName, const string& fileName) { string target = ShapeToTarget(shapeName); - int type = workNif.GetShapeType(shapeName); FBXWrangler fbxw; string invalidBones; bool result = fbxw.ImportScene(fileName); if (!result) - return 1; + return 1; + vectorshapes; fbxw.GetShapeNames(shapes); bool found = false; - for (auto s : shapes) { - if (s == shapeName) { + for (auto &s : shapes) + if (s == shapeName) found = true; - } - } - if (!found) { + + if (!found) return false; - } - FBXShape* shape = fbxw.InShape(shapeName); + FBXShape* shape = fbxw.InShape(shapeName); unordered_map diff; if (IsBaseShape(shapeName)) { @@ -876,8 +875,8 @@ bool OutfitProject::SetSliderFromFBX(const string& sliderName, const string& sha morpher.SetResultDiff(target, sliderName, diff); } - return true; + return true; } void OutfitProject::SetSliderFromTRI(const string& sliderName, const string& shapeName, unordered_map& diff) { @@ -1958,34 +1957,39 @@ int OutfitProject::ImportShapeFBX(const string& fileName, const string& shapeNam bool result = fbxw.ImportScene(fileName); if (!result) return 1; + + if (!shapeName.empty()) + outfitName = shapeName; + else if (outfitName.empty()) + outfitName = "New Outfit"; + vectorshapes; fbxw.GetShapeNames(shapes); - for (int i = 0; i < shapes.size(); i++) { - FBXShape* shape = fbxw.InShape(shapes[i]); - - string useShapeName = shapes[i]; + for (auto &s : shapes) { + FBXShape* shape = fbxw.InShape(s); + string useShapeName = s; - if (mergeShape != "") { + if (!mergeShape.empty()) { vector shapeVerts; workNif.GetVertsForShape(mergeShape, shapeVerts); if (shapeVerts.size() == shape->numverts) { - int r = wxMessageBox("The vertex count of the selected .fbx file matches the currently selected outfit shape. Do you wish to update the current shape? (click No to create a new shape)", "Merge or New", wxYES_NO | wxICON_QUESTION); - if (r == wxYES) { - r = wxMessageBox("Update Vertex Positions?", "Vertex Position Update", wxYES_NO | wxICON_QUESTION); - if (r == wxYES) { - workNif.SetVertsForShape(mergeShape, shape->verts); - } - r = wxMessageBox("Update Animation Weighting?", "Animation Weight Update", wxYES_NO | wxICON_QUESTION); - if (r == wxYES) { - for (auto &bn : shape->boneNames) { + int ret = wxMessageBox("The vertex count of the selected .fbx file matches the currently selected outfit shape. Do you wish to update the current shape? (click No to create a new shape)", "Merge or New", wxYES_NO | wxICON_QUESTION); + if (ret == wxYES) { + ret = wxMessageBox("Update Vertex Positions?", "Vertex Position Update", wxYES_NO | wxICON_QUESTION); + if (ret == wxYES) + workNif.SetVertsForShape(mergeShape, shape->verts); + + ret = wxMessageBox("Update Animation Weighting?", "Animation Weight Update", wxYES_NO | wxICON_QUESTION); + if (ret == wxYES) + for (auto &bn : shape->boneNames) workAnim.SetWeights(mergeShape, bn, shape->boneSkin[bn].vertweights); - } - } + return 101; } } + useShapeName = wxGetTextFromUser("Please specify a name for the new shape", "New Shape Name", useShapeName); - if (useShapeName == "") + if (useShapeName.empty()) return 100; } @@ -2003,12 +2007,13 @@ int OutfitProject::ImportShapeFBX(const string& fileName, const string& shapeNam workAnim.shapeBones[useShapeName].push_back(bn); workAnim.shapeSkinning[useShapeName].boneNames[bn] = slot; workAnim.SetWeights(useShapeName, bn, shape->boneSkin[bn].vertweights); - // workAnim.shapeSkinning[useShapeName].boneWeights[slot].weights = shape->boneSkin[bn].vertweights; + //workAnim.shapeSkinning[useShapeName].boneWeights[slot].weights = shape->boneSkin[bn].vertweights; slot++; } - CreateNifShapeFromData(shapes[i], shape->verts, shape->tris, shape->uvs, &shape->normals); + CreateNifShapeFromData(s, shape->verts, shape->tris, shape->uvs, &shape->normals); } + return 0; } diff --git a/OutfitProject.h b/OutfitProject.h index 6ebc9b4e..b1bc861a 100644 --- a/OutfitProject.h +++ b/OutfitProject.h @@ -101,9 +101,7 @@ class OutfitProject { void AddZapSlider(const string& newName, unordered_map& verts, const string& shapeName); void AddCombinedSlider(const string& newName); - // AddShapeFromObjFile - shapeName is modified during a successful import to reflect the name of the news hape. - int AddShapeFromObjFile(const string& fileName, string& shapeName, const string& mergeShape = ""); - + int AddShapeFromObjFile(const string& fileName, const string& shapeName, const string& mergeShape = ""); int CreateNifShapeFromData(const string& shapeName, vector& v, vector& t, vector& uv, vector* norms = nullptr); // Slider data can have a separate name from the shape target. diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index d011d351..05b66aa5 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -2970,13 +2970,11 @@ void OutfitStudio::OnImportShape(wxCommandEvent& WXUNUSED(event)) { wxLogMessage("Importing shape from OBJ file '%s'...", fn); - string shapeName = "New Shape"; - int ret; if (activeItem) - ret = project->AddShapeFromObjFile(fn, shapeName, activeItem->shapeName); + ret = project->AddShapeFromObjFile(fn, project->OutfitName(), activeItem->shapeName); else - ret = project->AddShapeFromObjFile(fn, shapeName); + ret = project->AddShapeFromObjFile(fn, project->OutfitName()); if (ret == 101) { // User chose to merge shapes vector v; @@ -3031,17 +3029,15 @@ void OutfitStudio::OnImportFBX(wxCommandEvent& WXUNUSED(event)) { string fn = wxFileSelector("Import .fbx file for new shape", wxEmptyString, wxEmptyString, ".fbx", "*.fbx", wxFD_FILE_MUST_EXIST, this); if (fn.empty()) return; - wxLogMessage("Importing shape from FBX file '%s'...", fn); - string shapeName = "New Shape"; - + wxLogMessage("Importing shape from FBX file '%s'...", fn); + int ret; - if (activeItem) { - ret = project->ImportShapeFBX(fn, shapeName, activeItem->shapeName); - } - else { - ret = project->ImportShapeFBX(fn, shapeName); - } + if (activeItem) + ret = project->ImportShapeFBX(fn, project->OutfitName(), activeItem->shapeName); + else + ret = project->ImportShapeFBX(fn, project->OutfitName()); + if (ret == 101) { vector v; project->GetLiveVerts(activeItem->shapeName, v); @@ -3070,14 +3066,10 @@ void OutfitStudio::OnExportFBX(wxCommandEvent& WXUNUSED(event)) { if (fn.empty()) return; - if (activeItem){ + if (activeItem) project->ExportShapeFBX(fn, activeItem->shapeName); - } - else { + else project->ExportShapeFBX(fn, ""); - } - - } void OutfitStudio::OnRenameShape(wxCommandEvent& WXUNUSED(event)) { @@ -4699,9 +4691,9 @@ bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames) { inputFile = fileNames.Item(0); string mergeShapeName = ""; - if (owner->activeItem) { + if (owner->activeItem) mergeShapeName = owner->activeItem->shapeName; - } + wxString dataName = inputFile.AfterLast('\\'); dataName = dataName.BeforeLast('.'); diff --git a/half.hpp b/half.hpp index 441a652b..75197845 100644 --- a/half.hpp +++ b/half.hpp @@ -22,6 +22,8 @@ #ifndef HALF_HALF_HPP #define HALF_HALF_HPP +#pragma warning (disable : 4244 4800) + /// Combined gcc version number. #define HALF_GNUC_VERSION (__GNUC__*100+__GNUC_MINOR__) diff --git a/res/BodyslideFrame.xrc b/res/BodyslideFrame.xrc index 747b4355..a41a1a4c 100644 --- a/res/BodyslideFrame.xrc +++ b/res/BodyslideFrame.xrc @@ -1040,6 +1040,21 @@ along with this program. If not, see htt Simple OpenGL Image Libary 2 (SOIL2)
Public Domain
https://bitbucket.org/SpartanJ/soil2
http://lonesock.net/soil.html



+Autodesk® FBX®
This software contains Autodesk® FBX® code developed by Autodesk, Inc.
+Copyright 2014 Autodesk, Inc. All rights, reserved.

+Such code is provided “as is” and Autodesk, Inc. disclaims
+any and all warranties, whether express or implied, including
+without limitation the implied warranties of merchantability,
+fitness for a particular purpose or non-infringement
+of third party rights. In no event shall Autodesk, Inc.
+be liable for any direct, indirect, incidental, special,
+exemplary, or consequential damages (including,
+but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption)
+however caused and on any theory of liability, whether in contract,
+strict liability, or tort (including negligence or otherwise)
+arising in any way out of such code.



+ TinyXML-2

zlib License
Original code by Lee Thomason (http://www.grinninglizard.com/)

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.

Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:

@@ -1047,6 +1062,17 @@ Permission is granted to anyone to use this software for any
purpose, includi would be appreciated but is not required.

2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.

3. This notice may not be removed or altered from any source
distribution.



+half - IEEE 754-based half-precision floating point library
Copyright (c) 2012-2013 Christian Rau (rauy@users.sourceforge.net)

+Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation +files (the "Software"),
to deal in the Software without restriction,
including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:

+The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.



+ fsengine (BSA Library)

BSD License
Copyright (c) 2005-2012, NIF File Format Library and Tools
Modified by ousnius.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
diff --git a/res/SkeletonBlank_fo4.nif b/res/SkeletonBlank_fo4.nif index 5e72987cc34c245bc9f77864b88aa3a5b0e94976..ff901730d4462ea79b0b85e00d9bd76afaedde82 100644 GIT binary patch delta 45 xcmexo{?KHC0i*3i!$clN1~vu;2ERJ(Co?^xBr`8PI3qD7wJ4w{zaX`! zq*4eh2N4TNttcriN)1jenYgf=6DYyRz{KFdI9ZPI-DCqs7S=gHq5YdVnF1v0S%FMD zAO?Z|K)}qD(9j6sLdgbu28ITEm>PssgFR4!ff+0SQUd}IwWu_M{r~^<^=Hrc*h0h? zILw+UX>V-2*&Zmy2{g9>$T(v^aiK^a7tjbpAa+bH$uBC_cg{#GN=z Date: Sat, 12 Dec 2015 19:23:42 +0100 Subject: [PATCH 47/64] Prepare vertex deletion fix for BSTriShape --- NifBlock.cpp | 4 ++++ NifFile.cpp | 9 +++++++-- NifFile.h | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/NifBlock.cpp b/NifBlock.cpp index 6ef0c8c4..8596d28f 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -843,6 +843,10 @@ void BSTriShape::notifyBlockSwap(int blockIndexLo, int blockIndexHi) { shaderPropertyRef = blockIndexLo; } +void BSTriShape::notifyVerticesDelete(const vector& vertIndices) { + //Implement +} + int BSTriShape::CalcBlockSize() { blockSize = 118 + 6 * numTris; diff --git a/NifFile.cpp b/NifFile.cpp index 3966104e..fce96127 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -2822,10 +2822,15 @@ void NifFile::DeleteVertsForShape(const string& shapeName, const vector& } } else { - // Not IMplemented BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { - //alphaRef = siTriShape->alphaPropertyRef; + siTriShape->notifyVerticesDelete(indices); + if (siTriShape->numverts == 0 || siTriShape->numTris == 0) { + // Deleted all verts or tris, remove shape and children + DeleteShape(shapeName); + return; + } + hdr.blockSizes[dataRef] = siTriShape->CalcBlockSize(); } } diff --git a/NifFile.h b/NifFile.h index f9c547cd..800507fa 100644 --- a/NifFile.h +++ b/NifFile.h @@ -407,6 +407,7 @@ class BSTriShape : public NiAVObject{ virtual void Put(fstream& file); virtual void notifyBlockDelete(int blockID); virtual void notifyBlockSwap(int blockIndexLo, int blockIndexHi); + virtual void notifyVerticesDelete(const vector& vertIndices); virtual int CalcBlockSize(); const vector* GetRawVerts(bool xform = true); From 0822d4ba418e515d64d83a224bb5ba6b40f26770 Mon Sep 17 00:00:00 2001 From: ousnius Date: Sun, 13 Dec 2015 18:24:37 +0100 Subject: [PATCH 48/64] Fixed NiAlphaProperty, shape properties and more of NifFile for FO4 --- NifBlock.cpp | 67 ++++---- NifFile.cpp | 373 +++++++++++++++++++++++--------------------- NifFile.h | 8 +- ShapeProperties.cpp | 51 +++--- 4 files changed, 267 insertions(+), 232 deletions(-) diff --git a/NifBlock.cpp b/NifBlock.cpp index 8596d28f..d2d3ebd4 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -816,7 +816,7 @@ void BSTriShape::Put(fstream& file) { } void BSTriShape::notifyBlockDelete(int blockID) { - NiObjectNET::notifyBlockDelete(blockID); + NiAVObject::notifyBlockDelete(blockID); if (skinInstanceRef == blockID) skinInstanceRef = -1; @@ -827,11 +827,16 @@ void BSTriShape::notifyBlockDelete(int blockID) { shaderPropertyRef = -1; else if (shaderPropertyRef > blockID) shaderPropertyRef--; + + if (alphaPropertyRef == blockID) + alphaPropertyRef = -1; + else if (alphaPropertyRef > blockID) + alphaPropertyRef--; } void BSTriShape::notifyBlockSwap(int blockIndexLo, int blockIndexHi) { + NiAVObject::notifyBlockSwap(blockIndexLo, blockIndexHi); - NiObjectNET::notifyBlockSwap(blockIndexLo, blockIndexHi); if (skinInstanceRef == blockIndexLo) skinInstanceRef = blockIndexHi; else if (skinInstanceRef == blockIndexHi) @@ -841,6 +846,11 @@ void BSTriShape::notifyBlockSwap(int blockIndexLo, int blockIndexHi) { shaderPropertyRef = blockIndexHi; else if (shaderPropertyRef == blockIndexHi) shaderPropertyRef = blockIndexLo; + + if (alphaPropertyRef == blockIndexLo) + alphaPropertyRef = blockIndexHi; + else if (alphaPropertyRef == blockIndexHi) + alphaPropertyRef = blockIndexLo; } void BSTriShape::notifyVerticesDelete(const vector& vertIndices) { @@ -848,8 +858,10 @@ void BSTriShape::notifyVerticesDelete(const vector& vertIndices) { } int BSTriShape::CalcBlockSize() { - blockSize = 118 + 6 * numTris; - + NiAVObject::CalcBlockSize(); + + blockSize += 46 + 6 * numTris; + int vdataSize = 12; if (vertFlags[6] & 0x1) { //normals vdataSize += 8; @@ -861,12 +873,11 @@ int BSTriShape::CalcBlockSize() { if (vertFlags[6] & 0x4) { //skinning vdataSize += 12; - } + blockSize += vdataSize * numverts; return blockSize; - } @@ -3837,6 +3848,13 @@ float NiShader::GetEmissiveMultiple() { void NiShader::SetEmissiveMultiple(float emissive) { } +uint NiShader::GetWetMaterialNameRef() { + return 0xFFFFFFFF; +} + +void NiShader::SetWetMaterialNameRef(uint matRef) { +} + int NiShader::CalcBlockSize() { return blockSize; } @@ -3865,6 +3883,7 @@ BSLightingShaderProperty::BSLightingShaderProperty(NiHeader& hdr) { emissiveColor.Zero(); emissiveMultiple = 1.0f; + wetMaterialNameRef = 0xFFFFFFFF; textureClampMode = 3; alpha = 1.0f; refractionStrength = 0.0f; @@ -4216,6 +4235,14 @@ void BSLightingShaderProperty::SetEmissiveMultiple(float emissive) { emissiveMultiple = emissive; } +uint BSLightingShaderProperty::GetWetMaterialNameRef() { + return wetMaterialNameRef; +} + +void BSLightingShaderProperty::SetWetMaterialNameRef(uint matRef) { + wetMaterialNameRef = matRef; +} + int BSLightingShaderProperty::CalcBlockSize() { NiProperty::CalcBlockSize(); @@ -4713,39 +4740,17 @@ NiAlphaProperty::NiAlphaProperty(fstream& file, NiHeader& hdr) { } void NiAlphaProperty::Get(fstream& file) { - if (header->userVersion <= 12 && header->userVersion2 < 130) { - NiProperty::Get(file); - } - - if (header->userVersion == 12 && header->userVersion2 >= 130) { - file.read((char*)&unkRef, 4); - } - + NiProperty::Get(file); file.read((char*)&flags, 2); - file.read((char*)&threshold, 1); - if (header->userVersion == 12 && header->userVersion2 >= 130) { - file.read((char*)&unk1, 4); - file.read((char*)&unk2, 4); - } + file.read((char*)&threshold, 1); } void NiAlphaProperty::Put(fstream& file) { - if (header->userVersion <= 12 && header->userVersion2 < 130) { - NiProperty::Put(file); - } - - if (header->userVersion == 12 && header->userVersion2 >= 130) { - file.write((char*)&unkRef, 4); - } - + NiProperty::Put(file); file.write((char*)&flags, 2); file.write((char*)&threshold, 1); - if (header->userVersion == 12 && header->userVersion2 >= 130) { - file.write((char*)&unk1, 4); - file.write((char*)&unk2, 4); - } } void NiAlphaProperty::notifyBlockDelete(int blockID) { diff --git a/NifFile.cpp b/NifFile.cpp index fce96127..7b73c2ab 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -77,7 +77,7 @@ int NifFile::shapeDataIdForName(const string& name, int& outBlockType) { if (type == NITRISHAPE || type == NITRISTRIPS) { NiTriBasedGeom* geom = dynamic_cast(block); if (geom && !name.compare(geom->name)) { - NiTriBasedGeomData* geomData = dynamic_cast(blocks[geom->dataRef]); + NiTriBasedGeomData* geomData = dynamic_cast(GetBlock(geom->dataRef)); outBlockType = geomData->blockType; return geom->dataRef; } @@ -143,9 +143,9 @@ int NifFile::shapeBoneIndex(const string& shapeName, const string& boneName) { BSTriShape* bsTriShape = geomForNameF4(shapeName); if (bsTriShape) { - NiBoneContainer* bonelist = (NiBoneContainer*)blocks[bsTriShape->skinInstanceRef]; + NiBoneContainer* bonelist = (NiBoneContainer*)GetBlock(bsTriShape->skinInstanceRef); for (int i = 0; ibones.size();i++) { - if (bonelist->bones[i] > -1 && ((NiNode*)blocks[bonelist->bones[i]])->name == boneName) { + if (bonelist->bones[i] > -1 && ((NiNode*)GetBlock(bonelist->bones[i]))->name == boneName) { return i; } } @@ -158,12 +158,12 @@ int NifFile::shapeBoneIndex(const string& shapeName, const string& boneName) { if (skinRef == -1) return -1; - NiSkinInstance* skinInst = dynamic_cast(blocks[skinRef]); + NiSkinInstance* skinInst = dynamic_cast(GetBlock(skinRef)); if (skinInst) { for (int i = 0; i < skinInst->bones.size(); i++) { int boneBlock = skinInst->bones[i]; if (boneBlock != -1) { - NiNode* node = (NiNode*)blocks[boneBlock]; + NiNode* node = (NiNode*)GetBlock(boneBlock); if (node->name == boneName) return i; } @@ -573,7 +573,7 @@ int NifFile::AddNode(const string& nodeName, vector& rot, Vector3& tran } string NifFile::NodeName(int blockID) { - NiNode* n = dynamic_cast(blocks[blockID]); + NiNode* n = dynamic_cast(GetBlock(blockID)); if (!n) return ""; if (n->name.empty()) @@ -612,12 +612,11 @@ NiShader* NifFile::GetShaderF4(const string& shapeName) { BSTriShape* geom = geomForNameF4(shapeName); if (geom) prop1 = geom->shaderPropertyRef; - else { - return nullptr; - } + else + return nullptr; if (prop1 != -1) { - NiShader* shader = dynamic_cast(blocks[prop1]); + NiShader* shader = dynamic_cast(GetBlock(prop1)); if (shader) { ushort type = shader->blockType; if (type == BSLIGHTINGSHADERPROPERTY || @@ -625,7 +624,7 @@ NiShader* NifFile::GetShaderF4(const string& shapeName) { type == BSSHADERPPLIGHTINGPROPERTY) return shader; } - } + } return nullptr; } @@ -636,13 +635,11 @@ NiShader* NifFile::GetShader(const string& shapeName) { NiTriBasedGeom* geom = geomForName(shapeName); if (geom) prop1 = geom->propertiesRef1; - else { - return NifFile::GetShaderF4(shapeName); - - } + else + return GetShaderF4(shapeName); if (prop1 != -1) { - NiShader* shader = dynamic_cast(blocks[prop1]); + NiShader* shader = dynamic_cast(GetBlock(prop1)); if (shader) { ushort type = shader->blockType; if (type == BSLIGHTINGSHADERPROPERTY || @@ -657,7 +654,7 @@ NiShader* NifFile::GetShader(const string& shapeName) { return nullptr; for (int i = 0; i < props.size(); i++) { - NiShader* shader = dynamic_cast(blocks[props[i]]); + NiShader* shader = dynamic_cast(GetBlock(props[i])); if (shader) { ushort type = shader->blockType; if (type == BSLIGHTINGSHADERPROPERTY || @@ -689,7 +686,7 @@ NiMaterialProperty* NifFile::GetMaterialProperty(const string& shapeName) { return nullptr; for (int i = 0; i < props.size(); i++) { - NiMaterialProperty* material = dynamic_cast(blocks[props[i]]); + NiMaterialProperty* material = dynamic_cast(GetBlock(props[i])); if (material) return material; } @@ -721,7 +718,7 @@ int NifFile::GetTextureForShape(const string& shapeName, string& outTexFile, int return 0; } - BSShaderTextureSet* textureSet = dynamic_cast(blocks[textureSetRef]); + BSShaderTextureSet* textureSet = dynamic_cast(GetBlock(textureSetRef)); if (!textureSet || texIndex + 1 > textureSet->numTextures) return 0; @@ -751,7 +748,7 @@ void NifFile::SetTextureForShape(const string& shapeName, string& outTexFile, in return; } - BSShaderTextureSet* textureSet = dynamic_cast(blocks[textureSetRef]); + BSShaderTextureSet* textureSet = dynamic_cast(GetBlock(textureSetRef)); if (!textureSet || texIndex + 1 > textureSet->numTextures) return; @@ -830,10 +827,15 @@ void NifFile::CopyShader(const string& shapeDest, int srcShaderRef, NifFile& src int dataRef = -1; NiTriBasedGeom* geom = geomForName(shapeDest); - if (geom) + BSTriShape* siTriShape = nullptr; + if (geom) { dataRef = geom->dataRef; - else - return; + } + else { + siTriShape = geomForNameF4(shapeDest); + if (!siTriShape) + return; + } // Get source shader NiShader* srcShader = dynamic_cast(srcNif.GetBlock(srcShaderRef)); @@ -887,6 +889,11 @@ void NifFile::CopyShader(const string& shapeDest, int srcShaderRef, NifFile& src destShader->SetTextureSetRef(texsetId); } + // Wet Material Name Ref + int wetMaterialNameRef = srcShader->GetWetMaterialNameRef(); + if (wetMaterialNameRef != 0xFFFFFFFF) + destShader->SetWetMaterialNameRef(AddOrFindStringId(srcNif.hdr.strings[wetMaterialNameRef].str)); + // Controller int controllerId = -1; NiTimeController* destController = nullptr; @@ -924,16 +931,20 @@ void NifFile::CopyShader(const string& shapeDest, int srcShaderRef, NifFile& src destShader->controllerRef = controllerId; } - if (srcShader->blockType == BSLIGHTINGSHADERPROPERTY) - geom->propertiesRef1 = shaderId; - else if (srcShader->blockType == BSSHADERPPLIGHTINGPROPERTY) - geom->propertiesRef[propRef1] = shaderId; - else if (srcShader->blockType == BSEFFECTSHADERPROPERTY) - geom->propertiesRef1 = shaderId; + if (geom) { + if (srcShader->blockType == BSLIGHTINGSHADERPROPERTY) + geom->propertiesRef1 = shaderId; + else if (srcShader->blockType == BSSHADERPPLIGHTINGPROPERTY) + geom->propertiesRef[propRef1] = shaderId; + else if (srcShader->blockType == BSEFFECTSHADERPROPERTY) + geom->propertiesRef1 = shaderId; + } + else + siTriShape->shaderPropertyRef = shaderId; // Kill normals, set numUVSets to 1 if (dataRef != -1 && destShader->IsSkin() && hdr.userVersion >= 12) { - NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); + NiTriBasedGeomData* geomData = dynamic_cast(GetBlock(dataRef)); if (geomData) { geomData->hasNormals = 0; geomData->normals.clear(); @@ -955,12 +966,17 @@ void NifFile::CopyShader(const string& shapeDest, int srcShaderRef, NifFile& src if (addAlpha) { NiAlphaProperty* alphaProp = new NiAlphaProperty(hdr); - if (srcShader->blockType == BSLIGHTINGSHADERPROPERTY) - geom->propertiesRef2 = blocks.size(); - else if (srcShader->blockType == BSSHADERPPLIGHTINGPROPERTY) - geom->propertiesRef[propRef2] = blocks.size(); - else if (srcShader->blockType == BSEFFECTSHADERPROPERTY) - geom->propertiesRef2 = blocks.size(); + if (geom) { + if (srcShader->blockType == BSLIGHTINGSHADERPROPERTY) + geom->propertiesRef2 = blocks.size(); + else if (srcShader->blockType == BSSHADERPPLIGHTINGPROPERTY) + geom->propertiesRef[propRef2] = blocks.size(); + else if (srcShader->blockType == BSEFFECTSHADERPROPERTY) + geom->propertiesRef2 = blocks.size(); + } + else + siTriShape->alphaPropertyRef = blocks.size(); + blocks.push_back(alphaProp); hdr.numBlocks++; hdr.blockSizes.push_back(alphaProp->CalcBlockSize()); @@ -1019,7 +1035,6 @@ void NifFile::CopyGeometry(const string& shapeDest, NifFile& srcNif, const strin } void NifFile::CopyGeometry(const string& shapeDest, NifFile& srcNif, const string& srcShape, NiTriBasedGeom* srcGeom) { - bool skipSkinInst = false; if (srcGeom->skinInstanceRef == -1) skipSkinInst = true; @@ -1266,8 +1281,8 @@ void NifFile::CopyGeometry(const string& shapeDest, NifFile& srcNif, const strin BSTriShape* destShape = (BSTriShape*)srcGeom; newBlockSize = destShape->CalcBlockSize(); destGeom = new BSTriShape(*destShape); - } + destGeom->header = &hdr; destGeom->nameRef = AddOrFindStringId(shapeDest); destGeom->name = shapeDest; @@ -1299,30 +1314,13 @@ void NifFile::CopyGeometry(const string& shapeDest, NifFile& srcNif, const strin } } - if (srcGeom->shaderPropertyRef != -1) { - BSLightingShaderProperty * bsShader = new BSLightingShaderProperty(*(BSLightingShaderProperty*)srcNif.GetBlock(srcGeom->shaderPropertyRef)); - blocks.push_back(bsShader); - destGeom->shaderPropertyRef = hdr.numBlocks; - hdr.numBlocks++; - hdr.blockSizes.push_back(bsShader->CalcBlockSize()); - hdr.blockIndex.push_back(AddOrFindBlockTypeId(srcNif.hdr.blockTypes[srcNif.hdr.blockIndex[srcGeom->shaderPropertyRef]].str)); - - if (bsShader->textureSetRef) { - BSShaderTextureSet* bsTexSet = new BSShaderTextureSet(*(BSShaderTextureSet*)srcNif.GetBlock(bsShader->textureSetRef)); - blocks.push_back(bsTexSet); - hdr.blockSizes.push_back(bsTexSet->CalcBlockSize()); - hdr.blockIndex.push_back(AddOrFindBlockTypeId(srcNif.hdr.blockTypes[srcNif.hdr.blockIndex[bsShader->textureSetRef]].str)); - bsShader->textureSetRef = hdr.numBlocks; - hdr.numBlocks++; - } - if (bsShader->nameRef != -1) { - bsShader->name = srcNif.hdr.strings[bsShader->nameRef].str; - bsShader->nameRef = AddOrFindStringId(bsShader->name); - } - if (bsShader->wetMaterialNameRef != -1) { - bsShader->wetMaterialNameRef = AddOrFindStringId(srcNif.hdr.strings[bsShader->wetMaterialNameRef].str); - } + bool shaderAlpha = false; + NiShader* srcShader = dynamic_cast(srcNif.GetBlock(srcGeom->shaderPropertyRef)); + if (srcShader) { + if (srcGeom->alphaPropertyRef != -1) + shaderAlpha = true; + CopyShader(shapeDest, srcGeom->shaderPropertyRef, srcNif, shaderAlpha); } vector srcBoneList; @@ -1343,7 +1341,6 @@ void NifFile::CopyGeometry(const string& shapeDest, NifFile& srcNif, const strin } hdr.blockSizes[0] = rootNode->CalcBlockSize(); - } int NifFile::Save(const string& filename) { @@ -1425,7 +1422,7 @@ void NifFile::RenameDuplicateShape(const string& dupedShape) { } void NifFile::SetNodeName(int blockID, const string& newName) { - NiNode* node = dynamic_cast(blocks[blockID]); + NiNode* node = dynamic_cast(GetBlock(blockID)); if (!node) return; @@ -1436,8 +1433,6 @@ void NifFile::SetNodeName(int blockID, const string& newName) { hdr.maxStringLen = newName.length(); } - - int NifFile::GetNodeID(const string& nodeName) { int id = -1; for (auto& block : blocks) { @@ -1501,11 +1496,10 @@ int NifFile::GetShapeBoneList(const string& shapeName, vector& outList) } } - if (skinRef == -1) return 0; - NiBoneContainer* skinInst = dynamic_cast(blocks[skinRef]); + NiBoneContainer* skinInst = dynamic_cast(GetBlock(skinRef)); if (!skinInst) return 0; @@ -1513,7 +1507,7 @@ int NifFile::GetShapeBoneList(const string& shapeName, vector& outList) for (int i = 0; i < skinInst->bones.size(); i++) { boneBlock = skinInst->bones[i]; if (boneBlock != -1) { - NiNode* node = (NiNode*)blocks[boneBlock]; + NiNode* node = (NiNode*)GetBlock(boneBlock); outList.push_back(node->name); } } @@ -1539,7 +1533,7 @@ int NifFile::GetShapeBoneIDList(const string& shapeName, vector& outList) { if (skinRef == -1) return 0; - NiBoneContainer* skinInst = dynamic_cast(blocks[skinRef]); + NiBoneContainer* skinInst = dynamic_cast(GetBlock(skinRef)); if (!skinInst) return 0; @@ -1562,10 +1556,9 @@ void NifFile::SetShapeBoneIDList(const string& shapeName, vector& inList) { BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { skinRef = siTriShape->skinInstanceRef; - BSSkinInstance * tmpskin = dynamic_cast(blocks[skinRef]); + BSSkinInstance * tmpskin = dynamic_cast(GetBlock(skinRef)); if (tmpskin) { - boneData = dynamic_cast(blocks[tmpskin->boneDataRef]); - + boneData = dynamic_cast(GetBlock(tmpskin->boneDataRef)); } } } @@ -1573,7 +1566,7 @@ void NifFile::SetShapeBoneIDList(const string& shapeName, vector& inList) { if (skinRef == -1) return; - NiBoneContainer* boneCont = dynamic_cast(blocks[skinRef]); + NiBoneContainer* boneCont = dynamic_cast(GetBlock(skinRef)); if (!boneCont) return; @@ -1582,9 +1575,10 @@ void NifFile::SetShapeBoneIDList(const string& shapeName, vector& inList) { bool feedBoneData = false; if (boneData && boneData->nBones != inList.size()) { // bone data array, clear it out if it doesn't match size boneData->nBones = 0; - boneData->boneXforms.clear(); + boneData->boneXforms.clear(); feedBoneData = true; } + for (int i = 0; i < inList.size(); i++) { boneCont->bones.push_back(inList[i]); boneCont->numBones++; @@ -1598,7 +1592,7 @@ void NifFile::SetShapeBoneIDList(const string& shapeName, vector& inList) { NiSkinInstance* skinInst = dynamic_cast(boneCont); if (skinInst) { - NiSkinData* skinData = (NiSkinData*)blocks[skinInst->dataRef]; + NiSkinData* skinData = (NiSkinData*)GetBlock(skinInst->dataRef); int nBonesToAdd = skinInst->bones.size() - skinData->numBones; if (nBonesToAdd > 0) { for (int i = 0; i < nBonesToAdd; i++) { @@ -1636,14 +1630,14 @@ int NifFile::GetShapeBoneWeights(const string& shapeName, int boneIndex, unorder if (skinRef == -1) return 0; - NiSkinInstance* skinInst = dynamic_cast(blocks[skinRef]); + NiSkinInstance* skinInst = dynamic_cast(GetBlock(skinRef)); if (!skinInst) return 0; if (skinInst->dataRef == -1) return 0; - NiSkinData* skinData = (NiSkinData*)blocks[skinInst->dataRef]; + NiSkinData* skinData = (NiSkinData*)GetBlock(skinInst->dataRef); if (boneIndex > skinData->numBones) return 0; @@ -1678,9 +1672,9 @@ bool NifFile::SetShapeBoneTransform(const string& shapeName, int boneIndex, Skin if (skinRef == -1) { return false; } - BSSkinInstance * tmpskin = dynamic_cast(blocks[skinRef]); + BSSkinInstance * tmpskin = dynamic_cast(GetBlock(skinRef)); if (tmpskin && boneIndex!=-1) { - BSSkinBoneData* bsskin = dynamic_cast(blocks[tmpskin->boneDataRef]); + BSSkinBoneData* bsskin = dynamic_cast(GetBlock(tmpskin->boneDataRef)); bsskin->boneXforms[boneIndex].boundSphereOffset = inSphereOffset; bsskin->boneXforms[boneIndex].boundSphereRadius = inSphereRadius; bsskin->boneXforms[boneIndex].boneTransform = inXform; @@ -1691,14 +1685,14 @@ bool NifFile::SetShapeBoneTransform(const string& shapeName, int boneIndex, Skin if (skinRef == -1) return false; - NiSkinInstance* skinInst = dynamic_cast(blocks[skinRef]); + NiSkinInstance* skinInst = dynamic_cast(GetBlock(skinRef)); if (!skinInst) return false; if (skinInst->dataRef == -1) return false; - NiSkinData* skinData = (NiSkinData*)blocks[skinInst->dataRef]; + NiSkinData* skinData = (NiSkinData*)GetBlock(skinInst->dataRef); if (boneIndex == -1) { // Set the overall skin transform skinData->skinTransform = inXform; @@ -1726,13 +1720,13 @@ bool NifFile::GetShapeBoneTransform(const string& shapeName, int boneIndex, Skin if (siTriShape) { skinRef = siTriShape->skinInstanceRef; if (skinRef != -1) { - int dataref = dynamic_cast(blocks[skinRef])->boneDataRef; + int dataref = dynamic_cast(GetBlock(skinRef))->boneDataRef; if (dataref != -1) { if (boneIndex == -1) { // overall skin transform not found in fo4 meshes :( return false; } - BSSkinBoneData* bd = dynamic_cast(blocks[dataref]); + BSSkinBoneData* bd = dynamic_cast(GetBlock(dataref)); outXform = bd->boneXforms[boneIndex].boneTransform; outSphereOffset = bd->boneXforms[boneIndex].boundSphereOffset; outSphereRadius = bd->boneXforms[boneIndex].boundSphereRadius; @@ -1747,14 +1741,14 @@ bool NifFile::GetShapeBoneTransform(const string& shapeName, int boneIndex, Skin if (skinRef == -1) return false; - NiSkinInstance* skinInst = dynamic_cast(blocks[skinRef]); + NiSkinInstance* skinInst = dynamic_cast(GetBlock(skinRef)); if (!skinInst) return false; if (skinInst->dataRef == -1) return false; - NiSkinData* skinData = (NiSkinData*)blocks[skinInst->dataRef]; + NiSkinData* skinData = (NiSkinData*)GetBlock(skinInst->dataRef); if (boneIndex == -1) { // Want the overall skin transform outXform = skinData->skinTransform; @@ -1784,7 +1778,7 @@ void NifFile::UpdateShapeBoneID(const string& shapeName, int oldID, int newID) { if (siTriShape) { skinRef = siTriShape->skinInstanceRef; if (skinRef != -1) { - for (auto& b : dynamic_cast(blocks[skinRef])->bones) { + for (auto& b : dynamic_cast(GetBlock(skinRef))->bones) { if (b == oldID) b = newID; } @@ -1795,7 +1789,7 @@ void NifFile::UpdateShapeBoneID(const string& shapeName, int oldID, int newID) { if (skinRef == -1) return; - NiSkinInstance* skinInst = dynamic_cast(blocks[skinRef]); + NiSkinInstance* skinInst = dynamic_cast(GetBlock(skinRef)); if (!skinInst) return; @@ -1821,14 +1815,14 @@ void NifFile::SetShapeBoneWeights(const string& shapeName, int boneIndex, unorde if (skinRef == -1) return; - NiSkinInstance* skinInst = dynamic_cast(blocks[skinRef]); + NiSkinInstance* skinInst = dynamic_cast(GetBlock(skinRef)); if (!skinInst) return; if (skinInst->dataRef == -1) return; - NiSkinData* skinData = (NiSkinData*)blocks[skinInst->dataRef]; + NiSkinData* skinData = (NiSkinData*)GetBlock(skinInst->dataRef); if (boneIndex > skinData->numBones) return; @@ -1843,14 +1837,13 @@ void NifFile::SetShapeBoneWeights(const string& shapeName, int boneIndex, unorde } void NifFile::SetShapeVertWeights(const string& shapeName, int vertIndex, vector& boneids, vector& weights) { - - BSTriShape* trishape = geomForNameF4(shapeName); - if (!trishape) { + BSTriShape* siTriShape = geomForNameF4(shapeName); + if (!siTriShape) { return; } - memset(trishape->vertData[vertIndex].weights, 0, sizeof(float)* 4); - memset(trishape->vertData[vertIndex].weightBones, 0, sizeof(unsigned char) * 4); + memset(siTriShape->vertData[vertIndex].weights, 0, sizeof(float) * 4); + memset(siTriShape->vertData[vertIndex].weightBones, 0, sizeof(unsigned char) * 4); // sum weights to normalize weight values float sum = 0.0f; @@ -1860,11 +1853,10 @@ void NifFile::SetShapeVertWeights(const string& shapeName, int vertIndex, vector int num = (weights.size() < 4 ? weights.size() : 4); - for (int i= 0; i vertData[vertIndex].weightBones[i] = boneids[i]; - trishape->vertData[vertIndex].weights[i] = weights[i] / sum; + for (int i = 0; i < num; i++) { + siTriShape->vertData[vertIndex].weightBones[i] = boneids[i]; + siTriShape->vertData[vertIndex].weights[i] = weights[i] / sum; } - } const vector* NifFile::GetRawVertsForShape(const string& shapeName) { @@ -1873,11 +1865,11 @@ const vector* NifFile::GetRawVertsForShape(const string& shapeName) { if (dataRef == -1) return nullptr; if (bType == NITRISHAPEDATA || bType == NITRISTRIPSDATA) { - NiTriBasedGeomData* geomData = static_cast(blocks[dataRef]); + NiTriBasedGeomData* geomData = static_cast(GetBlock(dataRef)); return &geomData->vertices; } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - BSTriShape* siTriShape = static_cast(blocks[dataRef]); + BSTriShape* siTriShape = static_cast(GetBlock(dataRef)); return siTriShape->GetRawVerts(); } return nullptr; @@ -1890,17 +1882,17 @@ bool NifFile::GetTrisForShape(const string& shapeName, vector* outTris return false; if (bType == NITRISHAPEDATA) { - NiTriShapeData* shapeData = static_cast(blocks[dataID]); + NiTriShapeData* shapeData = static_cast(GetBlock(dataID)); *outTris = shapeData->triangles; return true; } else if (bType == NITRISTRIPSDATA) { - NiTriStripsData* stripsData = static_cast(blocks[dataID]); + NiTriStripsData* stripsData = static_cast(GetBlock(dataID)); stripsData->StripsToTris(outTris); return true; } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - BSTriShape* shapeData = static_cast(blocks[dataID]); + BSTriShape* shapeData = static_cast(GetBlock(dataID)); *outTris = shapeData->triangles; return true; @@ -1915,18 +1907,17 @@ const vector* NifFile::GetNormalsForShape(const string& shapeName, bool return nullptr; if (bType == NITRISHAPEDATA) { - NiTriShapeData* shapeData = (NiTriShapeData*)blocks[dataID]; + NiTriShapeData* shapeData = (NiTriShapeData*)GetBlock(dataID); if (shapeData->hasNormals) return &shapeData->normals; } else if (bType == NITRISTRIPSDATA) { - NiTriStripsData* stripsData = (NiTriStripsData*)blocks[dataID]; + NiTriStripsData* stripsData = (NiTriStripsData*)GetBlock(dataID); if (stripsData->hasNormals) return &stripsData->normals; } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - // NOT IMPLEMENTED - BSTriShape* shapeData = (BSTriShape*)(blocks[dataID]); + BSTriShape* shapeData = (BSTriShape*)(GetBlock(dataID)); return shapeData->GetNormalData(transform); } @@ -1946,8 +1937,7 @@ const vector* NifFile::GetTangentsForShape(const string& shapeName, boo return nullptr; } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - // NOT IMPLEMENTED - BSTriShape* shapeData = (BSTriShape*)(blocks[dataID]); + BSTriShape* shapeData = (BSTriShape*)(GetBlock(dataID)); return shapeData->GetTangentData(transform); } @@ -1967,8 +1957,7 @@ const vector* NifFile::GetBitangentsForShape(const string& shapeName, b return nullptr; } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - // NOT IMPLEMENTED - BSTriShape* shapeData = (BSTriShape*)(blocks[dataID]); + BSTriShape* shapeData = (BSTriShape*)(GetBlock(dataID)); return shapeData->GetBitangentData(transform); } @@ -1982,17 +1971,17 @@ const vector* NifFile::GetUvsForShape(const string& shapeName) { return nullptr; if (bType == NITRISHAPEDATA) { - NiTriShapeData* shapeData = (NiTriShapeData*)blocks[dataID]; + NiTriShapeData* shapeData = (NiTriShapeData*)GetBlock(dataID); if (shapeData->numUVSets > 0) return &shapeData->uvSets; } else if (bType == NITRISTRIPSDATA) { - NiTriStripsData* stripsData = (NiTriStripsData*)blocks[dataID]; + NiTriStripsData* stripsData = (NiTriStripsData*)GetBlock(dataID); if (stripsData->numUVSets > 0) return &stripsData->uvSets; } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - BSTriShape* shapeData = (BSTriShape*)(blocks[dataID]); + BSTriShape* shapeData = (BSTriShape*)(GetBlock(dataID)); return shapeData->GetUVData(); } @@ -2006,12 +1995,12 @@ bool NifFile::GetUvsForShape(const string& shapeName, vector& outUvs) { return false; if (bType == NITRISHAPEDATA) { - NiTriShapeData* shapeData = (NiTriShapeData*)blocks[dataID]; + NiTriShapeData* shapeData = (NiTriShapeData*)GetBlock(dataID); outUvs.assign(shapeData->uvSets.begin(), shapeData->uvSets.end()); return true; } else if (bType == NITRISTRIPSDATA) { - NiTriStripsData* stripsData = (NiTriStripsData*)blocks[dataID]; + NiTriStripsData* stripsData = (NiTriStripsData*)GetBlock(dataID); outUvs.assign(stripsData->uvSets.begin(), stripsData->uvSets.end()); return true; } @@ -2031,11 +2020,11 @@ const vector>* NifFile::GetSeamVertsForShape(const string& shapeName return nullptr; if (bType == NITRISHAPEDATA) { - //NiTriShapeData* shapeData = (NiTriShapeData*)blocks[dataID]; + //NiTriShapeData* shapeData = (NiTriShapeData*)GetBlock(dataID); // dosomthin } else if (bType == NITRISTRIPSDATA) { - //NiTriStripsData* stripsData = (NiTriStripsData*)blocks[dataID]; + //NiTriStripsData* stripsData = (NiTriStripsData*)GetBlock(dataID); // dosomthin } else if (bType == BSSUBINDEXTRISHAPE|| bType == BSTRISHAPE) { @@ -2053,19 +2042,19 @@ bool NifFile::GetVertsForShape(const string& shapeName, vector& outVert return false; if (bType == NITRISHAPEDATA) { - NiTriShapeData* shapeData = static_cast(blocks[dataRef]); + NiTriShapeData* shapeData = static_cast(GetBlock(dataRef)); for (auto &v : shapeData->vertices) outVerts.push_back(v); return true; } else if (bType == NITRISTRIPSDATA) { - NiTriStripsData* stripsData = static_cast(blocks[dataRef]); + NiTriStripsData* stripsData = static_cast(GetBlock(dataRef)); for (auto &v : stripsData->vertices) outVerts.push_back(v); return true; } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - BSTriShape* siTriShape = static_cast(blocks[dataRef]); + BSTriShape* siTriShape = static_cast(GetBlock(dataRef)); for (auto &v : siTriShape->vertData) outVerts.push_back(v.vert); return true; @@ -2081,17 +2070,17 @@ int NifFile::GetVertCountForShape(const string& shapeName) { return -1; if (bType == NITRISHAPEDATA) { - NiTriShapeData* shapeData = static_cast(blocks[dataID]); + NiTriShapeData* shapeData = static_cast(GetBlock(dataID)); if (shapeData) return shapeData->numVertices; } else if (bType == NITRISTRIPSDATA) { - NiTriStripsData* stripsData = static_cast(blocks[dataID]); + NiTriStripsData* stripsData = static_cast(GetBlock(dataID)); if (stripsData) return stripsData->numVertices; } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - BSTriShape* siTriShape = static_cast(blocks[dataID]); + BSTriShape* siTriShape = static_cast(GetBlock(dataID)); return siTriShape->numverts; } @@ -2105,7 +2094,7 @@ void NifFile::SetVertsForShape(const string& shapeName, const vector& v return; if (bType == NITRISHAPEDATA) { - NiTriShapeData* shapeData = static_cast(blocks[dataID]); + NiTriShapeData* shapeData = static_cast(GetBlock(dataID)); if (verts.size() != shapeData->vertices.size()) return; @@ -2113,7 +2102,7 @@ void NifFile::SetVertsForShape(const string& shapeName, const vector& v shapeData->vertices[i] = verts[i]; } else if (bType == NITRISTRIPSDATA) { - NiTriStripsData* stripsData = static_cast(blocks[dataID]); + NiTriStripsData* stripsData = static_cast(GetBlock(dataID)); if (verts.size() != stripsData->vertices.size()) return; @@ -2121,7 +2110,7 @@ void NifFile::SetVertsForShape(const string& shapeName, const vector& v stripsData->vertices[i] = verts[i]; } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - BSTriShape* siTriShape = static_cast(blocks[dataID]); + BSTriShape* siTriShape = static_cast(GetBlock(dataID)); if (verts.size() != siTriShape->numverts) { return; } @@ -2139,20 +2128,20 @@ void NifFile::SetUvsForShape(const string& shapeName, const vector& uvs return; if (bType == NITRISHAPEDATA) { - NiTriShapeData* shapeData = static_cast(blocks[dataID]); + NiTriShapeData* shapeData = static_cast(GetBlock(dataID)); if (uvs.size() != shapeData->vertices.size()) return; shapeData->uvSets.assign(uvs.begin(), uvs.end()); } else if (bType == NITRISTRIPSDATA) { - NiTriStripsData* stripsData = static_cast(blocks[dataID]); + NiTriStripsData* stripsData = static_cast(GetBlock(dataID)); if (uvs.size() != stripsData->vertices.size()) return; stripsData->uvSets.assign(uvs.begin(), uvs.end()); } if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - BSTriShape* siTriShape = static_cast(blocks[dataID]); + BSTriShape* siTriShape = static_cast(GetBlock(dataID)); if (uvs.size() != siTriShape->numverts) { return; } @@ -2171,7 +2160,7 @@ void NifFile::SetNormalsForShape(const string& shapeName, const vector& return; if (bType == NITRISHAPEDATA) { - NiTriShapeData* shapeData = (NiTriShapeData*)blocks[dataID]; + NiTriShapeData* shapeData = (NiTriShapeData*)GetBlock(dataID); if (norms.size() != shapeData->normals.size()) shapeData->normals.resize(norms.size()); for (int i = 0; i < shapeData->vertices.size(); i++) @@ -2181,7 +2170,7 @@ void NifFile::SetNormalsForShape(const string& shapeName, const vector& hdr.blockSizes[dataID] = shapeData->CalcBlockSize(); } else if (bType == NITRISTRIPSDATA) { - NiTriStripsData* stripsData = (NiTriStripsData*)blocks[dataID]; + NiTriStripsData* stripsData = (NiTriStripsData*)GetBlock(dataID); if (norms.size() != stripsData->normals.size()) stripsData->normals.resize(norms.size()); for (int i = 0; i < stripsData->vertices.size(); i++) @@ -2191,7 +2180,7 @@ void NifFile::SetNormalsForShape(const string& shapeName, const vector& hdr.blockSizes[dataID] = stripsData->CalcBlockSize(); } if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - BSTriShape* shape = (BSTriShape*)blocks[dataID]; + BSTriShape* shape = (BSTriShape*)GetBlock(dataID); shape->setNormals(norms); } } @@ -2203,17 +2192,17 @@ void NifFile::CalcTangentsForShape(const string& shapeName) { return; if (bType == NITRISHAPEDATA) { - NiTriShapeData* shapeData = (NiTriShapeData*)blocks[dataID]; + NiTriShapeData* shapeData = (NiTriShapeData*)GetBlock(dataID); shapeData->CalcTangentSpace(); hdr.blockSizes[dataID] = shapeData->CalcBlockSize(); } else if (bType == NITRISTRIPSDATA) { - NiTriStripsData* stripsData = (NiTriStripsData*)blocks[dataID]; + NiTriStripsData* stripsData = (NiTriStripsData*)GetBlock(dataID); stripsData->CalcTangentSpace(); hdr.blockSizes[dataID] = stripsData->CalcBlockSize(); } if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - BSTriShape* shape = (BSTriShape*)blocks[dataID]; + BSTriShape* shape = (BSTriShape*)GetBlock(dataID); shape->SetTangentData(); } } @@ -2231,7 +2220,7 @@ void NifFile::CalcTangentsForShape(const string& shapeName, vector** ou return; } if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - BSTriShape* shape = (BSTriShape*)blocks[dataID]; + BSTriShape* shape = (BSTriShape*)GetBlock(dataID); shape->calcTangentSpace(outNormals, outTagents, outBitangents, transform); } } @@ -2354,7 +2343,7 @@ void NifFile::ApplyShapeTranslation(const string& shapeName, const Vector3& offs if (!geom) return; - NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); + NiTriBasedGeomData* geomData = dynamic_cast(GetBlock(dataRef)); if (!geomData) return; @@ -2364,7 +2353,7 @@ void NifFile::ApplyShapeTranslation(const string& shapeName, const Vector3& offs geom->translation = Vector3(0.0f, 0.0f, 0.0f); } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - BSTriShape* geom = dynamic_cast(blocks[dataRef]); + BSTriShape* geom = dynamic_cast(GetBlock(dataRef)); if (!geom) return; @@ -2381,14 +2370,13 @@ void NifFile::MoveVertex(const string& shapeName, const Vector3& pos, const int& if (dataRef == -1) return; - if (bType == NITRISHAPEDATA || bType == NITRISTRIPSDATA) { - NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); + NiTriBasedGeomData* geomData = dynamic_cast(GetBlock(dataRef)); if (geomData && geomData->numVertices > id) geomData->vertices[id] = pos; } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - BSTriShape* geom = dynamic_cast(blocks[dataRef]); + BSTriShape* geom = dynamic_cast(GetBlock(dataRef)); if (geom && geom->numverts > id) geom->vertData[id].vert = pos; } @@ -2401,7 +2389,7 @@ void NifFile::OffsetShape(const string& shapeName, const Vector3& offset, unorde return; if (bType == NITRISHAPEDATA || bType == NITRISTRIPSDATA) { - NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); + NiTriBasedGeomData* geomData = dynamic_cast(GetBlock(dataRef)); if (!geomData) return; @@ -2420,7 +2408,7 @@ void NifFile::OffsetShape(const string& shapeName, const Vector3& offset, unorde } } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - BSTriShape* geomData = dynamic_cast(blocks[dataRef]); + BSTriShape* geomData = dynamic_cast(GetBlock(dataRef)); if (!geomData) return; @@ -2438,7 +2426,6 @@ void NifFile::OffsetShape(const string& shapeName, const Vector3& offset, unorde geomData->vertData[i].vert += offset; } } - } void NifFile::ScaleShape(const string& shapeName, const float& scale, unordered_map* mask) { @@ -2451,11 +2438,10 @@ void NifFile::ScaleShape(const string& shapeName, const float& scale, unordered_ GetRootTranslation(root); if (bType == NITRISHAPEDATA || bType == NITRISTRIPSDATA) { - NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); + NiTriBasedGeomData* geomData = dynamic_cast(GetBlock(dataRef)); if (!geomData) return; - unordered_map diff; for (int i = 0; i < geomData->vertices.size(); i++) { Vector3 target = geomData->vertices[i] - root; @@ -2471,14 +2457,13 @@ void NifFile::ScaleShape(const string& shapeName, const float& scale, unordered_ } } geomData->vertices[i] = target; - } + } } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - BSTriShape* geomData = dynamic_cast(blocks[dataRef]); + BSTriShape* geomData = dynamic_cast(GetBlock(dataRef)); if (!geomData) return; - unordered_map diff; for (int i = 0; i < geomData->numverts; i++) { Vector3 target = geomData->vertData[i].vert - root; @@ -2496,7 +2481,6 @@ void NifFile::ScaleShape(const string& shapeName, const float& scale, unordered_ geomData->vertData[i].vert = target; } } - } void NifFile::RotateShape(const string& shapeName, const Vector3& angle, unordered_map* mask) { @@ -2508,11 +2492,10 @@ void NifFile::RotateShape(const string& shapeName, const Vector3& angle, unorder Vector3 root; GetRootTranslation(root); if (bType == NITRISHAPEDATA || bType == NITRISTRIPSDATA) { - NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); + NiTriBasedGeomData* geomData = dynamic_cast(GetBlock(dataRef)); if (!geomData) return; - unordered_map diff; for (int i = 0; i < geomData->vertices.size(); i++) { Vector3 target = geomData->vertices[i] - root; @@ -2535,13 +2518,12 @@ void NifFile::RotateShape(const string& shapeName, const Vector3& angle, unorder } } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { - BSTriShape* geomData = dynamic_cast(blocks[dataRef]); + BSTriShape* geomData = dynamic_cast(GetBlock(dataRef)); if (!geomData) return; - unordered_map diff; - for (int i = 0; i < geomData->numverts ; i++) { + for (int i = 0; i < geomData->numverts; i++) { Vector3 target = geomData->vertData[i].vert - root; Matrix4 mat; mat.Rotate(angle.x * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f)); @@ -2561,7 +2543,6 @@ void NifFile::RotateShape(const string& shapeName, const Vector3& angle, unorder geomData->vertData[i].vert = target; } } - } bool NifFile::GetAlphaForShape(const string& shapeName, ushort& outFlags, byte& outThreshold) { @@ -2582,9 +2563,8 @@ bool NifFile::GetAlphaForShape(const string& shapeName, ushort& outFlags, byte& } else { BSTriShape* siTriShape = geomForNameF4(shapeName); - if (siTriShape) { - //alphaRef = siTriShape->alphaPropertyRef; - } + if (siTriShape) + alphaRef = siTriShape->alphaPropertyRef; } if (alphaRef == -1) @@ -2643,7 +2623,24 @@ void NifFile::SetAlphaForShape(const string& shapeName, ushort flags, ushort thr else { BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { - //alphaRef = siTriShape->alphaPropertyRef; + alphaRef = siTriShape->alphaPropertyRef; + if (alphaRef == -1) { + NiShader* shader = GetShader(shapeName); + if (!shader) + return; + + alphaRef = blocks.size(); + + NiAlphaProperty* alphaProp = new NiAlphaProperty(hdr); + siTriShape->alphaPropertyRef = alphaRef; + + blocks.push_back(alphaProp); + hdr.numBlocks++; + hdr.blockSizes.push_back(alphaProp->CalcBlockSize()); + + ushort alphaBlockTypeId = AddOrFindBlockTypeId("NiAlphaProperty"); + hdr.blockIndex.push_back(alphaBlockTypeId); + } } } @@ -2709,6 +2706,9 @@ void NifFile::DeleteShape(const string& shapeName) { DeleteBlock(siTriShape->shaderPropertyRef); } + if (siTriShape->alphaPropertyRef != -1) + DeleteBlock(siTriShape->alphaPropertyRef); + BSSkinInstance* bsSkinInst = dynamic_cast(GetBlock(siTriShape->skinInstanceRef)); if (bsSkinInst) { DeleteBlock(bsSkinInst->boneDataRef); @@ -2756,11 +2756,23 @@ void NifFile::DeleteShader(const string& shapeName) { } } else { - // Not IMplemented BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { - if (siTriShape->skinInstanceRef != -1) { - + if (siTriShape->shaderPropertyRef != -1) { + NiShader* shader = dynamic_cast(GetBlock(siTriShape->shaderPropertyRef)); + if (shader) { + DeleteBlock(shader->GetTextureSetRef()); + DeleteBlock(siTriShape->shaderPropertyRef); + siTriShape->shaderPropertyRef = -1; + } + + if (siTriShape->alphaPropertyRef != -1) { + NiAlphaProperty* alpha = dynamic_cast(GetBlock(siTriShape->alphaPropertyRef)); + if (alpha) { + DeleteBlock(siTriShape->alphaPropertyRef); + siTriShape->alphaPropertyRef = -1; + } + } } } } @@ -2788,10 +2800,15 @@ void NifFile::DeleteAlpha(const string& shapeName) { } } else { - // Not IMplemented BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { - //alphaRef = siTriShape->alphaPropertyRef; + if (siTriShape->alphaPropertyRef != -1) { + NiAlphaProperty* alpha = dynamic_cast(GetBlock(siTriShape->alphaPropertyRef)); + if (alpha) { + DeleteBlock(siTriShape->alphaPropertyRef); + siTriShape->alphaPropertyRef = -1; + } + } } } } @@ -2809,7 +2826,7 @@ void NifFile::DeleteVertsForShape(const string& shapeName, const vector& skinRef = geom->skinInstanceRef; if (dataRef != -1) { - NiTriBasedGeomData* geomData = dynamic_cast(blocks[dataRef]); + NiTriBasedGeomData* geomData = dynamic_cast(GetBlock(dataRef)); if (geomData) { geomData->notifyVerticesDelete(indices); if (geomData->numVertices == 0 || geomData->numTriangles == 0) { @@ -2837,13 +2854,13 @@ void NifFile::DeleteVertsForShape(const string& shapeName, const vector& if (skinRef == -1) return; - NiSkinInstance* skinInst = dynamic_cast(blocks[skinRef]); + NiSkinInstance* skinInst = dynamic_cast(GetBlock(skinRef)); if (skinInst) { - NiSkinData* skinData = (NiSkinData*)blocks[skinInst->dataRef]; + NiSkinData* skinData = (NiSkinData*)GetBlock(skinInst->dataRef); skinData->notifyVerticesDelete(indices); hdr.blockSizes[skinInst->dataRef] = skinData->CalcBlockSize(); - NiSkinPartition* skinPartition = (NiSkinPartition*)blocks[skinInst->skinPartitionRef]; + NiSkinPartition* skinPartition = (NiSkinPartition*)GetBlock(skinInst->skinPartitionRef); skinPartition->notifyVerticesDelete(indices); vector emptyIndices; if (skinPartition->RemoveEmptyPartitions(emptyIndices)) { @@ -2908,10 +2925,10 @@ void NifFile::UpdateSkinPartitions(const string& shapeName) { NiSkinData* skinData = nullptr; NiSkinPartition* skinPart = nullptr; - NiSkinInstance* skinInst = dynamic_cast(blocks[skinRef]); + NiSkinInstance* skinInst = dynamic_cast(GetBlock(skinRef)); if (skinInst) { - skinData = (NiSkinData*)blocks[skinInst->dataRef]; - skinPart = (NiSkinPartition*)blocks[skinInst->skinPartitionRef]; + skinData = (NiSkinData*)GetBlock(skinInst->dataRef); + skinPart = (NiSkinPartition*)GetBlock(skinInst->skinPartitionRef); } else return; @@ -3031,7 +3048,7 @@ void NifFile::BuildSkinPartitions(const string& shapeName, int maxBonesPerPartit NiTriStripsData* stripsData = nullptr; if (bType == NITRISHAPEDATA) { skinRef = geom->skinInstanceRef; - shapeData = (NiTriShapeData*)blocks[geom->dataRef]; + shapeData = (NiTriShapeData*)GetBlock(geom->dataRef); if (skinRef == -1) { NiSkinData* nifSkinData = new NiSkinData(hdr); int skinDataID = AddBlock((NiObject*)nifSkinData, "NiSkinData"); @@ -3054,7 +3071,7 @@ void NifFile::BuildSkinPartitions(const string& shapeName, int maxBonesPerPartit return; skinRef = geom->skinInstanceRef; - stripsData = (NiTriStripsData*)blocks[geom->dataRef]; + stripsData = (NiTriStripsData*)GetBlock(geom->dataRef); if (skinRef == -1) { NiSkinData* nifSkinData = new NiSkinData(hdr); int skinDataID = AddBlock((NiObject*)nifSkinData, "NiSkinData"); @@ -3075,10 +3092,10 @@ void NifFile::BuildSkinPartitions(const string& shapeName, int maxBonesPerPartit NiSkinData* skinData = nullptr; NiSkinPartition* skinPart = nullptr; - NiSkinInstance* skinInst = dynamic_cast(blocks[skinRef]); + NiSkinInstance* skinInst = dynamic_cast(GetBlock(skinRef)); if (skinInst) { - skinData = (NiSkinData*)blocks[skinInst->dataRef]; - skinPart = (NiSkinPartition*)blocks[skinInst->skinPartitionRef]; + skinData = (NiSkinData*)GetBlock(skinInst->dataRef); + skinPart = (NiSkinPartition*)GetBlock(skinInst->skinPartitionRef); } else return; diff --git a/NifFile.h b/NifFile.h index 800507fa..684016dc 100644 --- a/NifFile.h +++ b/NifFile.h @@ -963,6 +963,8 @@ class NiShader : public NiProperty { virtual void SetEmissiveColor(Color4 color); virtual float GetEmissiveMultiple(); virtual void SetEmissiveMultiple(float emissive); + virtual uint GetWetMaterialNameRef(); + virtual void SetWetMaterialNameRef(uint matRef); virtual int CalcBlockSize(); }; @@ -1031,6 +1033,8 @@ class BSLightingShaderProperty : public NiShader { void SetEmissiveColor(Color4 color); float GetEmissiveMultiple(); void SetEmissiveMultiple(float emissive); + uint GetWetMaterialNameRef(); + void SetWetMaterialNameRef(uint matRef); int CalcBlockSize(); }; @@ -1144,10 +1148,6 @@ class NiAlphaProperty : public NiProperty { ushort flags; byte threshold; - uint unkRef; - uint unk1; - uint unk2; - NiAlphaProperty(NiHeader& hdr); NiAlphaProperty(fstream& file, NiHeader& hdr); diff --git a/ShapeProperties.cpp b/ShapeProperties.cpp index a4a7165b..958a28f0 100644 --- a/ShapeProperties.cpp +++ b/ShapeProperties.cpp @@ -186,29 +186,41 @@ void ShapeProperties::OnAddShader(wxCommandEvent& WXUNUSED(event)) { void ShapeProperties::AddShader() { NiTriBasedGeom* geom = nif->geomForName(shape); - if (!geom) - return; - - switch (os->targetGame) { - case FO3: - case FONV: { - BSShaderPPLightingProperty* shader = new BSShaderPPLightingProperty(nif->hdr); - geom->propertiesRef.push_back(nif->AddBlock(shader, "BSShaderPPLightingProperty")); - geom->numProperties++; - - NiMaterialProperty* material = new NiMaterialProperty(nif->hdr); - geom->propertiesRef.push_back(nif->AddBlock(material, "NiMaterialProperty")); - geom->numProperties++; - break; + if (geom) { + switch (os->targetGame) { + case FO3: + case FONV: { + BSShaderPPLightingProperty* shader = new BSShaderPPLightingProperty(nif->hdr); + geom->propertiesRef.push_back(nif->AddBlock(shader, "BSShaderPPLightingProperty")); + geom->numProperties++; + + NiMaterialProperty* material = new NiMaterialProperty(nif->hdr); + geom->propertiesRef.push_back(nif->AddBlock(material, "NiMaterialProperty")); + geom->numProperties++; + break; + } + case SKYRIM: + default: { + BSLightingShaderProperty* shader = new BSLightingShaderProperty(nif->hdr); + geom->propertiesRef1 = nif->AddBlock(shader, "BSLightingShaderProperty"); + } } - case SKYRIM: - case FO4: - default: { - BSLightingShaderProperty* shader = new BSLightingShaderProperty(nif->hdr); - geom->propertiesRef1 = nif->AddBlock(shader, "BSLightingShaderProperty"); + } + else { + BSTriShape* siTriShape = nif->geomForNameF4(shape); + if (!siTriShape) + return; + + switch (os->targetGame) { + case FO4: + default: { + BSLightingShaderProperty* shader = new BSLightingShaderProperty(nif->hdr); + siTriShape->shaderPropertyRef = nif->AddBlock(shader, "BSLightingShaderProperty"); + } } } + NiShader* shader = nif->GetShader(shape); if (shader) { BSShaderTextureSet* nifTexSet = new BSShaderTextureSet(nif->hdr); @@ -227,6 +239,7 @@ void ShapeProperties::RemoveShader() { nif->DeleteShader(shape); AssignDefaultTexture(); GetShader(); + GetTransparency(); } void ShapeProperties::OnSetTextures(wxCommandEvent& WXUNUSED(event)) { From 9c2b27bbf195e49692d438d73afeca3902db0d9d Mon Sep 17 00:00:00 2001 From: ousnius Date: Mon, 14 Dec 2015 00:28:02 +0100 Subject: [PATCH 49/64] Implemented BSTS vertex deletion, tmp fix for normals matching sliders --- BodySlideApp.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++++++-- NifBlock.cpp | 40 +++++++++++++++++++++++- NifFile.cpp | 5 ++- 3 files changed, 122 insertions(+), 4 deletions(-) diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index 0b93fd94..cfefcf27 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -690,7 +690,8 @@ void BodySlideApp::UpdatePreview() { vertsLow = verts; ApplySliders(it->first, sliderManager.slidersBig, vertsHigh, zapIdx, &uv); - ApplySliders(it->first, sliderManager.slidersSmall, vertsLow, zapIdx, &uv); + if (activeSet.GenWeights()) + ApplySliders(it->first, sliderManager.slidersSmall, vertsLow, zapIdx, &uv); // Calculate result of weight for (int i = 0; i < verts.size(); i++) @@ -738,7 +739,8 @@ void BodySlideApp::RebuildPreviewMeshes() { vertsLow = verts; ApplySliders(it->first, sliderManager.slidersBig, vertsHigh, zapIdx); - ApplySliders(it->first, sliderManager.slidersSmall, vertsLow, zapIdx); + if (activeSet.GenWeights()) + ApplySliders(it->first, sliderManager.slidersSmall, vertsLow, zapIdx); // Calculate result of weight for (int i = 0; i < verts.size(); i++) @@ -1203,6 +1205,81 @@ int BodySlideApp::BuildBodies(bool localPath, bool clean, bool tri) { nifSmall.DeleteVertsForShape(it->second, zapIdx); nifBig.SetVertsForShape(it->second, vertsHigh); + if (targetGame == FO4) { + // Temp Fix + vector tris; + nifBig.GetTrisForShape(it->second, &tris); + + Vector3 norm; + float scale = 0.1f; + mesh* m = new mesh(); + + m->nVerts = vertsHigh.size(); + m->verts = new Vertex[m->nVerts]; + + m->nTris = tris.size(); + m->tris = new Triangle[m->nTris]; + + for (int i = 0; i < m->nVerts; i++) { + m->verts[i].x = vertsHigh[i].x * -scale; + m->verts[i].z = vertsHigh[i].y * scale; + m->verts[i].y = vertsHigh[i].z * scale; + m->verts[i].indexRef = i; + } + + // Load tris. Also sum face normals here. + for (int j = 0; j < m->nTris; j++) { + Vector3 norm; + m->tris[j].p1 = tris[j].p1; + m->tris[j].p2 = tris[j].p2; + m->tris[j].p3 = tris[j].p3; + m->tris[j].trinormal(m->verts, &norm); + m->verts[m->tris[j].p1].nx += norm.x; + m->verts[m->tris[j].p1].ny += norm.y; + m->verts[m->tris[j].p1].nz += norm.z; + m->verts[m->tris[j].p2].nx += norm.x; + m->verts[m->tris[j].p2].ny += norm.y; + m->verts[m->tris[j].p2].nz += norm.z; + m->verts[m->tris[j].p3].nx += norm.x; + m->verts[m->tris[j].p3].ny += norm.y; + m->verts[m->tris[j].p3].nz += norm.z; + } + + // Normalize all vertex normals to smooth them out. + for (int i = 0; i < m->nVerts; i++) { + Vector3* pn = (Vector3*)&m->verts[i].nx; + pn->Normalize(); + } + + kd_matcher matcher(m->verts, m->nVerts); + for (int i = 0; i < matcher.matches.size(); i++) { + Vertex* a = matcher.matches[i].first; + Vertex* b = matcher.matches[i].second; + m->weldVerts[a->indexRef].push_back(b->indexRef); + m->weldVerts[b->indexRef].push_back(a->indexRef); + + if (m->smoothSeamNormals) { + float dot = (a->nx * b->nx + a->ny * b->ny + a->nz * b->nz); + if (dot < 1.57079633f) { + a->nx = ((a->nx + b->nx) / 2.0f); + a->ny = ((a->ny + b->ny) / 2.0f); + a->nz = ((a->nz + b->nz) / 2.0f); + b->nx = a->nx; + b->ny = a->ny; + b->nz = a->nz; + } + } + } + + m->SmoothNormals(); + + vector newNorms; + for (int i = 0; i < m->nVerts; i++) + newNorms.push_back(Vector3(-m->verts[i].nx, m->verts[i].nz, m->verts[i].ny)); + + nifBig.SetNormalsForShape(it->second, newNorms); + delete m; + } nifBig.DeleteVertsForShape(it->second, zapIdx); zapIdxAll[it->second] = zapIdx; diff --git a/NifBlock.cpp b/NifBlock.cpp index d2d3ebd4..dcd981f9 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -854,7 +854,45 @@ void BSTriShape::notifyBlockSwap(int blockIndexLo, int blockIndexHi) { } void BSTriShape::notifyVerticesDelete(const vector& vertIndices) { - //Implement + vector indexCollapse(vertData.size(), 0); + vector indexCollapseTris(vertData.size(), 0); + + for (int i = 0, j = 0; i < indexCollapse.size(); i++) { + if (j < vertIndices.size() && vertIndices[j] == i) { // Found one to remove + indexCollapse[i] = -1; // Flag delete + j++; + } + } + + int remCount = 0; + for (int i = 0, j = 0; i < indexCollapseTris.size(); i++) { + if (j < vertIndices.size() && vertIndices[j] == i) { // Found one to remove + indexCollapseTris[i] = -1; // Flag delete + remCount++; + j++; + } + else + indexCollapseTris[i] = remCount; + } + + for (int i = vertData.size() - 1; i >= 0; i--) { + if (indexCollapse[i] == -1) { + vertData.erase(vertData.begin() + i); + numverts--; + } + } + + for (int i = numTris - 1; i >= 0; i--) { + if (indexCollapseTris[triangles[i].p1] == -1 || indexCollapseTris[triangles[i].p2] == -1 || indexCollapseTris[triangles[i].p3] == -1) { + triangles.erase(triangles.begin() + i); + numTris--; + } + else { + triangles[i].p1 = triangles[i].p1 - indexCollapseTris[triangles[i].p1]; + triangles[i].p2 = triangles[i].p2 - indexCollapseTris[triangles[i].p2]; + triangles[i].p3 = triangles[i].p3 - indexCollapseTris[triangles[i].p3]; + } + } } int BSTriShape::CalcBlockSize() { diff --git a/NifFile.cpp b/NifFile.cpp index 7b73c2ab..dd0c4fd4 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -2847,7 +2847,10 @@ void NifFile::DeleteVertsForShape(const string& shapeName, const vector& DeleteShape(shapeName); return; } - hdr.blockSizes[dataRef] = siTriShape->CalcBlockSize(); + + int shapeID = shapeIdForName(shapeName); + if (shapeID != -1) + hdr.blockSizes[shapeID] = siTriShape->CalcBlockSize(); } } From a1a41686d3ab1eec918d327803412b4bb874e1d9 Mon Sep 17 00:00:00 2001 From: ousnius Date: Mon, 14 Dec 2015 15:52:56 +0100 Subject: [PATCH 50/64] Moved normal smoothing code to NifBlock (WIP), cleanup --- BodySlideApp.cpp | 75 +----- NifBlock.cpp | 611 ++++++++++++++++++++--------------------------- NifFile.cpp | 80 ++++--- NifFile.h | 37 +-- Object3d.h | 2 +- 5 files changed, 336 insertions(+), 469 deletions(-) diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index cfefcf27..b2feb958 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -1206,79 +1206,8 @@ int BodySlideApp::BuildBodies(bool localPath, bool clean, bool tri) { nifBig.SetVertsForShape(it->second, vertsHigh); if (targetGame == FO4) { - // Temp Fix - vector tris; - nifBig.GetTrisForShape(it->second, &tris); - - Vector3 norm; - float scale = 0.1f; - mesh* m = new mesh(); - - m->nVerts = vertsHigh.size(); - m->verts = new Vertex[m->nVerts]; - - m->nTris = tris.size(); - m->tris = new Triangle[m->nTris]; - - for (int i = 0; i < m->nVerts; i++) { - m->verts[i].x = vertsHigh[i].x * -scale; - m->verts[i].z = vertsHigh[i].y * scale; - m->verts[i].y = vertsHigh[i].z * scale; - m->verts[i].indexRef = i; - } - - // Load tris. Also sum face normals here. - for (int j = 0; j < m->nTris; j++) { - Vector3 norm; - m->tris[j].p1 = tris[j].p1; - m->tris[j].p2 = tris[j].p2; - m->tris[j].p3 = tris[j].p3; - m->tris[j].trinormal(m->verts, &norm); - m->verts[m->tris[j].p1].nx += norm.x; - m->verts[m->tris[j].p1].ny += norm.y; - m->verts[m->tris[j].p1].nz += norm.z; - m->verts[m->tris[j].p2].nx += norm.x; - m->verts[m->tris[j].p2].ny += norm.y; - m->verts[m->tris[j].p2].nz += norm.z; - m->verts[m->tris[j].p3].nx += norm.x; - m->verts[m->tris[j].p3].ny += norm.y; - m->verts[m->tris[j].p3].nz += norm.z; - } - - // Normalize all vertex normals to smooth them out. - for (int i = 0; i < m->nVerts; i++) { - Vector3* pn = (Vector3*)&m->verts[i].nx; - pn->Normalize(); - } - - kd_matcher matcher(m->verts, m->nVerts); - for (int i = 0; i < matcher.matches.size(); i++) { - Vertex* a = matcher.matches[i].first; - Vertex* b = matcher.matches[i].second; - m->weldVerts[a->indexRef].push_back(b->indexRef); - m->weldVerts[b->indexRef].push_back(a->indexRef); - - if (m->smoothSeamNormals) { - float dot = (a->nx * b->nx + a->ny * b->ny + a->nz * b->nz); - if (dot < 1.57079633f) { - a->nx = ((a->nx + b->nx) / 2.0f); - a->ny = ((a->ny + b->ny) / 2.0f); - a->nz = ((a->nz + b->nz) / 2.0f); - b->nx = a->nx; - b->ny = a->ny; - b->nz = a->nz; - } - } - } - - m->SmoothNormals(); - - vector newNorms; - for (int i = 0; i < m->nVerts; i++) - newNorms.push_back(Vector3(-m->verts[i].nx, m->verts[i].nz, m->verts[i].ny)); - - nifBig.SetNormalsForShape(it->second, newNorms); - delete m; + nifBig.CalcNormalsForShape(it->second); + nifBig.SmoothNormalsForShape(it->second); } nifBig.DeleteVertsForShape(it->second, zapIdx); diff --git a/NifBlock.cpp b/NifBlock.cpp index dcd981f9..537f586e 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -580,6 +580,7 @@ int NiNode::CalcBlockSize() { BSTriShape::BSTriShape(NiHeader& hdr) { NiAVObject::Init(); + blockType = BSTRISHAPE; header = &hdr; @@ -598,30 +599,27 @@ BSTriShape::BSTriShape(NiHeader& hdr) { vertFlags[5] = 0xB0; vertFlags[6] = 0x1; vertFlags[7] = 0x0; - numTris = 0; - numverts = 0; - datasize = 0; - vertRecSize = 20; // size of vertex structure calculated with (datasize - (numtris*6)) / numverts; - - CalcBlockSize(); + numTriangles = 0; + numVertices = 0; + dataSize = 0; + vertRecSize = 20; // size of vertex structure calculated with (datasize - (numtris*6)) / numverts; } BSTriShape::BSTriShape(fstream& file, NiHeader& hdr) { NiAVObject::Init(); + blockType = BSTRISHAPE; header = &hdr; + Get(file); - CalcBlockSize(); } void BSTriShape::Get(fstream& file) { - half_float::half halfData; // The order of definition deviates slightly from previous versions, so can't directly use the super Get... instead // that code is duplicated here and the super super get is called. NiObjectNET::Get(file); file.read((char*)&flags, 2); - file.read((char*)&unkShort1, 2); file.read((char*)&translation.x, 4); @@ -635,95 +633,82 @@ void BSTriShape::Get(fstream& file) { } file.read((char*)&scale, 4); - file.read((char*)&collisionRef, 4); - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) file.read((char*)&unkProps[i], 4); - } file.read((char*)&skinInstanceRef, 4); file.read((char*)&shaderPropertyRef, 4); file.read((char*)&alphaPropertyRef, 4); - for (int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) file.read((char*)&vertFlags[i], 1); - } - - file.read((char*)&numTris, 4); - file.read((char*)&numverts, 2); - - file.read((char*)&datasize, 4); - vertRecSize = (datasize - (numTris * 6)) / numverts; + file.read((char*)&numTriangles, 4); + file.read((char*)&numVertices, 2); + file.read((char*)&dataSize, 4); + vertRecSize = (dataSize - (numTriangles * 6)) / numVertices; - vertData.resize(numverts); - for (int i = 0; i < numverts; i++) { + half_float::half halfData; + vertData.resize(numVertices); + for (int i = 0; i < numVertices; i++) { file.read((char*)&halfData, 2); - vertData[i].vert.x = halfData;//h2float(shortData); + vertData[i].vert.x = halfData; file.read((char*)&halfData, 2); - vertData[i].vert.y = halfData;//h2float(shortData); + vertData[i].vert.y = halfData; file.read((char*)&halfData, 2); - vertData[i].vert.z = halfData;//h2float(shortData); + vertData[i].vert.z = halfData; file.read((char*)&halfData, 2); - vertData[i].bitangentX = halfData;//h2float(shortData); + vertData[i].bitangentX = halfData; file.read((char*)&halfData, 2); - vertData[i].uv.u = halfData;//h2float(shortData); + vertData[i].uv.u = halfData; file.read((char*)&halfData, 2); - vertData[i].uv.v = halfData;//h2float(shortData); + vertData[i].uv.v = halfData; if (vertFlags[6] & 0x1) { - for (int j = 0; j < 3; j++) { + for (int j = 0; j < 3; j++) file.read((char*)&vertData[i].normal[j], 1); - } file.read((char*)&vertData[i].bitangentY, 1); - for (int j = 0; j < 3; j++) { + for (int j = 0; j < 3; j++) file.read((char*)&vertData[i].tangent[j], 1); - } + file.read((char*)&vertData[i].bitangentZ, 1); } - if (vertFlags[6] & 0x2) { + if (vertFlags[6] & 0x2) file.read((char*)&vertData[i].colorData, 4); - } if (vertFlags[6] & 0x4) { for (int j = 0; j < 4; j++) { file.read((char*)&halfData, 2); vertData[i].weights[j] = halfData;//h2float(shortData); } - for (int j = 0; j < 4; j++) { + + for (int j = 0; j < 4; j++) file.read((char*)&vertData[i].weightBones[j], 1); - } } } - - triangles.resize(numTris); - for (int i = 0; i < numTris; i++) { + triangles.resize(numTriangles); + for (int i = 0; i < numTriangles; i++) { file.read((char*)&triangles[i].p1, 2); file.read((char*)&triangles[i].p2, 2); file.read((char*)&triangles[i].p3, 2); } - - } - void BSTriShape::Put(fstream& file) { - half_float::half halfData; // The order of definition deviates slightly from previous versions, so can't directly use the super Get... instead // that code is duplicated here and the super super get is called. NiObjectNET::Put(file); file.write((char*)&flags, 2); - - file.write((char*)&unkShort1, 2); file.write((char*)&translation.x, 4); @@ -737,35 +722,31 @@ void BSTriShape::Put(fstream& file) { } file.write((char*)&scale, 4); - file.write((char*)&collisionRef, 4); - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) file.write((char*)&unkProps[i], 4); - } file.write((char*)&skinInstanceRef, 4); file.write((char*)&shaderPropertyRef, 4); file.write((char*)&alphaPropertyRef, 4); - for (int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) file.write((char*)&vertFlags[i], 1); - } - file.write((char*)&numTris, 4); - file.write((char*)&numverts, 2); - - file.write((char*)&datasize, 4); - - for (int i = 0; i < numverts; i++) { + file.write((char*)&numTriangles, 4); + file.write((char*)&numVertices, 2); + file.write((char*)&dataSize, 4); + + half_float::half halfData; + for (int i = 0; i < numVertices; i++) { halfData = vertData[i].vert.x; file.write((char*)&halfData, 2); halfData = vertData[i].vert.y; file.write((char*)&halfData, 2); - halfData = vertData[i].vert.z; file.write((char*)&halfData, 2); @@ -775,44 +756,40 @@ void BSTriShape::Put(fstream& file) { halfData = vertData[i].uv.u; file.write((char*)&halfData, 2); - halfData = vertData[i].uv.v; file.write((char*)&halfData, 2); if (vertFlags[6] & 0x1) { - for (int j = 0; j < 3; j++) { + for (int j = 0; j < 3; j++) file.write((char*)&vertData[i].normal[j], 1); - } file.write((char*)&vertData[i].bitangentY, 1); - for (int j = 0; j < 3; j++) { + for (int j = 0; j < 3; j++) file.write((char*)&vertData[i].tangent[j], 1); - } file.write((char*)&vertData[i].bitangentZ, 1); } - if (vertFlags[6] & 0x2) { + if (vertFlags[6] & 0x2) file.write((char*)&vertData[i].colorData, 4); - } + if (vertFlags[6] & 0x4) { for (int j = 0; j < 4; j++) { halfData = vertData[i].weights[j]; file.write((char*)&halfData, 2); } - for (int j = 0; j < 4; j++) { + + for (int j = 0; j < 4; j++) file.write((char*)&vertData[i].weightBones[j], 1); - } } } - for (int i = 0; i < numTris; i++) { + for (int i = 0; i < numTriangles; i++) { file.write((char*)&triangles[i].p1, 2); file.write((char*)&triangles[i].p2, 2); file.write((char*)&triangles[i].p3, 2); } - } void BSTriShape::notifyBlockDelete(int blockID) { @@ -856,17 +833,11 @@ void BSTriShape::notifyBlockSwap(int blockIndexLo, int blockIndexHi) { void BSTriShape::notifyVerticesDelete(const vector& vertIndices) { vector indexCollapse(vertData.size(), 0); vector indexCollapseTris(vertData.size(), 0); - + + int remCount = 0; for (int i = 0, j = 0; i < indexCollapse.size(); i++) { if (j < vertIndices.size() && vertIndices[j] == i) { // Found one to remove indexCollapse[i] = -1; // Flag delete - j++; - } - } - - int remCount = 0; - for (int i = 0, j = 0; i < indexCollapseTris.size(); i++) { - if (j < vertIndices.size() && vertIndices[j] == i) { // Found one to remove indexCollapseTris[i] = -1; // Flag delete remCount++; j++; @@ -878,14 +849,14 @@ void BSTriShape::notifyVerticesDelete(const vector& vertIndices) { for (int i = vertData.size() - 1; i >= 0; i--) { if (indexCollapse[i] == -1) { vertData.erase(vertData.begin() + i); - numverts--; + numVertices--; } } - for (int i = numTris - 1; i >= 0; i--) { + for (int i = numTriangles - 1; i >= 0; i--) { if (indexCollapseTris[triangles[i].p1] == -1 || indexCollapseTris[triangles[i].p2] == -1 || indexCollapseTris[triangles[i].p3] == -1) { triangles.erase(triangles.begin() + i); - numTris--; + numTriangles--; } else { triangles[i].p1 = triangles[i].p1 - indexCollapseTris[triangles[i].p1]; @@ -898,99 +869,92 @@ void BSTriShape::notifyVerticesDelete(const vector& vertIndices) { int BSTriShape::CalcBlockSize() { NiAVObject::CalcBlockSize(); - blockSize += 46 + 6 * numTris; + blockSize += 46 + 6 * numTriangles; int vdataSize = 12; - if (vertFlags[6] & 0x1) { //normals + if (vertFlags[6] & 0x1) //normals vdataSize += 8; - } - if (vertFlags[6] & 0x2) { //colors + if (vertFlags[6] & 0x2) //colors vdataSize += 4; - } - if (vertFlags[6] & 0x4) { //skinning + if (vertFlags[6] & 0x4) //skinning vdataSize += 12; - } - blockSize += vdataSize * numverts; + blockSize += vdataSize * numVertices; return blockSize; } - const vector* BSTriShape::GetRawVerts(bool xform) { - rawverts.clear(); - rawverts.resize(numverts); - for (int i = 0; i < numverts; i++) { - rawverts[i] = vertData[i].vert; - } + rawVertices.clear(); + rawVertices.resize(numVertices); + for (int i = 0; i < numVertices; i++) + rawVertices[i] = vertData[i].vert; - return &rawverts; + return &rawVertices; } - const vector* BSTriShape::GetNormalData(bool xform) { - rawnorms.clear(); - rawnorms.resize(numverts); - for (int i = 0; i < numverts; i++) { - - float q1 = (((float)vertData[i].normal[0])/255.0f) *2.0f - 1.0f; - float q2 = (((float)vertData[i].normal[1])/255.0f) *2.0f - 1.0f; - float q3 = (((float)vertData[i].normal[2])/255.0f) *2.0f - 1.0f; + rawNormals.clear(); + rawNormals.resize(numVertices); + for (int i = 0; i < numVertices; i++) { + float q1 = (((float)vertData[i].normal[0])/255.0f) * 2.0f - 1.0f; + float q2 = (((float)vertData[i].normal[1])/255.0f) * 2.0f - 1.0f; + float q3 = (((float)vertData[i].normal[2])/255.0f) * 2.0f - 1.0f; float x = q1; float y = q2; float z = q3; if (xform) { - rawnorms[i].x = -x; - rawnorms[i].z = y; - rawnorms[i].y = z; + rawNormals[i].x = -x; + rawNormals[i].z = y; + rawNormals[i].y = z; } else { - rawnorms[i].x = x; - rawnorms[i].z = z; - rawnorms[i].y = y; + rawNormals[i].x = x; + rawNormals[i].z = z; + rawNormals[i].y = y; } - } - return &rawnorms; + return &rawNormals; } const vector* BSTriShape::GetTangentData(bool xform) { - rawtangents.clear(); - rawtangents.resize(numverts); - for (int i = 0; i < numverts; i++) { - float q6 = (((float)vertData[i].tangent[0]) / 255.0f) *2.0f - 1.0f; - float q7 = (((float)vertData[i].tangent[1]) / 255.0f) *2.0f - 1.0f; - float q8 = (((float)vertData[i].tangent[2]) / 255.0f) *2.0f - 1.0f; + rawTangents.clear(); + rawTangents.resize(numVertices); + for (int i = 0; i < numVertices; i++) { + float q6 = (((float)vertData[i].tangent[0]) / 255.0f) * 2.0f - 1.0f; + float q7 = (((float)vertData[i].tangent[1]) / 255.0f) * 2.0f - 1.0f; + float q8 = (((float)vertData[i].tangent[2]) / 255.0f) * 2.0f - 1.0f; float x = q6; float y = q7; float z = q8; if (xform) { - rawtangents[i].x = -x; - rawtangents[i].z = y; - rawtangents[i].y = z; + rawTangents[i].x = -x; + rawTangents[i].z = y; + rawTangents[i].y = z; } else { - rawtangents[i].x = x; - rawtangents[i].z = z; - rawtangents[i].y = y; + rawTangents[i].x = x; + rawTangents[i].z = z; + rawTangents[i].y = y; } } - return &rawtangents; + + return &rawTangents; } const vector* BSTriShape::GetBitangentData(bool xform) { rawBitangents.clear(); - rawBitangents.resize(numverts); - for (int i = 0; i < numverts; i++) { + rawBitangents.resize(numVertices); + for (int i = 0; i < numVertices; i++) { float x = (vertData[i].bitangentX); - float y = (((float)vertData[i].bitangentY) / 255.0f) *2.0f - 1.0f; - float z = (((float)vertData[i].bitangentZ) / 255.0f) *2.0f - 1.0f; + float y = (((float)vertData[i].bitangentY) / 255.0f) * 2.0f - 1.0f; + float z = (((float)vertData[i].bitangentZ) / 255.0f) * 2.0f - 1.0f; if (xform) { @@ -1008,157 +972,155 @@ const vector* BSTriShape::GetBitangentData(bool xform) { } const vector* BSTriShape::GetUVData() { - rawuvs.clear(); - rawuvs.resize(numverts); - for (int i = 0; i < numverts; i++) { - rawuvs[i] = vertData[i].uv; - } - - return &rawuvs; + rawUvs.clear(); + rawUvs.resize(numVertices); + for (int i = 0; i < numVertices; i++) + rawUvs[i] = vertData[i].uv; + return &rawUvs; } -void BSTriShape::calcTangentSpace(vector** outNorms, vector** outTangents, vector** outBitangents, bool transform) { - - GetNormalData(false); - - vector tan1; - vector tan2; - tan1.resize(numverts); - tan2.resize(numverts); - - - for (int i = 0; i < triangles.size(); i++) { - int i1 = triangles[i].p1; - int i2 = triangles[i].p2; - int i3 = triangles[i].p3; - - Vector3 v1 = vertData[i1].vert; - Vector3 v2 = vertData[i2].vert; - Vector3 v3 = vertData[i3].vert; - - Vector2 w1 = vertData[i1].uv; - Vector2 w2 = vertData[i2].uv; - Vector2 w3 = vertData[i3].uv; - - float x1 = v2.x - v1.x; - float x2 = v3.x - v1.x; - float y1 = v2.y - v1.y; - float y2 = v3.y - v1.y; - float z1 = v2.z - v1.z; - float z2 = v3.z - v1.z; - - float s1 = w2.u - w1.u; - float s2 = w3.u - w1.u; - float t1 = w2.v - w1.v; - float t2 = w3.v - w1.v; - - float r = (s1 * t2 - s2 * t1); - r = (r >= 0.0f ? +1.0f : -1.0f); - - Vector3 sdir = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); - Vector3 tdir = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); - - tan1[i1] += tdir; - tan1[i2] += tdir; - tan1[i3] += tdir; - - tan2[i1] += sdir; - tan2[i2] += sdir; - tan2[i3] += sdir; +void BSTriShape::SetNormals(const vector& inNorms) { + rawNormals.clear(); + rawNormals.resize(numVertices); + for (int i = 0; i < numVertices; i++) { + rawNormals[i] = inNorms[i]; + vertData[i].normal[0] = (unsigned char)round((((inNorms[i].x + 1.0f) / 2.0f) * 255.0f)); + vertData[i].normal[1] = (unsigned char)round((((inNorms[i].y + 1.0f) / 2.0f) * 255.0f)); + vertData[i].normal[2] = (unsigned char)round((((inNorms[i].z + 1.0f) / 2.0f) * 255.0f)); } +} - rawBitangents.resize(numverts); - rawtangents.resize(numverts); - - for (int i = 0; i < numverts; i++) { - Vector3 n = rawnorms[i]; - - rawtangents[i] = tan1[i]; - rawBitangents[i] = tan2[i]; +void BSTriShape::SmoothNormals(const float& smoothThreshold) { + // WIP - if (rawtangents[i].IsZero() || rawBitangents[i].IsZero()) { - rawtangents[i].x = rawnorms[i].y; rawtangents[i].y = rawnorms[i].z; rawtangents[i].z = rawnorms[i].x; - rawBitangents[i] = rawnorms[i].cross(rawtangents[i]); + // Find weld verts + /* + kd_matcher matcher(m->verts, m->nVerts); + for (i = 0; i < matcher.matches.size(); i++) { + Vertex* a = matcher.matches[i].first; + Vertex* b = matcher.matches[i].second; + m->weldVerts[a->indexRef].push_back(b->indexRef); + m->weldVerts[b->indexRef].push_back(a->indexRef); + float dot = (a->nx * b->nx + a->ny*b->ny + a->nz*b->nz); + if (dot < 1.57079633f) { + a->nx = ((a->nx + b->nx) / 2.0f); + a->ny = ((a->ny + b->ny) / 2.0f); + a->nz = ((a->nz + b->nz) / 2.0f); + b->nx = a->nx; + b->ny = a->ny; + b->nz = a->nz; } - else { - rawtangents[i].Normalize(); - rawtangents[i] = (rawtangents[i] - rawnorms[i] * rawnorms[i].dot(rawtangents[i])); - rawtangents[i].Normalize(); - - rawBitangents[i].Normalize(); - - rawBitangents[i] = (rawBitangents[i] - rawnorms[i] * rawnorms[i].dot(rawBitangents[i])); - rawBitangents[i] = (rawBitangents[i] - rawtangents[i] * rawtangents[i].dot(rawBitangents[i])); + } + */ - rawBitangents[i].Normalize(); + // Smooth normals + /* + Vector3 norm; + Vector3 tn; + for (int v = 0; v < numVertices; v++) { + norm.x = norm.y = norm.z = 0.0f; + for (auto &t : vertTris[v]) { + tris[t].trinormal(verts, &tn); + norm += tn; + } + for (auto &wv : weldVerts[v]) { + bool first = true; + if (vertTris[wv].size() < 2) + continue; + for (auto &t : vertTris[wv]) { + tris[t].trinormal(verts, &tn); + if (!first) { + float angle = fabs(norm.angle(tn)); + if (angle > smoothThreshold) + continue; + } + else + first = false; + + norm += tn; + } } + norm = norm / (float)vertTris[v].size(); + norm.Normalize(); + verts[v].nx = norm.x; + verts[v].ny = norm.y; + verts[v].nz = norm.z; + } + */ +} +void BSTriShape::RecalcNormals() { + GetRawVerts(); - //rawBitangents[i] = tan1[i] ; - //rawBitangents[i].Normalize(); + // Calc normal + Vector3 norm; + rawNormals.resize(numVertices); + for (int i = 0; i < numTriangles; i++) { + triangles[i].trinormal(rawVertices, &norm); + rawNormals[triangles[i].p1].x += norm.x; + rawNormals[triangles[i].p1].y += norm.y; + rawNormals[triangles[i].p1].z += norm.z; + rawNormals[triangles[i].p2].x += norm.x; + rawNormals[triangles[i].p2].y += norm.y; + rawNormals[triangles[i].p2].z += norm.z; + rawNormals[triangles[i].p3].x += norm.x; + rawNormals[triangles[i].p3].y += norm.y; + rawNormals[triangles[i].p3].z += norm.z; + } - //rawtangents[i] = rawBitangents[i].cross(rawnorms[i]); - //rawtangents[i].Normalize(); + // Normalize all vertex normals to smooth them out + for (int i = 0; i < numVertices; i++) + rawNormals[i].Normalize(); + Vertex* matchVerts = new Vertex[numVertices]; + for (int i = 0; i < numVertices; i++) { + matchVerts[i].x = rawVertices[i].x; + matchVerts[i].nx = rawNormals[i].x; + matchVerts[i].y = rawVertices[i].y; + matchVerts[i].ny = rawNormals[i].y; + matchVerts[i].z = rawVertices[i].z; + matchVerts[i].nz = rawNormals[i].z; + } - float tmp; - if (transform) { - rawnorms[i].x = -rawnorms[i].x; - tmp = rawnorms[i].y; - rawnorms[i].y = rawnorms[i].z; - rawnorms[i].z = tmp; - - - rawBitangents[i].x = -rawBitangents[i].x; - tmp = rawBitangents[i].y; - rawBitangents[i].y = rawBitangents[i].z; - rawBitangents[i].z = tmp; - - rawtangents[i].x = -rawtangents[i].x; - tmp = rawtangents[i].y; - rawtangents[i].y = rawtangents[i].z; - rawtangents[i].z = tmp; + kd_matcher matcher(matchVerts, numVertices); + for (int i = 0; i < matcher.matches.size(); i++) { + Vertex* a = matcher.matches[i].first; + Vertex* b = matcher.matches[i].second; + float dot = (a->nx * b->nx + a->ny*b->ny + a->nz*b->nz); + if (dot < 1.57079633f) { + a->nx = ((a->nx + b->nx) / 2.0f); + a->ny = ((a->ny + b->ny) / 2.0f); + a->nz = ((a->nz + b->nz) / 2.0f); + b->nx = a->nx; + b->ny = a->ny; + b->nz = a->nz; } - } - if (outNorms) - *outNorms = &rawnorms; - if (outTangents) - *outTangents = &rawtangents; - if (outBitangents) - *outBitangents = &rawBitangents; - - - -} - -void BSTriShape::setNormals(const vector& inNorms) { - rawnorms.clear(); - rawnorms.resize(numverts); - for (int i = 0;i < numverts; i++) { - rawnorms[i] = inNorms[i]; - vertData[i].normal[0] = (unsigned char)round((((inNorms[i].x + 1.0f) /2.0f )*255.0f)); - vertData[i].normal[1] = (unsigned char)round((((inNorms[i].y + 1.0f) / 2.0f)*255.0f));; - vertData[i].normal[2] = (unsigned char)round((((inNorms[i].z + 1.0f) / 2.0f)*255.0f));; + for (int i = 0; i < numVertices; i++) { + rawNormals[i].x = matchVerts[i].nx; + rawNormals[i].y = matchVerts[i].ny; + rawNormals[i].z = matchVerts[i].nz; + vertData[i].normal[0] = (unsigned char)round((((rawNormals[i].x + 1.0f) / 2.0f) * 255.0f)); + vertData[i].normal[1] = (unsigned char)round((((rawNormals[i].y + 1.0f) / 2.0f) * 255.0f)); + vertData[i].normal[2] = (unsigned char)round((((rawNormals[i].z + 1.0f) / 2.0f) * 255.0f)); } + delete[] matchVerts; } -void BSTriShape::SetTangentData() { - if (rawnorms.empty()) { +void BSTriShape::CalcTangentSpace() { + if (rawNormals.empty()) GetNormalData(false); - } vector tan1; vector tan2; - tan1.resize(numverts); - tan2.resize(numverts); - + tan1.resize(numVertices); + tan2.resize(numVertices); for (int i = 0; i < triangles.size(); i++) { int i1 = triangles[i].p1; @@ -1203,64 +1165,49 @@ void BSTriShape::SetTangentData() { tan2[i3] += sdir; } - rawBitangents.resize(numverts); - rawtangents.resize(numverts); + rawBitangents.resize(numVertices); + rawTangents.resize(numVertices); - for (int i = 0; i < numverts; i++) { - - rawtangents[i] = tan1[i]; + for (int i = 0; i < numVertices; i++) { + rawTangents[i] = tan1[i]; rawBitangents[i] = tan2[i]; - if (rawtangents[i].IsZero() || rawBitangents[i].IsZero()) { - rawtangents[i].x = rawnorms[i].y; rawtangents[i].y = rawnorms[i].z; rawtangents[i].z = rawnorms[i].x; - rawBitangents[i] = rawnorms[i].cross(rawtangents[i]); + if (rawTangents[i].IsZero() || rawBitangents[i].IsZero()) { + rawTangents[i].x = rawNormals[i].y; + rawTangents[i].y = rawNormals[i].z; + rawTangents[i].z = rawNormals[i].x; + rawBitangents[i] = rawNormals[i].cross(rawTangents[i]); } else { - rawtangents[i].Normalize(); - rawtangents[i] = (rawtangents[i] - rawnorms[i] * rawnorms[i].dot(rawtangents[i])); - rawtangents[i].Normalize(); + rawTangents[i].Normalize(); + rawTangents[i] = (rawTangents[i] - rawNormals[i] * rawNormals[i].dot(rawTangents[i])); + rawTangents[i].Normalize(); rawBitangents[i].Normalize(); - rawBitangents[i] = (rawBitangents[i] - rawnorms[i] * rawnorms[i].dot(rawBitangents[i])); - rawBitangents[i] = (rawBitangents[i] - rawtangents[i] * rawtangents[i].dot(rawBitangents[i])); + rawBitangents[i] = (rawBitangents[i] - rawNormals[i] * rawNormals[i].dot(rawBitangents[i])); + rawBitangents[i] = (rawBitangents[i] - rawTangents[i] * rawTangents[i].dot(rawBitangents[i])); rawBitangents[i].Normalize(); - - } - - ///* Old wrong way */ - //rawBitangents[i] = tan1[i]; - //rawBitangents[i].Normalize(); - - //rawtangents[i] = rawBitangents[i].cross(rawnorms[i]); - //rawtangents[i].Normalize(); - - - - vertData[i].tangent[0] = (unsigned char)round((((rawtangents[i].x + 1.0f) / 2.0f)*255.0f)); - vertData[i].tangent[1] = (unsigned char)round((((rawtangents[i].y + 1.0f) / 2.0f)*255.0f));; - vertData[i].tangent[2] = (unsigned char)round((((rawtangents[i].z + 1.0f) / 2.0f)*255.0f));; + vertData[i].tangent[0] = (unsigned char)round((((rawTangents[i].x + 1.0f) / 2.0f) * 255.0f)); + vertData[i].tangent[1] = (unsigned char)round((((rawTangents[i].y + 1.0f) / 2.0f) * 255.0f)); + vertData[i].tangent[2] = (unsigned char)round((((rawTangents[i].z + 1.0f) / 2.0f) * 255.0f)); vertData[i].bitangentX = rawBitangents[i].x; - vertData[i].bitangentY = (unsigned char)round((((rawBitangents[i].y + 1.0f) / 2.0f)*255.0f)); - vertData[i].bitangentZ = (unsigned char)round((((rawBitangents[i].z + 1.0f) / 2.0f)*255.0f)); - + vertData[i].bitangentY = (unsigned char)round((((rawBitangents[i].y + 1.0f) / 2.0f) * 255.0f)); + vertData[i].bitangentZ = (unsigned char)round((((rawBitangents[i].z + 1.0f) / 2.0f) * 255.0f)); } - - - - } void BSTriShape::Create(vector* verts, vector* tris, vector* uvs, vector* normals) { - unkShort1 = 0; //from AVObject -- zero for these blocks. - numverts = verts->size(); - numTris = tris->size(); - vertData.resize(verts->size()); - for (int i = 0; i < numverts; i++) { + unkShort1 = 0; //from AVObject -- zero for these blocks. + numVertices = verts->size(); + numTriangles = tris->size(); + + vertData.resize(numVertices); + for (int i = 0; i < numVertices; i++) { vertData[i].vert = (*verts)[i]; vertData[i].uv = (*uvs)[i]; @@ -1271,73 +1218,61 @@ void BSTriShape::Create(vector* verts, vector* tris, vectorsize() == numverts) { - setNormals((*normals)); - calcTangentSpace(NULL, NULL, NULL); + + if (normals && normals->size() == numVertices) { + SetNormals((*normals)); + CalcTangentSpace(); } + vertRecSize = 12; - if (vertFlags[6] & 0x1) { //normals + if (vertFlags[6] & 0x1) //normals vertRecSize += 8; - } - if (vertFlags[6] & 0x2) { //colors + if (vertFlags[6] & 0x2) //colors vertRecSize += 4; - } - if (vertFlags[6] & 0x4) { //skinning + if (vertFlags[6] & 0x4) //skinning vertRecSize += 12; - } - datasize = 6 * numTris + numverts * vertRecSize; - triangles.resize(numTris); - for (int i = 0; i < numTris; i++) { - triangles[i] = (*tris)[i]; - } - - CalcBlockSize(); + dataSize = 6 * numTriangles + numVertices * vertRecSize; + triangles.resize(numTriangles); + for (int i = 0; i < numTriangles; i++) + triangles[i] = (*tris)[i]; } BSSubIndexTriShape::BSSubIndexTriShape(NiHeader& hdr) : BSTriShape(hdr) { blockType = BSSUBINDEXTRISHAPE; - numtris2 = 0; + + numTriangles2 = 0; numSubIndexRecordA = 0; numSubIndexRecordB = 0; numSubIndexRecordA_2 = 0; numSubIndexRecordB_2 = 0; - CalcBlockSize(); } -BSSubIndexTriShape::BSSubIndexTriShape(fstream& file, NiHeader& hdr) : -BSTriShape(file, hdr) -{ +BSSubIndexTriShape::BSSubIndexTriShape(fstream& file, NiHeader& hdr) : BSTriShape(file, hdr) { blockType = BSSUBINDEXTRISHAPE; Get(file); - CalcBlockSize(); } void BSSubIndexTriShape::Get(fstream& file) { - - - file.read((char*)&numtris2, 4); + file.read((char*)&numTriangles2, 4); file.read((char*)&numSubIndexRecordA, 4); file.read((char*)&numSubIndexRecordB, 4); subIndexRecordsA.resize(numSubIndexRecordB * 4); - for (int i = 0; i < numSubIndexRecordB * 4; i++) { + for (int i = 0; i < numSubIndexRecordB * 4; i++) file.read((char*)&subIndexRecordsA[i], 4); - } if (numSubIndexRecordB > numSubIndexRecordA) { file.read((char*)&numSubIndexRecordA_2, 4); file.read((char*)&numSubIndexRecordB_2, 4); sequence.resize(numSubIndexRecordA); - for (int i = 0; i < numSubIndexRecordA; i++) { + for (int i = 0; i < numSubIndexRecordA; i++) file.read((char*)&sequence[i], 4); - } subIndexRecordsB.resize(numSubIndexRecordB); for (int i = 0; i < numSubIndexRecordB; i++) { @@ -1345,68 +1280,53 @@ void BSSubIndexTriShape::Get(fstream& file) { file.read((char*)&subIndexRecordsB[i].unk2, 4); file.read((char*)&subIndexRecordsB[i].numExtra, 4); subIndexRecordsB[i].extraData.resize(subIndexRecordsB[i].numExtra); - for (int j = 0; j < subIndexRecordsB[i].numExtra; j++) { + for (int j = 0; j < subIndexRecordsB[i].numExtra; j++) file.read((char*)&subIndexRecordsB[i].extraData[j], 4); - } - } - ssfFile.Get(file, 2); } - } - void BSSubIndexTriShape::Put(fstream& file) { BSTriShape::Put(file); - file.write((char*)&numtris2, 4); + file.write((char*)&numTriangles2, 4); file.write((char*)&numSubIndexRecordA, 4); file.write((char*)&numSubIndexRecordB, 4); - for (int i = 0; i < numSubIndexRecordB * 4; i++) { + for (int i = 0; i < numSubIndexRecordB * 4; i++) file.write((char*)&subIndexRecordsA[i], 4); - } if (numSubIndexRecordB > numSubIndexRecordA) { file.write((char*)&numSubIndexRecordA_2, 4); file.write((char*)&numSubIndexRecordB_2, 4); - for (int i = 0; i < numSubIndexRecordA; i++) { + for (int i = 0; i < numSubIndexRecordA; i++) file.write((char*)&sequence[i], 4); - } for (int i = 0; i < numSubIndexRecordB; i++) { file.write((char*)&subIndexRecordsB[i].unk1, 4); file.write((char*)&subIndexRecordsB[i].unk2, 4); file.write((char*)&subIndexRecordsB[i].numExtra, 4); - for (int j = 0; j < subIndexRecordsB[i].numExtra; j++) { + for (int j = 0; j < subIndexRecordsB[i].numExtra; j++) file.write((char*)&subIndexRecordsB[i].extraData[j], 4); - } - } - ssfFile.Put(file, 2,false); } - } void BSSubIndexTriShape::notifyBlockDelete(int blockID) { BSTriShape::notifyBlockDelete(blockID); - - - } void BSSubIndexTriShape::notifyBlockSwap(int blockIndexLo, int blockIndexHi) { - BSTriShape::notifyBlockSwap(blockIndexLo, blockIndexHi); - } int BSSubIndexTriShape::CalcBlockSize() { BSTriShape::CalcBlockSize(); + blockSize += 12; // tris and first record counts blockSize += numSubIndexRecordB * 4 * 4; // sub inex record arrayA @@ -1419,11 +1339,9 @@ int BSSubIndexTriShape::CalcBlockSize() { } blockSize += 2; blockSize += ssfFile.str.length(); - } return blockSize; - } void BSSubIndexTriShape::Create(vector* verts, vector* tris, vector* uvs, vector* normals) { @@ -1432,7 +1350,7 @@ void BSSubIndexTriShape::Create(vector* verts, vector* tris, vertFlags[0] = 8; vertFlags[6] = 5; - numtris2 = numTris; + numTriangles2 = numTriangles; numSubIndexRecordA = 0; numSubIndexRecordB = 0; numSubIndexRecordA_2 = 0; @@ -1450,12 +1368,9 @@ void BSSubIndexTriShape::Create(vector* verts, vector* tris, } subIndexRecordsA[n++] = 0x0; - subIndexRecordsA[n++] = numTris; + subIndexRecordsA[n++] = numTriangles; subIndexRecordsA[n++] = 0xFFFFFFFF; subIndexRecordsA[n++] = 0x0; - - CalcBlockSize(); - } void NiGeometry::Init() { diff --git a/NifFile.cpp b/NifFile.cpp index dd0c4fd4..d9a35842 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -1616,7 +1616,7 @@ int NifFile::GetShapeBoneWeights(const string& shapeName, int boneIndex, unorder else { BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { - for (int vid = 0; vid < siTriShape->numverts; vid++) { + for (int vid = 0; vid < siTriShape->numVertices; vid++) { for (int i = 0; i < 4; i++) { if (siTriShape->vertData[vid].weightBones[i] == boneIndex && siTriShape->vertData[vid].weights[i] != 0) { outWeights[vid] = siTriShape->vertData[vid].weights[i]; @@ -2058,7 +2058,6 @@ bool NifFile::GetVertsForShape(const string& shapeName, vector& outVert for (auto &v : siTriShape->vertData) outVerts.push_back(v.vert); return true; - } return false; } @@ -2081,8 +2080,7 @@ int NifFile::GetVertCountForShape(const string& shapeName) { } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { BSTriShape* siTriShape = static_cast(GetBlock(dataID)); - return siTriShape->numverts; - + return siTriShape->numVertices; } return -1; } @@ -2111,13 +2109,11 @@ void NifFile::SetVertsForShape(const string& shapeName, const vector& v } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { BSTriShape* siTriShape = static_cast(GetBlock(dataID)); - if (verts.size() != siTriShape->numverts) { + if (verts.size() != siTriShape->numVertices) return; - } - for (int i = 0; i < siTriShape->numverts; i++) { - siTriShape->vertData[i].vert = verts[i]; - } + for (int i = 0; i < siTriShape->numVertices; i++) + siTriShape->vertData[i].vert = verts[i]; } } @@ -2142,11 +2138,10 @@ void NifFile::SetUvsForShape(const string& shapeName, const vector& uvs stripsData->uvSets.assign(uvs.begin(), uvs.end()); } if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { BSTriShape* siTriShape = static_cast(GetBlock(dataID)); - if (uvs.size() != siTriShape->numverts) { + if (uvs.size() != siTriShape->numVertices) return; - } - for (int i = 0; i < siTriShape->numverts; i++) { + for (int i = 0; i < siTriShape->numVertices; i++) { //// VALIDATE LATER for now don't touch the data. // siTriShape->vertData[i].uv = uvs[i]; } @@ -2181,11 +2176,32 @@ void NifFile::SetNormalsForShape(const string& shapeName, const vector& } if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { BSTriShape* shape = (BSTriShape*)GetBlock(dataID); - shape->setNormals(norms); + shape->SetNormals(norms); + hdr.blockSizes[dataID] = shape->CalcBlockSize(); } } - -void NifFile::CalcTangentsForShape(const string& shapeName) { + +void NifFile::SmoothNormalsForShape(const string& shapeName) { + int bType; + int dataID = shapeDataIdForName(shapeName, bType); + if (dataID == -1) + return; + + if (bType == NITRISHAPEDATA) { + //NiTriShapeData* shapeData = (NiTriShapeData*)GetBlock(dataID); + //shapeData->SmoothNormals(); + } + else if (bType == NITRISTRIPSDATA) { + //NiTriStripsData* stripsData = (NiTriStripsData*)GetBlock(dataID); + //stripsData->SmoothNormals(); + } + if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { + BSTriShape* shape = (BSTriShape*)GetBlock(dataID); + shape->SmoothNormals(); + } +} + +void NifFile::CalcNormalsForShape(const string& shapeName) { int bType; int dataID = shapeDataIdForName(shapeName, bType); if (dataID == -1) @@ -2193,37 +2209,43 @@ void NifFile::CalcTangentsForShape(const string& shapeName) { if (bType == NITRISHAPEDATA) { NiTriShapeData* shapeData = (NiTriShapeData*)GetBlock(dataID); - shapeData->CalcTangentSpace(); + shapeData->RecalcNormals(); hdr.blockSizes[dataID] = shapeData->CalcBlockSize(); } else if (bType == NITRISTRIPSDATA) { NiTriStripsData* stripsData = (NiTriStripsData*)GetBlock(dataID); - stripsData->CalcTangentSpace(); + stripsData->RecalcNormals(); hdr.blockSizes[dataID] = stripsData->CalcBlockSize(); } if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { BSTriShape* shape = (BSTriShape*)GetBlock(dataID); - shape->SetTangentData(); + shape->RecalcNormals(); + hdr.blockSizes[dataID] = shape->CalcBlockSize(); } } -void NifFile::CalcTangentsForShape(const string& shapeName, vector** outNormals, vector** outTagents, vector** outBitangents, bool transform) { +void NifFile::CalcTangentsForShape(const string& shapeName) { int bType; int dataID = shapeDataIdForName(shapeName, bType); if (dataID == -1) return; if (bType == NITRISHAPEDATA) { - return; + NiTriShapeData* shapeData = (NiTriShapeData*)GetBlock(dataID); + shapeData->CalcTangentSpace(); + hdr.blockSizes[dataID] = shapeData->CalcBlockSize(); } else if (bType == NITRISTRIPSDATA) { - return; + NiTriStripsData* stripsData = (NiTriStripsData*)GetBlock(dataID); + stripsData->CalcTangentSpace(); + hdr.blockSizes[dataID] = stripsData->CalcBlockSize(); } if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { BSTriShape* shape = (BSTriShape*)GetBlock(dataID); - shape->calcTangentSpace(outNormals, outTagents, outBitangents, transform); + shape->CalcTangentSpace(); + hdr.blockSizes[dataID] = shape->CalcBlockSize(); } -} +} void NifFile::ClearShapeTransform(const string& shapeName) { NiAVObject* avo = avObjectForName(shapeName); @@ -2357,7 +2379,7 @@ void NifFile::ApplyShapeTranslation(const string& shapeName, const Vector3& offs if (!geom) return; - for (int i = 0; i < geom->numverts; i++) + for (int i = 0; i < geom->numVertices; i++) geom->vertData[i].vert += geom->translation + offset; geom->translation = Vector3(0.0f, 0.0f, 0.0f); @@ -2377,7 +2399,7 @@ void NifFile::MoveVertex(const string& shapeName, const Vector3& pos, const int& } else if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { BSTriShape* geom = dynamic_cast(GetBlock(dataRef)); - if (geom && geom->numverts > id) + if (geom && geom->numVertices > id) geom->vertData[id].vert = pos; } } @@ -2412,7 +2434,7 @@ void NifFile::OffsetShape(const string& shapeName, const Vector3& offset, unorde if (!geomData) return; - for (int i = 0; i < geomData->numverts; i++) { + for (int i = 0; i < geomData->numVertices; i++) { if (mask) { float maskFactor = 1.0f; Vector3 diff = offset; @@ -2465,7 +2487,7 @@ void NifFile::ScaleShape(const string& shapeName, const float& scale, unordered_ return; unordered_map diff; - for (int i = 0; i < geomData->numverts; i++) { + for (int i = 0; i < geomData->numVertices; i++) { Vector3 target = geomData->vertData[i].vert - root; target *= scale; diff[i] = geomData->vertData[i].vert - target; @@ -2523,7 +2545,7 @@ void NifFile::RotateShape(const string& shapeName, const Vector3& angle, unorder return; unordered_map diff; - for (int i = 0; i < geomData->numverts; i++) { + for (int i = 0; i < geomData->numVertices; i++) { Vector3 target = geomData->vertData[i].vert - root; Matrix4 mat; mat.Rotate(angle.x * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f)); @@ -2842,7 +2864,7 @@ void NifFile::DeleteVertsForShape(const string& shapeName, const vector& BSTriShape* siTriShape = geomForNameF4(shapeName); if (siTriShape) { siTriShape->notifyVerticesDelete(indices); - if (siTriShape->numverts == 0 || siTriShape->numTris == 0) { + if (siTriShape->numVertices == 0 || siTriShape->numTriangles == 0) { // Deleted all verts or tris, remove shape and children DeleteShape(shapeName); return; diff --git a/NifFile.h b/NifFile.h index 684016dc..c8a6bfb7 100644 --- a/NifFile.h +++ b/NifFile.h @@ -361,10 +361,9 @@ class NiNode : public NiAVObject { int CalcBlockSize(); }; -// Fallout 4 trishape and trishape data for non-skinned meshes. uses half floats for vertices. -class BSTriShape : public NiAVObject{ +// Fallout 4 geometry for non-skinned meshes. Mostly uses half floats for vertex data. +class BSTriShape : public NiAVObject { public: - class TSVertData { public: Vector3 vert; // Stored half-float, convert! @@ -388,16 +387,16 @@ class BSTriShape : public NiAVObject{ // flags for vert data look to be stored in here. byte 0 or byte 6 specifically look promising . // using byte 6 currently, bit 3 indicating sub index data, bit 2 indicating the presence of color data. bit 1 indicating presence of normal data byte vertFlags[8]; - uint numTris; - ushort numverts; - uint datasize; + uint numTriangles; + ushort numVertices; + uint dataSize; uint vertRecSize; // size of vertex structure calculated with (datasize - (numtris*6)) / numverts; - vector rawverts; // filled by GetRawVerts function and returned. - vector rawnorms; // filled by GetNormalData function and returned. - vector rawtangents; // filled by calcTangentSpace function and returned. - vector rawBitangents; // filled in calcTangentSpace - vector rawuvs; // filled by GetUVData function and returned. + vector rawVertices; // filled by GetRawVerts function and returned. + vector rawNormals; // filled by GetNormalData function and returned. + vector rawTangents; // filled by calcTangentSpace function and returned. + vector rawBitangents; // filled in calcTangentSpace + vector rawUvs; // filled by GetUVData function and returned. vector vertData; vector triangles; @@ -415,17 +414,18 @@ class BSTriShape : public NiAVObject{ const vector* GetTangentData(bool xform = true); const vector* GetBitangentData(bool xform = true); const vector* GetUVData(); - void calcTangentSpace(vector** outNorms = nullptr, vector** outTangents = nullptr, vector** outBitangents = nullptr, bool transform = true); - void setNormals(const vector& inNorms); - void SetTangentData(); + + void SetNormals(const vector& inNorms); + void SmoothNormals(const float& smoothThreshold = 60.0f * DEG2RAD); + void RecalcNormals(); + void CalcTangentSpace(); virtual void Create(vector* verts, vector* tris, vector* uvs, vector* normals = nullptr); }; - -// Fallout 4 trishape and trishape data for skinned meshes. uses half floats for vertices. +// Fallout 4 geometry for non-skinned meshes. Mostly uses half floats for vertex data. class BSSubIndexTriShape : public BSTriShape { public: - uint numtris2; + uint numTriangles2; uint numSubIndexRecordA; uint numSubIndexRecordB; @@ -1358,8 +1358,9 @@ class NifFile void SetVertsForShape(const string& shapeName, const vector& verts); void SetUvsForShape(const string& shapeName, const vector& uvs); void SetNormalsForShape(const string& shapeName, const vector& norms); + void SmoothNormalsForShape(const string& shapeName); + void CalcNormalsForShape(const string& shapeName); void CalcTangentsForShape(const string& shapeName); - void CalcTangentsForShape(const string& shapeName, vector** outNormals, vector** outTagents, vector** outBitangents, bool transform = true); void ClearShapeTransform(const string& shapeName); void GetShapeTransform(const string& shapeName, Matrix4& outTransform); diff --git a/Object3d.h b/Object3d.h index 8ccc45c0..07f13c13 100644 --- a/Object3d.h +++ b/Object3d.h @@ -628,7 +628,7 @@ struct Triangle { void trinormal(Vertex* vertref, Vector3* outNormal); - void trinormal(vector& vertref, Vector3* outNormal) { + void trinormal(const vector& vertref, Vector3* outNormal) { Vertex va(vertref[p2].x - vertref[p1].x, vertref[p2].y - vertref[p1].y, vertref[p2].z - vertref[p1].z); Vertex vb(vertref[p3].x - vertref[p1].x, vertref[p3].y - vertref[p1].y, vertref[p3].z - vertref[p1].z); From 307ea1c827d33460b5e0e81e5dd12c894cd906a8 Mon Sep 17 00:00:00 2001 From: ousnius Date: Tue, 15 Dec 2015 02:19:19 +0100 Subject: [PATCH 51/64] Added BSTriShape::RecalcNormals function with optional smoothing --- BodySlideApp.cpp | 96 +++++++++++++---------- NifBlock.cpp | 193 +++++++++++++++++++++++------------------------ NifFile.cpp | 2 +- NifFile.h | 3 +- 4 files changed, 156 insertions(+), 138 deletions(-) diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index b2feb958..00d977e4 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -1174,14 +1174,15 @@ int BodySlideApp::BuildBodies(bool localPath, bool clean, bool tri) { return 0; } - int error = nifSmall.Load(inputFileName); + int error = nifBig.Load(inputFileName); if (error) { wxLogError("Failed to load '%s' (%d)!", inputFileName, error); return 1; } - if (nifBig.Load(inputFileName)) - return 1; + if (activeSet.GenWeights()) + if (nifSmall.Load(inputFileName)) + return 1; vector vertsLow; vector vertsHigh; @@ -1189,28 +1190,30 @@ int BodySlideApp::BuildBodies(bool localPath, bool clean, bool tri) { unordered_map> zapIdxAll; for (auto it = activeSet.TargetShapesBegin(); it != activeSet.TargetShapesEnd(); ++it) { - if (!nifSmall.GetVertsForShape(it->second, vertsLow)) - continue; - if (!nifBig.GetVertsForShape(it->second, vertsHigh)) continue; + if (activeSet.GenWeights()) + if (!nifSmall.GetVertsForShape(it->second, vertsLow)) + continue; + zapIdxAll.emplace(it->second, vector()); - ApplySliders(it->first, sliderManager.slidersSmall, vertsLow, zapIdx); - zapIdx.clear(); ApplySliders(it->first, sliderManager.slidersBig, vertsHigh, zapIdx); - - nifSmall.SetVertsForShape(it->second, vertsLow); - nifSmall.DeleteVertsForShape(it->second, zapIdx); - nifBig.SetVertsForShape(it->second, vertsHigh); if (targetGame == FO4) { - nifBig.CalcNormalsForShape(it->second); nifBig.SmoothNormalsForShape(it->second); + nifBig.CalcTangentsForShape(it->second); } nifBig.DeleteVertsForShape(it->second, zapIdx); + if (activeSet.GenWeights()) { + zapIdx.clear(); + ApplySliders(it->first, sliderManager.slidersSmall, vertsLow, zapIdx); + nifSmall.SetVertsForShape(it->second, vertsLow); + nifSmall.DeleteVertsForShape(it->second, zapIdx); + } + zapIdxAll[it->second] = zapIdx; } @@ -1230,8 +1233,9 @@ int BodySlideApp::BuildBodies(bool localPath, bool clean, bool tri) { for (auto it = activeSet.TargetShapesBegin(); it != activeSet.TargetShapesEnd(); ++it) { triShapeLink = it->second; if (tri && nifBig.GetVertCountForShape(triShapeLink) > 0) { - nifSmall.AddStringExtraData(triShapeLink, "BODYTRI", triPathTrimmed); nifBig.AddStringExtraData(triShapeLink, "BODYTRI", triPathTrimmed); + if (activeSet.GenWeights()) + nifSmall.AddStringExtraData(triShapeLink, "BODYTRI", triPathTrimmed); tri = false; } } @@ -1403,12 +1407,14 @@ int BodySlideApp::BuildListBodies(const vector& outfitList, map vertsLow; @@ -1417,13 +1423,15 @@ int BodySlideApp::BuildListBodies(const vector& outfitList, map> zapIdxAll; for (auto it = currentSet.TargetShapesBegin(); it != currentSet.TargetShapesEnd(); ++it) { - if (!nifSmall.GetVertsForShape(it->second, vertsLow)) - continue; if (!nifBig.GetVertsForShape(it->second, vertsHigh)) continue; - float vsmall; - float vbig; + if (currentSet.GenWeights()) + if (!nifSmall.GetVertsForShape(it->second, vertsLow)) + continue; + + float vbig = 0.0f; + float vsmall = 0.0f; vector clamps; zapIdx.clear(); zapIdxAll.emplace(it->second, vector()); @@ -1439,16 +1447,7 @@ int BodySlideApp::BuildListBodies(const vector& outfitList, map& outfitList, map& outfitList, mapfirst); string target = it->first; - if (currentSet[c].defSmallValue > 0) - currentDiffs.ApplyClamp(dn, target, &vertsLow); if (currentSet[c].defBigValue > 0) currentDiffs.ApplyClamp(dn, target, &vertsHigh); + + if (currentSet.GenWeights()) + if (currentSet[c].defSmallValue > 0) + currentDiffs.ApplyClamp(dn, target, &vertsLow); } } - nifSmall.SetVertsForShape(it->second, vertsLow); - nifSmall.DeleteVertsForShape(it->second, zapIdx); - nifBig.SetVertsForShape(it->second, vertsHigh); + if (targetGame == FO4) { + nifBig.SmoothNormalsForShape(it->second); + nifBig.CalcTangentsForShape(it->second); + } nifBig.DeleteVertsForShape(it->second, zapIdx); + + if (currentSet.GenWeights()) { + nifSmall.SetVertsForShape(it->second, vertsLow); + nifSmall.DeleteVertsForShape(it->second, zapIdx); + } } /* Create directory for the outfit */ @@ -1519,8 +1538,9 @@ int BodySlideApp::BuildListBodies(const vector& outfitList, mapsecond; if (triEnd && nifBig.GetVertCountForShape(triShapeLink) > 0) { - nifSmall.AddStringExtraData(triShapeLink, "BODYTRI", triPathTrimmed); nifBig.AddStringExtraData(triShapeLink, "BODYTRI", triPathTrimmed); + if (currentSet.GenWeights()) + nifSmall.AddStringExtraData(triShapeLink, "BODYTRI", triPathTrimmed); triEnd = false; } } diff --git a/NifBlock.cpp b/NifBlock.cpp index 537f586e..e0dabde7 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -991,126 +991,125 @@ void BSTriShape::SetNormals(const vector& inNorms) { } } -void BSTriShape::SmoothNormals(const float& smoothThreshold) { - // WIP +void BSTriShape::RecalcNormals(const bool& smooth, const float& smoothThresh) { + GetRawVerts(); + + Vertex* verts = new Vertex[numVertices]; + Triangle* tris = new Triangle[numTriangles]; + + for (int i = 0; i < numVertices; i++) { + verts[i].x = rawVertices[i].x * -0.1f; + verts[i].z = rawVertices[i].y * 0.1f; + verts[i].y = rawVertices[i].z * 0.1f; + verts[i].indexRef = i; + } + + // Load tris. Also sum face normals here. + Vector3 norm; + for (int j = 0; j < numTriangles; j++) { + tris[j].p1 = triangles[j].p1; + tris[j].p2 = triangles[j].p2; + tris[j].p3 = triangles[j].p3; + tris[j].trinormal(verts, &norm); + verts[tris[j].p1].nx += norm.x; + verts[tris[j].p1].ny += norm.y; + verts[tris[j].p1].nz += norm.z; + verts[tris[j].p2].nx += norm.x; + verts[tris[j].p2].ny += norm.y; + verts[tris[j].p2].nz += norm.z; + verts[tris[j].p3].nx += norm.x; + verts[tris[j].p3].ny += norm.y; + verts[tris[j].p3].nz += norm.z; + } + + // Normalize all vertex normals to smooth them out. + for (int i = 0; i < numVertices; i++) { + Vector3* pn = (Vector3*)&verts[i].nx; + pn->Normalize(); + } + + vector* vertTris = new vector[numVertices]; + for (int t = 0; t < numTriangles; t++) { + vertTris[tris[t].p1].push_back(t); + vertTris[tris[t].p2].push_back(t); + vertTris[tris[t].p3].push_back(t); + } - // Find weld verts - /* - kd_matcher matcher(m->verts, m->nVerts); - for (i = 0; i < matcher.matches.size(); i++) { + unordered_map> weldVerts; + kd_matcher matcher(verts, numVertices); + for (int i = 0; i < matcher.matches.size(); i++) { Vertex* a = matcher.matches[i].first; Vertex* b = matcher.matches[i].second; - m->weldVerts[a->indexRef].push_back(b->indexRef); - m->weldVerts[b->indexRef].push_back(a->indexRef); - float dot = (a->nx * b->nx + a->ny*b->ny + a->nz*b->nz); - if (dot < 1.57079633f) { - a->nx = ((a->nx + b->nx) / 2.0f); - a->ny = ((a->ny + b->ny) / 2.0f); - a->nz = ((a->nz + b->nz) / 2.0f); - b->nx = a->nx; - b->ny = a->ny; - b->nz = a->nz; + weldVerts[a->indexRef].push_back(b->indexRef); + weldVerts[b->indexRef].push_back(a->indexRef); + + if (smooth) { + float dot = (a->nx * b->nx + a->ny * b->ny + a->nz * b->nz); + if (dot < 1.57079633f) { + a->nx = ((a->nx + b->nx) / 2.0f); + a->ny = ((a->ny + b->ny) / 2.0f); + a->nz = ((a->nz + b->nz) / 2.0f); + b->nx = a->nx; + b->ny = a->ny; + b->nz = a->nz; + } } } - */ // Smooth normals - /* - Vector3 norm; - Vector3 tn; - for (int v = 0; v < numVertices; v++) { - norm.x = norm.y = norm.z = 0.0f; - for (auto &t : vertTris[v]) { - tris[t].trinormal(verts, &tn); - norm += tn; - } - - for (auto &wv : weldVerts[v]) { - bool first = true; - if (vertTris[wv].size() < 2) + if (smooth) { + Vector3 tn; + for (int v = 0; v < numVertices; v++) { + norm.x = norm.y = norm.z = 0.0f; + if (weldVerts.find(v) != weldVerts.end()) continue; - for (auto &t : vertTris[wv]) { + for (auto &t : vertTris[v]) { tris[t].trinormal(verts, &tn); - if (!first) { - float angle = fabs(norm.angle(tn)); - if (angle > smoothThreshold) - continue; - } - else - first = false; - norm += tn; } - } - norm = norm / (float)vertTris[v].size(); - norm.Normalize(); - verts[v].nx = norm.x; - verts[v].ny = norm.y; - verts[v].nz = norm.z; - } - */ -} - -void BSTriShape::RecalcNormals() { - GetRawVerts(); - // Calc normal - Vector3 norm; - rawNormals.resize(numVertices); - for (int i = 0; i < numTriangles; i++) { - triangles[i].trinormal(rawVertices, &norm); - rawNormals[triangles[i].p1].x += norm.x; - rawNormals[triangles[i].p1].y += norm.y; - rawNormals[triangles[i].p1].z += norm.z; - rawNormals[triangles[i].p2].x += norm.x; - rawNormals[triangles[i].p2].y += norm.y; - rawNormals[triangles[i].p2].z += norm.z; - rawNormals[triangles[i].p3].x += norm.x; - rawNormals[triangles[i].p3].y += norm.y; - rawNormals[triangles[i].p3].z += norm.z; - } - - // Normalize all vertex normals to smooth them out - for (int i = 0; i < numVertices; i++) - rawNormals[i].Normalize(); - - Vertex* matchVerts = new Vertex[numVertices]; - - for (int i = 0; i < numVertices; i++) { - matchVerts[i].x = rawVertices[i].x; - matchVerts[i].nx = rawNormals[i].x; - matchVerts[i].y = rawVertices[i].y; - matchVerts[i].ny = rawNormals[i].y; - matchVerts[i].z = rawVertices[i].z; - matchVerts[i].nz = rawNormals[i].z; - } + for (auto &wv : weldVerts[v]) { + bool first = true; + if (vertTris[wv].size() < 2) + continue; + + for (auto &t : vertTris[wv]) { + tris[t].trinormal(verts, &tn); + if (!first) { + float angle = fabs(norm.angle(tn)); + if (angle > smoothThresh * DEG2RAD) + continue; + } + else + first = false; + + norm += tn; + } + } - kd_matcher matcher(matchVerts, numVertices); - for (int i = 0; i < matcher.matches.size(); i++) { - Vertex* a = matcher.matches[i].first; - Vertex* b = matcher.matches[i].second; - float dot = (a->nx * b->nx + a->ny*b->ny + a->nz*b->nz); - if (dot < 1.57079633f) { - a->nx = ((a->nx + b->nx) / 2.0f); - a->ny = ((a->ny + b->ny) / 2.0f); - a->nz = ((a->nz + b->nz) / 2.0f); - b->nx = a->nx; - b->ny = a->ny; - b->nz = a->nz; + norm = norm / (float)vertTris[v].size(); + norm.Normalize(); + verts[v].nx = norm.x; + verts[v].ny = norm.y; + verts[v].nz = norm.z; } } + rawNormals.clear(); + rawNormals.resize(numVertices); for (int i = 0; i < numVertices; i++) { - rawNormals[i].x = matchVerts[i].nx; - rawNormals[i].y = matchVerts[i].ny; - rawNormals[i].z = matchVerts[i].nz; + rawNormals[i].x = -verts[i].nx; + rawNormals[i].y = verts[i].nz; + rawNormals[i].z = verts[i].ny; vertData[i].normal[0] = (unsigned char)round((((rawNormals[i].x + 1.0f) / 2.0f) * 255.0f)); vertData[i].normal[1] = (unsigned char)round((((rawNormals[i].y + 1.0f) / 2.0f) * 255.0f)); vertData[i].normal[2] = (unsigned char)round((((rawNormals[i].z + 1.0f) / 2.0f) * 255.0f)); } - delete[] matchVerts; + delete[] vertTris; + delete[] verts; + delete[] tris; } void BSTriShape::CalcTangentSpace() { diff --git a/NifFile.cpp b/NifFile.cpp index d9a35842..770c43f5 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -2197,7 +2197,7 @@ void NifFile::SmoothNormalsForShape(const string& shapeName) { } if (bType == BSSUBINDEXTRISHAPE || bType == BSTRISHAPE) { BSTriShape* shape = (BSTriShape*)GetBlock(dataID); - shape->SmoothNormals(); + shape->RecalcNormals(true); } } diff --git a/NifFile.h b/NifFile.h index c8a6bfb7..dd3f19eb 100644 --- a/NifFile.h +++ b/NifFile.h @@ -416,8 +416,7 @@ class BSTriShape : public NiAVObject { const vector* GetUVData(); void SetNormals(const vector& inNorms); - void SmoothNormals(const float& smoothThreshold = 60.0f * DEG2RAD); - void RecalcNormals(); + void RecalcNormals(const bool& smooth = false, const float& smoothThres = 60.0f); void CalcTangentSpace(); virtual void Create(vector* verts, vector* tris, vector* uvs, vector* normals = nullptr); }; From 3a81214a362d7770d5e20d5ee9760f1f6a0c5df1 Mon Sep 17 00:00:00 2001 From: ousnius Date: Wed, 16 Dec 2015 22:25:02 +0100 Subject: [PATCH 52/64] Fixed some normals problems --- GLSurface.cpp | 3 +-- OutfitProject.cpp | 2 +- OutfitStudio.cpp | 2 +- OutfitStudio.h | 9 +++------ 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/GLSurface.cpp b/GLSurface.cpp index 564f6054..08016490 100644 --- a/GLSurface.cpp +++ b/GLSurface.cpp @@ -1163,7 +1163,6 @@ void GLSurface::AddMeshFromNif(NifFile* nif, string shapeName, Vector3* color, b nif->GetVertsForShape(shapeName, nifVerts); nif->GetTrisForShape(shapeName, &nifTris); - const vector* nifNorms = nullptr; const vector* nifUvs = nif->GetUvsForShape(shapeName); nifNorms = nif->GetNormalsForShape(shapeName, false); @@ -1181,7 +1180,7 @@ void GLSurface::AddMeshFromNif(NifFile* nif, string shapeName, Vector3* color, b } m->shapeName = shapeName; - m->smoothSeamNormals = false; // smoothNormalSeams; + m->smoothSeamNormals = smoothNormalSeams; m->nVerts = nifVerts.size(); m->verts = new Vertex[m->nVerts]; diff --git a/OutfitProject.cpp b/OutfitProject.cpp index bb89e0c7..cf790a7a 100644 --- a/OutfitProject.cpp +++ b/OutfitProject.cpp @@ -1894,7 +1894,7 @@ void OutfitProject::RenameShape(const string& shapeName, const string& newShapeN void OutfitProject::UpdateNifNormals(NifFile* nif, const vector& shapeMeshes) { vector liveNorms; for (auto &m : shapeMeshes) { - if (nif->IsShaderSkin(m->shapeName)) + if (nif->IsShaderSkin(m->shapeName) && owner->targetGame != FO4) continue; liveNorms.clear(); diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index 05b66aa5..abcd4036 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -3948,7 +3948,7 @@ void wxGLPanel::AddMeshFromNif(NifFile* nif, const string& shapeName, bool build // Removed -- smoothing normals here breaks fallout 4 mesh normals. meshes without normals have their normals calculated/smoothed during mesh load. if (buildNormals) { - RecalcNormals(shapeList[i], true); + RecalcNormals(shapeList[i]); } } } diff --git a/OutfitStudio.h b/OutfitStudio.h index 83335c2e..9e3c93fb 100644 --- a/OutfitStudio.h +++ b/OutfitStudio.h @@ -175,15 +175,12 @@ class wxGLPanel : public wxGLCanvas { m->SmoothNormals(); } - void RecalcNormals(const string& shape, bool forceSmoothSeam = false) { + void RecalcNormals(const string& shape) { mesh* m = gls.GetMesh(shape); if (!m) return; - if (forceSmoothSeam) { - m->smoothSeamNormals = true; - m->SmoothNormals(); - m->smoothSeamNormals = false; - } + + m->SmoothNormals(); } void ToggleAutoNormals() { if (bAutoNormals) From 656990cd54d5210884487893e7cb9af590f4b220 Mon Sep 17 00:00:00 2001 From: ousnius Date: Thu, 17 Dec 2015 01:22:25 +0100 Subject: [PATCH 53/64] Fixed some more normals problems --- GLSurface.cpp | 4 ++-- Mesh.cpp | 27 +++++++++++++++++++++------ OutfitProject.cpp | 4 ---- OutfitStudio.cpp | 17 ++--------------- OutfitStudio.h | 17 ----------------- 5 files changed, 25 insertions(+), 44 deletions(-) diff --git a/GLSurface.cpp b/GLSurface.cpp index 08016490..00817d78 100644 --- a/GLSurface.cpp +++ b/GLSurface.cpp @@ -1124,7 +1124,7 @@ void GLSurface::AddMeshExplicit(vector* verts, vector* tris, m->weldVerts[a->indexRef].push_back(b->indexRef); m->weldVerts[b->indexRef].push_back(a->indexRef); float dot = (a->nx * b->nx + a->ny*b->ny + a->nz*b->nz); - if (dot < 1.57079633f) { + if (dot < 90.0f * DEG2RAD) { a->nx = ((a->nx + b->nx) / 2.0f); a->ny = ((a->ny + b->ny) / 2.0f); a->nz = ((a->nz + b->nz) / 2.0f); @@ -1248,7 +1248,7 @@ void GLSurface::AddMeshFromNif(NifFile* nif, string shapeName, Vector3* color, b if (smoothNormalSeams) { float dot = (a->nx * b->nx + a->ny * b->ny + a->nz * b->nz); - if (dot < 1.57079633f) { + if (dot < 90.0f * DEG2RAD) { a->nx = ((a->nx + b->nx) / 2.0f); a->ny = ((a->ny + b->ny) / 2.0f); a->nz = ((a->nz + b->nz) / 2.0f); diff --git a/Mesh.cpp b/Mesh.cpp index 23d54940..03ebdca9 100644 --- a/Mesh.cpp +++ b/Mesh.cpp @@ -22,7 +22,7 @@ mesh::mesh() { rendermode = RenderMode::Normal; doublesided = false; smoothSeamNormals = true; - smoothThresh = 60.0f * DEG2RAD; + smoothThresh = 90.0f * DEG2RAD; scale = 1.0f; } @@ -298,16 +298,30 @@ void mesh::SmoothNormals() { Vector3 tn; for (int v = 0; v < nVerts; v++) { norm.x = norm.y = norm.z = 0.0f; - if (!smoothSeamNormals && weldVerts.find(v)!= weldVerts.end()) { - // if smooth seams is off, don't update seam normals to preserve continuity for normal mapping - continue; - } + for (auto &t : vertTris[v]) { tris[t].trinormal(verts, &tn); norm += tn; } - if (smoothSeamNormals) { + if (weldVerts.find(v) == weldVerts.end()) { + bool first = true; + for (auto &t : vertTris[v]) { + tris[t].trinormal(verts, &tn); + + if (!first) { + float angle = fabs(norm.angle(tn)); + if (angle > smoothThresh) + continue; + } + else + first = false; + + norm += tn; + } + norm = norm / (float)vertTris[v].size(); + } + else if (smoothSeamNormals) { for (auto &wv : weldVerts[v]) { bool first = true; if (vertTris[wv].size() < 2) @@ -328,6 +342,7 @@ void mesh::SmoothNormals() { } norm = norm / (float)vertTris[v].size(); } + norm.Normalize(); verts[v].nx = norm.x; verts[v].ny = norm.y; diff --git a/OutfitProject.cpp b/OutfitProject.cpp index cf790a7a..e6104509 100644 --- a/OutfitProject.cpp +++ b/OutfitProject.cpp @@ -422,9 +422,6 @@ int OutfitProject::AddShapeFromObjFile(const string& fileName, const string& sha int OutfitProject::CreateNifShapeFromData(const string& shapeName, vector& v, vector& t, vector& uv, vector* norms) { - if (norms == nullptr) - owner->setShapeImporting(shapeName, true); - bool staticMode = Config["StaticMeshMode"] == "True"; string blankSkel = "res\\SkeletonBlank.nif"; @@ -436,7 +433,6 @@ int OutfitProject::CreateNifShapeFromData(const string& shapeName, vectortargetGame == FO4) blankSkel = "res\\SkeletonBlank_fo4.nif"; - NifFile blank; blank.Load(blankSkel); if (!blank.IsValid()) { diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index abcd4036..3da58e79 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -1223,12 +1223,7 @@ void OutfitStudio::WorkingGUIFromProj() { for (auto &shape : shapes) { glView->DeleteMesh(shape); - glView->AddMeshFromNif(project->GetWorkNif(), shape, shapeIsImporting(shape)); - if (shapeIsImporting(shape)) { - vector updateshape; - updateshape.push_back(glView->GetMesh(shape)); - project->UpdateNifNormals(project->GetWorkNif(), updateshape); - } + glView->AddMeshFromNif(project->GetWorkNif(), shape, true); glView->SetMeshTexture(shape, project->GetShapeTexture(shape), project->GetWorkNif()->IsShaderSkin(shape)); if (outfitShapes) { subItem = outfitShapes->AppendItem(outfitRoot, shape); @@ -2988,9 +2983,6 @@ void OutfitStudio::OnImportShape(wxCommandEvent& WXUNUSED(event)) { wxLogMessage("Imported shape."); WorkingGUIFromProj(); - - finishImporting(); - glView->Refresh(); } @@ -3051,9 +3043,6 @@ void OutfitStudio::OnImportFBX(wxCommandEvent& WXUNUSED(event)) { WorkingGUIFromProj(); AnimationGUIFromProj(); - - finishImporting(); - glView->Refresh(); } @@ -3946,10 +3935,8 @@ void wxGLPanel::AddMeshFromNif(NifFile* nif, const string& shapeName, bool build gls.GetMesh(shapeList[i])->BuildEdgeList(); gls.GetMesh(shapeList[i])->ColorFill(Vector3()); - // Removed -- smoothing normals here breaks fallout 4 mesh normals. meshes without normals have their normals calculated/smoothed during mesh load. - if (buildNormals) { + if (buildNormals) RecalcNormals(shapeList[i]); - } } } diff --git a/OutfitStudio.h b/OutfitStudio.h index 9e3c93fb..69901d67 100644 --- a/OutfitStudio.h +++ b/OutfitStudio.h @@ -636,23 +636,6 @@ class OutfitStudio : public wxFrame { progWnd->Update(progressVal, msg); } - - bool shapeIsImporting(const string& shapeName) { - auto ss = shapeStates.find(shapeName); - if (ss != shapeStates.end()) { - return ss->second.bIsImporting; - } - return false; - } - void setShapeImporting(const string& shapeName, bool isOn) { - shapeStates[shapeName].bIsImporting = isOn; - } - void finishImporting() { - for (auto &ss : shapeStates) { - ss.second.bIsImporting = false; - } - } - private: class ShapeState { // metadata state of shapes by shape name public: From 4a36203745e8f4c494a0ec7f8d660c0f31ef56a1 Mon Sep 17 00:00:00 2001 From: ousnius Date: Sat, 19 Dec 2015 19:39:23 +0100 Subject: [PATCH 54/64] Added slider "displayname" attribute to category files --- BodySlideApp.cpp | 23 ++++++++++++++++------- BodySlideApp.h | 2 +- SliderCategories.cpp | 28 +++++++++++++++++++++++++++- SliderCategories.h | 4 ++++ 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index 00d977e4..955bd808 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -430,8 +430,10 @@ void BodySlideApp::DisplayActiveSet() { } iter++; } + + // Not in a category if (regularSlider) - sliderView->AddSliderGUI(activeSet[i].name.c_str(), activeSet[i].bZap, !activeSet.GenWeights()); + sliderView->AddSliderGUI(activeSet[i].name, activeSet[i].name, activeSet[i].bZap, !activeSet.GenWeights()); } // Create category UI @@ -440,12 +442,19 @@ void BodySlideApp::DisplayActiveSet() { for (auto &cat : sliderCategories) { string name = get<0>(cat); bool show = get<2>(cat); + string displayName; if (catSliders.size() > iter && catSliders[iter].size() > 0) { sliderView->AddCategorySliderUI(name, show, !activeSet.GenWeights()); - if (show) - for (auto &s : catSliders[iter]) - sliderView->AddSliderGUI(activeSet[s].name.c_str(), activeSet[s].bZap, !activeSet.GenWeights()); + if (show) { + for (auto &s : catSliders[iter]) { + displayName = cCollection.GetSliderDisplayName(name, activeSet[s].name); + if (displayName.empty()) + displayName = activeSet[s].name; + + sliderView->AddSliderGUI(activeSet[s].name, displayName, activeSet[s].bZap, !activeSet.GenWeights()); + } + } } iter++; } @@ -1752,7 +1761,7 @@ void BodySlideFrame::AddCategorySliderUI(const wxString& name, bool show, bool o scrollWindow->FitInside(); } -void BodySlideFrame::AddSliderGUI(const wxString& name, bool isZap, bool oneSize) { +void BodySlideFrame::AddSliderGUI(const wxString& name, const wxString& displayName, bool isZap, bool oneSize) { wxScrolledWindow* scrollWindow = (wxScrolledWindow*)FindWindowByName("SliderScrollWindow", this); if (!scrollWindow) return; @@ -1769,7 +1778,7 @@ void BodySlideFrame::AddSliderGUI(const wxString& name, bool isZap, bool oneSize int maxValue = Config.GetIntValue("Input/SliderMaximum"); if (!oneSize) { - sd->lblSliderLo = new wxStaticText(scrollWindow, wxID_ANY, name, wxDefaultPosition, wxSize(-1, 22), wxALIGN_CENTER_HORIZONTAL); + sd->lblSliderLo = new wxStaticText(scrollWindow, wxID_ANY, displayName, wxDefaultPosition, wxSize(-1, 22), wxALIGN_CENTER_HORIZONTAL); sd->lblSliderLo->SetBackgroundColour(wxColor(0x40, 0x40, 0x40)); sd->lblSliderLo->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_SCROLLBAR)); sliderLayout->Add(sd->lblSliderLo, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT, 5); @@ -1795,7 +1804,7 @@ void BodySlideFrame::AddSliderGUI(const wxString& name, bool isZap, bool oneSize } } - sd->lblSliderHi = new wxStaticText(scrollWindow, wxID_ANY, name, wxDefaultPosition, wxSize(-1, 22), wxALIGN_CENTER_HORIZONTAL); + sd->lblSliderHi = new wxStaticText(scrollWindow, wxID_ANY, displayName, wxDefaultPosition, wxSize(-1, 22), wxALIGN_CENTER_HORIZONTAL); sd->lblSliderHi->SetBackgroundColour(wxColor(0x40, 0x40, 0x40)); sd->lblSliderHi->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_SCROLLBAR)); sliderLayout->Add(sd->lblSliderHi, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT, 5); diff --git a/BodySlideApp.h b/BodySlideApp.h index 9cb7e79d..8b4991a4 100644 --- a/BodySlideApp.h +++ b/BodySlideApp.h @@ -247,7 +247,7 @@ class BodySlideFrame : public wxFrame { void ShowLowColumn(bool show); void AddCategorySliderUI(const wxString& name, bool show, bool oneSize); - void AddSliderGUI(const wxString& name, bool isZap, bool oneSize = false); + void AddSliderGUI(const wxString& name, const wxString& displayName, bool isZap, bool oneSize = false); BodySlideFrame::SliderDisplay* GetSliderDisplay(const string& name) { if (sliderDisplays.find(name) != sliderDisplays.end()) diff --git a/SliderCategories.cpp b/SliderCategories.cpp index f14f83fa..53e50dd3 100644 --- a/SliderCategories.cpp +++ b/SliderCategories.cpp @@ -39,6 +39,14 @@ int SliderCategoryCollection::GetAllCategories(vector& outCategories) { return outCategories.size(); } +string SliderCategoryCollection::GetSliderDisplayName(const string& categoryName, const string& sliderName) { + auto git = categories.find(categoryName); + if (git == categories.end()) + return ""; + + return git->second.GetSliderDisplayName(sliderName); +} + int SliderCategoryCollection::GetSliderCategory(const string& sliderName, string& outCategory) { for (auto &c : categories) if (c.second.HasSlider(sliderName)) { @@ -105,11 +113,22 @@ int SliderCategory::LoadCategory(XMLElement* srcCategoryElement) { name = srcCategoryElement->Attribute("name"); XMLElement* slider = srcCategoryElement->FirstChildElement("Slider"); while (slider) { - string tempC = ""; + if (!slider->Attribute("name")) { + slider = slider->NextSiblingElement("Slider"); + continue; + } + string sName = slider->Attribute("name"); sliders.push_back(sName); + + if (slider->Attribute("displayname")) + displayNames[sName] = slider->Attribute("displayname"); + else + displayNames[sName] = ""; + sourceFiles.push_back(slider->GetDocument()->Value()); uniqueSourceFiles.insert(sourceFiles.back()); + slider = slider->NextSiblingElement("Slider"); } return 0; @@ -123,6 +142,13 @@ bool SliderCategory::HasSlider(const string& search) { return false; } +string SliderCategory::GetSliderDisplayName(const string& sliderName) { + if (!HasSlider(sliderName)) + return ""; + + return displayNames[sliderName]; +} + bool SliderCategory::GetHidden() { return isHidden; } diff --git a/SliderCategories.h b/SliderCategories.h index ee617a7e..512e8e86 100644 --- a/SliderCategories.h +++ b/SliderCategories.h @@ -20,6 +20,7 @@ using namespace tinyxml2; class SliderCategory { string name; vector sliders; + map displayNames; vector sourceFiles; unordered_set uniqueSourceFiles; bool isValid; @@ -49,6 +50,8 @@ class SliderCategory { int AppendSliders(vector& outSliders); int AppendSliders(unordered_set& outSliders); + string GetSliderDisplayName(const string& sliderName); + bool GetHidden(); void SetHidden(bool hide); @@ -70,6 +73,7 @@ class SliderCategoryCollection { int GetAllCategories(vector& outCategories); int GetSliderCategory(const string& sliderName, string& outCategory); + string GetSliderDisplayName(const string& categoryName, const string& sliderName); bool GetCategoryHidden(const string& categoryName); int SetCategoryHidden(const string& categoryName, bool hide); From 73969e8829bea6affc0acb6393cd127e17dc29a3 Mon Sep 17 00:00:00 2001 From: ousnius Date: Sun, 20 Dec 2015 00:10:19 +0100 Subject: [PATCH 55/64] Slider Properties dialog now hides the low value for single-weighted sets --- OutfitStudio.cpp | 6 ++++++ res/outfitStudio.xrc | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index 3da58e79..47b4f8f0 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -2843,6 +2843,12 @@ void OutfitStudio::OnSliderProperties(wxCommandEvent& WXUNUSED(event)) { tmpstr.sprintf("%d", hiVal); XRCCTRL(dlg, "edValHi", wxTextCtrl)->SetValue(tmpstr); + if (!project->mGenWeights) { + XRCCTRL(dlg, "lbValLo", wxStaticText)->Hide(); + XRCCTRL(dlg, "edValLo", wxTextCtrl)->Hide(); + XRCCTRL(dlg, "lbValHi", wxStaticText)->SetLabel("Default"); + } + if (project->SliderHidden(curSlider)) XRCCTRL(dlg, "chkHidden", wxCheckBox)->Set3StateValue(wxCheckBoxState::wxCHK_CHECKED); if (project->SliderInvert(curSlider)) diff --git a/res/outfitStudio.xrc b/res/outfitStudio.xrc index 07322403..7c40d9c2 100644 --- a/res/outfitStudio.xrc +++ b/res/outfitStudio.xrc @@ -2864,7 +2864,7 @@ wxALL 5 - + -1 @@ -2887,7 +2887,7 @@ wxALL 5 - + -1 From 4a68ac31e7126b6a7b139dc1e9f4e75524a6e1e3 Mon Sep 17 00:00:00 2001 From: ousnius Date: Sun, 20 Dec 2015 05:43:28 +0100 Subject: [PATCH 56/64] Minor fixes SkeletonBlanks_fo4.nif: Corrected numChildren of root node. Added BSTriShape to PrettySortBlocks(). Moved bone information warning to the end. --- Anim.cpp | 33 +++++++++++++++++++++------------ NifFile.cpp | 14 +++++++------- OutfitProject.cpp | 17 ++++++++++++----- OutfitStudio.cpp | 3 +-- res/SkeletonBlank_fo4.nif | Bin 6753 -> 6749 bytes 5 files changed, 41 insertions(+), 26 deletions(-) diff --git a/Anim.cpp b/Anim.cpp index 8edcce18..c7225cbe 100644 --- a/Anim.cpp +++ b/Anim.cpp @@ -303,16 +303,17 @@ void AnimInfo::WriteToNif(NifFile* nif, bool synchBoneIDs, const string& shapeEx } } + bool incomplete; SkinTransform xForm; for (auto &shapeBoneList : shapeBones) { if (shapeBoneList.first == shapeException) continue; + int stype = nif->GetShapeType(shapeBoneList.first); bool bIsFo4 = (stype == BSTRISHAPE || stype == BSSUBINDEXTRISHAPE); - - if (shapeSkinning[shapeBoneList.first].bNeedsBoundsCalc) { + + if (shapeSkinning[shapeBoneList.first].bNeedsBoundsCalc) CalcShapeSkinBounds(shapeBoneList.first); - } unordered_map vertWeights; for (auto &boneName : shapeBoneList.second) { @@ -324,12 +325,12 @@ void AnimInfo::WriteToNif(NifFile* nif, bool synchBoneIDs, const string& shapeEx int bid = GetShapeBoneIndex(shapeBoneList.first, boneName); AnimWeight& bw = shapeSkinning[shapeBoneList.first].boneWeights[bid]; if (bIsFo4) { - for (auto vw : bw.weights) { + for (auto vw : bw.weights) vertWeights[vw.first].Add(bid, vw.second); - } + AnimBone* bptr = AnimSkeleton::getInstance().GetBonePtr(boneName); - if (!bptr->hasSkinXform) { - wxMessageBox("Warning: Bone information incomplete, exported data will not contain correct BSBoneData entries! Be sure to Load a reference nif prior to export.", "Export warning"); + if (!bptr || !bptr->hasSkinXform) { + incomplete = true; nif->SetShapeBoneTransform(shapeBoneList.first, bid, bw.xform, bw.bSphereOffset, bw.bSphereRadius); } else { @@ -338,23 +339,31 @@ void AnimInfo::WriteToNif(NifFile* nif, bool synchBoneIDs, const string& shapeEx st.rotation[1] = Vector3(bptr->skinRot[4], bptr->skinRot[5], bptr->skinRot[6]); st.rotation[2] = Vector3(bptr->skinRot[8], bptr->skinRot[9], bptr->skinRot[10]); st.translation = bptr->skinTrans; - nif->SetShapeBoneTransform(shapeBoneList.first, bid,st, bw.bSphereOffset, bw.bSphereRadius); + nif->SetShapeBoneTransform(shapeBoneList.first, bid, st, bw.bSphereOffset, bw.bSphereRadius); } } else { - if (AnimSkeleton::getInstance().GetSkinTransform(boneName, xForm)) { + AnimBone* bptr = AnimSkeleton::getInstance().GetBonePtr(boneName); + if (!bptr || !bptr->hasSkinXform) { + incomplete = true; + nif->SetShapeBoneTransform(shapeBoneList.first, bid, bw.xform, bw.bSphereOffset, bw.bSphereRadius); + nif->SetShapeBoneWeights(shapeBoneList.first, bid, bw.weights); + } + else if (AnimSkeleton::getInstance().GetSkinTransform(boneName, xForm)) { nif->SetShapeBoneTransform(shapeBoneList.first, bid, xForm, bw.bSphereOffset, bw.bSphereRadius); nif->SetShapeBoneWeights(shapeBoneList.first, bid, bw.weights); } } } + if (bIsFo4) { - for (auto vid : vertWeights) { + for (auto vid : vertWeights) nif->SetShapeVertWeights(shapeBoneList.first, vid.first, vid.second.boneIds, vid.second.weights); - } - } } + + if (incomplete) + wxMessageBox("Bone information incomplete. Exported data will not contain correct bone entries! Be sure to load a reference NIF prior to export.", "Export Warning", wxICON_WARNING); } void AnimInfo::RenameShape(const string& shapeName, const string& newShapeName) { diff --git a/NifFile.cpp b/NifFile.cpp index 770c43f5..34754a88 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -448,16 +448,15 @@ void NifFile::SetShapeOrder(vector order) { } -void NifFile::PrettySortBlocks() { +void NifFile::PrettySortBlocks() { NiNode* root = (NiNode*)blocks[0]; vector oldchildren(root->children.begin(), root->children.end()); root->children.clear(); - for (int i = 0; i < blocks.size();i++) { - if (std::find(oldchildren.begin(), oldchildren.end(), i)!=oldchildren.end()) { + for (int i = 0; i < blocks.size(); i++) { + if (std::find(oldchildren.begin(), oldchildren.end(), i) != oldchildren.end()) { root->children.push_back(i); } - } auto bookmark = root->children.begin(); @@ -465,11 +464,12 @@ void NifFile::PrettySortBlocks() { for (int i = 0; peek < root->children.end(); i++) { NiObject* block = GetBlock(root->children[i]); - if (block->blockType == BlockType::NITRISHAPE || - block->blockType == BlockType::NITRISTRIPS) { + if (block->blockType == NITRISHAPE || + block->blockType == NITRISTRIPS || + block->blockType == BSTRISHAPE || block->blockType == BSSUBINDEXTRISHAPE) { iter_swap(bookmark, peek); bookmark++; - } + } peek++; } } diff --git a/OutfitProject.cpp b/OutfitProject.cpp index e6104509..8e47d395 100644 --- a/OutfitProject.cpp +++ b/OutfitProject.cpp @@ -1989,25 +1989,32 @@ int OutfitProject::ImportShapeFBX(const string& fileName, const string& shapeNam return 100; } + CreateNifShapeFromData(s, shape->verts, shape->tris, shape->uvs, &shape->normals); int slot = 0; + vector boneIndices; for (auto &bn : shape->boneNames) { if (!AnimSkeleton::getInstance().RefBone(bn)) { - // no bone reference exist for this bone name. + // Not found in reference skeleton, use default values AnimBone& cstm = AnimSkeleton::getInstance().AddBone(bn, true); if (!cstm.isValidBone) invalidBones += bn + "\n"; - // using default transformation data, needs to be set up later somehow.... + AnimSkeleton::getInstance().RefBone(bn); } + workAnim.shapeBones[useShapeName].push_back(bn); workAnim.shapeSkinning[useShapeName].boneNames[bn] = slot; workAnim.SetWeights(useShapeName, bn, shape->boneSkin[bn].vertweights); - //workAnim.shapeSkinning[useShapeName].boneWeights[slot].weights = shape->boneSkin[bn].vertweights; - slot++; + boneIndices.push_back(slot++); } - CreateNifShapeFromData(s, shape->verts, shape->tris, shape->uvs, &shape->normals); + workNif.SetShapeBoneIDList(useShapeName, boneIndices); + + if (!invalidBones.empty()) { + wxLogWarning("Bones in shape '%s' not found in reference skeleton:\n%s", useShapeName, invalidBones); + wxMessageBox(wxString::Format("Bones in shape '%s' not found in reference skeleton:\n\n%s", useShapeName, invalidBones), "Invalid Bones"); + } } return 0; diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index 47b4f8f0..dda1a67c 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -3047,8 +3047,7 @@ void OutfitStudio::OnImportFBX(wxCommandEvent& WXUNUSED(event)) { wxLogMessage("Imported shape."); - WorkingGUIFromProj(); - AnimationGUIFromProj(); + RefreshGUIFromProj(); glView->Refresh(); } diff --git a/res/SkeletonBlank_fo4.nif b/res/SkeletonBlank_fo4.nif index ff901730d4462ea79b0b85e00d9bd76afaedde82..b5d6c4272e75ccd8483627628014ee6187de3306 100644 GIT binary patch delta 34 qcmaE8a@S;o1S69T<77F;casemSvK=9wX!nWOrFI4d2=Vn4M70JaSLkz delta 39 ucmca>^3Y_11S69J<77F;casemSvK=9wX!nWPM*a6ndLtaY;NVaAqW5wGY@P4 From 8032bfcdbbbf1b395be5730185c5e54f380bd568 Mon Sep 17 00:00:00 2001 From: ousnius Date: Sun, 20 Dec 2015 06:16:24 +0100 Subject: [PATCH 57/64] Fixed warning 4a68ac3 --- Anim.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Anim.cpp b/Anim.cpp index c7225cbe..246529df 100644 --- a/Anim.cpp +++ b/Anim.cpp @@ -303,7 +303,7 @@ void AnimInfo::WriteToNif(NifFile* nif, bool synchBoneIDs, const string& shapeEx } } - bool incomplete; + bool incomplete = false; SkinTransform xForm; for (auto &shapeBoneList : shapeBones) { if (shapeBoneList.first == shapeException) From 74b535e8a16a7cba4ba0744b7eb98cadf7a05253 Mon Sep 17 00:00:00 2001 From: ousnius Date: Sun, 20 Dec 2015 22:20:12 +0100 Subject: [PATCH 58/64] Fixed "Keep other shapes" load and name of copied shaders --- NifFile.cpp | 3 ++- OutfitStudio.cpp | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NifFile.cpp b/NifFile.cpp index 34754a88..e510577b 100644 --- a/NifFile.cpp +++ b/NifFile.cpp @@ -864,7 +864,8 @@ void NifFile::CopyShader(const string& shapeDest, int srcShaderRef, NifFile& src return; destShader->header = &hdr; - destShader->nameRef = 0xFFFFFFFF; + destShader->nameRef = AddOrFindStringId(srcShader->name); + destShader->name = srcShader->name; // Add shader block to nif int shaderId = blocks.size(); diff --git a/OutfitStudio.cpp b/OutfitStudio.cpp index dda1a67c..b5abe429 100644 --- a/OutfitStudio.cpp +++ b/OutfitStudio.cpp @@ -1095,7 +1095,6 @@ void OutfitStudio::OnLoadOutfit(wxCommandEvent& WXUNUSED(event)) { int ret = 0; if (XRCCTRL(dlg, "npWorkNif", wxRadioButton)->GetValue() == true) { - project->ClearOutfit(); if (!XRCCTRL(dlg, "npWorkAdd", wxCheckBox)->IsChecked()) { ret = project->AddNif(XRCCTRL(dlg, "npNifFilename", wxFilePickerCtrl)->GetPath().ToStdString(), true, outfitName); } From f897872148b0aa94e4547bf738365c8a1de55ced Mon Sep 17 00:00:00 2001 From: ousnius Date: Sun, 20 Dec 2015 22:50:10 +0100 Subject: [PATCH 59/64] Fixed zap indices not clearing on build --- BodySlideApp.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index 955bd808..8a5283f2 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -1224,6 +1224,7 @@ int BodySlideApp::BuildBodies(bool localPath, bool clean, bool tri) { } zapIdxAll[it->second] = zapIdx; + zapIdx.clear(); } /* Add RaceMenu TRI path for in-game morphs */ @@ -1442,7 +1443,6 @@ int BodySlideApp::BuildListBodies(const vector& outfitList, map clamps; - zapIdx.clear(); zapIdxAll.emplace(it->second, vector()); for (int s = 0; s < currentSet.size(); s++) { @@ -1517,6 +1517,8 @@ int BodySlideApp::BuildListBodies(const vector& outfitList, mapsecond, vertsLow); nifSmall.DeleteVertsForShape(it->second, zapIdx); } + + zapIdx.clear(); } /* Create directory for the outfit */ From 1e7276a901a5e91c4ec0384cd40be93c327c61a4 Mon Sep 17 00:00:00 2001 From: ousnius Date: Tue, 22 Dec 2015 17:01:21 +0100 Subject: [PATCH 60/64] Fixed default slider value using the wrong weight for single-weight --- SliderSet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SliderSet.cpp b/SliderSet.cpp index 586163fd..26804c9b 100644 --- a/SliderSet.cpp +++ b/SliderSet.cpp @@ -193,7 +193,7 @@ void SliderSet::WriteSliderSet(XMLElement* sliderSetElement) { sliderElement->SetAttribute("big", (int)slider.defBigValue); } else - sliderElement->SetAttribute("default", (int)slider.defSmallValue); + sliderElement->SetAttribute("default", (int)slider.defBigValue); if (slider.bHidden) sliderElement->SetAttribute("hidden", "true"); From 7ac22dde299ccbca9c5c7e03000658a3d1b53736 Mon Sep 17 00:00:00 2001 From: ousnius Date: Tue, 22 Dec 2015 18:19:57 +0100 Subject: [PATCH 61/64] Added conversion references to Config.xml --- Config.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Config.xml b/Config.xml index 67acb11a..088f3eb0 100644 --- a/Config.xml +++ b/Config.xml @@ -43,7 +43,11 @@ 45 - + + + + + res\skeleton_fo4.nif From 50a0e9dcecd518551e5fe067e3a5c2fc0c540d58 Mon Sep 17 00:00:00 2001 From: ousnius Date: Tue, 22 Dec 2015 23:11:08 +0100 Subject: [PATCH 62/64] BSSkinInstance initialize target ref properly --- NifBlock.cpp | 6 +++--- NifFile.h | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/NifBlock.cpp b/NifBlock.cpp index e0dabde7..3f091e06 100644 --- a/NifBlock.cpp +++ b/NifBlock.cpp @@ -2625,7 +2625,7 @@ BSSkinInstance::BSSkinInstance(fstream& file, NiHeader& hdr) { void BSSkinInstance::Init() { NiObject::Init(); - unk = 0; + targetRef = 0xFFFFFFFF; boneDataRef = 0xFFFFFFFF; numBones = 0; numVertices = 0; @@ -2635,7 +2635,7 @@ void BSSkinInstance::Get(fstream& file) { NiObject::Get(file); uint intData; - file.read((char*)&unk, 4); + file.read((char*)&targetRef, 4); file.read((char*)&boneDataRef, 4); file.read((char*)&numBones, 4); for (int i = 0; i < numBones; i++) { @@ -2649,7 +2649,7 @@ void BSSkinInstance::Get(fstream& file) { void BSSkinInstance::Put(fstream& file) { NiObject::Put(file); - file.write((char*)&unk, 4); + file.write((char*)&targetRef, 4); file.write((char*)&boneDataRef, 4); file.write((char*)&numBones, 4); for (int i = 0; i < numBones; i++) { diff --git a/NifFile.h b/NifFile.h index dd3f19eb..e8f87186 100644 --- a/NifFile.h +++ b/NifFile.h @@ -649,13 +649,12 @@ class BSDismemberSkinInstance : public NiSkinInstance { class BSSkinInstance : public NiBoneContainer { public: - uint unk; + int targetRef; int boneDataRef; uint numVertices; vector vertexWeights; - - BSSkinInstance() : unk(0), boneDataRef(-1), numVertices(0) { numBones = 0; }; + BSSkinInstance() : targetRef(-1), boneDataRef(-1), numVertices(0) { numBones = 0; }; BSSkinInstance(NiHeader& hdr); BSSkinInstance(fstream& file, NiHeader& hdr); From b5ce9092b385ee696320901d30710c162a8cf2f5 Mon Sep 17 00:00:00 2001 From: ousnius Date: Wed, 23 Dec 2015 13:21:36 +0100 Subject: [PATCH 63/64] Hide slider copy buttons for single-weighted sets --- BodySlideApp.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/BodySlideApp.cpp b/BodySlideApp.cpp index 8a5283f2..3c1fabf0 100644 --- a/BodySlideApp.cpp +++ b/BodySlideApp.cpp @@ -1711,15 +1711,19 @@ void BodySlideFrame::ShowLowColumn(bool show) { return; if (show) { - XRCCTRL(*this, "lblLowWt", wxStaticText)->Show(true); - XRCCTRL(*this, "lblHighWt", wxStaticText)->Show(true); - XRCCTRL(*this, "lblSingleWt", wxStaticText)->Show(false); + XRCCTRL(*this, "lblLowWt", wxStaticText)->Show(); + XRCCTRL(*this, "lblHighWt", wxStaticText)->Show(); + XRCCTRL(*this, "lblSingleWt", wxStaticText)->Hide(); + XRCCTRL(*this, "btnLowToHigh", wxButton)->Show(); + XRCCTRL(*this, "btnHighToLow", wxButton)->Show(); sliderLayout->SetCols(6); } else { - XRCCTRL(*this, "lblLowWt", wxStaticText)->Show(false); - XRCCTRL(*this, "lblHighWt", wxStaticText)->Show(false); - XRCCTRL(*this, "lblSingleWt", wxStaticText)->Show(true); + XRCCTRL(*this, "lblLowWt", wxStaticText)->Hide(); + XRCCTRL(*this, "lblHighWt", wxStaticText)->Hide(); + XRCCTRL(*this, "lblSingleWt", wxStaticText)->Show(); + XRCCTRL(*this, "btnLowToHigh", wxButton)->Hide(); + XRCCTRL(*this, "btnHighToLow", wxButton)->Hide(); sliderLayout->SetCols(3); } } From a6061cdca818172cd1f2f5c15a5a0f12a0059329 Mon Sep 17 00:00:00 2001 From: ousnius Date: Wed, 23 Dec 2015 15:24:00 +0100 Subject: [PATCH 64/64] Tooltip updates --- res/BodyslideFrame.xrc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/res/BodyslideFrame.xrc b/res/BodyslideFrame.xrc index a41a1a4c..5d5496d4 100644 --- a/res/BodyslideFrame.xrc +++ b/res/BodyslideFrame.xrc @@ -227,7 +227,7 @@ 128,-1 #000000 - Build multiple outfits using the currently selected preset.\nNote: You must save slider settings to a preset before you can batch build with them.\n\nHold CTRL = Build to custom folders\nHold ALT = Clean all files from folders + Build multiple outfits using the currently active slider values.\n\nHold CTRL = Build to custom directory\nHold ALT = Delete from output directory @@ -238,7 +238,7 @@ #c8c8c8 - Builds a TRI file alongside the low and high weight meshes for accessing the sliders in-game. Requires the RaceMenu mod and matching plugin/scripts for the collection of sliders. + Builds a morphs (.tri) file alongside the meshes for accessing the sliders in-game. Requires the RaceMenu mod and matching plugin/scripts for the collection of sliders.
@@ -276,7 +276,7 @@ Andalus #000000 - Create the low and high weight meshes for the currently selected outfit.\n\nHold CTRL = Build to custom folder\nHold ALT = Clean all files from folder + Creates the currently selected outfit/body.\n\nHold CTRL = Build to working directory\nHold ALT = Delete from output directory 0