ELEC2645 (2018/19) / Mbed 2 deprecated el17cd

Dependencies:   mbed

Revision:
31:e681177037ef
Child:
33:02c5048b3b3f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Renderer/Renderer.cpp	Fri Apr 05 15:34:28 2019 +0000
@@ -0,0 +1,264 @@
+#include "Renderer.h"
+N5110 lcd(PTC9,PTC0,PTC7,PTD2,PTD1,PTC11);
+
+
+Renderer::Renderer() {
+    for(int i = 0; i < 6; i++){ //set the selection cubes faces to visible
+        selectionCube.getFace(i).setVisible(true);
+    }
+}
+
+void Renderer::init() {
+    lcd.init(); //initialize the lcd
+    fov = 50; //set the field of view to 50
+}
+
+float Renderer::xTo2D(float x, float z) { //Project 3D x coordinate to 2D perspective
+    return x * (fov/z) + 42;
+}
+
+float Renderer::yTo2D(float y, float z){ //Project 3D y coordinate to 2D perspective
+    return y * (fov/z) + 21;
+}
+
+void Renderer::drawHorizon(float angle){ //draw the line at the horizon
+    lcd.drawLine(0,
+             21-rint(-angle*40),
+             84,
+             21+rint(-angle*40),
+             1);
+}
+
+void Renderer::drawFace(Face *face, float angle) { //Draw a single face from a cube
+    float points[4][3];
+    float y, x;
+
+    
+    for(int vertex = 0; vertex < 4; vertex++) {
+        for(int axis = 0; axis < 3; axis++) {
+            points[vertex][axis] = face->getVertexValue(vertex, axis); //copy all cube verticies to local array
+        }
+        y = points[vertex][1];
+        x = points[vertex][0];
+        
+        points[vertex][0] = x*cos(-angle)-y*sin(-angle); //perform temporary rotation for lean effect when moving in x axis
+        points[vertex][1] = y*cos(-angle)+x*sin(-angle);
+    }
+    
+    if (checkOnScreen(points)){ //if face is on the screen then fill the face and draw its outline
+        rasterizeFace(points, face);
+        drawFaceOutline(points);
+    }
+}
+
+void Renderer::rasterizeFace(float (&points)[4][3], Face *face) { //Fill in the face using white lines
+    int diffX1, diffY1, diffX2, diffY2;
+    float stepBottomY, stepTopX, stepTopY;
+    diffX1 = xTo2D(points[0][0], points[0][2])-xTo2D(points[1][0], points[1][2]); //Calculate difference between top horizontal edge x coordnates
+    diffY1 = yTo2D(points[0][1], points[0][2])-yTo2D(points[1][1], points[1][2]); //Calculate difference between right vertical edge y coordinates
+    diffX2 = xTo2D(points[2][0], points[2][2])-xTo2D(points[3][0], points[3][2]); //Calculate difference between bottom horizontal edge x coordinates
+    diffY2 = yTo2D(points[2][1], points[2][2])-yTo2D(points[3][1], points[3][2]); //Calculate difference between left horizontal edge y coordinates
+    if(diffX2 != 0 && face->getVisible()) {
+        stepBottomY = (float)diffY2/(float)diffX2; //increment multiplier for Y axis on bottom edge of face
+        stepTopX = (float)diffX1/(float)diffX2; //increment multiplier for X axis on top edge of face
+        stepTopY = (float)diffY1/(float)diffX2; //increment multiplier for Y axis on top edge of face
+        
+        drawFillLines(points, diffX2, stepBottomY, stepTopX, stepTopY); //fill the face with white lines
+    }
+}
+
+void Renderer::drawFillLines(float (&points)[4][3],
+int diffX2, int stepBottomY, int stepTopX, int stepTopY) { //draw the white lines within the face to fill it in
+    
+    for(int step = 0; step< abs(diffX2); step++) {
+        if(diffX2 > 0) { //determine whether the face is inverted in y axis
+            lcd.drawLine(rint(xTo2D(points[0][0], points[0][2])-stepTopX*step), //draw lines from top edge to bottom edge until face is filled in
+                rint(yTo2D(points[0][1], points[0][2])-stepTopY*step),
+                rint(xTo2D(points[3][0], points[3][2])+step), 
+                rint(yTo2D(points[3][1], points[3][2])+stepBottomY*step),
+                0);
+        }
+        else {
+            lcd.drawLine(rint(xTo2D(points[0][0], points[0][2])+stepTopX*step),
+                rint(yTo2D(points[0][1], points[0][2])+stepTopY*step),
+                rint(xTo2D(points[3][0], points[3][2])-step), 
+                rint(yTo2D(points[3][1], points[3][2])-stepBottomY*step),
+                0);
+        }
+    }
+}
+
+void Renderer::drawFaceOutline(float(&points)[4][3]) { //Draw the outline of the face
+    for (int i = 0; i < 3; i++) { //cycle through each edge and draw them
+        lcd.drawLine(rint(xTo2D(points[i][0], points[i][2])),
+            rint(yTo2D(points[i][1], points[i][2])),
+            rint(xTo2D(points[i+1][0], points[i+1][2])),
+            rint(yTo2D(points[i+1][1], points[i+1][2])),
+            1);
+    }
+    lcd.drawLine(rint(xTo2D(points[0][0], points[0][2])),
+        rint(yTo2D(points[0][1], points[0][2])),
+        rint(xTo2D(points[3][0], points[3][2])),
+        rint(yTo2D(points[3][1], points[3][2])),
+        1);
+}
+
+void Renderer::drawAllFaces(Face *faceArray, int noOfCubes, float angle) { //draw all faces in game
+    Face temp;
+    for (int f = 0; f< (noOfCubes*6)-1; f++) { //sort the faces in decreasing average z value using bubble sort
+        for (int f2 = 0; f2< (noOfCubes*6)-f-1; f2++) {
+            if(faceArray[f2].getAvgZ() < faceArray[f2+1].getAvgZ()) {
+                temp = faceArray[f2+1];
+                faceArray[f2+1] = faceArray[f2];
+                faceArray[f2] = temp;
+            }
+        }
+    }
+    for (int f = 0; f< noOfCubes*6 ; f++) { //draw each face from furthest away to closest
+        drawFace(&faceArray[f], angle/15);
+    }
+}
+
+bool Renderer::checkOnScreen(float (&points)[4][3]) { //Check whether any part of the face is on screen
+    if (points[0][2] < 6 || points[1][2] < 6 || points[2][2] < 6 || points[3][2] < 6) { //not on screen if behind perspective
+        return false;
+    }
+    else if ((xTo2D(points[0][0], points[0][2]) < 0 ||  xTo2D(points[0][0], points[0][2]) > 84) //check if any 2D projection verticies are within screen boundaries
+    && (xTo2D(points[1][0], points[1][2]) < 0 ||  xTo2D(points[1][0], points[1][2]) > 84)
+    && (xTo2D(points[2][0], points[2][2]) < 0 ||  xTo2D(points[2][0], points[2][2]) > 84)
+    && (xTo2D(points[3][0], points[3][2]) < 0 ||  xTo2D(points[3][0], points[3][2]) > 84)){
+        return false;
+    }
+    return true;
+}
+
+void Renderer::print(const char *text, int x, int y) { //print string at x, y position
+    lcd.printString(text, x, y);
+}
+
+void Renderer::printScore(int score, int x, int y) { //print a score at x, y position
+    char buffer[5];
+    sprintf(buffer, "%d", score/3);
+    print(buffer, x, y);
+    memset(buffer, 0, sizeof buffer);    
+}
+
+void Renderer::clear() { //clear the display
+    lcd.clear();
+}
+
+void Renderer::refresh() { //refresh display and wait for 1/60th second (target fps = 60)
+    lcd.refresh();
+    wait_ms(1000/60);
+}
+
+void Renderer::turnOff() { //turn off the display
+    lcd.turnOff();
+}
+
+void Renderer::drawDeathScreen(int selection, int highScore) { //draw the screen once the user has collided with cube
+    Face faces[6];
+    int x, y, z;
+    if(selection == 0){ //determine position of seleciton cube based on menu selection
+        x = -30;
+        y = -3;
+        z = 50;
+    }
+    else{
+        x = -30;
+        y = 15;
+        z = 50;
+    }
+    
+    print("Best:", 30, 0); //print high score
+    printScore(highScore, 60, 0);
+    drawDeathButtons(); 
+    drawSelectionCube(x, y, z, 2);
+}
+
+void Renderer::drawDeathButtons() {//draw the death screen buttons
+    lcd.drawRect(24, 14, 45, 11, FILL_WHITE);
+    lcd.drawRect(24, 14, 45, 11, FILL_TRANSPARENT);
+    lcd.printString("Restart",26,2);
+    lcd.drawRect(24, 30, 45, 11, FILL_WHITE);
+    lcd.drawRect(24, 30, 45, 11, FILL_TRANSPARENT);
+    lcd.printString("Menu",35,4);
+}
+
+void Renderer::drawHomeScreen(int selection) { //draw the home screen
+    int x, y, z;
+    if(selection == 0) { //determine position of selection cube based on home screen selection
+        x = -30;
+        y = -12;
+        z = 50;
+    }
+    else if(selection == 1) {
+        x = -30;
+        y = 5;
+        z = 50;
+    }
+    else {
+        x = -30;
+        y = 22;
+        z = 50;
+    }
+    drawHomeButtons();
+    drawSelectionCube(x, y, z, -1);
+}
+
+void Renderer::drawHomeButtons() { //draw home screen buttons
+    lcd.drawRect(24, 6, 45, 10, FILL_WHITE);
+    lcd.printString("Play",35,1);
+    lcd.drawRect(24, 6, 45, 10, FILL_TRANSPARENT);
+
+    lcd.drawRect(24, 22, 45, 10, FILL_WHITE);
+    lcd.printString("Help",35,3);
+    lcd.drawRect(24, 22, 45, 10, FILL_TRANSPARENT);
+
+    lcd.drawRect(24, 38, 45, 10, FILL_WHITE);
+    lcd.printString("Quit",35,5);
+    lcd.drawRect(24, 38, 45, 10, FILL_TRANSPARENT);
+}
+
+void Renderer::drawSelectionCube(int x, int y, int z, int rotationSpeed) { //draw the seleciton cube
+    Face faces[6];
+    selectionCube.translate(x, y, z); //translate from origin to required position
+    
+    for(int i = 0; i < 6; i++) {
+        faces[i] = selectionCube.getFace(i);
+    }
+    drawAllFaces(faces, 1, 0); //draw all faces of the cube
+    selectionCube.translate(-x, -y, -z); //translate back to origin
+    selectionCube.rotateX(-0.05*rotationSpeed); //rotate the cube
+    selectionCube.rotateY(-0.025*rotationSpeed);
+    selectionCube.rotateZ(0.04*rotationSpeed);
+}
+
+void Renderer::drawHelpScreen1() { //draw the first help screen
+    lcd.printString("Use the",20,0);
+    lcd.printString("joystick",17,1);
+    lcd.printString("to move",20,2);
+    lcd.printString("left and right.",0,3);
+    lcd.printString("(Press A)",17,5);
+}
+
+void Renderer::drawHelpScreen2(){ //draw the second help screen
+    lcd.printString("Dodge the",15,0);
+    lcd.printString("cubes as they",3,1);
+    lcd.printString("move closer",10,2);
+    lcd.printString("to you",25,3);
+    lcd.printString("(Press A)",17,5);
+}
+
+void Renderer::drawHelpScreen3(){ //draw the third help screen
+    lcd.printString("Even the",17,0);
+    lcd.printString("smallest",17,1);
+    lcd.printString("touch can",15,2);
+    lcd.printString("kill you",17,3);
+    lcd.printString("(Press A)",17,5);
+}
+
+void Renderer::drawHelpScreen4(){ //draw the fourth help screen
+    lcd.printString("Good luck!",15,1);
+    lcd.printString("(Press A)",17,5);
+}
\ No newline at end of file