mirror of https://github.com/AxioDL/metaforce.git
Add PATH .blend file type
This commit is contained in:
parent
c96dbee40b
commit
06797cd9fc
|
@ -12,7 +12,8 @@ list(APPEND PY_SOURCES
|
||||||
hecl/swld/__init__.py
|
hecl/swld/__init__.py
|
||||||
hecl/mapa.py
|
hecl/mapa.py
|
||||||
hecl/mapu.py
|
hecl/mapu.py
|
||||||
hecl/frme.py)
|
hecl/frme.py
|
||||||
|
hecl/path.py)
|
||||||
|
|
||||||
bintoc(hecl_blendershell.cpp hecl_blendershell.py HECL_BLENDERSHELL)
|
bintoc(hecl_blendershell.cpp hecl_blendershell.py HECL_BLENDERSHELL)
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ bl_info = {
|
||||||
"category": "System"}
|
"category": "System"}
|
||||||
|
|
||||||
# Package import
|
# Package import
|
||||||
from . import hmdl, sact, srea, swld, mapa, mapu, frme, Nodegrid, Patching
|
from . import hmdl, sact, srea, swld, mapa, mapu, frme, path, Nodegrid, Patching
|
||||||
Nodegrid = Nodegrid.Nodegrid
|
Nodegrid = Nodegrid.Nodegrid
|
||||||
import bpy, os, sys, struct
|
import bpy, os, sys, struct
|
||||||
from bpy.app.handlers import persistent
|
from bpy.app.handlers import persistent
|
||||||
|
@ -26,7 +26,8 @@ hecl_typeS = [
|
||||||
('WORLD', "World", "Active scene represents a HECL World", swld.draw),
|
('WORLD', "World", "Active scene represents a HECL World", swld.draw),
|
||||||
('MAPAREA', "Map Area", "Active scene represents a HECL Map Area", mapa.draw),
|
('MAPAREA', "Map Area", "Active scene represents a HECL Map Area", mapa.draw),
|
||||||
('MAPUNIVERSE', "Map Universe", "Active scene represents a HECL Map Universe", mapu.draw),
|
('MAPUNIVERSE', "Map Universe", "Active scene represents a HECL Map Universe", mapu.draw),
|
||||||
('FRAME', "Gui Frame", "Active scene represents a HECL Gui Frame", frme.draw)]
|
('FRAME', "Gui Frame", "Active scene represents a HECL Gui Frame", frme.draw),
|
||||||
|
('PATH', "Path Mesh", "Active scene represents a HECL Path Mesh", path.draw)]
|
||||||
|
|
||||||
# Main Scene Panel
|
# Main Scene Panel
|
||||||
class hecl_scene_panel(bpy.types.Panel):
|
class hecl_scene_panel(bpy.types.Panel):
|
||||||
|
@ -115,6 +116,15 @@ def scene_loaded(dummy):
|
||||||
if o.library:
|
if o.library:
|
||||||
o.hide = True
|
o.hide = True
|
||||||
|
|
||||||
|
# Show PATH library objects as wireframes
|
||||||
|
if bpy.context.scene.hecl_type == 'PATH':
|
||||||
|
if bpy.context.scene.background_set:
|
||||||
|
for o in bpy.context.scene.background_set.objects:
|
||||||
|
o.draw_type = 'WIRE'
|
||||||
|
if bpy.context.scene.hecl_path_obj in bpy.context.scene.objects:
|
||||||
|
path_obj = bpy.context.scene.objects[bpy.context.scene.hecl_path_obj]
|
||||||
|
path_obj.show_wire = True
|
||||||
|
|
||||||
# Linked-Child Detection
|
# Linked-Child Detection
|
||||||
for scene in bpy.data.scenes:
|
for scene in bpy.data.scenes:
|
||||||
if scene.hecl_type == 'ACTOR':
|
if scene.hecl_type == 'ACTOR':
|
||||||
|
@ -149,6 +159,7 @@ def register():
|
||||||
frme.register()
|
frme.register()
|
||||||
mapa.register()
|
mapa.register()
|
||||||
mapu.register()
|
mapu.register()
|
||||||
|
path.register()
|
||||||
bpy.utils.register_class(hecl_scene_panel)
|
bpy.utils.register_class(hecl_scene_panel)
|
||||||
bpy.types.Scene.hecl_auto_select = bpy.props.BoolProperty(name='HECL Auto Select', default=True)
|
bpy.types.Scene.hecl_auto_select = bpy.props.BoolProperty(name='HECL Auto Select', default=True)
|
||||||
bpy.app.handlers.load_post.append(scene_loaded)
|
bpy.app.handlers.load_post.append(scene_loaded)
|
||||||
|
@ -159,6 +170,7 @@ def unregister():
|
||||||
hmdl.unregister()
|
hmdl.unregister()
|
||||||
sact.unregister()
|
sact.unregister()
|
||||||
srea.unregister()
|
srea.unregister()
|
||||||
|
path.unregister()
|
||||||
bpy.utils.unregister_class(hecl_scene_panel)
|
bpy.utils.unregister_class(hecl_scene_panel)
|
||||||
Patching.unregister()
|
Patching.unregister()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
def draw(layout, context):
|
||||||
|
layout.prop_search(context.scene, 'hecl_path_obj', context.scene, 'objects')
|
||||||
|
layout.operator('view3d.toggle_path_height_visualization', text='Toggle Height Viz', icon='MANIPUL')
|
||||||
|
layout.operator('view3d.toggle_path_background_wireframe', text='Toggle Background Wire', icon='WIRE')
|
||||||
|
|
||||||
|
def cook(writebuf, mesh_obj):
|
||||||
|
pass
|
||||||
|
|
||||||
|
import bpy, bgl
|
||||||
|
from mathutils import Vector, Matrix
|
||||||
|
from mathutils.geometry import intersect_ray_tri, tessellate_polygon
|
||||||
|
|
||||||
|
def correlate_polygon_heights(context, obj):
|
||||||
|
ret = {}
|
||||||
|
if obj.type != 'MESH':
|
||||||
|
return ret
|
||||||
|
for p in obj.data.polygons:
|
||||||
|
pl = [obj.matrix_world * obj.data.vertices[vert].co for vert in p.vertices]
|
||||||
|
tpl = tessellate_polygon((pl,))
|
||||||
|
found = False
|
||||||
|
for eobj in context.scene.objects:
|
||||||
|
for tri in tpl:
|
||||||
|
if eobj.type == 'EMPTY' and eobj.library is None:
|
||||||
|
intersect = intersect_ray_tri(pl[tri[0]], pl[tri[1]], pl[tri[2]],
|
||||||
|
Vector((0.0, 0.0, -999.0)),
|
||||||
|
eobj.location)
|
||||||
|
if intersect is not None:
|
||||||
|
ret[p] = abs(intersect.z - eobj.location.z)
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
if found:
|
||||||
|
break
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def draw_line_3d(color, start, end):
|
||||||
|
bgl.glColor4f(*color)
|
||||||
|
bgl.glBegin(bgl.GL_LINES)
|
||||||
|
bgl.glVertex3f(*start)
|
||||||
|
bgl.glVertex3f(*end)
|
||||||
|
|
||||||
|
def draw_callback_3d(self, context):
|
||||||
|
# object locations
|
||||||
|
if context.scene.hecl_path_obj not in context.scene.objects:
|
||||||
|
return
|
||||||
|
obj = context.scene.objects[context.scene.hecl_path_obj]
|
||||||
|
if obj.type != 'MESH':
|
||||||
|
return
|
||||||
|
heights = correlate_polygon_heights(context, obj)
|
||||||
|
obj_mtx = obj.matrix_world
|
||||||
|
|
||||||
|
for p in obj.data.polygons:
|
||||||
|
height = 1.0
|
||||||
|
if p in heights:
|
||||||
|
height = heights[p]
|
||||||
|
for ek in p.edge_keys:
|
||||||
|
co0 = obj_mtx * obj.data.vertices[ek[0]].co
|
||||||
|
co1 = obj_mtx * obj.data.vertices[ek[1]].co
|
||||||
|
draw_line_3d((0.0, 0.0, 1.0, 0.7), co0 + Vector((0.0, 0.0, height)),
|
||||||
|
co1 + Vector((0.0, 0.0, height)))
|
||||||
|
for vk in p.vertices:
|
||||||
|
co = obj_mtx * obj.data.vertices[vk].co
|
||||||
|
draw_line_3d((1.0, 0.0, 0.0, 0.7), co, co + Vector((0.0, 0.0, height)))
|
||||||
|
|
||||||
|
bgl.glEnd()
|
||||||
|
# restore opengl defaults
|
||||||
|
bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
|
||||||
|
|
||||||
|
class PathHeightDrawOperator(bpy.types.Operator):
|
||||||
|
bl_idname = "view3d.toggle_path_height_visualization"
|
||||||
|
bl_label = "Toggle PATH height visualization"
|
||||||
|
_handle_3d = None
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
#heights = correlate_polygon_heights(context, bpy.data.objects['Plane'])
|
||||||
|
# the arguments we pass the the callback
|
||||||
|
args = (self, context)
|
||||||
|
# Add the region OpenGL drawing callback
|
||||||
|
# draw in view space with 'POST_VIEW' and 'PRE_VIEW'
|
||||||
|
if self._handle_3d is None:
|
||||||
|
PathHeightDrawOperator._handle_3d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_3d, args, 'WINDOW', 'POST_VIEW')
|
||||||
|
else:
|
||||||
|
bpy.types.SpaceView3D.draw_handler_remove(PathHeightDrawOperator._handle_3d, 'WINDOW')
|
||||||
|
PathHeightDrawOperator._handle_3d = None
|
||||||
|
|
||||||
|
for ar in bpy.context.screen.areas:
|
||||||
|
ar.tag_redraw()
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
class PathBackgroundWireframeOperator(bpy.types.Operator):
|
||||||
|
bl_idname = "view3d.toggle_path_background_wireframe"
|
||||||
|
bl_label = "Toggle PATH background wireframe"
|
||||||
|
_handle_3d = None
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
if context.scene.background_set:
|
||||||
|
to_wire = False
|
||||||
|
for o in context.scene.background_set.objects:
|
||||||
|
if o.draw_type != 'WIRE':
|
||||||
|
to_wire = True
|
||||||
|
break
|
||||||
|
if to_wire:
|
||||||
|
for o in context.scene.background_set.objects:
|
||||||
|
o.draw_type = 'WIRE'
|
||||||
|
else:
|
||||||
|
for o in context.scene.background_set.objects:
|
||||||
|
o.draw_type = 'TEXTURED'
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
# Registration
|
||||||
|
def register():
|
||||||
|
bpy.types.Scene.hecl_path_obj = bpy.props.StringProperty(
|
||||||
|
name='HECL Path Object',
|
||||||
|
description='Blender Mesh Object to export during PATH\'s cook process')
|
||||||
|
bpy.utils.register_class(PathHeightDrawOperator)
|
||||||
|
bpy.utils.register_class(PathBackgroundWireframeOperator)
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
bpy.utils.unregister_class(PathHeightDrawOperator)
|
||||||
|
bpy.utils.unregister_class(PathBackgroundWireframeOperator)
|
|
@ -267,6 +267,15 @@ def dataout_loop():
|
||||||
bpy.data.objects.remove(join_obj)
|
bpy.data.objects.remove(join_obj)
|
||||||
bpy.data.meshes.remove(join_mesh)
|
bpy.data.meshes.remove(join_mesh)
|
||||||
|
|
||||||
|
elif cmdargs[0] == 'MESHCOMPILEPATH':
|
||||||
|
meshName = bpy.context.scene.hecl_path_obj
|
||||||
|
if meshName not in bpy.data.objects:
|
||||||
|
writepipestr(('mesh %s not found' % meshName).encode())
|
||||||
|
continue
|
||||||
|
|
||||||
|
writepipestr(b'OK')
|
||||||
|
hecl.path.cook(writepipebuf, bpy.data.objects[meshName])
|
||||||
|
|
||||||
elif cmdargs[0] == 'WORLDCOMPILE':
|
elif cmdargs[0] == 'WORLDCOMPILE':
|
||||||
writepipestr(b'OK')
|
writepipestr(b'OK')
|
||||||
hecl.swld.cook(writepipebuf)
|
hecl.swld.cook(writepipebuf)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 62b6d6792a04792587f19d8fdf4c34d251fcfce0
|
Subproject commit 17a0959dbd0a79f9f9630dc616adc79fff65ad80
|
|
@ -99,7 +99,7 @@ public:
|
||||||
#endif
|
#endif
|
||||||
void format(const char* fmt, ...);
|
void format(const char* fmt, ...);
|
||||||
void linkBlend(const char* target, const char* objName, bool link=true);
|
void linkBlend(const char* target, const char* objName, bool link=true);
|
||||||
void linkBackground(const char* target, const char* sceneName);
|
void linkBackground(const char* target, const char* sceneName=nullptr);
|
||||||
void AABBToBMesh(const atVec3f& min, const atVec3f& max);
|
void AABBToBMesh(const atVec3f& min, const atVec3f& max);
|
||||||
void centerView();
|
void centerView();
|
||||||
|
|
||||||
|
@ -509,6 +509,12 @@ struct Actor
|
||||||
Actor(Connection& conn);
|
Actor(Connection& conn);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Intermediate pathfinding representation prepared by blender */
|
||||||
|
struct PathMesh
|
||||||
|
{
|
||||||
|
PathMesh(Connection& conn);
|
||||||
|
};
|
||||||
|
|
||||||
class DataStream
|
class DataStream
|
||||||
{
|
{
|
||||||
friend class Connection;
|
friend class Connection;
|
||||||
|
@ -549,6 +555,9 @@ public:
|
||||||
/** Gather all lights in scene (AREA blends only) */
|
/** Gather all lights in scene (AREA blends only) */
|
||||||
std::vector<Light> compileLights();
|
std::vector<Light> compileLights();
|
||||||
|
|
||||||
|
/** Get PathMesh from scene (PATH blends only) */
|
||||||
|
PathMesh compilePathMesh();
|
||||||
|
|
||||||
/** Compile GUI into FRME data (FRAME blends only) */
|
/** Compile GUI into FRME data (FRAME blends only) */
|
||||||
void compileGuiFrame(std::string_view pathOut, int version);
|
void compileGuiFrame(std::string_view pathOut, int version);
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,8 @@ enum class BlendType
|
||||||
World,
|
World,
|
||||||
MapArea,
|
MapArea,
|
||||||
MapUniverse,
|
MapUniverse,
|
||||||
Frame
|
Frame,
|
||||||
|
PathMesh
|
||||||
};
|
};
|
||||||
|
|
||||||
class Connection;
|
class Connection;
|
||||||
|
@ -78,6 +79,7 @@ struct Actor;
|
||||||
struct Armature;
|
struct Armature;
|
||||||
struct Action;
|
struct Action;
|
||||||
struct Bone;
|
struct Bone;
|
||||||
|
struct PathMesh;
|
||||||
struct Matrix3f;
|
struct Matrix3f;
|
||||||
struct PoolSkinIndex;
|
struct PoolSkinIndex;
|
||||||
|
|
||||||
|
|
|
@ -608,6 +608,7 @@ static const char* BlendTypeStrs[] =
|
||||||
"MAPAREA",
|
"MAPAREA",
|
||||||
"MAPUNIVERSE",
|
"MAPUNIVERSE",
|
||||||
"FRAME",
|
"FRAME",
|
||||||
|
"PATH",
|
||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -778,20 +779,37 @@ void PyOutStream::linkBlend(const char* target, const char* objName, bool link)
|
||||||
|
|
||||||
void PyOutStream::linkBackground(const char* target, const char* sceneName)
|
void PyOutStream::linkBackground(const char* target, const char* sceneName)
|
||||||
{
|
{
|
||||||
format("if '%s' not in bpy.data.scenes:\n"
|
if (!sceneName)
|
||||||
" with bpy.data.libraries.load('''%s''', link=True, relative=True) as (data_from, data_to):\n"
|
{
|
||||||
" data_to.scenes = data_from.scenes\n"
|
format("with bpy.data.libraries.load('''%s''', link=True, relative=True) as (data_from, data_to):\n"
|
||||||
" obj_scene = None\n"
|
" data_to.scenes = data_from.scenes\n"
|
||||||
" for scene in data_to.scenes:\n"
|
"obj_scene = None\n"
|
||||||
" if scene.name == '%s':\n"
|
"for scene in data_to.scenes:\n"
|
||||||
" obj_scene = scene\n"
|
" obj_scene = scene\n"
|
||||||
" break\n"
|
" break\n"
|
||||||
" if not obj_scene:\n"
|
"if not obj_scene:\n"
|
||||||
" raise RuntimeError('''unable to find %s in %s. try deleting it and restart the extract.''')\n"
|
" raise RuntimeError('''unable to find %s. try deleting it and restart the extract.''')\n"
|
||||||
"\n"
|
"\n"
|
||||||
"bpy.context.scene.background_set = bpy.data.scenes['%s']\n",
|
"bpy.context.scene.background_set = obj_scene\n",
|
||||||
sceneName, target,
|
target, target);
|
||||||
sceneName, sceneName, target, sceneName);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
format("if '%s' not in bpy.data.scenes:\n"
|
||||||
|
" with bpy.data.libraries.load('''%s''', link=True, relative=True) as (data_from, data_to):\n"
|
||||||
|
" 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"
|
||||||
|
" if not obj_scene:\n"
|
||||||
|
" raise RuntimeError('''unable to find %s in %s. try deleting it and restart the extract.''')\n"
|
||||||
|
"\n"
|
||||||
|
"bpy.context.scene.background_set = bpy.data.scenes['%s']\n",
|
||||||
|
sceneName, target,
|
||||||
|
sceneName, sceneName, target, sceneName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PyOutStream::AABBToBMesh(const atVec3f& min, const atVec3f& max)
|
void PyOutStream::AABBToBMesh(const atVec3f& min, const atVec3f& max)
|
||||||
|
@ -1502,6 +1520,11 @@ Actor::Actor(Connection& conn)
|
||||||
actions.emplace_back(conn);
|
actions.emplace_back(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PathMesh::PathMesh(Connection& conn)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const Bone* Armature::lookupBone(const char* name) const
|
const Bone* Armature::lookupBone(const char* name) const
|
||||||
{
|
{
|
||||||
for (const Bone& b : bones)
|
for (const Bone& b : bones)
|
||||||
|
@ -1895,6 +1918,22 @@ std::vector<Light> DataStream::compileLights()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PathMesh DataStream::compilePathMesh()
|
||||||
|
{
|
||||||
|
if (m_parent->getBlendType() != BlendType::PathMesh)
|
||||||
|
BlenderLog.report(logvisor::Fatal, _S("%s is not a PATH blend"),
|
||||||
|
m_parent->getBlendPath().getAbsolutePath().data());
|
||||||
|
|
||||||
|
m_parent->_writeStr("MESHCOMPILEPATH");
|
||||||
|
|
||||||
|
char readBuf[256];
|
||||||
|
m_parent->_readStr(readBuf, 256);
|
||||||
|
if (strcmp(readBuf, "OK"))
|
||||||
|
BlenderLog.report(logvisor::Fatal, "unable to path collision mesh: %s", readBuf);
|
||||||
|
|
||||||
|
return PathMesh(*m_parent);
|
||||||
|
}
|
||||||
|
|
||||||
void DataStream::compileGuiFrame(std::string_view pathOut, int version)
|
void DataStream::compileGuiFrame(std::string_view pathOut, int version)
|
||||||
{
|
{
|
||||||
if (m_parent->getBlendType() != BlendType::Frame)
|
if (m_parent->getBlendType() != BlendType::Frame)
|
||||||
|
|
Loading…
Reference in New Issue