#include <stdio.h>
 
 
 
#include "CORE/FW/brlists.h"
 
#include "CORE/FW/fwsetup.h"
 
#include "CORE/FW/pattern.h"
 
#include "CORE/FW/resource.h"
 
#include "CORE/MATH/matrix34.h"
 
#include "CORE/MATH/transfrm.h"
 
#include "CORE/V1DB/dbsetup.h"
 
#include "CORE/V1DB/enables.h"
 
#include "actsupt.h"
 
#include "harness/trace.h"
 
 
 
// IDA: br_uint_32 __cdecl BrActorEnum(br_actor *parent, br_actor_enum_cbfn *callback, void *arg)
 
br_uint_32 BrActorEnum(br_actor* parent, br_actor_enum_cbfn* callback, void* arg) {
 
    br_actor* a;
 
    br_actor* next;
 
    br_uint_32 r;
 
    LOG_TRACE("(%p, %p, %p)", parent, callback, arg);
 
 
 
    a = parent->children;
 
 
 
    while (a) {
 
        next = a->next;
 
 
 
        if ((r = callback(a, arg)))
 
            return r;
 
 
 
        a = next;
 
    }
 
 
 
    return 0;
 
}
 
 
 
// IDA: br_uint_32 __cdecl BrActorSearchMany(br_actor *root, char *pattern, br_actor **actors, int max)
 
br_uint_32 BrActorSearchMany(br_actor* root, char* pattern, br_actor** actors, int max) {
 
    br_actor* a;
 
    char* sub;
 
    int n;
 
    int remaining;
 
    LOG_TRACE("(%p, \"%s\", %p, %d)", root, pattern, actors, max);
 
 
 
    sub = NULL;
 
    if (pattern != NULL) {
 
        while (*pattern == '/') {
 
            pattern++;
 
        }
 
        sub = pattern;
 
        while (*sub != '\0' && *sub != '/') {
 
            sub++;
 
        }
 
        while (*sub == '/') {
 
            sub++;
 
        }
 
    }
 
    a = root->children;
 
    remaining = max;
 
    while (a != NULL && remaining > 0) {
 
        if (BrNamePatternMatch(pattern, a->identifier) != 0) {
 
            if (sub == NULL || *sub == '\0') {
 
                *actors = a;
 
                actors++;
 
                remaining--;
 
            } else {
 
                n = BrActorSearchMany(a, sub, actors, remaining);
 
                actors += n;
 
                remaining -= n;
 
            }
 
        }
 
        a = a->next;
 
    }
 
    return max - remaining;
 
}
 
 
 
// IDA: br_actor* __cdecl BrActorSearch(br_actor *root, char *pattern)
 
br_actor* BrActorSearch(br_actor* root, char* pattern) {
 
    br_actor* a;
 
    LOG_TRACE("(%p, \"%s\")", root, pattern);
 
 
 
    if (BrActorSearchMany(root, pattern, &a, 1) == 1) {
 
        return a;
 
    }
 
    return NULL;
 
}
 
 
 
// IDA: void __usercall RenumberActor(br_actor *a@<EAX>, int d@<EDX>)
 
void RenumberActor(br_actor* a, int d) {
 
    br_actor* ac;
 
    LOG_TRACE("(%p, %d)", a, d);
 
 
 
    ac = a->children;
 
    a->depth = d;
 
    while (ac != NULL) {
 
        RenumberActor(ac, d + 1);
 
        ac = ac->next;
 
    }
 
}
 
 
 
// IDA: br_actor* __cdecl BrActorAdd(br_actor *parent, br_actor *a)
 
br_actor* BrActorAdd(br_actor* parent, br_actor* a) {
 
    br_actor* ac;
 
    br_actor* ac2;
 
    LOG_TRACE("(%p, %p)", parent, a);
 
 
 
    BrSimpleAddHead((br_simple_list*)&parent->children, (br_simple_node*)a);
 
    a->parent = parent;
 
 
 
    a->depth = parent->depth + 1;
 
    for (ac = a->children; ac != NULL; ac = ac->next) {
 
        ac->depth = a->depth + 1;
 
        ac2 = ac->children;
 
        while (ac2 != NULL) {
 
            RenumberActor(ac2, a->depth + 2);
 
            ac2 = ac2->next;
 
        }
 
    }
 
    return a;
 
}
 
 
 
// IDA: br_actor* __cdecl BrActorRemove(br_actor *a)
 
br_actor* BrActorRemove(br_actor* a) {
 
    br_actor* ac;
 
    LOG_TRACE("(%p)", a);
 
 
 
    br_actor* ac2; // Added ?
 
 
 
    BrSimpleRemove((br_simple_node*)a);
 
    a->parent = NULL;
 
    a->depth = 0;
 
 
 
    for (ac2 = a->children; ac2; ac2 = ac2->next) {
 
        ac2->depth = 1;
 
        for (ac = ac2->children; ac; ac = ac->next) {
 
            RenumberActor(ac, 2);
 
        }
 
    }
 
    return a;
 
}
 
 
 
// IDA: void __cdecl BrActorRelink(br_actor *parent, br_actor *a)
 
void BrActorRelink(br_actor* parent, br_actor* a) {
 
    br_matrix34 mat;
 
    LOG_TRACE("(%p, %p)", parent, a);
 
 
 
    if (a->parent == parent) {
 
        return;
 
    }
 
 
 
    BrActorToActorMatrix34(&mat, a, parent);
 
    BrMatrix34ToTransform(&a->t, &mat);
 
    BrActorAdd(parent, BrActorRemove(a));
 
}
 
 
 
// IDA: br_actor* __cdecl BrActorAllocate(br_uint_8 type, void *type_data)
 
br_actor* BrActorAllocate(br_uint_8 type, void* type_data) {
 
    br_actor* a;
 
    br_light* light;
 
    br_camera* camera;
 
    br_bounds* bounds;
 
    br_vector4* clip_plane;
 
    LOG_TRACE("(%d, %p)", type, type_data);
 
 
 
    a = BrResAllocate(v1db.res, sizeof(br_actor), BR_MEMORY_ACTOR);
 
    BrSimpleNewList((br_simple_list*)&a->children);
 
    a->type = type;
 
    a->depth = 0;
 
    a->t.type = 0;
 
    a->type_data = NULL;
 
    BrMatrix34Identity(&a->t.t.mat);
 
 
 
    if (type_data) {
 
        a->type_data = type_data;
 
    } else {
 
        switch (type) {
 
        case BR_ACTOR_NONE:
 
            break;
 
        case BR_ACTOR_LIGHT:
 
            light = BrResAllocate(a, sizeof(br_light), BR_MEMORY_LIGHT);
 
            a->type_data = light;
 
            light->type = BR_LIGHT_DIRECT;
 
            light->colour = BR_COLOUR_RGB(255, 255, 255);
 
            light->attenuation_c = 1.0f;
 
            light->cone_outer = BR_ANGLE_DEG(15);
 
            light->cone_inner = BR_ANGLE_DEG(10);
 
            break;
 
        case BR_ACTOR_CAMERA:
 
            camera = (br_camera*)BrResAllocate(a, sizeof(br_camera), BR_MEMORY_CAMERA);
 
            a->type_data = camera;
 
            camera->type = BR_CAMERA_PERSPECTIVE_FOV;
 
            camera->field_of_view = BR_ANGLE_DEG(45.0f);
 
            camera->hither_z = 1.0f;
 
            camera->yon_z = 10.0f;
 
            camera->aspect = 1.0f;
 
            break;
 
        case BR_ACTOR_BOUNDS:
 
        case BR_ACTOR_BOUNDS_CORRECT:
 
            bounds = BrResAllocate(a, sizeof(br_bounds), BR_MEMORY_CLIP_PLANE);
 
            a->type_data = bounds;
 
            break;
 
        case BR_ACTOR_CLIP_PLANE:
 
            clip_plane = BrResAllocate(a, sizeof(br_vector4), BR_MEMORY_CLIP_PLANE);
 
            clip_plane->v[0] = 0;
 
            clip_plane->v[1] = 0;
 
            clip_plane->v[2] = 1.0;
 
            clip_plane->v[3] = 0;
 
            a->type_data = clip_plane;
 
            break;
 
        case BR_ACTOR_MODEL:
 
            // nothing to do
 
            break;
 
        default:
 
            LOG_WARN("Warning: Unknown type %d for BrActorAllocate", type);
 
        }
 
    }
 
    return a;
 
}
 
 
 
// IDA: void __usercall InternalActorFree(br_actor *a@<EAX>)
 
void InternalActorFree(br_actor* a) {
 
 
 
    while (a->children != NULL) {
 
        InternalActorFree((br_actor*)BrSimpleRemove((br_simple_node*)a->children));
 
    }
 
    BrActorEnableCheck(a);
 
    BrResFree(a);
 
}
 
 
 
// IDA: void __cdecl BrActorFree(br_actor *a)
 
void BrActorFree(br_actor* a) {
 
 
 
    while (a->children != NULL) {
 
        InternalActorFree((br_actor*)BrSimpleRemove((br_simple_node*)a->children));
 
    }
 
    BrActorEnableCheck(a);
 
    BrResFree(a);
 
}
 
 
 
// IDA: br_boolean __usercall ActorToRoot@<EAX>(br_actor *a@<EAX>, br_actor *world@<EDX>, br_matrix34 *m@<EBX>)
 
br_boolean ActorToRoot(br_actor* a, br_actor* world, br_matrix34* m) {
 
    LOG_TRACE("(%p, %p, %p)", a, world, m);
 
    NOT_IMPLEMENTED();
 
}
 
 
 
// IDA: br_boolean __usercall ActorToRootTyped@<EAX>(br_actor *a@<EAX>, br_actor *world@<EDX>, br_matrix34 *m@<EBX>, br_int_32 *type@<ECX>)
 
br_boolean ActorToRootTyped(br_actor* a, br_actor* world, br_matrix34* m, br_int_32* type) {
 
    //br_int_32 t; // Pierre-Marie Baty -- unused variable
 
    LOG_TRACE("(%p, %p, %p, %p)", a, world, m, type);
 
    NOT_IMPLEMENTED();
 
}
 
 
 
// IDA: void __usercall Matrix4PerspectiveNew(br_matrix4 *mat@<EAX>, br_angle field_of_view@<EDX>, br_scalar aspect, br_scalar hither, br_scalar yon, br_scalar origin_x, br_scalar origin_y)
 
void Matrix4PerspectiveNew(br_matrix4* mat, br_angle field_of_view, br_scalar aspect, br_scalar hither, br_scalar yon, br_scalar origin_x, br_scalar origin_y) {
 
    //br_scalar scale; // Pierre-Marie Baty -- unused variable
 
    LOG_TRACE("(%p, %d, %f, %f, %f, %f, %f)", mat, field_of_view, aspect, hither, yon, origin_x, origin_y);
 
    NOT_IMPLEMENTED();
 
}
 
 
 
// IDA: br_token __usercall CameraToScreenMatrix4@<EAX>(br_matrix4 *mat@<EAX>, br_actor *camera@<EDX>)
 
br_token CameraToScreenMatrix4(br_matrix4* mat, br_actor* camera) {
 
    //br_camera* camera_type; // Pierre-Marie Baty -- unused variable
 
    //br_matrix34 mat34; // Pierre-Marie Baty -- unused variable
 
    LOG_TRACE("(%p, %p)", mat, camera);
 
    NOT_IMPLEMENTED();
 
}
 
 
 
