refactor of UI layer

This commit is contained in:
Jorj Bauer 2018-01-07 14:43:17 -05:00
parent 7f6e7dd73a
commit 7da0ed9a2b
21 changed files with 29816 additions and 29750 deletions

View File

@ -6,7 +6,7 @@ CXXFLAGS=-Wall -I .. -I . -I apple -I sdl -I/usr/local/include/SDL2 -O3 -g
TSRC=cpu.cpp util/testharness.cpp
COMMONOBJS=cpu.o apple/appledisplay.o apple/applekeyboard.o apple/applemmu.o apple/applevm.o apple/diskii.o apple/nibutil.o LRingBuffer.o globals.o apple/parallelcard.o apple/fx80.o lcg.o apple/hd32.o
COMMONOBJS=cpu.o apple/appledisplay.o apple/applekeyboard.o apple/applemmu.o apple/applevm.o apple/diskii.o apple/nibutil.o LRingBuffer.o globals.o apple/parallelcard.o apple/fx80.o lcg.o apple/hd32.o images.o apple/appleui.o
SDLOBJS=sdl/sdl-speaker.o sdl/sdl-display.o sdl/sdl-keyboard.o sdl/sdl-paddles.o sdl/sdl-filemanager.o sdl/aiie.o sdl/sdl-printer.o sdl/sdl-clock.o

View File

@ -40,7 +40,7 @@
#if DISPLAYRUN == 512
#define drawPixel(c, x, y) { \
#define drawApplePixel(c, x, y) { \
uint16_t idx = (((y) << 9) + (x)) >> 1; \
if ((x) & 1) { \
videoBuffer[idx] = (videoBuffer[idx] & 0xF0) | (c); \
@ -56,7 +56,7 @@
#else
#define drawPixel(c, x, y) { \
#define drawApplePixel(c, x, y) { \
uint16_t idx = ((y) * DISPLAYRUN + (x)) / 2; \
if ((x) & 1) { \
videoBuffer[idx] = (videoBuffer[idx] & 0xF0) | (c); \
@ -76,13 +76,13 @@
uint8_t pixel = c & 0x0F; \
for (uint8_t y2 = 0; y2<4; y2++) { \
for (int8_t x2 = 6; x2>=0; x2--) { \
drawPixel(pixel, x*7+x2, y*8+y2); \
drawApplePixel(pixel, x*7+x2, y*8+y2); \
} \
} \
pixel = (c >> 4); \
for (uint8_t y2 = 4; y2<8; y2++) { \
for (int8_t x2 = 6; x2>=0; x2--) { \
drawPixel(pixel, x*7+x2, y*8+y2); \
drawApplePixel(pixel, x*7+x2, y*8+y2); \
} \
} \
}
@ -243,8 +243,8 @@ inline void AppleDisplay::Draw14DoubleHiresPixelsAt(uint16_t addr)
// pixels for every color.
for (int8_t xoff = 0; xoff < 14; xoff += 2) {
drawPixel(bitTrain & 0x0F, col+xoff, row);
drawPixel(bitTrain & 0x0F, col+xoff+1, row);
drawApplePixel(bitTrain & 0x0F, col+xoff, row);
drawApplePixel(bitTrain & 0x0F, col+xoff+1, row);
bitTrain >>= 4;
}
@ -425,10 +425,10 @@ void AppleDisplay::redraw80ColumnText(uint8_t startingY)
bool pixelOn = ( (d & (1<<x2)) | (d & (1<<(x2+1))) );
if (pixelOn) {
uint8_t val = (invert ? c_black : textColor);
drawPixel(val, (basex+x2)/2, row*8+y2);
drawApplePixel(val, (basex+x2)/2, row*8+y2);
} else {
uint8_t val = (invert ? textColor : c_black);
drawPixel(val, (basex+x2)/2, row*8+y2);
drawApplePixel(val, (basex+x2)/2, row*8+y2);
}
}
}
@ -442,10 +442,10 @@ void AppleDisplay::redraw80ColumnText(uint8_t startingY)
bool pixelOn = ( (d & (1<<x2)) | (d & (1<<(x2+1))) );
if (pixelOn) {
uint8_t val = (invert ? c_black : textColor);
drawPixel(val, (basex+x2)/2, row*8+y2);
drawApplePixel(val, (basex+x2)/2, row*8+y2);
} else {
uint8_t val = (invert ? textColor : c_black);
drawPixel(val, (basex+x2)/2, row*8+y2);
drawApplePixel(val, (basex+x2)/2, row*8+y2);
}
}
}
@ -480,10 +480,10 @@ void AppleDisplay::redraw40ColumnText(uint8_t startingY)
for (uint8_t x2 = 0; x2 < 7; x2++) {
if (d & 1) {
uint8_t val = (invert ? c_black : textColor);
drawPixel(val, col*7+x2, row*8+y2);
drawApplePixel(val, col*7+x2, row*8+y2);
} else {
uint8_t val = (invert ? textColor : c_black);
drawPixel(val, col*7+x2, row*8+y2);
drawApplePixel(val, col*7+x2, row*8+y2);
}
d >>= 1;
}
@ -562,14 +562,14 @@ void AppleDisplay::Draw80LoresPixelAt(uint8_t c, uint8_t x, uint8_t y, uint8_t o
uint8_t pixel = c & 0x0F;
for (uint8_t y2 = 0; y2<4; y2++) {
for (int8_t x2 = 3; x2>=offset; x2--) {
drawPixel(pixel, x*7+x2+offset*3, y*8+y2);
drawApplePixel(pixel, x*7+x2+offset*3, y*8+y2);
}
}
pixel = (c >> 4);
for (uint8_t y2 = 4; y2<8; y2++) {
for (int8_t x2 = 3; x2>=offset; x2--) {
drawPixel(pixel, x*7+x2+offset*3, y*8+y2);
drawApplePixel(pixel, x*7+x2+offset*3, y*8+y2);
}
}
}

127
apple/appleui.cpp Normal file
View File

@ -0,0 +1,127 @@
#include "appleui.h"
#include "vm.h" // for DISPLAYHEIGHT. Probably not the most sensible.
#include "images.h"
#include "globals.h"
// FIXME: abstract and standardize the sizes, onscreen locations, and
// underlying bitmap types
AppleUI::AppleUI()
{
}
AppleUI::~AppleUI()
{
}
void AppleUI::drawStaticUIElement(uint8_t element)
{
// Only one static UI element right now...
if (element != UIeOverlay)
return;
g_display->drawImageOfSizeAt(displayBitmap, DBITMAP_WIDTH, DBITMAP_HEIGHT, 0, 0);
}
void AppleUI::drawOnOffUIElement(uint8_t element, bool state)
{
uint16_t xoff = 55;
uint8_t yoff = 216;
uint16_t xsize;
uint8_t ysize;
const uint8_t *img;
switch (element) {
case UIeDisk1_state:
xoff = 55;
yoff = 216;
xsize = 43;
ysize = 20;
img = state ? driveLatchOpen : driveLatch;
break;
case UIeDisk2_state:
xoff = 55+134;
yoff = 216;
xsize = 43;
ysize = 20;
img = state ? driveLatchOpen : driveLatch;
break;
case UIeDisk1_activity:
case UIeDisk2_activity:
{
uint16_t xoff = 125;
uint16_t yoff = 213;
if (element == UIeDisk2_activity)
xoff += 135;
for (int x=0; x<6; x++) {
g_display->drawPixel(x + xoff, yoff, state ? 0xF800 : 0x8AA9);
g_display->drawPixel(x + xoff, yoff + 1, state ? 0xF800 : 0x8AA9);
}
}
return;
default:
return;
}
g_display->drawImageOfSizeAt(img, xsize, ysize, xoff, yoff);
}
void AppleUI::drawPercentageUIElement(uint8_t element, uint8_t percent)
{
// only 1 element of this type
if (element != UIePowerPercentage) {
return;
}
drawBatteryStatus(percent);
}
void AppleUI::drawBatteryStatus(uint8_t percent)
{
uint16_t xoff = 301;
uint16_t yoff = 222;
// the area around the apple is 12 wide; it's exactly 11 high the
// color is 210/202/159
float watermark = ((float)percent / 100.0) * 11;
for (int y=0; y<11; y++) {
uint8_t bgr = 210;
uint8_t bgg = 202;
uint8_t bgb = 159;
if (11-y > watermark) {
// black...
bgr = bgg = bgb = 0;
}
for (int x=0; x<10; x++) {
#ifdef TEENSYDUINO
uint8_t r = pgm_read_byte(&appleBitmap[(y * 10 + x)*4 + 0]);
uint8_t g = pgm_read_byte(&appleBitmap[(y * 10 + x)*4 + 1]);
uint8_t b = pgm_read_byte(&appleBitmap[(y * 10 + x)*4 + 2]);
uint8_t a = pgm_read_byte(&appleBitmap[(y * 10 + x)*4 + 3]);
#else
const uint8_t *p = &appleBitmap[(y * 10 + (x-1))*4];
uint8_t r, g, b, a;
r = p[0];
g = p[1];
b = p[2];
a = p[3];
#endif
// It's RGBA; blend w/ background color
float alpha = (float)a / 255.0;
r = (float)r * alpha + (bgr * (1.0 - alpha));
g = (float)g * alpha + (bgg * (1.0 - alpha));
b = (float)b * alpha + (bgb * (1.0 - alpha));
g_display->drawPixel(x+xoff, y+yoff, r, g, b);
}
}
}

