// ---------------------------- VSOBJECT.C -----------------------
// VSpace 3d library.
// Designed and written by Javier Ar‚valo Baeza.
// 3D Object mesh handling.

#if 0
#include "vsobject.h"

#include <stdio.h>

#define NTEMPVERT 4000
static VSO_TTempVertex TempVert[NTEMPVERT];
static int NTempVert = 0;

#define MAXFACEV 15

int         VSO_NLights = 0;
VSL_PLight  VSO_Lights[VSL_MAXLIGHTS];

extern VSL_PLight  VSO_AmbientLight     = NULL;
extern VSL_PLight  VSO_DirectionalLight = NULL;
extern VSL_PLight  VSO_FogLight         = NULL;


VSB_PBitmap VSO_LightBitmap = NULL;


    // Copy base rotations to dynamic rotations.
extern void VSO_CopyRotations(VSO_PMesh mesh) {
    while (mesh != NULL) {
        VSALG_Copy3DVector(&mesh->c, &mesh->bc);
        VSALG_Copy3DMatrix(&mesh->m, &mesh->bm);
        VSO_CopyRotations(mesh->child);
        mesh = mesh->sibling;
    }
}

    // Rotate a hierarchy of meshes, chaining rotations and all stuff.
extern void VSO_RotateHierarchy(VSO_PMesh mesh) {
    VSALG_T3DPoint  tp;
    VSO_PMesh m;

    if (mesh == NULL)
        return;
    for (m = mesh->child; m != NULL; m = m->sibling) {
        VSALG_RotateAdd(&tp, &m->c, &mesh->c, &mesh->m);
        VSALG_Copy3DVector(&m->c, &tp);
        VSALG_Compose(&m->m, &mesh->m, &m->m);
        VSO_RotateHierarchy(m);
    }
}

extern VSO_PMesh VSO_FindMeshName(VSO_PMesh mesh, const char *name) {
    VSO_PMesh m = NULL;
    while (mesh != NULL && m == NULL) {
        if (strnicmp(mesh->name, name, VSO_OBJNAMELEN) == 0) {
            m = mesh;
        } else {
            m = VSO_FindMeshName(mesh->child, name);
        }
        mesh = mesh->sibling;
    }
    return m;
}

extern VSALG_TCoord VSO_CalcRadius(VSO_PMesh pm) {
    VSALG_TCoord rad = 0;
    VSALG_TCoord r;
    VSO_PVertex pv;

    while (pm != NULL) {
        int j;
        VSALG_T3DPoint av;

        r = VSALG_Length3D(&pm->c);
        if (r > rad)
            rad = r;
        pv = pm->v;
        for (j = pm->nv; j > 0; j--, pv++) {
            VSALG_Add3D(&av, &pv->v, &pm->c);
            r = VSALG_Length3D(&av);
            if (r > rad)
                rad = r;
        }
        VSLOG("  Radius for mesh %s is %f\n", pm->name, rad);

        r = VSO_CalcRadius(pm->child);
//        r += VSALG_Length3D(&pm->child->c);
        if (r > rad)
            rad = r;
        pm->radius = rad;
        pm = pm->sibling;
    }
    return rad;
}

