/* bsp.c
 *
 * Bsp file reading and writing
 *
 * Created: 9/7/97
 */

#include "brender.h"

#include "chaos.h"

c_mci *c_MciLoad(char *name)
{
    void *file;
    br_uint_32 hbuffer[2];
    br_int_32 *buffer, *bufptr;
    int n, i, numnodes;
    br_uint_32 size;
    c_bsp *bsp, *bspptr;
    c_mci *mci;

    file = BrFileOpenRead(name, 0, NULL, NULL);
    if(file){
        if((n = BrFileRead((void *)hbuffer, 4, 2, file)) != 2){
            BrFileClose(file);
            return NULL;
        }
        if(hbuffer[0] != 'CBSP'){
            BrFileClose(file);
            return NULL;
        }
        size = hbuffer[1];

        if((buffer = (br_int_32 *)BrResAllocate(NULL, size,
            BR_MEMORY_APPLICATION)) == NULL){
            BrFileClose(file);
            return NULL;
        }
        if((n = BrFileRead((void *)buffer, 4, size/4, file)) != size/4){
            BrResFree(buffer);
            BrFileClose(file);
            return NULL;
        }

        if((mci = (c_mci *)BrResAllocate(game, sizeof(c_mci),
            BR_MEMORY_APPLICATION)) == NULL){
            BrResFree(buffer);
            BrFileClose(file);
            return NULL;
        }
        for(bufptr = buffer; bufptr < buffer+size; bufptr += 2+(*(bufptr+1)/4))
            if(*bufptr == 'NODE' && ((bufptr+2) < (buffer+size))){
                numnodes = *(bufptr+2);
                bsp = (c_bsp *)BrResAllocate(mci, sizeof(c_bsp)*numnodes,
                    BR_MEMORY_APPLICATION);
                break;
            }
        if(!bsp){
            BrResFree(mci);
            BrResFree(buffer);
            BrFileClose(file);
            return NULL;
        }
        mci->bsp = bsp;

        n = 0;
        while(n < size/4){
            switch(buffer[n]){
                case 'NODE':
                    n += 3;
                    for(i = 0, bspptr = bsp; i < numnodes; i++, bspptr++){
                        bspptr->plane.v[0] = BrFixedToScalar(buffer[n++]);
                        bspptr->plane.v[1] = BrFixedToScalar(buffer[n++]);
                        bspptr->plane.v[2] = BrFixedToScalar(buffer[n++]);
                        bspptr->plane.v[3] = BrFixedToScalar(buffer[n++]);
                        bspptr->in = buffer[n++] ? bsp+buffer[n-1] : NULL;
                        bspptr->out = buffer[n++] ? bsp+buffer[n-1] : NULL;
                    }
                    break;
                case 'CINF':
                    n += 2;
                    mci->lowest = BrFixedToScalar(buffer[n++]);
                    mci->highest = BrFixedToScalar(buffer[n++]);
                    mci->flags = buffer[n++];
                    break;
                default:
                    n += buffer[n+1]/4+2;
                    break;
            }
        }

        BrResFree(buffer);
        BrFileClose(file);

        return mci;
    }
    return NULL;
}

static int BspSize(c_bsp *bsp)
{
    if(!bsp)
        return 0;
    return 1+BspSize(bsp->in)+BspSize(bsp->out);
}

static void BspWrite(c_bsp *bsp, void *file, int nodenum)
{
    br_int_32 buffer[6];

    if(bsp){
        buffer[0] = BrScalarToFixed(bsp->plane.v[0]);
        buffer[1] = BrScalarToFixed(bsp->plane.v[1]);
        buffer[2] = BrScalarToFixed(bsp->plane.v[2]);
        buffer[3] = BrScalarToFixed(bsp->plane.v[3]);

        buffer[4] = bsp->in ? nodenum+1 : 0;
        buffer[5] = bsp->out ? nodenum+1+BspSize(bsp->in) : 0;

        BrFileWrite(buffer, 4, 6, file);

        BspWrite(bsp->in, file, nodenum+1);
        BspWrite(bsp->out, file, nodenum+1+BspSize(bsp->in));
    }
}

void c_MciSave(char *name, c_mci *mci)
{
    void *file;
    br_int_32 buffer[5];
    int n, i, numnodes;
    br_uint_32 size;

    file = BrFileOpenWrite(name, BR_FS_MODE_BINARY);
    if(file){
        numnodes = BspSize(mci->bsp);
        buffer[0] = 'CBSP';
        buffer[1] = 32+sizeof(c_bsp)*numnodes;
        buffer[2] = 'NODE';
        buffer[3] = 4+sizeof(c_bsp)*numnodes;
        buffer[4] = numnodes;
        BrFileWrite(buffer, 4, 5, file);

        BspWrite(mci->bsp, file, 0);

        buffer[0] = 'CINF';
        buffer[1] = 12;
        buffer[2] = BrScalarToFixed(mci->lowest);
        buffer[3] = BrScalarToFixed(mci->highest);
        buffer[4] = mci->flags;

        BrFileWrite(buffer, 4, 5, file);

        BrFileClose(file);
    }
}

