mirror of https://github.com/AxioDL/metaforce.git
work on CMDL
This commit is contained in:
parent
8e89d7efd0
commit
aeb6089053
|
@ -18,7 +18,7 @@ bool BuildMasterShader(const HECL::ProjectPath& path)
|
||||||
if (!conn.createBlend(path.getAbsolutePath()))
|
if (!conn.createBlend(path.getAbsolutePath()))
|
||||||
return false;
|
return false;
|
||||||
{
|
{
|
||||||
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut();
|
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut(true);
|
||||||
os << RETRO_MASTER_SHADER;
|
os << RETRO_MASTER_SHADER;
|
||||||
os << "make_master_shader_library()\n";
|
os << "make_master_shader_library()\n";
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <NOD/DiscBase.hpp>
|
#include <NOD/DiscBase.hpp>
|
||||||
#include "HECL/HECL.hpp"
|
#include "HECL/HECL.hpp"
|
||||||
#include "HECL/Database.hpp"
|
#include "HECL/Database.hpp"
|
||||||
|
#include "../SpecBase.hpp"
|
||||||
|
|
||||||
namespace Retro
|
namespace Retro
|
||||||
{
|
{
|
||||||
|
@ -246,8 +247,8 @@ class PAKRouter;
|
||||||
template <class PAKBRIDGE>
|
template <class PAKBRIDGE>
|
||||||
struct ResExtractor
|
struct ResExtractor
|
||||||
{
|
{
|
||||||
std::function<bool(PAKEntryReadStream&, const HECL::ProjectPath&)> func_a;
|
std::function<bool(const SpecBase&, PAKEntryReadStream&, const HECL::ProjectPath&)> func_a;
|
||||||
std::function<bool(PAKEntryReadStream&, const HECL::ProjectPath&, PAKRouter<PAKBRIDGE>&,
|
std::function<bool(const SpecBase&, PAKEntryReadStream&, const HECL::ProjectPath&, PAKRouter<PAKBRIDGE>&,
|
||||||
const typename PAKBRIDGE::PAKType::Entry&)> func_b;
|
const typename PAKBRIDGE::PAKType::Entry&)> func_b;
|
||||||
const char* fileExt;
|
const char* fileExt;
|
||||||
unsigned weight;
|
unsigned weight;
|
||||||
|
@ -257,6 +258,7 @@ struct ResExtractor
|
||||||
template <class BRIDGETYPE>
|
template <class BRIDGETYPE>
|
||||||
class PAKRouter
|
class PAKRouter
|
||||||
{
|
{
|
||||||
|
const SpecBase& m_dataSpec;
|
||||||
const HECL::ProjectPath& m_gameWorking;
|
const HECL::ProjectPath& m_gameWorking;
|
||||||
const HECL::ProjectPath& m_gameCooked;
|
const HECL::ProjectPath& m_gameCooked;
|
||||||
HECL::ProjectPath m_sharedWorking;
|
HECL::ProjectPath m_sharedWorking;
|
||||||
|
@ -268,8 +270,9 @@ class PAKRouter
|
||||||
std::unordered_map<typename BRIDGETYPE::PAKType::IDType, typename BRIDGETYPE::PAKType::Entry*> m_uniqueEntries;
|
std::unordered_map<typename BRIDGETYPE::PAKType::IDType, typename BRIDGETYPE::PAKType::Entry*> m_uniqueEntries;
|
||||||
std::unordered_map<typename BRIDGETYPE::PAKType::IDType, typename BRIDGETYPE::PAKType::Entry*> m_sharedEntries;
|
std::unordered_map<typename BRIDGETYPE::PAKType::IDType, typename BRIDGETYPE::PAKType::Entry*> m_sharedEntries;
|
||||||
public:
|
public:
|
||||||
PAKRouter(const HECL::ProjectPath& working, const HECL::ProjectPath& cooked)
|
PAKRouter(const SpecBase& dataSpec, const HECL::ProjectPath& working, const HECL::ProjectPath& cooked)
|
||||||
: m_gameWorking(working), m_gameCooked(cooked),
|
: m_dataSpec(dataSpec),
|
||||||
|
m_gameWorking(working), m_gameCooked(cooked),
|
||||||
m_sharedWorking(working, "Shared"), m_sharedCooked(cooked, "Shared") {}
|
m_sharedWorking(working, "Shared"), m_sharedCooked(cooked, "Shared") {}
|
||||||
void build(std::vector<BRIDGETYPE>& bridges, std::function<void(float)> progress)
|
void build(std::vector<BRIDGETYPE>& bridges, std::function<void(float)> progress)
|
||||||
{
|
{
|
||||||
|
@ -435,7 +438,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_a(s, working);
|
extractor.func_a(m_dataSpec, s, working);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (extractor.func_b) /* Needs PAKRouter access */
|
else if (extractor.func_b) /* Needs PAKRouter access */
|
||||||
|
@ -443,7 +446,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, *item.second);
|
extractor.func_b(m_dataSpec, s, working, *this, *item.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -247,6 +247,18 @@ enum PTTexMtx
|
||||||
PTIDENTITY = 125
|
PTIDENTITY = 125
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Primitive
|
||||||
|
{
|
||||||
|
POINTS = 0xb8,
|
||||||
|
LINES = 0xa8,
|
||||||
|
LINESTRIP = 0xb0,
|
||||||
|
TRIANGLES = 0x90,
|
||||||
|
TRIANGLESTRIP = 0x98,
|
||||||
|
TRIANGLEFAN = 0xa0,
|
||||||
|
QUADS = 0x80
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _DNACOMMON_GX_HPP_
|
#endif // _DNACOMMON_GX_HPP_
|
||||||
|
|
|
@ -479,7 +479,7 @@ static void PNGWarn(png_structp png, png_const_charp msg)
|
||||||
Log.report(LogVisor::Warning, msg);
|
Log.report(LogVisor::Warning, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TXTR::Extract(PAKEntryReadStream& rs, const HECL::ProjectPath& outPath)
|
bool TXTR::Extract(const SpecBase& dataspec, PAKEntryReadStream& rs, const HECL::ProjectPath& outPath)
|
||||||
{
|
{
|
||||||
rs.setEndian(Athena::BigEndian);
|
rs.setEndian(Athena::BigEndian);
|
||||||
uint32_t format = rs.readUint32();
|
uint32_t format = rs.readUint32();
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace Retro
|
||||||
|
|
||||||
struct TXTR
|
struct TXTR
|
||||||
{
|
{
|
||||||
static bool Extract(PAKEntryReadStream& rs, const HECL::ProjectPath& outPath);
|
static bool Extract(const SpecBase& dataspec, PAKEntryReadStream& rs, const HECL::ProjectPath& outPath);
|
||||||
static bool Cook(const HECL::ProjectPath& inPath, const HECL::ProjectPath& outPath);
|
static bool Cook(const HECL::ProjectPath& inPath, const HECL::ProjectPath& outPath);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,13 @@
|
||||||
#include "DNAMP1.hpp"
|
#include "DNAMP1.hpp"
|
||||||
#include "CMDLMaterials.hpp"
|
#include "CMDLMaterials.hpp"
|
||||||
|
|
||||||
|
struct DLPrimVert
|
||||||
|
{
|
||||||
|
atUint16 pos;
|
||||||
|
atUint16 norm;
|
||||||
|
atUint16 uvs[8];
|
||||||
|
};
|
||||||
|
|
||||||
namespace Retro
|
namespace Retro
|
||||||
{
|
{
|
||||||
namespace DNAMP1
|
namespace DNAMP1
|
||||||
|
@ -11,7 +18,8 @@ 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)
|
const PAK::Entry& entry,
|
||||||
|
const HECL::ProjectPath& masterShader)
|
||||||
{
|
{
|
||||||
reader.setEndian(Athena::BigEndian);
|
reader.setEndian(Athena::BigEndian);
|
||||||
|
|
||||||
|
@ -31,101 +39,102 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open Py Stream */
|
/* Open Py Stream */
|
||||||
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut();
|
HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut(true);
|
||||||
os << "import bpy\n"
|
os.format("import bpy\n"
|
||||||
"import bmesh\n"
|
"import bmesh\n"
|
||||||
"\n"
|
"\n"
|
||||||
"bpy.context.scene.name = '%s'\n"
|
"bpy.context.scene.name = '%s'\n"
|
||||||
"bpy.context.scene.rwk_type = 'MESH'\n"
|
"bpy.context.scene.hecl_type = 'MESH'\n"
|
||||||
"bpy.context.scene.rwk_mesh = bpy.context.scene.name\n"
|
"bpy.context.scene.hecl_mesh_obj = bpy.context.scene.name\n"
|
||||||
"\n"
|
"\n"
|
||||||
"# Using 'Blender Game'\n"
|
"# Using 'Blender Game'\n"
|
||||||
"bpy.context.scene.render.engine = 'BLENDER_GAME'\n"
|
"bpy.context.scene.render.engine = 'BLENDER_GAME'\n"
|
||||||
"\n"
|
"\n"
|
||||||
"# Clear Scene\n"
|
"# Clear Scene\n"
|
||||||
"for ob in bpy.data.objects:\n"
|
"for ob in bpy.data.objects:\n"
|
||||||
" if ob.type != 'LAMP':\n"
|
" if ob.type != 'LAMP':\n"
|
||||||
" bpy.context.scene.objects.unlink(ob)\n"
|
" bpy.context.scene.objects.unlink(ob)\n"
|
||||||
" bpy.data.objects.remove(ob)\n"
|
" bpy.data.objects.remove(ob)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"# Property to convey original vert indices in overdraw meshes\n"
|
"# Property to convey original vert indices in overdraw meshes\n"
|
||||||
"class RWKOriginalIndex(bpy.types.PropertyGroup):\n"
|
"class CMDLOriginalIndex(bpy.types.PropertyGroup):\n"
|
||||||
" index = bpy.props.IntProperty(name='Original Vertex Index')\n"
|
" index = bpy.props.IntProperty(name='Original Vertex Index')\n"
|
||||||
"bpy.utils.register_class(RWKOriginalIndex)\n"
|
"bpy.utils.register_class(CMDLOriginalIndex)\n"
|
||||||
"bpy.types.Mesh.rwk_orig_verts = bpy.props.CollectionProperty(type=RWKOriginalIndex)\n"
|
"bpy.types.Mesh.cmdl_orig_verts = bpy.props.CollectionProperty(type=CMDLOriginalIndex)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"def loop_from_facevert(face, vert_idx):\n"
|
"def loop_from_facevert(face, vert_idx):\n"
|
||||||
" for loop in face.loops:\n"
|
" for loop in face.loops:\n"
|
||||||
" if loop.vert.index == vert_idx:\n"
|
" if loop.vert.index == vert_idx:\n"
|
||||||
" return loop\n"
|
" return loop\n"
|
||||||
"\n"
|
"\n"
|
||||||
"def add_triangle(bm, vert_seq, vert_indices, norm_seq, norm_indices, mat_nr, od_list):\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"
|
" if len(set(vert_indices)) != 3:\n"
|
||||||
" return None, None\n"
|
" return None, None\n"
|
||||||
"\n"
|
"\n"
|
||||||
" ret_mesh = bm\n"
|
" ret_mesh = bm\n"
|
||||||
" vert_seq.ensure_lookup_table()\n"
|
" vert_seq.ensure_lookup_table()\n"
|
||||||
" verts = [vert_seq[i] for i in vert_indices]\n"
|
" verts = [vert_seq[i] for i in vert_indices]\n"
|
||||||
" norms = [norm_seq[i] for i in norm_indices]\n"
|
" norms = [norm_seq[i] for i in norm_indices]\n"
|
||||||
"\n"
|
"\n"
|
||||||
" # Make the face\n"
|
" # Make the face\n"
|
||||||
" face = bm.faces.get(verts)\n"
|
" face = bm.faces.get(verts)\n"
|
||||||
"\n"
|
"\n"
|
||||||
" if face is not None and face.material_index != mat_nr: # Same poly, new material\n"
|
" if face is not None and face.material_index != mat_nr: # Same poly, new material\n"
|
||||||
" # Overdraw detected; track copy\n"
|
" # Overdraw detected; track copy\n"
|
||||||
" od_entry = None\n"
|
" od_entry = None\n"
|
||||||
" for entry in od_list:\n"
|
" for entry in od_list:\n"
|
||||||
" if entry['material'] == mat_nr:\n"
|
" if entry['material'] == mat_nr:\n"
|
||||||
" od_entry = entry\n"
|
" od_entry = entry\n"
|
||||||
" if od_entry is None:\n"
|
" if od_entry is None:\n"
|
||||||
" bm_cpy = bm.copy()\n"
|
" bm_cpy = bm.copy()\n"
|
||||||
" od_entry = {'material':mat_nr, 'bm':bm_cpy}\n"
|
" od_entry = {'material':mat_nr, 'bm':bm_cpy}\n"
|
||||||
" bmesh.ops.delete(od_entry['bm'], geom=od_entry['bm'].faces, context=3)\n"
|
" bmesh.ops.delete(od_entry['bm'], geom=od_entry['bm'].faces, context=3)\n"
|
||||||
" od_list.append(od_entry)\n"
|
" od_list.append(od_entry)\n"
|
||||||
" od_entry['bm'].verts.ensure_lookup_table()\n"
|
" od_entry['bm'].verts.ensure_lookup_table()\n"
|
||||||
" verts = [od_entry['bm'].verts[i] for i in vert_indices]\n"
|
" verts = [od_entry['bm'].verts[i] for i in vert_indices]\n"
|
||||||
" face = od_entry['bm'].faces.get(verts)\n"
|
" face = od_entry['bm'].faces.get(verts)\n"
|
||||||
" if face is None:\n"
|
" if face is None:\n"
|
||||||
" face = od_entry['bm'].faces.new(verts)\n"
|
" face = od_entry['bm'].faces.new(verts)\n"
|
||||||
" else: # Probably a double-sided surface\n"
|
" else: # Probably a double-sided surface\n"
|
||||||
" face = face.copy()\n"
|
" face = face.copy()\n"
|
||||||
" face.normal_flip()\n"
|
" face.normal_flip()\n"
|
||||||
" ret_mesh = od_entry['bm']\n"
|
" ret_mesh = od_entry['bm']\n"
|
||||||
"\n"
|
"\n"
|
||||||
" elif face is not None: # Same material, probably double-sided\n"
|
" elif face is not None: # Same material, probably double-sided\n"
|
||||||
" face = face.copy()\n"
|
" face = face.copy()\n"
|
||||||
" face.normal_flip()\n"
|
" face.normal_flip()\n"
|
||||||
"\n"
|
"\n"
|
||||||
" else: \n"
|
" else: \n"
|
||||||
" face = bm.faces.new(verts)\n"
|
" face = bm.faces.new(verts)\n"
|
||||||
"\n"
|
"\n"
|
||||||
" # Apply normals\n"
|
" # Apply normals\n"
|
||||||
" for i in range(3):\n"
|
" for i in range(3):\n"
|
||||||
" verts[i].normal = norms[i]\n"
|
" verts[i].normal = norms[i]\n"
|
||||||
"\n"
|
"\n"
|
||||||
" for i in range(3):\n"
|
" for i in range(3):\n"
|
||||||
" face.verts[i].index = vert_indices[i]\n"
|
" face.verts[i].index = vert_indices[i]\n"
|
||||||
" face.material_index = mat_nr\n"
|
" face.material_index = mat_nr\n"
|
||||||
" face.smooth = True\n"
|
" face.smooth = True\n"
|
||||||
"\n"
|
"\n"
|
||||||
" return face, ret_mesh\n"
|
" return face, ret_mesh\n"
|
||||||
"\n"
|
"\n"
|
||||||
"# Begin bmesh\n"
|
"# Begin bmesh\n"
|
||||||
"bm = bmesh.new()\n"
|
"bm = bmesh.new()\n"
|
||||||
"\n";
|
"\n", pakRouter.getBestEntryName(entry).c_str());
|
||||||
|
|
||||||
/* Link master shader library */
|
/* 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"
|
os.format("# Master shader library\n"
|
||||||
"with bpy.data.libraries.load('//%s', link=True, relative=True) as (data_from, data_to):\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"
|
" data_to.node_groups = data_from.node_groups\n"
|
||||||
"\n", masterShaderPath.c_str());
|
"\n", masterShader.getAbsolutePathUTF8().c_str());
|
||||||
|
|
||||||
MaterialSet::RegisterMaterialProps(os);
|
MaterialSet::RegisterMaterialProps(os);
|
||||||
|
os << "# Materials\n"
|
||||||
|
"materials = []\n"
|
||||||
|
"\n"
|
||||||
|
"# Overdraw-tracking\n"
|
||||||
|
"od_list = []\n"
|
||||||
|
"\n";
|
||||||
|
|
||||||
for (size_t s=0 ; s<head.secCount ; ++s)
|
for (size_t s=0 ; s<head.secCount ; ++s)
|
||||||
{
|
{
|
||||||
|
@ -168,6 +177,7 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
|
||||||
uvCounts.emplace_back();
|
uvCounts.emplace_back();
|
||||||
unsigned& uvCount = uvCounts.back();
|
unsigned& uvCount = uvCounts.back();
|
||||||
MaterialSet::ConstructMaterial(os, mat, s, m++, uvCount);
|
MaterialSet::ConstructMaterial(os, mat, s, m++, uvCount);
|
||||||
|
os << "materials.append(new_material)\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -181,7 +191,7 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
|
||||||
for (size_t i=0 ; i<vertCount ; ++i)
|
for (size_t i=0 ; i<vertCount ; ++i)
|
||||||
{
|
{
|
||||||
atVec3f pos = reader.readVec3f();
|
atVec3f pos = reader.readVec3f();
|
||||||
os.format("bm.verts.new(co=(%f,%f,%f))\n",
|
os.format("bm.verts.new((%f,%f,%f))\n",
|
||||||
pos.vec[0], pos.vec[1], pos.vec[2]);
|
pos.vec[0], pos.vec[1], pos.vec[2]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -259,6 +269,180 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
|
||||||
/* GX Display List (surface) */
|
/* GX Display List (surface) */
|
||||||
SurfaceHeader sHead;
|
SurfaceHeader sHead;
|
||||||
sHead.read(reader);
|
sHead.read(reader);
|
||||||
|
unsigned matUVCount = matUVCounts[0][sHead.matIdx];
|
||||||
|
|
||||||
|
std::unique_ptr<atUint8[]> dlBuf = reader.readUBytes(sHead.dlSize);
|
||||||
|
atUint8* origDl = dlBuf.get();
|
||||||
|
atUint8* dl = origDl;
|
||||||
|
|
||||||
|
while (*dl && (dl-origDl) < sHead.dlSize)
|
||||||
|
{
|
||||||
|
|
||||||
|
GX::Primitive ptype = GX::Primitive(*dl);
|
||||||
|
atUint16 vert_count = HECL::SBig(*(atUint16*)(dl + 1));
|
||||||
|
os.format("# VAT Type: %u\n", (*(atUint8*)dl)&7);
|
||||||
|
|
||||||
|
atUint16* dli = (atUint16*)(dl + 3);
|
||||||
|
|
||||||
|
/* First vert */
|
||||||
|
DLPrimVert first_prim_vert;
|
||||||
|
first_prim_vert.pos = HECL::SBig(dli[0]);
|
||||||
|
first_prim_vert.norm = HECL::SBig(dli[1]);
|
||||||
|
for (int uv=0 ; uv<matUVCount ; ++uv)
|
||||||
|
first_prim_vert.uvs[uv] = HECL::SBig(dli[2+uv]);
|
||||||
|
|
||||||
|
/* 3 Prim Verts to start */
|
||||||
|
int c = 0;
|
||||||
|
DLPrimVert prim_verts[3];
|
||||||
|
for (int pv=0 ; pv<3 ; ++pv)
|
||||||
|
{
|
||||||
|
prim_verts[pv].pos = HECL::SBig(*dli++);
|
||||||
|
prim_verts[pv].norm = HECL::SBig(*dli++);
|
||||||
|
for (int uv=0 ; uv<matUVCount ; ++uv)
|
||||||
|
prim_verts[pv].uvs[uv] = HECL::SBig(*dli++);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptype == GX::TRIANGLESTRIP)
|
||||||
|
{
|
||||||
|
atUint8 flip = 0;
|
||||||
|
for (int v=0 ; v<vert_count-2 ; ++v)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (flip)
|
||||||
|
{
|
||||||
|
os.format("last_face, last_mesh = add_triangle(bm, bm.verts, (%u,%u,%u), norm_list, (%u,%u,%u), %u, od_list)\n",
|
||||||
|
prim_verts[c%3].pos,
|
||||||
|
prim_verts[(c+2)%3].pos,
|
||||||
|
prim_verts[(c+1)%3].pos,
|
||||||
|
prim_verts[c%3].norm,
|
||||||
|
prim_verts[(c+2)%3].norm,
|
||||||
|
prim_verts[(c+1)%3].norm,
|
||||||
|
sHead.matIdx);
|
||||||
|
if (matUVCount)
|
||||||
|
{
|
||||||
|
os << "if last_face is not None:\n";
|
||||||
|
for (int j=0 ; j<matUVCount ; ++j)
|
||||||
|
os.format(" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n"
|
||||||
|
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n"
|
||||||
|
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n",
|
||||||
|
prim_verts[c%3].pos, j, prim_verts[c%3].uvs[j],
|
||||||
|
prim_verts[(c+2)%3].pos, j, prim_verts[(c+2)%3].uvs[j],
|
||||||
|
prim_verts[(c+1)%3].pos, j, prim_verts[(c+1)%3].uvs[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
os.format("last_face, last_mesh = add_triangle(bm, bm.verts, (%u,%u,%u), norm_list, (%u,%u,%u), %u, od_list)\n",
|
||||||
|
prim_verts[c%3].pos,
|
||||||
|
prim_verts[(c+1)%3].pos,
|
||||||
|
prim_verts[(c+2)%3].pos,
|
||||||
|
prim_verts[c%3].norm,
|
||||||
|
prim_verts[(c+1)%3].norm,
|
||||||
|
prim_verts[(c+2)%3].norm,
|
||||||
|
sHead.matIdx);
|
||||||
|
if (matUVCount)
|
||||||
|
{
|
||||||
|
os << "if last_face is not None:\n";
|
||||||
|
for (int j=0 ; j<matUVCount ; ++j)
|
||||||
|
os.format(" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n"
|
||||||
|
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n"
|
||||||
|
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n",
|
||||||
|
prim_verts[c%3].pos, j, prim_verts[c%3].uvs[j],
|
||||||
|
prim_verts[(c+1)%3].pos, j, prim_verts[(c+1)%3].uvs[j],
|
||||||
|
prim_verts[(c+2)%3].pos, j, prim_verts[(c+2)%3].uvs[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flip ^= 1;
|
||||||
|
|
||||||
|
dl = (atUint8*)dli;
|
||||||
|
|
||||||
|
/* Advance one prim vert */
|
||||||
|
prim_verts[c%3].pos = HECL::SBig(*dli++);
|
||||||
|
prim_verts[c%3].norm = HECL::SBig(*dli++);
|
||||||
|
for (int uv=0 ; uv<matUVCount ; ++uv)
|
||||||
|
prim_verts[c%3].uvs[uv] = HECL::SBig(*dli++);
|
||||||
|
++c;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ptype == GX::TRIANGLES)
|
||||||
|
{
|
||||||
|
for (int v=0 ; v<vert_count ; v+=3)
|
||||||
|
{
|
||||||
|
|
||||||
|
os.format("last_face, last_mesh = add_triangle(bm, bm.verts, (%u,%u,%u), norm_list, (%u,%u,%u), %u, od_list)\n",
|
||||||
|
prim_verts[0].pos,
|
||||||
|
prim_verts[1].pos,
|
||||||
|
prim_verts[2].pos,
|
||||||
|
prim_verts[0].norm,
|
||||||
|
prim_verts[1].norm,
|
||||||
|
prim_verts[2].norm,
|
||||||
|
sHead.matIdx);
|
||||||
|
if (matUVCount)
|
||||||
|
{
|
||||||
|
os << "if last_face is not None:\n";
|
||||||
|
for (int j=0 ; j<matUVCount ; ++j)
|
||||||
|
os.format(" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n"
|
||||||
|
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n"
|
||||||
|
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n",
|
||||||
|
prim_verts[0].pos, j, prim_verts[0].uvs[j],
|
||||||
|
prim_verts[1].pos, j, prim_verts[1].uvs[j],
|
||||||
|
prim_verts[2].pos, j, prim_verts[2].uvs[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
dl = (atUint8*)dli;
|
||||||
|
|
||||||
|
/* Break if done */
|
||||||
|
if (v+3 >= vert_count)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Advance 3 Prim Verts */
|
||||||
|
for (int pv=0 ; pv<3 ; ++pv)
|
||||||
|
{
|
||||||
|
prim_verts[pv].pos = HECL::SBig(*dli++);
|
||||||
|
prim_verts[pv].norm = HECL::SBig(*dli++);
|
||||||
|
for (int uv=0 ; uv<matUVCount ; ++uv)
|
||||||
|
prim_verts[pv].uvs[uv] = HECL::SBig(*dli++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ptype == GX::TRIANGLEFAN)
|
||||||
|
{
|
||||||
|
++c;
|
||||||
|
for (int v=0 ; v<vert_count-2 ; ++v)
|
||||||
|
{
|
||||||
|
os.format("last_face, last_mesh = add_triangle(bm, bm.verts, (%u,%u,%u), norm_list, (%u,%u,%u), %u, od_list)\n",
|
||||||
|
first_prim_vert.pos,
|
||||||
|
prim_verts[c%3].pos,
|
||||||
|
prim_verts[(c+1)%3].pos,
|
||||||
|
first_prim_vert.norm,
|
||||||
|
prim_verts[c%3].norm,
|
||||||
|
prim_verts[(c+1)%3].norm,
|
||||||
|
sHead.matIdx);
|
||||||
|
if (matUVCount)
|
||||||
|
{
|
||||||
|
os << "if last_face is not None:\n";
|
||||||
|
for (int j=0 ; j<matUVCount ; ++j)
|
||||||
|
os.format(" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n"
|
||||||
|
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n"
|
||||||
|
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n",
|
||||||
|
first_prim_vert.pos, j, first_prim_vert.uvs[j],
|
||||||
|
prim_verts[c%3].pos, j, prim_verts[c%3].uvs[j],
|
||||||
|
prim_verts[(c+1)%3].pos, j, prim_verts[(c+1)%3].uvs[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
dl = (atUint8*)dli;
|
||||||
|
|
||||||
|
/* Advance one prim vert */
|
||||||
|
prim_verts[(c+2)%3].pos = HECL::SBig(*dli++);
|
||||||
|
prim_verts[(c+2)%3].norm = HECL::SBig(*dli++);
|
||||||
|
for (int uv=0 ; uv<matUVCount ; ++uv)
|
||||||
|
prim_verts[(c+2)%3].uvs[uv] = HECL::SBig(*dli++);
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os << "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,6 +451,56 @@ bool CMDL::ReadToBlender(HECL::BlenderConnection& conn,
|
||||||
reader.seek(secStart + head.secSizes[s], Athena::Begin);
|
reader.seek(secStart + head.secSizes[s], Athena::Begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Finish Mesh */
|
||||||
|
os.format("mesh = bpy.data.meshes.new(bpy.context.scene.name)\n"
|
||||||
|
"obj = bpy.data.objects.new(mesh.name, mesh)\n"
|
||||||
|
"obj.show_transparent = True\n"
|
||||||
|
"bpy.context.scene.objects.link(obj)\n"
|
||||||
|
"mesh.cmdl_material_count = %u\n"
|
||||||
|
"for material in materials:\n"
|
||||||
|
" mesh.materials.append(material)\n"
|
||||||
|
"\n"
|
||||||
|
"# Preserve original indices\n"
|
||||||
|
"for vert in bm.verts:\n"
|
||||||
|
" ov = mesh.cmdl_orig_verts.add()\n"
|
||||||
|
" ov.index = vert.index\n"
|
||||||
|
"\n"
|
||||||
|
"# Merge OD meshes\n"
|
||||||
|
"for od_entry in od_list:\n"
|
||||||
|
" vert_dict = {}\n"
|
||||||
|
"\n"
|
||||||
|
" for vert in od_entry['bm'].verts:\n"
|
||||||
|
" if len(vert.link_faces):\n"
|
||||||
|
" vert_dict[vert.index] = bm.verts.new(vert.co, vert)\n"
|
||||||
|
" ov = mesh.cmdl_orig_verts.add()\n"
|
||||||
|
" ov.index = vert.index\n"
|
||||||
|
"\n"
|
||||||
|
" for face in od_entry['bm'].faces:\n"
|
||||||
|
" merge_verts = [vert_dict[fv.index] for fv in face.verts]\n"
|
||||||
|
" if bm.faces.get(merge_verts) is not None:\n"
|
||||||
|
" continue\n"
|
||||||
|
" merge_face = bm.faces.new(merge_verts)\n"
|
||||||
|
" for i in range(len(face.loops)):\n"
|
||||||
|
" old = face.loops[i]\n"
|
||||||
|
" new = merge_face.loops[i]\n"
|
||||||
|
" for j in range(len(od_entry['bm'].loops.layers.uv)):\n"
|
||||||
|
" new[bm.loops.layers.uv[j]] = old[od_entry['bm'].loops.layers.uv[j]]\n"
|
||||||
|
" merge_face.smooth = True\n"
|
||||||
|
" merge_face.material_index = face.material_index\n"
|
||||||
|
"\n"
|
||||||
|
" od_entry['bm'].free()\n"
|
||||||
|
"\n"
|
||||||
|
"# Remove loose vertices\n"
|
||||||
|
"#to_remove = []\n"
|
||||||
|
"#for vert in bm.verts:\n"
|
||||||
|
"# if not len(vert.link_faces):\n"
|
||||||
|
"# to_remove.append(vert)\n"
|
||||||
|
"#bmesh.ops.delete(bm, geom=to_remove, context=1)\n"
|
||||||
|
"\n"
|
||||||
|
"bm.to_mesh(mesh)\n"
|
||||||
|
"bm.free()\n"
|
||||||
|
"\n", head.matSetCount);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,9 +52,11 @@ 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);
|
const PAK::Entry& entry,
|
||||||
|
const HECL::ProjectPath& masterShader);
|
||||||
|
|
||||||
static bool Extract(PAKEntryReadStream& rs,
|
static bool Extract(const SpecBase& dataSpec,
|
||||||
|
PAKEntryReadStream& rs,
|
||||||
const HECL::ProjectPath& outPath,
|
const HECL::ProjectPath& outPath,
|
||||||
PAKRouter<PAKBridge>& pakRouter,
|
PAKRouter<PAKBridge>& pakRouter,
|
||||||
const PAK::Entry& entry)
|
const PAK::Entry& entry)
|
||||||
|
@ -62,7 +64,8 @@ struct CMDL
|
||||||
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, entry);
|
ReadToBlender(conn, rs, pakRouter, entry, dataSpec.getMasterShaderPath());
|
||||||
|
return conn.saveBlend();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ void MaterialSet::RegisterMaterialProps(Stream& out)
|
||||||
"bpy.types.Material.retro_shadow_occluder = bpy.props.BoolProperty(name='Retro: Shadow Occluder')\n"
|
"bpy.types.Material.retro_shadow_occluder = bpy.props.BoolProperty(name='Retro: Shadow Occluder')\n"
|
||||||
"bpy.types.Material.retro_samus_reflection_indirect = bpy.props.BoolProperty(name='Retro: Samus Reflection Indirect Texture')\n"
|
"bpy.types.Material.retro_samus_reflection_indirect = bpy.props.BoolProperty(name='Retro: Samus Reflection Indirect Texture')\n"
|
||||||
"bpy.types.Material.retro_lightmapped = bpy.props.BoolProperty(name='Retro: Lightmapped')\n"
|
"bpy.types.Material.retro_lightmapped = bpy.props.BoolProperty(name='Retro: Lightmapped')\n"
|
||||||
|
"bpy.types.Material.retro_lightmap = bpy.props.StringProperty(name='Retro: Lightmap')\n"
|
||||||
|
"bpy.types.Mesh.cmdl_material_count = bpy.props.IntProperty(name='CMDL: Material Count')\n"
|
||||||
"\n";
|
"\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -574,7 +576,7 @@ void _ConstructMaterial(Stream& out,
|
||||||
"material_node = new_nodetree.nodes['Material']\n"
|
"material_node = new_nodetree.nodes['Material']\n"
|
||||||
"final_node = new_nodetree.nodes['Output']\n"
|
"final_node = new_nodetree.nodes['Output']\n"
|
||||||
"\n"
|
"\n"
|
||||||
"gridder = nodegrid(new_nodetree)\n"
|
"gridder = hecl.Nodegrid(new_nodetree)\n"
|
||||||
"gridder.place_node(final_node, 3)\n"
|
"gridder.place_node(final_node, 3)\n"
|
||||||
"gridder.place_node(material_node, 0)\n"
|
"gridder.place_node(material_node, 0)\n"
|
||||||
"material_node.material = new_material\n"
|
"material_node.material = new_material\n"
|
||||||
|
@ -690,7 +692,7 @@ void _ConstructMaterial(Stream& out,
|
||||||
if (material.tevStages[0].colorInB() == GX::CC_C1)
|
if (material.tevStages[0].colorInB() == GX::CC_C1)
|
||||||
{
|
{
|
||||||
if (material.tevStageTexInfo[0].texSlot != 0xff)
|
if (material.tevStageTexInfo[0].texSlot != 0xff)
|
||||||
out << "new_material.rwk_lightmap = tex_maps[0].name\n"
|
out << "new_material.retro_lightmap = tex_maps[0].name\n"
|
||||||
"tex_maps[0].image.use_fake_user = True\n";
|
"tex_maps[0].image.use_fake_user = True\n";
|
||||||
AddLightmap(out, "texture_nodes[0].outputs['Color']", c_combiner_idx);
|
AddLightmap(out, "texture_nodes[0].outputs['Color']", c_combiner_idx);
|
||||||
strncpy(c_regs[GX::TEVREG1], "world_light_node.outputs[0]", 64);
|
strncpy(c_regs[GX::TEVREG1], "world_light_node.outputs[0]", 64);
|
||||||
|
|
|
@ -104,7 +104,7 @@ struct MLVL : BigYAML
|
||||||
Value<atUint32> layerNameOffsetCount;
|
Value<atUint32> layerNameOffsetCount;
|
||||||
Vector<atUint32, DNA_COUNT(layerNameOffsetCount)> layerNameOffsets;
|
Vector<atUint32, DNA_COUNT(layerNameOffsetCount)> layerNameOffsets;
|
||||||
|
|
||||||
static bool Extract(PAKEntryReadStream& rs, const HECL::ProjectPath& outPath)
|
static bool Extract(const SpecBase& dataspec, PAKEntryReadStream& rs, const HECL::ProjectPath& outPath)
|
||||||
{
|
{
|
||||||
MLVL mlvl;
|
MLVL mlvl;
|
||||||
mlvl.read(rs);
|
mlvl.read(rs);
|
||||||
|
|
|
@ -61,7 +61,7 @@ struct STRG : ISTRG, BigYAML
|
||||||
bool readAngelScript(const AngelScript::asIScriptModule& in);
|
bool readAngelScript(const AngelScript::asIScriptModule& in);
|
||||||
void writeAngelScript(std::ofstream& out) const;
|
void writeAngelScript(std::ofstream& out) const;
|
||||||
|
|
||||||
static bool Extract(PAKEntryReadStream& rs, const HECL::ProjectPath& outPath)
|
static bool Extract(const SpecBase& dataspec, PAKEntryReadStream& rs, const HECL::ProjectPath& outPath)
|
||||||
{
|
{
|
||||||
STRG strg;
|
STRG strg;
|
||||||
strg.read(rs);
|
strg.read(rs);
|
||||||
|
|
|
@ -66,7 +66,7 @@ struct STRG : ISTRG, BigDNA
|
||||||
bool readAngelScript(const AngelScript::asIScriptModule& in);
|
bool readAngelScript(const AngelScript::asIScriptModule& in);
|
||||||
void writeAngelScript(std::ofstream& out) const;
|
void writeAngelScript(std::ofstream& out) const;
|
||||||
|
|
||||||
static bool Extract(PAKEntryReadStream& rs, const HECL::ProjectPath& outPath)
|
static bool Extract(const SpecBase& dataspec, PAKEntryReadStream& rs, const HECL::ProjectPath& outPath)
|
||||||
{
|
{
|
||||||
STRG strg;
|
STRG strg;
|
||||||
strg.read(rs);
|
strg.read(rs);
|
||||||
|
|
|
@ -66,7 +66,7 @@ struct STRG : ISTRG, BigDNA
|
||||||
bool readAngelScript(const AngelScript::asIScriptModule& in);
|
bool readAngelScript(const AngelScript::asIScriptModule& in);
|
||||||
void writeAngelScript(std::ofstream& out) const;
|
void writeAngelScript(std::ofstream& out) const;
|
||||||
|
|
||||||
static bool Extract(PAKEntryReadStream& rs, const HECL::ProjectPath& outPath)
|
static bool Extract(const SpecBase& dataspec, PAKEntryReadStream& rs, const HECL::ProjectPath& outPath)
|
||||||
{
|
{
|
||||||
std::unique_ptr<ISTRG> strg = LoadSTRG(rs);
|
std::unique_ptr<ISTRG> strg = LoadSTRG(rs);
|
||||||
std::ofstream strgOut(outPath.getAbsolutePath());
|
std::ofstream strgOut(outPath.getAbsolutePath());
|
||||||
|
|
|
@ -6,8 +6,7 @@ namespace Retro
|
||||||
|
|
||||||
static LogVisor::LogModule Log("Retro::SpecBase");
|
static LogVisor::LogModule Log("Retro::SpecBase");
|
||||||
|
|
||||||
bool SpecBase::canExtract(HECL::Database::Project& project,
|
bool SpecBase::canExtract(const ExtractPassInfo& info, std::vector<ExtractReport>& reps)
|
||||||
const ExtractPassInfo& info, std::vector<ExtractReport>& reps)
|
|
||||||
{
|
{
|
||||||
m_disc = NOD::OpenDiscFromImage(info.srcpath.c_str(), m_isWii);
|
m_disc = NOD::OpenDiscFromImage(info.srcpath.c_str(), m_isWii);
|
||||||
if (!m_disc)
|
if (!m_disc)
|
||||||
|
@ -41,20 +40,19 @@ bool SpecBase::canExtract(HECL::Database::Project& project,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_standalone)
|
if (m_standalone)
|
||||||
return checkFromStandaloneDisc(project, *m_disc.get(), *regstr, info.extractArgs, reps);
|
return checkFromStandaloneDisc(*m_disc, *regstr, info.extractArgs, reps);
|
||||||
else
|
else
|
||||||
return checkFromTrilogyDisc(project, *m_disc.get(), *regstr, info.extractArgs, reps);
|
return checkFromTrilogyDisc(*m_disc, *regstr, info.extractArgs, reps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpecBase::doExtract(HECL::Database::Project& project, const ExtractPassInfo& info,
|
void SpecBase::doExtract(const ExtractPassInfo& info, FExtractProgress progress)
|
||||||
FExtractProgress progress)
|
|
||||||
{
|
{
|
||||||
if (!Blender::BuildMasterShader(HECL::ProjectPath(project.getProjectRootPath(), ".hecl/RetroMasterShader.blend")))
|
if (!Blender::BuildMasterShader(m_masterShader))
|
||||||
Log.report(LogVisor::FatalError, "Unable to build master shader 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 */
|
||||||
const HECL::SystemString& target = project.getProjectRootPath().getAbsolutePath();
|
const HECL::SystemString& target = m_project.getProjectRootPath().getAbsolutePath();
|
||||||
NOD::DiscBase::IPartition* update = m_disc->getUpdatePartition();
|
NOD::DiscBase::IPartition* update = m_disc->getUpdatePartition();
|
||||||
if (update)
|
if (update)
|
||||||
{
|
{
|
||||||
|
@ -74,29 +72,29 @@ void SpecBase::doExtract(HECL::Database::Project& project, const ExtractPassInfo
|
||||||
progress(_S("Trilogy Files"), 1, 1.0);
|
progress(_S("Trilogy Files"), 1, 1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
extractFromDisc(project, *m_disc.get(), info.force, progress);
|
extractFromDisc(*m_disc, info.force, progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpecBase::canCook(const HECL::Database::Project& project, const CookTaskInfo& info)
|
bool SpecBase::canCook(const CookTaskInfo& info)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpecBase::doCook(const HECL::Database::Project& project, const CookTaskInfo& info)
|
void SpecBase::doCook(const CookTaskInfo& info)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpecBase::canPackage(const HECL::Database::Project& project, const PackagePassInfo& info)
|
bool SpecBase::canPackage(const PackagePassInfo& info)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpecBase::gatherDependencies(const HECL::Database::Project& project, const PackagePassInfo& info,
|
void SpecBase::gatherDependencies(const PackagePassInfo& info,
|
||||||
std::unordered_set<HECL::ProjectPath>& implicitsOut)
|
std::unordered_set<HECL::ProjectPath>& implicitsOut)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpecBase::doPackage(const HECL::Database::Project& project, const PackagePassInfo& info)
|
void SpecBase::doPackage(const PackagePassInfo& info)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,34 +11,31 @@ namespace Retro
|
||||||
|
|
||||||
struct SpecBase : HECL::Database::IDataSpec
|
struct SpecBase : HECL::Database::IDataSpec
|
||||||
{
|
{
|
||||||
bool canExtract(HECL::Database::Project& project, const ExtractPassInfo& info,
|
bool canExtract(const ExtractPassInfo& info, std::vector<ExtractReport>& reps);
|
||||||
std::vector<ExtractReport>& reps);
|
void doExtract(const ExtractPassInfo& info, FExtractProgress progress);
|
||||||
void doExtract(HECL::Database::Project& project, const ExtractPassInfo& info, FExtractProgress progress);
|
|
||||||
|
|
||||||
bool canCook(const HECL::Database::Project& project, const CookTaskInfo& info);
|
bool canCook(const CookTaskInfo& info);
|
||||||
void doCook(const HECL::Database::Project& project, const CookTaskInfo& info);
|
void doCook(const CookTaskInfo& info);
|
||||||
|
|
||||||
bool canPackage(const HECL::Database::Project& project, const PackagePassInfo& info);
|
bool canPackage(const PackagePassInfo& info);
|
||||||
void gatherDependencies(const HECL::Database::Project& project, const PackagePassInfo& info,
|
void gatherDependencies(const PackagePassInfo& info,
|
||||||
std::unordered_set<HECL::ProjectPath>& implicitsOut);
|
std::unordered_set<HECL::ProjectPath>& implicitsOut);
|
||||||
void doPackage(const HECL::Database::Project& project, const PackagePassInfo& info);
|
void doPackage(const PackagePassInfo& info);
|
||||||
|
|
||||||
virtual bool checkStandaloneID(const char* id) const=0;
|
virtual bool checkStandaloneID(const char* id) const=0;
|
||||||
virtual bool checkFromStandaloneDisc(HECL::Database::Project& project,
|
virtual bool checkFromStandaloneDisc(NOD::DiscBase& disc,
|
||||||
NOD::DiscBase& disc,
|
|
||||||
const HECL::SystemString& regstr,
|
const HECL::SystemString& regstr,
|
||||||
const std::vector<HECL::SystemString>& args,
|
const std::vector<HECL::SystemString>& args,
|
||||||
std::vector<ExtractReport>& reps)=0;
|
std::vector<ExtractReport>& reps)=0;
|
||||||
virtual bool checkFromTrilogyDisc(HECL::Database::Project& project,
|
virtual bool checkFromTrilogyDisc(NOD::DiscBase& disc,
|
||||||
NOD::DiscBase& disc,
|
|
||||||
const HECL::SystemString& regstr,
|
const HECL::SystemString& regstr,
|
||||||
const std::vector<HECL::SystemString>& args,
|
const std::vector<HECL::SystemString>& args,
|
||||||
std::vector<ExtractReport>& reps)=0;
|
std::vector<ExtractReport>& reps)=0;
|
||||||
virtual bool extractFromDisc(HECL::Database::Project& project, NOD::DiscBase& disc, bool force,
|
virtual bool extractFromDisc(NOD::DiscBase& disc, bool force,
|
||||||
FExtractProgress progress)=0;
|
FExtractProgress progress)=0;
|
||||||
|
|
||||||
virtual bool checkFromProject(HECL::Database::Project& proj)=0;
|
virtual bool checkFromProject()=0;
|
||||||
virtual bool readFromProject(HECL::Database::Project& proj)=0;
|
virtual bool readFromProject()=0;
|
||||||
|
|
||||||
virtual bool visitGameObjects(std::function<bool(const HECL::Database::ObjectBase&)>)=0;
|
virtual bool visitGameObjects(std::function<bool(const HECL::Database::ObjectBase&)>)=0;
|
||||||
struct ILevelSpec
|
struct ILevelSpec
|
||||||
|
@ -52,6 +49,14 @@ struct SpecBase : HECL::Database::IDataSpec
|
||||||
};
|
};
|
||||||
virtual bool visitLevels(std::function<bool(const ILevelSpec&)>)=0;
|
virtual bool visitLevels(std::function<bool(const ILevelSpec&)>)=0;
|
||||||
|
|
||||||
|
inline const HECL::ProjectPath& getMasterShaderPath() const {return m_masterShader;}
|
||||||
|
|
||||||
|
SpecBase(HECL::Database::Project& project)
|
||||||
|
: m_project(project),
|
||||||
|
m_masterShader(project.getProjectRootPath(), ".hecl/RetroMasterShader.blend") {}
|
||||||
|
protected:
|
||||||
|
HECL::Database::Project& m_project;
|
||||||
|
HECL::ProjectPath m_masterShader;
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<NOD::DiscBase> m_disc;
|
std::unique_ptr<NOD::DiscBase> m_disc;
|
||||||
bool m_isWii;
|
bool m_isWii;
|
||||||
|
|
|
@ -30,9 +30,10 @@ struct SpecMP1 : SpecBase
|
||||||
PAKRouter<DNAMP1::PAKBridge> m_pakRouter;
|
PAKRouter<DNAMP1::PAKBridge> m_pakRouter;
|
||||||
|
|
||||||
SpecMP1(HECL::Database::Project& project)
|
SpecMP1(HECL::Database::Project& project)
|
||||||
: m_workPath(project.getProjectRootPath(), _S("MP1")),
|
: SpecBase(project),
|
||||||
|
m_workPath(project.getProjectRootPath(), _S("MP1")),
|
||||||
m_cookPath(project.getProjectCookedPath(SpecEntMP1), _S("MP1")),
|
m_cookPath(project.getProjectCookedPath(SpecEntMP1), _S("MP1")),
|
||||||
m_pakRouter(m_workPath, m_cookPath) {}
|
m_pakRouter(*this, m_workPath, m_cookPath) {}
|
||||||
|
|
||||||
void buildPaks(HECL::Database::Project& project,
|
void buildPaks(HECL::Database::Project& project,
|
||||||
NOD::DiscBase::IPartition::Node& root,
|
NOD::DiscBase::IPartition::Node& root,
|
||||||
|
@ -116,8 +117,7 @@ struct SpecMP1 : SpecBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkFromStandaloneDisc(HECL::Database::Project& project,
|
bool checkFromStandaloneDisc(NOD::DiscBase& disc,
|
||||||
NOD::DiscBase& disc,
|
|
||||||
const HECL::SystemString& regstr,
|
const HECL::SystemString& regstr,
|
||||||
const std::vector<HECL::SystemString>& args,
|
const std::vector<HECL::SystemString>& args,
|
||||||
std::vector<ExtractReport>& reps)
|
std::vector<ExtractReport>& reps)
|
||||||
|
@ -141,13 +141,12 @@ struct SpecMP1 : SpecBase
|
||||||
|
|
||||||
/* Iterate PAKs and build level options */
|
/* Iterate PAKs and build level options */
|
||||||
NOD::DiscBase::IPartition::Node& root = partition->getFSTRoot();
|
NOD::DiscBase::IPartition::Node& root = partition->getFSTRoot();
|
||||||
buildPaks(project, root, args, rep);
|
buildPaks(m_project, root, args, rep);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkFromTrilogyDisc(HECL::Database::Project& project,
|
bool checkFromTrilogyDisc(NOD::DiscBase& disc,
|
||||||
NOD::DiscBase& disc,
|
|
||||||
const HECL::SystemString& regstr,
|
const HECL::SystemString& regstr,
|
||||||
const std::vector<HECL::SystemString>& args,
|
const std::vector<HECL::SystemString>& args,
|
||||||
std::vector<ExtractReport>& reps)
|
std::vector<ExtractReport>& reps)
|
||||||
|
@ -202,13 +201,12 @@ struct SpecMP1 : SpecBase
|
||||||
NOD::DiscBase::IPartition::Node::DirectoryIterator mp1It = root.find("MP1");
|
NOD::DiscBase::IPartition::Node::DirectoryIterator mp1It = root.find("MP1");
|
||||||
if (mp1It == root.end())
|
if (mp1It == root.end())
|
||||||
return false;
|
return false;
|
||||||
buildPaks(project, *mp1It, mp1args, rep);
|
buildPaks(m_project, *mp1It, mp1args, rep);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool extractFromDisc(HECL::Database::Project& project, NOD::DiscBase&, bool force,
|
bool extractFromDisc(NOD::DiscBase&, bool force, FExtractProgress progress)
|
||||||
FExtractProgress progress)
|
|
||||||
{
|
{
|
||||||
if (!doMP1)
|
if (!doMP1)
|
||||||
return true;
|
return true;
|
||||||
|
@ -230,7 +228,7 @@ struct SpecMP1 : SpecBase
|
||||||
}
|
}
|
||||||
progress(_S("MP1 Root"), 3, 1.0);
|
progress(_S("MP1 Root"), 3, 1.0);
|
||||||
|
|
||||||
const HECL::ProjectPath& cookPath = project.getProjectCookedPath(SpecEntMP1);
|
const HECL::ProjectPath& cookPath = m_project.getProjectCookedPath(SpecEntMP1);
|
||||||
cookPath.makeDir();
|
cookPath.makeDir();
|
||||||
m_cookPath.makeDir();
|
m_cookPath.makeDir();
|
||||||
|
|
||||||
|
@ -253,11 +251,11 @@ struct SpecMP1 : SpecBase
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkFromProject(HECL::Database::Project& proj)
|
bool checkFromProject()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool readFromProject(HECL::Database::Project& proj)
|
bool readFromProject()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,12 +28,12 @@ struct SpecMP2 : SpecBase
|
||||||
PAKRouter<DNAMP2::PAKBridge> m_pakRouter;
|
PAKRouter<DNAMP2::PAKBridge> m_pakRouter;
|
||||||
|
|
||||||
SpecMP2(HECL::Database::Project& project)
|
SpecMP2(HECL::Database::Project& project)
|
||||||
: m_workPath(project.getProjectRootPath(), _S("MP2")),
|
: SpecBase(project),
|
||||||
|
m_workPath(project.getProjectRootPath(), _S("MP2")),
|
||||||
m_cookPath(project.getProjectCookedPath(SpecEntMP2), _S("MP2")),
|
m_cookPath(project.getProjectCookedPath(SpecEntMP2), _S("MP2")),
|
||||||
m_pakRouter(m_workPath, m_cookPath) {}
|
m_pakRouter(*this, m_workPath, m_cookPath) {}
|
||||||
|
|
||||||
void buildPaks(HECL::Database::Project& project,
|
void buildPaks(NOD::DiscBase::IPartition::Node& root,
|
||||||
NOD::DiscBase::IPartition::Node& root,
|
|
||||||
const std::vector<HECL::SystemString>& args,
|
const std::vector<HECL::SystemString>& args,
|
||||||
ExtractReport& rep)
|
ExtractReport& rep)
|
||||||
{
|
{
|
||||||
|
@ -89,7 +89,7 @@ struct SpecMP2 : SpecBase
|
||||||
}
|
}
|
||||||
|
|
||||||
if (good)
|
if (good)
|
||||||
m_paks.emplace_back(project, child);
|
m_paks.emplace_back(m_project, child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,8 +113,7 @@ struct SpecMP2 : SpecBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkFromStandaloneDisc(HECL::Database::Project& project,
|
bool checkFromStandaloneDisc(NOD::DiscBase& disc,
|
||||||
NOD::DiscBase& disc,
|
|
||||||
const HECL::SystemString& regstr,
|
const HECL::SystemString& regstr,
|
||||||
const std::vector<HECL::SystemString>& args,
|
const std::vector<HECL::SystemString>& args,
|
||||||
std::vector<ExtractReport>& reps)
|
std::vector<ExtractReport>& reps)
|
||||||
|
@ -138,13 +137,12 @@ struct SpecMP2 : SpecBase
|
||||||
|
|
||||||
/* Iterate PAKs and build level options */
|
/* Iterate PAKs and build level options */
|
||||||
NOD::DiscBase::IPartition::Node& root = partition->getFSTRoot();
|
NOD::DiscBase::IPartition::Node& root = partition->getFSTRoot();
|
||||||
buildPaks(project, root, args, rep);
|
buildPaks(root, args, rep);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkFromTrilogyDisc(HECL::Database::Project& project,
|
bool checkFromTrilogyDisc(NOD::DiscBase& disc,
|
||||||
NOD::DiscBase& disc,
|
|
||||||
const HECL::SystemString& regstr,
|
const HECL::SystemString& regstr,
|
||||||
const std::vector<HECL::SystemString>& args,
|
const std::vector<HECL::SystemString>& args,
|
||||||
std::vector<ExtractReport>& reps)
|
std::vector<ExtractReport>& reps)
|
||||||
|
@ -199,13 +197,12 @@ struct SpecMP2 : SpecBase
|
||||||
NOD::DiscBase::IPartition::Node::DirectoryIterator mp2It = root.find("MP2");
|
NOD::DiscBase::IPartition::Node::DirectoryIterator mp2It = root.find("MP2");
|
||||||
if (mp2It == root.end())
|
if (mp2It == root.end())
|
||||||
return false;
|
return false;
|
||||||
buildPaks(project, *mp2It, mp2args, rep);
|
buildPaks(*mp2It, mp2args, rep);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool extractFromDisc(HECL::Database::Project& project, NOD::DiscBase&, bool force,
|
bool extractFromDisc(NOD::DiscBase&, bool force, FExtractProgress progress)
|
||||||
FExtractProgress progress)
|
|
||||||
{
|
{
|
||||||
if (!doMP2)
|
if (!doMP2)
|
||||||
return true;
|
return true;
|
||||||
|
@ -227,7 +224,7 @@ struct SpecMP2 : SpecBase
|
||||||
}
|
}
|
||||||
progress(_S("MP2 Root"), 3, 1.0);
|
progress(_S("MP2 Root"), 3, 1.0);
|
||||||
|
|
||||||
const HECL::ProjectPath& cookPath = project.getProjectCookedPath(SpecEntMP2);
|
const HECL::ProjectPath& cookPath = m_project.getProjectCookedPath(SpecEntMP2);
|
||||||
cookPath.makeDir();
|
cookPath.makeDir();
|
||||||
m_cookPath.makeDir();
|
m_cookPath.makeDir();
|
||||||
|
|
||||||
|
@ -250,11 +247,11 @@ struct SpecMP2 : SpecBase
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkFromProject(HECL::Database::Project& proj)
|
bool checkFromProject()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool readFromProject(HECL::Database::Project& proj)
|
bool readFromProject()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,15 +39,15 @@ struct SpecMP3 : SpecBase
|
||||||
PAKRouter<DNAMP3::PAKBridge> m_fePakRouter;
|
PAKRouter<DNAMP3::PAKBridge> m_fePakRouter;
|
||||||
|
|
||||||
SpecMP3(HECL::Database::Project& project)
|
SpecMP3(HECL::Database::Project& project)
|
||||||
: m_workPath(project.getProjectRootPath(), _S("MP3")),
|
: SpecBase(project),
|
||||||
|
m_workPath(project.getProjectRootPath(), _S("MP3")),
|
||||||
m_cookPath(project.getProjectCookedPath(SpecEntMP3), _S("MP3")),
|
m_cookPath(project.getProjectCookedPath(SpecEntMP3), _S("MP3")),
|
||||||
m_pakRouter(m_workPath, m_cookPath),
|
m_pakRouter(*this, m_workPath, m_cookPath),
|
||||||
m_feWorkPath(project.getProjectRootPath(), _S("fe")),
|
m_feWorkPath(project.getProjectRootPath(), _S("fe")),
|
||||||
m_feCookPath(project.getProjectCookedPath(SpecEntMP3), _S("fe")),
|
m_feCookPath(project.getProjectCookedPath(SpecEntMP3), _S("fe")),
|
||||||
m_fePakRouter(m_feWorkPath, m_feCookPath) {}
|
m_fePakRouter(*this, m_feWorkPath, m_feCookPath) {}
|
||||||
|
|
||||||
void buildPaks(HECL::Database::Project& project,
|
void buildPaks(NOD::DiscBase::IPartition::Node& root,
|
||||||
NOD::DiscBase::IPartition::Node& root,
|
|
||||||
const std::vector<HECL::SystemString>& args,
|
const std::vector<HECL::SystemString>& args,
|
||||||
ExtractReport& rep,
|
ExtractReport& rep,
|
||||||
bool fe)
|
bool fe)
|
||||||
|
@ -114,9 +114,9 @@ struct SpecMP3 : SpecBase
|
||||||
if (good)
|
if (good)
|
||||||
{
|
{
|
||||||
if (fe)
|
if (fe)
|
||||||
m_fePaks.emplace_back(project, child);
|
m_fePaks.emplace_back(m_project, child);
|
||||||
else
|
else
|
||||||
m_paks.emplace_back(project, child);
|
m_paks.emplace_back(m_project, child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,8 +163,7 @@ struct SpecMP3 : SpecBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkFromStandaloneDisc(HECL::Database::Project& project,
|
bool checkFromStandaloneDisc(NOD::DiscBase& disc,
|
||||||
NOD::DiscBase& disc,
|
|
||||||
const HECL::SystemString& regstr,
|
const HECL::SystemString& regstr,
|
||||||
const std::vector<HECL::SystemString>& args,
|
const std::vector<HECL::SystemString>& args,
|
||||||
std::vector<ExtractReport>& reps)
|
std::vector<ExtractReport>& reps)
|
||||||
|
@ -188,13 +187,12 @@ struct SpecMP3 : SpecBase
|
||||||
|
|
||||||
/* Iterate PAKs and build level options */
|
/* Iterate PAKs and build level options */
|
||||||
NOD::DiscBase::IPartition::Node& root = partition->getFSTRoot();
|
NOD::DiscBase::IPartition::Node& root = partition->getFSTRoot();
|
||||||
buildPaks(project, root, args, rep, false);
|
buildPaks(root, args, rep, false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkFromTrilogyDisc(HECL::Database::Project& project,
|
bool checkFromTrilogyDisc(NOD::DiscBase& disc,
|
||||||
NOD::DiscBase& disc,
|
|
||||||
const HECL::SystemString& regstr,
|
const HECL::SystemString& regstr,
|
||||||
const std::vector<HECL::SystemString>& args,
|
const std::vector<HECL::SystemString>& args,
|
||||||
std::vector<ExtractReport>& reps)
|
std::vector<ExtractReport>& reps)
|
||||||
|
@ -269,7 +267,7 @@ struct SpecMP3 : SpecBase
|
||||||
NOD::DiscBase::IPartition::Node::DirectoryIterator mp3It = root.find("MP3");
|
NOD::DiscBase::IPartition::Node::DirectoryIterator mp3It = root.find("MP3");
|
||||||
if (mp3It == root.end())
|
if (mp3It == root.end())
|
||||||
return false;
|
return false;
|
||||||
buildPaks(project, *mp3It, mp3args, rep, false);
|
buildPaks(*mp3It, mp3args, rep, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MPT Frontend extract */
|
/* MPT Frontend extract */
|
||||||
|
@ -298,14 +296,13 @@ struct SpecMP3 : SpecBase
|
||||||
NOD::DiscBase::IPartition::Node::DirectoryIterator feIt = root.find("fe");
|
NOD::DiscBase::IPartition::Node::DirectoryIterator feIt = root.find("fe");
|
||||||
if (feIt == root.end())
|
if (feIt == root.end())
|
||||||
return false;
|
return false;
|
||||||
buildPaks(project, *feIt, feargs, rep, true);
|
buildPaks(*feIt, feargs, rep, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool extractFromDisc(HECL::Database::Project& project, NOD::DiscBase&, bool force,
|
bool extractFromDisc(NOD::DiscBase&, bool force, FExtractProgress progress)
|
||||||
FExtractProgress progress)
|
|
||||||
{
|
{
|
||||||
int compIdx = 2;
|
int compIdx = 2;
|
||||||
int prog;
|
int prog;
|
||||||
|
@ -318,7 +315,7 @@ struct SpecMP3 : SpecBase
|
||||||
});
|
});
|
||||||
progress(_S("Indexing PAKs"), compIdx++, 1.0);
|
progress(_S("Indexing PAKs"), compIdx++, 1.0);
|
||||||
|
|
||||||
HECL::ProjectPath mp3WorkPath(project.getProjectRootPath(), "MP3");
|
HECL::ProjectPath mp3WorkPath(m_project.getProjectRootPath(), "MP3");
|
||||||
mp3WorkPath.makeDir();
|
mp3WorkPath.makeDir();
|
||||||
progress(_S("MP3 Root"), compIdx, 0.0);
|
progress(_S("MP3 Root"), compIdx, 0.0);
|
||||||
prog = 0;
|
prog = 0;
|
||||||
|
@ -329,7 +326,7 @@ struct SpecMP3 : SpecBase
|
||||||
}
|
}
|
||||||
progress(_S("MP3 Root"), compIdx++, 1.0);
|
progress(_S("MP3 Root"), compIdx++, 1.0);
|
||||||
|
|
||||||
const HECL::ProjectPath& cookPath = project.getProjectCookedPath(SpecEntMP3);
|
const HECL::ProjectPath& cookPath = m_project.getProjectCookedPath(SpecEntMP3);
|
||||||
cookPath.makeDir();
|
cookPath.makeDir();
|
||||||
HECL::ProjectPath mp3CookPath(cookPath, "MP3");
|
HECL::ProjectPath mp3CookPath(cookPath, "MP3");
|
||||||
mp3CookPath.makeDir();
|
mp3CookPath.makeDir();
|
||||||
|
@ -371,7 +368,7 @@ struct SpecMP3 : SpecBase
|
||||||
}
|
}
|
||||||
progress(_S("fe Root"), compIdx++, 1.0);
|
progress(_S("fe Root"), compIdx++, 1.0);
|
||||||
|
|
||||||
const HECL::ProjectPath& cookPath = project.getProjectCookedPath(SpecEntMP3);
|
const HECL::ProjectPath& cookPath = m_project.getProjectCookedPath(SpecEntMP3);
|
||||||
cookPath.makeDir();
|
cookPath.makeDir();
|
||||||
m_feCookPath.makeDir();
|
m_feCookPath.makeDir();
|
||||||
|
|
||||||
|
@ -394,11 +391,11 @@ struct SpecMP3 : SpecBase
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkFromProject(HECL::Database::Project& proj)
|
bool checkFromProject()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool readFromProject(HECL::Database::Project& proj)
|
bool readFromProject()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
2
NODLib
2
NODLib
|
@ -1 +1 @@
|
||||||
Subproject commit ebb5c0743da7fafbe4c3945d0117700c43845425
|
Subproject commit 28ed4ba6afe64b1e529799bfb8d87c35fe868e4c
|
Loading…
Reference in New Issue