extern void VSO_GenerateNormals(VSO_PMesh pm) {
    int i, j, k;
    VSO_PFace pf;
    VSO_PVertex pv;
    VSO_PFaceVertex pfv;

    if (pm == NULL)
        return;

        // Clear vertex normals
    pf = pm->f;
    for (i = 0; i < pm->nf; i++, pf++) {
        pfv = pf->v;
        for (k = 0; k < pf->nv; k++, pfv++) {
            VSALG_Set3D(&pm->v[pfv->nvert].n, 0, 0, 0);
        }
    }

        // Generate face normals and vertex normals
    pf = pm->f;
    for (i = 0; i < pm->nf; i++, pf++) {
        VSALG_T3DPoint e1, e2;

        if (pf->v[0].nvert >= pm->nv
         || pf->v[1].nvert >= pm->nv
         || pf->v[2].nvert >= pm->nv)
            BASE_Abort("face %d: %d, %d, %d; nv == %d\n",
                        i, pf->v[0].nvert, pf->v[1].nvert, pf->v[2].nvert, pm->nv);
        VSALG_Sub3D(&e1, &pm->v[pf->v[1].nvert].v, &pm->v[pf->v[0].nvert].v);
        VSALG_Sub3D(&e2, &pm->v[pf->v[2].nvert].v, &pm->v[pf->v[0].nvert].v);
        VSALG_Cross3D(&pf->n, &e1, &e2);
        VSALG_Normalize3D(&pf->n, &pf->n);
        pfv = pf->v;
        for (k = 0; k < pf->nv; k++, pfv++) {
            VSALG_Add3D(&pm->v[pfv->nvert].n, &pm->v[pfv->nvert].n, &pf->n);
        }
    }

        // Normalize vertex normals
    pv = pm->v;
    for (j = 0; j < pm->nv; j++, pv++) {
        VSALG_Normalize3D(&pv->n, &pv->n);
    }
}

extern void VSO_DrawHierarchy(VSV_PViewport scr, VSO_PMesh mesh, const VSC_TCamera *cam) {
    while (mesh != NULL) {
        if (VSO_DrawMesh(scr, mesh, cam))
            VSO_DrawHierarchy(scr, mesh->child, cam);
        mesh = mesh->sibling;
    }
}

#define GETTVERT(pfv) (TempVert[(pfv)->nvert])

#define CopyVert(d,v) (memcpy((d),(v),sizeof(*(d))))

static void GenerateSplit(VSO_PFaceVertex p, VSO_PFaceVertex pi,
                          VSO_PFaceVertex pnx, VSALG_TCoord fi, VSALG_TCoord fnx,
                          VSC_PCamera cam) {
    VSALG_TCoord d = fi/(fi - fnx);
    VSO_PTempVertex tvp, tvi, tvnx;

    tvp  = &GETTVERT(p);
    tvi  = &GETTVERT(pi);
    tvnx = &GETTVERT(pnx);

    tvp->v.x = tvi->v.x + (tvnx->v.x - tvi->v.x)*d;
    tvp->v.y = tvi->v.y + (tvnx->v.y - tvi->v.y)*d;
    tvp->v.z = tvi->v.z + (tvnx->v.z - tvi->v.z)*d;
    if (tvp->v.z > 0) {
        tvp->iz = 1.0/tvp->v.z;
        tvp->p.x = VSPLY_Pix2Scr(cam->cx + cam->fx*tvp->v.x*tvp->iz);
        tvp->p.y = VSPLY_Pix2Scr(cam->cy + cam->fy*tvp->v.y*tvp->iz);
    }

    p->t.x = pi->t.x + (pnx->t.x - pi->t.x)*d;
    p->t.y = pi->t.y + (pnx->t.y - pi->t.y)*d;

    tvp->a = tvi->a + (tvnx->a - tvi->a)*d;
    tvp->r = tvi->r + (tvnx->r - tvi->r)*d;
    tvp->g = tvi->g + (tvnx->g - tvi->g)*d;
    tvp->b = tvi->b + (tvnx->b - tvi->b)*d;

    tvp->d[0] = tvp->v.z + tvp->v.y*cam->xz[0];
    tvp->d[1] = tvp->v.z + tvp->v.y*cam->xz[1];
    tvp->d[2] = tvp->v.z + tvp->v.x*cam->xz[2];
    tvp->d[3] = tvp->v.z + tvp->v.x*cam->xz[3];

}

