mirror of https://github.com/AxioDL/metaforce.git
Add ability to search for blender version dynamically
This commit is contained in:
parent
77bef70555
commit
8fc39c4ce6
|
@ -57,7 +57,7 @@ class PathHasher:
|
||||||
read_str = readpipestr()
|
read_str = readpipestr()
|
||||||
return int(read_str[0:8], 16)
|
return int(read_str[0:8], 16)
|
||||||
|
|
||||||
# Ensure Blender 2.90 is being used
|
# Ensure Blender 2.90+ is being used
|
||||||
if bpy.app.version < (2, 90, 0):
|
if bpy.app.version < (2, 90, 0):
|
||||||
writepipestr(b'NOT290')
|
writepipestr(b'NOT290')
|
||||||
_quitblender()
|
_quitblender()
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 1805568808e8c78450365fef7d55cf7d0c985ab0
|
Subproject commit 1d0727fae08bf0c8260174015e3b74679b2eb6f0
|
|
@ -48,6 +48,11 @@ using namespace std::literals;
|
||||||
|
|
||||||
namespace hecl::blender {
|
namespace hecl::blender {
|
||||||
|
|
||||||
|
static const uint32_t MinBlenderMajorSearch = 2;
|
||||||
|
static const uint32_t MaxBlenderMajorSearch = 2;
|
||||||
|
static const uint32_t MinBlenderMinorSearch = 90;
|
||||||
|
static const uint32_t MaxBlenderMinorSearch = 91;
|
||||||
|
|
||||||
logvisor::Module BlenderLog("hecl::blender::Connection");
|
logvisor::Module BlenderLog("hecl::blender::Connection");
|
||||||
Token SharedBlenderToken;
|
Token SharedBlenderToken;
|
||||||
|
|
||||||
|
@ -342,6 +347,7 @@ Connection::Connection(int verbosityLevel) {
|
||||||
|
|
||||||
/* User-specified blender path */
|
/* User-specified blender path */
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
|
wchar_t BLENDER_BIN_BUF[2048];
|
||||||
std::wstring blenderBinBuf;
|
std::wstring blenderBinBuf;
|
||||||
const wchar_t* blenderBin = _wgetenv(L"BLENDER_BIN");
|
const wchar_t* blenderBin = _wgetenv(L"BLENDER_BIN");
|
||||||
#else
|
#else
|
||||||
|
@ -364,12 +370,24 @@ Connection::Connection(int verbosityLevel) {
|
||||||
if (!RegFileExists(blenderBin)) {
|
if (!RegFileExists(blenderBin)) {
|
||||||
/* No steam; try default */
|
/* No steam; try default */
|
||||||
wchar_t progFiles[256];
|
wchar_t progFiles[256];
|
||||||
if (!GetEnvironmentVariableW(L"ProgramFiles", progFiles, 256))
|
if (GetEnvironmentVariableW(L"ProgramFiles", progFiles, 256)) {
|
||||||
BlenderLog.report(logvisor::Fatal, FMT_STRING(L"unable to determine 'Program Files' path"));
|
for (size_t major = MinBlenderMajorSearch; major <= MaxBlenderMajorSearch; ++major) {
|
||||||
blenderBinBuf = fmt::format(FMT_STRING(L"{}\\Blender Foundation\\Blender 2.90\\blender.exe"), progFiles);
|
bool found = false;
|
||||||
blenderBin = blenderBinBuf.c_str();
|
for (size_t minor = MinBlenderMinorSearch; minor <= MaxBlenderMinorSearch; ++minor) {
|
||||||
if (!RegFileExists(blenderBin))
|
_snwprintf(BLENDER_BIN_BUF, 2048, L"%s\\Blender Foundation\\Blender %i.%i\\blender.exe", progFiles, major,
|
||||||
BlenderLog.report(logvisor::Fatal, FMT_STRING(L"unable to find {}"), blenderBin);
|
minor);
|
||||||
|
if (RegFileExists(BLENDER_BIN_BUF)) {
|
||||||
|
blenderBin = BLENDER_BIN_BUF;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,7 +413,8 @@ Connection::Connection(int verbosityLevel) {
|
||||||
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0,
|
nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0,
|
||||||
nullptr);
|
nullptr);
|
||||||
BlenderLog.report(logvisor::Fatal, FMT_STRING(L"unable to launch blender from {}: {}"), blenderBin, messageBuffer);
|
BlenderLog.report(logvisor::Fatal, FMT_STRING(L"unable to launch blender from {}: {}"), blenderBin,
|
||||||
|
messageBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(m_writepipe[0]);
|
close(m_writepipe[0]);
|
||||||
|
@ -417,7 +436,8 @@ Connection::Connection(int verbosityLevel) {
|
||||||
if (err == ERROR_BROKEN_PIPE)
|
if (err == ERROR_BROKEN_PIPE)
|
||||||
break; // pipe done - normal exit path.
|
break; // pipe done - normal exit path.
|
||||||
else
|
else
|
||||||
BlenderLog.report(logvisor::Error, FMT_STRING("Error with ReadFile: {:08X}"), err); // Something bad happened.
|
BlenderLog.report(logvisor::Error, FMT_STRING("Error with ReadFile: {:08X}"),
|
||||||
|
err); // Something bad happened.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display the character read on the screen.
|
// Display the character read on the screen.
|
||||||
|
@ -623,14 +643,14 @@ std::streamsize PyOutStream::StreamBuf::xsputn(const char_type* __first, std::st
|
||||||
return __n;
|
return __n;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr std::array<std::string_view, 12> BlendTypeStrs{
|
constexpr std::array<std::string_view, 12> BlendTypeStrs{"NONE"sv, "MESH"sv, "CMESH"sv, "ARMATURE"sv,
|
||||||
"NONE"sv, "MESH"sv, "CMESH"sv, "ARMATURE"sv, "ACTOR"sv, "AREA"sv,
|
"ACTOR"sv, "AREA"sv, "WORLD"sv, "MAPAREA"sv,
|
||||||
"WORLD"sv, "MAPAREA"sv, "MAPUNIVERSE"sv, "FRAME"sv, "PATH"sv
|
"MAPUNIVERSE"sv, "FRAME"sv, "PATH"sv};
|
||||||
};
|
|
||||||
|
|
||||||
bool Connection::createBlend(const ProjectPath& path, BlendType type) {
|
bool Connection::createBlend(const ProjectPath& path, BlendType type) {
|
||||||
if (m_lock) {
|
if (m_lock) {
|
||||||
BlenderLog.report(logvisor::Fatal, FMT_STRING("BlenderConnection::createBlend() musn't be called with stream active"));
|
BlenderLog.report(logvisor::Fatal,
|
||||||
|
FMT_STRING("BlenderConnection::createBlend() musn't be called with stream active"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_writeStr(fmt::format(FMT_STRING("CREATE \"{}\" {}"), path.getAbsolutePathUTF8(), BlendTypeStrs[int(type)]));
|
_writeStr(fmt::format(FMT_STRING("CREATE \"{}\" {}"), path.getAbsolutePathUTF8(), BlendTypeStrs[int(type)]));
|
||||||
|
@ -646,7 +666,8 @@ bool Connection::createBlend(const ProjectPath& path, BlendType type) {
|
||||||
|
|
||||||
bool Connection::openBlend(const ProjectPath& path, bool force) {
|
bool Connection::openBlend(const ProjectPath& path, bool force) {
|
||||||
if (m_lock) {
|
if (m_lock) {
|
||||||
BlenderLog.report(logvisor::Fatal, FMT_STRING("BlenderConnection::openBlend() musn't be called with stream active"));
|
BlenderLog.report(logvisor::Fatal,
|
||||||
|
FMT_STRING("BlenderConnection::openBlend() musn't be called with stream active"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!force && path == m_loadedBlend)
|
if (!force && path == m_loadedBlend)
|
||||||
|
@ -678,7 +699,8 @@ bool Connection::openBlend(const ProjectPath& path, bool force) {
|
||||||
|
|
||||||
bool Connection::saveBlend() {
|
bool Connection::saveBlend() {
|
||||||
if (m_lock) {
|
if (m_lock) {
|
||||||
BlenderLog.report(logvisor::Fatal, FMT_STRING("BlenderConnection::saveBlend() musn't be called with stream active"));
|
BlenderLog.report(logvisor::Fatal,
|
||||||
|
FMT_STRING("BlenderConnection::saveBlend() musn't be called with stream active"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_writeStr("SAVE");
|
_writeStr("SAVE");
|
||||||
|
@ -710,28 +732,30 @@ void PyOutStream::close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PyOutStream::linkBlend(std::string_view target, std::string_view objName, bool link) {
|
void PyOutStream::linkBlend(std::string_view target, std::string_view objName, bool link) {
|
||||||
format(FMT_STRING("if '{}' not in bpy.data.scenes:\n"
|
format(
|
||||||
" with bpy.data.libraries.load('''{}''', link={}, relative=True) as (data_from, data_to):\n"
|
FMT_STRING("if '{}' not in bpy.data.scenes:\n"
|
||||||
" data_to.scenes = data_from.scenes\n"
|
" with bpy.data.libraries.load('''{}''', link={}, relative=True) as (data_from, data_to):\n"
|
||||||
" obj_scene = None\n"
|
" data_to.scenes = data_from.scenes\n"
|
||||||
" for scene in data_to.scenes:\n"
|
" obj_scene = None\n"
|
||||||
" if scene.name == '{}':\n"
|
" for scene in data_to.scenes:\n"
|
||||||
" obj_scene = scene\n"
|
" if scene.name == '{}':\n"
|
||||||
" break\n"
|
" obj_scene = scene\n"
|
||||||
" if not obj_scene:\n"
|
" break\n"
|
||||||
" raise RuntimeError('''unable to find {} in {}. try deleting it and restart the extract.''')\n"
|
" if not obj_scene:\n"
|
||||||
" obj = None\n"
|
" raise RuntimeError('''unable to find {} in {}. try deleting it and restart the extract.''')\n"
|
||||||
" for object in obj_scene.objects:\n"
|
" obj = None\n"
|
||||||
" if object.name == obj_scene.name:\n"
|
" for object in obj_scene.objects:\n"
|
||||||
" obj = object\n"
|
" if object.name == obj_scene.name:\n"
|
||||||
"else:\n"
|
" obj = object\n"
|
||||||
" obj = bpy.data.objects['{}']\n"
|
"else:\n"
|
||||||
"\n"),
|
" obj = bpy.data.objects['{}']\n"
|
||||||
objName, target, link ? "True" : "False", objName, objName, target, objName);
|
"\n"),
|
||||||
|
objName, target, link ? "True" : "False", objName, objName, target, objName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PyOutStream::linkArmature(std::string_view target, std::string_view armName) {
|
void PyOutStream::linkArmature(std::string_view target, std::string_view armName) {
|
||||||
format(FMT_STRING("target_arm_name = '{}'\n"
|
format(FMT_STRING(
|
||||||
|
"target_arm_name = '{}'\n"
|
||||||
"if target_arm_name not in bpy.data.armatures:\n"
|
"if target_arm_name not in bpy.data.armatures:\n"
|
||||||
" with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n"
|
" with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n"
|
||||||
" if target_arm_name not in data_from.armatures:\n"
|
" if target_arm_name not in data_from.armatures:\n"
|
||||||
|
@ -745,7 +769,8 @@ void PyOutStream::linkArmature(std::string_view target, std::string_view armName
|
||||||
}
|
}
|
||||||
|
|
||||||
void PyOutStream::linkMesh(std::string_view target, std::string_view meshName) {
|
void PyOutStream::linkMesh(std::string_view target, std::string_view meshName) {
|
||||||
format(FMT_STRING("target_mesh_name = '{}'\n"
|
format(FMT_STRING(
|
||||||
|
"target_mesh_name = '{}'\n"
|
||||||
"if target_mesh_name not in bpy.data.objects:\n"
|
"if target_mesh_name not in bpy.data.objects:\n"
|
||||||
" with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n"
|
" with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n"
|
||||||
" if target_mesh_name not in data_from.objects:\n"
|
" if target_mesh_name not in data_from.objects:\n"
|
||||||
|
@ -759,18 +784,19 @@ void PyOutStream::linkMesh(std::string_view target, std::string_view meshName) {
|
||||||
void PyOutStream::linkBackground(std::string_view target, std::string_view sceneName) {
|
void PyOutStream::linkBackground(std::string_view target, std::string_view sceneName) {
|
||||||
if (sceneName.empty()) {
|
if (sceneName.empty()) {
|
||||||
format(FMT_STRING("with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n"
|
format(FMT_STRING("with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n"
|
||||||
" data_to.scenes = data_from.scenes\n"
|
" data_to.scenes = data_from.scenes\n"
|
||||||
"obj_scene = None\n"
|
"obj_scene = None\n"
|
||||||
"for scene in data_to.scenes:\n"
|
"for scene in data_to.scenes:\n"
|
||||||
" obj_scene = scene\n"
|
" obj_scene = scene\n"
|
||||||
" break\n"
|
" break\n"
|
||||||
"if not obj_scene:\n"
|
"if not obj_scene:\n"
|
||||||
" raise RuntimeError('''unable to find {}. try deleting it and restart the extract.''')\n"
|
" raise RuntimeError('''unable to find {}. try deleting it and restart the extract.''')\n"
|
||||||
"\n"
|
"\n"
|
||||||
"bpy.context.scene.background_set = obj_scene\n"),
|
"bpy.context.scene.background_set = obj_scene\n"),
|
||||||
target, target);
|
target, target);
|
||||||
} else {
|
} else {
|
||||||
format(FMT_STRING("if '{}' not in bpy.data.scenes:\n"
|
format(FMT_STRING(
|
||||||
|
"if '{}' not in bpy.data.scenes:\n"
|
||||||
" with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n"
|
" with bpy.data.libraries.load('''{}''', link=True, relative=True) as (data_from, data_to):\n"
|
||||||
" data_to.scenes = data_from.scenes\n"
|
" data_to.scenes = data_from.scenes\n"
|
||||||
" obj_scene = None\n"
|
" obj_scene = None\n"
|
||||||
|
@ -790,27 +816,27 @@ void PyOutStream::AABBToBMesh(const atVec3f& min, const atVec3f& max) {
|
||||||
athena::simd_floats minf(min.simd);
|
athena::simd_floats minf(min.simd);
|
||||||
athena::simd_floats maxf(max.simd);
|
athena::simd_floats maxf(max.simd);
|
||||||
format(FMT_STRING("bm = bmesh.new()\n"
|
format(FMT_STRING("bm = bmesh.new()\n"
|
||||||
"bm.verts.new(({},{},{}))\n"
|
"bm.verts.new(({},{},{}))\n"
|
||||||
"bm.verts.new(({},{},{}))\n"
|
"bm.verts.new(({},{},{}))\n"
|
||||||
"bm.verts.new(({},{},{}))\n"
|
"bm.verts.new(({},{},{}))\n"
|
||||||
"bm.verts.new(({},{},{}))\n"
|
"bm.verts.new(({},{},{}))\n"
|
||||||
"bm.verts.new(({},{},{}))\n"
|
"bm.verts.new(({},{},{}))\n"
|
||||||
"bm.verts.new(({},{},{}))\n"
|
"bm.verts.new(({},{},{}))\n"
|
||||||
"bm.verts.new(({},{},{}))\n"
|
"bm.verts.new(({},{},{}))\n"
|
||||||
"bm.verts.new(({},{},{}))\n"
|
"bm.verts.new(({},{},{}))\n"
|
||||||
"bm.verts.ensure_lookup_table()\n"
|
"bm.verts.ensure_lookup_table()\n"
|
||||||
"bm.edges.new((bm.verts[0], bm.verts[1]))\n"
|
"bm.edges.new((bm.verts[0], bm.verts[1]))\n"
|
||||||
"bm.edges.new((bm.verts[0], bm.verts[2]))\n"
|
"bm.edges.new((bm.verts[0], bm.verts[2]))\n"
|
||||||
"bm.edges.new((bm.verts[0], bm.verts[4]))\n"
|
"bm.edges.new((bm.verts[0], bm.verts[4]))\n"
|
||||||
"bm.edges.new((bm.verts[3], bm.verts[1]))\n"
|
"bm.edges.new((bm.verts[3], bm.verts[1]))\n"
|
||||||
"bm.edges.new((bm.verts[3], bm.verts[2]))\n"
|
"bm.edges.new((bm.verts[3], bm.verts[2]))\n"
|
||||||
"bm.edges.new((bm.verts[3], bm.verts[7]))\n"
|
"bm.edges.new((bm.verts[3], bm.verts[7]))\n"
|
||||||
"bm.edges.new((bm.verts[5], bm.verts[1]))\n"
|
"bm.edges.new((bm.verts[5], bm.verts[1]))\n"
|
||||||
"bm.edges.new((bm.verts[5], bm.verts[4]))\n"
|
"bm.edges.new((bm.verts[5], bm.verts[4]))\n"
|
||||||
"bm.edges.new((bm.verts[5], bm.verts[7]))\n"
|
"bm.edges.new((bm.verts[5], bm.verts[7]))\n"
|
||||||
"bm.edges.new((bm.verts[6], bm.verts[2]))\n"
|
"bm.edges.new((bm.verts[6], bm.verts[2]))\n"
|
||||||
"bm.edges.new((bm.verts[6], bm.verts[4]))\n"
|
"bm.edges.new((bm.verts[6], bm.verts[4]))\n"
|
||||||
"bm.edges.new((bm.verts[6], bm.verts[7]))\n"),
|
"bm.edges.new((bm.verts[6], bm.verts[7]))\n"),
|
||||||
minf[0], minf[1], minf[2], maxf[0], minf[1], minf[2], minf[0], maxf[1], minf[2], maxf[0], maxf[1], minf[2],
|
minf[0], minf[1], minf[2], maxf[0], minf[1], minf[2], minf[0], maxf[1], minf[2], maxf[0], maxf[1], minf[2],
|
||||||
minf[0], minf[1], maxf[2], maxf[0], minf[1], maxf[2], minf[0], maxf[1], maxf[2], maxf[0], maxf[1], maxf[2]);
|
minf[0], minf[1], maxf[2], maxf[0], minf[1], maxf[2], minf[0], maxf[1], maxf[2], maxf[0], maxf[1], maxf[2]);
|
||||||
}
|
}
|
||||||
|
@ -900,9 +926,7 @@ void Mesh::normalizeSkinBinds() {
|
||||||
|
|
||||||
Mesh::Mesh(Connection& conn, HMDLTopology topologyIn, int skinSlotCount, bool useLuvs)
|
Mesh::Mesh(Connection& conn, HMDLTopology topologyIn, int skinSlotCount, bool useLuvs)
|
||||||
: topology(topologyIn), sceneXf(conn), aabbMin(conn), aabbMax(conn) {
|
: topology(topologyIn), sceneXf(conn), aabbMin(conn), aabbMax(conn) {
|
||||||
conn._readVectorFunc(materialSets, [&]() {
|
conn._readVectorFunc(materialSets, [&]() { conn._readVector(materialSets.emplace_back()); });
|
||||||
conn._readVector(materialSets.emplace_back());
|
|
||||||
});
|
|
||||||
|
|
||||||
MeshOptimizer opt(conn, materialSets[0], useLuvs);
|
MeshOptimizer opt(conn, materialSets[0], useLuvs);
|
||||||
opt.optimize(*this, skinSlotCount);
|
opt.optimize(*this, skinSlotCount);
|
||||||
|
@ -1137,9 +1161,7 @@ World::Area::Area(Connection& conn) {
|
||||||
conn._readVector(docks);
|
conn._readVector(docks);
|
||||||
}
|
}
|
||||||
|
|
||||||
World::World(Connection& conn) {
|
World::World(Connection& conn) { conn._readVector(areas); }
|
||||||
conn._readVector(areas);
|
|
||||||
}
|
|
||||||
|
|
||||||
Light::Light(Connection& conn) : sceneXf(conn), color(conn) {
|
Light::Light(Connection& conn) : sceneXf(conn), color(conn) {
|
||||||
conn._readBuf(&layer, 29);
|
conn._readBuf(&layer, 29);
|
||||||
|
@ -1197,9 +1219,7 @@ Actor::Actor(Connection& conn) {
|
||||||
conn._readVector(actions);
|
conn._readVector(actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
PathMesh::PathMesh(Connection& conn) {
|
PathMesh::PathMesh(Connection& conn) { conn._readVector(data); }
|
||||||
conn._readVector(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Bone* Armature::lookupBone(const char* name) const {
|
const Bone* Armature::lookupBone(const char* name) const {
|
||||||
for (const Bone& b : bones)
|
for (const Bone& b : bones)
|
||||||
|
@ -1230,9 +1250,7 @@ const Bone* Armature::getRoot() const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Armature::Armature(Connection& conn) {
|
Armature::Armature(Connection& conn) { conn._readVector(bones); }
|
||||||
conn._readVector(bones);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bone::Bone(Connection& conn) {
|
Bone::Bone(Connection& conn) {
|
||||||
name = conn._readStdString();
|
name = conn._readStdString();
|
||||||
|
@ -1452,9 +1470,7 @@ std::vector<ProjectPath> DataStream::getTextures() {
|
||||||
m_parent->_checkOk("unable to get textures"sv);
|
m_parent->_checkOk("unable to get textures"sv);
|
||||||
|
|
||||||
std::vector<ProjectPath> texs;
|
std::vector<ProjectPath> texs;
|
||||||
m_parent->_readVectorFunc(texs, [&]() {
|
m_parent->_readVectorFunc(texs, [&]() { texs.push_back(m_parent->_readPath()); });
|
||||||
texs.push_back(m_parent->_readPath());
|
|
||||||
});
|
|
||||||
|
|
||||||
return texs;
|
return texs;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue