make screenimage be a wxFrame; break out REPT key handling into dedicated class; progress on wx paddle handling
This commit is contained in:
parent
f63dcd908a
commit
29165a5685
|
@ -91,6 +91,8 @@ firmwarecard.cpp
|
||||||
gui.cpp
|
gui.cpp
|
||||||
keyboardbuffermode.cpp
|
keyboardbuffermode.cpp
|
||||||
keyboard.cpp
|
keyboard.cpp
|
||||||
|
KeyEventHandler.cpp
|
||||||
|
KeyRepeatHandler.cpp
|
||||||
languagecard.cpp
|
languagecard.cpp
|
||||||
lss.cpp
|
lss.cpp
|
||||||
magneticfield.cpp
|
magneticfield.cpp
|
||||||
|
@ -201,7 +203,10 @@ include_directories(${PROJECT_BINARY_DIR})
|
||||||
# TODO: can we remove this without being too backwardly incompatible?
|
# TODO: can we remove this without being too backwardly incompatible?
|
||||||
target_compile_definitions(${APP_NAME} PRIVATE ETCDIR="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR}")
|
target_compile_definitions(${APP_NAME} PRIVATE ETCDIR="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_SYSCONFDIR}")
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
else()
|
||||||
|
target_compile_options(${APP_NAME} PRIVATE -ggdb3)
|
||||||
|
endif()
|
||||||
|
|
||||||
set_target_properties(${APP_NAME} PROPERTIES RESOURCE "${resources}")
|
set_target_properties(${APP_NAME} PROPERTIES RESOURCE "${resources}")
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,8 @@ public:
|
||||||
const std::filesystem::path GetConfigDir() const;
|
const std::filesystem::path GetConfigDir() const;
|
||||||
const std::filesystem::path GetDocumentsDir() const;
|
const std::filesystem::path GetDocumentsDir() const;
|
||||||
|
|
||||||
|
E2wxFrame *GetFrame() { return this->frame; }
|
||||||
|
|
||||||
void StartEmulator();
|
void StartEmulator();
|
||||||
void StopEmulator();
|
void StopEmulator();
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
enum E2MenuID {
|
enum E2MenuID {
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
epple2
|
||||||
|
Copyright (C) 2022 by Christopher A. Mosher <cmosher01@gmail.com>
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File: KeyEventHandler.cpp
|
||||||
|
* Author: chris.mosher
|
||||||
|
*
|
||||||
|
* Created on December 19, 2022, 7:36 AM
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "KeyEventHandler.h"
|
||||||
|
|
||||||
|
KeyEventHandler::KeyEventHandler() {
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyEventHandler::KeyEventHandler(const KeyEventHandler& orig) {
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyEventHandler::~KeyEventHandler() {
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
epple2
|
||||||
|
Copyright (C) 2022 by Christopher A. Mosher <cmosher01@gmail.com>
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File: KeyEventHandler.h
|
||||||
|
* Author: chris.mosher
|
||||||
|
*
|
||||||
|
* Created on December 19, 2022, 7:36 AM
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KEYEVENTHANDLER_H
|
||||||
|
#define KEYEVENTHANDLER_H
|
||||||
|
|
||||||
|
class KeyEventHandler {
|
||||||
|
public:
|
||||||
|
KeyEventHandler();
|
||||||
|
KeyEventHandler(const KeyEventHandler& orig);
|
||||||
|
virtual ~KeyEventHandler();
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* KEYEVENTHANDLER_H */
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
epple2
|
||||||
|
Copyright (C) 2022 by Christopher A. Mosher <cmosher01@gmail.com>
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File: KeyRepeatHandler.cpp
|
||||||
|
* Author: chris.mosher
|
||||||
|
*
|
||||||
|
* Created on December 19, 2022, 7:35 AM
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "KeyRepeatHandler.h"
|
||||||
|
#include "e2const.h"
|
||||||
|
|
||||||
|
// U.A.2 p. 7-13: REPT key repeats at 10Hz.
|
||||||
|
static const int CYCLES_PER_REPT(E2Const::AVG_CPU_HZ / 10);
|
||||||
|
|
||||||
|
KeyRepeatHandler::KeyRepeatHandler(KeypressQueue &q) :
|
||||||
|
repeat(false),
|
||||||
|
is_key_down(false),
|
||||||
|
keypresses(q) {
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyRepeatHandler::~KeyRepeatHandler() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyRepeatHandler::tick() {
|
||||||
|
if (this->repeat) {
|
||||||
|
// Count our way down to when the timer for the REPT key
|
||||||
|
// fires off: 10Hz in terms of how many CPU cycles have gone
|
||||||
|
// by
|
||||||
|
--this->rept;
|
||||||
|
// If it's time for the REPT key timer to fire (at long
|
||||||
|
// last)...
|
||||||
|
if (this->rept <= 0) {
|
||||||
|
// ...reload the timer for the next firing 1/10 second from
|
||||||
|
// now ( *reset* the timer )
|
||||||
|
this->rept = CYCLES_PER_REPT;
|
||||||
|
// If any other keys are actually being held down...
|
||||||
|
if (this->is_key_down) {
|
||||||
|
// ...REPEAT the most recent one that was pressed
|
||||||
|
this->keypresses.push(this->key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyRepeatHandler::setKey(unsigned char lastKeyDown) {
|
||||||
|
this->is_key_down = true;
|
||||||
|
this->key = lastKeyDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyRepeatHandler::clearKey() {
|
||||||
|
this->is_key_down = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyRepeatHandler::press() {
|
||||||
|
this->repeat = true;
|
||||||
|
this->rept = CYCLES_PER_REPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyRepeatHandler::release() {
|
||||||
|
this->repeat = false;
|
||||||
|
this->rept = 0;
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
epple2
|
||||||
|
Copyright (C) 2022 by Christopher A. Mosher <cmosher01@gmail.com>
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File: KeyRepeatHandler.h
|
||||||
|
* Author: chris.mosher
|
||||||
|
*
|
||||||
|
* Created on December 19, 2022, 7:35 AM
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KEYREPEATHANDLER_H
|
||||||
|
#define KEYREPEATHANDLER_H
|
||||||
|
|
||||||
|
#include "keyboard.h"
|
||||||
|
|
||||||
|
class KeyRepeatHandler {
|
||||||
|
bool repeat;
|
||||||
|
int rept;
|
||||||
|
bool is_key_down;
|
||||||
|
unsigned char key;
|
||||||
|
|
||||||
|
KeypressQueue &keypresses;
|
||||||
|
|
||||||
|
public:
|
||||||
|
KeyRepeatHandler(KeypressQueue &keypresses);
|
||||||
|
virtual ~KeyRepeatHandler();
|
||||||
|
|
||||||
|
virtual void tick();
|
||||||
|
|
||||||
|
void setKey(unsigned char lastKeyDown);
|
||||||
|
void clearKey();
|
||||||
|
|
||||||
|
void press();
|
||||||
|
void release();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* KEYREPEATHANDLER_H */
|
|
@ -20,6 +20,7 @@
|
||||||
#include "e2config.h"
|
#include "e2config.h"
|
||||||
#include "e2command.h"
|
#include "e2command.h"
|
||||||
#include "e2const.h"
|
#include "e2const.h"
|
||||||
|
#include "KeyRepeatHandler.h"
|
||||||
|
|
||||||
#include <wx/msgdlg.h>
|
#include <wx/msgdlg.h>
|
||||||
#include <wx/string.h>
|
#include <wx/string.h>
|
||||||
|
@ -52,7 +53,7 @@ Emulator::Emulator() :
|
||||||
videoStatic(display),
|
videoStatic(display),
|
||||||
apple2(keypresses, paddleButtonStates, display, buffered, screenImage),
|
apple2(keypresses, paddleButtonStates, display, buffered, screenImage),
|
||||||
timable(nullptr), // No ticked object (NULL pointer)
|
timable(nullptr), // No ticked object (NULL pointer)
|
||||||
repeat(false),
|
keyrepeater(keypresses),
|
||||||
keysDown(0),
|
keysDown(0),
|
||||||
prev_ms(SDL_GetTicks()) {
|
prev_ms(SDL_GetTicks()) {
|
||||||
}
|
}
|
||||||
|
@ -70,31 +71,6 @@ void Emulator::config(E2Config& cfg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// U.A.2 p. 7-13: REPT key repeats at 10Hz.
|
|
||||||
static const int CYCLES_PER_REPT(E2Const::AVG_CPU_HZ / 10);
|
|
||||||
|
|
||||||
// If the Apple ][ keyboard repeat is on (the REPT key is
|
|
||||||
// down)...
|
|
||||||
void Emulator::handleRepeatKey() {
|
|
||||||
if (this->repeat) {
|
|
||||||
// Count our way down to when the timer for the REPT key
|
|
||||||
// fires off: 10Hz in terms of how many CPU cycles have gone
|
|
||||||
// by
|
|
||||||
--this->rept;
|
|
||||||
// If it's time for the REPT key timer to fire (at long
|
|
||||||
// last)...
|
|
||||||
if (this->rept <= 0) {
|
|
||||||
// ...reload the timer for the next firing 1/10 second from
|
|
||||||
// now ( *reset* the timer )
|
|
||||||
this->rept = CYCLES_PER_REPT;
|
|
||||||
// If any other keys are actually being held down...
|
|
||||||
if (this->keysDown > 0) {
|
|
||||||
// ...REPEAT the most recent one that was pressed
|
|
||||||
this->keypresses.push(this->lastKeyDown);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Emulator::handleAnyPendingEvents() {
|
void Emulator::handleAnyPendingEvents() {
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
|
@ -134,10 +110,12 @@ void Emulator::tick50ms() {
|
||||||
if (this->timable) {
|
if (this->timable) {
|
||||||
for (int i = 0; i < CHECK_EVERY_CYCLE; ++i) {
|
for (int i = 0; i < CHECK_EVERY_CYCLE; ++i) {
|
||||||
this->timable->tick(); // this runs the emulator!
|
this->timable->tick(); // this runs the emulator!
|
||||||
handleRepeatKey();
|
this->keyrepeater.tick(); // TODO move into Apple2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAnyPendingEvents();
|
handleAnyPendingEvents();
|
||||||
|
|
||||||
this->screenImage.displayHz((1000*CHECK_EVERY_CYCLE)/(SDL_GetTicks() - this->prev_ms));
|
this->screenImage.displayHz((1000*CHECK_EVERY_CYCLE)/(SDL_GetTicks() - this->prev_ms));
|
||||||
this->prev_ms = SDL_GetTicks();
|
this->prev_ms = SDL_GetTicks();
|
||||||
}
|
}
|
||||||
|
@ -225,7 +203,7 @@ static bool translateKeysToAppleModernized(SDL_Keycode keycode, SDL_Keymod modif
|
||||||
// Take real-world keystrokes from SDL and filter them to emulate the Apple ][ keyboard
|
// Take real-world keystrokes from SDL and filter them to emulate the Apple ][ keyboard
|
||||||
void Emulator::dispatchKeyDown(const SDL_KeyboardEvent& keyEvent) {
|
void Emulator::dispatchKeyDown(const SDL_KeyboardEvent& keyEvent) {
|
||||||
if (keyEvent.repeat) {
|
if (keyEvent.repeat) {
|
||||||
// To repeat on the real Apple ][, you need to use the REPT key (emulated below by F10)
|
// To repeat on the real Apple ][, you need to use the REPT key (emulated by F10)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,18 +217,16 @@ void Emulator::dispatchKeyDown(const SDL_KeyboardEvent& keyEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sym == SDLK_F10) {
|
if (sym == SDLK_F10) {
|
||||||
// handle REPT key
|
this->keyrepeater.press();
|
||||||
this->repeat = true;
|
// } else if (SDLK_F1 <= sym && sym <= SDLK_F12) {
|
||||||
this->rept = CYCLES_PER_REPT;
|
// wxGetApp().OnFnKeyPressed(sym);
|
||||||
} else if (SDLK_F1 <= sym && sym <= SDLK_F12) {
|
|
||||||
wxGetApp().OnFnKeyPressed(sym);
|
|
||||||
} else {
|
} else {
|
||||||
unsigned char key;
|
unsigned char key;
|
||||||
const bool sendKey = translateKeysToAppleModernized(sym, mod, &key);
|
const bool sendKey = translateKeysToAppleModernized(sym, mod, &key);
|
||||||
if (sendKey) {
|
if (sendKey) {
|
||||||
//printf(" sending to apple as ASCII ------------------------------> %02X (%02X) (%d)\n", key, key | 0x80, key | 0x80);
|
//printf(" sending to apple as ASCII ------------------------------> %02X (%02X) (%d)\n", key, key | 0x80, key | 0x80);
|
||||||
this->keypresses.push(key);
|
this->keypresses.push(key);
|
||||||
this->lastKeyDown = key;
|
this->keyrepeater.setKey(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,11 +237,13 @@ void Emulator::dispatchKeyUp(const SDL_KeyboardEvent& keyEvent) {
|
||||||
|
|
||||||
if (isKeyDown(sym, mod)) {
|
if (isKeyDown(sym, mod)) {
|
||||||
--this->keysDown;
|
--this->keysDown;
|
||||||
} else if (sym == SDLK_F10) {
|
if (this->keysDown <= 0) {
|
||||||
// ...else if this is the emulated REPT key on the Apple keyboard...
|
this->keyrepeater.clearKey();
|
||||||
// ...stop repeating. The key has been released
|
}
|
||||||
this->repeat = false;
|
}
|
||||||
this->rept = 0;
|
|
||||||
|
if (sym == SDLK_F10) {
|
||||||
|
this->keyrepeater.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,10 +315,11 @@ bool Emulator::isSafeToQuit() {
|
||||||
|
|
||||||
|
|
||||||
void Emulator::toggleComputerPower() {
|
void Emulator::toggleComputerPower() {
|
||||||
if (this->timable == &this->videoStatic)
|
if (this->timable == &this->videoStatic) {
|
||||||
powerOnComputer();
|
powerOnComputer();
|
||||||
else
|
} else {
|
||||||
powerOffComputer();
|
powerOffComputer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emulator::powerOnComputer() {
|
void Emulator::powerOnComputer() {
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "screenimage.h"
|
#include "screenimage.h"
|
||||||
#include "analogtv.h"
|
#include "analogtv.h"
|
||||||
#include "keyboardbuffermode.h"
|
#include "keyboardbuffermode.h"
|
||||||
|
#include "KeyRepeatHandler.h"
|
||||||
#include "clipboardhandler.h"
|
#include "clipboardhandler.h"
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <wx/string.h>
|
#include <wx/string.h>
|
||||||
|
@ -35,6 +36,7 @@ class E2Config;
|
||||||
class Emulator {
|
class Emulator {
|
||||||
PaddleButtonStates paddleButtonStates;
|
PaddleButtonStates paddleButtonStates;
|
||||||
KeypressQueue keypresses;
|
KeypressQueue keypresses;
|
||||||
|
KeyRepeatHandler keyrepeater;
|
||||||
|
|
||||||
KeyboardBufferMode buffered;
|
KeyboardBufferMode buffered;
|
||||||
ScreenImage screenImage;
|
ScreenImage screenImage;
|
||||||
|
@ -45,10 +47,7 @@ class Emulator {
|
||||||
|
|
||||||
Timable* timable;
|
Timable* timable;
|
||||||
|
|
||||||
bool repeat;
|
int keysDown; // TODO move to KeyEventHandler
|
||||||
int keysDown;
|
|
||||||
int rept;
|
|
||||||
unsigned char lastKeyDown;
|
|
||||||
Uint32 prev_ms;
|
Uint32 prev_ms;
|
||||||
|
|
||||||
void powerOnComputer();
|
void powerOnComputer();
|
||||||
|
|
|
@ -14,79 +14,88 @@
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include "e2const.h"
|
#include "e2const.h"
|
||||||
#include "paddles.h"
|
#include "paddles.h"
|
||||||
|
|
||||||
|
#include <wx/gdicmn.h>
|
||||||
|
#include <wx/window.h>
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
|
|
||||||
Paddles::Paddles():
|
|
||||||
rTick(PADDLE_COUNT)
|
Paddles::Paddles() : rTick(PADDLE_COUNT) {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Paddles::~Paddles() {
|
||||||
Paddles::~Paddles()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Paddles::tick() {
|
||||||
void Paddles::tick()
|
for (int paddle = 0; paddle < PADDLE_COUNT; ++paddle) {
|
||||||
{
|
if (this->rTick[paddle] > 0) {
|
||||||
for (int paddle = 0; paddle < PADDLE_COUNT; ++paddle)
|
|
||||||
{
|
|
||||||
if (this->rTick[paddle] > 0)
|
|
||||||
--this->rTick[paddle];
|
--this->rTick[paddle];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Paddles::startTimers()
|
void Paddles::startTimers() {
|
||||||
{
|
try {
|
||||||
try
|
|
||||||
{
|
|
||||||
tryStartPaddleTimers();
|
tryStartPaddleTimers();
|
||||||
}
|
} catch (...) {
|
||||||
catch (...)
|
BOOST_LOG_TRIVIAL(error) << "Warning: cannot start paddle timers; mouse will not function as paddles.";
|
||||||
{
|
|
||||||
std::cerr << "Warning: cannot start paddle timers; mouse will not function as paddles." << std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Paddles::tryStartPaddleTimers()
|
static wxPoint current_mouse_position() {
|
||||||
{
|
|
||||||
int x, y;
|
int x, y;
|
||||||
SDL_GetMouseState(&x,&y);
|
SDL_GetMouseState(&x, &y);
|
||||||
|
return wxPoint(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Paddles::tryStartPaddleTimers() {
|
||||||
|
// wxWindow *pwin = ::wxGetActiveWindow();
|
||||||
|
// const wxPoint w = pwin->GetPosition(); // crash
|
||||||
|
// BOOST_LOG_TRIVIAL(info) << "x: " << w.x << ", y: " << w.y;
|
||||||
|
// constwxPoint m = ::wxGetMousePosition();
|
||||||
|
// const wxPoint p = w-m;
|
||||||
|
const wxPoint p = current_mouse_position();
|
||||||
|
|
||||||
double pMin = 0;
|
double pMin = 0;
|
||||||
double pMax = 500;
|
double pMax = 500;
|
||||||
x = (int)((x-pMin)/(pMax-pMin)*PADDLE_CYCLES+.5);
|
int x = (int) ((p.x - pMin) / (pMax - pMin) * PADDLE_CYCLES + .5);
|
||||||
y = (int)((y-pMin)/(pMax-pMin)*PADDLE_CYCLES+.5);
|
int y = (int) ((p.y - pMin) / (pMax - pMin) * PADDLE_CYCLES + .5);
|
||||||
|
|
||||||
if (isTimedOut(0))
|
if (isTimedOut(0)) {
|
||||||
this->rTick[0] = x;
|
this->rTick[0] = x;
|
||||||
if (isTimedOut(1))
|
}
|
||||||
|
if (isTimedOut(1)) {
|
||||||
this->rTick[1] = y;
|
this->rTick[1] = y;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Here we emulate having 4700 ohm across pins 7 and 1
|
Here we emulate having 4700 ohm across pins 7 and 1
|
||||||
of the game controller, and a 47Kohm resistor acros
|
of the game controller, and a 47K ohm resistor across
|
||||||
pins 11 and 1, to give cheap real-time clocks at
|
pins 11 and 1, to give cheap real-time clocks at
|
||||||
paddles 2 and 3. Paddle 2 is the 100 microsecond reference,
|
paddles 2 and 3. Paddle 2 is the 100 microsecond reference,
|
||||||
and paddle 3 is the 1 millisecond reference. This is
|
and paddle 3 is the 1 millisecond reference. This is
|
||||||
described in U.A.2, p. 7-33.
|
described in U.A.2, p. 7-33.
|
||||||
*/
|
*/
|
||||||
if (isTimedOut(2))
|
if (isTimedOut(2)) {
|
||||||
this->rTick[2] = E2Const::AVG_CPU_HZ/10000; // was 90, but why?
|
this->rTick[2] = E2Const::AVG_CPU_HZ / 10000; // was 90, but why?
|
||||||
if (isTimedOut(3))
|
}
|
||||||
this->rTick[3] = E2Const::AVG_CPU_HZ/1000;
|
if (isTimedOut(3)) {
|
||||||
|
this->rTick[3] = E2Const::AVG_CPU_HZ / 1000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Paddles::isTimedOut(const int paddle)
|
bool Paddles::isTimedOut(const int paddle) {
|
||||||
{
|
if (paddle < 0 || PADDLE_COUNT <= paddle) {
|
||||||
if (paddle < 0 || PADDLE_COUNT <= paddle)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this->rTick[paddle] <= 0;
|
return this->rTick[paddle] <= 0;
|
||||||
|
|
|
@ -16,11 +16,19 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include "screenimage.h"
|
#include "screenimage.h"
|
||||||
|
#include "E2wxApp.h"
|
||||||
|
#include "E2wxFrame.h"
|
||||||
#include "e2const.h"
|
#include "e2const.h"
|
||||||
#include "applentsc.h"
|
#include "applentsc.h"
|
||||||
#include "card.h"
|
#include "card.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <wx/panel.h>
|
||||||
|
#include <wx/sizer.h>
|
||||||
|
#include <wx/gdicmn.h>
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
@ -57,6 +65,8 @@ class ScreenException {
|
||||||
};
|
};
|
||||||
|
|
||||||
ScreenImage::ScreenImage() :
|
ScreenImage::ScreenImage() :
|
||||||
|
wxFrame(nullptr/*wxGetApp().GetFrame()*/, wxID_ANY, "Emulator", wxDefaultPosition, wxDefaultSize,
|
||||||
|
wxSYSTEM_MENU | wxCLOSE_BOX | wxCAPTION | wxCLIP_CHILDREN),
|
||||||
fullscreen(false),
|
fullscreen(false),
|
||||||
buffer(true),
|
buffer(true),
|
||||||
display(AnalogTV::TV_OLD_COLOR),
|
display(AnalogTV::TV_OLD_COLOR),
|
||||||
|
@ -64,12 +74,16 @@ ScreenImage::ScreenImage() :
|
||||||
cassInName(32, ' '),
|
cassInName(32, ' '),
|
||||||
cassOutName(32, ' ') {
|
cassOutName(32, ' ') {
|
||||||
createScreen();
|
createScreen();
|
||||||
|
Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenImage::~ScreenImage() {
|
ScreenImage::~ScreenImage() {
|
||||||
destroyScreen();
|
destroyScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxBEGIN_EVENT_TABLE(ScreenImage, wxFrame)
|
||||||
|
wxEND_EVENT_TABLE()
|
||||||
|
|
||||||
void ScreenImage::exitFullScreen() {
|
void ScreenImage::exitFullScreen() {
|
||||||
if (this->fullscreen) {
|
if (this->fullscreen) {
|
||||||
toggleFullScreen();
|
toggleFullScreen();
|
||||||
|
@ -83,7 +97,30 @@ void ScreenImage::toggleFullScreen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenImage::createScreen() {
|
void ScreenImage::createScreen() {
|
||||||
this->window = SDL_CreateWindow("Epple ][", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCRW, SCRH*ASPECT_RATIO, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN);
|
wxSizer *pszr = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|
||||||
|
this->panelTop = new wxPanel(this);
|
||||||
|
// TODO why won't shaped work? (Disabled frame resize as a workaround, for now.)
|
||||||
|
pszr->Add(this->panelTop, wxSizerFlags(0).Expand().Shaped().Center());
|
||||||
|
|
||||||
|
wxPanel *panelSdl = new wxPanel(this->panelTop, wxID_ANY, wxDefaultPosition, wxSize(SCRW,SCRH*ASPECT_RATIO));
|
||||||
|
createSdlTexture(panelSdl);
|
||||||
|
|
||||||
|
drawLabels();
|
||||||
|
notifyObservers();
|
||||||
|
|
||||||
|
SetSizer(pszr);
|
||||||
|
pszr->SetSizeHints(this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenImage::createSdlTexture(wxPanel *panelSdl) {
|
||||||
|
WXWidget nativeSdl = panelSdl->GetHandle();
|
||||||
|
// TODO: do we need special gtk handling here, to get xid using:
|
||||||
|
// GtkWidget* widget = panel->GetHandle();
|
||||||
|
// gtk_widget_realize(widget);
|
||||||
|
// Window xid = GDK_WINDOW_XWINDOW(widget->window);
|
||||||
|
this->window = SDL_CreateWindowFrom(static_cast<void*>(nativeSdl));
|
||||||
if (this->window == NULL) {
|
if (this->window == NULL) {
|
||||||
printf("Unable to create window: %s\n", SDL_GetError());
|
printf("Unable to create window: %s\n", SDL_GetError());
|
||||||
throw ScreenException();
|
throw ScreenException();
|
||||||
|
@ -105,9 +142,6 @@ void ScreenImage::createScreen() {
|
||||||
|
|
||||||
this->pixels = (unsigned int*) calloc(SCRW * SCRH, sizeof (unsigned int));
|
this->pixels = (unsigned int*) calloc(SCRW * SCRH, sizeof (unsigned int));
|
||||||
this->screen_pitch = SCRW;
|
this->screen_pitch = SCRW;
|
||||||
|
|
||||||
drawLabels();
|
|
||||||
notifyObservers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenImage::destroyScreen() {
|
void ScreenImage::destroyScreen() {
|
||||||
|
|
|
@ -19,6 +19,10 @@
|
||||||
#define SCREENIMAGE_H
|
#define SCREENIMAGE_H
|
||||||
|
|
||||||
#include "analogtv.h"
|
#include "analogtv.h"
|
||||||
|
|
||||||
|
#include <wx/frame.h>
|
||||||
|
#include <wx/panel.h>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -28,8 +32,9 @@ struct SDL_Texture;
|
||||||
struct SDL_Renderer;
|
struct SDL_Renderer;
|
||||||
struct SDL_Window;
|
struct SDL_Window;
|
||||||
|
|
||||||
class ScreenImage {
|
class ScreenImage : public wxFrame {
|
||||||
private:
|
private:
|
||||||
|
wxPanel *panelTop;
|
||||||
SDL_Window* window;
|
SDL_Window* window;
|
||||||
SDL_Renderer* renderer;
|
SDL_Renderer* renderer;
|
||||||
SDL_Texture* texture;
|
SDL_Texture* texture;
|
||||||
|
@ -39,6 +44,7 @@ private:
|
||||||
bool buffer;
|
bool buffer;
|
||||||
AnalogTV::DisplayType display;
|
AnalogTV::DisplayType display;
|
||||||
void createScreen();
|
void createScreen();
|
||||||
|
void createSdlTexture(wxPanel *panelSdl);
|
||||||
void destroyScreen();
|
void destroyScreen();
|
||||||
std::vector<std::string> slotnames;
|
std::vector<std::string> slotnames;
|
||||||
std::string cassInName;
|
std::string cassInName;
|
||||||
|
@ -46,6 +52,8 @@ private:
|
||||||
|
|
||||||
static std::string truncateFilePath(const std::filesystem::path& filepath);
|
static std::string truncateFilePath(const std::filesystem::path& filepath);
|
||||||
|
|
||||||
|
wxDECLARE_EVENT_TABLE();
|
||||||
|
|
||||||
// TODO some of these methods should be private
|
// TODO some of these methods should be private
|
||||||
public:
|
public:
|
||||||
ScreenImage();
|
ScreenImage();
|
||||||
|
|
Loading…
Reference in New Issue