//transform from doa3 to doa2u model format
#include <iostream>
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include <string>
#include <stdio.h>
#include <set>
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <map>
#include <vector>
using namespace std;

int main()
{
    ofstream logFile2("MyLog2.log");
//    ofstream logFile3("MyLog3.log");
    cout << hex << setfill('0');
    logFile2 << hex << setfill('0');
//    logFile3 << hex << setfill('0');
    int iterato1 = 0, iterato23 = 0;

    WIN32_FIND_DATAA findS;
	HANDLE findH = FindFirstFile("*.xpr", &findS);
	if(findH == INVALID_HANDLE_VALUE){
		MessageBox(0, "bin File not found", 0, 0);
		return 0;
	}
	try{
        do{
            //open emp
            string fName(findS.cFileName);
            logFile2 << fName.c_str() << " ";
            cout << fName.c_str() << " ";
            int fh = _open(fName.c_str(), O_RDONLY | O_BINARY);
            if(fh == -1){
                MessageBox(0, "Can't open the bin file", "Error", MB_OK);
                return 0;
            }
            int bufSize2 = _lseek(fh, 0, SEEK_END);
            byte* buf2 = (byte*)malloc(bufSize2);
            int* ibuf2 = (int*)buf2;
            WORD* Wbuf2 = (WORD*)buf2;
            _lseek(fh, 0, SEEK_SET);
            _read(fh, buf2, bufSize2);
            close(fh);


            const int dwsz4 = 4;
            const int wrdsz2 = 2;
            const int iobjsOffset10 = 10;
            int someIntOffset1 = 27; // delete this if it's not needed


            DWORD shit1[4] = {'JBO', 0, 4, 0};//first line of obj {OBJ, jointTypeX, someOffset4, unusedX};
            DWORD shit2[4] = {0x42480000, 1, 1, -1};//?texture shit {brightnes, items, type, FFs};{type1 has no brightness}
            DWORD shit3[4] = {0x20, 0, 2, 1};//?{WORD vertexSize,WORD bufferNo, indexBuffer start offset, number of primitives, ?2}
            DWORD xV4Head = 0x12345678;
            DWORD defaultFloat = 0x3F800000;

            byte* newMdl2 = (byte*)malloc(bufSize2);
            int* inewMdl2 = (int*)newMdl2;
            byte* obj2Offset;
            int sizeOfObj = 0;

            memset(newMdl2, 0, bufSize2);
            memcpy(newMdl2, buf2, ibuf2[iobjsOffset10]);//copy the header of xpr0 with mdl header wich size = offset of first OBJ

            int vtfCounter = 0;
            if(ibuf2[5] == 'LDM'){
                for(int i = 0; i < ibuf2[6]; i++){ // for each OBJ
                    sizeOfObj = 0;
                    obj2Offset = newMdl2 + inewMdl2[i + iobjsOffset10];

                    int fullSize = 0;
                    for(int j = 0; j < 4; j++){ // for each vtf
                        int vtfDeclaredSize = *(DWORD*)(buf2 + ibuf2[i + iobjsOffset10] + 0x10 + j * 0x10);
                        if(vtfDeclaredSize != 0){//has vtfDeclaredSize
                            int vtfSize = *(DWORD*)(buf2 + ibuf2[4] + 20 + vtfCounter * 12  + 16) - *(DWORD*)(buf2 + ibuf2[4] + 20 + vtfCounter * 12  + 4);
                            if((vtfSize%vtfDeclaredSize == 0) && (vtfSize/vtfDeclaredSize != 0x20) && (vtfSize/vtfDeclaredSize != 0x18) && (vtfSize/vtfDeclaredSize != 0x30)){
                                cout << " " << i << "_" << fName.c_str() << " " << vtfSize << "/" << vtfDeclaredSize <<  "=" << (vtfSize/vtfDeclaredSize) << "\r\n";
                                logFile2 << " " << i << "_" << fName.c_str() << " " << (vtfSize/vtfDeclaredSize) << "\r\n";
                            }
                            vtfCounter++;
                            fullSize += vtfDeclaredSize;
                        }
                    }

                    memcpy(obj2Offset + sizeOfObj, shit1, 0x10);//1 line is shit1
                    sizeOfObj += 0x10;
                    memcpy(obj2Offset + sizeOfObj, buf2 + ibuf2[i + iobjsOffset10] + 0x50, 0x10);//2 4floats1
                    sizeOfObj += 0x10;
                    memcpy(obj2Offset + sizeOfObj, buf2 + ibuf2[i + iobjsOffset10] + 0x10, 0x40);//3-4 vtxOffnSz; need to fix later the xV4 offset
                    sizeOfObj += 0x80; // also jump over the bunch of nulls

                    int txtr3Offset = ibuf2[i + iobjsOffset10] + 0x60;//texture offset in begining of texture; relate all offsets to it

            int allSecondXV2sizes = 0;

                    while(*(int*)(buf2 + txtr3Offset) != 0){//convert textures while it's aviable(header's not null)
        //                memcpy(obj2Offset + sizeOfObj, buf2 + txtr3Offset + 0, 0x60);//11-16 txtType+floats+4nulls has some wrong shit
        //                memcpy(obj2Offset + sizeOfObj + 0x20, &defaultFloat, 0x4);//try to fix the missing part of float field
        //                *(int*)&obj2Offset[sizeOfObj + 4] = 0x90;//need to find more abou this unknown 90
        //                sizeOfObj += 0x60;//some shit fixed before this
                        memcpy(obj2Offset + sizeOfObj, buf2 + txtr3Offset + 0, 0x20);//11-16 txtType+floats+4nulls has some wrong shit
                        //if(buf2[txtr3Offset + 0x68] == 1){obj2Offset[sizeOfObj] = 1;}//?? add transparency(sometimes is wrong)//////////////////
                        int array1size = *(int*)(buf2 + txtr3Offset + 0x68);//the amount of items in array is right before the array
                        int transparency = 0;
                        for(int l=0; l < array1size; l++){
                            int textureNo = *(int*)(buf2 + txtr3Offset + 0x6C + l*0x10);
                            if(textureNo == 0x888)continue;
                            if(*(int*)(buf2 + txtr3Offset + 0x78 + l*0x10) == 0x1000400){
                                transparency = 0;
                                break;
                            }
                            if(buf2[ibuf2[4]+20 +ibuf2[9]*12 + textureNo*20 +12 +1] != 0xC)transparency = 1;
                        }
                        obj2Offset[sizeOfObj] = transparency;//patch transparency

                        *(int*)&obj2Offset[sizeOfObj + 4] = 0x80 + array1size * 0x10;//the size of the entire textured item
                        *(int*)&obj2Offset[sizeOfObj + 8] = 0;//just checking something; erase me
                        *(int*)&obj2Offset[sizeOfObj + 0xC] = 0;//just checking something; erase me
                        sizeOfObj += 0x20;
                        memcpy(obj2Offset + sizeOfObj, buf2 + txtr3Offset + 0x24, 0x2C);//11-16 txtType+floats+4nulls has some wrong shit
                        sizeOfObj += 0x2C;
                        memcpy(obj2Offset + sizeOfObj, &defaultFloat, 0x4);//try to fix the missing part of float field
                        sizeOfObj += 0x4 + 0x10; //jump over nulls

                        shit2[0] = *(int*)(buf2 + txtr3Offset + 0x64);//fix the brightness
                        shit2[1] = array1size;//fix the amount of items in linked array1
                       //shit2[2] = 3;//change texture type to 3////////////////////use 1 for clear look
                        memcpy(obj2Offset + sizeOfObj, shit2, 0x10);//17 ?texture shit
                        sizeOfObj += 0x10;
                        txtr3Offset += 0x6C;//move the texture offset to it's array1
                        for(int j = 0; j < array1size; j++){//18 copy every item of array1 coz they're linked
                            memcpy(obj2Offset + sizeOfObj, buf2 + txtr3Offset + j * 0x10, 0x10);
                            sizeOfObj += 0x10;
                        }
                        txtr3Offset += array1size * 0x10 + 4;//move the texture offset to it's array2

                        array1size = *(int*)(buf2 + txtr3Offset - 4);//the amount of items in array is right before the array
         //               int secondXV2size = 0;
        //                for(int j = 0; j < array1size; j++){//resolve secondXV2size
        //                    secondXV2size += *(int*)(buf2 + txtr3Offset + j*0x10 + 3*4);
        //                    secondXV2size += 4;
        //                }
        //                secondXV2size -= 4;

                        shit3[1] = *(int*)(buf2 + txtr3Offset + 0x8);//vertex start
                        shit3[2] = *(int*)(buf2 + txtr3Offset + 0x8 + (array1size - 1)*0x10) + *(int*)(buf2 + txtr3Offset + 0xC + (array1size - 1)*0x10) - shit3[1];//vertex end
                        if(array1size > 1)shit3[2] += 2;
                        memcpy(obj2Offset + sizeOfObj, shit3, 0x10);//19 ?unknown shit with 20
        //                *(int*)&obj2Offset[sizeOfObj + 8] = secondXV2size;//the ammount of vertexes to draw
                        sizeOfObj += 0x10;

                        txtr3Offset += array1size * 0x10 + 4;//move the texture offset to begining of the next texture
               allSecondXV2sizes += shit3[2] + 2;
                    }

                    sizeOfObj += 4; //jump over the null "header for next texture" //USE ONLY FOR THE LAST TEXTURE
                    memcpy(obj2Offset + sizeOfObj, &xV4Head, 4);//header of vertex buffer
                    sizeOfObj += 4;

                    for(int j = 0; j < 4; j++){//for each possible vector offset n size
                        int xV4Offset = *(DWORD*)(obj2Offset + 11 * dwsz4 + j * 0x10);
                        int xV4Size = *(DWORD*)(obj2Offset + 10 * dwsz4 + j * 0x10);

                        if(xV4Offset != 0){
                            *(int*)&obj2Offset[11 * dwsz4 + j * 0x10] = obj2Offset - newMdl2 + sizeOfObj;//fix the xV4 offset in the obj for DOA2
                            memcpy(obj2Offset + sizeOfObj, buf2 + xV4Offset, xV4Size * wrdsz2);//copy each short of xV4
                            sizeOfObj += xV4Size * wrdsz2;

                            allSecondXV2sizes -= xV4Size;
                        }
                    }
        //     if(allSecondXV2sizes != 0)cout << i << " do not match " << allSecondXV2sizes << endl;//check if all vertexes are used
                    inewMdl2[i + iobjsOffset10 + 1] = obj2Offset - newMdl2 + sizeOfObj;//fix the offset of the next obj in newMdl
                }
            }else{
                continue;
            }
            inewMdl2[4] = sizeOfObj - 20 + obj2Offset - newMdl2;
            int sizeOfDirHead = ibuf2[2] - ibuf2[4] - 20;
            memcpy(obj2Offset + sizeOfObj, buf2 + ibuf2[4] + 20, sizeOfDirHead);//copy included directory header

            memcpy(buf2, newMdl2, ibuf2[2]);//copy new mdl over the old one

            string catName = fName;

            DWORD bytesRead;
            fName = "converted//" + fName;// + ".xpr";
            HANDLE h = CreateFile(fName.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
            if(!h){
                MessageBox(0,"Can't create file", "Error(Already exist?)", MB_OK);
                return 0;
            }
        	WriteFile(h, (byte*)buf2, bufSize2, &bytesRead, 0);//ogg offset 82
            CloseHandle(h);
            free(newMdl2);
            free(buf2);



            ////////////////////// transform the cat file here ///////////////////////
            byte cat2tempBuf[200] = {0};//buffer for new cat header
            //open cat
            catName.resize(catName.size() - 3);
            catName += "cat";
            fh = _open(catName.c_str(), O_RDONLY | O_BINARY);
            if(fh == -1){
                logFile2 << endl;
                cout << endl;
                continue;
            }
            int bufSize3 = _lseek(fh, 0, SEEK_END);
            byte* buf3 = (byte*)malloc(bufSize3);
            int* ibuf3 = (int*)buf3;
            WORD* Wbuf3 = (WORD*)buf3;
            _lseek(fh, 0, SEEK_SET);
            _read(fh, buf3, bufSize3);
            close(fh);

            logFile2 << catName.c_str() << " " << endl;
            cout << catName.c_str() << " " << endl;
            if(ibuf3[0] != 1){
                logFile2 << " the cat header is crypted " << endl;
                cout << " the cat header is crypted " << endl;
            }
////////convert bones arrays from 3 to 2
            int pHair = ibuf3[2], pBoobs = ibuf3[3], pJoints = ibuf3[4];
            int cat2Head[19] = {0x20, 0x14,/*hair*/ 0,/*boobs*/ 0,/*joints*/ 0, /*doa3skeletonType*/1, -1, /*high offset*/0x39, /*high*/1, 0,0, 0,0, 0,0, 0,0, 0,0};

            vector<byte> vBones;
            vector<DWORD> vBonesHeads;
            int newHeadSize = sizeof(cat2Head), boneOffset = ibuf3[7] + 0x14 + 1;
            //high poly
            vBones.push_back(0xFE);
            vBonesHeads.push_back(sizeof(cat2Head) + vBones.size() - 0x14);
            vBonesHeads.push_back(1);
            for(int highBone = 0; highBone < 0xf; highBone++, boneOffset++){
                vBones.push_back(1);
                vBones.push_back(highBone);
                vBones.push_back(buf3[boneOffset]);
            }
            if(buf3[boneOffset] == 0xFD){//eyes
                boneOffset++;
                vBones.push_back(1);
                vBones.push_back(0x11);
                vBones.push_back(buf3[boneOffset]);
                boneOffset++;
                vBones.push_back(1);
                vBones.push_back(0x15);
                vBones.push_back(buf3[boneOffset]);
                boneOffset++;
            }
            if(buf3[boneOffset] == 0xFB){//wirsts //problem here
                boneOffset++;
                vBones.push_back(1);
                vBones.push_back(0x80);
                vBones.push_back(buf3[boneOffset]);
                boneOffset++;
                vBones.push_back(1);
                vBones.push_back(0x81);
                vBones.push_back(buf3[boneOffset]);
                boneOffset++;
            }
            vBones.push_back(0);
            vBones.push_back(0);
            vBones.push_back(0);
            //low poly
            if(buf3[boneOffset] == 0xF9){
                vBonesHeads.push_back(sizeof(cat2Head) + vBones.size() - 0x14);
                vBonesHeads.push_back(9);
                boneOffset++;
                for(int lowBone = 0; lowBone < 0xf; lowBone++, boneOffset++){
                    vBones.push_back(1);
                    vBones.push_back(lowBone);
                    vBones.push_back(buf3[boneOffset]);
                }
                vBones.push_back(0);
                vBones.push_back(0);
                vBones.push_back(0);
            }
            //shadow
            if(buf3[boneOffset] == 0xF8){
                vBonesHeads.push_back(sizeof(cat2Head) + vBones.size() - 0x14);
                vBonesHeads.push_back(5);
                vBones.push_back(0xF0);
                boneOffset++;
                for(int shadowBone = 0; shadowBone < 0xf; shadowBone++, boneOffset++){
                    vBones.push_back(buf3[boneOffset]);
                };
                vBones.push_back(0);
                newHeadSize += vBones.size();
            }
            //ninja effect
            if(buf3[boneOffset] == 0xF7){
                vBones.push_back(0xFE);
                vBonesHeads.push_back(sizeof(cat2Head) + vBones.size() - 0x14);
                vBonesHeads.push_back(7);
                boneOffset++;
                for(int petal = 0; petal < 0x3; petal++, boneOffset++){
                    vBones.push_back(buf3[boneOffset]);
                };
                vBones.push_back(0);
            }
//                //genra weapon effect
//                if(buf3[boneOffset] == 0xF6){
//                }
//                //glowing effect for zack and genra
//                if(buf3[10] == 4){
//                }

            int shiftToHex = 0x10 - (sizeof(cat2Head) + vBones.size()) % 0x10;
            for(int i = 0; i < shiftToHex; i++){
                vBones.push_back(0);
            }
            if(buf3[0] == 1){
                cat2Head[2] = pHair + sizeof(cat2Head) + vBones.size();
                cat2Head[4] = pJoints + sizeof(cat2Head) + vBones.size();

                if(pJoints != 0){
                    ////////// find and replace all doa3 wrists with doau wrists
                    int curJoint = 0;
                    while(*(DWORD*)(buf3 + pJoints + curJoint*4)){
                        int temp = pJoints +*(DWORD*)(buf3 +pJoints +curJoint*4) +10;
                        if(buf3[temp] == 0x13)buf3[temp] = 0x80;//80
                        if(buf3[temp] == 0x14)buf3[temp] = 0x81;//81
                        if(buf3[temp+1] != 1)
                            buf3[temp+1] = 1;//joint any type to 1
                        curJoint++;
                    }
                }

            }
            for(int i = 0; i < vBonesHeads.size(); i++){//copy the offsets to temp header
                cat2Head[7 + i] = vBonesHeads[i];
            }
            memcpy(cat2tempBuf, cat2Head, sizeof(cat2Head));
            for(int i = 0; i < vBones.size(); i++){
                cat2tempBuf[i + sizeof(cat2Head)] = vBones[i];
            }

////////end convert bones


            bytesRead;
            catName = "converted//" + catName;// + ".cat";
            h = CreateFile(catName.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
            if(!h){
                MessageBox(0,"Can't create file", "Error(Already exist?)", MB_OK);
                return 0;
            }
            WriteFile(h, cat2tempBuf, sizeof(cat2Head) + vBones.size(), &bytesRead, 0);
            WriteFile(h, buf3, bufSize3, &bytesRead, 0);
            CloseHandle(h);

            free(buf3);
            ////////////////////// cat transformation ends here ///////////////////////

        }while(FindNextFile(findH, &findS));
        FindClose(findH);
	}catch(...){}

    system("pause");
    return 0;
}
