mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-12-10 03:47:42 +00:00
database refinements; blender shell
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
#if _WIN32
|
||||
#else
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <system_error>
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
#include "CBlenderConnection.hpp"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define DEFAULT_BLENDER_BIN "/Applications/Blender.app/Contents/MacOS/blender"
|
||||
#elif _WIN32
|
||||
#define DEFAULT_BLENDER_BIN "%ProgramFiles%\\Blender Foundation\\Blender\\blender.exe"
|
||||
#else
|
||||
#define DEFAULT_BLENDER_BIN "blender"
|
||||
#endif
|
||||
|
||||
#define TEMP_SHELLSCRIPT "/home/jacko/hecl/blender/blendershell.py"
|
||||
|
||||
size_t CBlenderConnection::readLine(char* buf, size_t bufSz)
|
||||
{
|
||||
size_t readBytes = 0;
|
||||
while (true)
|
||||
{
|
||||
if (readBytes >= bufSz)
|
||||
throw std::length_error("Pipe buffer overrun");
|
||||
ssize_t ret = read(m_readpipe[0], buf, 1);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
else if (ret == 1)
|
||||
{
|
||||
if (*buf == '\n')
|
||||
{
|
||||
*buf = '\0';
|
||||
return readBytes;
|
||||
}
|
||||
++readBytes;
|
||||
++buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
*buf = '\0';
|
||||
return readBytes;
|
||||
}
|
||||
}
|
||||
err:
|
||||
throw std::error_code(errno, std::system_category());
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t CBlenderConnection::writeLine(const char* buf)
|
||||
{
|
||||
ssize_t ret, nlerr;
|
||||
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:
|
||||
throw std::error_code(errno, std::system_category());
|
||||
}
|
||||
|
||||
size_t CBlenderConnection::readBuf(char* buf, size_t len)
|
||||
{
|
||||
ssize_t ret = read(m_readpipe[0], buf, len);
|
||||
if (ret < 0)
|
||||
throw std::error_code(errno, std::system_category());
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t CBlenderConnection::writeBuf(const char* buf, size_t len)
|
||||
{
|
||||
ssize_t ret = write(m_writepipe[1], buf, len);
|
||||
if (ret < 0)
|
||||
throw std::error_code(errno, std::system_category());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CBlenderConnection::closePipe()
|
||||
{
|
||||
close(m_readpipe[0]);
|
||||
close(m_writepipe[1]);
|
||||
}
|
||||
|
||||
CBlenderConnection::CBlenderConnection(bool silenceBlender)
|
||||
{
|
||||
/* Construct communication pipes */
|
||||
pipe(m_readpipe);
|
||||
pipe(m_writepipe);
|
||||
|
||||
/* User-specified blender path */
|
||||
char* blenderBin = getenv("BLENDER_BIN");
|
||||
|
||||
/* Child process of blender */
|
||||
pid_t pid = fork();
|
||||
if (!pid)
|
||||
{
|
||||
close(m_writepipe[1]);
|
||||
close(m_readpipe[0]);
|
||||
|
||||
if (silenceBlender)
|
||||
{
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
}
|
||||
|
||||
char errbuf[256];
|
||||
char readfds[32];
|
||||
snprintf(readfds, 32, "%d", m_writepipe[0]);
|
||||
char writefds[32];
|
||||
snprintf(writefds, 32, "%d", m_readpipe[1]);
|
||||
|
||||
/* User-specified blender first */
|
||||
if (blenderBin)
|
||||
{
|
||||
execlp(blenderBin, blenderBin, "--background", "-P", TEMP_SHELLSCRIPT,
|
||||
"--", readfds, writefds, NULL);
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
snprintf(errbuf, 256, "NOLAUNCH %s\n", strerror(errno));
|
||||
write(m_writepipe[1], errbuf, strlen(errbuf));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Default blender next */
|
||||
execlp(DEFAULT_BLENDER_BIN, DEFAULT_BLENDER_BIN, "--background", "-P", TEMP_SHELLSCRIPT,
|
||||
"--", readfds, writefds, NULL);
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
snprintf(errbuf, 256, "NOLAUNCH %s\n", strerror(errno));
|
||||
write(m_writepipe[1], errbuf, strlen(errbuf));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Unable to find blender */
|
||||
write(m_writepipe[1], "NOBLENDER\n", 10);
|
||||
exit(1);
|
||||
|
||||
}
|
||||
close(m_writepipe[0]);
|
||||
close(m_readpipe[1]);
|
||||
m_blenderProc = pid;
|
||||
|
||||
/* Handle first response */
|
||||
char lineBuf[256];
|
||||
readLine(lineBuf, sizeof(lineBuf));
|
||||
if (!strcmp(lineBuf, "NOLAUNCH"))
|
||||
{
|
||||
closePipe();
|
||||
throw std::runtime_error("Unable to launch blender");
|
||||
}
|
||||
else if (!strcmp(lineBuf, "NOBLENDER"))
|
||||
{
|
||||
closePipe();
|
||||
if (blenderBin)
|
||||
throw std::runtime_error("Unable to find blender at '" + std::string(blenderBin) + "' or '" +
|
||||
std::string(DEFAULT_BLENDER_BIN) + "'");
|
||||
else
|
||||
throw std::runtime_error("Unable to find blender at '" +
|
||||
std::string(DEFAULT_BLENDER_BIN) + "'");
|
||||
}
|
||||
else if (!strcmp(lineBuf, "NOADDON"))
|
||||
{
|
||||
closePipe();
|
||||
throw std::runtime_error("HECL addon not installed within blender");
|
||||
}
|
||||
else if (strcmp(lineBuf, "READY"))
|
||||
{
|
||||
closePipe();
|
||||
throw std::runtime_error("read '" + std::string(lineBuf) + "' from blender; expected 'READY'");
|
||||
}
|
||||
writeLine("ACK");
|
||||
|
||||
writeLine("HELLOBLENDER!!");
|
||||
readLine(lineBuf, sizeof(lineBuf));
|
||||
printf("%s\n", lineBuf);
|
||||
quitBlender();
|
||||
|
||||
}
|
||||
|
||||
CBlenderConnection::~CBlenderConnection()
|
||||
{
|
||||
closePipe();
|
||||
}
|
||||
|
||||
void CBlenderConnection::quitBlender()
|
||||
{
|
||||
writeLine("QUIT");
|
||||
char lineBuf[256];
|
||||
readLine(lineBuf, sizeof(lineBuf));
|
||||
printf("%s\n", lineBuf);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,34 @@
|
||||
#ifndef CBLENDERCONNECTION_HPP
|
||||
#define CBLENDERCONNECTION_HPP
|
||||
|
||||
#if _WIN32
|
||||
#define _WIN32_LEAN_AND_MEAN 1
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
class CBlenderConnection
|
||||
{
|
||||
#if _WIN32
|
||||
HANDLE m_blenderProc;
|
||||
HANDLE m_readpipe;
|
||||
HANDLE m_writepipe;
|
||||
#else
|
||||
pid_t m_blenderProc;
|
||||
int m_readpipe[2];
|
||||
int m_writepipe[2];
|
||||
#endif
|
||||
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:
|
||||
CBlenderConnection();
|
||||
CBlenderConnection(bool silenceBlender=false);
|
||||
~CBlenderConnection();
|
||||
|
||||
void quitBlender();
|
||||
};
|
||||
|
||||
#endif // CBLENDERCONNECTION_HPP
|
||||
|
||||
@@ -97,7 +97,7 @@ def generate_skeleton_info(armature, endian_char='<'):
|
||||
def cook(writefd, platform_type, endian_char):
|
||||
mesh_obj = bpy.data.objects[bpy.context.scene.hecl_mesh_obj]
|
||||
if mesh_obj.type != 'MESH':
|
||||
raise RuntimeError("{0} is not a mesh".format(mesh_obj.name))
|
||||
raise RuntimeError("%s is not a mesh" % mesh_obj.name)
|
||||
|
||||
# Partial meshes
|
||||
part_meshes = set()
|
||||
@@ -162,7 +162,6 @@ def cook(writefd, platform_type, endian_char):
|
||||
for mat in bpy.data.materials:
|
||||
if mat.name.endswith('_%u_%u' % (grp_idx, mat_idx)):
|
||||
hecl_str = hmdl_shader.shader(mat, mesh_obj, bpy.data.filepath)
|
||||
|
||||
|
||||
else:
|
||||
mat = mesh_obj.data.materials[mat_idx]
|
||||
|
||||
@@ -42,8 +42,11 @@ def recursive_color_trace(mat_obj, mesh_obj, blend_path, node, socket=None):
|
||||
|
||||
elif node.type == 'TEXTURE':
|
||||
|
||||
if not node.texture or not hasattr(node.texture, 'name'):
|
||||
raise RuntimeError("HMDL texture nodes must specify a texture object")
|
||||
|
||||
if not node.inputs['Vector'].is_linked:
|
||||
raise RuntimeError("HMDL texture nodes must have a 'Geometry', 'Group' UV modifier node linked")
|
||||
raise RuntimeError("HMDL texture nodes must have a 'Geometry' or 'Group' UV modifier node linked")
|
||||
|
||||
# Determine matrix generator type
|
||||
matrix_str = None
|
||||
@@ -89,6 +92,8 @@ def recursive_color_trace(mat_obj, mesh_obj, blend_path, node, socket=None):
|
||||
if soc_from.name == 'UV':
|
||||
uv_name = soc_from.node.uv_layer
|
||||
uv_idx = mesh_obj.data.uv_layers.find(uv_name)
|
||||
if uv_idx == -1:
|
||||
raise RuntimeError('UV Layer "%s" doesn\'t exist' % uv_name)
|
||||
uvsource_str = 'hecl_TexCoord[%d]' % uv_idx
|
||||
|
||||
elif soc_from.name == 'Normal':
|
||||
@@ -163,8 +168,11 @@ def recursive_alpha_trace(mat_obj, mesh_obj, blend_path, node, socket=None):
|
||||
|
||||
elif node.type == 'TEXTURE':
|
||||
|
||||
if not node.texture or not hasattr(node.texture, 'name'):
|
||||
raise RuntimeError("HMDL texture nodes must specify a texture object")
|
||||
|
||||
if not node.inputs['Vector'].is_linked:
|
||||
raise RuntimeError("HMDL texture nodes must have a 'Geometry', 'Group' UV modifier node linked")
|
||||
raise RuntimeError("HMDL texture nodes must have a 'Geometry' or 'Group' UV modifier node linked")
|
||||
|
||||
# Determine matrix generator type
|
||||
matrix_str = None
|
||||
@@ -210,6 +218,8 @@ def recursive_alpha_trace(mat_obj, mesh_obj, blend_path, node, socket=None):
|
||||
if soc_from.name == 'UV':
|
||||
uv_name = soc_from.node.uv_layer
|
||||
uv_idx = mesh_obj.data.uv_layers.find(uv_name)
|
||||
if uv_idx == -1:
|
||||
raise RuntimeError('UV Layer "%s" doesn\'t exist' % uv_name)
|
||||
uvsource_str = 'hecl_TexCoord[%d]' % uv_idx
|
||||
|
||||
elif soc_from.name == 'Normal':
|
||||
|
||||
@@ -3,7 +3,7 @@ HMDL Export Blender Addon
|
||||
By Jack Andersen <jackoalan@gmail.com>
|
||||
|
||||
This file defines the `hmdl_skin` class to iteratively construct
|
||||
a Skinning Info Section for `PAR1` HMDL files. Used by draw-format
|
||||
a Skinning Info Section for HMDL files. Used by draw-format
|
||||
generators to select an optimal skin entry for a draw primitive,
|
||||
or have a new one established.
|
||||
'''
|
||||
@@ -96,6 +96,3 @@ class hmdl_skin:
|
||||
|
||||
return info_bytes
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import bpy, sys, os
|
||||
|
||||
# Extract pipe file descriptors from arguments
|
||||
print(sys.argv)
|
||||
if '--' not in sys.argv:
|
||||
bpy.ops.wm.quit_blender()
|
||||
args = sys.argv[sys.argv.index('--')+1:]
|
||||
readfd = int(args[0])
|
||||
writefd = int(args[1])
|
||||
print('READ', readfd, 'WRITE', writefd)
|
||||
|
||||
def readpipeline():
|
||||
retval = bytearray()
|
||||
@@ -20,6 +24,12 @@ def quitblender():
|
||||
writepipeline(b'QUITTING')
|
||||
bpy.ops.wm.quit_blender()
|
||||
|
||||
# Check that HECL addon is installed/enabled
|
||||
if 'hecl' not in bpy.context.user_preferences.addons:
|
||||
if 'FINISHED' not in bpy.ops.wm.addon_enable(module='hecl'):
|
||||
writepipeline(b'NOADDON')
|
||||
bpy.ops.wm.quit_blender()
|
||||
|
||||
# Intro handshake
|
||||
writepipeline(b'READY')
|
||||
ackbytes = readpipeline()
|
||||
@@ -34,9 +44,12 @@ while True:
|
||||
quitblender()
|
||||
|
||||
elif cmdline[0] == b'OPEN':
|
||||
bpy.ops.wm.open_mainfile(filepath=cmdline[1].encode())
|
||||
bpy.ops.wm.open_mainfile(filepath=cmdline[1].decode())
|
||||
writepipeline(b'SUCCESS')
|
||||
|
||||
elif cmdline[0] == b'TYPE':
|
||||
objname = cmdline[1].encode()
|
||||
objname = cmdline[1].decode()
|
||||
|
||||
else:
|
||||
writepipeline(b'RESP ' + cmdline[0])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user