1214 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1214 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include <string>
 | 
						|
#include <fstream>
 | 
						|
#include <iomanip>
 | 
						|
#include <iostream>
 | 
						|
#include <algorithm>
 | 
						|
#include <atomic>
 | 
						|
 | 
						|
#include "memory.h"
 | 
						|
#include "timing.h"
 | 
						|
#include "editor.h"
 | 
						|
#include "loader.h"
 | 
						|
#include "graphics.h"
 | 
						|
#include "expression.h"
 | 
						|
#include "assembler.h"
 | 
						|
#include "inih/INIReader.h"
 | 
						|
#include "defaultKeys.h"
 | 
						|
 | 
						|
// Use this if you ever want to change the default font, but it better be 6x8 per char or otherwise you will be in a world of hurt
 | 
						|
//#define CREATE_FONT_HEADER
 | 
						|
#ifndef CREATE_FONT_HEADER
 | 
						|
#include "emuFont96x48.h"
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
namespace Graphics
 | 
						|
{
 | 
						|
    int _width, _height;
 | 
						|
    int _posX = 0, _posY = 0;
 | 
						|
 | 
						|
    float _aspect = 0.0f;
 | 
						|
    float _scaleX, _scaleY;
 | 
						|
 | 
						|
    bool _fullScreen = false;
 | 
						|
    bool _resizable = false;
 | 
						|
    bool _borderless = true;
 | 
						|
    bool _vSync = false;
 | 
						|
    bool _fixedSize = false;
 | 
						|
 | 
						|
    int _filter = 0;
 | 
						|
 | 
						|
    bool _displayHelpScreen = false;
 | 
						|
    uint8_t _displayHelpScreenAlpha = 0;
 | 
						|
 | 
						|
    std::atomic<bool> _enableUploadBar(false);
 | 
						|
    std::atomic<int> _uploadCursorY(-1);
 | 
						|
    std::atomic<float> _uploadPercentage(0.0f);
 | 
						|
    std::string _uploadFilename;
 | 
						|
 | 
						|
    uint32_t _pixels[SCREEN_WIDTH * SCREEN_HEIGHT];
 | 
						|
    uint32_t _colours[COLOUR_PALETTE];
 | 
						|
    uint32_t _hlineTiming[GIGA_HEIGHT];
 | 
						|
 | 
						|
    SDL_Window* _window = NULL;
 | 
						|
    SDL_Renderer* _renderer = NULL;
 | 
						|
    SDL_Texture* _screenTexture = NULL;
 | 
						|
    SDL_Texture* _helpTexture = NULL;
 | 
						|
    SDL_Surface* _helpSurface = NULL;
 | 
						|
    SDL_Surface* _fontSurface = NULL;
 | 
						|
 | 
						|
    INIReader _configIniReader;
 | 
						|
 | 
						|
    int getWidth(void) {return _width;}
 | 
						|
    int getHeight(void) {return _height;}
 | 
						|
 | 
						|
    uint32_t* getPixels(void) {return _pixels;}
 | 
						|
    uint32_t* getColours(void) {return _colours;}
 | 
						|
 | 
						|
    SDL_Window* getWindow(void) {return _window;}
 | 
						|
    SDL_Renderer* getRenderer(void) {return _renderer;}
 | 
						|
    SDL_Texture* getScreenTexture(void) {return _screenTexture;}
 | 
						|
    SDL_Texture* getHelpTexture(void) {return _helpTexture;}
 | 
						|
    SDL_Surface* getHelpSurface(void) {return _helpSurface;}
 | 
						|
    SDL_Surface* getFontSurface(void) {return _fontSurface;}
 | 
						|
 | 
						|
    void setDisplayHelpScreen(bool display) {_displayHelpScreen = display;}
 | 
						|
    void setWidthHeight(int width, int height) {_width = width, _height = height;}
 | 
						|
 | 
						|
    bool getUploadBarEnabled(void) {return _enableUploadBar;}
 | 
						|
    void setUploadFilename(const std::string& uploadFilename) {_uploadFilename = uploadFilename;}
 | 
						|
    void updateUploadBar(float uploadPercentage) {_uploadPercentage = uploadPercentage;}
 | 
						|
    void enableUploadBar(bool enableUploadBar)
 | 
						|
    {
 | 
						|
        _uploadPercentage = 0.0f;
 | 
						|
        _enableUploadBar = enableUploadBar;
 | 
						|
        if(enableUploadBar)
 | 
						|
        {
 | 
						|
            _uploadCursorY = 34;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            _uploadCursorY = -1;
 | 
						|
            _uploadFilename = "";
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    SDL_Surface* createSurface(int width, int height)
 | 
						|
    {
 | 
						|
        uint32_t rmask, gmask, bmask, amask;
 | 
						|
 | 
						|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
 | 
						|
        rmask = 0xff000000;
 | 
						|
        gmask = 0x00ff0000;
 | 
						|
        bmask = 0x0000ff00;
 | 
						|
        amask = 0x000000ff;
 | 
						|
#else
 | 
						|
        rmask = 0x000000ff;
 | 
						|
        gmask = 0x0000ff00;
 | 
						|
        bmask = 0x00ff0000;
 | 
						|
        amask = 0xff000000;
 | 
						|
#endif
 | 
						|
 | 
						|
        SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, 32, rmask, gmask, bmask, amask);
 | 
						|
        if(surface == NULL)
 | 
						|
        {
 | 
						|
            Cpu::shutdown();
 | 
						|
            fprintf(stderr, "Graphics::createSurface() :  failed to create SDL surface.\n");
 | 
						|
            _EXIT_(EXIT_FAILURE);
 | 
						|
        }
 | 
						|
 | 
						|
        return surface;
 | 
						|
    }
 | 
						|
 | 
						|
    void writeToSurface(const SDL_Surface* surface, const uint32_t* data, int width, int height)
 | 
						|
    {
 | 
						|
        uint32_t* srcPixels = (uint32_t*)data;
 | 
						|
        uint32_t* dstPixels = (uint32_t*)surface->pixels;
 | 
						|
        for(int j=0; j<height; j++)
 | 
						|
        {
 | 
						|
            for(int i=0; i<width; i++)
 | 
						|
            {
 | 
						|
                *dstPixels++ = *srcPixels++;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    void createFontHeader(const SDL_Surface* fontSurface, const std::string& filename, const std::string& name, int width, int height)
 | 
						|
    {
 | 
						|
        std::ofstream outfile(filename);
 | 
						|
        if(!outfile.is_open())
 | 
						|
        {
 | 
						|
            fprintf(stderr, "Graphics::createFontHeader() : failed to create '%s'\n", filename.c_str());
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        outfile << "uint32_t " << name + "[] = \n";
 | 
						|
        outfile << "{\n";
 | 
						|
        outfile << "    ";
 | 
						|
 | 
						|
        int colCount = 0;
 | 
						|
        uint32_t* pixels = (uint32_t*)fontSurface->pixels;
 | 
						|
        for(int j=0; j<height; j++)
 | 
						|
        {
 | 
						|
            for(int i=0; i<width; i++)
 | 
						|
            {
 | 
						|
                outfile << "0x" << std::hex << std::setw(8) << std::setfill('0') << pixels[j*width + i] << ", ";
 | 
						|
                if(++colCount == 8)
 | 
						|
                {
 | 
						|
                    colCount = 0;
 | 
						|
                    if(j < height-1  ||  i < width-1) outfile << "\n    ";
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        outfile << "\n};" << std::endl;
 | 
						|
    }
 | 
						|
 | 
						|
    void createHelpTexture(void)
 | 
						|
    {
 | 
						|
        bool useDefault = false;
 | 
						|
        std::ifstream infile(INPUT_CONFIG_INI);
 | 
						|
        if(!infile.is_open()) useDefault = true;
 | 
						|
 | 
						|
        int lines = 1;
 | 
						|
        std::string lineToken;
 | 
						|
        std::vector<std::string> lineTokens;
 | 
						|
 | 
						|
        if(useDefault)
 | 
						|
        {
 | 
						|
            lineTokens = _defaultKeys;
 | 
						|
            lines = int(_defaultKeys.size());
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            // Read ini file into lines buffer
 | 
						|
            while(!infile.eof())
 | 
						|
            {
 | 
						|
                std::getline(infile, lineToken);
 | 
						|
                lineTokens.push_back(lineToken);
 | 
						|
                if(!infile.good()  &&  !infile.eof())
 | 
						|
                {
 | 
						|
                    Cpu::shutdown();
 | 
						|
                    fprintf(stderr, "Graphics::createHelpTexture() : Bad line : '%s' : in %s : on line %d\n", lineToken.c_str(), INPUT_CONFIG_INI, lines);
 | 
						|
                    _EXIT_(EXIT_FAILURE);
 | 
						|
                }
 | 
						|
 | 
						|
                lines++;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Print text in lines with spaces as padding to the help screen surface
 | 
						|
        int maxLines = SCREEN_HEIGHT / (FONT_HEIGHT + 2);
 | 
						|
        int numLines = std::min(lines-1, maxLines);
 | 
						|
        uint32_t* pixels = (uint32_t*)_helpSurface->pixels;
 | 
						|
 | 
						|
        for(int i=0; i<numLines; i++)
 | 
						|
        {
 | 
						|
            int y = i*(FONT_HEIGHT + 2) + (maxLines - numLines)/2 * (FONT_HEIGHT + 2);
 | 
						|
            size_t nonWhiteSpace = lineTokens[i].find_first_not_of("  \n\r\f\t\v");
 | 
						|
 | 
						|
            if(nonWhiteSpace == std::string::npos) lineTokens[i] = std::string(MAX_CHARS_HELP, ' ');
 | 
						|
            if(lineTokens[i].size() < MAX_CHARS_HELP) lineTokens[i] += std::string(MAX_CHARS_HELP - lineTokens[i].size(), ' ');
 | 
						|
            drawText(lineTokens[i], pixels, 0, y, 0xFF00FF00, false, 0, 0, 0x00000000, false, -1, true, 0xFFFFFFFF, 0xFF00FFFF);
 | 
						|
 | 
						|
            // Fill in the gaps
 | 
						|
            for(int j=FONT_HEIGHT; j<FONT_HEIGHT+2; j++)
 | 
						|
            {
 | 
						|
                for(int k=0; k<SCREEN_WIDTH*3/4; k++)
 | 
						|
                {
 | 
						|
                    pixels[(y + j)*SCREEN_WIDTH + k] = 0xFF000000;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Create help screen texture
 | 
						|
        _helpTexture = SDL_CreateTextureFromSurface(_renderer, _helpSurface);
 | 
						|
        if(_helpTexture == NULL)
 | 
						|
        {
 | 
						|
            Cpu::shutdown();
 | 
						|
            fprintf(stderr, "Graphics::createHelpTexture() :  failed to create SDL texture.\n");
 | 
						|
            _EXIT_(EXIT_FAILURE);
 | 
						|
        }
 | 
						|
 | 
						|
        // Enable blending on help screen texture
 | 
						|
        SDL_SetTextureBlendMode(_helpTexture, SDL_BLENDMODE_BLEND);
 | 
						|
        SDL_SetTextureAlphaMod(_helpTexture, 0);
 | 
						|
    }
 | 
						|
 | 
						|
    bool getKeyAsString(const std::string& sectionString, const std::string& iniKey, const std::string& defaultKey, std::string& result)
 | 
						|
    {
 | 
						|
        result = _configIniReader.Get(sectionString, iniKey, defaultKey);
 | 
						|
        if(result == defaultKey) return false;
 | 
						|
        Expression::strToUpper(result);
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    void initialise(void)
 | 
						|
    {
 | 
						|
        // HLINE sync error bar
 | 
						|
        for(int i=0; i<GIGA_HEIGHT; i++) _hlineTiming[i] = 0xFF00FF00;
 | 
						|
 | 
						|
        // Colour palette
 | 
						|
        for(int i=0; i<COLOUR_PALETTE; i++)
 | 
						|
        {
 | 
						|
            uint8_t r = uint8_t(double((i & 0x03) >>0) / 3.0 * 255.0);
 | 
						|
            uint8_t g = uint8_t(double((i & 0x0C) >>2) / 3.0 * 255.0);
 | 
						|
            uint8_t b = uint8_t(double((i & 0x30) >>4) / 3.0 * 255.0);
 | 
						|
 | 
						|
            _colours[i] = 0xFF000000 | (r <<16) | (g <<8) | b;
 | 
						|
            //fprintf(stderr, "%08X\n", _colours[i]); // use to create a Paint.Net palette
 | 
						|
        }
 | 
						|
 | 
						|
        // Safe resolution by default
 | 
						|
        SDL_DisplayMode DM;
 | 
						|
        SDL_GetCurrentDisplayMode(0, &DM);
 | 
						|
        _aspect = float(DM.w) / float(DM.h);
 | 
						|
        _fullScreen = false;
 | 
						|
        _resizable = true;
 | 
						|
        _borderless = false;
 | 
						|
        _vSync = false;
 | 
						|
        _fixedSize = false;
 | 
						|
        _filter = 0;
 | 
						|
        _width = 640;
 | 
						|
        _height = 480;
 | 
						|
        _scaleX = 1.5f;
 | 
						|
        _scaleY = 1.5f;
 | 
						|
        _posX = 40;
 | 
						|
        _posY = 40;
 | 
						|
 | 
						|
        // Parse graphics config file
 | 
						|
        INIReader iniReader(Loader::getExePath() + "/" + GRAPHICS_CONFIG_INI);
 | 
						|
        _configIniReader = iniReader;
 | 
						|
        if(_configIniReader.ParseError() < 0)
 | 
						|
        {
 | 
						|
            fprintf(stderr, "Graphics::initialise() : couldn't load INI file '%s' : reverting to default graphics options.\n", GRAPHICS_CONFIG_INI);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            // Parse Monitor Keys
 | 
						|
            enum Section {Monitor};
 | 
						|
            std::map<std::string, Section> section;
 | 
						|
            section["Monitor"] = Monitor;
 | 
						|
            for(auto sectionString : _configIniReader.Sections())
 | 
						|
            {
 | 
						|
                if(section.find(sectionString) == section.end())
 | 
						|
                {
 | 
						|
                    fprintf(stderr, "Graphics::initialise() : INI file '%s' has bad Sections : reverting to default values.\n", GRAPHICS_CONFIG_INI);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
 | 
						|
                std::string result;
 | 
						|
                switch(section[sectionString])
 | 
						|
                {
 | 
						|
                    case Monitor:
 | 
						|
                    {
 | 
						|
                        getKeyAsString(sectionString, "Fullscreen", "0", result);   
 | 
						|
                        _fullScreen = strtol(result.c_str(), nullptr, 10);
 | 
						|
                        getKeyAsString(sectionString, "Resizable", "1", result);   
 | 
						|
                        _resizable = strtol(result.c_str(), nullptr, 10);
 | 
						|
                        getKeyAsString(sectionString, "Borderless", "0", result);   
 | 
						|
                        _borderless = strtol(result.c_str(), nullptr, 10);
 | 
						|
                        getKeyAsString(sectionString, "VSync", "0", result);        
 | 
						|
                        _vSync = strtol(result.c_str(), nullptr, 10);
 | 
						|
                        getKeyAsString(sectionString, "FixedSize", "0", result);        
 | 
						|
                        _fixedSize = strtol(result.c_str(), nullptr, 10);
 | 
						|
 | 
						|
                        getKeyAsString(sectionString, "Filter", "0", result);        
 | 
						|
                        _filter = strtol(result.c_str(), nullptr, 10);
 | 
						|
                        _filter = (_filter<0 || _filter>2) ? 0 : _filter;
 | 
						|
 | 
						|
                        getKeyAsString(sectionString, "Width", "640", result);
 | 
						|
                        _width = (result == "DESKTOP") ? DM.w : std::strtol(result.c_str(), nullptr, 10);
 | 
						|
                        getKeyAsString(sectionString, "Height", "480", result);
 | 
						|
                        _height = (result == "DESKTOP") ? DM.h : std::strtol(result.c_str(), nullptr, 10);
 | 
						|
 | 
						|
                        getKeyAsString(sectionString, "ScaleX", "1.5", result);
 | 
						|
                        _scaleX = std::stof(result.c_str());
 | 
						|
                        getKeyAsString(sectionString, "ScaleY", "1.5", result);
 | 
						|
                        _scaleY = std::stof(result.c_str());
 | 
						|
 | 
						|
                        getKeyAsString(sectionString, "PosX", "0", result);
 | 
						|
                        _posX = strtol(result.c_str(), nullptr, 10);
 | 
						|
                        getKeyAsString(sectionString, "PosY", "0", result);
 | 
						|
                        _posY = strtol(result.c_str(), nullptr, 10);
 | 
						|
                    }
 | 
						|
                    break;
 | 
						|
 | 
						|
                    default: break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // SDL hints, VSync and Batching
 | 
						|
        char vsChar = char(_vSync + '0');
 | 
						|
        SDL_SetHint(SDL_HINT_RENDER_VSYNC, &vsChar);
 | 
						|
        SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, std::to_string(_filter).c_str());
 | 
						|
 | 
						|
        // Fullscreen
 | 
						|
        if(_fullScreen)
 | 
						|
        {
 | 
						|
            if(SDL_CreateWindowAndRenderer(0, 0, SDL_WINDOW_FULLSCREEN_DESKTOP, &_window, &_renderer) < 0)
 | 
						|
            {
 | 
						|
                Cpu::shutdown();
 | 
						|
                fprintf(stderr, "Graphics::initialise() : failed to create SDL fullscreen window.\n");
 | 
						|
                _EXIT_(EXIT_FAILURE);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        // Windowed
 | 
						|
        else
 | 
						|
        {
 | 
						|
            if(_fixedSize)
 | 
						|
            {
 | 
						|
                SDL_RenderSetLogicalSize(_renderer, _width, _height);
 | 
						|
 | 
						|
                if(SDL_CreateWindowAndRenderer(_width, _height, 0, &_window, &_renderer) < 0)
 | 
						|
                {
 | 
						|
                    Cpu::shutdown();
 | 
						|
                    fprintf(stderr, "Graphics::initialise() : failed to create SDL window.\n");
 | 
						|
                    _EXIT_(EXIT_FAILURE);
 | 
						|
                }
 | 
						|
 | 
						|
                SDL_SetWindowTitle(_window, VERSION_STR);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                // Try and keep faithful to Gigatron's real aspect ratio no matter what the window/monitor resolution is
 | 
						|
                _width = int(_width * _scaleX * _aspect * float(_height) / float(_width));
 | 
						|
                _height = int(_height * _scaleY);
 | 
						|
 | 
						|
                if(SDL_CreateWindowAndRenderer(_width, _height, 0, &_window, &_renderer) < 0)
 | 
						|
                {
 | 
						|
                    Cpu::shutdown();
 | 
						|
                    fprintf(stderr, "Graphics::initialise() : failed to create SDL window.\n");
 | 
						|
                    _EXIT_(EXIT_FAILURE);
 | 
						|
                }
 | 
						|
 | 
						|
                if(!_borderless)
 | 
						|
                {
 | 
						|
                    SDL_SetWindowResizable(_window, (SDL_bool)_resizable);
 | 
						|
                    SDL_SetWindowTitle(_window, VERSION_STR);
 | 
						|
                }
 | 
						|
 | 
						|
                SDL_SetWindowBordered(_window, (SDL_bool)!_borderless);
 | 
						|
                SDL_SetWindowPosition(_window, _posX, _posY);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Screen texture
 | 
						|
        _screenTexture = SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT);
 | 
						|
        if(_screenTexture == NULL)
 | 
						|
        {
 | 
						|
            Cpu::shutdown();
 | 
						|
            fprintf(stderr, "Graphics::initialise() :  failed to create SDL texture.\n");
 | 
						|
            _EXIT_(EXIT_FAILURE);
 | 
						|
        }
 | 
						|
 | 
						|
#ifdef CREATE_FONT_HEADER
 | 
						|
        // Load font file
 | 
						|
        SDL_Surface* fontSurface = SDL_LoadBMP("EmuFont-96x48.bmp");
 | 
						|
        if(fontSurface == NULL)
 | 
						|
        {
 | 
						|
            Cpu::shutdown();
 | 
						|
            fprintf(stderr, "Graphics::initialise() : failed to create SDL font surface, you're probably missing 'EmuFont-96x48.bmp' in the current directory/path.\n");
 | 
						|
            _EXIT_(EXIT_FAILURE);
 | 
						|
        }
 | 
						|
        _fontSurface = SDL_ConvertSurfaceFormat(fontSurface, SDL_PIXELFORMAT_ARGB8888, NULL);
 | 
						|
        SDL_FreeSurface(fontSurface);
 | 
						|
        if(_fontSurface == NULL)
 | 
						|
        {
 | 
						|
            Cpu::shutdown();
 | 
						|
            fprintf(stderr, "Graphics::initialise() : failed to convert SDL font surface format to screen surface format.\n");
 | 
						|
            _EXIT_(EXIT_FAILURE);
 | 
						|
        }
 | 
						|
        // Use this if you want to change the default font
 | 
						|
        createFontHeader(_fontSurface, "emuFont96x48.h", "_emuFont96x48", FONT_BMP_WIDTH, FONT_BMP_HEIGHT);
 | 
						|
#else
 | 
						|
        _fontSurface = createSurface(FONT_BMP_WIDTH, FONT_BMP_HEIGHT);
 | 
						|
        writeToSurface(_fontSurface, _emuFont96x48, FONT_BMP_WIDTH, FONT_BMP_HEIGHT);
 | 
						|
#endif
 | 
						|
 | 
						|
        // Help screen
 | 
						|
        _helpSurface = createSurface(SCREEN_WIDTH, SCREEN_HEIGHT);
 | 
						|
        createHelpTexture();
 | 
						|
 | 
						|
#ifdef _WIN32
 | 
						|
        Cpu::restoreWin32Console();
 | 
						|
#endif
 | 
						|
 | 
						|
        SDL_RaiseWindow(_window);
 | 
						|
    }
 | 
						|
 | 
						|
    uint32_t savedPixels[6*5];
 | 
						|
    void restoreReticlePixel(int x, int y)
 | 
						|
    {
 | 
						|
        if(x < 0  ||  x > SCREEN_WIDTH - 1) return;
 | 
						|
        if(y < 0  ||  y > SCREEN_HEIGHT - 1) return;
 | 
						|
        int index = (x % 5) + (y % 6)*5;
 | 
						|
        _pixels[x + y*SCREEN_WIDTH] = savedPixels[index];
 | 
						|
    }
 | 
						|
    void saveReticlePixel(int x, int y)
 | 
						|
    {
 | 
						|
        if(x < 0  ||  x > SCREEN_WIDTH - 1) return;
 | 
						|
        if(y < 0  ||  y > SCREEN_HEIGHT - 1) return;
 | 
						|
        int index = (x % 5) + (y % 6)*5;
 | 
						|
        savedPixels[index] = _pixels[x + y*SCREEN_WIDTH];
 | 
						|
    }
 | 
						|
    void drawReticlePixel(int x, int y)
 | 
						|
    {
 | 
						|
        if(x < 0  ||  x > SCREEN_WIDTH - 1) return;
 | 
						|
        if(y < 0  ||  y > SCREEN_HEIGHT - 1) return;
 | 
						|
        //fprintf(stderr, "%d %d\n", x, y);
 | 
						|
        _pixels[x + y*SCREEN_WIDTH] = 0xFFFFFFFF; //(0x00FFFFFF ^ _pixels[x + y*SCREEN_WIDTH]) & 0x00FFFFFF;
 | 
						|
    }
 | 
						|
    void drawReticle(int vgaX, int vgaY)
 | 
						|
    {
 | 
						|
        for(int j=-1; j<5; j++)
 | 
						|
        {
 | 
						|
            for(int i=-1; i<4; i++)
 | 
						|
            {
 | 
						|
                int x = vgaX*3 + i;
 | 
						|
                int y = vgaY*4 + j;
 | 
						|
                saveReticlePixel(x, y);
 | 
						|
                if(j==-1 || j==4 || i==-1 || i==3) drawReticlePixel(x, y);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    void restoreReticle(int vgaX, int vgaY)
 | 
						|
    {
 | 
						|
        for(int j=-1; j<5; j++)
 | 
						|
        {
 | 
						|
            for(int i=-1; i<4; i++)
 | 
						|
            {
 | 
						|
                int x = vgaX*3 + i;
 | 
						|
                int y = vgaY*4 + j;
 | 
						|
                restoreReticlePixel(x, y);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    void resetVTable(void)
 | 
						|
    {
 | 
						|
        for(int i=0; i<GIGA_HEIGHT; i++)
 | 
						|
        {
 | 
						|
            Cpu::setRAM(uint16_t(GIGA_VTABLE + i*2), uint8_t((GIGA_VRAM >>8) + i));
 | 
						|
            Cpu::setRAM(uint16_t(GIGA_VTABLE + 1 + i*2), 0x00);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    void refreshTimingPixel(const Cpu::State& S, int vgaX, int pixelY, uint32_t colour, bool debugging)
 | 
						|
    {
 | 
						|
        UNREFERENCED_PARAM(S);
 | 
						|
 | 
						|
        _hlineTiming[pixelY % GIGA_HEIGHT] = colour;
 | 
						|
 | 
						|
        if(debugging) return;
 | 
						|
 | 
						|
        uint32_t screen = (vgaX % (GIGA_WIDTH + 1))*3 + (pixelY % GIGA_HEIGHT)*4*SCREEN_WIDTH;
 | 
						|
        _pixels[screen + 0 + 0*SCREEN_WIDTH] = colour; _pixels[screen + 1 + 0*SCREEN_WIDTH] = colour; _pixels[screen + 2 + 0*SCREEN_WIDTH] = colour;
 | 
						|
        _pixels[screen + 0 + 1*SCREEN_WIDTH] = colour; _pixels[screen + 1 + 1*SCREEN_WIDTH] = colour; _pixels[screen + 2 + 1*SCREEN_WIDTH] = colour;
 | 
						|
        _pixels[screen + 0 + 2*SCREEN_WIDTH] = colour; _pixels[screen + 1 + 2*SCREEN_WIDTH] = colour; _pixels[screen + 2 + 2*SCREEN_WIDTH] = colour;
 | 
						|
        _pixels[screen + 0 + 3*SCREEN_WIDTH] = 0x00;   _pixels[screen + 1 + 3*SCREEN_WIDTH] = 0x00;   _pixels[screen + 2 + 3*SCREEN_WIDTH] = 0x00;
 | 
						|
    }
 | 
						|
 | 
						|
    void refreshPixel(const Cpu::State& S, int vgaX, int vgaY)
 | 
						|
    {
 | 
						|
        uint32_t colour = _colours[S._OUT & (COLOUR_PALETTE - 1)];
 | 
						|
        uint32_t address = (vgaX % GIGA_WIDTH)*3 + (vgaY % SCREEN_HEIGHT)*SCREEN_WIDTH;
 | 
						|
        _pixels[address + 0] = colour;
 | 
						|
        _pixels[address + 1] = colour;
 | 
						|
        _pixels[address + 2] = colour;
 | 
						|
    }
 | 
						|
 | 
						|
    void refreshScreen(void)
 | 
						|
    {
 | 
						|
        uint8_t offsetx = 0;
 | 
						|
 | 
						|
        for (int y = 0; y<GIGA_HEIGHT; y++)
 | 
						|
        {
 | 
						|
            offsetx += Cpu::getRAM(uint16_t(GIGA_VTABLE + 1 + y * 2));
 | 
						|
 | 
						|
            for (int x = 0; x <= GIGA_WIDTH; x++)
 | 
						|
            {
 | 
						|
                uint16_t address = (Cpu::getRAM(uint16_t(GIGA_VTABLE + y * 2)) << 8) + ((offsetx + x) & 0xFF);
 | 
						|
                uint32_t colour = (x < GIGA_WIDTH) ? _colours[Cpu::getRAM(address) & (COLOUR_PALETTE - 1)] : _hlineTiming[y];
 | 
						|
                uint32_t screen = (y * 4 % SCREEN_HEIGHT)*SCREEN_WIDTH + (x * 3 % SCREEN_WIDTH);
 | 
						|
 | 
						|
                _pixels[screen + 0 + 0 * SCREEN_WIDTH] = colour; _pixels[screen + 1 + 0 * SCREEN_WIDTH] = colour; _pixels[screen + 2 + 0 * SCREEN_WIDTH] = colour;
 | 
						|
                _pixels[screen + 0 + 1 * SCREEN_WIDTH] = colour; _pixels[screen + 1 + 1 * SCREEN_WIDTH] = colour; _pixels[screen + 2 + 1 * SCREEN_WIDTH] = colour;
 | 
						|
                _pixels[screen + 0 + 2 * SCREEN_WIDTH] = colour; _pixels[screen + 1 + 2 * SCREEN_WIDTH] = colour; _pixels[screen + 2 + 2 * SCREEN_WIDTH] = colour;
 | 
						|
                _pixels[screen + 0 + 3 * SCREEN_WIDTH] = 0x00;   _pixels[screen + 1 + 3 * SCREEN_WIDTH] = 0x00;   _pixels[screen + 2 + 3 * SCREEN_WIDTH] = 0x00;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    void clearScreen(uint32_t colour)
 | 
						|
    {
 | 
						|
        for(int y=0; y<SCREEN_HEIGHT; y++)
 | 
						|
        {
 | 
						|
            for(int x=0; x<SCREEN_WIDTH*3/4; x++)
 | 
						|
            {
 | 
						|
                _pixels[y*SCREEN_WIDTH + x] = colour;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    void rectFill(int x0, int y0, int x1, int y1, uint32_t colour)
 | 
						|
    {
 | 
						|
        x0 *= 3;
 | 
						|
        x1 *= 3;
 | 
						|
        y0 *= 4;
 | 
						|
        y1 *= 4;
 | 
						|
        for(int y=y0; y<=y1; y++)
 | 
						|
        {
 | 
						|
            for(int x=x0; x<=x1; x++)
 | 
						|
            {
 | 
						|
                _pixels[y*SCREEN_WIDTH + x] = colour;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    void pixelReticle(const Cpu::State& S, int vgaX, int vgaY)
 | 
						|
    {
 | 
						|
        // Draw pixel reticle, but only for active pixels
 | 
						|
        if(S._PC >= 0x020D  &&  S._PC <= 0x02AD)
 | 
						|
        {
 | 
						|
            if(vgaX > 0) restoreReticle(vgaX - 1, vgaY/4);
 | 
						|
            if(vgaX < HPIXELS_END - HPIXELS_START) drawReticle(vgaX, vgaY/4);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    void drawPixel(uint8_t x, uint8_t y, uint32_t colour)
 | 
						|
    {
 | 
						|
        x = x % GIGA_WIDTH;
 | 
						|
        y = y % GIGA_HEIGHT;
 | 
						|
        uint32_t screen = x*3 + y*4*SCREEN_WIDTH;
 | 
						|
 | 
						|
        _pixels[screen + 0 + 0*SCREEN_WIDTH] = colour; _pixels[screen + 1 + 0*SCREEN_WIDTH] = colour; _pixels[screen + 2 + 0*SCREEN_WIDTH] = colour;
 | 
						|
        _pixels[screen + 0 + 1*SCREEN_WIDTH] = colour; _pixels[screen + 1 + 1*SCREEN_WIDTH] = colour; _pixels[screen + 2 + 1*SCREEN_WIDTH] = colour;
 | 
						|
        _pixels[screen + 0 + 2*SCREEN_WIDTH] = colour; _pixels[screen + 1 + 2*SCREEN_WIDTH] = colour; _pixels[screen + 2 + 2*SCREEN_WIDTH] = colour;
 | 
						|
        _pixels[screen + 0 + 3*SCREEN_WIDTH] = 0x00;   _pixels[screen + 1 + 3*SCREEN_WIDTH] = 0x00;   _pixels[screen + 2 + 3*SCREEN_WIDTH] = 0x00;
 | 
						|
    }
 | 
						|
 | 
						|
    void drawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint32_t colour)
 | 
						|
    {
 | 
						|
        int16_t sx = x2 - x1;
 | 
						|
        int16_t sy = y2 - y1;
 | 
						|
        int h = sy;
 | 
						|
        int16_t dx1 = 1, dx2 = 1, dy1 = 1, dy2 = 0;
 | 
						|
 | 
						|
        if(sx & 0x8000)
 | 
						|
        {
 | 
						|
            dx1 = -1;
 | 
						|
            dx2 = -1;
 | 
						|
            sx = 0 - sx;
 | 
						|
        }
 | 
						|
 | 
						|
        if(sy & 0x8000)
 | 
						|
        {
 | 
						|
            dy1 = -1;
 | 
						|
            sy = 0 - sy;
 | 
						|
            if(sx < sy) dy2 = -1;
 | 
						|
        }
 | 
						|
 | 
						|
        if(sx < sy) 
 | 
						|
        {
 | 
						|
            dx2 = 0;
 | 
						|
            std::swap(sx, sy);
 | 
						|
            if(h > 0) dy2 = 1;
 | 
						|
        }
 | 
						|
 | 
						|
        int16_t numerator = sx >> 1;
 | 
						|
        int16_t xy1 = x1 | (y1<<8);
 | 
						|
        int16_t xy2 = x2 | (y2<<8);
 | 
						|
        int16_t dxy1 = dx1 + (dy1<<8);
 | 
						|
        int16_t dxy2 = dx2 + (dy2<<8);
 | 
						|
 | 
						|
        for(uint16_t i=0; i<=sx/2; i++) 
 | 
						|
        {
 | 
						|
            drawPixel(uint8_t(xy1), uint8_t(xy1>>8), colour);
 | 
						|
            drawPixel(uint8_t(xy2), uint8_t(xy2>>8), colour);
 | 
						|
            numerator += sy;
 | 
						|
            if(numerator > sx) 
 | 
						|
            {
 | 
						|
                numerator -= sx;
 | 
						|
                xy1 += dxy1;
 | 
						|
                xy2 -= dxy1;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                xy1 += dxy2;
 | 
						|
                xy2 -= dxy2;
 | 
						|
            }
 | 
						|
        }     
 | 
						|
    }
 | 
						|
 | 
						|
    void drawLeds(void)
 | 
						|
    {
 | 
						|
        for(int i=0; i<NUM_LEDS; i++)
 | 
						|
        {
 | 
						|
            int mask = 1 << (NUM_LEDS-1 - i);
 | 
						|
            int state = Cpu::getXOUT() & mask;
 | 
						|
            uint32_t colour = state ? 0xFF00FF00 : 0xFF770000;
 | 
						|
 | 
						|
            int address = int(float(SCREEN_WIDTH) * 0.866f) + i*NUM_LEDS + 3*SCREEN_WIDTH;
 | 
						|
            _pixels[address + 0] = colour;
 | 
						|
            _pixels[address + 1] = colour;
 | 
						|
            _pixels[address + 2] = colour;
 | 
						|
            address += SCREEN_WIDTH;
 | 
						|
            _pixels[address + 0] = colour;
 | 
						|
            _pixels[address + 1] = colour;
 | 
						|
            _pixels[address + 2] = colour;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Simple text routine, font is a non proportional 6*8 font loaded from a 96*48 BMP file
 | 
						|
    bool drawText(const std::string& text, uint32_t* pixels, int x, int y, uint32_t fgColour, bool invert, int invertSize, int invertPos, 
 | 
						|
                  uint32_t bgColour, bool colourKey, int numChars, bool fullscreen, uint32_t commentColour, uint32_t sectionColour)
 | 
						|
    {
 | 
						|
        if(!fullscreen)
 | 
						|
        {
 | 
						|
            x += UI_START_X;
 | 
						|
            y += UI_START_Y;
 | 
						|
        }
 | 
						|
        if(x<0 || x>=SCREEN_WIDTH || y<0 || y>=SCREEN_HEIGHT) return false;
 | 
						|
 | 
						|
        uint32_t* fontPixels = (uint32_t*)_fontSurface->pixels;
 | 
						|
        numChars = (numChars == -1) ? int(text.size()) : numChars;
 | 
						|
        for(int i=0; i<numChars; i++)
 | 
						|
        {
 | 
						|
            if(sectionColour)
 | 
						|
            {
 | 
						|
                static bool useSectionColour = false;
 | 
						|
                if(x == 0) useSectionColour = false;
 | 
						|
                if(text.c_str()[i] == '[') useSectionColour = true;
 | 
						|
                if(text.c_str()[i] == ']') useSectionColour = false;
 | 
						|
                if(useSectionColour) fgColour = sectionColour;
 | 
						|
            }
 | 
						|
            if(commentColour)
 | 
						|
            {
 | 
						|
                static bool useCommentColour = false;
 | 
						|
                if(x == 0) useCommentColour = false;
 | 
						|
                if(text.c_str()[i] == ';') useCommentColour = true;
 | 
						|
                if(useCommentColour) fgColour = commentColour;
 | 
						|
            }
 | 
						|
 | 
						|
            uint8_t chr = text.c_str()[i] - 32;
 | 
						|
            uint8_t row = chr % CHARS_PER_ROW;
 | 
						|
            uint8_t col = chr / CHARS_PER_ROW;
 | 
						|
 | 
						|
            int srcx = row*FONT_WIDTH, srcy = col*FONT_HEIGHT;
 | 
						|
            if(srcx+FONT_WIDTH-1>=FONT_BMP_WIDTH || srcy+FONT_HEIGHT-1>=FONT_BMP_HEIGHT) return false;
 | 
						|
 | 
						|
            int dstx = x + i*FONT_WIDTH, dsty = y;
 | 
						|
            if(dstx+FONT_WIDTH-1>=SCREEN_WIDTH-FONT_WIDTH || dsty+FONT_HEIGHT-1>=SCREEN_HEIGHT) return false;
 | 
						|
 | 
						|
            for(int j=0; j<FONT_WIDTH; j++)
 | 
						|
            {
 | 
						|
                for(int k=0; k<FONT_HEIGHT; k++)
 | 
						|
                {
 | 
						|
                    int fontAddress = (srcx + j)  +  (srcy + k)*FONT_BMP_WIDTH;
 | 
						|
                    int pixelAddress = (dstx + j)  +  (dsty + k)*SCREEN_WIDTH;
 | 
						|
                    uint32_t fontPixel = fontPixels[fontAddress] & 0x00FFFFFF;
 | 
						|
                    if((invert  &&  i>=invertPos  &&  i<invertPos+invertSize) ? !fontPixel : fontPixel)
 | 
						|
                    {
 | 
						|
                        pixels[pixelAddress] = 0xFF000000 | fgColour;
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        if(!colourKey) pixels[pixelAddress] = 0xFF000000 | bgColour;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    bool drawText(const std::string& text, int x, int y, uint32_t fgColour, bool invert, int invertSize, int invertPos)
 | 
						|
    {
 | 
						|
        return drawText(text, _pixels, x, y, fgColour, invert, invertSize, invertPos, 0x00000000, true, -1, true, 0x00000000, 0x00000000);
 | 
						|
    }
 | 
						|
 | 
						|
    bool drawMenuItem(const std::string& text, int x, int y, uint32_t fgColour, bool invert, int invertSize, uint32_t bgColour)
 | 
						|
    {
 | 
						|
        return drawText(text, _pixels, x, y, fgColour, invert, invertSize, 0, bgColour, false, -1, true, 0x00000000, 0x00000000);
 | 
						|
    }
 | 
						|
 | 
						|
    bool drawDialog(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t bgColour, uint32_t bdColour)
 | 
						|
    {
 | 
						|
        Graphics::drawLine(x,   y,   x+w, y,       bdColour);
 | 
						|
        Graphics::drawLine(x,   y+h+1, x+w, y+h+1, bdColour);
 | 
						|
        Graphics::drawLine(x,   y,   x,   y+h+1,   bdColour);
 | 
						|
        Graphics::drawLine(x+w, y,   x+w, y+h+1,   bdColour);
 | 
						|
        for(int16_t yy=y+1; yy<=y+h; yy++)
 | 
						|
        {
 | 
						|
            Graphics::drawLine(x+1, yy, x+w-1, yy, bgColour);
 | 
						|
        }
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    bool drawDialogItem(const std::string& text, int x, int y, uint32_t fgColour, uint32_t bdColour)
 | 
						|
    {
 | 
						|
        return Graphics::drawText(text, _pixels, x, y, fgColour, false, 0, 0, bdColour, false, -1, true, 0x00000000, 0x00000000);
 | 
						|
    }
 | 
						|
 | 
						|
    void drawDigitBox(uint8_t digit, int x, int y, uint32_t colour)
 | 
						|
    {
 | 
						|
        x += UI_START_X;
 | 
						|
        y += UI_START_Y;
 | 
						|
        if(x<0 || x>=SCREEN_WIDTH || y<0 || y>=SCREEN_HEIGHT) return;
 | 
						|
 | 
						|
        uint32_t pixelAddress = x + digit*FONT_WIDTH + y*SCREEN_WIDTH;
 | 
						|
 | 
						|
        pixelAddress += (FONT_HEIGHT-1)*SCREEN_WIDTH;
 | 
						|
        for(int i=0; i<FONT_WIDTH; i++) _pixels[pixelAddress+i] = colour;
 | 
						|
    }
 | 
						|
 | 
						|
    float powStepRising(float x, float a, float b, float p)
 | 
						|
    {
 | 
						|
        float f = std::min(std::max(x, a), b);
 | 
						|
        f = (f - a) / (b - a);
 | 
						|
        return powf(f, p);
 | 
						|
    }
 | 
						|
    float powStepFalling(float x, float a, float b, float p)
 | 
						|
    {
 | 
						|
        float f = std::max(std::min(x, a), b);
 | 
						|
        f = (f - a) / (b - a);
 | 
						|
        return powf(f, p);
 | 
						|
    }
 | 
						|
    void drawUsageBar(float usage, int x, int y, int w, int h)
 | 
						|
    {
 | 
						|
        int ww = int(float(w)*usage);
 | 
						|
 | 
						|
        x += UI_START_X;
 | 
						|
        y += UI_START_Y;
 | 
						|
 | 
						|
        for(int j=y; j<(y + h); j++)
 | 
						|
        {
 | 
						|
            for(int i=x; i<(x + ww); i++)
 | 
						|
            {
 | 
						|
                float normalised = float(i - x) / float(w);
 | 
						|
                uint8_t red = uint8_t(powStepRising(normalised, 0.0f, 0.5f, 1.0f) * 255.0f);
 | 
						|
                uint8_t grn = uint8_t(powStepFalling(normalised, 1.0f, 0.5f, 1.0f) * 255.0f);
 | 
						|
                int pixelAddress = i + j*SCREEN_WIDTH;
 | 
						|
                _pixels[pixelAddress] = (red <<16) + (grn <<8);
 | 
						|
            }
 | 
						|
            for(int i=(x + ww); i<(x + w); i++)
 | 
						|
            {
 | 
						|
                int pixelAddress = i + j*SCREEN_WIDTH;
 | 
						|
                _pixels[pixelAddress] = 0x00400000;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    void drawUploadBar(float upload)
 | 
						|
    {
 | 
						|
        if(!_enableUploadBar  ||  _uploadCursorY == -1) return;
 | 
						|
 | 
						|
        char uploadPercentage[UI_TEXT_SIZE+2] = "";
 | 
						|
        std::string uploadFilename = _uploadFilename;
 | 
						|
        if(uploadFilename.size() < UI_TEXT_SIZE+1) uploadFilename.append(UI_TEXT_SIZE+1 - uploadFilename.size(), ' ');
 | 
						|
        if(upload < 1.0f)
 | 
						|
        {
 | 
						|
            strcpy(uploadPercentage, uploadFilename.substr(0, UI_TEXT_SIZE+1).c_str());
 | 
						|
            sprintf(&uploadPercentage[UI_TEXT_SIZE+1 - 6], " %3d%%\r", int(upload * 100.0f));
 | 
						|
        }
 | 
						|
 | 
						|
        drawText(uploadPercentage, _pixels, HEX_START_X, int(FONT_CELL_Y*4.4) + _uploadCursorY*FONT_CELL_Y, 0xFFB0B0B0, true, UI_TEXT_SIZE+1, 0, 0x00000000, false, UI_TEXT_SIZE+1);
 | 
						|
    }
 | 
						|
 | 
						|
    void renderText(void)
 | 
						|
    {
 | 
						|
        char str[32];
 | 
						|
 | 
						|
        sprintf(str, "CPU        A:%04X B:%04X", 0x200, 0x220);
 | 
						|
        drawText(std::string(str), _pixels, 0, FONT_CELL_Y*2, 0xFFFFFFFF, false, 0, false);
 | 
						|
        sprintf(str, "%05.1f%%", Cpu::getvCpuUtilisation() * 100.0);
 | 
						|
        drawUsageBar(Cpu::getvCpuUtilisation(), FONT_WIDTH*4 - 3, FONT_CELL_Y*2 - 3, FONT_WIDTH*6 + 5, FONT_HEIGHT + 5);
 | 
						|
        drawText(std::string(str), _pixels, FONT_WIDTH*4, FONT_CELL_Y*2, 0x80808080, false, 0, 0, 0x00000000, true);
 | 
						|
 | 
						|
        //drawText(std::string("LEDS:"), _pixels, 0, 0, 0xFFFFFFFF, false, 0);
 | 
						|
        sprintf(str, "FPS %5.1f  XOUT:%02X IN:%02X", 1.0f / Timing::getFrameTime(), Cpu::getXOUT(), Cpu::getIN());
 | 
						|
        drawText(std::string(str), _pixels, 0, FONT_CELL_Y, 0xFFFFFFFF, false, 0);
 | 
						|
        drawText("M:              R:", _pixels, 0, 472 - FONT_CELL_Y, 0xFFFFFFFF, false, 0);
 | 
						|
 | 
						|
        switch(Editor::getEditorMode())
 | 
						|
        {
 | 
						|
            case Editor::Hex:   (Editor::getSingleStepEnabled()) ? strcpy(str, "Debug ") : strcpy(str, "Hex   "); break;
 | 
						|
            case Editor::Rom:   (Editor::getSingleStepEnabled()) ? strcpy(str, "Debug ") : strcpy(str, "Rom   "); break;
 | 
						|
            case Editor::Load:  (Editor::getSingleStepEnabled()) ? strcpy(str, "Debug ") : strcpy(str, "Load  "); break;
 | 
						|
            case Editor::Dasm:  (Editor::getSingleStepEnabled()) ? strcpy(str, "Debug ") : strcpy(str, "Dasm  "); break;
 | 
						|
            case Editor::Term:  (Editor::getSingleStepEnabled()) ? strcpy(str, "Debug ") : strcpy(str, "Term  "); break;
 | 
						|
            case Editor::Image: (Editor::getSingleStepEnabled()) ? strcpy(str, "Debug ") : strcpy(str, "Image "); break;
 | 
						|
            case Editor::Audio: (Editor::getSingleStepEnabled()) ? strcpy(str, "Debug ") : strcpy(str, "Audio "); break;
 | 
						|
 | 
						|
            default: strcpy(str, "     ");
 | 
						|
        }
 | 
						|
        drawText(std::string(str), _pixels, 12, 472 - FONT_CELL_Y, 0xFF00FF00, false, 0);
 | 
						|
 | 
						|
        switch(Editor::getKeyboardMode())
 | 
						|
        {
 | 
						|
            case Editor::Giga:   strcpy(str, "Kbd   "); break;
 | 
						|
            case Editor::PS2:    strcpy(str, "PS2   "); break;
 | 
						|
            case Editor::HwGiga: strcpy(str, "HwKbd "); break;
 | 
						|
            case Editor::HwPS2:  strcpy(str, "HwPS2 "); break;
 | 
						|
 | 
						|
            default: strcpy(str, "     ");
 | 
						|
        }
 | 
						|
        drawText("K:", _pixels, 48, 472 - FONT_CELL_Y, 0xFFFFFFFF, false, 0);
 | 
						|
        drawText(std::string(str), _pixels, 60, 472 - FONT_CELL_Y, 0xFF00FF00, false, 0);
 | 
						|
 | 
						|
        sprintf(str, "%-5d", Memory::getSizeFreeRAM());
 | 
						|
        drawText(std::string(str), _pixels, RAM_START, 472 - FONT_CELL_Y, 0xFF00FF00, false, 0);
 | 
						|
        sprintf(str, " ROM %02X", Cpu::getRomType());
 | 
						|
        drawText(std::string(VERSION_STR) + std::string(str), _pixels, 0, 472, 0xFFFFFFFF, false, 0);
 | 
						|
    }
 | 
						|
 | 
						|
    int renderHexMonitor(bool onHex)
 | 
						|
    {
 | 
						|
        char str[32] = "";
 | 
						|
        int hexDigitIndex = -1;
 | 
						|
 | 
						|
        switch(Editor::getMemoryMode())
 | 
						|
        {
 | 
						|
            case Editor::RAM:  drawText("RAM:       Vars:", _pixels, 0, FONT_CELL_Y*3, 0xFFFFFFFF, false, 0); break;
 | 
						|
            case Editor::ROM0: drawText("ROM0:      Vars:", _pixels, 0, FONT_CELL_Y*3, 0xFFFFFFFF, false, 0); break;
 | 
						|
            case Editor::ROM1: drawText("ROM1:      Vars:", _pixels, 0, FONT_CELL_Y*3, 0xFFFFFFFF, false, 0); break;
 | 
						|
 | 
						|
            default: break;
 | 
						|
        }
 | 
						|
 | 
						|
        // 8 * 32 hex display of memory
 | 
						|
        uint16_t hexAddress = Editor::getHexBaseAddress();
 | 
						|
        uint16_t cursorAddress = Editor::getHexBaseAddress();
 | 
						|
        for(int j=0; j<HEX_CHARS_Y; j++)
 | 
						|
        {
 | 
						|
            for(int i=0; i<HEX_CHARS_X; i++)
 | 
						|
            {
 | 
						|
                uint8_t value = 0;
 | 
						|
                switch(Editor::getMemoryMode())
 | 
						|
                {
 | 
						|
                    case Editor::RAM:  value = Cpu::getRAM(hexAddress);    break;
 | 
						|
                    case Editor::ROM0: value = Cpu::getROM(hexAddress, 0); break;
 | 
						|
                    case Editor::ROM1: value = Cpu::getROM(hexAddress, 1); break;
 | 
						|
 | 
						|
                    default: break;
 | 
						|
                }
 | 
						|
                sprintf(str, "%02X ", value);
 | 
						|
                bool onCursor = (i == Editor::getCursorX()  &&  j == Editor::getCursorY());
 | 
						|
                if(onCursor) hexDigitIndex = j*HEX_CHARS_X + i;
 | 
						|
                uint32_t colour = (Editor::getHexEdit() && Editor::getMemoryMode() == Editor::RAM && onCursor) ? 0xFF00FF00 : 0xFFB0B0B0;
 | 
						|
                drawText(std::string(str), _pixels, HEX_START_X + i*HEX_CHAR_WIDE, FONT_CELL_Y*4 + j*(FONT_HEIGHT+FONT_GAP_Y), colour, onCursor, 2);
 | 
						|
                if(onCursor) cursorAddress = hexAddress;
 | 
						|
                hexAddress = (Editor::getMemoryMode() == Editor::RAM) ? (hexAddress + 1) & (Memory::getSizeRAM() - 1) : hexAddress + 1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        sprintf(str, "%04X", cursorAddress);
 | 
						|
        uint32_t colour = (Editor::getHexEdit() && onHex) ? 0xFF00FF00 : 0xFFFFFFFF;
 | 
						|
        drawText(std::string(str), _pixels, HEX_START, FONT_CELL_Y*3, colour, onHex, 4);
 | 
						|
 | 
						|
        // Edit digit select for monitor
 | 
						|
        if(Editor::getHexEdit())
 | 
						|
        {
 | 
						|
            // Draw memory digit selection box                
 | 
						|
            if(Editor::getCursorY() >= 0  &&  Editor::getCursorY() < 32  &&  Editor::getCursorX() < 8  &&  Editor::getMemoryMode() == Editor::RAM)
 | 
						|
            {
 | 
						|
                drawDigitBox(Editor::getMemoryDigit(), HEX_START_X + Editor::getCursorX()*HEX_CHAR_WIDE, FONT_CELL_Y*4 + Editor::getCursorY()*FONT_CELL_Y, 0xFFFF00FF);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return hexDigitIndex;
 | 
						|
    }
 | 
						|
 | 
						|
    void renderRomBrowser(void)
 | 
						|
    {
 | 
						|
        drawText("ROM:       Vars:", _pixels, 0, FONT_CELL_Y*3, 0xFFFFFFFF, false, 0);
 | 
						|
 | 
						|
        // Clear window
 | 
						|
        for(int i=0; i<HEX_CHARS_Y; i++) drawText("                       ", _pixels, HEX_START_X, FONT_CELL_Y*4 + i*FONT_CELL_Y, 0xFFFFFFFF, false, 0);
 | 
						|
 | 
						|
        // ROM list
 | 
						|
        for(int i=0; i<HEX_CHARS_Y; i++)
 | 
						|
        {
 | 
						|
            bool onCursor = (i == Editor::getCursorY());
 | 
						|
            int index = Editor::getRomEntriesIndex() + i;
 | 
						|
            if(index >= int(Editor::getRomEntriesSize())) break;
 | 
						|
            uint32_t colour = (i < NUM_INT_ROMS) ? 0xFFB0B0B0 : 0xFFFFFFFF;
 | 
						|
            if(i == Cpu::getRomIndex()) drawText("*", _pixels, HEX_START_X, FONT_CELL_Y*4 + i*FONT_CELL_Y,  0xFFD0D000, onCursor, UI_TEXT_SIZE, 0, 0x00000000, false, UI_TEXT_SIZE);
 | 
						|
            drawText(*Editor::getRomEntryName(index), _pixels, HEX_START_X + 6, FONT_CELL_Y*4 + i*FONT_CELL_Y, colour, onCursor, UI_TEXT_SIZE, 0, 0x00000000, false, UI_TEXT_SIZE);
 | 
						|
        }
 | 
						|
 | 
						|
        // ROM type
 | 
						|
        char str[32] = "";
 | 
						|
        (Editor::getCursorY() < 0  ||  Editor::getCursorY() >= Editor::getRomEntriesSize()) ? sprintf(str, "  ") : sprintf(str, "%02X", Editor::getRomEntryType(Editor::getCursorY()));
 | 
						|
        drawText(std::string(str), _pixels, HEX_START-6, FONT_CELL_Y*3, 0xFFFFFFFF, false, 4);
 | 
						|
    }
 | 
						|
 | 
						|
    void renderLoadBrowser(bool onHex)
 | 
						|
    {
 | 
						|
        uint16_t hexLoadAddress = (Editor::getEditorMode() == Editor::Load) ? Editor::getLoadBaseAddress() : Editor::getHexBaseAddress();
 | 
						|
 | 
						|
        drawText("Load:      Vars:", _pixels, 0, FONT_CELL_Y*3, 0xFFFFFFFF, false, 0);
 | 
						|
 | 
						|
        // Clear window
 | 
						|
        for(int i=0; i<HEX_CHARS_Y; i++) drawText("                       ", _pixels, HEX_START_X, FONT_CELL_Y*4 + i*FONT_CELL_Y, 0xFFFFFFFF, false, 0);
 | 
						|
 | 
						|
        // File list
 | 
						|
        for(int i=0; i<HEX_CHARS_Y; i++)
 | 
						|
        {
 | 
						|
            bool onCursor = (i == Editor::getCursorY());
 | 
						|
            int index = Editor::getFileEntriesIndex() + i;
 | 
						|
            if(index >= int(Editor::getFileEntriesSize())) break;
 | 
						|
            uint32_t colour = (Editor::getFileEntryType(index) == Editor::Dir) ? 0xFFB0B0B0 : 0xFFFFFFFF;
 | 
						|
            drawText(*Editor::getFileEntryName(index), _pixels, HEX_START_X, FONT_CELL_Y*4 + i*FONT_CELL_Y, colour, onCursor, UI_TEXT_SIZE, 0, 0x00000000, false, UI_TEXT_SIZE);
 | 
						|
        }
 | 
						|
 | 
						|
        // Load address
 | 
						|
        char str[32] = "";
 | 
						|
        sprintf(str, "%04X", hexLoadAddress);
 | 
						|
        uint32_t colour = (Editor::getHexEdit() && onHex) ? 0xFF00FF00 : 0xFFFFFFFF;
 | 
						|
        drawText(std::string(str), _pixels, HEX_START, FONT_CELL_Y*3, colour, onHex, 4);
 | 
						|
    }
 | 
						|
 | 
						|
    void renderDisassembler(bool onHex)
 | 
						|
    {
 | 
						|
        char str[32] = "";
 | 
						|
 | 
						|
        (Editor::getMemoryMode() == Editor::RAM) ? Assembler::disassemble(Editor::getVpcBaseAddress()) : Assembler::disassemble(Editor::getNtvBaseAddress());
 | 
						|
 | 
						|
        //sprintf(str, "%d\n", Editor::getVpcBreakpointsSize());
 | 
						|
        //sprintf(str, "%d\n", Editor::getNtvBreakpointsSize());
 | 
						|
        //fprintf(stderr, str);
 | 
						|
 | 
						|
        // Clear window
 | 
						|
        for(int i=0; i<HEX_CHARS_Y; i++) drawText("                       ", _pixels, HEX_START_X, FONT_CELL_Y*4 + i*FONT_CELL_Y, 0xFFFFFFFF, false, 0);
 | 
						|
 | 
						|
        for(int i=0; i<Assembler::getDisassembledCodeSize(); i++)
 | 
						|
        {
 | 
						|
            bool onPC = false;
 | 
						|
            if(Editor::getSingleStepEnabled())
 | 
						|
            {
 | 
						|
                if(Editor::getMemoryMode() == Editor::RAM)
 | 
						|
                {
 | 
						|
                    onPC = (Assembler::getDisassembledCode(i)->_address == Cpu::getVPC());
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    onPC = (Assembler::getDisassembledCode(i)->_address == Cpu::getStateS()._PC);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            // Program counter icon in debug mode
 | 
						|
            bool onCursor = (i == Editor::getCursorY());
 | 
						|
            if(onPC) drawText(">", _pixels, HEX_START_X, FONT_CELL_Y*4 + i*FONT_CELL_Y,  0xFF00FF00, onCursor, UI_TEXT_SIZE, 0, 0x00000000, false, UI_TEXT_SIZE);
 | 
						|
 | 
						|
            // Breakpoint icons
 | 
						|
            if(Editor::getMemoryMode() == Editor::RAM)
 | 
						|
            {
 | 
						|
                for(int j=0; j<Editor::getVpcBreakPointsSize(); j++)
 | 
						|
                {
 | 
						|
                    if(Assembler::getDisassembledCode(i)->_address == Editor::getVpcBreakPointAddress(j)  &&  Editor::getSingleStepEnabled())
 | 
						|
                    {
 | 
						|
                        drawText("*", _pixels, HEX_START_X, FONT_CELL_Y*4 + i*FONT_CELL_Y,  0xFFC000C0, onCursor, UI_TEXT_SIZE, 0, 0x00000000, false, UI_TEXT_SIZE);
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                for(int j=0; j<Editor::getNtvBreakPointsSize(); j++)
 | 
						|
                {
 | 
						|
                    if(Assembler::getDisassembledCode(i)->_address == Editor::getNtvBreakPointAddress(j)  &&  Editor::getSingleStepEnabled())
 | 
						|
                    {
 | 
						|
                        drawText("*", _pixels, HEX_START_X, FONT_CELL_Y*4 + i*FONT_CELL_Y,  0xFFC0C000, onCursor, UI_TEXT_SIZE, 0, 0x00000000, false, UI_TEXT_SIZE);
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            // Mnemonic, highlight if on vPC and show cursor in debug mode
 | 
						|
            uint32_t colour = (onPC) ? 0xFFFFFFFF : 0xFFB0B0B0;
 | 
						|
            bool highlight = (onCursor || onPC)  &&  (Editor::getSingleStepEnabled());
 | 
						|
            drawText(Assembler::getDisassembledCode(i)->_text, _pixels, HEX_START_X+6, FONT_CELL_Y*4 + i*FONT_CELL_Y, colour, highlight, UI_TEXT_SIZE, 0, 0x00000000, false, UI_TEXT_SIZE);
 | 
						|
        }
 | 
						|
 | 
						|
        switch(Editor::getMemoryMode())
 | 
						|
        {
 | 
						|
            case Editor::RAM:  drawText("RAM:       Vars:", _pixels, 0, FONT_CELL_Y*3, 0xFFFFFFFF, false, 0); break;
 | 
						|
            case Editor::ROM0: drawText("ROM:       Vars:", _pixels, 0, FONT_CELL_Y*3, 0xFFFFFFFF, false, 0); break;
 | 
						|
            case Editor::ROM1: drawText("ROM:       Vars:", _pixels, 0, FONT_CELL_Y*3, 0xFFFFFFFF, false, 0); break;
 | 
						|
 | 
						|
            default: break;
 | 
						|
        }
 | 
						|
 | 
						|
        (Editor::getMemoryMode() == Editor::RAM) ? sprintf(str, "%04X", Editor::getVpcBaseAddress()) : sprintf(str, "%04X", Editor::getNtvBaseAddress());
 | 
						|
        uint32_t colour = (Editor::getHexEdit() && onHex) ? 0xFF00FF00 : 0xFFFFFFFF;
 | 
						|
        drawText(std::string(str), _pixels, HEX_START, FONT_CELL_Y*3, colour, onHex, 4);
 | 
						|
 | 
						|
        if(Editor::getMemoryMode() == Editor::RAM)
 | 
						|
        {
 | 
						|
            // Display vCPU registers
 | 
						|
            sprintf(str, "PC:%04X LR:%04X Fn:%04X", Cpu::getVPC(), Cpu::getRAM(0x001A) | (Cpu::getRAM(0x001B)<<8), Cpu::getRAM(0x0022) | (Cpu::getRAM(0x0023)<<8));
 | 
						|
            drawText(std::string(str), _pixels, HEX_START_X, int(FONT_CELL_Y*2.0) + FONT_CELL_Y*HEX_CHARS_Y, 0xFF00FFFF, false, 0);
 | 
						|
            sprintf(str, "AC:%04X SP:%04X Sr:%04X", Cpu::getRAM(0x0018) | (Cpu::getRAM(0x0019)<<8), Assembler::getvSpMin() | (Cpu::getRAM(0x001C)<<8), Cpu::getRAM(0x000F) | (Cpu::getRAM(0x0011)<<8));
 | 
						|
            drawText(std::string(str), _pixels, HEX_START_X, int(FONT_CELL_Y*3.0) + FONT_CELL_Y*HEX_CHARS_Y, 0xFF00FFFF, false, 0);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            // Display Native registers
 | 
						|
            sprintf(str, "PC:%04X  IR:%02X  OUT:%02X", Cpu::getStateS()._PC, Cpu::getStateT()._IR, Cpu::getStateT()._OUT);
 | 
						|
            drawText(std::string(str), _pixels, HEX_START_X, int(FONT_CELL_Y*2.0) + FONT_CELL_Y*HEX_CHARS_Y, 0xFF00FFFF, false, 0);
 | 
						|
            sprintf(str, "AC:%02X  X:%02X  Y:%02X  D:%02X", Cpu::getStateT()._AC, Cpu::getStateT()._X, Cpu::getStateT()._Y, Cpu::getStateT()._D);
 | 
						|
            drawText(std::string(str), _pixels, HEX_START_X, int(FONT_CELL_Y*3.0) + FONT_CELL_Y*HEX_CHARS_Y, 0xFF00FFFF, false, 0);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    void renderTextWindow(void)
 | 
						|
    {
 | 
						|
        char str[32] = "";
 | 
						|
 | 
						|
        int x, y, cy;
 | 
						|
        Editor::getMouseUiCursor(x, y, cy);
 | 
						|
        Editor::setCursorX(x);
 | 
						|
        Editor::setCursorY(cy);
 | 
						|
 | 
						|
        // Addresses
 | 
						|
        uint16_t cpuUsageAddressA = Editor::getCpuUsageAddressA();
 | 
						|
        uint16_t cpuUsageAddressB = Editor::getCpuUsageAddressB();
 | 
						|
        uint16_t varsAddress = Editor::getVarsBaseAddress();
 | 
						|
 | 
						|
        // Mouse cursor over vars
 | 
						|
        Editor::OnVarType onVarType = Editor::getOnVarType();
 | 
						|
        bool onHex   = (onVarType == Editor::OnHex);
 | 
						|
        bool onCpuA  = (onVarType == Editor::OnCpuA);
 | 
						|
        bool onCpuB  = (onVarType == Editor::OnCpuB);
 | 
						|
        bool onVars  = (onVarType == Editor::OnVars);
 | 
						|
        bool onWatch = (onVarType == Editor::OnWatch);
 | 
						|
        uint8_t onVarMask = uint8_t(onHex) | (uint8_t(onCpuA) <<1) | (uint8_t(onCpuB) <<2) | (uint8_t(onVars) <<3) | (uint8_t(onWatch) <<4);
 | 
						|
        static uint8_t onVarMaskPrev = onVarMask;
 | 
						|
 | 
						|
        // Text window
 | 
						|
        int hexDigitIndex = -1;
 | 
						|
        static int hexDigitIndexPrev = hexDigitIndex;
 | 
						|
        switch(Editor::getEditorMode())
 | 
						|
        {
 | 
						|
            case Editor::Hex:  hexDigitIndex = renderHexMonitor(onHex); break;
 | 
						|
            case Editor::Rom:  renderRomBrowser();                      break;
 | 
						|
            case Editor::Audio:
 | 
						|
            case Editor::Image:
 | 
						|
            case Editor::Load: renderLoadBrowser(onHex);                break;
 | 
						|
            case Editor::Dasm: renderDisassembler(onHex);               break;
 | 
						|
 | 
						|
            default: break;
 | 
						|
        }
 | 
						|
 | 
						|
        // Disable hex/var editing when mouse moves off a currently editing field
 | 
						|
        if(onVarMask != onVarMaskPrev  ||  hexDigitIndex != hexDigitIndexPrev) Editor::setHexEdit(false);
 | 
						|
        onVarMaskPrev = onVarMask;
 | 
						|
        hexDigitIndexPrev = hexDigitIndex;
 | 
						|
 | 
						|
        // Draw addresses
 | 
						|
        if(Editor::getSingleStepEnabled())
 | 
						|
        {
 | 
						|
            drawText("Watch:", _pixels, WATCH_START, FONT_CELL_Y*2, 0xFFFFFFFF, false, 0);
 | 
						|
            sprintf(str, "%04X   ", Editor::getSingleStepAddress());
 | 
						|
            uint32_t colour = (Editor::getHexEdit() && onWatch) ? 0xFF00FF00 : 0xFFFFFFFF;
 | 
						|
            drawText(str, _pixels, WATCH_START+36, FONT_CELL_Y*2, colour, onWatch, 4);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            sprintf(str, "%04X", cpuUsageAddressA);
 | 
						|
            uint32_t colourA = (Editor::getHexEdit() && onCpuA) ? 0xFF00FF00 : 0xFFFFFFFF;
 | 
						|
            drawText(std::string(str), _pixels, CPUA_START, FONT_CELL_Y*2, colourA, onCpuA, 4);
 | 
						|
            sprintf(str, "%04X", cpuUsageAddressB);
 | 
						|
            uint32_t colourB = (Editor::getHexEdit() && onCpuB) ? 0xFF00FF00 : 0xFFFFFFFF;
 | 
						|
            drawText(std::string(str), _pixels, CPUB_START, FONT_CELL_Y*2, colourB, onCpuB, 4);
 | 
						|
        }
 | 
						|
        sprintf(str, "%04X", varsAddress);
 | 
						|
        uint32_t colour = (Editor::getHexEdit() && onVars) ? 0xFF00FF00 : 0xFFFFFFFF;
 | 
						|
        drawText(std::string(str), _pixels, VAR_START, FONT_CELL_Y*3, colour, onVars, 4);
 | 
						|
 | 
						|
        // Edit digit select for addresses
 | 
						|
        if(Editor::getHexEdit())
 | 
						|
        {
 | 
						|
            // Draw address digit selections
 | 
						|
            if(onCpuA)       drawDigitBox(Editor::getAddressDigit(), CPUA_START,     FONT_CELL_Y*2, 0xFFFF00FF);
 | 
						|
            else if(onCpuB)  drawDigitBox(Editor::getAddressDigit(), CPUB_START,     FONT_CELL_Y*2, 0xFFFF00FF);
 | 
						|
            else if(onHex)   drawDigitBox(Editor::getAddressDigit(), HEX_START,      FONT_CELL_Y*3, 0xFFFF00FF);
 | 
						|
            else if(onVars)  drawDigitBox(Editor::getAddressDigit(), VAR_START,      FONT_CELL_Y*3, 0xFFFF00FF);
 | 
						|
            else if(onWatch) drawDigitBox(Editor::getAddressDigit(), WATCH_START+36, FONT_CELL_Y*2, 0xFFFF00FF);
 | 
						|
        }
 | 
						|
 | 
						|
        // 8 * 2 hex display of vCPU program variables
 | 
						|
        for(int j=0; j<2; j++)
 | 
						|
        {
 | 
						|
            for(int i=0; i<HEX_CHARS_X; i++)
 | 
						|
            {
 | 
						|
                sprintf(str, "%02X ", Cpu::getRAM(varsAddress++));
 | 
						|
                drawText(std::string(str), _pixels, HEX_START_X + i*HEX_CHAR_WIDE, int(FONT_CELL_Y*4.25) + FONT_CELL_Y*HEX_CHARS_Y + j*(FONT_HEIGHT+FONT_GAP_Y), 0xFF00FFFF, false, 0);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Upload bar
 | 
						|
        drawUploadBar(_uploadPercentage);
 | 
						|
 | 
						|
        // Page up/down icons
 | 
						|
        strcpy(str, "^");
 | 
						|
        drawText(std::string(str), _pixels, PAGEUP_START_X, PAGEUP_START_Y, 0xFF00FF00, Editor::getPageUpButton(), 1);
 | 
						|
        str[0] = 127; str[1] = 0;
 | 
						|
        drawText(std::string(str), _pixels, PAGEDN_START_X, PAGEDN_START_Y, 0xFF00FF00, Editor::getPageDnButton(), 1);
 | 
						|
 | 
						|
        // Delete icon, (currently only used for clearing breakpoints)
 | 
						|
        if(Editor::getEditorMode() == Editor::Dasm  &&  (Editor::getSingleStepEnabled()))
 | 
						|
        {
 | 
						|
            int numBrkPoints = (Editor::getMemoryMode() == Editor::RAM) ? Editor::getVpcBreakPointsSize() : Editor::getNtvBreakPointsSize();
 | 
						|
            sprintf(str, "%02d", numBrkPoints);
 | 
						|
            drawText(str, _pixels, DELALL_START_X-12, DELALL_START_Y, 0xFFFFFFFF, false, 0);
 | 
						|
            drawText("x", _pixels, DELALL_START_X, DELALL_START_Y, 0xFFFF0000, Editor::getDelAllButton(), 1);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            drawText("   ", _pixels, DELALL_START_X-12, DELALL_START_Y, 0, false, 0);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    void renderHelpScreen(void)
 | 
						|
    {
 | 
						|
        // Only display help screen if it is enabled or has alpha > 0
 | 
						|
        if(_displayHelpScreen  ||  _displayHelpScreenAlpha)
 | 
						|
        {
 | 
						|
            SDL_SetTextureAlphaMod(_helpTexture, _displayHelpScreenAlpha);
 | 
						|
            SDL_RenderCopy(_renderer, _helpTexture, NULL, NULL);
 | 
						|
            // Fade help screen in
 | 
						|
            if(_displayHelpScreen  &&  _displayHelpScreenAlpha < 220)
 | 
						|
            {
 | 
						|
                _displayHelpScreenAlpha += 10;
 | 
						|
                if(_displayHelpScreenAlpha > 220) _displayHelpScreenAlpha = 220;
 | 
						|
            }
 | 
						|
            // Fade help screen out
 | 
						|
            if(!_displayHelpScreen  &&  _displayHelpScreenAlpha > 0)
 | 
						|
            {
 | 
						|
                _displayHelpScreenAlpha -= 10;
 | 
						|
                if(_displayHelpScreenAlpha > 240) _displayHelpScreenAlpha = 0;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    void render(bool synchronise)
 | 
						|
    {
 | 
						|
        drawLeds();
 | 
						|
        renderText();
 | 
						|
        renderTextWindow();
 | 
						|
 | 
						|
        SDL_UpdateTexture(_screenTexture, NULL, _pixels, SCREEN_WIDTH * sizeof(uint32_t));
 | 
						|
        SDL_RenderCopy(_renderer, _screenTexture, NULL, NULL);
 | 
						|
        renderHelpScreen();
 | 
						|
        SDL_RenderPresent(_renderer);
 | 
						|
        if(synchronise) Timing::synchronise();
 | 
						|
    }
 | 
						|
}
 |