metaforce/hecl/blender/BlenderConnection.hpp

181 lines
5.5 KiB
C++
Raw Normal View History

2015-07-22 19:14:50 +00:00
#ifndef BLENDERCONNECTION_HPP
#define BLENDERCONNECTION_HPP
2015-05-24 04:51:16 +00:00
#if _WIN32
#define _WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#else
#include <unistd.h>
2015-05-24 04:51:16 +00:00
#endif
2015-07-22 19:14:50 +00:00
#include <stdint.h>
2015-08-03 02:05:04 +00:00
#include <stdio.h>
2015-05-24 22:19:28 +00:00
#include <string>
#include <functional>
2015-07-28 02:25:33 +00:00
#include "HECL/HECL.hpp"
namespace HECL
{
extern LogVisor::LogModule BlenderLog;
extern class BlenderConnection* SharedBlenderConnection;
2015-07-22 19:14:50 +00:00
class BlenderConnection
{
2015-08-16 23:01:35 +00:00
bool m_lock;
2015-05-24 04:51:16 +00:00
#if _WIN32
HANDLE m_blenderProc;
2015-07-22 19:14:50 +00:00
HANDLE m_readpipe[2];
HANDLE m_writepipe[2];
2015-05-24 04:51:16 +00:00
#else
pid_t m_blenderProc;
2015-05-24 04:51:16 +00:00
int m_readpipe[2];
int m_writepipe[2];
#endif
2015-05-24 22:19:28 +00:00
std::string m_loadedBlend;
size_t _readLine(char* buf, size_t bufSz);
size_t _writeLine(const char* buf);
size_t _readBuf(char* buf, size_t len);
size_t _writeBuf(const char* buf, size_t len);
void _closePipe();
public:
2015-07-22 19:14:50 +00:00
BlenderConnection(bool silenceBlender=false);
~BlenderConnection();
2015-05-24 04:51:16 +00:00
2015-07-28 02:25:33 +00:00
bool createBlend(const SystemString& path);
bool openBlend(const SystemString& path);
bool saveBlend();
2015-08-05 22:59:59 +00:00
void deleteBlend();
2015-05-24 22:19:28 +00:00
enum CookPlatform
{
CP_MODERN = 0,
CP_GX = 1,
};
2015-05-26 04:42:20 +00:00
bool cookBlend(std::function<char*(uint32_t)> bufGetter,
2015-05-24 22:19:28 +00:00
const std::string& expectedType,
const std::string& platform,
bool bigEndian=false);
2015-07-25 23:01:02 +00:00
class PyOutStream : public std::ostream
{
friend class BlenderConnection;
BlenderConnection* m_parent;
2015-08-05 22:59:59 +00:00
bool m_deleteOnError;
2015-07-25 23:01:02 +00:00
struct StreamBuf : std::streambuf
{
2015-08-05 22:59:59 +00:00
PyOutStream& m_parent;
2015-07-28 02:25:33 +00:00
std::string m_lineBuf;
2015-08-05 22:59:59 +00:00
bool m_deleteOnError;
StreamBuf(PyOutStream& parent, bool deleteOnError)
: m_parent(parent), m_deleteOnError(deleteOnError) {}
2015-07-25 23:01:02 +00:00
StreamBuf(const StreamBuf& other) = delete;
StreamBuf(StreamBuf&& other) = default;
int_type overflow(int_type ch)
{
2015-08-16 23:01:35 +00:00
if (!m_parent.m_parent || !m_parent.m_parent->m_lock)
2015-08-05 22:59:59 +00:00
BlenderLog.report(LogVisor::FatalError, "lock not held for PyOutStream writing");
2015-07-28 02:25:33 +00:00
if (ch != traits_type::eof() && ch != '\n')
2015-07-25 23:01:02 +00:00
{
2015-07-28 02:25:33 +00:00
m_lineBuf += char_type(ch);
return ch;
2015-07-25 23:01:02 +00:00
}
2015-08-05 22:59:59 +00:00
m_parent.m_parent->_writeLine(m_lineBuf.c_str());
2015-07-28 02:25:33 +00:00
char readBuf[16];
2015-08-05 22:59:59 +00:00
m_parent.m_parent->_readLine(readBuf, 16);
2015-07-28 02:25:33 +00:00
if (strcmp(readBuf, "OK"))
2015-08-05 22:59:59 +00:00
{
if (m_deleteOnError)
m_parent.m_parent->deleteBlend();
2015-07-28 02:25:33 +00:00
BlenderLog.report(LogVisor::FatalError, "error sending '%s' to blender", m_lineBuf.c_str());
2015-08-05 22:59:59 +00:00
}
2015-07-28 02:25:33 +00:00
m_lineBuf.clear();
2015-07-25 23:01:02 +00:00
return ch;
}
} m_sbuf;
2015-08-05 22:59:59 +00:00
PyOutStream(BlenderConnection* parent, bool deleteOnError)
2015-08-16 23:01:35 +00:00
: m_parent(parent),
2015-08-05 22:59:59 +00:00
m_sbuf(*this, deleteOnError),
m_deleteOnError(deleteOnError),
std::ostream(&m_sbuf)
2015-07-25 23:01:02 +00:00
{
2015-08-16 23:01:35 +00:00
m_parent->m_lock = true;
2015-07-28 02:25:33 +00:00
m_parent->_writeLine("PYBEGIN");
char readBuf[16];
m_parent->_readLine(readBuf, 16);
if (strcmp(readBuf, "READY"))
BlenderLog.report(LogVisor::FatalError, "unable to open PyOutStream with blender");
2015-07-25 23:01:02 +00:00
}
public:
PyOutStream(const PyOutStream& other) = delete;
PyOutStream(PyOutStream&& other)
2015-08-16 23:01:35 +00:00
: m_parent(other.m_parent), m_sbuf(std::move(other.m_sbuf))
2015-07-25 23:01:02 +00:00
{other.m_parent = nullptr;}
2015-08-05 22:59:59 +00:00
~PyOutStream() {close();}
void close()
2015-07-25 23:01:02 +00:00
{
2015-08-16 23:01:35 +00:00
if (m_parent && m_parent->m_lock)
2015-07-28 02:25:33 +00:00
{
2015-08-16 23:01:35 +00:00
m_parent->_writeLine("PYEND");
char readBuf[16];
m_parent->_readLine(readBuf, 16);
if (strcmp(readBuf, "DONE"))
BlenderLog.report(LogVisor::FatalError, "unable to close PyOutStream with blender");
m_parent->m_lock = false;
2015-07-28 02:25:33 +00:00
}
2015-07-25 23:01:02 +00:00
}
2015-08-03 02:05:04 +00:00
void format(const char* fmt, ...)
{
2015-08-16 23:01:35 +00:00
if (!m_parent || !m_parent->m_lock)
2015-08-05 22:59:59 +00:00
BlenderLog.report(LogVisor::FatalError, "lock not held for PyOutStream::format()");
2015-08-03 02:05:04 +00:00
va_list ap;
va_start(ap, fmt);
char* result = nullptr;
int length = vasprintf(&result, fmt, ap);
if (length > 0)
this->write(result, length);
free(result);
va_end(ap);
}
void linkBlend(const SystemString& target, const std::string& objName, bool link=true);
2015-07-25 23:01:02 +00:00
};
2015-08-05 22:59:59 +00:00
inline PyOutStream beginPythonOut(bool deleteOnError=false)
2015-07-25 23:01:02 +00:00
{
2015-08-16 23:01:35 +00:00
if (m_lock)
BlenderLog.report(LogVisor::FatalError, "lock already held for BlenderConnection::beginPythonOut()");
2015-08-05 22:59:59 +00:00
return PyOutStream(this, deleteOnError);
2015-07-25 23:01:02 +00:00
}
2015-05-24 04:51:16 +00:00
void quitBlender();
2015-07-28 02:25:33 +00:00
static inline BlenderConnection& SharedConnection()
{
if (!SharedBlenderConnection)
2015-08-06 19:10:12 +00:00
SharedBlenderConnection = new BlenderConnection(HECL::VerbosityLevel?false:true);
2015-07-28 02:25:33 +00:00
return *SharedBlenderConnection;
}
2015-08-16 23:01:35 +00:00
inline void closeStream()
{
if (m_lock)
deleteBlend();
}
2015-07-28 02:25:33 +00:00
static inline void Shutdown()
{
2015-08-16 23:01:35 +00:00
if (SharedBlenderConnection)
{
SharedBlenderConnection->closeStream();
SharedBlenderConnection->quitBlender();
delete SharedBlenderConnection;
SharedBlenderConnection = nullptr;
BlenderLog.report(LogVisor::Info, "BlenderConnection Shutdown Successful");
}
2015-07-28 02:25:33 +00:00
}
2015-08-16 23:01:35 +00:00
};
2015-07-28 02:25:33 +00:00
}
2015-07-22 19:14:50 +00:00
#endif // BLENDERCONNECTION_HPP