#include #include "CMDL.hpp" #include "DNAMP1.hpp" #include "CMDLMaterials.hpp" struct DLPrimVert { atUint16 pos; atUint16 norm; atUint16 uvs[8]; }; namespace Retro { namespace DNAMP1 { bool CMDL::ReadToBlender(HECL::BlenderConnection& conn, Athena::io::IStreamReader& reader, PAKRouter& pakRouter, const PAK::Entry& entry, const HECL::ProjectPath& masterShader) { reader.setEndian(Athena::BigEndian); CMDL::Header head; head.read(reader); if (head.magic != 0xDEADBABE) { Log.report(LogVisor::Error, "invalid CMDL magic"); return false; } if (head.version != 2) { Log.report(LogVisor::Error, "invalid CMDL version for MP1"); return false; } /* Open Py Stream */ HECL::BlenderConnection::PyOutStream os = conn.beginPythonOut(true); os.format("import bpy\n" "import bmesh\n" "\n" "bpy.context.scene.name = '%s'\n" "bpy.context.scene.hecl_type = 'MESH'\n" "bpy.context.scene.hecl_mesh_obj = 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 CMDLOriginalIndex(bpy.types.PropertyGroup):\n" " index = bpy.props.IntProperty(name='Original Vertex Index')\n" "bpy.utils.register_class(CMDLOriginalIndex)\n" "bpy.types.Mesh.cmdl_orig_verts = bpy.props.CollectionProperty(type=CMDLOriginalIndex)\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", pakRouter.getBestEntryName(entry).c_str()); /* Link master shader library */ 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", masterShader.getAbsolutePathUTF8().c_str()); MaterialSet::RegisterMaterialProps(os); os << "# Materials\n" "materials = []\n" "\n" "# Overdraw-tracking\n" "od_list = []\n" "\n"; std::vector> matUVCounts; matUVCounts.reserve(head.matSetCount); bool visitedDLOffsets = false; unsigned createdUVLayers = 0; unsigned surfIdx = 0; for (size_t s=0 ; s& uvCounts = matUVCounts.back(); uvCounts.reserve(matSet.head.materialCount); unsigned m=0; for (const MaterialSet::Material& mat : matSet.materials) { uvCounts.emplace_back(); unsigned& uvCount = uvCounts.back(); MaterialSet::ConstructMaterial(os, mat, s, m++, uvCount); os << "materials.append(new_material)\n"; } } else { switch (s-head.matSetCount) { case 0: { /* Positions */ size_t vertCount = head.secSizes[s] / 12; for (size_t i=0 ; i createdUVLayers) { for (int l=createdUVLayers ; l dlBuf = reader.readUBytes(sHead.dlSize); atUint8* origDl = dlBuf.get(); atUint8* dl = origDl; while (*dl && (dl-origDl) < sHead.dlSize) { GX::Primitive ptype = GX::Primitive(*dl & 0xf8); atUint16 vert_count = HECL::SBig(*(atUint16*)(dl + 1)); os.format("# VAT Type: %u\n", *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= 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