mirror of https://github.com/bsnes-emu/bsnes.git
Update to v098r12 release.
byuu says: Changelog: - higan/video: added support for Emulator::Sprite - higan/resource: a new system for accessing embedded binary files inside the emulation cores; holds the sprites - higan/sfc/superscope,justifier: re-enabled display of crosshairs - higan/sfc/superscope: fixed turbo toggle (also shows different crosshair color when in turbo mode) - higan/sfc/ppu: always outputs at 512x480 resolution now - causes a slight speed-hit from ~127fps to ~125fps; - but allows high-resolution 32x32 cursors that look way better; - also avoids the need to implement sprite scaling logic Right now, the PPU code to always output at 480-height is a really gross hack. Don't worry, I'll make that nicer before release. Also, superscope.cpp and justifier.cpp are built around a 256x240 screen. But since we now have 512x480, we can make the cursor's movement much smoother by doubling the resolution on both axes. The actual games won't see any accuracy improvements when firing the light guns, but the cursors will animate nicer so I think it's still worth it. I'll work on that before the next release as well. The current 32x32 cursors are nicer, but we can do better now with full 24-bit color. So feel free to submit alternatives. I'll probably reject them, but you can always try :D The sprites don't support alpha blending, just color keying (0x00000000 = transparent; anything else is 0xff......). We can revisit that later if necessary. The way I have it designed, the only files that do anything with Emulator::Sprite at all are the superscope and justifier folders. I didn't have to add any hooks anywhere else. Rendering the sprite is a lot cleaner than the old code, too.
This commit is contained in:
parent
ae5d380d06
commit
7f3cfa17b9
|
@ -5,7 +5,7 @@ target := tomoko
|
|||
# console := true
|
||||
|
||||
flags += -I. -I.. -O3
|
||||
objects := libco audio video
|
||||
objects := libco audio video resource
|
||||
|
||||
# profile-guided optimization mode
|
||||
# pgo := instrument
|
||||
|
@ -56,6 +56,7 @@ all: build;
|
|||
obj/libco.o: ../libco/libco.c $(call rwildcard,../libco/)
|
||||
obj/audio.o: audio/audio.cpp $(call rwildcard,audio/)
|
||||
obj/video.o: video/video.cpp $(call rwildcard,video/)
|
||||
obj/resource.o: resource/resource.cpp $(call rwildcard,resource/)
|
||||
|
||||
ui := target-$(target)
|
||||
include $(ui)/GNUmakefile
|
||||
|
|
|
@ -5,10 +5,11 @@ using namespace nall;
|
|||
|
||||
#include <audio/audio.hpp>
|
||||
#include <video/video.hpp>
|
||||
#include <resource/resource.hpp>
|
||||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "098.11";
|
||||
static const string Version = "098.12";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
all:
|
||||
sourcery resource.bml resource.cpp resource.hpp
|
|
@ -0,0 +1,5 @@
|
|||
namespace name=Resource
|
||||
namespace name=Sprite
|
||||
binary name=CrosshairRed file=sprite/crosshair-red.png
|
||||
binary name=CrosshairGreen file=sprite/crosshair-green.png
|
||||
binary name=CrosshairBlue file=sprite/crosshair-blue.png
|
|
@ -0,0 +1,46 @@
|
|||
#include <nall/nall.hpp>
|
||||
#include "resource.hpp"
|
||||
|
||||
namespace Resource {
|
||||
namespace Sprite {
|
||||
const nall::vector<uint8_t> CrosshairRed = { //size: 342
|
||||
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122,
|
||||
244,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,14,196,0,0,14,
|
||||
196,1,149,43,14,27,0,0,0,248,73,68,65,84,88,133,205,87,65,14,196,32,8,132,102,255,255,101,246,176,177,139,
|
||||
148,81,80,27,229,212,70,102,6,212,0,50,229,77,26,107,156,37,139,2,228,241,209,39,11,113,71,156,68,139,106,128,
|
||||
56,255,198,175,203,223,114,16,79,68,253,138,90,99,141,113,112,80,231,131,196,11,83,52,19,43,196,53,135,147,7,38,
|
||||
150,104,244,212,32,86,235,228,236,20,6,200,207,191,117,215,70,12,242,94,139,133,166,236,173,236,67,252,111,139,67,157,
|
||||
237,71,48,27,192,244,142,93,228,23,148,144,184,228,131,96,254,3,164,4,176,213,108,37,52,5,208,53,47,227,81,28,
|
||||
49,153,102,163,88,96,149,68,150,193,21,223,59,128,68,43,69,13,103,4,199,246,8,34,151,240,209,249,38,112,251,47,
|
||||
97,177,209,74,152,246,95,93,9,211,51,160,181,99,142,128,104,115,55,124,59,136,115,7,146,237,51,33,2,71,166,226,
|
||||
94,23,13,77,214,104,44,103,174,163,143,86,189,244,187,224,232,151,81,21,132,39,210,33,91,246,54,132,193,44,226,219,
|
||||
107,95,57,136,120,253,172,254,16,23,0,0,0,0,73,69,78,68,174,66,96,130,
|
||||
};
|
||||
const nall::vector<uint8_t> CrosshairGreen = { //size: 329
|
||||
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122,
|
||||
244,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,14,196,0,0,14,
|
||||
196,1,149,43,14,27,0,0,0,235,73,68,65,84,88,133,213,87,65,18,195,32,8,196,78,31,230,211,253,153,61,180,
|
||||
52,18,145,1,193,97,178,39,141,44,139,24,69,11,216,209,133,177,98,117,166,37,92,162,77,176,170,118,223,26,163,78,
|
||||
68,71,145,198,244,169,157,57,35,84,248,43,222,255,109,154,254,113,140,114,102,222,18,239,165,120,251,181,42,0,232,103,
|
||||
114,217,85,226,163,27,124,232,163,87,142,115,153,82,137,71,98,233,247,21,44,228,194,169,217,171,252,159,22,95,234,164,
|
||||
47,129,55,128,144,140,237,166,63,132,151,190,4,247,147,16,103,35,157,90,220,140,119,121,80,224,94,108,0,164,227,119,
|
||||
182,221,229,13,182,82,193,225,176,42,56,59,188,105,9,52,5,3,109,58,243,205,202,203,255,9,17,251,91,202,169,227,
|
||||
205,128,235,198,19,17,64,40,82,171,225,233,32,158,113,33,65,164,222,9,105,16,50,81,55,238,88,210,212,119,1,0,
|
||||
238,241,241,126,143,125,62,216,173,151,209,35,222,134,235,96,98,252,229,226,3,112,72,179,236,202,138,114,18,0,0,0,
|
||||
0,73,69,78,68,174,66,96,130,
|
||||
};
|
||||
const nall::vector<uint8_t> CrosshairBlue = { //size: 332
|
||||
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122,
|
||||
244,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,14,196,0,0,14,
|
||||
196,1,149,43,14,27,0,0,0,238,73,68,65,84,88,133,213,87,91,18,195,32,8,196,78,15,232,81,189,161,253,9,
|
||||
25,52,98,121,57,76,246,43,137,44,11,24,69,11,232,209,55,99,69,235,76,74,184,69,107,229,245,91,27,220,137,124,
|
||||
75,140,58,21,165,34,181,246,199,251,100,167,174,200,32,124,137,119,124,134,177,252,116,108,224,44,120,44,190,156,56,102,
|
||||
163,204,228,182,107,173,80,31,93,225,67,30,189,112,124,85,41,145,120,36,88,191,159,96,33,23,78,101,47,242,127,90,
|
||||
156,213,73,159,2,111,0,33,21,179,150,63,132,151,62,5,243,78,136,217,236,118,173,85,198,86,30,20,152,154,13,192,
|
||||
118,251,125,216,90,121,212,118,215,112,86,224,26,142,133,247,152,2,73,195,64,155,190,248,166,229,229,255,132,8,243,146,
|
||||
242,234,120,43,224,58,241,68,4,16,138,212,110,120,58,136,119,28,72,16,169,103,194,33,136,63,68,209,184,103,74,83,
|
||||
239,5,0,215,26,167,231,123,124,103,130,53,221,140,94,113,55,100,131,9,242,151,139,31,79,50,234,237,105,206,30,22,
|
||||
0,0,0,0,73,69,78,68,174,66,96,130,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace Resource {
|
||||
namespace Sprite {
|
||||
extern const nall::vector<uint8_t> CrosshairRed;
|
||||
extern const nall::vector<uint8_t> CrosshairGreen;
|
||||
extern const nall::vector<uint8_t> CrosshairBlue;
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 332 B |
Binary file not shown.
After Width: | Height: | Size: 329 B |
Binary file not shown.
After Width: | Height: | Size: 342 B |
|
@ -13,6 +13,9 @@ Controller::Controller(bool port) : port(port) {
|
|||
if(!thread) create(Controller::Enter, 1);
|
||||
}
|
||||
|
||||
Controller::~Controller() {
|
||||
}
|
||||
|
||||
auto Controller::Enter() -> void {
|
||||
while(true) {
|
||||
scheduler.synchronize();
|
||||
|
|
|
@ -15,6 +15,7 @@ struct Controller : Cothread {
|
|||
enum : bool { Port1 = 0, Port2 = 1 };
|
||||
|
||||
Controller(bool port);
|
||||
virtual ~Controller();
|
||||
static auto Enter() -> void;
|
||||
|
||||
virtual auto main() -> void;
|
||||
|
|
|
@ -3,17 +3,21 @@ Controller(port),
|
|||
chained(chained),
|
||||
device(chained == false ? Device::Justifier : Device::Justifiers)
|
||||
{
|
||||
create(Controller::Enter, 21477272);
|
||||
create(Controller::Enter, 21'477'272);
|
||||
latched = 0;
|
||||
counter = 0;
|
||||
active = 0;
|
||||
prev = 0;
|
||||
|
||||
player1.sprite = Emulator::video.createSprite(32, 32);
|
||||
player1.sprite->setPixels(Resource::Sprite::CrosshairGreen);
|
||||
player1.x = 256 / 2;
|
||||
player1.y = 240 / 2;
|
||||
player1.trigger = false;
|
||||
player2.start = false;
|
||||
|
||||
player2.sprite = Emulator::video.createSprite(32, 32);
|
||||
player2.sprite->setPixels(Resource::Sprite::CrosshairRed);
|
||||
player2.x = 256 / 2;
|
||||
player2.y = 240 / 2;
|
||||
player2.trigger = false;
|
||||
|
@ -28,14 +32,19 @@ device(chained == false ? Device::Justifier : Device::Justifiers)
|
|||
}
|
||||
}
|
||||
|
||||
auto Justifier::main() -> void {
|
||||
unsigned next = cpu.vcounter() * 1364 + cpu.hcounter();
|
||||
Justifier::~Justifier() {
|
||||
Emulator::video.removeSprite(player1.sprite);
|
||||
Emulator::video.removeSprite(player2.sprite);
|
||||
}
|
||||
|
||||
signed x = (active == 0 ? player1.x : player2.x), y = (active == 0 ? player1.y : player2.y);
|
||||
auto Justifier::main() -> void {
|
||||
uint next = cpu.vcounter() * 1364 + cpu.hcounter();
|
||||
|
||||
int x = (active == 0 ? player1.x : player2.x), y = (active == 0 ? player1.y : player2.y);
|
||||
bool offscreen = (x < 0 || y < 0 || x >= 256 || y >= ppu.vdisp());
|
||||
|
||||
if(offscreen == false) {
|
||||
unsigned target = y * 1364 + (x + 24) * 4;
|
||||
if(!offscreen) {
|
||||
uint target = y * 1364 + (x + 24) * 4;
|
||||
if(next >= target && prev < target) {
|
||||
//CRT raster detected, toggle iobit to latch counters
|
||||
iobit(0);
|
||||
|
@ -50,6 +59,8 @@ auto Justifier::main() -> void {
|
|||
ny1 += player1.y;
|
||||
player1.x = max(-16, min(256 + 16, nx1));
|
||||
player1.y = max(-16, min(240 + 16, ny1));
|
||||
player1.sprite->setPosition(player1.x * 2 - 16, player1.y * 2 - 16);
|
||||
player1.sprite->setVisible(true);
|
||||
}
|
||||
|
||||
if(next < prev && chained) {
|
||||
|
@ -59,6 +70,8 @@ auto Justifier::main() -> void {
|
|||
ny2 += player2.y;
|
||||
player2.x = max(-16, min(256 + 16, nx2));
|
||||
player2.y = max(-16, min(240 + 16, ny2));
|
||||
player2.sprite->setPosition(player2.x * 2 - 16, player2.y * 2 - 16);
|
||||
player2.sprite->setVisible(true);
|
||||
}
|
||||
|
||||
prev = next;
|
||||
|
|
|
@ -4,6 +4,7 @@ struct Justifier : Controller {
|
|||
};
|
||||
|
||||
Justifier(bool port, bool chained);
|
||||
~Justifier();
|
||||
|
||||
auto main() -> void;
|
||||
auto data() -> uint2;
|
||||
|
@ -11,14 +12,17 @@ struct Justifier : Controller {
|
|||
|
||||
//private:
|
||||
const bool chained; //true if the second justifier is attached to the first
|
||||
const unsigned device;
|
||||
const uint device;
|
||||
bool latched;
|
||||
unsigned counter;
|
||||
unsigned prev;
|
||||
uint counter;
|
||||
uint prev;
|
||||
|
||||
bool active;
|
||||
struct Player {
|
||||
signed x, y;
|
||||
bool trigger, start;
|
||||
shared_pointer<Emulator::Sprite> sprite;
|
||||
int x;
|
||||
int y;
|
||||
bool trigger;
|
||||
bool start;
|
||||
} player1, player2;
|
||||
};
|
||||
|
|
|
@ -11,7 +11,10 @@
|
|||
//Note that no commercial game ever utilizes a Super Scope in port 1.
|
||||
|
||||
SuperScope::SuperScope(bool port) : Controller(port) {
|
||||
create(Controller::Enter, 21477272);
|
||||
create(Controller::Enter, 21'477'272);
|
||||
sprite = Emulator::video.createSprite(32, 32);
|
||||
sprite->setPixels(Resource::Sprite::CrosshairGreen);
|
||||
|
||||
latched = 0;
|
||||
counter = 0;
|
||||
|
||||
|
@ -25,18 +28,22 @@ SuperScope::SuperScope(bool port) : Controller(port) {
|
|||
pause = false;
|
||||
offscreen = false;
|
||||
|
||||
turbolock = false;
|
||||
oldturbo = false;
|
||||
triggerlock = false;
|
||||
pauselock = false;
|
||||
|
||||
prev = 0;
|
||||
}
|
||||
|
||||
auto SuperScope::main() -> void {
|
||||
unsigned next = cpu.vcounter() * 1364 + cpu.hcounter();
|
||||
SuperScope::~SuperScope() {
|
||||
Emulator::video.removeSprite(sprite);
|
||||
}
|
||||
|
||||
if(offscreen == false) {
|
||||
unsigned target = y * 1364 + (x + 24) * 4;
|
||||
auto SuperScope::main() -> void {
|
||||
uint next = cpu.vcounter() * 1364 + cpu.hcounter();
|
||||
|
||||
if(!offscreen) {
|
||||
uint target = y * 1364 + (x + 24) * 4;
|
||||
if(next >= target && prev < target) {
|
||||
//CRT raster detected, toggle iobit to latch counters
|
||||
iobit(0);
|
||||
|
@ -53,6 +60,8 @@ auto SuperScope::main() -> void {
|
|||
x = max(-16, min(256 + 16, nx));
|
||||
y = max(-16, min(240 + 16, ny));
|
||||
offscreen = (x < 0 || y < 0 || x >= 256 || y >= ppu.vdisp());
|
||||
sprite->setPosition(x * 2 - 16, y * 2 - 16);
|
||||
sprite->setVisible(true);
|
||||
}
|
||||
|
||||
prev = next;
|
||||
|
@ -65,12 +74,11 @@ auto SuperScope::data() -> uint2 {
|
|||
if(counter == 0) {
|
||||
//turbo is a switch; toggle is edge sensitive
|
||||
bool newturbo = interface->inputPoll(port, Device::SuperScope, Turbo);
|
||||
if(newturbo && !turbo) {
|
||||
if(newturbo && !oldturbo) {
|
||||
turbo = !turbo; //toggle state
|
||||
turbolock = true;
|
||||
} else {
|
||||
turbolock = false;
|
||||
sprite->setPixels(turbo ? Resource::Sprite::CrosshairRed : Resource::Sprite::CrosshairGreen);
|
||||
}
|
||||
oldturbo = newturbo;
|
||||
|
||||
//trigger is a button
|
||||
//if turbo is active, trigger is level sensitive; otherwise, it is edge sensitive
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
struct SuperScope : Controller {
|
||||
shared_pointer<Emulator::Sprite> sprite;
|
||||
|
||||
enum : uint {
|
||||
X, Y, Trigger, Cursor, Turbo, Pause,
|
||||
};
|
||||
|
||||
SuperScope(bool port);
|
||||
~SuperScope();
|
||||
|
||||
auto main() -> void;
|
||||
auto data() -> uint2;
|
||||
auto latch(bool data) -> void;
|
||||
|
||||
//private:
|
||||
private:
|
||||
bool latched;
|
||||
unsigned counter;
|
||||
uint counter;
|
||||
|
||||
signed x, y;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
bool trigger;
|
||||
bool cursor;
|
||||
|
@ -21,9 +25,9 @@ struct SuperScope : Controller {
|
|||
bool pause;
|
||||
bool offscreen;
|
||||
|
||||
bool turbolock;
|
||||
bool oldturbo;
|
||||
bool triggerlock;
|
||||
bool pauselock;
|
||||
|
||||
unsigned prev;
|
||||
uint prev;
|
||||
};
|
||||
|
|
|
@ -227,9 +227,9 @@ auto PPU::frame() -> void {
|
|||
auto PPU::refresh() -> void {
|
||||
auto output = this->output;
|
||||
if(!overscan()) output -= 14 * 512;
|
||||
auto pitch = 1024 >> interlace();
|
||||
auto pitch = 512;
|
||||
auto width = 512;
|
||||
auto height = !interlace() ? 240 : 480;
|
||||
auto height = 480;
|
||||
Emulator::video.refresh(output, pitch * sizeof(uint32), width, height);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,9 @@ PPU::Screen::Screen(PPU& self) : self(self) {
|
|||
}
|
||||
|
||||
auto PPU::Screen::scanline() -> void {
|
||||
line = self.output + self.vcounter() * 1024;
|
||||
if(self.display.interlace && self.field()) line += 512;
|
||||
lineA = self.output + self.vcounter() * 1024;
|
||||
lineB = lineA + (self.display.interlace ? 0 : 512);
|
||||
if(self.display.interlace && self.field()) lineA += 512, lineB += 512;
|
||||
|
||||
//the first hires pixel of each scanline is transparent
|
||||
//note: exact value initializations are not confirmed on hardware
|
||||
|
@ -25,8 +26,8 @@ auto PPU::Screen::run() -> void {
|
|||
auto sscolor = get_pixel_sub(hires);
|
||||
auto mscolor = get_pixel_main();
|
||||
|
||||
*line++ = (self.regs.display_brightness << 15) | (hires ? sscolor : mscolor);
|
||||
*line++ = (self.regs.display_brightness << 15) | (mscolor);
|
||||
*lineA++ = *lineB++ = (self.regs.display_brightness << 15) | (hires ? sscolor : mscolor);
|
||||
*lineA++ = *lineB++ = (self.regs.display_brightness << 15) | (mscolor);
|
||||
}
|
||||
|
||||
auto PPU::Screen::get_pixel_sub(bool hires) -> uint16 {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
struct Screen {
|
||||
uint32* line;
|
||||
uint32* lineA;
|
||||
uint32* lineB;
|
||||
|
||||
struct Regs {
|
||||
bool addsub_mode;
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
Sprite::Sprite(uint width, uint height) : width(width), height(height) {
|
||||
pixels = new uint32[width * height]();
|
||||
}
|
||||
|
||||
Sprite::~Sprite() {
|
||||
delete[] pixels;
|
||||
}
|
||||
|
||||
auto Sprite::setPixels(const nall::image& image) -> void {
|
||||
memory::copy(this->pixels, width * height * sizeof(uint32), image.data(), image.size());
|
||||
}
|
||||
|
||||
auto Sprite::setVisible(bool visible) -> void {
|
||||
this->visible = visible;
|
||||
}
|
||||
|
||||
auto Sprite::setPosition(int x, int y) -> void {
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Emulator {
|
||||
|
||||
#include "sprite.cpp"
|
||||
Video video;
|
||||
|
||||
Video::~Video() {
|
||||
|
@ -10,6 +11,7 @@ Video::~Video() {
|
|||
|
||||
auto Video::reset() -> void {
|
||||
interface = nullptr;
|
||||
sprites.reset();
|
||||
delete output;
|
||||
output = nullptr;
|
||||
delete palette;
|
||||
|
@ -85,6 +87,22 @@ auto Video::setEffect(Effect effect, const any& value) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
auto Video::createSprite(uint width, uint height) -> shared_pointer<Sprite> {
|
||||
shared_pointer<Sprite> sprite = new Sprite{width, height};
|
||||
sprites.append(sprite);
|
||||
return sprite;
|
||||
}
|
||||
|
||||
auto Video::removeSprite(shared_pointer<Sprite> sprite) -> bool {
|
||||
for(uint n : range(sprites)) {
|
||||
if(sprite == sprites[n]) {
|
||||
sprites.remove(n);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto Video::refresh(uint32* input, uint pitch, uint width, uint height) -> void {
|
||||
if(this->width != width || this->height != height) {
|
||||
delete output;
|
||||
|
@ -123,6 +141,23 @@ auto Video::refresh(uint32* input, uint pitch, uint width, uint height) -> void
|
|||
}
|
||||
}
|
||||
|
||||
for(auto& sprite : sprites) {
|
||||
if(!sprite->visible) continue;
|
||||
|
||||
for(int y : range(sprite->height)) {
|
||||
for(int x : range(sprite->width)) {
|
||||
int pixelY = sprite->y + y;
|
||||
if(pixelY < 0 || pixelY >= height) continue;
|
||||
|
||||
int pixelX = sprite->x + x;
|
||||
if(pixelX < 0 || pixelX >= width) continue;
|
||||
|
||||
auto pixel = sprite->pixels[y * sprite->width + x];
|
||||
if(pixel) output[pixelY * width + pixelX] = 0xff000000 | pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface->videoRefresh(output, width * sizeof(uint32), width, height);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
namespace Emulator {
|
||||
|
||||
struct Interface;
|
||||
struct Video;
|
||||
struct Sprite;
|
||||
|
||||
struct Video {
|
||||
enum class Effect : uint {
|
||||
|
@ -22,12 +24,18 @@ struct Video {
|
|||
|
||||
auto setEffect(Effect effect, const any& value) -> void;
|
||||
|
||||
auto createSprite(uint width, uint height) -> shared_pointer<Sprite>;
|
||||
auto removeSprite(shared_pointer<Sprite> sprite) -> bool;
|
||||
|
||||
auto refresh(uint32* input, uint pitch, uint width, uint height) -> void;
|
||||
|
||||
private:
|
||||
Emulator::Interface* interface = nullptr;
|
||||
vector<shared_pointer<Sprite>> sprites;
|
||||
|
||||
uint32* output = nullptr;
|
||||
uint32* palette = nullptr;
|
||||
|
||||
uint width = 0;
|
||||
uint height = 0;
|
||||
uint colors = 0;
|
||||
|
@ -40,6 +48,28 @@ private:
|
|||
bool colorBleed = false;
|
||||
bool interframeBlending = false;
|
||||
} effects;
|
||||
|
||||
friend class Sprite;
|
||||
};
|
||||
|
||||
struct Sprite {
|
||||
Sprite(uint width, uint height);
|
||||
~Sprite();
|
||||
|
||||
auto setPixels(const nall::image& image) -> void;
|
||||
auto setVisible(bool visible) -> void;
|
||||
auto setPosition(int x, int y) -> void;
|
||||
|
||||
private:
|
||||
const uint width;
|
||||
const uint height;
|
||||
uint32* pixels = nullptr;
|
||||
|
||||
bool visible = false;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
friend class Video;
|
||||
};
|
||||
|
||||
extern Video video;
|
||||
|
|
Loading…
Reference in New Issue