2015-05-24 04:51:16 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2015-08-31 19:47:59 +00:00
|
|
|
#include <inttypes.h>
|
2015-05-24 04:51:16 +00:00
|
|
|
#include <system_error>
|
|
|
|
#include <string>
|
|
|
|
|
2015-07-22 19:14:50 +00:00
|
|
|
#include <HECL/HECL.hpp>
|
|
|
|
#include <LogVisor/LogVisor.hpp>
|
2015-07-08 04:26:29 +00:00
|
|
|
#include "BlenderConnection.hpp"
|
2015-05-24 04:51:16 +00:00
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
#if _WIN32
|
|
|
|
#include <io.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#endif
|
|
|
|
|
2015-07-28 02:25:33 +00:00
|
|
|
namespace HECL
|
|
|
|
{
|
|
|
|
|
|
|
|
LogVisor::LogModule BlenderLog("BlenderConnection");
|
|
|
|
BlenderConnection* SharedBlenderConnection = nullptr;
|
2015-07-22 19:14:50 +00:00
|
|
|
|
2015-05-24 04:51:16 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
#define DEFAULT_BLENDER_BIN "/Applications/Blender.app/Contents/MacOS/blender"
|
|
|
|
#else
|
|
|
|
#define DEFAULT_BLENDER_BIN "blender"
|
|
|
|
#endif
|
|
|
|
|
2015-08-13 07:30:23 +00:00
|
|
|
extern "C" uint8_t HECL_BLENDERSHELL[];
|
|
|
|
extern "C" size_t HECL_BLENDERSHELL_SZ;
|
2015-05-24 04:51:16 +00:00
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
extern "C" uint8_t HECL_ADDON[];
|
|
|
|
extern "C" size_t HECL_ADDON_SZ;
|
2015-09-06 20:08:23 +00:00
|
|
|
|
|
|
|
extern "C" uint8_t HECL_STARTUP[];
|
|
|
|
extern "C" size_t HECL_STARTUP_SZ;
|
2015-08-31 03:36:24 +00:00
|
|
|
|
2015-09-06 20:08:23 +00:00
|
|
|
static void InstallBlendershell(const SystemChar* path)
|
|
|
|
{
|
|
|
|
FILE* fp = HECL::Fopen(path, _S("w"));
|
|
|
|
if (!fp)
|
|
|
|
BlenderLog.report(LogVisor::FatalError, _S("unable to open %s for writing"), path);
|
|
|
|
fwrite(HECL_BLENDERSHELL, 1, HECL_BLENDERSHELL_SZ, fp);
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void InstallAddon(const SystemChar* path)
|
2015-08-31 03:36:24 +00:00
|
|
|
{
|
|
|
|
FILE* fp = HECL::Fopen(path, _S("wb"));
|
|
|
|
if (!fp)
|
|
|
|
BlenderLog.report(LogVisor::FatalError, _S("Unable to install blender addon at '%s'"), path);
|
|
|
|
fwrite(HECL_ADDON, 1, HECL_ADDON_SZ, fp);
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
|
2015-09-06 20:08:23 +00:00
|
|
|
static void InstallStartup(const char* path)
|
|
|
|
{
|
|
|
|
FILE* fp = fopen(path, "wb");
|
|
|
|
if (!fp)
|
|
|
|
BlenderLog.report(LogVisor::FatalError, "Unable to place hecl_startup.blend at '%s'", path);
|
|
|
|
fwrite(HECL_STARTUP, 1, HECL_STARTUP_SZ, fp);
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
|
2015-07-22 19:14:50 +00:00
|
|
|
size_t BlenderConnection::_readLine(char* buf, size_t bufSz)
|
2015-05-24 04:51:16 +00:00
|
|
|
{
|
|
|
|
size_t readBytes = 0;
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
if (readBytes >= bufSz)
|
2015-05-25 01:34:31 +00:00
|
|
|
{
|
2015-08-08 04:52:20 +00:00
|
|
|
BlenderLog.report(LogVisor::FatalError, "Pipe buffer overrun");
|
2015-05-25 01:34:31 +00:00
|
|
|
*(buf-1) = '\0';
|
|
|
|
return bufSz - 1;
|
|
|
|
}
|
2015-08-31 03:36:24 +00:00
|
|
|
int ret = read(m_readpipe[0], buf, 1);
|
2015-05-24 04:51:16 +00:00
|
|
|
if (ret < 0)
|
|
|
|
goto err;
|
|
|
|
else if (ret == 1)
|
|
|
|
{
|
|
|
|
if (*buf == '\n')
|
|
|
|
{
|
|
|
|
*buf = '\0';
|
|
|
|
return readBytes;
|
|
|
|
}
|
|
|
|
++readBytes;
|
|
|
|
++buf;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*buf = '\0';
|
|
|
|
return readBytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err:
|
2015-07-28 02:25:33 +00:00
|
|
|
BlenderLog.report(LogVisor::FatalError, strerror(errno));
|
2015-05-24 04:51:16 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-22 19:14:50 +00:00
|
|
|
size_t BlenderConnection::_writeLine(const char* buf)
|
2015-05-24 04:51:16 +00:00
|
|
|
{
|
2015-08-31 03:36:24 +00:00
|
|
|
int ret, nlerr;
|
2015-05-24 04:51:16 +00:00
|
|
|
ret = write(m_writepipe[1], buf, strlen(buf));
|
|
|
|
if (ret < 0)
|
|
|
|
goto err;
|
|
|
|
nlerr = write(m_writepipe[1], "\n", 1);
|
|
|
|
if (nlerr < 0)
|
|
|
|
goto err;
|
|
|
|
return (size_t)ret;
|
|
|
|
err:
|
2015-07-28 02:25:33 +00:00
|
|
|
BlenderLog.report(LogVisor::FatalError, strerror(errno));
|
2015-07-26 02:52:02 +00:00
|
|
|
return 0;
|
2015-05-24 04:51:16 +00:00
|
|
|
}
|
|
|
|
|
2015-10-02 04:06:45 +00:00
|
|
|
size_t BlenderConnection::_readBuf(void* buf, size_t len)
|
2015-05-24 04:51:16 +00:00
|
|
|
{
|
2015-08-31 03:36:24 +00:00
|
|
|
int ret = read(m_readpipe[0], buf, len);
|
2015-05-24 04:51:16 +00:00
|
|
|
if (ret < 0)
|
2015-07-22 19:14:50 +00:00
|
|
|
goto err;
|
2015-05-24 04:51:16 +00:00
|
|
|
return ret;
|
2015-07-22 19:14:50 +00:00
|
|
|
err:
|
2015-07-28 02:25:33 +00:00
|
|
|
BlenderLog.report(LogVisor::FatalError, strerror(errno));
|
2015-07-22 19:14:50 +00:00
|
|
|
return 0;
|
2015-05-24 04:51:16 +00:00
|
|
|
}
|
|
|
|
|
2015-10-02 04:06:45 +00:00
|
|
|
size_t BlenderConnection::_writeBuf(const void* buf, size_t len)
|
2015-05-24 04:51:16 +00:00
|
|
|
{
|
2015-08-31 03:36:24 +00:00
|
|
|
int ret = write(m_writepipe[1], buf, len);
|
2015-05-24 04:51:16 +00:00
|
|
|
if (ret < 0)
|
2015-07-22 19:14:50 +00:00
|
|
|
goto err;
|
2015-05-24 04:51:16 +00:00
|
|
|
return ret;
|
2015-07-22 19:14:50 +00:00
|
|
|
err:
|
2015-07-28 02:25:33 +00:00
|
|
|
BlenderLog.report(LogVisor::FatalError, strerror(errno));
|
2015-07-22 19:14:50 +00:00
|
|
|
return 0;
|
2015-05-24 04:51:16 +00:00
|
|
|
}
|
|
|
|
|
2015-07-22 19:14:50 +00:00
|
|
|
void BlenderConnection::_closePipe()
|
2015-05-24 04:51:16 +00:00
|
|
|
{
|
|
|
|
close(m_readpipe[0]);
|
|
|
|
close(m_writepipe[1]);
|
|
|
|
}
|
|
|
|
|
2015-09-22 01:41:38 +00:00
|
|
|
BlenderConnection::BlenderConnection(int verbosityLevel)
|
2015-05-24 04:51:16 +00:00
|
|
|
{
|
2015-09-02 02:31:33 +00:00
|
|
|
BlenderLog.report(LogVisor::Info, "Establishing BlenderConnection...");
|
|
|
|
|
2015-08-13 07:30:23 +00:00
|
|
|
/* Put hecl_blendershell.py in temp dir */
|
2015-08-04 21:37:12 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
wchar_t* TMPDIR = _wgetenv(L"TEMP");
|
|
|
|
if (!TMPDIR)
|
|
|
|
TMPDIR = (wchar_t*)L"\\Temp";
|
2015-09-06 21:00:50 +00:00
|
|
|
m_startupBlend = HECL::WideToUTF8(TMPDIR);
|
2015-08-04 21:37:12 +00:00
|
|
|
#else
|
|
|
|
char* TMPDIR = getenv("TMPDIR");
|
|
|
|
if (!TMPDIR)
|
|
|
|
TMPDIR = (char*)"/tmp";
|
2015-09-06 21:00:50 +00:00
|
|
|
m_startupBlend = TMPDIR;
|
2015-08-04 21:37:12 +00:00
|
|
|
#endif
|
|
|
|
HECL::SystemString blenderShellPath(TMPDIR);
|
2015-08-13 07:30:23 +00:00
|
|
|
blenderShellPath += _S("/hecl_blendershell.py");
|
2015-09-06 20:08:23 +00:00
|
|
|
InstallBlendershell(blenderShellPath.c_str());
|
2015-08-04 21:37:12 +00:00
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
HECL::SystemString blenderAddonPath(TMPDIR);
|
|
|
|
blenderAddonPath += _S("/hecl_blenderaddon.zip");
|
2015-09-02 02:31:33 +00:00
|
|
|
InstallAddon(blenderAddonPath.c_str());
|
2015-09-06 20:08:23 +00:00
|
|
|
|
2015-09-06 21:00:50 +00:00
|
|
|
m_startupBlend += "/hecl_startup.blend";
|
2015-09-06 20:08:23 +00:00
|
|
|
InstallStartup(m_startupBlend.c_str());
|
2015-08-31 03:36:24 +00:00
|
|
|
|
|
|
|
int installAttempt = 0;
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* Construct communication pipes */
|
2015-07-22 19:14:50 +00:00
|
|
|
#if _WIN32
|
2015-08-31 03:36:24 +00:00
|
|
|
_pipe(m_readpipe, 2048, _O_BINARY);
|
|
|
|
_pipe(m_writepipe, 2048, _O_BINARY);
|
|
|
|
HANDLE writehandle = HANDLE(_get_osfhandle(m_writepipe[0]));
|
|
|
|
SetHandleInformation(writehandle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
|
|
|
HANDLE readhandle = HANDLE(_get_osfhandle(m_readpipe[1]));
|
|
|
|
SetHandleInformation(readhandle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
2015-07-22 19:14:50 +00:00
|
|
|
#else
|
2015-08-31 03:36:24 +00:00
|
|
|
pipe(m_readpipe);
|
|
|
|
pipe(m_writepipe);
|
2015-07-22 19:14:50 +00:00
|
|
|
#endif
|
2015-05-24 04:51:16 +00:00
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
/* User-specified blender path */
|
2015-07-22 19:14:50 +00:00
|
|
|
#if _WIN32
|
2015-08-31 03:36:24 +00:00
|
|
|
wchar_t BLENDER_BIN_BUF[2048];
|
|
|
|
wchar_t* blenderBin = _wgetenv(L"BLENDER_BIN");
|
2015-07-22 19:14:50 +00:00
|
|
|
#else
|
2015-08-31 03:36:24 +00:00
|
|
|
char* blenderBin = getenv("BLENDER_BIN");
|
2015-07-22 19:14:50 +00:00
|
|
|
#endif
|
2015-05-24 04:51:16 +00:00
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
/* Child process of blender */
|
2015-07-22 19:14:50 +00:00
|
|
|
#if _WIN32
|
2015-08-31 03:36:24 +00:00
|
|
|
if (!blenderBin)
|
2015-07-22 19:14:50 +00:00
|
|
|
{
|
2015-08-31 03:36:24 +00:00
|
|
|
/* Environment not set; use default */
|
|
|
|
wchar_t progFiles[256];
|
|
|
|
if (!GetEnvironmentVariableW(L"ProgramFiles", progFiles, 256))
|
|
|
|
BlenderLog.report(LogVisor::FatalError, L"unable to determine 'Program Files' path");
|
|
|
|
_snwprintf(BLENDER_BIN_BUF, 2048, L"%s\\Blender Foundation\\Blender\\blender.exe", progFiles);
|
|
|
|
blenderBin = BLENDER_BIN_BUF;
|
2015-07-22 19:14:50 +00:00
|
|
|
}
|
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
wchar_t cmdLine[2048];
|
2015-09-22 01:41:38 +00:00
|
|
|
_snwprintf(cmdLine, 2048, L" --background -P \"%s\" -- %" PRIuPTR " %" PRIuPTR " %d \"%s\"",
|
|
|
|
blenderShellPath.c_str(), uintptr_t(writehandle), uintptr_t(readhandle),
|
|
|
|
verbosityLevel > 1 ? 1 : 0, blenderAddonPath.c_str());
|
2015-07-22 19:14:50 +00:00
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
|
|
|
|
HANDLE nulHandle = NULL;
|
2015-09-27 04:35:36 +00:00
|
|
|
if (verbosityLevel == 0)
|
2015-08-31 03:36:24 +00:00
|
|
|
{
|
|
|
|
SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
|
|
|
|
nulHandle = CreateFileW(L"nul", GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, &sattrs, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
sinfo.hStdError = nulHandle;
|
|
|
|
sinfo.hStdOutput = nulHandle;
|
|
|
|
sinfo.dwFlags = STARTF_USESTDHANDLES;
|
|
|
|
}
|
2015-07-22 19:14:50 +00:00
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
PROCESS_INFORMATION pinfo;
|
|
|
|
if (!CreateProcessW(blenderBin, cmdLine, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &sinfo, &pinfo))
|
|
|
|
{
|
|
|
|
LPWSTR messageBuffer = nullptr;
|
|
|
|
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL);
|
|
|
|
BlenderLog.report(LogVisor::FatalError, L"unable to launch blender from %s: %s", blenderBin, messageBuffer);
|
|
|
|
}
|
2015-07-22 19:14:50 +00:00
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
close(m_writepipe[0]);
|
|
|
|
close(m_readpipe[1]);
|
2015-07-22 19:14:50 +00:00
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
if (nulHandle)
|
|
|
|
CloseHandle(nulHandle);
|
2015-07-22 19:14:50 +00:00
|
|
|
|
|
|
|
#else
|
2015-08-31 03:36:24 +00:00
|
|
|
pid_t pid = fork();
|
|
|
|
if (!pid)
|
2015-05-24 04:51:16 +00:00
|
|
|
{
|
2015-08-31 03:36:24 +00:00
|
|
|
close(m_writepipe[1]);
|
|
|
|
close(m_readpipe[0]);
|
2015-05-24 04:51:16 +00:00
|
|
|
|
2015-09-22 01:41:38 +00:00
|
|
|
if (verbosityLevel == 0)
|
2015-08-31 03:36:24 +00:00
|
|
|
{
|
|
|
|
int devNull = open("/dev/null", O_WRONLY);
|
|
|
|
dup2(devNull, STDOUT_FILENO);
|
|
|
|
dup2(devNull, STDERR_FILENO);
|
|
|
|
}
|
2015-05-24 04:51:16 +00:00
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
char errbuf[256];
|
|
|
|
char readfds[32];
|
|
|
|
snprintf(readfds, 32, "%d", m_writepipe[0]);
|
|
|
|
char writefds[32];
|
|
|
|
snprintf(writefds, 32, "%d", m_readpipe[1]);
|
2015-09-22 01:41:38 +00:00
|
|
|
char dverbose[32];
|
|
|
|
snprintf(dverbose, 32, "%d", verbosityLevel > 1 ? 1 : 0);
|
2015-08-31 03:36:24 +00:00
|
|
|
|
|
|
|
/* Try user-specified blender first */
|
|
|
|
if (blenderBin)
|
|
|
|
{
|
2015-09-02 02:31:33 +00:00
|
|
|
execlp(blenderBin, blenderBin,
|
|
|
|
"--background", "-P", blenderShellPath.c_str(),
|
2015-09-22 01:41:38 +00:00
|
|
|
"--", readfds, writefds, dverbose, blenderAddonPath.c_str(), NULL);
|
2015-08-31 03:36:24 +00:00
|
|
|
if (errno != ENOENT)
|
|
|
|
{
|
|
|
|
snprintf(errbuf, 256, "NOLAUNCH %s\n", strerror(errno));
|
|
|
|
write(m_writepipe[1], errbuf, strlen(errbuf));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Otherwise default blender */
|
2015-09-02 02:31:33 +00:00
|
|
|
execlp(DEFAULT_BLENDER_BIN, DEFAULT_BLENDER_BIN,
|
|
|
|
"--background", "-P", blenderShellPath.c_str(),
|
2015-09-22 01:41:38 +00:00
|
|
|
"--", readfds, writefds, dverbose, blenderAddonPath.c_str(), NULL);
|
2015-05-24 04:51:16 +00:00
|
|
|
if (errno != ENOENT)
|
|
|
|
{
|
|
|
|
snprintf(errbuf, 256, "NOLAUNCH %s\n", strerror(errno));
|
|
|
|
write(m_writepipe[1], errbuf, strlen(errbuf));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
/* Unable to find blender */
|
|
|
|
write(m_writepipe[1], "NOBLENDER\n", 10);
|
2015-05-24 04:51:16 +00:00
|
|
|
exit(1);
|
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
}
|
|
|
|
close(m_writepipe[0]);
|
|
|
|
close(m_readpipe[1]);
|
|
|
|
m_blenderProc = pid;
|
2015-07-22 19:14:50 +00:00
|
|
|
#endif
|
2015-05-24 04:51:16 +00:00
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
/* Handle first response */
|
|
|
|
char lineBuf[256];
|
|
|
|
_readLine(lineBuf, sizeof(lineBuf));
|
|
|
|
if (!strcmp(lineBuf, "NOLAUNCH"))
|
|
|
|
{
|
|
|
|
_closePipe();
|
|
|
|
BlenderLog.report(LogVisor::FatalError, "Unable to launch blender");
|
|
|
|
}
|
|
|
|
else if (!strcmp(lineBuf, "NOBLENDER"))
|
|
|
|
{
|
|
|
|
_closePipe();
|
|
|
|
if (blenderBin)
|
|
|
|
BlenderLog.report(LogVisor::FatalError, _S("Unable to find blender at '%s' or '%s'"),
|
|
|
|
blenderBin, DEFAULT_BLENDER_BIN);
|
|
|
|
else
|
|
|
|
BlenderLog.report(LogVisor::FatalError, _S("Unable to find blender at '%s'"),
|
|
|
|
DEFAULT_BLENDER_BIN);
|
|
|
|
}
|
|
|
|
else if (!strcmp(lineBuf, "NOADDON"))
|
|
|
|
{
|
|
|
|
_closePipe();
|
|
|
|
InstallAddon(blenderAddonPath.c_str());
|
|
|
|
++installAttempt;
|
|
|
|
if (installAttempt >= 2)
|
|
|
|
BlenderLog.report(LogVisor::FatalError, "unable to install blender addon using '%s'", blenderAddonPath.c_str());
|
|
|
|
continue;
|
|
|
|
}
|
2015-09-17 19:50:01 +00:00
|
|
|
else if (!strcmp(lineBuf, "ADDONINSTALLED"))
|
|
|
|
{
|
|
|
|
_closePipe();
|
|
|
|
blenderAddonPath = _S("SKIPINSTALL");
|
|
|
|
continue;
|
|
|
|
}
|
2015-08-31 03:36:24 +00:00
|
|
|
else if (strcmp(lineBuf, "READY"))
|
|
|
|
{
|
|
|
|
_closePipe();
|
|
|
|
BlenderLog.report(LogVisor::FatalError, "read '%s' from blender; expected 'READY'", lineBuf);
|
|
|
|
}
|
|
|
|
_writeLine("ACK");
|
2015-05-24 04:51:16 +00:00
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-05-24 04:51:16 +00:00
|
|
|
}
|
|
|
|
|
2015-07-22 19:14:50 +00:00
|
|
|
BlenderConnection::~BlenderConnection()
|
2015-05-24 04:51:16 +00:00
|
|
|
{
|
2015-05-24 22:19:28 +00:00
|
|
|
_closePipe();
|
|
|
|
}
|
|
|
|
|
2015-10-01 00:40:06 +00:00
|
|
|
static std::string BlendTypeStrs[] =
|
|
|
|
{
|
|
|
|
"NONE",
|
|
|
|
"MESH",
|
|
|
|
"ACTOR",
|
|
|
|
"AREA",
|
|
|
|
""
|
|
|
|
};
|
|
|
|
|
|
|
|
bool BlenderConnection::createBlend(const SystemString& path, BlendType type)
|
2015-07-28 02:25:33 +00:00
|
|
|
{
|
2015-08-16 23:01:35 +00:00
|
|
|
if (m_lock)
|
2015-08-05 22:59:59 +00:00
|
|
|
{
|
|
|
|
BlenderLog.report(LogVisor::FatalError,
|
|
|
|
"BlenderConnection::createBlend() musn't be called with stream active");
|
|
|
|
return false;
|
|
|
|
}
|
2015-08-04 21:37:12 +00:00
|
|
|
HECL::SystemUTF8View pathView(path);
|
2015-10-01 00:40:06 +00:00
|
|
|
_writeLine(("CREATE \"" + pathView.str() + "\" " + BlendTypeStrs[type] + " \"" + m_startupBlend + "\"").c_str());
|
2015-07-28 02:25:33 +00:00
|
|
|
char lineBuf[256];
|
|
|
|
_readLine(lineBuf, sizeof(lineBuf));
|
|
|
|
if (!strcmp(lineBuf, "FINISHED"))
|
|
|
|
{
|
2015-08-31 03:36:24 +00:00
|
|
|
m_loadedBlend = path;
|
2015-07-28 02:25:33 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-01 00:40:06 +00:00
|
|
|
BlenderConnection::BlendType BlenderConnection::getBlendType()
|
|
|
|
{
|
|
|
|
_writeLine("GETTYPE");
|
|
|
|
char lineBuf[256];
|
|
|
|
_readLine(lineBuf, sizeof(lineBuf));
|
|
|
|
unsigned idx = 0;
|
|
|
|
while (BlendTypeStrs[idx].size())
|
|
|
|
if (!BlendTypeStrs[idx].compare(lineBuf))
|
|
|
|
return BlendType(idx);
|
|
|
|
return TypeNone;
|
|
|
|
}
|
|
|
|
|
2015-07-28 02:25:33 +00:00
|
|
|
bool BlenderConnection::openBlend(const SystemString& path)
|
2015-05-24 22:19:28 +00:00
|
|
|
{
|
2015-08-16 23:01:35 +00:00
|
|
|
if (m_lock)
|
2015-08-05 22:59:59 +00:00
|
|
|
{
|
|
|
|
BlenderLog.report(LogVisor::FatalError,
|
|
|
|
"BlenderConnection::openBlend() musn't be called with stream active");
|
|
|
|
return false;
|
|
|
|
}
|
2015-10-02 04:06:45 +00:00
|
|
|
if (path == m_loadedBlend)
|
|
|
|
return true;
|
2015-08-04 21:37:12 +00:00
|
|
|
HECL::SystemUTF8View pathView(path);
|
|
|
|
_writeLine(("OPEN \"" + pathView.str() + "\"").c_str());
|
2015-05-24 22:19:28 +00:00
|
|
|
char lineBuf[256];
|
|
|
|
_readLine(lineBuf, sizeof(lineBuf));
|
|
|
|
if (!strcmp(lineBuf, "FINISHED"))
|
|
|
|
{
|
2015-08-31 03:36:24 +00:00
|
|
|
m_loadedBlend = path;
|
2015-05-24 22:19:28 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-08-04 21:37:12 +00:00
|
|
|
bool BlenderConnection::saveBlend()
|
|
|
|
{
|
2015-08-16 23:01:35 +00:00
|
|
|
if (m_lock)
|
2015-08-05 22:59:59 +00:00
|
|
|
{
|
|
|
|
BlenderLog.report(LogVisor::FatalError,
|
|
|
|
"BlenderConnection::saveBlend() musn't be called with stream active");
|
|
|
|
return false;
|
|
|
|
}
|
2015-08-04 21:37:12 +00:00
|
|
|
_writeLine("SAVE");
|
|
|
|
char lineBuf[256];
|
|
|
|
_readLine(lineBuf, sizeof(lineBuf));
|
|
|
|
if (!strcmp(lineBuf, "FINISHED"))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-08-05 22:59:59 +00:00
|
|
|
void BlenderConnection::deleteBlend()
|
|
|
|
{
|
|
|
|
if (m_loadedBlend.size())
|
|
|
|
{
|
|
|
|
HECL::Unlink(m_loadedBlend.c_str());
|
2015-08-31 03:36:24 +00:00
|
|
|
BlenderLog.report(LogVisor::Info, _S("Deleted '%s'"), m_loadedBlend.c_str());
|
2015-08-05 22:59:59 +00:00
|
|
|
m_loadedBlend.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-02 04:06:45 +00:00
|
|
|
void BlenderConnection::PyOutStream::linkBlend(const std::string& target,
|
|
|
|
const std::string& objName,
|
2015-08-04 21:37:12 +00:00
|
|
|
bool link)
|
|
|
|
{
|
|
|
|
format("if '%s' not in bpy.data.scenes:\n"
|
2015-08-08 04:52:20 +00:00
|
|
|
" with bpy.data.libraries.load('''%s''', link=%s, relative=True) as (data_from, data_to):\n"
|
2015-08-04 21:37:12 +00:00
|
|
|
" data_to.scenes = data_from.scenes\n"
|
|
|
|
" obj_scene = None\n"
|
|
|
|
" for scene in data_to.scenes:\n"
|
|
|
|
" if scene.name == '%s':\n"
|
|
|
|
" obj_scene = scene\n"
|
|
|
|
" break\n"
|
2015-08-13 07:30:23 +00:00
|
|
|
" if not obj_scene:\n"
|
2015-08-15 04:12:57 +00:00
|
|
|
" raise RuntimeError('''unable to find %s in %s. try deleting it and restart the extract.''')\n"
|
2015-08-04 21:37:12 +00:00
|
|
|
" obj = None\n"
|
|
|
|
" for object in obj_scene.objects:\n"
|
|
|
|
" if object.name == obj_scene.name:\n"
|
|
|
|
" obj = object\n"
|
|
|
|
"else:\n"
|
|
|
|
" obj = bpy.data.objects['%s']\n"
|
|
|
|
"\n",
|
2015-08-05 22:59:59 +00:00
|
|
|
objName.c_str(), target.c_str(), link?"True":"False",
|
2015-08-13 07:30:23 +00:00
|
|
|
objName.c_str(), objName.c_str(), target.c_str(), objName.c_str());
|
2015-08-04 21:37:12 +00:00
|
|
|
}
|
|
|
|
|
2015-10-02 04:06:45 +00:00
|
|
|
BlenderConnection::DataStream::Mesh::Mesh(BlenderConnection& conn)
|
|
|
|
{
|
|
|
|
uint32_t matCount;
|
|
|
|
conn._readBuf(&matCount, 4);
|
|
|
|
materials.reserve(matCount);
|
|
|
|
for (int i=0 ; i<matCount ; ++i)
|
|
|
|
{
|
|
|
|
char mat[2048];
|
|
|
|
conn._readLine(mat, 2048);
|
|
|
|
materials.push_back(mat);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t submeshCount;
|
|
|
|
conn._readBuf(&submeshCount, 4);
|
|
|
|
submeshes.reserve(submeshCount);
|
|
|
|
for (int i=0 ; i<submeshCount ; ++i)
|
|
|
|
submeshes.emplace_back(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
BlenderConnection::DataStream::Mesh::Submesh::Submesh(BlenderConnection& conn)
|
|
|
|
{
|
|
|
|
uint32_t count;
|
|
|
|
conn._readBuf(&count, 4);
|
|
|
|
pos.reserve(count);
|
|
|
|
for (int i=0 ; i<count ; ++i)
|
|
|
|
pos.emplace_back(conn);
|
|
|
|
|
|
|
|
conn._readBuf(&count, 4);
|
|
|
|
norm.reserve(count);
|
|
|
|
for (int i=0 ; i<count ; ++i)
|
|
|
|
norm.emplace_back(conn);
|
|
|
|
|
|
|
|
conn._readBuf(&colorLayerCount, 4);
|
|
|
|
for (int i=0 ; i<colorLayerCount ; ++i)
|
|
|
|
{
|
|
|
|
conn._readBuf(&count, 4);
|
|
|
|
color[i].reserve(count);
|
|
|
|
for (int j=0 ; j<count ; ++j)
|
|
|
|
color[i].emplace_back(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
conn._readBuf(&uvLayerCount, 4);
|
|
|
|
for (int i=0 ; i<uvLayerCount ; ++i)
|
|
|
|
{
|
|
|
|
conn._readBuf(&count, 4);
|
|
|
|
uv[i].reserve(count);
|
|
|
|
for (int j=0 ; j<count ; ++j)
|
|
|
|
uv[i].emplace_back(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
conn._readBuf(&count, 4);
|
|
|
|
boneNames.reserve(count);
|
|
|
|
for (int i=0 ; i<count ; ++i)
|
|
|
|
{
|
|
|
|
char name[128];
|
|
|
|
conn._readLine(name, 128);
|
|
|
|
boneNames.emplace_back(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
conn._readBuf(&count, 4);
|
|
|
|
skins.reserve(count);
|
|
|
|
for (int i=0 ; i<count ; ++i)
|
|
|
|
{
|
|
|
|
skins.emplace_back();
|
|
|
|
std::vector<SkinBind>& binds = skins.back();
|
|
|
|
uint32_t bindCount;
|
|
|
|
conn._readBuf(&bindCount, 4);
|
|
|
|
binds.reserve(bindCount);
|
|
|
|
for (int j=0 ; j<bindCount ; ++j)
|
|
|
|
binds.emplace_back(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
conn._readBuf(&count, 4);
|
|
|
|
skinBanks.reserve(count);
|
|
|
|
for (int i=0 ; i<count ; ++i)
|
|
|
|
{
|
|
|
|
skinBanks.emplace_back();
|
|
|
|
std::vector<Index>& bank = skinBanks.back();
|
|
|
|
uint32_t idxCount;
|
|
|
|
conn._readBuf(&idxCount, 4);
|
|
|
|
bank.reserve(idxCount);
|
|
|
|
for (int j=0 ; j<idxCount ; ++j)
|
|
|
|
bank.emplace_back(conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
conn._readBuf(&count, 4);
|
|
|
|
surfaces.reserve(count);
|
|
|
|
for (int i=0 ; i<count ; ++i)
|
|
|
|
surfaces.emplace_back(conn, *this);
|
|
|
|
}
|
|
|
|
|
|
|
|
BlenderConnection::DataStream::Mesh::Submesh::Surface::Surface
|
|
|
|
(BlenderConnection& conn, const Submesh& parent)
|
|
|
|
: centroid(conn), materialIdx(conn), aabbMin(conn), aabbMax(conn),
|
|
|
|
reflectionNormal(conn), skinBankIdx(conn)
|
|
|
|
{
|
|
|
|
uint32_t count;
|
|
|
|
conn._readBuf(&count, 4);
|
|
|
|
verts.reserve(count);
|
|
|
|
for (int i=0 ; i<count ; ++i)
|
|
|
|
verts.emplace_back(conn, parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
BlenderConnection::DataStream::Mesh::Submesh::Surface::Vert::Vert
|
|
|
|
(BlenderConnection& conn, const Submesh& parent)
|
|
|
|
{
|
|
|
|
conn._readBuf(&iPos, 4);
|
|
|
|
conn._readBuf(&iNorm, 4);
|
|
|
|
if (parent.colorLayerCount)
|
|
|
|
conn._readBuf(iColor, 4 * parent.colorLayerCount);
|
|
|
|
if (parent.uvLayerCount)
|
|
|
|
conn._readBuf(iUv, 4 * parent.uvLayerCount);
|
|
|
|
conn._readBuf(&iSkin, 4);
|
|
|
|
}
|
|
|
|
|
2015-07-22 19:14:50 +00:00
|
|
|
void BlenderConnection::quitBlender()
|
2015-05-24 04:51:16 +00:00
|
|
|
{
|
2015-05-24 22:19:28 +00:00
|
|
|
_writeLine("QUIT");
|
2015-05-24 04:51:16 +00:00
|
|
|
char lineBuf[256];
|
2015-05-24 22:19:28 +00:00
|
|
|
_readLine(lineBuf, sizeof(lineBuf));
|
2015-05-24 04:51:16 +00:00
|
|
|
}
|
2015-07-28 02:25:33 +00:00
|
|
|
|
|
|
|
}
|