ELEC2645 (2018/19) / Mbed 2 deprecated el17cd

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Renderer.cpp Source File

Renderer.cpp

00001 #include "Renderer.h"
00002 
00003 N5110 lcd(PTC9,PTC0,PTC7,PTD2,PTD1,PTC11);
00004 
00005 Renderer::Renderer() {
00006     selectionCube.setVisible();
00007 }
00008 
00009 void Renderer::init() {
00010     lcd.init(); //initialize the lcd
00011     fov = 50; //set the field of view to 50
00012 }
00013 
00014 
00015 float Renderer::xTo2D(float x, float z) { //Project 3D x coordinate to 2D perspective
00016     return x * (fov/z) + 42;
00017 }
00018 
00019 float Renderer::yTo2D(float y, float z){ //Project 3D y coordinate to 2D perspective
00020     return y * (fov/z) + 21;
00021 }
00022 
00023 void Renderer::drawHorizon(float angle){ //draw the line at the horizon
00024     lcd.drawLine(0,
00025              21-rint(-angle*40),
00026              84,
00027              21+rint(-angle*40),
00028              1);
00029 }
00030 
00031 void Renderer::drawFace(Face *face, float angle) { //Draw a single face from a cube
00032     float points[4][3];
00033     float y, x;
00034     
00035     for(int vertex = 0; vertex < 4; vertex++) {
00036         for(int axis = 0; axis < 3; axis++) {
00037             points[vertex][axis] = face->getVertexValue(vertex, axis); //copy all cube verticies to local array
00038         }
00039         y = points[vertex][1];
00040         x = points[vertex][0];
00041         
00042         points[vertex][0] = x*cos(-angle)-y*sin(-angle); //perform temporary rotation for lean effect when moving in x axis
00043         points[vertex][1] = y*cos(-angle)+x*sin(-angle);
00044     }
00045     
00046     if (checkOnScreen(points)){ //if face is on the screen then fill the face and draw its outline
00047         rasterizeFace(points, face);
00048         drawFaceOutline(points);
00049     }
00050 }
00051 
00052 void Renderer::rasterizeFace(float (&points)[4][3], Face *face) { //Fill in the face using white lines
00053     int diffX1, diffY1, diffX2, diffY2;
00054     float stepBottomY, stepTopX, stepTopY;
00055     diffX1 = xTo2D(points[0][0], points[0][2])-xTo2D(points[1][0],
00056     points[1][2]); //Calculate difference between top horizontal edge x coordnates
00057     diffY1 = yTo2D(points[0][1], points[0][2])-yTo2D(points[1][1],
00058     points[1][2]); //Calculate difference between right vertical edge y coordinates
00059     diffX2 = xTo2D(points[2][0], points[2][2])-xTo2D(points[3][0],
00060     points[3][2]); //Calculate difference between bottom horizontal edge x coordinates
00061     diffY2 = yTo2D(points[2][1], points[2][2])-yTo2D(points[3][1],
00062     points[3][2]); //Calculate difference between left horizontal edge y coordinates
00063     if(diffX2 != 0) {
00064         stepBottomY = (float)diffY2/(float)diffX2; //increment multiplier for Y axis on bottom edge of face
00065         stepTopX = (float)diffX1/(float)diffX2; //increment multiplier for X axis on top edge of face
00066         stepTopY = (float)diffY1/(float)diffX2; //increment multiplier for Y axis on top edge of face
00067         
00068         drawFillLines(points, diffX2, stepBottomY, stepTopX, stepTopY); //fill the face with white lines
00069     }
00070 }
00071 
00072 void Renderer::drawFillLines(float (&points)[4][3],
00073 int diffX2, int stepBottomY, int stepTopX, int stepTopY) { //draw the white lines within the face to fill it in
00074     
00075     for(int step = 0; step< abs(diffX2); step++) {
00076         if(diffX2 > 0) { //determine whether the face is inverted in y axis
00077             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
00078                 rint(yTo2D(points[0][1], points[0][2])-stepTopY*step),
00079                 rint(xTo2D(points[3][0], points[3][2])+step), 
00080                 rint(yTo2D(points[3][1], points[3][2])+stepBottomY*step),
00081                 0);
00082         }
00083         else {
00084             lcd.drawLine(rint(xTo2D(points[0][0], points[0][2])+stepTopX*step),
00085                 rint(yTo2D(points[0][1], points[0][2])+stepTopY*step),
00086                 rint(xTo2D(points[3][0], points[3][2])-step), 
00087                 rint(yTo2D(points[3][1], points[3][2])-stepBottomY*step),
00088                 0);
00089         }
00090     }
00091 }
00092 
00093 void Renderer::drawFaceOutline(float(&points)[4][3]) { //Draw the outline of the face
00094     for (int i = 0; i < 3; i++) { //cycle through each edge and draw them
00095         lcd.drawLine(rint(xTo2D(points[i][0], points[i][2])),
00096             rint(yTo2D(points[i][1], points[i][2])),
00097             rint(xTo2D(points[i+1][0], points[i+1][2])),
00098             rint(yTo2D(points[i+1][1], points[i+1][2])),
00099             1);
00100     }
00101     lcd.drawLine(rint(xTo2D(points[0][0], points[0][2])),
00102         rint(yTo2D(points[0][1], points[0][2])),
00103         rint(xTo2D(points[3][0], points[3][2])),
00104         rint(yTo2D(points[3][1], points[3][2])),
00105         1);
00106 }
00107 
00108 void Renderer::drawAllFaces(Face *faceArray, int noOfCubes, float angle) { //draw all faces in game using the painters algorithm
00109     Face temp;
00110     for (int f = 0; f< (noOfCubes*6)-1; f++) { //sort the faces in decreasing average z value using bubble sort
00111         for (int f2 = 0; f2< (noOfCubes*6)-f-1; f2++) {
00112             if(faceArray[f2].getAvgZ() < faceArray[f2+1].getAvgZ()) {
00113                 temp = faceArray[f2+1];
00114                 faceArray[f2+1] = faceArray[f2];
00115                 faceArray[f2] = temp;
00116             }
00117         }
00118     }
00119     for (int f = 0; f< noOfCubes*6 ; f++) { //draw each face from furthest away to closest
00120         if (faceArray[f].getVisible()) {
00121             drawFace(&faceArray[f], angle/15);
00122         }
00123     }
00124 }
00125 
00126 bool Renderer::checkOnScreen(float (&points)[4][3]) { //Check whether any part of the face is on screen
00127     if (points[0][2] < 6 || points[1][2] < 6 || points[2][2] < 6 ||
00128     points[3][2] < 6) { //not on screen if behind perspective
00129         return false;
00130     }
00131     else if ((xTo2D(points[0][0], points[0][2]) < 0 ||  xTo2D(points[0][0],
00132     points[0][2]) > 84) //check if any 2D projection verticies are within screen boundaries
00133     && (xTo2D(points[1][0], points[1][2]) < 0 ||  xTo2D(points[1][0],
00134     points[1][2]) > 84)
00135     && (xTo2D(points[2][0], points[2][2]) < 0 ||  xTo2D(points[2][0],
00136     points[2][2]) > 84)
00137     && (xTo2D(points[3][0], points[3][2]) < 0 ||  xTo2D(points[3][0],
00138     points[3][2]) > 84)){
00139         return false;
00140     }
00141     return true;
00142 }
00143 
00144 void Renderer::print(const char *text, int x, int y) { //print string at x, y position
00145     lcd.printString(text, x, y);
00146 }
00147 
00148 void Renderer::printScore(int score, int x, int y) { //print a score at x, y position
00149     char buffer[5];
00150     sprintf(buffer, "%d", score/3);
00151     print(buffer, x, y);
00152     memset(buffer, 0, sizeof buffer);    
00153 }
00154 
00155 void Renderer::clear() { //clear the display
00156     lcd.clear();
00157 }
00158 
00159 void Renderer::refresh() { //refresh display and wait for 1/60th second (target fps = 60)
00160     lcd.refresh();
00161     wait_ms(1000/60);
00162 }
00163 
00164 void Renderer::turnOff() { //turn off the display
00165     lcd.turnOff();
00166 }
00167 
00168 void Renderer::setContrast(float contrast) { //set the contrast of the display
00169     lcd.setContrast(contrast);
00170 }
00171 
00172 void Renderer::drawDeathScreen(int selection, int highScore) { //draw the screen once the user has collided with cube
00173     Face faces[6];
00174     int x, y, z;
00175     if(selection == 0){ //determine position of seleciton cube based on menu selection
00176         x = -30;
00177         y = -3;
00178         z = 50;
00179     }
00180     else{
00181         x = -30;
00182         y = 15;
00183         z = 50;
00184     }
00185     
00186     print("Best:", 30, 0); //print high score
00187     printScore(highScore, 60, 0);
00188     drawDeathButtons(); 
00189     drawSelectionCube(x, y, z, 2);
00190 }
00191 
00192 void Renderer::drawDeathButtons() {//draw the death screen buttons
00193     lcd.drawRect(24, 14, 45, 11, FILL_WHITE);
00194     lcd.drawRect(24, 14, 45, 11, FILL_TRANSPARENT);
00195     lcd.printString("Restart",26,2);
00196     lcd.drawRect(24, 30, 45, 11, FILL_WHITE);
00197     lcd.drawRect(24, 30, 45, 11, FILL_TRANSPARENT);
00198     lcd.printString("Menu",35,4);
00199 }
00200 
00201 void Renderer::drawHomeScreen(int selection) { //draw the home screen
00202     int x, y, z;
00203     if(selection == 0) { //determine position of selection cube based on home screen selection
00204         x = -30;
00205         y = -12;
00206         z = 50;
00207     }
00208     else if(selection == 1) {
00209         x = -30;
00210         y = 5;
00211         z = 50;
00212     }
00213     else {
00214         x = -30;
00215         y = 22;
00216         z = 50;
00217     }
00218     drawHomeButtons();
00219     drawSelectionCube(x, y, z, -1);
00220 }
00221 
00222 void Renderer::drawHomeButtons() { //draw home screen buttons
00223     lcd.drawRect(24, 6, 45, 10, FILL_WHITE);
00224     lcd.printString("Play",35,1);
00225     lcd.drawRect(24, 6, 45, 10, FILL_TRANSPARENT);
00226 
00227     lcd.drawRect(24, 22, 45, 10, FILL_WHITE);
00228     lcd.printString("Help",35,3);
00229     lcd.drawRect(24, 22, 45, 10, FILL_TRANSPARENT);
00230 
00231     lcd.drawRect(24, 38, 45, 10, FILL_WHITE);
00232     lcd.printString("Quit",35,5);
00233     lcd.drawRect(24, 38, 45, 10, FILL_TRANSPARENT);
00234 }
00235 
00236 void Renderer::drawSelectionCube(int x, int y, int z, int rotationSpeed) { //draw the seleciton cube
00237     Face faces[6];
00238     selectionCube.translate(x, y, z); //translate from origin to required position
00239     
00240     for(int i = 0; i < 6; i++) {
00241         faces[i] = selectionCube.getFace(i);
00242     }
00243     drawAllFaces(faces, 1, 0); //draw all faces of the cube
00244     selectionCube.translate(-x, -y, -z); //translate back to origin
00245     selectionCube.rotateX(-0.05*rotationSpeed); //rotate the cube
00246     selectionCube.rotateY(-0.025*rotationSpeed);
00247     selectionCube.rotateZ(0.04*rotationSpeed);
00248 }
00249 
00250 void Renderer::drawHelpScreen1() { //draw the first help screen
00251     lcd.printString("Use the",20,0);
00252     lcd.printString("joystick",17,1);
00253     lcd.printString("to move",20,2);
00254     lcd.printString("left and right.",0,3);
00255     lcd.printString("(Press B)",17,5);
00256 }
00257 
00258 void Renderer::drawHelpScreen2(){ //draw the second help screen
00259     lcd.printString("Dodge the",15,0);
00260     lcd.printString("cubes as they",3,1);
00261     lcd.printString("move closer",10,2);
00262     lcd.printString("to you",25,3);
00263     lcd.printString("(Press B)",17,5);
00264 }
00265 
00266 void Renderer::drawHelpScreen3(){ //draw the third help screen
00267     lcd.printString("Even the",17,0);
00268     lcd.printString("smallest",17,1);
00269     lcd.printString("touch can",15,2);
00270     lcd.printString("kill you",17,3);
00271     lcd.printString("(Press B)",17,5);
00272 }
00273 
00274 void Renderer::drawHelpScreen4(){ //draw the fourth help screen
00275     lcd.printString("Good luck!",15,1);
00276     lcd.printString("(Press B)",17,5);
00277 }