added 'bintoc' tool; embedded blender python scripts

This commit is contained in:
Jack Andersen 2015-08-04 11:35:41 -10:00
parent 73185fc32c
commit 8e89d7efd0
9 changed files with 634 additions and 38 deletions

View File

@ -0,0 +1,29 @@
#include <stdint.h>
#include <BlenderConnection.hpp>
#include "BlenderSupport.hpp"
extern "C" uint8_t RETRO_MASTER_SHADER[];
extern "C" size_t RETRO_MASTER_SHADER_SZ;
namespace Retro
{
namespace Blender
{
bool BuildMasterShader(const HECL::ProjectPath& path)
{
if (path.getPathType() == HECL::ProjectPath::PT_FILE)
return true;
HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection();
if (!conn.createBlend(path.getAbsolutePath()))
return false;
{
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut();
os << RETRO_MASTER_SHADER;
os << "make_master_shader_library()\n";
}
return conn.saveBlend();
}
}
}

View File

@ -0,0 +1,16 @@
#ifndef _RETRO_BLENDER_SUPPORT_HPP_
#define _RETRO_BLENDER_SUPPORT_HPP_
#include <HECL/HECL.hpp>
namespace Retro
{
namespace Blender
{
bool BuildMasterShader(const HECL::ProjectPath& path);
}
}
#endif // _RETRO_BLENDER_SUPPORT_HPP_

View File

@ -0,0 +1,419 @@
"Defines a node group for all game shaders to provide individual outputs to"
import bpy
# UV modifier nodes:
# http://www.metroid2002.com/retromodding/wiki/Materials_(Metroid_Prime)#UV_Animations
# 0 - Modelview Inverse (zero translation)
def make_uvm0():
new_grp = bpy.data.node_groups.new('RWKUVMode0Node', 'ShaderNodeTree')
new_grp.inputs.new('NodeSocketVector', 'UV In')
new_grp.outputs.new('NodeSocketVector', 'UV Out')
new_grp.use_fake_user = True
# Group inputs
grp_in = new_grp.nodes.new('NodeGroupInput')
grp_in.location = (-100, 0)
# Group outputs
grp_out = new_grp.nodes.new('NodeGroupOutput')
grp_out.location = (500, 0)
# UV vertical-flip (to match GameCube's UV-coordinate space)
v_flip = new_grp.nodes.new('ShaderNodeMapping')
v_flip.location = (100, 0)
v_flip.vector_type = 'TEXTURE'
v_flip.scale[1] = -1.0
# Links
new_grp.links.new(grp_in.outputs[0], v_flip.inputs[0])
new_grp.links.new(v_flip.outputs[0], grp_out.inputs[0])
# 1 - Modelview Inverse
def make_uvm1():
new_grp = bpy.data.node_groups.new('RWKUVMode1Node', 'ShaderNodeTree')
new_grp.inputs.new('NodeSocketVector', 'UV In')
new_grp.outputs.new('NodeSocketVector', 'UV Out')
new_grp.use_fake_user = True
# Group inputs
grp_in = new_grp.nodes.new('NodeGroupInput')
grp_in.location = (-300, 0)
# Group outputs
grp_out = new_grp.nodes.new('NodeGroupOutput')
grp_out.location = (500, 0)
# Geometry input
geom_in = new_grp.nodes.new('ShaderNodeGeometry')
geom_in.location = (-700, 0)
# View flip
view_flip = new_grp.nodes.new('ShaderNodeMapping')
view_flip.location = (-500, -100)
view_flip.vector_type = 'TEXTURE'
view_flip.scale = (-1.0, -1.0, 1.0)
# Normal/translation add
adder = new_grp.nodes.new('ShaderNodeVectorMath')
adder.location = (-100, 0)
adder.operation = 'ADD'
# UV vertical-flip (to match GameCube's UV-coordinate space)
v_flip = new_grp.nodes.new('ShaderNodeMapping')
v_flip.location = (100, 0)
v_flip.vector_type = 'TEXTURE'
v_flip.scale[1] = -1.0
# Links
new_grp.links.new(grp_in.outputs[0], adder.inputs[0])
new_grp.links.new(geom_in.outputs['View'], view_flip.inputs[0])
new_grp.links.new(view_flip.outputs[0], adder.inputs[1])
new_grp.links.new(adder.outputs[0], v_flip.inputs[0])
new_grp.links.new(v_flip.outputs[0], grp_out.inputs[0])
# 2 - UV Scroll
def make_uvm2():
new_grp = bpy.data.node_groups.new('RWKUVMode2Node', 'ShaderNodeTree')
new_grp.inputs.new('NodeSocketVector', 'UV In')
new_grp.inputs.new('NodeSocketVector', 'Offset')
new_grp.inputs.new('NodeSocketVector', 'Scale')
new_grp.outputs.new('NodeSocketVector', 'UV Out')
new_grp.use_fake_user = True
# Group inputs
grp_in = new_grp.nodes.new('NodeGroupInput')
grp_in.location = (-100, 0)
# Group outputs
grp_out = new_grp.nodes.new('NodeGroupOutput')
grp_out.location = (500, 0)
# Adder1
adder1 = new_grp.nodes.new('ShaderNodeVectorMath')
adder1.operation = 'ADD'
adder1.location = (100, 0)
# Adder2
adder2 = new_grp.nodes.new('ShaderNodeVectorMath')
adder2.operation = 'ADD'
adder2.location = (100, 200)
# Links
new_grp.links.new(grp_in.outputs[0], adder2.inputs[0])
new_grp.links.new(grp_in.outputs[1], adder1.inputs[0])
new_grp.links.new(grp_in.outputs[2], adder1.inputs[1])
new_grp.links.new(adder1.outputs[0], adder2.inputs[1])
new_grp.links.new(adder2.outputs[0], grp_out.inputs[0])
# 3 - Rotation
def make_uvm3():
new_grp = bpy.data.node_groups.new('RWKUVMode3Node', 'ShaderNodeTree')
new_grp.inputs.new('NodeSocketVector', 'UV In')
new_grp.inputs.new('NodeSocketFloat', 'Offset')
new_grp.inputs.new('NodeSocketFloat', 'Scale')
new_grp.outputs.new('NodeSocketVector', 'UV Out')
new_grp.use_fake_user = True
# Group inputs
grp_in = new_grp.nodes.new('NodeGroupInput')
grp_in.location = (-100, 0)
# Group outputs
grp_out = new_grp.nodes.new('NodeGroupOutput')
grp_out.location = (700, 0)
# Adder1
add1 = new_grp.nodes.new('ShaderNodeMath')
add1.operation = 'ADD'
add1.location = (500, 0)
# Links
new_grp.links.new(grp_in.outputs[0], grp_out.inputs[0])
new_grp.links.new(grp_in.outputs[1], add1.inputs[0])
new_grp.links.new(grp_in.outputs[2], add1.inputs[1])
# 4 - Horizontal Filmstrip Animation
def make_uvm4():
new_grp = bpy.data.node_groups.new('RWKUVMode4Node', 'ShaderNodeTree')
new_grp.inputs.new('NodeSocketVector', 'UV In')
new_grp.inputs.new('NodeSocketFloat', 'Scale')
new_grp.inputs.new('NodeSocketFloat', 'NumFrames')
new_grp.inputs.new('NodeSocketFloat', 'Step')
new_grp.inputs.new('NodeSocketFloat', 'Offset')
new_grp.outputs.new('NodeSocketVector', 'UV Out')
new_grp.use_fake_user = True
# Group inputs
grp_in = new_grp.nodes.new('NodeGroupInput')
grp_in.location = (-1000, 0)
# Group outputs
grp_out = new_grp.nodes.new('NodeGroupOutput')
grp_out.location = (800, 0)
# Multiply1
mult1 = new_grp.nodes.new('ShaderNodeMath')
mult1.operation = 'MULTIPLY'
mult1.location = (-800, 0)
# Multiply2
mult2 = new_grp.nodes.new('ShaderNodeMath')
mult2.operation = 'MULTIPLY'
mult2.location = (-600, 0)
# Modulo
mod1 = new_grp.nodes.new('ShaderNodeMath')
mod1.operation = 'MODULO'
mod1.inputs[1].default_value = 1.0
mod1.location = (-400, 0)
# Multiply3
mult3 = new_grp.nodes.new('ShaderNodeMath')
mult3.operation = 'MULTIPLY'
mult3.location = (-200, 0)
# Multiply4
mult4 = new_grp.nodes.new('ShaderNodeMath')
mult4.operation = 'MULTIPLY'
mult4.location = (0, 0)
# Mapping
map1 = new_grp.nodes.new('ShaderNodeMapping')
map1.scale = (1.0, 0.0, 0.0)
map1.location = (200, 0)
# Add
add1 = new_grp.nodes.new('ShaderNodeVectorMath')
add1.operation = 'ADD'
add1.location = (600, 0)
# Links
new_grp.links.new(grp_in.outputs[0], add1.inputs[1])
new_grp.links.new(grp_in.outputs[1], mult1.inputs[1])
new_grp.links.new(grp_in.outputs[2], mult3.inputs[1])
new_grp.links.new(grp_in.outputs[3], mult4.inputs[1])
new_grp.links.new(grp_in.outputs[3], mult1.inputs[0])
new_grp.links.new(grp_in.outputs[4], mult2.inputs[1])
new_grp.links.new(mult1.outputs[0], mult2.inputs[0])
new_grp.links.new(mult2.outputs[0], mod1.inputs[0])
new_grp.links.new(mod1.outputs[0], mult3.inputs[0])
new_grp.links.new(mult3.outputs[0], mult4.inputs[0])
new_grp.links.new(mult4.outputs[0], map1.inputs[0])
new_grp.links.new(map1.outputs[0], add1.inputs[0])
new_grp.links.new(add1.outputs[0], grp_out.inputs[0])
# 5 - Vertical Filmstrip Animation
def make_uvm5():
new_grp = bpy.data.node_groups.new('RWKUVMode5Node', 'ShaderNodeTree')
new_grp.inputs.new('NodeSocketVector', 'UV In')
new_grp.inputs.new('NodeSocketFloat', 'Scale')
new_grp.inputs.new('NodeSocketFloat', 'NumFrames')
new_grp.inputs.new('NodeSocketFloat', 'Step')
new_grp.inputs.new('NodeSocketFloat', 'Offset')
new_grp.outputs.new('NodeSocketVector', 'UV Out')
new_grp.use_fake_user = True
# Group inputs
grp_in = new_grp.nodes.new('NodeGroupInput')
grp_in.location = (-1000, 0)
# Group outputs
grp_out = new_grp.nodes.new('NodeGroupOutput')
grp_out.location = (800, 0)
# Multiply1
mult1 = new_grp.nodes.new('ShaderNodeMath')
mult1.operation = 'MULTIPLY'
mult1.location = (-800, 0)
# Multiply2
mult2 = new_grp.nodes.new('ShaderNodeMath')
mult2.operation = 'MULTIPLY'
mult2.location = (-600, 0)
# Modulo
mod1 = new_grp.nodes.new('ShaderNodeMath')
mod1.operation = 'MODULO'
mod1.inputs[1].default_value = 1.0
mod1.location = (-400, 0)
# Multiply3
mult3 = new_grp.nodes.new('ShaderNodeMath')
mult3.operation = 'MULTIPLY'
mult3.location = (-200, 0)
# Multiply4
mult4 = new_grp.nodes.new('ShaderNodeMath')
mult4.operation = 'MULTIPLY'
mult4.location = (0, 0)
# Mapping
map1 = new_grp.nodes.new('ShaderNodeMapping')
map1.scale = (0.0, 1.0, 0.0)
map1.location = (200, 0)
# Add
add1 = new_grp.nodes.new('ShaderNodeVectorMath')
add1.operation = 'ADD'
add1.location = (600, 0)
# Links
new_grp.links.new(grp_in.outputs[0], add1.inputs[1])
new_grp.links.new(grp_in.outputs[1], mult1.inputs[1])
new_grp.links.new(grp_in.outputs[2], mult3.inputs[1])
new_grp.links.new(grp_in.outputs[3], mult4.inputs[1])
new_grp.links.new(grp_in.outputs[3], mult1.inputs[0])
new_grp.links.new(grp_in.outputs[4], mult2.inputs[1])
new_grp.links.new(mult1.outputs[0], mult2.inputs[0])
new_grp.links.new(mult2.outputs[0], mod1.inputs[0])
new_grp.links.new(mod1.outputs[0], mult3.inputs[0])
new_grp.links.new(mult3.outputs[0], mult4.inputs[0])
new_grp.links.new(mult4.outputs[0], map1.inputs[0])
new_grp.links.new(map1.outputs[0], add1.inputs[0])
new_grp.links.new(add1.outputs[0], grp_out.inputs[0])
# 6 - Model Matrix
def make_uvm6():
new_grp = bpy.data.node_groups.new('RWKUVMode6Node', 'ShaderNodeTree')
new_grp.inputs.new('NodeSocketVector', 'UV In')
new_grp.outputs.new('NodeSocketVector', 'UV Out')
new_grp.use_fake_user = True
# Group inputs
grp_in = new_grp.nodes.new('NodeGroupInput')
grp_in.location = (-100, 0)
# Group outputs
grp_out = new_grp.nodes.new('NodeGroupOutput')
grp_out.location = (300, 0)
# Geometry input
geom_in = new_grp.nodes.new('ShaderNodeGeometry')
geom_in.location = (-300, 0)
# Adder1
adder1 = new_grp.nodes.new('ShaderNodeVectorMath')
adder1.operation = 'ADD'
adder1.location = (100, 0)
# Links
new_grp.links.new(grp_in.outputs[0], adder1.inputs[0])
new_grp.links.new(geom_in.outputs['Global'], adder1.inputs[1])
new_grp.links.new(adder1.outputs[0], grp_out.inputs[0])
# 7 - Mode Who Must Not Be Named
def make_uvm7():
new_grp = bpy.data.node_groups.new('RWKUVMode7Node', 'ShaderNodeTree')
new_grp.inputs.new('NodeSocketVector', 'UV In')
new_grp.inputs.new('NodeSocketFloat', 'ParamA')
new_grp.inputs.new('NodeSocketFloat', 'ParamB')
new_grp.outputs.new('NodeSocketVector', 'UV Out')
new_grp.use_fake_user = True
# Group inputs
grp_in = new_grp.nodes.new('NodeGroupInput')
grp_in.location = (-800, 0)
# Group outputs
grp_out = new_grp.nodes.new('NodeGroupOutput')
grp_out.location = (0, 0)
# Geometry input
geom_in = new_grp.nodes.new('ShaderNodeGeometry')
geom_in.location = (-1000, 0)
# View flip
view_flip = new_grp.nodes.new('ShaderNodeMapping')
view_flip.location = (-800, -150)
view_flip.vector_type = 'TEXTURE'
view_flip.scale = (-1.0, -1.0, 1.0)
# Separate
sep1 = new_grp.nodes.new('ShaderNodeSeparateRGB')
sep1.location = (-400, -200)
# Add1
add1 = new_grp.nodes.new('ShaderNodeMath')
add1.operation = 'ADD'
add1.location = (-200, -200)
# Multiply1
mult1 = new_grp.nodes.new('ShaderNodeMath')
mult1.operation = 'MULTIPLY'
mult1.inputs[1].default_value = 0.025
mult1.location = (0, -200)
# Multiply2
mult2 = new_grp.nodes.new('ShaderNodeMath')
mult2.operation = 'MULTIPLY'
mult2.location = (200, -200)
# Multiply3
mult3 = new_grp.nodes.new('ShaderNodeMath')
mult3.operation = 'MULTIPLY'
mult3.inputs[1].default_value = 0.05
mult3.location = (0, -400)
# Multiply4
mult4 = new_grp.nodes.new('ShaderNodeMath')
mult4.operation = 'MULTIPLY'
mult4.location = (200, -400)
# Combine1
comb1 = new_grp.nodes.new('ShaderNodeCombineRGB')
comb1.location = (400, -300)
# Combine2
comb2 = new_grp.nodes.new('ShaderNodeCombineRGB')
comb2.location = (-600, 0)
# Multiply5
mult5 = new_grp.nodes.new('ShaderNodeMixRGB')
mult5.blend_type = 'MULTIPLY'
mult5.inputs[0].default_value = 1.0
mult5.location = (-400, 0)
# Add2
add2 = new_grp.nodes.new('ShaderNodeVectorMath')
add2.operation = 'ADD'
add2.location = (-200, 0)
# Links
new_grp.links.new(grp_in.outputs[0], add2.inputs[0])
new_grp.links.new(geom_in.outputs['View'], view_flip.inputs[0])
new_grp.links.new(view_flip.outputs[0], sep1.inputs[0])
new_grp.links.new(grp_in.outputs[1], comb2.inputs[0])
new_grp.links.new(grp_in.outputs[1], comb2.inputs[1])
new_grp.links.new(grp_in.outputs[1], comb2.inputs[2])
new_grp.links.new(comb2.outputs[0], mult5.inputs[1])
new_grp.links.new(grp_in.outputs[2], mult2.inputs[1])
new_grp.links.new(grp_in.outputs[2], mult4.inputs[1])
new_grp.links.new(sep1.outputs[0], add1.inputs[0])
new_grp.links.new(sep1.outputs[1], add1.inputs[1])
new_grp.links.new(sep1.outputs[2], mult3.inputs[0])
new_grp.links.new(add1.outputs[0], mult1.inputs[0])
new_grp.links.new(mult1.outputs[0], mult2.inputs[0])
new_grp.links.new(mult2.outputs[0], comb1.inputs[0])
new_grp.links.new(mult3.outputs[0], mult4.inputs[0])
new_grp.links.new(mult4.outputs[0], comb1.inputs[1])
new_grp.links.new(comb1.outputs[0], mult5.inputs[2])
new_grp.links.new(mult5.outputs[0], add2.inputs[1])
new_grp.links.new(add2.outputs[0], grp_out.inputs[0])
UV_MODIFIER_GROUPS = [
make_uvm0,
make_uvm1,
make_uvm2,
make_uvm3,
make_uvm4,
make_uvm5,
make_uvm6,
make_uvm7
]
def make_master_shader_library():
for uvm in UV_MODIFIER_GROUPS:
uvm()

