“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:
Sat Apr 24 21:31:19 2021 +0000
Revision:
8:1fc5e14b0db6
Parent:
7:559edc36f261
Before game engine. ball done

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 8:1fc5e14b0db6 420 {
alex_20 8:1fc5e14b0db6 421 int rx2 = rx*rx, ry2 = ry*ry;
alex_20 8:1fc5e14b0db6 422 int x = 0, y = ry; //Starting point
alex_20 8:1fc5e14b0db6 423
alex_20 8:1fc5e14b0db6 424 int incSW = ry2*2 + rx2*2;
alex_20 8:1fc5e14b0db6 425
alex_20 8:1fc5e14b0db6 426 // Slopes deduced from incremental algorithm with the second-order logic
alex_20 8:1fc5e14b0db6 427 int W = ry2*(-2*x + 3);
alex_20 8:1fc5e14b0db6 428 int S = rx2*(-2*y + 3);
alex_20 8:1fc5e14b0db6 429 int SW = W + S;
alex_20 8:1fc5e14b0db6 430
alex_20 8:1fc5e14b0db6 431 // Decision parameter of Region 1 and Region 2
alex_20 8:1fc5e14b0db6 432 int p1 = ry2 - rx2*ry + rx2/4;
alex_20 8:1fc5e14b0db6 433 int p2 = ry2*(x - 0.5)*(x - 0.5) + rx2*(y - 1)*(y - 1) - rx2*ry2;
alex_20 8:1fc5e14b0db6 434
alex_20 8:1fc5e14b0db6 435 // Region 1
alex_20 8:1fc5e14b0db6 436 while(rx2*(y-0.5) >= ry2*(-x-1)) {
alex_20 7:559edc36f261 437
alex_20 8:1fc5e14b0db6 438 // Set points based on 4-way symmetry
alex_20 8:1fc5e14b0db6 439 setPixel(-x+xc,-y+yc, true);
alex_20 8:1fc5e14b0db6 440 setPixel(-x+xc, y+yc, true);
alex_20 8:1fc5e14b0db6 441 setPixel( x+xc, y+yc, true);
alex_20 8:1fc5e14b0db6 442 setPixel( x+xc,-y+yc, true);
alex_20 7:559edc36f261 443
alex_20 8:1fc5e14b0db6 444 if(p1 > 0) {
alex_20 8:1fc5e14b0db6 445 p1 += SW;
alex_20 8:1fc5e14b0db6 446 W += ry2*2;
alex_20 8:1fc5e14b0db6 447 SW += incSW;
alex_20 7:559edc36f261 448 y--;
alex_20 8:1fc5e14b0db6 449 }
alex_20 8:1fc5e14b0db6 450 else {
alex_20 8:1fc5e14b0db6 451 p1 += W;
alex_20 8:1fc5e14b0db6 452 W += 2*ry2;
alex_20 8:1fc5e14b0db6 453 SW += 2*ry2;
alex_20 7:559edc36f261 454 }
alex_20 8:1fc5e14b0db6 455 x--;
alex_20 7:559edc36f261 456 }
alex_20 8:1fc5e14b0db6 457
alex_20 8:1fc5e14b0db6 458 SW = ry2*(2 - 2*x) + rx2*(-2*y + 3);
alex_20 8:1fc5e14b0db6 459
alex_20 7:559edc36f261 460 // Region 2
alex_20 8:1fc5e14b0db6 461 while(y >= 0) {
alex_20 7:559edc36f261 462
alex_20 8:1fc5e14b0db6 463 // Set points based on 4-way symmetry
alex_20 8:1fc5e14b0db6 464 setPixel(-x+xc,-y+yc, true);
alex_20 8:1fc5e14b0db6 465 setPixel(-x+xc, y+yc, true);
alex_20 8:1fc5e14b0db6 466 setPixel( x+xc, y+yc, true);
alex_20 8:1fc5e14b0db6 467 setPixel( x+xc,-y+yc, true);
alex_20 7:559edc36f261 468
alex_20 8:1fc5e14b0db6 469 if(p2 > 0) {
alex_20 8:1fc5e14b0db6 470 p2 += S;
alex_20 8:1fc5e14b0db6 471 S += rx2*2;
alex_20 8:1fc5e14b0db6 472 SW += rx2*2;
alex_20 7:559edc36f261 473 }
alex_20 8:1fc5e14b0db6 474 else {
alex_20 8:1fc5e14b0db6 475 p2 += SW;
alex_20 8:1fc5e14b0db6 476 SW += incSW;
alex_20 8:1fc5e14b0db6 477 S += rx2*2;
alex_20 8:1fc5e14b0db6 478 x--;
alex_20 7:559edc36f261 479 }
alex_20 8:1fc5e14b0db6 480 y--;
alex_20 7:559edc36f261 481 }
alex_20 7:559edc36f261 482 }
alex_20 7:559edc36f261 483
alex_20 3:cbe2dcca5058 484 // take points on a curve, decide whether to draw them or not
alex_20 5:7930d289e7fc 485 void N5110::drawCurve(std::vector<Vector2Df> curve_points, float offset, int dash_len, int type)
alex_20 3:cbe2dcca5058 486 {
alex_20 3:cbe2dcca5058 487 if(type == TYPE_SOLID){
alex_20 8:1fc5e14b0db6 488 for(int i = 0; i < curve_points.size()-1; i++){
alex_20 4:def20a1665d1 489 // take the current and the following coordinates and draw a line between them
alex_20 3:cbe2dcca5058 490 drawLine(static_cast<int>(curve_points[i].x),static_cast<int>(curve_points[i].y),
alex_20 4:def20a1665d1 491 static_cast<int>(curve_points[i+1].x),static_cast<int>(curve_points[i+1].y),0,1);
alex_20 3:cbe2dcca5058 492 }
alex_20 3:cbe2dcca5058 493 }
alex_20 4:def20a1665d1 494 if(type == TYPE_DOTTED){
alex_20 4:def20a1665d1 495 int counter = 0;
alex_20 5:7930d289e7fc 496 for(int i = curve_points.size()-1; i > 0 ; i--){
alex_20 4:def20a1665d1 497 int x0 = static_cast<int>(curve_points[i].x);
alex_20 5:7930d289e7fc 498 int x1 = static_cast<int>(curve_points[i-1].x);
alex_20 4:def20a1665d1 499 int y0 = static_cast<int>(curve_points[i].y);
alex_20 5:7930d289e7fc 500 int y1 = static_cast<int>(curve_points[i-1].y);
alex_20 4:def20a1665d1 501
alex_20 5:7930d289e7fc 502 int const y_range = y0 - y1;
alex_20 5:7930d289e7fc 503 int const x_range = x1 - x0;
alex_20 5:7930d289e7fc 504
alex_20 5:7930d289e7fc 505 // ensure we loop from smallest to largest or else for-loop won't run as expected
alex_20 5:7930d289e7fc 506 //unsigned int const start = y_range > 0 ? y0:y1;
alex_20 5:7930d289e7fc 507 //unsigned int const stop = y_range > 0 ? y1:y0;
alex_20 5:7930d289e7fc 508
alex_20 5:7930d289e7fc 509 for (unsigned int y = y0; y <= y1 ; y++) {
alex_20 5:7930d289e7fc 510 // do linear interpolation
alex_20 5:7930d289e7fc 511 int const dy = y0 - y;
alex_20 5:7930d289e7fc 512 unsigned int const x = x0 + (x_range * (dy / (float)y_range));
alex_20 5:7930d289e7fc 513
alex_20 5:7930d289e7fc 514 // If the line type is '0', this will clear the pixel
alex_20 5:7930d289e7fc 515 // If it is '1' or '2', the pixel will be set
alex_20 6:40ef2030334c 516 setPixel(x,y, fmod(pow(counter, 0.6) - fmod(offset, (2 * dash_len)), (2 * dash_len)) < dash_len);
alex_20 5:7930d289e7fc 517 counter++;
alex_20 5:7930d289e7fc 518 }
alex_20 4:def20a1665d1 519 }
alex_20 4:def20a1665d1 520 }
alex_20 4:def20a1665d1 521 }
alex_20 3:cbe2dcca5058 522
eencae 0:be41a15e7a86 523 void N5110::drawLine(unsigned int const x0,
eencae 0:be41a15e7a86 524 unsigned int const y0,
eencae 0:be41a15e7a86 525 unsigned int const x1,
eencae 0:be41a15e7a86 526 unsigned int const y1,
alex_20 4:def20a1665d1 527 unsigned int const offset,
alex_20 4:def20a1665d1 528 unsigned int const step)
eencae 0:be41a15e7a86 529 {
eencae 0:be41a15e7a86 530 // Note that the ranges can be negative so we have to turn the input values
eencae 0:be41a15e7a86 531 // into signed integers first
eencae 0:be41a15e7a86 532 int const y_range = static_cast<int>(y1) - static_cast<int>(y0);
eencae 0:be41a15e7a86 533 int const x_range = static_cast<int>(x1) - static_cast<int>(x0);
eencae 0:be41a15e7a86 534
eencae 0:be41a15e7a86 535 // make sure we loop over the largest range to get the most pixels on the display
eencae 0:be41a15e7a86 536 // for instance, if drawing a vertical line (x_range = 0), we need to loop down the y pixels
eencae 0:be41a15e7a86 537 // or else we'll only end up with 1 pixel in the x column
eencae 0:be41a15e7a86 538 if ( abs(x_range) > abs(y_range) ) {
eencae 0:be41a15e7a86 539
eencae 0:be41a15e7a86 540 // ensure we loop from smallest to largest or else for-loop won't run as expected
eencae 0:be41a15e7a86 541 unsigned int const start = x_range > 0 ? x0:x1;
eencae 0:be41a15e7a86 542 unsigned int const stop = x_range > 0 ? x1:x0;
eencae 0:be41a15e7a86 543
eencae 0:be41a15e7a86 544 // loop between x pixels
eencae 0:be41a15e7a86 545 for (unsigned int x = start; x<= stop ; x+=step) {
eencae 0:be41a15e7a86 546 // do linear interpolation
alex_20 4:def20a1665d1 547 int const dx = static_cast<int>(x) - static_cast<int>(x0);
eencae 0:be41a15e7a86 548 unsigned int const y = y0 + y_range * dx / x_range;
eencae 0:be41a15e7a86 549
eencae 0:be41a15e7a86 550 // If the line type is '0', this will clear the pixel
eencae 0:be41a15e7a86 551 // If it is '1' or '2', the pixel will be set
alex_20 4:def20a1665d1 552 setPixel(x,y, FILL_BLACK);
eencae 0:be41a15e7a86 553 }
eencae 0:be41a15e7a86 554 } else {
eencae 0:be41a15e7a86 555
eencae 0:be41a15e7a86 556 // ensure we loop from smallest to largest or else for-loop won't run as expected
eencae 0:be41a15e7a86 557 unsigned int const start = y_range > 0 ? y0:y1;
eencae 0:be41a15e7a86 558 unsigned int const stop = y_range > 0 ? y1:y0;
eencae 0:be41a15e7a86 559
eencae 0:be41a15e7a86 560 for (unsigned int y = start; y<= stop ; y+=step) {
eencae 0:be41a15e7a86 561 // do linear interpolation
eencae 0:be41a15e7a86 562 int const dy = static_cast<int>(y)-static_cast<int>(y0);
eencae 0:be41a15e7a86 563 unsigned int const x = x0 + x_range * dy / y_range;
eencae 0:be41a15e7a86 564
eencae 0:be41a15e7a86 565 // If the line type is '0', this will clear the pixel
eencae 0:be41a15e7a86 566 // If it is '1' or '2', the pixel will be set
alex_20 4:def20a1665d1 567 setPixel(x,y, FILL_BLACK);
eencae 0:be41a15e7a86 568 }
eencae 0:be41a15e7a86 569 }
eencae 0:be41a15e7a86 570
eencae 0:be41a15e7a86 571 }
eencae 0:be41a15e7a86 572
eencae 0:be41a15e7a86 573 void N5110::drawRect(unsigned int const x0,
eencae 0:be41a15e7a86 574 unsigned int const y0,
eencae 0:be41a15e7a86 575 unsigned int const width,
eencae 0:be41a15e7a86 576 unsigned int const height,
eencae 0:be41a15e7a86 577 FillType const fill)
eencae 0:be41a15e7a86 578 {
eencae 0:be41a15e7a86 579 if (fill == FILL_TRANSPARENT) { // transparent, just outline
alex_20 4:def20a1665d1 580 drawLine(x0,y0,x0+(width-1),y0,0,1); // top
alex_20 4:def20a1665d1 581 drawLine(x0,y0+(height-1),x0+(width-1),y0+(height-1),0,1); // bottom
alex_20 4:def20a1665d1 582 drawLine(x0,y0,x0,y0+(height-1),0,1); // left
alex_20 4:def20a1665d1 583 drawLine(x0+(width-1),y0,x0+(width-1),y0+(height-1),0,1); // right
eencae 0:be41a15e7a86 584 } else { // filled rectangle
alex_20 4:def20a1665d1 585 int step = (fill==FILL_BLACK) ? 1:0; // black or white fill
eencae 0:be41a15e7a86 586 for (int y = y0; y<y0+height; y++) { // loop through rows of rectangle
alex_20 4:def20a1665d1 587 drawLine(x0,y,x0+(width-1),y,0,step); // draw line across screen
eencae 0:be41a15e7a86 588 }
eencae 0:be41a15e7a86 589 }
eencae 0:be41a15e7a86 590 }
eencae 0:be41a15e7a86 591
eencae 0:be41a15e7a86 592 void N5110::drawSprite(int x0,
eencae 0:be41a15e7a86 593 int y0,
eencae 0:be41a15e7a86 594 int nrows,
eencae 0:be41a15e7a86 595 int ncols,
eencae 0:be41a15e7a86 596 int *sprite)
eencae 0:be41a15e7a86 597 {
eencae 0:be41a15e7a86 598 for (int i = 0; i < nrows; i++) {
eencae 0:be41a15e7a86 599 for (int j = 0 ; j < ncols ; j++) {
eencae 0:be41a15e7a86 600
eencae 0:be41a15e7a86 601 int pixel = *((sprite+i*ncols)+j);
eencae 0:be41a15e7a86 602 setPixel(x0+j,y0+i, pixel);
eencae 0:be41a15e7a86 603 }
eencae 0:be41a15e7a86 604 }
eencae 0:be41a15e7a86 605 }