Kingdom Hearts: Final Mix Translation Patch (In progress)

Discussion in 'Code Vault' started by Trilix, Feb 20, 2012.

  1. Hidden Smithery King's Apprentice

    Joined:
    Feb 2, 2010
    81
    452
    So I just hex edit the ISO directly again? :|
     
  2. crazycatz00 Twilight Town Denizen

    Joined:
    Apr 12, 2013
    40
    236
    No, extract the file and edit that. Or use my attached file.

    Edit:
    Found a 2nd font in the game, "kanji.knj", used for journal entries. It seems to be a different format then the sysfont (and evt-font from KH2), so I can't edit it yet. (and the English one cuts stuff in half, of course -.-)

    Edit: Attachment deleted.
     
  3. root670 Destiny Islands Resident

    Joined:
    Feb 28, 2013
    5
    52
    For a look at how 3D models and textures are stored, take a look at the source for the Noesis KH plugin. The textures in particular aren't your typical TIM2 images; they use their own format. Here's a link to the plugin w/ the source included: http://oasis.xentax.com/files/plug/kingdom_hearts.zip. Below is the meat of the plugin
    Code:
    //this is kind of a poor example for plugins, since the format's not totally known and the code is WIP.
    //but it does showcase some interesting usages.
     
    #include "stdafx.h"
     
    mathImpFn_t *g_mfn = NULL;
    noePluginFn_t *g_nfn = NULL;
     
    #pragma pack(push, 1)
     
    typedef  unsigned char    uint8;
    typedef  unsigned short  uint16;
    typedef  unsigned long    uint32;
    typedef  unsigned __int64 uint64;
    typedef  signed  char    int8;
    typedef  signed  short  int16;
    typedef  signed  long    int32;
    typedef  signed  __int64 int64;
     
    struct MDLS_MOBJ_HEADER
    {
    // 0x00
    uint32 dataTag; // 'MOBJ'
    uint32 dataSize;
    uint32 imageInfoOffset;
    uint32 imageInfoSize;
    // 0x10
    uint32 imageOffset;
    uint32 imageSize;
    uint32 clutOffset;
    uint32 clutSize;
    // 0x20
    uint32 meshDataOffset;
    uint32 meshDataSize;
    uint32 unknownOffset0x28;
    uint32 unknownSize0x2C;
    // 0x30
    uint32 unknown0x30;
    uint32 unknown0x34[3];
    };
     
    struct MDLS_IMAGE_INFO
    {
    uint16 dataSize; // image data size / 16
    uint8  w_exp;    // width exponent (2^w)
    uint8  h_exp;    // height exponent (2^h)
    uint16 width;
    uint16 height;
    uint32 unknown0x0C[2];
    };
     
    struct MDLS_MODEL_HEADER
    {
    // 0x00
    uint32 jointCount;
    uint32 jointDataOffset;
    uint32 unknownOffset0x08;
    uint32 meshCount;
    };
     
    struct MDLS_JOINT_BLOCK
    {
    // 0x00
    uint32 dataTag;
    uint32 jointIndex;
    uint32 tableIndex;
    uint32 unknown0x0C;
    // 0x10
    uint32 unknown0x10[28];
    };
     
    struct MDLS_MESH_ENTRY
    {
    uint32 unknown0x00; // unk, object id, unk, unk
    uint32 unknown0x04; // texture index
    uint32 unknown0x08; // texture index
    uint32 dataOffset;
    };
     
    struct MDLS_VERTEX
    {
    // 0x00
    float  normal[3];
    uint32 jointIndex;
    // 0x10
    float  position[3];
    float  jointWeight;
    // 0x20
    float  textureCoord[3];
    uint32 unknown0x2C; // ?
    };
     
    struct MDLS_VERTEX_BLOCK
    {
    // 0x00
    uint32 dataTag;
    uint32 dataSize;
    uint32 vertexCount0;
    uint32 unknown0x0C;
    // 0x10
    uint32 vertexCount1;
    uint32 unknown0x14;
    uint32 unknown0x18;
    uint32 unknown0x1C;
    // 0x20
    //struct MDLS_VERTEX vertices[vertexCount0];
    };
     
    struct MDLS_MODEL_JOINT
    {
    float  scale[3];
    uint32 index;
     
    float  rotation[3];
    uint32 padding;
     
    float  position[3];
    int32  parent  : 10;
    int32  sibling : 10;
    int32  child  : 10;
    int32  unk1    :  2;
    };
     
    struct MDLS_MATRIX_BLOCK
    {
    // 0x00
    uint32 dataTag;
    uint32 dataSize;
    uint32 lineCount;
    uint32 unknown0x0C;
    // 0x10
    uint32 matrixIndices[1];
    };
     
    #pragma pack(pop)
     
    //see if something is valid KH .mdls data
    bool Model_KH_Check(BYTE *fileBuffer, int bufferLen, noeRAPI_t *rapi)
    {
    if (bufferLen < (sizeof(MDLS_MOBJ_HEADER) + 8))
    {
    return false;
    }
     
    // read mobj data offset
    uint32 mobjOffset = *((uint32*)(fileBuffer + 4));
     
    if (bufferLen < (sizeof(MDLS_MOBJ_HEADER) + mobjOffset))
    {
    return false;
    }
     
    uint8 *mobjData = (fileBuffer + mobjOffset);
     
    MDLS_MOBJ_HEADER *mobjHeader = (MDLS_MOBJ_HEADER *)(mobjData);
     
    if (mobjHeader->dataTag != 0x4A424F4D)
    {
    return false;
    }
     
    if ((bufferLen < (mobjHeader->dataSize + mobjOffset)) ||
    (mobjHeader->imageInfoOffset > 0 && bufferLen < (mobjHeader->imageInfoOffset + mobjOffset)) ||
    (mobjHeader->imageOffset    > 0 && bufferLen < (mobjHeader->imageOffset    + mobjOffset)) ||
    (mobjHeader->clutOffset      > 0 && bufferLen < (mobjHeader->clutOffset      + mobjOffset)) ||
    (mobjHeader->meshDataOffset  > 0 && bufferLen < (mobjHeader->meshDataOffset  + mobjOffset)))
    {
    return false;
    }
     
    return true;
    }
     
    //load texture bundle
    static void Model_KH_LoadTextures(CArrayList<noesisTex_t *> &textures, CArrayList<noesisMaterial_t *> &materials, BYTE *data, int dataSize, noeRAPI_t *rapi)
    {
    MDLS_MOBJ_HEADER *mobjHeader = (MDLS_MOBJ_HEADER *)(data);
     
    char matName[128] = {0};
     
    noesisTex_t *nt = NULL;
    noesisMaterial_t *nmat = NULL;
     
    // calculate texture count
    int textureCount = mobjHeader->imageInfoSize >> 4;
    if (textureCount > 0)
    {
    // calculate image data offsets
    uint8 *imageInfo = (data + mobjHeader->imageInfoOffset);
    uint8 *imageData = (data + mobjHeader->imageOffset);
    uint8 *clutData  = (data + mobjHeader->clutOffset);
     
    // read texture information
    int texNum = 0;
    for (texNum = 0; texNum < textureCount; ++texNum, imageInfo += sizeof(MDLS_IMAGE_INFO), clutData  += 0x400)
    {
    MDLS_IMAGE_INFO &info = *((MDLS_IMAGE_INFO*)imageInfo);
     
    int imageSize = (info.dataSize << 4);
     
    uint8 *tempImage = (uint8 *)rapi->Noesis_UnpooledAlloc(info.width * info.height * 4);
    uint8 *dstPixel = tempImage;
     
    int pixelNum = 0;
    for (pixelNum = 0; pixelNum < imageSize; ++pixelNum, ++imageData, dstPixel += 4)
    {
    uint32 pixelIndex = *imageData;
     
    if ((pixelIndex & 31) >= 8)
    {
    if ((pixelIndex & 31) < 16)
    {
    pixelIndex += 8; // +8 - 15 to +16 - 23
    }
    else if ((pixelIndex & 31) < 24)
    {
    pixelIndex -= 8; // +16 - 23 to +8 - 15
    }
    }
     
    pixelIndex <<= 2;
     
    dstPixel[0] =  clutData[pixelIndex + 0];
    dstPixel[1] =  clutData[pixelIndex + 1];
    dstPixel[2] =  clutData[pixelIndex + 2];
    dstPixel[3] = (clutData[pixelIndex + 3] * 0xFF) >> 7;
    }
     
    // create texture
    sprintf_s(matName, 128, "texture%03d", texNum);
    nt = rapi->Noesis_TextureAlloc(matName, info.width, info.height, tempImage, NOESISTEX_RGBA32);
    nt->shouldFreeData = true;
    textures.Append(nt);
     
    sprintf_s(matName, 128, "material%03d", texNum);
    nmat = rapi->Noesis_GetMaterialList(1, true);
    nmat->name = rapi->Noesis_PooledString(matName);
    nmat->noDefaultBlend = false;
    nmat->noLighting = true;
    nmat->texIdx = texNum;
    materials.Append(nmat);
    }
    }
    }
     
    #define PI (3.1415926535897932384626433832795)
    #define DEG2RAD(a) ((a) * PI / 180.0)
    #define RAD2DEG(a) ((a) * 180.0 / PI)
     
    //convert the bones
    modelBone_t *Model_KH_CreateBones(BYTE *data, noeRAPI_t *rapi, int &numBones)
    {
    MDLS_MOBJ_HEADER *mobjHeader = (MDLS_MOBJ_HEADER *)(data);
     
    uint8 *modelData = (data + mobjHeader->meshDataOffset);
     
    MDLS_MODEL_HEADER *modelHeader = (MDLS_MODEL_HEADER*)modelData;
     
    numBones = 0;
     
    if (modelHeader->jointCount > 0)
    {
    uint8 *jointData = (modelData + modelHeader->jointDataOffset);
     
    // save joint count...
    numBones = modelHeader->jointCount;
    // ...and allocate joint data
    modelBone_t *bones = rapi->Noesis_AllocBones(numBones);
    modelBone_t *bone = bones;
     
    modelMatrix_t sclMatrix = g_identityMatrix;
    modelMatrix_t xMatrix = g_identityMatrix;
    modelMatrix_t yMatrix = g_identityMatrix;
    modelMatrix_t zMatrix = g_identityMatrix;
    modelMatrix_t rotMatrix = g_identityMatrix;
     
    MDLS_MODEL_JOINT *joint = (MDLS_MODEL_JOINT*)jointData;
     
    int jointNum = 0;
    for (jointNum = 0; jointNum < numBones; ++jointNum, ++joint, ++bone)
    {
    bone->index = jointNum;
    sprintf_s(bone->name, 30, "bone%03i", jointNum);
     
    // copy joint information
    sclMatrix.x1[0] = joint->scale[0];
    sclMatrix.x2[1] = joint->scale[1];
    sclMatrix.x3[2] = joint->scale[2];
     
    rotMatrix = g_identityMatrix;
    g_mfn->Math_RotateMatrix(&rotMatrix, RAD2DEG(-joint->rotation[2]), 0, 0, 1);
    g_mfn->Math_RotateMatrix(&rotMatrix, RAD2DEG( joint->rotation[1]), 0, 1, 0);
    g_mfn->Math_RotateMatrix(&rotMatrix, RAD2DEG(-joint->rotation[0]), 1, 0, 0);
    g_mfn->Math_MatrixMultiply(&sclMatrix, &rotMatrix, &bone->mat);
    // g_mfn->Math_RotationMatrix( joint->rotation[0], 0, &xMatrix);
    // g_mfn->Math_RotationMatrix(-joint->rotation[1], 1, &yMatrix);
    // g_mfn->Math_RotationMatrix( joint->rotation[2], 2, &zMatrix);
    // g_mfn->Math_MatrixMultiply(&zMatrix,  &yMatrix,  &rotMatrix);
    // g_mfn->Math_MatrixMultiply(&rotMatrix, &xMatrix,  &zMatrix);
    // g_mfn->Math_MatrixMultiply(&zMatrix,  &sclMatrix, &bone->mat);
     
    g_mfn->Math_VecCopy(joint->position, bone->mat.o);
     
    bone->eData.parent = (joint->parent < 0) ? NULL : (bones + joint->parent);
    }
     
    // transform bones
    rapi->rpgMultiplyBones(bones, numBones);
    return bones;
    }
     
    return NULL;
    }
     
    //load a single model from a dat set
    static void Model_KH_LoadModel(BYTE* data, CArrayList<noesisTex_t *> &textures, CArrayList<noesisMaterial_t *> &materials, modelBone_t *bones, int numBones, noeRAPI_t *rapi)
    {
    MDLS_MOBJ_HEADER *mobjHeader = (MDLS_MOBJ_HEADER *)(data);
     
    uint8 *modelData = (data + mobjHeader->meshDataOffset);
     
    MDLS_MODEL_HEADER *modelHeader = (MDLS_MODEL_HEADER*)modelData;
     
    // process mesh information
    if (modelHeader->meshCount > 0)
    {
    uint8 *meshInfo = (modelData + 0x10);
     
    MDLS_MESH_ENTRY *meshEntries = (MDLS_MESH_ENTRY*)meshInfo;
     
    int meshCount = modelHeader->meshCount;
     
    char meshName[128] = {0};
    int meshCnt = 0;
     
    int meshNum = 0;
    for (meshNum = 0; meshNum < meshCount; ++meshNum, ++meshEntries)
    {
    rapi->rpgSetMaterialIndex(meshEntries->unknown0x04);
     
    uint8 *meshStart = (meshInfo + meshEntries->dataOffset);
     
    uint32 vertexCount = 0;
    uint32 faceCount = 0;
     
    MDLS_MATRIX_BLOCK *matrixPalette = NULL;
    uint32 matrixIndices[16] = {0};
     
    uint32 tableSize = 0;
    uint32 extraMax = 0;
    uint32 extraCount = 0;
    uint32 nextOffset = 0;
    do
    {
    uint32 dataTag = *((uint32*)meshStart);
    switch (dataTag)
    {
    case 0:
    {
    uint32 jointIndex  = *((uint32*)(meshStart + 0x04));
    uint32 tableIndex0 = *((uint32*)(meshStart + 0x08));
    uint32 tableIndex1 = *((uint32*)(meshStart + 0x0C));
     
    if (tableIndex1 == 0)
    {
    matrixIndices[tableIndex0] = jointIndex;
    }
     
    if (tableIndex1 > 0)
    {
    if (tableIndex1 == 1)
    tableSize = 0;
    matrixIndices[tableSize + 8] = jointIndex;
    ++tableSize;
    }
     
    nextOffset = 0x80;
    }
    break;
    case 1:
    {
    nextOffset = *((uint32*)(meshStart + 4));
     
    MDLS_VERTEX_BLOCK *vertexBlock = (MDLS_VERTEX_BLOCK*)meshStart;
     
    if (vertexBlock->dataSize > 0 && vertexBlock->vertexCount0 > 0)
    {
    uint8 *vertexStart = (meshStart + 0x20);
     
    CArrayList<modelVert_t> vertices;
    CArrayList<modelVert_t> normals;
    CArrayList<modelTexCoord_t> texCoords;
     
    uint32 numVertices = vertexBlock->vertexCount0;
    uint32 vertexNum = 0;
    rapi->rpgBegin(RPGEO_TRIANGLE_STRIP);
    for (vertexNum = 0; vertexNum < numVertices; ++vertexNum)
    {
    uint32 jointInfo = *((uint32*)(vertexStart + 0x0C));
    uint32 jointIndex = 0;
    uint32 positionCount = 1;
     
    uint8 *normalStart = vertexStart;
    vertexStart += 0x10;
     
    uint8 *positionStart = vertexStart;
    if (matrixPalette)
    {
    positionCount = jointInfo;
    vertexStart += 0x10 * jointInfo;
    }
    else
    {
    vertexStart += 0x10;
    }
     
    uint8 *uvStart = vertexStart;
    vertexStart += 0x10;
     
    CArrayList<DWORD> boneIndices;
    CArrayList<float> boneWeights;
     
    uint32 posNum = 0;
    float position[4] = {0};
    float temp[4] = {0};
    modelBone_t *bone = NULL;
    fourxMatrix_t jointMatrix = g_identityMatrix4x4;
    fourxMatrix_t vertexMatrix = g_identityMatrix4x4;
    fourxMatrix_t outputMatrix = g_identityMatrix4x4;
    for (posNum = 0; posNum < positionCount; ++posNum, ++extraCount)
    {
    if (matrixPalette)
    {
    jointIndex = matrixPalette->matrixIndices[extraCount];
    if (jointIndex < 0x100)
    jointIndex = matrixIndices[jointIndex];
    else
    {
    jointIndex = ((jointIndex & 0xFF) >> 3);
    matrixIndices[2] = matrixIndices[jointIndex + 8];
    jointIndex = matrixIndices[2];
    }
    }
    else
    {
    jointIndex = matrixIndices[jointInfo];
    }
    bone = bones + jointIndex;
    memcpy(vertexMatrix.c4, (float*)positionStart, sizeof(vertexMatrix.c4));
    g_mfn->Math_ModelMatToGL(&bone->mat, (float*)(&jointMatrix));
    g_mfn->Math_MatrixMultiply4x4(&vertexMatrix, &jointMatrix, &outputMatrix);
    g_mfn->Math_VecAdd(outputMatrix.c4, position, position);
     
    boneIndices.Append(jointIndex);
    boneWeights.Append(vertexMatrix.c4[3]);
     
    positionStart += 0x10;
    }
    normals.Append(*((modelVert_t*)normalStart));
    texCoords.Append(*((modelTexCoord_t*)uvStart));
    vertices.Append(*((modelVert_t*)position));
    if (vertexNum == 0 &&
    vertexBlock->unknown0x0C != 0)
    {
    rapi->rpgVertBoneIndexUI(&boneIndices[0], boneIndices.Num());
    rapi->rpgVertBoneWeightF(&boneWeights[0], boneWeights.Num());
    rapi->rpgVertNormal3f((float*)normalStart);
    rapi->rpgVertUV2f((float*)uvStart, 0);
    rapi->rpgVertex3f((float*)position);
    }
    rapi->rpgVertBoneIndexUI(&boneIndices[0], boneIndices.Num());
    rapi->rpgVertBoneWeightF(&boneWeights[0], boneWeights.Num());
    rapi->rpgVertNormal3f((float*)normalStart);
    rapi->rpgVertUV2f((float*)uvStart, 0);
    rapi->rpgVertex3f((float*)position);
    }
    rapi->rpgEnd();
    }
    }
    break;
    case 2:
    {
    matrixPalette = (MDLS_MATRIX_BLOCK*)meshStart;
    extraCount = 0;
    extraMax = matrixPalette->lineCount * 4;
     
    nextOffset = matrixPalette->dataSize;
    }
    break;
    case 0x8000:
    {
    nextOffset = *((uint32*)(meshStart + 4));
    }
    break;
    default:
    {
    nextOffset = 0;
    }
    break;
    }
    meshStart += nextOffset;
    } while (nextOffset > 0);
    }
    }
    }
     
    //load it
    noesisModel_t *Model_KH_Load(BYTE *fileBuffer, int bufferLen, int &numMdl, noeRAPI_t *rapi)
    {
    numMdl = 0;
     
    if (bufferLen < (sizeof(MDLS_MOBJ_HEADER) + 8))
    {
    return NULL;
    }
     
    // read mobj data offset
    uint32 mobjOffset = *((uint32*)(fileBuffer + 4));
     
    if (bufferLen < (sizeof(MDLS_MOBJ_HEADER) + mobjOffset))
    {
    return NULL;
    }
     
    uint8 *mobjData = (fileBuffer + mobjOffset);
     
    CArrayList<noesisTex_t *> textures;
    CArrayList<noesisMaterial_t *> materials;
     
    // attempt to load textures
    Model_KH_LoadTextures(textures, materials, mobjData, bufferLen, rapi);
     
    int numBones = 0;
    modelBone_t *bones = NULL;
    // process joint data
    bones = Model_KH_CreateBones(mobjData, rapi, numBones);
     
    void *pgctx = rapi->rpgCreateContext();
    rapi->rpgSetEndian(false);
    rapi->rpgSetTriWinding(false);
     
    noesisMatData_t *md = rapi->Noesis_GetMatDataFromLists(materials, textures);
    rapi->rpgSetExData_Materials(md);
    rapi->rpgSetExData_Bones(bones, numBones);
     
    CArrayList<noesisModel_t *> models;
    Model_KH_LoadModel(mobjData, textures, materials, bones, numBones, rapi);
     
    #if 0 //create a procedural anim to move random bones around
    if (bones)
    {
    const int numMoveBones = 1 + rand()%(numBones-1);
    sharedPAnimParm_t *aparms = (sharedPAnimParm_t *)_alloca(sizeof(sharedPAnimParm_t)*numMoveBones);
    memset(aparms, 0, sizeof(aparms)); //it's a good idea to do this, in case future noesis versions add more meaningful fields.
    for (int i = 0; i < numMoveBones; i++)
    {
    aparms[i].angAmt = 25.0f;
    aparms[i].axis = 1; //rotate left and right
    aparms[i].boneIdx = rand()%numBones; //random bone
    aparms[i].timeScale = 0.1f; //acts as a framestep
    }
    noesisAnim_t *anim = rapi->rpgCreateProceduralAnim(bones, numBones, aparms, numMoveBones, 500);
    if (anim)
    {
    rapi->rpgSetExData_AnimsNum(anim, 1);
    }
    }
    #endif
     
    noesisModel_t *mdl = rapi->rpgConstructModel();
    if (!mdl)
    {
    //nothing could be created
    return NULL;
    }
     
    models.Append(mdl);
    rapi->rpgDestroyContext(pgctx);
     
    materials.Clear();
     
    if (models.Num() <= 0)
    {
    return NULL;
    }
     
    numMdl = models.Num();
     
    noesisModel_t *mdlList = rapi->Noesis_ModelsFromList(models, numMdl);
    models.Clear();
     
    return mdlList;
    }
     
    //called by Noesis to init the plugin
    NPLUGIN_API bool NPAPI_Init(mathImpFn_t *mathfn, noePluginFn_t *noepfn)
    {
    g_mfn = mathfn;
    g_nfn = noepfn;
     
    if (g_nfn->NPAPI_GetAPIVersion() < NOESIS_PLUGINAPI_VERSION)
    { //bad version of noesis for this plugin
    return false;
    }
     
    int fh = g_nfn->NPAPI_Register("Kingdom Hearts Model", ".mdls");
    if (fh < 0)
    {
    return false;
    }
     
    //set the data handlers for this format
    g_nfn->NPAPI_SetTypeHandler_TypeCheck(fh, Model_KH_Check);
    g_nfn->NPAPI_SetTypeHandler_LoadModel(fh, Model_KH_Load);
     
    return true;
    }
     
    //called by Noesis before the plugin is freed
    NPLUGIN_API void NPAPI_Shutdown(void)
    {
    //nothing to do in this plugin
    }
     
    NPLUGIN_API int NPAPI_GetPluginVer(void)
    {
    return NOESIS_PLUGIN_VERSION;
    }
     
    NPLUGIN_API bool NPAPI_GetPluginInfo(noePluginInfo_t *infOut)
    {
    strcpy_s(infOut->pluginName, 64, "kingdom_hearts");
    strcpy_s(infOut->pluginDesc, 512, "Kingdom Hearts model handler, by revel8n.");
    return true;
    }
     
    BOOL APIENTRY DllMain( HMODULE hModule,
                          DWORD  ul_reason_for_call,
                          LPVOID lpReserved
    )
    {
        return TRUE;
    }
    
     
  4. Hidden Smithery King's Apprentice

    Joined:
    Feb 2, 2010
    81
    452
    Also, this is more of a curiosity question more than anything; despite changing the game's sysfont to the English equivalent, why don't the cutscenes' font change to random letters? Do they use the same font file as the Journal which, as you said, is separate from the one you replaced already? Or is it something else?
     
  5. crazycatz00 Twilight Town Denizen

    Joined:
    Apr 12, 2013
    40
    236
    Text in the journal, text in speech-bubble cut-scenes, and subtitles are using the "kanji.knj" font.
    A simple way to tell, assuming sysfont is the only file changed: If it shows as Japanese characters, it's kanji.knj. Our modded English font has no Japanese characters in it at all.

    0.o ... I hate 3D formats... :P
    But thanks, I'll have a look at this later!
     
  6. sora6645 Kingdom Keeper

    Joined:
    Feb 17, 2011
    51
    909
    So . Can u guys edit the game now ? May i help with this translation project. ?
     
  7. Hidden Smithery King's Apprentice

    Joined:
    Feb 2, 2010
    81
    452
    Bumping because I miss this thread already. It's been a week of dead silence. crazycat, come back! ;~;
     
  8. crazycatz00 Twilight Town Denizen

    Joined:
    Apr 12, 2013
    40
    236
    So ya.... this kanji font is killing me.
    As far as I can tell, it's not like textures in models. Models look like they use pallet images, but I'm pretty sure the font doesn't. The fonts are normally just grayscale pixel data, and the game colors it on-the-fly as it needs to. In addition, I was able to pull this out using TexMod (it modifies DirectX textures), to have an idea what the English kanji.knj looks like: PCSX2.EXE_0x5702378C.png This would be the top of the font, with an artifact from the title screen on the corner there.

    Still working on its format atm...
     
  9. sora6645 Kingdom Keeper

    Joined:
    Feb 17, 2011
    51
    909
    So u can't edit the game into English ?[DOUBLEPOST=1370144935][/DOUBLEPOST]
    So u can't translate this into English ? I want to help in some form of a shape . Plz let me help u ! I want to get in this project
     
  10. crazycatz00 Twilight Town Denizen

    Joined:
    Apr 12, 2013
    40
    236
    Calm down, people stalk the forums all the time; Your other post isn't even an hour old. ;P

    We'll get this into English one way or another. I asked on a hacking forum if they could help with the font, and I'm still going at it myself.
    As for helping, there's not much you can do if you can't program or reverse engineer in some way. Even changing the text requires hex-editing for now. Maybe once we actually get some things really rolling, you can play-test and such; look for bugs in the translation or the game.

    That does remind me, though: How are we going to distribute the patch, when we're at that stage? If we do the ISO as a whole, then it would be outright illegal. PPF-O-Matic maybe?
     
  11. sora6645 Kingdom Keeper

    Joined:
    Feb 17, 2011
    51
    909
    Yes PPF Patch would do the trick . Mabey we could Make a own website and I could test the game before reading the patch . So instead of real sing the download link here . We should PM on here the download link and test it before officially relase the patch
     
  12. テイジ Moogle Assistant

    Joined:
    May 31, 2013
    Gender:
    Male
    Location:
    Spain
    1
    2
    Hi there! :)

    Like Roxas79, I registered here just to join this project.

    I contacted with Xeeynamo a few days ago via Twitter, and he told me he's not going to work on Kingdom Hearts series anymore and he knows nobody who know programming or how to do it... That's a shame...
    Although he finished English (and Italian) translation of KH2FM UNDUB, so it's something.

    I have a PS3, but, personally, I'm not going to buy KH HD 1.5 ReMIX, because I'm not looking for any Kingdom Hearts title with English voices.
    I hate when Japanese games which have Japanese voices on the original title are dubbed into English and the original tracks are deleted. That's why I don't buy Japanese games if the audio is only in English, so I'm interested on Patch KHFM AND UNDUB it. I'd like to translate it into my language (Spanish) too.

    So, If I can, please, I'd like to help you guys. I have no idea about ISO hacks, but I'm so interested about learning it.

    What I need for start to unpacking the game and translating? Where can I help you continuing this project? What about lipsync?

    Thanks for everything.

    PD: I can read Katakana and Hiragana (both two syllabic Japanese scripts), so I'd like to help you translating it... I have Japanese friends who I can ask them about something I don't understand, like difficult Kanjis or something... (If I can copy-paste it, then I'm sure I can translate it, because I have a special program for Kanji).
     
  13. Hidden Smithery King's Apprentice

    Joined:
    Feb 2, 2010
    81
    452
    I suppose ppf-o-matic would be the only legal option, however, would the changes (such as the replaced files) be reflexed in a patch like that?
     
  14. crazycatz00 Twilight Town Denizen

    Joined:
    Apr 12, 2013
    40
    236
    No idea. Guess we'll find out when we get there.

    As for the font, I'm making progress. I found the routine that loads the font in the ELF, and from there found where it loads it to in memory (0x00495280 -> 0x004D59E3). So now I can change values and see how it affects the font as I do it.

    As for knowns right now
    • the font is not transformed in memory, it's the same as the file (so it's probably PS2 swizzled or w\e texture-people call it)
    • It probably has a width of 256 pixels, height unknown
    • Picture data IS 256*1024 bytes
    • After pixel data is a block that tells the game how wide to make the characters (Signed byte per character; aka 0x00 = no width, 0x7F = max width; 0x80 = max negative width)
    These are mostly so I don't forget myself, but figured they might be interesting for others. :P
     
  15. gledson999 Destiny Islands Resident

    Joined:
    Mar 15, 2013
    Gender:
    Male
    Location:
    Brazil
    28
    96
    I have interest in translate this game too, I'm finishing the Kingdom Heart 2 Final Mix to Portuguese, translation progress are in 94% are 54 image left to finish all ;)

    Crazycatz00 look

    [​IMG]


    I come here because i have interest in Kingdom Heart 1 Final Mix too and a Special Thank for you for this Great Help
     
  16. sora6645 Kingdom Keeper

    Joined:
    Feb 17, 2011
    51
    909
    Dude. This is for Kingdom Hearts 1 final mix not Kingdom. hearts 2 final Mix . U should remove the as soon possible cuz it don't relate to Kingdom Hears 1
     
  17. Hidden Smithery King's Apprentice

    Joined:
    Feb 2, 2010
    81
    452
    (S)He's just showing what they're are capable of by using that game as an example.
     
  18. crazycatz00 Twilight Town Denizen

    Joined:
    Apr 12, 2013
    40
    236
    Heads up: I'm won't be able to access my workplace related to this game, so no progress from me for a while. Sorry. :\
    Also, the forum I asked about the font at has yet to respond, too. Either no-one has any interest or they're quiet about it. I did figure it out a little bit, but I still have no idea on the order of the pixels. It makes no sense to me.
    Let's say the image is 2 rows of 8 pixels:
    0 1 2 3 4 5 6 7
    8 9 A B C D E F
    Gong from 0 to 16 in the data, the pixels are filled similar to this:
    0 C 1 D 2 E 3 F B 7 A 6 9 5 8 4
    Now, this isn't exactly what it does, but is similar. That direction change in the middle really has me confused. ><
     
  19. sora6645 Kingdom Keeper

    Joined:
    Feb 17, 2011
    51
    909
    Any news on translating yet ?
     
  20. Jadentheman Hollow Bastion Committee

    Joined:
    Mar 31, 2007
    Location:
    None of your business
    51
    742
    lol Sora you post every week asking the same thing. Just be patient. Personally I'd wait till September 10th before asking anything lol