View File

@ -20,9 +20,16 @@ add_subdirectory(DNAMP1)
add_subdirectory(DNAMP2) add_subdirectory(DNAMP2)
add_subdirectory(DNAMP3) add_subdirectory(DNAMP3)
# Embed master shader script
bintoc(RetroMasterShader.c Blender/RetroMasterShader.py RETRO_MASTER_SHADER)
# Each game's DataSpec implementation # Each game's DataSpec implementation
add_library(RetroDataSpec add_library(RetroDataSpec
SpecBase.cpp SpecBase.cpp
SpecMP1.cpp SpecMP1.cpp
SpecMP2.cpp SpecMP2.cpp
SpecMP3.cpp) SpecMP3.cpp
Blender/BlenderSupport.hpp
Blender/BlenderSupport.cpp
Blender/RetroMasterShader.py
RetroMasterShader.c)

View File

@ -247,7 +247,8 @@ template <class PAKBRIDGE>
struct ResExtractor struct ResExtractor
{ {
std::function<bool(PAKEntryReadStream&, const HECL::ProjectPath&)> func_a; std::function<bool(PAKEntryReadStream&, const HECL::ProjectPath&)> func_a;
std::function<bool(PAKEntryReadStream&, const HECL::ProjectPath&, PAKRouter<PAKBRIDGE>&)> func_b; std::function<bool(PAKEntryReadStream&, const HECL::ProjectPath&, PAKRouter<PAKBRIDGE>&,
const typename PAKBRIDGE::PAKType::Entry&)> func_b;
const char* fileExt; const char* fileExt;
unsigned weight; unsigned weight;
}; };
@ -368,6 +369,43 @@ public:
return HECL::ProjectPath(); return HECL::ProjectPath();
} }
HECL::SystemString getResourceRelativePath(const typename BRIDGETYPE::PAKType::Entry& a,
const typename BRIDGETYPE::PAKType::IDType& b) const
{
if (!m_pak)
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter::enterPAKBridge() must be called before PAKRouter::getResourceRelativePath()");
const typename BRIDGETYPE::PAKType::Entry* be = m_pak->lookupEntry(b);
if (!be)
return HECL::SystemString();
HECL::ProjectPath aPath = getWorking(&a, BRIDGETYPE::LookupExtractor(a));
HECL::SystemString ret;
for (int i=0 ; i<aPath.levelCount() ; ++i)
ret += "../";
HECL::ProjectPath bPath = getWorking(be, BRIDGETYPE::LookupExtractor(*be));
ret += bPath.getRelativePath();
return ret;
}
std::string getBestEntryName(const typename BRIDGETYPE::PAKType::Entry& entry) const
{
if (!m_pak)
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter::enterPAKBridge() must be called before PAKRouter::getBestEntryName()");
return m_pak->bestEntryName(entry);
}
std::string getBestEntryName(const typename BRIDGETYPE::PAKType::IDType& entry) const
{
if (!m_pak)
LogDNACommon.report(LogVisor::FatalError,
"PAKRouter::enterPAKBridge() must be called before PAKRouter::getBestEntryName()");
const typename BRIDGETYPE::PAKType::Entry* e = m_pak->lookupEntry(entry);
if (!e)
return entry.toString();
return m_pak->bestEntryName(*e);
}
bool extractResources(const BRIDGETYPE& pakBridge, bool force, std::function<void(float)> progress) bool extractResources(const BRIDGETYPE& pakBridge, bool force, std::function<void(float)> progress)
{ {
enterPAKBridge(pakBridge); enterPAKBridge(pakBridge);
@ -405,7 +443,7 @@ public:
if (force || working.getPathType() == HECL::ProjectPath::PT_NONE) if (force || working.getPathType() == HECL::ProjectPath::PT_NONE)
{ {
PAKEntryReadStream s = item.second->beginReadStream(*m_node); PAKEntryReadStream s = item.second->beginReadStream(*m_node);
extractor.func_b(s, working, *this); extractor.func_b(s, working, *this, *item.second);
} }
} }

