Fixes for GameCube targeting

This commit is contained in:
Jack Andersen 2018-03-27 22:06:34 -10:00
parent d1a66e15d4
commit c9f61eb9da
16 changed files with 148 additions and 56 deletions

View File

@ -273,7 +273,7 @@ def recursive_cook(buffer, obj, version, path_hasher, parent_name):
recursive_cook(buffer, ch, version, path_hasher, obj.name)
def cook(path_out, version, path_hasher):
def cook(writepipebuf, version, path_hasher):
global hjustifications, vjustifications, model_draw_flags_e
hjustifications = dict((i[0], i[3]) for i in bpy.types.Object.retro_textpane_hjustification[1]['items'])
vjustifications = dict((i[0], i[3]) for i in bpy.types.Object.retro_textpane_vjustification[1]['items'])
@ -292,12 +292,7 @@ def cook(path_out, version, path_hasher):
if obj.retro_widget_type != 'RETRO_NONE' and not obj.parent:
recursive_cook(buffer, obj, version, path_hasher, 'kGSYS_DummyWidgetID')
rem_bytes = 32 - len(buffer) % 32
for i in range(rem_bytes):
buffer.append(0xff)
fout = open(path_out, 'wb')
fout.write(buffer)
fout.close()
return buffer
# Registration

View File

@ -5,17 +5,20 @@ from mathutils import Vector
class VertPool:
# Initialize hash-unique index for each available attribute
def __init__(self, bm, rna_loops):
def __init__(self, bm, rna_loops, use_luv, material_slots):
self.bm = bm
self.rna_loops = rna_loops
self.material_slots = material_slots
self.pos = {}
self.norm = {}
self.skin = {}
self.color = {}
self.uv = {}
self.luv = {}
self.dlay = None
self.clays = []
self.ulays = []
self.luvlay = None
dlay = None
if len(bm.verts.layers.deform):
@ -27,6 +30,10 @@ class VertPool:
clays.append(bm.loops.layers.color[cl])
self.clays = clays
luvlay = None
if use_luv:
luvlay = bm.loops.layers.uv[0]
self.luvlay = luvlay
ulays = []
for ul in range(len(bm.loops.layers.uv)):
ulays.append(bm.loops.layers.uv[ul])
@ -48,6 +55,7 @@ class VertPool:
# Per-loop pool attributes
for f in bm.faces:
lightmapped = material_slots[f.material_index].material['retro_lightmapped']
for l in f.loops:
if rna_loops:
nf = rna_loops[l.index].normal.copy().freeze()
@ -57,7 +65,13 @@ class VertPool:
cf = l[clays[cl]].copy().freeze()
if cf not in self.color:
self.color[cf] = len(self.color)
for ul in range(len(ulays)):
start_uvlay = 0
if use_luv and lightmapped:
start_uvlay = 1
uf = l[luvlay].uv.copy().freeze()
if uf not in self.luv:
self.luv[uf] = len(self.luv)
for ul in range(start_uvlay, len(ulays)):
uf = l[ulays[ul]].uv.copy().freeze()
if uf not in self.uv:
self.uv[uf] = len(self.uv)
@ -79,6 +93,13 @@ class VertPool:
for u in sorted(self.uv.items(), key=operator.itemgetter(1)):
writebuf(struct.pack('ff', u[0][0], u[0][1]))
luv_count = 0
if self.luvlay is not None:
luv_count = 1
writebuf(struct.pack('II', luv_count, len(self.luv)))
for u in sorted(self.luv.items(), key=operator.itemgetter(1)):
writebuf(struct.pack('ff', u[0][0], u[0][1]))
writebuf(struct.pack('I', len(vert_groups)))
for vgrp in vert_groups:
writebuf(struct.pack('I', len(vgrp.name)))
@ -122,6 +143,10 @@ class VertPool:
return self.color[cf]
def get_uv_idx(self, loop, uidx):
if self.luvlay is not None and uidx == 0:
if self.material_slots[loop.face.material_index].material['retro_lightmapped']:
uf = loop[self.luvlay].uv.copy().freeze()
return self.luv[uf]
uf = loop[self.ulays[uidx]].uv.copy().freeze()
return self.uv[uf]

