[Scummvm-git-logs] scummvm master -> 5ba26fdf35e3358dad4bca5c3e5aa7a4e62c202c
sev-
noreply at scummvm.org
Sat Mar 4 22:38:49 UTC 2023
This automated email contains information about 10 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
a359ee1316 COMMON: Fix build when zlib not present
387ceddef1 AUDIO: Use 49170 Hz instead of 44100 Hz for the FreeMiNT platform
06c9928f3a COMMON: gfx_mode is not always propagated
9285e5a66e COMMON: Fix null graphics backend without USE_RGB_COLOR
4d21a496d2 BACKENDS: ATARI: Add new backend (graphics, mixer, platform)
276cf354bf BACKENDS: ATARI: Separate AtariEventSource from OSystem_Atari
72f6c4ef61 SCUMM: Increase {min,max}HeapThreshold for ATARI
896d7cf309 BACKENDS: ATARI: Use "saves" directory for savegames
4892d0b48b CONFIGURE: Adjustments for ATARI
5ba26fdf35 GRAPHICS: ATARI: Introduce accelerated blitting
Commit: a359ee131676b2ef308dc2b4f78df4068fcb19c8
https://github.com/scummvm/scummvm/commit/a359ee131676b2ef308dc2b4f78df4068fcb19c8
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2023-03-04T23:38:42+01:00
Commit Message:
COMMON: Fix build when zlib not present
Changed paths:
common/compression/vise.cpp
diff --git a/common/compression/vise.cpp b/common/compression/vise.cpp
index 83bfbe25d3d..c1ada443a78 100644
--- a/common/compression/vise.cpp
+++ b/common/compression/vise.cpp
@@ -185,10 +185,14 @@ Common::SeekableReadStream *MacVISEArchive::ArchiveMember::createReadStream() co
//
// If this turns out to be significant, then this will need to be updated to pass information to the deflate decompressor to
// handle the non-standard behavior.
+#if defined(USE_ZLIB)
if (!Common::inflateZlibHeaderless(decompressedData, uncompressedSize, &compressedData[0], compressedSize)) {
free(decompressedData);
return nullptr;
}
+#else
+ return nullptr;
+#endif
return new Common::MemoryReadStream(decompressedData, uncompressedSize, DisposeAfterUse::YES);
}
Commit: 387ceddef1d1ec302898708c5efab28951cc55d3
https://github.com/scummvm/scummvm/commit/387ceddef1d1ec302898708c5efab28951cc55d3
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2023-03-04T23:38:42+01:00
Commit Message:
AUDIO: Use 49170 Hz instead of 44100 Hz for the FreeMiNT platform
Changed paths:
backends/mixer/sdl/sdl-mixer.cpp
diff --git a/backends/mixer/sdl/sdl-mixer.cpp b/backends/mixer/sdl/sdl-mixer.cpp
index ae3ff5dfeac..e7d773e6ad3 100644
--- a/backends/mixer/sdl/sdl-mixer.cpp
+++ b/backends/mixer/sdl/sdl-mixer.cpp
@@ -33,6 +33,8 @@
#define SAMPLES_PER_SEC 11025
#elif defined(PLAYSTATION3) || defined(PSP2) || defined(NINTENDO_SWITCH)
#define SAMPLES_PER_SEC 48000
+#elif defined(__MINT__)
+#define SAMPLES_PER_SEC 49170
#else
#define SAMPLES_PER_SEC 44100
#endif
Commit: 06c9928f3a09a0a2e5f7087e9a14be4612345e24
https://github.com/scummvm/scummvm/commit/06c9928f3a09a0a2e5f7087e9a14be4612345e24
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2023-03-04T23:38:42+01:00
Commit Message:
COMMON: gfx_mode is not always propagated
Changed paths:
engines/engine.cpp
diff --git a/engines/engine.cpp b/engines/engine.cpp
index dc93286b88a..b295e90d43f 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -223,6 +223,14 @@ void initCommonGFX() {
if (gameDomain->contains("shader"))
g_system->setShader(ConfMan.get("shader"));
+
+ // TODO: switching between OpenGL and SurfaceSDL is quite fragile
+ // and the SDL backend doesn't really need this so leave it out
+ // for now to avoid regressions
+#ifndef SDL_BACKEND
+ if (gameDomain->contains("gfx_mode"))
+ g_system->setGraphicsMode(ConfMan.get("gfx_mode").c_str());
+#endif
}
}
Commit: 9285e5a66e1ddba14441361b4311c629d6dca490
https://github.com/scummvm/scummvm/commit/9285e5a66e1ddba14441361b4311c629d6dca490
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2023-03-04T23:38:42+01:00
Commit Message:
COMMON: Fix null graphics backend without USE_RGB_COLOR
Changed paths:
backends/graphics/null/null-graphics.h
diff --git a/backends/graphics/null/null-graphics.h b/backends/graphics/null/null-graphics.h
index 60437e23238..885b0c99266 100644
--- a/backends/graphics/null/null-graphics.h
+++ b/backends/graphics/null/null-graphics.h
@@ -32,6 +32,7 @@ public:
void setFeatureState(OSystem::Feature f, bool enable) override {}
bool getFeatureState(OSystem::Feature f) const override { return false; }
+#ifdef USE_RGB_COLOR
Graphics::PixelFormat getScreenFormat() const override {
return _format;
}
@@ -46,6 +47,7 @@ public:
list.push_back(Graphics::PixelFormat::createFormatCLUT8());
return list;
}
+#endif
void initSize(uint width, uint height, const Graphics::PixelFormat *format = NULL) override {
_width = width;
Commit: 4d21a496d2c216fcdf5e43dc2dead92ef31da09e
https://github.com/scummvm/scummvm/commit/4d21a496d2c216fcdf5e43dc2dead92ef31da09e
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2023-03-04T23:38:42+01:00
Commit Message:
BACKENDS: ATARI: Add new backend (graphics, mixer, platform)
Compile as:
./configure --backend=atari --host=m68k-atari-mint --enable-release --disable-mt32emu --disable-lua --disable-nuked-opl --disable-16bit --disable-scalers --disable-translation --disable-eventrecorder --disable-tts --disable-bink --opengl-mode=none --enable-verbose-build --prefix=/usr --bindir=/ --datarootdir=share --datadir=data && make -j 16 && m68k-atari-mint-flags -S -r ./scummvm && make install DESTDIR=$PWD/_release/ && mv $PWD/_release/scummvm $PWD/_release/scummvm.ttp
Changed paths:
A backends/graphics/atari/atari-graphics-asm.S
A backends/graphics/atari/atari-graphics-asm.h
A backends/graphics/atari/atari-graphics-superblitter.h
A backends/graphics/atari/atari-graphics-supervidel.h
A backends/graphics/atari/atari-graphics-videl.h
A backends/graphics/atari/atari-graphics.cpp
A backends/graphics/atari/atari-graphics.h
A backends/graphics/atari/atari_c2p-asm.S
A backends/graphics/atari/atari_c2p-asm.h
A backends/graphics/atari/videl-resolutions.cpp
A backends/graphics/atari/videl-resolutions.h
A backends/mixer/atari/atari-mixer.cpp
A backends/mixer/atari/atari-mixer.h
A backends/platform/atari/atari.cpp
A backends/platform/atari/atari_ikbd.S
A backends/platform/atari/module.mk
A backends/platform/atari/native_features.cpp
A backends/platform/atari/readme.txt
backends/module.mk
configure
diff --git a/backends/graphics/atari/atari-graphics-asm.S b/backends/graphics/atari/atari-graphics-asm.S
new file mode 100644
index 00000000000..aa2a40a0e46
--- /dev/null
+++ b/backends/graphics/atari/atari-graphics-asm.S
@@ -0,0 +1,354 @@
+/* ScummVM - Graphic Adventure Engine
+*
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY| without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+ .globl _asm_screen_tt_save
+ .globl _asm_screen_falcon_save
+
+ .globl _asm_screen_tt_restore
+ .globl _asm_screen_falcon_restore
+
+ .globl _asm_screen_set_tt_palette
+ .globl _asm_screen_set_falcon_palette
+
+ .globl _asm_screen_set_vram
+ .globl _asm_screen_set_scp_res
+
+ .globl _vbl_counter
+
+ .text
+
+| extern void asm_screen_tt_save(void);
+|
+_asm_screen_tt_save:
+ bsr wait_vbl | avoid flickering
+
+ lea 0xffff8400.w,a0
+ lea save_pal,a1
+ moveq #256/2-1,d0
+
+tt_save_loop:
+ move.l (a0)+,(a1)+
+ dbra d0,tt_save_loop
+
+ lea save_video,a1
+ move.l 0xffff8200.w,(a1)+ | vidhm
+ move.w 0xffff820c.w,(a1)+ | vidl
+ move.w 0xffff8262.w,(a1)+ | tt shifter
+ rts
+
+| extern void asm_screen_falcon_save(void);
+|
+_asm_screen_falcon_save:
+ movem.l d2-d7/a2,-(sp)
+
+ bsr wait_vbl | avoid flickering
+
+ lea 0xffff9800.w,a0 | save falcon palette
+ lea save_pal,a1 |
+ moveq #256/2-1,d7 |
+ |
+falcon_save_loop:
+ move.l (a0)+,(a1)+ |
+ move.l (a0)+,(a1)+ |
+ dbra d7,falcon_save_loop |
+
+ movem.l 0xffff8240.w,d0-d7 | save st palette
+ movem.l d0-d7,(a1) |
+
+ lea save_video,a0
+ move.l 0xffff8200.w,(a0)+ | vidhm
+ move.w 0xffff820c.w,(a0)+ | vidl
+
+ move.l 0xffff8282.w,(a0)+ | h-regs
+ move.l 0xffff8286.w,(a0)+ |
+ move.l 0xffff828a.w,(a0)+ |
+
+ move.l 0xffff82a2.w,(a0)+ | v-regs
+ move.l 0xffff82a6.w,(a0)+ |
+ move.l 0xffff82aa.w,(a0)+ |
+
+ move.w 0xffff82c0.w,(a0)+ | vco
+ move.w 0xffff82c2.w,(a0)+ | c_s
+
+ move.l 0xffff820e.w,(a0)+ | offset+width
+ move.w 0xffff820a.w,(a0)+ | sync
+
+ move.b 0xffff8265.w,(a0)+ | p_o
+
+ cmpi.w #0xb0,0xffff8282.w | st(e) / falcon test
+ sle (a0)+ | it's a falcon resolution
+
+ move.w 0xffff8266.w,(a0)+ | f_s
+ move.w 0xffff8260.w,(a0)+ | st_s
+
+ | install custom VBL handler
+ move sr,-(sp)
+ or #0x700,sr
+
+ move.l 0x70.w,old_vbl
+ move.l #vbl,0x70.w
+
+ move (sp)+,sr
+
+ movem.l (sp)+,d2-d7/a2
+ rts
+
+| extern void asm_screen_tt_restore(void);
+|
+_asm_screen_tt_restore:
+ bsr wait_vbl | avoid flickering
+
+ lea save_video,a1
+ move.l (a1)+,0xffff8200.w | vidhm
+ move.w (a1)+,0xffff820c.w | vidl
+ move.w (a1)+,0xffff8262.w | tt shifter
+
+ lea save_pal,a0
+ lea 0xffff8400.w,a1
+ moveq #256/2-1,d0
+
+.loop: move.l (a0)+,(a1)+
+ dbra d0,.loop
+ rts
+
+| extern void asm_screen_falcon_restore(void);
+|
+_asm_screen_falcon_restore:
+ movem.l d2-d7/a2,-(sp)
+
+ | uninstall custom VBL handler
+ move sr,-(sp)
+ or #0x700,sr
+
+ move.l old_vbl,0x70.w
+
+ move (sp)+,sr
+
+ bsr wait_vbl | avoid flickering
+
+ lea save_video,a0
+
+ move.l (a0)+,0xffff8200.w | videobase_address:h&m
+ move.w (a0)+,0xffff820c.w | l
+
+ move.l (a0)+,0xffff8282.w | h-regs
+ move.l (a0)+,0xffff8286.w |
+ move.l (a0)+,0xffff828a.w |
+
+ move.l (a0)+,0xffff82a2.w | v-regs
+ move.l (a0)+,0xffff82a6.w |
+ move.l (a0)+,0xffff82aa.w |
+
+ move.w (a0)+,0xffff82c0.w | vco
+ move.w (a0)+,0xffff82c2.w | c_s
+
+ move.l (a0)+,0xffff820e.w | offset+width
+ move.w (a0)+,0xffff820a.w | sync
+
+ move.b (a0)+,0xffff8265.w | p_o
+
+ tst.b (a0)+ | st(e) compatible mode?
+ bne falcon_restore_st_comp | yes
+
+falcon_restore_falcon:
+ move.l a0,-(sp)
+ bsr wait_vbl | Patch to avoid
+ clr.w 0xffff8266.w | monochrome sync errors
+ bsr wait_vbl | (ripped from
+ move.l (sp)+,a0 | FreeMiNT kernel,
+ move.w (a0),0xffff8266.w | by Draco/Yescrew)
+
+ bra falcon_restore_restored
+
+falcon_restore_st_comp:
+ move.w (a0)+,0xffff8266.w | falcon-shift
+ move.w (a0),0xffff8260.w | st-shift
+ lea save_video,a0
+ move.w 32(a0),0xffff82c2.w | c_s
+ move.l 34(a0),0xffff820e.w | offset+width
+
+falcon_restore_restored:
+ lea save_pal,a0 | restore falcon palette
+ lea 0xffff9800.w,a1 |
+ moveq #128-1,d7 |
+ |
+falcon_restore_loop:
+ move.l (a0)+,(a1)+ |
+ move.l (a0)+,(a1)+ |
+ dbra d7,falcon_restore_loop |
+
+ movem.l (a0),d0-d7 | restore st palette
+ movem.l d0-d7,0xffff8240.w |
+
+ movem.l (sp)+,d2-d7/a2
+ rts
+
+| extern void asm_screen_set_tt_palette(const uint16 pPalette[256]);
+|
+_asm_screen_set_tt_palette:
+ move.l (4,sp),a0
+ lea 0xffff8400.w,a1
+ moveq #256/2-1,d0
+
+set_tt_palette_loop:
+ move.l (a0)+,(a1)+
+ dbra d0,set_tt_palette_loop
+ rts
+
+| extern void asm_screen_set_falcon_palette(const uint32 pPalette[256]);
+|
+_asm_screen_set_falcon_palette:
+ move.l (4,sp),a0
+ lea pending_palette,a1
+ moveq #256/2-1,d0
+
+set_falcon_palette_loop:
+ move.l (a0)+,(a1)+
+ move.l (a0)+,(a1)+
+ dbra d0,set_falcon_palette_loop
+
+ addq.w #1,has_pending_palette
+ rts
+
+| extern void asm_screen_set_vram(const void* pScreen);
+|
+_asm_screen_set_vram:
+ move.l (4,sp),pending_vram
+
+ addq.w #1,has_pending_vram
+ rts
+
+| void asm_screen_set_scp_res(const void* pScp);
+|
+_asm_screen_set_scp_res:
+ move.l (4,sp),a0
+ lea (122,a0),a0
+ lea pending_scp,a1
+ moveq #(158-122)/4-1,d0
+set_scp_res_loop:
+ move.l (a0)+,(a1)+
+ dbra d0,set_scp_res_loop
+
+ addq.w #1,has_pending_scp
+ rts
+
+wait_vbl:
+ move.w #0x25,-(sp) | Vsync()
+ trap #14 |
+ addq.l #2,sp |
+ rts
+
+ .ascii "XBRA"
+ .ascii "SCUM"
+old_vbl:
+ dc.l 0
+vbl:
+ movem.l d0-d1/a0-a1,-(sp)
+
+ addq.l #1,0x0462.w | _vbclock
+ addq.l #1,0x0466.w | _frclock
+ addq.l #1,_vbl_counter | to avoid accessing protected memory
+
+ tst.w has_pending_scp
+ beq.b vbl_no_pending_scp
+
+ lea pending_scp,a0
+ move.l (a0)+,0xffff8282.w
+ move.l (a0)+,0xffff8286.w
+ move.l (a0)+,0xffff828a.w
+ move.l (a0)+,0xffff82a2.w
+ move.l (a0)+,0xffff82a6.w
+ move.l (a0)+,0xffff82aa.w
+ move.w (a0)+,0xffff820a.w
+ move.w (a0)+,0xffff82c0.w
+ clr.w 0xffff8266.w
+ tst.w (a0)+
+ bne.b vbl_st
+
+vbl_falcon:
+ move.w (a0)+,0xffff8266.w
+ bra.b vbl_skip
+
+vbl_st: addq.l #1,a0
+ move.b (a0)+,0xffff8260.w
+
+vbl_skip:
+ move.w (a0)+,0xffff82c2.w
+ move.w (a0)+,0xffff8210.w
+
+ clr.w has_pending_scp
+vbl_no_pending_scp:
+
+ tst.w has_pending_vram
+ beq.b vbl_no_pending_vram
+
+ move.l pending_vram,d0
+ move.l d0,d1
+ lsr.w #8,d0
+ move.l d0,0xffff8200.w
+ move.b d1,0xffff820d.w
+
+ clr.w has_pending_vram
+vbl_no_pending_vram:
+
+ tst.w has_pending_palette
+ beq.b vbl_no_pending_palette
+
+ lea pending_palette,a0
+ lea 0xffff9800.w,a1
+ moveq #256/2-1,d0
+
+vbl_falcon_palette_loop:
+ move.l (a0)+,(a1)+
+ move.l (a0)+,(a1)+
+ dbra d0,vbl_falcon_palette_loop
+
+ clr.w has_pending_palette
+
+vbl_no_pending_palette:
+ movem.l (sp)+,d0-d1/a0-a1
+ rte
+
+
+ .bss
+ .even
+
+has_pending_scp:
+ ds.w 1
+has_pending_vram:
+ ds.w 1
+has_pending_palette:
+ ds.w 1
+
+pending_scp:
+ ds.b 158-122 | pending SCP resolution data
+pending_vram:
+ ds.l 1 | pending vram pointer
+pending_palette:
+ ds.l 256 | pending palette
+
+save_pal:
+ ds.l 256+16/2 | old colours (sized for falcon+ste palette)
+save_video:
+ ds.b 32+12+2 | old video regs (size of falcon regs)
+
+_vbl_counter:
+ ds.l 1
diff --git a/backends/graphics/atari/atari-graphics-asm.h b/backends/graphics/atari/atari-graphics-asm.h
new file mode 100644
index 00000000000..a13f6c29d93
--- /dev/null
+++ b/backends/graphics/atari/atari-graphics-asm.h
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_ATARI_ASM_H
+#define BACKENDS_GRAPHICS_ATARI_ASM_H
+
+#include "common/scummsys.h"
+
+extern "C" {
+
+/**
+ * Save Atari TT video registers.
+ */
+void asm_screen_tt_save(void);
+/**
+ * Save Atari Falcon video registers.
+ */
+void asm_screen_falcon_save(void);
+
+/**
+ * Restore Atari TT video registers.
+ */
+void asm_screen_tt_restore(void);
+/**
+ * Restore Atari Falcon video registers.
+ */
+void asm_screen_falcon_restore(void);
+
+/**
+ * Set Atari TT palette.
+ * @param pPalette 256 palette entries (0000 RRRR GGGG BBBB)
+ */
+void asm_screen_set_tt_palette(const uint16 pPalette[256]);
+/**
+ * Set Atari Falcon palette.
+ * @param pPalette 256 palette entries (RRRRRRrr GGGGGGgg 00000000 BBBBBBbb)
+ */
+void asm_screen_set_falcon_palette(const uint32 pPalette[256]);
+
+/**
+ * Set Atari TT/Falcon video base.
+ */
+void asm_screen_set_vram(const void* pScreen);
+
+/**
+ * Set Atari Falcon Videl resolution (Screenspain's SCP format).
+ */
+void asm_screen_set_scp_res(const void* pScp);
+
+}
+
+#endif
diff --git a/backends/graphics/atari/atari-graphics-superblitter.h b/backends/graphics/atari/atari-graphics-superblitter.h
new file mode 100644
index 00000000000..fb295b554a0
--- /dev/null
+++ b/backends/graphics/atari/atari-graphics-superblitter.h
@@ -0,0 +1,53 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_ATARI_SUPERBLITTER_H
+#define BACKENDS_GRAPHICS_ATARI_SUPERBLITTER_H
+
+#include <mint/trap14.h>
+
+#define ct60_vm(mode, value) (long)trap_14_wwl((short)0xc60e, (short)(mode), (long)(value))
+#define ct60_vmalloc(value) ct60_vm(0, value)
+#define ct60_vmfree(value) ct60_vm(1, value)
+
+// bits 26:0
+#define SV_BLITTER_SRC1 ((volatile long*)0x80010058)
+#define SV_BLITTER_SRC2 ((volatile long*)0x8001005C)
+#define SV_BLITTER_DST ((volatile long*)0x80010060)
+// The amount of bytes that are to be copied in a horizontal line, minus 1
+#define SV_BLITTER_COUNT ((volatile long*)0x80010064)
+// The amount of bytes that are to be added to the line start adress after a line has been copied, in order to reach the next one
+#define SV_BLITTER_SRC1_OFFSET ((volatile long*)0x80010068)
+#define SV_BLITTER_SRC2_OFFSET ((volatile long*)0x8001006C)
+#define SV_BLITTER_DST_OFFSET ((volatile long*)0x80010070)
+// bits 11:0 - The amount of horizontal lines to do
+#define SV_BLITTER_MASK_AND_LINES ((volatile long*)0x80010074)
+// bit 0 - busy / start
+// bits 4:1 - blit mode
+#define SV_BLITTER_CONTROL ((volatile long*)0x80010078)
+// bits 9:0
+#define SV_VERSION ((volatile long*)0x8001007C)
+// bit 0 - empty (read only)
+// bit 1 - full (read only)
+// bits 31:0 - data (write only)
+#define SV_BLITTER_FIFO ((volatile long*)0x80010080)
+
+#endif
diff --git a/backends/graphics/atari/atari-graphics-supervidel.h b/backends/graphics/atari/atari-graphics-supervidel.h
new file mode 100644
index 00000000000..e7e98b38b5d
--- /dev/null
+++ b/backends/graphics/atari/atari-graphics-supervidel.h
@@ -0,0 +1,201 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_ATARI_SUPERVIDEL_H
+#define BACKENDS_GRAPHICS_ATARI_SUPERVIDEL_H
+
+#define USE_SV_BLITTER // TODO: into configure?
+
+#include "backends/graphics/atari/atari-graphics.h"
+
+#include <cstring>
+#include <mint/osbind.h>
+
+#ifdef USE_SV_BLITTER
+#include "backends/graphics/atari/atari-graphics-superblitter.h"
+#endif
+
+#include "backends/graphics/atari/videl-resolutions.h"
+#include "common/scummsys.h"
+#include "common/textconsole.h" // for error()
+
+class AtariSuperVidelManager : public AtariGraphicsManager {
+public:
+ AtariSuperVidelManager() {
+#ifdef USE_SV_BLITTER
+ _fwVersion = *SV_VERSION & 0x01ff;
+ debug("SuperVidel FW Revision: %d, using %s", _fwVersion, _fwVersion >= 9
+ ? "fast async FIFO" : "slower sync blitting" );
+#endif
+
+ for (int i = 0; i < SCREENS; ++i) {
+ if (!allocateAtariSurface(_screen[i], _screenSurface,
+ SCREEN_WIDTH, SCREEN_HEIGHT, PIXELFORMAT8,
+ MX_STRAM, 0xA0000000))
+ error("Failed to allocate screen memory in ST RAM");
+ _screenAligned[i] = (byte*)_screenSurface.getPixels();
+ }
+ _screenSurface.setPixels(_screenAligned[getDefaultGraphicsMode() <= 1 ? FRONT_BUFFER : BACK_BUFFER1]);
+
+ if (!allocateAtariSurface(_chunkyBuffer, _chunkySurface,
+ SCREEN_WIDTH, SCREEN_HEIGHT, PIXELFORMAT8,
+ MX_PREFTTRAM))
+ error("Failed to allocate chunky buffer memory in ST/TT RAM");
+
+ if (!allocateAtariSurface(_overlayScreen, _screenOverlaySurface,
+ getOverlayWidth(), getOverlayHeight(), getOverlayFormat(),
+ MX_STRAM, 0xA0000000))
+ error("Failed to allocate overlay memory in ST RAM");
+
+ if (!allocateAtariSurface(_overlayBuffer, _overlaySurface,
+ getOverlayWidth(), getOverlayHeight(), getOverlayFormat(),
+ MX_PREFTTRAM))
+ error("Failed to allocate overlay buffer memory in ST/TT RAM");
+
+ // patch SPSHIFT for SuperVidel's BPS8C
+ for (byte *p : {scp_320x200x8_vga, scp_320x240x8_vga, scp_640x400x8_vga, scp_640x480x8_vga}) {
+ uint16 *p16 = (uint16*)(p + 122 + 30);
+ *p16 |= 0x1000;
+ }
+ }
+
+ ~AtariSuperVidelManager() {
+#ifdef USE_SV_BLITTER
+ ct60_vmfree(_chunkyBuffer);
+#else
+ Mfree(_chunkyBuffer);
+#endif
+ _chunkyBuffer = nullptr;
+
+#ifdef USE_SV_BLITTER
+ ct60_vmfree(_overlayBuffer);
+#else
+ Mfree(_overlayBuffer);
+#endif
+ _overlayBuffer = nullptr;
+ }
+
+ virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const override {
+ static const OSystem::GraphicsMode graphicsModes[] = {
+ {"direct", "Direct rendering", 0},
+ {"single", "Single buffering", 1},
+ {"double", "Double buffering", 2},
+ {"triple", "Triple buffering", 3},
+ {nullptr, nullptr, 0 }
+ };
+ return graphicsModes;
+ }
+
+ int16 getOverlayHeight() const override { return 2 * OVERLAY_HEIGHT; }
+ int16 getOverlayWidth() const override { return 2 * OVERLAY_WIDTH; }
+
+private:
+ virtual void* allocFast(size_t bytes) const override {
+#ifdef USE_SV_BLITTER
+ return (void*)ct60_vmalloc(bytes);
+#else
+ return (void*)Mxalloc(bytes, MX_PREFTTRAM);
+#endif
+ }
+
+ void copySurfaceToSurface(const Graphics::Surface &srcSurface, Graphics::Surface &dstSurface) const override {
+#ifdef USE_SV_BLITTER
+ if (_fwVersion >= 9) {
+ *SV_BLITTER_FIFO = (long)srcSurface.getPixels(); // SV_BLITTER_SRC1
+ *SV_BLITTER_FIFO = 0x00000000; // SV_BLITTER_SRC2
+ *SV_BLITTER_FIFO = (long)dstSurface.getPixels(); // SV_BLITTER_DST
+ *SV_BLITTER_FIFO = srcSurface.w - 1; // SV_BLITTER_COUNT
+ *SV_BLITTER_FIFO = srcSurface.pitch; // SV_BLITTER_SRC1_OFFSET
+ *SV_BLITTER_FIFO = 0x00000000; // SV_BLITTER_SRC2_OFFSET
+ *SV_BLITTER_FIFO = dstSurface.pitch; // SV_BLITTER_DST_OFFSET
+ *SV_BLITTER_FIFO = srcSurface.h; // SV_BLITTER_MASK_AND_LINES
+ *SV_BLITTER_FIFO = 0x01; // SV_BLITTER_CONTROL
+ } else {
+ sync();
+
+ *SV_BLITTER_SRC1 = (long)srcSurface.getPixels();
+ *SV_BLITTER_SRC2 = 0x00000000;
+ *SV_BLITTER_DST = (long)dstSurface.getPixels();
+ *SV_BLITTER_COUNT = srcSurface.w - 1;
+ *SV_BLITTER_SRC1_OFFSET = srcSurface.pitch;
+ *SV_BLITTER_SRC2_OFFSET = 0x00000000;
+ *SV_BLITTER_DST_OFFSET = dstSurface.pitch;
+ *SV_BLITTER_MASK_AND_LINES = srcSurface.h;
+ *SV_BLITTER_CONTROL = 0x01;
+ }
+#else
+ memcpy(dstSurface.getPixels(), srcSurface.getPixels(), srcSurface.h * srcSurface.pitch);
+#endif
+ }
+
+ void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY, Graphics::Surface &dstSurface,
+ const Common::Rect &subRect) const override {
+#ifdef USE_SV_BLITTER
+ if (_fwVersion >= 9) {
+ *SV_BLITTER_FIFO = (long)srcSurface.getBasePtr(subRect.left, subRect.top); // SV_BLITTER_SRC1
+ *SV_BLITTER_FIFO = 0x00000000; // SV_BLITTER_SRC2
+ *SV_BLITTER_FIFO = (long)dstSurface.getBasePtr(destX, destY); // SV_BLITTER_DST
+ *SV_BLITTER_FIFO = subRect.width() - 1; // SV_BLITTER_COUNT
+ *SV_BLITTER_FIFO = srcSurface.pitch; // SV_BLITTER_SRC1_OFFSET
+ *SV_BLITTER_FIFO = 0x00000000; // SV_BLITTER_SRC2_OFFSET
+ *SV_BLITTER_FIFO = dstSurface.pitch; // SV_BLITTER_DST_OFFSET
+ *SV_BLITTER_FIFO = subRect.height(); // SV_BLITTER_MASK_AND_LINES
+ *SV_BLITTER_FIFO = 0x01; // SV_BLITTER_CONTROL
+ } else {
+ sync();
+
+ *SV_BLITTER_SRC1 = (long)srcSurface.getBasePtr(subRect.left, subRect.top);
+ *SV_BLITTER_SRC2 = 0x00000000;
+ *SV_BLITTER_DST = (long)dstSurface.getBasePtr(destX, destY);
+ *SV_BLITTER_COUNT = subRect.width() - 1;
+ *SV_BLITTER_SRC1_OFFSET = srcSurface.pitch;
+ *SV_BLITTER_SRC2_OFFSET = 0x00000000;
+ *SV_BLITTER_DST_OFFSET = dstSurface.pitch;
+ *SV_BLITTER_MASK_AND_LINES = subRect.height();
+ *SV_BLITTER_CONTROL = 0x01;
+ }
+#else
+ dstSurface.copyRectToSurface(srcSurface, destX, destY, subRect);
+#endif
+ }
+
+ void copyRectToSurfaceWithKey(const Graphics::Surface &srcSurface, int destX, int destY, Graphics::Surface &dstSurface,
+ const Common::Rect &subRect, uint32 key) const override {
+ sync();
+ dstSurface.copyRectToSurfaceWithKey(srcSurface, destX, destY, subRect, key);
+ }
+
+ virtual void sync() const override {
+#ifdef USE_SV_BLITTER
+ // while FIFO not empty...
+ if (_fwVersion >= 9)
+ while (!(*SV_BLITTER_FIFO & 1));
+ // while busy blitting...
+ while (*SV_BLITTER_CONTROL & 1);
+#endif
+ }
+
+#ifdef USE_SV_BLITTER
+ int _fwVersion = 0;
+#endif
+};
+
+#endif
diff --git a/backends/graphics/atari/atari-graphics-videl.h b/backends/graphics/atari/atari-graphics-videl.h
new file mode 100644
index 00000000000..6771085e79d
--- /dev/null
+++ b/backends/graphics/atari/atari-graphics-videl.h
@@ -0,0 +1,162 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_ATARI_VIDEL_H
+#define BACKENDS_GRAPHICS_ATARI_VIDEL_H
+
+#include "backends/graphics/atari/atari-graphics.h"
+
+#include <mint/osbind.h>
+
+#include "backends/graphics/atari/atari_c2p-asm.h"
+#include "common/system.h"
+#include "common/textconsole.h" // for error()
+
+class AtariVidelManager : public AtariGraphicsManager {
+public:
+ AtariVidelManager() {
+ for (int i = 0; i < SCREENS; ++i) {
+ if (!allocateAtariSurface(_screen[i], _screenSurface, SCREEN_WIDTH, SCREEN_HEIGHT, PIXELFORMAT8, MX_STRAM))
+ error("Failed to allocate screen memory in ST RAM");
+ _screenAligned[i] = (byte*)_screenSurface.getPixels();
+ }
+ _screenSurface.setPixels(_screenAligned[getDefaultGraphicsMode() <= 1 ? FRONT_BUFFER : BACK_BUFFER1]);
+
+ if (!allocateAtariSurface(_chunkyBuffer, _chunkySurface, SCREEN_WIDTH, SCREEN_HEIGHT, PIXELFORMAT8, MX_PREFTTRAM))
+ error("Failed to allocate chunky buffer memory in ST/TT RAM");
+
+ if (!allocateAtariSurface(_overlayScreen, _screenOverlaySurface, getOverlayWidth(), getOverlayHeight(),
+ getOverlayFormat(), MX_STRAM))
+ error("Failed to allocate overlay memory in ST RAM");
+
+ if (!allocateAtariSurface(_overlayBuffer, _overlaySurface, getOverlayWidth(), getOverlayHeight(),
+ getOverlayFormat(), MX_PREFTTRAM))
+ error("Failed to allocate overlay buffer memory in ST/TT RAM");
+ }
+
+ ~AtariVidelManager() {
+ Mfree(_chunkyBuffer);
+ _chunkyBuffer = nullptr;
+
+ Mfree(_overlayBuffer);
+ _overlayBuffer = nullptr;
+ }
+
+ virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const override {
+ static const OSystem::GraphicsMode graphicsModes[] = {
+ {"single", "Single buffering", 1},
+ {"double", "Double buffering", 2},
+ {"triple", "Triple buffering", 3},
+ {nullptr, nullptr, 0 }
+ };
+ return graphicsModes;
+ }
+
+ OSystem::TransactionError endGFXTransaction() override {
+ int error = OSystem::TransactionError::kTransactionSuccess;
+
+ if (_pendingState.mode == GraphicsMode::DirectRendering)
+ error |= OSystem::TransactionError::kTransactionModeSwitchFailed;
+
+ if (error != OSystem::TransactionError::kTransactionSuccess) {
+ // all our errors are fatal but engine.cpp takes only this one seriously
+ error |= OSystem::TransactionError::kTransactionSizeChangeFailed;
+ return static_cast<OSystem::TransactionError>(error);
+ }
+
+ return AtariGraphicsManager::endGFXTransaction();
+ }
+
+ int16 getOverlayHeight() const override { return _vgaMonitor ? OVERLAY_HEIGHT : 2 * OVERLAY_HEIGHT; }
+ int16 getOverlayWidth() const override { return _vgaMonitor ? OVERLAY_WIDTH : 2 * OVERLAY_WIDTH; }
+
+private:
+ virtual void* allocFast(size_t bytes) const override {
+ return (void*)Mxalloc(bytes, MX_PREFTTRAM);
+ }
+
+ void copySurfaceToSurface(const Graphics::Surface &srcSurface, Graphics::Surface &dstSurface) const override {
+ asm_c2p1x1_8(
+ (const byte*)srcSurface.getPixels(),
+ (const byte*)srcSurface.getBasePtr(srcSurface.w, srcSurface.h-1),
+ (byte*)dstSurface.getPixels());
+ }
+
+ void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY,
+ Graphics::Surface &dstSurface, const Common::Rect &subRect) const override {
+ // 'pChunkyEnd' is a delicate parameter: the c2p routine compares it to the address register
+ // used for pixel reading; two common mistakes:
+ // 1. (subRect.left, subRect.bottom) = beginning of the next line *including the offset*
+ // 2. (subRect.right, subRect.bottom) = even worse, end of the *next* line, not current one
+ asm_c2p1x1_8_rect(
+ (const byte*)srcSurface.getBasePtr(subRect.left, subRect.top),
+ (const byte*)srcSurface.getBasePtr(subRect.right, subRect.bottom-1),
+ subRect.width(),
+ srcSurface.pitch,
+ (byte*)dstSurface.getBasePtr(destX, destY),
+ dstSurface.pitch);
+ }
+
+ // TODO: allow specifying different background than _chunkySurface?
+ void copyRectToSurfaceWithKey(const Graphics::Surface &srcSurface, int destX, int destY,
+ Graphics::Surface &dstSurface, const Common::Rect &subRect, uint32 key) const override {
+ Common::Rect backgroundRect(destX, destY, destX + subRect.width(), destY + subRect.height());
+
+ // ensure that background's left and right lie on a 16px boundary and double the width if needed
+ backgroundRect.moveTo(backgroundRect.left & 0xfff0, backgroundRect.top);
+
+ const int deltaX = destX - backgroundRect.left;
+
+ backgroundRect.right = (backgroundRect.right + deltaX + 15) & 0xfff0;
+ if (backgroundRect.right > _chunkySurface.w)
+ backgroundRect.right = _chunkySurface.w;
+
+ static Graphics::Surface cachedSurface;
+
+ if (cachedSurface.w != backgroundRect.width() || cachedSurface.h != backgroundRect.height()) {
+ cachedSurface.create(
+ backgroundRect.width(),
+ backgroundRect.height(),
+ _chunkySurface.format);
+ }
+
+ // copy background
+ cachedSurface.copyRectToSurface(_chunkySurface, 0, 0, backgroundRect);
+ // copy cursor
+ cachedSurface.copyRectToSurfaceWithKey(srcSurface, deltaX, 0, subRect, key);
+
+ copyRectToSurface(
+ cachedSurface,
+ backgroundRect.left, backgroundRect.top,
+ dstSurface,
+ Common::Rect(cachedSurface.w, cachedSurface.h));
+ }
+
+ void alignRect(const Graphics::Surface &srcSurface, Common::Rect &rect) const override {
+ // align on 16px
+ rect.left &= 0xfff0;
+ rect.right = (rect.right + 15) & 0xfff0;
+ if (rect.right > srcSurface.w)
+ rect.right = srcSurface.w;
+ }
+};
+
+#endif
diff --git a/backends/graphics/atari/atari-graphics.cpp b/backends/graphics/atari/atari-graphics.cpp
new file mode 100644
index 00000000000..462d7385553
--- /dev/null
+++ b/backends/graphics/atari/atari-graphics.cpp
@@ -0,0 +1,1011 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "backends/graphics/atari/atari-graphics.h"
+
+#include <mint/cookie.h>
+#include <mint/falcon.h>
+#include <mint/osbind.h>
+
+#include "backends/graphics/atari/atari-graphics-asm.h"
+#include "backends/graphics/atari/videl-resolutions.h"
+#include "backends/keymapper/action.h"
+#include "backends/keymapper/keymap.h"
+
+#include "common/config-manager.h"
+#include "common/str.h"
+#include "common/textconsole.h" // for warning() & error()
+#include "common/translation.h"
+#include "graphics/blit.h"
+#include "gui/ThemeEngine.h"
+
+#define SCREEN_ACTIVE
+
+AtariGraphicsManager::AtariGraphicsManager() {
+ _vgaMonitor = VgetMonitor() == MON_VGA;
+
+ // make the standard GUI renderer default (!DISABLE_FANCY_THEMES implies anti-aliased rendering in ThemeEngine.cpp)
+ // (and without DISABLE_FANCY_THEMES we can't use 640x480 themes)
+ const char *standardThemeEngineName = GUI::ThemeEngine::findModeConfigName(GUI::ThemeEngine::kGfxStandard);
+ ConfMan.registerDefault("gui_renderer", standardThemeEngineName);
+ if (!ConfMan.hasKey("gui_renderer"))
+ ConfMan.set("gui_renderer", standardThemeEngineName);
+
+ // make the built-in theme default to avoid long loading times
+ ConfMan.registerDefault("gui_theme", "builtin");
+ if (!ConfMan.hasKey("gui_theme"))
+ ConfMan.set("gui_theme", "builtin");
+
+ // make "data" the default theme path (defining DATA_PATH as "data"
+ // is forbidden, it must be an absolute path, see bug #14174)
+ ConfMan.registerDefault("themepath", "data");
+ if (!ConfMan.hasKey("themepath"))
+ ConfMan.set("themepath", "data");
+
+ ConfMan.flushToDisk();
+
+ g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);
+}
+
+AtariGraphicsManager::~AtariGraphicsManager() {
+ g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
+
+ for (int i = 0; i < SCREENS; ++i) {
+ Mfree(_screen[i]);
+ _screen[i] = _screenAligned[i] = nullptr;
+ }
+
+ Mfree(_overlayScreen);
+ _overlayScreen = nullptr;
+}
+
+bool AtariGraphicsManager::hasFeature(OSystem::Feature f) const {
+ switch (f) {
+ case OSystem::Feature::kFeatureAspectRatioCorrection:
+ debug("hasFeature(kFeatureAspectRatioCorrection): %d", !_vgaMonitor);
+ return !_vgaMonitor;
+ case OSystem::Feature::kFeatureCursorPalette:
+ debug("hasFeature(kFeatureCursorPalette): %d", isOverlayVisible());
+ return isOverlayVisible();
+ case OSystem::Feature::kFeatureVSync:
+ debug("hasFeature(kFeatureVSync): %d", _vsync);
+ return true;
+ default:
+ return false;
+ }
+}
+
+void AtariGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
+ switch (f) {
+ case OSystem::Feature::kFeatureAspectRatioCorrection:
+ debug("setFeatureState(kFeatureAspectRatioCorrection): %d", enable);
+ _oldAspectRatioCorrection = _aspectRatioCorrection;
+ _aspectRatioCorrection = enable;
+ break;
+ case OSystem::Feature::kFeatureVSync:
+ debug("setFeatureState(kFeatureVSync): %d", enable);
+ _vsync = enable;
+ break;
+ default:
+ [[fallthrough]];
+ }
+}
+
+bool AtariGraphicsManager::getFeatureState(OSystem::Feature f) const {
+ switch (f) {
+ case OSystem::Feature::kFeatureAspectRatioCorrection:
+ //debug("getFeatureState(kFeatureAspectRatioCorrection): %d", _aspectRatioCorrection);
+ return _aspectRatioCorrection;
+ case OSystem::Feature::kFeatureCursorPalette:
+ //debug("getFeatureState(kFeatureCursorPalette): %d", isOverlayVisible());
+ return isOverlayVisible();
+ case OSystem::Feature::kFeatureVSync:
+ //debug("getFeatureState(kFeatureVSync): %d", _vsync);
+ return _vsync;
+ default:
+ return false;
+ }
+}
+
+bool AtariGraphicsManager::setGraphicsMode(int mode, uint flags) {
+ debug("setGraphicsMode: %d, %d", mode, flags);
+
+ if (mode >= 0 && mode <= 3) {
+ _pendingState.mode = (GraphicsMode)mode;
+ return true;
+ }
+
+ return false;
+}
+
+void AtariGraphicsManager::initSize(uint width, uint height, const Graphics::PixelFormat *format) {
+ debug("initSize: %d, %d, %d (vsync: %d, mode: %d)", width, height, format ? format->bytesPerPixel : 1, _vsync, (int)_pendingState.mode);
+
+ _pendingState.width = width;
+ _pendingState.height = height;
+ _pendingState.format = format ? *format : PIXELFORMAT8;
+}
+
+void AtariGraphicsManager::beginGFXTransaction() {
+ debug("beginGFXTransaction");
+}
+
+OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
+ debug("endGFXTransaction");
+
+ int error = OSystem::TransactionError::kTransactionSuccess;
+
+ // always initialize (clear screen, mouse init, ...)
+ //if (_pendingState == _currentState)
+ // return static_cast<OSystem::TransactionError>(error);
+
+ if (_pendingState.format != PIXELFORMAT8)
+ error |= OSystem::TransactionError::kTransactionFormatNotSupported;
+
+ // TODO: Several engines support unusual resolutions like 256x240 (NES Maniac Mansion),
+ // 512x342 (MacVenture, WAGE) or 544x332 (Myst)
+ if ((_pendingState.width != 320 || (_pendingState.height != 200 && _pendingState.height != 240))
+ && (_pendingState.width != 640 || (_pendingState.height != 400 && _pendingState.height != 480)))
+ error |= OSystem::TransactionError::kTransactionSizeChangeFailed;
+
+ if (error != OSystem::TransactionError::kTransactionSuccess) {
+ // all our errors are fatal but engine.cpp takes only this one seriously
+ error |= OSystem::TransactionError::kTransactionSizeChangeFailed;
+ return static_cast<OSystem::TransactionError>(error);
+ }
+
+ _chunkySurface.init(_pendingState.width, _pendingState.height, _pendingState.width,
+ _chunkySurface.getPixels(), _pendingState.format);
+ _screenSurface.init(_pendingState.width, _pendingState.height, _pendingState.width,
+ _screenAligned[(int)_pendingState.mode <= 1 ? FRONT_BUFFER : BACK_BUFFER1], _screenSurface.format);
+
+ // some games do not initialize their viewport entirely
+ if (_pendingState.mode != GraphicsMode::DirectRendering) {
+ memset(_chunkySurface.getPixels(), 0, _chunkySurface.pitch * _chunkySurface.h);
+
+ if (_pendingState.mode == GraphicsMode::SingleBuffering)
+ handleModifiedRect(_chunkySurface, Common::Rect(_chunkySurface.w, _chunkySurface.h), _modifiedChunkyRects);
+ else
+ _screenModified = true;
+ } else {
+ memset(_screenSurface.getPixels(), 0, _screenSurface.pitch * _screenSurface.h);
+ }
+
+ memset(_palette, 0, sizeof(_palette));
+ _pendingScreenChange = kPendingScreenChangeScreen | kPendingScreenChangePalette;
+
+ static bool firstRun = true;
+ if (firstRun) {
+ _cursor.setPosition(getOverlayWidth() / 2, getOverlayHeight() / 2, true);
+ _cursor.swap();
+ firstRun = false;
+ }
+
+ // reinitialize old cursor position, there's no use for it anymore and it's dangerous
+ // to let it set to possibly bigger values then the upcoming resolution
+ _oldCursorRect = Common::Rect();
+
+ warpMouse(_pendingState.width / 2, _pendingState.height / 2);
+
+ _currentState = _pendingState;
+
+ return OSystem::kTransactionSuccess;
+}
+
+void AtariGraphicsManager::setPalette(const byte *colors, uint start, uint num) {
+ //debug("setPalette: %d, %d", start, num);
+
+ memcpy(&_palette[start * 3], colors, num * 3);
+ _pendingScreenChange |= kPendingScreenChangePalette;
+}
+
+void AtariGraphicsManager::grabPalette(byte *colors, uint start, uint num) const {
+ //debug("grabPalette: %d, %d", start, num);
+
+ memcpy(colors, &_palette[start * 3], num * 3);
+}
+
+void AtariGraphicsManager::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) {
+ //debug("copyRectToScreen: %d, %d, %d, %d, %d", pitch, x, y, w, h);
+
+ if (_currentState.mode != GraphicsMode::DirectRendering) {
+ _chunkySurface.copyRectToSurface(buf, pitch, x, y, w, h);
+
+ if (_currentState.mode == GraphicsMode::SingleBuffering)
+ handleModifiedRect(_chunkySurface, Common::Rect(x, y, x + w, y + h), _modifiedChunkyRects);
+ else
+ _screenModified = true;
+ } else {
+ // TODO: c2p with 16pix align
+ _screenSurface.copyRectToSurface(buf, pitch, x, y, w, h);
+
+ _modifiedScreenRect = Common::Rect(x, y, x + w, y + h);
+
+ bool vsync = _vsync;
+ _vsync = false;
+ updateScreen();
+ _vsync = vsync;
+ }
+}
+
+Graphics::Surface *AtariGraphicsManager::lockScreen() {
+ //debug("lockScreen");
+
+ return _currentState.mode != GraphicsMode::DirectRendering ? &_chunkySurface : &_screenSurface;
+}
+
+void AtariGraphicsManager::unlockScreen() {
+ if (_currentState.mode != GraphicsMode::DirectRendering) {
+ if (_currentState.mode == GraphicsMode::SingleBuffering)
+ handleModifiedRect(_chunkySurface, Common::Rect(_chunkySurface.w, _chunkySurface.h), _modifiedChunkyRects);
+ else
+ _screenModified = true;
+ } else {
+ _modifiedScreenRect = Common::Rect(_screenSurface.w, _screenSurface.h);
+
+ bool vsync = _vsync;
+ _vsync = false;
+ updateScreen();
+ _vsync = vsync;
+ }
+}
+
+void AtariGraphicsManager::fillScreen(uint32 col) {
+ debug("fillScreen: %d", col);
+
+ if (_currentState.mode != GraphicsMode::DirectRendering) {
+ const Common::Rect rect = Common::Rect(_chunkySurface.w, _chunkySurface.h);
+ _chunkySurface.fillRect(rect, col);
+
+ if (_currentState.mode == GraphicsMode::SingleBuffering)
+ handleModifiedRect(_chunkySurface, rect, _modifiedChunkyRects);
+ else
+ _screenModified = true;
+ } else {
+ const Common::Rect rect = Common::Rect(_screenSurface.w, _screenSurface.h);
+ _screenSurface.fillRect(rect, col);
+ }
+}
+
+void AtariGraphicsManager::updateScreen() {
+ //debug("updateScreen");
+
+ // updates outOfScreen OR srcRect/dstRect (only if visible/needed)
+ _cursor.update(isOverlayVisible() ? _screenOverlaySurface : _screenSurface);
+
+ bool screenUpdated = false;
+
+ if (isOverlayVisible()) {
+ screenUpdated = updateOverlay();
+ } else {
+ switch(_currentState.mode) {
+ case GraphicsMode::DirectRendering:
+ screenUpdated = updateDirectBuffer();
+ break;
+ case GraphicsMode::SingleBuffering:
+ screenUpdated = updateSingleBuffer();
+ break;
+ case GraphicsMode::DoubleBuffering:
+ case GraphicsMode::TripleBuffering:
+ screenUpdated = updateDoubleAndTripleBuffer();
+ break;
+ }
+ }
+
+ //if (_cursor.outOfScreen)
+ // warning("mouse out of screen");
+
+ bool vsync = _vsync;
+
+ if (_screenModified) {
+ sync();
+
+ if (_currentState.mode == GraphicsMode::DoubleBuffering) {
+ byte *tmp = _screenAligned[FRONT_BUFFER];
+ _screenAligned[FRONT_BUFFER] = _screenAligned[BACK_BUFFER1];
+ _screenAligned[BACK_BUFFER1] = tmp;
+
+ // always wait for vbl
+ vsync = true;
+ } else if (_currentState.mode == GraphicsMode::TripleBuffering) {
+ if (vsync) {
+ // render into BACK_BUFFER1 and/or BACK_BUFFER2 and set the most recent one
+ _screenAligned[FRONT_BUFFER] = _screenAligned[BACK_BUFFER1];
+
+ byte *tmp = _screenAligned[BACK_BUFFER1];
+ _screenAligned[BACK_BUFFER1] = _screenAligned[BACK_BUFFER2];
+ _screenAligned[BACK_BUFFER2] = tmp;
+ } else {
+ // render into BACK_BUFFER1 and/or BACK_BUFFER2 and/or FRONT_BUFFER
+ byte *tmp = _screenAligned[FRONT_BUFFER];
+ _screenAligned[FRONT_BUFFER] = _screenAligned[BACK_BUFFER1];
+ _screenAligned[BACK_BUFFER1] = _screenAligned[BACK_BUFFER2];
+ _screenAligned[BACK_BUFFER2] = tmp;
+ }
+
+ // never wait for vbl (use it only as a flag for the modes above)
+ vsync = false;
+ }
+
+#ifdef SCREEN_ACTIVE
+ asm_screen_set_vram(_screenAligned[FRONT_BUFFER]);
+#endif
+ _screenSurface.setPixels(_screenAligned[BACK_BUFFER1]);
+ _screenModified = false;
+ }
+
+ // everything below this line is done in VBL so don't wait if nothing has been updated!
+ vsync &= screenUpdated;
+
+#ifdef SCREEN_ACTIVE
+ bool resolutionChanged = false;
+
+ if (_pendingScreenChange & kPendingScreenChangeOverlay) {
+ if (_vgaMonitor) {
+ if (getOverlayWidth() == 640 && getOverlayHeight() == 480)
+ asm_screen_set_scp_res(scp_640x480x16_vga);
+ else
+ asm_screen_set_scp_res(scp_320x240x16_vga);
+ } else {
+ //asm_screen_set_scp_res(scp_320x240x16_rgb);
+ asm_screen_set_scp_res(scp_640x480x16_rgb);
+ }
+
+ asm_screen_set_vram(_screenOverlaySurface.getPixels());
+ resolutionChanged = true;
+ }
+
+ if (_pendingScreenChange & kPendingScreenChangeScreen) {
+ setVidelResolution();
+ asm_screen_set_vram(_screenAligned[FRONT_BUFFER]);
+ resolutionChanged = true;
+ }
+
+ if ((_pendingScreenChange & kPendingScreenChangePalette) && !isOverlayVisible()) {
+ static uint falconPalette[256];
+
+ for (uint i = 0; i < 256; ++i) {
+ // RRRRRRRR GGGGGGGG BBBBBBBB -> RRRRRRrr GGGGGGgg 00000000 BBBBBBbb
+ falconPalette[i] = (_palette[i * 3 + 0] << 24) | (_palette[i * 3 + 1] << 16) | _palette[i * 3 + 2];
+ }
+#ifdef SCREEN_ACTIVE
+ asm_screen_set_falcon_palette(falconPalette);
+#endif
+ }
+
+ _pendingScreenChange = kPendingScreenChangeNone;
+
+ if (_oldAspectRatioCorrection != _aspectRatioCorrection) {
+ if (!isOverlayVisible() && !resolutionChanged) {
+ setVidelResolution();
+ }
+ _oldAspectRatioCorrection = _aspectRatioCorrection;
+ }
+
+ if (vsync)
+ waitForVbl();
+#endif
+ //debug("end of updateScreen");
+}
+
+void AtariGraphicsManager::setShakePos(int shakeXOffset, int shakeYOffset) {
+ debug("setShakePos: %d, %d", shakeXOffset, shakeYOffset);
+}
+
+void AtariGraphicsManager::showOverlay(bool inGUI) {
+ debug("showOverlay");
+
+ if (_overlayVisible)
+ return;
+
+ _pendingScreenChange &= ~kPendingScreenChangeScreen;
+ _pendingScreenChange |= kPendingScreenChangeOverlay;
+
+ _cursor.swap();
+ if (_currentState.mode == GraphicsMode::DirectRendering) {
+ // make sure that _oldCursorRect is used to restore the original game graphics
+ // (but only if resolution hasn't changed, see endGFXTransaction())
+ bool wasVisible = showMouse(false);
+ updateDirectBuffer();
+ showMouse(wasVisible);
+ }
+
+ _overlayVisible = true;
+}
+
+void AtariGraphicsManager::hideOverlay() {
+ debug("hideOverlay");
+
+ if (!_overlayVisible)
+ return;
+
+ _pendingScreenChange &= ~kPendingScreenChangeOverlay;
+ _pendingScreenChange |= kPendingScreenChangeScreen;
+
+ _cursor.swap();
+ // don't fool game cursor logic (especially direct rendering)
+ // (the overlay doesn't need any restoration upon re-entering)
+ _oldCursorRect = Common::Rect();
+
+ _overlayVisible = false;
+}
+
+void AtariGraphicsManager::clearOverlay() {
+ debug("clearOverlay");
+
+ if (!_overlayVisible)
+ return;
+
+ const Graphics::Surface &sourceSurface = _currentState.mode == GraphicsMode::DirectRendering ? _screenSurface : _chunkySurface;
+
+ int w = sourceSurface.w;
+ int h = sourceSurface.h;
+ int vOffset = 0;
+
+ if (h == 200) {
+ h = 240;
+ vOffset = (240 - 200) / 2;
+ } else if (h == 400) {
+ h = 480;
+ vOffset = (480 - 400) / 2;
+ }
+
+ ScaleMode scaleMode;
+ if (w == _overlaySurface.w && h == _overlaySurface.h) {
+ scaleMode = ScaleMode::NONE;
+ } else if (w / _overlaySurface.w == 2 && h / _overlaySurface.h == 2) {
+ scaleMode = ScaleMode::DOWNSCALE;
+ vOffset /= 2;
+ } else if (_overlaySurface.w / w == 2 && _overlaySurface.h / h == 2) {
+ scaleMode = ScaleMode::UPSCALE;
+ vOffset *= 2;
+ } else {
+ warning("Unknown overlay (%d, %d) / screen (%d, %d) ratio: ",
+ _overlaySurface.w, _overlaySurface.h, w, h);
+ return;
+ }
+
+ memset(_overlaySurface.getBasePtr(0, 0), 0, _overlaySurface.pitch * vOffset);
+ copySurface8ToSurface16(
+ sourceSurface,
+ _palette,
+ _overlaySurface,
+ 0, vOffset,
+ Common::Rect(sourceSurface.w, sourceSurface.h),
+ scaleMode);
+ memset(_overlaySurface.getBasePtr(0, _overlaySurface.h - vOffset), 0, _overlaySurface.pitch * vOffset);
+
+ handleModifiedRect(_overlaySurface, Common::Rect(_overlaySurface.w, _overlaySurface.h), _modifiedOverlayRects);
+}
+
+void AtariGraphicsManager::grabOverlay(Graphics::Surface &surface) const {
+ debug("grabOverlay: %d, %d, %d", surface.pitch, surface.w, surface.h);
+
+ memcpy(surface.getPixels(), _overlaySurface.getPixels(), surface.pitch * surface.h);
+}
+
+void AtariGraphicsManager::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) {
+ //debug("copyRectToOverlay: %d, %d, %d, %d, %d", pitch, x, y, w, h);
+
+ _overlaySurface.copyRectToSurface(buf, pitch, x, y, w, h);
+
+ handleModifiedRect(_overlaySurface, Common::Rect(x, y, x + w, y + h), _modifiedOverlayRects);
+}
+
+bool AtariGraphicsManager::showMouse(bool visible) {
+ //debug("showMouse: %d", visible);
+
+ if (_cursor.visible == visible) {
+ return visible;
+ }
+
+ bool last = _cursor.visible;
+ _cursor.visible = visible;
+ return last;
+}
+
+void AtariGraphicsManager::warpMouse(int x, int y) {
+ //debug("warpMouse: %d, %d", x, y);
+
+ _cursor.setPosition(x, y, true);
+}
+
+void AtariGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor,
+ bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
+ //debug("setMouseCursor: %d, %d, %d, %d, %d, %d", w, h, hotspotX, hotspotY, keycolor, format ? format->bytesPerPixel : 1);
+
+ const Graphics::PixelFormat cursorFormat = format ? *format : PIXELFORMAT8;
+ _cursor.setSurface(buf, (int)w, (int)h, hotspotX, hotspotY, keycolor, cursorFormat);
+}
+
+void AtariGraphicsManager::setCursorPalette(const byte *colors, uint start, uint num) {
+ debug("setCursorPalette: %d, %d", start, num);
+
+ memcpy(&_cursor.palette[start * 3], colors, num * 3);
+ _cursor.surfaceChanged = true;
+}
+
+void AtariGraphicsManager::updateMousePosition(int deltaX, int deltaY) {
+ _cursor.updatePosition(deltaX, deltaY, isOverlayVisible() ? _screenOverlaySurface : _screenSurface);
+}
+
+bool AtariGraphicsManager::notifyEvent(const Common::Event &event) {
+ if (event.type != Common::EVENT_CUSTOM_BACKEND_ACTION_START) {
+ return false;
+ }
+
+ switch ((CustomEventAction) event.customType) {
+ case kActionToggleAspectRatioCorrection:
+ _aspectRatioCorrection = !_aspectRatioCorrection;
+ return true;
+ }
+
+ return false;
+}
+
+Common::Keymap *AtariGraphicsManager::getKeymap() const {
+ Common::Keymap *keymap = new Common::Keymap(Common::Keymap::kKeymapTypeGlobal, "atari-graphics", _("Graphics"));
+ Common::Action *act;
+
+ if (hasFeature(OSystem::kFeatureAspectRatioCorrection)) {
+ act = new Common::Action("ASPT", _("Toggle aspect ratio correction"));
+ act->addDefaultInputMapping("C+A+a");
+ act->setCustomBackendActionEvent(kActionToggleAspectRatioCorrection);
+ keymap->addAction(act);
+ }
+
+ return keymap;
+}
+
+bool AtariGraphicsManager::allocateAtariSurface(
+ byte *&buf, Graphics::Surface &surface, int width, int height,
+ const Graphics::PixelFormat &format, int mode, uintptr mask) {
+ buf = (mode == MX_STRAM)
+ ? (byte*)Mxalloc(width * height * format.bytesPerPixel + 15, mode)
+ : (byte*)allocFast(width * height * format.bytesPerPixel + 15);
+
+ if (!buf)
+ return false;
+
+ byte *bufAligned = (byte*)((((uintptr)buf + 15) | mask) & 0xfffffff0);
+ memset(bufAligned, 0, width * height * format.bytesPerPixel);
+
+ surface.init(width, height, width * format.bytesPerPixel, bufAligned, format);
+ return true;
+}
+
+void AtariGraphicsManager::setVidelResolution() const {
+ if (_vgaMonitor) {
+ // TODO: aspect ratio correction
+ // TODO: supervidel 320x240...
+ if (_screenSurface.w == 320) {
+ if (_screenSurface.h == 200)
+ asm_screen_set_scp_res(scp_320x200x8_vga);
+ else
+ asm_screen_set_scp_res(scp_320x240x8_vga);
+ } else {
+ if (_screenSurface.h == 400)
+ asm_screen_set_scp_res(scp_640x400x8_vga);
+ else
+ asm_screen_set_scp_res(scp_640x480x8_vga);
+ }
+ } else {
+ if (_screenSurface.w == 320) {
+ if (_screenSurface.h == 240)
+ asm_screen_set_scp_res(scp_320x240x8_rgb);
+ else if (_screenSurface.h == 200 && _aspectRatioCorrection)
+ asm_screen_set_scp_res(scp_320x200x8_rgb60);
+ else
+ asm_screen_set_scp_res(scp_320x200x8_rgb);
+ } else {
+ if (_screenSurface.h == 480)
+ asm_screen_set_scp_res(scp_640x480x8_rgb);
+ else if (_screenSurface.h == 400 && _aspectRatioCorrection)
+ asm_screen_set_scp_res(scp_640x400x8_rgb60);
+ else
+ asm_screen_set_scp_res(scp_640x400x8_rgb);
+ }
+ }
+}
+
+void AtariGraphicsManager::waitForVbl() const {
+ extern volatile uint32 vbl_counter;
+ uint32 counter = vbl_counter;
+
+ while (counter == vbl_counter);
+}
+
+bool AtariGraphicsManager::updateOverlay() {
+ bool updated = false;
+ bool drawCursor = _cursor.isModified();
+
+ while (!_modifiedOverlayRects.empty()) {
+ const Common::Rect &rect = _modifiedOverlayRects.back();
+
+ if (!drawCursor && !_cursor.outOfScreen && _cursor.visible)
+ drawCursor = rect.intersects(_cursor.dstRect);
+
+ _screenOverlaySurface.copyRectToSurface(_overlaySurface, rect.left, rect.top, rect);
+
+ _modifiedOverlayRects.pop_back();
+
+ updated = true;
+ }
+
+ if (_cursor.outOfScreen)
+ return updated;
+
+ if ((_cursor.positionChanged || !_cursor.visible) && !_oldCursorRect.isEmpty()) {
+ _screenOverlaySurface.copyRectToSurface(_overlaySurface, _oldCursorRect.left, _oldCursorRect.top, _oldCursorRect);
+ _oldCursorRect = Common::Rect();
+
+ updated = true;
+ }
+
+ if (drawCursor && _cursor.visible) {
+ //debug("Redraw cursor (overlay): %d %d %d %d", _cursor.dstRect.left, _cursor.dstRect.top, _cursor.dstRect.width(), _cursor.dstRect.height());
+
+ copySurface8ToSurface16WithKey(
+ _cursor.surface,
+ _cursor.palette,
+ _screenOverlaySurface,
+ _cursor.dstRect.left, _cursor.dstRect.top,
+ _cursor.srcRect,
+ _cursor.keycolor);
+
+ _cursor.positionChanged = _cursor.surfaceChanged = false;
+ _oldCursorRect = _cursor.dstRect;
+
+ updated = true;
+ }
+
+ return updated;
+}
+
+bool AtariGraphicsManager::updateDirectBuffer() {
+ bool updated = false;
+
+ if (_cursor.outOfScreen)
+ return updated;
+
+ bool drawCursor = _cursor.isModified();
+
+ if (!drawCursor && _cursor.visible && !_modifiedScreenRect.isEmpty())
+ drawCursor = _modifiedScreenRect.intersects(_cursor.dstRect);
+
+ static Graphics::Surface cachedCursorSurface;
+
+ if (!_oldCursorRect.isEmpty() && !_modifiedScreenRect.isEmpty()) {
+ const Common::Rect intersectingRect = _modifiedScreenRect.findIntersectingRect(_oldCursorRect);
+ if (!intersectingRect.isEmpty()) {
+ // update cached surface
+ const Graphics::Surface intersectingScreenSurface = _screenSurface.getSubArea(intersectingRect);
+ cachedCursorSurface.copyRectToSurface(
+ intersectingScreenSurface,
+ intersectingRect.left - _oldCursorRect.left,
+ intersectingRect.top - _oldCursorRect.top,
+ Common::Rect(intersectingScreenSurface.w, intersectingScreenSurface.h));
+ }
+ }
+
+ _modifiedScreenRect = Common::Rect();
+
+ if ((_cursor.positionChanged || !_cursor.visible) && !_oldCursorRect.isEmpty()) {
+ _screenSurface.copyRectToSurface(
+ cachedCursorSurface,
+ _oldCursorRect.left, _oldCursorRect.top,
+ Common::Rect(_oldCursorRect.width(), _oldCursorRect.height()));
+
+ _oldCursorRect = Common::Rect();
+
+ updated = true;
+ }
+
+ if (drawCursor && _cursor.visible) {
+ //debug("Redraw cursor (direct): %d %d %d %d", _cursor.dstRect.left, _cursor.dstRect.top, _cursor.dstRect.width(), _cursor.dstRect.height());
+
+ if (cachedCursorSurface.w != _cursor.dstRect.width() || cachedCursorSurface.h != _cursor.dstRect.height()) {
+ cachedCursorSurface.create(_cursor.dstRect.width(), _cursor.dstRect.height(), _cursor.surface.format);
+ }
+
+ // background has been restored, so it's safe to read _screenSurface
+ if (_oldCursorRect.isEmpty())
+ cachedCursorSurface.copyRectToSurface(_screenSurface, 0, 0, _cursor.dstRect);
+
+ _screenSurface.copyRectToSurfaceWithKey(
+ _cursor.surface,
+ _cursor.dstRect.left, _cursor.dstRect.top,
+ _cursor.srcRect,
+ _cursor.keycolor);
+
+ _cursor.positionChanged = _cursor.surfaceChanged = false;
+ _oldCursorRect = _cursor.dstRect;
+
+ updated = true;
+ }
+
+ return updated;
+}
+
+bool AtariGraphicsManager::updateSingleBuffer() {
+ bool updated = false;
+ bool drawCursor = _cursor.isModified();
+
+ while (!_modifiedChunkyRects.empty()) {
+ const Common::Rect &rect = _modifiedChunkyRects.back();
+
+ if (!drawCursor && !_cursor.outOfScreen && _cursor.visible)
+ drawCursor = rect.intersects(_cursor.dstRect);
+
+ if (rect.width() == _screenSurface.w && rect.height() == _screenSurface.h)
+ copySurfaceToSurface(_chunkySurface, _screenSurface);
+ else
+ copyRectToSurface(_chunkySurface, rect.left, rect.top, _screenSurface, rect);
+
+ _modifiedChunkyRects.pop_back();
+
+ updated = true;
+ }
+
+ if (_cursor.outOfScreen)
+ return updated;
+
+ if ((_cursor.positionChanged || !_cursor.visible) && !_oldCursorRect.isEmpty()) {
+ alignRect(_chunkySurface, _oldCursorRect);
+ copyRectToSurface(_chunkySurface, _oldCursorRect.left, _oldCursorRect.top,
+ _screenSurface, _oldCursorRect);
+
+ _oldCursorRect = Common::Rect();
+
+ updated = true;
+ }
+
+ if (drawCursor && _cursor.visible) {
+ //debug("Redraw cursor (single): %d %d %d %d", _cursor.dstRect.left, _cursor.dstRect.top, _cursor.dstRect.width(), _cursor.dstRect.height());
+ copyRectToSurfaceWithKey(_cursor.surface, _cursor.dstRect.left, _cursor.dstRect.top,
+ _screenSurface, _cursor.srcRect, _cursor.keycolor);
+
+ _cursor.positionChanged = _cursor.surfaceChanged = false;
+ _oldCursorRect = _cursor.dstRect;
+
+ updated = true;
+ }
+
+ return updated;
+}
+
+bool AtariGraphicsManager::updateDoubleAndTripleBuffer() {
+ bool updated = false;
+ bool drawCursor = _cursor.isModified();
+
+ if (_screenModified) {
+ drawCursor = true;
+
+ copySurfaceToSurface(_chunkySurface, _screenSurface);
+
+ // updated in screen swapping
+ //_screenModified = false;
+ updated = true;
+ }
+
+ if (_cursor.outOfScreen)
+ return updated;
+
+ // render directly to the screen to be swapped (so we don't have to refresh full screen when only cursor moves)
+ Graphics::Surface frontBufferScreenSurface;
+ frontBufferScreenSurface.init(_screenSurface.w, _screenSurface.h, _screenSurface.pitch,
+ _screenAligned[_screenModified ? BACK_BUFFER1 : FRONT_BUFFER], _screenSurface.format);
+
+ if ((_cursor.positionChanged || !_cursor.visible) && !_oldCursorRect.isEmpty() && !_screenModified) {
+ alignRect(_chunkySurface, _oldCursorRect);
+ copyRectToSurface(_chunkySurface, _oldCursorRect.left, _oldCursorRect.top,
+ frontBufferScreenSurface, _oldCursorRect);
+
+ _oldCursorRect = Common::Rect();
+
+ updated = true;
+ }
+
+ if (drawCursor && _cursor.visible) {
+ //debug("Redraw cursor (double/triple): %d %d %d %d", _cursor.dstRect.left, _cursor.dstRect.top, _cursor.dstRect.width(), _cursor.dstRect.height());
+
+ copyRectToSurfaceWithKey(_cursor.surface, _cursor.dstRect.left, _cursor.dstRect.top,
+ frontBufferScreenSurface, _cursor.srcRect, _cursor.keycolor);
+
+ _cursor.positionChanged = _cursor.surfaceChanged = false;
+ _oldCursorRect = _cursor.dstRect;
+
+ updated = true;
+ }
+
+ return updated;
+}
+
+void AtariGraphicsManager::copySurface8ToSurface16(
+ const Graphics::Surface &srcSurface, const byte *srcPalette,
+ Graphics::Surface &dstSurface, int destX, int destY,
+ const Common::Rect subRect, ScaleMode scaleMode) const {
+ assert(srcSurface.format.bytesPerPixel == 1);
+ assert(dstSurface.format.bytesPerPixel == 2);
+
+ // faster (no memory (re-)allocation) version of Surface::convertTo()
+ const int w = subRect.width();
+ const int h = subRect.height();
+
+ const int srcScale = scaleMode == ScaleMode::DOWNSCALE ? 2 : 1;
+ const byte *srcRow = (const byte*)srcSurface.getBasePtr(subRect.left * srcScale, subRect.top * srcScale);
+ uint16 *dstRow = (uint16*)dstSurface.getBasePtr(destX, destY); // already upscaled if needed
+
+ static uint32 srcPaletteMap[256];
+ Graphics::convertPaletteToMap(srcPaletteMap, srcPalette, 256, dstSurface.format);
+
+ // optimized paths for each case...
+ if (scaleMode == ScaleMode::NONE) {
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ *dstRow++ = srcPaletteMap[*srcRow++];
+ }
+
+ srcRow += srcSurface.w - w;
+ dstRow += dstSurface.w - w;
+ }
+ } else if (scaleMode == ScaleMode::DOWNSCALE) {
+ for (int y = 0; y < h / 2; y++) {
+ for (int x = 0; x < w / 2; x++) {
+ *dstRow++ = srcPaletteMap[*srcRow];
+ srcRow += 2;
+ }
+
+ srcRow += srcSurface.w - w + srcSurface.w;
+ dstRow += dstSurface.w - w / 2;
+ }
+ } else if (scaleMode == ScaleMode::UPSCALE) {
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ const uint16 pixel = srcPaletteMap[*srcRow++];
+
+ *(dstRow + dstSurface.w) = pixel;
+ *dstRow++ = pixel;
+ *(dstRow + dstSurface.w) = pixel;
+ *dstRow++ = pixel;
+ }
+
+ srcRow += srcSurface.w - w;
+ dstRow += dstSurface.w - w * 2 + dstSurface.w;
+ }
+ }
+}
+
+void AtariGraphicsManager::copySurface8ToSurface16WithKey(
+ const Graphics::Surface &srcSurface, const byte *srcPalette,
+ Graphics::Surface &dstSurface, int destX, int destY,
+ const Common::Rect subRect, uint32 key) const {
+ assert(srcSurface.format.bytesPerPixel == 1);
+ assert(dstSurface.format.bytesPerPixel == 2);
+
+ // faster (no memory (re-)allocation) version of Surface::convertTo()
+ const int w = subRect.width();
+ const int h = subRect.height();
+
+ const byte *srcRow = (const byte *)srcSurface.getBasePtr(subRect.left, subRect.top);
+ uint16 *dstRow = (uint16 *)dstSurface.getBasePtr(destX, destY);
+
+ static uint32 srcPaletteMap[256];
+ Graphics::convertPaletteToMap(srcPaletteMap, srcPalette, 256, dstSurface.format);
+
+ const uint16 keyColor = srcPaletteMap[key];
+
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ const uint16 pixel = srcPaletteMap[*srcRow++];
+
+ if (pixel != keyColor) {
+ *dstRow++ = pixel;
+ } else {
+ dstRow++;
+ }
+ }
+
+ srcRow += srcSurface.w - w;
+ dstRow += dstSurface.w - w;
+ }
+}
+
+void AtariGraphicsManager::handleModifiedRect(
+ const Graphics::Surface &surface,
+ Common::Rect rect, Common::Array<Common::Rect> &rects) const {
+ if (_currentState.mode == GraphicsMode::SingleBuffering)
+ alignRect(surface, rect);
+
+ if (rect.width() == surface.w && rect.height() == surface.h) {
+ //debug("handleModifiedRect: purge");
+
+ rects.clear();
+ rects.push_back(rect);
+ return;
+ }
+
+ for (const Common::Rect &r : rects) {
+ if (r.contains(rect))
+ return;
+ }
+
+ rects.push_back(rect);
+}
+
+void AtariGraphicsManager::Cursor::update(const Graphics::Surface &screen) {
+ if (!surface.getPixels()) {
+ outOfScreen = true;
+ return;
+ }
+
+ if (!visible || (!surfaceChanged && !positionChanged))
+ return;
+
+ srcRect = Common::Rect(surface.w, surface.h);
+
+ dstRect = Common::Rect(
+ x - hotspotX, // left
+ y - hotspotY, // top
+ x - hotspotX + surface.w, // right
+ y - hotspotY + surface.h); // bottom
+
+ outOfScreen = !screen.clip(srcRect, dstRect);
+}
+
+void AtariGraphicsManager::Cursor::updatePosition(int deltaX, int deltaY, const Graphics::Surface &screen) {
+ if (!visible)
+ return;
+
+ x += deltaX;
+ y += deltaY;
+
+ if (x < 0)
+ x = 0;
+ else if (x >= screen.w)
+ x = screen.w - 1;
+
+ if (y < 0)
+ y = 0;
+ else if (y >= screen.h)
+ y = screen.h - 1;
+
+ positionChanged = true;
+}
+
+void AtariGraphicsManager::Cursor::setSurface(const void *buf, int w, int h, int _hotspotX, int _hotspotY, uint32 _keycolor, const Graphics::PixelFormat &format) {
+ if (w == 0 || h == 0 || buf == nullptr) {
+ if (surface.getPixels())
+ surface.free();
+ return;
+ }
+
+ if (surface.w != w || surface.h != h || surface.format != format)
+ surface.create(w, h, format);
+
+ surface.copyRectToSurface(buf, surface.pitch, 0, 0, w, h);
+
+ hotspotX = _hotspotX;
+ hotspotY = _hotspotY;
+ keycolor = _keycolor;
+
+ surfaceChanged = true;
+}
diff --git a/backends/graphics/atari/atari-graphics.h b/backends/graphics/atari/atari-graphics.h
new file mode 100644
index 00000000000..277e2d6a269
--- /dev/null
+++ b/backends/graphics/atari/atari-graphics.h
@@ -0,0 +1,272 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_ATARI_H
+#define BACKENDS_GRAPHICS_ATARI_H
+
+#include "backends/graphics/graphics.h"
+
+#include "common/array.h"
+#include "common/events.h"
+#include "common/rect.h"
+#include "graphics/surface.h"
+
+// maximum screen dimensions
+constexpr int SCREEN_WIDTH = 640;
+constexpr int SCREEN_HEIGHT = 480;
+
+// minimum overlay dimensions
+constexpr int OVERLAY_WIDTH = 320;
+constexpr int OVERLAY_HEIGHT = 240;
+
+class AtariGraphicsManager : public GraphicsManager, Common::EventObserver {
+public:
+ AtariGraphicsManager();
+ virtual ~AtariGraphicsManager();
+
+ bool hasFeature(OSystem::Feature f) const override;
+ void setFeatureState(OSystem::Feature f, bool enable) override;
+ bool getFeatureState(OSystem::Feature f) const override;
+
+ int getDefaultGraphicsMode() const override { return (int)GraphicsMode::TripleBuffering; }
+ bool setGraphicsMode(int mode, uint flags = OSystem::kGfxModeNoFlags) override;
+ int getGraphicsMode() const override { return (int)_currentState.mode; }
+
+ void initSize(uint width, uint height, const Graphics::PixelFormat *format = NULL) override;
+
+ int getScreenChangeID() const override { return 0; }
+
+ void beginGFXTransaction() override;
+ OSystem::TransactionError endGFXTransaction() override;
+
+ int16 getHeight() const override { return _currentState.height; }
+ int16 getWidth() const override { return _currentState.width; }
+ void setPalette(const byte *colors, uint start, uint num) override;
+ void grabPalette(byte *colors, uint start, uint num) const override;
+ void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) override;
+ Graphics::Surface *lockScreen() override;
+ void unlockScreen() override;
+ void fillScreen(uint32 col) override;
+ void updateScreen() override;
+ void setShakePos(int shakeXOffset, int shakeYOffset) override;
+ void setFocusRectangle(const Common::Rect& rect) override {}
+ void clearFocusRectangle() override {}
+
+ void showOverlay(bool inGUI) override;
+ void hideOverlay() override;
+ bool isOverlayVisible() const override { return _overlayVisible; }
+ Graphics::PixelFormat getOverlayFormat() const override { return Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); }
+ void clearOverlay() override;
+ void grabOverlay(Graphics::Surface &surface) const override;
+ void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) override;
+
+ bool showMouse(bool visible) override;
+ void warpMouse(int x, int y) override;
+ void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor,
+ bool dontScale = false, const Graphics::PixelFormat *format = NULL, const byte *mask = NULL) override;
+ void setCursorPalette(const byte *colors, uint start, uint num) override;
+
+ Common::Point getMousePosition() const { return _cursor.getPosition(); }
+ void updateMousePosition(int deltaX, int deltaY);
+
+ bool notifyEvent(const Common::Event &event) override;
+ Common::Keymap *getKeymap() const;
+
+protected:
+ const Graphics::PixelFormat PIXELFORMAT8 = Graphics::PixelFormat::createFormatCLUT8();
+ const Graphics::PixelFormat PIXELFORMAT16 = getOverlayFormat();
+
+ bool allocateAtariSurface(byte *&buf, Graphics::Surface &surface,
+ int width, int height, const Graphics::PixelFormat &format,
+ int mode, uintptr mask = 0x00000000);
+
+ bool _vgaMonitor = true;
+
+ enum class GraphicsMode : int {
+ DirectRendering,
+ SingleBuffering,
+ DoubleBuffering,
+ TripleBuffering
+ };
+
+ struct GraphicsState {
+ bool operator==(const GraphicsState &other) const {
+ return mode == other.mode
+ && width == other.width
+ && height == other.height
+ && format == other.format;
+ }
+ bool operator!=(const GraphicsState &other) const {
+ return !(*this == other);
+ }
+
+ GraphicsMode mode;
+ int width;
+ int height;
+ Graphics::PixelFormat format;
+ };
+ GraphicsState _pendingState = {};
+
+ static const int SCREENS = 3;
+ static const int FRONT_BUFFER = 0;
+ static const int BACK_BUFFER1 = 1;
+ static const int BACK_BUFFER2 = 2;
+ byte *_screen[SCREENS] = {}; // for Mfree() purposes only
+ byte *_screenAligned[SCREENS] = {};
+ Graphics::Surface _screenSurface;
+
+ byte *_chunkyBuffer = nullptr; // for Mfree() purposes only
+ Graphics::Surface _chunkySurface;
+
+ byte *_overlayScreen = nullptr; // for Mfree() purposes only
+ Graphics::Surface _screenOverlaySurface;
+
+ byte *_overlayBuffer = nullptr; // for Mfree() purposes only
+ Graphics::Surface _overlaySurface;
+
+private:
+ enum CustomEventAction {
+ kActionToggleAspectRatioCorrection = 100,
+ };
+
+ void setVidelResolution() const;
+ void waitForVbl() const;
+
+ bool updateOverlay();
+ bool updateDirectBuffer();
+ bool updateSingleBuffer();
+ bool updateDoubleAndTripleBuffer();
+
+ virtual void* allocFast(size_t bytes) const = 0;
+
+ virtual void copySurfaceToSurface(const Graphics::Surface &srcSurface, Graphics::Surface &dstSurface) const = 0;
+ virtual void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY,
+ Graphics::Surface &dstSurface, const Common::Rect &subRect) const = 0;
+ virtual void copyRectToSurfaceWithKey(const Graphics::Surface &srcSurface, int destX, int destY,
+ Graphics::Surface &dstSurface, const Common::Rect &subRect, uint32 key) const = 0;
+ virtual void alignRect(const Graphics::Surface &srcSurface, Common::Rect &rect) const {}
+ virtual void sync() const {}
+
+ enum class ScaleMode {
+ NONE,
+ UPSCALE,
+ DOWNSCALE
+ };
+ void copySurface8ToSurface16(const Graphics::Surface &srcSurface, const byte *srcPalette,
+ Graphics::Surface &dstSurface, int destX, int destY,
+ const Common::Rect subRect, ScaleMode scaleMode) const;
+ void copySurface8ToSurface16WithKey(const Graphics::Surface &srcSurface, const byte* srcPalette,
+ Graphics::Surface &dstSurface, int destX, int destY,
+ const Common::Rect subRect, uint32 key) const;
+
+ void handleModifiedRect(const Graphics::Surface &surface, Common::Rect rect, Common::Array<Common::Rect> &rects) const;
+
+ void updateCursorRect();
+
+ bool _aspectRatioCorrection = false;
+ bool _oldAspectRatioCorrection = false;
+ bool _vsync = true;
+
+ GraphicsState _currentState = {};
+
+ enum PendingScreenChange {
+ kPendingScreenChangeNone = 0,
+ kPendingScreenChangeOverlay = 1<<0,
+ kPendingScreenChangeScreen = 1<<1,
+ kPendingScreenChangePalette = 1<<2
+ };
+ int _pendingScreenChange = kPendingScreenChangeNone;
+
+ bool _screenModified = false; // double/triple buffering only
+ Common::Rect _modifiedScreenRect; // direct rendering only
+
+ Common::Array<Common::Rect> _modifiedChunkyRects;
+
+ bool _overlayVisible = false;
+ Common::Array<Common::Rect> _modifiedOverlayRects;
+
+ struct Cursor {
+ void update(const Graphics::Surface &screen);
+
+ bool isModified() const {
+ return surfaceChanged || positionChanged;
+ }
+
+ bool visible = false;
+
+ // position
+ Common::Point getPosition() const {
+ return Common::Point(x, y);
+ }
+ void setPosition(int x_, int y_, bool override = false) {
+ if (x == x_ && y == y_)
+ return;
+
+ if (!visible && !override)
+ return;
+
+ x = x_;
+ y = y_;
+ positionChanged = true;
+ }
+ void updatePosition(int deltaX, int deltaY, const Graphics::Surface &screen);
+ bool positionChanged = false;
+ void swap() {
+ const int tmpX = oldX;
+ const int tmpY = oldY;
+
+ oldX = x;
+ oldY = y;
+
+ x = tmpX;
+ y = tmpY;
+
+ positionChanged = false;
+ }
+
+ // surface
+ void setSurface(const void *buf, int w, int h, int _hotspotX, int _hotspotY, uint32 _keycolor, const Graphics::PixelFormat &format);
+ bool surfaceChanged = false;
+ Graphics::Surface surface;
+ uint32 keycolor;
+
+ // rects (valid only if !outOfScreen)
+ bool outOfScreen = true;
+ Common::Rect srcRect;
+ Common::Rect dstRect;
+
+ // palette (only used for 16bpp screen surfaces)
+ byte palette[256*3] = {};
+
+ private:
+ int x = -1, y = -1;
+ int oldX = -1, oldY = -1;
+
+ int hotspotX;
+ int hotspotY;
+ } _cursor;
+
+ Common::Rect _oldCursorRect;
+
+ byte _palette[256*3] = {};
+};
+
+#endif
diff --git a/backends/graphics/atari/atari_c2p-asm.S b/backends/graphics/atari/atari_c2p-asm.S
new file mode 100644
index 00000000000..03b57afc380
--- /dev/null
+++ b/backends/graphics/atari/atari_c2p-asm.S
@@ -0,0 +1,474 @@
+/* ScummVM - Graphic Adventure Engine
+*
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY| without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+| C2P by Mikael Kalms (public domain)
+| See https://github.com/Kalmalyzer/kalms-c2p
+
+ .globl _asm_c2p1x1_8
+ .globl _asm_c2p1x1_8_rect
+
+
+ .text
+
+| void asm_c2p1x1_8(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen);
+_asm_c2p1x1_8:
+ move.l (4,sp),a0 | chunky
+ move.l (8,sp),d0 | chunky end
+ move.l (12,sp),a1 | screen
+ movem.l d2-d7/a2-a6,-(sp)
+ move.l d0,a2
+ move.l #0x0f0f0f0f,d4
+ move.l #0x00ff00ff,d5
+ move.l #0x55555555,d6
+
+ move.l (a0)+,d0
+ move.l (a0)+,d1
+ move.l (a0)+,d2
+ move.l (a0)+,d3
+
+ | a7a6a5a4a3a2a1a0 b7b6b5b4b3b2b1b0 c7c6c5c4c3c2c1c0 d7d6d5d4d3d2d1d0
+ | e7e6e5e4e3e2e1e0 f7f6f5f4f3f2f1f0 g7g6g5g4g3g2g1g0 h7h6h5h4h3h2h1h0
+ | i7i6i5i4i3i2i1i0 j7j6j5j4j3j2j1j0 k7k6k5k4k3k2k1k0 l7l6l5l4l3l2l1l0
+ | m7m6m5m4m3m2m1m0 n7n6n5n4n3n2n1n0 o7o6o5o4o3o2o1o0 p7p6p5p4p3p2p1p0
+
+ move.l d1,d7
+ lsr.l #4,d7
+ eor.l d0,d7
+ and.l d4,d7
+ eor.l d7,d0
+ lsl.l #4,d7
+ eor.l d7,d1
+ move.l d3,d7
+ lsr.l #4,d7
+ eor.l d2,d7
+ and.l d4,d7
+ eor.l d7,d2
+ lsl.l #4,d7
+ eor.l d7,d3
+
+ | a7a6a5a4e7e6e5e4 b7b6b5b4f7f6f5f4 c7c6c5c4g7g6g5g4 d7d6d5d4h7h6h5h4
+ | a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
+ | i7i6i5i4m7m6m5m4 j7j6j5j4n7n6n5n4 k7k6k5k4o7o6o5o4 l7l6l5l4p7p6p5p4
+ | i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
+
+ move.l d2,d7
+ lsr.l #8,d7
+ eor.l d0,d7
+ and.l d5,d7
+ eor.l d7,d0
+ lsl.l #8,d7
+ eor.l d7,d2
+ move.l d3,d7
+ lsr.l #8,d7
+ eor.l d1,d7
+ and.l d5,d7
+ eor.l d7,d1
+ lsl.l #8,d7
+ eor.l d7,d3
+
+ | a7a6a5a4e7e6e5e4 i7i6i5i4m7m6m5m4 c7c6c5c4g7g6g5g4 k7k6k5k4o7o6o5o4
+ | a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
+ | b7b6b5b4f7f6f5f4 j7j6j5j4n7n6n5n4 d7d6d5d4h7h6h5h4 l7l6l5l4p7p6p5p4
+ | b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
+
+ bra.s c2p1x1_8_start
+
+c2p1x1_8_pix16:
+ move.l (a0)+,d0
+ move.l (a0)+,d1
+ move.l (a0)+,d2
+ move.l (a0)+,d3
+
+ | a7a6a5a4a3a2a1a0 b7b6b5b4b3b2b1b0 c7c6c5c4c3c2c1c0 d7d6d5d4d3d2d1d0
+ | e7e6e5e4e3e2e1e0 f7f6f5f4f3f2f1f0 g7g6g5g4g3g2g1g0 h7h6h5h4h3h2h1h0
+ | i7i6i5i4i3i2i1i0 j7j6j5j4j3j2j1j0 k7k6k5k4k3k2k1k0 l7l6l5l4l3l2l1l0
+ | m7m6m5m4m3m2m1m0 n7n6n5n4n3n2n1n0 o7o6o5o4o3o2o1o0 p7p6p5p4p3p2p1p0
+
+ move.l d1,d7
+ lsr.l #4,d7
+ move.l a3,(a1)+
+ eor.l d0,d7
+ and.l d4,d7
+ eor.l d7,d0
+ lsl.l #4,d7
+ eor.l d7,d1
+ move.l d3,d7
+ lsr.l #4,d7
+ eor.l d2,d7
+ and.l d4,d7
+ eor.l d7,d2
+ move.l a4,(a1)+
+ lsl.l #4,d7
+ eor.l d7,d3
+
+ | a7a6a5a4e7e6e5e4 b7b6b5b4f7f6f5f4 c7c6c5c4g7g6g5g4 d7d6d5d4h7h6h5h4
+ | a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
+ | i7i6i5i4m7m6m5m4 j7j6j5j4n7n6n5n4 k7k6k5k4o7o6o5o4 l7l6l5l4p7p6p5p4
+ | i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
+
+ move.l d2,d7
+ lsr.l #8,d7
+ eor.l d0,d7
+ and.l d5,d7
+ eor.l d7,d0
+ move.l a5,(a1)+
+ lsl.l #8,d7
+ eor.l d7,d2
+ move.l d3,d7
+ lsr.l #8,d7
+ eor.l d1,d7
+ and.l d5,d7
+ eor.l d7,d1
+ move.l a6,(a1)+
+ lsl.l #8,d7
+ eor.l d7,d3
+
+ | a7a6a5a4e7e6e5e4 i7i6i5i4m7m6m5m4 c7c6c5c4g7g6g5g4 k7k6k5k4o7o6o5o4
+ | a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
+ | b7b6b5b4f7f6f5f4 j7j6j5j4n7n6n5n4 d7d6d5d4h7h6h5h4 l7l6l5l4p7p6p5p4
+ | b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
+
+c2p1x1_8_start:
+ move.l d2,d7
+ lsr.l #1,d7
+ eor.l d0,d7
+ and.l d6,d7
+ eor.l d7,d0
+ add.l d7,d7
+ eor.l d7,d2
+ move.l d3,d7
+ lsr.l #1,d7
+ eor.l d1,d7
+ and.l d6,d7
+ eor.l d7,d1
+ add.l d7,d7
+ eor.l d7,d3
+
+ | a7b7a5b5e7f7e5f5 i7j7i5j5m7n7m5n5 c7d7c5d5g7h7g5h5 k7l7k5l5o7p7o5p5
+ | a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1
+ | a6b6a4b4e6f6e4f4 i6j6i4j4m6n6m4n4 c6d6c4d4g6h6g4h4 k6l6k4l4o6p6o4p4
+ | a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
+
+ move.w d2,d7
+ move.w d0,d2
+ swap d2
+ move.w d2,d0
+ move.w d7,d2
+ move.w d3,d7
+ move.w d1,d3
+ swap d3
+ move.w d3,d1
+ move.w d7,d3
+
+ | a7b7a5b5e7f7e5f5 i7j7i5j5m7n7m5n5 a6b6a4b4e6f6e4f4 i6j6i4j4m6n6m4n4
+ | a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0
+ | c7d7c5d5g7h7g5h5 k7l7k5l5o7p7o5p5 c6d6c4d4g6h6g4h4 k6l6k4l4o6p6o4p4
+ | c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
+
+ move.l d2,d7
+ lsr.l #2,d7
+ eor.l d0,d7
+ and.l #0x33333333,d7
+ eor.l d7,d0
+ lsl.l #2,d7
+ eor.l d7,d2
+ move.l d3,d7
+ lsr.l #2,d7
+ eor.l d1,d7
+ and.l #0x33333333,d7
+ eor.l d7,d1
+ lsl.l #2,d7
+ eor.l d7,d3
+
+ | a7b7c7d7e7f7g7h7 i7j7k7l7m7n7o7p7 a6b6c6d6e6f6g6h6 i6j6k6l6m6n6o6p6
+ | a3b3c3d3e3f3g3h3 i3j3k3l3m3n3o3p3 a2b2c2d2e2f2g2h2 i2j2k2l2m2n2o2p2
+ | a5b5c5d5e5f5g5h5 i5j5k5l5m5n5o5p5 a4b4c4d4e4f4g4h4 i4j4k4l4m4n4o4p4
+ | a1b1c1d1e1f1g1h1 i1j1k1l1m1n1o1p1 a0b0c0d0e0f0g0h0 i0j0k0l0m0n0o0p0
+
+ swap d0
+ swap d1
+ swap d2
+ swap d3
+
+ move.l d0,a6
+ move.l d2,a5
+ move.l d1,a4
+ move.l d3,a3
+
+ cmp.l a0,a2
+ bne c2p1x1_8_pix16
+
+ move.l a3,(a1)+
+ move.l a4,(a1)+
+ move.l a5,(a1)+
+ move.l a6,(a1)+
+
+ movem.l (sp)+,d2-d7/a2-a6
+ rts
+
+
+| void asm_c2p1x1_8_rect(const byte *pChunky, const byte *pChunkyEnd, uint32 chunkyWidth, uint32 chunkyPitch, byte *pScreen, uint32 screenPitch);
+_asm_c2p1x1_8_rect:
+ movem.l d2-d7/a2-a6,-(sp) | 6 + 5 = 11 longs
+
+ move.l (11*4+4,sp),a0 | a0: chunky
+ move.l (11*4+8,sp),chunky_end
+ move.l (11*4+12,sp),d0 | d0.l: chunky width
+ move.l (11*4+16,sp),d2 | d2.l: chunky pitch
+ move.l (11*4+20,sp),a1 | a1: screen
+ move.l (11*4+24,sp),d1 | d1.l: screen pitch
+
+ move.l sp,old_sp
+
+ lea (a0,d0.l),a2 | a2: end of first src line
+ lea (a1,d0.l),a7 | a7: end of first dst line
+
+ move.l d1,screen_pitch
+
+ sub.l d0,d1
+ move.l d1,screen_offset
+
+ move.l d2,chunky_pitch
+
+ sub.l d0,d2
+ move.l d2,chunky_offset
+
+ move.l #0x0f0f0f0f,d4
+ move.l #0x00ff00ff,d5
+ move.l #0x55555555,d6
+
+ move.l (a0)+,d0
+ move.l (a0)+,d1
+ move.l (a0)+,d2
+ move.l (a0)+,d3
+
+ | a7a6a5a4a3a2a1a0 b7b6b5b4b3b2b1b0 c7c6c5c4c3c2c1c0 d7d6d5d4d3d2d1d0
+ | e7e6e5e4e3e2e1e0 f7f6f5f4f3f2f1f0 g7g6g5g4g3g2g1g0 h7h6h5h4h3h2h1h0
+ | i7i6i5i4i3i2i1i0 j7j6j5j4j3j2j1j0 k7k6k5k4k3k2k1k0 l7l6l5l4l3l2l1l0
+ | m7m6m5m4m3m2m1m0 n7n6n5n4n3n2n1n0 o7o6o5o4o3o2o1o0 p7p6p5p4p3p2p1p0
+
+ move.l d1,d7
+ lsr.l #4,d7
+ eor.l d0,d7
+ and.l d4,d7
+ eor.l d7,d0
+ lsl.l #4,d7
+ eor.l d7,d1
+ move.l d3,d7
+ lsr.l #4,d7
+ eor.l d2,d7
+ and.l d4,d7
+ eor.l d7,d2
+ lsl.l #4,d7
+ eor.l d7,d3
+
+ | a7a6a5a4e7e6e5e4 b7b6b5b4f7f6f5f4 c7c6c5c4g7g6g5g4 d7d6d5d4h7h6h5h4
+ | a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
+ | i7i6i5i4m7m6m5m4 j7j6j5j4n7n6n5n4 k7k6k5k4o7o6o5o4 l7l6l5l4p7p6p5p4
+ | i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
+
+ move.l d2,d7
+ lsr.l #8,d7
+ eor.l d0,d7
+ and.l d5,d7
+ eor.l d7,d0
+ lsl.l #8,d7
+ eor.l d7,d2
+ move.l d3,d7
+ lsr.l #8,d7
+ eor.l d1,d7
+ and.l d5,d7
+ eor.l d7,d1
+ lsl.l #8,d7
+ eor.l d7,d3
+
+ | a7a6a5a4e7e6e5e4 i7i6i5i4m7m6m5m4 c7c6c5c4g7g6g5g4 k7k6k5k4o7o6o5o4
+ | a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
+ | b7b6b5b4f7f6f5f4 j7j6j5j4n7n6n5n4 d7d6d5d4h7h6h5h4 l7l6l5l4p7p6p5p4
+ | b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
+
+ bra.s c2p1x1_8_rect_start
+
+c2p1x1_8_rect_pix16:
+ move.l (a0)+,d0
+ move.l (a0)+,d1
+ move.l (a0)+,d2
+ move.l (a0)+,d3
+
+ | a7a6a5a4a3a2a1a0 b7b6b5b4b3b2b1b0 c7c6c5c4c3c2c1c0 d7d6d5d4d3d2d1d0
+ | e7e6e5e4e3e2e1e0 f7f6f5f4f3f2f1f0 g7g6g5g4g3g2g1g0 h7h6h5h4h3h2h1h0
+ | i7i6i5i4i3i2i1i0 j7j6j5j4j3j2j1j0 k7k6k5k4k3k2k1k0 l7l6l5l4l3l2l1l0
+ | m7m6m5m4m3m2m1m0 n7n6n5n4n3n2n1n0 o7o6o5o4o3o2o1o0 p7p6p5p4p3p2p1p0
+
+ move.l d1,d7
+ lsr.l #4,d7
+ move.l a3,(a1)+
+ eor.l d0,d7
+ and.l d4,d7
+ eor.l d7,d0
+ lsl.l #4,d7
+ eor.l d7,d1
+ move.l d3,d7
+ lsr.l #4,d7
+ eor.l d2,d7
+ and.l d4,d7
+ eor.l d7,d2
+ move.l a4,(a1)+
+ lsl.l #4,d7
+ eor.l d7,d3
+
+ | a7a6a5a4e7e6e5e4 b7b6b5b4f7f6f5f4 c7c6c5c4g7g6g5g4 d7d6d5d4h7h6h5h4
+ | a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
+ | i7i6i5i4m7m6m5m4 j7j6j5j4n7n6n5n4 k7k6k5k4o7o6o5o4 l7l6l5l4p7p6p5p4
+ | i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
+
+ move.l d2,d7
+ lsr.l #8,d7
+ eor.l d0,d7
+ and.l d5,d7
+ eor.l d7,d0
+ move.l a5,(a1)+
+ lsl.l #8,d7
+ eor.l d7,d2
+ move.l d3,d7
+ lsr.l #8,d7
+ eor.l d1,d7
+ and.l d5,d7
+ eor.l d7,d1
+ move.l a6,(a1)+
+ lsl.l #8,d7
+ eor.l d7,d3
+
+ | a7a6a5a4e7e6e5e4 i7i6i5i4m7m6m5m4 c7c6c5c4g7g6g5g4 k7k6k5k4o7o6o5o4
+ | a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
+ | b7b6b5b4f7f6f5f4 j7j6j5j4n7n6n5n4 d7d6d5d4h7h6h5h4 l7l6l5l4p7p6p5p4
+ | b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
+
+ cmp.l a1,a7 | end of dst line?
+ bne.s c2p1x1_8_rect_start
+
+ add.l (screen_offset,pc),a1
+ add.l (screen_pitch,pc),a7
+
+c2p1x1_8_rect_start:
+ move.l d2,d7
+ lsr.l #1,d7
+ eor.l d0,d7
+ and.l d6,d7
+ eor.l d7,d0
+ add.l d7,d7
+ eor.l d7,d2
+ move.l d3,d7
+ lsr.l #1,d7
+ eor.l d1,d7
+ and.l d6,d7
+ eor.l d7,d1
+ add.l d7,d7
+ eor.l d7,d3
+
+ | a7b7a5b5e7f7e5f5 i7j7i5j5m7n7m5n5 c7d7c5d5g7h7g5h5 k7l7k5l5o7p7o5p5
+ | a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1
+ | a6b6a4b4e6f6e4f4 i6j6i4j4m6n6m4n4 c6d6c4d4g6h6g4h4 k6l6k4l4o6p6o4p4
+ | a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
+
+ move.w d2,d7
+ move.w d0,d2
+ swap d2
+ move.w d2,d0
+ move.w d7,d2
+ move.w d3,d7
+ move.w d1,d3
+ swap d3
+ move.w d3,d1
+ move.w d7,d3
+
+ | a7b7a5b5e7f7e5f5 i7j7i5j5m7n7m5n5 a6b6a4b4e6f6e4f4 i6j6i4j4m6n6m4n4
+ | a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0
+ | c7d7c5d5g7h7g5h5 k7l7k5l5o7p7o5p5 c6d6c4d4g6h6g4h4 k6l6k4l4o6p6o4p4
+ | c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
+
+ move.l d2,d7
+ lsr.l #2,d7
+ eor.l d0,d7
+ and.l #0x33333333,d7
+ eor.l d7,d0
+ lsl.l #2,d7
+ eor.l d7,d2
+ move.l d3,d7
+ lsr.l #2,d7
+ eor.l d1,d7
+ and.l #0x33333333,d7
+ eor.l d7,d1
+ lsl.l #2,d7
+ eor.l d7,d3
+
+ | a7b7c7d7e7f7g7h7 i7j7k7l7m7n7o7p7 a6b6c6d6e6f6g6h6 i6j6k6l6m6n6o6p6
+ | a3b3c3d3e3f3g3h3 i3j3k3l3m3n3o3p3 a2b2c2d2e2f2g2h2 i2j2k2l2m2n2o2p2
+ | a5b5c5d5e5f5g5h5 i5j5k5l5m5n5o5p5 a4b4c4d4e4f4g4h4 i4j4k4l4m4n4o4p4
+ | a1b1c1d1e1f1g1h1 i1j1k1l1m1n1o1p1 a0b0c0d0e0f0g0h0 i0j0k0l0m0n0o0p0
+
+ swap d0
+ swap d1
+ swap d2
+ swap d3
+
+ move.l d0,a6
+ move.l d2,a5
+ move.l d1,a4
+ move.l d3,a3
+
+ cmp.l a0,a2 | end of src line?
+ bne c2p1x1_8_rect_pix16
+
+ cmp.l (chunky_end,pc),a2
+ beq.s c2p1x1_8_rect_done
+
+ add.l (chunky_offset,pc),a0
+ add.l (chunky_pitch,pc),a2
+
+ bra c2p1x1_8_rect_pix16
+
+c2p1x1_8_rect_done:
+ move.l a3,(a1)+
+ move.l a4,(a1)+
+ move.l a5,(a1)+
+ move.l a6,(a1)+
+
+ move.l old_sp,sp
+ movem.l (sp)+,d2-d7/a2-a6
+ rts
+
+| place it within reach of 32K (PC relative)
+screen_pitch:
+ ds.l 1
+screen_offset:
+ ds.l 1
+chunky_pitch:
+ ds.l 1
+chunky_offset:
+ ds.l 1
+chunky_end:
+ ds.l 1
+
+ .bss
+ .even
+
+old_sp: ds.l 1
diff --git a/backends/graphics/atari/atari_c2p-asm.h b/backends/graphics/atari/atari_c2p-asm.h
new file mode 100644
index 00000000000..66129f8cb7a
--- /dev/null
+++ b/backends/graphics/atari/atari_c2p-asm.h
@@ -0,0 +1,54 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_ATARI_C2P_ASM_H
+#define BACKENDS_GRAPHICS_ATARI_C2P_ASM_H
+
+#include "common/scummsys.h"
+
+extern "C" {
+
+/**
+ * Chunky to planar conversion routine. Converts a chunky (byte) buffer into eight bitplanes.
+ * Optimized for surface-to-surface copy with the same pitch.
+ *
+ * @param pChunky chunky buffer start
+ * @param pChunkyEnd chunky buffer end (including the last byte)
+ * @param pScreen bitplane screen start
+ */
+void asm_c2p1x1_8(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen);
+
+/**
+ * Chunky to planar conversion routine. Converts a chunky (byte) buffer into eight bitplanes.
+ * Optimized for arbitrary rectangle position and dimension (16px aligned).
+ *
+ * @param pChunky chunky buffer at rectangle's [X1, Y1] position
+ * @param pChunkyEnd chunky buffer at rectangle's [X2, Y2] position (included)
+ * @param chunkyWidth rectangle width
+ * @param chunkyPitch chunky buffer width (in bytes)
+ * @param pScreen bitplane screen at rectangle's [X1, Y1] position
+ * @param screenPitch bitplane screen width (in bytes)
+ */
+void asm_c2p1x1_8_rect(const byte *pChunky, const byte *pChunkyEnd, uint32 chunkyWidth, uint32 chunkyPitch, byte *pScreen, uint32 screenPitch);
+
+}
+
+#endif
diff --git a/backends/graphics/atari/videl-resolutions.cpp b/backends/graphics/atari/videl-resolutions.cpp
new file mode 100644
index 00000000000..337a1b4f3a8
--- /dev/null
+++ b/backends/graphics/atari/videl-resolutions.cpp
@@ -0,0 +1,262 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "backends/graphics/atari/videl-resolutions.h"
+
+#include "common/scummsys.h"
+
+const byte scp_320x200x8_rgb[] = {
+ 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x7a, 0xb0, 0x00, 0xa9, 0xc1, 0x08, 0x00, 0xc2, 0x8c, 0xb0,
+ 0x01, 0x64, 0x05, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x3d, 0x09, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x40,
+ 0x00, 0xc8, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01, 0xe8, 0x48, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0x00, 0x99, 0x00, 0x59, 0x00, 0x26, 0x00, 0x87,
+ 0x00, 0xd9, 0x02, 0x71, 0x02, 0x11, 0x00, 0x81, 0x00, 0x81, 0x02, 0x11,
+ 0x02, 0x6b, 0x02, 0x00, 0x01, 0x81, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+ 0x00, 0xa0
+};
+
+const byte scp_320x200x8_rgb60[] = {
+ 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x7a, 0xb0, 0x00, 0xa7, 0xd8, 0xc0, 0x00, 0xc4, 0x74, 0xf8,
+ 0x01, 0x60, 0x05, 0x00, 0x02, 0x54, 0x00, 0x00, 0x3d, 0x09, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x08, 0xc0, 0x00, 0x00, 0x06, 0xc0, 0x00, 0x23,
+ 0x00, 0xc8, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01, 0xe8, 0x48, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0x00, 0x98, 0x00, 0x58, 0x00, 0x25, 0x00, 0x86,
+ 0x00, 0xd9, 0x02, 0x0d, 0x01, 0xd7, 0x00, 0x47, 0x00, 0x47, 0x01, 0xd7,
+ 0x02, 0x07, 0x02, 0x00, 0x01, 0x81, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+ 0x00, 0xa0
+};
+
+byte scp_320x200x8_vga[] = {
+ 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3a, 0x2f, 0x00, 0x00, 0x19, 0x74, 0x90, 0x00, 0x46, 0x4e, 0x20,
+ 0x00, 0x2a, 0x02, 0x80, 0x02, 0x58, 0x00, 0x00, 0x7a, 0xee, 0x00, 0x00,
+ 0x00, 0x3e, 0x00, 0x00, 0x08, 0x7a, 0x00, 0x00, 0x06, 0x8a, 0x00, 0x46,
+ 0x01, 0x90, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x01, 0xe8, 0x48, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xc6, 0x00, 0x8d, 0x00, 0x15, 0x02, 0x9a, 0x00, 0x7b,
+ 0x00, 0x97, 0x04, 0x19, 0x03, 0xad, 0x00, 0x8d, 0x00, 0x8d, 0x03, 0xad,
+ 0x04, 0x15, 0x02, 0x00, 0x01, 0x86, 0x00, 0x00, 0x00, 0x10, 0x00, 0x05,
+ 0x00, 0xa0
+};
+
+const byte scp_320x240x8_rgb[] = {
+ 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x01, 0x33, 0x32, 0x30, 0x2a,
+ 0x32, 0x30, 0x30, 0x2c, 0x20, 0x32, 0x35, 0x36, 0x20, 0x46, 0x61, 0x72,
+ 0x62, 0x65, 0x6e, 0x2c, 0x20, 0x35, 0x30, 0x2e, 0x30, 0x20, 0x48, 0x7a,
+ 0x2c, 0x20, 0x31, 0x35, 0x36, 0x32, 0x35, 0x20, 0x48, 0x7a, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x7a, 0xb0, 0x00, 0xa9, 0xc1, 0x08, 0x00, 0xc2, 0x8c, 0xb0,
+ 0x01, 0x64, 0x05, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x3d, 0x09, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x2c,
+ 0x00, 0xf0, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01, 0xe8, 0x48, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0x00, 0x99, 0x00, 0x59, 0x00, 0x26, 0x00, 0x87,
+ 0x00, 0xd9, 0x02, 0x71, 0x02, 0x39, 0x00, 0x59, 0x00, 0x59, 0x02, 0x39,
+ 0x02, 0x6b, 0x02, 0x00, 0x01, 0x81, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+ 0x00, 0xa0
+};
+
+byte scp_320x240x8_vga[] = {
+ 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3a, 0x2f, 0x00, 0x00, 0x19, 0x74, 0x90, 0x00, 0x46, 0x4e, 0x20,
+ 0x00, 0x2a, 0x02, 0x80, 0x02, 0x58, 0x00, 0x00, 0x7a, 0xee, 0x00, 0x00,
+ 0x00, 0x3e, 0x00, 0x00, 0x03, 0xc1, 0x00, 0x00, 0x01, 0x93, 0x00, 0x1f,
+ 0x01, 0xe0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x01, 0xe8, 0x48, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xc6, 0x00, 0x8d, 0x00, 0x15, 0x02, 0x9a, 0x00, 0x7b,
+ 0x00, 0x97, 0x04, 0x19, 0x03, 0xff, 0x00, 0x3f, 0x00, 0x3f, 0x03, 0xff,
+ 0x04, 0x15, 0x02, 0x00, 0x01, 0x86, 0x00, 0x00, 0x00, 0x10, 0x00, 0x05,
+ 0x00, 0xa0
+};
+
+const byte scp_320x240x16_rgb[] = {
+ 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x7a, 0xb0, 0x00, 0xa9, 0xc1, 0x08, 0x00, 0xc2, 0x8c, 0xb0,
+ 0x01, 0x64, 0x05, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x3d, 0x09, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x2c,
+ 0x00, 0xf0, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x01, 0xe8, 0x48, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0x00, 0x99, 0x00, 0x59, 0x00, 0x38, 0x00, 0x99,
+ 0x00, 0xd9, 0x02, 0x71, 0x02, 0x39, 0x00, 0x59, 0x00, 0x59, 0x02, 0x39,
+ 0x02, 0x6b, 0x02, 0x00, 0x01, 0x81, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x40
+};
+
+const byte scp_320x240x16_vga[] = {
+ 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3a, 0x2f, 0x00, 0x00, 0x19, 0x74, 0x90, 0x00, 0x46, 0x4e, 0x20,
+ 0x00, 0x2a, 0x02, 0x80, 0x02, 0x58, 0x00, 0x00, 0x7a, 0xee, 0x00, 0x00,
+ 0x00, 0x3e, 0x00, 0x00, 0x03, 0xc1, 0x00, 0x00, 0x01, 0xb2, 0x00, 0x1e,
+ 0x01, 0xe0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x01, 0xe8, 0x48, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xc6, 0x00, 0x8d, 0x00, 0x15, 0x02, 0xac, 0x00, 0x8d,
+ 0x00, 0x97, 0x04, 0x19, 0x03, 0xfd, 0x00, 0x3f, 0x00, 0x3d, 0x03, 0xfd,
+ 0x04, 0x15, 0x02, 0x00, 0x01, 0x86, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05,
+ 0x01, 0x40
+};
+
+const byte scp_640x400x8_rgb[] = {
+ 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x7a, 0xb0, 0x00, 0xab, 0xa9, 0x50, 0x00, 0xc1, 0x98, 0x8c,
+ 0x01, 0x68, 0x05, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x3d, 0x09, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x40,
+ 0x00, 0xc8, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01, 0xe8, 0x48, 0x00,
+ 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0xfe, 0x01, 0x34, 0x00, 0xb4, 0x00, 0x71, 0x01, 0x22,
+ 0x01, 0xb3, 0x02, 0x70, 0x02, 0x11, 0x00, 0x81, 0x00, 0x80, 0x02, 0x10,
+ 0x02, 0x6b, 0x02, 0x00, 0x01, 0x81, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06,
+ 0x01, 0x40
+};
+
+const byte scp_640x400x8_rgb60[] = {
+ 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x47, 0x86, 0x8c, 0x00, 0xb1, 0x62, 0x28, 0x00, 0xbd, 0xc7, 0xfc,
+ 0x01, 0x74, 0x05, 0x00, 0x02, 0x53, 0x00, 0x00, 0x3c, 0xea, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x06, 0x40, 0x00, 0x25,
+ 0x00, 0xc8, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01, 0xe8, 0x48, 0x00,
+ 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0xff, 0x01, 0x39, 0x00, 0xba, 0x00, 0x77, 0x01, 0x27,
+ 0x01, 0xb5, 0x02, 0x0c, 0x01, 0xdb, 0x00, 0x4b, 0x00, 0x4a, 0x01, 0xda,
+ 0x02, 0x07, 0x02, 0x00, 0x01, 0x81, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06,
+ 0x01, 0x40
+};
+
+byte scp_640x400x8_vga[] = {
+ 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x02, 0x36, 0x34, 0x30, 0x2a,
+ 0x34, 0x38, 0x30, 0x2c, 0x20, 0x32, 0x35, 0x36, 0x20, 0x46, 0x61, 0x72,
+ 0x62, 0x65, 0x6e, 0x2c, 0x20, 0x36, 0x30, 0x2e, 0x30, 0x20, 0x48, 0x7a,
+ 0x2c, 0x20, 0x33, 0x31, 0x34, 0x37, 0x30, 0x20, 0x48, 0x7a, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3a, 0x2f, 0x00, 0x00, 0x1a, 0xaa, 0xe0, 0x00, 0x45, 0x17, 0xd0,
+ 0x00, 0x2c, 0x02, 0x80, 0x02, 0x58, 0x00, 0x00, 0x7a, 0xee, 0x00, 0x00,
+ 0x00, 0x3e, 0x00, 0x00, 0x08, 0x99, 0x00, 0x00, 0x06, 0x6b, 0x00, 0x47,
+ 0x01, 0x90, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x01, 0xe8, 0x48, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xc6, 0x00, 0x8e, 0x00, 0x16, 0x02, 0xac, 0x00, 0x85,
+ 0x00, 0x97, 0x04, 0x19, 0x03, 0xaf, 0x00, 0x8f, 0x00, 0x8f, 0x03, 0xaf,
+ 0x04, 0x15, 0x02, 0x00, 0x01, 0x86, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08,
+ 0x01, 0x40
+};
+
+const byte scp_640x480x8_rgb[] = {
+ 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x01, 0x36, 0x34, 0x30, 0x2a,
+ 0x34, 0x30, 0x30, 0x2c, 0x20, 0x32, 0x35, 0x36, 0x20, 0x46, 0x61, 0x72,
+ 0x62, 0x65, 0x6e, 0x2c, 0x20, 0x35, 0x30, 0x2e, 0x30, 0x20, 0x48, 0x7a,
+ 0x20, 0x28, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x2e, 0x29, 0x2c, 0x20,
+ 0x31, 0x35, 0x36, 0x32, 0x35, 0x20, 0x48, 0x7a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x7a, 0xb0, 0x00, 0xab, 0xa9, 0x50, 0x00, 0xc1, 0x98, 0x8c,
+ 0x01, 0x68, 0x05, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x3d, 0x09, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x0a, 0xc0, 0x00, 0x00, 0x07, 0x40, 0x00, 0x2b,
+ 0x00, 0xf0, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01, 0xe8, 0x48, 0x00,
+ 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0xfe, 0x01, 0x34, 0x00, 0xb4, 0x00, 0x71, 0x01, 0x22,
+ 0x01, 0xb3, 0x02, 0x70, 0x02, 0x37, 0x00, 0x57, 0x00, 0x56, 0x02, 0x36,
+ 0x02, 0x6b, 0x02, 0x00, 0x01, 0x81, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06,
+ 0x01, 0x40
+};
+
+byte scp_640x480x8_vga[] = {
+ 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3a, 0x2f, 0x00, 0x00, 0x1a, 0xaa, 0xe0, 0x00, 0x45, 0x17, 0xd0,
+ 0x00, 0x2c, 0x02, 0x80, 0x02, 0x58, 0x00, 0x00, 0x7a, 0xee, 0x00, 0x00,
+ 0x00, 0x3e, 0x00, 0x00, 0x03, 0xc1, 0x00, 0x00, 0x01, 0x93, 0x00, 0x1f,
+ 0x01, 0xe0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x01, 0xe8, 0x48, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xc6, 0x00, 0x8e, 0x00, 0x16, 0x02, 0xac, 0x00, 0x85,
+ 0x00, 0x97, 0x04, 0x19, 0x03, 0xff, 0x00, 0x3f, 0x00, 0x3f, 0x03, 0xff,
+ 0x04, 0x15, 0x02, 0x00, 0x01, 0x86, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08,
+ 0x01, 0x40
+};
+
+const byte scp_640x480x16_rgb[] = {
+ 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x01, 0x36, 0x34, 0x30, 0x2a,
+ 0x34, 0x38, 0x30, 0x2c, 0x20, 0x54, 0x72, 0x75, 0x65, 0x20, 0x43, 0x6f,
+ 0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x35, 0x30, 0x2e, 0x30, 0x20, 0x48, 0x7a,
+ 0x20, 0x28, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x2e, 0x29, 0x2c, 0x20,
+ 0x31, 0x35, 0x36, 0x32, 0x35, 0x20, 0x48, 0x7a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x7a, 0xb0, 0x00, 0xa9, 0xc1, 0x08, 0x00, 0xc3, 0x80, 0xd4,
+ 0x01, 0x64, 0x05, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x3d, 0x09, 0x00, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x2c,
+ 0x00, 0xf0, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x01, 0xe8, 0x48, 0x00,
+ 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0xfe, 0x01, 0x32, 0x00, 0xb2, 0x00, 0x81, 0x01, 0x32,
+ 0x01, 0xb3, 0x02, 0x70, 0x02, 0x39, 0x00, 0x59, 0x00, 0x58, 0x02, 0x38,
+ 0x02, 0x6b, 0x02, 0x00, 0x01, 0x81, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06,
+ 0x02, 0x80
+};
+
+const byte scp_640x480x16_vga[] = {
+ 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x02, 0x36, 0x34, 0x30, 0x2a,
+ 0x34, 0x38, 0x30, 0x2c, 0x20, 0x54, 0x72, 0x75, 0x65, 0x20, 0x43, 0x6f,
+ 0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x36, 0x30, 0x2e, 0x30, 0x20, 0x48, 0x7a,
+ 0x2c, 0x20, 0x33, 0x31, 0x34, 0x37, 0x30, 0x20, 0x48, 0x7a, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3a, 0x2f, 0x00, 0x00, 0x1a, 0xaa, 0xe0, 0x00, 0x45, 0x17, 0xd0,
+ 0x00, 0x2c, 0x02, 0x80, 0x02, 0x58, 0x00, 0x00, 0x7a, 0xee, 0x00, 0x00,
+ 0x00, 0x3e, 0x00, 0x00, 0x03, 0xc1, 0x00, 0x00, 0x01, 0x93, 0x00, 0x1f,
+ 0x01, 0xe0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x01, 0x01, 0xe8, 0x48, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xc6, 0x00, 0x8e, 0x00, 0x16, 0x02, 0xb5, 0x00, 0x8e,
+ 0x00, 0x97, 0x04, 0x19, 0x03, 0xff, 0x00, 0x3f, 0x00, 0x3f, 0x03, 0xff,
+ 0x04, 0x15, 0x02, 0x00, 0x01, 0x86, 0x00, 0x00, 0x01, 0x00, 0x00, 0x08,
+ 0x02, 0x80
+};
diff --git a/backends/graphics/atari/videl-resolutions.h b/backends/graphics/atari/videl-resolutions.h
new file mode 100644
index 00000000000..2dbae53374b
--- /dev/null
+++ b/backends/graphics/atari/videl-resolutions.h
@@ -0,0 +1,47 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_ATARI_VIDEL_RESOLUTIONS_H
+#define BACKENDS_GRAPHICS_ATARI_VIDEL_RESOLUTIONS_H
+
+#include "common/scummsys.h"
+
+constexpr int SCP_SIZE = 158;
+
+extern const byte scp_320x200x8_rgb[SCP_SIZE];
+extern const byte scp_320x200x8_rgb60[SCP_SIZE];
+extern byte scp_320x200x8_vga[SCP_SIZE];
+
+extern const byte scp_320x240x8_rgb[SCP_SIZE];
+extern byte scp_320x240x8_vga[SCP_SIZE];
+extern const byte scp_320x240x16_rgb[SCP_SIZE];
+extern const byte scp_320x240x16_vga[SCP_SIZE];
+
+extern const byte scp_640x400x8_rgb[SCP_SIZE];
+extern const byte scp_640x400x8_rgb60[SCP_SIZE];
+extern byte scp_640x400x8_vga[SCP_SIZE];
+
+extern const byte scp_640x480x8_rgb[SCP_SIZE];
+extern byte scp_640x480x8_vga[SCP_SIZE];
+extern const byte scp_640x480x16_rgb[SCP_SIZE];
+extern const byte scp_640x480x16_vga[SCP_SIZE];
+
+#endif
diff --git a/backends/mixer/atari/atari-mixer.cpp b/backends/mixer/atari/atari-mixer.cpp
new file mode 100644
index 00000000000..b4121897ee2
--- /dev/null
+++ b/backends/mixer/atari/atari-mixer.cpp
@@ -0,0 +1,221 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "backends/mixer/atari/atari-mixer.h"
+
+#include <math.h>
+
+#include <mint/falcon.h>
+
+#include "common/config-manager.h"
+#include "common/debug.h"
+
+#define DEFAULT_OUTPUT_RATE 24585
+
+AtariMixerManager::AtariMixerManager() : MixerManager() {
+ ConfMan.registerDefault("output_rate", DEFAULT_OUTPUT_RATE);
+
+ _outputRate = ConfMan.getInt("output_rate");
+ if (_outputRate <= 0)
+ _outputRate = DEFAULT_OUTPUT_RATE;
+
+ int diff50, diff33, diff25, diff20, diff16, diff12, diff10, diff8;
+ diff50 = abs(49170 - (int)_outputRate);
+ diff33 = abs(32780 - (int)_outputRate);
+ diff25 = abs(24585 - (int)_outputRate);
+ diff20 = abs(19668 - (int)_outputRate);
+ diff16 = abs(16390 - (int)_outputRate);
+ diff12 = abs(12292 - (int)_outputRate);
+ diff10 = abs(9834 - (int)_outputRate);
+ diff8 = abs(8195 - (int)_outputRate);
+
+ if (diff50 < diff33) {
+ _outputRate = 49170;
+ _clk = CLK50K;
+ } else if (diff33 < diff25) {
+ _outputRate = 32780;
+ _clk = CLK33K;
+ } else if (diff25 < diff20) {
+ _outputRate = 24585;
+ _clk = CLK25K;
+ } else if (diff20 < diff16) {
+ _outputRate = 19668;
+ _clk = CLK20K;
+ } else if (diff16 < diff12) {
+ _outputRate = 16390;
+ _clk = CLK16K;
+ } else if (diff12 < diff10) {
+ _outputRate = 12292;
+ _clk = CLK12K;
+ } else if (diff10 < diff8) {
+ _outputRate = 9834;
+ _clk = CLK10K;
+ } else {
+ _outputRate = 8195;
+ _clk = CLK8K;
+ }
+
+ ConfMan.setInt("output_rate", _outputRate);
+ debug("setting %d Hz mixing frequency", _outputRate);
+
+ _samples = 8192;
+ while (_samples * 16 > _outputRate * 2)
+ _samples >>= 1;
+
+ ConfMan.registerDefault("output_samples", (int)_samples);
+
+ int samples = ConfMan.getInt("output_samples");
+ if (samples > 0)
+ _samples = samples;
+
+ ConfMan.setInt("output_samples", (int)_samples);
+ debug("sample buffer size: %d", _samples);
+
+ ConfMan.flushToDisk();
+
+ _samplesBuf = new uint8[_samples * 4];
+
+ g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);
+}
+
+AtariMixerManager::~AtariMixerManager() {
+ g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
+
+ Buffoper(0x00);
+
+ Mfree(_atariSampleBuffer);
+ _atariSampleBuffer = _atariPhysicalSampleBuffer = _atariLogicalSampleBuffer = nullptr;
+
+ Sndstatus(SND_RESET);
+
+ Unlocksnd();
+
+ _atariInitialized = false;
+
+ delete[] _samplesBuf;
+}
+
+void AtariMixerManager::init() {
+ _mixer = new Audio::MixerImpl(_outputRate, _samples);
+ _mixer->setReady(true);
+
+ _atariSampleBufferSize = _samples * 4;
+
+ _atariSampleBuffer = (byte*)Mxalloc(_atariSampleBufferSize * 2, MX_STRAM);
+ if (!_atariSampleBuffer)
+ return;
+
+ _atariPhysicalSampleBuffer = _atariSampleBuffer;
+ _atariLogicalSampleBuffer = _atariSampleBuffer + _atariSampleBufferSize;
+
+ memset(_atariSampleBuffer, 0, 2 * _atariSampleBufferSize);
+
+ if (Locksnd() < 0)
+ return;
+
+ Sndstatus(SND_RESET);
+ Setmode(MODE_STEREO16);
+ Devconnect(DMAPLAY, DAC, CLK25M, _clk, NO_SHAKE);
+ Soundcmd(ADDERIN, MATIN);
+ Setbuffer(SR_PLAY, _atariSampleBuffer, _atariSampleBuffer + 2 * _atariSampleBufferSize);
+ Buffoper(SB_PLA_ENA | SB_PLA_RPT);
+
+ _atariInitialized = true;
+}
+
+void AtariMixerManager::suspendAudio() {
+ debug("suspendAudio");
+
+ Buffoper(0x00);
+
+ _audioSuspended = true;
+}
+
+int AtariMixerManager::resumeAudio() {
+ debug("resumeAudio 1");
+
+ if (!_audioSuspended || !_atariInitialized) {
+ return -2;
+ }
+
+ debug("resumeAudio 2");
+
+ Buffoper(SB_PLA_ENA | SB_PLA_RPT);
+
+ _audioSuspended = false;
+ return 0;
+}
+
+bool AtariMixerManager::notifyEvent(const Common::Event &event) {
+ switch (event.type) {
+ case Common::EVENT_QUIT:
+ case Common::EVENT_RETURN_TO_LAUNCHER:
+ debug("silencing the mixer");
+ memset(_atariSampleBuffer, 0, 2 * _atariSampleBufferSize);
+ return false;
+ case Common::EVENT_MUTE:
+ _muted = !_muted;
+ debug("audio %s", _muted ? "off" : "on");
+ return false;
+ default:
+ [[fallthrough]];
+ }
+
+ return false;
+}
+
+void AtariMixerManager::update() {
+ if (_audioSuspended && !_muted) {
+ return;
+ }
+
+ static bool loadSampleFlag = true;
+ byte *buf = nullptr;
+
+ SndBufPtr sPtr;
+ if (Buffptr(&sPtr) != 0)
+ return;
+
+ if (!loadSampleFlag) {
+ // we play from _atariPhysicalSampleBuffer (1st buffer)
+ if ((byte*)sPtr.play < _atariLogicalSampleBuffer) {
+ buf = _atariLogicalSampleBuffer;
+ loadSampleFlag = !loadSampleFlag;
+ }
+ } else {
+ // we play from _atariLogicalSampleBuffer (2nd buffer)
+ if ((byte*)sPtr.play >= _atariLogicalSampleBuffer) {
+ buf = _atariPhysicalSampleBuffer;
+ loadSampleFlag = !loadSampleFlag;
+ }
+ }
+
+ if (_atariInitialized && buf != nullptr) {
+ assert(_mixer);
+ // generates stereo 16-bit samples
+ int processed = _mixer->mixCallback(_samplesBuf, _samples * 4);
+ if (processed > 0) {
+ memcpy(buf, _samplesBuf, processed * 4);
+ } else {
+ memset(buf, 0, _atariSampleBufferSize);
+ }
+ }
+}
diff --git a/backends/mixer/atari/atari-mixer.h b/backends/mixer/atari/atari-mixer.h
new file mode 100644
index 00000000000..cbbd20a611f
--- /dev/null
+++ b/backends/mixer/atari/atari-mixer.h
@@ -0,0 +1,60 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef BACKENDS_MIXER_ATARI_H
+#define BACKENDS_MIXER_ATARI_H
+
+#include "backends/mixer/mixer.h"
+#include "common/events.h"
+
+/**
+ * Atari XBIOS based audio mixer.
+ */
+
+class AtariMixerManager : public MixerManager, Common::EventObserver {
+public:
+ AtariMixerManager();
+ virtual ~AtariMixerManager();
+
+ virtual void init() override;
+ void update();
+
+ void suspendAudio() override;
+ int resumeAudio() override;
+
+ bool notifyEvent(const Common::Event &event) override;
+
+private:
+ int _clk;
+ uint32 _outputRate;
+ uint32 _samples;
+ uint8 *_samplesBuf;
+
+ bool _atariInitialized = false;
+ byte *_atariSampleBuffer = nullptr;
+ byte *_atariPhysicalSampleBuffer = nullptr;
+ byte *_atariLogicalSampleBuffer = nullptr;
+ size_t _atariSampleBufferSize; // one buffer (logical/physical)
+
+ bool _muted = false;
+};
+
+#endif
diff --git a/backends/module.mk b/backends/module.mk
index 73247a32180..7b99c4a6103 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -321,6 +321,15 @@ MODULE_OBJS += \
plugins/3ds/3ds-provider.o
endif
+ifeq ($(BACKEND),atari)
+MODULE_OBJS += \
+ graphics/atari/atari_c2p-asm.o \
+ graphics/atari/atari-graphics.o \
+ graphics/atari/atari-graphics-asm.o \
+ graphics/atari/videl-resolutions.o \
+ mixer/atari/atari-mixer.o
+endif
+
ifeq ($(BACKEND),ds)
MODULE_OBJS += \
events/ds/ds-events.o \
diff --git a/backends/platform/atari/atari.cpp b/backends/platform/atari/atari.cpp
new file mode 100644
index 00000000000..ec3a0337f9a
--- /dev/null
+++ b/backends/platform/atari/atari.cpp
@@ -0,0 +1,660 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <mint/cookie.h>
+#include <mint/falcon.h>
+#include <mint/osbind.h>
+
+// We use some stdio.h functionality here thus we need to allow some
+// symbols. Alternatively, we could simply allow everything by defining
+// FORBIDDEN_SYMBOL_ALLOW_ALL
+#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
+#define FORBIDDEN_SYMBOL_EXCEPTION_stdout
+#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
+#define FORBIDDEN_SYMBOL_EXCEPTION_fputs
+#define FORBIDDEN_SYMBOL_EXCEPTION_exit
+#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
+#define FORBIDDEN_SYMBOL_EXCEPTION_getenv
+
+#include "common/scummsys.h"
+
+#if defined(ATARI)
+#include "backends/graphics/atari/atari-graphics-asm.h"
+#include "backends/keymapper/hardware-input.h"
+#include "backends/modular-backend.h"
+#include "backends/mutex/null/null-mutex.h"
+#include "base/main.h"
+
+#include "backends/saves/default/default-saves.h"
+#include "backends/timer/default/default-timer.h"
+#include "backends/events/default/default-events.h"
+#include "backends/mixer/atari/atari-mixer.h"
+#include "backends/graphics/atari/atari-graphics.h"
+#include "backends/graphics/atari/atari-graphics-supervidel.h"
+#include "backends/graphics/atari/atari-graphics-videl.h"
+#include "common/hashmap.h"
+#include "gui/debugger.h"
+
+/*
+ * Include header files needed for the getFilesystemFactory() method.
+ */
+#include "backends/fs/posix/posix-fs-factory.h"
+
+class OSystem_Atari : public ModularMixerBackend, public ModularGraphicsBackend, Common::EventSource {
+public:
+ OSystem_Atari();
+ virtual ~OSystem_Atari();
+
+ void initBackend() override;
+
+ bool pollEvent(Common::Event &event) override;
+
+ Common::MutexInternal *createMutex() override;
+ uint32 getMillis(bool skipRecord = false) override;
+ void delayMillis(uint msecs) override;
+ void getTimeAndDate(TimeDate &td, bool skipRecord = false) const override;
+
+ Common::KeymapArray getGlobalKeymaps() override;
+ Common::HardwareInputSet *getHardwareInputSet() override;
+
+ void quit() override;
+
+ void logMessage(LogMessageType::Type type, const char *message) override;
+
+ void addSysArchivesToSearchSet(Common::SearchSet &s, int priority) override;
+ Common::String getDefaultConfigFileName() override;
+
+private:
+ AtariGraphicsManager *_atariGraphicsManager;
+
+ clock_t _startTime;
+
+ bool _video_initialized = false;
+ bool _ikbd_initialized = false;
+
+ bool _oldLmbDown = false;
+ bool _oldRmbDown = false;
+
+ bool _lshiftActive = false;
+ bool _rshiftActive = false;
+ bool _ctrlActive = false;
+ bool _altActive = false;
+ bool _capslockActive = false;
+
+ byte _unshiftToAscii[128];
+ byte _shiftToAscii[128];
+ byte _capsToAscii[128];
+
+ const Common::KeyCode _asciiToKeycode[128 - 32 - 1] = {
+ Common::KEYCODE_SPACE,
+ Common::KEYCODE_EXCLAIM,
+ Common::KEYCODE_QUOTEDBL,
+ Common::KEYCODE_HASH,
+ Common::KEYCODE_DOLLAR,
+ Common::KEYCODE_PERCENT,
+ Common::KEYCODE_AMPERSAND,
+ Common::KEYCODE_QUOTE,
+ Common::KEYCODE_LEFTPAREN,
+ Common::KEYCODE_RIGHTPAREN,
+ Common::KEYCODE_ASTERISK,
+ Common::KEYCODE_PLUS,
+ Common::KEYCODE_COMMA,
+ Common::KEYCODE_MINUS,
+ Common::KEYCODE_PERIOD,
+ Common::KEYCODE_SLASH,
+ Common::KEYCODE_0,
+ Common::KEYCODE_1,
+ Common::KEYCODE_2,
+ Common::KEYCODE_3,
+ Common::KEYCODE_4,
+ Common::KEYCODE_5,
+ Common::KEYCODE_6,
+ Common::KEYCODE_7,
+ Common::KEYCODE_8,
+ Common::KEYCODE_9,
+ Common::KEYCODE_COLON,
+ Common::KEYCODE_SEMICOLON,
+ Common::KEYCODE_LESS,
+ Common::KEYCODE_EQUALS,
+ Common::KEYCODE_GREATER,
+ Common::KEYCODE_QUESTION,
+ Common::KEYCODE_AT,
+ Common::KEYCODE_a,
+ Common::KEYCODE_b,
+ Common::KEYCODE_c,
+ Common::KEYCODE_d,
+ Common::KEYCODE_e,
+ Common::KEYCODE_f,
+ Common::KEYCODE_g,
+ Common::KEYCODE_h,
+ Common::KEYCODE_i,
+ Common::KEYCODE_j,
+ Common::KEYCODE_k,
+ Common::KEYCODE_l,
+ Common::KEYCODE_m,
+ Common::KEYCODE_n,
+ Common::KEYCODE_o,
+ Common::KEYCODE_p,
+ Common::KEYCODE_q,
+ Common::KEYCODE_r,
+ Common::KEYCODE_s,
+ Common::KEYCODE_t,
+ Common::KEYCODE_u,
+ Common::KEYCODE_v,
+ Common::KEYCODE_w,
+ Common::KEYCODE_x,
+ Common::KEYCODE_y,
+ Common::KEYCODE_z,
+ Common::KEYCODE_LEFTBRACKET,
+ Common::KEYCODE_BACKSLASH,
+ Common::KEYCODE_RIGHTBRACKET,
+ Common::KEYCODE_CARET,
+ Common::KEYCODE_UNDERSCORE,
+ Common::KEYCODE_BACKQUOTE,
+ Common::KEYCODE_a,
+ Common::KEYCODE_b,
+ Common::KEYCODE_c,
+ Common::KEYCODE_d,
+ Common::KEYCODE_e,
+ Common::KEYCODE_f,
+ Common::KEYCODE_g,
+ Common::KEYCODE_h,
+ Common::KEYCODE_i,
+ Common::KEYCODE_j,
+ Common::KEYCODE_k,
+ Common::KEYCODE_l,
+ Common::KEYCODE_m,
+ Common::KEYCODE_n,
+ Common::KEYCODE_o,
+ Common::KEYCODE_p,
+ Common::KEYCODE_q,
+ Common::KEYCODE_r,
+ Common::KEYCODE_s,
+ Common::KEYCODE_t,
+ Common::KEYCODE_u,
+ Common::KEYCODE_v,
+ Common::KEYCODE_w,
+ Common::KEYCODE_x,
+ Common::KEYCODE_y,
+ Common::KEYCODE_z,
+ Common::KEYCODE_INVALID, // {
+ Common::KEYCODE_INVALID, // |
+ Common::KEYCODE_INVALID, // }
+ Common::KEYCODE_TILDE
+ };
+ Common::HashMap<byte, Common::KeyCode> _scancodeToKeycode;
+};
+
+extern "C" void atari_ikbd_init();
+extern "C" void atari_ikbd_shutdown();
+
+extern void nf_init(void);
+extern void nf_print(const char* msg);
+
+OSystem_Atari::OSystem_Atari() {
+ _fsFactory = new POSIXFilesystemFactory();
+
+ _scancodeToKeycode[0x01] = Common::KEYCODE_ESCAPE;
+ _scancodeToKeycode[0x0e] = Common::KEYCODE_BACKSPACE;
+ _scancodeToKeycode[0x0f] = Common::KEYCODE_TAB;
+ _scancodeToKeycode[0x1c] = Common::KEYCODE_RETURN;
+ _scancodeToKeycode[0x39] = Common::KEYCODE_SPACE;
+ _scancodeToKeycode[0x3b] = Common::KEYCODE_F1;
+ _scancodeToKeycode[0x3c] = Common::KEYCODE_F2;
+ _scancodeToKeycode[0x3d] = Common::KEYCODE_F3;
+ _scancodeToKeycode[0x3e] = Common::KEYCODE_F4;
+ _scancodeToKeycode[0x3f] = Common::KEYCODE_F5;
+ _scancodeToKeycode[0x40] = Common::KEYCODE_F6;
+ _scancodeToKeycode[0x41] = Common::KEYCODE_F7;
+ _scancodeToKeycode[0x42] = Common::KEYCODE_F8;
+ _scancodeToKeycode[0x43] = Common::KEYCODE_F9;
+ _scancodeToKeycode[0x44] = Common::KEYCODE_F10;
+ _scancodeToKeycode[0x45] = Common::KEYCODE_PAGEUP; // Eiffel only
+ _scancodeToKeycode[0x46] = Common::KEYCODE_PAGEDOWN; // Eiffel only
+ _scancodeToKeycode[0x47] = Common::KEYCODE_HOME;
+ _scancodeToKeycode[0x48] = Common::KEYCODE_UP;
+ _scancodeToKeycode[0x4a] = Common::KEYCODE_KP_MINUS;
+ _scancodeToKeycode[0x4b] = Common::KEYCODE_LEFT;
+ _scancodeToKeycode[0x4c] = Common::KEYCODE_LMETA;
+ _scancodeToKeycode[0x4d] = Common::KEYCODE_RIGHT;
+ _scancodeToKeycode[0x4e] = Common::KEYCODE_KP_PLUS;
+ _scancodeToKeycode[0x4f] = Common::KEYCODE_PAUSE; // Eiffel only
+ _scancodeToKeycode[0x50] = Common::KEYCODE_DOWN;
+ _scancodeToKeycode[0x52] = Common::KEYCODE_INSERT;
+ _scancodeToKeycode[0x53] = Common::KEYCODE_DELETE;
+ _scancodeToKeycode[0x55] = Common::KEYCODE_END; // Eiffel only
+ _scancodeToKeycode[0x5b] = Common::KEYCODE_TILDE; // Eiffel only
+ _scancodeToKeycode[0x61] = Common::KEYCODE_F12; // UNDO
+ _scancodeToKeycode[0x62] = Common::KEYCODE_F11; // HELP
+ _scancodeToKeycode[0x63] = Common::KEYCODE_SLASH; // KEYPAD /
+ _scancodeToKeycode[0x64] = Common::KEYCODE_KP_DIVIDE;
+ _scancodeToKeycode[0x65] = Common::KEYCODE_KP_MULTIPLY;
+ _scancodeToKeycode[0x66] = Common::KEYCODE_KP_MULTIPLY; // duplicate?
+ _scancodeToKeycode[0x67] = Common::KEYCODE_7; // KEYPAD 7
+ _scancodeToKeycode[0x68] = Common::KEYCODE_8; // KEYPAD 8
+ _scancodeToKeycode[0x69] = Common::KEYCODE_9; // KEYPAD 9
+ _scancodeToKeycode[0x6a] = Common::KEYCODE_4; // KEYPAD 4
+ _scancodeToKeycode[0x6b] = Common::KEYCODE_5; // KEYPAD 5
+ _scancodeToKeycode[0x6c] = Common::KEYCODE_6; // KEYPAD 6
+ _scancodeToKeycode[0x6d] = Common::KEYCODE_1; // KEYPAD 1
+ _scancodeToKeycode[0x6e] = Common::KEYCODE_2; // KEYPAD 2
+ _scancodeToKeycode[0x6f] = Common::KEYCODE_3; // KEYPAD 3
+ _scancodeToKeycode[0x70] = Common::KEYCODE_0; // KEYPAD 0
+ _scancodeToKeycode[0x71] = Common::KEYCODE_KP_PERIOD;
+ _scancodeToKeycode[0x72] = Common::KEYCODE_KP_ENTER;
+}
+
+OSystem_Atari::~OSystem_Atari() {
+ debug("OSystem_Atari::~OSystem_Atari()");
+
+ if (_video_initialized) {
+ Supexec(asm_screen_falcon_restore);
+ _video_initialized = false;
+ }
+
+ if (_ikbd_initialized) {
+ Supexec(atari_ikbd_shutdown);
+ _ikbd_initialized = false;
+ }
+}
+
+static void ikbd_and_video_restore() {
+ Supexec(asm_screen_falcon_restore);
+ Supexec(atari_ikbd_shutdown);
+}
+
+void OSystem_Atari::initBackend() {
+ enum {
+ MCH_ST = 0,
+ MCH_STE,
+ MCH_TT,
+ MCH_FALCON,
+ MCH_CLONE,
+ MCH_ARANYM
+ };
+
+ long mch = MCH_ST<<16;
+ Getcookie(C__MCH, &mch);
+ mch >>= 16;
+
+ if (mch != MCH_FALCON && mch != MCH_ARANYM) {
+ error("ScummVM works only on Atari Falcon and ARAnyM");
+ }
+
+ if (mch == MCH_ARANYM && Getcookie(C_fVDI, NULL) == C_FOUND) {
+ logMessage(LogMessageType::kError, "Disable fVDI, ScummVM accesses Videl directly\n");
+ quit();
+ }
+
+ nf_init();
+
+ _startTime = clock();
+
+ bool superVidel = VgetMonitor() == MON_VGA && Getcookie(C_SupV, NULL) == C_FOUND;
+
+ _timerManager = new DefaultTimerManager();
+ _eventManager = new DefaultEventManager(makeKeyboardRepeatingEventSource(this));
+ _savefileManager = new DefaultSaveFileManager();
+ if (superVidel)
+ _atariGraphicsManager = new AtariSuperVidelManager();
+ else
+ _atariGraphicsManager = new AtariVidelManager();
+ _graphicsManager = _atariGraphicsManager;
+ _mixerManager = new AtariMixerManager();
+ // Setup and start mixer
+ _mixerManager->init();
+
+ _KEYTAB *pKeyTables = (_KEYTAB*)Keytbl(KT_NOCHANGE, KT_NOCHANGE, KT_NOCHANGE);
+
+ memcpy(_unshiftToAscii, pKeyTables->unshift, 128);
+ memcpy(_shiftToAscii, pKeyTables->shift, 128);
+ memcpy(_capsToAscii, pKeyTables->caps, 128);
+
+ Supexec(atari_ikbd_init);
+ _ikbd_initialized = true;
+
+ Supexec(asm_screen_falcon_save);
+ _video_initialized = true;
+
+ Setexc(VEC_PROCTERM, ikbd_and_video_restore);
+
+ BaseBackend::initBackend();
+}
+
+//! bit 0: rmb
+//! bit 1: lmb
+volatile uint8 g_atari_ikbd_mouse_buttons_state = 0;
+volatile int16 g_atari_ikbd_mouse_delta_x = 0;
+volatile int16 g_atari_ikbd_mouse_delta_y = 0;
+
+#define SCANCODES_SIZE 256
+volatile uint8 g_atari_ikbd_scancodes[SCANCODES_SIZE];
+uint16 g_atari_ikbd_scancodes_mask = SCANCODES_SIZE-1;
+volatile uint16 g_atari_ikbb_scancodes_head = 0;
+static uint16 g_atari_ikbb_scancodes_tail = 0;
+
+bool OSystem_Atari::pollEvent(Common::Event &event) {
+ {
+ static uint32 startMillis = getMillis();
+ static uint32 oldMillis = getMillis();
+ uint32 curMillis = getMillis();
+
+ uint32 diff = curMillis - oldMillis;
+ oldMillis = curMillis;
+
+ if (diff > 0) {
+ static float avgFpsSum;
+ static int avgFpsCount;
+
+ avgFpsSum += 1000.0f / diff;
+ avgFpsCount++;
+
+ if (curMillis - startMillis >= 1000) {
+ float avgFps = avgFpsSum / avgFpsCount;
+ debug("*** Average FPS in 1s: %f ***", avgFps);
+ startMillis = curMillis;
+ avgFpsSum = 0;
+ avgFpsCount = 0;
+ }
+ }
+ }
+
+ ((DefaultTimerManager *)_timerManager)->checkTimers();
+ ((AtariMixerManager *)_mixerManager)->update();
+
+ if ((g_atari_ikbd_mouse_buttons_state & 0x01) && !_oldRmbDown) {
+ event.type = Common::EVENT_RBUTTONDOWN;
+ event.mouse = _atariGraphicsManager->getMousePosition();
+ _oldRmbDown = true;
+ return true;
+ }
+
+ if (!(g_atari_ikbd_mouse_buttons_state & 0x01) && _oldRmbDown) {
+ event.type = Common::EVENT_RBUTTONUP;
+ event.mouse = _atariGraphicsManager->getMousePosition();
+ _oldRmbDown = false;
+ return true;
+ }
+
+ if ((g_atari_ikbd_mouse_buttons_state & 0x02) && !_oldLmbDown) {
+ event.type = Common::EVENT_LBUTTONDOWN;
+ event.mouse = _atariGraphicsManager->getMousePosition();
+ _oldLmbDown = true;
+ return true;
+ }
+
+ if (!(g_atari_ikbd_mouse_buttons_state & 0x02) && _oldLmbDown) {
+ event.type = Common::EVENT_LBUTTONUP;
+ event.mouse = _atariGraphicsManager->getMousePosition();
+ _oldLmbDown = false;
+ return true;
+ }
+
+ if (g_atari_ikbd_mouse_delta_x != 0 || g_atari_ikbd_mouse_delta_y != 0) {
+ const int deltaX = g_atari_ikbd_mouse_delta_x;
+ const int deltaY = g_atari_ikbd_mouse_delta_y;
+
+ g_atari_ikbd_mouse_delta_x = g_atari_ikbd_mouse_delta_y = 0;
+
+ _atariGraphicsManager->updateMousePosition(deltaX, deltaY);
+
+ event.type = Common::EVENT_MOUSEMOVE;
+ event.mouse = _atariGraphicsManager->getMousePosition();
+ event.relMouse = Common::Point(deltaX, deltaY);
+ return true;
+ }
+
+ if (g_atari_ikbb_scancodes_head != g_atari_ikbb_scancodes_tail) {
+ byte scancode = g_atari_ikbd_scancodes[g_atari_ikbb_scancodes_tail++];
+ g_atari_ikbb_scancodes_tail &= SCANCODES_SIZE-1;
+
+ bool pressed = !(scancode & 0x80);
+ scancode &= 0x7f;
+
+ if (scancode == 0x1d)
+ _ctrlActive = pressed;
+
+ if (scancode == 0x2a)
+ _lshiftActive = pressed;
+
+ if (scancode == 0x36)
+ _rshiftActive = pressed;
+
+ if (scancode == 0x38)
+ _altActive = pressed;
+
+ if (scancode == 0x3a && pressed)
+ _capslockActive = !_capslockActive;
+
+ // Eiffel only
+ if (scancode == 0x59) {
+ event.type = Common::EVENT_WHEELUP;
+ event.mouse = _atariGraphicsManager->getMousePosition();
+ return true;
+ }
+
+ // Eiffel only
+ if (scancode == 0x5a) {
+ event.type = Common::EVENT_WHEELDOWN;
+ event.mouse = _atariGraphicsManager->getMousePosition();
+ return true;
+ }
+
+ uint16 ascii;
+ if (_lshiftActive || _rshiftActive) {
+ ascii = _shiftToAscii[scancode];
+ } else if (_capslockActive) {
+ ascii = _capsToAscii[scancode];
+ } else {
+ ascii = _unshiftToAscii[scancode];
+ }
+
+ Common::KeyCode keycode = _scancodeToKeycode.getValOrDefault(scancode, Common::KEYCODE_INVALID);
+ switch (keycode) {
+ case Common::KEYCODE_BACKSPACE:
+ ascii = Common::ASCII_BACKSPACE;
+ break;
+ case Common::KEYCODE_TAB:
+ ascii = Common::ASCII_TAB;
+ break;
+ case Common::KEYCODE_RETURN:
+ case Common::KEYCODE_KP_ENTER:
+ ascii = Common::ASCII_RETURN;
+ break;
+ case Common::KEYCODE_ESCAPE:
+ ascii = Common::ASCII_ESCAPE;
+ break;
+ case Common::KEYCODE_SPACE:
+ ascii = Common::ASCII_SPACE;
+ break;
+ case Common::KEYCODE_F1:
+ ascii = Common::ASCII_F1;
+ break;
+ case Common::KEYCODE_F2:
+ ascii = Common::ASCII_F2;
+ break;
+ case Common::KEYCODE_F3:
+ ascii = Common::ASCII_F3;
+ break;
+ case Common::KEYCODE_F4:
+ ascii = Common::ASCII_F4;
+ break;
+ case Common::KEYCODE_F5:
+ ascii = Common::ASCII_F5;
+ break;
+ case Common::KEYCODE_F6:
+ ascii = Common::ASCII_F6;
+ break;
+ case Common::KEYCODE_F7:
+ ascii = Common::ASCII_F7;
+ break;
+ case Common::KEYCODE_F8:
+ ascii = Common::ASCII_F8;
+ break;
+ case Common::KEYCODE_F9:
+ ascii = Common::ASCII_F9;
+ break;
+ case Common::KEYCODE_F10:
+ ascii = Common::ASCII_F10;
+ break;
+ case Common::KEYCODE_F11:
+ ascii = Common::ASCII_F11;
+ break;
+ case Common::KEYCODE_F12:
+ ascii = Common::ASCII_F12;
+ break;
+ default:
+ break;
+ }
+
+ if (ascii >= ' ' && ascii <= '~') {
+ if (keycode == Common::KEYCODE_INVALID)
+ keycode = _asciiToKeycode[ascii - ' '];
+ }
+
+ event.type = pressed ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP;
+ event.kbd = Common::KeyState(keycode, ascii);
+ event.kbd.flags |= _ctrlActive ? Common::KBD_CTRL : 0;
+ event.kbd.flags |= _altActive ? Common::KBD_ALT : 0;
+ event.kbd.flags |= (_lshiftActive || _rshiftActive) ? Common::KBD_SHIFT : 0;
+ event.kbd.flags |= _capslockActive ? Common::KBD_CAPS : 0;
+
+ return true;
+ }
+
+ return false;
+}
+
+Common::MutexInternal *OSystem_Atari::createMutex() {
+ return new NullMutexInternal();
+}
+
+uint32 OSystem_Atari::getMillis(bool skipRecord) {
+ // CLOCKS_PER_SEC is 200, so no need to use floats
+ return 1000 * (clock() - _startTime) / CLOCKS_PER_SEC;
+}
+
+void OSystem_Atari::delayMillis(uint msecs) {
+ usleep(msecs * 1000);
+}
+
+void OSystem_Atari::getTimeAndDate(TimeDate &td, bool skipRecord) const {
+ debug("getTimeAndDate");
+ time_t curTime = time(0);
+ // TODO: if too slow (e.g. when calling RandomSource::RandomSource()), rewrite
+ struct tm t = *localtime(&curTime);
+ td.tm_sec = t.tm_sec;
+ td.tm_min = t.tm_min;
+ td.tm_hour = t.tm_hour;
+ td.tm_mday = t.tm_mday;
+ td.tm_mon = t.tm_mon;
+ td.tm_year = t.tm_year;
+ td.tm_wday = t.tm_wday;
+}
+
+Common::KeymapArray OSystem_Atari::getGlobalKeymaps() {
+ Common::KeymapArray globalMaps = BaseBackend::getGlobalKeymaps();
+
+ Common::Keymap *keymap = _atariGraphicsManager->getKeymap();
+ globalMaps.push_back(keymap);
+
+ return globalMaps;
+}
+
+Common::HardwareInputSet *OSystem_Atari::getHardwareInputSet() {
+ Common::CompositeHardwareInputSet *inputSet = new Common::CompositeHardwareInputSet();
+ inputSet->addHardwareInputSet(new Common::MouseHardwareInputSet(Common::defaultMouseButtons));
+ inputSet->addHardwareInputSet(new Common::KeyboardHardwareInputSet(Common::defaultKeys, Common::defaultModifiers));
+
+ return inputSet;
+}
+
+void OSystem_Atari::quit() {
+ Common::String str = Common::String::format("OSystem_Atari::quit()\n");
+ logMessage(LogMessageType::kDebug, str.c_str());
+
+ g_system->destroy();
+
+ exit(0);
+}
+
+void OSystem_Atari::logMessage(LogMessageType::Type type, const char *message) {
+ FILE *output = 0;
+
+ if (type == LogMessageType::kInfo || type == LogMessageType::kDebug)
+ output = stdout;
+ else
+ output = stderr;
+
+ fputs(message, output);
+ fflush(output);
+
+ nf_print(message);
+}
+
+void OSystem_Atari::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
+#ifdef DATA_PATH
+ // Add the global DATA_PATH to the directory search list
+ // See also OSystem_SDL::addSysArchivesToSearchSet()
+ Common::FSNode dataNode(DATA_PATH);
+ if (dataNode.exists() && dataNode.isDirectory()) {
+ s.add(DATA_PATH, new Common::FSDirectory(dataNode, 4), priority);
+ }
+#endif
+}
+
+Common::String OSystem_Atari::getDefaultConfigFileName() {
+ const Common::String baseConfigName = OSystem::getDefaultConfigFileName();
+
+ Common::String configFile;
+
+ const char *envVar = getenv("HOME");
+ if (envVar && *envVar) {
+ configFile = envVar;
+ configFile += '/';
+ configFile += baseConfigName;
+
+ if (configFile.size() < MAXPATHLEN)
+ return configFile;
+ }
+
+ return baseConfigName;
+}
+
+OSystem *OSystem_Atari_create() {
+ return new OSystem_Atari();
+}
+
+int main(int argc, char *argv[]) {
+ g_system = OSystem_Atari_create();
+ assert(g_system);
+
+ // Invoke the actual ScummVM main entry point:
+ int res = scummvm_main(argc, argv);
+ g_system->destroy();
+ return res;
+}
+
+#endif
diff --git a/backends/platform/atari/atari_ikbd.S b/backends/platform/atari/atari_ikbd.S
new file mode 100644
index 00000000000..b5a796611f9
--- /dev/null
+++ b/backends/platform/atari/atari_ikbd.S
@@ -0,0 +1,233 @@
+/* ScummVM - Graphic Adventure Engine
+*
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * IKBD 6301 interrupt routine
+ *
+ * Patrice Mandin
+ */
+
+ .globl _atari_ikbd_init
+ .globl _atari_ikbd_shutdown
+
+ .globl _g_atari_ikbd_mouse_buttons_state
+ .globl _g_atari_ikbd_mouse_delta_x
+ .globl _g_atari_ikbd_mouse_delta_y
+
+ .globl _g_atari_ikbd_scancodes
+ .globl _g_atari_ikbd_scancodes_size
+ .globl _g_atari_ikbb_scancodes_head
+
+
+ .text
+
+_atari_ikbd_init:
+ | Disable interrupts
+
+ movew sr,d1
+ movew #0x2700,sr
+
+ | Save MFP registers used for keyboard
+
+ lea 0xfffffa00:w,a0
+ btst #6,a0@(0x09)
+ sne ikbd_ierb
+ btst #6,a0@(0x15)
+ sne ikbd_imrb
+
+ | Set our routine
+
+ movel 0x118:w,old_ikbd
+ movel #ikbd,0x118:w
+ bset #6,0xfffffa09:w | IERB
+ bset #6,0xfffffa15:w | IMRB
+
+ | Set mouse relative mode
+
+ moveb #8,0xfffffc02:w
+
+ | Reenable interrupts
+
+ movew d1,sr
+ rts
+
+_atari_ikbd_shutdown:
+ | Disable interrupts
+
+ movew sr,d1
+ movew #0x2700,sr
+
+ | Restore previous MFP registers
+
+ lea 0xfffffa00:w,a0
+
+ bclr #6,a0@(0x09)
+ tstb ikbd_ierb
+ beqs ikbd_restoreierb
+ bset #6,a0@(0x09)
+ikbd_restoreierb:
+
+ bclr #6,a0@(0x15)
+ tstb ikbd_imrb
+ beqs ikbd_restoreimrb
+ bset #6,a0@(0x15)
+ikbd_restoreimrb:
+
+ movel old_ikbd,0x118:w
+
+ | Clear keyboard buffer
+
+ lea 0xfffffc00:w,a0
+ikbd_videbuffer:
+ btst #0,a0@
+ beqs ikbd_finbuffer
+ tstb a0@(0x02)
+ bras ikbd_videbuffer
+ikbd_finbuffer:
+
+ | Reenable interrupts
+
+ movew d1,sr
+ rts
+
+ .bss
+
+ .even
+ikbd_ierb:
+ .ds.b 1
+ikbd_imrb:
+ .ds.b 1
+
+/*--- Our custom IKBD vector ---*/
+
+ .text
+ .even
+ .ascii "XBRA"
+ .ascii "SCUM"
+old_ikbd:
+ .dc.l 0
+ikbd:
+ moveml d0-d1/a0,sp at -
+
+ | Check if source is IKBD or MIDI
+
+ btst #0,0xfffffc00.w
+ beqs ikbd_oldmidi
+
+ moveb 0xfffffc02:w,d0
+
+ | Not supported packets ?
+
+ | status report
+ cmpb #0xf6,d0
+ beqs ikbd_endit_stack
+ | absolute mouse position record
+ cmpb #0xf7,d0
+ beqs ikbd_endit_stack
+ | time-of-day
+ cmpb #0xfc,d0
+ beqs ikbd_endit_stack
+
+ | Joystick packet ?
+
+ | joystick report (both sticks), joystick 0 event, joystick 1 event
+ cmpb #0xfd,d0
+ bhss ikbd_endit_stack
+
+ | Mouse packet ?
+
+ cmpb #0xf8,d0
+ blos ikbd_no_mouse
+ cmpb #0xfc,d0
+ bhss ikbd_no_mouse
+
+ | Mouse packet, byte #1
+
+ikbd_yes_mouse:
+ andw #3,d0
+ moveb d0,_g_atari_ikbd_mouse_buttons_state
+
+ movel #ikbd_mousex,0x118:w
+ bras ikbd_endit_stack
+
+ | Keyboard press/release
+
+ikbd_no_mouse:
+ lea _g_atari_ikbd_scancodes,a0
+ movew _g_atari_ikbb_scancodes_head,d1
+
+ | g_atari_ikbd_scancodes[g_atari_ikbb_scancodes_head] = scancode
+
+ moveb d0,(0.b,a0,d1.w)
+
+ addql #1,d1
+ andw _g_atari_ikbd_scancodes_mask,d1
+ movew d1,_g_atari_ikbb_scancodes_head
+
+ | End of interrupt
+
+ikbd_endit_stack:
+ moveml sp at +,d0-d1/a0
+
+ bclr #6,0xfffffa11:w
+ rte
+
+ | Call old MIDI interrupt
+
+ikbd_oldmidi:
+ moveml sp at +,d0-d1/a0
+
+ movel old_ikbd,sp at -
+ rts
+
+ | Mouse packet, byte #2
+
+ikbd_mousex:
+ moveml d0-d1/a0,sp at -
+
+ | Check if source is IKBD or MIDI
+ btst #0,0xfffffc00.w
+ beqs ikbd_oldmidi
+
+ moveb 0xfffffc02:w,d0
+ extw d0
+ addw d0,_g_atari_ikbd_mouse_delta_x
+
+ movel #ikbd_mousey,0x118:w
+ bras ikbd_endit_stack
+
+ | Mouse packet, byte #3
+
+ikbd_mousey:
+ moveml d0-d1/a0,sp at -
+
+ | Check if source is IKBD or MIDI
+
+ btst #0,0xfffffc00.w
+ beqs ikbd_oldmidi
+
+ moveb 0xfffffc02:w,d0
+ extw d0
+
+ addw d0,_g_atari_ikbd_mouse_delta_y
+
+ movel #ikbd,0x118:w
+ bras ikbd_endit_stack
diff --git a/backends/platform/atari/module.mk b/backends/platform/atari/module.mk
new file mode 100644
index 00000000000..16bd53ec57b
--- /dev/null
+++ b/backends/platform/atari/module.mk
@@ -0,0 +1,11 @@
+MODULE := backends/platform/atari
+
+MODULE_OBJS := \
+ atari.o \
+ atari_ikbd.o \
+ native_features.o
+
+# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
+MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
+OBJS := $(MODULE_OBJS) $(OBJS)
+MODULE_DIRS += $(sort $(dir $(MODULE_OBJS)))
diff --git a/backends/platform/atari/native_features.cpp b/backends/platform/atari/native_features.cpp
new file mode 100644
index 00000000000..9763ec8ceae
--- /dev/null
+++ b/backends/platform/atari/native_features.cpp
@@ -0,0 +1,96 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+// Taken from mintlib (https://github.com/freemint/mintlib)
+// (c) Thorsten Otto
+
+#include <mint/osbind.h>
+#include <stdint.h>
+
+#define NATFEAT_ID 0x7300
+#define NATFEAT_CALL 0x7301
+
+#define ASM_NATFEAT3(opcode) "\t.word " #opcode "\n"
+#define ASM_NATFEAT2(opcode) ASM_NATFEAT3(opcode)
+#define ASM_NATFEAT(n) ASM_NATFEAT2(n)
+
+static unsigned short const nf_id_opcodes[] = { NATFEAT_ID, 0x4e75 };
+static unsigned short const nf_call_opcodes[] = { NATFEAT_CALL, 0x4e75 };
+
+#define _nf_get_id(feature_name) ((long (__CDECL *)(const char *))nf_id_opcodes)(feature_name)
+#define _nf_call(id, ...) ((long (__CDECL *)(long, ...))nf_call_opcodes)(id, __VA_ARGS__)
+
+/*
+ * on ColdFire, the NATFEAT_ID opcode is actually
+ * "mvs.b d0,d1",
+ * which means the following code will NOT detect
+ * the presence of an emulator (should there ever
+ * be an emulator capable of emulating a ColdFire processor).
+ * Luckily, executing the code on a CF processor is still
+ * harmless since all it does is clobber D1.
+ */
+static long _nf_detect_tos(void) {
+ register long ret __asm__ ("d0");
+ register const char *nf_version __asm__("a1") = "NF_VERSION";
+
+ __asm__ volatile(
+ "\tmove.l %1,-(%%sp)\n"
+ "\tmoveq #0,%%d0\n" /* assume no NatFeats available */
+ "\tmove.l %%d0,-(%%sp)\n"
+ "\tlea (1f:w,%%pc),%%a1\n"
+ "\tmove.l (0x0010).w,%%a0\n" /* illegal instruction vector */
+ "\tmove.l %%a1,(0x0010).w\n"
+ "\tmove.l %%sp,%%a1\n" /* save the ssp */
+
+ "\tnop\n" /* flush pipelines (for 68040+) */
+
+ ASM_NATFEAT(NATFEAT_ID) /* Jump to NATFEAT_ID */
+ "\ttst.l %%d0\n"
+ "\tbeq.s 1f\n"
+ "\tmoveq #1,%%d0\n" /* NatFeats detected */
+ "\tmove.l %%d0,(%%sp)\n"
+
+"1:\n"
+ "\tmove.l %%a1,%%sp\n"
+ "\tmove.l %%a0,(0x0010).w\n"
+ "\tmove.l (%%sp)+,%%d0\n"
+ "\taddq.l #4,%%sp\n" /* pop nf_version argument */
+
+ "\tnop\n" /* flush pipelines (for 68040+) */
+ : "=g"(ret) /* outputs */
+ : "g"(nf_version) /* inputs */
+ : __CLOBBER_RETURN("d0") "a0", "d1", "cc" AND_MEMORY
+ );
+ return ret;
+}
+
+static long nf_stderr_id;
+
+void nf_init(void) {
+ long ret = Supexec(_nf_detect_tos);
+ if (ret == 1)
+ nf_stderr_id = _nf_get_id("NF_STDERR");
+}
+
+void nf_print(const char* msg) {
+ if (nf_stderr_id)
+ _nf_call(nf_stderr_id | 0, (uint32_t)msg);
+}
diff --git a/backends/platform/atari/readme.txt b/backends/platform/atari/readme.txt
new file mode 100644
index 00000000000..f235c595132
--- /dev/null
+++ b/backends/platform/atari/readme.txt
@@ -0,0 +1,422 @@
+ScummVM
+=======
+
+This is a new port of ScummVM (https://www.scummvm.org), a program which allows
+you to run certain classic graphical adventure and role-playing games, provided
+you already have their data files.
+
+You can find a full list with details on which games are supported and how well
+on the compatibility page: https://www.scummvm.org/compatibility.
+
+
+Yet another port?
+-----------------
+
+Yes, I am aware of the official Atari/FreeMiNT port done by KeithS over the
+years (https://docs.scummvm.org/en/v2.6.1/other_platforms/atari.html). It is
+even updated every release and put on the official ScummVM website. That port
+is basically just a recompiled SDL backend for our platform - that certainly
+has some advantages (works in GEM, can be easily compiled for the FireBee etc.)
+but I have decided to take a different route:
+
+- Reduced executable size, basically whatever is not essential or plausible on
+ our platform is left out. That reduces the file size to half. See also the
+ next point.
+
+- Because there's a limited horsepower available on our platform, features like
+ hi-res 16bpp graphics, software synthesizers, scalers, real-time software
+ MP3/OGG/FLAC playback etc., are omitted. This saves memory and disk space,
+ making the whole port more lightweight.
+
+- This port natively talks to the hardware, avoiding intermediate layers like
+ SDL. Thus, it has more optimisations, fewer redraws, fewer data copying and
+ is less crash-prone.
+
+- Because we limit scope only to 8bpp games, it opens a door to more thorough
+ testing and there is a certain interest in this in the community. 16bpp games
+ could be played only in ARAnyM or similar, limiting the test audience a lot.
+
+After I had seen how snappy NovaCoder's ScummVM on the Amiga is (who coded
+his own backend), I decided to do the same and see whether I could do better.
+And I could!
+
+
+Main features
+-------------
+
+- Optimized for the Atari Falcon (ideally with the CT60/CT63/CT60e but for the
+less hungry games even a CT2/DFB at 50 MHz or the AfterBurner040 could be enough).
+
+- Full support for the SuperVidel, incl. the SuperBlitter (!)
+
+- Removed features found too demanding for our platform; the most visible
+ change is the exclusion of the 16bpp games (those are mostly hi-res anyway)
+ but games in 640x480 at 8bpp work nicely.
+
+- Direct rendering and single/double/triple buffering support.
+
+- Custom (and optimal) drawing routines (especially for the cursor).
+
+- Custom (Super)Videl resolutions for the best possible performance and visual
+ experience (320x240 in RGB, chunky modes with SuperVidel, 640x480 at 16bpp for
+ the overlay in RGB/SuperVidel, ...)
+
+- Custom (hardware based) aspect ratio correction (!)
+
+- Support for PC keys (page up, page down, pause, F11/F12, ...) and mouse wheel
+ (Eiffel/Aranym only)
+
+- Still without any assembly optimizations...
+
+This makes such games as The Curse of Monkey Island better playable (on
+SuperVidel nearly always also with CD (WAV) music and speech). Also, AdLib
+emulation works nicely with many games without noticeable slow downs.
+
+
+Platform-specific features outside the GUI
+------------------------------------------
+
+Keyboard shortcut "CONTROL+u": immediate mute on/off toggle (disables also
+sample mixing, contrary to what "Mute all" in the options does!)
+
+Keyboard shortcut "CONTROL+ALT+a": immediate aspect ratio correction on/off
+toggle.
+
+"output_rate" in scummvm.ini: sample rate for mixing, can be 49170, 32780,
+24585, 19668, 16390, 12292, 9834, 8195 (the lower the value, the faster the
+mixing but also in worse quality). Default is 24585 Hz (16-bit, stereo).
+
+"output_samples" in scummvm.ini: number of samples to preload. Default is 2048
+which equals to about 83ms of audio lag and seems to be about right for most
+games on my CT60 at 66 MHz.
+
+If you want to play with those two values, the rule of thumb is: (lag in ms) =
+(output_samples / output_rate) * 1000. But it's totally OK just to double the
+samples value to get rid of stuttering in a heavier game.
+
+
+Graphics modes
+--------------
+
+This topic is more complex than it looks. ScummVM renders game graphics using
+rectangles and this port offers following options to render them:
+
+Direct rendering (vsync on/off) - present only with the SuperVidel
+Single buffering (vsync on/off)
+Double buffering (vsync always on, the checkbox is ignored)
+Triple buffering (vsync always off, the checkbox just selects a different kind)
+
+Direct rendering:
+~~~~~~~~~~~~~~~~~
+
+This is direct writing of the pixels into (SuperVidel's) screen buffer. Since
+the updates are supplied as rectangles and not the whole screen there's no way
+to implement direct writing *and* double/triple buffering. Vsync() only
+synchronizes the point when the rendering process begins - if it takes more
+than the time reserved for the vertical blank interrupt (what happens
+with most of the games), you'll see screen tearing.
+
+Pros:
+
+- fastest possible rendering (especially in 640x480 with a lot of small
+ rectangle updates where the buffer copying drags performance down)
+
+Cons:
+
+- screen tearing in most cases
+
+- SuperVidel only: using C2P would be not only suboptimal (every rectangle
+ would be C2P'ed instead of just copy and C2P of the final screen) but poses an
+ additional problem as C2P requires data aligned on a 16px boundary and
+ ScummVM supplies arbitrarily-sized rectangles (this is solvable by custom
+ Surface allocation but it's not bullet-proof). In theory I could implement
+ direct rendering for the Falcon hicolor (320x240 at 16bpp) but this creates
+ another set of issues like when palette would be updated but not the whole
+ screen - so some rectangles would be rendered in old palette and some in new.
+
+SuperBlitter used: sometimes (when ScummVM allocates surface via its create()
+function; custom/small buffers originating in the engine code are still copied
+using the CPU).
+
+Single buffering:
+~~~~~~~~~~~~~~~~~
+
+This is very similar to the previous mode with the difference that the engine
+uses an intermediate buffer for storing the rectangles but yet it remembers
+which ones they were. It works also on plain Videl and applies the chunky to
+planar process to each one of the rectangles separately, avoiding fullscreen
+updates (but if such is needed, there is an optimized code path for it). Vsync()
+is used the same way as in the previous mode, i.e. screen tearing is still
+possible.
+
+Pros:
+
+- second fastest possible rendering
+
+- doesn't update the whole screen (works best with a moderate amount of
+ rectangles to update)
+
+Cons:
+
+- screen tearing in most cases
+
+- if there are too many smaller rectangles, it can be less efficient than
+ updating the whole buffer at once
+
+SuperBlitter used: yes, for rectangle blitting to screen and cursor restoration.
+Sometimes also for generic copying between buffers (see above).
+
+Double buffering:
+~~~~~~~~~~~~~~~~~
+
+The most common rendering mode. It extends the idea of single buffering - it
+renders into two buffers, one is visible while the other one is used for
+updating. At the end of the update process the two buffers are swapped, so the
+newly updated one is displayed. By definition, Vsync() must be always enabled
+(the buffers are swapped in the vertical blank handler) otherwise you'd see
+screen tearing.
+
+Pros:
+
+- stable frame rate, leading to fixed e.g. 30 FPS rendering for the whole time
+ if game takes, say, 1.7 - 1.9 frames per update
+
+- no screen tearing in any situation
+
+Cons:
+
+- since two buffers are present, the buffer is always blitted into the screen
+ surface as whole, even if only one tiny little rectangle is changed (excluding
+ the cursor)
+
+- frame rate is set to 60/30/15/etc FPS so you can see big irregular jumps
+ between 30 and 15 FPS for example; this is happening when screen updates take
+ variable amount of time but since Vsync() is always called, the rendering
+ pipeline has to wait until the next frame even if only 1% of the frame time
+ has been used.
+
+SuperBlitter used: yes, for rectangle blitting to screen and cursor restoration.
+Sometimes also for generic copying between buffers (see above).
+
+Triple buffering:
+~~~~~~~~~~~~~~~~~
+
+Best of both worlds - screen tearing is avoided thanks to using of multiple
+buffers and the rendering pipeline doesn't have to wait until Vsync(). The vsync
+flag is used only to differentiate between two (very similar) modes of
+operation:
+
+1. "True triple buffering" as described in
+https://en.wikipedia.org/wiki/Multiple_buffering#Triple_buffering (vsync on)
+
+2. "Swap chain" as described in https://en.wikipedia.org/wiki/Swap_chain (vsync
+off)
+
+Pros:
+
+- best compromise between performance and visual experience
+
+- works well with both higher and lower frame rates
+
+Cons:
+
+- since three buffers are present, the buffer is always blitted into the screen
+ surface as whole, even if only one tiny little rectangle is changed (excluding
+ the cursor)
+
+- slightly irregular frame rate (depends solely on the game's complexity)
+
+- in case of extremely fast rendering in 1.), one or more buffers are
+ dropped in favor of showing only the most recent one (unlikely)
+
+- in case of extremely fast rendering in 2.), screen tearing is possible
+ because the rendering pipeline starts overwriting the buffer which is
+ currently displayed (unlikely)
+
+SuperBlitter used: yes, for rectangle blitting to screen and cursor restoration.
+Sometimes also for generic copying between buffers (see above).
+
+Triple buffering with vsync on is the default mode for this port.
+
+
+SuperVidel and SuperBlitter
+---------------------------
+
+As mentioned, this port uses SuperVidel and its SuperBlitter heavily. That
+means that if the SuperVidel is detected, it does the following:
+
+- patches all 8bpp VGA resolutions to chunky ones, rendering all C2P routines
+ useless
+
+- patches all surface addresses with OR'ing 0xA0000000, i.e. using SV RAM
+ instead of slow ST RAM (and even instead of TT RAM for allowing pure
+ SuperBlitter copying)
+
+- when SuperVidel FW version >= 9 is detected, the async FIFO buffer is used
+ instead of the slower sync blitting (where one has to wait for every
+ rectangle blit to finish). This applies only for chunky buffer -> screen
+ surfaces copy (as the generic surface copy can't rely on this behavior) but
+ despite this limitation it sometimes leads to nearly zero-cost rendering
+ and makes a *huge* difference for 640x480 fullscreen updates.
+
+
+Performance considerations/pitfalls
+-----------------------------------
+
+It's important to understand what affects performance on our limited platform
+to avoid unpleasant playing experiences.
+
+Game engines with unexpected performance hit
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A typical example from this category is the Gobliins engine (and its
+sequels). At first it looks like our machine / backend is doing something
+terribly wrong but the truth is it is the engine itself which is doing a lot of
+unnecessary redraws and updates, sometimes even before reaching the backend.
+The only real solution is to profile and fix the engine.
+
+Too many fullscreen updates
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Somewhat related to the previous point - sometimes the engine authors didn't
+realize the impact of every update on the overall performance and instead of
+updating only the rectangles that really had changed, they ask for a full screen
+update. Not a problem on a >1 GHz machine but very visible on Atari! Also, this
+is (by definition) the case of animated intros, especially those in 640x480.
+
+MIDI vs. AdLib vs. sampled music
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It could seem that sample music replay must be the most demanding one but on the
+contrary! _Always_ choose a CD version of a game (with *.wav tracks) to any
+other version. With one exception: if you have a native MIDI device able to
+replay the given game's MIDI notes (using the STMIDI plugin). MIDI emulation
+(synthesis) can easily take down as many as 10 FPS.
+
+CD music slows everything down
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some games use separate audio *and* video streams (files). Even if the CPU is
+able to handle both, the bottleneck becomes ... disk access. This is visible in
+The Curse Of Monkey Island for example -- there's audible stuttering during the
+intro sequence (and during the game as well). Increasing "output_samples" makes
+the rendering literally crawling! Why? Because disk I/O is busy with loading
+even *more* sample data so there's less time for video loading and rendering.
+Try to put "musdisk1.bun" and "musdisk2.bun" into a ramdisk (i.e. u:/ram in
+FreeMiNT), you'll be pleasantly surprised with the performance boost gained.
+
+"Mute" vs. "Mute all" in GUI vs. "No music" in GUI
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Not the same thing. "Mute" (available only via the shortcut CONTROL+u) generates
+an event to which the sample mixer can react (i.e. stop mixing the silence...).
+
+"Mute all" doesn't generate anything, it basically just lowers the volume of the
+music to zero.
+
+"No music" means using the null audio plugin which prevents generating any MIDI
+music (and therefore avoiding the expensive synthesis emulation) but beware, it
+doesn't affect CD (*.wav) playback at all!
+
+So for the best performance, always choose "No music" in the GUI options when
+the game contains MIDI tracks and "Mute" when the game contains a sampled
+soundtrack.
+
+Please note that it is not that bad, you surely can play The Secret of Monkey
+Island with AdLib enabled (but the CD/talkie versions sound better and
+are cheaper to play ;)).
+
+Vsync in GUI
+~~~~~~~~~~~~
+
+Carefully with the vsync option. It can easily cripple direct/single buffer
+rendering by 10-15 FPS if not used with caution. That happens if a game takes,
+say, 1.2 frames per update (so causing screen tearing anyway and rendering the
+option useless) but Vsync() forces it to wait 2 full frames instead.
+
+By the way, the vsync flag in Global Options affects also the overlay rendering
+(with all the pitfalls which apply to the single buffering mode)
+
+Slow GUI
+~~~~~~~~
+
+Themes handling is quite slow - each theme must be depacked, each one contains
+quite a few XML files to parse and quite a few images to load/convert. That's
+the reason why the built-in one is used as default, it dramatically speeds up
+loading time. A compromise solution is to depack the theme in an equally named
+directory (i.e. avoiding the depacking phase) but you need a filesystem with
+long name support for that to work.
+
+
+Known issues
+------------
+
+- aspect ratio correction works on RGB only (yet)
+
+- SuperVidel's DVI output is stretched when in 320x200 or 640x400; I'll wait
+ for other people's experiences, maybe only my LCD is so lame.
+
+- adding a game in TOS and loading it in FreeMiNT (and vice versa) generates
+ incompatible paths. Either use only one system or edit scummvm.ini and set
+ there only relative paths (mintlib bug/limitation).
+
+- the talkie version of MI1 needs to be merged from two sources: first generate
+ the DOS version and then additionally also the flac version. Then convert all
+ *.flac files into *.wav and replace monkey.sof (flac) with monster.sou (DOS).
+ And of course, don't forget to set the extra path in Game options to the
+ folder where *.wav files are located! For MI2 just use the DOS version,
+ there are no CD tracks available. :(
+
+
+Future plans
+------------
+
+- aspect ratio correction for VGA/SuperVidel
+
+- unified file paths in scummvm.ini
+
+- 8bpp overlay (and get rid of all that 16bpp handling code)
+
+- profiling :) (see also https://github.com/scummvm/scummvm/pull/2382)
+
+- DSP-based sample mixer
+
+- avoid loading music/speech files (and thus slowing down everything) if muted
+
+- assembly copy routines for screen/chunky surfaces (even with SuperVidel
+ present it is not possible to use the SuperBlitter for every surface)
+
+- cached audio/video streams (i.e. don't load only "output_samples" number of
+ samples but cache, say, 1 second so disk i/o wont be so stressed)
+
+- using LDG or Thorsten Otto's sharedlibs: https://tho-otto.de/sharedlibs.php
+ for game engine plugins to relieve the huge binary size
+
+- reuse modified rects in double/triple buffer in the next frame - that way we
+ wouldn't need to refresh the whole screen in every case
+
+- add support for the TT030; this would be easily possible when I rewrite the
+ renderer with a more flexible resolution switching
+
+- ignore (queue) updateScreen() calls to avoid aggressive drawing / buffer
+ switching from some engines; update every X ms instead
+
+- don't hardcode some of the buffers for cacheing purposes, determine the size
+ based on amount of free RAM
+
+- true audio CD support via MetaDOS API
+
+- OPL2LPT and Retrowave support (if I manage to purchase it somewhere)
+
+Closing words
+â------------
+
+I have opened a pull request with all of my code
+(https://github.com/scummvm/scummvm/pull/4687) so who knows, maybe ScummVM
+2.8.0 for Atari will be already present on the official website. :-)
+
+
+MiKRO / Mystic Bytes, XX.XX.2023
+Kosice / Slovakia
+miro.kropacek at gmail.com
+http://mikro.atari.org
diff --git a/configure b/configure
index 7c263e049e8..d7b180dce8e 100755
--- a/configure
+++ b/configure
@@ -1637,6 +1637,11 @@ kos32)
_host_cpu=i686
_host_alias=kos32
;;
+m68k-atari-mint)
+ _host_os=mint
+ _host_cpu=m68k
+ _host_alias=m68k-atari-mint
+ ;;
maemo)
_host_os=maemo
_host_cpu=arm
@@ -3553,6 +3558,17 @@ if test -n "$_host"; then
_port_mk="backends/platform/sdl/kolibrios/kolibrios.mk"
;;
m68k-atari-mint)
+ # auto -> yes
+ if test "$_debug_build" = "no"; then
+ # --disable-debug
+ append_var LDFLAGS "-s"
+ fi
+
+ # auto -> no
+ if test "$_optimizations" = "yes"; then
+ # --enable-release, --enable-optimizations
+ append_var CXXFLAGS "-fomit-frame-pointer"
+ fi
_seq_midi=no
_timidity=no
;;
@@ -3841,6 +3857,16 @@ case $_backend in
_sdlnet=no
fi
;;
+ atari)
+ append_var DEFINES "-DATARI"
+ #append_var DEFINES "-DDISABLE_FANCY_THEMES"
+ #append_var DEFINES "-DDISABLE_SID"
+ #append_var DEFINES "-DDISABLE_NES_APU"
+ #append_var DEFINES "-DDISABLE_DOSBOX_OPL"
+ append_var ASFLAGS "-m68030"
+ append_var CXXFLAGS "-m68020-60"
+ append_var LDFLAGS "-m68020-60"
+ ;;
dc)
append_var INCLUDES '-I$(srcdir)/backends/platform/dc'
append_var INCLUDES "-isystem $RONINDIR/include"
Commit: 276cf354bf01b69e3bac272ca4d3c113fdc38d58
https://github.com/scummvm/scummvm/commit/276cf354bf01b69e3bac272ca4d3c113fdc38d58
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2023-03-04T23:38:42+01:00
Commit Message:
BACKENDS: ATARI: Separate AtariEventSource from OSystem_Atari
Changed paths:
A backends/events/atari/atari-events.cpp
A backends/events/atari/atari-events.h
A backends/platform/atari/osystem_atari.cpp
A backends/platform/atari/osystem_atari.h
R backends/platform/atari/atari.cpp
backends/module.mk
backends/platform/atari/module.mk
diff --git a/backends/events/atari/atari-events.cpp b/backends/events/atari/atari-events.cpp
new file mode 100644
index 00000000000..65f8f773c32
--- /dev/null
+++ b/backends/events/atari/atari-events.cpp
@@ -0,0 +1,295 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
+
+#include "backends/events/atari/atari-events.h"
+
+#include <mint/osbind.h>
+
+#include "backends/graphics/atari/atari-graphics.h"
+#include "backends/platform/atari/osystem_atari.h"
+#include "common/rect.h"
+
+//! bit 0: rmb
+//! bit 1: lmb
+volatile uint8 g_atari_ikbd_mouse_buttons_state = 0;
+volatile int16 g_atari_ikbd_mouse_delta_x = 0;
+volatile int16 g_atari_ikbd_mouse_delta_y = 0;
+
+#define SCANCODES_SIZE 256
+volatile uint8 g_atari_ikbd_scancodes[SCANCODES_SIZE];
+uint16 g_atari_ikbd_scancodes_mask = SCANCODES_SIZE-1;
+volatile uint16 g_atari_ikbb_scancodes_head = 0;
+static uint16 g_atari_ikbb_scancodes_tail = 0;
+
+
+AtariEventSource::AtariEventSource() {
+ _system = dynamic_cast<OSystem_Atari*>(g_system);
+ assert(_system != nullptr);
+
+ _KEYTAB *pKeyTables = (_KEYTAB*)Keytbl(KT_NOCHANGE, KT_NOCHANGE, KT_NOCHANGE);
+
+ memcpy(_unshiftToAscii, pKeyTables->unshift, 128);
+ memcpy(_shiftToAscii, pKeyTables->shift, 128);
+ memcpy(_capsToAscii, pKeyTables->caps, 128);
+
+ _scancodeToKeycode[0x01] = Common::KEYCODE_ESCAPE;
+ _scancodeToKeycode[0x0e] = Common::KEYCODE_BACKSPACE;
+ _scancodeToKeycode[0x0f] = Common::KEYCODE_TAB;
+ _scancodeToKeycode[0x1c] = Common::KEYCODE_RETURN;
+ _scancodeToKeycode[0x39] = Common::KEYCODE_SPACE;
+ _scancodeToKeycode[0x3b] = Common::KEYCODE_F1;
+ _scancodeToKeycode[0x3c] = Common::KEYCODE_F2;
+ _scancodeToKeycode[0x3d] = Common::KEYCODE_F3;
+ _scancodeToKeycode[0x3e] = Common::KEYCODE_F4;
+ _scancodeToKeycode[0x3f] = Common::KEYCODE_F5;
+ _scancodeToKeycode[0x40] = Common::KEYCODE_F6;
+ _scancodeToKeycode[0x41] = Common::KEYCODE_F7;
+ _scancodeToKeycode[0x42] = Common::KEYCODE_F8;
+ _scancodeToKeycode[0x43] = Common::KEYCODE_F9;
+ _scancodeToKeycode[0x44] = Common::KEYCODE_F10;
+ _scancodeToKeycode[0x45] = Common::KEYCODE_PAGEUP; // Eiffel only
+ _scancodeToKeycode[0x46] = Common::KEYCODE_PAGEDOWN; // Eiffel only
+ _scancodeToKeycode[0x47] = Common::KEYCODE_HOME;
+ _scancodeToKeycode[0x48] = Common::KEYCODE_UP;
+ _scancodeToKeycode[0x4a] = Common::KEYCODE_KP_MINUS;
+ _scancodeToKeycode[0x4b] = Common::KEYCODE_LEFT;
+ _scancodeToKeycode[0x4c] = Common::KEYCODE_LMETA;
+ _scancodeToKeycode[0x4d] = Common::KEYCODE_RIGHT;
+ _scancodeToKeycode[0x4e] = Common::KEYCODE_KP_PLUS;
+ _scancodeToKeycode[0x4f] = Common::KEYCODE_PAUSE; // Eiffel only
+ _scancodeToKeycode[0x50] = Common::KEYCODE_DOWN;
+ _scancodeToKeycode[0x52] = Common::KEYCODE_INSERT;
+ _scancodeToKeycode[0x53] = Common::KEYCODE_DELETE;
+ _scancodeToKeycode[0x55] = Common::KEYCODE_END; // Eiffel only
+ _scancodeToKeycode[0x5b] = Common::KEYCODE_TILDE; // Eiffel only
+ _scancodeToKeycode[0x61] = Common::KEYCODE_F12; // UNDO
+ _scancodeToKeycode[0x62] = Common::KEYCODE_F11; // HELP
+ _scancodeToKeycode[0x63] = Common::KEYCODE_SLASH; // KEYPAD /
+ _scancodeToKeycode[0x64] = Common::KEYCODE_KP_DIVIDE;
+ _scancodeToKeycode[0x65] = Common::KEYCODE_KP_MULTIPLY;
+ _scancodeToKeycode[0x66] = Common::KEYCODE_KP_MULTIPLY; // duplicate?
+ _scancodeToKeycode[0x67] = Common::KEYCODE_7; // KEYPAD 7
+ _scancodeToKeycode[0x68] = Common::KEYCODE_8; // KEYPAD 8
+ _scancodeToKeycode[0x69] = Common::KEYCODE_9; // KEYPAD 9
+ _scancodeToKeycode[0x6a] = Common::KEYCODE_4; // KEYPAD 4
+ _scancodeToKeycode[0x6b] = Common::KEYCODE_5; // KEYPAD 5
+ _scancodeToKeycode[0x6c] = Common::KEYCODE_6; // KEYPAD 6
+ _scancodeToKeycode[0x6d] = Common::KEYCODE_1; // KEYPAD 1
+ _scancodeToKeycode[0x6e] = Common::KEYCODE_2; // KEYPAD 2
+ _scancodeToKeycode[0x6f] = Common::KEYCODE_3; // KEYPAD 3
+ _scancodeToKeycode[0x70] = Common::KEYCODE_0; // KEYPAD 0
+ _scancodeToKeycode[0x71] = Common::KEYCODE_KP_PERIOD;
+ _scancodeToKeycode[0x72] = Common::KEYCODE_KP_ENTER;
+}
+
+bool AtariEventSource::pollEvent(Common::Event &event) {
+ if (!_graphicsManager)
+ return false;
+
+ static uint32 startMillis = _system->getMillis();
+ static uint32 oldMillis = _system->getMillis();
+ uint32 curMillis = _system->getMillis();
+
+ uint32 diff = curMillis - oldMillis;
+ oldMillis = curMillis;
+
+ if (diff > 0) {
+ static float avgFpsSum;
+ static int avgFpsCount;
+
+ avgFpsSum += 1000.0f / diff;
+ avgFpsCount++;
+
+ if (curMillis - startMillis >= 1000) {
+ float avgFps = avgFpsSum / avgFpsCount;
+ debug("*** Average FPS in 1s: %f ***", avgFps);
+ startMillis = curMillis;
+ avgFpsSum = 0;
+ avgFpsCount = 0;
+ }
+ }
+
+ _system->update();
+
+ if ((g_atari_ikbd_mouse_buttons_state & 0x01) && !_oldRmbDown) {
+ event.type = Common::EVENT_RBUTTONDOWN;
+ event.mouse = _graphicsManager->getMousePosition();
+ _oldRmbDown = true;
+ return true;
+ }
+
+ if (!(g_atari_ikbd_mouse_buttons_state & 0x01) && _oldRmbDown) {
+ event.type = Common::EVENT_RBUTTONUP;
+ event.mouse = _graphicsManager->getMousePosition();
+ _oldRmbDown = false;
+ return true;
+ }
+
+ if ((g_atari_ikbd_mouse_buttons_state & 0x02) && !_oldLmbDown) {
+ event.type = Common::EVENT_LBUTTONDOWN;
+ event.mouse = _graphicsManager->getMousePosition();
+ _oldLmbDown = true;
+ return true;
+ }
+
+ if (!(g_atari_ikbd_mouse_buttons_state & 0x02) && _oldLmbDown) {
+ event.type = Common::EVENT_LBUTTONUP;
+ event.mouse = _graphicsManager->getMousePosition();
+ _oldLmbDown = false;
+ return true;
+ }
+
+ if (g_atari_ikbd_mouse_delta_x != 0 || g_atari_ikbd_mouse_delta_y != 0) {
+ const int deltaX = g_atari_ikbd_mouse_delta_x;
+ const int deltaY = g_atari_ikbd_mouse_delta_y;
+
+ g_atari_ikbd_mouse_delta_x = g_atari_ikbd_mouse_delta_y = 0;
+
+ _graphicsManager->updateMousePosition(deltaX, deltaY);
+
+ event.type = Common::EVENT_MOUSEMOVE;
+ event.mouse = _graphicsManager->getMousePosition();
+ event.relMouse = Common::Point(deltaX, deltaY);
+ return true;
+ }
+
+ if (g_atari_ikbb_scancodes_head != g_atari_ikbb_scancodes_tail) {
+ byte scancode = g_atari_ikbd_scancodes[g_atari_ikbb_scancodes_tail++];
+ g_atari_ikbb_scancodes_tail &= SCANCODES_SIZE-1;
+
+ bool pressed = !(scancode & 0x80);
+ scancode &= 0x7f;
+
+ if (scancode == 0x1d)
+ _ctrlActive = pressed;
+
+ if (scancode == 0x2a)
+ _lshiftActive = pressed;
+
+ if (scancode == 0x36)
+ _rshiftActive = pressed;
+
+ if (scancode == 0x38)
+ _altActive = pressed;
+
+ if (scancode == 0x3a && pressed)
+ _capslockActive = !_capslockActive;
+
+ // Eiffel only
+ if (scancode == 0x59) {
+ event.type = Common::EVENT_WHEELUP;
+ event.mouse = _graphicsManager->getMousePosition();
+ return true;
+ }
+
+ // Eiffel only
+ if (scancode == 0x5a) {
+ event.type = Common::EVENT_WHEELDOWN;
+ event.mouse = _graphicsManager->getMousePosition();
+ return true;
+ }
+
+ uint16 ascii;
+ if (_lshiftActive || _rshiftActive) {
+ ascii = _shiftToAscii[scancode];
+ } else if (_capslockActive) {
+ ascii = _capsToAscii[scancode];
+ } else {
+ ascii = _unshiftToAscii[scancode];
+ }
+
+ Common::KeyCode keycode = _scancodeToKeycode.getValOrDefault(scancode, Common::KEYCODE_INVALID);
+ switch (keycode) {
+ case Common::KEYCODE_BACKSPACE:
+ ascii = Common::ASCII_BACKSPACE;
+ break;
+ case Common::KEYCODE_TAB:
+ ascii = Common::ASCII_TAB;
+ break;
+ case Common::KEYCODE_RETURN:
+ case Common::KEYCODE_KP_ENTER:
+ ascii = Common::ASCII_RETURN;
+ break;
+ case Common::KEYCODE_ESCAPE:
+ ascii = Common::ASCII_ESCAPE;
+ break;
+ case Common::KEYCODE_SPACE:
+ ascii = Common::ASCII_SPACE;
+ break;
+ case Common::KEYCODE_F1:
+ ascii = Common::ASCII_F1;
+ break;
+ case Common::KEYCODE_F2:
+ ascii = Common::ASCII_F2;
+ break;
+ case Common::KEYCODE_F3:
+ ascii = Common::ASCII_F3;
+ break;
+ case Common::KEYCODE_F4:
+ ascii = Common::ASCII_F4;
+ break;
+ case Common::KEYCODE_F5:
+ ascii = Common::ASCII_F5;
+ break;
+ case Common::KEYCODE_F6:
+ ascii = Common::ASCII_F6;
+ break;
+ case Common::KEYCODE_F7:
+ ascii = Common::ASCII_F7;
+ break;
+ case Common::KEYCODE_F8:
+ ascii = Common::ASCII_F8;
+ break;
+ case Common::KEYCODE_F9:
+ ascii = Common::ASCII_F9;
+ break;
+ case Common::KEYCODE_F10:
+ ascii = Common::ASCII_F10;
+ break;
+ case Common::KEYCODE_F11:
+ ascii = Common::ASCII_F11;
+ break;
+ case Common::KEYCODE_F12:
+ ascii = Common::ASCII_F12;
+ break;
+ default:
+ break;
+ }
+
+ if (ascii >= ' ' && ascii <= '~') {
+ if (keycode == Common::KEYCODE_INVALID)
+ keycode = _asciiToKeycode[ascii - ' '];
+ }
+
+ event.type = pressed ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP;
+ event.kbd = Common::KeyState(keycode, ascii);
+ event.kbd.flags |= _ctrlActive ? Common::KBD_CTRL : 0;
+ event.kbd.flags |= _altActive ? Common::KBD_ALT : 0;
+ event.kbd.flags |= (_lshiftActive || _rshiftActive) ? Common::KBD_SHIFT : 0;
+ event.kbd.flags |= _capslockActive ? Common::KBD_CAPS : 0;
+
+ return true;
+ }
+
+ return false;
+}
diff --git a/backends/events/atari/atari-events.h b/backends/events/atari/atari-events.h
new file mode 100644
index 00000000000..c98b6e307cf
--- /dev/null
+++ b/backends/events/atari/atari-events.h
@@ -0,0 +1,160 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef BACKEND_EVENTS_ATARI_H
+#define BACKEND_EVENTS_ATARI_H
+
+#include "common/events.h"
+
+#include "common/hashmap.h"
+
+class AtariGraphicsManager;
+class OSystem_Atari;
+
+/**
+ * The Atari event source.
+ */
+class AtariEventSource : public Common::EventSource {
+public:
+ AtariEventSource();
+
+ bool pollEvent(Common::Event &event) override;
+
+ void setGraphicsManager(AtariGraphicsManager *graphicsManager) { _graphicsManager = graphicsManager; }
+
+private:
+ OSystem_Atari *_system = nullptr;
+ AtariGraphicsManager *_graphicsManager = nullptr;
+
+ bool _oldLmbDown = false;
+ bool _oldRmbDown = false;
+
+ bool _lshiftActive = false;
+ bool _rshiftActive = false;
+ bool _ctrlActive = false;
+ bool _altActive = false;
+ bool _capslockActive = false;
+
+ byte _unshiftToAscii[128];
+ byte _shiftToAscii[128];
+ byte _capsToAscii[128];
+
+ const Common::KeyCode _asciiToKeycode[128 - 32 - 1] = {
+ Common::KEYCODE_SPACE,
+ Common::KEYCODE_EXCLAIM,
+ Common::KEYCODE_QUOTEDBL,
+ Common::KEYCODE_HASH,
+ Common::KEYCODE_DOLLAR,
+ Common::KEYCODE_PERCENT,
+ Common::KEYCODE_AMPERSAND,
+ Common::KEYCODE_QUOTE,
+ Common::KEYCODE_LEFTPAREN,
+ Common::KEYCODE_RIGHTPAREN,
+ Common::KEYCODE_ASTERISK,
+ Common::KEYCODE_PLUS,
+ Common::KEYCODE_COMMA,
+ Common::KEYCODE_MINUS,
+ Common::KEYCODE_PERIOD,
+ Common::KEYCODE_SLASH,
+ Common::KEYCODE_0,
+ Common::KEYCODE_1,
+ Common::KEYCODE_2,
+ Common::KEYCODE_3,
+ Common::KEYCODE_4,
+ Common::KEYCODE_5,
+ Common::KEYCODE_6,
+ Common::KEYCODE_7,
+ Common::KEYCODE_8,
+ Common::KEYCODE_9,
+ Common::KEYCODE_COLON,
+ Common::KEYCODE_SEMICOLON,
+ Common::KEYCODE_LESS,
+ Common::KEYCODE_EQUALS,
+ Common::KEYCODE_GREATER,
+ Common::KEYCODE_QUESTION,
+ Common::KEYCODE_AT,
+ Common::KEYCODE_a,
+ Common::KEYCODE_b,
+ Common::KEYCODE_c,
+ Common::KEYCODE_d,
+ Common::KEYCODE_e,
+ Common::KEYCODE_f,
+ Common::KEYCODE_g,
+ Common::KEYCODE_h,
+ Common::KEYCODE_i,
+ Common::KEYCODE_j,
+ Common::KEYCODE_k,
+ Common::KEYCODE_l,
+ Common::KEYCODE_m,
+ Common::KEYCODE_n,
+ Common::KEYCODE_o,
+ Common::KEYCODE_p,
+ Common::KEYCODE_q,
+ Common::KEYCODE_r,
+ Common::KEYCODE_s,
+ Common::KEYCODE_t,
+ Common::KEYCODE_u,
+ Common::KEYCODE_v,
+ Common::KEYCODE_w,
+ Common::KEYCODE_x,
+ Common::KEYCODE_y,
+ Common::KEYCODE_z,
+ Common::KEYCODE_LEFTBRACKET,
+ Common::KEYCODE_BACKSLASH,
+ Common::KEYCODE_RIGHTBRACKET,
+ Common::KEYCODE_CARET,
+ Common::KEYCODE_UNDERSCORE,
+ Common::KEYCODE_BACKQUOTE,
+ Common::KEYCODE_a,
+ Common::KEYCODE_b,
+ Common::KEYCODE_c,
+ Common::KEYCODE_d,
+ Common::KEYCODE_e,
+ Common::KEYCODE_f,
+ Common::KEYCODE_g,
+ Common::KEYCODE_h,
+ Common::KEYCODE_i,
+ Common::KEYCODE_j,
+ Common::KEYCODE_k,
+ Common::KEYCODE_l,
+ Common::KEYCODE_m,
+ Common::KEYCODE_n,
+ Common::KEYCODE_o,
+ Common::KEYCODE_p,
+ Common::KEYCODE_q,
+ Common::KEYCODE_r,
+ Common::KEYCODE_s,
+ Common::KEYCODE_t,
+ Common::KEYCODE_u,
+ Common::KEYCODE_v,
+ Common::KEYCODE_w,
+ Common::KEYCODE_x,
+ Common::KEYCODE_y,
+ Common::KEYCODE_z,
+ Common::KEYCODE_INVALID, // {
+ Common::KEYCODE_INVALID, // |
+ Common::KEYCODE_INVALID, // }
+ Common::KEYCODE_TILDE
+ };
+ Common::HashMap<byte, Common::KeyCode> _scancodeToKeycode;
+};
+
+#endif
diff --git a/backends/module.mk b/backends/module.mk
index 7b99c4a6103..9cbb3f47a46 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -323,6 +323,7 @@ endif
ifeq ($(BACKEND),atari)
MODULE_OBJS += \
+ events/atari/atari-events.o \
graphics/atari/atari_c2p-asm.o \
graphics/atari/atari-graphics.o \
graphics/atari/atari-graphics-asm.o \
diff --git a/backends/platform/atari/atari.cpp b/backends/platform/atari/atari.cpp
deleted file mode 100644
index ec3a0337f9a..00000000000
--- a/backends/platform/atari/atari.cpp
+++ /dev/null
@@ -1,660 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * 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 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <mint/cookie.h>
-#include <mint/falcon.h>
-#include <mint/osbind.h>
-
-// We use some stdio.h functionality here thus we need to allow some
-// symbols. Alternatively, we could simply allow everything by defining
-// FORBIDDEN_SYMBOL_ALLOW_ALL
-#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
-#define FORBIDDEN_SYMBOL_EXCEPTION_stdout
-#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
-#define FORBIDDEN_SYMBOL_EXCEPTION_fputs
-#define FORBIDDEN_SYMBOL_EXCEPTION_exit
-#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
-#define FORBIDDEN_SYMBOL_EXCEPTION_getenv
-
-#include "common/scummsys.h"
-
-#if defined(ATARI)
-#include "backends/graphics/atari/atari-graphics-asm.h"
-#include "backends/keymapper/hardware-input.h"
-#include "backends/modular-backend.h"
-#include "backends/mutex/null/null-mutex.h"
-#include "base/main.h"
-
-#include "backends/saves/default/default-saves.h"
-#include "backends/timer/default/default-timer.h"
-#include "backends/events/default/default-events.h"
-#include "backends/mixer/atari/atari-mixer.h"
-#include "backends/graphics/atari/atari-graphics.h"
-#include "backends/graphics/atari/atari-graphics-supervidel.h"
-#include "backends/graphics/atari/atari-graphics-videl.h"
-#include "common/hashmap.h"
-#include "gui/debugger.h"
-
-/*
- * Include header files needed for the getFilesystemFactory() method.
- */
-#include "backends/fs/posix/posix-fs-factory.h"
-
-class OSystem_Atari : public ModularMixerBackend, public ModularGraphicsBackend, Common::EventSource {
-public:
- OSystem_Atari();
- virtual ~OSystem_Atari();
-
- void initBackend() override;
-
- bool pollEvent(Common::Event &event) override;
-
- Common::MutexInternal *createMutex() override;
- uint32 getMillis(bool skipRecord = false) override;
- void delayMillis(uint msecs) override;
- void getTimeAndDate(TimeDate &td, bool skipRecord = false) const override;
-
- Common::KeymapArray getGlobalKeymaps() override;
- Common::HardwareInputSet *getHardwareInputSet() override;
-
- void quit() override;
-
- void logMessage(LogMessageType::Type type, const char *message) override;
-
- void addSysArchivesToSearchSet(Common::SearchSet &s, int priority) override;
- Common::String getDefaultConfigFileName() override;
-
-private:
- AtariGraphicsManager *_atariGraphicsManager;
-
- clock_t _startTime;
-
- bool _video_initialized = false;
- bool _ikbd_initialized = false;
-
- bool _oldLmbDown = false;
- bool _oldRmbDown = false;
-
- bool _lshiftActive = false;
- bool _rshiftActive = false;
- bool _ctrlActive = false;
- bool _altActive = false;
- bool _capslockActive = false;
-
- byte _unshiftToAscii[128];
- byte _shiftToAscii[128];
- byte _capsToAscii[128];
-
- const Common::KeyCode _asciiToKeycode[128 - 32 - 1] = {
- Common::KEYCODE_SPACE,
- Common::KEYCODE_EXCLAIM,
- Common::KEYCODE_QUOTEDBL,
- Common::KEYCODE_HASH,
- Common::KEYCODE_DOLLAR,
- Common::KEYCODE_PERCENT,
- Common::KEYCODE_AMPERSAND,
- Common::KEYCODE_QUOTE,
- Common::KEYCODE_LEFTPAREN,
- Common::KEYCODE_RIGHTPAREN,
- Common::KEYCODE_ASTERISK,
- Common::KEYCODE_PLUS,
- Common::KEYCODE_COMMA,
- Common::KEYCODE_MINUS,
- Common::KEYCODE_PERIOD,
- Common::KEYCODE_SLASH,
- Common::KEYCODE_0,
- Common::KEYCODE_1,
- Common::KEYCODE_2,
- Common::KEYCODE_3,
- Common::KEYCODE_4,
- Common::KEYCODE_5,
- Common::KEYCODE_6,
- Common::KEYCODE_7,
- Common::KEYCODE_8,
- Common::KEYCODE_9,
- Common::KEYCODE_COLON,
- Common::KEYCODE_SEMICOLON,
- Common::KEYCODE_LESS,
- Common::KEYCODE_EQUALS,
- Common::KEYCODE_GREATER,
- Common::KEYCODE_QUESTION,
- Common::KEYCODE_AT,
- Common::KEYCODE_a,
- Common::KEYCODE_b,
- Common::KEYCODE_c,
- Common::KEYCODE_d,
- Common::KEYCODE_e,
- Common::KEYCODE_f,
- Common::KEYCODE_g,
- Common::KEYCODE_h,
- Common::KEYCODE_i,
- Common::KEYCODE_j,
- Common::KEYCODE_k,
- Common::KEYCODE_l,
- Common::KEYCODE_m,
- Common::KEYCODE_n,
- Common::KEYCODE_o,
- Common::KEYCODE_p,
- Common::KEYCODE_q,
- Common::KEYCODE_r,
- Common::KEYCODE_s,
- Common::KEYCODE_t,
- Common::KEYCODE_u,
- Common::KEYCODE_v,
- Common::KEYCODE_w,
- Common::KEYCODE_x,
- Common::KEYCODE_y,
- Common::KEYCODE_z,
- Common::KEYCODE_LEFTBRACKET,
- Common::KEYCODE_BACKSLASH,
- Common::KEYCODE_RIGHTBRACKET,
- Common::KEYCODE_CARET,
- Common::KEYCODE_UNDERSCORE,
- Common::KEYCODE_BACKQUOTE,
- Common::KEYCODE_a,
- Common::KEYCODE_b,
- Common::KEYCODE_c,
- Common::KEYCODE_d,
- Common::KEYCODE_e,
- Common::KEYCODE_f,
- Common::KEYCODE_g,
- Common::KEYCODE_h,
- Common::KEYCODE_i,
- Common::KEYCODE_j,
- Common::KEYCODE_k,
- Common::KEYCODE_l,
- Common::KEYCODE_m,
- Common::KEYCODE_n,
- Common::KEYCODE_o,
- Common::KEYCODE_p,
- Common::KEYCODE_q,
- Common::KEYCODE_r,
- Common::KEYCODE_s,
- Common::KEYCODE_t,
- Common::KEYCODE_u,
- Common::KEYCODE_v,
- Common::KEYCODE_w,
- Common::KEYCODE_x,
- Common::KEYCODE_y,
- Common::KEYCODE_z,
- Common::KEYCODE_INVALID, // {
- Common::KEYCODE_INVALID, // |
- Common::KEYCODE_INVALID, // }
- Common::KEYCODE_TILDE
- };
- Common::HashMap<byte, Common::KeyCode> _scancodeToKeycode;
-};
-
-extern "C" void atari_ikbd_init();
-extern "C" void atari_ikbd_shutdown();
-
-extern void nf_init(void);
-extern void nf_print(const char* msg);
-
-OSystem_Atari::OSystem_Atari() {
- _fsFactory = new POSIXFilesystemFactory();
-
- _scancodeToKeycode[0x01] = Common::KEYCODE_ESCAPE;
- _scancodeToKeycode[0x0e] = Common::KEYCODE_BACKSPACE;
- _scancodeToKeycode[0x0f] = Common::KEYCODE_TAB;
- _scancodeToKeycode[0x1c] = Common::KEYCODE_RETURN;
- _scancodeToKeycode[0x39] = Common::KEYCODE_SPACE;
- _scancodeToKeycode[0x3b] = Common::KEYCODE_F1;
- _scancodeToKeycode[0x3c] = Common::KEYCODE_F2;
- _scancodeToKeycode[0x3d] = Common::KEYCODE_F3;
- _scancodeToKeycode[0x3e] = Common::KEYCODE_F4;
- _scancodeToKeycode[0x3f] = Common::KEYCODE_F5;
- _scancodeToKeycode[0x40] = Common::KEYCODE_F6;
- _scancodeToKeycode[0x41] = Common::KEYCODE_F7;
- _scancodeToKeycode[0x42] = Common::KEYCODE_F8;
- _scancodeToKeycode[0x43] = Common::KEYCODE_F9;
- _scancodeToKeycode[0x44] = Common::KEYCODE_F10;
- _scancodeToKeycode[0x45] = Common::KEYCODE_PAGEUP; // Eiffel only
- _scancodeToKeycode[0x46] = Common::KEYCODE_PAGEDOWN; // Eiffel only
- _scancodeToKeycode[0x47] = Common::KEYCODE_HOME;
- _scancodeToKeycode[0x48] = Common::KEYCODE_UP;
- _scancodeToKeycode[0x4a] = Common::KEYCODE_KP_MINUS;
- _scancodeToKeycode[0x4b] = Common::KEYCODE_LEFT;
- _scancodeToKeycode[0x4c] = Common::KEYCODE_LMETA;
- _scancodeToKeycode[0x4d] = Common::KEYCODE_RIGHT;
- _scancodeToKeycode[0x4e] = Common::KEYCODE_KP_PLUS;
- _scancodeToKeycode[0x4f] = Common::KEYCODE_PAUSE; // Eiffel only
- _scancodeToKeycode[0x50] = Common::KEYCODE_DOWN;
- _scancodeToKeycode[0x52] = Common::KEYCODE_INSERT;
- _scancodeToKeycode[0x53] = Common::KEYCODE_DELETE;
- _scancodeToKeycode[0x55] = Common::KEYCODE_END; // Eiffel only
- _scancodeToKeycode[0x5b] = Common::KEYCODE_TILDE; // Eiffel only
- _scancodeToKeycode[0x61] = Common::KEYCODE_F12; // UNDO
- _scancodeToKeycode[0x62] = Common::KEYCODE_F11; // HELP
- _scancodeToKeycode[0x63] = Common::KEYCODE_SLASH; // KEYPAD /
- _scancodeToKeycode[0x64] = Common::KEYCODE_KP_DIVIDE;
- _scancodeToKeycode[0x65] = Common::KEYCODE_KP_MULTIPLY;
- _scancodeToKeycode[0x66] = Common::KEYCODE_KP_MULTIPLY; // duplicate?
- _scancodeToKeycode[0x67] = Common::KEYCODE_7; // KEYPAD 7
- _scancodeToKeycode[0x68] = Common::KEYCODE_8; // KEYPAD 8
- _scancodeToKeycode[0x69] = Common::KEYCODE_9; // KEYPAD 9
- _scancodeToKeycode[0x6a] = Common::KEYCODE_4; // KEYPAD 4
- _scancodeToKeycode[0x6b] = Common::KEYCODE_5; // KEYPAD 5
- _scancodeToKeycode[0x6c] = Common::KEYCODE_6; // KEYPAD 6
- _scancodeToKeycode[0x6d] = Common::KEYCODE_1; // KEYPAD 1
- _scancodeToKeycode[0x6e] = Common::KEYCODE_2; // KEYPAD 2
- _scancodeToKeycode[0x6f] = Common::KEYCODE_3; // KEYPAD 3
- _scancodeToKeycode[0x70] = Common::KEYCODE_0; // KEYPAD 0
- _scancodeToKeycode[0x71] = Common::KEYCODE_KP_PERIOD;
- _scancodeToKeycode[0x72] = Common::KEYCODE_KP_ENTER;
-}
-
-OSystem_Atari::~OSystem_Atari() {
- debug("OSystem_Atari::~OSystem_Atari()");
-
- if (_video_initialized) {
- Supexec(asm_screen_falcon_restore);
- _video_initialized = false;
- }
-
- if (_ikbd_initialized) {
- Supexec(atari_ikbd_shutdown);
- _ikbd_initialized = false;
- }
-}
-
-static void ikbd_and_video_restore() {
- Supexec(asm_screen_falcon_restore);
- Supexec(atari_ikbd_shutdown);
-}
-
-void OSystem_Atari::initBackend() {
- enum {
- MCH_ST = 0,
- MCH_STE,
- MCH_TT,
- MCH_FALCON,
- MCH_CLONE,
- MCH_ARANYM
- };
-
- long mch = MCH_ST<<16;
- Getcookie(C__MCH, &mch);
- mch >>= 16;
-
- if (mch != MCH_FALCON && mch != MCH_ARANYM) {
- error("ScummVM works only on Atari Falcon and ARAnyM");
- }
-
- if (mch == MCH_ARANYM && Getcookie(C_fVDI, NULL) == C_FOUND) {
- logMessage(LogMessageType::kError, "Disable fVDI, ScummVM accesses Videl directly\n");
- quit();
- }
-
- nf_init();
-
- _startTime = clock();
-
- bool superVidel = VgetMonitor() == MON_VGA && Getcookie(C_SupV, NULL) == C_FOUND;
-
- _timerManager = new DefaultTimerManager();
- _eventManager = new DefaultEventManager(makeKeyboardRepeatingEventSource(this));
- _savefileManager = new DefaultSaveFileManager();
- if (superVidel)
- _atariGraphicsManager = new AtariSuperVidelManager();
- else
- _atariGraphicsManager = new AtariVidelManager();
- _graphicsManager = _atariGraphicsManager;
- _mixerManager = new AtariMixerManager();
- // Setup and start mixer
- _mixerManager->init();
-
- _KEYTAB *pKeyTables = (_KEYTAB*)Keytbl(KT_NOCHANGE, KT_NOCHANGE, KT_NOCHANGE);
-
- memcpy(_unshiftToAscii, pKeyTables->unshift, 128);
- memcpy(_shiftToAscii, pKeyTables->shift, 128);
- memcpy(_capsToAscii, pKeyTables->caps, 128);
-
- Supexec(atari_ikbd_init);
- _ikbd_initialized = true;
-
- Supexec(asm_screen_falcon_save);
- _video_initialized = true;
-
- Setexc(VEC_PROCTERM, ikbd_and_video_restore);
-
- BaseBackend::initBackend();
-}
-
-//! bit 0: rmb
-//! bit 1: lmb
-volatile uint8 g_atari_ikbd_mouse_buttons_state = 0;
-volatile int16 g_atari_ikbd_mouse_delta_x = 0;
-volatile int16 g_atari_ikbd_mouse_delta_y = 0;
-
-#define SCANCODES_SIZE 256
-volatile uint8 g_atari_ikbd_scancodes[SCANCODES_SIZE];
-uint16 g_atari_ikbd_scancodes_mask = SCANCODES_SIZE-1;
-volatile uint16 g_atari_ikbb_scancodes_head = 0;
-static uint16 g_atari_ikbb_scancodes_tail = 0;
-
-bool OSystem_Atari::pollEvent(Common::Event &event) {
- {
- static uint32 startMillis = getMillis();
- static uint32 oldMillis = getMillis();
- uint32 curMillis = getMillis();
-
- uint32 diff = curMillis - oldMillis;
- oldMillis = curMillis;
-
- if (diff > 0) {
- static float avgFpsSum;
- static int avgFpsCount;
-
- avgFpsSum += 1000.0f / diff;
- avgFpsCount++;
-
- if (curMillis - startMillis >= 1000) {
- float avgFps = avgFpsSum / avgFpsCount;
- debug("*** Average FPS in 1s: %f ***", avgFps);
- startMillis = curMillis;
- avgFpsSum = 0;
- avgFpsCount = 0;
- }
- }
- }
-
- ((DefaultTimerManager *)_timerManager)->checkTimers();
- ((AtariMixerManager *)_mixerManager)->update();
-
- if ((g_atari_ikbd_mouse_buttons_state & 0x01) && !_oldRmbDown) {
- event.type = Common::EVENT_RBUTTONDOWN;
- event.mouse = _atariGraphicsManager->getMousePosition();
- _oldRmbDown = true;
- return true;
- }
-
- if (!(g_atari_ikbd_mouse_buttons_state & 0x01) && _oldRmbDown) {
- event.type = Common::EVENT_RBUTTONUP;
- event.mouse = _atariGraphicsManager->getMousePosition();
- _oldRmbDown = false;
- return true;
- }
-
- if ((g_atari_ikbd_mouse_buttons_state & 0x02) && !_oldLmbDown) {
- event.type = Common::EVENT_LBUTTONDOWN;
- event.mouse = _atariGraphicsManager->getMousePosition();
- _oldLmbDown = true;
- return true;
- }
-
- if (!(g_atari_ikbd_mouse_buttons_state & 0x02) && _oldLmbDown) {
- event.type = Common::EVENT_LBUTTONUP;
- event.mouse = _atariGraphicsManager->getMousePosition();
- _oldLmbDown = false;
- return true;
- }
-
- if (g_atari_ikbd_mouse_delta_x != 0 || g_atari_ikbd_mouse_delta_y != 0) {
- const int deltaX = g_atari_ikbd_mouse_delta_x;
- const int deltaY = g_atari_ikbd_mouse_delta_y;
-
- g_atari_ikbd_mouse_delta_x = g_atari_ikbd_mouse_delta_y = 0;
-
- _atariGraphicsManager->updateMousePosition(deltaX, deltaY);
-
- event.type = Common::EVENT_MOUSEMOVE;
- event.mouse = _atariGraphicsManager->getMousePosition();
- event.relMouse = Common::Point(deltaX, deltaY);
- return true;
- }
-
- if (g_atari_ikbb_scancodes_head != g_atari_ikbb_scancodes_tail) {
- byte scancode = g_atari_ikbd_scancodes[g_atari_ikbb_scancodes_tail++];
- g_atari_ikbb_scancodes_tail &= SCANCODES_SIZE-1;
-
- bool pressed = !(scancode & 0x80);
- scancode &= 0x7f;
-
- if (scancode == 0x1d)
- _ctrlActive = pressed;
-
- if (scancode == 0x2a)
- _lshiftActive = pressed;
-
- if (scancode == 0x36)
- _rshiftActive = pressed;
-
- if (scancode == 0x38)
- _altActive = pressed;
-
- if (scancode == 0x3a && pressed)
- _capslockActive = !_capslockActive;
-
- // Eiffel only
- if (scancode == 0x59) {
- event.type = Common::EVENT_WHEELUP;
- event.mouse = _atariGraphicsManager->getMousePosition();
- return true;
- }
-
- // Eiffel only
- if (scancode == 0x5a) {
- event.type = Common::EVENT_WHEELDOWN;
- event.mouse = _atariGraphicsManager->getMousePosition();
- return true;
- }
-
- uint16 ascii;
- if (_lshiftActive || _rshiftActive) {
- ascii = _shiftToAscii[scancode];
- } else if (_capslockActive) {
- ascii = _capsToAscii[scancode];
- } else {
- ascii = _unshiftToAscii[scancode];
- }
-
- Common::KeyCode keycode = _scancodeToKeycode.getValOrDefault(scancode, Common::KEYCODE_INVALID);
- switch (keycode) {
- case Common::KEYCODE_BACKSPACE:
- ascii = Common::ASCII_BACKSPACE;
- break;
- case Common::KEYCODE_TAB:
- ascii = Common::ASCII_TAB;
- break;
- case Common::KEYCODE_RETURN:
- case Common::KEYCODE_KP_ENTER:
- ascii = Common::ASCII_RETURN;
- break;
- case Common::KEYCODE_ESCAPE:
- ascii = Common::ASCII_ESCAPE;
- break;
- case Common::KEYCODE_SPACE:
- ascii = Common::ASCII_SPACE;
- break;
- case Common::KEYCODE_F1:
- ascii = Common::ASCII_F1;
- break;
- case Common::KEYCODE_F2:
- ascii = Common::ASCII_F2;
- break;
- case Common::KEYCODE_F3:
- ascii = Common::ASCII_F3;
- break;
- case Common::KEYCODE_F4:
- ascii = Common::ASCII_F4;
- break;
- case Common::KEYCODE_F5:
- ascii = Common::ASCII_F5;
- break;
- case Common::KEYCODE_F6:
- ascii = Common::ASCII_F6;
- break;
- case Common::KEYCODE_F7:
- ascii = Common::ASCII_F7;
- break;
- case Common::KEYCODE_F8:
- ascii = Common::ASCII_F8;
- break;
- case Common::KEYCODE_F9:
- ascii = Common::ASCII_F9;
- break;
- case Common::KEYCODE_F10:
- ascii = Common::ASCII_F10;
- break;
- case Common::KEYCODE_F11:
- ascii = Common::ASCII_F11;
- break;
- case Common::KEYCODE_F12:
- ascii = Common::ASCII_F12;
- break;
- default:
- break;
- }
-
- if (ascii >= ' ' && ascii <= '~') {
- if (keycode == Common::KEYCODE_INVALID)
- keycode = _asciiToKeycode[ascii - ' '];
- }
-
- event.type = pressed ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP;
- event.kbd = Common::KeyState(keycode, ascii);
- event.kbd.flags |= _ctrlActive ? Common::KBD_CTRL : 0;
- event.kbd.flags |= _altActive ? Common::KBD_ALT : 0;
- event.kbd.flags |= (_lshiftActive || _rshiftActive) ? Common::KBD_SHIFT : 0;
- event.kbd.flags |= _capslockActive ? Common::KBD_CAPS : 0;
-
- return true;
- }
-
- return false;
-}
-
-Common::MutexInternal *OSystem_Atari::createMutex() {
- return new NullMutexInternal();
-}
-
-uint32 OSystem_Atari::getMillis(bool skipRecord) {
- // CLOCKS_PER_SEC is 200, so no need to use floats
- return 1000 * (clock() - _startTime) / CLOCKS_PER_SEC;
-}
-
-void OSystem_Atari::delayMillis(uint msecs) {
- usleep(msecs * 1000);
-}
-
-void OSystem_Atari::getTimeAndDate(TimeDate &td, bool skipRecord) const {
- debug("getTimeAndDate");
- time_t curTime = time(0);
- // TODO: if too slow (e.g. when calling RandomSource::RandomSource()), rewrite
- struct tm t = *localtime(&curTime);
- td.tm_sec = t.tm_sec;
- td.tm_min = t.tm_min;
- td.tm_hour = t.tm_hour;
- td.tm_mday = t.tm_mday;
- td.tm_mon = t.tm_mon;
- td.tm_year = t.tm_year;
- td.tm_wday = t.tm_wday;
-}
-
-Common::KeymapArray OSystem_Atari::getGlobalKeymaps() {
- Common::KeymapArray globalMaps = BaseBackend::getGlobalKeymaps();
-
- Common::Keymap *keymap = _atariGraphicsManager->getKeymap();
- globalMaps.push_back(keymap);
-
- return globalMaps;
-}
-
-Common::HardwareInputSet *OSystem_Atari::getHardwareInputSet() {
- Common::CompositeHardwareInputSet *inputSet = new Common::CompositeHardwareInputSet();
- inputSet->addHardwareInputSet(new Common::MouseHardwareInputSet(Common::defaultMouseButtons));
- inputSet->addHardwareInputSet(new Common::KeyboardHardwareInputSet(Common::defaultKeys, Common::defaultModifiers));
-
- return inputSet;
-}
-
-void OSystem_Atari::quit() {
- Common::String str = Common::String::format("OSystem_Atari::quit()\n");
- logMessage(LogMessageType::kDebug, str.c_str());
-
- g_system->destroy();
-
- exit(0);
-}
-
-void OSystem_Atari::logMessage(LogMessageType::Type type, const char *message) {
- FILE *output = 0;
-
- if (type == LogMessageType::kInfo || type == LogMessageType::kDebug)
- output = stdout;
- else
- output = stderr;
-
- fputs(message, output);
- fflush(output);
-
- nf_print(message);
-}
-
-void OSystem_Atari::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
-#ifdef DATA_PATH
- // Add the global DATA_PATH to the directory search list
- // See also OSystem_SDL::addSysArchivesToSearchSet()
- Common::FSNode dataNode(DATA_PATH);
- if (dataNode.exists() && dataNode.isDirectory()) {
- s.add(DATA_PATH, new Common::FSDirectory(dataNode, 4), priority);
- }
-#endif
-}
-
-Common::String OSystem_Atari::getDefaultConfigFileName() {
- const Common::String baseConfigName = OSystem::getDefaultConfigFileName();
-
- Common::String configFile;
-
- const char *envVar = getenv("HOME");
- if (envVar && *envVar) {
- configFile = envVar;
- configFile += '/';
- configFile += baseConfigName;
-
- if (configFile.size() < MAXPATHLEN)
- return configFile;
- }
-
- return baseConfigName;
-}
-
-OSystem *OSystem_Atari_create() {
- return new OSystem_Atari();
-}
-
-int main(int argc, char *argv[]) {
- g_system = OSystem_Atari_create();
- assert(g_system);
-
- // Invoke the actual ScummVM main entry point:
- int res = scummvm_main(argc, argv);
- g_system->destroy();
- return res;
-}
-
-#endif
diff --git a/backends/platform/atari/module.mk b/backends/platform/atari/module.mk
index 16bd53ec57b..d3982a71a11 100644
--- a/backends/platform/atari/module.mk
+++ b/backends/platform/atari/module.mk
@@ -1,7 +1,7 @@
MODULE := backends/platform/atari
MODULE_OBJS := \
- atari.o \
+ osystem_atari.o \
atari_ikbd.o \
native_features.o
diff --git a/backends/platform/atari/osystem_atari.cpp b/backends/platform/atari/osystem_atari.cpp
new file mode 100644
index 00000000000..44259335b59
--- /dev/null
+++ b/backends/platform/atari/osystem_atari.cpp
@@ -0,0 +1,265 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <mint/cookie.h>
+#include <mint/falcon.h>
+#include <mint/osbind.h>
+
+// We use some stdio.h functionality here thus we need to allow some
+// symbols. Alternatively, we could simply allow everything by defining
+// FORBIDDEN_SYMBOL_ALLOW_ALL
+#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
+#define FORBIDDEN_SYMBOL_EXCEPTION_stdout
+#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
+#define FORBIDDEN_SYMBOL_EXCEPTION_fputs
+#define FORBIDDEN_SYMBOL_EXCEPTION_exit
+#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
+#define FORBIDDEN_SYMBOL_EXCEPTION_getenv
+
+#include "backends/platform/atari/osystem_atari.h"
+
+#if defined(ATARI)
+#include "backends/graphics/atari/atari-graphics-asm.h"
+#include "backends/keymapper/hardware-input.h"
+#include "backends/mutex/null/null-mutex.h"
+#include "base/main.h"
+
+#include "backends/saves/default/default-saves.h"
+#include "backends/timer/default/default-timer.h"
+#include "backends/events/atari/atari-events.h"
+#include "backends/events/default/default-events.h"
+#include "backends/mixer/atari/atari-mixer.h"
+#include "backends/graphics/atari/atari-graphics.h"
+#include "backends/graphics/atari/atari-graphics-supervidel.h"
+#include "backends/graphics/atari/atari-graphics-videl.h"
+#include "gui/debugger.h"
+
+/*
+ * Include header files needed for the getFilesystemFactory() method.
+ */
+#include "backends/fs/posix/posix-fs-factory.h"
+
+extern "C" void atari_ikbd_init();
+extern "C" void atari_ikbd_shutdown();
+
+extern void nf_init(void);
+extern void nf_print(const char* msg);
+
+OSystem_Atari::OSystem_Atari() {
+ _fsFactory = new POSIXFilesystemFactory();
+}
+
+OSystem_Atari::~OSystem_Atari() {
+ debug("OSystem_Atari::~OSystem_Atari()");
+
+ if (_video_initialized) {
+ Supexec(asm_screen_falcon_restore);
+ _video_initialized = false;
+ }
+
+ if (_ikbd_initialized) {
+ Supexec(atari_ikbd_shutdown);
+ _ikbd_initialized = false;
+ }
+}
+
+static void ikbd_and_video_restore() {
+ Supexec(asm_screen_falcon_restore);
+ Supexec(atari_ikbd_shutdown);
+}
+
+void OSystem_Atari::initBackend() {
+ enum {
+ MCH_ST = 0,
+ MCH_STE,
+ MCH_TT,
+ MCH_FALCON,
+ MCH_CLONE,
+ MCH_ARANYM
+ };
+
+ long mch = MCH_ST<<16;
+ Getcookie(C__MCH, &mch);
+ mch >>= 16;
+
+ if (mch != MCH_FALCON && mch != MCH_ARANYM) {
+ error("ScummVM works only on Atari Falcon and ARAnyM");
+ }
+
+ if (mch == MCH_ARANYM && Getcookie(C_fVDI, NULL) == C_FOUND) {
+ error("Disable fVDI, ScummVM accesses Videl directly");
+ }
+
+ nf_init();
+
+ _startTime = clock();
+
+ bool superVidel = VgetMonitor() == MON_VGA && Getcookie(C_SupV, NULL) == C_FOUND;
+
+ _timerManager = new DefaultTimerManager();
+ _savefileManager = new DefaultSaveFileManager();
+
+ AtariEventSource *atariEventSource = new AtariEventSource();
+ _eventManager = new DefaultEventManager(makeKeyboardRepeatingEventSource(atariEventSource));
+
+ // AtariGraphicsManager needs _eventManager ready
+ AtariGraphicsManager *atariGraphicsManager;
+ if (superVidel)
+ atariGraphicsManager = new AtariSuperVidelManager();
+ else
+ atariGraphicsManager = new AtariVidelManager();
+ _graphicsManager = atariGraphicsManager;
+
+ atariEventSource->setGraphicsManager(atariGraphicsManager);
+
+ _mixerManager = new AtariMixerManager();
+ // Setup and start mixer
+ _mixerManager->init();
+
+ Supexec(atari_ikbd_init);
+ _ikbd_initialized = true;
+
+ Supexec(asm_screen_falcon_save);
+ _video_initialized = true;
+
+ Setexc(VEC_PROCTERM, ikbd_and_video_restore);
+
+ BaseBackend::initBackend();
+}
+
+Common::MutexInternal *OSystem_Atari::createMutex() {
+ return new NullMutexInternal();
+}
+
+uint32 OSystem_Atari::getMillis(bool skipRecord) {
+ // CLOCKS_PER_SEC is 200, so no need to use floats
+ return 1000 * (clock() - _startTime) / CLOCKS_PER_SEC;
+}
+
+void OSystem_Atari::delayMillis(uint msecs) {
+ usleep(msecs * 1000);
+}
+
+void OSystem_Atari::getTimeAndDate(TimeDate &td, bool skipRecord) const {
+ debug("getTimeAndDate");
+ time_t curTime = time(0);
+ // TODO: if too slow (e.g. when calling RandomSource::RandomSource()), rewrite
+ struct tm t = *localtime(&curTime);
+ td.tm_sec = t.tm_sec;
+ td.tm_min = t.tm_min;
+ td.tm_hour = t.tm_hour;
+ td.tm_mday = t.tm_mday;
+ td.tm_mon = t.tm_mon;
+ td.tm_year = t.tm_year;
+ td.tm_wday = t.tm_wday;
+}
+
+Common::KeymapArray OSystem_Atari::getGlobalKeymaps() {
+ Common::KeymapArray globalMaps = BaseBackend::getGlobalKeymaps();
+
+ Common::Keymap *keymap = ((AtariGraphicsManager*)_graphicsManager)->getKeymap();
+ globalMaps.push_back(keymap);
+
+ return globalMaps;
+}
+
+Common::HardwareInputSet *OSystem_Atari::getHardwareInputSet() {
+ Common::CompositeHardwareInputSet *inputSet = new Common::CompositeHardwareInputSet();
+ inputSet->addHardwareInputSet(new Common::MouseHardwareInputSet(Common::defaultMouseButtons));
+ inputSet->addHardwareInputSet(new Common::KeyboardHardwareInputSet(Common::defaultKeys, Common::defaultModifiers));
+
+ return inputSet;
+}
+
+void OSystem_Atari::quit() {
+ debug("OSystem_Atari::quit()");
+
+ g_system->destroy();
+
+ exit(0);
+}
+
+void OSystem_Atari::logMessage(LogMessageType::Type type, const char *message) {
+ FILE *output = 0;
+
+ if (type == LogMessageType::kInfo || type == LogMessageType::kDebug)
+ output = stdout;
+ else
+ output = stderr;
+
+ fputs(message, output);
+ fflush(output);
+
+ nf_print(message);
+}
+
+void OSystem_Atari::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
+#ifdef DATA_PATH
+ // Add the global DATA_PATH to the directory search list
+ // See also OSystem_SDL::addSysArchivesToSearchSet()
+ Common::FSNode dataNode(DATA_PATH);
+ if (dataNode.exists() && dataNode.isDirectory()) {
+ s.add(DATA_PATH, new Common::FSDirectory(dataNode, 4), priority);
+ }
+#endif
+}
+
+Common::String OSystem_Atari::getDefaultConfigFileName() {
+ const Common::String baseConfigName = OSystem::getDefaultConfigFileName();
+
+ Common::String configFile;
+
+ const char *envVar = getenv("HOME");
+ if (envVar && *envVar) {
+ configFile = envVar;
+ configFile += '/';
+ configFile += baseConfigName;
+
+ if (configFile.size() < MAXPATHLEN)
+ return configFile;
+ }
+
+ return baseConfigName;
+}
+
+void OSystem_Atari::update() {
+ ((DefaultTimerManager *)_timerManager)->checkTimers();
+ ((AtariMixerManager *)_mixerManager)->update();
+}
+
+OSystem *OSystem_Atari_create() {
+ return new OSystem_Atari();
+}
+
+int main(int argc, char *argv[]) {
+ g_system = OSystem_Atari_create();
+ assert(g_system);
+
+ // Invoke the actual ScummVM main entry point:
+ int res = scummvm_main(argc, argv);
+ g_system->destroy();
+ return res;
+}
+
+#endif
diff --git a/backends/platform/atari/osystem_atari.h b/backends/platform/atari/osystem_atari.h
new file mode 100644
index 00000000000..c27e207135b
--- /dev/null
+++ b/backends/platform/atari/osystem_atari.h
@@ -0,0 +1,60 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef PLATFORM_ATARI_H
+#define PLATFORM_ATARI_H
+
+#include "backends/modular-backend.h"
+
+#include <time.h>
+
+class OSystem_Atari : public ModularMixerBackend, public ModularGraphicsBackend {
+public:
+ OSystem_Atari();
+ virtual ~OSystem_Atari();
+
+ void initBackend() override;
+
+ Common::MutexInternal *createMutex() override;
+ uint32 getMillis(bool skipRecord = false) override;
+ void delayMillis(uint msecs) override;
+ void getTimeAndDate(TimeDate &td, bool skipRecord = false) const override;
+
+ Common::KeymapArray getGlobalKeymaps() override;
+ Common::HardwareInputSet *getHardwareInputSet() override;
+
+ void quit() override;
+
+ void logMessage(LogMessageType::Type type, const char *message) override;
+
+ void addSysArchivesToSearchSet(Common::SearchSet &s, int priority) override;
+ Common::String getDefaultConfigFileName() override;
+
+ void update();
+
+private:
+ clock_t _startTime;
+
+ bool _video_initialized = false;
+ bool _ikbd_initialized = false;
+};
+
+#endif
Commit: 72f6c4ef612e019fa008cb5a4593c89bb952b62e
https://github.com/scummvm/scummvm/commit/72f6c4ef612e019fa008cb5a4593c89bb952b62e
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2023-03-04T23:38:42+01:00
Commit Message:
SCUMM: Increase {min,max}HeapThreshold for ATARI
Changed paths:
engines/scumm/scumm.cpp
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 4d574c206d8..40fa616d415 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -1409,6 +1409,7 @@ void ScummEngine::setupScumm(const Common::String &macResourceFile) {
_bootParam = -1;
}
+#ifndef ATARI
int maxHeapThreshold = -1;
if (_game.features & GF_16BIT_COLOR) {
@@ -1423,6 +1424,10 @@ void ScummEngine::setupScumm(const Common::String &macResourceFile) {
}
_res->setHeapThreshold(400000, maxHeapThreshold);
+#else
+ // RAM is cheap, disk I/O isn't... helps with retaining the resources in COMI and similar
+ _res->setHeapThreshold(16 * 1024 * 1024, 32 * 1024 * 1024);
+#endif
free(_compositeBuf);
_compositeBuf = (byte *)malloc(_screenWidth * _textSurfaceMultiplier * _screenHeight * _textSurfaceMultiplier * _outputPixelFormat.bytesPerPixel);
Commit: 896d7cf309f76eda87856d624d3e8afc2515a40f
https://github.com/scummvm/scummvm/commit/896d7cf309f76eda87856d624d3e8afc2515a40f
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2023-03-04T23:38:42+01:00
Commit Message:
BACKENDS: ATARI: Use "saves" directory for savegames
Changed paths:
backends/platform/atari/osystem_atari.cpp
diff --git a/backends/platform/atari/osystem_atari.cpp b/backends/platform/atari/osystem_atari.cpp
index 44259335b59..4c7d504a859 100644
--- a/backends/platform/atari/osystem_atari.cpp
+++ b/backends/platform/atari/osystem_atari.cpp
@@ -118,7 +118,7 @@ void OSystem_Atari::initBackend() {
bool superVidel = VgetMonitor() == MON_VGA && Getcookie(C_SupV, NULL) == C_FOUND;
_timerManager = new DefaultTimerManager();
- _savefileManager = new DefaultSaveFileManager();
+ _savefileManager = new DefaultSaveFileManager("saves");
AtariEventSource *atariEventSource = new AtariEventSource();
_eventManager = new DefaultEventManager(makeKeyboardRepeatingEventSource(atariEventSource));
Commit: 4892d0b48b6bdf58daced8467331c48172da7553
https://github.com/scummvm/scummvm/commit/4892d0b48b6bdf58daced8467331c48172da7553
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2023-03-04T23:38:42+01:00
Commit Message:
CONFIGURE: Adjustments for ATARI
- add NDEBUG for smaller file size and better performance when building
with --enable-release
- add exe extensions for both ATARI and FreeMiNT
- use "dist-generic" instead of the clunky ./configure paths
Build as:
./configure --backend=atari --host=m68k-atari-mint --enable-release --disable-mt32emu --disable-lua --disable-nuked-opl --disable-16bit --disable-scalers --disable-translation --disable-eventrecorder --disable-tts --disable-bink --opengl-mode=none --enable-verbose-build && make -j 16 && rm -rf dist-generic; make dist-generic
Changed paths:
.gitignore
configure
ports.mk
diff --git a/.gitignore b/.gitignore
index cee8d1665df..b33ad8edfbd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,6 +39,7 @@ lib*.a
/*.bnr
/romfs
/dist_3ds
+/dist-generic
/.project
/.cproject
/.settings
@@ -231,6 +232,8 @@ ScummVM.config
ScummVM.creator
ScummVM.files
ScummVM.includes
+ScummVM.cflags
+ScummVM.cxxflags
#Ignore Komodo IDE/Edit project files
*.komodoproject
@@ -288,3 +291,7 @@ android_project
dists/emscripten/libs/
dists/emscripten/games/
dists/emscripten/emsdk-*
+
+#Ignore Atari/FreeMiNT files
+scummvm.gtp
+scummvm.ttp
diff --git a/configure b/configure
index d7b180dce8e..79b718e28b2 100755
--- a/configure
+++ b/configure
@@ -563,6 +563,15 @@ get_system_exe_extension() {
mingw* | *os2-emx)
_exeext=".exe"
;;
+ mint)
+ if test "$_backend" = "atari"; then
+ # ATARI backend
+ _exeext=".ttp"
+ else
+ # SDL backend
+ _exeext=".gtp"
+ fi
+ ;;
emscripten)
_exeext=".html"
;;
@@ -793,7 +802,7 @@ Usage: $0 [OPTIONS]...
Configuration:
-h, --help display this help and exit
- --backend=BACKEND backend to build (3ds, android, dc, dingux, ds, gcw0,
+ --backend=BACKEND backend to build (3ds, atari, android, dc, dingux, ds, gcw0,
gph, iphone, ios7, ios7-arm64, maemo, n64, null, opendingux,
openpandora, psp, psp2, samsungtv, sdl, switch, wii) [sdl]
@@ -3558,7 +3567,7 @@ if test -n "$_host"; then
_port_mk="backends/platform/sdl/kolibrios/kolibrios.mk"
;;
m68k-atari-mint)
- # auto -> yes
+ # auto -> yes (overriden by $_release_build = yes)
if test "$_debug_build" = "no"; then
# --disable-debug
append_var LDFLAGS "-s"
@@ -3569,6 +3578,13 @@ if test -n "$_host"; then
# --enable-release, --enable-optimizations
append_var CXXFLAGS "-fomit-frame-pointer"
fi
+
+ # auto -> no
+ if test "$_release_build" = "yes"; then
+ # --enable-release
+ append_var DEFINES "-DNDEBUG"
+ fi
+
_seq_midi=no
_timidity=no
;;
diff --git a/ports.mk b/ports.mk
index b6506bddcfd..2d9f69e84d3 100644
--- a/ports.mk
+++ b/ports.mk
@@ -60,6 +60,9 @@ dist-generic: $(EXECUTABLE) $(PLUGINS)
mkdir -p ./dist-generic/scummvm/data
mkdir -p ./dist-generic/scummvm/doc
cp $(EXECUTABLE) ./dist-generic/scummvm
+ifeq ($(BACKEND), atari)
+ m68k-atari-mint-flags -S ./dist-generic/scummvm/$(EXECUTABLE)
+endif
cp $(DIST_FILES_DOCS) ./dist-generic/scummvm/doc
cp $(DIST_FILES_THEMES) ./dist-generic/scummvm/data
ifdef DIST_FILES_ENGINEDATA
Commit: 5ba26fdf35e3358dad4bca5c3e5aa7a4e62c202c
https://github.com/scummvm/scummvm/commit/5ba26fdf35e3358dad4bca5c3e5aa7a4e62c202c
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2023-03-04T23:38:42+01:00
Commit Message:
GRAPHICS: ATARI: Introduce accelerated blitting
Changed paths:
A graphics/blit-atari.cpp
configure
graphics/blit.cpp
graphics/module.mk
graphics/surface.cpp
diff --git a/configure b/configure
index 79b718e28b2..f93a6b31a69 100755
--- a/configure
+++ b/configure
@@ -3874,7 +3874,7 @@ case $_backend in
fi
;;
atari)
- append_var DEFINES "-DATARI"
+ define_in_config_if_yes yes "ATARI"
#append_var DEFINES "-DDISABLE_FANCY_THEMES"
#append_var DEFINES "-DDISABLE_SID"
#append_var DEFINES "-DDISABLE_NES_APU"
diff --git a/graphics/blit-atari.cpp b/graphics/blit-atari.cpp
new file mode 100644
index 00000000000..aa80e235290
--- /dev/null
+++ b/graphics/blit-atari.cpp
@@ -0,0 +1,100 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "graphics/blit.h"
+#include "graphics/surface.h"
+
+#include <cstdlib> // calloc
+#include <cstring> // memcpy
+#include <mint/cookie.h>
+#include <mint/falcon.h>
+
+#include "backends/graphics/atari/atari-graphics-superblitter.h"
+
+namespace Graphics {
+
+// hijack surface overrides here as well as these are tightly related
+// to the blitting routine below
+void Surface::create(int16 width, int16 height, const PixelFormat &f) {
+ assert(width >= 0 && height >= 0);
+ free();
+
+ w = width;
+ h = height;
+ format = f;
+ pitch = w * format.bytesPerPixel;
+
+ if (width && height) {
+ if (VgetMonitor() == MON_VGA && Getcookie(C_SupV, NULL) == C_FOUND)
+ pixels = (void*)ct60_vmalloc(width * height * format.bytesPerPixel);
+ else
+ pixels = calloc(width * height, format.bytesPerPixel);
+ assert(pixels);
+ }
+}
+
+void Surface::free() {
+ if (((uintptr)pixels & 0xFF000000) >= 0xA0000000)
+ ct60_vmfree(pixels);
+ else
+ ::free(pixels);
+
+ pixels = 0;
+ w = h = pitch = 0;
+ format = PixelFormat();
+}
+
+// Function to blit a rect (version optimized for Atari Falcon with SuperVidel's SuperBlitter)
+void copyBlit(byte *dst, const byte *src,
+ const uint dstPitch, const uint srcPitch,
+ const uint w, const uint h,
+ const uint bytesPerPixel) {
+ if (dst == src)
+ return;
+
+ if (((uintptr)src & 0xFF000000) >= 0xA0000000 && ((uintptr)dst & 0xFF000000) >= 0xA0000000) {
+ // while busy blitting...
+ while (*SV_BLITTER_CONTROL & 1);
+
+ *SV_BLITTER_SRC1 = (long)src;
+ *SV_BLITTER_SRC2 = 0x00000000;
+ *SV_BLITTER_DST = (long)dst;
+ *SV_BLITTER_COUNT = w * bytesPerPixel - 1;
+ *SV_BLITTER_SRC1_OFFSET = srcPitch;
+ *SV_BLITTER_SRC2_OFFSET = 0x00000000;
+ *SV_BLITTER_DST_OFFSET = dstPitch;
+ *SV_BLITTER_MASK_AND_LINES = h;
+ *SV_BLITTER_CONTROL = 0x01;
+
+ // wait until we finish otherwise we may overwrite pixels written manually afterwards
+ while (*SV_BLITTER_CONTROL & 1);
+ } else if (dstPitch == srcPitch && ((w * bytesPerPixel) == dstPitch)) {
+ memcpy(dst, src, dstPitch * h);
+ } else {
+ for (uint i = 0; i < h; ++i) {
+ memcpy(dst, src, w * bytesPerPixel);
+ dst += dstPitch;
+ src += srcPitch;
+ }
+ }
+}
+
+} // End of namespace Graphics
diff --git a/graphics/blit.cpp b/graphics/blit.cpp
index 2cb90a6ff55..cb2d353f825 100644
--- a/graphics/blit.cpp
+++ b/graphics/blit.cpp
@@ -24,6 +24,8 @@
namespace Graphics {
+// see graphics/blit-atari.cpp, Atari Falcon's SuperVidel addon allows accelerated blitting
+#ifndef ATARI
// Function to blit a rect
void copyBlit(byte *dst, const byte *src,
const uint dstPitch, const uint srcPitch,
@@ -42,6 +44,7 @@ void copyBlit(byte *dst, const byte *src,
}
}
}
+#endif
namespace {
diff --git a/graphics/module.mk b/graphics/module.mk
index 59e1ed4f08b..33ddb8527e7 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -63,6 +63,11 @@ MODULE_OBJS += \
scaler/downscalerARM.o
endif
+ifdef ATARI
+MODULE_OBJS += \
+ blit-atari.o
+endif
+
ifdef USE_TINYGL
MODULE_OBJS += \
tinygl/api.o \
diff --git a/graphics/surface.cpp b/graphics/surface.cpp
index 98c6cf85d92..6da32b87d63 100644
--- a/graphics/surface.cpp
+++ b/graphics/surface.cpp
@@ -63,6 +63,8 @@ void Surface::drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY,
error("Surface::drawThickLine: bytesPerPixel must be 1, 2, or 4");
}
+// see graphics/blit-atari.cpp, Atari Falcon's SuperVidel addon allows accelerated blitting
+#ifndef ATARI
void Surface::create(int16 width, int16 height, const PixelFormat &f) {
assert(width >= 0 && height >= 0);
free();
@@ -84,6 +86,7 @@ void Surface::free() {
w = h = pitch = 0;
format = PixelFormat();
}
+#endif
void Surface::init(int16 width, int16 height, int16 newPitch, void *newPixels, const PixelFormat &f) {
w = width;
More information about the Scummvm-git-logs
mailing list