View File

@ -10,9 +10,9 @@ namespace DNAMP1
bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
Athena::io::IStreamReader& reader, Athena::io::IStreamReader& reader,
PAKRouter<PAKBridge>& pakRouter) PAKRouter<PAKBridge>& pakRouter,
const PAK::Entry& entry)
{ {
return true;
reader.setEndian(Athena::BigEndian); reader.setEndian(Athena::BigEndian);
CMDL::Header head; CMDL::Header head;
@ -32,24 +32,104 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
/* Open Py Stream */ /* Open Py Stream */
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut(); HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut();
os << "import bmesh\n" os << "import bpy\n"
"import bpy\n" "import bmesh\n"
"bm = bmesh.new()\n"; "\n"
"bpy.context.scene.name = '%s'\n"
"bpy.context.scene.rwk_type = 'MESH'\n"
"bpy.context.scene.rwk_mesh = bpy.context.scene.name\n"
"\n"
"# Using 'Blender Game'\n"
"bpy.context.scene.render.engine = 'BLENDER_GAME'\n"
"\n"
"# Clear Scene\n"
"for ob in bpy.data.objects:\n"
" if ob.type != 'LAMP':\n"
" bpy.context.scene.objects.unlink(ob)\n"
" bpy.data.objects.remove(ob)\n"
"\n"
"# Property to convey original vert indices in overdraw meshes\n"
"class RWKOriginalIndex(bpy.types.PropertyGroup):\n"
" index = bpy.props.IntProperty(name='Original Vertex Index')\n"
"bpy.utils.register_class(RWKOriginalIndex)\n"
"bpy.types.Mesh.rwk_orig_verts = bpy.props.CollectionProperty(type=RWKOriginalIndex)\n"
"\n"
"def loop_from_facevert(face, vert_idx):\n"
" for loop in face.loops:\n"
" if loop.vert.index == vert_idx:\n"
" return loop\n"
"\n"
"def add_triangle(bm, vert_seq, vert_indices, norm_seq, norm_indices, mat_nr, od_list):\n"
" if len(set(vert_indices)) != 3:\n"
" return None, None\n"
"\n"
" ret_mesh = bm\n"
" vert_seq.ensure_lookup_table()\n"
" verts = [vert_seq[i] for i in vert_indices]\n"
" norms = [norm_seq[i] for i in norm_indices]\n"
"\n"
" # Make the face\n"
" face = bm.faces.get(verts)\n"
"\n"
" if face is not None and face.material_index != mat_nr: # Same poly, new material\n"
" # Overdraw detected; track copy\n"
" od_entry = None\n"
" for entry in od_list:\n"
" if entry['material'] == mat_nr:\n"
" od_entry = entry\n"
" if od_entry is None:\n"
" bm_cpy = bm.copy()\n"
" od_entry = {'material':mat_nr, 'bm':bm_cpy}\n"
" bmesh.ops.delete(od_entry['bm'], geom=od_entry['bm'].faces, context=3)\n"
" od_list.append(od_entry)\n"
" od_entry['bm'].verts.ensure_lookup_table()\n"
" verts = [od_entry['bm'].verts[i] for i in vert_indices]\n"
" face = od_entry['bm'].faces.get(verts)\n"
" if face is None:\n"
" face = od_entry['bm'].faces.new(verts)\n"
" else: # Probably a double-sided surface\n"
" face = face.copy()\n"
" face.normal_flip()\n"
" ret_mesh = od_entry['bm']\n"
"\n"
" elif face is not None: # Same material, probably double-sided\n"
" face = face.copy()\n"
" face.normal_flip()\n"
"\n"
" else: \n"
" face = bm.faces.new(verts)\n"
"\n"
" # Apply normals\n"
" for i in range(3):\n"
" verts[i].normal = norms[i]\n"
"\n"
" for i in range(3):\n"
" face.verts[i].index = vert_indices[i]\n"
" face.material_index = mat_nr\n"
" face.smooth = True\n"
"\n"
" return face, ret_mesh\n"
"\n"
"# Begin bmesh\n"
"bm = bmesh.new()\n"
"\n";
/* Link master shader library */
HECL::ProjectPath selfPath = pakRouter.getWorking(&entry, PAKBridge::LookupExtractor(entry));
std::string masterShaderPath;
for (int i=0 ; i<selfPath.levelCount() ; ++i)
masterShaderPath += "../";
masterShaderPath += ".hecl/RetroMasterShader.blend";
os.format("# Master shader library\n"
"with bpy.data.libraries.load('//%s', link=True, relative=True) as (data_from, data_to):\n"
" data_to.node_groups = data_from.node_groups\n"
"\n", masterShaderPath.c_str());
MaterialSet::RegisterMaterialProps(os); MaterialSet::RegisterMaterialProps(os);
for (size_t s=0 ; s<head.secCount ; ++s) for (size_t s=0 ; s<head.secCount ; ++s)
{ {
atUint64 secStart = reader.position(); atUint64 secStart = reader.position();
/*
std::unique_ptr<atVec3f[]> vertPos;
std::unique_ptr<atVec3f[]> vertNorm;
typedef atInt16 ShortVec3[3];
std::unique_ptr<ShortVec3[]> vertNormShort;
std::unique_ptr<atVec2f[]> vertUVs;
typedef atInt16 ShortVec2[2];
std::unique_ptr<ShortVec2[]> vertUVsShort;
*/
std::vector<std::vector<unsigned>> matUVCounts; std::vector<std::vector<unsigned>> matUVCounts;
matUVCounts.reserve(head.matSetCount); matUVCounts.reserve(head.matSetCount);
bool visitedDLOffsets = false; bool visitedDLOffsets = false;
@ -62,18 +142,20 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
os << "texmap_list = []\n"; os << "texmap_list = []\n";
for (const UniqueID32& tex : matSet.head.textureIDs) for (const UniqueID32& tex : matSet.head.textureIDs)
{ {
std::string texName = pakRouter.getBestEntryName(tex);
HECL::SystemString resPath = pakRouter.getResourceRelativePath(entry, tex);
HECL::SystemUTF8View resPathView(resPath);
os.format("if '%s' in bpy.data.textures:\n" os.format("if '%s' in bpy.data.textures:\n"
" image = bpy.data.images['%s']\n" " image = bpy.data.images['%s']\n"
" texture = bpy.data.textures[image.name]\n" " texture = bpy.data.textures[image.name]\n"
"else:\n" "else:\n"
" image_path = os.path.relpath('../../%s/textures/%s.png')\n" " image = bpy.data.images.load('//%s')\n"
" print(os.getcwd()+image_path)\n"
" image = bpy.data.images.load('//' + image_path)\n"
" image.name = '%s'\n" " image.name = '%s'\n"
" texture = bpy.data.textures.new(image.name, 'IMAGE')\n" " texture = bpy.data.textures.new(image.name, 'IMAGE')\n"
" texture.image = image\n" " texture.image = image\n"
"texmap_list.append(texture)\n" "texmap_list.append(texture)\n"
"\n"); "\n", texName.c_str(), texName.c_str(),
resPathView.str().c_str(), texName.c_str());
} }
matUVCounts.emplace_back(); matUVCounts.emplace_back();
@ -96,10 +178,8 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
{ {
/* Positions */ /* Positions */
size_t vertCount = head.secSizes[s] / 12; size_t vertCount = head.secSizes[s] / 12;
//vertPos.reset(new atVec3f[vertCount]);
for (size_t i=0 ; i<vertCount ; ++i) for (size_t i=0 ; i<vertCount ; ++i)
{ {
//vertPos[i] = reader.readVec3f();
atVec3f pos = reader.readVec3f(); atVec3f pos = reader.readVec3f();
os.format("bm.verts.new(co=(%f,%f,%f))\n", os.format("bm.verts.new(co=(%f,%f,%f))\n",
pos.vec[0], pos.vec[1], pos.vec[2]); pos.vec[0], pos.vec[1], pos.vec[2]);
@ -113,12 +193,8 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
if (head.flags.shortNormals()) if (head.flags.shortNormals())
{ {
size_t normCount = head.secSizes[s] / 6; size_t normCount = head.secSizes[s] / 6;
//vertNormShort.reset(new ShortVec3[normCount]);
for (size_t i=0 ; i<normCount ; ++i) for (size_t i=0 ; i<normCount ; ++i)
{ {
//vertNormShort[i][0] = reader.readInt16();
//vertNormShort[i][1] = reader.readInt16();
//vertNormShort[i][2] = reader.readInt16();
os.format("normals.append((%f,%f,%f))\n", os.format("normals.append((%f,%f,%f))\n",
reader.readInt16(), reader.readInt16(), reader.readInt16()); reader.readInt16(), reader.readInt16(), reader.readInt16());
} }
@ -126,10 +202,8 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
else else
{ {
size_t normCount = head.secSizes[s] / 12; size_t normCount = head.secSizes[s] / 12;
//vertNorm.reset(new atVec3f[normCount]);
for (size_t i=0 ; i<normCount ; ++i) for (size_t i=0 ; i<normCount ; ++i)
{ {
//vertNorm[i] = reader.readVec3f();
atVec3f norm = reader.readVec3f(); atVec3f norm = reader.readVec3f();
os.format("normals.append((%f,%f,%f))\n", os.format("normals.append((%f,%f,%f))\n",
norm.vec[0], norm.vec[1], norm.vec[2]); norm.vec[0], norm.vec[1], norm.vec[2]);
@ -147,10 +221,8 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
/* Float UVs */ /* Float UVs */
os << "uv_list = []\n"; os << "uv_list = []\n";
size_t uvCount = head.secSizes[s] / 8; size_t uvCount = head.secSizes[s] / 8;
//vertUVs.reset(new atVec2f[uvCount]);
for (size_t i=0 ; i<uvCount ; ++i) for (size_t i=0 ; i<uvCount ; ++i)
{ {
//vertUVs[i] = reader.readVec2f();
atVec2f uv = reader.readVec2f(); atVec2f uv = reader.readVec2f();
os.format("uv_list.append((%f,%f))\n", os.format("uv_list.append((%f,%f))\n",
uv.vec[0], uv.vec[1]); uv.vec[0], uv.vec[1]);
@ -164,7 +236,6 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
if (head.flags.shortUVs()) if (head.flags.shortUVs())
{ {
size_t uvCount = head.secSizes[s] / 4; size_t uvCount = head.secSizes[s] / 4;
//vertUVsShort.reset(new ShortVec2[uvCount]);
for (size_t i=0 ; i<uvCount ; ++i) for (size_t i=0 ; i<uvCount ; ++i)
{ {
os.format("suv_list.append((%f,%f))\n", os.format("suv_list.append((%f,%f))\n",

View File

@ -51,16 +51,18 @@ struct CMDL
static bool ReadToBlender(HECL::BlenderConnection& conn, static bool ReadToBlender(HECL::BlenderConnection& conn,
Athena::io::IStreamReader& reader, Athena::io::IStreamReader& reader,
PAKRouter<PAKBridge>& pakRouter); PAKRouter<PAKBridge>& pakRouter,
const PAK::Entry& entry);
static bool Extract(PAKEntryReadStream& rs, static bool Extract(PAKEntryReadStream& rs,
const HECL::ProjectPath& outPath, const HECL::ProjectPath& outPath,
PAKRouter<PAKBridge>& pakRouter) PAKRouter<PAKBridge>& pakRouter,
const PAK::Entry& entry)
{ {
HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection(); HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection();
if (!conn.createBlend(outPath.getAbsolutePath())) if (!conn.createBlend(outPath.getAbsolutePath()))
return false; return false;
return ReadToBlender(conn, rs, pakRouter); return ReadToBlender(conn, rs, pakRouter, entry);
} }
}; };

View File

@ -136,11 +136,20 @@ void PAKBridge::build()
} }
if (areaDeps.name.empty()) if (areaDeps.name.empty())
{ {
areaDeps.name = area.internalAreaName;
#if HECL_UCS2 #if HECL_UCS2
areaDeps.name = _S("MREA_") + HECL::UTF8ToWide(area.areaMREAId.toString()); areaDeps.name = HECL::UTF8ToWide(area.internalAreaName);
#else #else
areaDeps.name = "MREA_" + area.areaMREAId.toString(); areaDeps.name = area.internalAreaName;
#endif #endif
if (areaDeps.name.empty())
{
#if HECL_UCS2
areaDeps.name = _S("MREA_") + HECL::UTF8ToWide(area.areaMREAId.toString());
#else
areaDeps.name = "MREA_" + area.areaMREAId.toString();
#endif
}
} }
areaDeps.layers.reserve(area.depLayerCount-1); areaDeps.layers.reserve(area.depLayerCount-1);

View File

@ -1,8 +1,11 @@
#include "SpecBase.hpp" #include "SpecBase.hpp"
#include "Blender/BlenderSupport.hpp"
namespace Retro namespace Retro
{ {
static LogVisor::LogModule Log("Retro::SpecBase");
bool SpecBase::canExtract(HECL::Database::Project& project, bool SpecBase::canExtract(HECL::Database::Project& project,
const ExtractPassInfo& info, std::vector<ExtractReport>& reps) const ExtractPassInfo& info, std::vector<ExtractReport>& reps)
{ {
@ -46,6 +49,8 @@ bool SpecBase::canExtract(HECL::Database::Project& project,
void SpecBase::doExtract(HECL::Database::Project& project, const ExtractPassInfo& info, void SpecBase::doExtract(HECL::Database::Project& project, const ExtractPassInfo& info,
FExtractProgress progress) FExtractProgress progress)
{ {
if (!Blender::BuildMasterShader(HECL::ProjectPath(project.getProjectRootPath(), ".hecl/RetroMasterShader.blend")))
Log.report(LogVisor::FatalError, "Unable to build master shader blend");
if (m_isWii) if (m_isWii)
{ {
/* Extract update partition for repacking later */ /* Extract update partition for repacking later */