extern VSO_PFaceVertex VSO_ClipFace(VSO_PFaceVertex dfv, VSO_PFaceVertex pfv,
                                    int *ncfv, int j, VSC_PCamera cam) {
    int nv;
    VSALG_TCoord fi, fnx;     // Distances from point to plane.
    int i, nx, npin;
    VSO_PFaceVertex pin, pi, pnx;

    nv = *ncfv;

    pin = dfv;
    npin = 0;
    i = nv - 1;
    fi = GETTVERT(pfv + i).d[j];
    pi = pfv + i;
    pnx = pfv;
    for (nx = 0; nx < nv; i = nx, fi = fnx, pi = pnx, pnx++, nx++) {
        fnx = GETTVERT(pfv + nx).d[j];
        if (fi >= 0) {    // Add pi to pin
            CopyVert(pin, pi);
            pin++;
            npin++;
        }
            // If point is on plane (distance==0), don't split.
        if ((fi < 0 && fnx > 0) || (fi > 0 && fnx < 0)) {
            if (NTempVert >= NTEMPVERT)
                return NULL;    // No more temporary vertices available.
            pin->nvert = NTempVert;
            NTempVert++;
                // Split here.
            GenerateSplit(pin, pi, pnx, fi, fnx, cam);
            pin++;
            npin++;
        }
    }
    if (npin <= 0)
        return NULL;
    *ncfv = npin;
    return dfv;
}

static void PrepareLight(VSL_PLight l, VSO_PMesh mesh, VSALG_P3DMatrix c2o) {
    VSALG_T3DPoint lc2o;

    if (l == NULL)
        return;
    switch (l->type) {
        case VSLT_DIRECTIONAL:
                // Rotate light direction by inverse of object rotation.
            VSALG_Rotate(&l->dir.rd, &l->dir.dir, c2o);
            break;
        case VSLT_OMNI:
                // Send light position into object space.
            VSALG_Sub3D(&lc2o, &l->omni.v, &mesh->c);
            VSALG_Rotate(&l->omni.rv, &lc2o, c2o);
            break;
    }
}

    // The camera matrix denotes the *inverse* of the rotation of the camera.
    // The mesh dynamic rotation must be already chained with the parent
    // rotation, and same with the spatial position.
    // That's what VSO_RotateHierarchy() is for.
