2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-07-07 07:25:52 +00:00

Lightmap rendering

This commit is contained in:
Jack Andersen 2015-09-17 09:50:43 -10:00
parent 8b653fd7f6
commit da24b39957
9 changed files with 126 additions and 50 deletions

View File

@ -80,6 +80,14 @@ void InitGeomBlenderContext(HECL::BlenderConnection::PyOutStream& os,
" face.smooth = True\n" " face.smooth = True\n"
"\n" "\n"
" return face, ret_mesh\n" " return face, ret_mesh\n"
"\n"
"def expand_lightmap_triangle(uva, uvb, uvc):\n"
" result = ([uva[0],uva[1]], [uvb[0],uvb[1]], [uvc[0],uvc[1]])\n"
" if uva == uvb:\n"
" result[1][0] += 0.005\n"
" if uva == uvc:\n"
" result[2][1] -= 0.005\n"
" return result\n"
"\n"; "\n";
/* Link master shader library */ /* Link master shader library */

View File

@ -589,12 +589,14 @@ atUint32 ReadGeomSectionsToBlender(HECL::BlenderConnection::PyOutStream& os,
for (unsigned j=0 ; j<matUVCount ; ++j) for (unsigned j=0 ; j<matUVCount ; ++j)
{ {
if (j==0 && matShortUVs) if (j==0 && matShortUVs)
os.format(" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = suv_list[%u]\n" os.format(" uv_tri = expand_lightmap_triangle(suv_list[%u], suv_list[%u], suv_list[%u])\n"
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = suv_list[%u]\n" " loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_tri[0]\n"
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = suv_list[%u]\n", " loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_tri[1]\n"
primVerts[c%3].pos, j, primVerts[c%3].uvs[j], " loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_tri[2]\n",
primVerts[(c+2)%3].pos, j, primVerts[(c+2)%3].uvs[j], primVerts[c%3].uvs[j], primVerts[(c+2)%3].uvs[j], primVerts[(c+1)%3].uvs[j],
primVerts[(c+1)%3].pos, j, primVerts[(c+1)%3].uvs[j]); primVerts[c%3].pos, j,
primVerts[(c+2)%3].pos, j,
primVerts[(c+1)%3].pos, j);
else else
os.format(" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n" 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"
@ -621,12 +623,14 @@ atUint32 ReadGeomSectionsToBlender(HECL::BlenderConnection::PyOutStream& os,
for (unsigned j=0 ; j<matUVCount ; ++j) for (unsigned j=0 ; j<matUVCount ; ++j)
{ {
if (j==0 && matShortUVs) if (j==0 && matShortUVs)
os.format(" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = suv_list[%u]\n" os.format(" uv_tri = expand_lightmap_triangle(suv_list[%u], suv_list[%u], suv_list[%u])\n"
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = suv_list[%u]\n" " loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_tri[0]\n"
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = suv_list[%u]\n", " loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_tri[1]\n"
primVerts[c%3].pos, j, primVerts[c%3].uvs[j], " loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_tri[2]\n",
primVerts[(c+1)%3].pos, j, primVerts[(c+1)%3].uvs[j], primVerts[c%3].uvs[j], primVerts[(c+1)%3].uvs[j], primVerts[(c+2)%3].uvs[j],
primVerts[(c+2)%3].pos, j, primVerts[(c+2)%3].uvs[j]); primVerts[c%3].pos, j,
primVerts[(c+1)%3].pos, j,
primVerts[(c+2)%3].pos, j);
else else
os.format(" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n" 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"
@ -666,12 +670,14 @@ atUint32 ReadGeomSectionsToBlender(HECL::BlenderConnection::PyOutStream& os,
for (unsigned j=0 ; j<matUVCount ; ++j) for (unsigned j=0 ; j<matUVCount ; ++j)
{ {
if (j==0 && matShortUVs) if (j==0 && matShortUVs)
os.format(" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = suv_list[%u]\n" os.format(" uv_tri = expand_lightmap_triangle(suv_list[%u], suv_list[%u], suv_list[%u])\n"
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = suv_list[%u]\n" " loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_tri[0]\n"
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = suv_list[%u]\n", " loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_tri[1]\n"
primVerts[0].pos, j, primVerts[0].uvs[j], " loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_tri[2]\n",
primVerts[1].pos, j, primVerts[1].uvs[j], primVerts[0].uvs[j], primVerts[1].uvs[j], primVerts[2].uvs[j],
primVerts[2].pos, j, primVerts[2].uvs[j]); primVerts[0].pos, j,
primVerts[1].pos, j,
primVerts[2].pos, j);
else else
os.format(" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n" 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"
@ -710,12 +716,14 @@ atUint32 ReadGeomSectionsToBlender(HECL::BlenderConnection::PyOutStream& os,
for (unsigned j=0 ; j<matUVCount ; ++j) for (unsigned j=0 ; j<matUVCount ; ++j)
{ {
if (j==0 && matShortUVs) if (j==0 && matShortUVs)
os.format(" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = suv_list[%u]\n" os.format(" uv_tri = expand_lightmap_triangle(suv_list[%u], suv_list[%u], suv_list[%u])\n"
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = suv_list[%u]\n" " loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_tri[0]\n"
" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = suv_list[%u]\n", " loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_tri[1]\n"
firstPrimVert.pos, j, firstPrimVert.uvs[j], " loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_tri[2]\n",
primVerts[c%3].pos, j, primVerts[c%3].uvs[j], firstPrimVert.uvs[j], primVerts[c%3].uvs[j], primVerts[(c+1)%3].uvs[j],
primVerts[(c+1)%3].pos, j, primVerts[(c+1)%3].uvs[j]); firstPrimVert.pos, j,
primVerts[c%3].pos, j,
primVerts[(c+1)%3].pos, j);
else else
os.format(" loop_from_facevert(last_face, %u)[last_mesh.loops.layers.uv[%u]].uv = uv_list[%u]\n" 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"

View File

@ -18,7 +18,6 @@ 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"
"\n"; "\n";
} }
@ -323,19 +322,6 @@ static void AddAlphaCombiner(Stream& out, enum CombinerType type,
out << "alpha_combiner_nodes.append(combiner_node)\n\n"; out << "alpha_combiner_nodes.append(combiner_node)\n\n";
} }
static void AddLightmap(Stream& out, const char* tex, unsigned& c_combiner_idx)
{
out << "world_light_node = new_nodetree.nodes.new('ShaderNodeRGB')\n"
"gridder.place_node(world_light_node, 1)\n"
"world_light_node.label = 'WORLD_LIGHTING'\n"
"world_light_node.outputs[0].default_value = (1.0,1.0,1.0,1.0)\n";
AddColorCombiner(out, COMB_MULT, tex, "world_light_node.outputs[0]", nullptr);
AddColorCombiner(out, COMB_ADD,
"color_combiner_nodes[-1].outputs[0]",
"material_node.outputs['Color']", nullptr);
c_combiner_idx += 2;
}
static void TranslateColorSocket(char* socketOut, GX::TevColorArg arg, static void TranslateColorSocket(char* socketOut, GX::TevColorArg arg,
GX::TevKColorSel kcolor, GX::TevKColorSel kcolor,
const MaterialSet::Material::TEVStageTexInfo& stageTex, const MaterialSet::Material::TEVStageTexInfo& stageTex,
@ -669,9 +655,12 @@ void _ConstructMaterial(Stream& out,
if (material.flags.lightmap() && material.tevStages[0].colorInB() == GX::CC_C1) if (material.flags.lightmap() && material.tevStages[0].colorInB() == GX::CC_C1)
{ {
if (material.tevStageTexInfo[0].texSlot != 0xff) if (material.tevStageTexInfo[0].texSlot != 0xff)
out << "new_material.retro_lightmap = tex_maps[0].name\n" out << "new_material.hecl_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); out << "world_light_node = new_nodetree.nodes.new('ShaderNodeRGB')\n"
"gridder.place_node(world_light_node, 1)\n"
"world_light_node.label = 'WORLD_LIGHTING'\n"
"world_light_node.outputs[0].default_value = (1.0,1.0,1.0,1.0)\n";
strncpy(c_regs[GX::TEVREG1], "world_light_node.outputs[0]", 64); strncpy(c_regs[GX::TEVREG1], "world_light_node.outputs[0]", 64);
} }

View File

@ -127,6 +127,28 @@ void PAKBridge::build()
mlvl.read(rs); mlvl.read(rs);
m_areaDeps.reserve(mlvl.areaCount); m_areaDeps.reserve(mlvl.areaCount);
unsigned layerIdx = 0; unsigned layerIdx = 0;
/* Pre-pass: find duplicate area names */
std::unordered_map<HECL::SystemString, std::pair<atUint32, atUint32>> dupeTracker;
dupeTracker.reserve(mlvl.areas.size());
for (const MLVL::Area& area : mlvl.areas)
{
const PAK::Entry* areaNameEnt = m_pak.lookupEntry(area.areaNameId);
if (areaNameEnt)
{
STRG areaName;
PAKEntryReadStream rs = areaNameEnt->beginReadStream(m_node);
areaName.read(rs);
HECL::SystemString name = areaName.getSystemString(FOURCC('ENGL'), 0);
auto search = dupeTracker.find(name);
if (search != dupeTracker.end())
++search->second.first;
else
dupeTracker[name] = std::make_pair(1, 1);
}
}
/* Main-pass: index areas */
for (const MLVL::Area& area : mlvl.areas) for (const MLVL::Area& area : mlvl.areas)
{ {
Area& areaDeps = m_areaDeps[area.areaMREAId]; Area& areaDeps = m_areaDeps[area.areaMREAId];
@ -137,6 +159,13 @@ void PAKBridge::build()
PAKEntryReadStream rs = areaNameEnt->beginReadStream(m_node); PAKEntryReadStream rs = areaNameEnt->beginReadStream(m_node);
areaName.read(rs); areaName.read(rs);
areaDeps.name = areaName.getSystemString(FOURCC('ENGL'), 0); areaDeps.name = areaName.getSystemString(FOURCC('ENGL'), 0);
auto search = dupeTracker.find(areaDeps.name);
if (search != dupeTracker.end() && search->second.first > 1)
{
char num[16];
snprintf(num, 16, " (%d)", search->second.second++);
areaDeps.name += num;
}
/* Trim possible trailing whitespace */ /* Trim possible trailing whitespace */
#if HECL_UCS2 #if HECL_UCS2

View File

@ -12,6 +12,10 @@ void MREA::ReadBabeDeadToBlender_1_2(HECL::BlenderConnection::PyOutStream& os,
atUint32 bdMagic = rs.readUint32Big(); atUint32 bdMagic = rs.readUint32Big();
if (bdMagic != 0xBABEDEAD) if (bdMagic != 0xBABEDEAD)
Log.report(LogVisor::FatalError, "invalid BABEDEAD magic"); Log.report(LogVisor::FatalError, "invalid BABEDEAD magic");
os << "bpy.context.scene.render.engine = 'CYCLES'\n"
"bpy.context.scene.world.use_nodes = True\n"
"bpy.context.scene.render.engine = 'BLENDER_GAME'\n"
"bg_node = bpy.context.scene.world.node_tree.nodes['Background']\n";
for (atUint32 s=0 ; s<2 ; ++s) for (atUint32 s=0 ; s<2 ; ++s)
{ {
atUint32 lightCount = rs.readUint32Big(); atUint32 lightCount = rs.readUint32Big();
@ -22,8 +26,10 @@ void MREA::ReadBabeDeadToBlender_1_2(HECL::BlenderConnection::PyOutStream& os,
switch (light.lightType) switch (light.lightType)
{ {
case BabeDeadLight::LightLocalAmbient: case BabeDeadLight::LightLocalAmbient:
os.format("bpy.context.scene.world.horizon_color = (%f,%f,%f)\n", os.format("bg_node.inputs[0].default_value = (%f,%f,%f,1.0)\n"
light.color.vec[0], light.color.vec[1], light.color.vec[2]); "bg_node.inputs[1].default_value = %f\n",
light.color.vec[0], light.color.vec[1], light.color.vec[2],
light.q / 8.0);
continue; continue;
case BabeDeadLight::LightDirectional: case BabeDeadLight::LightDirectional:
os.format("lamp = bpy.data.lamps.new('LAMP_%01u_%03u', 'SUN')\n" os.format("lamp = bpy.data.lamps.new('LAMP_%01u_%03u', 'SUN')\n"
@ -54,23 +60,30 @@ void MREA::ReadBabeDeadToBlender_1_2(HECL::BlenderConnection::PyOutStream& os,
os.format("lamp.retro_layer = %u\n" os.format("lamp.retro_layer = %u\n"
"lamp.use_nodes = True\n" "lamp.use_nodes = True\n"
"falloff_node = lamp.node_tree.nodes.new('ShaderNodeLightFalloff')\n" "falloff_node = lamp.node_tree.nodes.new('ShaderNodeLightFalloff')\n"
"lamp.energy = 0.0\n"
"falloff_node.inputs[0].default_value = %f\n" "falloff_node.inputs[0].default_value = %f\n"
"lamp.node_tree.nodes['Emission'].inputs[0].default_value = (%f,%f,%f,1.0)\n" "hue_sat_node = lamp.node_tree.nodes.new('ShaderNodeHueSaturation')\n"
"lamp_obj.hide_render = True\n" "hue_sat_node.inputs[1].default_value = 1.25\n"
"hue_sat_node.inputs[4].default_value = (%f,%f,%f,1.0)\n"
"lamp.node_tree.links.new(hue_sat_node.outputs[0], lamp.node_tree.nodes['Emission'].inputs[0])\n"
"lamp_obj.location = (%f,%f,%f)\n" "lamp_obj.location = (%f,%f,%f)\n"
"bpy.context.scene.objects.link(lamp_obj)\n" "bpy.context.scene.objects.link(lamp_obj)\n"
"\n", s, light.q, "\n", s, light.q / 8.0,
light.color.vec[0], light.color.vec[1], light.color.vec[2], light.color.vec[0], light.color.vec[1], light.color.vec[2],
light.position.vec[0], light.position.vec[1], light.position.vec[2]); light.position.vec[0], light.position.vec[1], light.position.vec[2]);
switch (light.falloff) switch (light.falloff)
{ {
case BabeDeadLight::FalloffConstant: case BabeDeadLight::FalloffConstant:
os << "lamp.node_tree.links.new(falloff_node.outputs[2], lamp.node_tree.nodes['Emission'].inputs[1])\n"; os << "falloff_node.inputs[0].default_value *= 75.0\n"
"lamp.node_tree.links.new(falloff_node.outputs[2], lamp.node_tree.nodes['Emission'].inputs[1])\n";
break;
case BabeDeadLight::FalloffLinear: case BabeDeadLight::FalloffLinear:
os << "lamp.node_tree.links.new(falloff_node.outputs[1], lamp.node_tree.nodes['Emission'].inputs[1])\n"; os << "lamp.node_tree.links.new(falloff_node.outputs[1], lamp.node_tree.nodes['Emission'].inputs[1])\n";
break;
case BabeDeadLight::FalloffQuadratic: case BabeDeadLight::FalloffQuadratic:
os << "lamp.node_tree.links.new(falloff_node.outputs[0], lamp.node_tree.nodes['Emission'].inputs[1])\n"; os << "lamp.node_tree.links.new(falloff_node.outputs[0], lamp.node_tree.nodes['Emission'].inputs[1])\n";
break;
default: break; default: break;
} }

View File

@ -126,6 +126,28 @@ void PAKBridge::build()
mlvl.read(rs); mlvl.read(rs);
m_areaDeps.reserve(mlvl.areaCount); m_areaDeps.reserve(mlvl.areaCount);
unsigned layerIdx = 0; unsigned layerIdx = 0;
/* Pre-pass: find duplicate area names */
std::unordered_map<HECL::SystemString, std::pair<atUint32, atUint32>> dupeTracker;
dupeTracker.reserve(mlvl.areas.size());
for (const MLVL::Area& area : mlvl.areas)
{
const DNAMP1::PAK::Entry* areaNameEnt = m_pak.lookupEntry(area.areaNameId);
if (areaNameEnt)
{
STRG areaName;
PAKEntryReadStream rs = areaNameEnt->beginReadStream(m_node);
areaName.read(rs);
HECL::SystemString name = areaName.getSystemString(FOURCC('ENGL'), 0);
auto search = dupeTracker.find(name);
if (search != dupeTracker.end())
++search->second.first;
else
dupeTracker[name] = std::make_pair(1, 1);
}
}
/* Main-pass: index areas */
for (const MLVL::Area& area : mlvl.areas) for (const MLVL::Area& area : mlvl.areas)
{ {
Area& areaDeps = m_areaDeps[area.areaMREAId]; Area& areaDeps = m_areaDeps[area.areaMREAId];
@ -136,6 +158,13 @@ void PAKBridge::build()
PAKEntryReadStream rs = areaNameEnt->beginReadStream(m_node); PAKEntryReadStream rs = areaNameEnt->beginReadStream(m_node);
areaName.read(rs); areaName.read(rs);
areaDeps.name = areaName.getSystemString(FOURCC('ENGL'), 0); areaDeps.name = areaName.getSystemString(FOURCC('ENGL'), 0);
auto search = dupeTracker.find(areaDeps.name);
if (search != dupeTracker.end() && search->second.first > 1)
{
char num[16];
snprintf(num, 16, " (%d)", search->second.second++);
areaDeps.name += num;
}
/* Trim possible trailing whitespace */ /* Trim possible trailing whitespace */
#if HECL_UCS2 #if HECL_UCS2

View File

@ -48,7 +48,7 @@ class CMain : public boo::IApplicationCallback
CMemorySys x6c_memSys; CMemorySys x6c_memSys;
CTweaks x70_tweaks; CTweaks x70_tweaks;
EGameplayResult xe4_gameplayResult; EGameplayResult xe4_gameplayResult;
bool xe8_finished = false; bool xe8_b24_finished = false;
public: public:
CMain(); CMain();

View File

@ -154,9 +154,9 @@ int CMain::RsMain(int argc, const boo::SystemChar* argv[])
g_TweakManager->ReadFromMemoryCard("AudioTweaks"); g_TweakManager->ReadFromMemoryCard("AudioTweaks");
FillInAssetIDs(); FillInAssetIDs();
TOneStatic<CGameArchitectureSupport> archSupport; TOneStatic<CGameArchitectureSupport> archSupport;
while (!xe8_finished) while (!xe8_b24_finished)
{ {
xe8_finished = archSupport->Update(); xe8_b24_finished = archSupport->Update();
} }
return 0; return 0;
} }

2
hecl

@ -1 +1 @@
Subproject commit b2b3d9c34daa2e2c0e4b8cfd9c7d775f61d4bf56 Subproject commit 893e16c79579499d3834873c99d3fba5c1236898