metaforce/hecl/lib/Blender/FindBlender.cpp

161 lines
4.5 KiB
C++
Raw Normal View History

#include "hecl/Blender/FindBlender.hpp"
2021-10-27 14:54:34 +00:00
2018-01-10 06:19:48 +00:00
#include "hecl/SteamFinder.hpp"
2021-10-27 14:54:34 +00:00
#include <sstream>
2018-01-10 06:19:48 +00:00
2018-12-08 05:19:40 +00:00
namespace hecl::blender {
2018-01-10 06:19:48 +00:00
#ifdef __APPLE__
#define DEFAULT_BLENDER_BIN "/Applications/Blender.app/Contents/MacOS/blender"
#else
#define DEFAULT_BLENDER_BIN "blender"
#endif
2020-06-24 15:44:00 +00:00
static const std::regex regBlenderVersion(R"(Blender (\d+)\.(\d+)(?:\.(\d+))?)",
2018-12-08 05:19:40 +00:00
std::regex::ECMAScript | std::regex::optimize);
2018-01-10 06:19:48 +00:00
static bool RegFileExists(const char* path) {
2018-12-08 05:19:40 +00:00
if (!path)
return false;
#if !defined(WIN32)
if (path[0] != '/') {
auto envPath = hecl::GetEnv("PATH");
if (envPath) {
std::istringstream iss(*envPath);
std::string item;
while (std::getline(iss, item, ':')) {
if (RegFileExists((item + "/" + path).c_str())) {
return true;
}
}
}
}
#endif
2018-12-08 05:19:40 +00:00
hecl::Sstat theStat;
return !hecl::Stat(path, &theStat) && S_ISREG(theStat.st_mode);
2018-01-10 06:19:48 +00:00
}
std::optional<std::string> FindBlender(int& major, int& minor) {
2018-12-08 05:19:40 +00:00
major = 0;
minor = 0;
2018-01-10 06:19:48 +00:00
2018-12-08 05:19:40 +00:00
/* User-specified blender path */
2018-01-10 06:19:48 +00:00
#if _WIN32
auto blenderBin = GetEnv("BLENDER_BIN");
2018-01-10 06:19:48 +00:00
#else
const char* cblenderBin = getenv("BLENDER_BIN");
std::optional<std::string> blenderBin{};
if (cblenderBin != nullptr) {
blenderBin = cblenderBin;
}
2018-01-10 06:19:48 +00:00
#endif
2018-12-08 05:19:40 +00:00
/* Steam blender */
std::string steamBlender;
2018-01-10 06:19:48 +00:00
2018-12-08 05:19:40 +00:00
/* Child process of blender */
2018-01-10 06:19:48 +00:00
#if _WIN32
if (!blenderBin || !RegFileExists(blenderBin->c_str())) {
2018-12-08 05:19:40 +00:00
/* Environment not set; try steam */
steamBlender = hecl::FindCommonSteamApp("Blender");
2018-12-08 05:19:40 +00:00
if (steamBlender.size()) {
steamBlender += "\\blender.exe";
2018-12-08 05:19:40 +00:00
blenderBin = steamBlender.c_str();
}
2018-01-10 06:19:48 +00:00
if (!RegFileExists(blenderBin->c_str())) {
2018-12-08 05:19:40 +00:00
/* No steam; try default */
wchar_t wProgFiles[256];
if (GetEnvironmentVariableW(L"ProgramFiles", wProgFiles, 256)) {
auto progFiles = nowide::narrow(wProgFiles);
for (size_t major = MaxBlenderMajorSearch; major >= MinBlenderMajorSearch; --major) {
bool found = false;
for (size_t minor = MaxBlenderMinorSearch; minor >= MinBlenderMinorSearch; --minor) {
std::string blenderBinBuf = fmt::format(FMT_STRING("{}\\Blender Foundation\\Blender {}.{}\\blender.exe"),
progFiles, major, minor);
if (RegFileExists(blenderBinBuf.c_str())) {
blenderBin = std::move(blenderBinBuf);
found = true;
break;
}
}
if (found) {
break;
}
}
}
2018-01-10 06:19:48 +00:00
}
2018-12-08 05:19:40 +00:00
}
2018-01-10 06:19:48 +00:00
#else
if (!RegFileExists(blenderBin->c_str())) {
2018-12-08 05:19:40 +00:00
/* Try steam */
steamBlender = hecl::FindCommonSteamApp("Blender");
2018-12-08 05:19:40 +00:00
if (steamBlender.size()) {
2018-01-10 06:19:48 +00:00
#ifdef __APPLE__
2018-12-08 05:19:40 +00:00
steamBlender += "/blender.app/Contents/MacOS/blender";
2018-01-10 06:19:48 +00:00
#else
2018-12-08 05:19:40 +00:00
steamBlender += "/blender";
2018-01-10 06:19:48 +00:00
#endif
blenderBin = steamBlender;
if (!RegFileExists(blenderBin->c_str())) {
2018-12-08 05:19:40 +00:00
blenderBin = DEFAULT_BLENDER_BIN;
if (!RegFileExists(blenderBin->c_str())) {
blenderBin.reset();
}
2018-12-08 05:19:40 +00:00
}
} else {
blenderBin = DEFAULT_BLENDER_BIN;
if (!RegFileExists(blenderBin->c_str())) {
blenderBin.reset();
2018-12-08 05:19:40 +00:00
}
2018-01-10 06:19:48 +00:00
}
2018-12-08 05:19:40 +00:00
}
2018-01-10 06:19:48 +00:00
#endif
2018-12-08 05:19:40 +00:00
if (!blenderBin)
return {};
2018-01-10 06:19:48 +00:00
#if _WIN32
const nowide::wstackstring wblenderBin(blenderBin.value());
DWORD handle = 0;
DWORD infoSize = GetFileVersionInfoSizeW(wblenderBin.get(), &handle);
if (infoSize != NULL) {
auto* infoData = new char[infoSize];
if (GetFileVersionInfoW(wblenderBin.get(), handle, infoSize, infoData)) {
UINT size = 0;
LPVOID lpBuffer = nullptr;
if (VerQueryValueW(infoData, L"\\", &lpBuffer, &size) && size != 0u) {
auto* verInfo = static_cast<VS_FIXEDFILEINFO*>(lpBuffer);
if (verInfo->dwSignature == 0xfeef04bd) {
major = static_cast<int>((verInfo->dwFileVersionMS >> 16) & 0xffff);
minor = static_cast<int>((verInfo->dwFileVersionMS >> 0 & 0xffff) * 10 +
(verInfo->dwFileVersionLS >> 16 & 0xffff));
}
}
}
delete[] infoData;
}
2018-01-10 06:19:48 +00:00
#else
std::string command = std::string("\"") + blenderBin.value() + "\" --version";
2018-12-08 05:19:40 +00:00
FILE* fp = popen(command.c_str(), "r");
char versionBuf[256];
size_t rdSize = fread(versionBuf, 1, 255, fp);
versionBuf[rdSize] = '\0';
pclose(fp);
2018-01-10 06:19:48 +00:00
2018-12-08 05:19:40 +00:00
std::cmatch match;
if (std::regex_search(versionBuf, match, regBlenderVersion)) {
major = atoi(match[1].str().c_str());
minor = atoi(match[2].str().c_str());
}
#endif
2018-01-10 06:19:48 +00:00
2018-12-08 05:19:40 +00:00
return blenderBin;
2018-01-10 06:19:48 +00:00
}
2018-12-08 05:19:40 +00:00
} // namespace hecl::blender