/**
 *  Unimplemented.
 */

public class Warnock {
    float xmin[], xmax[], ymin[], ymax[], zmin[], zmax[];
    Face face[];
    Raster raster;
    int shadingMethod;
    
    Warnock() {
    }
    
    void getBoundsMem(int numfaces) {
        xmin = new float[numfaces];
        ymin = new float[numfaces];
        zmin = new float[numfaces];
        xmax = new float[numfaces];
        ymax = new float[numfaces];
        zmax = new float[numfaces];
        face = new Face[numfaces];
        
    }
    
    
    void drawObjectsWarnock(Pipeline p, int numfaces)
    {
        raster = p.raster;
        
        
        tri = new Triangle(p.zbuf, p.shader);
        float T = 0, L = 0, R = (float)(raster.width -1), B = (float)(raster.height -1);
        int i,j,k,m;
        int index[];
        float low = 0;
        float hix = R;
        float hiy = B;
        float hiz = 32767;
        Vector3D v;
        PolygonObject s;
        Face f;
        
        if (xmin == null || xmin.length < numfaces) getBoundsMem(numfaces);
        
        for (i=0; i < numfaces; ++i) {
            xmax[i] = ymax[i] = zmax[i] = low;
            xmin[i] = hix;
            ymin[i] = hiy;
            zmin[i] = hiz;
        }
        
        for (i=0, m=0; i < p.objects; ++i) {
            s = p.objList[i];
            for (j=0; j < s.clipfaces; ++j) {
                if (s.faceInvisible[j]) continue;
                face[m] = s.faceList[j];
                face[m].vs = s.tranList;
                face[m++].computePlaneEqnW();
            }
        }
        numfaces = m;
        
        for (m=0; m < numfaces; ++m) {
            f = face[m];
            for (k=0; k < f.num; ++k) {
                v = f.vs[f.index[k]];
                xmin[m] = (v.x < xmin[m]) ? (float)v.x : xmin[m];
                xmax[m] = (v.x > xmax[m]) ? (float)v.x : xmax[m];
                ymin[m] = (v.y < ymin[m]) ? (float)v.y : ymin[m];
                ymax[m] = (v.y > ymax[m]) ? (float)v.y : ymax[m];
                zmin[m] = (v.z < zmin[m]) ? (float)v.z : zmin[m];
                zmax[m] = (v.z > zmax[m]) ? (float)v.z : zmax[m];
            }
            xmax[m] += Constants.EPSILON;
            xmin[m] -= Constants.EPSILON;
            ymax[m] += Constants.EPSILON;
            ymin[m] -= Constants.EPSILON;
            zmax[m] += Constants.EPSILON;
            zmin[m] -= Constants.EPSILON;
        }
        
        if (inside == null || inside[0].length < numfaces) {
            inside = new int [20][numfaces];
            for (i=0; i < numfaces; ++i) {
                inside[0][i] = i;
            }
        }
        
    
        warnockRec(numfaces, L, T, R, B, 1);
        
    }
    
    Triangle tri;
    int inside[][];
    