// IDA: br_uint_16 __cdecl BrActorToActorMatrix34(br_matrix34 *m, br_actor *a, br_actor *b)
 
br_uint_16 BrActorToActorMatrix34(br_matrix34* m, br_actor* a, br_actor* b) {
 
    br_matrix34 mata;
 
    br_matrix34 matb;
 
    br_matrix34 matc;
 
    br_uint_8 at;
 
    br_uint_8 bt;
 
    LOG_TRACE("(%p, %p, %p)", m, a, b);
 
 
 
    if (a == b) {
 
        BrMatrix34Identity(m);
 
        return BR_TRANSFORM_IDENTITY;
 
    }
 
 
 
    if (a->parent == b) {
 
        BrTransformToMatrix34(m, &a->t);
 
        return a->t.type;
 
    }
 
 
 
    if (b->parent == a) {
 
        BrTransformToMatrix34(&matb, &b->t);
 
 
 
        if (BrTransformTypeIsLP(b->t.type))
 
            BrMatrix34LPInverse(m, &matb);
 
        else
 
            BrMatrix34Inverse(m, &matb);
 
 
 
        return b->t.type;
 
    }
 
 
 
    at = BR_TRANSFORM_IDENTITY;
 
    BrMatrix34Identity(&mata);
 
 
 
    bt = BR_TRANSFORM_IDENTITY;
 
    BrMatrix34Identity(&matb);
 
 
 
    while (a && b && a != b) {
 
 
 
        if (a->depth > b->depth) {
 
 
 
            if (a->t.type != BR_TRANSFORM_IDENTITY) {
 
                BrMatrix34PostTransform(&mata, &a->t);
 
                at = BrTransformCombineTypes(at, a->t.type);
 
            }
 
            a = a->parent;
 
 
 
        } else if (b->depth > a->depth) {
 
 
 
            if (b->t.type != BR_TRANSFORM_IDENTITY) {
 
                BrMatrix34PostTransform(&matb, &b->t);
 
                bt = BrTransformCombineTypes(bt, b->t.type);
 
            }
 
            b = b->parent;
 
 
 
        } else {
 
 
 
            if (a->t.type != BR_TRANSFORM_IDENTITY) {
 
                BrMatrix34PostTransform(&mata, &a->t);
 
                at = BrTransformCombineTypes(at, a->t.type);
 
            }
 
            if (b->t.type != BR_TRANSFORM_IDENTITY) {
 
                BrMatrix34PostTransform(&matb, &b->t);
 
                bt = BrTransformCombineTypes(bt, b->t.type);
 
            }
 
            b = b->parent;
 
            a = a->parent;
 
        }
 
    }
 
 
 
    if (bt == BR_TRANSFORM_IDENTITY) {
 
        BrMatrix34Copy(m, &mata);
 
        return at;
 
    }
 
 
 
    if (at == BR_TRANSFORM_IDENTITY) {
 
        if (BrTransformTypeIsLP(bt)) {
 
            BrMatrix34LPInverse(m, &matb);
 
        } else
 
            BrMatrix34Inverse(m, &matb);
 
 
 
        return bt;
 
    }
 
 
 
    if (BrTransformTypeIsLP(bt)) {
 
        BrMatrix34LPInverse(&matc, &matb);
 
    } else
 
        BrMatrix34Inverse(&matc, &matb);
 
 
 
    BrMatrix34Mul(m, &mata, &matc);
 
 
 
    return BrTransformCombineTypes(at, bt);
 
}
 
 
 
// IDA: void __cdecl BrActorToScreenMatrix4(br_matrix4 *m, br_actor *a, br_actor *camera)
 
void BrActorToScreenMatrix4(br_matrix4* m, br_actor* a, br_actor* camera) {
 
    //br_matrix34 a2c; // Pierre-Marie Baty -- unused variable
 
    LOG_TRACE("(%p, %p, %p)", m, a, camera);
 
    NOT_IMPLEMENTED();
 
}
 
 
 
