Helios Lyons 201239214

Dependencies:   mbed

Brief

My aim for this project was to create a FRDM K64F adapted version of the classic Space Invaders by Tomohiro Nishikado. The game itself has a number of clear features to implement;

  • Left to right movement for the player 'canon'
  • A fixed amount of player lives
  • Firing mechanics for both canon and invaders (hence collision systems)
  • Random firing from remaining invaders
  • Wave based combat

My own addition to these established ideas was Boss waves, featuring a single, larger sprite which fires at a faster interval than previous waves. The addition of a movement system using a basic for loop, as opposed to a velocity based system, will enhance the nostalgic feel of the game.

https://os.mbed.com/media/uploads/helioslyons/screenshot_2020-05-27_at_06.12.00.png

Gameplay

Movement is controlled with the joystick, moving the canon left or right. Fire by pressing A. Invaders spawn at set positions, but randomly fire at a set interval, which is higher for boss waves. Time is taken during each wave, and displayed at wave intervals, and if the play wins.

Controls are shown on the Gamepad below: (attribution: Craig A. Evans, ELEC2645 University of Leeds)

https://os.mbed.com/media/uploads/helioslyons/screenshot_2020-05-27_at_06.20.18.png

Committer:
helioslyons
Date:
Tue Mar 24 18:02:01 2020 +0000
Revision:
1:a3f43007030e
Initial commit, 24th March

Who changed what in which revision?

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