October 2Oct 2 Hi,I'm reverse engineering the .mdl model format used by Resident Evil Code: Veronica X HD.I'm specifically looking for help from someone experienced with Noesis Python plugins / Capcom model formats to turn the information below into a working Noesis importer that actually displays the complete mesh correctly.I already have a substantial amount of the format mapped, but the last part of the encoded face/UV streams is preventing me from producing a reliable complete importer.I am not looking for an approximate mesh. The objective is a deterministic parser that reconstructs the complete geometry correctly.1. MDL blocksThe files contain blocks identified by:4D 44 4C BCand sometimes:4D 44 4C ADThe MDL blocks contain a table of entries.Each entry is:0x34 bytesThe important fields identified so far are:entry + 0x08 = entry type entry + 0x0C = relative targetThe relative offsets are relative to the MDL block.2. TYPE 0x06 / TYPE 0x16 mesh entriesTYPE 0x06 is confirmed to be a geometry/submesh descriptor.For example, in en52a00.mdl:MDL base = 0xD50 entry = base + 0x94 type = 0x06 target = base + 0x398 target + 0x10 -> vertex descriptor target + 0x14 -> face-stream descriptorVertex descriptor:VD = 0x3E0 relative vertex count = 0x330 = 816 vertex data = VD + 0x50Therefore:vertex data abs = 0x1180The vertex data occupies:0x1180 ... 0x7783and the face stream begins at:0x7784The face-stream pointer itself is:target + 0x14with the actual stream beginning at:face_pointer + 0x10The same structure was observed in several independent models.3. Confirmed examplesen92a00.mdlMDL base = 0x1884 TYPE 06 entry = base + 0x114 target = base + 0x654 vertex descriptor = 0x66C vertex count = 0x5EE = 1518 vertex data = 0x1F40 face pointer = relative 0xC470 face stream = 0xDD04Face stream starts:13 25 00 04 7F 7F 7F FF 7F 7F 7F FF 08 34 40 09 42 02 18 C4 ...en91a00.mdlMDL base = 0x1958 TYPE 06 entry = base + 0x118 target = base + 0x658 vertex descriptor = 0x698 vertex count = 0x623 = 1571 vertex data = 0x2040 face pointer = relative 0xCB3C face stream = 0xE4A4Face stream:13 25 00 04 ... 42 02 1E 80 ...en05a00.mdlLibrary sample:file size = 58560 bytes MDL base = 0xF70TYPE 06:entry = base + 0x84 target = base + 0x5F8 vertex descriptor = base + 0x640 vertex count = 0x3A8 = 936 vertex data = 0x1600Vertex data ends at:0x8B00Face stream:face stream = 0x8B04The beginning is:13 25 00 04 ... 08 34 40 ... 42 12 ...There are also multiple TYPE 16 submeshes.4. Vertex streamThe external reverse-engineering work on this format already established that the vertex/face data are encoded as multiple streams with 32-bit stream headers.The known vertex stream example is:00 6D 00 29followed by:00 12 00 00and floating-point data.The documented interpretation is that 0x0029 contains:position = float3 normal = float3while another descriptor such as 0x0022 contains position-only data.This agrees with the vertex buffers found in my samples.5. Face streamThe known first stream is:13 25 00 04followed by RGBA data.This is consistent with the previous reverse-engineering work which identified 0x25130004 as a face-colour stream.The colour applies to following faces until another colour stream occurs.The important part is the following encoded geometry streams.6. 42 streamsThe major unresolved part is the 42 stream.Examples:42 02 ... 42 0A ... 42 12 ...The records following the 4-byte header consist of 16-bit values.The important discovery is that these are not simply three fixed fields ofindex, U, Vfor the entire stream.The role of the fields changes depending on the current state.7. 42 0A — strong evidence for rotating index stateOne very useful example is:en78a00.mdl face stream @ 0x1EB4Header:42 0A 00 70Control:00 09 FF F6followed by 28 records.The first records are:0002 02DC 0143 0001 02DC 0133 0005 02F4 0143 0004 02F4 0133 0008 030C 0143 0007 030C 0133 000B 0324 0143 000A 0324 0133 000E 033C 0143 000D 033C 0133Here the first field behaves as the vertex index.Then:FFF6 0000 02DC 0123 0002 02DC 0113 0003 02F4 0123 0005 02F4 0113 0006 030C 0123 0008 030C ...The index has moved to another field.Later:0113 FFF6 000C 033C 0123 000D 033C 0133 0009 0324 0123 000A ...The index has moved again.So the evidence strongly suggests a state machine where the active index field can rotate:field 0 -> field 1 -> field 2and the other two fields contain texture-coordinate-related data.This produces coherent box-like geometry when decoded with the appropriate state changes.8. 42 12 — the remaining problemThe difficult streams are 42 12.For example:en05a00.mdl face stream @ 0xCFC4Header:42 12 00 74Control:00 06 00 0618 records:0 000A 0391 0307 1 0000 0367 0369 2 0002 0367 0307 3 0001 0319 0369 4 0003 0319 0307 5 000B 02CB 0308 6 0004 0000 0367 7 0359 0005 0367 8 03D7 0001 0319 9 0359 0006 031A 10 03D6 0003 000B 11 0188 02D5 000A 12 01D6 02D5 0007 13 01AF 02B0 FFFB 14 000B 0188 02D5 15 0003 0188 0289 16 0007 01AF 02B0 17 0002 01D6 0288The first several records clearly have a small first field corresponding to vertex indices, while the other fields are UV-like values.But later records show the active index field changing.For example:13 01AF 02B0 FFFBHere FFFB cannot simply be treated as a restart/index because the other values are clearly consistent with UV data.Therefore:FFFx is NOT universally a restart marker.It can occur in a field which is not currently the index field.9. Another 42 12 exampleen05a00.mdl, stream around:0xD304contains:42 12 00 74with control:00 06 00 0BThe beginning:11 02D0 0302 03 0318 0302 01 0318 035F 02 0363 0302 00 0363 035E 0A 03AB 0302 08 03AA 035E 09 03EE 035F 0C 03A9 03D2 0D 03EF 03D2 04 0341 03FE FFFB 0003 0187then:0278 0002 01D6 0275 0007 01AF 02A8 000A 01D6 02D3 000B 0188 02D5 0003 000A 03AC 0301 000BAgain, the active index field changes.The final record is particularly interesting:03AC 0301 000Bbecause the only value which fits the local vertex-index range is the third field.10. Main 42 12 streamThe main en05a00 geometry stream begins at approximately:0x8B14and has:control = 0x0175, 0x0004The associated vertex count is:936There are 1332 records according to the current stream analysis.A section around records 396-407 looks like:396 FFF6 0083 02B3 397 0302 0086 030D 398 0302 0071 030D 399 035A 006E 036D ... 406 035A FFF5 0081 407 02B3 0302 0080Again, this strongly suggests that the current index field is changing without necessarily having a simple explicit FFFx marker in the same field.11. Known stream controlsSome confirmed examples:en53: 42 02 control = (6, 13) records = 21 en63: 42 02 control = (33, -18) records = 105 en67: 42 02 control = (2, 3) records = 4 en78: 42 0A control = (9, -10) records = 28 en05: 42 12 control = (373, 4) records = 1332 en92: 42 02 control = (230, 3) records = 1056 en91: 42 02 control = (297, -5) records = 1300 en52: 42 0A control = (52, 35) records = 183I don't yet want to claim that these control values are counts. They may instead be part of the state/decoder parameters.12. Models testedThe same structure has been reproduced across multiple MDLs:en05a00.mdl en52a00.mdl en53a00.mdl en63a00.mdl en67a00.mdl en78a00.mdl en81a00.mdl en91a00.mdl en92a00.mdl en96a01.mdl ob_603.mdlExamples of exact vertex counts:en05 = 936 en52 = 816 en78 TYPE06 = 8 / 4 / 4 en78 TYPE16 = 39 en91 = 1571 en92 = 151813. What I needI would like help with a working Noesis Python importer, preferably something along these lines:def registerNoesisTypes(): handle = noesis.register("Resident Evil Code Veronica X HD MDL", ".mdl") noesis.setHandlerTypeCheck(handle, mdlCheckType) noesis.setHandlerLoadModel(handle, mdlLoadModel) return 1The importer should:Locate MDL blocks.Parse the 0x34-byte entry table.Locate TYPE 0x06 / TYPE 0x16 geometry entries.Resolve the vertex descriptor.Read the exact vertex count.Decode the vertex stream.Decode the face stream.Correctly distinguish triangle lists and triangle strips.Decode the UV coordinates.Build the mesh with rapi.rpg....Produce a visible mesh in Noesis.Eventually expose materials/textures and skeleton/weights.At this stage the priority is only geometry + UVs.14. Important Noesis detailI am using:Noesis 4.474The plugin environment has:rapi.rpgCreateContext() rapi.rpgConstructModel()but does NOT have:rapi.rpgDestroyContext()So a plugin written for this environment should not call rpgDestroyContext().15. Current stateThe MDL table / mesh descriptors / vertex counts / vertex locations are already reproducible.The remaining unknown is essentially:How exactly does the 42 xx face/UV stream encode its current index-field/state, and how should all of its records be converted into Noesis triangles + UVs?I would particularly appreciate either:an explanation of the 42 02 / 42 0A / 42 12 stream bitfields/state machine, ora working Noesis Python decoder for these streams.Once this is solved, the rest of the model format should be considerably easier to implement.FILES OF TEMPLATE: randalfcastro-tech/Resident-Evil-Code-Veronica-X-HD-PS3: Files of RECVXHD of PS3Thanks! Edited October 20Oct 20 by Randalf2theReturn
October 2Oct 2 Author In addition to researching the MDL format, I have found two other related formats that I believe could be important for completing animation support for *Resident Evil Code: Veronica X HD* (PS3).I have attached actual .RMT and .MTN files:* rm_9100(1).rmt — 61,504 bytes* en05ms(1).mtn — 369,152 bytesI performed an initial hex inspection, and both use a structure that begins with:00 00 XX XX 4D 54 4E 80that is:[size][MTN 80]The .RMT file contains at least two consecutive MTN blocks:offset 0x0000size 0x34DCmagic MTN 80field 0x0010000Brelative/size field 0x000034C0offset 0x34E0size 0xBB28magic MTN 80field 0x00100016relative/size field 0x0000BB0CThe .MTN file contains many consecutive MTN blocks. For example:0x0000 size 0x2B2C type 0x0010001C0x2B30 size 0x0F0C type 0x0010001C0x3A40 size 0x1598 type 0x0010001C0x4FDC size 0x2B2C type 0x0010001C...The pattern repeats throughout the file. The first few bytes of en05ms.mtn are:00 00 2B 2C4D 54 4E 8000 10 00 1C00 00 2B 10FF FF FF FF00 00 00 00C0 3F C2 A000 00 00 00...and those of rm_9100.rmt:00 00 34 DC4D 54 4E 8000 10 00 0B00 00 34 C0FF FF FF FF41 C8 00 0041 E6 66 6642 A0 00 00...The subsequent data contains numerous big-endian IEEE-754 values that appear potentially related to transformations/frames, although I do not yet want to claim they represent positions, rotations, or scales without a proven correlation.My goal is not merely to create an importer for static MDL models. I would eventually like to achieve:1. MDL → complete geometry.2. MDL → materials/textures.3. MDL → skeleton/bones.4. MDL → weights/skin.5. MTN/RMT → animations.6. The ability to correctly associate an MTN/RMT animation with the corresponding MDL skeleton.7. Importing all of this into Noesis and/or Blender while preserving the animations.That is why I would like to know if anyone is familiar with the MTN 80 structure as well, specifically:* the meaning of 0x0010000B, 0x00100016, and 0x0010001C; * the meaning of the DWORD located immediately after;* the meaning of FFFFFFFF;* the structure of the consecutive blocks;* how frames/keyframes are stored;* how bones/tracks are identified;* whether .RMT is a container for one or multiple .MTN files;* the relationship between .RMT.MTN filenames and .MDL models.Files template: Resident-Evil-Code-Veronica-X-HD-PS3/Animation+modelsmdl at main · randalfcastro-tech/Resident-Evil-Code-Veronica-X-HD-PS3I am simultaneously reverse-engineering the .MDL format for a Noesis importer, but I would also like to tackle .MTN.RMT from the start so that the final result can import models with skeletons, weights, and animations, rather than just the static mesh.If anyone has documentation, legacy code, or extraction tools, or is familiar with these formats from any version of *Biohazard*/*Resident Evil Code: Veronica*, any information would be extremely helpful. Edited October 20Oct 20 by Randalf2theReturn
October 20Oct 20 Author I thought someone would respond or have an idea about the format; I made this Noesis script although the meshes look bad, but it's a start...import struct import rapi import noesis from inc_noesis import * # ================================================================ # Resident Evil Code Veronica X HD - MDL Noesis Importer (Don't' Complete) # ================================================================ DEBUG = True UV_SCALE = 1024.0 def _u16be(data, off): if off < 0 or off + 2 > len(data): return 0 return struct.unpack_from(">H", data, off)[0] def _u32be(data, off): if off < 0 or off + 4 > len(data): return 0 return struct.unpack_from(">I", data, off)[0] def _log(msg): if DEBUG: print("[RECVX-MDL] " + msg) def _find_mdl_blocks(data): # Locate all MDL blocks based on magic headers starts = [] p = 0 while p + 4 <= len(data): tag = data[p:p + 4] if tag == b"MDL\xBC" or tag == b"MDL\xAD": starts.append(p) p += 1 blocks = [] for i in range(len(starts)): start = starts[i] end = starts[i + 1] if i + 1 < len(starts) else len(data) blocks.append((start, end)) return blocks def _find_type16_vertex_code(data, target, block_end): # Safely search for the vertex block marker 0x3300 after skipping metadata stop = min(block_end - 8, target + 0x200) p = target + 0x10 while p <= stop: if data[p:p + 2] == b"\x33\x00": count = _u32be(data, p + 4) if 0 < count < 100000: return p p += 4 return -1 def _get_mesh_entry(data, block_start, block_end, entry_off): # Validate and extract mesh entry parameters from pointers entry = block_start + entry_off if entry + 0x34 > block_end: return None mesh_type = _u32be(data, entry + 8) if mesh_type != 0x06 and mesh_type != 0x16: return None target_rel = _u32be(data, entry + 0x0C) target = block_start + target_rel if target < block_start or target + 0x18 > block_end: return None face_rel = _u32be(data, target + 0x14) face_ptr = block_start + face_rel if face_ptr < block_start or face_ptr + 0x24 > block_end: return None face_stream = face_ptr + 0x20 if face_stream + 8 > block_end or data[face_stream] != 0x42: return None if mesh_type == 0x06: v_desc_rel = _u32be(data, target + 0x10) v_desc = block_start + v_desc_rel if v_desc < block_start or v_desc + 0x54 > block_end: return None vertex_code = v_desc + 0x10 else: vertex_code = _find_type16_vertex_code(data, target, block_end) if vertex_code < 0: return None if vertex_code + 8 > block_end or data[vertex_code:vertex_code + 2] != b"\x33\x00": return None vertex_count = _u32be(data, vertex_code + 4) if vertex_count <= 0 or vertex_count > 100000: return None # Dynamic offset adjustment to avoid colliding with strings like object names vertex_data = vertex_code + 0x40 if vertex_data + vertex_count * 16 > block_end: return None stream_len = _u16be(data, face_stream + 2) if stream_len < 8 or face_stream + stream_len > block_end: return None return { "entry": entry_off, "type": mesh_type, "target": target, "vertex_code": vertex_code, "vertex_count": vertex_count, "vertex_data": vertex_data, "face_ptr": face_ptr, "face_stream": face_stream, "flag": data[face_stream + 1], "stream_len": stream_len, "stream_end": face_stream + stream_len } def _decode_face_stream(data, stream_off, stream_end, vertex_count): # Decode triangle strips and UV coordinates from the face stream payload stream_len = _u16be(data, stream_off + 2) payload_bytes = stream_len - 8 record_count = payload_bytes // 6 state = 0 strips, current_indices, current_uvs = [], [], [] for i in range(record_count): off = stream_off + 8 + i * 6 a, b, c = struct.unpack_from(">HHH", data, off) values = (a, b, c) marker_field = -1 for f in range(3): if values[f] >= 0xFF00 and f == state: marker_field = f break if marker_field < 0 and values[state] >= vertex_count: for f in range(3): if f != state and values[f] >= 0xFF00: marker_field = f break if marker_field >= 0: if len(current_indices) >= 3: strips.append((current_indices, current_uvs)) current_indices, current_uvs = [], [] state = (marker_field + 1) % 3 continue if values[state] >= vertex_count: new_state = -1 for k in (1, 2): candidate = (state + k) % 3 val = values[candidate] if val < vertex_count and val < 0xFF00: new_state = candidate break if new_state < 0: raise RuntimeError("42 state failure") state = new_state index_value = values[state] if index_value >= vertex_count: raise RuntimeError("Index out of range") uv_vals = [values[f] for f in range(3) if f != state] u = float(uv_vals[0]) / UV_SCALE v = float(uv_vals[1]) / UV_SCALE current_indices.append(index_value) current_uvs.append((u, v)) if len(current_indices) >= 3: strips.append((current_indices, current_uvs)) return strips def _read_positions(data, vertex_data, vertex_count): # Read vertex position buffers as 16-bit signed integers and scale them positions = [] for i in range(vertex_count): off = vertex_data + (i * 16) # Using a 16-byte stride if off + 6 <= len(data): # Read as Big Endian 16-bit signed integers (short) sx, sy, sz = struct.unpack_from(">3h", data, off) # Standard fixed-point scale factor for SEGA/Ninja structures scale = 4096.0 x = float(sx) / scale y = float(sy) / scale z = float(sz) / scale positions.append((x, y, z)) else: positions.append((0.0, 0.0, 0.0)) return positions def _expand_strips(positions, strips): # Expand triangle strips into individual renderable triangles out_pos, out_uvs, tri_count = [], [], 0 for indices, uvs in strips: if len(indices) < 3: continue for i in range(len(indices) - 2): # Correct index winding order to prevent flipped normals and malformed faces tri = (i, i + 1, i + 2) if (i & 1) else (i + 1, i, i + 2) ia, ib, ic = indices[tri[0]], indices[tri[1]], indices[tri[2]] if ia == ib or ib == ic or ia == ic: continue out_pos.extend([positions[ia], positions[ib], positions[ic]]) out_uvs.extend([uvs[tri[0]], uvs[tri[1]], uvs[tri[2]]]) tri_count += 1 return out_pos, out_uvs, tri_count def _collect_meshes(data): # Collect all valid mesh entries across all blocks in the file meshes, seen = [], set() blocks = _find_mdl_blocks(data) for b_idx, block in enumerate(blocks): block_start, block_end = block[0], block[1] max_scan = min(block_end - 0x34, block_start + 0x10000) for entry_abs in range(block_start, max_scan, 4): info = _get_mesh_entry(data, block_start, block_end, entry_abs - block_start) if info: key = (block_start, info["target"], info["face_stream"]) if key not in seen: seen.add(key) info["block"] = b_idx meshes.append(info) return meshes def registerNoesisTypes(): # Register plugin handlers with Noesis h = noesis.register("Resident Evil Code Veronica X HD MDL", ".mdl") noesis.setHandlerTypeCheck(h, mdlCheckType) noesis.setHandlerLoadModel(h, mdlLoadModel) return 1 def mdlCheckType(data): # Check if file contains valid MDL signatures return 1 if (b"MDL\xBC" in data or b"MDL\xAD" in data) else 0 def mdlLoadModel(data, mdlList): # Main model loading handler for Noesis ctx = rapi.rpgCreateContext() meshes = _collect_meshes(data) if not meshes: return 1 for idx, info in enumerate(meshes): try: positions = _read_positions(data, info["vertex_data"], info["vertex_count"]) strips = _decode_face_stream(data, info["face_stream"], info["stream_end"], info["vertex_count"]) draw_pos, draw_uvs, tri_count = _expand_strips(positions, strips) if tri_count <= 0 or len(draw_pos) < 3: continue pos_buf = bytearray() for x, y, z in draw_pos: pos_buf += struct.pack("<3f", x, y, z) uv_buf = bytearray() for u, v in draw_uvs: uv_buf += struct.pack("<2f", u, v) idx_buf = bytearray() for i in range(len(draw_pos)): idx_buf += struct.pack("<H", i) rapi.rpgSetName(f"MDL_{idx:02d}") rapi.rpgBindPositionBuffer(bytes(pos_buf), noesis.RPGEODATA_FLOAT, 12) rapi.rpgBindUV1Buffer(bytes(uv_buf), noesis.RPGEODATA_FLOAT, 8) rapi.rpgCommitTriangles(bytes(idx_buf), noesis.RPGEODATA_USHORT, len(draw_pos), noesis.RPGEO_TRIANGLE, 1) rapi.rpgClearBufferBinds() except Exception as e: _log(f"Mesh {idx} failed: {e}") mdl = rapi.rpgConstructModel() if mdl: mdlList.append(mdl) return 1It should be noted that the game is decompiled for PS2 at this link: "https://github.com/AshfordFamily/recvx-decomp/tree/master" also look for njCnk and NJS_CNK_OBJECT which I think are what the game manages in memory to understand the mdls within that directory with results in:[Found 'njCnk'] in: recvx-decomp-master\config\reloc_addrs.txt[Found 'njCnk'] in: recvx-decomp-master\config\symbol_addrs.txt[Found 'NJS_CNK_MODEL'] in: recvx-decomp-master\include\ps2\veronica\prog\binfunc.h[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\include\ps2\veronica\prog\door.h[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\include\ps2\veronica\prog\en03.h[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\include\ps2\veronica\prog\en13.h[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\include\ps2\veronica\prog\en22.h[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\include\ps2\veronica\prog\face.h[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\include\ps2\veronica\prog\face_bh.h[Found 'NJS_CNK_MODEL'] in: recvx-decomp-master\include\ps2\veronica\prog\hitchkl.h[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\include\ps2\veronica\prog\itemview.h[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\include\ps2\veronica\prog\map.h[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\include\ps2\veronica\prog\MdlPut.h[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\include\ps2\veronica\prog\njplus.h[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\include\ps2\veronica\prog\playpch.h[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\include\ps2\veronica\prog\ps2_NinjaCnk.h[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\include\ps2\veronica\prog\types.h[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\binfunc.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\cut.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\door.c[Found 'njCnk'] in: recvx-decomp-master\src\ps2\veronica\prog\effect.c[Found 'eval'] in: recvx-decomp-master\src\ps2\veronica\prog\effsub1.c[Found 'njCnk'] in: recvx-decomp-master\src\ps2\veronica\prog\effsub1b.c[found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\effsub2.c[Found 'NJS_CNK_MODEL'] in: recvx-decomp-master\src\ps2\veronica\prog\effsub3.c[Found 'njCnk'] in: recvx-decomp-master\src\ps2\veronica\prog\effsub4.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en01.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en01b.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en01sub.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en03.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en04.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en05.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en06.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en07.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en09.c[found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en11.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en12.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en13.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en14.c[Found 'model'] in: recvx-decomp-master\src\ps2\veronica\prog\en15.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en17.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en17sub.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en18.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en19.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en22.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en23.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en26.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\en30.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\event.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\face_bh.c[Found 'njCnk'] in: recvx-decomp-master\src\ps2\veronica\prog\game.c[Found 'NJS_CNK_MODEL'] in: recvx-decomp-master\src\ps2\veronica\prog\hitchkl.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\itemview.c[Found 'njCnk'] in: recvx-decomp-master\src\ps2\veronica\prog\light.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\map.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\MdlPut.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\Motion.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\njplus.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\objitm.c[Found 'eval'] in: recvx-decomp-master\src\ps2\veronica\prog\player.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\playpch.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\ps2_NinjaCnk.c[Found 'njCnk'] in: recvx-decomp-master\src\ps2\veronica\prog\screen.c[Found 'njCnk'] in: recvx-decomp-master\src\ps2\veronica\prog\sp_evt.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\weapon.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\zonzon.c[Found 'NJS_CNK_OBJECT'] in: recvx-decomp-master\src\ps2\veronica\prog\zonzon1.cI also found this Blender script for the PS2 version: https://github.com/kapdap/re-cvx-blender/tree/main, but it only works for environments—not for the mdl files used in the high-resolution PS3 version. I’ve been using the ARC extractor from https://github.com/kapdap/re-cvx-tools, along with Kuriimu2 for the textures. However, the models are in mdl format, and the animations—once converted—are in mnt or rmt format. How can I go about converting these, or perhaps creating a functional parser that reads the mesh indices and correctly displays the model, including the skeleton weights and the actual UVs?The main problem is that the vertex positions in PS3 models come with a transformation vector or local bone matrix per sub-mesh, or the position floats are preceded by skinning weight data even in static objects.If we apply an identity matrix or tell Noesis to ignore the weight bytes before each coordinate, the model should end up assembling its 3D volume completely.If anyone could help me with this, I would be truly grateful. Edited October 20Oct 20 by Randalf2theReturn
Create an account or sign in to comment