// IDA: void __usercall BrMatrix34ApplyBounds(br_bounds *d@<EAX>, br_bounds *s@<EDX>, br_matrix34 *m@<EBX>)
 
void BrMatrix34ApplyBounds(br_bounds* A, br_bounds* B, br_matrix34* C) {
 
    int i;
 
    int j;
 
    br_scalar a;
 
    br_scalar b;
 
    LOG_TRACE("(%p, %p, %p)", A, B, C);
 
 
 
    A->min.v[0] = A->max.v[0] = C->m[3][0];
 
    A->min.v[1] = A->max.v[1] = C->m[3][1];
 
    A->min.v[2] = A->max.v[2] = C->m[3][2];
 
 
 
    for (i = 0; i < 3; i++) {
 
        for (j = 0; j < 3; j++) {
 
            a = C->m[j][i] * B->min.v[j];
 
            b = C->m[j][i] * B->max.v[j];
 
            if (a < b) {
 
                A->min.v[i] += a;
 
                A->max.v[i] += b;
 
            } else {
 
                A->min.v[i] += b;
 
                A->max.v[i] += a;
 
            }
 
        }
 
    }
 
}
 
 
 
// IDA: void __usercall ActorToBounds(br_bounds *dest@<EAX>, br_actor *ap@<EDX>, br_model *model@<EBX>)
 
void ActorToBounds(br_bounds* dest, br_actor* ap, br_model* model) {
 
    br_actor* a;
 
    br_bounds new;
 
    br_matrix34 m2v;
 
    int i;
 
    LOG_TRACE("(%p, %p, %p)", dest, ap, model);
 
 
 
    if (ap->model != NULL)
 
        model = ap->model;
 
 
 
    m2v = v1db.model_to_view;
 
    BrMatrix34PreTransform(&v1db.model_to_view, &ap->t);
 
 
 
    if (ap->type == BR_ACTOR_MODEL) {
 
        BrMatrix34ApplyBounds(&new, &model->bounds, &v1db.model_to_view);
 
 
 
        for (i = 0; i < 3; i++) {
 
            if (new.min.v[i] < dest->min.v[i])
 
                dest->min.v[i] = new.min.v[i];
 
 
 
            if (new.max.v[i] > dest->max.v[i])
 
                dest->max.v[i] = new.max.v[i];
 
        }
 
    }
 
 
 
    BR_FOR_SIMPLELIST(&ap->children, a)
 
    ActorToBounds(dest, a, model);
 
 
 
    v1db.model_to_view = m2v;
 
}
 
 
 
// IDA: br_bounds* __cdecl BrActorToBounds(br_bounds *b, br_actor *ap)
 
br_bounds* BrActorToBounds(br_bounds* b, br_actor* ap) {
 
    br_matrix34 m2v;
 
    br_model* model;
 
    br_actor* a;
 
    LOG_TRACE("(%p, %p)", b, ap);
 
 
 
    m2v = v1db.model_to_view;
 
 
 
    if (ap->model == NULL)
 
        model = v1db.default_model;
 
    else
 
        model = ap->model;
 
 
 
    BrMatrix34Identity(&v1db.model_to_view);
 
 
 
    if (ap->type == BR_ACTOR_MODEL) {
 
        *b = model->bounds;
 
    } else {
 
        b->min.v[0] = b->min.v[1] = b->min.v[2] = BR_SCALAR_MAX;
 
        b->max.v[0] = b->max.v[1] = b->max.v[2] = BR_SCALAR_MIN;
 
    }
 
 
 
    BR_FOR_SIMPLELIST(&ap->children, a)
 
    ActorToBounds(b, a, model);
 
 
 
    v1db.model_to_view = m2v;
 
    return b;
 
}