483 lines
No EOL
10 KiB
C
483 lines
No EOL
10 KiB
C
/*
|
|
* display.c
|
|
*
|
|
* This file is part of Emu48
|
|
*
|
|
* Copyright (C) 1995 Sebastien Carlier
|
|
*
|
|
*/
|
|
#include "pch.h"
|
|
#include "resource.h"
|
|
#include "Emu48.h"
|
|
#include "kml.h"
|
|
|
|
#define LCD1_ROW 144
|
|
#define LCD2_ROW 288
|
|
|
|
UINT nBackgroundX = 0;
|
|
UINT nBackgroundY = 0;
|
|
UINT nBackgroundW = 0;
|
|
UINT nBackgroundH = 0;
|
|
UINT nLcdX = 0;
|
|
UINT nLcdY = 0;
|
|
BOOL bLcdDoubled = FALSE;
|
|
LPBYTE pbyLcd;
|
|
HDC hLcdDC;
|
|
HDC hMainDC;
|
|
static HBITMAP hLcdBitmap;
|
|
static HBITMAP hMainBitmap;
|
|
static HBITMAP hOldLcdBitmap;
|
|
static HBITMAP hOldMainBitmap;
|
|
|
|
#define B 0xFFFFFF
|
|
#define W 0x000000
|
|
static struct
|
|
{
|
|
BITMAPINFOHEADER Lcd_bmih;
|
|
DWORD dwColor[32];
|
|
} bmiLcd =
|
|
{
|
|
{0x28,0/*x*/,0/*y*/,1,8,BI_RGB,0,0,0,32,0},
|
|
{
|
|
B,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,
|
|
W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W
|
|
}
|
|
};
|
|
#undef B
|
|
#undef W
|
|
|
|
static DWORD Pattern4[16];
|
|
static DWORD Pattern2[4];
|
|
|
|
VOID UpdateContrast(BYTE byContrast)
|
|
{
|
|
if (bLcdDoubled)
|
|
{
|
|
BYTE c = byContrast;
|
|
Pattern2[0] = 0;
|
|
Pattern2[1] = (c<<8)|(c);
|
|
Pattern2[2] = (c<<24)|(c<<16);
|
|
Pattern2[3] = (c<<24)|(c<<16)|(c<<8)|(c);
|
|
}
|
|
else
|
|
{
|
|
DWORD c = (DWORD)byContrast;
|
|
FillMemory(Pattern4, 16*sizeof(DWORD), 0);
|
|
Pattern4[0x1] = c;
|
|
Pattern4[0x3] = c;
|
|
Pattern4[0x5] = c;
|
|
Pattern4[0x7] = c;
|
|
Pattern4[0x9] = c;
|
|
Pattern4[0xB] = c;
|
|
Pattern4[0xD] = c;
|
|
Pattern4[0xF] = c;
|
|
c<<=8;
|
|
Pattern4[0x2] |= c;
|
|
Pattern4[0x3] |= c;
|
|
Pattern4[0x6] |= c;
|
|
Pattern4[0x7] |= c;
|
|
Pattern4[0xA] |= c;
|
|
Pattern4[0xB] |= c;
|
|
Pattern4[0xE] |= c;
|
|
Pattern4[0xF] |= c;
|
|
c<<=8;
|
|
Pattern4[0x4] |= c;
|
|
Pattern4[0x5] |= c;
|
|
Pattern4[0x6] |= c;
|
|
Pattern4[0x7] |= c;
|
|
Pattern4[0xC] |= c;
|
|
Pattern4[0xD] |= c;
|
|
Pattern4[0xE] |= c;
|
|
Pattern4[0xF] |= c;
|
|
c<<=8;
|
|
Pattern4[0x8] |= c;
|
|
Pattern4[0x9] |= c;
|
|
Pattern4[0xA] |= c;
|
|
Pattern4[0xB] |= c;
|
|
Pattern4[0xC] |= c;
|
|
Pattern4[0xD] |= c;
|
|
Pattern4[0xE] |= c;
|
|
Pattern4[0xF] |= c;
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID SetLcdColor(UINT nId, UINT nRed, UINT nGreen, UINT nBlue)
|
|
{
|
|
bmiLcd.dwColor[nId&0x1F] = (nRed&0xFF)|((nGreen&0xFF)<<8)|((nBlue&0xFF)<<16);
|
|
return;
|
|
}
|
|
|
|
VOID CreateLcdBitmap()
|
|
{
|
|
// create LCD bitmap
|
|
if (bLcdDoubled)
|
|
{
|
|
bmiLcd.Lcd_bmih.biWidth = LCD2_ROW;
|
|
bmiLcd.Lcd_bmih.biHeight = -128;
|
|
}
|
|
else
|
|
{
|
|
bmiLcd.Lcd_bmih.biWidth = LCD1_ROW;
|
|
bmiLcd.Lcd_bmih.biHeight = -64;
|
|
}
|
|
hLcdDC = CreateCompatibleDC(hWindowDC);
|
|
hLcdBitmap = CreateDIBSection(hLcdDC, (BITMAPINFO*)&bmiLcd,
|
|
DIB_RGB_COLORS, (LPVOID*)&pbyLcd, NULL, 0);
|
|
hOldLcdBitmap = SelectObject(hLcdDC, hLcdBitmap);
|
|
UpdateContrast(0x10);
|
|
}
|
|
|
|
VOID DestroyLcdBitmap()
|
|
{
|
|
if (hLcdDC != NULL)
|
|
{
|
|
// destroy LCD bitmap
|
|
SelectObject(hLcdDC, hOldLcdBitmap);
|
|
DeleteObject(hLcdBitmap);
|
|
DeleteDC(hLcdDC);
|
|
hLcdDC = NULL;
|
|
hLcdBitmap = NULL;
|
|
hOldLcdBitmap = NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
BOOL CreateMainBitmap(LPSTR szFilename)
|
|
{
|
|
hMainDC = CreateCompatibleDC(hWindowDC);
|
|
hMainBitmap = LoadBitmapFile(szFilename);
|
|
if (hMainBitmap == NULL)
|
|
{
|
|
DeleteDC(hMainDC);
|
|
return FALSE;
|
|
}
|
|
hOldMainBitmap = SelectObject(hMainDC, hMainBitmap);
|
|
SelectPalette(hMainDC, hPalette, FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
VOID DestroyMainBitmap()
|
|
{
|
|
if (hMainDC != NULL)
|
|
{
|
|
// destroy Main bitmap
|
|
SelectObject(hMainDC, hOldMainBitmap);
|
|
DeleteObject(hMainBitmap);
|
|
DeleteDC(hMainDC);
|
|
hMainDC = NULL;
|
|
hMainBitmap = NULL;
|
|
hOldMainBitmap = NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
//****************
|
|
//*
|
|
//* LCD functions
|
|
//*
|
|
//****************
|
|
|
|
VOID UpdateDisplayPointers()
|
|
{
|
|
if (Chipset.boffset&4)
|
|
{
|
|
Chipset.width = Chipset.loffset + 36;
|
|
}
|
|
else
|
|
{
|
|
Chipset.width = Chipset.loffset + 34;
|
|
}
|
|
Chipset.end1 = Chipset.start1 + (Chipset.lcounter+1)*Chipset.width;
|
|
if (Chipset.end1 < Chipset.start1)
|
|
{
|
|
Chipset.start12 = Chipset.end1;
|
|
Chipset.end1 = Chipset.start1;
|
|
}
|
|
else
|
|
{
|
|
Chipset.start12 = Chipset.start1;
|
|
}
|
|
Chipset.end2 = Chipset.start2 + (63 - Chipset.lcounter)*34;
|
|
}
|
|
|
|
static BYTE Buf[36];
|
|
static BOOL bScreenIsClean = FALSE;
|
|
|
|
VOID UpdateMainDisplay()
|
|
{
|
|
UINT x, y;
|
|
DWORD d = Chipset.start1;
|
|
BYTE *p = pbyLcd;
|
|
|
|
if (!Chipset.dispon)
|
|
{
|
|
if (!bScreenIsClean)
|
|
{
|
|
bScreenIsClean = TRUE;
|
|
if (bLcdDoubled)
|
|
FillMemory(pbyLcd, LCD2_ROW*64, 0);
|
|
else
|
|
FillMemory(pbyLcd, LCD1_ROW*64, 0);
|
|
}
|
|
return;
|
|
}
|
|
bScreenIsClean = FALSE;
|
|
if (bLcdDoubled)
|
|
{
|
|
for (y=0; y<=Chipset.lcounter; y++)
|
|
{
|
|
Npeek(Buf,d,36);
|
|
for (x=0; x<36; x++,p+=8)
|
|
{
|
|
*((DWORD*)(p+0))=Pattern2[Buf[x]&3];
|
|
*((DWORD*)(p+4))=Pattern2[Buf[x]>>2];
|
|
}
|
|
CopyMemory(p, p-LCD2_ROW, LCD2_ROW);
|
|
p+=LCD2_ROW;
|
|
d+=Chipset.width;
|
|
}
|
|
BitBlt(hWindowDC, nLcdX, nLcdY, 262, (Chipset.lcounter+1)*2, hLcdDC, Chipset.boffset*2, 0, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
for (y=0; y<=Chipset.lcounter; y++)
|
|
{
|
|
Npeek(Buf,d,36);
|
|
for (x=0; x<36; x++,p+=4) *((DWORD*)p)=Pattern4[Buf[x]];
|
|
d+=Chipset.width;
|
|
}
|
|
BitBlt(hWindowDC, nLcdX, nLcdY, 131, Chipset.lcounter+1, hLcdDC, Chipset.boffset, 0, SRCCOPY);
|
|
}
|
|
}
|
|
|
|
VOID UpdateMenuDisplay()
|
|
{
|
|
UINT x, y;
|
|
DWORD d = Chipset.start2;
|
|
|
|
if (!Chipset.dispon) return;
|
|
if (Chipset.lcounter==0x3F) return; // menu disabled
|
|
if (bLcdDoubled)
|
|
{
|
|
BYTE *p = pbyLcd + ((Chipset.lcounter+1)*2*LCD2_ROW);
|
|
for (y=Chipset.lcounter+1; y<64; y++)
|
|
{
|
|
Npeek(Buf,d,36);
|
|
for (x=0; x<36; x++,p+=8)
|
|
{
|
|
*((DWORD*)(p+0))=Pattern2[Buf[x]&3];
|
|
*((DWORD*)(p+4))=Pattern2[Buf[x]>>2];
|
|
}
|
|
CopyMemory(p, p-LCD2_ROW, LCD2_ROW);
|
|
p+=LCD2_ROW;
|
|
d+=34;
|
|
}
|
|
BitBlt(hWindowDC, nLcdX, nLcdY+(Chipset.lcounter+1)*2, 262, (63-Chipset.lcounter)*2, hLcdDC, 0, (Chipset.lcounter+1)*2, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
BYTE *p = pbyLcd + (Chipset.lcounter+1)*LCD1_ROW;
|
|
for (y=Chipset.lcounter+1; y<64; y++)
|
|
{
|
|
Npeek(Buf,d,36);
|
|
for (x=0; x<36; x++,p+=4) *((DWORD*)p)=Pattern4[Buf[x]];
|
|
d+=34;
|
|
}
|
|
BitBlt(hWindowDC, nLcdX, nLcdY+(Chipset.lcounter+1), 131, 63-Chipset.lcounter, hLcdDC, 0, Chipset.lcounter+1, SRCCOPY);
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID WriteToMainDisplay(LPBYTE a, DWORD d, UINT s)
|
|
{
|
|
UINT x0, x;
|
|
UINT y0, y;
|
|
DWORD *p;
|
|
|
|
if (Chipset.width<0) return;
|
|
d -= Chipset.start1;
|
|
y0 = y = d / Chipset.width;
|
|
x0 = x = d % Chipset.width;
|
|
if ((x0*4+Chipset.boffset)>=131) return;
|
|
if (bLcdDoubled)
|
|
{
|
|
p = (DWORD*)(pbyLcd + y0*LCD2_ROW*2 + x0*8);
|
|
while (s--)
|
|
{
|
|
if (x<36)
|
|
{
|
|
p[72] = p[0] = Pattern2[(*a)&3];
|
|
p[73] = p[1] = Pattern2[(*a)>>2];
|
|
}
|
|
a++;
|
|
x++;
|
|
if ((x==(UINT)Chipset.width)&&s)
|
|
{
|
|
x=0;
|
|
y++;
|
|
if (y==(Chipset.lcounter+1)) break;
|
|
p=(DWORD*)(pbyLcd+y*LCD2_ROW*2);
|
|
} else p+=2;
|
|
}
|
|
if (y0!=y)
|
|
{
|
|
y++;
|
|
y0<<=1; y<<=1;
|
|
BitBlt(hWindowDC, nLcdX, nLcdY+y0, 262, y-y0, hLcdDC, Chipset.boffset*2, y0, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
x0<<=3; x<<=3;
|
|
if (x>262) x=262;
|
|
y0<<=1; y<<=1;
|
|
BitBlt(hWindowDC, nLcdX+x0, nLcdY+y0, x-x0, 2, hLcdDC, x0+Chipset.boffset*2, y0, SRCCOPY);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
p = (DWORD*)(pbyLcd + y0*LCD1_ROW + x0*4);
|
|
while (s--)
|
|
{
|
|
if (x<36) *p = Pattern4[*a];
|
|
a++;
|
|
x++;
|
|
if ((x==(UINT)Chipset.width)&&s)
|
|
{
|
|
x=0;
|
|
y++;
|
|
if (y==(Chipset.lcounter+1)) break;
|
|
p=(DWORD*)(pbyLcd+y*LCD1_ROW);
|
|
} else p++;
|
|
}
|
|
if (y0!=y)
|
|
{
|
|
BitBlt(hWindowDC, nLcdX, nLcdY+y0, 131, y-y0+1, hLcdDC, Chipset.boffset, y0, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
x0<<=2; x<<=2;
|
|
if (x>131) x=131;
|
|
BitBlt(hWindowDC, nLcdX+x0, nLcdY+y0, x-x0, 1, hLcdDC, x0+Chipset.boffset, y0, SRCCOPY);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID WriteToMenuDisplay(LPBYTE a, DWORD d, UINT s)
|
|
{
|
|
UINT x0, x;
|
|
UINT y0, y;
|
|
DWORD *p;
|
|
|
|
if (Chipset.width<0) return;
|
|
if (Chipset.lcounter==0x3F) return; // menu disabled
|
|
d -= Chipset.start2;
|
|
y0 = y = (d / 34) + (Chipset.lcounter+1);
|
|
x0 = x = d % 34;
|
|
if ((x0*4)>=131) return;
|
|
if (bLcdDoubled)
|
|
{
|
|
p = (DWORD*)(pbyLcd + y0*LCD2_ROW*2 + x0*8);
|
|
while (s--)
|
|
{
|
|
if (x<34)
|
|
{
|
|
p[72] = p[0] = Pattern2[(*a)&3];
|
|
p[73] = p[1] = Pattern2[(*a)>>2];
|
|
}
|
|
a++;
|
|
x++;
|
|
if ((x==34)&&s)
|
|
{
|
|
x=0;
|
|
y++;
|
|
if (y==64) break;
|
|
p=(DWORD*)(pbyLcd+y*LCD2_ROW*2);
|
|
} else p+=2;
|
|
}
|
|
if (y0!=y)
|
|
{
|
|
y0<<=1; y<<=1;
|
|
BitBlt(hWindowDC, nLcdX, nLcdY+y0, 262, y-y0+2, hLcdDC, 0, y0, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
x0<<=3; x<<=3;
|
|
y0<<=1; y<<=1;
|
|
if (x>262) x=262;
|
|
BitBlt(hWindowDC, nLcdX+x0, nLcdY+y0, x-x0, y-y0+2, hLcdDC, x0, y0, SRCCOPY);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
p = (DWORD*)(pbyLcd + y0*LCD1_ROW + x0*4);
|
|
while (s--)
|
|
{
|
|
if (x<34) *p = Pattern4[*a];
|
|
a++;
|
|
x++;
|
|
if ((x==34)&&s)
|
|
{
|
|
x=0;
|
|
y++;
|
|
if (y==64) break;
|
|
p=(DWORD*)(pbyLcd+y*LCD1_ROW);
|
|
} else p++;
|
|
}
|
|
if (y0!=y)
|
|
{
|
|
BitBlt(hWindowDC, nLcdX, nLcdY+y0, 131, y-y0+1, hLcdDC, 0, y0, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
x0<<=2; x<<=2;
|
|
if (x>131) x=131;
|
|
BitBlt(hWindowDC, nLcdX+x0, nLcdY+y0, x-x0, y-y0+1, hLcdDC, x0, y0, SRCCOPY);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
VOID UpdateAnnunciators()
|
|
{
|
|
BYTE c;
|
|
|
|
c = (BYTE)(Chipset.IORam[0xB] | (Chipset.IORam[0xC]<<4));
|
|
if (!(c&0x80)) c=0;
|
|
DrawAnnunciator(1,c&0x01);
|
|
DrawAnnunciator(2,c&0x02);
|
|
DrawAnnunciator(3,c&0x04);
|
|
DrawAnnunciator(4,c&0x08);
|
|
DrawAnnunciator(5,c&0x10);
|
|
DrawAnnunciator(6,c&0x20);
|
|
return;
|
|
}
|
|
|
|
VOID ResizeWindow()
|
|
{
|
|
RECT rectWindow;
|
|
RECT rectClient;
|
|
|
|
rectWindow.left = 0;
|
|
rectWindow.top = 0;
|
|
rectWindow.right = nBackgroundW;
|
|
rectWindow.bottom = nBackgroundH;
|
|
AdjustWindowRect(&rectWindow, WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_OVERLAPPED, TRUE);
|
|
SetWindowPos (hWnd, (HWND)NULL, 0, 0,
|
|
rectWindow.right - rectWindow.left,
|
|
rectWindow.bottom - rectWindow.top,
|
|
SWP_NOMOVE | SWP_NOZORDER);
|
|
GetClientRect(hWnd, &rectClient);
|
|
AdjustWindowRect(&rectClient, WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_OVERLAPPED, TRUE);
|
|
if (rectClient.bottom < rectWindow.bottom)
|
|
{
|
|
rectWindow.bottom += (rectWindow.bottom - rectClient.bottom);
|
|
SetWindowPos (hWnd, (HWND)NULL, 0, 0,
|
|
rectWindow.right - rectWindow.left,
|
|
rectWindow.bottom - rectWindow.top,
|
|
SWP_NOMOVE | SWP_NOZORDER);
|
|
}
|
|
InvalidateRect(hWnd,NULL,TRUE);
|
|
return;
|
|
} |