Files
atari2600/source/display.cpp
T
raimon@prometeo e245410c0a - [NEW] 6502dis i 6502debugger implementats
- [FIX] font.bmp afegit
- [NEW] Afegides regles de comprobació de memòria en la versió debug de compilació en el lagueirtofile
- [FIX] la rom ha de carregar abans de atari2600::init()
- [NEW] Implementació bàsica del PIA completada.
- [FIX] El framebuffer intern en el mòdul TIA era incorrecte.
- [NEW] Afegits accesors als registres del 6502
- [NEW] m6502::reset()
- [FIX] [6502m] Corregits opcodes amb direccionament implicit: CLC, SEC, PHA, CLI, PLA, SEI, DEY, TXA, TYA, TXS, TAY, TAX, CLV, TSX, INY, DEX, CLD, INX, NOP i SED). Augmentaven el PC una posició de més.
2026-09-17 17:43:33 +02:00

252 lines
8.7 KiB
C++

#include "display.h"
#include <SDL3/SDL.h>
#include "tia.h"
#include "atari2600.h"
#include "ui_window.h"
#include "6502debugger.h"
#include "ui.h"
namespace display
{
constexpr int screen_width = 160;
constexpr int screen_height = 192;
// Standard Stella NTSC Palette (ARGB format: 0xFFRRGGBB)
// Indexed by: (COLUx >> 1) & 0x7F
const uint32_t palette[128] = {
// Hue $0 (Grayscale / Monochromatic)
0xFF000000, 0xFF282828, 0xFF444444, 0xFF5C5C5C, 0xFF707070, 0xFF848484, 0xFF989898, 0xFFACACAC,
// Hue $1 (Gold / Yellow-Orange)
0xFF4C2C00, 0xFF684400, 0xFF845C00, 0xFF9C7400, 0xFFB48C00, 0xFFCCA414, 0xFFE4BC34, 0xFFFCD454,
// Hue $2 (Orange / Red-Orange)
0xFF541800, 0xFF742C00, 0xFF904400, 0xFFA85C00, 0xFFC07400, 0xFFD88C00, 0xFFF0A420, 0xFFFFBC40,
// Hue $3 (Red-Orange)
0xFF580C00, 0xFF781C00, 0xFF943000, 0xFFB04800, 0xFFC86000, 0xFFE07808, 0xFFF89028, 0xFFFFA848,
// Hue $4 (Magenta / Red-Violet)
0xFF540420, 0xFF74103C, 0xFF902058, 0xFFAC3474, 0xFFC4488C, 0xFFDC5CA8, 0xFFF474C0, 0xFFFF8CD8,
// Hue $5 (Purple / Violet)
0xFF440454, 0xFF601074, 0xFF7C2090, 0xFF9434AC, 0xFFAC48C4, 0xFFC45CDC, 0xFFDC74F4, 0xFFF48CFF,
// Hue $6 (Blue-Violet / Indigo)
0xFF2C0874, 0xFF441494, 0xFF5C24B0, 0xFF7438CC, 0xFF8C4CE4, 0xFFA460FC, 0xFFBC78FF, 0xFFD490FF,
// Hue $7 (Blue)
0xFF101480, 0xFF2424A0, 0xFF3C38BC, 0xFF504CD4, 0xFF6860EC, 0xFF8078FF, 0xFF9890FF, 0xFFB0A8FF,
// Hue $8 (Blue-Cyan)
0xFF002074, 0xFF003494, 0xFF0C48B0, 0xFF2060CC, 0xFF3474E4, 0xFF4C8CFC, 0xFF64A4FF, 0xFF7CBCFF,
// Hue $9 (Cyan / Blue-Green)
0xFF002854, 0xFF004074, 0xFF005490, 0xFF006CAC, 0xFF1880C4, 0xFF3098DC, 0xFF48B0F4, 0xFF60C8FF,
// Hue $A (Teal / Green-Cyan)
0xFF00302C, 0xFF004844, 0xFF00605C, 0xFF007874, 0xFF00908C, 0xFF1CA8A4, 0xFF38C0BC, 0xFF54D8D4,
// Hue $B (Green)
0xFF003408, 0xFF004C18, 0xFF00642C, 0xFF007C40, 0xFF009454, 0xFF14AC6C, 0xFF30C484, 0xFF4CDC9C,
// Hue $C (Yellow-Green)
0xFF0C3400, 0xFF204C00, 0xFF346400, 0xFF487C00, 0xFF5C9400, 0xFF74AC10, 0xFF8CC428, 0xFFA4DC44,
// Hue $D (Olive Green)
0xFF243000, 0xFF3C4800, 0xFF546000, 0xFF6C7800, 0xFF849000, 0xFF9CA800, 0xFFB4C018, 0xFFCCC434,
// Hue $E (Brown / Olive-Yellow)
0xFF3C2C00, 0xFF584000, 0xFF745800, 0xFF8C6C00, 0xFFA48400, 0xFFBC9C00, 0xFFD4B420, 0xFFECC83C,
// Hue $F (Orange-Brown)
0xFF482400, 0xFF643800, 0xFF805000, 0xFF986400, 0xFFB07C00, 0xFFC89400, 0xFFE0AC28, 0xFFF8C444
};
SDL_Window *win = nullptr;
SDL_Renderer *ren = nullptr;
SDL_Texture *tex = nullptr;
SDL_Texture *uitex = nullptr;
uint8_t zoom = 1;
bool fullscreen = false;
int fullscreen_scale = 1;
SDL_FRect dest_rect;
bool eventHandler(SDL_Event *e)
{
if (e->type==SDL_EVENT_WINDOW_CLOSE_REQUESTED) {
return false;
} else if ((e->type==SDL_EVENT_WINDOW_SHOWN) || (e->type==SDL_EVENT_WINDOW_EXPOSED)) {
redraw();
}
if (e->type == SDL_EVENT_KEY_DOWN) {
const SDL_Scancode &key = e->key.scancode;
switch (key) {
case SDL_SCANCODE_F8: atari2600::pause(); m6502debugger::show(); break;
case SDL_SCANCODE_F12: if (atari2600::is_paused()) atari2600::resume(); else atari2600::pause(); break;
case SDL_SCANCODE_Q: if (e->key.mod & SDL_KMOD_CTRL) { return false; break; }
default: break;
}
if (atari2600::is_paused()) {
switch (key) {
case SDL_SCANCODE_F2: display::decZoom(); break;
case SDL_SCANCODE_F3: display::incZoom(); break;
case SDL_SCANCODE_F4: display::toggleFullscreen(); break;
default: break;
}
}
}
if (e->type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
if (atari2600::is_paused())
atari2600::resume();
else
atari2600::pause();
}
if (e->type == SDL_EVENT_MOUSE_MOTION) {
SDL_ShowCursor();
}
return true;
}
void init()
{
if (win) ui::window::unregisterWindow(SDL_GetWindowID(win));
if (tex) SDL_DestroyTexture(tex);
if (uitex) SDL_DestroyTexture(uitex);
if (ren) SDL_DestroyRenderer(ren);
if (win) SDL_DestroyWindow(win);
const int z = fullscreen ? 1 : zoom;
win = SDL_CreateWindow("Atari 2600 Screen", screen_width*2*z, screen_height*z, 0);
SDL_SetWindowFullscreen(win, fullscreen);
ren = SDL_CreateRenderer(win, NULL);
tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, screen_width, screen_height);
SDL_SetTextureScaleMode(tex, SDL_SCALEMODE_NEAREST);
uitex = ui::createtexture(ren);
ui::window::registerWindow(SDL_GetWindowID(win), eventHandler);
if (fullscreen)
{
int w, h;
SDL_GetWindowSize(win, &w, &h);
fullscreen_scale = h/screen_height;
dest_rect.w = screen_width*2 * fullscreen_scale;
dest_rect.h = screen_height * fullscreen_scale;
dest_rect.x = (w - dest_rect.w)/2;
dest_rect.y = (h - dest_rect.h)/2;
}
else
{
dest_rect.x = dest_rect.y = 0;
dest_rect.w = screen_width*2 * zoom;
dest_rect.h = screen_height * zoom;
}
focus();
}
void focus()
{
if (win)
{
SDL_RaiseWindow(win);
redraw();
}
}
void redraw(const bool present)
{
//if (zx_tape::getplaying() && zx_tape::getOption(ZXTAPE_OPTION_FAST_LOAD)) return;
//ui::setrenderer(ren, uitex);
const uint8_t *framebuffer = tia::get_framebuffer();
//framebuffer += screen_width*26;
Uint32* pixels;
int pitch;
SDL_LockTexture(tex, NULL, (void**)&pixels, &pitch);
for (int i=0; i<screen_width*screen_height;++i) *(pixels++) = palette[framebuffer[i]];
SDL_UnlockTexture(tex);
if (fullscreen)
{
SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
SDL_RenderClear(ren);
}
// Pintem la textura a pantalla
SDL_RenderTexture(ren, tex, NULL, &dest_rect);
// Pintem les ralles dels pixels
//if (zoom>2 || fullscreen) {
// SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND);
// SDL_SetRenderDrawColor(ren, 160, 170, 5, 96);
// const float scale = fullscreen ? fullscreen_scale : zoom;
// for (int i=0;i<144;++i) SDL_RenderDrawLine(ren, dest_rect.x, dest_rect.y+i*scale, dest_rect.x+159*scale, dest_rect.y+i*scale);
// for (int i=0;i<160;++i) SDL_RenderDrawLine(ren, dest_rect.x+i*scale, dest_rect.y, dest_rect.x+i*scale, dest_rect.y+143*scale);
//}
//if (present)
// SDL_RenderPresent(ren);
//else
//{
// SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND);
// SDL_SetRenderDrawColor(ren, 0, 0, 0, 128);
// int w = screen_width*zoom;
// int h = screen_height*zoom;
// if (fullscreen) SDL_GetWindowSize(win, &w, &h);
// SDL_FRect rect {0,0,float(w),float(h)};
// SDL_RenderFillRect(ren, &rect);
//}
if (atari2600::is_paused()) {
SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(ren, 0, 0, 0, 128);
int w = screen_width*2*zoom;
int h = screen_height*zoom;
if (fullscreen) SDL_GetWindowSize(win, &w, &h);
SDL_FRect rect {0,0,float(w),float(h)};
SDL_RenderFillRect(ren, &rect);
}
SDL_RenderPresent(ren);
}
void present()
{
SDL_RenderPresent(ren);
}
void setTitle(const char* title)
{
char tmp[256];
strcpy(tmp, "MSX Screen");
strcat(tmp, title);
SDL_SetWindowTitle(win, tmp);
}
void setZoom(const int value)
{
if (fullscreen) return;
if (value < 1) return;
const SDL_DisplayMode *dm = SDL_GetCurrentDisplayMode(SDL_GetDisplayForWindow(win));
if (screen_width*2*value > dm->w) return;
if (screen_height*value > dm->h) return;
zoom = value;
init();
}
void incZoom()
{
if (fullscreen) return;
setZoom(zoom+1);
}
void decZoom()
{
if (fullscreen) return;
setZoom(zoom-1);
}
void toggleFullscreen()
{
fullscreen = !fullscreen;
init();
}
const bool getFullscreen()
{
return fullscreen;
}
}