View File

@ -18,7 +18,6 @@ def write_out_material(writebuf, mat, mesh_obj):
if isinstance(prop[1], int):
prop_count += 1
writebuf(struct.pack('I', prop_count))
prop_count = 0
for prop in mat.items():
if isinstance(prop[1], int):
writebuf(struct.pack('I', len(prop[0])))
@ -34,7 +33,7 @@ def write_out_material(writebuf, mat, mesh_obj):
# Takes a Blender 'Mesh' object (not the datablock)
# and performs a one-shot conversion process to HMDL
def cook(writebuf, mesh_obj, output_mode, max_skin_banks, max_octant_length=None):
def cook(writebuf, mesh_obj, output_mode, max_skin_banks, use_luv=False):
if mesh_obj.type != 'MESH':
raise RuntimeError("%s is not a mesh" % mesh_obj.name)
@ -75,10 +74,9 @@ def cook(writebuf, mesh_obj, output_mode, max_skin_banks, max_octant_length=None
# Create master BMesh and VertPool
bm_master = bmesh.new()
bm_master.from_mesh(copy_mesh)
vert_pool = HMDLMesh.VertPool(bm_master, rna_loops)
vert_pool = HMDLMesh.VertPool(bm_master, rna_loops, use_luv, mesh_obj.material_slots)
# Tag edges where there are distinctive loops
splittable_edges = []
for e in bm_master.edges:
e.tag = vert_pool.splitable_edge(e)

View File

@ -53,7 +53,7 @@ def cook(writebuf, mesh_obj):
# Create master BMesh and VertPool
bm_master = bmesh.new()
bm_master.from_mesh(copy_obj.data)
vert_pool = VertPool(bm_master, rna_loops)
vert_pool = VertPool(bm_master, rna_loops, False, mesh_obj.material_slots)
# Output vert pool
vert_pool.write_out_map(writebuf)

View File

@ -217,13 +217,14 @@ def dataout_loop():
elif cmdargs[0] == 'MESHCOMPILENAME':
meshName = cmdargs[1]
maxSkinBanks = int(cmdargs[3])
useLuv = int(cmdargs[4])
if meshName not in bpy.data.objects:
writepipestr(('mesh %s not found' % meshName).encode())
continue
writepipestr(b'OK')
hecl.hmdl.cook(writepipebuf, bpy.data.objects[meshName], cmdargs[2], maxSkinBanks)
hecl.hmdl.cook(writepipebuf, bpy.data.objects[meshName], cmdargs[2], maxSkinBanks, useLuv)
elif cmdargs[0] == 'MESHCOMPILENAMECOLLISION':
meshName = cmdargs[1]
@ -281,15 +282,16 @@ def dataout_loop():
hecl.swld.cook(writepipebuf)
elif cmdargs[0] == 'FRAMECOMPILE':
pathOut = cmdargs[1]
version = int(cmdargs[2])
version = int(cmdargs[1])
if version != 0 and version != 1:
writepipestr(b'bad version')
continue
writepipestr(b'OK')
hecl.frme.cook(pathOut, version, PathHasher())
buffer = hecl.frme.cook(writepipebuf, version, PathHasher())
writepipestr(b'FRAMEDONE')
writepipebuf(struct.pack('I', len(buffer)))
writepipebuf(buffer)
elif cmdargs[0] == 'LIGHTCOMPILEALL':
writepipestr(b'OK')

View File

@ -78,7 +78,10 @@ protected:
#endif
{
if (ch == 'n' || ch == 'N')
{
hecl::Printf(_S("\n"));
return false;
}
if (ch == 'y' || ch == 'Y' || ch == '\r' || ch == '\n')
break;
}

View File

@ -19,8 +19,9 @@ class ToolExtract final : public ToolBase
{
const hecl::Database::DataSpecEntry* m_entry;
std::unique_ptr<hecl::Database::IDataSpec> m_instance;
SpecExtractPass(const hecl::Database::DataSpecEntry* entry, hecl::Database::IDataSpec* instance)
: m_entry(entry), m_instance(instance) {}
SpecExtractPass(const hecl::Database::DataSpecEntry* entry,
std::unique_ptr<hecl::Database::IDataSpec>&& instance)
: m_entry(entry), m_instance(std::move(instance)) {}
SpecExtractPass(const SpecExtractPass& other) = delete;
SpecExtractPass(SpecExtractPass&& other) = default;
};
@ -90,14 +91,9 @@ public:
{
if (entry->m_factory)
{
hecl::Database::IDataSpec* ds = entry->m_factory(*m_useProj, hecl::Database::DataSpecTool::Extract);
if (ds)
{
if (ds->canExtract(m_einfo, m_reps))
m_specPasses.emplace_back(entry, ds);
else
delete ds;
}
auto ds = entry->m_factory(*m_useProj, hecl::Database::DataSpecTool::Extract);
if (ds && ds->canExtract(m_einfo, m_reps))
m_specPasses.emplace_back(entry, std::move(ds));
}
}
}

