mirror of https://github.com/AxioDL/metaforce.git
added 'bintoc' tool; embedded blender python scripts
This commit is contained in:
parent
73185fc32c
commit
8e89d7efd0
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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_
|
|
@ -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()
|
||||
|
|
@ -20,9 +20,16 @@ add_subdirectory(DNAMP1)
|
|||
add_subdirectory(DNAMP2)
|
||||
add_subdirectory(DNAMP3)
|
||||
|
||||
# Embed master shader script
|
||||
bintoc(RetroMasterShader.c Blender/RetroMasterShader.py RETRO_MASTER_SHADER)
|
||||
|
||||
# Each game's DataSpec implementation
|
||||
add_library(RetroDataSpec
|
||||
SpecBase.cpp
|
||||
SpecMP1.cpp
|
||||
SpecMP2.cpp
|
||||
SpecMP3.cpp)
|
||||
SpecMP3.cpp
|
||||
Blender/BlenderSupport.hpp
|
||||
Blender/BlenderSupport.cpp
|
||||
Blender/RetroMasterShader.py
|
||||
RetroMasterShader.c)
|
||||
|
|
|
@ -247,7 +247,8 @@ template <class PAKBRIDGE>
|
|||
struct ResExtractor
|
||||
{
|
||||
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;
|
||||
unsigned weight;
|
||||
};
|
||||
|
@ -368,6 +369,43 @@ public:
|
|||
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)
|
||||
{
|
||||
enterPAKBridge(pakBridge);
|
||||
|
@ -405,7 +443,7 @@ public:
|
|||
if (force || working.getPathType() == HECL::ProjectPath::PT_NONE)
|
||||
{
|
||||
PAKEntryReadStream s = item.second->beginReadStream(*m_node);
|
||||
extractor.func_b(s, working, *this);
|
||||
extractor.func_b(s, working, *this, *item.second);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,9 @@ namespace DNAMP1
|
|||
|
||||
bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
|
||||
Athena::io::IStreamReader& reader,
|
||||
PAKRouter<PAKBridge>& pakRouter)
|
||||
PAKRouter<PAKBridge>& pakRouter,
|
||||
const PAK::Entry& entry)
|
||||
{
|
||||
return true;
|
||||
reader.setEndian(Athena::BigEndian);
|
||||
|
||||
CMDL::Header head;
|
||||
|
@ -32,24 +32,104 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
|
|||
|
||||
/* Open Py Stream */
|
||||
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut();
|
||||
os << "import bmesh\n"
|
||||
"import bpy\n"
|
||||
"bm = bmesh.new()\n";
|
||||
os << "import bpy\n"
|
||||
"import bmesh\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);
|
||||
|
||||
for (size_t s=0 ; s<head.secCount ; ++s)
|
||||
{
|
||||
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;
|
||||
matUVCounts.reserve(head.matSetCount);
|
||||
bool visitedDLOffsets = false;
|
||||
|
@ -62,18 +142,20 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
|
|||
os << "texmap_list = []\n";
|
||||
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"
|
||||
" image = bpy.data.images['%s']\n"
|
||||
" texture = bpy.data.textures[image.name]\n"
|
||||
"else:\n"
|
||||
" image_path = os.path.relpath('../../%s/textures/%s.png')\n"
|
||||
" print(os.getcwd()+image_path)\n"
|
||||
" image = bpy.data.images.load('//' + image_path)\n"
|
||||
" image = bpy.data.images.load('//%s')\n"
|
||||
" image.name = '%s'\n"
|
||||
" texture = bpy.data.textures.new(image.name, 'IMAGE')\n"
|
||||
" texture.image = image\n"
|
||||
"texmap_list.append(texture)\n"
|
||||
"\n");
|
||||
"\n", texName.c_str(), texName.c_str(),
|
||||
resPathView.str().c_str(), texName.c_str());
|
||||
}
|
||||
|
||||
matUVCounts.emplace_back();
|
||||
|
@ -96,10 +178,8 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
|
|||
{
|
||||
/* Positions */
|
||||
size_t vertCount = head.secSizes[s] / 12;
|
||||
//vertPos.reset(new atVec3f[vertCount]);
|
||||
for (size_t i=0 ; i<vertCount ; ++i)
|
||||
{
|
||||
//vertPos[i] = reader.readVec3f();
|
||||
atVec3f pos = reader.readVec3f();
|
||||
os.format("bm.verts.new(co=(%f,%f,%f))\n",
|
||||
pos.vec[0], pos.vec[1], pos.vec[2]);
|
||||
|
@ -113,12 +193,8 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
|
|||
if (head.flags.shortNormals())
|
||||
{
|
||||
size_t normCount = head.secSizes[s] / 6;
|
||||
//vertNormShort.reset(new ShortVec3[normCount]);
|
||||
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",
|
||||
reader.readInt16(), reader.readInt16(), reader.readInt16());
|
||||
}
|
||||
|
@ -126,10 +202,8 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
|
|||
else
|
||||
{
|
||||
size_t normCount = head.secSizes[s] / 12;
|
||||
//vertNorm.reset(new atVec3f[normCount]);
|
||||
for (size_t i=0 ; i<normCount ; ++i)
|
||||
{
|
||||
//vertNorm[i] = reader.readVec3f();
|
||||
atVec3f norm = reader.readVec3f();
|
||||
os.format("normals.append((%f,%f,%f))\n",
|
||||
norm.vec[0], norm.vec[1], norm.vec[2]);
|
||||
|
@ -147,10 +221,8 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
|
|||
/* Float UVs */
|
||||
os << "uv_list = []\n";
|
||||
size_t uvCount = head.secSizes[s] / 8;
|
||||
//vertUVs.reset(new atVec2f[uvCount]);
|
||||
for (size_t i=0 ; i<uvCount ; ++i)
|
||||
{
|
||||
//vertUVs[i] = reader.readVec2f();
|
||||
atVec2f uv = reader.readVec2f();
|
||||
os.format("uv_list.append((%f,%f))\n",
|
||||
uv.vec[0], uv.vec[1]);
|
||||
|
@ -164,7 +236,6 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
|
|||
if (head.flags.shortUVs())
|
||||
{
|
||||
size_t uvCount = head.secSizes[s] / 4;
|
||||
//vertUVsShort.reset(new ShortVec2[uvCount]);
|
||||
for (size_t i=0 ; i<uvCount ; ++i)
|
||||
{
|
||||
os.format("suv_list.append((%f,%f))\n",
|
||||
|
|
|
@ -51,16 +51,18 @@ struct CMDL
|
|||
|
||||
static bool ReadToBlender(HECL::BlenderConnection& conn,
|
||||
Athena::io::IStreamReader& reader,
|
||||
PAKRouter<PAKBridge>& pakRouter);
|
||||
PAKRouter<PAKBridge>& pakRouter,
|
||||
const PAK::Entry& entry);
|
||||
|
||||
static bool Extract(PAKEntryReadStream& rs,
|
||||
const HECL::ProjectPath& outPath,
|
||||
PAKRouter<PAKBridge>& pakRouter)
|
||||
PAKRouter<PAKBridge>& pakRouter,
|
||||
const PAK::Entry& entry)
|
||||
{
|
||||
HECL::BlenderConnection& conn = HECL::BlenderConnection::SharedConnection();
|
||||
if (!conn.createBlend(outPath.getAbsolutePath()))
|
||||
return false;
|
||||
return ReadToBlender(conn, rs, pakRouter);
|
||||
return ReadToBlender(conn, rs, pakRouter, entry);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -136,11 +136,20 @@ void PAKBridge::build()
|
|||
}
|
||||
if (areaDeps.name.empty())
|
||||
{
|
||||
areaDeps.name = area.internalAreaName;
|
||||
#if HECL_UCS2
|
||||
areaDeps.name = _S("MREA_") + HECL::UTF8ToWide(area.areaMREAId.toString());
|
||||
areaDeps.name = HECL::UTF8ToWide(area.internalAreaName);
|
||||
#else
|
||||
areaDeps.name = "MREA_" + area.areaMREAId.toString();
|
||||
areaDeps.name = area.internalAreaName;
|
||||
#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);
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
#include "SpecBase.hpp"
|
||||
#include "Blender/BlenderSupport.hpp"
|
||||
|
||||
namespace Retro
|
||||
{
|
||||
|
||||
static LogVisor::LogModule Log("Retro::SpecBase");
|
||||
|
||||
bool SpecBase::canExtract(HECL::Database::Project& project,
|
||||
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,
|
||||
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)
|
||||
{
|
||||
/* Extract update partition for repacking later */
|
||||
|
|
Loading…
Reference in New Issue