extern bool VSO_DrawMesh(VSV_PViewport scr, VSO_PMesh mesh, const VSC_TCamera *cam) {
    VSALG_T3DPoint  tp;
    VSALG_T3DPoint  c2v;
    VSALG_T3DMatrix c2o;
    VSO_PVertex     pv;
    VSO_PTempVertex ptv;
    VSO_PFace       pf;
    VSO_PFaceVertex pfv;
    VSPLY_PPolyPoint  ppv;
    int i;
    int j;
    VSALG_TCoord    depth;

    if (mesh->hidden)
        return TRUE;

    if (mesh->light) {
//        printf("Drawing light %s at %f, %f, %f with intensity %f and rgb %f, %f, %f\n", mesh->name, mesh->rgbl.intens, mesh->rgbl.r, mesh->rgbl.r, mesh->rgbl.b);
        VSO_DrawLight(scr, &mesh->c, &mesh->rgbl, VSO_LightBitmap, cam);
    }

    if (mesh->nv <= 0)
        return TRUE;

    if (mesh->nv > NTEMPVERT)
        return FALSE;

        // Make sure bounding box is possibly visible.
    if (mesh->radius > 0) {
        VSALG_T3DPoint oc, ocr;
        VSALG_TCoord l;

            // Rotate object into camera space.
        VSALG_Sub3D(&oc, &mesh->c, &cam->c);
        VSALG_Rotate(&ocr, &oc, &cam->im);

        if (ocr.z + mesh->radius < 0) {
//            VSLOG("Object %s behind camera\n", mesh->name);
            return FALSE;
        }
        if (VSO_FogLight != NULL)
            if (ocr.z - mesh->radius > VSO_FogLight->fog.dmax) {
//                VSLOG("Object %s into fog\n", mesh->name);
                return FALSE;
            }

            // Check against frustum
        l = VSALG_Length3D(&ocr);
        if (l > 10.0 && l > mesh->radius) {
            float cosang;

            cosang = (ocr.z)/l;
            if (cosang < 0.5)
                return FALSE;
        }

    }

        // c2o must hold the matrix that xforms points from world space
        // into object space.
        // c2v must hold the vector that xforms points from camera space
        // into object space.

        // c2o = Inverse(mesh->rot).
    VSALG_Transpose(&c2o, &mesh->m);
        // tp <- mesh->pos - cam->pos.
    VSALG_Sub3D(&tp, &mesh->c, &cam->c);
        // c2v = c2o*tp = Inverse(mesh->rot)*(mesh->pos - cam->pos).
    VSALG_Rotate(&c2v, &tp, &c2o);

    MemSetD(TempVert, 0, sizeof(*TempVert)*mesh->nv);

        // Prepare operations in mesh space:

        // Move directional lights to mesh space
    PrepareLight(VSO_DirectionalLight, mesh, &c2o);
    if (mesh->nv > 0) for (j = 0; j < VSO_NLights; j++) {
        VSL_PLight l;

        l = VSO_Lights[j];
        PrepareLight(l, mesh, &c2o);
    }

        // No more operations needed to get things into object space.

        // Rotate object into camera space.
    VSALG_Rotate(&mesh->c, &tp, &cam->im);
    VSALG_Compose(&mesh->m, &cam->im, &mesh->m);

/*
    if (mesh->c.z > 0) {
        VSDL_PDot dot;

        dot = (VSDL_PDot)VSDL_Add(scr->s, 0, VSDLET_DOT, VSDL_SIZEDOT(pf->nv));
        if (dot != NULL) {
            dot->c = VSV_MakePixel(255, 0, 0);
            dot->p.x = VSPLY_Pix2Scr(cam->cx + cam->fx*mesh->c.x/mesh->c.z);
            dot->p.y = VSPLY_Pix2Scr(cam->cy + cam->fy*mesh->c.y/mesh->c.z);
        }
    }
*/

        // Backface cull in object space
    for (i = mesh->nf, pf = mesh->f; i > 0; i--, pf++) {
        pv = mesh->v + pf->v[0].nvert;
        VSALG_Add3D(&tp, &pv->v, &c2v);
        pf->visible = (VSALG_Dot3D(&tp, &pf->n) <= 0);
        if (pf->visible) {
            for (j = pf->nv, pfv = pf->v; j > 0; j--, pfv++)
                GETTVERT(pfv).nfaces++;
        }
    }

        // Rotate visible vertices into camera space.
        // Calc distances from vertices to the four pyramid planes.
    for (i = mesh->nv, pv = mesh->v, ptv = TempVert; i > 0; i--, ptv++, pv++) {
        if (ptv->nfaces > 0) {
            byte oc;
            VSALG_RotateAdd(&ptv->v, &pv->v, &mesh->c, &mesh->m);
/*
            if (ptv->v.z > 0) {
                VSDL_PDot dot;
                dot = (VSDL_PDot)VSDL_Add(scr->s, 0, VSDLET_DOT, VSDL_SIZEDOT(0));
                if (dot != NULL) {
                    dot->c = VSV_MakePixel(0, 255, 0);
                    dot->p.x = VSPLY_Pix2Scr(cam->cx + cam->fx*ptv->v.x/ptv->v.z);
                    dot->p.y = VSPLY_Pix2Scr(cam->cy + cam->fy*ptv->v.y/ptv->v.z);
                }
            }
*/
            ptv->d[0] = ptv->v.z + ptv->v.y*cam->xz[0];
            oc = (ptv->d[0] < 0) << 0;
            ptv->d[1] = ptv->v.z + ptv->v.y*cam->xz[1];
            oc |= (ptv->d[1] < 0) << 1;
            ptv->d[2] = ptv->v.z + ptv->v.x*cam->xz[2];
            oc |= (ptv->d[2] < 0) << 2;
            ptv->d[3] = ptv->v.z + ptv->v.x*cam->xz[3];
            oc |= (ptv->d[3] < 0) << 3;
            oc |= (ptv->v.z <= 0) << 4;
            ptv->outcodes = oc;
//            printf("Outcodes for vertex %d : 0x%02X\n", i, oc);
        }
    }

        // Eliminate faces out of pyramid and their vertices.
    for (i = mesh->nf, pf = mesh->f; i > 0; i--, pf++) {
        byte oc0 = 0x0F, oc1 = 0;
        if (pf->visible) {
            for (j = pf->nv, pfv = pf->v; j > 0; j--, pfv++) {
                byte o;

                o = GETTVERT(pfv).outcodes;
                oc0 &= o;
                oc1 |= o;
            }

            if (oc0 != 0) {             // Face outcoded out
                pf->visible = FALSE;
                for (j = pf->nv, pfv = pf->v; j > 0; j--, pfv++)
                    GETTVERT(pfv).nfaces--;
            } else {                    // Or'ed outcodes mark clip planes.
                pf->outcodes = (oc1 & 0x0F);    // Don't count -Z outcode
            }
        }
    }

        // Project and shed light on visible vertices.
    for (i = mesh->nv, pv = mesh->v, ptv = TempVert; i > 0; i--, pv++, ptv++) {
        if (ptv->nfaces > 0) {
            VSL_TLightRGB vl;



                // Project.
            if (ptv->v.z > 0) {
                ptv->iz = 1.0/ptv->v.z;
                ptv->p.x = VSPLY_Pix2Scr(cam->cx + cam->fx*ptv->v.x*ptv->iz);
                ptv->p.y = VSPLY_Pix2Scr(cam->cy + cam->fy*ptv->v.y*ptv->iz);
            } else {
            }

                // Shed some light.
            vl.r = 0;
            vl.g = 0;
            vl.b = 0;
            vl.intens = 1;
            VSO_LightVertex(&vl, VSO_AmbientLight, pv, ptv);
            VSO_LightVertex(&vl, VSO_DirectionalLight, pv, ptv);
            for (j = 0; j < VSO_NLights; j++) {
                VSL_PLight l;

                l = VSO_Lights[j];

                VSO_LightVertex(&vl, l, pv, ptv);
            }
            VSO_LightVertex(&vl, VSO_FogLight, pv, ptv);

            if (vl.intens > 1)      vl.intens = 1;
            else if (vl.intens < 0) vl.intens = 0;
            if (vl.r > 1)      vl.r = 1;
            else if (vl.r < 0) vl.r = 0;
            if (vl.g > 1)      vl.g = 1;
            else if (vl.g < 0) vl.g = 0;
            if (vl.b > 1)      vl.b = 1;
            else if (vl.b < 0) vl.b = 0;

//            ptv->a = vl.intens*(0xF000) + (0x0800);
//            ptv->r = vl.r*(240 << 8) + (8 << 8);
//            ptv->g = vl.g*(240 << 8) + (8 << 8);
//            ptv->b = vl.b*(240 << 8) + (8 << 8);

            ptv->a = vl.intens*(0xFFF0) + (0x0000);
            ptv->r = vl.r*(254 << 8) + (1 << 8);
            ptv->g = vl.g*(254 << 8) + (1 << 8);
            ptv->b = vl.b*(254 << 8) + (1 << 8);
        }
    }

        // Insert visible faces, clipping those that need it.
    for (i = mesh->nf, pf = mesh->f; i > 0; i--, pf++) {
        if (pf->visible) {
            VSDL_PPolygon el;
/*
            depth = 0;
            for (j = pf->nv, pfv = pf->v; j > 0; j--, pfv++)
                depth += GETTVERT(pfv).v.z;
            depth /= pf->nv;
*/
            pfv = pf->v;
            depth = GETTVERT(pfv).v.z;
            pfv++;
            for (j = pf->nv; j > 1; j--, pfv++)
                if (depth < GETTVERT(pfv).v.z)
                    depth = GETTVERT(pfv).v.z;
            if (depth < 1)
                depth = 1;
            if (pf->outcodes == 0) {
                    // Insert full face.
                el = (VSDL_PPolygon)VSDL_Add(scr->s, depth, VSDLET_POLY, VSDL_SIZEPOLY(pf->nv));
                if (el == NULL) // No room for more elements in depthlist.
                    break;
                for (j = pf->nv, pfv = pf->v, ppv = el->p;
                     j > 0;
                     j--, pfv++, ppv++) {
                    ptv = &(GETTVERT(pfv));
                    ppv->px = ptv->p.x;
                    ppv->py = ptv->p.y;
                    ppv->l = ptv->a;
                    ppv->r = ptv->r;
                    ppv->g = ptv->g;
                    ppv->b = ptv->b;
                    ppv->z = ptv->iz;
                    ppv->tx = pfv->t.x;
                    ppv->ty = pfv->t.y;
                }
                el->nv = pf->nv;
                el->mat = pf->m;
                el->flags = pf->m->flags;
            } else {
                VSO_TFaceVertex tempfacev[2][MAXFACEV];
                int ntempf = 0;
                int ncfv;

                    // Insert clipped face.
                    // Start by thinking that face is equal to the original.
                ncfv = pf->nv;
                pfv = pf->v;
                NTempVert = mesh->nv;   // Room for new temporary vertices.

                    // Step through the four splitting planes.
                    // Generating a new face array each time.
                for (j = 0; pfv != NULL && j < 4; j++) {
                    if (pf->outcodes & (1 << j)) {
                            // Face needs clipping against this plane.
                        pfv = VSO_ClipFace(tempfacev[ntempf], pfv, &ncfv, j, cam);
                        ntempf ^= 1;
                    }
                }
                if (pfv != NULL) {
                        // Get new element to place face into.
                    el = (VSDL_PPolygon)VSDL_Add(scr->s, depth, VSDLET_POLY, VSDL_SIZEPOLY(pf->nv+4));
                    if (el == NULL) // No room for more elements in depthlist.
                        break;

                        // Copy the final face vertex array.
                    for (j = ncfv, ppv = el->p;
                         j > 0;
                         j--, pfv++, ppv++) {
                        ptv = &(GETTVERT(pfv));
                        ppv->px = ptv->p.x;
                        ppv->py = ptv->p.y;
                        ppv->l = ptv->a;
                        ppv->r = ptv->r;
                        ppv->g = ptv->g;
                        ppv->b = ptv->b;
                        ppv->z = ptv->iz;
                        ppv->tx = pfv->t.x;
                        ppv->ty = pfv->t.y;
                    }
                    el->nv = ncfv;
                    el->mat = pf->m;
                    el->flags = pf->m->flags;
                }
            }
        }
    }
    return TRUE;
}

extern void VSO_LightVertex(VSL_PLightRGB vl, VSL_PLight l,
                            VSO_PVertex pv, VSO_PTempVertex ptv) {
    VSALG_TCoord a;

    if (l == NULL)
        return;

    switch(l->type) {
        case VSLT_AMBIENT:
            vl->intens -= l->rgb.intens;
            break;
        case VSLT_DIRECTIONAL:
            a = -VSALG_Dot3D(&pv->n, &l->dir.rd);
            if (a > 0) {
                a *= l->rgb.intens;
                vl->intens -= a;
                vl->r += a*l->rgb.r;
                vl->g += a*l->rgb.g;
                vl->b += a*l->rgb.b;
            }
            break;
        case VSLT_OMNI: {
            VSALG_T3DPoint d, nd;
            VSALG_TCoord dl, pl;

            VSALG_Sub3D(&d, &pv->v, &l->omni.rv);
            dl = VSALG_Dot3D(&d, &d);
            a = dl / l->omni.falloff;

            pl = VSALG_Dot3D(&pv->n, &d);
            if (pl > 0)
                a = a/(1.1 - pl/sqrt(dl));

            if (a > 0) {
                a = l->rgb.intens/(1.0+a);
                if (a > 1)      a = 1;
                else if (a < 0) a = 0;
                vl->intens -= a;
                vl->r += a*l->rgb.r;
                vl->g += a*l->rgb.g;
                vl->b += a*l->rgb.b;
            }
            break;
        }
        case VSLT_FOG: {
            VSALG_TCoord rad;

                // Reprocess light alpha.
//            vl->intens -= (vl->r + vl->g + vl->b)/14;
//            vl->intens -= (vl->r + vl->g + vl->b)/3;

            rad = VSALG_Length3D(&ptv->v);
//            rad = ptv->v.z;
            if (rad > l->fog.dmax) {
                vl->intens = 1;
                vl->r = l->rgb.r;
                vl->g = l->rgb.g;
                vl->b = l->rgb.b;
            } else if (rad > l->fog.dmin) {
                VSALG_TCoord dist;
                dist = l->fog.dmax - l->fog.dmin;
                a = (rad - l->fog.dmin)/dist;
                vl->intens = vl->intens*(1.0-a) + 1.0*a;
                vl->r = vl->r*(1.0-a) + l->rgb.r*a;
                vl->g = vl->g*(1.0-a) + l->rgb.g*a;
                vl->b = vl->b*(1.0-a) + l->rgb.b*a;
            }
            break;
        }
        default:
;//                        printf("nlights %d, this is %d, Unknown\n", VSO_NLights, j);
    }
}

