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