2013-03-15 13:11:33 +00:00
|
|
|
namespace phoenix {
|
|
|
|
|
2013-07-29 09:42:45 +00:00
|
|
|
void pCanvas::setDroppable(bool droppable) {
|
|
|
|
qtCanvas->setAcceptDrops(droppable);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void pCanvas::setGeometry(Geometry geometry) {
|
|
|
|
if(canvas.state.width == 0 || canvas.state.height == 0) rasterize();
|
|
|
|
unsigned width = canvas.state.width;
|
|
|
|
unsigned height = canvas.state.height;
|
|
|
|
if(width == 0) width = widget.state.geometry.width;
|
|
|
|
if(height == 0) height = widget.state.geometry.height;
|
|
|
|
|
|
|
|
if(width < geometry.width) {
|
|
|
|
geometry.x += (geometry.width - width) / 2;
|
|
|
|
geometry.width = width;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(height < geometry.height) {
|
|
|
|
geometry.y += (geometry.height - height) / 2;
|
|
|
|
geometry.height = height;
|
|
|
|
}
|
|
|
|
|
|
|
|
pWidget::setGeometry(geometry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void pCanvas::setMode(Canvas::Mode mode) {
|
|
|
|
rasterize();
|
|
|
|
qtCanvas->update();
|
2011-04-27 08:57:31 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void pCanvas::setSize(Size size) {
|
|
|
|
rasterize();
|
2011-04-27 08:57:31 +00:00
|
|
|
qtCanvas->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void pCanvas::constructor() {
|
|
|
|
qtWidget = qtCanvas = new QtCanvas(*this);
|
2012-01-26 06:50:09 +00:00
|
|
|
qtCanvas->setMouseTracking(true);
|
2011-09-05 03:48:23 +00:00
|
|
|
|
Update to v082r18 release.
byuu says:
There we go, the GUI is nearly feature-complete once again.
All cores now output their native video format (NES={emphasis}{palette},
SNES=BGR555, GameBoy={ bright, normal, darker, darkest }), and are
transformed to RGB555 data that is passed to the video renderer.
The video renderer then uses its internal palette to apply
brightness/contrast/gamma/ramp adjustments and outputs in RGB888 color
space.
This does add in another rendering pass, unfortunately, but it's
a necessary one for universal support.
The plan is to adapt all filters to take RGB555 input, and output RGB555
data as well. By doing this, it will be possible to stack filters.
However, it's a bit complicated: I need to plan how the stacking should
occur (eg we never want to apply scanlines before HQ2x, etc.)
Added input frequency adjustments for all three systems. I can easily
get perfect video/audio sync on all three now, hooray.
Long-term, it seems like we only really need one, and we can do
a video/audio delta to get an adjusted value. But for now, this gets the
job done.
Added audio volume adjust. I left out the balance for now, since it's
obviously impossible to balance the NES' single channel audio (I can
duplicate the channel, and do twice the filtering work, but ... why?)
I replaced NTSC/PAL TV mode selection with an "Enable Overscan"
checkbox. On, you get 240 lines on NES+SNES. Off, you get 224 lines on
NES+SNES.
Also added aspect correction box back. I don't do that gross PAL
distortion shit anymore, sorry PAL people. I just scale up the
54/47*(240/224) aspect correction for overscan off mode.
All memory is loaded and saved now, for all three systems (hooray, now
you can actually play Zelda 1&2.)
Added all of the old bsnes hotkeys, with the exception of capture
screenshot. May add again later. May come up with something a bit
different for extra features.
Re-added the NSS DIP switch setting window. Since geometry is saved,
I didn't want to auto-hide rows, so now you'll see all eight possible
DIPs, and the ones not used are grayed out.
Ultimately, nobody will notice since we only have DIPs for ActRaiser
NSS, and nobody's probably even using the XML file for that anyway.
Whatever, it's nice to have anyway.
Took FitzRoy's advice and single-item combo boxes on the input selection
are disabled, so the user doesn't waste time checking them.
I wanted to leave text so that you know there's not a problem. Qt
disabled radio box items look almost exactly like enabled ones.
Fixed lots of issues in phoenix and extended it a bit. But I was still
having trouble with radio box grouping, so I said fuck it and made the
panels show/hide based instead of append/remove based.
That's all for stuff off the checklist, I did a bunch of other things
I don't recall.
So yeah, I'd say the GUI is 100% usable now. This is my opinion on how
multi-platform GUIs should be done =)
Oh, I figure I should mention, but the NES core is GPLv3, and all future
SNES+GB releases will be as well. It's a move against Microsoft's Metro
store.
2011-09-20 14:04:43 +00:00
|
|
|
pWidget::synchronizeState();
|
2013-11-28 10:29:01 +00:00
|
|
|
rasterize(), qtCanvas->update();
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void pCanvas::destructor() {
|
2013-11-28 10:29:01 +00:00
|
|
|
release();
|
2011-09-05 03:48:23 +00:00
|
|
|
delete qtCanvas;
|
2013-03-15 13:11:33 +00:00
|
|
|
qtWidget = qtCanvas = nullptr;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void pCanvas::orphan() {
|
|
|
|
destructor();
|
|
|
|
constructor();
|
2011-04-27 08:57:31 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void pCanvas::rasterize() {
|
|
|
|
unsigned width = canvas.state.width;
|
|
|
|
unsigned height = canvas.state.height;
|
|
|
|
if(width == 0) width = widget.state.geometry.width;
|
|
|
|
if(height == 0) height = widget.state.geometry.height;
|
|
|
|
|
|
|
|
if(canvas.state.mode != Canvas::Mode::Color) {
|
|
|
|
if(width != surfaceWidth || height != surfaceHeight) release();
|
|
|
|
if(!surface) surface = new QImage(width, height, QImage::Format_ARGB32);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(canvas.state.mode == Canvas::Mode::Gradient) {
|
|
|
|
nall::image image;
|
|
|
|
image.allocate(width, height);
|
Update to v094 release.
byuu says:
This release adds support for game libraries, and substantially improves
Game Boy and Game Boy Color emulation with cycle-based renderers. Many
other changes are also present.
It's very important to note that this release now defaults to optimal
drivers rather than safe drivers. This is particularly important if you
do not have strong OpenGL 3.2 drivers. If performance is bad, go to
Settings -> Configuration -> Advanced, change the video driver, and
restart higan. In the rare case that you have trouble opening higan, you
can edit settings.bml directly and change the setting there. The Windows
safe driver is Direct3D, and the Linux safe driver is XShm.
Also note that although display emulation shaders are now supported,
they have not been included in this release as they are not ready yet.
The support has been built-in anyway, so that they can be tested by
everyone. Once refined, future releases of higan will come with built-in
shaders for each emulated system that simulates the unique display
characteristics of each.
Changelog (since v093):
- sfc: added SA-1 MDR support (fixes SD Gundam G-Next bug)
- sfc: remove random/ and config/, merge to system/ with better
randomization
- gb: improved color emulation palette contrast
- gbc: do not sort sprites by X-priority
- gbc: allow transparency on BG priority pixels
- gbc: VRAM DMA timing and register fixes
- gbc: block invalid VRAM DMA transfer source and target addresses
- gba: added LCD color emulation (without it, colors are grossly
over-saturated)
- gba: removed internal frame blending (use shaders to simulate motion
blur if desired)
- gba: added Game Boy Player support (adds joypad rumble support to
supported games)
- gba: SOUND_CTL_H is readable
- gb/gbc: PPU renderer is now cycle-based (major accuracy improvement)
- gb/gbc: OAM DMA runs in parallel with the CPU
- gb/gbc: only HRAM can be accessed during OAM DMA
- gb/gbc: fixed serialization of games with SRAM
- gb/gbc: disallow up+down or left+right at the same time
- gb/gbc: added weak hipass filter to remove DC bias
- gb/gbc: STAT OAM+Hblank IRQs only trigger during active display
- gb/gbc: fixed underflow in window clamping
- gb/gbc/gba: audio mixes internally at 2MHz now instead of 4MHz (does
not affect accuracy)
- gb/gbc/gba: audio volume reduced for consistency with other systems
- fc/sfc/gb/gbc/gba: cheat codes are now stored in universal, decrypted
format
- ethos: replaced file loader with a proper game library
- ethos: added display emulation shader support
- ethos: added color emulation option to video settings
- ethos: program icon upgraded from 48x48 to 512x512
- ethos: settings and tools windows now use tab frames (less wasted
screen space)
- ethos: default to optimal (video, audio, input) drivers instead of
safest drivers
- ethos: input mapping system completely rewritten to support
hotplugging and unique device mappings
- ruby: added fixes for OpenGL 3.2 on AMD graphics cards
- ruby: quark shaders now support user settings inside of manifest
- ruby: quark shaders can use integral textures (allows display
emulation shaders to work with raw colors)
- ruby: add joypad rumble support
- ruby: XInput (Xbox 360) controllers now support hotplugging
- ruby: added Linux udev joypad driver with hotplug support
- phoenix: fixed a rare null pointer dereference issue on Windows
- port: target -std=c++11 instead of -std=gnu++11 (do not rely on GNU
C++ extensions)
- port: added out-of-the-box compilation support for BSD/Clang 3.3+
- port: applied a few Debian upstream patches
- cheats: updated to mightymo's 2014-01-02 release; decrypted all Game
Genie codes
2014-01-20 08:55:17 +00:00
|
|
|
image.gradient(
|
2013-11-28 10:29:01 +00:00
|
|
|
canvas.state.gradient[0].argb(), canvas.state.gradient[1].argb(), canvas.state.gradient[2].argb(), canvas.state.gradient[3].argb()
|
|
|
|
);
|
|
|
|
memcpy(surface->bits(), image.data, image.size);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(canvas.state.mode == Canvas::Mode::Image) {
|
|
|
|
nall::image image = canvas.state.image;
|
|
|
|
image.scale(width, height);
|
|
|
|
image.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0);
|
|
|
|
memcpy(surface->bits(), image.data, image.size);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(canvas.state.mode == Canvas::Mode::Data) {
|
|
|
|
if(width == canvas.state.width && height == canvas.state.height) {
|
|
|
|
memcpy(surface->bits(), canvas.state.data, width * height * sizeof(uint32_t));
|
|
|
|
} else {
|
|
|
|
memset(surface->bits(), 0x00, width * height * sizeof(uint32_t));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
surfaceWidth = width;
|
|
|
|
surfaceHeight = height;
|
|
|
|
}
|
|
|
|
|
|
|
|
void pCanvas::release() {
|
|
|
|
if(surface == nullptr) return;
|
|
|
|
delete surface;
|
|
|
|
surface = nullptr;
|
|
|
|
surfaceWidth = 0;
|
|
|
|
surfaceHeight = 0;
|
|
|
|
}
|
|
|
|
|
2013-07-29 09:42:45 +00:00
|
|
|
void pCanvas::QtCanvas::dragEnterEvent(QDragEnterEvent* event) {
|
|
|
|
if(event->mimeData()->hasUrls()) {
|
|
|
|
event->acceptProposedAction();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void pCanvas::QtCanvas::dropEvent(QDropEvent* event) {
|
|
|
|
lstring paths = DropPaths(event);
|
|
|
|
if(paths.empty()) return;
|
|
|
|
if(self.canvas.onDrop) self.canvas.onDrop(paths);
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
void pCanvas::QtCanvas::leaveEvent(QEvent* event) {
|
2012-01-26 06:50:09 +00:00
|
|
|
if(self.canvas.onMouseLeave) self.canvas.onMouseLeave();
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
void pCanvas::QtCanvas::mouseMoveEvent(QMouseEvent* event) {
|
2013-03-15 13:11:33 +00:00
|
|
|
if(self.canvas.onMouseMove) self.canvas.onMouseMove({event->pos().x(), event->pos().y()});
|
2012-01-26 06:50:09 +00:00
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
void pCanvas::QtCanvas::mousePressEvent(QMouseEvent* event) {
|
2013-03-15 13:11:33 +00:00
|
|
|
if(!self.canvas.onMousePress) return;
|
2012-01-26 06:50:09 +00:00
|
|
|
switch(event->button()) {
|
|
|
|
case Qt::LeftButton: self.canvas.onMousePress(Mouse::Button::Left); break;
|
|
|
|
case Qt::MidButton: self.canvas.onMousePress(Mouse::Button::Middle); break;
|
|
|
|
case Qt::RightButton: self.canvas.onMousePress(Mouse::Button::Right); break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
void pCanvas::QtCanvas::mouseReleaseEvent(QMouseEvent* event) {
|
2013-03-15 13:11:33 +00:00
|
|
|
if(!self.canvas.onMouseRelease) return;
|
2012-01-26 06:50:09 +00:00
|
|
|
switch(event->button()) {
|
|
|
|
case Qt::LeftButton: self.canvas.onMouseRelease(Mouse::Button::Left); break;
|
|
|
|
case Qt::MidButton: self.canvas.onMouseRelease(Mouse::Button::Middle); break;
|
|
|
|
case Qt::RightButton: self.canvas.onMouseRelease(Mouse::Button::Right); break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
void pCanvas::QtCanvas::paintEvent(QPaintEvent* event) {
|
2013-11-28 10:29:01 +00:00
|
|
|
Canvas& canvas = self.canvas;
|
2011-04-27 08:57:31 +00:00
|
|
|
QPainter painter(self.qtCanvas);
|
2013-11-28 10:29:01 +00:00
|
|
|
|
|
|
|
if(canvas.state.mode == Canvas::Mode::Color) {
|
|
|
|
painter.fillRect(event->rect(), QBrush(QColor(canvas.state.color.red, canvas.state.color.green, canvas.state.color.blue, canvas.state.color.alpha)));
|
|
|
|
} else {
|
|
|
|
painter.drawImage(0, 0, *self.surface);
|
|
|
|
}
|
2011-04-27 08:57:31 +00:00
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
pCanvas::QtCanvas::QtCanvas(pCanvas& self) : self(self) {
|
2011-04-27 08:57:31 +00:00
|
|
|
}
|
2013-03-15 13:11:33 +00:00
|
|
|
|
|
|
|
}
|