29
apple/appleui.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef __APPLEUI_H
#define __APPLEUI_H
#include "vmui.h"
// Element IDs
enum {
UIeOverlay = 0,
UIeDisk1_state = 1,
UIeDisk2_state = 2,
UIeDisk1_activity = 3,
UIeDisk2_activity = 4,
UIePowerPercentage = 5,
};
class AppleUI : public VMui {
public:
AppleUI();
~AppleUI();
virtual void drawStaticUIElement(uint8_t element);
virtual void drawOnOffUIElement(uint8_t element, bool state);
virtual void drawPercentageUIElement(uint8_t element, uint8_t percent);
void drawBatteryStatus(uint8_t percent);
};
#endif

View File

@ -13,6 +13,7 @@
#include "applemmu.h" // for FLOATING
#include "globals.h"
#include "appleui.h"
#include "diskii-rom.h"
@ -195,12 +196,12 @@ uint8_t DiskII::readSwitches(uint8_t s)
case 0x08: // drive off
indicatorIsOn[selectedDisk] = 99;
g_display->setDriveIndicator(selectedDisk, false); // FIXME: after a spell...
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false); // FIXME: delay a bit? Queue for later drawing?
checkFlush(curHalfTrack[selectedDisk]>>1);
break;
case 0x09: // drive on
indicatorIsOn[selectedDisk] = 100;
g_display->setDriveIndicator(selectedDisk, true);
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, true); // FIXME: delay a bit? Queue for later drawing?
break;
case 0x0A: // select drive 1
@ -238,12 +239,12 @@ uint8_t DiskII::readSwitches(uint8_t s)
if (!indicatorIsOn[selectedDisk]) {
// printf("Unexpected read while disk isn't on?\n");
indicatorIsOn[selectedDisk] = 100;
g_display->setDriveIndicator(selectedDisk, true);
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, true); // FIXME: queue for later drawing?
}
if (indicatorIsOn[selectedDisk] > 0 && indicatorIsOn[selectedDisk] < 100) {
// slowly spin it down...
if (--indicatorIsOn[selectedDisk] == 0) {
g_display->setDriveIndicator(selectedDisk, false);
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false); // FIXME: queue for later drawing?
}
}
@ -426,7 +427,7 @@ void DiskII::insertDisk(int8_t driveNum, const char *filename, bool drawIt)
ejectDisk(driveNum);
disk[driveNum] = g_filemanager->openFile(filename);
if (drawIt)
g_display->drawDriveDoor(driveNum, false);
g_ui->drawOnOffUIElement(UIeDisk1_state + driveNum, false);
if (_endsWithI(filename, ".nib")) {
diskType[driveNum] = nibDisk;
@ -446,7 +447,7 @@ void DiskII::ejectDisk(int8_t driveNum)
if (disk[driveNum] != -1) {
g_filemanager->closeFile(disk[driveNum]);
disk[driveNum] = -1;
g_display->drawDriveDoor(driveNum, true);
g_ui->drawOnOffUIElement(UIeDisk1_state + driveNum, true);
}
}
@ -457,7 +458,7 @@ void DiskII::select(int8_t which)
if (which != selectedDisk) {
indicatorIsOn[selectedDisk] = 0;
g_display->setDriveIndicator(selectedDisk, false);
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false); // FIXME: queue for later drawing?
checkFlush(curHalfTrack[selectedDisk]>>1);

View File

@ -8,5 +8,6 @@ PhysicalKeyboard *g_keyboard = NULL;
PhysicalSpeaker *g_speaker = NULL;
PhysicalPaddles *g_paddles = NULL;
PhysicalPrinter *g_printer = NULL;
VMui *g_ui;
int16_t g_volume = 15;
uint8_t g_displayType = 3; // FIXME m_perfectcolor

View File

@ -8,6 +8,7 @@
#include "physicalspeaker.h"
#include "physicalpaddles.h"
#include "physicalprinter.h"
#include "vmui.h"
extern FileManager *g_filemanager;
extern Cpu *g_cpu;
@ -17,5 +18,6 @@ extern PhysicalKeyboard *g_keyboard;
extern PhysicalSpeaker *g_speaker;
extern PhysicalPaddles *g_paddles;
extern PhysicalPrinter *g_printer;
extern VMui *g_ui;
extern int16_t g_volume;
extern uint8_t g_displayType;

29523
images.cpp Normal file

File diff suppressed because it is too large Load Diff

29529
images.h

File diff suppressed because it is too large Load Diff

View File

@ -13,14 +13,15 @@ class PhysicalDisplay {
virtual void redraw() = 0; // total redraw, assuming nothing
virtual void blit(AiieRect r) = 0; // redraw just the VM display area
virtual void drawDriveDoor(uint8_t which, bool isOpen) = 0;
virtual void setDriveIndicator(uint8_t which, bool isRunning) = 0;
virtual void drawBatteryStatus(uint8_t percent) = 0;
virtual void drawImageOfSizeAt(const uint8_t *img, uint16_t sizex, uint8_t sizey, uint16_t wherex, uint8_t wherey) = 0;
virtual void drawCharacter(uint8_t mode, uint16_t x, uint8_t y, char c) = 0;
virtual void drawString(uint8_t mode, uint16_t x, uint8_t y, const char *str) = 0;
virtual void debugMsg(const char *msg) { strncpy(overlayMessage, msg, sizeof(overlayMessage)); }
virtual void drawPixel(uint16_t x, uint16_t y, uint16_t color) = 0;
virtual void drawPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b) = 0;
protected:
char overlayMessage[40];
};

View File

@ -11,6 +11,7 @@
#include "sdl-paddles.h"
#include "sdl-filemanager.h"
#include "sdl-printer.h"
#include "appleui.h"
#include "globals.h"
@ -286,6 +287,8 @@ int main(int argc, char *argv[])
g_display = new SDLDisplay();
// g_displayType = m_blackAndWhite;
g_ui = new AppleUI();
// paddles have to be created after g_display created the window
g_paddles = new SDLPaddles();
@ -356,7 +359,7 @@ int main(int argc, char *argv[])
g_printer->update();
g_keyboard->maintainKeyboard();
g_display->drawBatteryStatus(100);
g_ui->drawPercentageUIElement(UIePowerPercentage, 100);
// calculate FPS & dynamically step up/down as necessary
static time_t startAt = time(NULL);

View File

@ -7,6 +7,8 @@
#include "globals.h"
#include "applevm.h"
#include "apple/appleui.h"
// RGB map of each of the lowres colors
const uint8_t loresPixelColors[16][3] = { { 0, 0, 0 }, // black
{ 195, 0, 48 }, // magenta
@ -53,85 +55,28 @@ void SDLDisplay::redraw()
// primarily for the device, where it's in and out of the
// bios. Draws the background image.
printf("redraw background\n");
g_ui->drawStaticUIElement(UIeOverlay);
for (int y=0; y<DISPLAYHEIGHT; y++) {
for (int x=0; x<DISPLAYWIDTH; x++) {
uint8_t *p = &displayBitmap[(y * DBITMAP_WIDTH + x)*3];
drawPixel(x, y, p[0], p[1], p[2]);
}
}
if (g_vm) {
drawDriveDoor(0, ((AppleVM *)g_vm)->DiskName(0)[0] == '\0');
drawDriveDoor(1, ((AppleVM *)g_vm)->DiskName(1)[0] == '\0');
if (g_vm && g_ui) {
// determine whether or not a disk is inserted & redraw each drive
g_ui->drawOnOffUIElement(UIeDisk1_state, ((AppleVM *)g_vm)->DiskName(0)[0] == '\0');
g_ui->drawOnOffUIElement(UIeDisk2_state, ((AppleVM *)g_vm)->DiskName(1)[0] == '\0');
}
}
void SDLDisplay::setDriveIndicator(uint8_t which, bool isRunning)
void SDLDisplay::drawImageOfSizeAt(const uint8_t *img,
uint16_t sizex, uint8_t sizey,
uint16_t wherex, uint8_t wherey)
{
driveIndicator[which] = isRunning;
driveIndicatorDirty = true;
}
void SDLDisplay::drawDriveDoor(uint8_t which, bool isOpen)
{
// location of drive door for left drive
uint16_t xoff = 55;
uint16_t yoff = 216;
// location for right drive
if (which == 1) {
xoff += 134;
}
for (int y=0; y<20; y++) {
for (int x=0; x<43; x++) {
uint8_t *p = &driveLatch[(y * 43 + x)*3];
if (isOpen) {
p = &driveLatchOpen[(y * 43 + x)*3];
}
drawPixel(x+xoff, y+yoff, p[0], p[1], p[2]);
for (uint8_t y=0; y<sizey; y++) {
for (uint16_t x=0; x<sizex; x++) {
const uint8_t *p = &img[(y * sizex + x)*3];
p = &img[(y * sizex + x)*3];
drawPixel(x+wherex, y+wherey, p[0], p[1], p[2]);
}
}
}
void SDLDisplay::drawBatteryStatus(uint8_t percent)
{
uint16_t xoff = 300;
uint16_t yoff = 222;
// the area around the apple is 12 wide
// it's exactly 11 high
// the color is 210/202/159
float watermark = ((float)percent / 100.0) * 11;
for (int y=0; y<11; y++) {
uint8_t bgr = 210;
uint8_t bgg = 202;
uint8_t bgb = 159;
if (11-y > watermark) {
// black...
bgr = bgg = bgb = 0;
}
for (int x=0; x<11; x++) {
uint8_t *p = &appleBitmap[(y * 10 + (x-1))*4];
// It's RGBA; blend w/ background color
uint8_t r,g,b;
float alpha = (float)p[3] / 255.0;
r = (float)p[0] * alpha + (bgr * (1.0 - alpha));
g = (float)p[1] * alpha + (bgg * (1.0 - alpha));
b = (float)p[2] * alpha + (bgb * (1.0 - alpha));
drawPixel(x+xoff, y+yoff, r, g, b);
}
}
}
#define BASEX 36
#define BASEY 26
@ -162,20 +107,6 @@ void SDLDisplay::blit(AiieRect r)
drawString(M_SELECTDISABLED, 1, 240 - 16 - 12, overlayMessage);
}
if (driveIndicatorDirty) {
// location of status indicator for left drive
uint16_t xoff = 125;
uint16_t yoff = 213;
for (int which=0; which<2; which++,xoff+=135) { // +135 for right drive
for (int y=0; y<1; y++) {
for (int x=0; x<6; x++) {
drawPixel(x + xoff, y + yoff, driveIndicator[which] ? 0xF800 : 0x8AA9);
}
}
}
driveIndicatorDirty = false;
}
SDL_RenderPresent(renderer);
}
@ -185,7 +116,7 @@ inline void putpixel(SDL_Renderer *renderer, int x, int y, uint8_t r, uint8_t g,
SDL_RenderDrawPoint(renderer, x, y);
}
void SDLDisplay::drawPixel(uint16_t x, uint8_t y, uint16_t color)
void SDLDisplay::drawPixel(uint16_t x, uint16_t y, uint16_t color)
{
uint8_t
r = (color & 0xF800) >> 8,
@ -201,7 +132,7 @@ void SDLDisplay::drawPixel(uint16_t x, uint8_t y, uint16_t color)
}
}
void SDLDisplay::drawPixel(uint16_t x, uint8_t y, uint8_t r, uint8_t g, uint8_t b)
void SDLDisplay::drawPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b)
{
// Pixel-doubling
for (int yoff=0; yoff<2; yoff++) {

View File

@ -28,12 +28,11 @@ class SDLDisplay : public PhysicalDisplay {
virtual void blit(AiieRect r);
virtual void redraw();
virtual void drawDriveDoor(uint8_t which, bool isOpen);
virtual void setDriveIndicator(uint8_t which, bool isRunning);
virtual void drawBatteryStatus(uint8_t percent);
virtual void drawImageOfSizeAt(const uint8_t *img, uint16_t sizex, uint8_t sizey, uint16_t wherex, uint8_t wherey);
virtual void drawPixel(uint16_t x, uint16_t y, uint16_t color);
virtual void drawPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b);
void drawPixel(uint16_t x, uint8_t y, uint16_t color);
void drawPixel(uint16_t x, uint8_t y, uint8_t r, uint8_t g, uint8_t b);
virtual void drawCharacter(uint8_t mode, uint16_t x, uint8_t y, char c);
virtual void drawString(uint8_t mode, uint16_t x, uint8_t y, const char *str);
virtual void debugMsg(const char *msg);
@ -41,9 +40,6 @@ class SDLDisplay : public PhysicalDisplay {
private:
SDL_Window *screen;
SDL_Renderer *renderer;
bool driveIndicator[2];
bool driveIndicatorDirty;
};
#endif

1
teensy/appleui.cpp Symbolic link
View File

@ -0,0 +1 @@
../apple/appleui.cpp

1
teensy/appleui.h Symbolic link
View File

@ -0,0 +1 @@
../apple/appleui.h

1
teensy/images.cpp Symbolic link
View File

@ -0,0 +1 @@
../images.cpp

View File

@ -2,7 +2,7 @@
#include "teensy-display.h"
#include "bios-font.h"
#include "images.h"
#include "appleui.h"
#define RS 16
#define WR 17
@ -212,19 +212,11 @@ void TeensyDisplay::redraw()
moveTo(0, 0);
for (int y=0; y<TEENSY_DHEIGHT; y++) {
for (int x=0; x<TEENSY_DWIDTH; x++) {
uint8_t r = pgm_read_byte(&displayBitmap[(y * DBITMAP_WIDTH + x)*3 + 0]);
uint8_t g = pgm_read_byte(&displayBitmap[(y * DBITMAP_WIDTH + x)*3 + 1]);
uint8_t b = pgm_read_byte(&displayBitmap[(y * DBITMAP_WIDTH + x)*3 + 2]);
uint16_t color16 = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
setPixel(color16);
}
}
g_ui->drawStaticUIElement(UIeOverlay);
if (g_vm) {
drawDriveDoor(0, ((AppleVM *)g_vm)->DiskName(0)[0] == '\0');
drawDriveDoor(1, ((AppleVM *)g_vm)->DiskName(1)[0] == '\0');
g_ui->drawOnOffUIElement(UIeDisk1_state, ((AppleVM *)g_vm)->DiskName(0)[0] == '\0');
g_ui->drawOnOffUIElement(UIeDisk2_state, ((AppleVM *)g_vm)->DiskName(1)[0] == '\0');
}
cbi(P_CS, B_CS);
@ -411,8 +403,6 @@ void TeensyDisplay::blit(AiieRect r)
drawString(M_SELECTDISABLED, 1, 240 - 16 - 12, overlayMessage);
}
redrawDriveIndicators();
}
void TeensyDisplay::drawCharacter(uint8_t mode, uint16_t x, uint8_t y, char c)
@ -470,98 +460,25 @@ void TeensyDisplay::drawString(uint8_t mode, uint16_t x, uint8_t y, const char *
}
}
void TeensyDisplay::drawDriveDoor(uint8_t which, bool isOpen)
void TeensyDisplay::drawImageOfSizeAt(const uint8_t *img,
uint16_t sizex, uint8_t sizey,
uint16_t wherex, uint8_t wherey)
{
// location of drive door for left drive
uint8_t r, g, b;
uint16_t xoff = 55;
uint16_t yoff = 216;
// location for right drive
if (which == 1) {
xoff += 134;
if (sizex == DISPLAYWIDTH) {
moveTo(0,0);
}
for (int y=0; y<20; y++) {
for (int x=0; x<43; x++) {
uint8_t r, g, b;
if (isOpen) {
r = pgm_read_byte(&driveLatchOpen[(y * 43 + x)*3 + 0]);
g = pgm_read_byte(&driveLatchOpen[(y * 43 + x)*3 + 1]);
b = pgm_read_byte(&driveLatchOpen[(y * 43 + x)*3 + 2]);
} else {
r = pgm_read_byte(&driveLatch[(y * 43 + x)*3 + 0]);
g = pgm_read_byte(&driveLatch[(y * 43 + x)*3 + 1]);
b = pgm_read_byte(&driveLatch[(y * 43 + x)*3 + 2]);
}
drawPixel(x+xoff, y+yoff, r, g, b);
for (uint8_t y=0; y<sizey; y++) {
if (sizex != DISPLAYWIDTH) {
moveTo(wherex, wherey + y);
}
for (uint16_t x=0; x<sizex; x++) {
r = pgm_read_byte(&img[(y*sizex + x)*3 + 0]);
g = pgm_read_byte(&img[(y*sizex + x)*3 + 1]);
b = pgm_read_byte(&img[(y*sizex + x)*3 + 2]);
setPixel((((r&248)|g>>5) << 8) | ((g&28)<<3|b>>3));
}
}
}
void TeensyDisplay::setDriveIndicator(uint8_t which, bool isRunning)
{
driveIndicator[which] = isRunning;
driveIndicatorDirty = true;
}
void TeensyDisplay::redrawDriveIndicators()
{
if (driveIndicatorDirty) {
// location of status indicator for left drive
uint16_t xoff = 125;
uint16_t yoff = 213;
for (int which = 0; which <= 1; which++,xoff += 135) {
for (int y=0; y<2; y++) {
for (int x=0; x<6; x++) {
drawPixel(x + xoff, y + yoff, driveIndicator[which] ? 0xF800 : 0x8AA9);
}
}
}
driveIndicatorDirty = false;
}
}
void TeensyDisplay::drawBatteryStatus(uint8_t percent)
{
uint16_t xoff = 300;
uint16_t yoff = 222;
// the area around the apple is 12 wide
// it's exactly 11 high
// the color is 210/202/159
float watermark = ((float)percent / 100.0) * 11;
for (int y=0; y<11; y++) {
uint8_t bgr = 210;
uint8_t bgg = 202;
uint8_t bgb = 159;
if (11-y > watermark) {
// black...
bgr = bgg = bgb = 0;
}
for (int x=0; x<11; x++) {
uint8_t *p = &appleBitmap[(y * 10 + (x-1))*4];
// It's RGBA; blend w/ background color
uint8_t r,g,b;
float alpha = (float)pgm_read_byte(&appleBitmap[(y * 10 + (x-1))*4 + 3]) / 255.0;
r = (float)pgm_read_byte(&appleBitmap[(y * 10 + (x-1))*4 + 0])
* alpha + (bgr * (1.0 - alpha));
g = (float)pgm_read_byte(&appleBitmap[(y * 10 + (x-1))*4 + 1])
* alpha + (bgr * (1.0 - alpha));
b = (float)pgm_read_byte(&appleBitmap[(y * 10 + (x-1))*4 + 2])
* alpha + (bgr * (1.0 - alpha));
drawPixel(x+xoff, y+yoff, r, g, b);
}
}
}

View File

@ -45,14 +45,11 @@ class TeensyDisplay : public PhysicalDisplay {
virtual void drawCharacter(uint8_t mode, uint16_t x, uint8_t y, char c);
virtual void drawString(uint8_t mode, uint16_t x, uint8_t y, const char *str);
virtual void drawDriveDoor(uint8_t which, bool isOpen);
virtual void setDriveIndicator(uint8_t which, bool isRunning);
virtual void drawBatteryStatus(uint8_t percent);
virtual void drawImageOfSizeAt(const uint8_t *img, uint16_t sizex, uint8_t sizey, uint16_t wherex, uint8_t wherey);
protected:
void moveTo(uint16_t col, uint16_t row);
void drawNextPixel(uint16_t color);
void redrawDriveIndicators();
private:
regtype *P_RS, *P_WR, *P_CS, *P_RST, *P_SDA, *P_SCL, *P_ALE;
@ -68,9 +65,9 @@ class TeensyDisplay : public PhysicalDisplay {
void setColor(byte r, byte g, byte b);
void setColor(uint16_t color);
void fillRect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
void drawPixel(uint16_t x, uint16_t y);
void drawPixel(uint16_t x, uint16_t y, uint16_t color);
void drawPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b);
virtual void drawPixel(uint16_t x, uint16_t y);
virtual void drawPixel(uint16_t x, uint16_t y, uint16_t color);
virtual void drawPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b);
inline void LCD_Writ_Bus(uint8_t VH,uint8_t VL) __attribute__((always_inline));
inline void LCD_Write_COM(uint8_t VL) __attribute__((always_inline));

View File

@ -11,6 +11,7 @@
#include "teensy-speaker.h"
#include "teensy-paddles.h"
#include "teensy-filemanager.h"
#include "appleui.h"
#define RESETPIN 39
#define BATTERYPIN A19
@ -94,6 +95,9 @@ void setup()
Serial.println(" display");
g_display = new TeensyDisplay();
Serial.println(" UI");
g_ui = new AppleUI();
// Next create the virtual CPU. This needs the VM's MMU in order to
// run, but we don't have that yet.
Serial.println(" cpu");
@ -128,8 +132,6 @@ void setup()
Serial.println("Reading prefs");
readPrefs(); // read from eeprom and set anything we need setting
Serial.println("free-running");
startMicros = nextInstructionMicros = micros();
// Debugging: insert a disk on startup...
@ -143,6 +145,8 @@ void setup()
Serial.print("Free RAM: ");
Serial.println(FreeRamEstimate());
Serial.println("free-running");
Timer1.initialize(3);
Timer1.attachInterrupt(runCPU);
Timer1.start();
@ -323,7 +327,7 @@ void loop()
batteryLevel = 168;
batteryLevel = map(batteryLevel, 146, 168, 0, 100);
g_display->drawBatteryStatus(batteryLevel);
g_ui->drawPercentageUIElement(UIePowerPercentage, batteryLevel);
}
}

1
teensy/vmui.h Symbolic link
View File

@ -0,0 +1 @@
../vmui.h

37
vmui.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef __VMUI_H
#define __VMUI_H
//#ifndef TEENSYDUINO
#include <stdint.h>
//#endif
/* Abstraction of VM-specific UI element drawing.
*
* UI elements are things like
* - disk drive 1/inserted, disk drive 1/ejected;
* - power icon percentage;
* - disk drive 1/activity indicator, on/off;
* - parallel port activity;
* - network activity;
* etc. (No, not all of those things exist yet.)
*
* This encapsulates the VM positioning and icon data. The actual
* drawing routines are in the physical implementation (TeensyDisplay
* or SDLDisplay).
*
* Most of those are on/off indicators. Some are percentage indicators.
* The element IDs are in the VM's UI class (cf. AppleUI).
*/
class VMui
{
public:
VMui() {};
~VMui() {};
virtual void drawStaticUIElement(uint8_t element) = 0;
virtual void drawOnOffUIElement(uint8_t element, bool state) = 0; // on or off
virtual void drawPercentageUIElement(uint8_t element, uint8_t percent) = 0; // 0-100
};
#endif