extern VSDL_PLight VSO_DrawLight(VSV_PViewport scr,
                          VSALG_P3DPoint pos, VSL_PLightRGB rgbl,
                          VSB_PBitmap bm,
                          const VSC_TCamera *cam) {
    VSALG_T3DPoint cp, rp;
    VSALG_T2DPoint pp, pw;
    VSDL_PLight pl = NULL;

    VSALG_Sub3D(&cp, pos, &cam->c);
    VSALG_Rotate(&rp, &cp, &cam->im);
    if (rp.z > 1.0) {
        VSALG_TCoord iz;

        iz = 1.0 / rp.z;
        pw.x = cam->fx * 100 * rgbl->intens * iz;
        pw.y = cam->fy * 100 * rgbl->intens * iz;
        pp.x = cam->cx + cam->fx*rp.x*iz - pw.x/2;
        pp.y = cam->cy + cam->fy*rp.y*iz - pw.y/2;
        if (pp.x < -(1 << 15)
         || pp.y < -(1 << 15)
         || pp.x+pw.x > (1 << 15)
         || pp.y+pw.y > (1 << 15))
            return NULL;

        pl = (VSDL_PLight)VSDL_Add(scr->s,
                                   rp.z,
                                   VSDLET_LIGHT,
                                   VSDL_SIZELIGHT(pf->nv));
        if (pl != NULL) {
            pl->pb = bm;

            pl->w = VSPLY_Pix2Scr(pw.x);
            pl->h = VSPLY_Pix2Scr(pw.y);
            pl->x = VSPLY_Pix2Scr(pp.x);
            pl->y = VSPLY_Pix2Scr(pp.y);
            pl->nsat = 20;
            pl->n = 64;
            pl->r = 255*rgbl->r;
            pl->g = 255*rgbl->g;
            pl->b = 255*rgbl->b;
        }
    }
    return pl;
}

// ---------------------------- VSOBJECT.C -----------------------
#endif