    void warnockRec(int numfaces, float L, float T, float R, float B, int depth) { 
        int i,m,j;
        float z;
        float zLTmin, zLBmin, zRTmin, zRBmin;
        int zLTind, zLBind, zRTind, zRBind;
        zLTmin = zLBmin = zRTmin = zRBmin = 32767.0f;
        zLTind = zLBind = zRTind = -1;
        zRBind = -2;
        Face f=null;
        
        int curinside[] = inside[depth-1];
        int newinside[] = inside[depth];
        
        boolean Tyes;
        boolean Byes;
        
        int nondisjoint = 0;
        for (i=0; i < numfaces; ++i) {
            m=curinside[i];
            if (xmin[m] > R || xmax[m] < L || ymin[m] > B || ymax[m] < T) {
                continue;
            }
            
            f = face[m];
            newinside[nondisjoint++] = m;
            Tyes = false;
            Byes = false;
            if (L > xmin[m] && L < xmax[m]) {
                if (T > ymin[m] && T < ymax[m]) {
                    Tyes = true;
                    if (zmin[m] < zLTmin) {
                        z = (-f.D - f.A * L  - f.B * T) * f.C_1;
                        if (z > zmin[m]  &&  z < zmax[m]  &&  z < zLTmin) { 
                            if (
                                (f.a0 * L + f.b0 * T + f.c0 <= 0.0f) &&
                                (f.a1 * L + f.b1 * T + f.c1 <= 0.0f) &&
                                (f.a2 * L + f.b2 * T + f.c2 <= 0.0f) 
                            ) {
                                zLTmin = z; zLTind = m;
                            }
                        }
                    }
                } 
                if (B > ymin[m] && B < ymax[m]) {
                    Byes = true;
                    if (zmin[m] < zLBmin) {
                        z = (-f.D - f.A * L  - f.B * B) * f.C_1;
                        if (z > zmin[m]  &&  z < zmax[m]  &&  z < zLBmin) {
                            if (
                                (f.a0 * L + f.b0 * B + f.c0 <= 0.0f) &&
                                (f.a1 * L + f.b1 * B + f.c1 <= 0.0f) &&
                                (f.a2 * L + f.b2 * B + f.c2 <= 0.0f) 
                            ) {
                                zLBmin = z; zLBind = m;
                            }
                        }
                    }
                }
            }
            if (R > xmin[m] && R < xmax[m]) {
                if (Tyes || (T > ymin[m] && T < ymax[m])) {
                    if (zmin[m] < zRTmin) {
                        z = (-f.D - f.A * R  - f.B * T) * f.C_1;
                        if (z > zmin[m]  &&  z < zmax[m]  &&  z < zRTmin) { 
                            if (
                                (f.a0 * R + f.b0 * T + f.c0 <= 0.0f) &&
                                (f.a1 * R + f.b1 * T + f.c1 <= 0.0f) &&
                                (f.a2 * R + f.b2 * T + f.c2 <= 0.0f) 
                            ) {
                                zRTmin = z; zRTind = m;
                            }
                        }
                    }
                }
                if (Byes || (B > ymin[m] && B < ymax[m])) {
                    if (zmin[m] < zRBmin) {
                        z = (-f.D - f.A * R  - f.B * B) * f.C_1;
                        if (z > zmin[m]  &&  z < zmax[m]  &&  z < zRBmin) { 
                            if (
                                (f.a0 * R + f.b0 * B + f.c0 <= 0.0f) &&
                                (f.a1 * R + f.b1 * B + f.c1 <= 0.0f) &&
                                (f.a2 * R + f.b2 * B + f.c2 <= 0.0f) 
                            ) {
                                zRBmin = z; zRBind = m;
                            }
                        }
                    }
                }
            }
        }
        
        if ((zLTind == zLBind)  && (zLBind == zRTind) && (zRTind == zRBind)) {
            // surrounding polygon in front
            f = face[zLTind];
            raster.fill(f.c, (int)L, (int)T, (int)R, (int)B);
            return;
        }
        
        
        if (nondisjoint == 0) {
            // nothing inside
            raster.fill(0xff000000, (int)L, (int)T, (int)R, (int)B);
            return;
        } else if (nondisjoint == 1) {
            // one intersecting or one contained polygon
            raster.fill(0xff000000, (int)L, (int)T, (int)R, (int)B);
            for (j=0; j < f.num-2; ++j) {                
                tri.init(f.vs[f.index[0]], f.vs[f.index[j+1]], f.vs[f.index[j+2]]);
                tri.setBounds((int)L, (int)T, (int)R, (int)B);
                tri.Draw(raster, f.c, f.surface, shadingMethod);
            }
            return;
        }
        if (R-L < .8f && B-T < .8f) {
            // area smaller than pixel            
            //L = (L+R)/2.0f;
            //T = (T+B)/2.0f;
            float min = 32767.0f;
            int ind = -1;
            for (i=0; i < numfaces; ++i) {
                m=curinside[i];
                
                if (xmin[m] > L || xmax[m] < L || ymin[m] > T || ymax[m] < T) 
                    continue;
                
                f = face[m];
                z = (-f.D - f.A * L  - f.B * T) * f.C_1;
                if (z < min) {
                    if (
                        (f.a0 * L + f.b0 * T + f.c0 <= 0.0f) &&
                        (f.a1 * L + f.b1 * T + f.c1 <= 0.0f) &&
                        (f.a2 * L + f.b2 * T + f.c2 <= 0.0f) 
                    ) {
                        ind = m;
                        min = z;
                    }
                }
            }
            if (ind != -1)
                raster.pixel[(int)((int)T*raster.width + (int)L)] = face[ind].c;
            else 
                raster.pixel[(int)((int)T*raster.width + (int)L)] = 0xff000000;
                
            return;
        }  
        warnockRec(nondisjoint, L, T, (L+R) / 2.0f, (T+B) / 2.0f, depth +1);
        warnockRec(nondisjoint, L, (T+B) / 2.0f, (L+R) / 2.0f, B, depth +1);
        warnockRec(nondisjoint, (L+R) / 2.0f, T, R, (T+B) / 2.0f, depth +1);
        warnockRec(nondisjoint, (L+R) / 2.0f, (T+B) / 2.0f, R, B, depth +1);
    }
}



