reinette-IIe/video.cpp

562 lines
27 KiB
C++

/*
* 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"
Video::Video() {
memset(ramHeatmap, 0xFF000000, sizeof(ramHeatmap));
memset(auxHeatmap, 0xFF000000, sizeof(auxHeatmap));
// array from https://github.com/Michaelangel007/apple2_hgr_font_tutorial/
const char FONT[] = {
0x10, 0x08, 0x36, 0x7F, 0x3F, 0x3F, 0x7E, 0x36, // 0x00 ^@
0x10, 0x08, 0x36, 0x41, 0x21, 0x21, 0x4A, 0x36, // 0x01 ^A
0x00, 0x00, 0x02, 0x06, 0x0E, 0x1E, 0x36, 0x42, // 0x02 ^B
0x7F, 0x22, 0x14, 0x08, 0x08, 0x14, 0x2A, 0x7F, // 0x03 ^C
0x00, 0x40, 0x20, 0x11, 0x0A, 0x04, 0x04, 0x00, // 0x04 ^D
0x7F, 0x3F, 0x5F, 0x6C, 0x75, 0x7B, 0x7B, 0x7F, // 0x05 ^E
0x70, 0x60, 0x7E, 0x31, 0x79, 0x30, 0x3F, 0x02, // 0x06 ^F
0x00, 0x18, 0x07, 0x00, 0x07, 0x0C, 0x08, 0x70, // 0x07 ^G
0x08, 0x04, 0x02, 0x7F, 0x02, 0x04, 0x08, 0x00, // 0x08 ^H
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, // 0x09 ^I
0x08, 0x08, 0x08, 0x08, 0x49, 0x2A, 0x1C, 0x08, // 0x0A ^J
0x08, 0x1C, 0x2A, 0x49, 0x08, 0x08, 0x08, 0x08, // 0x0B ^K
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0C ^L
0x40, 0x40, 0x40, 0x44, 0x46, 0x7F, 0x06, 0x04, // 0x0D ^M
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, // 0x0E ^N
0x13, 0x18, 0x1C, 0x7E, 0x1C, 0x18, 0x10, 0x6F, // 0x0F ^O
0x64, 0x0C, 0x1C, 0x3F, 0x1C, 0x0C, 0x04, 0x7B, // 0x10 ^P
0x40, 0x48, 0x08, 0x7F, 0x3E, 0x1C, 0x48, 0x40, // 0x11 ^Q
0x40, 0x48, 0x1C, 0x3E, 0x7E, 0x08, 0x48, 0x40, // 0x12 ^R
0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, // 0x13 ^S
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7F, // 0x14 ^T
0x08, 0x10, 0x20, 0x7F, 0x20, 0x10, 0x08, 0x00, // 0x15 ^U
0x2A, 0x55, 0x2A, 0x55, 0x2A, 0x55, 0x2A, 0x55, // 0x16 ^V
0x55, 0x2A, 0x55, 0x2A, 0x55, 0x2A, 0x55, 0x2A, // 0x17 ^W
0x00, 0x3E, 0x41, 0x01, 0x01, 0x01, 0x7F, 0x00, // 0x18 ^X
0x00, 0x00, 0x3F, 0x40, 0x40, 0x40, 0x7F, 0x00, // 0x19 ^Y
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x1A ^Z
0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x1C, 0x08, 0x00, // 0x1B ^[
0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, // 0x1C ^
0x14, 0x14, 0x77, 0x00, 0x77, 0x14, 0x14, 0x00, // 0x1D ^]
0x7F, 0x40, 0x40, 0x4C, 0x4C, 0x40, 0x40, 0x7F, // 0x1E ^^
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, // 0x1F ^_
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 space
0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, // 0x21 !
0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x22 "
0x14, 0x14, 0x3E, 0x14, 0x3E, 0x14, 0x14, 0x00, // 0x23 #
0x08, 0x3C, 0x0A, 0x1C, 0x28, 0x1E, 0x08, 0x00, // 0x24 $
0x06, 0x26, 0x10, 0x08, 0x04, 0x32, 0x30, 0x00, // 0x25 %
0x04, 0x0A, 0x0A, 0x04, 0x2A, 0x12, 0x2C, 0x00, // 0x26 &
0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x27 '
0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00, // 0x28 (
0x08, 0x10, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00, // 0x29 )
0x08, 0x2A, 0x1C, 0x08, 0x1C, 0x2A, 0x08, 0x00, // 0x2A *
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, // 0x2B +
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x04, 0x00, // 0x2C ,
0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, // 0x2D -
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, // 0x2E .
0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, // 0x2F /
0x1C, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x1C, 0x00, // 0x30 0
0x08, 0x0C, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, // 0x31 1
0x1C, 0x22, 0x20, 0x18, 0x04, 0x02, 0x3E, 0x00, // 0x32 2
0x3E, 0x20, 0x10, 0x18, 0x20, 0x22, 0x1C, 0x00, // 0x33 3
0x10, 0x18, 0x14, 0x12, 0x3E, 0x10, 0x10, 0x00, // 0x34 4
0x3E, 0x02, 0x1E, 0x20, 0x20, 0x22, 0x1C, 0x00, // 0x35 5
0x38, 0x04, 0x02, 0x1E, 0x22, 0x22, 0x1C, 0x00, // 0x36 6
0x3E, 0x20, 0x10, 0x08, 0x04, 0x04, 0x04, 0x00, // 0x37 7
0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, 0x00, // 0x38 8
0x1C, 0x22, 0x22, 0x3C, 0x20, 0x10, 0x0E, 0x00, // 0x39 9
0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, // 0x3A :
0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x04, 0x00, // 0x3B ;
0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, // 0x3C <
0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, // 0x3D =
0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, // 0x3E >
0x1C, 0x22, 0x10, 0x08, 0x08, 0x00, 0x08, 0x00, // 0x3F ?
0x1C, 0x22, 0x2A, 0x3A, 0x1A, 0x02, 0x3C, 0x00, // 0x40 @
0x08, 0x14, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x00, // 0x41 A
0x1E, 0x22, 0x22, 0x1E, 0x22, 0x22, 0x1E, 0x00, // 0x42 B
0x1C, 0x22, 0x02, 0x02, 0x02, 0x22, 0x1C, 0x00, // 0x43 C
0x1E, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1E, 0x00, // 0x44 D
0x3E, 0x02, 0x02, 0x1E, 0x02, 0x02, 0x3E, 0x00, // 0x45 E
0x3E, 0x02, 0x02, 0x1E, 0x02, 0x02, 0x02, 0x00, // 0x46 F
0x3C, 0x02, 0x02, 0x02, 0x32, 0x22, 0x3C, 0x00, // 0x47 G
0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x00, // 0x48 H
0x1C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, // 0x49 I
0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, // 0x4A J
0x22, 0x12, 0x0A, 0x06, 0x0A, 0x12, 0x22, 0x00, // 0x4B K
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x3E, 0x00, // 0x4C L
0x22, 0x36, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x00, // 0x4D M
0x22, 0x22, 0x26, 0x2A, 0x32, 0x22, 0x22, 0x00, // 0x4E N
0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, // 0x4F O
0x1E, 0x22, 0x22, 0x1E, 0x02, 0x02, 0x02, 0x00, // 0x50 P
0x1C, 0x22, 0x22, 0x22, 0x2A, 0x12, 0x2C, 0x00, // 0x51 Q
0x1E, 0x22, 0x22, 0x1E, 0x0A, 0x12, 0x22, 0x00, // 0x52 R
0x1C, 0x22, 0x02, 0x1C, 0x20, 0x22, 0x1C, 0x00, // 0x53 S
0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, // 0x54 T
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x00, // 0x55 U
0x22, 0x22, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, // 0x56 V
0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x00, // 0x57 W
0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, // 0x58 X
0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, // 0x59 Y
0x3E, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3E, 0x00, // 0x5A Z
0x3E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3E, 0x00, // 0x5B [
0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, // 0x5C back slash
0x3E, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3E, 0x00, // 0x5D ]
0x00, 0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, // 0x5E ^
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, // 0x5F _
0x04, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60 `
0x00, 0x00, 0x1C, 0x20, 0x3C, 0x22, 0x3C, 0x00, // 0x61 a
0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x1E, 0x00, // 0x62 b
0x00, 0x00, 0x3C, 0x02, 0x02, 0x02, 0x3C, 0x00, // 0x63 c
0x20, 0x20, 0x3C, 0x22, 0x22, 0x22, 0x3C, 0x00, // 0x64 d
0x00, 0x00, 0x1C, 0x22, 0x3E, 0x02, 0x3C, 0x00, // 0x65 e
0x18, 0x24, 0x04, 0x1E, 0x04, 0x04, 0x04, 0x00, // 0x66 f
0x00, 0x00, 0x1C, 0x22, 0x22, 0x3C, 0x20, 0x1C, // 0x67 g
0x02, 0x02, 0x1E, 0x22, 0x22, 0x22, 0x22, 0x00, // 0x68 h
0x08, 0x00, 0x0C, 0x08, 0x08, 0x08, 0x1C, 0x00, // 0x69 i
0x10, 0x00, 0x18, 0x10, 0x10, 0x10, 0x12, 0x0C, // 0x6A j
0x02, 0x02, 0x22, 0x12, 0x0E, 0x12, 0x22, 0x00, // 0x6B k
0x0C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C, 0x00, // 0x6C l
0x00, 0x00, 0x36, 0x2A, 0x2A, 0x2A, 0x22, 0x00, // 0x6D m
0x00, 0x00, 0x1E, 0x22, 0x22, 0x22, 0x22, 0x00, // 0x6E n
0x00, 0x00, 0x1C, 0x22, 0x22, 0x22, 0x1C, 0x00, // 0x6F o
0x00, 0x00, 0x1E, 0x22, 0x22, 0x1E, 0x02, 0x02, // 0x70 p
0x00, 0x00, 0x3C, 0x22, 0x22, 0x3C, 0x20, 0x20, // 0x71 q
0x00, 0x00, 0x3A, 0x06, 0x02, 0x02, 0x02, 0x00, // 0x72 r
0x00, 0x00, 0x3C, 0x02, 0x1C, 0x20, 0x1E, 0x00, // 0x73 s
0x04, 0x04, 0x1E, 0x04, 0x04, 0x24, 0x18, 0x00, // 0x74 t
0x00, 0x00, 0x22, 0x22, 0x22, 0x32, 0x2C, 0x00, // 0x75 u
0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, // 0x76 v
0x00, 0x00, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x00, // 0x77 w
0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, // 0x78 x
0x00, 0x00, 0x22, 0x22, 0x22, 0x3C, 0x20, 0x1C, // 0x79 y
0x00, 0x00, 0x3E, 0x10, 0x08, 0x04, 0x3E, 0x00, // 0x7A z
0x38, 0x0C, 0x0C, 0x06, 0x0C, 0x0C, 0x38, 0x00, // 0x7B {
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, // 0x7C |
0x0E, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0E, 0x00, // 0x7D }
0x2C, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x7E ~
0x00, 0x2A, 0x14, 0x2A, 0x14, 0x2A, 0x00, 0x00 // 0x7F DEL
};
// Generate the font arrays from the above array
int raw;
for (int c=0; c<128; c++) {
for (int y=0; y<8; y++) {
raw = FONT[c*8 + y];
for (int x=0; x<7; x++) {
if (raw & (1<<x)) {
fontInverse[c][y][x]= 0xFF000000;
fontNormal[c][y][x]= 0xFFFFFFFF;
}
else {
fontInverse[c][y][x]= 0xFFFFFFFF;
fontNormal[c][y][x]= 0xFF000000;
}
}
}
}
}
Video::~Video() {
// delete[] fontInverse;
// delete[] fontNormal;
// ...
}
void Video::clearCache() {
memset(previousDots, -2, sizeof(previousDots));
memset(previousBlocks, -2, sizeof(previousBlocks));
memset(previousChars, -2, sizeof(previousChars));
memset(previousChars80,-2, sizeof(previousChars80));
}
void Video::update() {
// Note: Colors may vary, depending upon the controls on the monitor or TV set
const uint32_t lcolor[16] = { // the 16 low res colors
0xFF000000, 0xFF5639E2, 0xFFCD741C, 0xFFAD6E7E,
0xFF80811F, 0xFF7A8289, 0xFFE4A856, 0xFFDFB290,
0xFF225897, 0xFF156CEA, 0xFF8F979E, 0xFFF0CEFF,
0xFF31C090, 0xFFA6FDFF, 0xFFD5D29F, 0xFFFFFFFF
};
const uint32_t hcolor[16] = { // the high res colors (light & dark levels)
0xFF000000, 0xFF31C090, 0xFFAD6E7E, 0xFFFFFFFF,
0xFF000000, 0xFF156CEA, 0xFFE4A856, 0xFFFFFFFF,
0xFF000000, 0xFF56373f, 0xFF196048, 0xFFFFFFFF,
0xFF000000, 0xFF72542B, 0xFF0A3675, 0xFFFFFFFF
};
const uint32_t dhcolor[16] = {
0xFF000000, 0xFFCD741C, 0xFF80811F, 0xFFDFB290,
0xFF225897, 0xFF7A8289, 0xFF31C090, 0xFFE4A856,
0xFF5639E2, 0xFFAD6E7E, 0xFF8F979E, 0xFFD5D29F,
0xFF156CEA, 0xFFF0CEFF, 0xFFA6FDFF, 0xFFFFFFFF
};
const uint16_t offsetGR[24] = { // base addresses for each line in TEXT or GR
0x000, 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, // lines 0-7
0x028, 0x0A8, 0x128, 0x1A8, 0x228, 0x2A8, 0x328, 0x3A8, // lines 8-15
0x050, 0x0D0, 0x150, 0x1D0, 0x250, 0x2D0, 0x350, 0x3D0 // lines 16-23
};
const uint16_t offsetHGR[192] = { // base addresses for each line in HGR
0x0000, 0x0400, 0x0800, 0x0C00, 0x1000, 0x1400, 0x1800, 0x1C00, // lines 0-7
0x0080, 0x0480, 0x0880, 0x0C80, 0x1080, 0x1480, 0x1880, 0x1C80, // lines 8-15
0x0100, 0x0500, 0x0900, 0x0D00, 0x1100, 0x1500, 0x1900, 0x1D00, // lines 16-23
0x0180, 0x0580, 0x0980, 0x0D80, 0x1180, 0x1580, 0x1980, 0x1D80,
0x0200, 0x0600, 0x0A00, 0x0E00, 0x1200, 0x1600, 0x1A00, 0x1E00,
0x0280, 0x0680, 0x0A80, 0x0E80, 0x1280, 0x1680, 0x1A80, 0x1E80,
0x0300, 0x0700, 0x0B00, 0x0F00, 0x1300, 0x1700, 0x1B00, 0x1F00,
0x0380, 0x0780, 0x0B80, 0x0F80, 0x1380, 0x1780, 0x1B80, 0x1F80,
0x0028, 0x0428, 0x0828, 0x0C28, 0x1028, 0x1428, 0x1828, 0x1C28,
0x00A8, 0x04A8, 0x08A8, 0x0CA8, 0x10A8, 0x14A8, 0x18A8, 0x1CA8,
0x0128, 0x0528, 0x0928, 0x0D28, 0x1128, 0x1528, 0x1928, 0x1D28,
0x01A8, 0x05A8, 0x09A8, 0x0DA8, 0x11A8, 0x15A8, 0x19A8, 0x1DA8,
0x0228, 0x0628, 0x0A28, 0x0E28, 0x1228, 0x1628, 0x1A28, 0x1E28,
0x02A8, 0x06A8, 0x0AA8, 0x0EA8, 0x12A8, 0x16A8, 0x1AA8, 0x1EA8,
0x0328, 0x0728, 0x0B28, 0x0F28, 0x1328, 0x1728, 0x1B28, 0x1F28,
0x03A8, 0x07A8, 0x0BA8, 0x0FA8, 0x13A8, 0x17A8, 0x1BA8, 0x1FA8,
0x0050, 0x0450, 0x0850, 0x0C50, 0x1050, 0x1450, 0x1850, 0x1C50,
0x00D0, 0x04D0, 0x08D0, 0x0CD0, 0x10D0, 0x14D0, 0x18D0, 0x1CD0,
0x0150, 0x0550, 0x0950, 0x0D50, 0x1150, 0x1550, 0x1950, 0x1D50,
0x01D0, 0x05D0, 0x09D0, 0x0DD0, 0x11D0, 0x15D0, 0x19D0, 0x1DD0,
0x0250, 0x0650, 0x0A50, 0x0E50, 0x1250, 0x1650, 0x1A50, 0x1E50,
0x02D0, 0x06D0, 0x0AD0, 0x0ED0, 0x12D0, 0x16D0, 0x1AD0, 0x1ED0, // lines 168-183
0x0350, 0x0750, 0x0B50, 0x0F50, 0x1350, 0x1750, 0x1B50, 0x1F50, // lines 176-183
0x03D0, 0x07D0, 0x0BD0, 0x0FD0, 0x13D0, 0x17D0, 0x1BD0, 0x1FD0 // lines 184-191
};
// HIGH RES GRAPHICS
if (!mmu->TEXT && mmu->HIRES && !mmu->DHIRES) {
gfxmode = 40;
uint8_t colorIdx; // index to the color array
uint16_t word;
uint8_t bits[16], bit, pbit, colorSet, even;
int vRamBase = 0x2000 + mmu->PAGE2 * 0x2000;
int endRaw = mmu->MIXED ? 160 : 192;
for (int line = 0; line < endRaw; line++) { // for every line
for (int col = 0; col < 40; col += 2) { // for every 7 horizontal dots
word = (uint16_t)(mmu->ram[vRamBase + offsetHGR[line] + col + 1]) << 8; // store the two next bytes into 'word'
word += mmu->ram[vRamBase + offsetHGR[line] + col]; // in reverse order
if (previousDots[line][col] != word) { // check if this group of 7 dots need a redraw
int x = col * 7;
even = 0;
for (bit = 0; bit < 16; bit++) // store all bits 'word' into 'bits'
bits[bit] = (word >> bit) & 1;
colorSet = bits[7] * 4; // select the right color set
pbit = previousBit[line][col]; // the bit value of the left dot
bit = 0; // starting at 1st bit of 1st byte
while (bit < 15) { // until we reach bit7 of 2nd byte
if (bit == 7) { // moving into the second byte
colorSet = bits[15] * 4; // update the color set
bit++; // skip bit 7
}
colorIdx = even + colorSet + (bits[bit] << 1) + (pbit);
screenPixels[line * 280 + x] = hcolor[colorIdx];
x++;
pbit = bits[bit++]; // proceed to the next pixel
even = even ? 0 : 8; // one pixel every two is darker
}
previousDots[line][col] = word; // update the video cache
if ((col < 37) && (previousBit[line][col + 2] != pbit)) { // check color franging effect on the dot after
previousBit[line][col + 2] = pbit; // set pbit and clear the
previousDots[line][col + 2] = -1; // video cache for next dot
}
} // if (previousDots[line][col] ...
}
}
}
// DOUBLE HIGH RES GRAPHICS
else if (!mmu->TEXT && mmu->HIRES && mmu->DHIRES) {
gfxmode = 80;
// int vRamBase = 0x2000 + PAGE2 * 0x2000;
int vRamBase = mmu->STORE80 ? 0x2000 : mmu->PAGE2 * 0x2000 + 0x2000; // TODO : CHECK THIS !
int endRaw = mmu->MIXED ? 160 : 192;
uint32_t color;
uint32_t dword;
for (int line = 0; line < endRaw; line++) {
for (int col = 0, x = 0; col < 39; col+=2) {
int address = vRamBase + offsetHGR[line] + col;
// combine 4 bytes of memory, from MAIN and AUX
dword = (uint32_t)(mmu->aux[address] & 0x7F);
dword |= (uint32_t)(mmu->ram[address] & 0x7F) << 7;
address++;
dword |= (uint32_t)(mmu->aux[address] & 0x7F) << 14;
dword |= (uint32_t)(mmu->ram[address] & 0x7F) << 21;
int offset1 = 560 * line * 2;
int offset2 = 560 + offset1;
for (int p=0; p<7; p++, dword >>= 4) {
color = dhcolor[dword & 0x0F];
for (int a=0; a<4; a++, x++) { // draw 4x2 pixels
screenPixels80[offset1 + x] = color;
screenPixels80[offset2 + x] = color;
}
}
}
}
}
// lOW RES GRAPHICS
else if (!mmu->TEXT && !mmu->HIRES && !mmu->DHIRES) { // and not in HIRES
gfxmode = 40;
int vRamBase = mmu->PAGE2 * 0x0400 + 0x400;
int endRaw = mmu->MIXED ? 20 : 24;
uint32_t color;
for (int col = 0; col < 40; col++) { // for each column
int x = col * 7;
for (int line = 0; line < endRaw; line++) { // for each row
glyph = mmu->ram[vRamBase + offsetGR[line] + col]; // read video memory
if (previousBlocks[line][col] != glyph) { // check if this block need a redraw
previousBlocks[line][col] = glyph;
int y = line * 8; // first block
color = lcolor[glyph & 0x0F]; // first nibble
for (int a=0; a<7; a++)
for (int b=0; b<4; b++)
screenPixels[(y+b) * 280 + x + a] = color;
y += 4; // second block
color = lcolor[(glyph & 0xF0) >> 4]; // second nibble
for (int a=0; a<7; a++)
for (int b=0; b<4; b++)
screenPixels[(y+b) * 280 + x + a] = color;
}
}
}
}
// DOUBLE lOW RES GRAPHICS
else if (!mmu->TEXT && !mmu->HIRES && mmu->DHIRES) {
gfxmode = 80;
int vRamBase = mmu->PAGE2 * 0x0400 + 0x400; // TODO : CHECK THIS !
int endRaw = mmu->MIXED ? 20 : 24;
int x, y;
uint32_t color;
for (int col = 0; col < 40; col++) { // for each column
x = col * 14;
for (int line = 0; line < endRaw; line++) { // for each row
y = line * 16; // first block
glyph = mmu->aux[vRamBase + offsetGR[line] + col]; // read AUX video memory
color = lcolor[glyph & 0x0F]; // first nibble
for (int a=0; a<7; a++)
for (int b=0; b<8; b++)
screenPixels80[(y+b) * 560 + (x+a)] = color;
color = lcolor[(glyph & 0xF0) >> 4]; // second nibble
for (int a=0; a<7; a++)
for (int b=8; b<16; b++)
screenPixels80[(y+b) * 560 + (x+a)] = color;
glyph = mmu->ram[vRamBase + offsetGR[line] + col]; // read MAIN video memory
color = lcolor[glyph & 0x0F]; // first nibble
for (int a=7; a<14; a++)
for (int b=0; b<8; b++)
screenPixels80[(y+b) * 560 + (x+a)] = color;
color = lcolor[(glyph & 0xF0) >> 4]; // second nibble
for (int a=7; a<14; a++)
for (int b=8; b<16; b++)
screenPixels80[(y+b) * 560 + (x+a)] = color;
}
}
}
// TEXT 40 COLUMNS
if (!mmu->COL80 && (mmu->TEXT || mmu->MIXED)) {
gfxmode = 40;
int vRamBase = mmu->PAGE2 * 0x0400 + 0x400;
int startRaw = mmu->TEXT ? 0 : 20;
for (int col = 0; col < 40; col++) { // for each column
for (int line = startRaw; line < 24; line++) { // for each row
glyph = mmu->ram[vRamBase + offsetGR[line] + col]; // read video memory
if (glyph > 0x7F) glyphAttr = A_NORMAL; // is NORMAL ?
else if (glyph < 0x40) glyphAttr = A_INVERSE; // is INVERSE ?
else glyphAttr = A_FLASH; // it's FLASH !
if (previousChars[line][col] != (glyph <<(8*mmu->ALTCHARSET)) || glyphAttr == A_FLASH) { // check if this char need a redraw
previousChars[line][col] = (glyph <<(8*mmu->ALTCHARSET));
glyph &= 0x7F; // unset bit 7
if (glyph < 0x20) glyph |= 0x40; // shifts to match the ASCII codes
if ((!mmu->ALTCHARSET) && (glyphAttr == A_FLASH) && (glyph > 0x5F))
glyph &= 0x3F;
if (mmu->ALTCHARSET && (glyphAttr == A_FLASH)) {
if (glyph >= 0x40 && glyph < 0x60) {
glyph &= 0x3F;
glyphAttr = A_NORMAL;
}
else if (glyph >= 0x60)
glyphAttr = A_INVERSE;
}
if (glyphAttr == A_NORMAL || ((glyphAttr == A_FLASH) && (gui->frameNumber % 30 < 16))) {
for (int yy=0; yy<8; yy++)
for (int xx=0; xx<7; xx++)
screenPixels[(yy+line*8)*280 + (xx+(col*7))] = fontNormal[glyph][yy][xx];
}
else {
for (int yy=0; yy<8; yy++)
for (int xx=0; xx<7; xx++)
screenPixels[(yy+line*8)*280 + (xx+(col*7))] = fontInverse[glyph][yy][xx];
}
}
}
}
}
// TEXT 80 COLUMNS
else if (mmu->COL80 && (mmu->TEXT || mmu->MIXED)) {
gfxmode = 80;
int startRaw = mmu->TEXT ? 0 : 20;
int vRamBase = 0x0400; // + PAGE2 * 0x400;
for (int col = 0; col < 40; col++) { // for each column
for (int line = startRaw; line < 24; line++) { // for each row
glyph = mmu->ram[vRamBase + offsetGR[line] + col]; // read video memory in Main memory
if (glyph > 0x7F) glyphAttr = A_NORMAL; // is NORMAL ?
else if (glyph < 0x40) glyphAttr = A_INVERSE; // is INVERSE ?
else glyphAttr = A_FLASH; // it's FLASH !
if (previousChars[line][col] != (glyph <<(8*mmu->ALTCHARSET)) || glyphAttr == A_FLASH) { // check if this char need a redraw
previousChars[line][col] = (glyph <<(8*mmu->ALTCHARSET));
glyph &= 0x7F; // unset bit 7
if (glyph < 0x20) glyph |= 0x40; // shifts to match the ASCII codes
if ((!mmu->ALTCHARSET) && (glyphAttr == A_FLASH) && (glyph > 0x5F))
glyph &= 0x3F;
if (mmu->ALTCHARSET && (glyphAttr == A_FLASH)) {
if (glyph >= 0x40 && glyph < 0x60) {
glyph &= 0x3F;
glyphAttr = A_NORMAL;
}
else if (glyph >= 0x60)
glyphAttr = A_INVERSE;
}
if (glyphAttr == A_NORMAL || ((glyphAttr == A_FLASH) && (gui->frameNumber % 30 < 16))) {
for (int yy=0; yy<16; yy+=2)
for (int xx=0; xx<7; xx++){
screenPixels80[(yy+line*16)*560 + (xx+(((col*2)+1)*7))] = fontNormal[glyph][yy/2][xx];
screenPixels80[(1+yy+line*16)*560 + (xx+(((col*2)+1)*7))] = fontNormal[glyph][yy/2][xx];
}
}
else {
for (int yy=0; yy<16; yy+=2)
for (int xx=0; xx<7; xx++){
screenPixels80[(yy+line*16)*560 + (xx+(((col*2)+1)*7))] = fontInverse[glyph][yy/2][xx];
screenPixels80[(1+yy+line*16)*560 + (xx+(((col*2)+1)*7))] = fontInverse[glyph][yy/2][xx];
}
}
}
glyph = mmu->aux[vRamBase + offsetGR[line] + col]; // read video memory in Auxiliary Memory
if (glyph > 0x7F) glyphAttr = A_NORMAL; // is NORMAL ?
else if (glyph < 0x40) glyphAttr = A_INVERSE; // is INVERSE ?
else glyphAttr = A_FLASH; // it's FLASH !
if (previousChars80[line][col] != (glyph <<(8*mmu->ALTCHARSET)) || glyphAttr == A_FLASH) { // check if this char need a redraw
previousChars80[line][col] = (glyph <<(8*mmu->ALTCHARSET));
glyph &= 0x7F; // unset bit 7
if (glyph < 0x20) glyph |= 0x40; // shifts to match the ASCII codes
if ((!mmu->ALTCHARSET) && (glyphAttr == A_FLASH) && (glyph > 0x5F))
glyph &= 0x3F;
if (mmu->ALTCHARSET && (glyphAttr == A_FLASH)) {
if (glyph >= 0x40 && glyph < 0x60) {
glyph &= 0x3F;
glyphAttr = A_NORMAL;
}
else if (glyph >= 0x60)
glyphAttr = A_INVERSE;
}
if (glyphAttr == A_NORMAL || ((glyphAttr == A_FLASH) && (gui->frameNumber % 30 < 16))) {
for (int yy=0; yy<16; yy+=2)
for (int xx=0; xx<7; xx++) {
screenPixels80[(yy+line*16)*560 + (xx+(col*2*7))] = fontNormal[glyph][yy/2][xx];
screenPixels80[(1+yy+line*16)*560 + (xx+(col*2*7))] = fontNormal[glyph][yy/2][xx];
}
}
else {
for (int yy=0; yy<16; yy+=2)
for (int xx=0; xx<7; xx++) {
screenPixels80[(yy+line*16)*560 + (xx+(col*2*7))] = fontInverse[glyph][yy/2][xx];
screenPixels80[(1+yy+line*16)*560 + (xx+(col*2*7))] = fontInverse[glyph][yy/2][xx];
}
}
}
}
}
}
// update ram & aux HEATMAPS (fade out green and red components)
for (int address=0; address<65536; address++){
if (ramHeatmap[address] & 0x000000FF)
ramHeatmap[address]--;
if (ramHeatmap[address] & 0x0000FF00)
ramHeatmap[address] -= 256;
if (auxHeatmap[address] & 0x000000FF)
auxHeatmap[address]--;
if (auxHeatmap[address] & 0x0000FF00)
auxHeatmap[address] -= 256;
}
}