“Race Collision” is a one player game in which a truck has to avoid “particles” that appear on the road. By the use of the joystick, the player can guide themselves through the menu system to start the game. The truck is the main element of the game and it can be moved from side to side with the joystick. The road curves randomly from time to time and the player has to be careful to keep the truck within the road boundaries. Particles appear on the screen at random positions and 4 collisions lead to the end of the game.

Dependencies:   ELEC2645_JoystickLCD_LPC1768_2021

Committer:
alex_20
Date:
Thu Apr 22 16:33:42 2021 +0000
Revision:
7:559edc36f261
Parent:
6:40ef2030334c
Child:
8:1fc5e14b0db6
first ellipse;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
eencae 0:be41a15e7a86 1 #include "mbed.h"
eencae 0:be41a15e7a86 2 #include "N5110.h"
alex_20 3:cbe2dcca5058 3
eencae 0:be41a15e7a86 4
eencae 0:be41a15e7a86 5 // overloaded constructor includes power pin - LCD Vcc connected to GPIO pin
eencae 0:be41a15e7a86 6 // this constructor works fine with LPC1768 - enough current sourced from GPIO
eencae 0:be41a15e7a86 7 // to power LCD. Doesn't work well with K64F.
eencae 0:be41a15e7a86 8 N5110::N5110(PinName const pwrPin,
eencae 0:be41a15e7a86 9 PinName const scePin,
eencae 0:be41a15e7a86 10 PinName const rstPin,
eencae 0:be41a15e7a86 11 PinName const dcPin,
eencae 0:be41a15e7a86 12 PinName const mosiPin,
eencae 0:be41a15e7a86 13 PinName const sclkPin,
eencae 0:be41a15e7a86 14 PinName const ledPin)
eencae 0:be41a15e7a86 15 :
eencae 0:be41a15e7a86 16 _spi(new SPI(mosiPin,NC,sclkPin)), // create new SPI instance and initialise
eencae 0:be41a15e7a86 17 _led(new DigitalOut(ledPin)),
eencae 0:be41a15e7a86 18 _pwr(new DigitalOut(pwrPin)),
eencae 0:be41a15e7a86 19 _sce(new DigitalOut(scePin)),
eencae 0:be41a15e7a86 20 _rst(new DigitalOut(rstPin)),
eencae 0:be41a15e7a86 21 _dc(new DigitalOut(dcPin))
eencae 0:be41a15e7a86 22 {}
eencae 0:be41a15e7a86 23
eencae 0:be41a15e7a86 24 // overloaded constructor does not include power pin - LCD Vcc must be tied to +3V3
eencae 0:be41a15e7a86 25 // Best to use this with K64F as the GPIO hasn't sufficient output current to reliably
eencae 0:be41a15e7a86 26 // drive the LCD.
eencae 0:be41a15e7a86 27 N5110::N5110(PinName const scePin,
eencae 0:be41a15e7a86 28 PinName const rstPin,
eencae 0:be41a15e7a86 29 PinName const dcPin,
eencae 0:be41a15e7a86 30 PinName const mosiPin,
eencae 0:be41a15e7a86 31 PinName const sclkPin,
eencae 0:be41a15e7a86 32 PinName const ledPin)
eencae 0:be41a15e7a86 33 :
eencae 0:be41a15e7a86 34 _spi(new SPI(mosiPin,NC,sclkPin)), // create new SPI instance and initialise
eencae 0:be41a15e7a86 35 _led(new DigitalOut(ledPin)),
eencae 0:be41a15e7a86 36 _pwr(NULL), // pwr not needed so null it to be safe
eencae 0:be41a15e7a86 37 _sce(new DigitalOut(scePin)),
eencae 0:be41a15e7a86 38 _rst(new DigitalOut(rstPin)),
eencae 0:be41a15e7a86 39 _dc(new DigitalOut(dcPin))
eencae 0:be41a15e7a86 40 {}
eencae 0:be41a15e7a86 41
eencae 0:be41a15e7a86 42
eencae 0:be41a15e7a86 43 N5110::~N5110()
eencae 0:be41a15e7a86 44 {
eencae 0:be41a15e7a86 45 delete _spi;
eencae 0:be41a15e7a86 46
eencae 0:be41a15e7a86 47 if(_pwr) {
eencae 0:be41a15e7a86 48 delete _pwr;
eencae 0:be41a15e7a86 49 }
eencae 0:be41a15e7a86 50
eencae 0:be41a15e7a86 51 delete _led;
eencae 0:be41a15e7a86 52 delete _sce;
eencae 0:be41a15e7a86 53 delete _rst;
eencae 0:be41a15e7a86 54 delete _dc;
eencae 0:be41a15e7a86 55 }
eencae 0:be41a15e7a86 56
eencae 0:be41a15e7a86 57 // initialise function - powers up and sends the initialisation commands
eencae 0:be41a15e7a86 58 void N5110::init()
eencae 0:be41a15e7a86 59 {
eencae 0:be41a15e7a86 60 turnOn(); // power up
eencae 0:be41a15e7a86 61 reset(); // reset LCD - must be done within 100 ms
eencae 0:be41a15e7a86 62 initSPI();
eencae 0:be41a15e7a86 63
eencae 0:be41a15e7a86 64 backLightOn();
eencae 0:be41a15e7a86 65 setContrast(0.55); // this may need tuning (say 0.4 to 0.6)
eencae 0:be41a15e7a86 66 setBias(3); // datasheet - 48:1 mux - don't mess with if you don't know what you're doing! (0 to 7)
eencae 0:be41a15e7a86 67 setTempCoefficient(0); // datasheet - may need increasing (range 0 to 3) at very low temperatures
eencae 0:be41a15e7a86 68 normalMode(); // normal video mode by default
eencae 0:be41a15e7a86 69
eencae 0:be41a15e7a86 70 clearRAM(); // RAM is undefined at power-up so clear to be sure
eencae 0:be41a15e7a86 71 clear(); // clear buffer
eencae 0:be41a15e7a86 72 }
eencae 0:be41a15e7a86 73
eencae 0:be41a15e7a86 74 // sets normal video mode (black on white)
eencae 0:be41a15e7a86 75 void N5110::normalMode()
eencae 0:be41a15e7a86 76 {
eencae 0:be41a15e7a86 77 sendCommand(0b00100000); // basic instruction
eencae 0:be41a15e7a86 78 sendCommand(0b00001100); // normal video mode- datasheet
eencae 0:be41a15e7a86 79 }
eencae 0:be41a15e7a86 80
eencae 0:be41a15e7a86 81 // sets normal video mode (white on black)
eencae 0:be41a15e7a86 82 void N5110::inverseMode()
eencae 0:be41a15e7a86 83 {
eencae 0:be41a15e7a86 84 sendCommand(0b00100000); // basic instruction
eencae 0:be41a15e7a86 85 sendCommand(0b00001101); // inverse video mode - datasheet
eencae 0:be41a15e7a86 86 }
eencae 0:be41a15e7a86 87
eencae 0:be41a15e7a86 88 // function to power up the LCD and backlight - only works when using GPIO to power
eencae 0:be41a15e7a86 89 void N5110::turnOn()
eencae 0:be41a15e7a86 90 {
eencae 0:be41a15e7a86 91 if (_pwr != NULL) {
eencae 0:be41a15e7a86 92 _pwr->write(1); // apply power
eencae 0:be41a15e7a86 93 }
eencae 0:be41a15e7a86 94 }
eencae 0:be41a15e7a86 95
eencae 0:be41a15e7a86 96 // function to power down LCD
eencae 0:be41a15e7a86 97 void N5110::turnOff()
eencae 0:be41a15e7a86 98 {
eencae 0:be41a15e7a86 99 clear(); // clear buffer
eencae 0:be41a15e7a86 100 refresh();
eencae 0:be41a15e7a86 101 backLightOff(); // turn backlight off
eencae 0:be41a15e7a86 102 clearRAM(); // clear RAM to ensure specified current consumption
eencae 0:be41a15e7a86 103 // send command to ensure we are in basic mode
eencae 0:be41a15e7a86 104
eencae 0:be41a15e7a86 105 sendCommand(0b00100000); // basic mode
eencae 0:be41a15e7a86 106 sendCommand(0b00001000); // clear display
eencae 0:be41a15e7a86 107 sendCommand(0b00100001); // extended mode
eencae 0:be41a15e7a86 108 sendCommand(0b00100100); // power down
eencae 0:be41a15e7a86 109
eencae 0:be41a15e7a86 110 // if we are powering the LCD using the GPIO then make it low to turn off
eencae 0:be41a15e7a86 111 if (_pwr != NULL) {
eencae 0:be41a15e7a86 112 wait_ms(10); // small delay and then turn off the power pin
eencae 0:be41a15e7a86 113 _pwr->write(0); // turn off power
eencae 0:be41a15e7a86 114 }
eencae 0:be41a15e7a86 115
eencae 0:be41a15e7a86 116 }
eencae 0:be41a15e7a86 117
eencae 0:be41a15e7a86 118 // function to change LED backlight brightness
eencae 0:be41a15e7a86 119 void N5110::backLightOn()
eencae 0:be41a15e7a86 120 {
eencae 0:be41a15e7a86 121 _led->write(1);
eencae 0:be41a15e7a86 122 }
eencae 0:be41a15e7a86 123
eencae 0:be41a15e7a86 124 // function to change LED backlight brightness
eencae 0:be41a15e7a86 125 void N5110::backLightOff()
eencae 0:be41a15e7a86 126 {
eencae 0:be41a15e7a86 127 _led->write(0);
eencae 0:be41a15e7a86 128 }
eencae 0:be41a15e7a86 129
eencae 0:be41a15e7a86 130 void N5110::setContrast(float contrast) {
eencae 0:be41a15e7a86 131
eencae 0:be41a15e7a86 132 // enforce limits
eencae 0:be41a15e7a86 133 if (contrast > 1.0f)
eencae 0:be41a15e7a86 134 contrast = 1.0f;
eencae 0:be41a15e7a86 135 else if (contrast < 0.0f)
eencae 0:be41a15e7a86 136 contrast = 0.0;
eencae 0:be41a15e7a86 137
eencae 0:be41a15e7a86 138 // convert to char in range 0 to 127 (i.e. 6 bits)
eencae 0:be41a15e7a86 139 char ic = char(contrast*127.0f);
eencae 0:be41a15e7a86 140
eencae 0:be41a15e7a86 141 sendCommand(0b00100001); // extended instruction set
eencae 0:be41a15e7a86 142 sendCommand(0b10000000 | ic); // set Vop (which controls contrast)
eencae 0:be41a15e7a86 143 sendCommand(0b00100000); // back to basic instruction set
eencae 0:be41a15e7a86 144 }
eencae 0:be41a15e7a86 145
eencae 0:be41a15e7a86 146 void N5110::setTempCoefficient(char tc) {
eencae 0:be41a15e7a86 147
eencae 0:be41a15e7a86 148 // enforce limits
eencae 0:be41a15e7a86 149 if (tc>3) {
eencae 0:be41a15e7a86 150 tc=3;
eencae 0:be41a15e7a86 151 }
eencae 0:be41a15e7a86 152
eencae 0:be41a15e7a86 153 // temperature coefficient may need increasing at low temperatures
eencae 0:be41a15e7a86 154
eencae 0:be41a15e7a86 155 sendCommand(0b00100001); // extended instruction set
eencae 0:be41a15e7a86 156 sendCommand(0b00000100 | tc);
eencae 0:be41a15e7a86 157 sendCommand(0b00100000); // back to basic instruction set
eencae 0:be41a15e7a86 158 }
eencae 0:be41a15e7a86 159
eencae 0:be41a15e7a86 160 void N5110::setBias(char bias) {
eencae 0:be41a15e7a86 161
eencae 0:be41a15e7a86 162 // from data sheet
eencae 0:be41a15e7a86 163 // bias mux rate
eencae 0:be41a15e7a86 164 // 0 1:100
eencae 0:be41a15e7a86 165 // 1 1:80
eencae 0:be41a15e7a86 166 // 2 1:65
eencae 0:be41a15e7a86 167 // 3 1:48 (default)
eencae 0:be41a15e7a86 168 // 4 1:40/1:34
eencae 0:be41a15e7a86 169 // 5 1:24
eencae 0:be41a15e7a86 170 // 6 1:18/1:16
eencae 0:be41a15e7a86 171 // 7 1:10/1:9/1:8
eencae 0:be41a15e7a86 172
eencae 0:be41a15e7a86 173 // enforce limits
eencae 0:be41a15e7a86 174 if (bias>7) {
eencae 0:be41a15e7a86 175 bias=7;
eencae 0:be41a15e7a86 176 }
eencae 0:be41a15e7a86 177
eencae 0:be41a15e7a86 178 sendCommand(0b00100001); // extended mode instruction
eencae 0:be41a15e7a86 179 sendCommand(0b00010000 | bias);
eencae 0:be41a15e7a86 180 sendCommand(0b00100000); // end of extended mode instruction
eencae 0:be41a15e7a86 181 }
eencae 0:be41a15e7a86 182
eencae 0:be41a15e7a86 183 // pulse the active low reset line
eencae 0:be41a15e7a86 184 void N5110::reset()
eencae 0:be41a15e7a86 185 {
eencae 0:be41a15e7a86 186 _rst->write(0); // reset the LCD
eencae 0:be41a15e7a86 187 _rst->write(1);
eencae 0:be41a15e7a86 188 }
eencae 0:be41a15e7a86 189
eencae 0:be41a15e7a86 190 // function to initialise SPI peripheral
eencae 0:be41a15e7a86 191 void N5110::initSPI()
eencae 0:be41a15e7a86 192 {
eencae 0:be41a15e7a86 193 _spi->format(8,1); // 8 bits, Mode 1 - polarity 0, phase 1 - base value of clock is 0, data captured on falling edge/propagated on rising edge
eencae 0:be41a15e7a86 194 _spi->frequency(4000000); // maximum of screen is 4 MHz
eencae 0:be41a15e7a86 195 }
eencae 0:be41a15e7a86 196
eencae 0:be41a15e7a86 197 // send a command to the display
eencae 0:be41a15e7a86 198 void N5110::sendCommand(unsigned char command)
eencae 0:be41a15e7a86 199 {
eencae 0:be41a15e7a86 200 _dc->write(0); // set DC low for command
eencae 0:be41a15e7a86 201 _sce->write(0); // set CE low to begin frame
eencae 0:be41a15e7a86 202 _spi->write(command); // send command
eencae 0:be41a15e7a86 203 _dc->write(1); // turn back to data by default
eencae 0:be41a15e7a86 204 _sce->write(1); // set CE high to end frame (expected for transmission of single byte)
eencae 0:be41a15e7a86 205 }
eencae 0:be41a15e7a86 206
eencae 0:be41a15e7a86 207 // send data to the display at the current XY address
eencae 0:be41a15e7a86 208 // dc is set to 1 (i.e. data) after sending a command and so should
eencae 0:be41a15e7a86 209 // be the default mode.
eencae 0:be41a15e7a86 210 void N5110::sendData(unsigned char data)
eencae 0:be41a15e7a86 211 {
eencae 0:be41a15e7a86 212 _sce->write(0); // set CE low to begin frame
eencae 0:be41a15e7a86 213 _spi->write(data);
eencae 0:be41a15e7a86 214 _sce->write(1); // set CE high to end frame (expected for transmission of single byte)
eencae 0:be41a15e7a86 215 }
eencae 0:be41a15e7a86 216
eencae 0:be41a15e7a86 217 // this function writes 0 to the 504 bytes to clear the RAM
eencae 0:be41a15e7a86 218 void N5110::clearRAM()
eencae 0:be41a15e7a86 219 {
eencae 0:be41a15e7a86 220 _sce->write(0); //set CE low to begin frame
eencae 0:be41a15e7a86 221 for(int i = 0; i < WIDTH * HEIGHT; i++) { // 48 x 84 bits = 504 bytes
eencae 0:be41a15e7a86 222 _spi->write(0x00); // send 0's
eencae 0:be41a15e7a86 223 }
eencae 0:be41a15e7a86 224 _sce->write(1); // set CE high to end frame
eencae 0:be41a15e7a86 225 }
eencae 0:be41a15e7a86 226
eencae 0:be41a15e7a86 227 // function to set the XY address in RAM for subsequenct data write
eencae 0:be41a15e7a86 228 void N5110::setXYAddress(unsigned int const x,
eencae 0:be41a15e7a86 229 unsigned int const y)
eencae 0:be41a15e7a86 230 {
eencae 0:be41a15e7a86 231 if (x<WIDTH && y<HEIGHT) { // check within range
eencae 0:be41a15e7a86 232 sendCommand(0b00100000); // basic instruction
eencae 0:be41a15e7a86 233 sendCommand(0b10000000 | x); // send addresses to display with relevant mask
eencae 0:be41a15e7a86 234 sendCommand(0b01000000 | y);
eencae 0:be41a15e7a86 235 }
eencae 0:be41a15e7a86 236 }
eencae 0:be41a15e7a86 237
eencae 0:be41a15e7a86 238 // These functions are used to set, clear and get the value of pixels in the display
eencae 0:be41a15e7a86 239 // Pixels are addressed in the range of 0 to 47 (y) and 0 to 83 (x). The refresh()
eencae 0:be41a15e7a86 240 // function must be called after set and clear in order to update the display
eencae 0:be41a15e7a86 241 void N5110::setPixel(unsigned int const x,
eencae 0:be41a15e7a86 242 unsigned int const y,
eencae 0:be41a15e7a86 243 bool const state)
eencae 0:be41a15e7a86 244 {
eencae 0:be41a15e7a86 245 if (x<WIDTH && y<HEIGHT) { // check within range
eencae 0:be41a15e7a86 246 // calculate bank and shift 1 to required position in the data byte
eencae 0:be41a15e7a86 247 if(state) buffer[x][y/8] |= (1 << y%8);
eencae 0:be41a15e7a86 248 else buffer[x][y/8] &= ~(1 << y%8);
eencae 0:be41a15e7a86 249 }
eencae 0:be41a15e7a86 250 }
eencae 0:be41a15e7a86 251
eencae 0:be41a15e7a86 252 void N5110::clearPixel(unsigned int const x,
eencae 0:be41a15e7a86 253 unsigned int const y)
eencae 0:be41a15e7a86 254 {
eencae 0:be41a15e7a86 255 if (x<WIDTH && y<HEIGHT) { // check within range
eencae 0:be41a15e7a86 256 // calculate bank and shift 1 to required position (using bit clear)
eencae 0:be41a15e7a86 257 buffer[x][y/8] &= ~(1 << y%8);
eencae 0:be41a15e7a86 258 }
eencae 0:be41a15e7a86 259 }
eencae 0:be41a15e7a86 260
eencae 0:be41a15e7a86 261 int N5110::getPixel(unsigned int const x,
eencae 0:be41a15e7a86 262 unsigned int const y) const
eencae 0:be41a15e7a86 263 {
eencae 0:be41a15e7a86 264 if (x<WIDTH && y<HEIGHT) { // check within range
eencae 0:be41a15e7a86 265 // return relevant bank and mask required bit
eencae 0:be41a15e7a86 266
eencae 0:be41a15e7a86 267 int pixel = (int) buffer[x][y/8] & (1 << y%8);
eencae 0:be41a15e7a86 268
eencae 0:be41a15e7a86 269 if (pixel)
eencae 0:be41a15e7a86 270 return 1;
eencae 0:be41a15e7a86 271 else
eencae 0:be41a15e7a86 272 return 0;
eencae 0:be41a15e7a86 273 }
eencae 0:be41a15e7a86 274
eencae 0:be41a15e7a86 275 return 0;
eencae 0:be41a15e7a86 276
eencae 0:be41a15e7a86 277 }
eencae 0:be41a15e7a86 278
eencae 0:be41a15e7a86 279 // function to refresh the display
eencae 0:be41a15e7a86 280 void N5110::refresh()
eencae 0:be41a15e7a86 281 {
eencae 0:be41a15e7a86 282 setXYAddress(0,0); // important to set address back to 0,0 before refreshing display
eencae 0:be41a15e7a86 283 // address auto increments after printing string, so buffer[0][0] will not coincide
eencae 0:be41a15e7a86 284 // with top-left pixel after priting string
eencae 0:be41a15e7a86 285
eencae 0:be41a15e7a86 286 _sce->write(0); //set CE low to begin frame
eencae 0:be41a15e7a86 287
eencae 0:be41a15e7a86 288 for(int j = 0; j < BANKS; j++) { // be careful to use correct order (j,i) for horizontal addressing
eencae 0:be41a15e7a86 289 for(int i = 0; i < WIDTH; i++) {
eencae 0:be41a15e7a86 290 _spi->write(buffer[i][j]); // send buffer
eencae 0:be41a15e7a86 291 }
eencae 0:be41a15e7a86 292 }
eencae 0:be41a15e7a86 293 _sce->write(1); // set CE high to end frame
eencae 0:be41a15e7a86 294
eencae 0:be41a15e7a86 295 }
eencae 0:be41a15e7a86 296
eencae 0:be41a15e7a86 297 // fills the buffer with random bytes. Can be used to test the display.
eencae 0:be41a15e7a86 298 // The rand() function isn't seeded so it probably creates the same pattern everytime
eencae 0:be41a15e7a86 299 void N5110::randomiseBuffer()
eencae 0:be41a15e7a86 300 {
eencae 0:be41a15e7a86 301 int i,j;
eencae 0:be41a15e7a86 302 for(j = 0; j < BANKS; j++) { // be careful to use correct order (j,i) for horizontal addressing
eencae 0:be41a15e7a86 303 for(i = 0; i < WIDTH; i++) {
eencae 0:be41a15e7a86 304 buffer[i][j] = rand()%256; // generate random byte
eencae 0:be41a15e7a86 305 }
eencae 0:be41a15e7a86 306 }
eencae 0:be41a15e7a86 307
eencae 0:be41a15e7a86 308 }
eencae 0:be41a15e7a86 309
eencae 0:be41a15e7a86 310 // function to print 5x7 font
eencae 0:be41a15e7a86 311 void N5110::printChar(char const c,
eencae 0:be41a15e7a86 312 unsigned int const x,
eencae 0:be41a15e7a86 313 unsigned int const y)
eencae 0:be41a15e7a86 314 {
eencae 0:be41a15e7a86 315 if (y<BANKS) { // check if printing in range of y banks
eencae 0:be41a15e7a86 316
eencae 0:be41a15e7a86 317 for (int i = 0; i < 5 ; i++ ) {
eencae 0:be41a15e7a86 318 int pixel_x = x+i;
eencae 0:be41a15e7a86 319 if (pixel_x > WIDTH-1) // ensure pixel isn't outside the buffer size (0 - 83)
eencae 0:be41a15e7a86 320 break;
eencae 0:be41a15e7a86 321 buffer[pixel_x][y] = font5x7[(c - 32)*5 + i];
eencae 0:be41a15e7a86 322 // array is offset by 32 relative to ASCII, each character is 5 pixels wide
eencae 0:be41a15e7a86 323 }
eencae 0:be41a15e7a86 324
eencae 0:be41a15e7a86 325 }
eencae 0:be41a15e7a86 326 }
eencae 0:be41a15e7a86 327
eencae 0:be41a15e7a86 328 // function to print string at specified position
eencae 0:be41a15e7a86 329 void N5110::printString(const char *str,
eencae 0:be41a15e7a86 330 unsigned int const x,
eencae 0:be41a15e7a86 331 unsigned int const y)
eencae 0:be41a15e7a86 332 {
eencae 0:be41a15e7a86 333 if (y<BANKS) { // check if printing in range of y banks
eencae 0:be41a15e7a86 334
eencae 0:be41a15e7a86 335 int n = 0 ; // counter for number of characters in string
eencae 0:be41a15e7a86 336 // loop through string and print character
eencae 0:be41a15e7a86 337 while(*str) {
eencae 0:be41a15e7a86 338
eencae 0:be41a15e7a86 339 // writes the character bitmap data to the buffer, so that
eencae 0:be41a15e7a86 340 // text and pixels can be displayed at the same time
eencae 0:be41a15e7a86 341 for (int i = 0; i < 5 ; i++ ) {
eencae 0:be41a15e7a86 342 int pixel_x = x+i+n*6;
eencae 0:be41a15e7a86 343 if (pixel_x > WIDTH-1) // ensure pixel isn't outside the buffer size (0 - 83)
eencae 0:be41a15e7a86 344 break;
eencae 0:be41a15e7a86 345 buffer[pixel_x][y] = font5x7[(*str - 32)*5 + i];
eencae 0:be41a15e7a86 346 }
eencae 0:be41a15e7a86 347 str++; // go to next character in string
eencae 0:be41a15e7a86 348 n++; // increment index
eencae 0:be41a15e7a86 349 }
eencae 0:be41a15e7a86 350 }
eencae 0:be41a15e7a86 351 }
eencae 0:be41a15e7a86 352
eencae 0:be41a15e7a86 353 // function to clear the screen buffer
eencae 0:be41a15e7a86 354 void N5110::clear()
eencae 0:be41a15e7a86 355 {
eencae 0:be41a15e7a86 356 memset(buffer,0,sizeof(buffer));
eencae 0:be41a15e7a86 357 }
eencae 0:be41a15e7a86 358
eencae 0:be41a15e7a86 359 // function to plot array on display
eencae 0:be41a15e7a86 360 void N5110::plotArray(float const array[])
eencae 0:be41a15e7a86 361 {
eencae 0:be41a15e7a86 362 for (int i=0; i<WIDTH; i++) { // loop through array
eencae 0:be41a15e7a86 363 // elements are normalised from 0.0 to 1.0, so multiply
eencae 0:be41a15e7a86 364 // by 47 to convert to pixel range, and subtract from 47
eencae 0:be41a15e7a86 365 // since top-left is 0,0 in the display geometry
eencae 0:be41a15e7a86 366 setPixel(i,47 - int(array[i]*47.0f),true);
eencae 0:be41a15e7a86 367 }
eencae 0:be41a15e7a86 368
eencae 0:be41a15e7a86 369 }
eencae 0:be41a15e7a86 370
eencae 0:be41a15e7a86 371 // function to draw circle
eencae 0:be41a15e7a86 372 void N5110:: drawCircle(unsigned int const x0,
eencae 0:be41a15e7a86 373 unsigned int const y0,
eencae 0:be41a15e7a86 374 unsigned int const radius,
eencae 0:be41a15e7a86 375 FillType const fill)
eencae 0:be41a15e7a86 376 {
eencae 0:be41a15e7a86 377 // from http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
eencae 0:be41a15e7a86 378 int x = radius;
eencae 0:be41a15e7a86 379 int y = 0;
eencae 0:be41a15e7a86 380 int radiusError = 1-x;
eencae 0:be41a15e7a86 381
eencae 0:be41a15e7a86 382 while(x >= y) {
eencae 0:be41a15e7a86 383
eencae 0:be41a15e7a86 384 // if transparent, just draw outline
eencae 0:be41a15e7a86 385 if (fill == FILL_TRANSPARENT) {
eencae 0:be41a15e7a86 386 setPixel( x + x0, y + y0,true);
eencae 0:be41a15e7a86 387 setPixel(-x + x0, y + y0,true);
eencae 0:be41a15e7a86 388 setPixel( y + x0, x + y0,true);
eencae 0:be41a15e7a86 389 setPixel(-y + x0, x + y0,true);
eencae 0:be41a15e7a86 390 setPixel(-y + x0, -x + y0,true);
eencae 0:be41a15e7a86 391 setPixel( y + x0, -x + y0,true);
eencae 0:be41a15e7a86 392 setPixel( x + x0, -y + y0,true);
eencae 0:be41a15e7a86 393 setPixel(-x + x0, -y + y0,true);
eencae 0:be41a15e7a86 394 } else { // drawing filled circle, so draw lines between points at same y value
eencae 0:be41a15e7a86 395
eencae 0:be41a15e7a86 396 int type = (fill==FILL_BLACK) ? 1:0; // black or white fill
eencae 0:be41a15e7a86 397
alex_20 4:def20a1665d1 398 drawLine(x+x0,y+y0,-x+x0,y+y0,0,type);
alex_20 4:def20a1665d1 399 drawLine(y+x0,x+y0,-y+x0,x+y0,0,type);
alex_20 4:def20a1665d1 400 drawLine(y+x0,-x+y0,-y+x0,-x+y0,0,type);
alex_20 4:def20a1665d1 401 drawLine(x+x0,-y+y0,-x+x0,-y+y0,0,type);
eencae 0:be41a15e7a86 402 }
eencae 0:be41a15e7a86 403
eencae 0:be41a15e7a86 404 y++;
alex_20 7:559edc36f261 405 if (radiusError < 0) {
eencae 0:be41a15e7a86 406 radiusError += 2 * y + 1;
eencae 0:be41a15e7a86 407 } else {
eencae 0:be41a15e7a86 408 x--;
eencae 0:be41a15e7a86 409 radiusError += 2 * (y - x) + 1;
eencae 0:be41a15e7a86 410 }
eencae 0:be41a15e7a86 411 }
eencae 0:be41a15e7a86 412
eencae 0:be41a15e7a86 413 }
eencae 0:be41a15e7a86 414
alex_20 7:559edc36f261 415 // function to draw ellipse
alex_20 7:559edc36f261 416 void N5110:: drawEllipse(unsigned int const xc,
alex_20 7:559edc36f261 417 unsigned int const yc,
alex_20 7:559edc36f261 418 unsigned int const rx,
alex_20 7:559edc36f261 419 unsigned int const ry)
alex_20 7:559edc36f261 420 {
alex_20 7:559edc36f261 421 float dx, dy, d1, d2, x, y;
alex_20 7:559edc36f261 422 x = 0;
alex_20 7:559edc36f261 423 y = ry;
alex_20 7:559edc36f261 424 int radiusError = 1-x;
alex_20 7:559edc36f261 425
alex_20 7:559edc36f261 426 // Initial decision parameter of region 1
alex_20 7:559edc36f261 427 d1 = (ry * ry) - (rx * rx * ry) + (0.25 * rx * rx);
alex_20 7:559edc36f261 428 dx = 2 * ry * ry * x;
alex_20 7:559edc36f261 429 dy = 2 * rx * rx * y;
alex_20 7:559edc36f261 430
alex_20 7:559edc36f261 431 // For region 1
alex_20 7:559edc36f261 432 while (dx < dy)
alex_20 7:559edc36f261 433 {
alex_20 7:559edc36f261 434 setPixel (xc + x, yc + y,true);
alex_20 7:559edc36f261 435 setPixel (xc - x, yc + y,true);
alex_20 7:559edc36f261 436 setPixel (xc + x, yc - y,true);
alex_20 7:559edc36f261 437 setPixel (xc - x, yc - y,true);
alex_20 7:559edc36f261 438
alex_20 7:559edc36f261 439 if (radiusError < 0) {
alex_20 7:559edc36f261 440 radiusError += 2 * x + 1;
alex_20 7:559edc36f261 441 } else {
alex_20 7:559edc36f261 442 x++;
alex_20 7:559edc36f261 443 radiusError += 2 * (x - y) + 1;
alex_20 7:559edc36f261 444 }
alex_20 7:559edc36f261 445
alex_20 7:559edc36f261 446 // Checking and updating value of
alex_20 7:559edc36f261 447 // decision parameter based on algorithm
alex_20 7:559edc36f261 448 if (d1 < 0)
alex_20 7:559edc36f261 449 {
alex_20 7:559edc36f261 450 dx = dx + (2 * ry * ry);
alex_20 7:559edc36f261 451 d1 = d1 + dx + (ry * ry);
alex_20 7:559edc36f261 452 }
alex_20 7:559edc36f261 453 else
alex_20 7:559edc36f261 454 {
alex_20 7:559edc36f261 455 y--;
alex_20 7:559edc36f261 456 dx = dx + (2 * ry * ry);
alex_20 7:559edc36f261 457 dy = dy - (2 * rx * rx);
alex_20 7:559edc36f261 458 d1 = d1 + dx - dy + (ry * ry);
alex_20 7:559edc36f261 459 }
alex_20 7:559edc36f261 460 }
alex_20 7:559edc36f261 461
alex_20 7:559edc36f261 462 // Region 2
alex_20 7:559edc36f261 463 // Decision parameter of region 2
alex_20 7:559edc36f261 464 d2 = ((ry * ry) * ((x + 0.5) * (x + 0.5))) +
alex_20 7:559edc36f261 465 ((rx * rx) * ((y - 1) * (y - 1))) -
alex_20 7:559edc36f261 466 (rx * rx * ry * ry);
alex_20 7:559edc36f261 467
alex_20 7:559edc36f261 468 // Plotting points of region 2
alex_20 7:559edc36f261 469 while (y >= 0)
alex_20 7:559edc36f261 470 {
alex_20 7:559edc36f261 471 setPixel (xc + x, yc + y,true);
alex_20 7:559edc36f261 472 setPixel (xc - x, yc + y,true);
alex_20 7:559edc36f261 473 setPixel (xc + x, yc - y,true);
alex_20 7:559edc36f261 474 setPixel (xc - x, yc - y,true);
alex_20 7:559edc36f261 475
alex_20 7:559edc36f261 476 y--;
alex_20 7:559edc36f261 477
alex_20 7:559edc36f261 478 // Checking and updating parameter
alex_20 7:559edc36f261 479 // value based on algorithm
alex_20 7:559edc36f261 480 if (d2 > 0)
alex_20 7:559edc36f261 481 {
alex_20 7:559edc36f261 482 dy = dy - (2 * rx * rx);
alex_20 7:559edc36f261 483 d2 = d2 + (rx * rx) - dy;
alex_20 7:559edc36f261 484 }
alex_20 7:559edc36f261 485 else
alex_20 7:559edc36f261 486 {
alex_20 7:559edc36f261 487 x++;
alex_20 7:559edc36f261 488 dx = dx + (2 * ry * ry);
alex_20 7:559edc36f261 489 dy = dy - (2 * rx * rx);
alex_20 7:559edc36f261 490 d2 = d2 + dx - dy + (rx * rx);
alex_20 7:559edc36f261 491 }
alex_20 7:559edc36f261 492 }
alex_20 7:559edc36f261 493 }
alex_20 7:559edc36f261 494
alex_20 7:559edc36f261 495
alex_20 3:cbe2dcca5058 496 // take points on a curve, decide whether to draw them or not
alex_20 5:7930d289e7fc 497 void N5110::drawCurve(std::vector<Vector2Df> curve_points, float offset, int dash_len, int type)
alex_20 3:cbe2dcca5058 498 {
alex_20 3:cbe2dcca5058 499 if(type == TYPE_SOLID){
alex_20 4:def20a1665d1 500 for(int i = 0; i < curve_points.size()-1; i ++){
alex_20 4:def20a1665d1 501 // take the current and the following coordinates and draw a line between them
alex_20 3:cbe2dcca5058 502 drawLine(static_cast<int>(curve_points[i].x),static_cast<int>(curve_points[i].y),
alex_20 4:def20a1665d1 503 static_cast<int>(curve_points[i+1].x),static_cast<int>(curve_points[i+1].y),0,1);
alex_20 3:cbe2dcca5058 504 }
alex_20 3:cbe2dcca5058 505 }
alex_20 4:def20a1665d1 506 if(type == TYPE_DOTTED){
alex_20 4:def20a1665d1 507 int counter = 0;
alex_20 5:7930d289e7fc 508 for(int i = curve_points.size()-1; i > 0 ; i--){
alex_20 4:def20a1665d1 509 int x0 = static_cast<int>(curve_points[i].x);
alex_20 5:7930d289e7fc 510 int x1 = static_cast<int>(curve_points[i-1].x);
alex_20 4:def20a1665d1 511 int y0 = static_cast<int>(curve_points[i].y);
alex_20 5:7930d289e7fc 512 int y1 = static_cast<int>(curve_points[i-1].y);
alex_20 4:def20a1665d1 513
alex_20 5:7930d289e7fc 514 int const y_range = y0 - y1;
alex_20 5:7930d289e7fc 515 int const x_range = x1 - x0;
alex_20 5:7930d289e7fc 516
alex_20 5:7930d289e7fc 517 // ensure we loop from smallest to largest or else for-loop won't run as expected
alex_20 5:7930d289e7fc 518 //unsigned int const start = y_range > 0 ? y0:y1;
alex_20 5:7930d289e7fc 519 //unsigned int const stop = y_range > 0 ? y1:y0;
alex_20 5:7930d289e7fc 520
alex_20 5:7930d289e7fc 521 for (unsigned int y = y0; y <= y1 ; y++) {
alex_20 5:7930d289e7fc 522 // do linear interpolation
alex_20 5:7930d289e7fc 523 int const dy = y0 - y;
alex_20 5:7930d289e7fc 524 unsigned int const x = x0 + (x_range * (dy / (float)y_range));
alex_20 5:7930d289e7fc 525
alex_20 5:7930d289e7fc 526 // If the line type is '0', this will clear the pixel
alex_20 5:7930d289e7fc 527 // If it is '1' or '2', the pixel will be set
alex_20 6:40ef2030334c 528 setPixel(x,y, fmod(pow(counter, 0.6) - fmod(offset, (2 * dash_len)), (2 * dash_len)) < dash_len);
alex_20 5:7930d289e7fc 529 counter++;
alex_20 5:7930d289e7fc 530 }
alex_20 4:def20a1665d1 531 }
alex_20 4:def20a1665d1 532 }
alex_20 4:def20a1665d1 533 }
alex_20 3:cbe2dcca5058 534
eencae 0:be41a15e7a86 535 void N5110::drawLine(unsigned int const x0,
eencae 0:be41a15e7a86 536 unsigned int const y0,
eencae 0:be41a15e7a86 537 unsigned int const x1,
eencae 0:be41a15e7a86 538 unsigned int const y1,
alex_20 4:def20a1665d1 539 unsigned int const offset,
alex_20 4:def20a1665d1 540 unsigned int const step)
eencae 0:be41a15e7a86 541 {
eencae 0:be41a15e7a86 542 // Note that the ranges can be negative so we have to turn the input values
eencae 0:be41a15e7a86 543 // into signed integers first
eencae 0:be41a15e7a86 544 int const y_range = static_cast<int>(y1) - static_cast<int>(y0);
eencae 0:be41a15e7a86 545 int const x_range = static_cast<int>(x1) - static_cast<int>(x0);
eencae 0:be41a15e7a86 546
eencae 0:be41a15e7a86 547 // make sure we loop over the largest range to get the most pixels on the display
eencae 0:be41a15e7a86 548 // for instance, if drawing a vertical line (x_range = 0), we need to loop down the y pixels
eencae 0:be41a15e7a86 549 // or else we'll only end up with 1 pixel in the x column
eencae 0:be41a15e7a86 550 if ( abs(x_range) > abs(y_range) ) {
eencae 0:be41a15e7a86 551
eencae 0:be41a15e7a86 552 // ensure we loop from smallest to largest or else for-loop won't run as expected
eencae 0:be41a15e7a86 553 unsigned int const start = x_range > 0 ? x0:x1;
eencae 0:be41a15e7a86 554 unsigned int const stop = x_range > 0 ? x1:x0;
eencae 0:be41a15e7a86 555
eencae 0:be41a15e7a86 556 // loop between x pixels
eencae 0:be41a15e7a86 557 for (unsigned int x = start; x<= stop ; x+=step) {
eencae 0:be41a15e7a86 558 // do linear interpolation
alex_20 4:def20a1665d1 559 int const dx = static_cast<int>(x) - static_cast<int>(x0);
eencae 0:be41a15e7a86 560 unsigned int const y = y0 + y_range * dx / x_range;
eencae 0:be41a15e7a86 561
eencae 0:be41a15e7a86 562 // If the line type is '0', this will clear the pixel
eencae 0:be41a15e7a86 563 // If it is '1' or '2', the pixel will be set
alex_20 4:def20a1665d1 564 setPixel(x,y, FILL_BLACK);
eencae 0:be41a15e7a86 565 }
eencae 0:be41a15e7a86 566 } else {
eencae 0:be41a15e7a86 567
eencae 0:be41a15e7a86 568 // ensure we loop from smallest to largest or else for-loop won't run as expected
eencae 0:be41a15e7a86 569 unsigned int const start = y_range > 0 ? y0:y1;
eencae 0:be41a15e7a86 570 unsigned int const stop = y_range > 0 ? y1:y0;
eencae 0:be41a15e7a86 571
eencae 0:be41a15e7a86 572 for (unsigned int y = start; y<= stop ; y+=step) {
eencae 0:be41a15e7a86 573 // do linear interpolation
eencae 0:be41a15e7a86 574 int const dy = static_cast<int>(y)-static_cast<int>(y0);
eencae 0:be41a15e7a86 575 unsigned int const x = x0 + x_range * dy / y_range;
eencae 0:be41a15e7a86 576
eencae 0:be41a15e7a86 577 // If the line type is '0', this will clear the pixel
eencae 0:be41a15e7a86 578 // If it is '1' or '2', the pixel will be set
alex_20 4:def20a1665d1 579 setPixel(x,y, FILL_BLACK);
eencae 0:be41a15e7a86 580 }
eencae 0:be41a15e7a86 581 }
eencae 0:be41a15e7a86 582
eencae 0:be41a15e7a86 583 }
eencae 0:be41a15e7a86 584
eencae 0:be41a15e7a86 585 void N5110::drawRect(unsigned int const x0,
eencae 0:be41a15e7a86 586 unsigned int const y0,
eencae 0:be41a15e7a86 587 unsigned int const width,
eencae 0:be41a15e7a86 588 unsigned int const height,
eencae 0:be41a15e7a86 589 FillType const fill)
eencae 0:be41a15e7a86 590 {
eencae 0:be41a15e7a86 591 if (fill == FILL_TRANSPARENT) { // transparent, just outline
alex_20 4:def20a1665d1 592 drawLine(x0,y0,x0+(width-1),y0,0,1); // top
alex_20 4:def20a1665d1 593 drawLine(x0,y0+(height-1),x0+(width-1),y0+(height-1),0,1); // bottom
alex_20 4:def20a1665d1 594 drawLine(x0,y0,x0,y0+(height-1),0,1); // left
alex_20 4:def20a1665d1 595 drawLine(x0+(width-1),y0,x0+(width-1),y0+(height-1),0,1); // right
eencae 0:be41a15e7a86 596 } else { // filled rectangle
alex_20 4:def20a1665d1 597 int step = (fill==FILL_BLACK) ? 1:0; // black or white fill
eencae 0:be41a15e7a86 598 for (int y = y0; y<y0+height; y++) { // loop through rows of rectangle
alex_20 4:def20a1665d1 599 drawLine(x0,y,x0+(width-1),y,0,step); // draw line across screen
eencae 0:be41a15e7a86 600 }
eencae 0:be41a15e7a86 601 }
eencae 0:be41a15e7a86 602 }
eencae 0:be41a15e7a86 603
eencae 0:be41a15e7a86 604 void N5110::drawSprite(int x0,
eencae 0:be41a15e7a86 605 int y0,
eencae 0:be41a15e7a86 606 int nrows,
eencae 0:be41a15e7a86 607 int ncols,
eencae 0:be41a15e7a86 608 int *sprite)
eencae 0:be41a15e7a86 609 {
eencae 0:be41a15e7a86 610 for (int i = 0; i < nrows; i++) {
eencae 0:be41a15e7a86 611 for (int j = 0 ; j < ncols ; j++) {
eencae 0:be41a15e7a86 612
eencae 0:be41a15e7a86 613 int pixel = *((sprite+i*ncols)+j);
eencae 0:be41a15e7a86 614 setPixel(x0+j,y0+i, pixel);
eencae 0:be41a15e7a86 615 }
eencae 0:be41a15e7a86 616 }
eencae 0:be41a15e7a86 617 }