View File

@ -198,6 +198,8 @@ struct Mesh
std::vector<Vector3f> color;
uint32_t uvLayerCount = 0;
std::vector<Vector2f> uv;
uint32_t luvLayerCount = 0;
std::vector<Vector2f> luv;
/* Skinning data */
std::vector<std::string> boneNames;
@ -537,7 +539,7 @@ public:
Mesh::SurfProgFunc surfProg=[](int){});
/** Compile mesh by name (AREA blends only) */
Mesh compileMesh(std::string_view name, HMDLTopology topology, int skinSlotCount=10,
Mesh compileMesh(std::string_view name, HMDLTopology topology, int skinSlotCount=10, bool useLuv=false,
Mesh::SurfProgFunc surfProg=[](int){});
/** Compile collision mesh by name (AREA blends only) */
@ -560,7 +562,7 @@ public:
PathMesh compilePathMesh();
/** Compile GUI into FRME data (FRAME blends only) */
void compileGuiFrame(std::string_view pathOut, int version);
std::vector<uint8_t> compileGuiFrame(int version);
/** Gather all texture paths in scene */
std::vector<ProjectPath> getTextures();

View File

@ -144,11 +144,12 @@ struct DataSpecEntry
{
SystemStringView m_name;
SystemStringView m_desc;
std::function<IDataSpec*(Project&, DataSpecTool)> m_factory;
SystemStringView m_pakExt;
std::function<std::unique_ptr<IDataSpec>(Project&, DataSpecTool)> m_factory;
DataSpecEntry(SystemStringView name, SystemStringView desc,
std::function<IDataSpec*(Project& project, DataSpecTool)>&& factory)
: m_name(name), m_desc(desc), m_factory(std::move(factory)) {}
DataSpecEntry(SystemStringView name, SystemStringView desc, SystemStringView pakExt,
std::function<std::unique_ptr<IDataSpec>(Project& project, DataSpecTool)>&& factory)
: m_name(name), m_desc(desc), m_pakExt(pakExt), m_factory(std::move(factory)) {}
};
/**

View File

@ -2,6 +2,7 @@
#define HECLMULTIPROGRESSPRINTER_HPP
#include "hecl.hpp"
#include <thread>
namespace hecl
{
@ -19,6 +20,7 @@ class MultiProgressPrinter
#endif
int width;
bool xtermColor = false;
bool truncate = false;
} m_termInfo;
struct ThreadStat
@ -34,7 +36,7 @@ class MultiProgressPrinter
mutable int m_indeterminateCounter = 0;
mutable int m_curThreadLines = 0;
mutable int m_curProgLines = 0;
mutable int m_latestThread = 0;
mutable int m_latestThread = -1;
mutable bool m_running = false;
mutable bool m_dirty = false;
mutable bool m_mainIndeterminate = false;

View File

@ -495,7 +495,7 @@ static inline bool PathRelative(const SystemChar* path)
#endif
}
static inline int ConsoleWidth()
static inline int ConsoleWidth(bool* ok = nullptr)
{
int retval = 80;
#if _WIN32
@ -503,11 +503,19 @@ static inline int ConsoleWidth()
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
retval = info.dwSize.X;
if (ok)
*ok = true;
#endif
#else
if (ok)
*ok = false;
struct winsize w;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1)
{
retval = w.ws_col;
if (ok)
*ok = true;
}
#endif
if (retval < 10)
return 10;
@ -547,6 +555,7 @@ public:
uint32_t val32() const {return uint32_t(hash) ^ uint32_t(hash >> 32);}
uint64_t val64() const {return uint64_t(hash);}
size_t valSizeT() const {return size_t(hash);}
template <typename T> T valT() const;
Hash& operator=(const Hash& other) {hash = other.hash; return *this;}
bool operator==(const Hash& other) const {return hash == other.hash;}
bool operator!=(const Hash& other) const {return hash != other.hash;}
@ -555,6 +564,8 @@ public:
bool operator<=(const Hash& other) const {return hash <= other.hash;}
bool operator>=(const Hash& other) const {return hash >= other.hash;}
};
template <> inline uint32_t Hash::valT<uint32_t>() const { return val32(); }
template <> inline uint64_t Hash::valT<uint64_t>() const { return val64(); }
/**
* @brief Timestamp representation used for comparing modtimes of cooked resources

View File

@ -260,6 +260,15 @@ GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const I
b->m_kColor = newKColor;
return TraceResult(b);
}
else if (aTrace.type == TraceResult::Type::TEVColorArg &&
bTrace.type == TraceResult::Type::TEVColorArg)
{
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[0] = aTrace.tevColorArg;
stage.m_color[3] = bTrace.tevColorArg;
stage.m_kColor = newKColor;
return TraceResult(&stage);
}
break;
}
case ArithmeticOp::Subtract:
@ -292,6 +301,16 @@ GX::TraceResult GX::RecursiveTraceColor(const IR& ir, Diagnostics& diag, const I
a->m_cop = TEV_SUB;
return TraceResult(a);
}
else if (aTrace.type == TraceResult::Type::TEVColorArg &&
bTrace.type == TraceResult::Type::TEVColorArg)
{
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_color[0] = aTrace.tevColorArg;
stage.m_color[3] = bTrace.tevColorArg;
stage.m_kColor = newKColor;
stage.m_cop = TEV_SUB;
return TraceResult(&stage);
}
break;
}
case ArithmeticOp::Multiply:
@ -544,6 +563,15 @@ GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const I
b->m_kAlpha = newKAlpha;
return TraceResult(b);
}
else if (aTrace.type == TraceResult::Type::TEVAlphaArg &&
bTrace.type == TraceResult::Type::TEVAlphaArg)
{
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_alpha[0] = aTrace.tevAlphaArg;
stage.m_alpha[3] = bTrace.tevAlphaArg;
stage.m_kAlpha = newKAlpha;
return TraceResult(&stage);
}
break;
}
case ArithmeticOp::Subtract:
@ -583,6 +611,16 @@ GX::TraceResult GX::RecursiveTraceAlpha(const IR& ir, Diagnostics& diag, const I
a->m_kAlpha = newKAlpha;
return TraceResult(a);
}
else if (aTrace.type == TraceResult::Type::TEVAlphaArg &&
bTrace.type == TraceResult::Type::TEVAlphaArg)
{
TEVStage& stage = addTEVStage(diag, inst.m_loc);
stage.m_alpha[0] = aTrace.tevAlphaArg;
stage.m_alpha[3] = bTrace.tevAlphaArg;
stage.m_kAlpha = newKAlpha;
stage.m_aop = TEV_SUB;
return TraceResult(&stage);
}
break;
}
case ArithmeticOp::Multiply:

View File

@ -1000,6 +1000,14 @@ Mesh::Mesh(Connection& conn, HMDLTopology topologyIn, int skinSlotCount, SurfPro
for (uint32_t i=0 ; i<count ; ++i)
uv.emplace_back(conn);
conn._readBuf(&luvLayerCount, 4);
if (luvLayerCount > 1)
LogModule.report(logvisor::Fatal, "mesh has %u LUV-layers; max 1", luvLayerCount);
conn._readBuf(&count, 4);
luv.reserve(count);
for (uint32_t i=0 ; i<count ; ++i)
luv.emplace_back(conn);
conn._readBuf(&count, 4);
boneNames.reserve(count);
for (uint32_t i=0 ; i<count ; ++i)
@ -1827,15 +1835,15 @@ Mesh DataStream::compileMesh(HMDLTopology topology, int skinSlotCount, Mesh::Sur
}
Mesh DataStream::compileMesh(std::string_view name, HMDLTopology topology,
int skinSlotCount, Mesh::SurfProgFunc surfProg)
int skinSlotCount, bool useLuv, Mesh::SurfProgFunc surfProg)
{
if (m_parent->getBlendType() != BlendType::Area)
BlenderLog.report(logvisor::Fatal, _S("%s is not an AREA blend"),
m_parent->getBlendPath().getAbsolutePath().data());
char req[128];
snprintf(req, 128, "MESHCOMPILENAME %s %s %d", name.data(),
MeshOutputModeString(topology), skinSlotCount);
snprintf(req, 128, "MESHCOMPILENAME %s %s %d %d", name.data(),
MeshOutputModeString(topology), skinSlotCount, int(useLuv));
m_parent->_writeStr(req);
char readBuf[256];
@ -1953,14 +1961,15 @@ PathMesh DataStream::compilePathMesh()
return PathMesh(*m_parent);
}
void DataStream::compileGuiFrame(std::string_view pathOut, int version)
std::vector<uint8_t> DataStream::compileGuiFrame(int version)
{
std::vector<uint8_t> ret;
if (m_parent->getBlendType() != BlendType::Frame)
BlenderLog.report(logvisor::Fatal, _S("%s is not a FRAME blend"),
m_parent->getBlendPath().getAbsolutePath().data());
char req[512];
snprintf(req, 512, "FRAMECOMPILE '%s' %d", pathOut.data(), version);
snprintf(req, 512, "FRAMECOMPILE %d", version);
m_parent->_writeStr(req);
char readBuf[1024];
@ -1987,6 +1996,12 @@ void DataStream::compileGuiFrame(std::string_view pathOut, int version)
snprintf(req, 512, "%016" PRIX64 , path.hash().val64());
m_parent->_writeStr(req);
}
uint32_t len;
m_parent->_readBuf(&len, 4);
ret.resize(len);
m_parent->_readBuf(&ret[0], len);
return ret;
}
std::vector<ProjectPath> DataStream::getTextures()
@ -2386,7 +2401,7 @@ void Token::shutdown()
{
m_conn->quitBlender();
m_conn.reset();
BlenderLog.report(logvisor::Info, "BlenderConnection Shutdown Successful");
BlenderLog.report(logvisor::Info, "Blender Shutdown Successful");
}
}

View File

@ -19,15 +19,17 @@ void MultiProgressPrinter::ThreadStat::print(const TermInfo& tinfo) const
float factor = std::max(0.f, std::min(1.f, m_factor));
int iFactor = factor * 100.f;
int messageLen = m_message.size();
int submessageLen = m_submessage.size();
int half;
if (blocks)
half = (tinfo.width + 1) / 2 - 2;
else
else if (tinfo.truncate)
half = tinfo.width - 4;
int rightHalf = tinfo.width - half - 4;
else
half = messageLen;
int messageLen = m_message.size();
int submessageLen = m_submessage.size();
if (half - messageLen < submessageLen-2)
submessageLen = 0;
@ -57,6 +59,7 @@ void MultiProgressPrinter::ThreadStat::print(const TermInfo& tinfo) const
if (blocks)
{
int rightHalf = tinfo.width - half - 4;
int blocks = rightHalf - 7;
int filled = blocks * factor;
int rem = blocks - filled;
@ -176,7 +179,7 @@ void MultiProgressPrinter::DoPrint()
if (m_dirty)
{
m_termInfo.width = (hecl::GuiMode ? 120 : std::max(80, hecl::ConsoleWidth()));
m_termInfo.width = (hecl::GuiMode ? 120 : std::max(80, hecl::ConsoleWidth(&m_termInfo.truncate)));
MoveCursorUp(m_curThreadLines + m_curProgLines);
m_curThreadLines = m_curProgLines = 0;
@ -237,7 +240,7 @@ void MultiProgressPrinter::DoPrint()
++m_curProgLines;
}
}
else
else if (m_latestThread != -1)
{
const ThreadStat& stat = m_threadStats[m_latestThread];
stat.print(m_termInfo);
@ -365,6 +368,7 @@ void MultiProgressPrinter::startNewLine() const
std::lock_guard<std::mutex> lk(m_logLock);
const_cast<MultiProgressPrinter&>(*this).DoPrint();
m_threadStats.clear();
m_latestThread = -1;
m_curThreadLines = 0;
m_mainFactor = -1.f;
auto logLk = logvisor::LockLog();

View File

@ -482,7 +482,7 @@ bool Project::cookPath(const ProjectPath& path, const hecl::MultiProgressPrinter
{
m_cookSpecs.clear();
if (spec->m_factory)
m_cookSpecs.push_back(std::unique_ptr<IDataSpec>(spec->m_factory(*this, DataSpecTool::Cook)));
m_cookSpecs.push_back(spec->m_factory(*this, DataSpecTool::Cook));
}
}
else if (m_cookSpecs.empty())
@ -490,7 +490,7 @@ bool Project::cookPath(const ProjectPath& path, const hecl::MultiProgressPrinter
m_cookSpecs.reserve(m_compiledSpecs.size());
for (const ProjectDataSpec& spec : m_compiledSpecs)
if (spec.active && spec.spec.m_factory)
m_cookSpecs.push_back(std::unique_ptr<IDataSpec>(spec.spec.m_factory(*this, DataSpecTool::Cook)));
m_cookSpecs.push_back(spec.spec.m_factory(*this, DataSpecTool::Cook));
}
/* Iterate complete directory/file/glob list */
@ -549,7 +549,7 @@ bool Project::packagePath(const ProjectPath& path, const hecl::MultiProgressPrin
LogModule.report(logvisor::Fatal, "No matching DataSpec");
if (!m_lastPackageSpec || m_lastPackageSpec->getDataSpecEntry() != specEntry)
m_lastPackageSpec = std::unique_ptr<IDataSpec>(specEntry->m_factory(*this, DataSpecTool::Package));
m_lastPackageSpec = specEntry->m_factory(*this, DataSpecTool::Package);
if (m_lastPackageSpec->canPackage(path))
{

View File

@ -14,9 +14,9 @@ static SystemString CanonRelPath(SystemStringView path)
hecl::SystemRegexMatch matches;
SystemString in(path);
SanitizePath(in);
for (; std::regex_search(in, matches, regPATHCOMP) ; in = matches.suffix())
for (; std::regex_search(in, matches, regPATHCOMP) ; in = matches.suffix().str())
{
const SystemString& match = matches[1];
hecl::SystemRegexMatch::const_reference match = matches[1];
if (!match.compare(_S(".")))
continue;
else if (!match.compare(_S("..")))
@ -30,7 +30,7 @@ static SystemString CanonRelPath(SystemStringView path)
comps.pop_back();
continue;
}
comps.push_back(match);
comps.push_back(match.str());
}
/* Emit relative path */
@ -210,7 +210,7 @@ static void _recursiveGlob(Database::Project& proj,
return;
if (S_ISDIR(theStat.st_mode))
_recursiveGlob(proj, outPaths, matches.suffix(), nextItStr, true);
_recursiveGlob(proj, outPaths, matches.suffix().str(), nextItStr, true);
else
outPaths.emplace_back(proj, nextItStr);
return;
@ -235,7 +235,7 @@ static void _recursiveGlob(Database::Project& proj,
continue;
if (ent.m_isDir)
_recursiveGlob(proj, outPaths, matches.suffix(), nextItStr, true);
_recursiveGlob(proj, outPaths, matches.suffix().str(), nextItStr, true);
else
outPaths.emplace_back(proj, nextItStr);
}