initial commit

first public release
This commit is contained in:
ArthurFerreira2 2021-07-07 17:00:47 +02:00 committed by GitHub
parent af2334c245
commit 4c8b396e53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 6475 additions and 3 deletions

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021 ArthurFerreira2
Copyright (c) 2020 Arthur Ferreira
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

104
Makefile Normal file
View File

@ -0,0 +1,104 @@
#
# Cross Platform Makefile
# Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X
#
# You will need SDL2 (http://www.libsdl.org):
# Linux:
# apt-get install libsdl2-dev
# Mac OS X:
# brew install sdl2
# MSYS2:
# pacman -S mingw-w64-i686-SDL2
#
# pick one
CXX = g++
#CXX = clang++
EXE = reinette
SOURCES = main.cpp puce65c02.cpp mmu.cpp video.cpp disk.cpp speaker.cpp paddles.cpp gui.cpp
IMGUI_DIR = lib/imgui-1.82
SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl2.cpp
ImGuiColorTextEdit_DIR = lib/ImGuiColorTextEdit-master
SOURCES += $(ImGuiColorTextEdit_DIR)/TextEditor.cpp
imfilebrowser_DIR = lib/imgui-filebrowser
imgui_club_DIR = lib/imgui_club-master
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
CXXFLAGS = -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends -I$(ImGuiColorTextEdit_DIR) -I$(imfilebrowser_DIR) -I$(imgui_club_DIR)
# CXXFLAGS += -O3
CXXFLAGS += -std=c++17 -lstdc++fs -Wall -Wformat -pedantic -Wpedantic -O3
LIBS =
WIN32-RC = reinette.rc
WIN32-RES = reinette.res
##---------------------------------------------------------------------
## BUILD FLAGS PER PLATFORM
##---------------------------------------------------------------------
ifeq ($(UNAME_S), Linux) #LINUX
ECHO_MESSAGE = "Linux"
LIBS += -lGL -ldl `sdl2-config --libs`
CXXFLAGS += `sdl2-config --cflags`
CFLAGS = $(CXXFLAGS)
endif
ifeq ($(UNAME_S), Darwin) #APPLE
ECHO_MESSAGE = "Mac OS X"
LIBS += -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo `sdl2-config --libs`
LIBS += -L/usr/local/lib -L/opt/local/lib
CXXFLAGS += `sdl2-config --cflags`
CXXFLAGS += -I/usr/local/include -I/opt/local/include
CFLAGS = $(CXXFLAGS)
endif
ifeq ($(OS), Windows_NT)
ECHO_MESSAGE = "MinGW"
# LIBS += -lgdi32 -lopengl32 -limm32 `pkg-config --static --libs sdl2`
LIBS += -lgdi32 -lopengl32 -limm32 -lmingw32 --static -Wl,-subsystem,windows -LC:/msys64/mingw64/lib -lmingw32 -lSDL2main -lSDL2 -mwindows -lmingw32 -ldinput8 -lshell32 -lsetupapi -ladvapi32 -luuid -lversion -loleaut32 -lole32 -limm32 -lwinmm -lgdi32 -luser32 -lm -mwindows -Wl,--no-undefined -pipe -Wl,--dynamicbase,--high-entropy-va,--nxcompat,--default-image-base-high
# CXXFLAGS += `pkg-config --cflags sdl2 `
CXXFLAGS += -IC:/msys64/mingw64/include/SDL2
CFLAGS = $(CXXFLAGS)
endif
##---------------------------------------------------------------------
## BUILD RULES
##---------------------------------------------------------------------
%.o:%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
%.o:$(IMGUI_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
%.o:$(IMGUI_DIR)/backends/%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
%.o:$(ImGuiColorTextEdit_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
all: $(EXE)
@echo Build complete for $(ECHO_MESSAGE)
$(EXE): $(OBJS) $(WIN32-RES)
$(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS)
$(WIN32-RES): $(WIN32-RC)
windres -o $@ $^ -O coff
clean:
rm -f $(EXE) $(OBJS) $(WIN32-RES)

View File

@ -1,2 +1,14 @@
# reinetteIIe
Reinette IIe, an enhanced Apple //e emulator
WORK IN PROGRESS
# reinette IIe
### reinette gets enhanced !
![screenshots](animated.gif)
\
\
\
*simplicity is the ultimate sophistication*

BIN
animated.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

129
disk.cpp Normal file
View File

@ -0,0 +1,129 @@
/*
* reinette, a french Apple II emulator, using SDL2
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
* Last modified 1st of July 2021
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include "reinette.h"
Disk::Disk() {
curDrv = 0; // Current Drive - only one can be enabled at a time
// TODO : initialize the unit[x] structs
}
int Disk::load( char *path, int drive) {
FILE *f = fopen(path, "rb"); // open file in read binary mode
if (!f || fread(unit[drive].data, 1, 232960, f) != 232960) // load it into memory and check size
return 0;
fclose(f);
sprintf(unit[drive].pathName, "%s", path); // update floppy image pathName record
// get filename
int i =0, a = 0;
while (unit[drive].pathName[i] != 0) { // find start of filename for disk0
if (unit[drive].pathName[i] == '/' || unit[drive].pathName[i] == '\\')
a = i + 1;
i++;
}
sprintf(unit[drive].fileName, "%s", unit[drive].pathName + a);
// is the file read only ?
f = fopen(path, "ab"); // try to open the file in append binary mode
if (f) { // success, file is writable
unit[drive].readOnly = false; // update the readOnly flag
fclose(f); // and close it untouched
} else {
unit[drive].readOnly = true; // f is NULL, no writable, no need to close it
}
return 1;
}
int Disk::save(int drive) {
if (!unit[drive].pathName[0]) return 0; // no file loaded into drive
if (unit[drive].readOnly) return 0; // file is read only write no aptempted
FILE *f = fopen(unit[drive].pathName, "wb");
if (!f) return 0; // could not open the file in write overide binary
if (fwrite(unit[drive].data, 1, 232960, f) != 232960) { // failed to write the full file (hdd full ?)
fclose(f); // release the ressource
return 0;
}
fclose(f); // success, release the ressource
return 1;
}
int Disk::eject(int drive) {
unit[drive].fileName[0] = 0;
unit[drive].pathName[0] = 0;
unit[drive].readOnly = false;
for (int i=0; i<232960; i++) // erase data
unit[drive].data[i]=0;
return 1;
}
void Disk::stepMotor(uint16_t address) {
static bool phases[2][4] = { 0 }; // phases states (for both drives)
static bool phasesB[2][4] = { 0 }; // phases states Before
static bool phasesBB[2][4] = { 0 }; // phases states Before Before
static int pIdx[2] = { 0 }; // phase index (for both drives)
static int pIdxB[2] = { 0 }; // phase index Before
static int halfTrackPos[2] = { 0 };
address &= 7;
int phase = address >> 1;
phasesBB[curDrv][pIdxB[curDrv]] = phasesB[curDrv][pIdxB[curDrv]];
phasesB[curDrv][pIdx[curDrv]] = phases[curDrv][pIdx[curDrv]];
pIdxB[curDrv] = pIdx[curDrv];
pIdx[curDrv] = phase;
if (!(address & 1)) { // head not moving (PHASE x OFF)
phases[curDrv][phase] = false;
return;
}
if ((phasesBB[curDrv][(phase + 1) & 3]) && (--halfTrackPos[curDrv] < 0)) // head is moving in
halfTrackPos[curDrv] = 0;
if ((phasesBB[curDrv][(phase - 1) & 3]) && (++halfTrackPos[curDrv] > 140)) // head is moving out
halfTrackPos[curDrv] = 140;
phases[curDrv][phase] = true; // update track#
unit[curDrv].track = (halfTrackPos[curDrv] + 1) / 2;
}
void Disk::setDrv(int drv) {
unit[drv].motorOn = unit[!drv].motorOn || unit[drv].motorOn; // if any of the motors were ON
unit[!drv].motorOn = false; // motor of the other drive is set to OFF
curDrv = drv; // set the current drive
}

57
disk.h Normal file
View File

@ -0,0 +1,57 @@
/*
* reinette, a french Apple II emulator, using SDL2
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
* Last modified 1st of July 2021
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __DISK_H__
#define __DISK_H__
typedef struct Drive_t {
char fileName[400]; // the floppy image file name
char pathName[400]; // the full floppy image path name
bool readOnly; // based on the image file attributes
uint8_t data[232960]; // nibblelized floppy image
bool motorOn; // motor status
bool writeMode; // writes to file are not implemented
uint8_t track; // current track position
uint16_t nibble; // ptr to nibble under head position
} Drive;
class Disk {
public:
int curDrv = 0; // Current Drive - only one can be enabled at a time
Drive unit[2] = {0}; // two disk ][ drive units
Disk();
~Disk();
int load(char *filename, int drv);
int save(int drive);
int eject(int drive);
void setDrv(int drv);
void stepMotor(uint16_t address);
};
#endif

748
gui.cpp Normal file
View File

@ -0,0 +1,748 @@
/*
* reinette, a french Apple II emulator, using SDL2
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
* Last modified 1st of July 2021
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "reinette.h"
Gui::Gui() {
frameNumber = 0;
screenScale = 2.0f;
fps = 60;
show_about_window = false;
show_help_window = false;
CRT_is_focused = false;
show_crt_window = true;
show_control_window = true;
show_disks_window = true;
show_info_window = true;
show_cpu_window = true;
show_code_window = true;
show_pageZero_window = true;
show_stack_window = true;
show_ram_window = true;
show_aux_window = true;
show_rom_window = true;
show_editor_window = true;
show_ramHeatmap_window = true;
show_auxHeatmap_window = true;
// Setup SDL
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) {
printf("Error: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
// Setup window
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
wdo = SDL_CreateWindow("Reinette", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1700, 900, window_flags);
gl_context = SDL_GL_CreateContext(wdo);
SDL_GL_MakeCurrent(wdo, gl_context);
SDL_GL_SetSwapInterval(1); // Enable vsync
SDL_EventState(SDL_DROPFILE, SDL_ENABLE); // ask SDL2 to read dropfile events
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
// io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
// io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
#include "imguiTheme.h"
// Setup Platform/Renderer backends
ImGui_ImplSDL2_InitForOpenGL(wdo, gl_context);
ImGui_ImplOpenGL2_Init();
clear_color = ImVec4((float)51/256, (float)58/256, (float)64/256, 1.00f); // fond de la fenetre principale
glGenTextures(1, &screenTexture);
glGenTextures(1, &ramHeatmapTexture);
glGenTextures(1, &auxHeatmapTexture);
// editor init
auto lang = TextEditor::LanguageDefinition::AppleSoft();
editor.SetLanguageDefinition(lang);
editor.SetShowWhitespaces(false);
editor.SetPalette(TextEditor::GetLightPalette());
fileToEdit = "program.bas";
std::ifstream t(fileToEdit);
if (t.good()) {
std::string str((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
editor.SetText(str);
}
}
int Gui::newFrame() {
// Start the Dear ImGui frame
ImGui_ImplOpenGL2_NewFrame();
ImGui_ImplSDL2_NewFrame(wdo);
ImGui::NewFrame();
return 0;
}
void Gui::getInputs() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
ImGui_ImplSDL2_ProcessEvent(&event);
SDL_bool ctrl, shift, alt;
alt = SDL_GetModState() & KMOD_ALT ? SDL_TRUE : SDL_FALSE;
ctrl = SDL_GetModState() & KMOD_CTRL ? SDL_TRUE : SDL_FALSE;
shift = SDL_GetModState() & KMOD_SHIFT ? SDL_TRUE : SDL_FALSE;
paddles->PB0 = alt ? 0xFF : 0x00; // update push button 0, Open Apple
paddles->PB1 = ctrl ? 0xFF : 0x00; // update push button 1, Solid Apple or option
paddles->PB2 = shift ? 0xFF : 0x00; // update push button 2, single-wire Shift-key mod
if (event.type == SDL_QUIT) running = false; // WM sent TERM signal
if (event.type == SDL_DROPFILE) { // user dropped a file
char *filename = event.drop.file; // get full pathname
if (!disk->load(filename, alt)) // if ALT : drv 1 else drv 0
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Load", "Not a valid nib file", NULL);
SDL_free(filename); // free filename memory
paused = false; // might already be the case
if (!(alt || ctrl)) { // unless ALT or CTRL were
mmu->init();
mmu->writeMem(0x3F4,0); // unset the Power-UP byte
cpu->RST(); // do a cold reset
}
}
if (CRT_is_focused) { // if (!io.WantCaptureKeyboard) {
if (event.type == SDL_KEYDOWN) { // a key has been pressed
switch (event.key.keysym.sym) {
// EMULATOR CONTROLS :
case SDLK_F3: // PASTE text from clipboard
if (SDL_HasClipboardText()) {
char *clipboardText = SDL_GetClipboardText();
int c = 0;
while (clipboardText[c]) { // all chars until ascii NUL
mmu->KBD = clipboardText[c++] | 0x80; // set bit7
if (mmu->KBD == 0x8A) mmu->KBD = 0x8D; // translate Line Feed to Carriage Ret
cpu->exec(400000); // give cpu (and applesoft) some cycles to process each char
}
SDL_free(clipboardText); // release the ressource
}
break;
case SDLK_F4: // VOLUME
if (shift) speaker->setVolume(volume+10); // increase volume
if (ctrl) speaker->setVolume(volume-10); // decrease volume
if (!ctrl && !shift) speaker->toggleMute(); // toggle mute / unmute
break;
case SDLK_F5: // JOYSTICK Release Speed
if (shift && (paddles->GCReleaseSpeed < 127)) paddles->GCReleaseSpeed += 2; // increase Release Speed
if (ctrl && (paddles->GCReleaseSpeed > 1)) paddles->GCReleaseSpeed -= 2; // decrease Release Speed
if (!ctrl && !shift) paddles->GCReleaseSpeed = 8; // reset Release Speed to 8
break;
case SDLK_F6: // JOYSTICK Action Speed
if (shift && (paddles->GCActionSpeed < 127)) paddles->GCActionSpeed += 2; // increase Action Speed
if (ctrl && (paddles->GCActionSpeed > 1)) paddles->GCActionSpeed -= 2; // decrease Action Speed
if (!ctrl && !shift) paddles->GCActionSpeed = 8; // reset Action Speed to 8
break;
case SDLK_F7: // ZOOM
if (shift && (screenScale <= 3.9f)) screenScale+=.1f; // zoom in
if (ctrl && (screenScale > 1.0f)) screenScale-=.1f; // zoom out
if (!ctrl && !shift) screenScale = 2.0f; // reset zoom to 2
break;
case SDLK_F10: paused = !paused; break; // toggle pause
case SDLK_F11: {
paused = true;
cpu->state = step;
} break;
case SDLK_F12: cpu->RST(); break; // reset
// EMULATED KEYS :
case SDLK_a: mmu->KBD = ctrl ? 0x81: 0xC1; break; // a
case SDLK_b: mmu->KBD = ctrl ? 0x82: 0xC2; break; // b STX
case SDLK_c: mmu->KBD = ctrl ? 0x83: 0xC3; break; // c ETX
case SDLK_d: mmu->KBD = ctrl ? 0x84: 0xC4; break; // d EOT
case SDLK_e: mmu->KBD = ctrl ? 0x85: 0xC5; break; // e
case SDLK_f: mmu->KBD = ctrl ? 0x86: 0xC6; break; // f ACK
case SDLK_g: mmu->KBD = ctrl ? 0x87: 0xC7; break; // g BELL
case SDLK_h: mmu->KBD = ctrl ? 0x88: 0xC8; break; // h BS
case SDLK_i: mmu->KBD = ctrl ? 0x89: 0xC9; break; // i HTAB
case SDLK_j: mmu->KBD = ctrl ? 0x8A: 0xCA; break; // j LF
case SDLK_k: mmu->KBD = ctrl ? 0x8B: 0xCB; break; // k VTAB
case SDLK_l: mmu->KBD = ctrl ? 0x8C: 0xCC; break; // l FF
case SDLK_m: mmu->KBD = ctrl ? shift ? 0x9D:0x8D:0xCD; break;// m CR ]
case SDLK_n: mmu->KBD = ctrl ? shift ? 0x9E:0x8E:0xCE; break;// n ^
case SDLK_o: mmu->KBD = ctrl ? 0x8F: 0xCF; break; // o
case SDLK_p: mmu->KBD = ctrl ? shift ? 0x80:0x90:0xD0; break; // p @
case SDLK_q: mmu->KBD = ctrl ? 0x91: 0xD1; break; // q
case SDLK_r: mmu->KBD = ctrl ? 0x92: 0xD2; break; // r
case SDLK_s: mmu->KBD = ctrl ? 0x93: 0xD3; break; // s ESC
case SDLK_t: mmu->KBD = ctrl ? 0x94: 0xD4; break; // t
case SDLK_u: mmu->KBD = ctrl ? 0x95: 0xD5; break; // u NAK
case SDLK_v: mmu->KBD = ctrl ? 0x96: 0xD6; break; // v
case SDLK_w: mmu->KBD = ctrl ? 0x97: 0xD7; break; // w
case SDLK_x: mmu->KBD = ctrl ? 0x98: 0xD8; break; // x CANCEL
case SDLK_y: mmu->KBD = ctrl ? 0x99: 0xD9; break; // y
case SDLK_z: mmu->KBD = ctrl ? 0x9A: 0xDA; break; // z
case SDLK_LEFTBRACKET: mmu->KBD = ctrl ? 0x9B: 0xDB; break; // [ {
case SDLK_BACKSLASH: mmu->KBD = ctrl ? 0x9C: 0xDC; break; // \ |
case SDLK_RIGHTBRACKET: mmu->KBD = ctrl ? 0x9D: 0xDD; break; // ] }
case SDLK_BACKSPACE: mmu->KBD = ctrl ? 0xDF: 0x88; break; // BS
case SDLK_0: mmu->KBD = shift? 0xA9: 0xB0; break; // 0 )
case SDLK_1: mmu->KBD = shift? 0xA1: 0xB1; break; // 1 !
case SDLK_2: mmu->KBD = shift? 0xC0: 0xB2; break; // 2
case SDLK_3: mmu->KBD = shift? 0xA3: 0xB3; break; // 3 #
case SDLK_4: mmu->KBD = shift? 0xA4: 0xB4; break; // 4 $
case SDLK_5: mmu->KBD = shift? 0xA5: 0xB5; break; // 5 %
case SDLK_6: mmu->KBD = shift? 0xDE: 0xB6; break; // 6 ^
case SDLK_7: mmu->KBD = shift? 0xA6: 0xB7; break; // 7 &
case SDLK_8: mmu->KBD = shift? 0xAA: 0xB8; break; // 8 *
case SDLK_9: mmu->KBD = shift? 0xA8: 0xB9; break; // 9 (
case SDLK_QUOTE: mmu->KBD = shift? 0xA2: 0xA7; break; // ' "
case SDLK_EQUALS: mmu->KBD = shift? 0xAB: 0xBD; break; // = +
case SDLK_SEMICOLON: mmu->KBD = shift? 0xBA: 0xBB; break; // ; :
case SDLK_COMMA: mmu->KBD = shift? 0xBC: 0xAC; break; // , <
case SDLK_PERIOD: mmu->KBD = shift? 0xBE: 0xAE; break; // . >
case SDLK_SLASH: mmu->KBD = shift? 0xBF: 0xAF; break; // / ?
case SDLK_MINUS: mmu->KBD = shift? 0xDF: 0xAD; break; // - _
case SDLK_BACKQUOTE: mmu->KBD = shift? 0xFE: 0xE0; break; // ` ~
case SDLK_LEFT: mmu->KBD = 0x88; break; // BS
case SDLK_RIGHT: mmu->KBD = 0x95; break; // NAK
case SDLK_DOWN: mmu->KBD = 0x8A; break; // LF
case SDLK_UP: mmu->KBD = 0x8B; break; // VTAB
case SDLK_SPACE: mmu->KBD = 0xA0; break;
case SDLK_ESCAPE: mmu->KBD = 0x9B; break; // ESC
case SDLK_RETURN: mmu->KBD = 0x8D; break; // CR
case SDLK_TAB: mmu->KBD = 0x89; break; // HTAB
// EMULATED JOYSTICK :
case SDLK_KP_1: paddles->GCD[0] = -1; paddles->GCA[0] = 1; break; // pdl0 <-
case SDLK_KP_3: paddles->GCD[0] = 1; paddles->GCA[0] = 1; break; // pdl0 ->
case SDLK_KP_5: paddles->GCD[1] = -1; paddles->GCA[1] = 1; break; // pdl1 <-
case SDLK_KP_2: paddles->GCD[1] = 1; paddles->GCA[1] = 1; break; // pdl1 ->
}
}
if (event.type == SDL_KEYUP) {
switch (event.key.keysym.sym) {
case SDLK_KP_1: paddles->GCD[0] = 1; paddles->GCA[0] = 0; break; // pdl0 ->
case SDLK_KP_3: paddles->GCD[0] = -1; paddles->GCA[0] = 0; break; // pdl0 <-
case SDLK_KP_5: paddles->GCD[1] = 1; paddles->GCA[1] = 0; break; // pdl1 ->
case SDLK_KP_2: paddles->GCD[1] = -1; paddles->GCA[1] = 0; break; // pdl1 <-
}
}
}
}
}
int Gui::update() {
if (ImGui::BeginMainMenuBar()) {
if (ImGui::BeginMenu("File")) {
if (ImGui::MenuItem("New", "Ctrl+N")) {
// void editor.SetText(const std::string& aText);
}
if (ImGui::MenuItem("Open", "Ctrl+O")) {
// void SetText(const std::string& aText);
}
if (ImGui::MenuItem("Save", "Ctrl+S")) {
// std::string textToSave = editor.GetText();
// std::ifstream t(fileToEdit);
// if (t.good()) {
// std::string str((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
// editor.SetText(str);
// }
}
if (ImGui::MenuItem("Save As..")) {
// TBD
}
if (ImGui::MenuItem("Quit", "CTRL+Q")) {
running = false;
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Edit")) {
bool ro = editor.IsReadOnly();
if (ImGui::MenuItem("Read-only mode", nullptr, &ro))
editor.SetReadOnly(ro);
ImGui::Separator();
if (ImGui::MenuItem("Undo", "CTRL+Z", nullptr, !ro && editor.CanUndo()))
editor.Undo();
if (ImGui::MenuItem("Redo", "CTRL+Y", nullptr, !ro && editor.CanRedo()))
editor.Redo();
ImGui::Separator();
if (ImGui::MenuItem("Copy", "Ctrl-C", nullptr, editor.HasSelection()))
editor.Copy();
if (ImGui::MenuItem("Cut", "Ctrl-X", nullptr, !ro && editor.HasSelection()))
editor.Cut();
if (ImGui::MenuItem("Delete", "Del", nullptr, !ro && editor.HasSelection()))
editor.Delete();
if (ImGui::MenuItem("Paste", "Ctrl-V", nullptr, !ro && ImGui::GetClipboardText() != nullptr))
editor.Paste();
ImGui::Separator();
if (ImGui::MenuItem("Select all", nullptr, nullptr))
editor.SetSelection(TextEditor::Coordinates(), TextEditor::Coordinates(editor.GetTotalLines(), 0));
ImGui::Separator();
if (ImGui::MenuItem("Dark palette"))
editor.SetPalette(TextEditor::GetDarkPalette());
if (ImGui::MenuItem("Light palette"))
editor.SetPalette(TextEditor::GetLightPalette());
if (ImGui::MenuItem("Retro blue palette"))
editor.SetPalette(TextEditor::GetRetroBluePalette());
ImGui::EndMenu();
}
if (ImGui::BeginMenu("View")) {
ImGui::MenuItem("CRT", NULL, &show_crt_window);
ImGui::Separator();
ImGui::MenuItem("Page Zero", NULL, &show_pageZero_window);
ImGui::MenuItem("Stack", NULL, &show_stack_window);
ImGui::MenuItem("Main RAM", NULL, &show_ram_window);
ImGui::MenuItem("Aux RAM", NULL, &show_aux_window);
ImGui::MenuItem("ROM", NULL, &show_rom_window);
ImGui::MenuItem("RAM Heatmap", NULL, &show_ramHeatmap_window);
ImGui::MenuItem("AUX Heatmap", NULL, &show_auxHeatmap_window);
ImGui::Separator();
ImGui::MenuItem("Controls", NULL, &show_control_window);
ImGui::MenuItem("CPU", NULL, &show_cpu_window);
ImGui::MenuItem("Code", NULL, &show_code_window);
ImGui::MenuItem("Disk", NULL, &show_disks_window);
ImGui::MenuItem("Info", NULL, &show_info_window);
ImGui::Separator();
ImGui::MenuItem("Editor", NULL, &show_editor_window);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Help")) {
ImGui::MenuItem("Help", NULL, &show_help_window);
ImGui::MenuItem("About", NULL, &show_about_window);
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
static MemoryEditor mem_edit_stack;
if (show_stack_window) {
mem_edit_stack.DrawWindow("STACK", mmu->ram+256, 256);
}
static MemoryEditor mem_edit_pageZero;
if (show_pageZero_window) {
mem_edit_pageZero.DrawWindow("PAGE ZERO", mmu->ram, 256);
}
static MemoryEditor mem_edit_ram;
if (show_ram_window) {
mem_edit_ram.DrawWindow("RAM", mmu->ram, RAMSIZE);
}
static MemoryEditor mem_edit_rom;
if (show_rom_window) {
mem_edit_rom.DrawWindow("ROM", mmu->rom, ROMSIZE);
}
static MemoryEditor mem_edit_aux;
if (show_aux_window) {
mem_edit_aux.DrawWindow("AUX", mmu->aux, AUXSIZE);
}
if (show_about_window) {
if (ImGui::Begin("ABOUT", &show_about_window, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Reinette 2021 Arthur Ferreira " );
ImGui::Separator();
ImGui::Text("version : %s", VERSION);
ImGui::Text("https://github.com/ArthurFerreira2");
ImGui::Text("\nReinette is licensed under the MIT License\nsee LICENSE for more information.\n");
ImGui::End();
}
}
if (show_help_window) {
if (ImGui::Begin("HELP", &show_help_window, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Reinette v%s", VERSION);
ImGui::Separator();
ImGui::Text( "\nctrl F1 writes the changes of the floppy in drive 0"
"\nalt F1 writes the changes of the floppy in drive 1"
"\n"
"\nF3 paste text from clipboard"
"\n"
"\nF4 mute / un-mute sound"
"\nshift F4 increase volume"
"\nctrl F4 decrease volume"
"\n"
"\nF5 reset joystick release speed"
"\nshift F5 increase joystick release speed"
"\ncrtl F5 decrease joystick release speed"
"\n"
"\nF6 reset joystick action speed"
"\nshift F6 increase joystick action speed"
"\ncrtl F6 decrease joystick action speed"
"\n"
"\nF7 reset the zoom to 2:1"
"\nshift F7 increase zoom up to 4:1 max"
"\nctrl F7 decrease zoom down to 1:1 pixels"
"\n"
"\nF8 monochrome / color display (only in HGR)"
"\nF9 pause / un-pause the emulator"
"\nF10 Not implemented"
"\nF11 reset");
ImGui::End();
}
}
if (show_ramHeatmap_window) {
ImGui::Begin("RAM HEATMAP", &show_ramHeatmap_window);
// Adjust the image to the window
auto window_size = ImGui::GetWindowSize();
auto image_size = ImVec2(window_size.x - 15, window_size.y - 50);
// Draw image
ImGui::Image((void*)((intptr_t)ramHeatmapTexture), image_size, ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(0,0,0,0));
ImGui::End();
}
if (show_auxHeatmap_window) {
ImGui::Begin("AUX HEATMAP", &show_auxHeatmap_window);
// Adjust the image to the window
auto window_size = ImGui::GetWindowSize();
auto image_size = ImVec2(window_size.x - 15, window_size.y - 50);
// Draw image
ImGui::Image((void*)((intptr_t)auxHeatmapTexture), image_size, ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(0,0,0,0));
ImGui::End();
}
if (show_control_window) {
ImGui::Begin("CONTROLS", &show_control_window);
ImGui::SliderInt("GC ACTION", &paddles->GCActionSpeed, 0, 128); // JOYSTICK Action Speed
ImGui::SliderInt("GC RELEASE", &paddles->GCReleaseSpeed, 0, 128); // JOYSTICK Release Speed
ImGui::Separator();
ImGui::SliderFloat("SCALE", &screenScale, 1, 4, "%.1f");
if (ImGui::SliderInt("VOLUME", &volume, 0, 127)) speaker->setVolume(volume);
ImGui::SameLine();
if (ImGui::Checkbox("MUTE", &muted)) speaker->toggleMute();
ImGui::Separator();
if (ImGui::SliderFloat("SPEED", &speed, .0f, 200, "%.4f MHz", ImGuiSliderFlags_Logarithmic));
ImGui::SameLine();
if (ImGui::Button("NORMAL")) speed = 1.023f;
ImGui::Checkbox("PAUSE", &paused);
ImGui::SameLine();
if (ImGui::Button("STEP")) {
paused = true;
cpu->state = step;
}
ImGui::Separator();
if (ImGui::Button("RESET"))
cpu->RST();
ImGui::SameLine();
if (ImGui::Button("POWER CYCLE")) {
cpu->RST(); // do a cold reset
mmu->init();
mmu->ram[0x3F4] = 0; // unset the Power-UP byte
}
ImGui::End();
}
static std::string floppy1="", floppy2="";
fileDialog1.Display();
if (fileDialog1.HasSelected()) {
floppy1 = fileDialog1.GetSelected().filename().string();
disk->load((char*)fileDialog1.GetSelected().string().c_str(), 0);
fileDialog1.ClearSelected();
}
fileDialog2.Display();
if (fileDialog2.HasSelected()) {
floppy2 = fileDialog2.GetSelected().filename().string();
disk->load((char*)fileDialog2.GetSelected().string().c_str(), 1);
fileDialog2.ClearSelected();
}
if (show_disks_window) {
ImGui::Begin("DISK ][", &show_disks_window);
if (ImGui::Button("LOAD FLOPPY #1")) {
fileDialog1.SetTitle("Insert floppy into drive #1");
fileDialog1.SetTypeFilters({ ".nib", ".dsk", ".woz" });
fileDialog1.Open();
}
ImGui::SameLine();
if (ImGui::Button("SAVE FLOPPY #1")) {
disk->save(0);
}
ImGui::SameLine();
if (ImGui::Button("EJECT FLOPPY #1")) {
disk->eject(0);
}
ImGui::Text("Floppy #1 : %s", disk->unit[0].fileName);
ImGui::Text("Read %s", disk->unit[0].readOnly ? "Only" : "and Write");
ImGui::Text("Status : ");
ImGui::SameLine();
if (disk->unit[0].motorOn) {
if (disk->unit[0].writeMode)
ImGui::Text("writting");
else
ImGui::Text("reading");
}
else
ImGui::Text("idle");
ImGui::Separator();
if (ImGui::Button("LOAD FLOPPY #2")) {
fileDialog2.SetTitle("Insert floppy into drive #2");
fileDialog2.SetTypeFilters({ ".nib", ".dsk", ".woz" });
fileDialog2.Open();
}
ImGui::SameLine();
if (ImGui::Button("SAVE FLOPPY #2")) {
disk->save(1);
}
ImGui::SameLine();
if (ImGui::Button("EJECT FLOPPY #2")) {
disk->eject(1);
}
ImGui::Text("Floppy #2 : %s", disk->unit[1].fileName);
ImGui::Text("Read %s", disk->unit[1].readOnly ? "Only" : "and Write");
ImGui::Text("Status : ");
ImGui::SameLine();
if (disk->unit[1].motorOn) {
if (disk->unit[1].writeMode)
ImGui::Text("writting");
else
ImGui::Text("reading");
}
else
ImGui::Text("idle");
ImGui::End();
}
if (show_info_window) {
ImGui::Begin("INFO", &show_info_window);
// Display FPS
ImGui::Text("%.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Separator();
ImGui::Text("KEY : %02X", mmu->KBD);
ImGui::Separator();
ImGui::Checkbox("TEXT", &mmu->TEXT);
ImGui::Checkbox("MIXED", &mmu->MIXED);
ImGui::Checkbox("PAGE2", &mmu->PAGE2);
ImGui::Checkbox("HIRES", &mmu->HIRES);
ImGui::Checkbox("DHIRES", &mmu->DHIRES);
ImGui::Checkbox("COL80", &mmu->COL80);
ImGui::Separator();
ImGui::Text("Language Card readable : %s", mmu->LCRD ? "True" : "False");
ImGui::Text("Language Card writable : %s", mmu->LCWR ? "True" : "False");
ImGui::Text("Language Card bank 2 : %s", mmu->LCBK2 ? "Enabled" : "Disabled");
ImGui::Text("Language Card prewrite : %s", mmu->LCWFF ? "On" : "Off");
ImGui::Separator();
ImGui::Text("RAMRD : %s", mmu->RAMRD ? "On" : "Off");
ImGui::Text("RAMWRT : %s", mmu->RAMWRT ? "On" : "Off");
ImGui::Text("ALTZP : %s", mmu->ALTZP ? "On" : "Off");
ImGui::Text("STORE80 : %s", mmu->STORE80 ? "On" : "Off");
ImGui::Text("ALTCHARSET : %s", mmu->ALTCHARSET ? "On" : "Off");
ImGui::Text("INTCXROM : %s", mmu->INTCXROM ? "On" : "Off");
ImGui::Text("SLOTC3ROM : %s", mmu->SLOTC3ROM ? "On" : "Off");
ImGui::Separator();
ImGui::Text("VERTBLANK : %s", mmu->VERTBLANK ? "On" : "Off");
ImGui::End();
}
if (show_cpu_window) {
char buffer[1000];
cpu->getRegs(buffer);
ImGui::Begin("REGISTERS", &show_cpu_window);
ImGui::Text("%s", buffer);
// ImGui::Text("TICK : %lld", ticks);
ImGui::End();
}
static char buffer[2000];
static char addressString[5];
static unsigned long int address = 0xFF00;
static bool followPC = true;
if (show_code_window) {
ImGui::Begin("CODE", &show_code_window);
if( ImGui::InputTextWithHint("", "address in hex", addressString, IM_ARRAYSIZE(addressString))) {
address = strtoul(addressString, NULL, 16);
cpu->getCode(address, buffer, 2000, 20);
}
ImGui::SameLine();
ImGui::Checkbox("PC", &followPC);
if (followPC)
cpu->getCode(cpu->getPC(), buffer, 2000, 20);
ImGui::Text("%s", buffer);
ImGui::End();
}
if (show_editor_window) {
ImGui::Begin("EDITOR", &show_editor_window, ImGuiWindowFlags_HorizontalScrollbar);
ImGui::SetWindowSize(ImVec2(100, 200), ImGuiCond_FirstUseEver);
ImGui::Separator();
if (ImGui::Button("NEW & RUN SELECTION")) {
if (editor.HasSelection()) {
std::string program = "NEW\n";
program += editor.GetSelectedText();
program += "\nRUN\n";
int c = 0;
while (program[c]) { // all chars until ascii NUL
mmu->KBD = program[c++] | 0x80; // set bit7
if (mmu->KBD == 0x8A) mmu->KBD = 0x8D; // translate Line Feed to Carriage Ret
cpu->exec(500000); // give cpu (and applesoft) some cycles to process each char
}
}
}
ImGui::SameLine();
if (ImGui::Button("PASTE SELECTION")) {
if (editor.HasSelection()) {
std::string program = "\n";
program += editor.GetSelectedText();
program += "\n";
int c = 0;
while (program[c]) { // all chars until ascii NUL
mmu->KBD = program[c++] | 0x80; // set bit7
if (mmu->KBD == 0x8A) mmu->KBD = 0x8D; // translate Line Feed to Carriage Ret
cpu->exec(500000); // give cpu (and applesoft) some cycles to process each char
}
}
}
ImGui::SameLine();
if (ImGui::Button("SEND RESET"))
cpu->RST();
ImGui::Separator();
auto cpos = editor.GetCursorPosition();
ImGui::Text("%4d/%-4d %4d lines | %s | %s | %s | %s",
cpos.mLine + 1,
cpos.mColumn + 1,
editor.GetTotalLines(),
editor.IsOverwrite() ? "Ovr" : "Ins",
editor.CanUndo() ? "*" : " ",
editor.GetLanguageDefinition().mName.c_str(),
fileToEdit.c_str());
ImGui::Separator();
editor.Render("TextEditor");
ImGui::End();
}
if (show_crt_window) {
ImGui::Begin("CRT", &show_crt_window);
// Adjust the window to the image
auto image_size = ImVec2(280 * screenScale, 192 * screenScale);
ImGui::SetWindowSize(ImVec2(280 * screenScale + 16, 192 * screenScale + 50));
// Draw image
ImGui::Image((void*)((intptr_t)screenTexture), image_size, ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(0,0,0,0));
// get inputs
CRT_is_focused = ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows);
ImGui::End();
}
return 1;
}
int Gui::render() {
// crt
if (video->gfxmode == 80) {
glBindTexture(GL_TEXTURE_2D, screenTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 560, 384, 0, GL_RGBA, GL_UNSIGNED_BYTE, video->screenPixels80);
}
else {
glBindTexture(GL_TEXTURE_2D, screenTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 280, 192, 0, GL_RGBA, GL_UNSIGNED_BYTE, video->screenPixels);
}
// RAM heatmap
glBindTexture(GL_TEXTURE_2D, ramHeatmapTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, video->ramHeatmap);
// AUX heatmap
glBindTexture(GL_TEXTURE_2D, auxHeatmapTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, video->auxHeatmap);
// Rendering
ImGui::Render();
glViewport(0, 0, (int)ImGui::GetIO().DisplaySize.x, (int)ImGui::GetIO().DisplaySize.y);
glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData());
SDL_GL_SwapWindow(wdo);
if (++frameNumber >= 60) frameNumber = 0; // reset to zero every second
return 1;
}
Gui::~Gui() {
ImGui_ImplOpenGL2_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
SDL_GL_DeleteContext(gl_context);
SDL_DestroyWindow(wdo);
SDL_AudioQuit();
SDL_Quit();
}

91
gui.h Normal file
View File

@ -0,0 +1,91 @@
/*
* reinette, a french Apple II emulator, using SDL2
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
* Last modified 1st of July 2021
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _GUI_H
#define _GUI_H
#include <cstdio>
#include <cstdlib>
#include "imgui.h"
#include "imgui_impl_sdl.h"
#include "imgui_impl_opengl2.h"
#include "imfilebrowser.h"
#include "imgui_memory_editor.h"
#include "TextEditor.h"
#include <SDL2/SDL.h>
#include <SDL_opengl.h>
#include <fstream>
class Gui {
public:
int fps;
unsigned int frameNumber;
private:
bool show_about_window;
bool show_help_window;
bool CRT_is_focused;
bool show_crt_window;
bool show_control_window;
bool show_disks_window;
bool show_info_window;
bool show_cpu_window;
bool show_code_window;
bool show_pageZero_window;
bool show_stack_window;
bool show_ram_window;
bool show_aux_window;
bool show_rom_window;
bool show_editor_window;
bool show_ramHeatmap_window;
bool show_auxHeatmap_window;
ImVec4 clear_color;
uint32_t screenTexture;
uint32_t ramHeatmapTexture;
uint32_t auxHeatmapTexture;
SDL_Window* wdo;
float screenScale;
SDL_GLContext gl_context;
TextEditor editor;
std::string fileToEdit;
ImGui::FileBrowser fileDialog1;
ImGui::FileBrowser fileDialog2;
public:
Gui();
~Gui();
void getInputs();
int update();
int newFrame();
int render();
int release();
};
#endif

95
imgui.ini Normal file
View File

@ -0,0 +1,95 @@
[Window][Debug##Default]
Pos=579,238
Size=476,315
Collapsed=0
[Window][RAM]
Pos=8,424
Size=546,155
Collapsed=0
[Window][ROM]
Pos=8,741
Size=546,150
Collapsed=0
[Window][AUX]
Pos=8,583
Size=546,153
Collapsed=0
[Window][STACK]
Pos=8,140
Size=512,278
Collapsed=0
[Window][PAGE ZERO]
Pos=39,24
Size=513,278
Collapsed=0
[Window][INFO]
Pos=859,464
Size=247,427
Collapsed=0
[Window][REGISTERS]
Pos=1111,492
Size=216,71
Collapsed=0
[Window][CODE]
Pos=1112,571
Size=218,320
Collapsed=0
[Window][HELP]
Pos=319,106
Size=444,407
Collapsed=0
[Window][ABOUT]
Pos=234,380
Size=311,129
Collapsed=0
[Window][CRT]
Pos=561,23
Size=576,434
Collapsed=0
[Window][RAM HEATMAP]
Pos=561,466
Size=289,203
Collapsed=0
[Window][AUX HEATMAP]
Pos=559,681
Size=295,210
Collapsed=0
[Window][EDITOR]
Pos=1142,23
Size=550,461
Collapsed=0
[Window][CONTROLS]
Pos=1334,492
Size=359,206
Collapsed=0
[Window][DISK ][]
Pos=1334,708
Size=357,183
Collapsed=0
[Window][Insert floppy into drive #2##filebrowser_2012684434080]
Pos=500,225
Size=700,450
Collapsed=0
[Window][Insert floppy into drive #1##filebrowser_2012684433760]
Pos=501,225
Size=700,450
Collapsed=0

54
imguiTheme.h Normal file
View File

@ -0,0 +1,54 @@
// Setup Dear ImGui style
// ImGui::StyleColorsDark();
// or create your own :
ImGuiStyle& style = ImGui::GetStyle();
style.Colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f);
style.Colors[ImGuiCol_ChildBg] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f);
style.Colors[ImGuiCol_PopupBg] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f);
style.Colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
style.Colors[ImGuiCol_FrameBg] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.38f, 0.38f, 0.38f, 1.00f);
style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.67f, 0.67f, 0.67f, 0.39f);
style.Colors[ImGuiCol_TitleBg] = ImVec4(0.08f, 0.08f, 0.09f, 1.00f);
style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.28f, 0.28f, 0.29f, 1.00f);
style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
style.Colors[ImGuiCol_CheckMark] = ImVec4(0.11f, 0.64f, 0.92f, 1.00f);
style.Colors[ImGuiCol_SliderGrab] = ImVec4(0.11f, 0.64f, 0.92f, 1.00f);
style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.08f, 0.50f, 0.72f, 1.00f);
style.Colors[ImGuiCol_Button] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.38f, 0.38f, 0.38f, 1.00f);
style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.67f, 0.67f, 0.67f, 0.39f);
style.Colors[ImGuiCol_Header] = ImVec4(0.22f, 0.22f, 0.22f, 1.00f);
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f);
style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.67f, 0.67f, 0.67f, 0.39f);
style.Colors[ImGuiCol_Separator] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.41f, 0.42f, 0.44f, 1.00f);
style.Colors[ImGuiCol_SeparatorActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
style.Colors[ImGuiCol_ResizeGrip] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.29f, 0.30f, 0.31f, 0.67f);
style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
style.Colors[ImGuiCol_Tab] = ImVec4(0.08f, 0.08f, 0.09f, 0.83f);
style.Colors[ImGuiCol_TabHovered] = ImVec4(0.33f, 0.34f, 0.36f, 0.83f);
style.Colors[ImGuiCol_TabActive] = ImVec4(0.23f, 0.23f, 0.24f, 1.00f);
style.Colors[ImGuiCol_TabUnfocused] = ImVec4(0.08f, 0.08f, 0.09f, 1.00f);
style.Colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.13f, 0.14f, 0.15f, 1.00f);
style.Colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
style.Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
style.Colors[ImGuiCol_DragDropTarget] = ImVec4(0.11f, 0.64f, 0.92f, 1.00f);
style.Colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
style.Colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
style.Colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
style.GrabRounding = style.FrameRounding = 2.0f;

83
main.cpp Normal file
View File

@ -0,0 +1,83 @@
/*
* reinette, a french Apple II emulator, using SDL2
* and powered by puce65c02 - a WDS 65c02 cpu emulator by the same author
* Last modified 1st of July 2021
* Copyright (c) 2021 Arthur Ferreira (arthur.ferreira2@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "reinette.h"
#include <iostream>
// global variables - TODO create a config file and make changes persistant
bool muted = false;
int volume = 10;
bool running = true;
bool paused = false;
float speed = 1.023f;
// instanciate all objects, calling their respective constructors
Mmu* mmu = new Mmu();
puce65c02* cpu = new puce65c02();
Video* video = new Video();
Disk* disk = new Disk();
Speaker* speaker = new Speaker();
Paddles* pa