public class Pipeline {
    
    
    // Scene variables.
    PolygonObject objList[], visObjList[], movedObjList[];
    int objects;
    
    CoordSysHeirarchy rootCoordSys[];
    
    Light lightList[];
    int lights;
    
    Matrix3D view;
    Matrix3D tran;
    
    // Camera spec.
    Vector3D eye;
    Vector3D lookat;
    Vector3D up;
    float fov;
    
    // Shading
    Shader shader;
    
    int shadingMethod = Constants.FLAT_SHADING;
    boolean backcull = true;
    
    // Image stuff.
    Raster raster;
    ZBuffer zbuf;
    
    public void Pipeline() 
    {
    }
    
    public void init(String filename, int width, int height) 
    {
        raster = new Raster(width, height);
        
        zbuf = new ZBuffer(width, height);
        
        lights = 0;
        growLights(Constants.CHUNKSIZE);
        
        Parser parser = new Parser();
        parser.readFile(filename, this);
        
        setupViewMatrix(firstProjectionMode);
        shader = new Shader(lightList, lights, eye);
        tran = new Matrix3D(raster);
        redrawRaster();
        
    }
        
    public void redrawRaster() 
    {  
        modelTransforms();          // modeling transformations
        backfaceCulling();          // backface culling   
        illumination();             // diffuse and specular illumination
        textureCoordinates();       // assign texture coords to vertices
        viewingTransform();         // viewing transformation
        clipping();                 // clipping
        screenTransform();          // to screen coordinates
        drawObjects();              // rasterization
        
    }
    
    public void modelTransforms() {
        for (int i=0; i < objects; ++i) {
            objList[i].modelTransforms();
        }
    }
    
    public void backfaceCulling() {
        for (int i=0; i < objects; ++i) {
            objList[i].backfaceCulling();
        }
    }
    
    public void illumination() {
        for (int i=0; i < objects; ++i) {
            objList[i].illumination();
        }
    }
    
    public void textureCoordinates() {
        for (int i=0; i < objects; ++i) {
            objList[i].textureCoordinates();
        }
    }
    
    public void viewingTransform() {
        setupViewMatrix(viewType);
        for (int i=0; i < objects; ++i) {
            objList[i].viewingTransform();
        }
    }
    
    int numfaces;
    public void clipping() {
        numfaces = 0;
        for (int i=0; i < objects; ++i) {
            numfaces += objList[i].clipping();
        }
    }
    
    public void screenTransform() {
        for (int i=0; i < objects; ++i) {
            objList[i].screenTransform();
        }
    }
    
    /**
     *  Draw points in the raster.
     */
    Vertex3D first = new Vertex3D();
    Warnock warnock = new Warnock();
    
    void drawObjects()
    {
        int k;
        for (k=0; k < 1; ++k) {
            //warnock.drawObjectsWarnock(this, numfaces);
            drawObjectsZBuffer();
            
        }
    }
    
    void drawObjectsZBuffer() {
        raster.clear();
        zbuf.clear();
        Triangle tri = new Triangle(zbuf, shader);
        tri.setBounds(-1, -1, 32767, 32767);
        for (int i=0; i < objects; ++i) {
            objList[i].drawObject(raster, tri);
        }
    }
    
    void setCullMode(boolean yesnomaybe) {
        backcull = yesnomaybe;
    }

    void setShadingType(int type) {
        shadingMethod = type;
    }

    int firstProjectionMode = Constants.PERSPECTIVE;
    int currentProjectionMode = -1;
    int viewType = Constants.PERSPECTIVE;
    
    void setProjectionType(int type) {
        viewType = type;
    }
    void setupViewMatrix(int mode)
    {   
        if (mode != currentProjectionMode) {
            currentProjectionMode = mode;
            view = new Matrix3D();
            
            float t = (float) Math.sin(Math.PI*(fov/2)/180);
            float s = (t*(float)raster.height)/(float)raster.width;
                    
            if (mode == Constants.PERSPECTIVE) {
                view.perspective(-t, t, -s, s, -1, -200);
            } else if (mode == Constants.ORTHOGRAPHIC) {
                view.orthographic(-t * 9, t * 9, -s * 9, s * 9, -1, -200);
            }
            view.lookAt(eye.x, eye.y, eye.z, lookat.x, lookat.y, lookat.z, up.x, up.y, up.z);
        }
    }
    
    public void growLights(int nextIndex) {
        if (lightList == null) {
            lightList = new Light[Constants.CHUNKSIZE];
        
        } else 
        if (lightList.length <= lights) {
            Light newList[] = new Light[lightList.length + Constants.CHUNKSIZE];
            System.arraycopy(lightList, 0, newList, 0, lightList.length);
            lightList = newList;
        }
    }
    
    public void growObjects(int numobj) {
        if (objList == null) {
            objList = new PolygonObject[Constants.CHUNKSIZE];
        }
        if (objList.length <= numobj) {
            int newlength = objList.length + Constants.CHUNKSIZE; 
            PolygonObject newList[] = new PolygonObject[newlength];
            System.arraycopy(objList, 0, newList, 0, objList.length);
            objList = newList;
        }
    }
    
    
}
