mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-08-21 20:21:29 +02:00
Update to v083r02 release.
byuu says: It seems impossible to pass blargg's NES ppu_vbl_nmi test 03 and 07 at the same time. Wrote up a description of the problem here: http://nesdev.parodius.com/bbs/viewtopic.php?p=85156#85156
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
#ifdef APU_CPP
|
#ifdef APU_CPP
|
||||||
|
|
||||||
void APU::serialize(serializer &s) {
|
void APU::serialize(serializer &s) {
|
||||||
|
Processor::serialize(s);
|
||||||
|
|
||||||
s.array(mmio_data);
|
s.array(mmio_data);
|
||||||
s.integer(sequencer_base);
|
s.integer(sequencer_base);
|
||||||
s.integer(sequencer_step);
|
s.integer(sequencer_step);
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
#ifdef CPU_CPP
|
#ifdef CPU_CPP
|
||||||
|
|
||||||
void CPU::serialize(serializer &s) {
|
void CPU::serialize(serializer &s) {
|
||||||
|
Processor::serialize(s);
|
||||||
|
|
||||||
s.array(wram);
|
s.array(wram);
|
||||||
s.array(hram);
|
s.array(hram);
|
||||||
|
|
||||||
|
@@ -80,14 +80,24 @@ namespace GameBoy {
|
|||||||
unsigned frequency;
|
unsigned frequency;
|
||||||
int64 clock;
|
int64 clock;
|
||||||
|
|
||||||
inline void create(void (*entrypoint_)(), unsigned frequency_) {
|
inline void create(void (*entrypoint)(), unsigned frequency) {
|
||||||
if(thread) co_delete(thread);
|
if(thread) co_delete(thread);
|
||||||
thread = co_create(65536 * sizeof(void*), entrypoint_);
|
thread = co_create(65536 * sizeof(void*), entrypoint);
|
||||||
frequency = frequency_;
|
this->frequency = frequency;
|
||||||
clock = 0;
|
clock = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Processor() : thread(nullptr) {}
|
inline void serialize(serializer &s) {
|
||||||
|
s.integer(frequency);
|
||||||
|
s.integer(clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Processor() : thread(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~Processor() {
|
||||||
|
if(thread) co_delete(thread);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <gameboy/memory/memory.hpp>
|
#include <gameboy/memory/memory.hpp>
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
#ifdef LCD_CPP
|
#ifdef LCD_CPP
|
||||||
|
|
||||||
void LCD::serialize(serializer &s) {
|
void LCD::serialize(serializer &s) {
|
||||||
|
Processor::serialize(s);
|
||||||
|
|
||||||
s.integer(status.lx);
|
s.integer(status.lx);
|
||||||
s.integer(status.wyc);
|
s.integer(status.wyc);
|
||||||
|
|
||||||
|
@@ -80,7 +80,7 @@ namespace NES {
|
|||||||
struct Processor {
|
struct Processor {
|
||||||
cothread_t thread;
|
cothread_t thread;
|
||||||
unsigned frequency;
|
unsigned frequency;
|
||||||
signed clock;
|
int64 clock;
|
||||||
|
|
||||||
inline void create(void (*entrypoint)(), unsigned frequency) {
|
inline void create(void (*entrypoint)(), unsigned frequency) {
|
||||||
if(thread) co_delete(thread);
|
if(thread) co_delete(thread);
|
||||||
@@ -94,7 +94,12 @@ namespace NES {
|
|||||||
s.integer(clock);
|
s.integer(clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Processor() : thread(nullptr) {}
|
inline Processor() : thread(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~Processor() {
|
||||||
|
if(thread) co_delete(thread);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <nes/system/system.hpp>
|
#include <nes/system/system.hpp>
|
||||||
|
@@ -20,23 +20,28 @@ void PPU::main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PPU::tick() {
|
void PPU::tick() {
|
||||||
|
if(status.ly == 240 && status.lx == 340) status.nmi_hold = 1;
|
||||||
|
if(status.ly == 241 && status.lx == 0) status.nmi_flag = status.nmi_hold;
|
||||||
|
if(status.ly == 241 && status.lx == 2) if(status.nmi_enable && status.nmi_flag) cpu.set_nmi_line(1);
|
||||||
|
if(status.ly == 261 && status.lx == 0) cpu.set_nmi_line(status.nmi_flag = 0);
|
||||||
|
if(status.ly == 261 && status.lx == 0) status.sprite_zero_hit = 0;
|
||||||
|
|
||||||
clock += 4;
|
clock += 4;
|
||||||
if(clock >= 0) co_switch(cpu.thread);
|
if(clock >= 0) co_switch(cpu.thread);
|
||||||
|
|
||||||
|
status.lx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::scanline_edge() {
|
void PPU::scanline() {
|
||||||
if(status.ly == 241) {
|
status.lx = 0;
|
||||||
status.nmi = 1;
|
if(++status.ly == 262) {
|
||||||
if(status.nmi_enable) cpu.set_nmi_line(1);
|
status.ly = 0;
|
||||||
}
|
frame();
|
||||||
if(status.ly == 261) {
|
|
||||||
status.nmi = 0;
|
|
||||||
cpu.set_nmi_line(0);
|
|
||||||
status.sprite_zero_hit = 0;
|
|
||||||
}
|
}
|
||||||
|
cartridge.scanline(status.ly);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::frame_edge() {
|
void PPU::frame() {
|
||||||
status.field ^= 1;
|
status.field ^= 1;
|
||||||
interface->videoRefresh(buffer);
|
interface->videoRefresh(buffer);
|
||||||
scheduler.exit(Scheduler::ExitReason::FrameEvent);
|
scheduler.exit(Scheduler::ExitReason::FrameEvent);
|
||||||
@@ -58,6 +63,9 @@ void PPU::reset() {
|
|||||||
status.taddr = 0x0000;
|
status.taddr = 0x0000;
|
||||||
status.xaddr = 0x00;
|
status.xaddr = 0x00;
|
||||||
|
|
||||||
|
status.nmi_hold = 0;
|
||||||
|
status.nmi_flag = 0;
|
||||||
|
|
||||||
//$2000
|
//$2000
|
||||||
status.nmi_enable = false;
|
status.nmi_enable = false;
|
||||||
status.master_select = 0;
|
status.master_select = 0;
|
||||||
@@ -75,18 +83,16 @@ void PPU::reset() {
|
|||||||
status.grayscale = false;
|
status.grayscale = false;
|
||||||
|
|
||||||
//$2002
|
//$2002
|
||||||
status.nmi = false;
|
|
||||||
status.sprite_zero_hit = false;
|
status.sprite_zero_hit = false;
|
||||||
status.sprite_overflow = false;
|
status.sprite_overflow = false;
|
||||||
|
|
||||||
//$2003
|
//$2003
|
||||||
status.oam_addr = 0x00;
|
status.oam_addr = 0x00;
|
||||||
|
|
||||||
memset(buffer, 0, sizeof buffer);
|
for(auto &n : buffer) n = 0;
|
||||||
|
for(auto &n : ciram ) n = 0;
|
||||||
memset(ciram, 0, sizeof ciram);
|
for(auto &n : cgram ) n = 0;
|
||||||
memset(cgram, 0, sizeof cgram);
|
for(auto &n : oam ) n = 0;
|
||||||
memset(oam, 0, sizeof oam);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 PPU::read(uint16 addr) {
|
uint8 PPU::read(uint16 addr) {
|
||||||
@@ -94,13 +100,13 @@ uint8 PPU::read(uint16 addr) {
|
|||||||
|
|
||||||
switch(addr & 7) {
|
switch(addr & 7) {
|
||||||
case 2: //PPUSTATUS
|
case 2: //PPUSTATUS
|
||||||
result |= status.nmi << 7;
|
result |= status.nmi_flag << 7;
|
||||||
result |= status.sprite_zero_hit << 6;
|
result |= status.sprite_zero_hit << 6;
|
||||||
result |= status.sprite_overflow << 5;
|
result |= status.sprite_overflow << 5;
|
||||||
result |= status.mdr & 0x1f;
|
result |= status.mdr & 0x1f;
|
||||||
status.nmi = 0;
|
|
||||||
cpu.set_nmi_line(0);
|
|
||||||
status.address_latch = 0;
|
status.address_latch = 0;
|
||||||
|
status.nmi_hold = 0;
|
||||||
|
cpu.set_nmi_line(status.nmi_flag = 0);
|
||||||
break;
|
break;
|
||||||
case 4: //OAMDATA
|
case 4: //OAMDATA
|
||||||
result = oam[status.oam_addr];
|
result = oam[status.oam_addr];
|
||||||
@@ -133,13 +139,13 @@ void PPU::write(uint16 addr, uint8 data) {
|
|||||||
switch(addr & 7) {
|
switch(addr & 7) {
|
||||||
case 0: //PPUCTRL
|
case 0: //PPUCTRL
|
||||||
status.nmi_enable = data & 0x80;
|
status.nmi_enable = data & 0x80;
|
||||||
cpu.set_nmi_line(status.nmi_enable && status.nmi);
|
|
||||||
status.master_select = data & 0x40;
|
status.master_select = data & 0x40;
|
||||||
status.sprite_size = data & 0x20;
|
status.sprite_size = data & 0x20;
|
||||||
status.bg_addr = (data & 0x10) ? 0x1000 : 0x0000;
|
status.bg_addr = (data & 0x10) ? 0x1000 : 0x0000;
|
||||||
status.sprite_addr = (data & 0x08) ? 0x1000 : 0x0000;
|
status.sprite_addr = (data & 0x08) ? 0x1000 : 0x0000;
|
||||||
status.vram_increment = (data & 0x04) ? 32 : 1;
|
status.vram_increment = (data & 0x04) ? 32 : 1;
|
||||||
status.taddr = (status.taddr & 0x73ff) | ((data & 0x03) << 10);
|
status.taddr = (status.taddr & 0x73ff) | ((data & 0x03) << 10);
|
||||||
|
cpu.set_nmi_line(status.nmi_enable && status.nmi_flag);
|
||||||
return;
|
return;
|
||||||
case 1: //PPUMASK
|
case 1: //PPUMASK
|
||||||
status.emphasis = data >> 5;
|
status.emphasis = data >> 5;
|
||||||
@@ -249,15 +255,6 @@ uint8 PPU::chr_load(uint16 addr) {
|
|||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
void PPU::ly_increment() {
|
|
||||||
if(++status.ly == 262) {
|
|
||||||
status.ly = 0;
|
|
||||||
frame_edge();
|
|
||||||
}
|
|
||||||
scanline_edge();
|
|
||||||
cartridge.scanline(status.ly);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PPU::scrollx_increment() {
|
void PPU::scrollx_increment() {
|
||||||
if(raster_enable() == false) return;
|
if(raster_enable() == false) return;
|
||||||
status.vaddr = (status.vaddr & 0x7fe0) | ((status.vaddr + 0x0001) & 0x001f);
|
status.vaddr = (status.vaddr & 0x7fe0) | ((status.vaddr + 0x0001) & 0x001f);
|
||||||
@@ -280,10 +277,10 @@ void PPU::scrolly_increment() {
|
|||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
void PPU::raster_pixel(unsigned x) {
|
void PPU::raster_pixel() {
|
||||||
uint16 *output = buffer + status.ly * 256;
|
uint16 *output = buffer + status.ly * 256;
|
||||||
|
|
||||||
unsigned mask = 0x8000 >> (status.xaddr + x);
|
unsigned mask = 0x8000 >> (status.xaddr + (status.lx & 7));
|
||||||
unsigned palette = 0, object_palette = 0;
|
unsigned palette = 0, object_palette = 0;
|
||||||
bool object_priority = 0;
|
bool object_priority = 0;
|
||||||
palette |= (raster.tiledatalo & mask) ? 1 : 0;
|
palette |= (raster.tiledatalo & mask) ? 1 : 0;
|
||||||
@@ -311,7 +308,7 @@ void PPU::raster_pixel(unsigned x) {
|
|||||||
sprite_palette |= (raster.oam[sprite].tiledatahi & mask) ? 2 : 0;
|
sprite_palette |= (raster.oam[sprite].tiledatahi & mask) ? 2 : 0;
|
||||||
if(sprite_palette == 0) continue;
|
if(sprite_palette == 0) continue;
|
||||||
|
|
||||||
if(raster.oam[sprite].id == 0 && palette) status.sprite_zero_hit = 1;
|
if(raster.oam[sprite].id == 0 && palette && status.lx != 255) status.sprite_zero_hit = 1;
|
||||||
sprite_palette |= (raster.oam[sprite].attr & 3) << 2;
|
sprite_palette |= (raster.oam[sprite].attr & 3) << 2;
|
||||||
|
|
||||||
object_priority = raster.oam[sprite].attr & 0x20;
|
object_priority = raster.oam[sprite].attr & 0x20;
|
||||||
@@ -323,7 +320,7 @@ void PPU::raster_pixel(unsigned x) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(raster_enable() == false) palette = 0;
|
if(raster_enable() == false) palette = 0;
|
||||||
output[status.lx++] = (status.emphasis << 6) | cgram_read(palette);
|
output[status.lx] = (status.emphasis << 6) | cgram_read(palette);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::raster_sprite() {
|
void PPU::raster_sprite() {
|
||||||
@@ -349,14 +346,10 @@ void PPU::raster_sprite() {
|
|||||||
|
|
||||||
void PPU::raster_scanline() {
|
void PPU::raster_scanline() {
|
||||||
if((status.ly >= 240 && status.ly <= 260)) {
|
if((status.ly >= 240 && status.ly <= 260)) {
|
||||||
for(unsigned x = 0; x < 340; x++) tick();
|
for(unsigned x = 0; x < 341; x++) tick();
|
||||||
if(raster_enable() == false || status.field != 1 || status.ly != 240) tick();
|
return scanline();
|
||||||
return ly_increment();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
signed lx = 0, ly = (status.ly == 261 ? -1 : status.ly);
|
|
||||||
status.lx = 0;
|
|
||||||
|
|
||||||
raster.oam_iterator = 0;
|
raster.oam_iterator = 0;
|
||||||
raster.oam_counter = 0;
|
raster.oam_counter = 0;
|
||||||
|
|
||||||
@@ -373,36 +366,36 @@ void PPU::raster_scanline() {
|
|||||||
for(unsigned tile = 0; tile < 32; tile++) { // 0-255
|
for(unsigned tile = 0; tile < 32; tile++) { // 0-255
|
||||||
unsigned nametable = chr_load(0x2000 | (status.vaddr & 0x0fff));
|
unsigned nametable = chr_load(0x2000 | (status.vaddr & 0x0fff));
|
||||||
unsigned tileaddr = status.bg_addr + (nametable << 4) + (scrolly() & 7);
|
unsigned tileaddr = status.bg_addr + (nametable << 4) + (scrolly() & 7);
|
||||||
raster_pixel(0);
|
raster_pixel();
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
raster_pixel(1);
|
raster_pixel();
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
unsigned attribute = chr_load(0x23c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
|
unsigned attribute = chr_load(0x23c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
|
||||||
if(scrolly() & 16) attribute >>= 4;
|
if(scrolly() & 16) attribute >>= 4;
|
||||||
if(scrollx() & 16) attribute >>= 2;
|
if(scrollx() & 16) attribute >>= 2;
|
||||||
raster_pixel(2);
|
raster_pixel();
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
scrollx_increment();
|
scrollx_increment();
|
||||||
if(tile == 31) scrolly_increment();
|
if(tile == 31) scrolly_increment();
|
||||||
raster_pixel(3);
|
raster_pixel();
|
||||||
raster_sprite();
|
raster_sprite();
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
unsigned tiledatalo = chr_load(tileaddr + 0);
|
unsigned tiledatalo = chr_load(tileaddr + 0);
|
||||||
raster_pixel(4);
|
raster_pixel();
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
raster_pixel(5);
|
raster_pixel();
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
unsigned tiledatahi = chr_load(tileaddr + 8);
|
unsigned tiledatahi = chr_load(tileaddr + 8);
|
||||||
raster_pixel(6);
|
raster_pixel();
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
raster_pixel(7);
|
raster_pixel();
|
||||||
raster_sprite();
|
raster_sprite();
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
@@ -476,14 +469,15 @@ void PPU::raster_scanline() {
|
|||||||
tick();
|
tick();
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
|
bool skip = (raster_enable() && status.field == 1 && status.ly == 261);
|
||||||
chr_load(0x2000 | (status.vaddr & 0x0fff));
|
chr_load(0x2000 | (status.vaddr & 0x0fff));
|
||||||
tick();
|
tick();
|
||||||
tick();
|
tick();
|
||||||
|
|
||||||
//340
|
//340
|
||||||
tick();
|
if(skip == false) tick();
|
||||||
|
|
||||||
return ly_increment();
|
return scanline();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -3,8 +3,8 @@ struct PPU : Processor {
|
|||||||
void main();
|
void main();
|
||||||
void tick();
|
void tick();
|
||||||
|
|
||||||
void scanline_edge();
|
void scanline();
|
||||||
void frame_edge();
|
void frame();
|
||||||
|
|
||||||
void power();
|
void power();
|
||||||
void reset();
|
void reset();
|
||||||
@@ -26,11 +26,10 @@ struct PPU : Processor {
|
|||||||
|
|
||||||
uint8 chr_load(uint16 addr);
|
uint8 chr_load(uint16 addr);
|
||||||
|
|
||||||
void ly_increment();
|
|
||||||
void scrollx_increment();
|
void scrollx_increment();
|
||||||
void scrolly_increment();
|
void scrolly_increment();
|
||||||
|
|
||||||
void raster_pixel(unsigned x);
|
void raster_pixel();
|
||||||
void raster_sprite();
|
void raster_sprite();
|
||||||
void raster_scanline();
|
void raster_scanline();
|
||||||
|
|
||||||
@@ -51,6 +50,9 @@ struct PPU : Processor {
|
|||||||
uint15 taddr;
|
uint15 taddr;
|
||||||
uint8 xaddr;
|
uint8 xaddr;
|
||||||
|
|
||||||
|
bool nmi_hold;
|
||||||
|
bool nmi_flag;
|
||||||
|
|
||||||
//$2000
|
//$2000
|
||||||
bool nmi_enable;
|
bool nmi_enable;
|
||||||
bool master_select;
|
bool master_select;
|
||||||
@@ -68,7 +70,6 @@ struct PPU : Processor {
|
|||||||
bool grayscale;
|
bool grayscale;
|
||||||
|
|
||||||
//$2002
|
//$2002
|
||||||
bool nmi;
|
|
||||||
bool sprite_zero_hit;
|
bool sprite_zero_hit;
|
||||||
bool sprite_overflow;
|
bool sprite_overflow;
|
||||||
|
|
||||||
|
@@ -15,6 +15,9 @@ void PPU::serialize(serializer &s) {
|
|||||||
s.integer(status.taddr);
|
s.integer(status.taddr);
|
||||||
s.integer(status.xaddr);
|
s.integer(status.xaddr);
|
||||||
|
|
||||||
|
s.integer(status.nmi_hold);
|
||||||
|
s.integer(status.nmi_flag);
|
||||||
|
|
||||||
s.integer(status.nmi_enable);
|
s.integer(status.nmi_enable);
|
||||||
s.integer(status.master_select);
|
s.integer(status.master_select);
|
||||||
s.integer(status.sprite_size);
|
s.integer(status.sprite_size);
|
||||||
@@ -29,7 +32,6 @@ void PPU::serialize(serializer &s) {
|
|||||||
s.integer(status.bg_edge_enable);
|
s.integer(status.bg_edge_enable);
|
||||||
s.integer(status.grayscale);
|
s.integer(status.grayscale);
|
||||||
|
|
||||||
s.integer(status.nmi);
|
|
||||||
s.integer(status.sprite_zero_hit);
|
s.integer(status.sprite_zero_hit);
|
||||||
s.integer(status.sprite_overflow);
|
s.integer(status.sprite_overflow);
|
||||||
|
|
||||||
|
@@ -106,10 +106,10 @@ namespace SNES {
|
|||||||
unsigned frequency;
|
unsigned frequency;
|
||||||
int64 clock;
|
int64 clock;
|
||||||
|
|
||||||
inline void create(void (*entrypoint_)(), unsigned frequency_) {
|
inline void create(void (*entrypoint)(), unsigned frequency) {
|
||||||
if(thread) co_delete(thread);
|
if(thread) co_delete(thread);
|
||||||
thread = co_create(65536 * sizeof(void*), entrypoint_);
|
thread = co_create(65536 * sizeof(void*), entrypoint);
|
||||||
frequency = frequency_;
|
this->frequency = frequency;
|
||||||
clock = 0;
|
clock = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +118,12 @@ namespace SNES {
|
|||||||
s.integer(clock);
|
s.integer(clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Processor() : thread(nullptr) {}
|
inline Processor() : thread(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~Processor() {
|
||||||
|
if(thread) co_delete(thread);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ChipDebugger {
|
struct ChipDebugger {
|
||||||
|
@@ -27,6 +27,8 @@ void Application::run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Application::Application(int argc, char **argv) {
|
Application::Application(int argc, char **argv) {
|
||||||
|
title = "bsnes v083.02";
|
||||||
|
|
||||||
application = this;
|
application = this;
|
||||||
quit = false;
|
quit = false;
|
||||||
pause = false;
|
pause = false;
|
||||||
@@ -49,8 +51,6 @@ Application::Application(int argc, char **argv) {
|
|||||||
inputManager = new InputManager;
|
inputManager = new InputManager;
|
||||||
utility = new Utility;
|
utility = new Utility;
|
||||||
|
|
||||||
title = "bsnes v083.01";
|
|
||||||
|
|
||||||
string fontFamily = Intrinsics::platform() == Intrinsics::Platform::Windows ? "Tahoma, " : "Sans, ";
|
string fontFamily = Intrinsics::platform() == Intrinsics::Platform::Windows ? "Tahoma, " : "Sans, ";
|
||||||
normalFont = { fontFamily, "8" };
|
normalFont = { fontFamily, "8" };
|
||||||
boldFont = { fontFamily, "8, Bold" };
|
boldFont = { fontFamily, "8, Bold" };
|
||||||
|
Reference in New Issue
Block a user