Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed
Renderer/Renderer.cpp@31:e681177037ef, 2019-04-05 (annotated)
- Committer:
- el17cd
- Date:
- Fri Apr 05 15:34:28 2019 +0000
- Revision:
- 31:e681177037ef
- Child:
- 33:02c5048b3b3f
Changed Rasturizer.cpp and Rasturizer.h to Renderer.cpp and Renderer.h, documented Renderer class
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
el17cd | 31:e681177037ef | 1 | #include "Renderer.h" |
el17cd | 31:e681177037ef | 2 | N5110 lcd(PTC9,PTC0,PTC7,PTD2,PTD1,PTC11); |
el17cd | 31:e681177037ef | 3 | |
el17cd | 31:e681177037ef | 4 | |
el17cd | 31:e681177037ef | 5 | Renderer::Renderer() { |
el17cd | 31:e681177037ef | 6 | for(int i = 0; i < 6; i++){ //set the selection cubes faces to visible |
el17cd | 31:e681177037ef | 7 | selectionCube.getFace(i).setVisible(true); |
el17cd | 31:e681177037ef | 8 | } |
el17cd | 31:e681177037ef | 9 | } |
el17cd | 31:e681177037ef | 10 | |
el17cd | 31:e681177037ef | 11 | void Renderer::init() { |
el17cd | 31:e681177037ef | 12 | lcd.init(); //initialize the lcd |
el17cd | 31:e681177037ef | 13 | fov = 50; //set the field of view to 50 |
el17cd | 31:e681177037ef | 14 | } |
el17cd | 31:e681177037ef | 15 | |
el17cd | 31:e681177037ef | 16 | float Renderer::xTo2D(float x, float z) { //Project 3D x coordinate to 2D perspective |
el17cd | 31:e681177037ef | 17 | return x * (fov/z) + 42; |
el17cd | 31:e681177037ef | 18 | } |
el17cd | 31:e681177037ef | 19 | |
el17cd | 31:e681177037ef | 20 | float Renderer::yTo2D(float y, float z){ //Project 3D y coordinate to 2D perspective |
el17cd | 31:e681177037ef | 21 | return y * (fov/z) + 21; |
el17cd | 31:e681177037ef | 22 | } |
el17cd | 31:e681177037ef | 23 | |
el17cd | 31:e681177037ef | 24 | void Renderer::drawHorizon(float angle){ //draw the line at the horizon |
el17cd | 31:e681177037ef | 25 | lcd.drawLine(0, |
el17cd | 31:e681177037ef | 26 | 21-rint(-angle*40), |
el17cd | 31:e681177037ef | 27 | 84, |
el17cd | 31:e681177037ef | 28 | 21+rint(-angle*40), |
el17cd | 31:e681177037ef | 29 | 1); |
el17cd | 31:e681177037ef | 30 | } |
el17cd | 31:e681177037ef | 31 | |
el17cd | 31:e681177037ef | 32 | void Renderer::drawFace(Face *face, float angle) { //Draw a single face from a cube |
el17cd | 31:e681177037ef | 33 | float points[4][3]; |
el17cd | 31:e681177037ef | 34 | float y, x; |
el17cd | 31:e681177037ef | 35 | |
el17cd | 31:e681177037ef | 36 | |
el17cd | 31:e681177037ef | 37 | for(int vertex = 0; vertex < 4; vertex++) { |
el17cd | 31:e681177037ef | 38 | for(int axis = 0; axis < 3; axis++) { |
el17cd | 31:e681177037ef | 39 | points[vertex][axis] = face->getVertexValue(vertex, axis); //copy all cube verticies to local array |
el17cd | 31:e681177037ef | 40 | } |
el17cd | 31:e681177037ef | 41 | y = points[vertex][1]; |
el17cd | 31:e681177037ef | 42 | x = points[vertex][0]; |
el17cd | 31:e681177037ef | 43 | |
el17cd | 31:e681177037ef | 44 | points[vertex][0] = x*cos(-angle)-y*sin(-angle); //perform temporary rotation for lean effect when moving in x axis |
el17cd | 31:e681177037ef | 45 | points[vertex][1] = y*cos(-angle)+x*sin(-angle); |
el17cd | 31:e681177037ef | 46 | } |
el17cd | 31:e681177037ef | 47 | |
el17cd | 31:e681177037ef | 48 | if (checkOnScreen(points)){ //if face is on the screen then fill the face and draw its outline |
el17cd | 31:e681177037ef | 49 | rasterizeFace(points, face); |
el17cd | 31:e681177037ef | 50 | drawFaceOutline(points); |
el17cd | 31:e681177037ef | 51 | } |
el17cd | 31:e681177037ef | 52 | } |
el17cd | 31:e681177037ef | 53 | |
el17cd | 31:e681177037ef | 54 | void Renderer::rasterizeFace(float (&points)[4][3], Face *face) { //Fill in the face using white lines |
el17cd | 31:e681177037ef | 55 | int diffX1, diffY1, diffX2, diffY2; |
el17cd | 31:e681177037ef | 56 | float stepBottomY, stepTopX, stepTopY; |
el17cd | 31:e681177037ef | 57 | diffX1 = xTo2D(points[0][0], points[0][2])-xTo2D(points[1][0], points[1][2]); //Calculate difference between top horizontal edge x coordnates |
el17cd | 31:e681177037ef | 58 | diffY1 = yTo2D(points[0][1], points[0][2])-yTo2D(points[1][1], points[1][2]); //Calculate difference between right vertical edge y coordinates |
el17cd | 31:e681177037ef | 59 | diffX2 = xTo2D(points[2][0], points[2][2])-xTo2D(points[3][0], points[3][2]); //Calculate difference between bottom horizontal edge x coordinates |
el17cd | 31:e681177037ef | 60 | diffY2 = yTo2D(points[2][1], points[2][2])-yTo2D(points[3][1], points[3][2]); //Calculate difference between left horizontal edge y coordinates |
el17cd | 31:e681177037ef | 61 | if(diffX2 != 0 && face->getVisible()) { |
el17cd | 31:e681177037ef | 62 | stepBottomY = (float)diffY2/(float)diffX2; //increment multiplier for Y axis on bottom edge of face |
el17cd | 31:e681177037ef | 63 | stepTopX = (float)diffX1/(float)diffX2; //increment multiplier for X axis on top edge of face |
el17cd | 31:e681177037ef | 64 | stepTopY = (float)diffY1/(float)diffX2; //increment multiplier for Y axis on top edge of face |
el17cd | 31:e681177037ef | 65 | |
el17cd | 31:e681177037ef | 66 | drawFillLines(points, diffX2, stepBottomY, stepTopX, stepTopY); //fill the face with white lines |
el17cd | 31:e681177037ef | 67 | } |
el17cd | 31:e681177037ef | 68 | } |
el17cd | 31:e681177037ef | 69 | |
el17cd | 31:e681177037ef | 70 | void Renderer::drawFillLines(float (&points)[4][3], |
el17cd | 31:e681177037ef | 71 | int diffX2, int stepBottomY, int stepTopX, int stepTopY) { //draw the white lines within the face to fill it in |
el17cd | 31:e681177037ef | 72 | |
el17cd | 31:e681177037ef | 73 | for(int step = 0; step< abs(diffX2); step++) { |
el17cd | 31:e681177037ef | 74 | if(diffX2 > 0) { //determine whether the face is inverted in y axis |
el17cd | 31:e681177037ef | 75 | 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 |
el17cd | 31:e681177037ef | 76 | rint(yTo2D(points[0][1], points[0][2])-stepTopY*step), |
el17cd | 31:e681177037ef | 77 | rint(xTo2D(points[3][0], points[3][2])+step), |
el17cd | 31:e681177037ef | 78 | rint(yTo2D(points[3][1], points[3][2])+stepBottomY*step), |
el17cd | 31:e681177037ef | 79 | 0); |
el17cd | 31:e681177037ef | 80 | } |
el17cd | 31:e681177037ef | 81 | else { |
el17cd | 31:e681177037ef | 82 | lcd.drawLine(rint(xTo2D(points[0][0], points[0][2])+stepTopX*step), |
el17cd | 31:e681177037ef | 83 | rint(yTo2D(points[0][1], points[0][2])+stepTopY*step), |
el17cd | 31:e681177037ef | 84 | rint(xTo2D(points[3][0], points[3][2])-step), |
el17cd | 31:e681177037ef | 85 | rint(yTo2D(points[3][1], points[3][2])-stepBottomY*step), |
el17cd | 31:e681177037ef | 86 | 0); |
el17cd | 31:e681177037ef | 87 | } |
el17cd | 31:e681177037ef | 88 | } |
el17cd | 31:e681177037ef | 89 | } |
el17cd | 31:e681177037ef | 90 | |
el17cd | 31:e681177037ef | 91 | void Renderer::drawFaceOutline(float(&points)[4][3]) { //Draw the outline of the face |
el17cd | 31:e681177037ef | 92 | for (int i = 0; i < 3; i++) { //cycle through each edge and draw them |
el17cd | 31:e681177037ef | 93 | lcd.drawLine(rint(xTo2D(points[i][0], points[i][2])), |
el17cd | 31:e681177037ef | 94 | rint(yTo2D(points[i][1], points[i][2])), |
el17cd | 31:e681177037ef | 95 | rint(xTo2D(points[i+1][0], points[i+1][2])), |
el17cd | 31:e681177037ef | 96 | rint(yTo2D(points[i+1][1], points[i+1][2])), |
el17cd | 31:e681177037ef | 97 | 1); |
el17cd | 31:e681177037ef | 98 | } |
el17cd | 31:e681177037ef | 99 | lcd.drawLine(rint(xTo2D(points[0][0], points[0][2])), |
el17cd | 31:e681177037ef | 100 | rint(yTo2D(points[0][1], points[0][2])), |
el17cd | 31:e681177037ef | 101 | rint(xTo2D(points[3][0], points[3][2])), |
el17cd | 31:e681177037ef | 102 | rint(yTo2D(points[3][1], points[3][2])), |
el17cd | 31:e681177037ef | 103 | 1); |
el17cd | 31:e681177037ef | 104 | } |
el17cd | 31:e681177037ef | 105 | |
el17cd | 31:e681177037ef | 106 | void Renderer::drawAllFaces(Face *faceArray, int noOfCubes, float angle) { //draw all faces in game |
el17cd | 31:e681177037ef | 107 | Face temp; |
el17cd | 31:e681177037ef | 108 | for (int f = 0; f< (noOfCubes*6)-1; f++) { //sort the faces in decreasing average z value using bubble sort |
el17cd | 31:e681177037ef | 109 | for (int f2 = 0; f2< (noOfCubes*6)-f-1; f2++) { |
el17cd | 31:e681177037ef | 110 | if(faceArray[f2].getAvgZ() < faceArray[f2+1].getAvgZ()) { |
el17cd | 31:e681177037ef | 111 | temp = faceArray[f2+1]; |
el17cd | 31:e681177037ef | 112 | faceArray[f2+1] = faceArray[f2]; |
el17cd | 31:e681177037ef | 113 | faceArray[f2] = temp; |
el17cd | 31:e681177037ef | 114 | } |
el17cd | 31:e681177037ef | 115 | } |
el17cd | 31:e681177037ef | 116 | } |
el17cd | 31:e681177037ef | 117 | for (int f = 0; f< noOfCubes*6 ; f++) { //draw each face from furthest away to closest |
el17cd | 31:e681177037ef | 118 | drawFace(&faceArray[f], angle/15); |
el17cd | 31:e681177037ef | 119 | } |
el17cd | 31:e681177037ef | 120 | } |
el17cd | 31:e681177037ef | 121 | |
el17cd | 31:e681177037ef | 122 | bool Renderer::checkOnScreen(float (&points)[4][3]) { //Check whether any part of the face is on screen |
el17cd | 31:e681177037ef | 123 | if (points[0][2] < 6 || points[1][2] < 6 || points[2][2] < 6 || points[3][2] < 6) { //not on screen if behind perspective |
el17cd | 31:e681177037ef | 124 | return false; |
el17cd | 31:e681177037ef | 125 | } |
el17cd | 31:e681177037ef | 126 | 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 |
el17cd | 31:e681177037ef | 127 | && (xTo2D(points[1][0], points[1][2]) < 0 || xTo2D(points[1][0], points[1][2]) > 84) |
el17cd | 31:e681177037ef | 128 | && (xTo2D(points[2][0], points[2][2]) < 0 || xTo2D(points[2][0], points[2][2]) > 84) |
el17cd | 31:e681177037ef | 129 | && (xTo2D(points[3][0], points[3][2]) < 0 || xTo2D(points[3][0], points[3][2]) > 84)){ |
el17cd | 31:e681177037ef | 130 | return false; |
el17cd | 31:e681177037ef | 131 | } |
el17cd | 31:e681177037ef | 132 | return true; |
el17cd | 31:e681177037ef | 133 | } |
el17cd | 31:e681177037ef | 134 | |
el17cd | 31:e681177037ef | 135 | void Renderer::print(const char *text, int x, int y) { //print string at x, y position |
el17cd | 31:e681177037ef | 136 | lcd.printString(text, x, y); |
el17cd | 31:e681177037ef | 137 | } |
el17cd | 31:e681177037ef | 138 | |
el17cd | 31:e681177037ef | 139 | void Renderer::printScore(int score, int x, int y) { //print a score at x, y position |
el17cd | 31:e681177037ef | 140 | char buffer[5]; |
el17cd | 31:e681177037ef | 141 | sprintf(buffer, "%d", score/3); |
el17cd | 31:e681177037ef | 142 | print(buffer, x, y); |
el17cd | 31:e681177037ef | 143 | memset(buffer, 0, sizeof buffer); |
el17cd | 31:e681177037ef | 144 | } |
el17cd | 31:e681177037ef | 145 | |
el17cd | 31:e681177037ef | 146 | void Renderer::clear() { //clear the display |
el17cd | 31:e681177037ef | 147 | lcd.clear(); |
el17cd | 31:e681177037ef | 148 | } |
el17cd | 31:e681177037ef | 149 | |
el17cd | 31:e681177037ef | 150 | void Renderer::refresh() { //refresh display and wait for 1/60th second (target fps = 60) |
el17cd | 31:e681177037ef | 151 | lcd.refresh(); |
el17cd | 31:e681177037ef | 152 | wait_ms(1000/60); |
el17cd | 31:e681177037ef | 153 | } |
el17cd | 31:e681177037ef | 154 | |
el17cd | 31:e681177037ef | 155 | void Renderer::turnOff() { //turn off the display |
el17cd | 31:e681177037ef | 156 | lcd.turnOff(); |
el17cd | 31:e681177037ef | 157 | } |
el17cd | 31:e681177037ef | 158 | |
el17cd | 31:e681177037ef | 159 | void Renderer::drawDeathScreen(int selection, int highScore) { //draw the screen once the user has collided with cube |
el17cd | 31:e681177037ef | 160 | Face faces[6]; |
el17cd | 31:e681177037ef | 161 | int x, y, z; |
el17cd | 31:e681177037ef | 162 | if(selection == 0){ //determine position of seleciton cube based on menu selection |
el17cd | 31:e681177037ef | 163 | x = -30; |
el17cd | 31:e681177037ef | 164 | y = -3; |
el17cd | 31:e681177037ef | 165 | z = 50; |
el17cd | 31:e681177037ef | 166 | } |
el17cd | 31:e681177037ef | 167 | else{ |
el17cd | 31:e681177037ef | 168 | x = -30; |
el17cd | 31:e681177037ef | 169 | y = 15; |
el17cd | 31:e681177037ef | 170 | z = 50; |
el17cd | 31:e681177037ef | 171 | } |
el17cd | 31:e681177037ef | 172 | |
el17cd | 31:e681177037ef | 173 | print("Best:", 30, 0); //print high score |
el17cd | 31:e681177037ef | 174 | printScore(highScore, 60, 0); |
el17cd | 31:e681177037ef | 175 | drawDeathButtons(); |
el17cd | 31:e681177037ef | 176 | drawSelectionCube(x, y, z, 2); |
el17cd | 31:e681177037ef | 177 | } |
el17cd | 31:e681177037ef | 178 | |
el17cd | 31:e681177037ef | 179 | void Renderer::drawDeathButtons() {//draw the death screen buttons |
el17cd | 31:e681177037ef | 180 | lcd.drawRect(24, 14, 45, 11, FILL_WHITE); |
el17cd | 31:e681177037ef | 181 | lcd.drawRect(24, 14, 45, 11, FILL_TRANSPARENT); |
el17cd | 31:e681177037ef | 182 | lcd.printString("Restart",26,2); |
el17cd | 31:e681177037ef | 183 | lcd.drawRect(24, 30, 45, 11, FILL_WHITE); |
el17cd | 31:e681177037ef | 184 | lcd.drawRect(24, 30, 45, 11, FILL_TRANSPARENT); |
el17cd | 31:e681177037ef | 185 | lcd.printString("Menu",35,4); |
el17cd | 31:e681177037ef | 186 | } |
el17cd | 31:e681177037ef | 187 | |
el17cd | 31:e681177037ef | 188 | void Renderer::drawHomeScreen(int selection) { //draw the home screen |
el17cd | 31:e681177037ef | 189 | int x, y, z; |
el17cd | 31:e681177037ef | 190 | if(selection == 0) { //determine position of selection cube based on home screen selection |
el17cd | 31:e681177037ef | 191 | x = -30; |
el17cd | 31:e681177037ef | 192 | y = -12; |
el17cd | 31:e681177037ef | 193 | z = 50; |
el17cd | 31:e681177037ef | 194 | } |
el17cd | 31:e681177037ef | 195 | else if(selection == 1) { |
el17cd | 31:e681177037ef | 196 | x = -30; |
el17cd | 31:e681177037ef | 197 | y = 5; |
el17cd | 31:e681177037ef | 198 | z = 50; |
el17cd | 31:e681177037ef | 199 | } |
el17cd | 31:e681177037ef | 200 | else { |
el17cd | 31:e681177037ef | 201 | x = -30; |
el17cd | 31:e681177037ef | 202 | y = 22; |
el17cd | 31:e681177037ef | 203 | z = 50; |
el17cd | 31:e681177037ef | 204 | } |
el17cd | 31:e681177037ef | 205 | drawHomeButtons(); |
el17cd | 31:e681177037ef | 206 | drawSelectionCube(x, y, z, -1); |
el17cd | 31:e681177037ef | 207 | } |
el17cd | 31:e681177037ef | 208 | |
el17cd | 31:e681177037ef | 209 | void Renderer::drawHomeButtons() { //draw home screen buttons |
el17cd | 31:e681177037ef | 210 | lcd.drawRect(24, 6, 45, 10, FILL_WHITE); |
el17cd | 31:e681177037ef | 211 | lcd.printString("Play",35,1); |
el17cd | 31:e681177037ef | 212 | lcd.drawRect(24, 6, 45, 10, FILL_TRANSPARENT); |
el17cd | 31:e681177037ef | 213 | |
el17cd | 31:e681177037ef | 214 | lcd.drawRect(24, 22, 45, 10, FILL_WHITE); |
el17cd | 31:e681177037ef | 215 | lcd.printString("Help",35,3); |
el17cd | 31:e681177037ef | 216 | lcd.drawRect(24, 22, 45, 10, FILL_TRANSPARENT); |
el17cd | 31:e681177037ef | 217 | |
el17cd | 31:e681177037ef | 218 | lcd.drawRect(24, 38, 45, 10, FILL_WHITE); |
el17cd | 31:e681177037ef | 219 | lcd.printString("Quit",35,5); |
el17cd | 31:e681177037ef | 220 | lcd.drawRect(24, 38, 45, 10, FILL_TRANSPARENT); |
el17cd | 31:e681177037ef | 221 | } |
el17cd | 31:e681177037ef | 222 | |
el17cd | 31:e681177037ef | 223 | void Renderer::drawSelectionCube(int x, int y, int z, int rotationSpeed) { //draw the seleciton cube |
el17cd | 31:e681177037ef | 224 | Face faces[6]; |
el17cd | 31:e681177037ef | 225 | selectionCube.translate(x, y, z); //translate from origin to required position |
el17cd | 31:e681177037ef | 226 | |
el17cd | 31:e681177037ef | 227 | for(int i = 0; i < 6; i++) { |
el17cd | 31:e681177037ef | 228 | faces[i] = selectionCube.getFace(i); |
el17cd | 31:e681177037ef | 229 | } |
el17cd | 31:e681177037ef | 230 | drawAllFaces(faces, 1, 0); //draw all faces of the cube |
el17cd | 31:e681177037ef | 231 | selectionCube.translate(-x, -y, -z); //translate back to origin |
el17cd | 31:e681177037ef | 232 | selectionCube.rotateX(-0.05*rotationSpeed); //rotate the cube |
el17cd | 31:e681177037ef | 233 | selectionCube.rotateY(-0.025*rotationSpeed); |
el17cd | 31:e681177037ef | 234 | selectionCube.rotateZ(0.04*rotationSpeed); |
el17cd | 31:e681177037ef | 235 | } |
el17cd | 31:e681177037ef | 236 | |
el17cd | 31:e681177037ef | 237 | void Renderer::drawHelpScreen1() { //draw the first help screen |
el17cd | 31:e681177037ef | 238 | lcd.printString("Use the",20,0); |
el17cd | 31:e681177037ef | 239 | lcd.printString("joystick",17,1); |
el17cd | 31:e681177037ef | 240 | lcd.printString("to move",20,2); |
el17cd | 31:e681177037ef | 241 | lcd.printString("left and right.",0,3); |
el17cd | 31:e681177037ef | 242 | lcd.printString("(Press A)",17,5); |
el17cd | 31:e681177037ef | 243 | } |
el17cd | 31:e681177037ef | 244 | |
el17cd | 31:e681177037ef | 245 | void Renderer::drawHelpScreen2(){ //draw the second help screen |
el17cd | 31:e681177037ef | 246 | lcd.printString("Dodge the",15,0); |
el17cd | 31:e681177037ef | 247 | lcd.printString("cubes as they",3,1); |
el17cd | 31:e681177037ef | 248 | lcd.printString("move closer",10,2); |
el17cd | 31:e681177037ef | 249 | lcd.printString("to you",25,3); |
el17cd | 31:e681177037ef | 250 | lcd.printString("(Press A)",17,5); |
el17cd | 31:e681177037ef | 251 | } |
el17cd | 31:e681177037ef | 252 | |
el17cd | 31:e681177037ef | 253 | void Renderer::drawHelpScreen3(){ //draw the third help screen |
el17cd | 31:e681177037ef | 254 | lcd.printString("Even the",17,0); |
el17cd | 31:e681177037ef | 255 | lcd.printString("smallest",17,1); |
el17cd | 31:e681177037ef | 256 | lcd.printString("touch can",15,2); |
el17cd | 31:e681177037ef | 257 | lcd.printString("kill you",17,3); |
el17cd | 31:e681177037ef | 258 | lcd.printString("(Press A)",17,5); |
el17cd | 31:e681177037ef | 259 | } |
el17cd | 31:e681177037ef | 260 | |
el17cd | 31:e681177037ef | 261 | void Renderer::drawHelpScreen4(){ //draw the fourth help screen |
el17cd | 31:e681177037ef | 262 | lcd.printString("Good luck!",15,1); |
el17cd | 31:e681177037ef | 263 | lcd.printString("(Press A)",17,5); |
el17cd | 31:e681177037ef | 264 | } |