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