2019-10-16: Updated to version 61
Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
This commit is contained in:
parent
9ed4c0cec5
commit
b29959b1f3
17 changed files with 4397 additions and 4454 deletions
|
@ -87,28 +87,32 @@ h3 { color:red; font-size:1.1em; }
|
|||
</div>
|
||||
<div id="main">
|
||||
<h1><a name=s1>1. General</a></h1>
|
||||
<p>Emu48 is an emulator for the Hewlett Packard HP38G, HP39G,
|
||||
HP40G, HP48SX, HP48GX and HP49G calculator hardware. These calculators
|
||||
are based on the 1LT8 Clarke (HP48SX) and on the Yorke chip.</p>
|
||||
<p><a href="http://hp.giesselink.com/emu42.htm">Emu48</a> is an
|
||||
emulator for the Hewlett Packard HP38G, HP39G, HP40G, HP48SX, HP48GX
|
||||
and HP49G calculator hardware. These calculators are based on the
|
||||
1LT8 Clarke (HP48SX) and on the Yorke chip.</p>
|
||||
<h1><a name=s2>2. Acknowledgements</a></h1>
|
||||
<p>First of all a big thank to Sébastien Carlier for publishing
|
||||
Emu48 v1.0 under the GPL. Without this decision newer versions of the
|
||||
emulator wouldn't have been possible or ports to other similar
|
||||
calculators wouldn't have been made. Also a big thank to Jean-Yves
|
||||
Avenard for his technical assistance in the beginning. Lode Vandevenne
|
||||
spend the PNG image decoder and finally I want to thank all the
|
||||
spent the PNG image decoder and finally I want to thank all the
|
||||
unnamed authors for publishing material about these calculators.</p>
|
||||
<h1><a name=s3>3. ROM Images</a></h1>
|
||||
<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
|
||||
higher nibble) or unpacked (one nibble per byte with even address first)
|
||||
<p>Emu48 needs a <a href="https://en.wikipedia.org/wiki/ROM_image">ROM
|
||||
image</a> for each calculator model you want to emulate. ROM images
|
||||
are valid in a packed (even address lower nibble, odd address higher
|
||||
nibble) or unpacked (one nibble per byte with even address first)
|
||||
form.</p>
|
||||
<p>Since fall 2000 the emulator ROM's for the HP38, 39, 40, 48 and 49
|
||||
are freely available on different Internet sites. Because there's no
|
||||
license for the distribution of the ROM images, they aren't included
|
||||
in the Emu48 package. You can still use the classic way extracting
|
||||
them from your own calculator. But in mostly all cases you have to
|
||||
convert the ROM files into the Emu48 ROM format.</p>
|
||||
in the Emu48 package. Since accepting packed ROM images, in most cases
|
||||
converting the given ROM format (which is regulary a packed ROM image)
|
||||
into the native Emu48 ROM format is not necessary any more. You can
|
||||
still use the classic way extracting them from your own calculator.
|
||||
</p>
|
||||
<ul>
|
||||
<li>HP38
|
||||
<p>To upload the ROM of your HP38G, you will need a special aplet
|
||||
|
@ -178,24 +182,24 @@ h3 { color:red; font-size:1.1em; }
|
|||
<p>To install Emu48 you may use the installer package which contain,
|
||||
among the binaries, some HP48 KML scripts or just unzip the emulator
|
||||
and the required emulator skins from archives into an empty directory.
|
||||
Finally you have to copy your ROM images into this directory and
|
||||
adjust the ROM image name to the name used in the corresponding KML
|
||||
script. When you first run Emu48, it will detect the directory in
|
||||
which you installed it, and will write the configuration to the
|
||||
registry at <i>HKCU\Software\Emu48</i>.</p>
|
||||
Finally copy your ROM images into this directory and adjust the ROM
|
||||
image name to the name used in the corresponding KML script. When you
|
||||
first run Emu48, it will detect the directory in which you installed
|
||||
it, and will write the configuration to the registry at
|
||||
<i>HKCU\Software\Emu48</i>.</p>
|
||||
<h1><a name=s5>5. How to Start</a></h1>
|
||||
<p>When Emu48 is installed and you have put valid KML scripts and the
|
||||
corresponding ROM image(s) into your Emu48 installation directory, you
|
||||
can start Emu48. You'll see a "Choose Your KML Script"
|
||||
box.</p>
|
||||
<p>KML scripts in fact define the visual aspect of Emu48, the behavior of
|
||||
the buttons, of the keyboard, ... It's a GREAT way to customize your copy
|
||||
of Emu48.</p>
|
||||
<p>Check that the path in the "Emu48 Directory" text area is
|
||||
correct. Modify it if the directory in which you installed Emu48 is not
|
||||
the directory displayed. Click the refresh button ("V") after
|
||||
modifying it to update the list box or use the ("...") button to
|
||||
start the directory browser.</p>
|
||||
<p>KML (Keyboard Mapping Language) scripts define the visual aspect
|
||||
of Emu48, the behaviour of the buttons, of the keyboard, ... It's a
|
||||
<b>great</b> way to customize your copy of Emu48.</p>
|
||||
<p>Check in this dialog that the path in the "Emu48 Directory"
|
||||
text area points to the directory in which you installed the Emu48 KML
|
||||
files. Click the refresh button ("V") after modifying the
|
||||
directory path manually to update the list box or use the
|
||||
("...") button to start a directory browser.</p>
|
||||
<p>Choose a KML script in the list box for your calculator ROM you put
|
||||
into Emu48's directory.</p>
|
||||
<p>Several HP48 scripts are included in the Emu48 archive:</p>
|
||||
|
@ -218,19 +222,21 @@ h3 { color:red; font-size:1.1em; }
|
|||
</ul>
|
||||
<p>If you want other great scripts, visit Rechlin's great HP archive
|
||||
<a href="http://www.hpcalc.org/"></a></p>
|
||||
<p>And if you are interested in writing new scripts, get the KML 2.0
|
||||
<p>If you are interested in writing new scripts, get the KML 2.0
|
||||
documentation from <a href="http://hp.giesselink.com/emu48.htm">the
|
||||
authors Emu48 page</a>.</p>
|
||||
<p>Once you have selected a script, press OK to start the emulator. In
|
||||
most cases, when Emu48 crash after pressing the OK button, you are using
|
||||
an invalid ROM image. While it's running, you can use the View/Change KML
|
||||
Script... command to change the visual aspect of Emu48.</p>
|
||||
<p>Having selected a script, press OK to start the emulator. In most
|
||||
cases, when Emu48 crash after pressing the OK button, you are using
|
||||
an invalid ROM image. While it's running, you can use the
|
||||
"<a href="#ss10.1">View/Change KML Script...</a>" command to
|
||||
change the visual aspect of Emu48.</p>
|
||||
<h1><a name=s6>6. Command Line</a></h1>
|
||||
<p>The command line syntax is "<i>Emu48 [E48file [Port2file]]</i>".
|
||||
The first parameter sets the filename for the emulation data
|
||||
independent from the "LastDocument" setting, the second
|
||||
parameter the Port2 file. You're not able to set a Port 2 file without
|
||||
setting the emulation data file. The arguments are optional.</p>
|
||||
The first parameter sets the filename of the emulation data
|
||||
independent from the "LastDocument" setting, normally
|
||||
reponsible for opening the last used state file. The second parameter
|
||||
the Port2 file. You're not able to set a Port 2 file without setting
|
||||
the emulation data file. The arguments are optional.</p>
|
||||
<h1><a name=s7>7. Virtual Keyboard</a></h1>
|
||||
<p>There are two ways to use the virtual keyboard on the emulated
|
||||
calculator:</p>
|
||||
|
@ -239,38 +245,41 @@ h3 { color:red; font-size:1.1em; }
|
|||
<li><a href="#keyboard">by PC keyboard</a></li>
|
||||
</ol>
|
||||
<p><a name=mouse></a>
|
||||
The easiest way to use the emulated calculator is using the mouse. The KML
|
||||
script define buttons with an area where mouse input is active. The mouse
|
||||
cursor change from an arrow to a hand cursor in these areas. The state of
|
||||
the virtual key follow the state of your left mouse button. When the mouse
|
||||
cursor leaves the virtual key area the virtual button automatically
|
||||
release. In some cases you need to press more than one key on the
|
||||
emulator. For these cases press the virtual key with the right mouse
|
||||
button. When you release the mouse button or leave the area of the virtual
|
||||
key, the key is still hold. To release all hold virtual buttons, just use
|
||||
the left mouse button again. A single release of a hold virtual key isn't
|
||||
possible.</p>
|
||||
The easiest way to use the emulated calculator is by using the mouse. The
|
||||
KML script defines buttons with an area where mouse clicks take effect.
|
||||
The active area is indicated by changing the cursor from an arrow to a
|
||||
hand cursor. Pressing the left mouse button over an active area will
|
||||
press the virtual button. When the mouse cursor leaves the virtual key
|
||||
area with still the left mouse button pressed, the virtual button is
|
||||
automatically released. The visual aspect of a pressed or released
|
||||
virtual button is defined in the KML script. In some cases you need to
|
||||
press more than one key on the emulator. For these cases press the
|
||||
virtual key with the right mouse button. When you release the mouse
|
||||
button or leave the area of the virtual key, the key is still held.
|
||||
To release all held virtual buttons, just use the left mouse button
|
||||
again. A single release of a hold virtual key isn't possible.</p>
|
||||
<p><a name=keyboard></a>
|
||||
Another convenient way is using the PC keyboard. The KML script language
|
||||
support a large variety of commands to implement this feature. So keyboard
|
||||
usage depends on your used KML script and not on the emulator. Because of
|
||||
this it's impossible to say what's happen when you press a key on the PC
|
||||
keyboard. For further details read the KML 2.0 documentation mentioned
|
||||
before please.</p>
|
||||
supports a large variety of commands to implement this feature. So
|
||||
keyboard usage mostly depends on your used KML script and not on the
|
||||
emulator. Because of this it's impossible to say what's happen when you
|
||||
press a key on the PC keyboard. Some Windows specific accelerator keys
|
||||
like F10 cannot be overloaded by the KML script. For further details
|
||||
read the KML 2.0 documentation mentioned before please.</p>
|
||||
<h1><a name=s8>8. File Menu</a></h1>
|
||||
<h2><a name=ss8.1>8.1 New...</a></h2>
|
||||
<p>Creates a new emulation session. You're asked for a new KML script
|
||||
where you can select the calculator type and skin to emulate.</p>
|
||||
<p>Creates a new emulation session. You're asked for a KML script where
|
||||
you can select the calculator type and skin to emulate.</p>
|
||||
<h2><a name=ss8.2>8.2 Open...</a></h2>
|
||||
<p>Opens an existing emulation session. The emulation continues at the
|
||||
same position where the loaded session was aborted. Loading emulation
|
||||
<p>Opens a previously saved emulation session. The emulation continues
|
||||
at the same position where the session was aborted. Loading emulation
|
||||
sessions made with a different ROM revision may <u>destroy</u> the memory
|
||||
content or may cause other unpredictable results.</p>
|
||||
<h2><a name=ss8.3>8.3 Save</a></h2>
|
||||
<p>Saves the current running session with the actual name.</p>
|
||||
<p>Saves the current session with the actual name.</p>
|
||||
<h2><a name=ss8.4>8.4 Save As...</a></h2>
|
||||
<p>Saves the current running session with a new name. You're also get in
|
||||
this dialog when you Exit a new session without a state file name.</p>
|
||||
<p>Saves the current session with a new name. You're also get this
|
||||
dialog when you Exit a new session without a state file name.</p>
|
||||
<h2><a name=ss8.5>8.5 Close</a></h2>
|
||||
<p>Closes the current session without closing the emulator.</p>
|
||||
<h2><a name=ss8.6>8.6 Settings</a></h2>
|
||||
|
@ -294,10 +303,10 @@ h3 { color:red; font-size:1.1em; }
|
|||
mouse is moved over the emulator window, the emulator is getting the
|
||||
focus and popping up into foreground.</p></li>
|
||||
<li><i>Single Instance</i>
|
||||
<p>When this option is checked, the program is only allowed to run in
|
||||
a single instance. If another running instance is detected, the detected
|
||||
<p>When this option is checked, only one instance of the emulator can
|
||||
be started. If another running instance is detected, the detected
|
||||
instance is set into foreground as active window and get a request to
|
||||
change his state file to the given one by the current instance. Finally
|
||||
change his state file to the given one by the current instance. Then
|
||||
the current instance is terminated.</p></li>
|
||||
<li><i>Automatically Save Files</i>
|
||||
<p>When this option is checked, the current state file will automatically
|
||||
|
@ -305,14 +314,15 @@ h3 { color:red; font-size:1.1em; }
|
|||
emulator program.</p></li>
|
||||
<li><i>Automatically Save Files On Exit</i>
|
||||
<p>When this option is checked, the current state file will be saved
|
||||
automatically at the end when the emulator program is closed.</p></li>
|
||||
automatically when the emulator program is closed.</p></li>
|
||||
<li><i>Show Load Object Warning</i>
|
||||
<p>When this option is checked, you'll get a warning message box when you
|
||||
try to load an object with the <i>Load Object...</i> menu command. If
|
||||
this option is unchecked, the warning will be skipped.</p></li>
|
||||
<li><i>Always Show KML Compilation Result</i>
|
||||
<p>When this option is checked, you see the results of the KML
|
||||
(Keyboard Macro Language) interpreter at every KML script load.</p></li>
|
||||
(Keyboard Mapping Language) interpreter at every KML script load.
|
||||
</p></li>
|
||||
</ul>
|
||||
<h4>8.6.1.2 Section Style</h4>
|
||||
<ul>
|
||||
|
@ -385,21 +395,24 @@ h3 { color:red; font-size:1.1em; }
|
|||
</ul>
|
||||
<h3><a name=ss8.6.3>8.6.3 Settings Peripheral</a></h3>
|
||||
<h4>8.6.3.1 Section Sound</h4>
|
||||
<p>A new implementation of the sound engine made ROM patches for sound
|
||||
output obsolete. The new sound engine emulates the behavior of the beeper
|
||||
output ports and only work in connection with a sound card. Using the
|
||||
internal PC speaker isn't possible any more. The old beeper method with a
|
||||
ROM patch is still working but deprecated, it's strongly recommended to
|
||||
remove all beep patches from your current KML scripts to enable the new
|
||||
sound engine. The support of the old sound implementation by a ROM patch
|
||||
maybe removed in later versions of the emulator and remaining beep
|
||||
patches will corrupt the ROM with an illegal opcode then.
|
||||
<p>A new implementation of the sound engine made ROM patches for sound
|
||||
output obsolete. The new sound engine emulates the behaviour of the
|
||||
beeper output ports and only work in connection with a sound card.
|
||||
Using the legacy PC speaker mode isn't possible any more. The old
|
||||
beeper method with a ROM patch is still working but deprecated, it's
|
||||
strongly recommended to remove all beep patches from your current KML
|
||||
scripts to enable the new sound engine. The support of the old sound
|
||||
implementation by a ROM patch maybe removed in later versions of the
|
||||
emulator and remaining beep patches will corrupt the ROM with an
|
||||
illegal opcode then. Actually the program informs you when
|
||||
detecting ROM beep patches by opening the "KML Script Compilation
|
||||
Result" dialog. To prevent this, remove the ROM beep patches
|
||||
from the KML script.
|
||||
</p>
|
||||
<p>
|
||||
For the sound generation the calculator must know his own CPU strobe
|
||||
<p>For the sound generation the calculator must know his own CPU strobe
|
||||
frequency. On the real calculator the speed depends on various settings
|
||||
like component tolerances, actual temperature, humidity and other
|
||||
variables. The resulting speed is measured by the calculator firmware
|
||||
variables. The actual speed is measured by the calculator firmware
|
||||
at a cold- or at a warmstart and stored in the =CSPEED variable. The
|
||||
content of this calculator variable has direct influence on the
|
||||
resulting frequency and duration. On the emulator the HP48SX CPU
|
||||
|
@ -414,27 +427,24 @@ h3 { color:red; font-size:1.1em; }
|
|||
frequency registry content has been changed since the last
|
||||
measurement, the =CSPEED variable of this session file may contain
|
||||
a wrong frequency value. You easily may discover this by measuring
|
||||
the real duration of a 10s beep. Is the difference to 10s less
|
||||
than 1s everything is ok, if not, you should perform a
|
||||
<u style="color:red">warmstart</u> of the calculator in this
|
||||
session file. Alternatively you may execute a
|
||||
<a href=#ss9.6>Reset Calculator</a>. This recalls the measuring
|
||||
routine and save the result in the speed variable. Both restart
|
||||
variants purge the stack content!
|
||||
the real duration of a 10s beep. A deviance less than 1s is ok,
|
||||
otherwise you should perform a <u style="color:red">warmstart</u>
|
||||
of the calculator in this session file. Alternatively you may
|
||||
execute a <a href=#ss9.6>Reset Calculator</a>. This recalls the
|
||||
measuring routine and save the result in the speed variable. Both
|
||||
restart variants purge the stack content!
|
||||
</p>
|
||||
<ul>
|
||||
<li><i>Volume</i>
|
||||
<p>The output volume can be selected with the Volume slider relative to
|
||||
the Master Volume control.
|
||||
<p>The output volume can be set with the Volume slider relative to
|
||||
the Windows Master Volume control.
|
||||
</p></li>
|
||||
<li><i>Device</i>
|
||||
<p>By default the sound device is set to "Standard Audio", but
|
||||
you can also manually choose the output device. The device name is
|
||||
somehow cut since Window Vista, but the method of reading the device
|
||||
name is used for backwards compatibility to older versions of the
|
||||
Operating System. When you change the Standard Audio device in the
|
||||
Operating System settings dialog, the internal device numbering may
|
||||
change, and so the manually selected audio device.</p></li>
|
||||
<p>By default the sound device is set to "Standard Audio",
|
||||
but you can also manually choose the output device. When you change
|
||||
the Standard Audio device in the Operating System settings dialog,
|
||||
the internal device numbering may change, and so the manually selected
|
||||
audio device.</p></li>
|
||||
</ul>
|
||||
<h4>8.6.3.2 Section Infrared Printer</h4>
|
||||
<p>The emulator has the ability to print data to a HP82240A/B printer
|
||||
|
@ -475,34 +485,34 @@ h3 { color:red; font-size:1.1em; }
|
|||
<h2><a name=ss9.3>9.3 Copy Screen</a></h2>
|
||||
<p>Copy the screen content as bitmap to the clipboard.</p>
|
||||
<h2><a name=ss9.4>9.4 Copy Stack</a></h2>
|
||||
<p>This is only valid for the HP48SX, HP48GX and the HP49G emulation.</p>
|
||||
<p>This menu item is enabled for the HP48SX, HP48GX and the HP49G
|
||||
emulation.</p>
|
||||
<p>Copy a "Real Number", "Complex Number" or
|
||||
"String" object in stack level 1 to the clipboard. On all
|
||||
other objects, the command will be ignored. This prevents sending
|
||||
binary objects to the clipboard.</p>
|
||||
<p>The decimal point (radix mark) of "Real Numbers" in the
|
||||
clipboard is equal to the calculator setting. This point maybe
|
||||
important when you try to paste the numbers into a program using the
|
||||
locale settings of the host operating system.</p>
|
||||
clipboard is equal to the calculator setting. This is important when
|
||||
you try to paste the numbers into a program using the locale settings
|
||||
of the host operating system.</p>
|
||||
<h2><a name=ss9.5>9.5 Paste Stack</a></h2>
|
||||
<p>This is only valid for the HP48SX, HP48GX and the HP49G emulation.</p>
|
||||
<p>This menu item is enabled for the HP48SX, HP48GX and the HP49G
|
||||
emulation.</p>
|
||||
<p>Paste the text field content of the clipboard to stack level 1 of
|
||||
the emulated calculator. If the clipboard content is representing a
|
||||
real number, the number will be saved as "Real Number"
|
||||
object. Is the content a complex number object, the number will be
|
||||
saved as "Complex Number" object, in all other cases as
|
||||
saved as "Complex Number" object, otherwise cases as
|
||||
"String" object.</p>
|
||||
<p>To import "Real or Complex Numbers" from the clipboard,
|
||||
the decimal point (radix mark) of the clipboard and calculator
|
||||
<u>must</u> be equal. A real or complex number is only detected in the
|
||||
case of valid real number characters in the clipboard. Especially
|
||||
heading and tailing white spaces aren't valid number characters
|
||||
also.</p>
|
||||
<p>Complex numbers must be in the form <i>(a,b)</i> when using the
|
||||
point radix mark or in the form <i>(a;b)</i> when using the comma
|
||||
radix mark. The Cartesian or algebraic form <i>a+bi</i> is not
|
||||
supported.</p>
|
||||
<h2><a name=ss9.6>9.6 Reset Calculator</a></h2>
|
||||
<p>To import "Real or Complex Numbers" from the clipboard, the
|
||||
decimal point (radix mark) of the clipboard and calculator <u>must</u>
|
||||
match. A real or complex number is only detected in the case of valid
|
||||
real number characters in the clipboard. Especially heading and tailing
|
||||
white spaces aren't valid number characters also.</p>
|
||||
<p>Complex numbers must be in the form <i>(a,b)</i> when using the point
|
||||
radix mark or in the form <i>(a;b)</i> when using the comma radix mark.
|
||||
The Cartesian or algebraic form <i>a+bi</i> is not supported.</p>
|
||||
<h2><a name=ss9.6>9.6 Reset Calculator</a></h2>
|
||||
<p>This emulates the Reset pin of the internal CPU.</p>
|
||||
<h2><a name=ss9.7>9.7 Backup</a></h2>
|
||||
<h3><a name=ss9.7.1>9.7.1 Backup Save</a></h3>
|
||||
|
@ -511,7 +521,7 @@ h3 { color:red; font-size:1.1em; }
|
|||
<h3><a name=ss9.7.2>9.7.2 Backup Restore</a></h3>
|
||||
<p>This restores a previous saved emulator status without request. If you
|
||||
changed the calculator model meanwhile, the emulator will switch back to
|
||||
the old model.</p>
|
||||
the model used in the backup.</p>
|
||||
<h3><a name=ss9.7.3>9.7.3 Backup Delete</a></h3>
|
||||
<p>This deletes the data in the backup slot.</p>
|
||||
<h1><a name=s10>10. View Menu</a></h1>
|
||||
|
@ -525,22 +535,22 @@ h3 { color:red; font-size:1.1em; }
|
|||
<p>Enter the address to disassemble in hexadecimal into the "Address
|
||||
(HEX)" field and press <Return>. With the "Next Address"
|
||||
button the next opcode is disassembled. With the "Copy Data" button
|
||||
you can copy all selected lines inside the list box to the clipboard.</p>
|
||||
you can copy all selected lines from the list box to the clipboard.</p>
|
||||
<h2><a name=ss11.2>11.2 Debugger...</a></h2>
|
||||
<p>The assembler code debugger of the emulator. For more details refer to the
|
||||
extra documentation of the debugger please.</p>
|
||||
<h2><a name=ss11.3>11.3 Macro</a></h2>
|
||||
<p>The keyboard macro recorder unit.</p>
|
||||
<h3><a name=ss11.3.1>11.3.1 Macro Record...</a></h3>
|
||||
<h3><a name=ss11.3.1>11.3.1 Macro Record...</a></h3>
|
||||
<p>Prompts a dialog to enter the macro file for the data to record. After
|
||||
accepting the confirm message, every key event is recorded into the macro
|
||||
file with it's time information.</p>
|
||||
<h3><a name=ss11.3.2>11.3.2 Macro Play...</a></h3>
|
||||
<h3><a name=ss11.3.2>11.3.2 Macro Play...</a></h3>
|
||||
<p>Prompts a dialog box to ask for the keyboard macro file to play. The
|
||||
replay starts immediately after selecting the file.</p>
|
||||
<h3><a name=ss11.3.3>11.3.3 Macro Stop</a></h3>
|
||||
replay starts immediately after opening the selected file.</p>
|
||||
<h3><a name=ss11.3.3>11.3.3 Macro Stop</a></h3>
|
||||
<p>Stops recording or replaying a keyboard macro file.</p>
|
||||
<h3><a name=ss11.3.4>11.3.4 Macro Settings...</a></h3>
|
||||
<h3><a name=ss11.3.4>11.3.4 Macro Settings...</a></h3>
|
||||
<p>Settings for the Macro Replay mode</p>
|
||||
<ul>
|
||||
<li><i>Real</i>
|
||||
|
@ -550,9 +560,9 @@ h3 { color:red; font-size:1.1em; }
|
|||
</ul>
|
||||
<h1><a name=s12>12. Help Menu</a></h1>
|
||||
<h2><a name=ss12.1>12.1 Help Topics</a></h2>
|
||||
<p>Call this document.</p>
|
||||
<p>Show this document.</p>
|
||||
<h2><a name=ss12.2>12.2 About Emu48...</a></h2>
|
||||
<p>The version, copyright and license message...</p>
|
||||
<p>Show the version, copyright and license message...</p>
|
||||
<h1><a name=s13>13. DDE Server</a></h1>
|
||||
<p>Emu48 has an integrated DDE server to transmit data from and to the HP
|
||||
stack. Because only the HP48 and HP49 have a stack, all DDE transfers
|
||||
|
@ -591,7 +601,7 @@ h3 { color:red; font-size:1.1em; }
|
|||
</table>
|
||||
<h1><a name=s14>14. License</a></h1>
|
||||
<p>Emu48 - A HP38G/39G/40G/48SX/48GX/49G Emulator<br>
|
||||
Copyright (C) 2018 Christoph Gießelink</p>
|
||||
Copyright (C) 2019 Christoph Gießelink</p>
|
||||
<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
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
BIN
Emu48.dll
BIN
Emu48.dll
Binary file not shown.
BIN
Emu48.exe
BIN
Emu48.exe
Binary file not shown.
|
@ -1,4 +1,4 @@
|
|||
Known bugs and restrictions of Emu48 V1.61
|
||||
Known bugs and restrictions of Emu48 V1.62
|
||||
------------------------------------------
|
||||
|
||||
- the following I/O bits aren't emulated (incomplete)
|
||||
|
@ -47,4 +47,4 @@ Known bugs and restrictions of Emu48 V1.61
|
|||
- quitting the emulator while programming the flash isn't allowed,
|
||||
because the content of flash state machine isn't saved so far
|
||||
|
||||
08/14/18 (c) by Christoph Gießelink, c dot giesselink at gmx dot de
|
||||
10/15/19 (c) by Christoph Gießelink, c dot giesselink at gmx dot de
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
Service Pack 59+ based on Emu48 Service Pack 61
|
||||
Service Pack 61+ based on Emu48 Service Pack 62
|
||||
|
||||
See CHANGES.TXT in Emu48 for full history.
|
||||
Only changes specifically made to Emu48+ are shown below.
|
||||
|
||||
Service Pack 60+ for Emu48 Version 1.0
|
||||
|
||||
DISPLAY.C
|
||||
- bugfix in function WriteToMainDisplay() to fix display corruption
|
||||
|
||||
Service Pack 55+ for Emu48 Version 1.0
|
||||
|
||||
DEBUGDLL.C
|
||||
|
@ -42,7 +47,7 @@ MOPS.C
|
|||
bit in the LCR (0x11C) register for apples; the Saturnator has no
|
||||
ELBE bit simulation so the LSRQ bit in SRQ2 register is untouched
|
||||
|
||||
Service Pack 51 for Emu48 Version 1.0
|
||||
Service Pack 51+ for Emu48 Version 1.0
|
||||
|
||||
EMU48DLL.C
|
||||
- bugfix in function DLLCreateWnd(), when starting an emulator
|
||||
|
|
|
@ -35,6 +35,9 @@
|
|||
|
||||
#define CODELABEL 0x80000000 // label in code window
|
||||
|
||||
// trace log file modes
|
||||
enum TRACE_MODE { TRACE_FILE_NEW = 0, TRACE_FILE_APPEND };
|
||||
|
||||
typedef struct CToolBarData
|
||||
{
|
||||
WORD wVersion;
|
||||
|
@ -81,6 +84,14 @@ static DWORD dwAdrMemFol = 0; // follow address memory window
|
|||
|
||||
static UINT uIDMap = ID_DEBUG_MEM_MAP; // current memory view mode
|
||||
|
||||
static BOOL bDbgTrace = FALSE; // enable trace output
|
||||
static HANDLE hLogFile = NULL; // log file handle
|
||||
static TCHAR szTraceFilename[MAX_PATH] = _T("trace.log"); // filename for trace file
|
||||
static UINT uTraceMode = TRACE_FILE_NEW; // trace log file mode
|
||||
static BOOL bTraceReg = TRUE; // enable register logging
|
||||
static BOOL bTraceMmu = FALSE; // disable MMU logging
|
||||
static BOOL bTraceOpc = TRUE; // enable opcode logging
|
||||
|
||||
static LONG lCharWidth; // width of a character (is a fix font)
|
||||
|
||||
static HMENU hMenuCode,hMenuMem,hMenuStack;// handle of context menues
|
||||
|
@ -108,6 +119,12 @@ static BOOL OnInfoWoRegister(HWND hDlg);
|
|||
static VOID UpdateProfileWnd(HWND hDlg);
|
||||
static BOOL OnMemLoadData(HWND hDlg);
|
||||
static BOOL OnMemSaveData(HWND hDlg);
|
||||
static VOID StartTrace(VOID);
|
||||
static VOID StopTrace(VOID);
|
||||
static VOID FlushTrace(VOID);
|
||||
static VOID OutTrace(VOID);
|
||||
static BOOL OnTraceSettings(HWND hDlg);
|
||||
static BOOL OnTraceEnable(HWND hDlg);
|
||||
|
||||
//################
|
||||
//#
|
||||
|
@ -1768,6 +1785,7 @@ BOOL CheckBreakpoint(DWORD dwAddr, DWORD dwRange, UINT nType)
|
|||
VOID NotifyDebugger(INT nType) // update registers
|
||||
{
|
||||
nRplBreak = nType; // save breakpoint type
|
||||
FlushTrace(); // flush trace buffer
|
||||
_ASSERT(hDlgDebug); // debug dialog box open
|
||||
PostMessage(hDlgDebug,WM_UPDATE,0,0);
|
||||
return;
|
||||
|
@ -1861,6 +1879,7 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
HDC hDC;
|
||||
HFONT hFont;
|
||||
HMENU hSysMenu;
|
||||
HMENU hDbgMenu;
|
||||
INT i;
|
||||
|
||||
switch (message)
|
||||
|
@ -1870,6 +1889,15 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
if (bAlwaysOnTop) SetWindowPos(hDlg,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
|
||||
SendMessage(hDlg,WM_SETICON,ICON_BIG,(LPARAM) LoadIcon(hApp,MAKEINTRESOURCE(IDI_EMU48)));
|
||||
|
||||
bDbgTrace = FALSE; // disable file trace
|
||||
|
||||
// load file trace settings
|
||||
ReadSettingsString(_T("Debugger"),_T("TraceFile"),szTraceFilename,szTraceFilename,ARRAYSIZEOF(szTraceFilename));
|
||||
uTraceMode = ReadSettingsInt(_T("Debugger"),_T("TraceFileMode"),uTraceMode);
|
||||
bTraceReg = ReadSettingsInt(_T("Debugger"),_T("TraceRegister"),bTraceReg);
|
||||
bTraceMmu = ReadSettingsInt(_T("Debugger"),_T("TraceMMU"),bTraceMmu);
|
||||
bTraceOpc = ReadSettingsInt(_T("Debugger"),_T("TraceOpcode"),bTraceOpc);
|
||||
|
||||
// add Settings item to sysmenu
|
||||
_ASSERT((IDM_DEBUG_SETTINGS & 0xFFF0) == IDM_DEBUG_SETTINGS);
|
||||
_ASSERT(IDM_DEBUG_SETTINGS < 0xF000);
|
||||
|
@ -1879,11 +1907,17 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
VERIFY(AppendMenu(hSysMenu,MF_STRING,IDM_DEBUG_SETTINGS,_T("Debugger Settings...")));
|
||||
}
|
||||
|
||||
hDbgMenu = GetMenu(hDlg); // menu of debugger dialog
|
||||
hWndToolbar = CreateToolbar(hDlg); // add toolbar
|
||||
CheckMenuItem(GetMenu(hDlg),ID_BREAKPOINTS_NOP3, bDbgNOP3 ? MF_CHECKED : MF_UNCHECKED);
|
||||
CheckMenuItem(GetMenu(hDlg),ID_BREAKPOINTS_DOCODE,bDbgCode ? MF_CHECKED : MF_UNCHECKED);
|
||||
CheckMenuItem(GetMenu(hDlg),ID_BREAKPOINTS_RPL, bDbgRPL ? MF_CHECKED : MF_UNCHECKED);
|
||||
CheckMenuItem(GetMenu(hDlg),ID_INTR_STEPOVERINT, bDbgSkipInt ? MF_CHECKED : MF_UNCHECKED);
|
||||
|
||||
CheckMenuItem(hDbgMenu,ID_BREAKPOINTS_NOP3, bDbgNOP3 ? MF_CHECKED : MF_UNCHECKED);
|
||||
CheckMenuItem(hDbgMenu,ID_BREAKPOINTS_DOCODE,bDbgCode ? MF_CHECKED : MF_UNCHECKED);
|
||||
CheckMenuItem(hDbgMenu,ID_BREAKPOINTS_RPL, bDbgRPL ? MF_CHECKED : MF_UNCHECKED);
|
||||
CheckMenuItem(hDbgMenu,ID_INTR_STEPOVERINT, bDbgSkipInt ? MF_CHECKED : MF_UNCHECKED);
|
||||
CheckMenuItem(hDbgMenu,ID_TRACE_ENABLE, bDbgTrace ? MF_CHECKED : MF_UNCHECKED);
|
||||
|
||||
EnableMenuItem(hDbgMenu,ID_TRACE_SETTINGS,bDbgTrace ? MF_GRAYED : MF_ENABLED);
|
||||
|
||||
hDlgDebug = hDlg; // handle for debugger dialog
|
||||
hEventDebug = CreateEvent(NULL,FALSE,FALSE,NULL);
|
||||
if (hEventDebug == NULL)
|
||||
|
@ -1931,6 +1965,7 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
InitBsArea(hDlg); // init bank switcher list box
|
||||
DisableMenuKeys(hDlg); // set debug menu keys into run state
|
||||
|
||||
fnOutTrace = OutTrace; // function for file trace
|
||||
RplReadNibble = GetMemNib; // get nibble function for RPL object viewer
|
||||
|
||||
dwDbgStopPC = -1; // no stop address for goto cursor
|
||||
|
@ -1949,6 +1984,7 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
case WM_DESTROY:
|
||||
// SetHP48Time(); // update time & date
|
||||
nDbgState = DBG_OFF; // debugger inactive
|
||||
StopTrace(); // finish trace
|
||||
bInterrupt = TRUE; // exit opcode loop
|
||||
SetEvent(hEventDebug);
|
||||
if (pdwInstrArray) // free last instruction circular buffer
|
||||
|
@ -1965,6 +2001,14 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
GetWindowPlacement(hDlg, &wndpl);
|
||||
nDbgPosX = wndpl.rcNormalPosition.left;
|
||||
nDbgPosY = wndpl.rcNormalPosition.top;
|
||||
|
||||
// save file trace settings
|
||||
WriteSettingsString(_T("Debugger"),_T("TraceFile"),szTraceFilename);
|
||||
WriteSettingsInt(_T("Debugger"),_T("TraceFileMode"),uTraceMode);
|
||||
WriteSettingsInt(_T("Debugger"),_T("TraceRegister"),bTraceReg);
|
||||
WriteSettingsInt(_T("Debugger"),_T("TraceMMU"),bTraceMmu);
|
||||
WriteSettingsInt(_T("Debugger"),_T("TraceOpcode"),bTraceOpc);
|
||||
|
||||
RplDeleteTable(); // delete rpl symbol table
|
||||
DeleteObject(hFontBold); // delete bold font
|
||||
DestroyMenu(hMenuMainCode);
|
||||
|
@ -2023,6 +2067,8 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
case ID_BREAKPOINTS_NOP3: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgNOP3);
|
||||
case ID_BREAKPOINTS_DOCODE: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgCode);
|
||||
case ID_BREAKPOINTS_RPL: return OnToggleMenuItem(hDlg,LOWORD(wParam),&bDbgRPL);
|
||||
case ID_TRACE_SETTINGS: return OnTraceSettings(hDlg);
|
||||
case ID_TRACE_ENABLE: return OnTraceEnable(hDlg);
|
||||
case ID_INFO_LASTINSTRUCTIONS: return OnInfoIntr(hDlg);
|
||||
case ID_INFO_PROFILE: return OnProfile(hDlg);
|
||||
case ID_INFO_WRITEONLYREG: return OnInfoWoRegister(hDlg);
|
||||
|
@ -2199,7 +2245,7 @@ static __inline BOOL OnFindOK(HWND hDlg,BOOL bASCII,DWORD *pdwAddrLast,INT nSear
|
|||
#if defined _UNICODE
|
||||
{
|
||||
// Unicode to byte translation
|
||||
LPTSTR szTmp = DuplicateString((LPTSTR) lpbySearch);
|
||||
LPTSTR szTmp = DuplicateString((LPCTSTR) lpbySearch);
|
||||
if (szTmp != NULL)
|
||||
{
|
||||
WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK,
|
||||
|
@ -2719,7 +2765,6 @@ static INT_PTR CALLBACK Settings(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
}
|
||||
}
|
||||
return FALSE;
|
||||
UNREFERENCED_PARAMETER(wParam);
|
||||
UNREFERENCED_PARAMETER(lParam);
|
||||
}
|
||||
|
||||
|
@ -2783,7 +2828,6 @@ static INT_PTR CALLBACK NewValue(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
}
|
||||
}
|
||||
return FALSE;
|
||||
UNREFERENCED_PARAMETER(wParam);
|
||||
}
|
||||
|
||||
static INT_PTR OnNewValue(LPTSTR lpszValue)
|
||||
|
@ -2835,7 +2879,6 @@ static INT_PTR CALLBACK EnterAddr(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
}
|
||||
}
|
||||
return FALSE;
|
||||
UNREFERENCED_PARAMETER(wParam);
|
||||
}
|
||||
|
||||
static VOID OnEnterAddress(HWND hDlg, DWORD *dwValue)
|
||||
|
@ -2888,7 +2931,6 @@ static INT_PTR CALLBACK EnterBreakpoint(HWND hDlg, UINT message, WPARAM wParam,
|
|||
}
|
||||
}
|
||||
return FALSE;
|
||||
UNREFERENCED_PARAMETER(wParam);
|
||||
}
|
||||
|
||||
static VOID OnEnterBreakpoint(HWND hDlg, BP_T *sValue)
|
||||
|
@ -3183,7 +3225,6 @@ static INT_PTR CALLBACK EditBreakpoint(HWND hDlg, UINT message, WPARAM wParam, L
|
|||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
UNREFERENCED_PARAMETER(wParam);
|
||||
UNREFERENCED_PARAMETER(lParam);
|
||||
}
|
||||
|
||||
|
@ -3569,7 +3610,6 @@ static INT_PTR CALLBACK DebugMemLoad(HWND hDlg, UINT message, WPARAM wParam, LPA
|
|||
}
|
||||
}
|
||||
return FALSE;
|
||||
UNREFERENCED_PARAMETER(wParam);
|
||||
UNREFERENCED_PARAMETER(lParam);
|
||||
}
|
||||
|
||||
|
@ -3577,7 +3617,6 @@ static BOOL OnMemLoadData(HWND hDlg)
|
|||
{
|
||||
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_MEMLOAD), hDlg, (DLGPROC)DebugMemLoad) == -1)
|
||||
AbortMessage(_T("DebugLoad Dialog Box Creation Error !"));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -3625,7 +3664,6 @@ static INT_PTR CALLBACK DebugMemSave(HWND hDlg, UINT message, WPARAM wParam, LPA
|
|||
}
|
||||
}
|
||||
return FALSE;
|
||||
UNREFERENCED_PARAMETER(wParam);
|
||||
UNREFERENCED_PARAMETER(lParam);
|
||||
}
|
||||
|
||||
|
@ -3633,6 +3671,337 @@ static BOOL OnMemSaveData(HWND hDlg)
|
|||
{
|
||||
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_DEBUG_MEMSAVE), hDlg, (DLGPROC)DebugMemSave) == -1)
|
||||
AbortMessage(_T("DebugSave Dialog Box Creation Error !"));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//################
|
||||
//#
|
||||
//# Trace Log
|
||||
//#
|
||||
//################
|
||||
|
||||
static VOID StartTrace(VOID)
|
||||
{
|
||||
if (hLogFile == NULL)
|
||||
{
|
||||
SetCurrentDirectory(szEmuDirectory);
|
||||
hLogFile = CreateFile(
|
||||
szTraceFilename,
|
||||
GENERIC_READ|GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
(uTraceMode == TRACE_FILE_NEW) ? CREATE_ALWAYS : OPEN_ALWAYS,
|
||||
0,
|
||||
NULL);
|
||||
SetCurrentDirectory(szCurrentDirectory);
|
||||
if (hLogFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
InfoMessage(_T("Unable to create trace log file."));
|
||||
hLogFile = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// goto end of file
|
||||
SetFilePointer(hLogFile,0L,NULL,FILE_END);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static VOID StopTrace(VOID)
|
||||
{
|
||||
if (hLogFile != NULL)
|
||||
{
|
||||
CloseHandle(hLogFile);
|
||||
}
|
||||
hLogFile = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
static VOID FlushTrace(VOID)
|
||||
{
|
||||
if (hLogFile != NULL)
|
||||
{
|
||||
VERIFY(FlushFileBuffers(hLogFile));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static __inline void __cdecl PrintTrace(LPCTSTR lpFormat, ...)
|
||||
{
|
||||
TCHAR cOutput[1024];
|
||||
DWORD dwWritten, dwRead;
|
||||
va_list arglist;
|
||||
|
||||
va_start(arglist,lpFormat);
|
||||
dwWritten = (DWORD) wvsprintf(cOutput,lpFormat,arglist);
|
||||
va_end(arglist);
|
||||
#if defined _UNICODE
|
||||
{
|
||||
// Unicode to byte translation
|
||||
LPTSTR szTmp = DuplicateString(cOutput);
|
||||
if (szTmp != NULL)
|
||||
{
|
||||
WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK,
|
||||
szTmp, -1,
|
||||
(LPSTR) cOutput, sizeof(cOutput), NULL, NULL);
|
||||
free(szTmp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
WriteFile(hLogFile,cOutput,dwWritten,&dwRead,NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
static VOID OutTrace(VOID)
|
||||
{
|
||||
enum MEM_MAPPING eMapMode;
|
||||
LPCTSTR lpszName;
|
||||
LPTSTR s,d;
|
||||
TCHAR szBuffer[128];
|
||||
TCHAR szOpc[8];
|
||||
DWORD dwNxtAddr,dwOpcAddr;
|
||||
UINT i;
|
||||
|
||||
if (hLogFile != NULL) // log file opened
|
||||
{
|
||||
if (bTraceReg) // show regs
|
||||
{
|
||||
INT nPos;
|
||||
|
||||
nPos = wsprintf(szBuffer,_T("\r\n A=%s"),RegToStr(Chipset.A,16));
|
||||
nPos += wsprintf(&szBuffer[nPos],_T(" B=%s"),RegToStr(Chipset.B,16));
|
||||
nPos += wsprintf(&szBuffer[nPos],_T(" C=%s"),RegToStr(Chipset.C,16));
|
||||
wsprintf(&szBuffer[nPos],_T(" D=%s\r\n"),RegToStr(Chipset.D,16));
|
||||
PrintTrace(szBuffer);
|
||||
|
||||
nPos = wsprintf(szBuffer,_T(" R0=%s"),RegToStr(Chipset.R0,16));
|
||||
nPos += wsprintf(&szBuffer[nPos],_T(" R1=%s"),RegToStr(Chipset.R1,16));
|
||||
nPos += wsprintf(&szBuffer[nPos],_T(" R2=%s"),RegToStr(Chipset.R2,16));
|
||||
wsprintf(&szBuffer[nPos],_T(" R3=%s\r\n"),RegToStr(Chipset.R3,16));
|
||||
PrintTrace(szBuffer);
|
||||
|
||||
PrintTrace(_T(" R4=%s D0=%05X D1=%05X P=%X CY=%d Mode=%c OUT=%03X IN=%04X\r\n"),
|
||||
RegToStr(Chipset.R4,16),Chipset.d0,Chipset.d1,Chipset.P,Chipset.carry,
|
||||
Chipset.mode_dec ? _T('D') : _T('H'),Chipset.out,Chipset.in);
|
||||
|
||||
PrintTrace(_T(" ST=%s MP=%d SR=%d SB=%d XM=%d IntrEn=%d KeyScan=%d BS=%02X\r\n"),
|
||||
RegToStr(Chipset.ST,4),
|
||||
(Chipset.HST & MP) != 0,(Chipset.HST & SR) != 0,(Chipset.HST & SB) != 0,(Chipset.HST & XM) != 0,
|
||||
Chipset.inte,Chipset.intk,Chipset.Bank_FF & 0x7F);
|
||||
|
||||
// hardware stack content
|
||||
PrintTrace(_T(" Stack="));
|
||||
for (i = 1; i <= ARRAYSIZEOF(Chipset.rstk); ++i)
|
||||
{
|
||||
PrintTrace(_T(" %05X"), Chipset.rstk[(Chipset.rstkp-i)&7]);
|
||||
}
|
||||
PrintTrace(_T("\r\n"));
|
||||
}
|
||||
|
||||
if (bTraceMmu) // show MMU
|
||||
{
|
||||
TCHAR szSize[8],szAddr[8];
|
||||
|
||||
if (!bTraceReg) // no regs
|
||||
{
|
||||
PrintTrace(_T("\r\n")); // add separator line
|
||||
}
|
||||
|
||||
wsprintf(szAddr, Chipset.IOCfig ? _T("%05X") : _T("-----"),Chipset.IOBase);
|
||||
PrintTrace(_T(" I/O=%s"),szAddr);
|
||||
|
||||
wsprintf(szSize, Chipset.P0Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P0Size^0xFF)<<12);
|
||||
wsprintf(szAddr, Chipset.P0Cfig ? _T("%05X") : _T("-----"),Chipset.P0Base<<12);
|
||||
PrintTrace(_T(" NCE2=%s/%s"),szSize,szAddr);
|
||||
|
||||
if (cCurrentRomType=='S')
|
||||
{
|
||||
wsprintf(szSize, Chipset.P1Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P1Size^0xFF)<<12);
|
||||
wsprintf(szAddr, Chipset.P1Cfig ? _T("%05X") : _T("-----"),Chipset.P1Base<<12);
|
||||
}
|
||||
else
|
||||
{
|
||||
wsprintf(szSize, Chipset.BSCfg2 ? _T("%05X") : _T("-----"),(Chipset.BSSize^0xFF)<<12);
|
||||
wsprintf(szAddr, Chipset.BSCfig ? _T("%05X") : _T("-----"),Chipset.BSBase<<12);
|
||||
}
|
||||
PrintTrace(_T(" CE1=%s/%s"),szSize,szAddr);
|
||||
|
||||
if (cCurrentRomType=='S')
|
||||
{
|
||||
wsprintf(szSize, Chipset.P2Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P2Size^0xFF)<<12);
|
||||
wsprintf(szAddr, Chipset.P2Cfig ? _T("%05X") : _T("-----"),Chipset.P2Base<<12);
|
||||
}
|
||||
else
|
||||
{
|
||||
wsprintf(szSize, Chipset.P1Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P1Size^0xFF)<<12);
|
||||
wsprintf(szAddr, Chipset.P1Cfig ? _T("%05X") : _T("-----"),Chipset.P1Base<<12);
|
||||
}
|
||||
PrintTrace(_T(" CE2=%s/%s"),szSize,szAddr);
|
||||
|
||||
if (cCurrentRomType=='S')
|
||||
{
|
||||
wsprintf(szSize, Chipset.BSCfg2 ? _T("%05X") : _T("-----"),(Chipset.BSSize^0xFF)<<12);
|
||||
wsprintf(szAddr, Chipset.BSCfig ? _T("%05X") : _T("-----"),Chipset.BSBase<<12);
|
||||
}
|
||||
else
|
||||
{
|
||||
wsprintf(szSize, Chipset.P2Cfg2 ? _T("%05X") : _T("-----"),(Chipset.P2Size^0xFF)<<12);
|
||||
wsprintf(szAddr, Chipset.P2Cfig ? _T("%05X") : _T("-----"),Chipset.P2Base<<12);
|
||||
}
|
||||
PrintTrace(_T(" NCE3=%s/%s\r\n"),szSize,szAddr);
|
||||
}
|
||||
|
||||
// disassemble line
|
||||
eMapMode = GetMemMapType(); // get current map mode
|
||||
SetMemMapType(MEM_MMU); // disassemble in mapped mode
|
||||
|
||||
// entry has a name
|
||||
if (disassembler_symb && (lpszName = RplGetName(Chipset.pc)) != NULL)
|
||||
{
|
||||
PrintTrace(_T("=%s\r\n"),lpszName); // print address as label
|
||||
}
|
||||
dwNxtAddr = disassemble(Chipset.pc,szBuffer);
|
||||
|
||||
// in disassembly replace space characters
|
||||
// between Opcode and Modifier with one TAB
|
||||
if ((s = _tcschr(szBuffer,_T(' '))) != NULL)
|
||||
{
|
||||
// skip blanks
|
||||
for (d = s; *d == _T(' '); ++d) { }
|
||||
|
||||
if (d == &szBuffer[8]) // on TAB position
|
||||
{
|
||||
*s++ = _T('\t'); // replace with TAB
|
||||
|
||||
// move the opcode modifier
|
||||
while ((*s++ = *d++) != 0) { }
|
||||
}
|
||||
}
|
||||
|
||||
if (bTraceOpc) // show opcode nibbles
|
||||
{
|
||||
dwOpcAddr = Chipset.pc; // init address
|
||||
|
||||
// show opcode nibbles in a block of 5
|
||||
for (i = 0; i < 5 && dwOpcAddr < dwNxtAddr; ++i)
|
||||
{
|
||||
szOpc[i] = cHex[GetMemNib(&dwOpcAddr)];
|
||||
}
|
||||
|
||||
if (i == 1) // only 1 nibble written
|
||||
{
|
||||
szOpc[i++] = _T('\t'); // one additional TAB necessary
|
||||
}
|
||||
szOpc[i] = 0; // EOS
|
||||
|
||||
PrintTrace(_T("%05lX %s\t%s\r\n"),Chipset.pc,szOpc,szBuffer);
|
||||
|
||||
while (dwOpcAddr < dwNxtAddr) // decode rest of opcode
|
||||
{
|
||||
// show opcode nibbles in a block of 5
|
||||
for (i = 0; i < 5 && dwOpcAddr < dwNxtAddr; ++i)
|
||||
{
|
||||
szOpc[i] = cHex[GetMemNib(&dwOpcAddr)];
|
||||
}
|
||||
szOpc[i] = 0; // EOS
|
||||
|
||||
PrintTrace(_T(" %s\r\n"),szOpc);
|
||||
}
|
||||
}
|
||||
else // without opcode nibbles
|
||||
{
|
||||
PrintTrace(_T("%05lX\t%s\r\n"),Chipset.pc,szBuffer);
|
||||
}
|
||||
|
||||
SetMemMapType(eMapMode); // switch back to old map mode
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// trace settings dialog
|
||||
//
|
||||
static BOOL OnBrowseTraceSettings(HWND hDlg)
|
||||
{
|
||||
TCHAR szBuffer[MAX_PATH];
|
||||
OPENFILENAME ofn;
|
||||
|
||||
// get current content of file edit box
|
||||
GetDlgItemText(hDlg,IDC_TRACE_FILE,szBuffer,ARRAYSIZEOF(szBuffer));
|
||||
|
||||
ZeroMemory(&ofn, sizeof(OPENFILENAME));
|
||||
ofn.lStructSize = sizeof(OPENFILENAME);
|
||||
ofn.hwndOwner = hDlg;
|
||||
ofn.lpstrFilter =
|
||||
_T("Trace Log Files (*.log)\0*.log\0")
|
||||
_T("All Files (*.*)\0*.*\0");
|
||||
ofn.lpstrDefExt = _T("log");
|
||||
ofn.nFilterIndex = 1;
|
||||
ofn.lpstrFile = szBuffer;
|
||||
ofn.nMaxFile = ARRAYSIZEOF(szBuffer);
|
||||
ofn.Flags = OFN_EXPLORER|OFN_HIDEREADONLY|OFN_CREATEPROMPT|OFN_OVERWRITEPROMPT;
|
||||
if (GetSaveFileName(&ofn))
|
||||
{
|
||||
SetDlgItemText(hDlg,IDC_TRACE_FILE,szBuffer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// trace settings
|
||||
//
|
||||
static INT_PTR CALLBACK TraceSettings(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
SetDlgItemText(hDlg,IDC_TRACE_FILE,szTraceFilename);
|
||||
CheckDlgButton(hDlg,(uTraceMode == TRACE_FILE_NEW) ? IDC_TRACE_NEW : IDC_TRACE_APPEND,BST_CHECKED);
|
||||
CheckDlgButton(hDlg,IDC_TRACE_REGISTER,bTraceReg);
|
||||
CheckDlgButton(hDlg,IDC_TRACE_MMU,bTraceMmu);
|
||||
CheckDlgButton(hDlg,IDC_TRACE_OPCODE,bTraceOpc);
|
||||
return TRUE;
|
||||
|
||||
case WM_COMMAND:
|
||||
switch(LOWORD(wParam))
|
||||
{
|
||||
case IDC_TRACE_BROWSE:
|
||||
return OnBrowseTraceSettings(hDlg);
|
||||
|
||||
case IDOK:
|
||||
// get filename
|
||||
GetDlgItemText(hDlg,IDC_TRACE_FILE,szTraceFilename,ARRAYSIZEOF(szTraceFilename));
|
||||
|
||||
// trace mode
|
||||
uTraceMode = IsDlgButtonChecked(hDlg,IDC_TRACE_NEW) ? TRACE_FILE_NEW : TRACE_FILE_APPEND;
|
||||
|
||||
// trace content
|
||||
bTraceReg = IsDlgButtonChecked(hDlg,IDC_TRACE_REGISTER);
|
||||
bTraceMmu = IsDlgButtonChecked(hDlg,IDC_TRACE_MMU);
|
||||
bTraceOpc = IsDlgButtonChecked(hDlg,IDC_TRACE_OPCODE);
|
||||
|
||||
// no break
|
||||
case IDCANCEL:
|
||||
EndDialog(hDlg,LOWORD(wParam));
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
UNREFERENCED_PARAMETER(lParam);
|
||||
}
|
||||
|
||||
static BOOL OnTraceSettings(HWND hDlg)
|
||||
{
|
||||
if (DialogBox(hApp, MAKEINTRESOURCE(IDD_TRACE), hDlg, (DLGPROC)TraceSettings) == -1)
|
||||
AbortMessage(_T("TraceSettings Dialog Box Creation Error !"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static BOOL OnTraceEnable(HWND hDlg)
|
||||
{
|
||||
OnToggleMenuItem(hDlg,ID_TRACE_ENABLE,&bDbgTrace);
|
||||
bDbgTrace ? StartTrace() : StopTrace();
|
||||
EnableMenuItem(GetMenu(hDlg),ID_TRACE_SETTINGS,bDbgTrace ? MF_GRAYED : MF_ENABLED);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -214,7 +214,7 @@ BOOL CreateMainBitmap(LPCTSTR szFilename)
|
|||
_ASSERT(hWindowDC != NULL);
|
||||
VERIFY(hMainDC = CreateCompatibleDC(hWindowDC));
|
||||
if (hMainDC == NULL) return FALSE; // quit if failed
|
||||
hMainBitmap = LoadBitmapFile(szFilename);
|
||||
hMainBitmap = LoadBitmapFile(szFilename,TRUE);
|
||||
if (hMainBitmap == NULL)
|
||||
{
|
||||
DeleteDC(hMainDC);
|
||||
|
@ -249,7 +249,7 @@ BOOL CreateAnnunBitmap(LPCTSTR szFilename)
|
|||
_ASSERT(hWindowDC != NULL);
|
||||
VERIFY(hAnnunDC = CreateCompatibleDC(hWindowDC));
|
||||
if (hAnnunDC == NULL) return FALSE; // quit if failed
|
||||
hAnnunBitmap = LoadBitmapFile(szFilename);
|
||||
hAnnunBitmap = LoadBitmapFile(szFilename,FALSE);
|
||||
if (hAnnunBitmap == NULL)
|
||||
{
|
||||
DeleteDC(hAnnunDC);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "kml.h"
|
||||
#include "debugger.h"
|
||||
|
||||
#define VERSION "1.60+"
|
||||
#define VERSION "1.61+"
|
||||
|
||||
#ifdef _DEBUG
|
||||
LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION)_T(" Debug");
|
||||
|
@ -41,6 +41,7 @@ static const LPCTSTR szLicence =
|
|||
|
||||
static BOOL bOwnCursor = FALSE;
|
||||
static BOOL bTitleBar = TRUE;
|
||||
static BOOL bMouseButton = FALSE;
|
||||
|
||||
|
||||
CRITICAL_SECTION csGDILock; // critical section for hWindowDC
|
||||
|
@ -1787,28 +1788,19 @@ static VOID OnContextMenu(LPARAM lParam)
|
|||
return;
|
||||
}
|
||||
|
||||
static BOOL OnNcHitTest(LPARAM lParam)
|
||||
{
|
||||
if (!bTitleBar || bClientWinMove) // no title bar or window movement over client enabled
|
||||
{
|
||||
POINT pt;
|
||||
|
||||
POINTSTOPOINT(pt,MAKEPOINTS(lParam)); // mouse position
|
||||
VERIFY(ScreenToClient(hWnd,&pt)); // convert mouse into client position
|
||||
|
||||
if (pt.y >= 0) // client area
|
||||
{
|
||||
// hit area not over a button
|
||||
return !MouseIsButton(pt.x,pt.y);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static LRESULT OnLButtonDown(UINT nFlags, WORD x, WORD y)
|
||||
{
|
||||
if (nMacroState == MACRO_PLAY) return 0; // playing macro
|
||||
if (nState == SM_RUN) MouseButtonDownAt(nFlags, x,y);
|
||||
|
||||
bMouseButton = MouseIsButton(x,y); // mouse is over button hit area
|
||||
|
||||
// no title bar or window movement over client enabled and hit area not over a button
|
||||
if ((!bTitleBar || bClientWinMove) && nFlags == MK_LBUTTON && !bMouseButton)
|
||||
{
|
||||
// move window while holding the left mouse button
|
||||
PostMessage(hWnd,WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(x,y));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1816,6 +1808,7 @@ static LRESULT OnLButtonUp(UINT nFlags, WORD x, WORD y)
|
|||
{
|
||||
if (nMacroState == MACRO_PLAY) return 0; // playing macro
|
||||
if (nState == SM_RUN) MouseButtonUpAt(nFlags, x,y);
|
||||
bMouseButton = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1851,6 +1844,7 @@ static LRESULT OnKeyDown(int nVirtKey, LPARAM lKeyData)
|
|||
// call RunKey() only once (suppress autorepeat feature)
|
||||
if (nState == SM_RUN && (lKeyData & 0x40000000) == 0)
|
||||
RunKey((BYTE)nVirtKey, TRUE);
|
||||
bMouseButton = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1994,12 +1988,18 @@ LRESULT CALLBACK MainWndProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lPar
|
|||
case SC_CLOSE: return OnFileExit();
|
||||
}
|
||||
break;
|
||||
case WM_CONTEXTMENU:
|
||||
case WM_NCRBUTTONUP:
|
||||
OnContextMenu(lParam);
|
||||
case WM_ENDSESSION:
|
||||
// session will end and any auto saving is enabled
|
||||
if (wParam == TRUE && (bAutoSave || bAutoSaveOnExit))
|
||||
{
|
||||
SwitchToState(SM_INVALID); // hold emulation thread
|
||||
if (szCurrentFilename[0] != 0) // has current filename
|
||||
SaveDocument();
|
||||
SwitchToState(SM_RUN); // on cancel restart emulation thread
|
||||
}
|
||||
break;
|
||||
case WM_NCHITTEST:
|
||||
if (OnNcHitTest(lParam)) return HTCAPTION;
|
||||
case WM_CONTEXTMENU:
|
||||
if (!bMouseButton) OnContextMenu(lParam);
|
||||
break;
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_LBUTTONDOWN: return OnLButtonDown((UINT) wParam, LOWORD(lParam), HIWORD(lParam));
|
||||
|
|
|
@ -282,7 +282,7 @@ SOURCE=.\kml.c
|
|||
# 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"
|
||||
# ADD CPP /D "LODEPNG_NO_COMPILE_ENCODER" /D "LODEPNG_NO_COMPILE_DISK" /D "LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS" /D "LODEPNG_NO_COMPILE_ERROR_TEXT" /D "LODEPNG_NO_COMPILE_CPP"
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
|
@ -218,6 +218,7 @@ extern DWORD *pdwInstrArray;
|
|||
extern WORD wInstrSize;
|
||||
extern WORD wInstrWp;
|
||||
extern WORD wInstrRp;
|
||||
extern VOID (*fnOutTrace)(VOID);
|
||||
extern VOID SuspendDebugger(VOID);
|
||||
extern VOID ResumeDebugger(VOID);
|
||||
extern VOID CheckSerial(VOID);
|
||||
|
@ -290,7 +291,7 @@ extern BOOL LoadObject(LPCTSTR szFilename);
|
|||
extern BOOL SaveObject(LPCTSTR szFilename);
|
||||
extern BOOL LoadIconFromFile(LPCTSTR szFilename);
|
||||
extern VOID LoadIconDefault(VOID);
|
||||
extern HBITMAP LoadBitmapFile(LPCTSTR szFilename);
|
||||
extern HBITMAP LoadBitmapFile(LPCTSTR szFilename,BOOL bPalette);
|
||||
extern HRGN CreateRgnFromBitmap(HBITMAP hBmp,COLORREF color,DWORD dwTol);
|
||||
|
||||
// Timer.c
|
||||
|
|
|
@ -206,6 +206,14 @@ BEGIN
|
|||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 109
|
||||
END
|
||||
|
||||
IDD_TRACE, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 240
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 106
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
@ -654,6 +662,30 @@ BEGIN
|
|||
PUSHBUTTON "Cancel",IDCANCEL,122,95,50,14
|
||||
END
|
||||
|
||||
IDD_TRACE DIALOG DISCARDABLE 0, 0, 247, 113
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Trace Settings"
|
||||
FONT 8, "MS Sans Serif"
|
||||
BEGIN
|
||||
LTEXT "Log File:",IDC_STATIC,7,13,28,8
|
||||
EDITTEXT IDC_TRACE_FILE,39,11,180,12,ES_AUTOHSCROLL
|
||||
PUSHBUTTON "...",IDC_TRACE_BROWSE,220,11,20,12
|
||||
CONTROL "&New",IDC_TRACE_NEW,"Button",BS_AUTORADIOBUTTON |
|
||||
WS_GROUP | WS_TABSTOP,16,49,41,10
|
||||
CONTROL "&Append",IDC_TRACE_APPEND,"Button",BS_AUTORADIOBUTTON,
|
||||
16,64,41,10
|
||||
GROUPBOX "File Mode",IDC_STATIC,7,32,113,53
|
||||
CONTROL "&Register",IDC_TRACE_REGISTER,"Button",BS_AUTOCHECKBOX |
|
||||
WS_TABSTOP,140,45,43,10
|
||||
CONTROL "&MMU",IDC_TRACE_MMU,"Button",BS_AUTOCHECKBOX |
|
||||
WS_TABSTOP,140,57,43,10
|
||||
CONTROL "&Opcode",IDC_TRACE_OPCODE,"Button",BS_AUTOCHECKBOX |
|
||||
WS_TABSTOP,140,69,43,10
|
||||
GROUPBOX "Logging",IDC_STATIC,127,32,113,53
|
||||
DEFPUSHBUTTON "OK",IDOK,62,92,50,14
|
||||
PUSHBUTTON "Cancel",IDCANCEL,135,92,50,14
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
@ -691,8 +723,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,6,0,0
|
||||
PRODUCTVERSION 1,6,0,0
|
||||
FILEVERSION 1,6,1,0
|
||||
PRODUCTVERSION 1,6,1,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -709,12 +741,12 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "Christoph Gießelink & Sebastien Carlier\0"
|
||||
VALUE "FileDescription", "HP38/39/40/48/49/50 Emulator\0"
|
||||
VALUE "FileVersion", "1, 6, 0, 0\0"
|
||||
VALUE "FileVersion", "1, 6, 1, 0\0"
|
||||
VALUE "InternalName", "Emu48\0"
|
||||
VALUE "LegalCopyright", "Copyright © 2019\0"
|
||||
VALUE "OriginalFilename", "Emu48.exe\0"
|
||||
VALUE "ProductName", "Emu48\0"
|
||||
VALUE "ProductVersion", "1, 6, 0, 0\0"
|
||||
VALUE "ProductVersion", "1, 6, 1, 0\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
@ -896,6 +928,11 @@ BEGIN
|
|||
BEGIN
|
||||
MENUITEM "&Step Over Interrupts", ID_INTR_STEPOVERINT
|
||||
END
|
||||
POPUP "&Trace"
|
||||
BEGIN
|
||||
MENUITEM "&Settings...", ID_TRACE_SETTINGS
|
||||
MENUITEM "&Enable", ID_TRACE_ENABLE
|
||||
END
|
||||
POPUP "&Info"
|
||||
BEGIN
|
||||
MENUITEM "&Last Instructions...", ID_INFO_LASTINSTRUCTIONS
|
||||
|
|
|
@ -59,6 +59,8 @@ WORD wInstrSize = 256; // size of last instruction array
|
|||
WORD wInstrWp; // write pointer of instruction array
|
||||
WORD wInstrRp; // read pointer of instruction array
|
||||
|
||||
VOID (*fnOutTrace)(VOID) = NULL; // callback function for file trace
|
||||
|
||||
static INT nDbgRplBreak = BN_ASM; // flag for RPL breakpoint detection
|
||||
static INT nDbgOldState = DBG_OFF; // old state of debugger for suspend/resume
|
||||
|
||||
|
@ -99,6 +101,10 @@ static __inline VOID Debugger(VOID) // debugger part
|
|||
UpdateDbgCycleCounter(); // update 64 bit cpu cycle counter
|
||||
|
||||
SaveInstrAddr(Chipset.pc); // save pc in last instruction buffer
|
||||
if (fnOutTrace != NULL) // has a trace function
|
||||
{
|
||||
fnOutTrace(); // write file trace
|
||||
}
|
||||
|
||||
nDbgRplBreak = BN_ASM; // notify ASM breakpoint
|
||||
|
||||
|
|
|
@ -855,6 +855,7 @@ BOOL NewDocument(VOID)
|
|||
if (!DisplayChooseKml(0)) goto restore;
|
||||
if (!InitKML(szCurrentKml,FALSE)) goto restore;
|
||||
Chipset.type = cCurrentRomType;
|
||||
CrcRom(&Chipset.wRomCrc); // save fingerprint of loaded ROM
|
||||
|
||||
if (Chipset.type == '6' || Chipset.type == 'A') // HP38G
|
||||
{
|
||||
|
@ -1805,7 +1806,7 @@ static HPALETTE CreateBIPalette(BITMAPINFOHEADER CONST *lpbi)
|
|||
return hpal;
|
||||
}
|
||||
|
||||
static HBITMAP DecodeBmp(LPBMPFILE pBmp)
|
||||
static HBITMAP DecodeBmp(LPBMPFILE pBmp,BOOL bPalette)
|
||||
{
|
||||
LPBITMAPFILEHEADER pBmfh;
|
||||
LPBITMAPINFO pBmi;
|
||||
|
@ -1855,7 +1856,7 @@ static HBITMAP DecodeBmp(LPBMPFILE pBmp)
|
|||
pBmi, DIB_RGB_COLORS));
|
||||
if (hBitmap == NULL) return NULL;
|
||||
|
||||
if (hPalette == NULL)
|
||||
if (bPalette && hPalette == NULL)
|
||||
{
|
||||
hPalette = CreateBIPalette(&pBmi->bmiHeader);
|
||||
// save old palette
|
||||
|
@ -1886,7 +1887,7 @@ static BOOL ReadGifWord(LPBMPFILE pGif, INT *n)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static HBITMAP DecodeGif(LPBMPFILE pBmp,DWORD *pdwTransparentColor)
|
||||
static HBITMAP DecodeGif(LPBMPFILE pBmp,DWORD *pdwTransparentColor,BOOL bPalette)
|
||||
{
|
||||
// this implementation base on the GIF image file
|
||||
// decoder engine of Free42 (c) by Thomas Okken
|
||||
|
@ -2380,7 +2381,7 @@ static HBITMAP DecodeGif(LPBMPFILE pBmp,DWORD *pdwTransparentColor)
|
|||
_ASSERT(bDecoding == FALSE); // decoding successful
|
||||
|
||||
// normal decoding exit
|
||||
if (hPalette == NULL)
|
||||
if (bPalette && hPalette == NULL)
|
||||
{
|
||||
hPalette = CreateBIPalette((PBITMAPINFOHEADER) &bmi);
|
||||
// save old palette
|
||||
|
@ -2397,7 +2398,7 @@ quit:
|
|||
return hBitmap;
|
||||
}
|
||||
|
||||
static HBITMAP DecodePng(LPBMPFILE pBmp)
|
||||
static HBITMAP DecodePng(LPBMPFILE pBmp,BOOL bPalette)
|
||||
{
|
||||
// this implementation use the PNG image file decoder
|
||||
// engine of Copyright (c) 2005-2018 Lode Vandevenne
|
||||
|
@ -2422,7 +2423,7 @@ static HBITMAP DecodePng(LPBMPFILE pBmp)
|
|||
if (uError) goto quit;
|
||||
|
||||
ZeroMemory(&bmi,sizeof(bmi)); // init bitmap info
|
||||
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biWidth = (LONG) uWidth;
|
||||
bmi.bmiHeader.biHeight = (LONG) uHeight;
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
|
@ -2460,7 +2461,7 @@ static HBITMAP DecodePng(LPBMPFILE pBmp)
|
|||
_ASSERT((DWORD) (pbyLine - pbyPixels) <= bmi.bmiHeader.biSizeImage);
|
||||
}
|
||||
|
||||
if (hPalette == NULL)
|
||||
if (bPalette && hPalette == NULL)
|
||||
{
|
||||
hPalette = CreateBIPalette((PBITMAPINFOHEADER) &bmi);
|
||||
// save old palette
|
||||
|
@ -2482,7 +2483,7 @@ quit:
|
|||
return hBitmap;
|
||||
}
|
||||
|
||||
HBITMAP LoadBitmapFile(LPCTSTR szFilename)
|
||||
HBITMAP LoadBitmapFile(LPCTSTR szFilename,BOOL bPalette)
|
||||
{
|
||||
HANDLE hFile;
|
||||
HANDLE hMap;
|
||||
|
@ -2513,7 +2514,7 @@ HBITMAP LoadBitmapFile(LPCTSTR szFilename)
|
|||
// check for bitmap file header "BM"
|
||||
if (Bmp.dwFileSize >= 2 && *(WORD *) Bmp.pbyFile == 0x4D42)
|
||||
{
|
||||
hBitmap = DecodeBmp(&Bmp);
|
||||
hBitmap = DecodeBmp(&Bmp,bPalette);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2521,14 +2522,14 @@ HBITMAP LoadBitmapFile(LPCTSTR szFilename)
|
|||
if ( Bmp.dwFileSize >= 6
|
||||
&& (memcmp(Bmp.pbyFile,"GIF87a",6) == 0 || memcmp(Bmp.pbyFile,"GIF89a",6) == 0))
|
||||
{
|
||||
hBitmap = DecodeGif(&Bmp,&dwTColor);
|
||||
hBitmap = DecodeGif(&Bmp,&dwTColor,bPalette);
|
||||
break;
|
||||
}
|
||||
|
||||
// check for PNG file header
|
||||
if (Bmp.dwFileSize >= 8 && memcmp(Bmp.pbyFile,"\x89PNG\r\n\x1a\n",8) == 0)
|
||||
{
|
||||
hBitmap = DecodePng(&Bmp);
|
||||
hBitmap = DecodePng(&Bmp,bPalette);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
12
source/KML.C
12
source/KML.C
|
@ -895,6 +895,8 @@ static KmlLine* ParseLines(BOOL bInclude)
|
|||
if (eToken == TOK_INCLUDE)
|
||||
{
|
||||
LPTSTR szFilename;
|
||||
UINT nLexLineKml;
|
||||
|
||||
eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString'
|
||||
if (eToken != TOK_STRING) // not a string (token don't begin with ")
|
||||
{
|
||||
|
@ -903,6 +905,7 @@ static KmlLine* ParseLines(BOOL bInclude)
|
|||
}
|
||||
szFilename = szLexString; // save pointer to allocated memory
|
||||
szLexString = NULL;
|
||||
nLexLineKml = nLexLine; // save line number
|
||||
eToken = Lex(LEX_PARAM); // decode argument
|
||||
if (eToken != TOK_EOL)
|
||||
{
|
||||
|
@ -925,7 +928,10 @@ static KmlLine* ParseLines(BOOL bInclude)
|
|||
}
|
||||
free(szFilename); // free filename string
|
||||
if (pLine == NULL) // parsing error
|
||||
{
|
||||
nLexLine = nLexLineKml; // restore line number
|
||||
goto abort;
|
||||
}
|
||||
while (pLine->pNext) pLine=pLine->pNext;
|
||||
continue;
|
||||
}
|
||||
|
@ -1096,6 +1102,8 @@ static KmlBlock* ParseBlocks(BOOL bInclude, BOOL bEndTokenEn)
|
|||
if (eToken == TOK_INCLUDE)
|
||||
{
|
||||
LPTSTR szFilename;
|
||||
UINT nLexLineKml;
|
||||
|
||||
eToken = Lex(LEX_PARAM); // get include parameter in 'szLexString'
|
||||
if (eToken != TOK_STRING) // not a string (token don't begin with ")
|
||||
{
|
||||
|
@ -1104,6 +1112,7 @@ static KmlBlock* ParseBlocks(BOOL bInclude, BOOL bEndTokenEn)
|
|||
}
|
||||
szFilename = szLexString; // save pointer to allocated memory
|
||||
szLexString = NULL;
|
||||
nLexLineKml = nLexLine; // save line number
|
||||
eToken = Lex(LEX_PARAM); // decode argument
|
||||
if (eToken != TOK_EOL)
|
||||
{
|
||||
|
@ -1117,7 +1126,10 @@ static KmlBlock* ParseBlocks(BOOL bInclude, BOOL bEndTokenEn)
|
|||
pBlock = pFirst = IncludeBlocks(bInclude,szFilename);
|
||||
free(szFilename); // free filename string
|
||||
if (pBlock == NULL) // parsing error
|
||||
{
|
||||
nLexLine = nLexLineKml; // restore line number
|
||||
goto abort;
|
||||
}
|
||||
while (pBlock->pNext) pBlock = pBlock->pNext;
|
||||
continue;
|
||||
}
|
||||
|
|
4163
source/LODEPNG.C
4163
source/LODEPNG.C
File diff suppressed because it is too large
Load diff
227
source/LODEPNG.H
227
source/LODEPNG.H
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
LodePNG version 20180910
|
||||
LodePNG version 20190914
|
||||
|
||||
Copyright (c) 2005-2018 Lode Vandevenne
|
||||
Copyright (c) 2005-2019 Lode Vandevenne
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
@ -44,36 +44,44 @@ the custom_zlib field of the compress and decompress settings*/
|
|||
#ifndef LODEPNG_NO_COMPILE_ZLIB
|
||||
#define LODEPNG_COMPILE_ZLIB
|
||||
#endif
|
||||
|
||||
/*png encoder and png decoder*/
|
||||
#ifndef LODEPNG_NO_COMPILE_PNG
|
||||
#define LODEPNG_COMPILE_PNG
|
||||
#endif
|
||||
|
||||
/*deflate&zlib decoder and png decoder*/
|
||||
#ifndef LODEPNG_NO_COMPILE_DECODER
|
||||
#define LODEPNG_COMPILE_DECODER
|
||||
#endif
|
||||
|
||||
/*deflate&zlib encoder and png encoder*/
|
||||
#ifndef LODEPNG_NO_COMPILE_ENCODER
|
||||
#define LODEPNG_COMPILE_ENCODER
|
||||
#endif
|
||||
|
||||
/*the optional built in harddisk file loading and saving functions*/
|
||||
#ifndef LODEPNG_NO_COMPILE_DISK
|
||||
#define LODEPNG_COMPILE_DISK
|
||||
#endif
|
||||
|
||||
/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/
|
||||
#ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
|
||||
#define LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||
#endif
|
||||
|
||||
/*ability to convert error numerical codes to English text string*/
|
||||
#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT
|
||||
#define LODEPNG_COMPILE_ERROR_TEXT
|
||||
#endif
|
||||
|
||||
/*Compile the default allocators (C's free, malloc and realloc). If you disable this,
|
||||
you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your
|
||||
source files with custom allocators.*/
|
||||
#ifndef LODEPNG_NO_COMPILE_ALLOCATORS
|
||||
#define LODEPNG_COMPILE_ALLOCATORS
|
||||
#endif
|
||||
|
||||
/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/
|
||||
#ifdef __cplusplus
|
||||
#ifndef LODEPNG_NO_COMPILE_CPP
|
||||
|
@ -87,14 +95,19 @@ source files with custom allocators.*/
|
|||
#endif /*LODEPNG_COMPILE_CPP*/
|
||||
|
||||
#ifdef LODEPNG_COMPILE_PNG
|
||||
/*The PNG color types (also used for raw).*/
|
||||
typedef enum LodePNGColorType
|
||||
{
|
||||
LCT_GREY = 0, /*greyscale: 1,2,4,8,16 bit*/
|
||||
/*The PNG color types (also used for raw image).*/
|
||||
typedef enum LodePNGColorType {
|
||||
LCT_GREY = 0, /*grayscale: 1,2,4,8,16 bit*/
|
||||
LCT_RGB = 2, /*RGB: 8,16 bit*/
|
||||
LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/
|
||||
LCT_GREY_ALPHA = 4, /*greyscale with alpha: 8,16 bit*/
|
||||
LCT_RGBA = 6 /*RGB with alpha: 8,16 bit*/
|
||||
LCT_GREY_ALPHA = 4, /*grayscale with alpha: 8,16 bit*/
|
||||
LCT_RGBA = 6, /*RGB with alpha: 8,16 bit*/
|
||||
/*LCT_MAX_OCTET_VALUE lets the compiler allow this enum to represent any invalid
|
||||
byte value from 0 to 255 that could be present in an invalid PNG file header. Do
|
||||
not use, compare with or set the name LCT_MAX_OCTET_VALUE, instead either use
|
||||
the valid color type names above, or numeric values like 1 or 7 when checking for
|
||||
particular disallowed color type byte values, or cast to integer to print it.*/
|
||||
LCT_MAX_OCTET_VALUE = 255
|
||||
} LodePNGColorType;
|
||||
|
||||
#ifdef LODEPNG_COMPILE_DECODER
|
||||
|
@ -196,8 +209,7 @@ unsigned lodepng_encode24_file(const char* filename,
|
|||
|
||||
|
||||
#ifdef LODEPNG_COMPILE_CPP
|
||||
namespace lodepng
|
||||
{
|
||||
namespace lodepng {
|
||||
#ifdef LODEPNG_COMPILE_DECODER
|
||||
/*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype
|
||||
is the format to output the pixels to. Default is RGBA 8-bit per channel.*/
|
||||
|
@ -253,18 +265,17 @@ const char* lodepng_error_text(unsigned code);
|
|||
#ifdef LODEPNG_COMPILE_DECODER
|
||||
/*Settings for zlib decompression*/
|
||||
typedef struct LodePNGDecompressSettings LodePNGDecompressSettings;
|
||||
struct LodePNGDecompressSettings
|
||||
{
|
||||
struct LodePNGDecompressSettings {
|
||||
/* Check LodePNGDecoderSettings for more ignorable errors such as ignore_crc */
|
||||
unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/
|
||||
unsigned ignore_nlen; /*ignore complement of len checksum in uncompressed blocks*/
|
||||
|
||||
/*use custom zlib decoder instead of built in one (default: null)*/
|
||||
unsigned (*custom_zlib)(unsigned char**, size_t*,
|
||||
const unsigned char*, size_t,
|
||||
const LodePNGDecompressSettings*);
|
||||
/*use custom deflate decoder instead of built in one (default: null)
|
||||
if custom_zlib is used, custom_deflate is ignored since only the built in
|
||||
zlib function will call custom_deflate*/
|
||||
if custom_zlib is not null, custom_inflate is ignored (the zlib format uses deflate)*/
|
||||
unsigned (*custom_inflate)(unsigned char**, size_t*,
|
||||
const unsigned char*, size_t,
|
||||
const LodePNGDecompressSettings*);
|
||||
|
@ -282,13 +293,12 @@ Settings for zlib compression. Tweaking these settings tweaks the balance
|
|||
between speed and compression ratio.
|
||||
*/
|
||||
typedef struct LodePNGCompressSettings LodePNGCompressSettings;
|
||||
struct LodePNGCompressSettings /*deflate = compress*/
|
||||
{
|
||||
struct LodePNGCompressSettings /*deflate = compress*/ {
|
||||
/*LZ77 related settings*/
|
||||
unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/
|
||||
unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/
|
||||
unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/
|
||||
unsigned minmatch; /*mininum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/
|
||||
unsigned minmatch; /*minimum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/
|
||||
unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/
|
||||
unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/
|
||||
|
||||
|
@ -316,8 +326,7 @@ Color mode of an image. Contains all information required to decode the pixel
|
|||
bits to RGBA colors. This information is the same as used in the PNG file
|
||||
format, and is used both for PNG and raw image data in LodePNG.
|
||||
*/
|
||||
typedef struct LodePNGColorMode
|
||||
{
|
||||
typedef struct LodePNGColorMode {
|
||||
/*header (IHDR)*/
|
||||
LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/
|
||||
unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/
|
||||
|
@ -342,7 +351,7 @@ typedef struct LodePNGColorMode
|
|||
transparent color key (tRNS)
|
||||
|
||||
This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit.
|
||||
For greyscale PNGs, r, g and b will all 3 be set to the same.
|
||||
For grayscale PNGs, r, g and b will all 3 be set to the same.
|
||||
|
||||
When decoding, by default you can ignore this information, since LodePNG sets
|
||||
pixels with this key to transparent already in the raw RGBA output.
|
||||
|
@ -350,7 +359,7 @@ typedef struct LodePNGColorMode
|
|||
The color key is only supported for color types 0 and 2.
|
||||
*/
|
||||
unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/
|
||||
unsigned key_r; /*red/greyscale component of color key*/
|
||||
unsigned key_r; /*red/grayscale component of color key*/
|
||||
unsigned key_g; /*green component of color key*/
|
||||
unsigned key_b; /*blue component of color key*/
|
||||
} LodePNGColorMode;
|
||||
|
@ -373,7 +382,7 @@ unsigned lodepng_get_bpp(const LodePNGColorMode* info);
|
|||
/*get the amount of color channels used, based on colortype in the struct.
|
||||
If a palette is used, it counts as 1 channel.*/
|
||||
unsigned lodepng_get_channels(const LodePNGColorMode* info);
|
||||
/*is it a greyscale type? (only colortype 0 or 4)*/
|
||||
/*is it a grayscale type? (only colortype 0 or 4)*/
|
||||
unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info);
|
||||
/*has it got an alpha channel? (only colortype 2 or 6)*/
|
||||
unsigned lodepng_is_alpha_type(const LodePNGColorMode* info);
|
||||
|
@ -395,8 +404,7 @@ size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* colo
|
|||
|
||||
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
|
||||
/*The information of a Time chunk in PNG.*/
|
||||
typedef struct LodePNGTime
|
||||
{
|
||||
typedef struct LodePNGTime {
|
||||
unsigned year; /*2 bytes used (0-65535)*/
|
||||
unsigned month; /*1-12*/
|
||||
unsigned day; /*1-31*/
|
||||
|
@ -407,8 +415,7 @@ typedef struct LodePNGTime
|
|||
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
|
||||
|
||||
/*Information about the PNG image, except pixels, width and height.*/
|
||||
typedef struct LodePNGInfo
|
||||
{
|
||||
typedef struct LodePNGInfo {
|
||||
/*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/
|
||||
unsigned compression_method;/*compression method of the original file. Always 0.*/
|
||||
unsigned filter_method; /*filter method of the original file*/
|
||||
|
@ -422,7 +429,7 @@ typedef struct LodePNGInfo
|
|||
This uses the same color mode and bit depth as the PNG (except no alpha channel),
|
||||
with values truncated to the bit depth in the unsigned integer.
|
||||
|
||||
For greyscale and palette PNGs, the value is stored in background_r. The values
|
||||
For grayscale and palette PNGs, the value is stored in background_r. The values
|
||||
in background_g and background_b are then unused.
|
||||
|
||||
So when decoding, you may get these in a different color mode than the one you requested
|
||||
|
@ -432,15 +439,15 @@ typedef struct LodePNGInfo
|
|||
these values. The encoder normally ignores info_png.color when auto_convert is on, but will
|
||||
use it to interpret these values (and convert copies of them to its chosen color model).
|
||||
|
||||
When encoding, avoid setting this to an expensive color, such as a non-grey value
|
||||
when the image is grey, or the compression will be worse since it will be forced to
|
||||
When encoding, avoid setting this to an expensive color, such as a non-gray value
|
||||
when the image is gray, or the compression will be worse since it will be forced to
|
||||
write the PNG with a more expensive color mode (when auto_convert is on).
|
||||
|
||||
The decoder does not use this background color to edit the color of pixels. This is a
|
||||
completely optional metadata feature.
|
||||
*/
|
||||
unsigned background_defined; /*is a suggested background color given?*/
|
||||
unsigned background_r; /*red/grey/palette component of suggested background color*/
|
||||
unsigned background_r; /*red/gray/palette component of suggested background color*/
|
||||
unsigned background_g; /*green component of suggested background color*/
|
||||
unsigned background_b; /*blue component of suggested background color*/
|
||||
|
||||
|
@ -530,12 +537,12 @@ typedef struct LodePNGInfo
|
|||
profile as closely as possible, if you wish to do this you should provide the correct values for gAMA and cHRM and
|
||||
enable their '_defined' flags since LodePNG will not automatically compute them from the ICC profile.
|
||||
|
||||
For encoding, the ICC profile is required by the PNG specification to be an "RGB" profile for non-grey
|
||||
PNG color types and a "GRAY" profile for grey PNG color types. If you disable auto_convert, you must ensure
|
||||
For encoding, the ICC profile is required by the PNG specification to be an "RGB" profile for non-gray
|
||||
PNG color types and a "GRAY" profile for gray PNG color types. If you disable auto_convert, you must ensure
|
||||
the ICC profile type matches your requested color type, else the encoder gives an error. If auto_convert is
|
||||
enabled (the default), and the ICC profile is not a good match for the pixel data, this will result in an encoder
|
||||
error if the pixel data has non-grey pixels for a GRAY profile, or a silent less-optimal compression of the pixel
|
||||
data if the pixels could be encoded as greyscale but the ICC profile is RGB.
|
||||
error if the pixel data has non-gray pixels for a GRAY profile, or a silent less-optimal compression of the pixel
|
||||
data if the pixels could be encoded as grayscale but the ICC profile is RGB.
|
||||
|
||||
To avoid this do not set an ICC profile in the image unless there is a good reason for it, and when doing so
|
||||
make sure you compute it carefully to avoid the above problems.
|
||||
|
@ -614,8 +621,7 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in,
|
|||
Settings for the decoder. This contains settings for the PNG and the Zlib
|
||||
decoder, but not the Info settings from the Info structs.
|
||||
*/
|
||||
typedef struct LodePNGDecoderSettings
|
||||
{
|
||||
typedef struct LodePNGDecoderSettings {
|
||||
LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/
|
||||
|
||||
/* Check LodePNGDecompressSettings for more ignorable errors such as ignore_adler32 */
|
||||
|
@ -641,10 +647,14 @@ void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings);
|
|||
|
||||
#ifdef LODEPNG_COMPILE_ENCODER
|
||||
/*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/
|
||||
typedef enum LodePNGFilterStrategy
|
||||
{
|
||||
typedef enum LodePNGFilterStrategy {
|
||||
/*every filter at zero*/
|
||||
LFS_ZERO,
|
||||
LFS_ZERO = 0,
|
||||
/*every filter at 1, 2, 3 or 4 (paeth), unlike LFS_ZERO not a good choice, but for testing*/
|
||||
LFS_ONE = 1,
|
||||
LFS_TWO = 2,
|
||||
LFS_THREE = 3,
|
||||
LFS_FOUR = 4,
|
||||
/*Use filter that gives minimum sum, as described in the official PNG filter heuristic.*/
|
||||
LFS_MINSUM,
|
||||
/*Use the filter type that gives smallest Shannon entropy for this scanline. Depending
|
||||
|
@ -661,40 +671,43 @@ typedef enum LodePNGFilterStrategy
|
|||
|
||||
/*Gives characteristics about the integer RGBA colors of the image (count, alpha channel usage, bit depth, ...),
|
||||
which helps decide which color model to use for encoding.
|
||||
Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.
|
||||
NOTE: This is not related to the ICC color profile, search "iccp_profile" instead to find the ICC/chromacity/...
|
||||
fields in this header file.*/
|
||||
typedef struct LodePNGColorProfile
|
||||
{
|
||||
unsigned colored; /*not greyscale*/
|
||||
Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/
|
||||
typedef struct LodePNGColorStats {
|
||||
unsigned colored; /*not grayscale*/
|
||||
unsigned key; /*image is not opaque and color key is possible instead of full alpha*/
|
||||
unsigned short key_r; /*key values, always as 16-bit, in 8-bit case the byte is duplicated, e.g. 65535 means 255*/
|
||||
unsigned short key_g;
|
||||
unsigned short key_b;
|
||||
unsigned alpha; /*image is not opaque and alpha channel or alpha palette required*/
|
||||
unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16.*/
|
||||
unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order*/
|
||||
unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for greyscale only. 16 if 16-bit per channel required.*/
|
||||
unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16 or allow_palette is disabled.*/
|
||||
unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order, only valid when numcolors is valid*/
|
||||
unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for grayscale only. 16 if 16-bit per channel required.*/
|
||||
size_t numpixels;
|
||||
} LodePNGColorProfile;
|
||||
|
||||
void lodepng_color_profile_init(LodePNGColorProfile* profile);
|
||||
/*user settings for computing/using the stats*/
|
||||
unsigned allow_palette; /*default 1. if 0, disallow choosing palette colortype in auto_choose_color, and don't count numcolors*/
|
||||
unsigned allow_greyscale; /*default 1. if 0, choose RGB or RGBA even if the image only has gray colors*/
|
||||
} LodePNGColorStats;
|
||||
|
||||
/*Get a LodePNGColorProfile of the image. The profile must already have been inited.
|
||||
NOTE: This is not related to the ICC color profile, search "iccp_profile" instead to find the ICC/chromacity/...
|
||||
fields in this header file.*/
|
||||
unsigned lodepng_get_color_profile(LodePNGColorProfile* profile,
|
||||
const unsigned char* image, unsigned w, unsigned h,
|
||||
const LodePNGColorMode* mode_in);
|
||||
/*The function LodePNG uses internally to decide the PNG color with auto_convert.
|
||||
Chooses an optimal color model, e.g. grey if only grey pixels, palette if < 256 colors, ...*/
|
||||
void lodepng_color_stats_init(LodePNGColorStats* stats);
|
||||
|
||||
/*Get a LodePNGColorStats of the image. The stats must already have been inited.*/
|
||||
void lodepng_compute_color_stats(LodePNGColorStats* stats,
|
||||
const unsigned char* image, unsigned w, unsigned h,
|
||||
const LodePNGColorMode* mode_in);
|
||||
/*Computes a minimal PNG color model that can contain all colors as indicated by the stats and it settings.
|
||||
The stats should be computed with lodepng_compute_color_stats.
|
||||
mode_in is raw color profile of the image the stats were computed on, to copy palette order from when relevant.
|
||||
Minimal PNG color model means the color type and bit depth that gives smallest amount of bits in the output image,
|
||||
e.g. gray if only grayscale pixels, palette if less than 256 colors, color key if only single transparent color, ...
|
||||
LodePNG uses this function internally if auto_convert is enabled (it is by default).
|
||||
*/
|
||||
unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out,
|
||||
const unsigned char* image, unsigned w, unsigned h,
|
||||
const LodePNGColorMode* mode_in);
|
||||
const LodePNGColorMode* mode_in,
|
||||
const LodePNGColorMode* stats);
|
||||
|
||||
/*Settings for the encoder.*/
|
||||
typedef struct LodePNGEncoderSettings
|
||||
{
|
||||
typedef struct LodePNGEncoderSettings {
|
||||
LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/
|
||||
|
||||
unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/
|
||||
|
@ -730,8 +743,7 @@ void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings);
|
|||
|
||||
#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER)
|
||||
/*The settings, state and information for extended encoding and decoding.*/
|
||||
typedef struct LodePNGState
|
||||
{
|
||||
typedef struct LodePNGState {
|
||||
#ifdef LODEPNG_COMPILE_DECODER
|
||||
LodePNGDecoderSettings decoder; /*the decoding settings*/
|
||||
#endif /*LODEPNG_COMPILE_DECODER*/
|
||||
|
@ -965,11 +977,9 @@ unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const
|
|||
|
||||
#ifdef LODEPNG_COMPILE_CPP
|
||||
/* The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. */
|
||||
namespace lodepng
|
||||
{
|
||||
namespace lodepng {
|
||||
#ifdef LODEPNG_COMPILE_PNG
|
||||
class State : public LodePNGState
|
||||
{
|
||||
class State : public LodePNGState {
|
||||
public:
|
||||
State();
|
||||
State(const State& other);
|
||||
|
@ -1042,17 +1052,21 @@ TODO:
|
|||
[.] check compatibility with various compilers - done but needs to be redone for every newer version
|
||||
[X] converting color to 16-bit per channel types
|
||||
[X] support color profile chunk types (but never let them touch RGB values by default)
|
||||
[ ] support all public PNG chunk types
|
||||
[ ] support all public PNG chunk types (almost done except sBIT, sPLT and hIST)
|
||||
[ ] make sure encoder generates no chunks with size > (2^31)-1
|
||||
[ ] partial decoding (stream processing)
|
||||
[X] let the "isFullyOpaque" function check color keys and transparent palettes too
|
||||
[X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl"
|
||||
[ ] don't stop decoding on errors like 69, 57, 58 (make warnings)
|
||||
[ ] allow treating some errors like warnings, when image is recoverable (e.g. 69, 57, 58)
|
||||
[ ] make warnings like: oob palette, checksum fail, data after iend, wrong/unknown crit chunk, no null terminator in text, ...
|
||||
[ ] errors with line numbers (and version)
|
||||
[ ] error messages with line numbers (and version)
|
||||
[ ] errors in state instead of as return code?
|
||||
[ ] new errors/warnings like suspiciously big decompressed ztxt or iccp chunk
|
||||
[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes
|
||||
[ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ...
|
||||
[ ] allow user to give data (void*) to custom allocator
|
||||
[ ] provide alternatives for C library functions not present on some platforms (memcpy, ...)
|
||||
[ ] rename "grey" to "gray" everywhere since "color" also uses US spelling (keep "grey" copies for backwards compatibility)
|
||||
*/
|
||||
|
||||
#endif /*LODEPNG_H inclusion guard*/
|
||||
|
@ -1147,8 +1161,10 @@ The following features are supported by the decoder:
|
|||
*) zlib decompression (inflate)
|
||||
*) zlib compression (deflate)
|
||||
*) CRC32 and ADLER32 checksums
|
||||
*) colorimetric color profile conversions: currently experimentally available in lodepng_util.cpp only,
|
||||
plus alternatively ability to pass on chroma/gamma/ICC profile information to other color management system.
|
||||
*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks.
|
||||
*) the following chunks are supported (generated/interpreted) by both encoder and decoder:
|
||||
*) the following chunks are supported by both encoder and decoder:
|
||||
IHDR: header information
|
||||
PLTE: color palette
|
||||
IDAT: pixel data
|
||||
|
@ -1160,6 +1176,10 @@ The following features are supported by the decoder:
|
|||
bKGD: suggested background color
|
||||
pHYs: physical dimensions
|
||||
tIME: modification time
|
||||
cHRM: RGB chromaticities
|
||||
gAMA: RGB gamma correction
|
||||
iCCP: ICC color profile
|
||||
sRGB: rendering intent
|
||||
|
||||
1.2. features not supported
|
||||
---------------------------
|
||||
|
@ -1168,10 +1188,10 @@ The following features are _not_ supported:
|
|||
|
||||
*) some features needed to make a conformant PNG-Editor might be still missing.
|
||||
*) partial loading/stream processing. All data must be available and is processed in one call.
|
||||
*) The following public chunks are not supported but treated as unknown chunks by LodePNG
|
||||
cHRM, gAMA, iCCP, sRGB, sBIT, hIST, sPLT
|
||||
Some of these are not supported on purpose: LodePNG wants to provide the RGB values
|
||||
stored in the pixels, not values modified by system dependent gamma or color models.
|
||||
*) The following public chunks are not (yet) supported but treated as unknown chunks by LodePNG:
|
||||
sBIT
|
||||
hIST
|
||||
sPLT
|
||||
|
||||
|
||||
2. C and C++ version
|
||||
|
@ -1245,7 +1265,7 @@ LodePNGColorMode info_raw
|
|||
When decoding, here you can specify which color type you want
|
||||
the resulting raw image to be. If this is different from the colortype of the
|
||||
PNG, then the decoder will automatically convert the result. This conversion
|
||||
always works, except if you want it to convert a color PNG to greyscale or to
|
||||
always works, except if you want it to convert a color PNG to grayscale or to
|
||||
a palette with missing colors.
|
||||
|
||||
By default, 32-bit color is used for the result.
|
||||
|
@ -1341,7 +1361,7 @@ can encode the colors of all pixels without information loss.
|
|||
An important thing to note about LodePNG, is that the color type of the PNG, and
|
||||
the color type of the raw image, are completely independent. By default, when
|
||||
you decode a PNG, you get the result as a raw image in the color type you want,
|
||||
no matter whether the PNG was encoded with a palette, greyscale or RGBA color.
|
||||
no matter whether the PNG was encoded with a palette, grayscale or RGBA color.
|
||||
And if you encode an image, by default LodePNG will automatically choose the PNG
|
||||
color type that gives good compression based on the values of colors and amount
|
||||
of colors in the image. It can be configured to let you control it instead as
|
||||
|
@ -1349,10 +1369,10 @@ well, though.
|
|||
|
||||
To be able to do this, LodePNG does conversions from one color mode to another.
|
||||
It can convert from almost any color type to any other color type, except the
|
||||
following conversions: RGB to greyscale is not supported, and converting to a
|
||||
following conversions: RGB to grayscale is not supported, and converting to a
|
||||
palette when the palette doesn't have a required color is not supported. This is
|
||||
not supported on purpose: this is information loss which requires a color
|
||||
reduction algorithm that is beyong the scope of a PNG encoder (yes, RGB to grey
|
||||
reduction algorithm that is beyond the scope of a PNG encoder (yes, RGB to gray
|
||||
is easy, but there are multiple ways if you want to give some channels more
|
||||
weight).
|
||||
|
||||
|
@ -1373,10 +1393,10 @@ decoding to have another color type, a conversion is done by LodePNG.
|
|||
|
||||
The PNG specification gives the following color types:
|
||||
|
||||
0: greyscale, bit depths 1, 2, 4, 8, 16
|
||||
0: grayscale, bit depths 1, 2, 4, 8, 16
|
||||
2: RGB, bit depths 8 and 16
|
||||
3: palette, bit depths 1, 2, 4 and 8
|
||||
4: greyscale with alpha, bit depths 8 and 16
|
||||
4: grayscale with alpha, bit depths 8 and 16
|
||||
6: RGBA, bit depths 8 and 16
|
||||
|
||||
Bit depth is the amount of bits per pixel per color channel. So the total amount
|
||||
|
@ -1425,15 +1445,22 @@ To avoid some confusion:
|
|||
the raw image correctly before encoding.
|
||||
-both encoder and decoder use the same color converter.
|
||||
|
||||
The function lodepng_convert does the color conversion. It is available in the
|
||||
interface but normally isn't needed since the encoder and decoder already call
|
||||
it.
|
||||
|
||||
Non supported color conversions:
|
||||
-color to greyscale: no error is thrown, but the result will look ugly because
|
||||
only the red channel is taken
|
||||
-anything to palette when that palette does not have that color in it: in this
|
||||
case an error is thrown
|
||||
-color to grayscale when non-gray pixels are present: no error is thrown, but
|
||||
the result will look ugly because only the red channel is taken (it assumes all
|
||||
three channels are the same in this case so ignores green and blue). The reason
|
||||
no error is given is to allow converting from three-channel grayscale images to
|
||||
one-channel even if there are numerical imprecisions.
|
||||
-anything to palette when the palette does not have an exact match for a from-color
|
||||
in it: in this case an error is thrown
|
||||
|
||||
Supported color conversions:
|
||||
-anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA
|
||||
-any grey or grey+alpha, to grey or grey+alpha
|
||||
-any gray or gray+alpha, to gray or gray+alpha
|
||||
-anything to a palette, as long as the palette has the requested colors in it
|
||||
-removing alpha channel
|
||||
-higher to smaller bitdepth, and vice versa
|
||||
|
@ -1446,10 +1473,6 @@ false.
|
|||
as the PNG has, by setting the color_convert setting to false. Settings in
|
||||
info_raw are then ignored.
|
||||
|
||||
The function lodepng_convert does the color conversion. It is available in the
|
||||
interface but normally isn't needed since the encoder and decoder already call
|
||||
it.
|
||||
|
||||
6.3. padding bits
|
||||
-----------------
|
||||
|
||||
|
@ -1458,7 +1481,7 @@ have a bit amount that isn't a multiple of 8, then padding bits are used so that
|
|||
scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output.
|
||||
The raw input image you give to the encoder, and the raw output image you get from the decoder
|
||||
will NOT have these padding bits, e.g. in the case of a 1-bit image with a width
|
||||
of 7 pixels, the first pixel of the second scanline will the the 8th bit of the first byte,
|
||||
of 7 pixels, the first pixel of the second scanline will the 8th bit of the first byte,
|
||||
not the first bit of a new byte.
|
||||
|
||||
6.4. A note about 16-bits per channel and endianness
|
||||
|
@ -1575,7 +1598,7 @@ The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3
|
|||
buffers (each with size) to contain 3 types of unknown chunks:
|
||||
the ones that come before the PLTE chunk, the ones that come between the PLTE
|
||||
and the IDAT chunks, and the ones that come after the IDAT chunks.
|
||||
It's necessary to make the distionction between these 3 cases because the PNG
|
||||
It's necessary to make the distinction between these 3 cases because the PNG
|
||||
standard forces to keep the ordering of unknown chunks compared to the critical
|
||||
chunks, but does not force any other ordering rules.
|
||||
|
||||
|
@ -1658,7 +1681,7 @@ C and C++.
|
|||
*) Other Compilers
|
||||
|
||||
If you encounter problems on any compilers, feel free to let me know and I may
|
||||
try to fix it if the compiler is modern and standards complient.
|
||||
try to fix it if the compiler is modern and standards compliant.
|
||||
|
||||
|
||||
10. examples
|
||||
|
@ -1673,8 +1696,7 @@ examples can be found on the LodePNG website.
|
|||
#include "lodepng.h"
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
const char* filename = argc > 1 ? argv[1] : "test.png";
|
||||
|
||||
//load and decode
|
||||
|
@ -1693,8 +1715,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
#include "lodepng.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
unsigned error;
|
||||
unsigned char* image;
|
||||
size_t width, height;
|
||||
|
@ -1763,6 +1784,13 @@ yyyymmdd.
|
|||
Some changes aren't backwards compatible. Those are indicated with a (!)
|
||||
symbol.
|
||||
|
||||
Not all changes are listed here, the commit history in github lists more:
|
||||
https://github.com/lvandeve/lodepng
|
||||
|
||||
*) 14 aug 2019: around 25% faster decoding thanks to huffman lookup tables.
|
||||
*) 15 jun 2019 (!): auto_choose_color API changed (for bugfix: don't use palette
|
||||
if gray ICC profile) and non-ICC LodePNGColorProfile renamed to LodePNGColorStats.
|
||||
*) 30 dec 2018: code style changes only: removed newlines before opening braces.
|
||||
*) 10 sep 2018: added way to inspect metadata chunks without full decoding.
|
||||
*) 19 aug 2018 (!): fixed color mode bKGD is encoded with and made it use
|
||||
palette index in case of palette.
|
||||
|
@ -1778,6 +1806,7 @@ symbol.
|
|||
*) 08 dec 2015: Made load_file function return error if file can't be opened.
|
||||
*) 24 okt 2015: Bugfix with decoding to palette output.
|
||||
*) 18 apr 2015: Boundary PM instead of just package-merge for faster encoding.
|
||||
*) 24 aug 2014: Moved to github
|
||||
*) 23 aug 2014: Reduced needless memory usage of decoder.
|
||||
*) 28 jun 2014: Removed fix_png setting, always support palette OOB for
|
||||
simplicity. Made ColorProfile public.
|
||||
|
@ -1920,5 +1949,5 @@ Domain: gmail dot com.
|
|||
Account: lode dot vandevenne.
|
||||
|
||||
|
||||
Copyright (c) 2005-2018 Lode Vandevenne
|
||||
Copyright (c) 2005-2019 Lode Vandevenne
|
||||
*/
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#define IDD_DEBUG_MEMSAVE 127
|
||||
#define IDD_DEBUG_MEMLOAD 128
|
||||
#define IDD_DEBUG_SETTINGS 129
|
||||
#define IDD_TRACE 130
|
||||
#define IDC_REALSPEED 1000
|
||||
#define IDC_GRAYSCALE 1001
|
||||
#define IDC_ALWAYSONTOP 1002
|
||||
|
@ -169,6 +170,13 @@
|
|||
#define IDC_MACRO_MANUAL 1133
|
||||
#define IDC_SOUND_SLIDER 1134
|
||||
#define IDC_SOUND_DEVICE 1135
|
||||
#define IDC_TRACE_FILE 1136
|
||||
#define IDC_TRACE_BROWSE 1137
|
||||
#define IDC_TRACE_NEW 1138
|
||||
#define IDC_TRACE_APPEND 1139
|
||||
#define IDC_TRACE_REGISTER 1140
|
||||
#define IDC_TRACE_MMU 1141
|
||||
#define IDC_TRACE_OPCODE 1142
|
||||
#define ID_FILE_NEW 40001
|
||||
#define ID_FILE_OPEN 40002
|
||||
#define ID_FILE_SAVE 40003
|
||||
|
@ -239,15 +247,17 @@
|
|||
#define ID_INFO_LASTINSTRUCTIONS 40069
|
||||
#define ID_INFO_PROFILE 40070
|
||||
#define ID_INFO_WRITEONLYREG 40071
|
||||
#define ID_TRACE_SETTINGS 40072
|
||||
#define ID_TRACE_ENABLE 40073
|
||||
#define ID_FILE_MRU_FILE1 40100
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 130
|
||||
#define _APS_NEXT_COMMAND_VALUE 40072
|
||||
#define _APS_NEXT_CONTROL_VALUE 1136
|
||||
#define _APS_NEXT_RESOURCE_VALUE 131
|
||||
#define _APS_NEXT_COMMAND_VALUE 40074
|
||||
#define _APS_NEXT_CONTROL_VALUE 1143
|
||||
#define _APS_NEXT_SYMED_VALUE 109
|
||||
#endif
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue