May 18May 18 Localization I wanted to be able to modify the model, or convert it. I tried to get Noesis to read it, or Blender, but it doesn't work. It doesn't looks complex. If anyone can help, I would be grateful. PL01.zip
May 18May 18 Localization The structure of the first 3/4 or so of the file is something like this (in ImHex Pattern Language). More sample files would make analyzing the rest of it easier. struct Vertex { float position[3]; float normal[3]; float uv[2]; float bone_weights[3]; s16 bone_indices[4]; } [[single_color]]; struct Bone { u8 bytes[76]; } [[single_color]]; struct Mesh { u32 vertex_count; Vertex vertices[vertex_count]; u32 tri_idx_count; u16 tri_strip_indices[tri_idx_count]; u32 bone_count; Bone bones[bone_count]; }; struct File { u32 mesh_count; Mesh meshes[mesh_count]; }; File file_at_0x00 @ 0x00; Edited May 18May 18 by jmancoder
May 19May 19 Author Localization 1 hour ago, shak-otay said: Did a quick check: Here's two more samples to help. Also, the textures from the models are inside them, in DDS format Samples2.zip
May 19May 19 Supporter PL02 seems to have 4 sub meshes, so you'll have to wait for a script. With textures I had no luck:
May 19May 19 Supporter //------------------------------------------------ //--- 010 Editor v14.0 Binary Template // // File: Tenchu: Return from Darkness // Authors: // Version: // Purpose: // Category: // File Type: *.s4 // ID Bytes: // History: //------------------------------------------------ LittleEndian();OutputPaneClear(); local uint32 i,j,k,l,ElementBaseOffset,IndexBaseOffset; uint32 MeshCount; struct { uint32 TotalElementCount; ElementBaseOffset=FTell(); byte Elements[TotalElementCount * 52]; uint32 TotalIndexCount; IndexBaseOffset=FTell(); ushort Indices[TotalIndexCount]; uint32 ShapeCount; struct { uint16 IndexOffset,IndexCount; uint32 ElementOffset,ElementCount; ubyte Unknown_0,Unknown_1,Unknown_2,Unknown_3; ubyte Unknown_4,Unknown_5,Unknown_6,Unknown_7; uint16 Unknown_8; ubyte Unknown_9; string ShapeName; FSeek(startof(ShapeName)); FSkip(16); string TextureName; FSeek(startof(ShapeName)); FSkip(53); }Shape[ShapeCount]<optimize=false>; }Mesh[MeshCount]<optimize=false>; struct { uint32 BoneIndex; struct { string Name0; FSeek(startof(Name0)); FSkip(32); string Name1; FSeek(startof(Name1)); FSkip(32); ubyte BoneData[208]; }Bone[BoneIndex]<optimize=false>; }Skeleton; struct { uint32 Null; uint32 TextureDataSize; uint32 TextureIndex; struct { uint32 TextureSize; string TextureName; FSeek(startof(TextureName)); FSkip(32); }TextureInfo[TextureIndex]<optimize=false>; struct { for (i=0; i < TextureIndex; i++) struct { byte TextureData[TextureInfo[i].TextureSize]; }Texture; }TextureData; }Textures; I didn't bother with skeleton, but should be easy. Well first part done. Now assign textures and skeleton UV's are fine. I dissabled LODs and shadow. Now it loads textures from file instead of externaly. Also i parsed skeleton but there are 2 more Transform 4x4 so not sure which one is right one. Edited May 23May 23 by h3x3r
May 23May 23 Supporter Solution Here's Noesis script. But without skeleton. I have no idea how to assign. from inc_noesis import * import noesis import rapi import os def registerNoesisTypes(): handle = noesis.register("Tenchu: Return from Darkness - Mesh", ".s4") noesis.setHandlerTypeCheck(handle, noepyCheckType) noesis.setHandlerLoadModel(handle, noepyLoadModel) noesis.logPopup() return 1 def noepyCheckType(data): bs = NoeBitStream(data) if len(data) < 20: return 0 return 1 def noepyLoadModel(data, mdlList): bs = NoeBitStream(data) baseName = rapi.getExtensionlessName(rapi.getLocalFileName(rapi.getInputName())) ctx = rapi.rpgCreateContext() Underline = "_" TextureNameList = [] TextureList = [] MaterialList = [] MeshIndex = bs.readUInt() MeshBaseOffset = bs.tell() # Skiping buffers for i in range(0, MeshIndex): TECount = bs.readUInt() bs.read(TECount * 52) TICount = bs.readUInt() bs.read(TICount * 2) SCount = bs.readUInt() bs.read(SCount * 76) # Skeleton BoneIndex = bs.readUInt() #print(BoneIndex) for b in range(0, BoneIndex): BNameStrPos = bs.tell() BoneName = bs.readString() bs.seek(BNameStrPos, NOESEEK_ABS) bs.read(32) PBNameStrPos = bs.tell() ParentBoneName = bs.readString() bs.seek(PBNameStrPos, NOESEEK_ABS) bs.read(32) Transform4x4_0 = bs.read(64) Transform4x4_1 = bs.read(64) Transform4x4_2 = bs.read(64) BoneIndex = bs.readInt() ParentIndex = bs.readInt() Unknown_0 = bs.readUInt() Unknown_1 = bs.readUInt() # Texture info bs.read(4) TextureDataSize = bs.readUInt() TextureIndex = bs.readUInt() for t in range(0, TextureIndex): TextureSize = bs.readUInt() TexNamePos = bs.tell() TextureNameList.append(bs.readString()) bs.seek(TexNamePos, NOESEEK_ABS) bs.read(32) # Texture data for t in range(0, TextureIndex): TextureName = TextureNameList[t] bs.read(12) TextureWidth = bs.readUInt() TexstureHeight = bs.readUInt() TextureDataSize = bs.readUInt() bs.read(60) PixelFormat = bs.readUInt() bs.read(40) TextureBuffer = bs.read(TextureDataSize) if PixelFormat == 894720068: Texture = NoeTexture(TextureName, TextureWidth, TexstureHeight, TextureBuffer, noesis.NOESISTEX_DXT5) elif PixelFormat == 827611204: Texture = NoeTexture(TextureName, TextureWidth, TexstureHeight, TextureBuffer, noesis.NOESISTEX_DXT1) TextureList.append(Texture) bs.seek(MeshBaseOffset, NOESEEK_ABS) for m in range(0, MeshIndex): TotalElementCount = bs.readUInt() ElementBaseOffset = bs.tell(); ElementBuffer = bs.read(TotalElementCount * 52) TotalIndexCount = bs.readUInt() IndexBaseOffset = bs.tell(); bs.read(TotalIndexCount * 2) rapi.rpgBindPositionBufferOfs(ElementBuffer, noesis.RPGEODATA_FLOAT, 52, 0) rapi.rpgBindNormalBufferOfs(ElementBuffer, noesis.RPGEODATA_FLOAT, 52, 12) rapi.rpgBindUV1BufferOfs(ElementBuffer, noesis.RPGEODATA_FLOAT, 52, 24) rapi.rpgBindBoneWeightBufferOfs(ElementBuffer, noesis.RPGEODATA_FLOAT, 52, 32, 3) rapi.rpgBindBoneIndexBufferOfs(ElementBuffer, noesis.RPGEODATA_SHORT, 52, 44, 4) ShapeIndex = bs.readUInt() for s in range(0, ShapeIndex): IndexOffset = bs.readUShort() * 2 IndexCount = bs.readUShort() + 2 ElementOffset = bs.readUInt() ElementCount = bs.readUInt() MaterialIndex = bs.readUByte() bs.read(2) HasNoUV = bs.readUByte() bs.read(4) IsLOD = bs.readUShort() bs.read(1) ShapeNameCurPos = bs.tell() ShapeName = bs.readString() bs.seek(ShapeNameCurPos, NOESEEK_ABS) bs.read(16) TextureNameCurPos = bs.tell() TextureName = bs.readString() bs.seek(TextureNameCurPos, NOESEEK_ABS) bs.read(37) cPos = bs.tell() ShapeId = "{:04d}".format(s) Material = NoeMaterial(TextureName, TextureName) MaterialList.append(Material) rapi.rpgSetMaterial(TextureName) rapi.rpgSetName(baseName + Underline + ShapeName + Underline + ShapeId) bs.seek(IndexBaseOffset + IndexOffset, NOESEEK_ABS) IndexBuffer = bs.read(IndexCount * 2) if IsLOD != 3 and HasNoUV != 1: rapi.rpgCommitTriangles(IndexBuffer, noesis.RPGEODATA_USHORT, IndexCount, noesis.RPGEO_TRIANGLE_STRIP) bs.seek(cPos, NOESEEK_ABS) mdl = rapi.rpgConstructModel() mdl.setModelMaterials(NoeModelMaterials(TextureList, MaterialList)) mdlList.append(mdl) return 1 Edited May 23May 23 by h3x3r
May 24May 24 Supporter Well, the hierarchy (taken from the script, with some corrections) is too confusing to me. -1 "root" 1 0 "EX-00 "2 1 "00-jnt" 3 2 "01-jnt" 4 3 "04-jnt" 5 4 "05-jnt" 6 5 "06-jnt" 7 6 "07-jnt" 8 7 "EX-03 "9 8 "EX-04 "-1 9 "08-jnt" 11 10 "09-jnt" 12 11 "10-jnt" 13 12 "11-jnt" 14 13 "EX-05 "15 14 "EX-06 "-1 15 "02-jnt" 17 16 "03-jnt" -1 17 "12-jnt" 19 18 "13-jnt" 20 19 "14-jnt" 21 20 "15-jnt" 22 21 "16-jnt" 23 22 "EX-01 "-1 23 "17-jnt" -1 24 "18-jnt" 26 25 "19-jnt" 27 26 "20-jnt" 28 27 "21-jnt" 29 28 "EX-02 "-1 29 "22-jnt" -1 Rearranging doesn't do better (where it's unclear whether to take the boneID from the script, first column or the joint number, 4 form 04-jnt, for example) -1 "root" 1 1 "00-jnt" 3 2 "01-jnt" 4 15 "02-jnt" 17 16 "03-jnt" -1 3 "04-jnt" 5 4 "05-jnt" 6 5 "06-jnt" 7 6 "07-jnt" 8 9 "08-jnt" 11 10 "09-jnt" 12 11 "10-jnt" 13 12 "11-jnt" 14 17 "12-jnt" 19 18 "13-jnt" 20 19 "14-jnt" 21 20 "15-jnt" 22 21 "16-jnt" 23 23 "17-jnt" -1 24 "18-jnt" 26 25 "19-jnt" 27 26 "20-jnt" 28 27 "21-jnt" 29 29 "22-jnt" -1 0 "EX-00 "2 22 "EX-01 "-1 28 "EX-02 "-1 7 "EX-03 "9 8 "EX-04 "-1 13 "EX-05 "15 14 "EX-06 "-1
Create an account or sign in to comment