From 7c4b38cb7d6b14b79000b015dc5703602418694a Mon Sep 17 00:00:00 2001 From: ekem Date: Thu, 30 Apr 2015 22:17:25 -0700 Subject: [PATCH] example game --- .gitignore | 1 + ArduBreakout.ino | 745 +++++++++++++++++++++++++++++++++++++++++++ Arduboy.cpp | 681 +++++++++++++++++++++++++++++++++++++++ Arduboy.h | 64 ++++ README.md | 1 + breakout_bitmaps.cpp | 124 +++++++ breakout_bitmaps.h | 13 + glcdfont.c | 267 ++++++++++++++++ 8 files changed, 1896 insertions(+) create mode 100644 .gitignore create mode 100644 ArduBreakout.ino create mode 100644 Arduboy.cpp create mode 100644 Arduboy.h create mode 100644 README.md create mode 100644 breakout_bitmaps.cpp create mode 100644 breakout_bitmaps.h create mode 100644 glcdfont.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1377554 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/ArduBreakout.ino b/ArduBreakout.ino new file mode 100644 index 0000000..6203ec6 --- /dev/null +++ b/ArduBreakout.ino @@ -0,0 +1,745 @@ + /* + Breakout + Copyright (C) 2011 Sebastian Goscik + All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + */ + +#include +#include +#include "Arduboy.h" + +#include +#include "breakout_bitmaps.h" + +#define OLED_DC 8 +#define OLED_CS 10 // SPI slave-select +#define OLED_CLK 13 // hardware SPI clock +#define OLED_MOSI 11 // hardware SPI MOSI +#define OLED_RESET 7 + +Arduboy display; + +const byte width = 128; //Width of screen +const byte height = 64; //Hight of screen +int dx = -1; //Initial movement of ball +int dy = -1; //Initial movement of ball +int xb; //Balls starting possition +int yb; //Balls starting possition +boolean released; //If the ball has been released by the player +boolean paused = false; //If the game has been paused +byte xPaddle; //X position of paddle +boolean isHit[5][12]; //Array of if bricks are hit or not +boolean bounced=false; //Used to fix double bounce glitch +byte lives = 3; //Amount of lives +byte level = 1; //Current level +unsigned int score=0; //Score for the game +unsigned int brickCount; //Amount of bricks hit +byte pad,pad2,pad3; //Button press buffer used to stop pause repeating +byte oldpad,oldpad2,oldpad3; +char text[16]; //General string buffer +boolean start=false; //If in menu or in game +boolean initialDraw=false;//If the inital draw has happened +char initials[3]; //Initials used in high score + +//Ball Bounds used in collision detection +byte leftBall; +byte rightBall; +byte topBall; +byte bottomBall; + +//Brick Bounds used in collision detection +byte leftBrick; +byte rightBrick; +byte topBrick; +byte bottomBrick; + +int ballclock = 0; + +#include "pins_arduino.h" // Arduino pre-1.0 needs this + +PROGMEM const unsigned char arduino [] = +{ + 0x3F, 0xFF, 0xFF, 0xFC, 0x40, 0x00, 0x00, 0x02, 0x89, 0x99,0x54, + 0x91, 0x95, 0x55, 0x56, 0xA9, 0x9D, 0x95, 0x55, 0xA9, 0x95, 0x59, + 0xD4, 0x91, 0x40, 0x00, 0x00, 0x02, 0x3F, 0xFF, 0xFF, 0xFC +}; + +void intro() +{ + for(int i = -8; i < 28; i = i + 2) + { + display.clearDisplay(); + display.setCursor(46, i); + display.print("ARDUBOY"); + display.display(); + } + + tone(A2, 987, 160); + delay(160); + tone(A2, 1318, 400); + delay(2000); +} + +void setup() +{ + SPI.begin(); + display.start(); + display.setTextSize(1); + display.setCursor(0, 0); + display.print("Hello World!"); + display.display(); + intro(); +} + +void movePaddle() +{ + //Move right + if(xPaddle < width - 12) + { + if( !digitalRead(5) ) + { + xPaddle++; + } + } + + //Move left + if(xPaddle > 0) + { + if( !digitalRead(9)) + { + xPaddle--; + } + } +} + +void moveBall() +{ + if(released) + { + //Move ball + xb=xb + dx; + yb=yb + dy; + + //Set bounds + leftBall = xb; + rightBall = xb + 2; + topBall = yb; + bottomBall = yb + 2; + + //Bounce off top edge + if (yb <= 0) + { + yb = 2; + dy = -dy; + tone(A2, 523, 250); + } + + //Lose a life if bottom edge hit + if (yb >= 64) + { + display.drawRect(xPaddle, 63, 11, 1, 0); + xPaddle = 54; + yb=60; + released = false; + lives--; + drawLives(); + tone(A2, 175, 250); + if (random(0, 2) == 0) + { + dx = 1; + } + else + { + dx = -1; + } + } + + //Bounce off left side + if (xb <= 0) + { + xb = 2; + dx = -dx; + tone(A2, 523, 250); + } + + //Bounce off right side + if (xb >= width - 2) + { + xb = width - 4; + dx = -dx; + tone(A2, 523, 250); + } + + //Bounce off paddle + if (xb+1>=xPaddle && xb<=xPaddle+12 && yb+2>=63 && yb<=64) + { + dy = -dy; + dx = ((xb-(xPaddle+6))/3); //Applies spin on the ball + tone(A2, 200, 250); + } + + //Bounce off Bricks + for (byte row = 0; row < 4; row++) + { + for (byte column = 0; column < 14; column++) + { + if (!isHit[row][column]) + { + //Sets Brick bounds + leftBrick = 10 * column; + rightBrick = 10 * column + 10; + topBrick = 6 * row + 1; + bottomBrick = 6 * row + 7; + + //If A collison has occured + if (topBall <= bottomBrick && bottomBall >= topBrick && + leftBall <= rightBrick && rightBall >= leftBrick) + { + Score(); + brickCount++; + isHit[row][column] = true; + display.drawRect(10*column, 2+6*row, 8, 4, 0); + + //Vertical collision + if (bottomBall > bottomBrick || topBall < topBrick) + { + //Only bounce once each ball move + if(!bounced) + { + dy =- dy; + yb += dy; + bounced = true; + tone(A2, 261, 250); + } + } + + //Hoizontal collision + if (leftBall < leftBrick || rightBall > rightBrick) + { + //Only bounce once brick each ball move + if(!bounced) + { + dx =- dx; + xb += dx; + bounced = true; + tone(A2, 261, 250); + } + } + } + } + } + } + //Reset Bounce + bounced = false; + } + else + { + //Ball follows paddle + xb=xPaddle + 5; + + //Release ball if FIRE pressed + pad3 = !digitalRead(A0); + if (pad3 == 1 && oldpad3 == 0) + { + released=true; + + //Apply random direction to ball on release + if (random(0, 2) == 0) + { + dx = 1; + } + else + { + dx = -1; + } + //Makes sure the ball heads upwards + dy = -1; + } + oldpad3 = pad3; + } +} + +void drawBall() +{ + display.drawPixel(xb, yb, 0); + display.drawPixel(xb+1, yb, 0); + display.drawPixel(xb, yb+1, 0); + display.drawPixel(xb+1, yb+1, 0); + + if(ballclock>4) + { + moveBall(); + ballclock=0; + } + + ballclock++; + + display.drawPixel(xb, yb, 1); + display.drawPixel(xb+1, yb, 1); + display.drawPixel(xb, yb+1, 1); + display.drawPixel(xb+1, yb+1, 1); +} + +void drawPaddle() +{ + display.drawRect(xPaddle, 63, 11, 1, 0); + movePaddle(); + display.drawRect(xPaddle, 63, 11, 1, 1); +} + +void drawLives() +{ + sprintf(text, "LIVES:%u", lives); + display.setCursor(0, 90); + display.print(text); +} + +void drawGameOver() +{ + display.drawPixel(xb, yb, 0); + display.drawPixel(xb+1, yb, 0); + display.drawPixel(xb, yb+1, 0); + display.drawPixel(xb+1, yb+1, 0); + display.setCursor(52, 42); + display.print( "Game"); + display.setCursor(52, 54); + display.print("Over"); + display.display(); + delay(4000); +} + +void pause() +{ + paused = true; + //Draw pause to the screen + display.setCursor(52, 45); + display.print("PAUSE"); + display.display(); + while (paused) + { + delay(150); + //Unpause if FIRE is pressed + pad2 = !digitalRead(A0); + if (pad2 > 1 && oldpad2 == 0 && released) + { + display.fillRect(52, 45, 30, 11, 0); + + paused=false; + } + oldpad2=pad2; + } +} + +void Score() +{ + score += (level*10); + sprintf(text, "SCORE:%u", score); + display.setCursor(80, 90); + display.print(text); +} + +void newLevel(){ + //Undraw paddle + display.drawRect(xPaddle, 63, 11, 1, 0); + + //Undraw ball + display.drawPixel(xb, yb, 0); + display.drawPixel(xb+1, yb, 0); + display.drawPixel(xb, yb+1, 0); + display.drawPixel(xb+1, yb+1, 0); + + //Alter various variables to reset the game + xPaddle = 54; + yb = 60; + brickCount = 0; + released = false; + + //Draws new bricks and resets their values + for (byte row = 0; row < 4; row++) { + for (byte column = 0; column < 13; column++) + { + isHit[row][column] = false; + display.drawRect(10*column, 2+6*row, 8, 4, 1); + } + } + + //Draws the initial lives + drawLives(); + + //Draws the initial score + sprintf(text, "SCORE:%u", score); + display.setCursor(80, 90); + display.print(text); +} + +//Used to delay images while reading button input +boolean pollFireButton(int n) +{ + for(int i = 0; i < n; i++) + { + delay(15); + pad = !digitalRead(A0); + if(pad == 1 && oldpad == 0) + { + oldpad3 = 1; //Forces pad loop 3 to run once + return true; + } + oldpad = pad; + } + return false; +} + +//Function by nootropic design to display highscores +boolean displayHighScores(byte file) +{ + byte y = 10; + byte x = 24; + // Each block of EEPROM has 10 high scores, and each high score entry + // is 5 bytes long: 3 bytes for initials and two bytes for score. + int address = file*10*5; + byte hi, lo; + display.clearDisplay(); + display.setCursor(32, 0); + display.print("HIGH SCORES"); + display.display(); + + for(int i = 0; i < 10; i++) + { + sprintf(text, "%2d", i+1); + display.setCursor(x,y+(i*8)); + display.print( text); + display.display(); + hi = EEPROM.read(address + (5*i)); + lo = EEPROM.read(address + (5*i) + 1); + + if ((hi == 0xFF) && (lo == 0xFF)) + { + score = 0; + } + else + { + score = (hi << 8) | lo; + } + + initials[0] = (char)EEPROM.read(address + (5*i) + 2); + initials[1] = (char)EEPROM.read(address + (5*i) + 3); + initials[2] = (char)EEPROM.read(address + (5*i) + 4); + + if (score > 0) + { + sprintf(text, "%c%c%c %u", initials[0], initials[1], initials[2], score); + display.setCursor(x + 24, y + (i*8)); + display.print(text); + display.display(); + } + } + if (pollFireButton(300)) + { + return true; + } + return false; + display.display(); +} + +boolean titleScreen() +{ + //Clears the screen + display.clearDisplay(); + display.setCursor(16,22); + display.setTextSize(2); + display.print("ARAKNOID"); + display.setTextSize(1); + display.display(); + if (pollFireButton(25)) + { + return true; + } + + //Flash "Press FIRE" 5 times + for(byte i = 0; i < 5; i++) + { + //Draws "Press FIRE" + //display.bitmap(31, 53, fire); display.display(); + display.setCursor(31, 53); + display.print("PRESS FIRE!"); + display.display(); + + if (pollFireButton(50)) + { + return true; + } + //Removes "Press FIRE" + display.clearDisplay(); + display.setCursor(16,22); + display.setTextSize(2); + display.print("ARAKNOID"); + display.setTextSize(1); + display.display(); + + display.display(); + if (pollFireButton(25)) + { + return true; + } + } + + return false; +} + +//Function by nootropic design to add high scores +void enterInitials() +{ + char index = 0; + + display.clearDisplay(); + + initials[0] = ' '; + initials[1] = ' '; + initials[2] = ' '; + + while (true) + { + display.display(); + display.clearDisplay(); + + display.setCursor(16,0); + display.print("HIGH SCORE"); + sprintf(text, "%u", score); + display.setCursor(88, 0); + display.print(text); + display.setCursor(56, 20); + display.print(initials[0]); + display.setCursor(64, 20); + display.print(initials[1]); + display.setCursor(72, 20); + display.print(initials[2]); + for(byte i = 0; i < 3; i++) + { + display.drawLine(56 + (i*8), 27, 56 + (i*8) + 6, 27, 1); + } + display.drawLine(56, 28, 88, 28, 0); + display.drawLine(56 + (index*8), 28, 56 + (index*8) + 6, 28, 1); + delay(150); + + if (!digitalRead(5)) + { + index--; + if (index < 0) + { + index = 0; + } else + { + tone(A2, 1046, 250); + } + } + + if (!digitalRead(9)) + { + index++; + if (index > 2) + { + index = 2; + } else { + tone(A2, 1046, 250); + } + } + + if (!digitalRead(8)) + { + initials[index]++; + tone(A2, 523, 250); + // A-Z 0-9 :-? !-/ ' ' + if (initials[index] == '0') + { + initials[index] = ' '; + } + if (initials[index] == '!') + { + initials[index] = 'A'; + } + if (initials[index] == '[') + { + initials[index] = '0'; + } + if (initials[index] == '@') + { + initials[index] = '!'; + } + } + + if (!digitalRead(10)) + { + initials[index]--; + tone(A2, 523, 250); + if (initials[index] == ' ') { + initials[index] = '?'; + } + if (initials[index] == '/') { + initials[index] = 'Z'; + } + if (initials[index] == 31) { + initials[index] = '/'; + } + if (initials[index] == '@') { + initials[index] = ' '; + } + } + + if (!digitalRead(A0)) + { + if (index < 2) + { + index++; + tone(A2, 1046, 250); + } else { + tone(A2, 1046, 250); + return; + } + } + } + +} + +void enterHighScore(byte file) +{ + // Each block of EEPROM has 10 high scores, and each high score entry + // is 5 bytes long: 3 bytes for initials and two bytes for score. + int address = file * 10 * 5; + byte hi, lo; + char tmpInitials[3]; + unsigned int tmpScore = 0; + + // High score processing + for(byte i = 0; i < 10; i++) + { + hi = EEPROM.read(address + (5*i)); + lo = EEPROM.read(address + (5*i) + 1); + if ((hi == 0xFF) && (lo == 0xFF)) + { + // The values are uninitialized, so treat this entry + // as a score of 0. + tmpScore = 0; + } else + { + tmpScore = (hi << 8) | lo; + } + if (score > tmpScore) + { + enterInitials(); + for(byte j=i;j<10;j++) + { + hi = EEPROM.read(address + (5*j)); + lo = EEPROM.read(address + (5*j) + 1); + + if ((hi == 0xFF) && (lo == 0xFF)) + { + tmpScore = 0; + } + else + { + tmpScore = (hi << 8) | lo; + } + + tmpInitials[0] = (char)EEPROM.read(address + (5*j) + 2); + tmpInitials[1] = (char)EEPROM.read(address + (5*j) + 3); + tmpInitials[2] = (char)EEPROM.read(address + (5*j) + 4); + + // write score and initials to current slot + EEPROM.write(address + (5*j), ((score >> 8) & 0xFF)); + EEPROM.write(address + (5*j) + 1, (score & 0xFF)); + EEPROM.write(address + (5*j) + 2, initials[0]); + EEPROM.write(address + (5*j) + 3, initials[1]); + EEPROM.write(address + (5*j) + 4, initials[2]); + + // tmpScore and tmpInitials now hold what we want to + //write in the next slot. + score = tmpScore; + initials[0] = tmpInitials[0]; + initials[1] = tmpInitials[1]; + initials[2] = tmpInitials[2]; + } + + score = 0; + initials[0] = ' '; + initials[1] = ' '; + initials[2] = ' '; + + return; + } + } +} + + + +void loop() +{ + display.display(); + + //Title screen loop switches from title screen + //and high scores utill FIRE is pressed + while (!start) + { + start = titleScreen(); + if (!start) + { + start = displayHighScores(2); + } + } + + //Inital level draw + if (!initialDraw) + { + //Clears the screen + display.display(); + display.clearDisplay(); + //Selects Font + //Draws the new level + newLevel(); + initialDraw=true; + } + + if (lives>0) + { + drawPaddle(); + + //Pause game if FIRE pressed + pad = !digitalRead(A0); + + if(pad >1 && oldpad==0 && released) + { + oldpad2=0; //Forces pad loop 2 to run once + pause(); + } + + oldpad=pad; + drawBall(); + + if(brickCount==60) + { + level++; + newLevel(); + } + } + else + { + drawGameOver(); + if (score > 0) + { + enterHighScore(2); + } + + display.clearDisplay(); + initialDraw=false; + start=false; + lives=3; + score=0; + newLevel(); + } +} + + diff --git a/Arduboy.cpp b/Arduboy.cpp new file mode 100644 index 0000000..3ec2463 --- /dev/null +++ b/Arduboy.cpp @@ -0,0 +1,681 @@ +#include "Arduboy.h" +#include "glcdfont.c" + +Arduboy::Arduboy() { } + +void Arduboy::start() +{ + pinMode(DC, OUTPUT); + pinMode(CS, OUTPUT); + pinMode(8, INPUT_PULLUP); + pinMode(9, INPUT_PULLUP); + pinMode(10, INPUT_PULLUP); + pinMode(5, INPUT_PULLUP); + pinMode(A0, INPUT_PULLUP); + pinMode(A1, INPUT_PULLUP); + + csport = portOutputRegister(digitalPinToPort(CS)); + cspinmask = digitalPinToBitMask(CS); + dcport = portOutputRegister(digitalPinToPort(DC)); + dcpinmask = digitalPinToBitMask(DC); + + /** + * Setup reset pin direction (used by both SPI and I2C) + */ + pinMode(RST, OUTPUT); + digitalWrite(RST, HIGH); + delay(1); // VDD (3.3V) goes high at start, lets just chill for a ms + digitalWrite(RST, LOW); // bring reset low + delay(10); // wait 10ms + digitalWrite(RST, HIGH); // bring out of reset + + *csport |= cspinmask; + *dcport &= ~dcpinmask; + *csport &= ~cspinmask; + + SPI.transfer(0xAE); // Display Off + SPI.transfer(0XD5); // Set Display Clock Divisor v + SPI.transfer(0xF0); // 0x80 is default + SPI.transfer(0xA8); // Set Multiplex Ratio v + SPI.transfer(0x3F); + SPI.transfer(0xD3); // Set Display Offset v + SPI.transfer(0x0); + SPI.transfer(0x40); // Set Start Line (0) + SPI.transfer(0x8D); // Charge Pump Setting v + SPI.transfer(0x14); // Enable + SPI.transfer(0x20); // Set Memory Mode v + SPI.transfer(0x00); // Horizontal Addressing + SPI.transfer(0xA1); // Set Segment Re-map (A0) | (b0001) + SPI.transfer(0xC8); // Set COM Output Scan Direction + SPI.transfer(0xDA); // Set COM Pins v + SPI.transfer(0x12); + SPI.transfer(0x81); // Set Contrast v + SPI.transfer(0xCF); + SPI.transfer(0xD9); // Set Precharge + SPI.transfer(0xF1); + SPI.transfer(0xDB); // Set VCom Detect + SPI.transfer(0x40); + SPI.transfer(0xA4); // Entire Display ON + SPI.transfer(0xA6); // Set normal/inverse display + SPI.transfer(0xAF); // Display On + + *csport |= cspinmask; + *csport |= cspinmask; + *dcport &= ~dcpinmask; + *csport &= ~cspinmask; + + SPI.transfer(0x20); // set display mode + SPI.transfer(0x00); // horizontal addressing mode + SPI.transfer(0x21); // set col address + + unsigned char start = 0; + unsigned char end = WIDTH - 1; + SPI.transfer(start & 0x7F); + SPI.transfer(end & 0x7F); + SPI.transfer(0x22); // set page address + + start = 0; + end = (HEIGHT/8)-1; + SPI.transfer(start & 0x07); + SPI.transfer(end & 0x07); + + *dcport |= dcpinmask; + *csport &= ~cspinmask; +} + +void Arduboy::blank() +{ + for (int a = 0; a < (HEIGHT*WIDTH)/8; a++) SPI.transfer(0x00); +} + +void Arduboy::clearDisplay() +{ + for (int a = 0; a < (HEIGHT*WIDTH)/8; a++) sBuffer[a] = 0x00; +} + +void Arduboy::drawPixel(int x, int y, uint16_t value) +{ + if (x < 0 || x > (WIDTH-1) || y < 0 || y > (HEIGHT-1)) + { + return; + } + + int row = y / 8; + if (value) + { + sBuffer[(row*WIDTH) + x] |= 1 << (y % 8); + } + else + { + sBuffer[(row*WIDTH) + x] &= ~(1 << (y % 8)); + } +} + +void Arduboy::drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color) +{ + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + drawPixel(x0, y0+r, color); + drawPixel(x0, y0-r, color); + drawPixel(x0+r, y0, color); + drawPixel(x0-r, y0, color); + + while (x= 0) + { + y--; + ddF_y += 2; + f += ddF_y; + } + + x++; + ddF_x += 2; + f += ddF_x; + + drawPixel(x0 + x, y0 + y, color); + drawPixel(x0 - x, y0 + y, color); + drawPixel(x0 + x, y0 - y, color); + drawPixel(x0 - x, y0 - y, color); + drawPixel(x0 + y, y0 + x, color); + drawPixel(x0 - y, y0 + x, color); + drawPixel(x0 + y, y0 - x, color); + drawPixel(x0 - y, y0 - x, color); + } +} + +void Arduboy::drawCircleHelper +(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color) +{ + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + while (x= 0) + { + y--; + ddF_y += 2; + f += ddF_y; + } + + x++; + ddF_x += 2; + f += ddF_x; + + if (cornername & 0x4) + { + drawPixel(x0 + x, y0 + y, color); + drawPixel(x0 + y, y0 + x, color); + } + if (cornername & 0x2) + { + drawPixel(x0 + x, y0 - y, color); + drawPixel(x0 + y, y0 - x, color); + } + if (cornername & 0x8) + { + drawPixel(x0 - y, y0 + x, color); + drawPixel(x0 - x, y0 + y, color); + } + if (cornername & 0x1) + { + drawPixel(x0 - y, y0 - x, color); + drawPixel(x0 - x, y0 - y, color); + } + } +} + +void Arduboy::fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color) +{ + drawFastVLine(x0, y0-r, 2*r+1, color); + fillCircleHelper(x0, y0, r, 3, 0, color); +} + +void Arduboy::fillCircleHelper +( + int16_t x0, + int16_t y0, + int16_t r, + uint8_t cornername, + int16_t delta, + uint16_t color +) +{ + // used to do circles and roundrects! + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + while (x < y) + { + if (f >= 0) + { + y--; + ddF_y += 2; + f += ddF_y; + } + + x++; + ddF_x += 2; + f += ddF_x; + + if (cornername & 0x1) + { + drawFastVLine(x0+x, y0-y, 2*y+1+delta, color); + drawFastVLine(x0+y, y0-x, 2*x+1+delta, color); + } + + if (cornername & 0x2) + { + drawFastVLine(x0-x, y0-y, 2*y+1+delta, color); + drawFastVLine(x0-y, y0-x, 2*x+1+delta, color); + } + } +} + +void Arduboy::drawLine +(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color) +{ + // bresenham's algorithm - thx wikpedia + int16_t steep = abs(y1 - y0) > abs(x1 - x0); + if (steep) { + swap(x0, y0); + swap(x1, y1); + } + + if (x0 > x1) { + swap(x0, x1); + swap(y0, y1); + } + + int16_t dx, dy; + dx = x1 - x0; + dy = abs(y1 - y0); + + int16_t err = dx / 2; + int16_t ystep; + + if (y0 < y1) + { + ystep = 1; + } + else + { + ystep = -1; + } + + for (; x0 <= x1; x0++) + { + if (steep) + { + drawPixel(y0, x0, color); + } + else + { + drawPixel(x0, y0, color); + } + + err -= dy; + if (err < 0) + { + y0 += ystep; + err += dx; + } + } +} + +void Arduboy::drawRect +(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) +{ + drawFastHLine(x, y, w, color); + drawFastHLine(x, y+h-1, w, color); + drawFastVLine(x, y, h, color); + drawFastVLine(x+w-1, y, h, color); +} + +void Arduboy::drawFastVLine +(int16_t x, int16_t y, int16_t h, uint16_t color) +{ + int end = y+h; + for (int a = max(0,y); a < min(end,HEIGHT); a++) + { + drawPixel(x,a,color); + } +} + +void Arduboy::drawFastHLine +(int16_t x, int16_t y, int16_t w, uint16_t color) +{ + int end = x+w; + for (int a = max(0,x); a < min(end,WIDTH); a++) + { + drawPixel(a,y,color); + } +} + +void Arduboy::fillRect +(int16_t x, int16_t y, int16_t w, int16_t h, int16_t color) +{ + // stupidest version - update in subclasses if desired! + for (int16_t i=x; i= y1 >= y0) + if (y0 > y1) + { + swap(y0, y1); swap(x0, x1); + } + if (y1 > y2) + { + swap(y2, y1); swap(x2, x1); + } + if (y0 > y1) + { + swap(y0, y1); swap(x0, x1); + } + + if(y0 == y2) + { // Handle awkward all-on-same-line case as its own thing + a = b = x0; + if(x1 < a) + { + a = x1; + } + else if(x1 > b) + { + b = x1; + } + if(x2 < a) + { + a = x2; + } + else if(x2 > b) + { + b = x2; + } + drawFastHLine(a, y0, b-a+1, color); + return; + } + + int16_t dx01 = x1 - x0, + dy01 = y1 - y0, + dx02 = x2 - x0, + dy02 = y2 - y0, + dx12 = x2 - x1, + dy12 = y2 - y1, + sa = 0, + sb = 0; + + // For upper part of triangle, find scanline crossings for segments + // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 + // is included here (and second loop will be skipped, avoiding a /0 + // error there), otherwise scanline y1 is skipped here and handled + // in the second loop...which also avoids a /0 error here if y0=y1 + // (flat-topped triangle). + if (y1 == y2) + { + last = y1; // Include y1 scanline + } + else + { + last = y1-1; // Skip it + } + + + for(y = y0; y <= last; y++) + { + a = x0 + sa / dy01; + b = x0 + sb / dy02; + sa += dx01; + sb += dx02; + + if(a > b) + { + swap(a,b); + } + + drawFastHLine(a, y, b-a+1, color); + } + + // For lower part of triangle, find scanline crossings for segments + // 0-2 and 1-2. This loop is skipped if y1=y2. + sa = dx12 * (y - y1); + sb = dx02 * (y - y0); + + for(; y <= y2; y++) + { + a = x1 + sa / dy12; + b = x0 + sb / dy02; + sa += dx12; + sb += dx02; + + if(a > b) + { + swap(a,b); + } + + drawFastHLine(a, y, b-a+1, color); + } +} +void Arduboy::drawBitmap +(int16_t x, + int16_t y, + const uint8_t *bitmap, + int16_t w, + int16_t h, + uint16_t color +) +{ + //bitmap is off screen + if (x+w < 0 || x > WIDTH-1 || y+h < 0 || y > HEIGHT-1) return; + + int yOffset = abs(y) % 8; + int sRow = y / 8; + + if (y < 0) + { + sRow--; + yOffset = 8 - yOffset; + } + + for (int a = 0; a < h/8; a++) + { + int bRow = sRow + a; + if (bRow > (HEIGHT/8)-1) break; + if (bRow > -2) { + for (int iCol = 0; iCol (WIDTH-1)) + { + break; + } + + if (iCol + x > 0) + { + if (bRow >= 0) + { + if (color) + { + this->sBuffer[ (bRow*WIDTH) + x + iCol ] + |= pgm_read_byte(bitmap+(a*w)+iCol) << yOffset; + } + else + { + this->sBuffer[ (bRow*WIDTH) + x + iCol ] + &= ~(pgm_read_byte(bitmap+(a*w)+iCol) << yOffset); + } + } + if (yOffset && bRow<(HEIGHT/8)-1 && bRow > -2) + { + if (color) + { + this->sBuffer[ ((bRow+1)*WIDTH) + x + iCol ] + |= pgm_read_byte(bitmap+(a*w)+iCol) >> (8-yOffset); + } + else + { + this->sBuffer[ ((bRow+1)*WIDTH) + x + iCol ] + &= ~(pgm_read_byte(bitmap+(a*w)+iCol) >> (8-yOffset)); + } + } + } + } + } + } +} + +void Arduboy::drawChar +(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size) +{ + + if ((x >= WIDTH) || // Clip right + (y >= HEIGHT) || // Clip bottom + ((x + 5 * size - 1) < 0) || // Clip left + ((y + 8 * size - 1) < 0) // Clip top + ) + { + return; + } + + for (int8_t i=0; i<6; i++ ) + { + uint8_t line; + if (i == 5) + { + line = 0x0; + } + else + { + line = pgm_read_byte(font+(c*5)+i); + } + + for (int8_t j = 0; j<8; j++) + { + if (line & 0x1) + { + if (size == 1) // default size + { + drawPixel(x+i, y+j, color); + } + else // big size + { + fillRect(x+(i*size), y+(j*size), size, size, color); + } + } + else if (bg != color) + { + if (size == 1) // default size + { + drawPixel(x+i, y+j, bg); + } + else + { // big size + fillRect(x+i*size, y+j*size, size, size, bg); + } + } + + line >>= 1; + } + } +} + +void Arduboy::setCursor(int16_t x, int16_t y) +{ + cursor_x = x; + cursor_y = y; +} + +void Arduboy::setTextSize(uint8_t s) +{ + textsize = (s > 0) ? s : 1; +} + +void Arduboy::setTextWrap(boolean w) +{ + wrap = w; +} + +size_t Arduboy::write(uint8_t c) +{ + if (c == '\n') + { + cursor_y += textsize*8; + cursor_x = 0; + } + else if (c == '\r') + { + // skip em + } + else + { + drawChar(cursor_x, cursor_y, c, 1, 0, textsize); + cursor_x += textsize*6; + if (wrap && (cursor_x > (WIDTH - textsize*6))) + { + cursor_y += textsize*8; + cursor_x = 0; + } + } +} + +void Arduboy::display() +{ + this->drawScreen(sBuffer); +} + +void Arduboy::drawScreen(const unsigned char *image) +{ + for (int a = 0; a < (HEIGHT*WIDTH)/8; a++) + { + SPI.transfer(pgm_read_byte(image + a)); + } +} + +void Arduboy::drawScreen(unsigned char image[]) +{ + for (int a = 0; a < (HEIGHT*WIDTH)/8; a++) + { + SPI.transfer(image[a]); + } +} + +uint8_t Arduboy::width() { return WIDTH; } + +uint8_t Arduboy::height() { return HEIGHT; } + +uint8_t Arduboy::getInput() +{ + // b00lurdab + uint8_t value = B00000000; + + if (digitalRead(9) == 0) { value = value | B00100000; } // left + if (digitalRead(8) == 0) { value = value | B00010000; } // up + if (digitalRead(5) == 0) { value = value | B00001000; } // right + if (digitalRead(10) == 0) { value = value | B00000100; } // down + if (digitalRead(A0) == 0) { value = value | B00000010; } // a? + if (digitalRead(A1) == 0) { value = value | B00000001; } // b? + return value; +} + +void Arduboy::swap(int16_t& a, int16_t& b) { + int temp = a; + a = b; + b = temp; +} diff --git a/Arduboy.h b/Arduboy.h new file mode 100644 index 0000000..0f15ff8 --- /dev/null +++ b/Arduboy.h @@ -0,0 +1,64 @@ +#ifndef Arduboy_h +#define Arduboy_h + +#include +#include + +#define CS 6 +#define DC 4 +#define RST 12 + +#define WIDTH 128 +#define HEIGHT 64 + +class Arduboy : public Print +{ +public: + Arduboy(); + uint8_t getInput(); + void start(); + void blank(); + void clearDisplay(); + void display(); + void drawScreen(const unsigned char *image); + void drawScreen(unsigned char image[]); + void drawPixel(int x, int y, uint16_t value); + void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color); + void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color); + void fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color); + void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint16_t color); + void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t color); + void fillScreen(uint16_t color); + void drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color); + void fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color); + void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color); + void fillTriangle (int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color); + void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color); + void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size); + void setCursor(int16_t x, int16_t y); + void setTextSize(uint8_t s); + void setTextWrap(boolean w); + uint8_t width(); + uint8_t height(); + virtual size_t write(uint8_t); + void swap(int16_t& a, int16_t& b); + +private: + unsigned char sBuffer[(HEIGHT*WIDTH)/8]; + uint8_t readCapacitivePin(int pinToMeasure); + uint8_t readCapXtal(int pinToMeasure); + volatile uint8_t *mosiport, *clkport, *csport, *dcport; + uint8_t mosipinmask, clkpinmask, cspinmask, dcpinmask; + +// Adafruit stuff +protected: + int16_t cursor_x, cursor_y; + uint8_t textsize; + boolean wrap; // If set, 'wrap' text at right edge of display +}; + +#endif diff --git a/README.md b/README.md new file mode 100644 index 0000000..5ed7155 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +#ArduBreak diff --git a/breakout_bitmaps.cpp b/breakout_bitmaps.cpp new file mode 100644 index 0000000..e87616b --- /dev/null +++ b/breakout_bitmaps.cpp @@ -0,0 +1,124 @@ +#include "breakout_bitmaps.h" + +PROGMEM const unsigned char title[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x07,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xE0,0x00, + 0x00,0x08,0x00,0x60,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x03,0xF4,0x10,0x00, + 0x00,0x0B,0xFF,0x10,0x00,0x00,0x00,0x20,0x80,0x00,0x00,0x04,0x09,0xD0,0x00, + 0x00,0x0B,0x83,0xD0,0x00,0x00,0x00,0x2E,0xB8,0x00,0x00,0x05,0xE1,0xD0,0x00, + 0x00,0x0B,0x83,0xD0,0x00,0x00,0x00,0x2E,0x44,0x00,0x00,0x05,0xE1,0xD0,0x00, + 0x00,0x0B,0x83,0xD0,0x00,0x00,0x00,0x2E,0x34,0x00,0x00,0x05,0xE1,0xD0,0x00, + 0x00,0x0B,0x83,0xCF,0xFF,0xF9,0xFF,0xAE,0x35,0xFF,0x7C,0xF9,0xE1,0xD0,0x00, + 0x00,0x0B,0x83,0xC0,0x00,0x06,0x00,0x4E,0x66,0x00,0x83,0x01,0xE1,0xD0,0x00, + 0x00,0x0B,0xFF,0x13,0xE7,0xF0,0xFF,0x0F,0xE0,0x7E,0x38,0x73,0xF9,0xD0,0x00, + 0x00,0x0B,0xFF,0x13,0xE7,0xF0,0xFF,0x0F,0xC0,0x7E,0x38,0x73,0xF9,0xD0,0x00, + 0x00,0x0B,0x83,0xDC,0x0E,0x0C,0x01,0xCF,0x80,0xE1,0x38,0x71,0xE1,0xD0,0x00, + 0x00,0x0B,0x83,0xDC,0xCE,0x0C,0x01,0xCF,0xC0,0xE1,0x38,0x71,0xE1,0xD0,0x00, + 0x00,0x0B,0x83,0xDD,0x2F,0xF0,0x7F,0xCE,0xE0,0xE1,0x38,0x71,0xE0,0x10,0x00, + 0x00,0x0B,0x83,0xDD,0x2F,0xF0,0xFF,0xCE,0x70,0xE1,0x38,0x71,0xE0,0x10,0x00, + 0x00,0x0B,0x83,0xDD,0x2E,0x00,0x81,0xCE,0x38,0xE1,0x38,0x71,0xE1,0xD0,0x00, + 0x00,0x0B,0xFF,0x1D,0x27,0xFC,0xFE,0xCE,0x1C,0x7E,0x1F,0xC4,0x79,0xD0,0x00, + 0x00,0x0B,0xFF,0x1D,0x17,0xFC,0x7E,0xCE,0x0C,0x7E,0x1F,0xCA,0x79,0xD0,0x00, + 0x00,0x08,0x00,0x41,0x10,0x01,0x00,0x00,0xE1,0x00,0xC0,0x11,0x00,0x10,0x00, + 0x00,0x07,0xFF,0xBE,0x0F,0xFE,0xFF,0xFF,0x1E,0xFF,0x3F,0xE0,0xFF,0xE0,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x04,0x04,0x10,0x03,0x8A,0x10,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x04,0x00,0x00,0x02,0x08,0x80,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xF3,0x35,0x54,0xD7,0x63,0x1A,0xD7,0x60,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x95,0x46,0x54,0x95,0x52,0x2A,0x95,0x50,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x93,0x35,0x25,0x97,0x53,0x9A,0x57,0x50,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xF0,0x06,0x04,0x00,0x04,0x00,0x38,0x00,0x0A,0x00,0x00,0x00, + 0x00,0x00,0x00,0x88,0x09,0x04,0x00,0x20,0x00,0x44,0x00,0x02,0x00,0x00,0x00, + 0x00,0x00,0x00,0xF2,0x84,0x27,0x31,0xB5,0x98,0x40,0xC6,0x6A,0x80,0x00,0x00, + 0x00,0x00,0x00,0x8A,0x82,0x54,0x8A,0x24,0x54,0x4D,0x28,0x8B,0x00,0x00,0x00, + 0x00,0x00,0x00,0x8A,0x89,0x44,0xA8,0xA5,0x54,0x45,0x22,0x8A,0x80,0x00,0x00, + 0x00,0x00,0x00,0xF1,0x06,0x37,0x1B,0x14,0xD4,0x3C,0xCC,0x6A,0x80,0x00,0x00, + 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +PROGMEM const unsigned char fire[] = +{ + 57,8, + 0xF8,0x00,0x00,0x00,0x3D,0xEF,0x8F,0x80, + 0xCC,0x00,0x00,0x00,0x60,0xCC,0xD8,0x00, + 0xCC,0x00,0x00,0x00,0x60,0xCC,0xD8,0x00, + 0xF9,0x67,0x1E,0x78,0x78,0xCF,0x9F,0x00, + 0xC1,0x8C,0xA0,0x80,0x60,0xCC,0xD8,0x00, + 0xC1,0x8F,0x1C,0x70,0x60,0xCC,0xD8,0x00, + 0xC1,0x8C,0x02,0x08,0x60,0xCC,0xDF,0x80, + 0xC1,0x87,0xBC,0xF0,0x61,0xEC,0xCF,0x80, +}; + +PROGMEM const unsigned char arrow[] = +{ + 5,5, + 0x20, + 0x10, + 0xF8, + 0x10, + 0x20, +}; diff --git a/breakout_bitmaps.h b/breakout_bitmaps.h new file mode 100644 index 0000000..a560d19 --- /dev/null +++ b/breakout_bitmaps.h @@ -0,0 +1,13 @@ +#ifndef ASTEROID_BITMAPS_H +#define ASTEROID_BITMAPS_H + +#include + +extern const unsigned char fire[]; +extern const unsigned char title[]; +extern const unsigned char arrow[]; + +#endif + + + diff --git a/glcdfont.c b/glcdfont.c new file mode 100644 index 0000000..07cacf6 --- /dev/null +++ b/glcdfont.c @@ -0,0 +1,267 @@ +#include +#include + +#ifndef FONT5X7_H +#define FONT5X7_H + +// standard ascii 5x7 font +const static unsigned char font[] PROGMEM = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, + 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, + 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, + 0x18, 0x3C, 0x7E, 0x3C, 0x18, + 0x1C, 0x57, 0x7D, 0x57, 0x1C, + 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, + 0x00, 0x18, 0x3C, 0x18, 0x00, + 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, + 0x00, 0x18, 0x24, 0x18, 0x00, + 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, + 0x30, 0x48, 0x3A, 0x06, 0x0E, + 0x26, 0x29, 0x79, 0x29, 0x26, + 0x40, 0x7F, 0x05, 0x05, 0x07, + 0x40, 0x7F, 0x05, 0x25, 0x3F, + 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, + 0x7F, 0x3E, 0x1C, 0x1C, 0x08, + 0x08, 0x1C, 0x1C, 0x3E, 0x7F, + 0x14, 0x22, 0x7F, 0x22, 0x14, + 0x5F, 0x5F, 0x00, 0x5F, 0x5F, + 0x06, 0x09, 0x7F, 0x01, 0x7F, + 0x00, 0x66, 0x89, 0x95, 0x6A, + 0x60, 0x60, 0x60, 0x60, 0x60, + 0x94, 0xA2, 0xFF, 0xA2, 0x94, + 0x08, 0x04, 0x7E, 0x04, 0x08, + 0x10, 0x20, 0x7E, 0x20, 0x10, + 0x08, 0x08, 0x2A, 0x1C, 0x08, + 0x08, 0x1C, 0x2A, 0x08, 0x08, + 0x1E, 0x10, 0x10, 0x10, 0x10, + 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, + 0x30, 0x38, 0x3E, 0x38, 0x30, + 0x06, 0x0E, 0x3E, 0x0E, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5F, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x07, 0x00, + 0x14, 0x7F, 0x14, 0x7F, 0x14, + 0x24, 0x2A, 0x7F, 0x2A, 0x12, + 0x23, 0x13, 0x08, 0x64, 0x62, + 0x36, 0x49, 0x56, 0x20, 0x50, + 0x00, 0x08, 0x07, 0x03, 0x00, + 0x00, 0x1C, 0x22, 0x41, 0x00, + 0x00, 0x41, 0x22, 0x1C, 0x00, + 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, + 0x08, 0x08, 0x3E, 0x08, 0x08, + 0x00, 0x80, 0x70, 0x30, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00, 0x60, 0x60, 0x00, + 0x20, 0x10, 0x08, 0x04, 0x02, + 0x3E, 0x51, 0x49, 0x45, 0x3E, + 0x00, 0x42, 0x7F, 0x40, 0x00, + 0x72, 0x49, 0x49, 0x49, 0x46, + 0x21, 0x41, 0x49, 0x4D, 0x33, + 0x18, 0x14, 0x12, 0x7F, 0x10, + 0x27, 0x45, 0x45, 0x45, 0x39, + 0x3C, 0x4A, 0x49, 0x49, 0x31, + 0x41, 0x21, 0x11, 0x09, 0x07, + 0x36, 0x49, 0x49, 0x49, 0x36, + 0x46, 0x49, 0x49, 0x29, 0x1E, + 0x00, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x40, 0x34, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x22, 0x41, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x00, 0x41, 0x22, 0x14, 0x08, + 0x02, 0x01, 0x59, 0x09, 0x06, + 0x3E, 0x41, 0x5D, 0x59, 0x4E, + 0x7C, 0x12, 0x11, 0x12, 0x7C, + 0x7F, 0x49, 0x49, 0x49, 0x36, + 0x3E, 0x41, 0x41, 0x41, 0x22, + 0x7F, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x49, 0x49, 0x49, 0x41, + 0x7F, 0x09, 0x09, 0x09, 0x01, + 0x3E, 0x41, 0x41, 0x51, 0x73, + 0x7F, 0x08, 0x08, 0x08, 0x7F, + 0x00, 0x41, 0x7F, 0x41, 0x00, + 0x20, 0x40, 0x41, 0x3F, 0x01, + 0x7F, 0x08, 0x14, 0x22, 0x41, + 0x7F, 0x40, 0x40, 0x40, 0x40, + 0x7F, 0x02, 0x1C, 0x02, 0x7F, + 0x7F, 0x04, 0x08, 0x10, 0x7F, + 0x3E, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x09, 0x09, 0x09, 0x06, + 0x3E, 0x41, 0x51, 0x21, 0x5E, + 0x7F, 0x09, 0x19, 0x29, 0x46, + 0x26, 0x49, 0x49, 0x49, 0x32, + 0x03, 0x01, 0x7F, 0x01, 0x03, + 0x3F, 0x40, 0x40, 0x40, 0x3F, + 0x1F, 0x20, 0x40, 0x20, 0x1F, + 0x3F, 0x40, 0x38, 0x40, 0x3F, + 0x63, 0x14, 0x08, 0x14, 0x63, + 0x03, 0x04, 0x78, 0x04, 0x03, + 0x61, 0x59, 0x49, 0x4D, 0x43, + 0x00, 0x7F, 0x41, 0x41, 0x41, + 0x02, 0x04, 0x08, 0x10, 0x20, + 0x00, 0x41, 0x41, 0x41, 0x7F, + 0x04, 0x02, 0x01, 0x02, 0x04, + 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x03, 0x07, 0x08, 0x00, + 0x20, 0x54, 0x54, 0x78, 0x40, + 0x7F, 0x28, 0x44, 0x44, 0x38, + 0x38, 0x44, 0x44, 0x44, 0x28, + 0x38, 0x44, 0x44, 0x28, 0x7F, + 0x38, 0x54, 0x54, 0x54, 0x18, + 0x00, 0x08, 0x7E, 0x09, 0x02, + 0x18, 0xA4, 0xA4, 0x9C, 0x78, + 0x7F, 0x08, 0x04, 0x04, 0x78, + 0x00, 0x44, 0x7D, 0x40, 0x00, + 0x20, 0x40, 0x40, 0x3D, 0x00, + 0x7F, 0x10, 0x28, 0x44, 0x00, + 0x00, 0x41, 0x7F, 0x40, 0x00, + 0x7C, 0x04, 0x78, 0x04, 0x78, + 0x7C, 0x08, 0x04, 0x04, 0x78, + 0x38, 0x44, 0x44, 0x44, 0x38, + 0xFC, 0x18, 0x24, 0x24, 0x18, + 0x18, 0x24, 0x24, 0x18, 0xFC, + 0x7C, 0x08, 0x04, 0x04, 0x08, + 0x48, 0x54, 0x54, 0x54, 0x24, + 0x04, 0x04, 0x3F, 0x44, 0x24, + 0x3C, 0x40, 0x40, 0x20, 0x7C, + 0x1C, 0x20, 0x40, 0x20, 0x1C, + 0x3C, 0x40, 0x30, 0x40, 0x3C, + 0x44, 0x28, 0x10, 0x28, 0x44, + 0x4C, 0x90, 0x90, 0x90, 0x7C, + 0x44, 0x64, 0x54, 0x4C, 0x44, + 0x00, 0x08, 0x36, 0x41, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, + 0x00, 0x41, 0x36, 0x08, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x02, + 0x3C, 0x26, 0x23, 0x26, 0x3C, + 0x1E, 0xA1, 0xA1, 0x61, 0x12, + 0x3A, 0x40, 0x40, 0x20, 0x7A, + 0x38, 0x54, 0x54, 0x55, 0x59, + 0x21, 0x55, 0x55, 0x79, 0x41, + 0x21, 0x54, 0x54, 0x78, 0x41, + 0x21, 0x55, 0x54, 0x78, 0x40, + 0x20, 0x54, 0x55, 0x79, 0x40, + 0x0C, 0x1E, 0x52, 0x72, 0x12, + 0x39, 0x55, 0x55, 0x55, 0x59, + 0x39, 0x54, 0x54, 0x54, 0x59, + 0x39, 0x55, 0x54, 0x54, 0x58, + 0x00, 0x00, 0x45, 0x7C, 0x41, + 0x00, 0x02, 0x45, 0x7D, 0x42, + 0x00, 0x01, 0x45, 0x7C, 0x40, + 0xF0, 0x29, 0x24, 0x29, 0xF0, + 0xF0, 0x28, 0x25, 0x28, 0xF0, + 0x7C, 0x54, 0x55, 0x45, 0x00, + 0x20, 0x54, 0x54, 0x7C, 0x54, + 0x7C, 0x0A, 0x09, 0x7F, 0x49, + 0x32, 0x49, 0x49, 0x49, 0x32, + 0x32, 0x48, 0x48, 0x48, 0x32, + 0x32, 0x4A, 0x48, 0x48, 0x30, + 0x3A, 0x41, 0x41, 0x21, 0x7A, + 0x3A, 0x42, 0x40, 0x20, 0x78, + 0x00, 0x9D, 0xA0, 0xA0, 0x7D, + 0x39, 0x44, 0x44, 0x44, 0x39, + 0x3D, 0x40, 0x40, 0x40, 0x3D, + 0x3C, 0x24, 0xFF, 0x24, 0x24, + 0x48, 0x7E, 0x49, 0x43, 0x66, + 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, + 0xFF, 0x09, 0x29, 0xF6, 0x20, + 0xC0, 0x88, 0x7E, 0x09, 0x03, + 0x20, 0x54, 0x54, 0x79, 0x41, + 0x00, 0x00, 0x44, 0x7D, 0x41, + 0x30, 0x48, 0x48, 0x4A, 0x32, + 0x38, 0x40, 0x40, 0x22, 0x7A, + 0x00, 0x7A, 0x0A, 0x0A, 0x72, + 0x7D, 0x0D, 0x19, 0x31, 0x7D, + 0x26, 0x29, 0x29, 0x2F, 0x28, + 0x26, 0x29, 0x29, 0x29, 0x26, + 0x30, 0x48, 0x4D, 0x40, 0x20, + 0x38, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x38, + 0x2F, 0x10, 0xC8, 0xAC, 0xBA, + 0x2F, 0x10, 0x28, 0x34, 0xFA, + 0x00, 0x00, 0x7B, 0x00, 0x00, + 0x08, 0x14, 0x2A, 0x14, 0x22, + 0x22, 0x14, 0x2A, 0x14, 0x08, + 0xAA, 0x00, 0x55, 0x00, 0xAA, + 0xAA, 0x55, 0xAA, 0x55, 0xAA, + 0x00, 0x00, 0x00, 0xFF, 0x00, + 0x10, 0x10, 0x10, 0xFF, 0x00, + 0x14, 0x14, 0x14, 0xFF, 0x00, + 0x10, 0x10, 0xFF, 0x00, 0xFF, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x14, 0x14, 0x14, 0xFC, 0x00, + 0x14, 0x14, 0xF7, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x14, 0x14, 0xF4, 0x04, 0xFC, + 0x14, 0x14, 0x17, 0x10, 0x1F, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0x1F, 0x00, + 0x10, 0x10, 0x10, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0xF0, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0xFF, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x14, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x1F, 0x10, 0x17, + 0x00, 0x00, 0xFC, 0x04, 0xF4, + 0x14, 0x14, 0x17, 0x10, 0x17, + 0x14, 0x14, 0xF4, 0x04, 0xF4, + 0x00, 0x00, 0xFF, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0xF7, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x17, 0x14, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0xF4, 0x14, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x00, 0x00, 0x1F, 0x10, 0x1F, + 0x00, 0x00, 0x00, 0x1F, 0x14, + 0x00, 0x00, 0x00, 0xFC, 0x14, + 0x00, 0x00, 0xF0, 0x10, 0xF0, + 0x10, 0x10, 0xFF, 0x10, 0xFF, + 0x14, 0x14, 0x14, 0xFF, 0x14, + 0x10, 0x10, 0x10, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x10, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x38, 0x44, 0x44, 0x38, 0x44, + 0x7C, 0x2A, 0x2A, 0x3E, 0x14, + 0x7E, 0x02, 0x02, 0x06, 0x06, + 0x02, 0x7E, 0x02, 0x7E, 0x02, + 0x63, 0x55, 0x49, 0x41, 0x63, + 0x38, 0x44, 0x44, 0x3C, 0x04, + 0x40, 0x7E, 0x20, 0x1E, 0x20, + 0x06, 0x02, 0x7E, 0x02, 0x02, + 0x99, 0xA5, 0xE7, 0xA5, 0x99, + 0x1C, 0x2A, 0x49, 0x2A, 0x1C, + 0x4C, 0x72, 0x01, 0x72, 0x4C, + 0x30, 0x4A, 0x4D, 0x4D, 0x30, + 0x30, 0x48, 0x78, 0x48, 0x30, + 0xBC, 0x62, 0x5A, 0x46, 0x3D, + 0x3E, 0x49, 0x49, 0x49, 0x00, + 0x7E, 0x01, 0x01, 0x01, 0x7E, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x44, 0x44, 0x5F, 0x44, 0x44, + 0x40, 0x51, 0x4A, 0x44, 0x40, + 0x40, 0x44, 0x4A, 0x51, 0x40, + 0x00, 0x00, 0xFF, 0x01, 0x03, + 0xE0, 0x80, 0xFF, 0x00, 0x00, + 0x08, 0x08, 0x6B, 0x6B, 0x08, + 0x36, 0x12, 0x36, 0x24, 0x36, + 0x06, 0x0F, 0x09, 0x0F, 0x06, + 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x00, + 0x30, 0x40, 0xFF, 0x01, 0x01, + 0x00, 0x1F, 0x01, 0x01, 0x1E, + 0x00, 0x19, 0x1D, 0x17, 0x12, + 0x00, 0x3C, 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +#endif