Updates to support VISI generation

This commit is contained in:
Jack Andersen 2017-02-23 22:27:07 -10:00
parent 9cf2aec5c1
commit 8c3a7da616
10 changed files with 295 additions and 10 deletions

View File

@ -11,8 +11,9 @@ bl_info = {
# Package import
from . import hmdl, sact, srea, swld, mapa, mapu, frme, Nodegrid, Patching
Nodegrid = Nodegrid.Nodegrid
import bpy, os, sys
import bpy, os, sys, struct
from bpy.app.handlers import persistent
from mathutils import Vector
# Appendable list allowing external addons to register additional resource types
@ -69,6 +70,41 @@ def add_export_type(type_tuple):
def command(cmdline, writepipeline, writepipebuf):
pass
def mesh_aabb(writepipebuf):
scene = bpy.context.scene
total_min = Vector((99999.0, 99999.0, 99999.0))
total_max = Vector((-99999.0, -99999.0, -99999.0))
if bpy.context.scene.hecl_type == 'ACTOR':
sact_data = bpy.context.scene.hecl_sact_data
for subtype in sact_data.subtypes:
if subtype.linked_mesh in bpy.data.objects:
mesh = bpy.data.objects[subtype.linked_mesh]
minPt = mesh.bound_box[0]
maxPt = mesh.bound_box[6]
for comp in range(3):
if minPt[comp] < total_min[comp]:
total_min[comp] = minPt[comp]
for comp in range(3):
if maxPt[comp] > total_max[comp]:
total_max[comp] = maxPt[comp]
elif bpy.context.scene.hecl_type == 'MESH':
meshName = bpy.context.scene.hecl_mesh_obj
if meshName in bpy.data.objects:
mesh = bpy.data.objects[meshName]
minPt = mesh.bound_box[0]
maxPt = mesh.bound_box[6]
for comp in range(3):
if minPt[comp] < total_min[comp]:
total_min[comp] = minPt[comp]
for comp in range(3):
if maxPt[comp] > total_max[comp]:
total_max[comp] = maxPt[comp]
writepipebuf(struct.pack('fff', total_min[0], total_min[1], total_min[2]))
writepipebuf(struct.pack('fff', total_max[0], total_max[1], total_max[2]))
# Load scene callback
from bpy.app.handlers import persistent
@persistent

View File

@ -25,6 +25,13 @@ def write_out_material(writebuf, mat, mesh_obj):
writebuf(prop[0].encode())
writebuf(struct.pack('i', prop[1]))
transparent = False
if mat.game_settings.alpha_blend == 'ALPHA' or mat.game_settings.alpha_blend == 'ALPHA_SORT':
transparent = True
elif mat.game_settings.alpha_blend == 'ADD':
transparent = True
writebuf(struct.pack('b', int(transparent)))
# Takes a Blender 'Mesh' object (not the datablock)
# and performs a one-shot conversion process to HMDL
def cook(writebuf, mesh_obj, output_mode, max_skin_banks, max_octant_length=None):

View File

@ -1,5 +1,7 @@
import bpy
from bpy.app.handlers import persistent
from mathutils import Quaternion, Color
import math
from .. import Nodegrid
# Preview update func (for lighting preview)
@ -404,6 +406,79 @@ class SREARenderLightmaps(bpy.types.Operator):
return {'FINISHED'}
def shadeless_material(idx):
name = 'SHADELESS_MAT_%d' % idx
if name in bpy.data.materials:
return bpy.data.materials[name]
mat = bpy.data.materials.new(name)
mat.use_shadeless = True
r = idx % 256
g = (idx % 65536) // 256
b = idx // 65536
mat.diffuse_color = Color((r / 255.0, g / 255.0, b / 255.0))
return mat
look_forward = Quaternion((1.0, 0.0, 0.0), math.radians(90.0))
look_backward = Quaternion((0.0, 0.0, 1.0), math.radians(180.0)) * Quaternion((1.0, 0.0, 0.0), math.radians(90.0))
look_up = Quaternion((1.0, 0.0, 0.0), math.radians(180.0))
look_down = Quaternion((1.0, 0.0, 0.0), math.radians(0.0))
look_left = Quaternion((0.0, 0.0, 1.0), math.radians(90.0)) * Quaternion((1.0, 0.0, 0.0), math.radians(90.0))
look_right = Quaternion((0.0, 0.0, 1.0), math.radians(-90.0)) * Quaternion((1.0, 0.0, 0.0), math.radians(90.0))
look_list = (look_forward, look_backward, look_up, look_down, look_left, look_right)
# Render PVS for location
def render_pvs(pathOut, location):
bpy.context.scene.render.resolution_x = 256
bpy.context.scene.render.resolution_y = 256
bpy.context.scene.render.resolution_percentage = 100
bpy.context.scene.render.use_antialiasing = False
bpy.context.scene.render.use_textures = False
bpy.context.scene.render.use_shadows = False
bpy.context.scene.render.use_sss = False
bpy.context.scene.render.use_envmaps = False
bpy.context.scene.render.use_raytrace = False
bpy.context.scene.render.engine = 'BLENDER_RENDER'
bpy.context.scene.display_settings.display_device = 'None'
bpy.context.scene.render.image_settings.file_format = 'PNG'
bpy.context.scene.world.horizon_color = Color((1.0, 1.0, 1.0))
bpy.context.scene.world.zenith_color = Color((1.0, 1.0, 1.0))
cam = bpy.data.cameras.new('CUBIC_CAM')
cam_obj = bpy.data.objects.new('CUBIC_CAM', cam)
bpy.context.scene.objects.link(cam_obj)
bpy.context.scene.camera = cam_obj
cam.lens_unit = 'FOV'
cam.angle = math.radians(90.0)
mat_idx = 0
for obj in bpy.data.objects:
if obj.type == 'MESH':
if obj.name == 'CMESH':
continue
mat = shadeless_material(mat_idx)
for slot in obj.material_slots:
slot.material = mat
mat_idx += 1
cam_obj.location = location
cam_obj.rotation_mode = 'QUATERNION'
for i in range(6):
cam_obj.rotation_quaternion = look_list[i]
bpy.context.scene.render.filepath = '%s%d' % (pathOut, i)
bpy.ops.render.render(write_still=True)
bpy.context.scene.camera = None
bpy.context.scene.objects.unlink(cam_obj)
bpy.data.objects.remove(cam_obj)
bpy.data.cameras.remove(cam)
# Render PVS for light
def render_pvs_light(pathOut, lightName):
if lightName not in bpy.data.objects:
raise RuntimeError('Unable to find light %s' % lightName)
render_pvs(pathOut, bpy.data.objects[lightName].location)
# Cook
def cook(writebuffunc, platform, endianchar):
print('COOKING SREA')

View File

@ -188,6 +188,20 @@ def dataout_loop():
if meshobj.type == 'MESH' and not meshobj.library:
writepipestr(meshobj.name.encode())
elif cmdargs[0] == 'LIGHTLIST':
lightCount = 0
for obj in bpy.context.scene.objects:
if obj.type == 'LAMP' and not obj.library:
lightCount += 1
writepipebuf(struct.pack('I', lightCount))
for obj in bpy.context.scene.objects:
if obj.type == 'LAMP' and not obj.library:
writepipestr(obj.name.encode())
elif cmdargs[0] == 'MESHAABB':
writepipestr(b'OK')
hecl.mesh_aabb(writepipebuf)
elif cmdargs[0] == 'MESHCOMPILE':
maxSkinBanks = int(cmdargs[2])
@ -281,6 +295,7 @@ def dataout_loop():
0.0, 0.0, 0.0, 1.0))
writepipebuf(struct.pack('fff', ambient_color[0], ambient_color[1], ambient_color[2]))
writepipebuf(struct.pack('IIfffffb', 0, 0, ambient_energy, 0.0, 1.0, 0.0, 0.0, False))
writepipestr(b'AMBIENT')
for obj in bpy.context.scene.objects:
if obj.type == 'LAMP':
@ -325,6 +340,8 @@ def dataout_loop():
writepipebuf(struct.pack('IIfffffb', layer, type, obj.data.energy, spotCutoff, constant, linear, quadratic,
castShadow))
writepipestr(obj.name.encode())
elif cmdargs[0] == 'GETTEXTURES':
writepipestr(b'OK')
@ -386,6 +403,20 @@ def dataout_loop():
for c in r:
writepipebuf(struct.pack('f', c))
elif cmdargs[0] == 'RENDERPVS':
pathOut = cmdargs[1]
locX = float(cmdargs[2])
locY = float(cmdargs[3])
locZ = float(cmdargs[4])
hecl.srea.render_pvs(pathOut, (locX, locY, locZ))
writepipestr(b'OK')
elif cmdargs[0] == 'RENDERPVSLIGHT':
pathOut = cmdargs[1]
lightName = cmdargs[2]
hecl.srea.render_pvs_light(pathOut, lightName)
writepipestr(b'OK')
loaded_blend = None
# Main exception handling

View File

@ -85,6 +85,9 @@ static void AthenaExc(athena::error::Level level, const char* file,
va_end(ap);
}
static hecl::SystemChar cwdbuf[1024];
hecl::SystemString ExeDir;
#if _WIN32
int wmain(int argc, const wchar_t** argv)
#else
@ -138,7 +141,6 @@ int main(int argc, const char** argv)
/* Assemble common tool pass info */
ToolPassInfo info;
info.pname = argv[0];
hecl::SystemChar cwdbuf[1024];
if (hecl::Getcwd(cwdbuf, 1024))
{
info.cwd = cwdbuf;
@ -148,6 +150,13 @@ int main(int argc, const char** argv)
#else
info.cwd += _S('/');
#endif
if (argv[0][0] != _S('/') && argv[0][0] != _S('\\'))
ExeDir = hecl::SystemString(cwdbuf) + _S('/');
hecl::SystemString Argv0(argv[0]);
hecl::SystemString::size_type lastIdx = Argv0.find_last_of(_S("/\\"));
if (lastIdx != hecl::SystemString::npos)
ExeDir.insert(ExeDir.end(), Argv0.begin(), Argv0.begin() + lastIdx);
}
/* Concatenate args */

2
hecl/extern/boo vendored

@ -1 +1 @@
Subproject commit 245a39fd92da80af40dcaf5e7567ff0b4cbf9a9a
Subproject commit 0cc794f49d8884c30ba43b195aecdfed14062a53

View File

@ -354,6 +354,40 @@ public:
return retval;
}
std::vector<std::string> getLightList()
{
m_parent->_writeStr("LIGHTLIST");
uint32_t count;
m_parent->_readBuf(&count, 4);
std::vector<std::string> retval;
retval.reserve(count);
for (uint32_t i=0 ; i<count ; ++i)
{
char name[128];
m_parent->_readStr(name, 128);
retval.push_back(name);
}
return retval;
}
std::pair<atVec3f, atVec3f> getMeshAABB()
{
if (m_parent->m_loadedType != BlendType::Mesh &&
m_parent->m_loadedType != BlendType::Actor)
BlenderLog.report(logvisor::Fatal, _S("%s is not a MESH or ACTOR blend"),
m_parent->m_loadedBlend.getAbsolutePath().c_str());
m_parent->_writeStr("MESHAABB");
char readBuf[256];
m_parent->_readStr(readBuf, 256);
if (strcmp(readBuf, "OK"))
BlenderLog.report(logvisor::Fatal, "unable get AABB: %s", readBuf);
Vector3f min(*m_parent);
Vector3f max(*m_parent);
return std::make_pair(min.val, max.val);
}
/* Vector types with integrated stream reading constructor */
struct Vector2f
{
@ -418,6 +452,7 @@ public:
std::string source;
std::vector<ProjectPath> texs;
std::unordered_map<std::string, int32_t> iprops;
bool transparent;
Material(BlenderConnection& conn);
bool operator==(const Material& other) const
@ -675,6 +710,8 @@ public:
float quadratic;
bool shadow;
std::string name;
Light(BlenderConnection& conn);
};
@ -814,6 +851,9 @@ public:
inline const atVec3f& operator[](size_t idx) const {return m[idx];}
};
std::unordered_map<std::string, Matrix3f> getBoneMatrices(const std::string& name);
bool renderPvs(const std::string& path, const atVec3f& location);
bool renderPvsLight(const std::string& path, const std::string& lightName);
};
DataStream beginData()
{

View File

@ -264,6 +264,10 @@ static inline bool IsAbsolute(const SystemString& path)
return false;
}
const SystemChar* GetTmpDir();
int RunProcess(const SystemChar* path, const SystemChar* const args[]);
enum class FileLockType
{
None = 0,

View File

@ -237,16 +237,11 @@ BlenderConnection::BlenderConnection(int verbosityLevel)
BlenderLog.report(logvisor::Info, "Establishing BlenderConnection...");
/* Put hecl_blendershell.py in temp dir */
const SystemChar* TMPDIR = GetTmpDir();
#ifdef _WIN32
wchar_t* TMPDIR = _wgetenv(L"TEMP");
if (!TMPDIR)
TMPDIR = (wchar_t*)L"\\Temp";
m_startupBlend = hecl::WideToUTF8(TMPDIR);
#else
signal(SIGPIPE, SIG_IGN);
char* TMPDIR = getenv("TMPDIR");
if (!TMPDIR)
TMPDIR = (char*)"/tmp";
m_startupBlend = TMPDIR;
#endif
@ -905,6 +900,8 @@ BlenderConnection::DataStream::Mesh::Material::Material
conn._readBuf(&val, 4);
iprops[readStr] = val;
}
conn._readBuf(&transparent, 1);
}
BlenderConnection::DataStream::Mesh::Surface::Surface
@ -1088,6 +1085,14 @@ BlenderConnection::DataStream::Light::Light(BlenderConnection& conn)
: sceneXf(conn), color(conn)
{
conn._readBuf(&layer, 29);
uint32_t nameLen;
conn._readBuf(&nameLen, 4);
if (nameLen)
{
name.assign(nameLen, '\0');
conn._readBuf(&name[0], nameLen);
}
}
BlenderConnection::DataStream::Actor::Actor(BlenderConnection& conn)
@ -1662,6 +1667,51 @@ BlenderConnection::DataStream::getBoneMatrices(const std::string& name)
}
bool BlenderConnection::DataStream::renderPvs(const std::string& path, const atVec3f& location)
{
if (path.empty())
return false;
if (m_parent->m_loadedType != BlendType::Area)
BlenderLog.report(logvisor::Fatal, _S("%s is not an AREA blend"),
m_parent->m_loadedBlend.getAbsolutePath().c_str());
char req[256];
snprintf(req, 256, "RENDERPVS %s %f %f %f", path.c_str(),
location.vec[0], location.vec[1], location.vec[2]);
m_parent->_writeStr(req);
char readBuf[256];
m_parent->_readStr(readBuf, 256);
if (strcmp(readBuf, "OK"))
BlenderLog.report(logvisor::Fatal, "unable to render PVS for: %s; %s",
m_parent->m_loadedBlend.getAbsolutePath().c_str(), readBuf);
return true;
}
bool BlenderConnection::DataStream::renderPvsLight(const std::string& path, const std::string& lightName)
{
if (path.empty())
return false;
if (m_parent->m_loadedType != BlendType::Area)
BlenderLog.report(logvisor::Fatal, _S("%s is not an AREA blend"),
m_parent->m_loadedBlend.getAbsolutePath().c_str());
char req[256];
snprintf(req, 256, "RENDERPVSLIGHT %s %s", path.c_str(), lightName.c_str());
m_parent->_writeStr(req);
char readBuf[256];
m_parent->_readStr(readBuf, 256);
if (strcmp(readBuf, "OK"))
BlenderLog.report(logvisor::Fatal, "unable to render PVS light %s for: %s; %s", lightName.c_str(),
m_parent->m_loadedBlend.getAbsolutePath().c_str(), readBuf);
return true;
}
void BlenderConnection::quitBlender()
{
char lineBuf[256];

View File

@ -744,4 +744,37 @@ int RecursiveMakeDir(const SystemChar* dir) {
}
#endif
const SystemChar* GetTmpDir()
{
#ifdef _WIN32
wchar_t* TMPDIR = _wgetenv(L"TEMP");
if (!TMPDIR)
TMPDIR = (wchar_t*)L"\\Temp";
#else
char* TMPDIR = getenv("TMPDIR");
if (!TMPDIR)
TMPDIR = (char*)"/tmp";
#endif
return TMPDIR;
}
int RunProcess(const SystemChar* path, const SystemChar* const args[])
{
#ifdef _WIN32
#else
pid_t pid = fork();
if (!pid)
{
execvp(path, (char * const *)args);
exit(1);
}
int ret;
if (waitpid(pid, &ret, 0) < 0)
return -1;
if (WIFEXITED(ret))
return WEXITSTATUS(ret);
return -1;
#endif
}
}