339 lines
6.8 KiB
C++
339 lines
6.8 KiB
C++
#include "frontends/sa2/emulator.h"
|
|
#include "frontends/sa2/sdirectsound.h"
|
|
|
|
#include <iostream>
|
|
|
|
#include "linux/videobuffer.h"
|
|
#include "linux/data.h"
|
|
#include "linux/paddle.h"
|
|
#include "linux/keyboard.h"
|
|
|
|
#include "StdAfx.h"
|
|
#include "Common.h"
|
|
#include "CardManager.h"
|
|
#include "Core.h"
|
|
#include "Disk.h"
|
|
#include "CPU.h"
|
|
#include "Frame.h"
|
|
#include "Video.h"
|
|
#include "Windows/WinVideo.h"
|
|
#include "NTSC.h"
|
|
#include "Mockingboard.h"
|
|
#include "Speaker.h"
|
|
|
|
namespace
|
|
{
|
|
|
|
void cycleVideoType(const std::shared_ptr<SDL_Window> & win)
|
|
{
|
|
g_eVideoType++;
|
|
if (g_eVideoType >= NUM_VIDEO_MODES)
|
|
g_eVideoType = 0;
|
|
|
|
SetWindowTitle();
|
|
SDL_SetWindowTitle(win.get(), g_pAppTitle.c_str());
|
|
|
|
Config_Save_Video();
|
|
VideoReinitialize();
|
|
VideoRedrawScreen();
|
|
}
|
|
|
|
void cycle50ScanLines(const std::shared_ptr<SDL_Window> & win)
|
|
{
|
|
VideoStyle_e videoStyle = GetVideoStyle();
|
|
videoStyle = VideoStyle_e(videoStyle ^ VS_HALF_SCANLINES);
|
|
|
|
SetVideoStyle(videoStyle);
|
|
|
|
SetWindowTitle();
|
|
SDL_SetWindowTitle(win.get(), g_pAppTitle.c_str());
|
|
|
|
Config_Save_Video();
|
|
VideoReinitialize();
|
|
VideoRedrawScreen();
|
|
}
|
|
|
|
void processAppleKey(const SDL_KeyboardEvent & key)
|
|
{
|
|
// using keycode (or scan code) one takes a physical view of the keyboard
|
|
// ignoring non US layouts
|
|
// SHIFT-3 on a A2 keyboard in # while on my UK keyboard is £?
|
|
// so for now all ASCII keys are handled as text below
|
|
// but this makes it impossible to detect CTRL-ASCII... more to follow
|
|
BYTE ch = 0;
|
|
|
|
switch (key.keysym.sym)
|
|
{
|
|
case SDLK_RETURN:
|
|
{
|
|
ch = 0x0d;
|
|
break;
|
|
}
|
|
case SDLK_BACKSPACE: // same as AppleWin
|
|
case SDLK_LEFT:
|
|
{
|
|
ch = 0x08;
|
|
break;
|
|
}
|
|
case SDLK_RIGHT:
|
|
{
|
|
ch = 0x15;
|
|
break;
|
|
}
|
|
case SDLK_UP:
|
|
{
|
|
ch = 0x0b;
|
|
break;
|
|
}
|
|
case SDLK_DOWN:
|
|
{
|
|
ch = 0x0a;
|
|
break;
|
|
}
|
|
case SDLK_DELETE:
|
|
{
|
|
ch = 0x7f;
|
|
break;
|
|
}
|
|
case SDLK_ESCAPE:
|
|
{
|
|
ch = 0x1b;
|
|
break;
|
|
}
|
|
case SDLK_TAB:
|
|
{
|
|
ch = 0x09;
|
|
break;
|
|
}
|
|
case SDLK_a ... SDLK_z:
|
|
{
|
|
ch = (key.keysym.sym - SDLK_a) + 0x01;
|
|
if (key.keysym.mod & KMOD_CTRL)
|
|
{
|
|
// ok
|
|
}
|
|
else if (key.keysym.mod & KMOD_SHIFT)
|
|
{
|
|
ch += 0x60;
|
|
}
|
|
else
|
|
{
|
|
ch += 0x40;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ch)
|
|
{
|
|
addKeyToBuffer(ch);
|
|
std::cerr << "SDL KeyboardEvent: " << std::hex << (int)ch << std::dec << std::endl;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
Emulator::Emulator(
|
|
const std::shared_ptr<SDL_Window> & window,
|
|
const std::shared_ptr<SDL_Renderer> & renderer,
|
|
const std::shared_ptr<SDL_Texture> & texture,
|
|
const bool fixedSpeed
|
|
)
|
|
: myWindow(window)
|
|
, myRenderer(renderer)
|
|
, myTexture(texture)
|
|
, myMultiplier(1)
|
|
, myFullscreen(false)
|
|
, mySpeed(fixedSpeed)
|
|
{
|
|
}
|
|
|
|
void Emulator::execute(const size_t next)
|
|
{
|
|
const size_t cyclesToExecute = mySpeed.getCyclesTillNext(next);
|
|
|
|
const bool bVideoUpdate = true;
|
|
const UINT dwClksPerFrame = NTSC_GetCyclesPerFrame();
|
|
|
|
const DWORD executedCycles = CpuExecute(cyclesToExecute, bVideoUpdate);
|
|
|
|
g_dwCyclesThisFrame = (g_dwCyclesThisFrame + executedCycles) % dwClksPerFrame;
|
|
GetCardMgr().GetDisk2CardMgr().UpdateDriveState(executedCycles);
|
|
MB_PeriodicUpdate(executedCycles);
|
|
SpkrUpdate(executedCycles);
|
|
}
|
|
|
|
SDL_Rect Emulator::updateTexture()
|
|
{
|
|
uint8_t * data;
|
|
int width;
|
|
int height;
|
|
int sx, sy;
|
|
int sw, sh;
|
|
|
|
getScreenData(data, width, height, sx, sy, sw, sh);
|
|
SDL_UpdateTexture(myTexture.get(), nullptr, data, width * 4);
|
|
|
|
SDL_Rect srect;
|
|
srect.x = sx;
|
|
srect.y = sy;
|
|
srect.w = sw;
|
|
srect.h = sh;
|
|
|
|
return srect;
|
|
}
|
|
|
|
void Emulator::refreshVideo(const SDL_Rect & rect)
|
|
{
|
|
SDL_RenderCopyEx(myRenderer.get(), myTexture.get(), &rect, nullptr, 0.0, nullptr, SDL_FLIP_VERTICAL);
|
|
SDL_RenderPresent(myRenderer.get());
|
|
}
|
|
|
|
void Emulator::processEvents(bool & quit)
|
|
{
|
|
SDL_Event e;
|
|
while (SDL_PollEvent(&e) != 0)
|
|
{
|
|
switch (e.type)
|
|
{
|
|
case SDL_QUIT:
|
|
{
|
|
quit = true;
|
|
break;
|
|
}
|
|
case SDL_KEYDOWN:
|
|
{
|
|
processKeyDown(e.key, quit);
|
|
break;
|
|
}
|
|
case SDL_KEYUP:
|
|
{
|
|
processKeyUp(e.key);
|
|
break;
|
|
}
|
|
case SDL_TEXTINPUT:
|
|
{
|
|
processText(e.text);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Emulator::processKeyDown(const SDL_KeyboardEvent & key, bool & quit)
|
|
{
|
|
// scancode vs keycode
|
|
// scancode is relative to the position on the keyboard
|
|
// keycode is what the os maps it to
|
|
// if the user has decided to change the layout, we just go with it and use the keycode
|
|
if (!key.repeat)
|
|
{
|
|
switch (key.keysym.sym)
|
|
{
|
|
case SDLK_F9:
|
|
{
|
|
cycleVideoType(myWindow);
|
|
break;
|
|
}
|
|
case SDLK_F6:
|
|
{
|
|
if ((key.keysym.mod & KMOD_CTRL) && (key.keysym.mod & KMOD_SHIFT))
|
|
{
|
|
cycle50ScanLines(myWindow);
|
|
}
|
|
else if (key.keysym.mod & KMOD_CTRL)
|
|
{
|
|
myMultiplier = myMultiplier == 1 ? 2 : 1;
|
|
const int sw = GetFrameBufferBorderlessWidth();
|
|
const int sh = GetFrameBufferBorderlessHeight();
|
|
SDL_SetWindowSize(myWindow.get(), sw * myMultiplier, sh * myMultiplier);
|
|
}
|
|
else if (!(key.keysym.mod & KMOD_SHIFT))
|
|
{
|
|
myFullscreen = !myFullscreen;
|
|
SDL_SetWindowFullscreen(myWindow.get(), myFullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
|
}
|
|
break;
|
|
}
|
|
case SDLK_F5:
|
|
{
|
|
CardManager & cardManager = GetCardMgr();
|
|
if (cardManager.QuerySlot(SLOT6) == CT_Disk2)
|
|
{
|
|
dynamic_cast<Disk2InterfaceCard*>(cardManager.GetObj(SLOT6))->DriveSwap();
|
|
}
|
|
break;
|
|
}
|
|
case SDLK_F2:
|
|
{
|
|
quit = true;
|
|
break;
|
|
}
|
|
case SDLK_F1:
|
|
{
|
|
SDirectSound::printInfo();
|
|
break;
|
|
}
|
|
case SDLK_LALT:
|
|
{
|
|
Paddle::setButtonPressed(Paddle::ourOpenApple);
|
|
break;
|
|
}
|
|
case SDLK_RALT:
|
|
{
|
|
Paddle::setButtonPressed(Paddle::ourSolidApple);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
processAppleKey(key);
|
|
|
|
#if LOGGING_VERBOSE
|
|
std::cerr << "KEY DOWN: " << key.keysym.scancode << "," << key.keysym.sym << "," << key.keysym.mod << "," << bool(key.repeat) << std::endl;
|
|
#endif
|
|
|
|
}
|
|
|
|
void Emulator::processKeyUp(const SDL_KeyboardEvent & key)
|
|
{
|
|
switch (key.keysym.sym)
|
|
{
|
|
case SDLK_LALT:
|
|
{
|
|
Paddle::setButtonReleased(Paddle::ourOpenApple);
|
|
break;
|
|
}
|
|
case SDLK_RALT:
|
|
{
|
|
Paddle::setButtonReleased(Paddle::ourSolidApple);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if LOGGING_VERBOSE
|
|
std::cerr << "KEY UP: " << key.keysym.scancode << "," << key.keysym.sym << "," << key.keysym.mod << "," << bool(key.repeat) << std::endl;
|
|
#endif
|
|
|
|
}
|
|
|
|
void Emulator::processText(const SDL_TextInputEvent & text)
|
|
{
|
|
if (strlen(text.text) == 1)
|
|
{
|
|
const char key = text.text[0];
|
|
switch (key) {
|
|
case 0x20 ... 0x40:
|
|
case 0x5b ... 0x60:
|
|
case 0x7b ... 0x7e:
|
|
{
|
|
// not the letters
|
|
// this is very simple, but one cannot handle CRTL-key combination.
|
|
addKeyToBuffer(key);
|
|
std::cerr << "SDL TextInputEvent: " << std::hex << (int)key << std::dec << std::endl;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|