mirror of
https://github.com/JorjBauer/aiie.git
synced 2024-12-12 10:30:26 +00:00
add luminance cutoff for B&W mode
This commit is contained in:
parent
efc36d40a8
commit
97059a0a5b
60
bios.cpp
60
bios.cpp
@ -60,20 +60,22 @@ enum {
|
||||
ACT_REBOOTANDEJECT = 4,
|
||||
ACT_MONITOR = 5,
|
||||
ACT_DISPLAYTYPE = 6,
|
||||
ACT_DEBUG = 7,
|
||||
ACT_DISK1 = 8,
|
||||
ACT_DISK2 = 9,
|
||||
ACT_HD1 = 10,
|
||||
ACT_HD2 = 11,
|
||||
ACT_VOLPLUS = 12,
|
||||
ACT_VOLMINUS = 13,
|
||||
ACT_SUSPEND = 14,
|
||||
ACT_RESTORE = 15,
|
||||
ACT_PADX_INV = 16,
|
||||
ACT_PADY_INV = 17,
|
||||
ACT_PADDLES = 18,
|
||||
ACT_SPEED = 19,
|
||||
ACT_ABOUT = 20,
|
||||
ACT_LUMINANCEUP = 7,
|
||||
ACT_LUMINANCEDOWN = 8,
|
||||
ACT_DEBUG = 9,
|
||||
ACT_DISK1 = 10,
|
||||
ACT_DISK2 = 11,
|
||||
ACT_HD1 = 12,
|
||||
ACT_HD2 = 13,
|
||||
ACT_VOLPLUS = 14,
|
||||
ACT_VOLMINUS = 15,
|
||||
ACT_SUSPEND = 16,
|
||||
ACT_RESTORE = 17,
|
||||
ACT_PADX_INV = 18,
|
||||
ACT_PADY_INV = 19,
|
||||
ACT_PADDLES = 20,
|
||||
ACT_SPEED = 21,
|
||||
ACT_ABOUT = 22,
|
||||
};
|
||||
|
||||
#define NUM_TITLES 4
|
||||
@ -85,7 +87,8 @@ const uint8_t aiieActions[] = { ACT_ABOUT };
|
||||
const uint8_t vmActions[] = { ACT_EXIT, ACT_RESET, ACT_REBOOT, ACT_REBOOTANDEJECT,
|
||||
ACT_MONITOR,
|
||||
ACT_DEBUG, ACT_SUSPEND, ACT_RESTORE };
|
||||
const uint8_t hardwareActions[] = { ACT_DISPLAYTYPE, ACT_SPEED,
|
||||
const uint8_t hardwareActions[] = { ACT_DISPLAYTYPE, ACT_LUMINANCEUP,
|
||||
ACT_LUMINANCEDOWN, ACT_SPEED,
|
||||
ACT_PADX_INV, ACT_PADY_INV,
|
||||
ACT_PADDLES, ACT_VOLPLUS, ACT_VOLMINUS };
|
||||
const uint8_t diskActions[] = { ACT_DISK1, ACT_DISK2,
|
||||
@ -386,6 +389,20 @@ uint16_t BIOS::HardwareMenuHandler(bool needsRedraw, bool performAction)
|
||||
((AppleDisplay*)g_display)->displayTypeChanged();
|
||||
localRedraw = true;
|
||||
break;
|
||||
|
||||
case ACT_LUMINANCEUP:
|
||||
if (g_luminanceCutoff < 255)
|
||||
g_luminanceCutoff++;
|
||||
((AppleDisplay*)g_display)->displayTypeChanged();
|
||||
localRedraw = true;
|
||||
break;
|
||||
|
||||
case ACT_LUMINANCEDOWN:
|
||||
if (g_luminanceCutoff > 0)
|
||||
g_luminanceCutoff--;
|
||||
((AppleDisplay*)g_display)->displayTypeChanged();
|
||||
localRedraw = true;
|
||||
break;
|
||||
|
||||
case ACT_SPEED:
|
||||
currentCPUSpeedIndex++;
|
||||
@ -797,6 +814,11 @@ bool BIOS::isActionActive(int8_t action)
|
||||
case ACT_PADDLES:
|
||||
return true;
|
||||
|
||||
case ACT_LUMINANCEUP:
|
||||
return (g_luminanceCutoff < 255);
|
||||
case ACT_LUMINANCEDOWN:
|
||||
return (g_luminanceCutoff > 0);
|
||||
|
||||
case ACT_VOLPLUS:
|
||||
return (g_volume < 15);
|
||||
case ACT_VOLMINUS:
|
||||
@ -934,6 +956,14 @@ void BIOS::DrawHardwareMenu()
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ACT_LUMINANCEUP:
|
||||
sprintf(buf, "Luminance+: %d", g_luminanceCutoff);
|
||||
break;
|
||||
case ACT_LUMINANCEDOWN:
|
||||
sprintf(buf, "Luminance-: %d", g_luminanceCutoff);
|
||||
break;
|
||||
|
||||
case ACT_SPEED:
|
||||
{
|
||||
const char *templateString = "CPU Speed: %s";
|
||||
|
@ -10,7 +10,7 @@ PhysicalSpeaker *g_speaker = NULL;
|
||||
PhysicalPaddles *g_paddles = NULL;
|
||||
PhysicalPrinter *g_printer = NULL;
|
||||
VMui *g_ui;
|
||||
int8_t g_volume = 15;
|
||||
int8_t g_volume = 7;
|
||||
uint8_t g_displayType = 3; // FIXME m_perfectcolor
|
||||
VMRam g_ram;
|
||||
volatile uint8_t g_debugMode = D_NONE;
|
||||
@ -19,6 +19,8 @@ uint32_t g_speed = 1023000; // Hz
|
||||
bool g_invertPaddleX = false;
|
||||
bool g_invertPaddleY = false;
|
||||
|
||||
uint8_t g_luminanceCutoff = 122; // reasonable values are 127 and 128 for 32-bit (SDL); and 122/123 for 16-bit (teensy) depending on whether we're talking about white-on-black or black-on-white
|
||||
|
||||
char debugBuf[255];
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
|
@ -56,6 +56,8 @@ extern uint32_t g_speed;
|
||||
extern bool g_invertPaddleX;
|
||||
extern bool g_invertPaddleY;
|
||||
|
||||
extern uint8_t g_luminanceCutoff;
|
||||
|
||||
extern char debugBuf[255];
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
|
@ -6,7 +6,7 @@
|
||||
// Fun trivia: the Apple //e was in production from January 1983 to
|
||||
// November 1993. And the 65C02 in them supported weird BCD math modes.
|
||||
#define PREFSMAGIC 0x01831093
|
||||
#define PREFSVERSION 3
|
||||
#define PREFSVERSION 4
|
||||
|
||||
#ifndef MAXPATH
|
||||
#define MAXPATH 255
|
||||
@ -21,6 +21,8 @@ typedef struct _prefs {
|
||||
|
||||
uint8_t volume;
|
||||
uint8_t displayType;
|
||||
uint8_t luminanceCutoff;
|
||||
|
||||
uint8_t debug;
|
||||
uint8_t speed;
|
||||
|
||||
@ -33,6 +35,8 @@ typedef struct _prefs {
|
||||
char disk2[MAXPATH];
|
||||
char hd1[MAXPATH];
|
||||
char hd2[MAXPATH];
|
||||
|
||||
uint32_t magicFooter;
|
||||
} prefs_t;
|
||||
|
||||
class PrefsStore {
|
||||
|
@ -451,6 +451,8 @@ void readPrefs()
|
||||
if (np.readPrefs(&p)) {
|
||||
g_volume = p.volume;
|
||||
g_displayType = p.displayType;
|
||||
g_luminanceCutoff = p.luminanceCutoff;
|
||||
|
||||
g_debugMode = p.debug;
|
||||
g_speed = (p.speed * (1023000/2)); // steps of half normal speed
|
||||
if (g_speed < (1023000/2))
|
||||
@ -484,7 +486,10 @@ void writePrefs()
|
||||
p.version = PREFSVERSION;
|
||||
|
||||
p.volume = g_volume;
|
||||
|
||||
p.displayType = g_displayType;
|
||||
p.luminanceCutoff = g_luminanceCutoff;
|
||||
|
||||
p.debug = g_debugMode;
|
||||
p.speed = g_speed / (1023000/2);
|
||||
strcpy(p.disk1, ((AppleVM *)g_vm)->DiskName(0));
|
||||
|
@ -39,10 +39,14 @@ const uint8_t loresPixelColors[16][3] = { { 0, 0, 0 }, // black
|
||||
|
||||
#define color16To32(x) ( (((x) & 0xF800) << 8) | (((x) & 0x07E0) << 5) | (((x) & 0x001F)<<3) )
|
||||
#define packColor32(x) ( (x[0] << 16) | (x[1] << 8) | (x[2]) )
|
||||
#define unpackRed(x) ( ((x) & 0xFF0000) >> 16 )
|
||||
#define unpackGreen(x) ( ((x) & 0xFF00) >> 8 )
|
||||
#define unpackBlue(x) ( ((x) & 0xFF) )
|
||||
// FIXME this blend could be optimized - and it's a dumb blend that
|
||||
// just averages RGB values individually, rather than trying to find a
|
||||
// sane blend of 2 pixels. Needs thought.
|
||||
#define blendPackedColor(x,y) ( (((x) & 0xFF0000) + ((y) & 0xFF0000) / 2) + (((x) & 0x00FF00) + ((y) & 0x00FF00)) / 2 + (((x) & 0x0000FF) + ((y) & 0x0000FF)) / 2 )
|
||||
#define blendPackedColor(x,y) ( (((unpackRed(x) + unpackRed(y))/2) << 16) + (((unpackGreen(x) + unpackGreen(y))/2) << 8) + ((unpackBlue(x) + unpackBlue(y))/2) )
|
||||
#define luminanceFromRGB(r,g,b) ( ((r)*0.2126) + ((g)*0.7152) + ((b)*0.0722) )
|
||||
|
||||
SDLDisplay::SDLDisplay()
|
||||
{
|
||||
@ -128,9 +132,9 @@ void SDLDisplay::blit(AiieRect r)
|
||||
b = (colorIdx & 0x0000FF);
|
||||
|
||||
if (g_displayType == m_monochrome) {
|
||||
float fv = 0.2125 * r + 0.7154 * g + 0.0721 * b;
|
||||
r = b = 0;
|
||||
g = fv;
|
||||
// float fv = 0.2125 * r + 0.7154 * g + 0.0721 * b;
|
||||
// r = b = 0;
|
||||
// g = fv;
|
||||
}
|
||||
else if (g_displayType == m_blackAndWhite) {
|
||||
// Used to reduce to B&W in this driver, but now it's up in the apple display
|
||||
@ -263,23 +267,32 @@ void SDLDisplay::clrScr(uint8_t coloridx)
|
||||
SDL_RenderPresent(renderer); // perform the render
|
||||
}
|
||||
|
||||
// This was called with the expectation that it can draw every one of
|
||||
// the 560x192 pixels that could be addressed. If TEENSYDISPLAY_SCALE
|
||||
// is 1, then we have half of that horizontal resolution - so we need
|
||||
// to be creative and blend neighboring pixels together.
|
||||
// This was called with the expectation that it can draw every one of
|
||||
// the 560x192 pixels that could be addressed. If TEENSYDISPLAY_SCALE
|
||||
// is 1, then we have half of that horizontal resolution - so we need
|
||||
// to be creative and blend neighboring pixels together.
|
||||
void SDLDisplay::cachePixel(uint16_t x, uint16_t y, uint8_t color)
|
||||
{
|
||||
#if SDLDISPLAY_SCALE == 1
|
||||
// This is the case where we need to blend together neighboring
|
||||
// pixels, because we don't have enough physical screen resoultion.
|
||||
// This is the case where we need to blend together neighboring
|
||||
// pixels, because we don't have enough physical screen resoultion.
|
||||
|
||||
if (x&1) {
|
||||
uint32_t origColor = videoBuffer[y][(x>>1)*SDLDISPLAY_SCALE];
|
||||
uint32_t newColor = packColor32(loresPixelColors[color]);
|
||||
if (g_displayType == m_blackAndWhite) {
|
||||
// FIXME: the two possible sets here of 'origColor && newColor' or 'origColor||newColor'
|
||||
// work well for black-on-white and white-on-black. But neither is good in the other.
|
||||
cacheDoubleWidePixel(x>>1,y,(uint32_t)((origColor && newColor) ? 0xFFFFFF : 0x000000));
|
||||
// There are four reasonable decisions here: if either pixel
|
||||
// *was* on, then it's on; if both pixels *were* on, then it's
|
||||
// on; and if the blended value of the two pixels were on, then
|
||||
// it's on; or if the blended value of the two is above some
|
||||
// certain overall brightness, then it's on. This is the last of
|
||||
// those - where the brightness cutoff is defined in the bios as
|
||||
// g_luminanceCutoff.
|
||||
uint32_t blendedColor = blendPackedColor(origColor, newColor);
|
||||
uint32_t luminance = luminanceFromRGB(unpackRed(blendedColor),
|
||||
unpackGreen(blendedColor),
|
||||
unpackBlue(blendedColor));
|
||||
cacheDoubleWidePixel(x>>1,y,(uint32_t)((luminance >= g_luminanceCutoff) ? 0xFFFFFF : 0x000000));
|
||||
} else {
|
||||
cacheDoubleWidePixel(x>>1,y,(uint32_t)blendPackedColor(origColor, newColor));
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <DMAChannel.h>
|
||||
|
||||
#include "teensy-display.h"
|
||||
#include "iocompat.h"
|
||||
|
||||
#include "appleui.h"
|
||||
// FIXME should be able to omit this include and rely on the xterns, which
|
||||
@ -54,8 +55,10 @@ DMAMEM uint16_t dmaBuffer[TEENSYDISPLAY_HEIGHT][TEENSYDISPLAY_WIDTH];
|
||||
|
||||
#define RGBto565(r,g,b) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | ((b) >> 3))
|
||||
#define _565toR(c) ( ((c) & 0xF800) >> 8 )
|
||||
#define _565toG(c) ( ((c) & 0x07E0) >> 5 )
|
||||
#define _565toB(c) ( ((c) & 0x001F) )
|
||||
#define _565toG(c) ( ((c) & 0x07E0) >> 3 )
|
||||
#define _565toB(c) ( ((c) & 0x001F) << 3 )
|
||||
#define luminanceFromRGB(r,g,b) ( ((r)*0.2126) + ((g)*0.7152) + ((b)*0.0722) )
|
||||
|
||||
|
||||
ILI9341_t3n tft = ILI9341_t3n(PIN_CS, PIN_DC, PIN_RST, PIN_MOSI, PIN_SCK, PIN_MISO);
|
||||
|
||||
@ -125,7 +128,7 @@ void TeensyDisplay::blit()
|
||||
if (overlayMessage[0]) {
|
||||
drawString(M_SELECTDISABLED, 1, TEENSYDISPLAY_HEIGHT - (16 + 12)*TEENSYDISPLAY_SCALE, overlayMessage);
|
||||
}
|
||||
nextMessageTime = millis() + 1000;
|
||||
nextMessageTime = millis() + 10; // DEBUGGING FIXME make 1000 again
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -262,17 +265,25 @@ void TeensyDisplay::cachePixel(uint16_t x, uint16_t y, uint8_t color)
|
||||
// This is the case where we need to blend together neighboring
|
||||
// pixels, because we don't have enough physical screen resoultion.
|
||||
if (x&1) {
|
||||
uint8_t origColor = dmaBuffer[y+SCREENINSET_Y][(x>>1)*TEENSYDISPLAY_SCALE+SCREENINSET_X];
|
||||
cacheDoubleWidePixel(x>>1, y, color);
|
||||
#if 0
|
||||
uint8_t newColor = (uint16_t) (origColor + color) / 2;
|
||||
uint16_t origColor = dmaBuffer[y+SCREENINSET_Y][(x>>1)*TEENSYDISPLAY_SCALE+SCREENINSET_X];
|
||||
uint16_t newColor = (uint16_t) loresPixelColors[color];
|
||||
if (g_displayType == m_blackAndWhite) {
|
||||
cacheDoubleWidePixel(x>>1, y, (origColor && newColor) ? 0xFFFF : 0x0000);
|
||||
// There are four reasonable decisions here: if either pixel
|
||||
// *was* on, then it's on; if both pixels *were* on, then it's
|
||||
// on; and if the blended value of the two pixels were on, then
|
||||
// it's on; or if the blended value of the two is above some
|
||||
// certain overall brightness, then it's on. This is the last of
|
||||
// those - where the brightness cutoff is defined in the bios as
|
||||
// g_luminanceCutoff.
|
||||
uint16_t blendedColor = blendColors(origColor, newColor);
|
||||
uint16_t luminance = luminanceFromRGB(_565toR(blendedColor),
|
||||
_565toG(blendedColor),
|
||||
_565toB(blendedColor));
|
||||
cacheDoubleWidePixel(x>>1,y,(uint16_t)((luminance >= g_luminanceCutoff) ? 0xFFFF : 0x0000));
|
||||
} else {
|
||||
cacheDoubleWidePixel(x>>1,y,blendColors(origColor, newColor));
|
||||
cacheDoubleWidePixel(x>>1,y,color);
|
||||
// Else if it's black, we leave whatever was in the other pixel.
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// The even pixels always draw.
|
||||
cacheDoubleWidePixel(x>>1,y,color);
|
||||
@ -289,6 +300,14 @@ void TeensyDisplay::cachePixel(uint16_t x, uint16_t y, uint8_t color)
|
||||
}
|
||||
|
||||
|
||||
void TeensyDisplay::cacheDoubleWidePixel(uint16_t x, uint16_t y, uint16_t color16)
|
||||
{
|
||||
for (int yoff=0; yoff<TEENSYDISPLAY_SCALE; yoff++) {
|
||||
for (int xoff=0; xoff<TEENSYDISPLAY_SCALE; xoff++) {
|
||||
dmaBuffer[(y*TEENSYDISPLAY_SCALE+yoff+SCREENINSET_Y)][x*TEENSYDISPLAY_SCALE+xoff+SCREENINSET_X] = color16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "DoubleWide" means "please double the X because I'm in low-res
|
||||
// width mode".
|
||||
|
@ -31,6 +31,7 @@ class TeensyDisplay : public PhysicalDisplay {
|
||||
|
||||
virtual void drawImageOfSizeAt(const uint8_t *img, uint16_t sizex, uint8_t sizey, uint16_t wherex, uint8_t wherey);
|
||||
|
||||
void cacheDoubleWidePixel(uint16_t x, uint16_t y, uint16_t color16);
|
||||
virtual void cacheDoubleWidePixel(uint16_t x, uint16_t y, uint8_t color);
|
||||
virtual void cache2DoubleWidePixels(uint16_t x, uint16_t y, uint8_t colorA, uint8_t colorB);
|
||||
virtual void cachePixel(uint16_t x, uint16_t y, uint8_t color);
|
||||
|
@ -18,7 +18,8 @@ bool TeensyPrefs::readPrefs(prefs_t *readTo)
|
||||
*pp++ = EEPROM.read(i);
|
||||
}
|
||||
|
||||
if (readTo->magic != PREFSMAGIC) {
|
||||
if (readTo->magic != PREFSMAGIC ||
|
||||
readTo->magicFooter != PREFSMAGIC) {
|
||||
return false;
|
||||
}
|
||||
if (readTo->prefsSize != sizeof(prefs_t)) {
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include "teensy-println.h"
|
||||
#include "smalloc.h"
|
||||
|
||||
#include "iocompat.h"
|
||||
|
||||
//#define DEBUG_TIMING
|
||||
|
||||
#if F_CPU < 240000000
|
||||
@ -127,7 +129,12 @@ static uint8_t usb_scanmap[256] = {
|
||||
|
||||
void onKeypress(uint8_t keycode)
|
||||
{
|
||||
((AppleVM *)g_vm)->getKeyboard()->keyDepressed(usb_scanmap[keycode]);
|
||||
if (keycode == 67) {
|
||||
// F10 is our interrupt button; FIXME this probably needs to be adjustable
|
||||
g_biosInterrupt = true;
|
||||
} else {
|
||||
((AppleVM *)g_vm)->getKeyboard()->keyDepressed(usb_scanmap[keycode]);
|
||||
}
|
||||
}
|
||||
|
||||
void onKeyrelease(uint8_t keycode)
|
||||
@ -510,7 +517,7 @@ void loop()
|
||||
wasBios = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!g_biosInterrupt) {
|
||||
runCPU(now);
|
||||
}
|
||||
@ -588,11 +595,22 @@ void readPrefs()
|
||||
if (p.hd2[0]) {
|
||||
((AppleVM *)g_vm)->insertHD(1, p.hd2);
|
||||
}
|
||||
|
||||
g_luminanceCutoff = p.luminanceCutoff;
|
||||
|
||||
g_invertPaddleX = p.invertPaddleX;
|
||||
g_invertPaddleY = p.invertPaddleY;
|
||||
|
||||
} else {
|
||||
// Set some defaults!
|
||||
g_volume = 7;
|
||||
g_displayType = 3; // FIXME constant
|
||||
g_debugMode = D_NONE;
|
||||
g_speed = 1023000;
|
||||
g_luminanceCutoff = 127;
|
||||
g_invertPaddleX = g_invertPaddleY = false;
|
||||
|
||||
}
|
||||
|
||||
g_invertPaddleX = p.invertPaddleX;
|
||||
g_invertPaddleY = p.invertPaddleY;
|
||||
|
||||
// Update the paddles with the new inversion state
|
||||
((TeensyPaddles *)g_paddles)->setRev(g_invertPaddleX, g_invertPaddleY);
|
||||
}
|
||||
@ -603,6 +621,7 @@ void writePrefs()
|
||||
prefs_t p;
|
||||
|
||||
p.magic = PREFSMAGIC;
|
||||
p.magicFooter = PREFSMAGIC;
|
||||
p.prefsSize = sizeof(prefs_t);
|
||||
p.version = PREFSVERSION;
|
||||
|
||||
@ -611,6 +630,7 @@ void writePrefs()
|
||||
|
||||
p.volume = g_volume;
|
||||
p.displayType = g_displayType;
|
||||
p.luminanceCutoff = g_luminanceCutoff;
|
||||
p.debug = g_debugMode;
|
||||
p.speed = g_speed / (1023000/2);
|
||||
strcpy(p.disk1, ((AppleVM *)g_vm)->DiskName(0));
|
||||
|
Loading…
Reference in New Issue
Block a user