From 399dbef68410198f4e18966e87ebc9c44c6f20f8 Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Fri, 15 Jan 2021 03:22:11 +0100 Subject: [PATCH] Added color supprt, render only happens every 1/60 of a second and added startup commands --- src/main.cpp | 164 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 129 insertions(+), 35 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index de5b135..3e78b74 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -20,6 +21,8 @@ #include "SDL_events.h" #include "SDL_keyboard.h" #include "SDL_keycode.h" +#include "SDL_pixels.h" +#include "SDL_surface.h" #include "Z/types/base.h" #include "Z80.h" @@ -28,11 +31,49 @@ #define SD_PAGE_SIZE 512 #define CPM_PAGES (SD_PAGE_SIZE/CPM_PAGE_SIZE*SD_PAGES) +struct Glyph { + uint8_t c = 0x00; + int fg = 0b111; + int bg = 0; + bool reverse = false; +}; + +struct RGB { + uint8_t r; + uint8_t g; + uint8_t b; +}; + +std::array color_map = { + // Normal colors + RGB{0x00, 0x00, 0x00}, + RGB{0xAA, 0x00, 0x00}, + RGB{0x00, 0xAA, 0x00}, + RGB{0xAA, 0x55, 0x00}, + RGB{0x00, 0x00, 0xAA}, + RGB{0xAA, 0x00, 0xAA}, + RGB{0x00, 0xAA, 0xAA}, + RGB{0xAA, 0xAA, 0xAA}, + + // Bright colors + RGB{0x55, 0x55, 0x55}, + RGB{0xFF, 0x55, 0x55}, + RGB{0x55, 0xFF, 0x55}, + RGB{0xFF, 0xFF, 0x55}, + RGB{0x55, 0x55, 0xFF}, + RGB{0xFF, 0x55, 0xFF}, + RGB{0x55, 0xFF, 0xFF}, + RGB{0xFF, 0xFF, 0xFF}, + + // Cursor + RGB{0xAA, 0xAA, 0x99} +}; + template class Screen { public: // @todo This should handle the input properly (same as fpga) - void input(char c) { + void input(uint8_t c) { if (escape == 1) { if (c == '[') { escape = 2; @@ -135,21 +176,27 @@ class Screen { } } - char get(int x, int y) { - return buffer[y*W + x]; + Glyph get(int x, int y) const { + Glyph g = buffer[((y+cursor.scroll) % H)*W + x]; + // @todo Disable this until we can turn cursor on and off + // if (x == cursor.x && y == cursor.y) { + // g.fg = 0; + // g.bg = 16; + // } + return g; } private: void set_foreground(int color) { - + current.fg = color; } void set_background(int color) { - + current.bg = color; } void reverse(bool enable) { - + current.reverse = enable; } void clear_screen() { @@ -157,8 +204,9 @@ class Screen { set_foreground(0b111); set_background(0); - for (char& c : buffer) { - c = 0x00; + for (Glyph& g : buffer) { + g = current; + g.c = 0x00; } cursor = {0, 0, 0}; @@ -174,8 +222,9 @@ class Screen { } } - void write(int x, int y, char c) { - buffer[y*W + x] = c; + void write(int x, int y, uint8_t c) { + buffer[((y+cursor.scroll) % H)*W + x] = current; + buffer[((y+cursor.scroll) % H)*W + x].c = c; } void next() { @@ -207,12 +256,14 @@ class Screen { } - std::array buffer = {0}; + std::array buffer; int escape = 0; int escape_parameter_1 = 0; int escape_parameter_2 = 0; + Glyph current = {0, 0b111, 0, false}; + struct { int x = 0; int y = 0; @@ -252,7 +303,7 @@ class Memory { ram[address] = value; } - uint8_t read(uint16_t address) { + uint8_t read(uint16_t address) const { if (cfg == 0 && address < 0x1000) { return rom[address]; } @@ -322,7 +373,7 @@ class Disk { } - bool is_ready() { + bool is_ready() const { return action != Action::NONE; } @@ -337,7 +388,7 @@ class Disk { template class Emulator { public: - Emulator(std::filesystem::path rom_name, std::filesystem::path disk_name) : memory(rom_name), disk(disk_name) { + Emulator(std::filesystem::path rom_name, std::filesystem::path disk_name, std::string startup = "") : memory(rom_name), disk(disk_name) { // SDL int render_flags = SDL_RENDERER_ACCELERATED; int window_flags = 0; @@ -362,12 +413,23 @@ class Emulator { } SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Loading '../convert-font/font.png'"); - font = IMG_LoadTexture(renderer, "../convert-font/font.png"); + SDL_Surface* surface = IMG_Load("../convert-font/font.png"); + + if (!surface) { + throw std::runtime_error("Failed to load font: " + std::string(IMG_GetError())); + } + + SDL_SetColorKey(surface, SDL_TRUE, SDL_MapRGB(surface->format, 0, 0, 0)); + + font = SDL_CreateTextureFromSurface(renderer, surface); if (!font) { - throw std::runtime_error("Failed to open font: " + std::string(IMG_GetError())); + throw std::runtime_error("Failed to create texture from surface: " + std::string(IMG_GetError())); } + SDL_FreeSurface(surface); + surface = nullptr; + // Z80 z.context = this; z.read = z_read; @@ -379,12 +441,21 @@ class Emulator { z80_reset(&z); SDL_StartTextInput(); + + for (char c : startup) { + input.push(c); + } } ~Emulator() { + SDL_DestroyTexture(font); + font = nullptr; + SDL_DestroyRenderer(renderer); + renderer = nullptr; SDL_DestroyWindow(window); + window = nullptr; SDL_Quit(); } @@ -408,7 +479,7 @@ class Emulator { // Input case 0x1E: { - char c = e->input.front(); + uint8_t c = e->input.front(); e->input.pop(); return c; } @@ -470,8 +541,7 @@ class Emulator { } void update() { - // Run for 1000 cycles - z80_run(&z, 1000); + z80_run(&z, 1); } void draw_screen() { @@ -483,18 +553,32 @@ class Emulator { dest.w = 16; dest.h = 16; - SDL_SetTextureColorMod(font, 255, 255, 255); - for (int x = 0; x < W; ++x) { for (int y = 0; y < H; ++y) { - char c = screen.get(x, y); - src.x = (c % 16) * 16; - src.y = (c / 16) * 16; + const Glyph& g = screen.get(x, y); + + RGB fg = color_map[g.fg]; + RGB bg = color_map[g.bg]; + + if (g.reverse) { + std::swap(fg, bg); + } + + SDL_SetTextureColorMod(font, fg.r, fg.g, fg.b); dest.x = x * 16; dest.y = y * 16; - SDL_RenderCopy(renderer, font, &src, &dest); + SDL_SetRenderDrawColor(renderer, bg.r, bg.g, bg.b, 0xFF); + SDL_RenderFillRect(renderer, &dest); + + // Only render if the char is not empty + if (g.c && g.c != ' ') { + src.x = (g.c % 16) * 16; + src.y = (g.c / 16) * 16; + + SDL_RenderCopy(renderer, font, &src, &dest); + } } } } @@ -517,7 +601,7 @@ class Emulator { break; case SDL_TEXTINPUT: { - char c = event.text.text[0]; + uint8_t c = event.text.text[0]; // @todo For some reason we cannot capture ctrl??? if (SDL_GetModState() & KMOD_ALT && c == 'c') { input.push(0x03); @@ -536,7 +620,8 @@ class Emulator { } void prepare() { - SDL_SetRenderDrawColor(renderer, 96, 128, 255, 255); + // If we see this color something is going wrong + SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0xFF, 0xFF); SDL_RenderClear(renderer); } @@ -555,20 +640,29 @@ class Emulator { Memory memory; Disk disk; - std::queue input; + std::queue input; bool ctrl = false; }; -int main() { - Emulator<80, 45> e("../../software/monitor/.build/rom_monitor.bin", "../create-disk/disk.img"); +int main(int argc, char* argv[]) { + std::string startup; + if (argc == 2) { + startup = std::string(argv[1]); + } + + Emulator<80, 45> e("../../software/monitor/.build/rom_monitor.bin", "../create-disk/disk.img", startup); + + std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); while (e.handle_events()) { - e.prepare(); - e.update(); - e.draw_screen(); - - e.render(); + // Make sure we only draw once every 60 seconds + if (std::chrono::duration_cast(std::chrono::steady_clock::now() - begin) >= std::chrono::milliseconds(1000/60)) { + begin = std::chrono::steady_clock::now(); + e.prepare(); + e.draw_screen(); + e.render(); + } } }