/*
public class Warnock {
    short xmin[], xmax[], ymin[], ymax[], zmin[], zmax[];
    Face face[];
    Raster raster;
    int shadingMethod;
    
    Warnock() {
    }
    
    void getBoundsMem(int numfaces) {
        xmin = new short[numfaces];
        ymin = new short[numfaces];
        zmin = new short[numfaces];
        xmax = new short[numfaces];
        ymax = new short[numfaces];
        zmax = new short[numfaces];
        face = new Face[numfaces];
        
    }
    
    
    void drawObjectsWarnock(Pipeline p, int numfaces)
    {
        raster = p.raster;
        
        
        tri = new Triangle(p.zbuf, p.shader);
        short T = 0, L = 0, R = (short)(raster.width -1), B = (short)(raster.height -1);
        int i,j,k,m;
        int index[];
        short low = 0;
        short hix = R;
        short hiy = B;
        short hiz = 32767;
        Vector3D v;
        PolygonObject s;
        Face f;
        
        if (xmin == null || xmin.length < numfaces) getBoundsMem(numfaces);
        
        for (i=0; i < numfaces; ++i) {
            xmax[i] = ymax[i] = zmax[i] = low;
            xmin[i] = hix;
            ymin[i] = hiy;
            zmin[i] = hiz;
        }
        
        for (i=0, m=0; i < p.objects; ++i) {
            s = p.objList[i];
            for (j=0; j < s.faces; ++j) {
                if (s.faceInvisible[j]) continue;
                face[m] = s.faceList[j];
                face[m].w = s.tranList;
                face[m++].computePlaneEqnW();
            }
        }
        numfaces = m;
        
        for (m=0; m < numfaces; ++m) {
            f = face[m];
            for (k=0; k < f.num; ++k) {
                v = f.w[f.index[k]];
                xmin[m] = (v.x < xmin[m]) ? (short)v.x : xmin[m];
                xmax[m] = (v.x > xmax[m]) ? (short)v.x : xmax[m];
                ymin[m] = (v.y < ymin[m]) ? (short)v.y : ymin[m];
                ymax[m] = (v.y > ymax[m]) ? (short)v.y : ymax[m];
                zmin[m] = (v.z < zmin[m]) ? (short)v.z : zmin[m];
                zmax[m] = (v.z > zmax[m]) ? (short)v.z : zmax[m];
            }
        }
        
        if (inside == null) {
            inside = new int [20][numfaces];
            for (i=0; i < numfaces; ++i) {
                inside[0][i] = i;
            }
        }
        
    
        warnockRec(numfaces, L, T, R, B, 1);
        
    }
    
    Triangle tri;
    int inside[][];
    
    void warnockRec(int numfaces, int L, int T, int R, int B, int depth) { 
        int i,m,j;
        float z;
        float zLTmin, zLBmin, zRTmin, zRBmin;
        int zLTind, zLBind, zRTind, zRBind;
        zLTmin = zLBmin = zRTmin = zRBmin = 32767;
        zLTind = zLBind = zRTind = -1;
        zRBind = -2;
        Face f=null;
        
        int curinside[] = inside[depth-1];
        int newinside[] = inside[depth];
        
        boolean Tyes;
        boolean Byes;
        
        int nondisjoint = 0;
        for (i=0; i < numfaces; ++i) {
            m=curinside[i];
            if (xmin[m] > R || xmax[m] < L || ymin[m] > B || ymax[m] < T) {
                continue;
            }
            
            f = face[m];
            newinside[nondisjoint++] = m;
            Tyes = false;
            Byes = false;
            if (L > xmin[m] && L < xmax[m]) {
                if (T > ymin[m] && T < ymax[m]) {
                    Tyes = true;
                    if (zmin[m] < zLTmin) {
                        z = (-f.D - f.A * L  - f.B * T) * f.C_1;
                        if (z > zmin[m]  &&  z < zmax[m]  &&  z < zLTmin) { 
                            if (
                                (f.a0 * L + f.b0 * T + f.c0 < 0.0f) &&
                                (f.a1 * L + f.b1 * T + f.c1 < 0.0f) &&
                                (f.a2 * L + f.b2 * T + f.c2 < 0.0f) 
                            ) {
                                zLTmin = z; zLTind = m;
                            }
                        }
                    }
                } 
                if (B > ymin[m] && B < ymax[m]) {
                    Byes = true;
                    if (zmin[m] < zLBmin) {
                        z = (-f.D - f.A * L  - f.B * B) * f.C_1;
                        if (z > zmin[m]  &&  z < zmax[m]  &&  z < zLBmin) {
                            if (
                                (f.a0 * L + f.b0 * B + f.c0 < 0.0f) &&
                                (f.a1 * L + f.b1 * B + f.c1 < 0.0f) &&
                                (f.a2 * L + f.b2 * B + f.c2 < 0.0f) 
                            ) {
                                zLBmin = z; zLBind = m;
                            }
                        }
                    }
                }
            }
            if (R > xmin[m] && R < xmax[m]) {
                if (Tyes || (T > ymin[m] && T < ymax[m])) {
                    if (zmin[m] < zRTmin) {
                        z = (-f.D - f.A * R  - f.B * T) * f.C_1;
                        if (z > zmin[m]  &&  z < zmax[m]  &&  z < zRTmin) { 
                            if (
                                (f.a0 * R + f.b0 * T + f.c0 < 0.0f) &&
                                (f.a1 * R + f.b1 * T + f.c1 < 0.0f) &&
                                (f.a2 * R + f.b2 * T + f.c2 < 0.0f) 
                            ) {
                                zRTmin = z; zRTind = m;
                            }
                        }
                    }
                }
                if (Byes || (B > ymin[m] && B < ymax[m])) {
                    if (zmin[m] < zRBmin) {
                        z = (-f.D - f.A * R  - f.B * B) * f.C_1;
                        if (z > zmin[m]  &&  z < zmax[m]  &&  z < zRBmin) { 
                            if (
                                (f.a0 * R + f.b0 * B + f.c0 < 0.0f) &&
                                (f.a1 * R + f.b1 * B + f.c1 < 0.0f) &&
                                (f.a2 * R + f.b2 * B + f.c2 < 0.0f) 
                            ) {
                                zRBmin = z; zRBind = m;
                            }
                        }
                    }
                }
            }
        }
        
        if ((zLTind == zLBind)  && (zLBind == zRTind) && (zRTind == zRBind)) {
            // surrounding polygon in front
            f = face[zLTind];
            raster.fill(f.c, (int)L, (int)T, (int)R, (int)B);
            return;
        }
        
        
        if (nondisjoint == 0) {
            // nothing inside
            raster.fill(0xff000000, (int)L, (int)T, (int)R, (int)B);
            return;
        } else if (nondisjoint == 1) {
            // one intersecting or one contained polygon
            raster.fill(0xff000000, (int)L, (int)T, (int)R, (int)B);
            for (j=0; j < f.num-2; ++j) {                
                tri.init(f.w[f.index[0]], f.w[f.index[j+1]], f.w[f.index[j+2]]);
                tri.setBounds((int)L, (int)T, (int)R, (int)B);
                tri.Draw(raster, f.c, f.surface, shadingMethod);
            }
            return;
        }
        if (R-L <= 1 && B-T <= 1) {
            // area smaller than pixel            
            L = (L+R)/2;
            T = (T+B)/2;
            float min = 32767.0f;
            int ind = -1;
            for (i=0; i < numfaces; ++i) {
                m=curinside[i];
                
                if (xmin[m] > L || xmax[m] < L || ymin[m] > T || ymax[m] < T) 
                    continue;
                
                f = face[m];
                z = (-f.D - f.A * L  - f.B * T) * f.C_1;
                if (z < min) {
                    if (
                        (f.a0 * L + f.b0 * T + f.c0 < 0.0f) &&
                        (f.a1 * L + f.b1 * T + f.c1 < 0.0f) &&
                        (f.a2 * L + f.b2 * T + f.c2 < 0.0f) 
                    ) {
                        ind = m;
                        min = z;
                    }
                }
            }
            if (ind != -1)
                raster.pixel[(int)((int)T*raster.width + (int)L)] = face[ind].c;
            else 
                raster.pixel[(int)((int)T*raster.width + (int)L)] = 0xff000000;
                
            return;
        }  
        warnockRec(nondisjoint, L, T, (L+R) / 2, (T+B)/2, depth +1);
        warnockRec(nondisjoint, L, (T+B)/2, (L+R)/2, B, depth +1);
        warnockRec(nondisjoint, (L+R)/2, T, R, (T+B)/2, depth +1);
        warnockRec(nondisjoint, (L+R)/2, (T+B)/2, R, B, depth +1);
    }
}

*/