ZenHAX

Free Game Research Forum | Official QuickBMS support | twitter @zenhax | SSL HTTPS://zenhax.com
It is currently Tue Jun 19, 2018 10:12 pm

All times are UTC




Post new topic  Reply to topic  [ 3 posts ] 
Author Message
PostPosted: Fri Jun 08, 2018 11:51 am 

Joined: Fri Jun 08, 2018 11:37 am
Posts: 2
Here is the first version of Recolove Model Importer for Noesis.
It loads mesh data (vertex, face, normals and UVs) from a *.fed model.

fmt_recolove_fed.py:
Code:
# v2: Fixed face direction and UV
import math
from inc_noesis import *


def registerNoesisTypes():
    """ register plugin
    """
    handle = noesis.register("Recolove Model", ".fed")
    noesis.setHandlerTypeCheck(handle, fedCheckType)
    noesis.setHandlerLoadModel(handle, fedLoadModel)

    # noesis.logPopup()  # show console
    return 1


def fedCheckType(data):
    """ check header
    """
    FED_HEADER = 0x43415046  # FPAC
    bs = NoeBitStream(data)
    bs.seek(0)
    if bs.readInt() != FED_HEADER:
        return 0
    return 1


def fedLoadModel(data, mdlList):
    """ load model (mesh and UV)
    """
    bs = NoeBitStream(data)
    meshes = []
    myMeshes = []

    # find face sets. eg. (0, 1, 2)
    bs.seek(0)
    while not bs.checkEOF():
        firstFace = (bs.readUShort(), bs.readUShort(), bs.readUShort())
        tailVals = (bs.readUShort(), bs.readUShort(), bs.readUShort(),
                    bs.readUShort(), bs.readUShort())
        if (firstFace == (0, 1, 2) and sum(tailVals) < 30):
            myMeshes.append({"faceOffset": bs.tell() - 16})
    if len(myMeshes) == 0:
        print("no face sets.")
        return 0

    # find face counts
    for myMesh in myMeshes:
        isFound = False
        ofs = myMesh["faceOffset"]
        while True:
            ofs -= 16  # go up
            if isFound:
                break
            if ofs < 0:
                print("face count not found.")
                return 0
            bs.seek(ofs)
            numFaceX3 = bs.readUShort()
            bs.readUShort()  # unknown
            magic1C = bs.readInt()
            magicZero1 = bs.readInt64()
            numVert = bs.readInt()
            magicZero2 = bs.readInt()
            magicZero3 = bs.readInt64()
            if (numFaceX3 % 3 == 0 and magic1C == 0x1C and magicZero1 == 0 and magicZero2 == 0 and magicZero3 == 0):
                isFound = True
                myMesh["numFace"] = numFaceX3 // 3
                myMesh["numVert"] = numVert
                myMesh["vertOffset"] = bs.tell()

    for myMesh in myMeshes:
        print(myMesh)

        verts = []
        bs.seek(myMesh["vertOffset"])
        for i in range(myMesh["numVert"]):
            x = _getFloat(bs)
            y = _getFloat(bs)
            z = _getFloat(bs)
            verts.append(NoeVec3((x, y, z)))
        _padding(bs)

        normals = []
        for i in range(myMesh["numVert"]):
            x = _getFloat(bs)
            y = _getFloat(bs)
            z = _getFloat(bs)
            normals.append(NoeVec3((x, y, z)))
        _padding(bs)

        if bs.readBytes(4)[3] == 0xFF:  # Skip, may be weights
            bs.seek(-4, NOESEEK_REL)
            bs.readBytes(myMesh["numVert"] * 4)
            _padding(bs)

        uvs = []
        for i in range(myMesh["numVert"]):
            u = _getFloat(bs)
            v = _getFloat(bs) + 1.0
            uvs.append(NoeVec3((u, v, 0.0)))
        _padding(bs)

        if bs.tell() != myMesh["faceOffset"]:
            print("  SKIP: UV exceeds faceOffset: %d" % bs.tell())
            continue

        idxList = []
        for i in range(myMesh["numFace"]):
            indices = (bs.readUShort(), bs.readUShort(), bs.readUShort())
            idxList.append(indices[2])
            idxList.append(indices[1])
            idxList.append(indices[0])
        _padding(bs)

        meshName = "mesh_%08X" % myMesh["vertOffset"]
        mesh = NoeMesh(idxList, verts, meshName)
        mesh.setNormals(normals)
        mesh.setUVs(uvs)
        meshes.append(mesh)

    mdlList.append(NoeModel(meshes))
    return 1


def _getFloat(bs: NoeBitStream):
    """ get float value, skipping NaN
    """
    val = bs.readFloat()
    if not math.isnan(val):
        return val
    else:
        return bs.readFloat()


def _padding(bs: NoeBitStream):
    """ padding by 16 bytes
    """
    mod = bs.tell() % 16
    if mod != 0:
        bs.readBytes(16 - mod)


You will also need to use the following tools.

1. CPK Unpacker (to obtain fed files):
https://github.com/esperknight/CriPakTo ... ster/Build

2. QuickBMS and this script (to extract *.tex files):
http://aluigi.altervista.org/bms/fpactex.bms

3. Texture Unpacker (to convert textures):
https://github.com/xdanieldzd/GXTConvert/releases


Last edited by kana4567 on Mon Jun 18, 2018 11:29 am, edited 2 times in total.

Top
   
PostPosted: Sat Jun 16, 2018 12:44 pm 

Joined: Sat Jun 16, 2018 12:31 pm
Posts: 1
I got recolove dumped data.
When I tried to expand. cpk with cripaktools, I could not extract it by saying cannnot find ALL.
https://imgur.com/a/uiwQ6pB
Is it necessary to decrypt it?
This is the .cpk file i got.
https://mega.nz/#!kIFDSIQI!x-CBWFLmHYyu ... QZDmAJC5JY


Top
   
PostPosted: Mon Jun 18, 2018 11:13 am 

Joined: Fri Jun 08, 2018 11:37 am
Posts: 2
Yes, you have to decrypt game files by using a tool like this:
https://github.com/motoharu-gosuto/psvpfstools/releases


Top
   
Display posts from previous:  Sort by  
Post new topic  Reply to topic  [ 3 posts ] 

All times are UTC


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Limited