Newer
Older
EPQ-3D-renderer / src / main / java / uk / org / floop / epq3d / Triangle.java
package uk.org.floop.epq3d;

import java.awt.*;
import java.awt.image.BufferedImage;

public class Triangle{
    public Point2D point1;
    public Point2D point2;
    public Point2D point3;

    public Matrix[] perspectiveMappingMatrix;

    public boolean[] edgeList; //edge 1-2 , 2-3, 3-1

    private Line2d LineLong;
    private Line2d LineA;
    private Line2d LineB;

    public Texture texture;

    // initialisation variables
    private boolean is_initialised = false;
    private Point2D min;
    private Point2D max;
    // progress variables
    private Point3D result = new Point3D(0,0,0);
    private Point2D result2 = new Point2D(0,0);
    public void invalidate() {
        is_initialised = false;
    }
    public Triangle(Point2D _pA, Point2D _pB, Point2D _pC, boolean[] _edgeList, Texture _texture, Matrix[] mapMatrix){
        point1 = _pA;
        point2 = _pB;
        point3 = _pC;
        edgeList = _edgeList;
        texture = _texture;
        perspectiveMappingMatrix = mapMatrix;
    }
    //  returns int for debug
    public int draw(BufferedImage img, BufferedImage zBuf, double FPDis, int scrX, int scrY){
        //
        long lastMillis;


        if (!is_initialised){initialise();}
        int[] point1;
        int[] point2;
        char currentLine = 'A';

        lastMillis = System.currentTimeMillis();

        point1 = LineLong.nextPix();
        point2 = LineA.nextPix();
        for(int x = min.x+1; x <= max.x; x += 1) {
            while(x-1 == point1[0]) {
                if(LineLong.isDrawn && // draw line pixels if needed, and on screen
                        point1[0] > 0 && point1[1] > 0 && point1[0] < img.getWidth() && point1[1] < img.getHeight()){
                    img.setRGB(point1[0], point1[1], Color.HSBtoRGB(0, 1, 1));
                }
                try { // this error seems to be thrown randomly, for various reasons // todo fix
                    point1 = LineLong.nextPix();
                }
                catch (Exception e){
                    throw new RuntimeException("accessed too many line pixels");
                }
            }
            while(x-1 == point2[0]) {
                if (currentLine == 'A') {
                    try{
                        if(LineA.isDrawn &&                // draw line pixels if needed, and on screen
                                point2[0] > 0 && point2[1] > 0 && point2[0] < img.getWidth() && point2[1] < img.getHeight()){
                            img.setRGB(point2[0], point2[1], Color.HSBtoRGB(0f, 1, 1));
                        }
                        point2 = LineA.nextPix();
                    }
                    catch (RuntimeException e){
                        currentLine = 'B';
                        // point2 = LineB.nextPix();
                    }
                }
                else {
                    if(LineB.isDrawn &&                // draw line pixels if needed, and on screen
                            point2[0] > 0 && point2[1] > 0 && point2[0] < img.getWidth() && point2[1] < img.getHeight()){
                        img.setRGB(point2[0], point2[1], Color.HSBtoRGB(0f, 1, 1));
                    }
                    point2 = LineB.nextPix();
                }
            }
            // cancel drawing if the x value of the triangle is out of bounds
            if (x >= img.getWidth()) {break;}
            if (x > 0) {
                // check which way to loop
                // TODO - work out a way of not needing to test for this every time
                if (point1[1] < point2[1]) {
                    for (int y = Math.max(point1[1], 0); y <= Math.min(point2[1], img.getHeight() - 1); y += 1) {
                        // function only exists so I don't have to copy paste code everywhere.
                        drawPix(img, zBuf, FPDis, scrX, scrY, currentLine, x, y, point1[1], point2[1]);
                    }
                } else {
                    for (int y = Math.max(point2[1], 0); y <= Math.min(point1[1], img.getHeight() - 1); y += 1) {
                        drawPix(img, zBuf, FPDis, scrX, scrY, currentLine, x,y, point1[1], point2[1]);
                    }
                }
            }
        }
        lastMillis = (System.currentTimeMillis() - lastMillis);
        return (int)lastMillis;
    }
    public void initialise(){
        if (point1 == null || point2 == null || point3 == null){
            throw new NullPointerException();
        }
        min = new Point2D(Math.min(point1.x, Math.min(point2.x, point3.x)), Math.min(point1.y, Math.min(point2.y, point3.y)));
        max = new Point2D(Math.max(point1.x, Math.max(point2.x, point3.x)), Math.max(point1.y, Math.max(point2.y, point3.y)));
        // woo horrible IFs mess.
        // we need to figure out which points touch the edges in order to find which line is the 'full length' edge,
        // and then assign line A and line B in order
        if (point1.x == min.x) {
            if (point2.x == max.x){
                LineLong = new Line2d(point1, point2, edgeList[0]);
                LineA = new Line2d(point1, point3, edgeList[2]);
                LineB = new Line2d(point3, point2, edgeList[1]);
            } else {
                LineLong = new Line2d(point1, point3, edgeList[2]);
                LineA = new Line2d(point1, point2, edgeList[0]);
                LineB = new Line2d(point2, point3, edgeList[1]);
            }
        }
        else if (point2.x == min.x) {
            if (point1.x == max.x) {
                LineLong = new Line2d(point2, point1, edgeList[0]);
                LineA = new Line2d(point2, point3, edgeList[1]);
                LineB = new Line2d(point3, point1, edgeList[2]);
            } else {
                LineLong = new Line2d(point2, point3, edgeList[1]);
                LineA = new Line2d(point2, point1, edgeList[0]);
                LineB = new Line2d(point1, point3, edgeList[2]);
            }
        }
        else if (point3.x == min.x){
            if (point1.x == max.x) {
                LineLong = new Line2d(point3, point1, edgeList[2]);
                LineA = new Line2d(point3, point2, edgeList[1]);
                LineB = new Line2d(point2, point1, edgeList[0]);
            } else {
                LineLong = new Line2d(point3, point2, edgeList[2]);
                LineA = new Line2d(point3, point1, edgeList[1]);
                LineB = new Line2d(point1, point2, edgeList[0]);
            }
        }
        // assign points to lines
        is_initialised = true;
    }
    private void drawPix(BufferedImage img, BufferedImage zBuf, double FPDis, int scrX, int scrY, char currentLine, int x, int y, int y1, int y2){
        // find Z coordinate of pixel
        double z1 = LineLong.getZVal(x); double z2;
        if(currentLine=='A'){z2=LineA.getZVal(x);} else{z2=LineB.getZVal(x);}
        double ZVal = z1 + ((z1-z2)/ (y1-y2) * (y - y1));

        // a value of 0 represents a value which is on the camera, at z=0.
        // not the best mapping but it's probably good enough
        int newZ = (int)((2147483648L/ZVal));
        // if the new Z value is greater than the existing Z value on the buffer, the new pixel is calculated and drawn
        if(zBuf.getRGB(x, y) == Color.HSBtoRGB(0, 0, 0) ||
        newZ > zBuf.getRGB(x, y)){ //newZ > zBuf.getRGB(x, y) ||
            zBuf.setRGB(x, y, newZ);
            result = new Point3D(0,0,0);
            //perspectiveMappingMatrix.multiplyPoint3to(new Point3D(x, y, 0), result);
            // project result
            Color pixColor;
            if(texture.isSolid()){
                pixColor = texture.color;
            } else {
                throw new RuntimeException("Textures are not supported");
            }
            img.setRGB(x, y, pixColor.getRGB());
//            result.projectOn(FPDis, scrX, scrY, result2);
//            int colour = texture.img.getRGB(
//                    Math.floorMod((result2.x), texture.img.getWidth()),
//                    Math.floorMod((result2.y), texture.img.getHeight()));
//            img.setRGB(x, y, (colour - 10*(result2.x/ texture.img.getWidth()) - 10*(result2.y/ texture.img.getHeight())));
        }
    }
}