331 lines
8.3 KiB
C++
331 lines
8.3 KiB
C++
// Metin2MSAMaker.cpp : Defines the entry point for the console application.
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include <windows.h>
|
|
|
|
#include "ModelManager.h"
|
|
|
|
#if GrannyProductMinorVersion==4
|
|
#pragma comment( lib, "granny2.4.0.10.lib" )
|
|
#elif GrannyProductMinorVersion==7
|
|
#pragma comment( lib, "granny2.7.0.30.lib" )
|
|
#elif GrannyProductMinorVersion==9
|
|
#pragma comment( lib, "granny2.9.12.0.lib" )
|
|
#elif GrannyProductMinorVersion==11
|
|
#pragma comment( lib, "granny2.11.8.0.lib" )
|
|
#else
|
|
#error "unknown granny version"
|
|
#endif
|
|
|
|
typedef std::list<fs::path> TPathInfoList;
|
|
|
|
static std::string s_IgnoreKeywords[] = { "ComboInputData", "AttackingData", "MotionEventData", "LoopData", };
|
|
|
|
bool FileIntoString(const fs::path& path, std::string* outString = NULL)
|
|
{
|
|
assert(NULL != outString);
|
|
|
|
fs::ifstream fs;
|
|
std::string line;
|
|
|
|
fs.open(path, std::ios::in);
|
|
|
|
if (!fs.is_open())
|
|
{
|
|
char errorMsg[255] = {0, };
|
|
strerror_s(errorMsg, sizeof(errorMsg), errno);
|
|
|
|
printf("[FAIL] %s\n\t%s \n", path.string().c_str(), errorMsg);
|
|
|
|
return true;
|
|
}
|
|
|
|
outString->clear();
|
|
|
|
fs.clear();
|
|
|
|
while(std::getline(fs, line))
|
|
outString->append(line);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool IsNeedIgnoreMSA(const fs::path& msaPath)
|
|
{
|
|
if (false == fs::is_regular_file(msaPath))
|
|
return false;
|
|
|
|
std::string fileContent;
|
|
if (false == FileIntoString(msaPath, &fileContent))
|
|
return false;
|
|
|
|
for (size_t i = 0; i < _countof(s_IgnoreKeywords); ++i)
|
|
if (fileContent.find(s_IgnoreKeywords[i]) != std::string::npos)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool IsNeedCalcAccumulation(const fs::path& path)
|
|
{
|
|
static std::string s_NeedCalcAccumulations[] = {"walk", "run" };
|
|
|
|
const std::string filename = boost::algorithm::to_lower_copy(path.string());
|
|
|
|
for (size_t i = 0; i < _countof(s_NeedCalcAccumulations); ++i)
|
|
{
|
|
if (filename.find(s_NeedCalcAccumulations[i]) != std::string::npos)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
enum EResult
|
|
{
|
|
EResult_OK,
|
|
EResult_Ignore,
|
|
EResult_Fail
|
|
};
|
|
|
|
|
|
EResult MakeMSA(const fs::path& filePath, std::string* outMsg = 0)
|
|
{
|
|
const int axisCount = 3;
|
|
bool bIsAccumulationMotion = true;
|
|
granny_real32 duration = 0.0f;
|
|
granny_real32* Accumulation = 0; // @fixme401
|
|
granny_matrix_4x4 modelMatrix = { 0, 0, 0 };
|
|
|
|
assert(0 != outMsg);
|
|
|
|
*outMsg = "OK";
|
|
|
|
if (false == CModel::IsGrannyFile(filePath))
|
|
return EResult_Fail;
|
|
|
|
fs::path basePath = filePath.parent_path();
|
|
|
|
fs::path msaPath = basePath / (filePath.stem().string() + ".msa");
|
|
|
|
if (IsNeedIgnoreMSA(msaPath))
|
|
{
|
|
*outMsg = "FAIL - Complicated MSA";
|
|
return EResult_Ignore;
|
|
}
|
|
|
|
|
|
granny_file* grannyFile = GrannyReadEntireFile(filePath.string().c_str());
|
|
granny_file_info* fileInfo = GrannyGetFileInfo(grannyFile);
|
|
|
|
if (1 != fileInfo->AnimationCount)
|
|
{
|
|
*outMsg = "IGNORE - NO Animation";
|
|
|
|
if (1 < fileInfo->AnimationCount)
|
|
*outMsg = "IGNORE - Too many animations";
|
|
|
|
if (0 < fileInfo->ModelCount)
|
|
{
|
|
CModelManager::Instance().RegisterModel(filePath);
|
|
*outMsg = "IGNORE - MODEL FILE(NO Animation)";
|
|
}
|
|
|
|
GrannyFreeFile(grannyFile);
|
|
return EResult_Ignore;
|
|
}
|
|
|
|
|
|
CModel* modelWrapper = CModelManager::Instance().GetModel(filePath);
|
|
if (0 == modelWrapper)
|
|
{
|
|
modelWrapper = CModelManager::Instance().GetModel(filePath.parent_path());
|
|
|
|
if (0 == modelWrapper)
|
|
{
|
|
modelWrapper = CModelManager::Instance().AutoRegisterAndGetModel(filePath, 2);
|
|
}
|
|
|
|
if (0 == modelWrapper)
|
|
{
|
|
*outMsg = "FAIL - Can't find model file";
|
|
GrannyFreeFile(grannyFile);
|
|
return EResult_Fail;
|
|
}
|
|
}
|
|
|
|
|
|
for (int i = 0; i < fileInfo->AnimationCount; ++i)
|
|
{
|
|
granny_animation* animation = fileInfo->Animations[i];
|
|
granny_model* model = modelWrapper->GetModel();
|
|
const int boneCount = model->Skeleton->BoneCount;
|
|
duration = animation->Duration;
|
|
// @fixme401 BEGIN
|
|
granny_track_group* trackGroup = fileInfo->TrackGroups[i];
|
|
Accumulation = trackGroup->LoopTranslation;
|
|
// @fixme401 END
|
|
|
|
if (IsNeedCalcAccumulation(filePath))
|
|
{
|
|
int trackIndex = -1, bip01Index = -1;
|
|
|
|
if (!GrannyFindTrackGroupForModel(animation, model->Name, &trackIndex))
|
|
trackIndex = 0;
|
|
|
|
if (1 > animation->TrackGroupCount)
|
|
{
|
|
*outMsg = "FAIL - Invalid Track Group Count";
|
|
GrannyFreeFile(grannyFile);
|
|
return EResult_Fail;
|
|
}
|
|
|
|
if (!GrannyFindBoneByName(model->Skeleton, "Bip01", &bip01Index))
|
|
bip01Index = 0;
|
|
|
|
granny_model_instance* modelInstance = GrannyInstantiateModel(model);
|
|
|
|
granny_local_pose* localPose = GrannyNewLocalPose(boneCount);
|
|
granny_world_pose* worldPose = GrannyNewWorldPose(boneCount);
|
|
|
|
granny_controlled_animation_builder *builder = GrannyBeginControlledAnimation(0.0f, animation);
|
|
GrannySetTrackGroupTarget(builder, trackIndex, modelInstance);
|
|
GrannySetTrackGroupAccumulation(builder, trackIndex, GrannyConstantExtractionAccumulation);
|
|
granny_control* control = GrannyEndControlledAnimation(builder);
|
|
|
|
GrannySetControlClock(control, 0.0f);
|
|
|
|
modelMatrix[0][0] = modelMatrix[1][1] = modelMatrix[2][2] = modelMatrix[3][3] = 1.0f;
|
|
#if GrannyProductMinorVersion==4
|
|
GrannyUpdateModelMatrix(modelInstance, 0.0f, (granny_real32*)modelMatrix, (granny_real32*)modelMatrix);
|
|
#elif GrannyProductMinorVersion==11 || GrannyProductMinorVersion==9 || GrannyProductMinorVersion==7
|
|
GrannyUpdateModelMatrix(modelInstance, 0.0f, (granny_real32*)modelMatrix, (granny_real32*)modelMatrix, false);
|
|
#else
|
|
#error "unknown granny version"
|
|
#endif
|
|
|
|
modelMatrix[0][0] = modelMatrix[1][1] = modelMatrix[2][2] = modelMatrix[3][3] = 1.0f;
|
|
#if GrannyProductMinorVersion==4
|
|
GrannyUpdateModelMatrix(modelInstance, animation->Duration - 0.000001f, (granny_real32*)modelMatrix, (granny_real32*)modelMatrix);
|
|
#elif GrannyProductMinorVersion==11 || GrannyProductMinorVersion==9 || GrannyProductMinorVersion==7
|
|
GrannyUpdateModelMatrix(modelInstance, animation->Duration - 0.000001f, (granny_real32*)modelMatrix, (granny_real32*)modelMatrix, false);
|
|
#else
|
|
#error "unknown granny version"
|
|
#endif
|
|
|
|
if (40.0f < fabs(Accumulation[1])) // @fixme401 modelMatrix[3] -> Accumulation
|
|
bIsAccumulationMotion = true;
|
|
|
|
GrannyFreeControlOnceUnused(control);
|
|
GrannyFreeCompletedModelControls(modelInstance);
|
|
GrannyFreeLocalPose(localPose);
|
|
GrannyFreeWorldPose(worldPose);
|
|
|
|
GrannyFreeModelInstance(modelInstance);
|
|
}
|
|
}
|
|
|
|
GrannyFreeFile(grannyFile);
|
|
|
|
|
|
#if 1
|
|
FILE* fp = 0;
|
|
fopen_s(&fp, msaPath.string().c_str(), "wt");
|
|
|
|
if (0 == fp)
|
|
{
|
|
*outMsg = "FAIL - Can't write MSA file";
|
|
return EResult_Fail;
|
|
}
|
|
|
|
|
|
fprintf(fp, "ScriptType MotionData\n");
|
|
fprintf(fp, "\n");
|
|
|
|
fprintf(fp, "MotionFileName \"%s\"\n", filePath.string().c_str());
|
|
fprintf(fp, "MotionDuration %f\n", duration);
|
|
|
|
if (bIsAccumulationMotion)
|
|
fprintf(fp, "Accumulation %.2f\t%.2f\t%.2f\n", 0.0f, Accumulation[1], 0.0f); // @fixme401 modelMatrix[3] -> Accumulation
|
|
|
|
fprintf(fp, "\n");
|
|
|
|
fclose(fp);
|
|
#endif
|
|
|
|
return EResult_OK;
|
|
}
|
|
|
|
int _tmain(int argc, _TCHAR* argv[])
|
|
{
|
|
TPathInfoList pathInfoList;
|
|
|
|
std::locale::global(std::locale("kor"));
|
|
std::string msg;
|
|
|
|
FILE* fpLog = 0;
|
|
|
|
// stdout stream redirection to log file
|
|
std::string logPath = std::string(argv[0]) + ".log";
|
|
freopen_s(&fpLog, logPath.c_str(), "a+t", stdout);
|
|
|
|
|
|
for (int i = 1; i < argc; ++i)
|
|
{
|
|
fs::path inPath = argv[i];
|
|
|
|
if (false == fs::exists(inPath))
|
|
continue;
|
|
|
|
const bool bIsDirectory = is_directory(inPath);
|
|
|
|
if (CModel::IsGrannyFile(inPath))
|
|
{
|
|
if (CModel::IsGrannyModelFile(inPath))
|
|
{
|
|
CModelManager::Instance().RegisterModel(inPath);
|
|
}
|
|
else
|
|
pathInfoList.push_back(inPath);
|
|
}
|
|
|
|
if (bIsDirectory)
|
|
{
|
|
for (boost::filesystem::recursive_directory_iterator end, dir_iter(inPath); dir_iter != end; ++dir_iter)
|
|
{
|
|
const fs::path& curPath = *dir_iter;
|
|
|
|
if (CModel::IsGrannyFile(curPath))
|
|
pathInfoList.push_back(curPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (TPathInfoList::iterator iter = pathInfoList.begin(); iter != pathInfoList.end(); ++iter)
|
|
{
|
|
const TPathInfoList::value_type& path = *iter;
|
|
|
|
EResult resultCode = MakeMSA(path, &msg);
|
|
|
|
fs::path parentPath = path.parent_path();
|
|
std::string shortPath = parentPath.parent_path().filename().string() + "\\" + parentPath.filename().string() + "\\" + path.filename().string();
|
|
|
|
tm t;
|
|
time_t timer;
|
|
timer = time(NULL);
|
|
localtime_s(&t, &timer);
|
|
|
|
printf("%04d/%02d/%02d %02d:%02d:%02d [%s] %s\n",
|
|
t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
|
|
msg.c_str(), shortPath.c_str());
|
|
}
|
|
|
|
CModelManager::Instance().Destroy();
|
|
|
|
return 0;
|
|
}
|
|
//martysama0134's 2e58d0b8baeb072acdf3afc4a5d1999f
|