2018-09-09: Updated to version 59

Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
This commit is contained in:
Gwenhael Le Moine 2024-03-20 07:46:28 +01:00
parent d048b845e4
commit 311f1aa6b5
No known key found for this signature in database
GPG key ID: FDFE3669426707A7
15 changed files with 8379 additions and 139 deletions

BIN
Emu48.dll

Binary file not shown.

BIN
Emu48.exe

Binary file not shown.

View file

@ -83,8 +83,7 @@ h3 { color:red; font-size:1.1em; }
<a href="#ss12.2">12.2 About Emu48...</a> <a href="#ss12.2">12.2 About Emu48...</a>
</span></p> </span></p>
<p><a class="nav1" href="#s13">13. DDE Server</a></p> <p><a class="nav1" href="#s13">13. DDE Server</a></p>
<p><a class="nav1" href="#s14">14. Emu48+ Changes</a></p> <p><a class="nav1" href="#s14">14. License</a></p>
<p><a class="nav1" href="#s15">15. License</a></p>
</div> </div>
<div id="main"> <div id="main">
<h1><a name=s1>1. General</a></h1> <h1><a name=s1>1. General</a></h1>
@ -96,9 +95,9 @@ h3 { color:red; font-size:1.1em; }
Emu48 v1.0 under the GPL. Without this decision newer versions of the Emu48 v1.0 under the GPL. Without this decision newer versions of the
emulator wouldn't have been possible or ports to other similar emulator wouldn't have been possible or ports to other similar
calculators wouldn't have been made. Also a big thank to Jean-Yves calculators wouldn't have been made. Also a big thank to Jean-Yves
Avenard for his technical assistance in the beginning. And finally I Avenard for his technical assistance in the beginning. Lode Vandevenne
want to thank all the unnamed authors for publishing material about spend the PNG image decoder and finally I want to thank all the
these calculators.</p> unnamed authors for publishing material about these calculators.</p>
<h1><a name=s3>3. ROM Images</a></h1> <h1><a name=s3>3. ROM Images</a></h1>
<p>Emu48 needs an image of a calculator ROM to be able to run. ROM <p>Emu48 needs an image of a calculator ROM to be able to run. ROM
images are valid in a packed (even address lower nibble, odd address images are valid in a packed (even address lower nibble, odd address
@ -590,51 +589,9 @@ h3 { color:red; font-size:1.1em; }
<td width="66%" align="center">HP object (normal HP object)</td> <td width="66%" align="center">HP object (normal HP object)</td>
</tr> </tr>
</table> </table>
<h1><a name=s14>14. Emu48+ Changes</a></h1> <h1><a name=s14>14. License</a></h1>
<p>Emu48+ is a modified version of Emu48 to add support for the ARM-based
calculators. It does not emulate the ARM CPU, but it enhances the
Saturn emulation to more closely match the emulation provided by the
Saturn emulator on the ARM-based calculators.</p>
<p>Emu48+ adds support for many of the Saturn+ instructions, including
some of the BUSCC instructions, and it also adds support for the 80-line
display used on the 49g+ and 50g.</p>
<p>At present, the additional calculators supported in Emu48+ are the
49g+, 48gII (hardware revision 1), 50g, and 39g+/39gs/40gs.</p>
<p>To create KML scripts for the additional calculator models, use the
following model codes:</p>
<table border="0" cellpadding="0" cellspacing="0" width="651" summary="DDE settings">
<tr>
<td width="111">39g+/39gs:</td>
<td width="536">Model "P"<br>
Class 39</td>
</tr>
<tr>
<td width="111">40gs:</td>
<td width="536">Model "P"<br>
Class 40</td>
</tr>
<tr>
<td width="111">48gII:</td>
<td width="536">Model "2"</td>
</tr>
<tr>
<td width="111">49g+:</td>
<td width="536">Model "Q"</td>
</tr>
<tr>
<td width="111">50g:</td>
<td width="536">Model "Q"<br>
Class 50</td>
</tr>
</table>
<p>Most of the code that was changed in Emu48+ over Emu48 was provided by
Cyrille de Brebisson of Hewlett-Packard.</p>
<h1><a name=s15>15. License</a></h1>
<p>Emu48 - A HP38G/39G/40G/48SX/48GX/49G Emulator<br> <p>Emu48 - A HP38G/39G/40G/48SX/48GX/49G Emulator<br>
Copyright (C) 2017 Christoph Gie&szlig;elink</p> Copyright (C) 2018 Christoph Gie&szlig;elink</p>
<p>Emu48+ - A 39g+/39gs/40gs/48gII/49g+/50g Emulator<br>
Copyright (C) 2017 Cyrille de Brebisson<br>
Additional changes by Bill Graves and Eric Rechlin</p>
<p>This program is free software; you can redistribute it and/or modify it <p>This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option) Software Foundation; either version 2 of the License, or (at your option)

View file

@ -1,10 +1,10 @@
Additional known bugs and restrictions of Emu48 V1.57+ Additional known bugs and restrictions of Emu48 V1.59+
------------------------------------------------------ ------------------------------------------------------
- some display issues, such as when scrolling up, that were fixed in - some display issues, such as when scrolling up, that were fixed in
regular Emu48 haven't yet been merged into Emu48+ regular Emu48 haven't yet been merged into Emu48+
Known bugs and restrictions of Emu48 V1.59 Known bugs and restrictions of Emu48 V1.61
------------------------------------------ ------------------------------------------
- the following I/O bits aren't emulated (incomplete) - the following I/O bits aren't emulated (incomplete)
@ -53,4 +53,4 @@ Known bugs and restrictions of Emu48 V1.59
- quitting the emulator while programming the flash isn't allowed, - quitting the emulator while programming the flash isn't allowed,
because the content of flash state machine isn't saved so far because the content of flash state machine isn't saved so far
08/15/17 (c) by Christoph Gießelink, c dot giesselink at gmx dot de 08/14/18 (c) by Christoph Gießelink, c dot giesselink at gmx dot de

View file

@ -1,4 +1,4 @@
Service Pack 57+ based on Emu48 Service Pack 59 Service Pack 59+ based on Emu48 Service Pack 61
See CHANGES.TXT in Emu48 for full history. See CHANGES.TXT in Emu48 for full history.
Only changes specifically made to Emu48+ are shown below. Only changes specifically made to Emu48+ are shown below.

View file

@ -348,7 +348,7 @@ VOID UpdateMainDisplay(VOID)
EnterCriticalSection(&csGDILock); // solving NT GDI problems EnterCriticalSection(&csGDILock); // solving NT GDI problems
{ {
// CdB for HP: add 64/80 line display for apples // CdB for HP: add 64/80 line display for apples
StretchBlt(hWindowDC, nLcdX, nLcdY+Chipset.d0size*nLcdZoom, 131*nLcdZoom, MAINSCREENHEIGHT*nLcdZoom, StretchBlt(hWindowDC, nLcdX, nLcdY+Chipset.d0size*nLcdZoom, 131*nLcdZoom*nGdiXZoom, MAINSCREENHEIGHT*nLcdZoom*nGdiYZoom,
hLcdDC, Chipset.boffset, Chipset.d0size, 131, MAINSCREENHEIGHT, SRCCOPY); hLcdDC, Chipset.boffset, Chipset.d0size, 131, MAINSCREENHEIGHT, SRCCOPY);
GdiFlush(); GdiFlush();
} }
@ -392,8 +392,8 @@ VOID UpdateMenuDisplay(VOID)
{ {
// CdB for HP: add 64/80 line display for apples // CdB for HP: add 64/80 line display for apples
StretchBlt(hWindowDC, StretchBlt(hWindowDC,
nLcdX, nLcdY+(MAINSCREENHEIGHT+Chipset.d0size)*nLcdZoom, nLcdX, nLcdY+(MAINSCREENHEIGHT+Chipset.d0size)*nLcdZoom*nGdiYZoom,
131*nLcdZoom, MENUHEIGHT*nLcdZoom, 131*nLcdZoom*nGdiXZoom, MENUHEIGHT*nLcdZoom*nGdiYZoom,
hLcdDC, hLcdDC,
0, (MAINSCREENHEIGHT+Chipset.d0size), 0, (MAINSCREENHEIGHT+Chipset.d0size),
131, MENUHEIGHT, 131, MENUHEIGHT,
@ -497,8 +497,8 @@ VOID WriteToMainDisplay(LPBYTE a, DWORD d, UINT s)
if (y==y0) y++; if (y==y0) y++;
EnterCriticalSection(&csGDILock); // solving NT GDI problems EnterCriticalSection(&csGDILock); // solving NT GDI problems
{ {
StretchBlt(hWindowDC, nLcdX, nLcdY+y0*nLcdZoom, StretchBlt(hWindowDC, nLcdX, nLcdY+y0*nLcdZoom*nGdiYZoom,
131*nLcdZoom, (y-y0)*nLcdZoom, 131*nLcdZoom*nGdiXZoom, (y-y0)*nLcdZoom*nGdiYZoom,
hLcdDC, Chipset.boffset, y0, 131, y-y0, SRCCOPY); // CdB for HP: add 64/80 line display for apples hLcdDC, Chipset.boffset, y0, 131, y-y0, SRCCOPY); // CdB for HP: add 64/80 line display for apples
GdiFlush(); GdiFlush();
} }
@ -554,8 +554,8 @@ VOID WriteToMenuDisplay(LPBYTE a, DWORD d, UINT s)
if (y==y0) y++; if (y==y0) y++;
EnterCriticalSection(&csGDILock); // solving NT GDI problems EnterCriticalSection(&csGDILock); // solving NT GDI problems
{ {
StretchBlt(hWindowDC, nLcdX, nLcdY+y0*nLcdZoom, StretchBlt(hWindowDC, nLcdX, nLcdY+y0*nLcdZoom*nGdiYZoom,
131*nLcdZoom, (y-y0)*nLcdZoom, (131*nLcdZoom)*nGdiXZoom, (y-y0)*nLcdZoom*nGdiYZoom,
hLcdDC, 0, y0, 131, y-y0, SRCCOPY); // CdB for HP: add 64/80 line display for apples hLcdDC, 0, y0, 131, y-y0, SRCCOPY); // CdB for HP: add 64/80 line display for apples
GdiFlush(); GdiFlush();
} }

View file

@ -266,7 +266,11 @@ static BOOL DoHexStream(DWORD *pdwAddr,String *str,UINT *pnLevel)
} }
dwLength -= 5; // no. of DOCODE nibbles dwLength -= 5; // no. of DOCODE nibbles
PutFS(str,_T("%X "),dwLength); // write length information PutFS(str,_T("%X"),dwLength); // write length information
if (dwLength > 0) // have data
{
PutC(str,_T(' '));
}
for (;dwLength > 0; --dwLength) for (;dwLength > 0; --dwLength)
{ {
@ -328,9 +332,9 @@ static BOOL DoIntStream(DWORD *pdwAddr,String *str,UINT *pnLevel)
for (i = 0; i < dwLength; ++i) // read data for (i = 0; i < dwLength; ++i) // read data
pbyData[i] = RplReadNibble(pdwAddr); pbyData[i] = RplReadNibble(pdwAddr);
if (dwLength == 1) // special implementation for zero if (dwLength <= 1) // special implementation for zero
{ {
_ASSERT(pbyData[0] == 0); _ASSERT(dwLength == 0 || (dwLength == 1 && pbyData[0] == 0));
PutC(str,_T('0')); PutC(str,_T('0'));
} }
else else
@ -674,7 +678,11 @@ static BOOL DoHxs(DWORD *pdwAddr,String *str,UINT *pnLevel)
PutS(str,_T("HXS ")); PutS(str,_T("HXS "));
dwLength -= 5; // no. of HXS dwLength -= 5; // no. of HXS
PutFS(str,_T("%X "),dwLength); // write length information PutFS(str,_T("%X"),dwLength); // write length information
if (dwLength > 0) // have data
{
PutC(str,_T(' '));
}
bRemove = TRUE; // remove leading zeros bRemove = TRUE; // remove leading zeros

View file

@ -13,7 +13,7 @@
#include "kml.h" #include "kml.h"
#include "debugger.h" #include "debugger.h"
#define VERSION "1.57+" #define VERSION "1.59+"
#ifdef _DEBUG #ifdef _DEBUG
LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION)_T(" Debug"); LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION)_T(" Debug");
@ -888,17 +888,17 @@ static LRESULT OnPaint(HWND hWindow)
// redraw header display area // redraw header display area
StretchBlt(hPaintDC, nLcdX, nLcdY, StretchBlt(hPaintDC, nLcdX, nLcdY,
131*nLcdZoom*nGdiXZoom, Chipset.d0size*nLcdZoom*nGdiYZoom, 131*nLcdZoom*nGdiXZoom, Chipset.d0size*nLcdZoom*nGdiYZoom,
hLcdDC, Chipset.d0offset, 0, 131, Chipset.d0size, SRCCOPY); hLcdDC, Chipset.d0offset, 0,
131, Chipset.d0size, SRCCOPY);
// redraw main display area // redraw main display area
StretchBlt(hPaintDC, nLcdX, nLcdY+Chipset.d0size*nLcdZoom*nGdiYZoom, StretchBlt(hPaintDC, nLcdX, nLcdY+Chipset.d0size*nLcdZoom*nGdiYZoom,
131*nLcdZoom*nGdiXZoom, nLines*nLcdZoom*nGdiYZoom, 131*nLcdZoom*nGdiXZoom, nLines*nLcdZoom*nGdiYZoom,
hLcdDC, Chipset.boffset, Chipset.d0size, hLcdDC, Chipset.boffset, Chipset.d0size,
131, MAINSCREENHEIGHT, SRCCOPY); 131, nLines, SRCCOPY);
// redraw menu display area // redraw menu display area
StretchBlt(hPaintDC, nLcdX, nLcdY+(MAINSCREENHEIGHT+Chipset.d0size)*nLcdZoom*nGdiYZoom, StretchBlt(hPaintDC, nLcdX, nLcdY+(nLines+Chipset.d0size)*nLcdZoom*nGdiYZoom,
131*nLcdZoom*nGdiXZoom, MENUHEIGHT*nLcdZoom*nGdiYZoom, 131*nLcdZoom*nGdiXZoom, MENUHEIGHT*nLcdZoom*nGdiYZoom,
hLcdDC, 0, (MAINSCREENHEIGHT+Chipset.d0size), hLcdDC, 0, (nLines+Chipset.d0size),
131, MENUHEIGHT, SRCCOPY); 131, MENUHEIGHT, SRCCOPY);
GdiFlush(); GdiFlush();
} }
@ -1172,11 +1172,32 @@ static LRESULT OnViewCopy(VOID)
WORD wBits; WORD wBits;
DWORD dwLen, dwSizeImage; DWORD dwLen, dwSizeImage;
_ASSERT(nLcdZoom == 1 || nLcdZoom == 2 || nLcdZoom == 4); _ASSERT(nLcdZoom >= 1 && nLcdZoom <= 4);
hBmp = CreateCompatibleBitmap(hLcdDC,131*nLcdZoom,SCREENHEIGHT*nLcdZoom); // CdB for HP: add apples display stuff hBmp = CreateCompatibleBitmap(hLcdDC,131*nLcdZoom*nGdiXZoom,SCREENHEIGHT*nLcdZoom*nGdiYZoom); // CdB for HP: add apples display stuff
hBmpDC = CreateCompatibleDC(hLcdDC); hBmpDC = CreateCompatibleDC(hLcdDC);
hBmp = (HBITMAP) SelectObject(hBmpDC,hBmp); hBmp = (HBITMAP) SelectObject(hBmpDC,hBmp);
StretchBlt(hBmpDC,0,0,131*nLcdZoom,SCREENHEIGHT*nLcdZoom,hLcdDC,0,0, 131, SCREENHEIGHT, SRCCOPY); // CdB for HP: add apples display stuff EnterCriticalSection(&csGDILock); // solving NT GDI problems
{
UINT nLines = MAINSCREENHEIGHT;
// copy header display area
StretchBlt(hBmpDC, 0, 0,
131*nLcdZoom*nGdiXZoom, Chipset.d0size*nLcdZoom*nGdiYZoom,
hLcdDC, Chipset.d0offset, 0,
131, Chipset.d0size, SRCCOPY);
// copy main display area
StretchBlt(hBmpDC, 0, Chipset.d0size*nLcdZoom*nGdiYZoom,
131*nLcdZoom*nGdiXZoom, nLines*nLcdZoom*nGdiYZoom,
hLcdDC, Chipset.boffset, Chipset.d0size,
131, nLines, SRCCOPY);
// copy menu display area
StretchBlt(hBmpDC, 0, (nLines+Chipset.d0size)*nLcdZoom*nGdiYZoom,
131*nLcdZoom*nGdiXZoom, MENUHEIGHT*nLcdZoom*nGdiYZoom,
hLcdDC, 0, (nLines+Chipset.d0size),
131, MENUHEIGHT, SRCCOPY);
GdiFlush();
}
LeaveCriticalSection(&csGDILock);
hBmp = (HBITMAP) SelectObject(hBmpDC,hBmp); hBmp = (HBITMAP) SelectObject(hBmpDC,hBmp);
// fill BITMAP structure for size information // fill BITMAP structure for size information

View file

@ -281,6 +281,12 @@ SOURCE=.\kml.c
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\lodepng.c
# ADD CPP /D "LODEPNG_NO_COMPILE_ENCODER" /D "LODEPNG_NO_COMPILE_DISK" /D "LODEPNG_NO_COMPILE_ERROR_TEXT" /D "LODEPNG_NO_COMPILE_CPP"
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# Begin Source File
SOURCE=.\lowbat.c SOURCE=.\lowbat.c
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -378,6 +384,10 @@ SOURCE=.\kml.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\lodepng.h
# End Source File
# Begin Source File
SOURCE=.\opcodes.h SOURCE=.\opcodes.h
# End Source File # End Source File
# Begin Source File # Begin Source File

View file

@ -295,7 +295,7 @@ FONT 8, "MS Sans Serif"
BEGIN BEGIN
ICON IDI_EMU48,IDC_STATIC,7,6,20,20,SS_REALSIZEIMAGE ICON IDI_EMU48,IDC_STATIC,7,6,20,20,SS_REALSIZEIMAGE
LTEXT "",IDC_VERSION,29,6,151,8,NOT WS_GROUP LTEXT "",IDC_VERSION,29,6,151,8,NOT WS_GROUP
LTEXT "Copyright © 2017 Christoph Gießelink && Sébastien Carlier", LTEXT "Copyright © 2018 Christoph Gießelink && Sébastien Carlier",
IDC_STATIC,29,18,181,8 IDC_STATIC,29,18,181,8
DEFPUSHBUTTON "OK",IDOK,215,12,39,14 DEFPUSHBUTTON "OK",IDOK,215,12,39,14
EDITTEXT IDC_LICENSE,7,33,247,112,ES_MULTILINE | ES_AUTOHSCROLL | EDITTEXT IDC_LICENSE,7,33,247,112,ES_MULTILINE | ES_AUTOHSCROLL |
@ -691,8 +691,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,5,7,0 FILEVERSION 1,5,9,0
PRODUCTVERSION 1,5,7,0 PRODUCTVERSION 1,5,9,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -709,12 +709,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Christoph Gießelink & Sebastien Carlier\0" VALUE "CompanyName", "Christoph Gießelink & Sebastien Carlier\0"
VALUE "FileDescription", "HP38/39/40/48/49/50 Emulator\0" VALUE "FileDescription", "HP38/39/40/48/49/50 Emulator\0"
VALUE "FileVersion", "1, 5, 7, 0\0" VALUE "FileVersion", "1, 5, 9, 0\0"
VALUE "InternalName", "Emu48\0" VALUE "InternalName", "Emu48\0"
VALUE "LegalCopyright", "Copyright © 2017\0" VALUE "LegalCopyright", "Copyright © 2018\0"
VALUE "OriginalFilename", "Emu48.exe\0" VALUE "OriginalFilename", "Emu48.exe\0"
VALUE "ProductName", "Emu48\0" VALUE "ProductName", "Emu48\0"
VALUE "ProductVersion", "1, 5, 7, 0\0" VALUE "ProductVersion", "1, 5, 9, 0\0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -168,6 +168,12 @@ SOURCE=.\kml.c
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\lodepng.c
# ADD CPP /D "LODEPNG_NO_COMPILE_ENCODER" /D "LODEPNG_NO_COMPILE_DISK" /D "LODEPNG_NO_COMPILE_ERROR_TEXT" /D "LODEPNG_NO_COMPILE_CPP"
# SUBTRACT CPP /YX /Yc /Yu
# End Source File
# Begin Source File
SOURCE=.\lowbat.c SOURCE=.\lowbat.c
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -265,6 +271,10 @@ SOURCE=.\kml.h
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\lodepng.h
# End Source File
# Begin Source File
SOURCE=.\opcodes.h SOURCE=.\opcodes.h
# End Source File # End Source File
# Begin Source File # Begin Source File

View file

@ -13,6 +13,7 @@
#include "kml.h" #include "kml.h"
#include "i28f160.h" // flash support #include "i28f160.h" // flash support
#include "debugger.h" #include "debugger.h"
#include "lodepng.h"
#pragma intrinsic(abs,labs) #pragma intrinsic(abs,labs)
@ -101,7 +102,7 @@ VOID SetWindowLocation(HWND hWnd,INT nPosX,INT nPosY)
DWORD GetCutPathName(LPCTSTR szFileName, LPTSTR szBuffer, DWORD dwBufferLength, INT nCutLength) DWORD GetCutPathName(LPCTSTR szFileName, LPTSTR szBuffer, DWORD dwBufferLength, INT nCutLength)
{ {
TCHAR cPath[_MAX_PATH]; // full filename TCHAR cPath[_MAX_PATH]; // full filename
TCHAR cDrive[_MAX_DRIVE]; TCHAR cDrive[_MAX_DRIVE];
TCHAR cDir[_MAX_DIR]; TCHAR cDir[_MAX_DIR];
TCHAR cFname[_MAX_FNAME]; TCHAR cFname[_MAX_FNAME];
@ -112,9 +113,9 @@ DWORD GetCutPathName(LPCTSTR szFileName, LPTSTR szBuffer, DWORD dwBufferLength,
// split original filename into parts // split original filename into parts
_tsplitpath(szFileName,cDrive,cDir,cFname,cExt); _tsplitpath(szFileName,cDrive,cDir,cFname,cExt);
if (*cDir != 0) // contain directory part if (*cDir != 0) // contain directory part
{ {
LPTSTR lpFilePart; // address of file name in path LPTSTR lpFilePart; // address of file name in path
INT nNameLen,nPathLen,nMaxPathLen; INT nNameLen,nPathLen,nMaxPathLen;
GetFullPathName(szFileName,ARRAYSIZEOF(cPath),cPath,&lpFilePart); GetFullPathName(szFileName,ARRAYSIZEOF(cPath),cPath,&lpFilePart);
@ -1480,8 +1481,8 @@ BOOL GetSaveObjectFilename(LPCTSTR lpstrFilter,LPCTSTR lpstrDefExt)
WORD WriteStack(UINT nStkLevel,LPBYTE lpBuf,DWORD dwSize) // separated from LoadObject() WORD WriteStack(UINT nStkLevel,LPBYTE lpBuf,DWORD dwSize) // separated from LoadObject()
{ {
BOOL bBinary; BOOL bBinary;
DWORD dwAddress, i; DWORD dwAddress, i;
bBinary = ((lpBuf[dwSize+0]=='H') bBinary = ((lpBuf[dwSize+0]=='H')
&& (lpBuf[dwSize+1]=='P') && (lpBuf[dwSize+1]=='P')
@ -1568,11 +1569,11 @@ BOOL LoadObject(LPCTSTR szFilename) // separated stack writing part
BOOL SaveObject(LPCTSTR szFilename) // separated stack reading part BOOL SaveObject(LPCTSTR szFilename) // separated stack reading part
{ {
HANDLE hFile; HANDLE hFile;
LPBYTE pbyHeader; LPBYTE pbyHeader;
DWORD lBytesWritten; DWORD lBytesWritten;
DWORD dwAddress; DWORD dwAddress;
DWORD dwLength; DWORD dwLength;
dwAddress = RPL_Pick(1); dwAddress = RPL_Pick(1);
if (dwAddress == 0) if (dwAddress == 0)
@ -1935,7 +1936,7 @@ static HBITMAP DecodeGif(LPBMPFILE pBmp,DWORD *pdwTransparentColor)
// allocate buffer for pixels // allocate buffer for pixels
VERIFY(hBitmap = CreateDIBSection(hWindowDC, VERIFY(hBitmap = CreateDIBSection(hWindowDC,
(LPBITMAPINFO)&bmi, &bmi,
DIB_RGB_COLORS, DIB_RGB_COLORS,
(VOID **)&pbyPixels, (VOID **)&pbyPixels,
NULL, NULL,
@ -2331,6 +2332,91 @@ quit:
return hBitmap; return hBitmap;
} }
static HBITMAP DecodePng(LPBMPFILE pBmp)
{
// this implementation use the PNG image file decoder
// engine of Copyright (c) 2005-2018 Lode Vandevenne
HBITMAP hBitmap;
UINT uError,uWidth,uHeight;
INT nWidth,nHeight;
LONG lBytesPerLine;
LPBYTE pbyImage; // PNG RGB image data
LPBYTE pbySrc; // source buffer pointer
LPBYTE pbyPixels; // BMP buffer
BITMAPINFO bmi;
hBitmap = NULL;
pbyImage = NULL;
// decode PNG image
uError = lodepng_decode_memory(&pbyImage,&uWidth,&uHeight,pBmp->pbyFile,pBmp->dwFileSize,LCT_RGB,8);
if (uError) goto quit;
ZeroMemory(&bmi,sizeof(bmi)); // init bitmap info
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = (LONG) uWidth;
bmi.bmiHeader.biHeight = (LONG) uHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 24; // create a true color DIB
bmi.bmiHeader.biCompression = BI_RGB;
// bitmap dimensions
lBytesPerLine = WIDTHBYTES(bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount);
bmi.bmiHeader.biSizeImage = lBytesPerLine * bmi.bmiHeader.biHeight;
// allocate buffer for pixels
VERIFY(hBitmap = CreateDIBSection(hWindowDC,
&bmi,
DIB_RGB_COLORS,
(VOID **)&pbyPixels,
NULL,
0));
if (hBitmap == NULL) goto quit;
pbySrc = pbyImage; // init source loop pointer
// fill bottom up DIB pixel buffer with color information
for (nHeight = bmi.bmiHeader.biHeight - 1; nHeight >= 0; --nHeight)
{
LPBYTE pbyLine = pbyPixels + nHeight * lBytesPerLine;
for (nWidth = 0; nWidth < bmi.bmiHeader.biWidth; ++nWidth)
{
*pbyLine++ = pbySrc[2]; // blue
*pbyLine++ = pbySrc[1]; // green
*pbyLine++ = pbySrc[0]; // red
pbySrc += 3;
}
_ASSERT((DWORD) (pbyLine - pbyPixels) <= bmi.bmiHeader.biSizeImage);
}
if (hPalette == NULL)
{
hPalette = CreateBIPalette((PBITMAPINFOHEADER) &bmi);
// save old palette
hOldPalette = SelectPalette(hWindowDC, hPalette, FALSE);
RealizePalette(hWindowDC);
}
quit:
if (pbyImage != NULL) // buffer for PNG image allocated
{
free(pbyImage); // free PNG image data
}
if (hBitmap != NULL && uError != 0) // creation failed
{
DeleteObject(hBitmap); // delete bitmap
hBitmap = NULL;
}
return hBitmap;
}
HBITMAP LoadBitmapFile(LPCTSTR szFilename) HBITMAP LoadBitmapFile(LPCTSTR szFilename)
{ {
HANDLE hFile; HANDLE hFile;
@ -2374,6 +2460,13 @@ HBITMAP LoadBitmapFile(LPCTSTR szFilename)
break; break;
} }
// check for PNG file header
if (Bmp.dwFileSize >= 8 && memcmp(Bmp.pbyFile,"\x89PNG\r\n\x1a\n",8) == 0)
{
hBitmap = DecodePng(&Bmp);
break;
}
// unknown file type // unknown file type
hBitmap = NULL; hBitmap = NULL;
} }
@ -2420,15 +2513,41 @@ static BOOL LabColorCmp(DWORD dwColor1,DWORD dwColor2,DWORD dwTol)
return dwDiff > dwTol; // FALSE = colors match return dwDiff > dwTol; // FALSE = colors match
} }
static DWORD EncodeColorBits(DWORD dwColorVal,DWORD dwMask)
{
#define MAXBIT 32
UINT uLshift = MAXBIT;
UINT uRshift = 8;
DWORD dwBitMask = dwMask;
dwColorVal &= 0xFF; // the color component using the lowest 8 bit
// position of highest bit
while ((dwBitMask & (1<<(MAXBIT-1))) == 0 && uLshift > 0)
{
dwBitMask <<= 1; // next bit
--uLshift; // next position
}
if (uLshift > 24) // avoid overflow on 32bit mask
{
uLshift -= uRshift; // normalize left shift
uRshift = 0;
}
return ((dwColorVal << uLshift) >> uRshift) & dwMask;
#undef MAXBIT
}
HRGN CreateRgnFromBitmap(HBITMAP hBmp,COLORREF color,DWORD dwTol) HRGN CreateRgnFromBitmap(HBITMAP hBmp,COLORREF color,DWORD dwTol)
{ {
#define ADD_RECTS_COUNT 256 #define ADD_RECTS_COUNT 256
BOOL (*fnColorCmp)(DWORD dwColor1,DWORD dwColor2,DWORD dwTol); BOOL (*fnColorCmp)(DWORD dwColor1,DWORD dwColor2,DWORD dwTol);
DWORD dwRed,dwGreen,dwBlue;
HRGN hRgn; HRGN hRgn;
LPRGNDATA pRgnData; LPRGNDATA pRgnData;
BITMAP bm;
LPBITMAPINFO bi; LPBITMAPINFO bi;
LPBYTE pbyBits; LPBYTE pbyBits;
LPBYTE pbyColor; LPBYTE pbyColor;
@ -2438,7 +2557,6 @@ HRGN CreateRgnFromBitmap(HBITMAP hBmp,COLORREF color,DWORD dwTol)
LONG x,y,xleft; LONG x,y,xleft;
BOOL bFoundLeft; BOOL bFoundLeft;
BOOL bIsMask; BOOL bIsMask;
HDC hDC;
if (dwTol >= 1000) // use CIE L*a*b compare if (dwTol >= 1000) // use CIE L*a*b compare
{ {
@ -2450,16 +2568,13 @@ HRGN CreateRgnFromBitmap(HBITMAP hBmp,COLORREF color,DWORD dwTol)
fnColorCmp = AbsColorCmp; fnColorCmp = AbsColorCmp;
} }
// get image properties
GetObject(hBmp,sizeof(bm),&bm);
// allocate memory for extended image information incl. RGBQUAD color table // allocate memory for extended image information incl. RGBQUAD color table
bi = (LPBITMAPINFO) calloc(1,sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); bi = (LPBITMAPINFO) calloc(1,sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
bi->bmiHeader.biSize = sizeof(bi->bmiHeader); bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
_ASSERT(bi->bmiHeader.biBitCount == 0); // for query without color table
// get information about image // get information about image
hDC = CreateCompatibleDC(hWindowDC); GetDIBits(hWindowDC,hBmp,0,0,NULL,bi,DIB_RGB_COLORS);
GetDIBits(hDC,hBmp,0,bm.bmHeight,NULL,bi,DIB_RGB_COLORS);
// DWORD aligned bitmap width in BYTES // DWORD aligned bitmap width in BYTES
dwAlignedWidthBytes = WIDTHBYTES( bi->bmiHeader.biWidth dwAlignedWidthBytes = WIDTHBYTES( bi->bmiHeader.biWidth
@ -2476,24 +2591,36 @@ HRGN CreateRgnFromBitmap(HBITMAP hBmp,COLORREF color,DWORD dwTol)
pbyBits = (LPBYTE) malloc(bi->bmiHeader.biSizeImage); pbyBits = (LPBYTE) malloc(bi->bmiHeader.biSizeImage);
// fill bits buffer // fill bits buffer
GetDIBits(hDC,hBmp,0,bi->bmiHeader.biHeight,pbyBits,bi,DIB_RGB_COLORS); GetDIBits(hWindowDC,hBmp,0,bi->bmiHeader.biHeight,pbyBits,bi,DIB_RGB_COLORS);
DeleteDC(hDC);
// convert color if current DC is 16-bit RGB coded // convert color if current DC is 16-bit/32-bit bitfield coded
if (bi->bmiHeader.biBitCount == 16) if (bi->bmiHeader.biCompression == BI_BITFIELDS)
{ {
// for 15 bit (5:5:5) dwRed = *(LPDWORD) &bi->bmiColors[0];
color = ((color & 0xF80000) >> 19) dwGreen = *(LPDWORD) &bi->bmiColors[1];
| ((color & 0x00F800) >> 6) dwBlue = *(LPDWORD) &bi->bmiColors[2];
| ((color & 0x0000F8) << 7);
} }
else else // RGB coded
{ {
// convert COLORREF to RGBQUAD color // convert color if current DC is 16-bit RGB coded
color = ((color & 0xFF0000) >> 16) if (bi->bmiHeader.biBitCount == 16)
| ((color & 0x00FF00) >> 0) {
| ((color & 0x0000FF) << 16); // for 15 bit (5:5:5)
dwRed = 0x00007C00;
dwGreen = 0x000003E0;
dwBlue = 0x0000001F;
}
else
{
// convert COLORREF to RGBQUAD color
dwRed = 0x00FF0000;
dwGreen = 0x0000FF00;
dwBlue = 0x000000FF;
}
} }
color = EncodeColorBits((color >> 16), dwBlue)
| EncodeColorBits((color >> 8), dwGreen)
| EncodeColorBits((color >> 0), dwRed);
dwBpp = bi->bmiHeader.biBitCount >> 3; // bytes per pixel dwBpp = bi->bmiHeader.biBitCount >> 3; // bytes per pixel
@ -2537,7 +2664,7 @@ HRGN CreateRgnFromBitmap(HBITMAP hBmp,COLORREF color,DWORD dwTol)
} }
pbyColor += dwBpp; // shift pointer to next color pbyColor += dwBpp; // shift pointer to next color
if (!bFoundLeft && bIsMask) // non transparent color found if (!bFoundLeft && bIsMask) // non transparent color found
{ {
xleft = x; xleft = x;
bFoundLeft = TRUE; bFoundLeft = TRUE;

View file

@ -1813,39 +1813,59 @@ static UINT iSqrt(UINT nNumber) // integer y=sqrt(x) function
return b; return b;
} }
static VOID AdjustPixel(UINT x, UINT y, BYTE byOffset) static VOID AdjustPixel(LPBYTE pbyPixel, BYTE byOffset)
{ {
COLORREF rgb; INT i = 3; // BGR colors
WORD wB, wG, wR;
rgb = GetPixel(hWindowDC, x, y); while (--i >= 0)
{
// adjust color red WORD wColor = (WORD) *pbyPixel + byOffset;
wR = (((WORD) rgb) & 0x00FF) + byOffset; // jumpless saturation to 0xFF
if (wR > 0xFF) wR = 0xFF; wColor = -(wColor >> 8) | (BYTE) wColor;
rgb >>= 8; *pbyPixel++ = (BYTE) wColor;
// adjust color green }
wG = (((WORD) rgb) & 0x00FF) + byOffset;
if (wG > 0xFF) wG = 0xFF;
rgb >>= 8;
// adjust color blue
wB = (((WORD) rgb) & 0x00FF) + byOffset;
if (wB > 0xFF) wB = 0xFF;
SetPixel(hWindowDC, x, y, RGB(wR,wG,wB));
return; return;
} }
// draw transparent circle with center coordinates and radius in pixel // draw transparent circle button type
static __inline VOID TransparentCircle(UINT cx, UINT cy, UINT r) static __inline VOID TransparentCircle(UINT nOx, UINT nOy, UINT nCx, UINT nCy)
{ {
#define HIGHADJ 0x80 // color incr. at center #define HIGHADJ 0x80 // color incr. at center
#define LOWADJ 0x10 // color incr. at border #define LOWADJ 0x10 // color incr. at border
UINT x, y, rr, rrc; BITMAPINFO bmi;
HDC hMemDC;
HBITMAP hMemBitMap;
LPBYTE pbyPixels; // BMP data
UINT x, y, cx, cy, r, rr, rrc;
r = min(nCx,nCy) / 2; // radius
if (r < 2) return; // radius 2 pixel minimum if (r < 2) return; // radius 2 pixel minimum
// create memory copy of button rectangle
ZeroMemory(&bmi,sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = (LONG) nCx;
bmi.bmiHeader.biHeight = (LONG) nCy;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32; // use 32 bit bitmap for easier buffer calculation
bmi.bmiHeader.biCompression = BI_RGB;
VERIFY(hMemBitMap = CreateDIBSection(hWindowDC,
&bmi,
DIB_RGB_COLORS,
(VOID **)&pbyPixels,
NULL,
0));
if (hMemBitMap == NULL) return;
hMemDC = CreateCompatibleDC(hWindowDC);
hMemBitMap = (HBITMAP) SelectObject(hMemDC,hMemBitMap);
BitBlt(hMemDC, 0, 0, nCx, nCy, hWindowDC, nOx, nOy, SRCCOPY);
cx = nCx / 2; // x-center coordinate
cy = nCy / 2; // y-center coordinate
rr = r * r; // calculate r^2 rr = r * r; // calculate r^2
rrc = (r-1) * (r-1); // calculate (r-1)^2 for color steps rrc = (r-1) * (r-1); // calculate (r-1)^2 for color steps
@ -1862,12 +1882,31 @@ static __inline VOID TransparentCircle(UINT cx, UINT cy, UINT r)
// color offset, sqrt(x*x+y*y) < r !!! // color offset, sqrt(x*x+y*y) < r !!!
BYTE byOff = HIGHADJ - (BYTE) (iSqrt((x*x+yy) * (HIGHADJ-LOWADJ)*(HIGHADJ-LOWADJ) / rrc)); BYTE byOff = HIGHADJ - (BYTE) (iSqrt((x*x+yy) * (HIGHADJ-LOWADJ)*(HIGHADJ-LOWADJ) / rrc));
AdjustPixel(cx+x, cy+y, byOff); AdjustPixel(pbyPixels + (((cy+y) * bmi.bmiHeader.biWidth + (cx+x)) << 2), byOff);
if (x != 0) AdjustPixel(cx-x, cy+y, byOff);
if (y != 0) AdjustPixel(cx+x, cy-y, byOff); if (x != 0)
if (x != 0 && y != 0) AdjustPixel(cx-x, cy-y, byOff); {
AdjustPixel(pbyPixels + (((cy+y) * bmi.bmiHeader.biWidth + (cx-x)) << 2), byOff);
}
if (y != 0)
{
AdjustPixel(pbyPixels + (((cy-y) * bmi.bmiHeader.biWidth + (cx+x)) << 2), byOff);
}
if (x != 0 && y != 0)
{
AdjustPixel(pbyPixels + (((cy-y) * bmi.bmiHeader.biWidth + (cx-x)) << 2), byOff);
}
} }
} }
// update button area with modified data
BitBlt(hWindowDC, nOx, nOy, nCx, nCy, hMemDC, 0, 0, SRCCOPY);
// delete memory bitmap
VERIFY(DeleteObject(SelectObject(hMemDC,hMemBitMap)));
DeleteDC(hMemDC);
return; return;
#undef HIGHADJ #undef HIGHADJ
@ -1948,9 +1987,7 @@ static VOID DrawButton(UINT nId)
case 5: // transparent circle case 5: // transparent circle
if (pButton[nId].bDown) if (pButton[nId].bDown)
{ {
TransparentCircle(x0 + pButton[nId].nCx / 2, // x-center coordinate TransparentCircle(x0, y0, pButton[nId].nCx, pButton[nId].nCy);
y0 + pButton[nId].nCy / 2, // y-center coordinate
min(pButton[nId].nCx,pButton[nId].nCy) / 2); // radius
} }
else else
{ {

6300
source/LODEPNG.C Normal file

File diff suppressed because it is too large Load diff

1770
source/LODEPNG.H Normal file

File diff suppressed because it is too large Load diff