diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 4cddd823..9266cc37 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -13,7 +13,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "106.55"; + static const string Version = "106.56"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "https://byuu.org/"; diff --git a/higan/target-bsnes/presentation/presentation.cpp b/higan/target-bsnes/presentation/presentation.cpp index de2ebc1d..6f60ecc7 100644 --- a/higan/target-bsnes/presentation/presentation.cpp +++ b/higan/target-bsnes/presentation/presentation.cpp @@ -214,29 +214,13 @@ auto Presentation::updateStatusIcon() -> void { icon.fill(0xff202020); if(emulator->loaded()) { - image emblem{program.verified() ? Icon::Emblem::Program : Icon::Emblem::Binary}; + image emblem{program.verified() ? (image)Icon::Emblem::Program : (image)Icon::Emblem::Binary}; icon.impose(image::blend::sourceAlpha, 0, (StatusHeight - 16) / 2, emblem, 0, 0, 16, 16); } statusIcon.setIcon(icon); } -auto Presentation::drawIcon(uint32_t* output, uint length, uint width, uint height) -> void { - return; - - int ox = width - 144; - int oy = height - 128; - if(ox >= 0 && oy >= 0) { - image icon{Resource::Icon}; - icon.alphaBlend(0xff000000); - for(uint y : range(128)) { - auto target = output + (y + oy) * (length >> 2) + ox; - auto source = (uint32_t*)icon.data() + y * 128; - memory::copy(target, source, 128); - } - } -} - auto Presentation::clearViewport() -> void { if(!emulator->loaded()) viewportLayout.setPadding(); if(!visible() || !video) return; @@ -250,7 +234,6 @@ auto Presentation::clearViewport() -> void { auto line = output + y * (length >> 2); for(uint x : range(width)) *line++ = 0xff000000; } - if(!emulator->loaded()) drawIcon(output, length, width, height); video.release(); video.output(); } diff --git a/higan/target-bsnes/presentation/presentation.hpp b/higan/target-bsnes/presentation/presentation.hpp index 0249d442..b36b7f72 100644 --- a/higan/target-bsnes/presentation/presentation.hpp +++ b/higan/target-bsnes/presentation/presentation.hpp @@ -26,7 +26,6 @@ struct Presentation : Window { enum : uint { StatusHeight = 24 }; auto updateStatusIcon() -> void; - auto drawIcon(uint32_t* output, uint length, uint width, uint height) -> void; auto clearViewport() -> void; auto resizeViewport() -> void; auto resizeWindow() -> void; @@ -103,8 +102,8 @@ struct Presentation : Window { VerticalLayout layout{this}; HorizontalLayout viewportLayout{&layout, Size{~0, ~0}, 0}; Viewport viewport{&viewportLayout, Size{~0, ~0}, 0}; - VerticalLayout iconLayout{&viewportLayout, Size{0, ~0}}; - Widget iconSpacer{&iconLayout, Size{144, ~0}}; + VerticalLayout iconLayout{&viewportLayout, Size{0, ~0}, 0}; + Widget iconSpacer{&iconLayout, Size{144, ~0}, 0}; Canvas iconCanvas{&iconLayout, Size{128, 128}, 0}; HorizontalLayout statusLayout{&layout, Size{~0, StatusHeight}, 0}; Label spacerIcon{&statusLayout, Size{8, ~0}, 0}; diff --git a/higan/target-bsnes/program/states.cpp b/higan/target-bsnes/program/states.cpp index cb2cf30e..3205f6c3 100644 --- a/higan/target-bsnes/program/states.cpp +++ b/higan/target-bsnes/program/states.cpp @@ -79,11 +79,15 @@ auto Program::saveState(string filename) -> bool { if(!s.size()) return showMessage({"Failed to save [", prefix, "]"}), false; auto serializerRLE = Encode::RLE(s.data(), s.size()); - image preview; - preview.allocate(screenshot.data, screenshot.pitch, screenshot.width, screenshot.height); - if(preview.width() != 256 || preview.height() != 240) preview.scale(256, 240, true); - preview.transform(0, 15, 0x8000, 0x7c00, 0x03e0, 0x001f); - auto previewRLE = Encode::RLE(preview.data(), preview.size()); + vector previewRLE; + //this can be null if a state is captured before the first frame of video output after power/reset + if(screenshot.data) { + image preview; + preview.copy(screenshot.data, screenshot.pitch, screenshot.width, screenshot.height); + if(preview.width() != 256 || preview.height() != 240) preview.scale(256, 240, true); + preview.transform(0, 15, 0x8000, 0x7c00, 0x03e0, 0x001f); + previewRLE = Encode::RLE(preview.data(), preview.size() / sizeof(uint16_t)); + } vector saveState; saveState.resize(3 * sizeof(uint)); diff --git a/higan/target-bsnes/program/utility.cpp b/higan/target-bsnes/program/utility.cpp index eecf4bf1..72682f6c 100644 --- a/higan/target-bsnes/program/utility.cpp +++ b/higan/target-bsnes/program/utility.cpp @@ -35,7 +35,7 @@ auto Program::captureScreenshot() -> bool { if(emulator->loaded() && screenshot.data) { if(auto filename = screenshotPath()) { image capture; - capture.allocate(screenshot.data, screenshot.pitch, screenshot.width, screenshot.height); + capture.copy(screenshot.data, screenshot.pitch, screenshot.width, screenshot.height); //normalize pixel aspect ratio to 1:1 if(capture.width() == 512 && capture.height() == 240) capture.scale(512, 480, false); //hires diff --git a/higan/target-bsnes/tools/cheat-editor.cpp b/higan/target-bsnes/tools/cheat-editor.cpp index c93849bc..96b26c3c 100644 --- a/higan/target-bsnes/tools/cheat-editor.cpp +++ b/higan/target-bsnes/tools/cheat-editor.cpp @@ -52,10 +52,12 @@ auto CheatDatabase::addCheats() -> void { auto CheatWindow::create() -> void { layout.setPadding(5); + tableLayout.setSize({2, 2}); + tableLayout.cell(0).setAlignment({1.0, 0.5}); + tableLayout.cell(2).setAlignment({1.0, 0.0}); nameLabel.setText("Name:"); nameValue.onActivate([&] { if(acceptButton.enabled()) acceptButton.doActivate(); }); nameValue.onChange([&] { doChange(); }); - codeLayout.setAlignment(0.0); codeLabel.setText("Code(s):"); codeValue.setFont(Font().setFamily(Font::Mono)); codeValue.onChange([&] { doChange(); }); diff --git a/higan/target-bsnes/tools/state-manager.cpp b/higan/target-bsnes/tools/state-manager.cpp index 7a52d498..2bbcf3d9 100644 --- a/higan/target-bsnes/tools/state-manager.cpp +++ b/higan/target-bsnes/tools/state-manager.cpp @@ -149,13 +149,19 @@ auto StateManager::updateSelection() -> void { statePreview.setColor({0, 0, 0}); if(batched.size() == 1) { if(auto saveState = program.loadStateData(batched.first().property("name"))) { - uint skip = memory::readl(saveState.data() + sizeof(uint)); - uint seek = 3 * sizeof(uint) + skip; - auto preview = Decode::RLE(saveState.data() + seek, max(seek, saveState.size()) - seek); - image icon{0, 15, 0x8000, 0x7c00, 0x03e0, 0x001f}; - icon.allocate(preview.data(), 256 * sizeof(uint16_t), 256, 240); - icon.transform(); - statePreview.setIcon(icon); + if(saveState.size() >= 3 * sizeof(uint)) { + uint signature = memory::readl(saveState.data() + 0 * sizeof(uint)); + uint serializer = memory::readl(saveState.data() + 1 * sizeof(uint)); + uint preview = memory::readl(saveState.data() + 2 * sizeof(uint)); + if(signature == Program::State::Signature && preview) { + uint offset = 3 * sizeof(uint) + serializer; + auto preview = Decode::RLE(saveState.data() + offset, max(offset, saveState.size()) - offset); + image icon{0, 15, 0x8000, 0x7c00, 0x03e0, 0x001f}; + icon.copy(preview.data(), 256 * sizeof(uint16_t), 256, 240); + icon.transform(); + statePreview.setIcon(icon); + } + } } } } diff --git a/higan/target-bsnes/tools/tools.hpp b/higan/target-bsnes/tools/tools.hpp index 6602a95a..7061721e 100644 --- a/higan/target-bsnes/tools/tools.hpp +++ b/higan/target-bsnes/tools/tools.hpp @@ -35,15 +35,14 @@ struct CheatWindow : Window { public: VerticalLayout layout{this}; - HorizontalLayout nameLayout{&layout, Size{~0, 0}}; - Label nameLabel{&nameLayout, Size{40, 0}}; - LineEdit nameValue{&nameLayout, Size{~0, 0}}; - HorizontalLayout codeLayout{&layout, Size{~0, ~0}}; - Label codeLabel{&codeLayout, Size{40, 0}}; - TextEdit codeValue{&codeLayout, Size{~0, ~0}}; + TableLayout tableLayout{&layout, Size{~0, ~0}}; + Label nameLabel{&tableLayout, Size{0, 0}}; + LineEdit nameValue{&tableLayout, Size{~0, 0}}; + Label codeLabel{&tableLayout, Size{0, 0}}; + TextEdit codeValue{&tableLayout, Size{~0, ~0}}; HorizontalLayout controlLayout{&layout, Size{~0, 0}}; - Widget spacer{&controlLayout, Size{40, 0}}; - CheckLabel enableOption{&controlLayout, Size{~0, 0}}; + Widget controlSpacer{&controlLayout, Size{~0, 0}}; + CheckLabel enableOption{&controlLayout, Size{0, 0}}; Button acceptButton{&controlLayout, Size{80, 0}}; Button cancelButton{&controlLayout, Size{80, 0}}; }; diff --git a/higan/target-higan/presentation/presentation.cpp b/higan/target-higan/presentation/presentation.cpp index d3bfc641..91af3b9a 100644 --- a/higan/target-higan/presentation/presentation.cpp +++ b/higan/target-higan/presentation/presentation.cpp @@ -116,16 +116,17 @@ Presentation::Presentation() { statusBar.setFont(Font().setBold()); statusBar.setVisible(settings["UserInterface/ShowStatusBar"].boolean()); - image icon{Resource::Icon}; - icon.alphaBlend(0xff000000); - canvas.setIcon(icon).setVisible(false); - - viewport.setDroppable().onDrop([&](auto locations) { - if(!directory::exists(locations(0))) return; - program->gameQueue.append(locations(0)); + viewport.setDroppable().onDrop([&](vector locations) { + if(!locations || !directory::exists(locations.first())) return; + program->gameQueue.append(locations.first()); program->load(); }); + iconLayout.setAlignment(0.0); + image icon{Resource::Icon}; + icon.alphaBlend(0x000000); + iconCanvas.setIcon(icon); + onSize([&] { resizeViewport(false); }); @@ -237,22 +238,6 @@ auto Presentation::updateEmulatorDeviceSelections() -> void { } } -auto Presentation::drawIcon(uint32_t* output, uint length, uint width, uint height) -> void { - return; - - int ox = width - 128; - int oy = height - 128; - if(ox >= 0 && oy >= 0) { - image icon{Resource::Icon}; - icon.alphaBlend(0xff000000); - for(uint y : range(112)) { - auto target = output + (y + oy) * (length >> 2) + ox; - auto source = (uint32_t*)icon.data() + y * 112; - memory::copy(target, source, 112); - } - } -} - auto Presentation::clearViewport() -> void { if(!video) return; @@ -269,7 +254,6 @@ auto Presentation::clearViewport() -> void { auto line = output + y * (length >> 2); for(uint x : range(width)) *line++ = 0xff000000; } - if(!emulator || !emulator->loaded()) drawIcon(output, length, width, height); video->release(); video->output(); } diff --git a/higan/target-higan/presentation/presentation.hpp b/higan/target-higan/presentation/presentation.hpp index 55cde3e9..747d24eb 100644 --- a/higan/target-higan/presentation/presentation.hpp +++ b/higan/target-higan/presentation/presentation.hpp @@ -12,7 +12,6 @@ struct Presentation : Window { Presentation(); auto updateEmulatorMenu() -> void; auto updateEmulatorDeviceSelections() -> void; - auto drawIcon(uint32_t* output, uint length, uint width, uint height) -> void; auto clearViewport() -> void; auto resizeViewport(bool resizeWindow = true) -> void; auto toggleFullScreen() -> void; @@ -79,9 +78,13 @@ struct Presentation : Window { MenuSeparator helpMenuSeparator{&helpMenu}; MenuItem about{&helpMenu}; - FixedLayout layout{this}; - Canvas canvas{&layout, Geometry{0, 0, 1, 1}}; - Viewport viewport{&layout, Geometry{0, 0, 1, 1}}; + VerticalLayout layout{this}; + HorizontalLayout viewportLayout{&layout, Size{~0, ~0}, 0}; + Viewport viewport{&viewportLayout, Size{~0, ~0}, 0}; + VerticalLayout iconLayout{&viewportLayout, Size{0, ~0}, 0}; + Widget iconBefore{&iconLayout, Size{128, ~0}, 0}; + Canvas iconCanvas{&iconLayout, Size{112, 112}, 0}; + Widget iconAfter{&iconLayout, Size{128, 8}, 0}; StatusBar statusBar{this}; }; diff --git a/higan/target-higan/program/game.cpp b/higan/target-higan/program/game.cpp index 0ad55222..6fa70529 100644 --- a/higan/target-higan/program/game.cpp +++ b/higan/target-higan/program/game.cpp @@ -40,6 +40,7 @@ auto Program::load(Emulator::Interface& interface) -> void { updateAudioDriver(); updateAudioEffects(); + presentation->viewportLayout.remove(presentation->iconLayout); presentation->resizeViewport(); presentation->setTitle(emulator->titles().merge(" + ")); presentation->systemMenu.setText(information.name).setVisible(true); @@ -60,6 +61,7 @@ auto Program::unload() -> void { emulator = nullptr; gamePaths.reset(); + presentation->viewportLayout.append(presentation->iconLayout, Size{0, ~0}); presentation->resizeViewport(); presentation->setTitle({"higan v", Emulator::Version}); presentation->systemMenu.setVisible(false); diff --git a/hiro/gtk/window.cpp b/hiro/gtk/window.cpp index 6937b1e3..ca62dc83 100644 --- a/hiro/gtk/window.cpp +++ b/hiro/gtk/window.cpp @@ -349,6 +349,8 @@ auto pWindow::setMaximized(bool maximized) -> void { } auto pWindow::setMaximumSize(Size size) -> void { + if(!state().resizable) size = state().geometry.size(); + //TODO: this doesn't have any effect in GTK2 or GTK3 GdkGeometry geometry; if(size.height()) size.setHeight(size.height() + _menuHeight() + _statusHeight()); @@ -367,8 +369,12 @@ auto pWindow::setMinimized(bool minimized) -> void { } auto pWindow::setMinimumSize(Size size) -> void { - gtk_widget_set_size_request(formContainer, size.width(), size.height()); //for GTK3 + if(!state().resizable) size = state().geometry.size(); + //for GTK3 + gtk_widget_set_size_request(formContainer, size.width(), size.height()); + + //for GTK2 GdkGeometry geometry; if(size.height()) size.setHeight(size.height() + _menuHeight() + _statusHeight()); geometry.min_width = !state().resizable ? state().geometry.width() : size.width() ? size.width() : 1; @@ -400,6 +406,9 @@ auto pWindow::setResizable(bool resizable) -> void { if(auto statusBar = state().statusBar) statusBarVisible = statusBar->visible(); gtk_window_set_has_resize_grip(GTK_WINDOW(widget), resizable && statusBarVisible); #endif + + setMaximumSize(state().maximumSize); + setMinimumSize(state().minimumSize); } auto pWindow::setTitle(const string& title) -> void { diff --git a/hiro/qt/qt.hpp b/hiro/qt/qt.hpp index 95526ce6..50ac3173 100644 --- a/hiro/qt/qt.hpp +++ b/hiro/qt/qt.hpp @@ -184,6 +184,16 @@ public slots: }; #endif +#if defined(Hiro_Label) +struct QtLabel : public QWidget { + Q_OBJECT +public: + QtLabel(pLabel& p) : p(p) {} + auto paintEvent(QPaintEvent*) -> void; + pLabel& p; +}; +#endif + #if defined(Hiro_LineEdit) struct QtLineEdit : public QLineEdit { Q_OBJECT diff --git a/hiro/qt/qt.moc b/hiro/qt/qt.moc index 4cfb678f..0df027f6 100644 --- a/hiro/qt/qt.moc +++ b/hiro/qt/qt.moc @@ -954,6 +954,67 @@ int hiro::QtHorizontalSlider::qt_metacall(QMetaObject::Call _c, int _id, void ** } return _id; } +static const uint qt_meta_data_hiro__QtLabel[] = { + + // content: + 6, // revision + 0, // classname + 0, 0, // classinfo + 0, 0, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 0, // signalCount + + 0 // eod +}; + +static const char qt_meta_stringdata_hiro__QtLabel[] = { + "hiro::QtLabel\0" +}; + +void hiro::QtLabel::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + Q_UNUSED(_o); + Q_UNUSED(_id); + Q_UNUSED(_c); + Q_UNUSED(_a); +} + +const QMetaObjectExtraData hiro::QtLabel::staticMetaObjectExtraData = { + 0, qt_static_metacall +}; + +const QMetaObject hiro::QtLabel::staticMetaObject = { + { &QWidget::staticMetaObject, qt_meta_stringdata_hiro__QtLabel, + qt_meta_data_hiro__QtLabel, &staticMetaObjectExtraData } +}; + +#ifdef Q_NO_DATA_RELOCATION +const QMetaObject &hiro::QtLabel::getStaticMetaObject() { return staticMetaObject; } +#endif //Q_NO_DATA_RELOCATION + +const QMetaObject *hiro::QtLabel::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; +} + +void *hiro::QtLabel::qt_metacast(const char *_clname) +{ + if (!_clname) return 0; + if (!strcmp(_clname, qt_meta_stringdata_hiro__QtLabel)) + return static_cast(const_cast< QtLabel*>(this)); + return QWidget::qt_metacast(_clname); +} + +int hiro::QtLabel::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QWidget::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + return _id; +} static const uint qt_meta_data_hiro__QtLineEdit[] = { // content: diff --git a/hiro/qt/widget/label.cpp b/hiro/qt/widget/label.cpp index 598747bf..2e8624cb 100644 --- a/hiro/qt/widget/label.cpp +++ b/hiro/qt/widget/label.cpp @@ -3,13 +3,10 @@ namespace hiro { auto pLabel::construct() -> void { - qtWidget = qtLabel = new QLabel; + qtWidget = qtLabel = new QtLabel(*this); pWidget::construct(); - setAlignment(state().alignment); - setBackgroundColor(state().backgroundColor); - setForegroundColor(state().foregroundColor); - setText(state().text); + qtLabel->update(); } auto pLabel::destruct() -> void { @@ -23,29 +20,40 @@ auto pLabel::minimumSize() const -> Size { } auto pLabel::setAlignment(Alignment alignment) -> void { - if(!alignment) alignment = {0.0, 0.5}; - qtLabel->setAlignment((Qt::Alignment)CalculateAlignment(alignment)); + qtLabel->update(); } auto pLabel::setBackgroundColor(Color color) -> void { - static auto defaultColor = qtLabel->palette().color(QPalette::Base); + qtLabel->update(); +} - auto palette = qtLabel->palette(); - palette.setColor(QPalette::Base, CreateColor(color, defaultColor)); - qtLabel->setPalette(palette); - qtLabel->setAutoFillBackground((bool)color); +auto pLabel::setFont(const Font& font) -> void { + pWidget::setFont(font); + qtLabel->update(); } auto pLabel::setForegroundColor(Color color) -> void { - static auto defaultColor = qtLabel->palette().color(QPalette::Text); - - auto palette = qtLabel->palette(); - palette.setColor(QPalette::Text, CreateColor(color, defaultColor)); - qtLabel->setPalette(palette); + qtLabel->update(); } auto pLabel::setText(const string& text) -> void { - qtLabel->setText(QString::fromUtf8(text)); + qtLabel->update(); +} + +//QLabel ignores QPalette ... so we have to implement our own Label class atop QWidget ... +auto QtLabel::paintEvent(QPaintEvent* event) -> void { + QPainter painter(p.qtLabel); + if(auto& color = p.state().backgroundColor) { + painter.fillRect(event->rect(), CreateColor(color)); + } + if(auto& text = p.state().text) { + if(auto& color = p.state().foregroundColor) { + QPen pen(CreateColor(color)); + painter.setPen(pen); + } + auto alignment = p.state().alignment ? p.state().alignment : Alignment{0.0, 0.5}; + painter.drawText(event->rect(), CalculateAlignment(alignment), QString::fromUtf8(text)); + } } } diff --git a/hiro/qt/widget/label.hpp b/hiro/qt/widget/label.hpp index 2b413157..0ba3456e 100644 --- a/hiro/qt/widget/label.hpp +++ b/hiro/qt/widget/label.hpp @@ -8,10 +8,11 @@ struct pLabel : pWidget { auto minimumSize() const -> Size override; auto setAlignment(Alignment alignment) -> void; auto setBackgroundColor(Color color) -> void; + auto setFont(const Font& font) -> void override; auto setForegroundColor(Color color) -> void; auto setText(const string& text) -> void; - QLabel* qtLabel = nullptr; + QtLabel* qtLabel = nullptr; }; } diff --git a/hiro/qt/widget/widget.cpp b/hiro/qt/widget/widget.cpp index 03666911..cf5242b3 100644 --- a/hiro/qt/widget/widget.cpp +++ b/hiro/qt/widget/widget.cpp @@ -54,9 +54,6 @@ auto pWidget::setFont(const Font& font) -> void { auto pWidget::setGeometry(Geometry geometry) -> void { if(!qtWidget) return; -// Position displacement = GetDisplacement(&widget); -// geometry.x -= displacement.x; -// geometry.y -= displacement.y; qtWidget->setGeometry(geometry.x(), geometry.y(), geometry.width(), geometry.height()); self().doSize(); } @@ -66,12 +63,6 @@ auto pWidget::setVisible(bool visible) -> void { qtWidget->setVisible(visible); } -//pWidget::constructor() called before p{Derived}::constructor(); ergo qtWidget is not yet valid -//pWidget::synchronizeState() is called to finish construction of p{Derived}::constructor() -//void pWidget::synchronizeState() { -// setFont(widget.font()); -//} - } #endif diff --git a/hiro/qt/window.cpp b/hiro/qt/window.cpp index 22e54977..9028df78 100644 --- a/hiro/qt/window.cpp +++ b/hiro/qt/window.cpp @@ -168,6 +168,7 @@ auto pWindow::setMaximized(bool maximized) -> void { auto pWindow::setMaximumSize(Size size) -> void { static auto maximumSize = qtWindow->maximumSize(); + if(!state().resizable) size = state().geometry.size(); if(size) { qtWindow->setMaximumSize(size.width(), size.height() + _menuHeight() + _statusHeight()); } else { @@ -180,6 +181,7 @@ auto pWindow::setMinimized(bool minimized) -> void { } auto pWindow::setMinimumSize(Size size) -> void { + if(!state().resizable) size = state().geometry.size(); qtWindow->setMinimumSize(size.width(), size.height() + _menuHeight() + _statusHeight()); } @@ -204,12 +206,15 @@ auto pWindow::setModal(bool modal) -> void { auto pWindow::setResizable(bool resizable) -> void { if(resizable) { qtLayout->setSizeConstraint(QLayout::SetDefaultConstraint); - qtContainer->setMinimumSize(state().geometry.width(), state().geometry.height()); + //qtContainer->setMinimumSize(state().geometry.width(), state().geometry.height()); } else { qtLayout->setSizeConstraint(QLayout::SetFixedSize); - qtContainer->setFixedSize(state().geometry.width(), state().geometry.height()); + //qtContainer->setFixedSize(state().geometry.width(), state().geometry.height()); } qtStatusBar->setSizeGripEnabled(resizable); + + setMaximumSize(state().maximumSize); + setMinimumSize(state().minimumSize); } auto pWindow::setTitle(const string& text) -> void { diff --git a/hiro/windows/utility.cpp b/hiro/windows/utility.cpp index 97c95786..4583ad3b 100644 --- a/hiro/windows/utility.cpp +++ b/hiro/windows/utility.cpp @@ -205,20 +205,6 @@ static auto CALLBACK Shared_windowProc(WindowProc windowProc, HWND hwnd, UINT ms break; } - case WM_DRAWITEM: { - auto drawItem = (LPDRAWITEMSTRUCT)lparam; - auto object = (mObject*)GetWindowLongPtr((HWND)drawItem->hwndItem, GWLP_USERDATA); - if(!object) break; - - #if defined(Hiro_TabFrame) - if(auto tabFrame = dynamic_cast(object)) { - return tabFrame->self()->onDrawItem(lparam), true; - } - #endif - - break; - } - case WM_GETMINMAXINFO: { auto info = (LPMINMAXINFO)lparam; auto frameMargin = pWindow->frameMargin(); diff --git a/hiro/windows/widget/tab-frame.cpp b/hiro/windows/widget/tab-frame.cpp index 5700f7f4..cfd2fb51 100644 --- a/hiro/windows/widget/tab-frame.cpp +++ b/hiro/windows/widget/tab-frame.cpp @@ -105,45 +105,28 @@ auto pTabFrame::_buildImageList() -> void { } } +//hide all TabFrameItems, and then display the selected TabFrameItem auto pTabFrame::_synchronizeSizable() -> void { for(auto& item : state().items) { - if(auto& sizable = item->state.sizable) { - sizable->setVisible(item->selected()); - } + if(auto& sizable = item->state.sizable) sizable->setVisible(false); + } + //without this call, widgets from the previous tab will remain visible + //alongside widgets from the newly selected tab for about one frame ... + Application::processEvents(); + uint selected = TabCtrl_GetCurSel(hwnd); + if(auto item = self().item(selected)) { + if(auto& sizable = item->state.sizable) sizable->setVisible(true); } } auto pTabFrame::onChange() -> void { - unsigned selected = TabCtrl_GetCurSel(hwnd); + uint selected = TabCtrl_GetCurSel(hwnd); for(auto& item : state().items) item->state.selected = false; if(auto item = self().item(selected)) item->state.selected = true; _synchronizeSizable(); self().doChange(); } -//called only if TCS_OWNERDRAWFIXED style is used -//this style disables XP/Vista theming of the TabFrame -auto pTabFrame::onDrawItem(LPARAM lparam) -> void { -/* - auto item = (LPDRAWITEMSTRUCT)lparam; - FillRect(item->hDC, &item->rcItem, GetSysColorBrush(COLOR_3DFACE)); - SetBkMode(item->hDC, TRANSPARENT); - SetTextColor(item->hDC, GetSysColor(COLOR_BTNTEXT)); - - unsigned selection = item->itemID; - if(selection < tabFrame.state.text.size()) { - string text = tabFrame.state.text[selection]; - Size size = pFont::size(hfont, text); - unsigned width = item->rcItem.right - item->rcItem.left + 1; - if(tabFrame.state.image[selection]) { - width += size.height + 2; - ImageList_Draw(imageList, selection, item->hDC, item->rcItem.left + (width - size.width) / 2 - (size.height + 3), item->rcItem.top + 2, ILD_NORMAL); - } - TextOut(item->hDC, item->rcItem.left + (width - size.width) / 2, item->rcItem.top + 2, utf16_t(text), text.size()); - } -*/ -} - } #endif diff --git a/hiro/windows/widget/tab-frame.hpp b/hiro/windows/widget/tab-frame.hpp index a96a1723..59fe3b64 100644 --- a/hiro/windows/widget/tab-frame.hpp +++ b/hiro/windows/widget/tab-frame.hpp @@ -13,7 +13,6 @@ struct pTabFrame : pWidget { auto setVisible(bool visible) -> void override; auto onChange() -> void; - auto onDrawItem(LPARAM lparam) -> void; auto _buildImageList() -> void; auto _synchronizeSizable() -> void; diff --git a/nall/image.hpp b/nall/image.hpp index 0623baa6..34380859 100644 --- a/nall/image.hpp +++ b/nall/image.hpp @@ -64,8 +64,8 @@ struct image { inline auto free() -> void; inline auto load(const string& filename) -> bool; + inline auto copy(const void* data, uint pitch, uint width, uint height) -> void; inline auto allocate(uint width, uint height) -> void; - inline auto allocate(const void* data, uint pitch, uint width, uint height) -> void; //fill.hpp inline auto fill(uint64_t color = 0) -> void; diff --git a/nall/image/core.hpp b/nall/image/core.hpp index 4c7bcbaa..933c9a5a 100644 --- a/nall/image/core.hpp +++ b/nall/image/core.hpp @@ -142,6 +142,16 @@ auto image::load(const string& filename) -> bool { return false; } +//assumes image and data are in the same format; pitch is adapted to image +auto image::copy(const void* data, uint pitch, uint width, uint height) -> void { + allocate(width, height); + for(uint y : range(height)) { + auto input = (const uint8_t*)data + y * pitch; + auto output = (uint8_t*)_data + y * this->pitch(); + memory::copy(output, input, width * stride()); + } +} + auto image::allocate(unsigned width, unsigned height) -> void { if(_data && _width == width && _height == height) return; free(); @@ -150,6 +160,7 @@ auto image::allocate(unsigned width, unsigned height) -> void { _data = allocate(_width, _height, stride()); } +//private auto image::allocate(unsigned width, unsigned height, unsigned stride) -> uint8_t* { //allocate 1x1 larger than requested; so that linear interpolation does not require bounds-checking unsigned size = width * height * stride; @@ -159,14 +170,4 @@ auto image::allocate(unsigned width, unsigned height, unsigned stride) -> uint8_ return data; } -//assumes image and data are in the same format; pitch is adapted to image -auto image::allocate(const void* data, uint pitch, uint width, uint height) -> void { - allocate(width, height); - for(uint y : range(height)) { - auto input = (const uint8_t*)data + y * pitch; - auto output = (uint8_t*)_data + y * this->pitch(); - memory::copy(output, input, width * stride()); - } -} - } diff --git a/ruby/audio/asio.cpp b/ruby/audio/asio.cpp index 3587eac2..ed635ec6 100644 --- a/ruby/audio/asio.cpp +++ b/ruby/audio/asio.cpp @@ -1,7 +1,7 @@ #include #include "asio.hpp" -struct AudioASIO : Audio { +struct AudioASIO : AudioDriver { static AudioASIO* instance; AudioASIO& self = *this; AudioASIO(Audio& super) : AudioDriver(super) { instance = this; } diff --git a/ruby/audio/pulseaudio.cpp b/ruby/audio/pulseaudio.cpp index eaa0112c..9a5ccdad 100644 --- a/ruby/audio/pulseaudio.cpp +++ b/ruby/audio/pulseaudio.cpp @@ -1,6 +1,6 @@ #include -struct AudioPulseAudio : Audio { +struct AudioPulseAudio : AudioDriver { AudioPulseAudio& self = *this; AudioPulseAudio(Audio& super) : AudioDriver(super) {} ~AudioPulseAudio() { terminate(); } diff --git a/ruby/audio/wasapi.cpp b/ruby/audio/wasapi.cpp index eb1f2cdd..e6ed1712 100644 --- a/ruby/audio/wasapi.cpp +++ b/ruby/audio/wasapi.cpp @@ -8,22 +8,31 @@ struct AudioWASAPI : AudioDriver { AudioWASAPI& self = *this; - AudioWASAPI(Audio& super) : AudioDriver(super) {} + AudioWASAPI(Audio& super) : AudioDriver(super) { enumerate(); } ~AudioWASAPI() { terminate(); } auto create() -> bool override { - super.setLatency(40); - return initialize(); + IMMDevice* defaultDevice = nullptr; + if(self.enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice) != S_OK) return false; + for(auto& device : self.devices) { + if(device.device != defaultDevice) continue; + super.setDevice(device.name); + super.setLatency(40); + return initialize(); + } + return false; } auto driver() -> string override { return "WASAPI"; } - auto ready() -> bool override { return _ready; } + auto ready() -> bool override { return self.isReady; } auto hasExclusive() -> bool override { return true; } auto hasBlocking() -> bool override { return true; } auto hasDevices() -> vector override { - return _devices; + vector devices; + for(auto& device : self.devices) devices.append(device.name); + return devices; } auto hasChannels() -> vector override { @@ -34,7 +43,7 @@ struct AudioWASAPI : AudioDriver { return {self.frequency}; } - auto availableLatencies() -> vector override { + auto hasLatencies() -> vector override { return {0, 20, 40, 60, 80, 100}; } @@ -45,153 +54,152 @@ struct AudioWASAPI : AudioDriver { auto setLatency(uint latency) -> bool override { return initialize(); } auto clear() -> void override { - _queue.read = 0; - _queue.write = 0; - _queue.count = 0; - _audioClient->Stop(); - _audioClient->Reset(); - _audioClient->Start(); + self.queue.read = 0; + self.queue.write = 0; + self.queue.count = 0; + self.audioClient->Stop(); + self.audioClient->Reset(); + self.audioClient->Start(); } auto output(const double samples[]) -> void override { - for(uint n : range(_channels)) { - _queue.samples[_queue.write][n] = samples[n]; + for(uint n : range(self.channels)) { + self.queue.samples[self.queue.write][n] = samples[n]; } - _queue.write++; - _queue.count++; + self.queue.write++; + self.queue.count++; - if(_queue.count >= _bufferSize) { - if(WaitForSingleObject(_eventHandle, self.blocking ? INFINITE : 0) == WAIT_OBJECT_0) { + if(self.queue.count >= self.bufferSize) { + if(WaitForSingleObject(self.eventHandle, self.blocking ? INFINITE : 0) == WAIT_OBJECT_0) { write(); } } } private: - auto initialize() -> bool { - terminate(); + auto enumerate() -> bool { + if(CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&self.enumerator) != S_OK) return false; - if(CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&_enumerator) != S_OK) return false; - - //enumerate all audio endpoint devices, and select the first to match the device() name IMMDeviceCollection* deviceCollection = nullptr; - if(_enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &deviceCollection) != S_OK) return false; + if(self.enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &deviceCollection) != S_OK) return false; uint deviceCount = 0; if(deviceCollection->GetCount(&deviceCount) != S_OK) return false; for(uint deviceIndex : range(deviceCount)) { IMMDevice* device = nullptr; - if(deviceCollection->Item(deviceIndex, &device) != S_OK) return false; + if(deviceCollection->Item(deviceIndex, &device) != S_OK) continue; IPropertyStore* propertyStore = nullptr; device->OpenPropertyStore(STGM_READ, &propertyStore); PROPVARIANT propVariant; propertyStore->GetValue(PKEY_Device_FriendlyName, &propVariant); - _devices.append((const char*)utf8_t(propVariant.pwszVal)); + Device item; + item.name = (const char*)utf8_t(propVariant.pwszVal); + item.device = device; + self.devices.append(item); propertyStore->Release(); - if(!_audioDevice && _devices.right() == _device) { - _audioDevice = device; - } else { - device->Release(); - } } deviceCollection->Release(); + return true; + } - //if no match is found, choose the default audio endpoint for the device() - if(!_audioDevice) { - if(_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &_audioDevice) != S_OK) return false; + auto initialize() -> bool { + terminate(); + if(auto index = self.devices.find([&](auto& device) { return device.name == self.device; })) { + self.audioDevice = self.devices[*index].device; + } else { + return false; } - if(_audioDevice->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, (void**)&_audioClient) != S_OK) return false; + if(self.audioDevice->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, (void**)&self.audioClient) != S_OK) return false; WAVEFORMATEXTENSIBLE waveFormat = {}; - if(_exclusive) { + if(self.exclusive) { IPropertyStore* propertyStore = nullptr; - if(_audioDevice->OpenPropertyStore(STGM_READ, &propertyStore) != S_OK) return false; + if(self.audioDevice->OpenPropertyStore(STGM_READ, &propertyStore) != S_OK) return false; PROPVARIANT propVariant; if(propertyStore->GetValue(PKEY_AudioEngine_DeviceFormat, &propVariant) != S_OK) return false; waveFormat = *(WAVEFORMATEXTENSIBLE*)propVariant.blob.pBlobData; propertyStore->Release(); - if(_audioClient->GetDevicePeriod(nullptr, &_devicePeriod) != S_OK) return false; - auto latency = max(_devicePeriod, (REFERENCE_TIME)self.latency * 10'000); //1ms to 100ns units - auto result = _audioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, latency, latency, &waveFormat.Format, nullptr); + if(self.audioClient->GetDevicePeriod(nullptr, &self.devicePeriod) != S_OK) return false; + auto latency = max(self.devicePeriod, (REFERENCE_TIME)self.latency * 10'000); //1ms to 100ns units + auto result = self.audioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, latency, latency, &waveFormat.Format, nullptr); if(result == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) { - if(_audioClient->GetBufferSize(&_bufferSize) != S_OK) return false; - _audioClient->Release(); - latency = (REFERENCE_TIME)(10'000 * 1'000 * _bufferSize / waveFormat.Format.nSamplesPerSec); - if(_audioDevice->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, (void**)&_audioClient) != S_OK) return false; - result = _audioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, latency, latency, &waveFormat.Format, nullptr); + if(self.audioClient->GetBufferSize(&self.bufferSize) != S_OK) return false; + self.audioClient->Release(); + latency = (REFERENCE_TIME)(10'000 * 1'000 * self.bufferSize / waveFormat.Format.nSamplesPerSec); + if(self.audioDevice->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, (void**)&self.audioClient) != S_OK) return false; + result = self.audioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, latency, latency, &waveFormat.Format, nullptr); } if(result != S_OK) return false; DWORD taskIndex = 0; - _taskHandle = AvSetMmThreadCharacteristics(L"Pro Audio", &taskIndex); + self.taskHandle = AvSetMmThreadCharacteristics(L"Pro Audio", &taskIndex); } else { WAVEFORMATEX* waveFormatEx = nullptr; - if(_audioClient->GetMixFormat(&waveFormatEx) != S_OK) return false; + if(self.audioClient->GetMixFormat(&waveFormatEx) != S_OK) return false; waveFormat = *(WAVEFORMATEXTENSIBLE*)waveFormatEx; CoTaskMemFree(waveFormatEx); - if(_audioClient->GetDevicePeriod(&_devicePeriod, nullptr)) return false; - auto latency = max(_devicePeriod, (REFERENCE_TIME)self.latency * 10'000); //1ms to 100ns units - if(_audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, latency, 0, &waveFormat.Format, nullptr) != S_OK) return false; + if(self.audioClient->GetDevicePeriod(&self.devicePeriod, nullptr)) return false; + auto latency = max(self.devicePeriod, (REFERENCE_TIME)self.latency * 10'000); //1ms to 100ns units + if(self.audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, latency, 0, &waveFormat.Format, nullptr) != S_OK) return false; } - _eventHandle = CreateEvent(nullptr, false, false, nullptr); - if(_audioClient->SetEventHandle(_eventHandle) != S_OK) return false; - if(_audioClient->GetService(IID_IAudioRenderClient, (void**)&_renderClient) != S_OK) return false; - if(_audioClient->GetBufferSize(&_bufferSize) != S_OK) return false; + self.eventHandle = CreateEvent(nullptr, false, false, nullptr); + if(self.audioClient->SetEventHandle(self.eventHandle) != S_OK) return false; + if(self.audioClient->GetService(IID_IAudioRenderClient, (void**)&self.renderClient) != S_OK) return false; + if(self.audioClient->GetBufferSize(&self.bufferSize) != S_OK) return false; self.channels = waveFormat.Format.nChannels; self.frequency = waveFormat.Format.nSamplesPerSec; - _mode = waveFormat.SubFormat.Data1; - _precision = waveFormat.Format.wBitsPerSample; + self.mode = waveFormat.SubFormat.Data1; + self.precision = waveFormat.Format.wBitsPerSample; - _ready = true; + self.isReady = true; clear(); return true; } auto terminate() -> void { - _ready = false; - _devices.reset(); - if(_audioClient) _audioClient->Stop(); - if(_renderClient) _renderClient->Release(), _renderClient = nullptr; - if(_audioClient) _audioClient->Release(), _audioClient = nullptr; - if(_audioDevice) _audioDevice->Release(), _audioDevice = nullptr; - if(_eventHandle) CloseHandle(_eventHandle), _eventHandle = nullptr; - if(_taskHandle) AvRevertMmThreadCharacteristics(_taskHandle), _taskHandle = nullptr; + self.isReady = false; + if(self.audioClient) self.audioClient->Stop(); + if(self.renderClient) self.renderClient->Release(), self.renderClient = nullptr; + if(self.audioClient) self.audioClient->Release(), self.audioClient = nullptr; + if(self.audioDevice) self.audioDevice->Release(), self.audioDevice = nullptr; + if(self.eventHandle) CloseHandle(self.eventHandle), self.eventHandle = nullptr; + if(self.taskHandle) AvRevertMmThreadCharacteristics(self.taskHandle), self.taskHandle = nullptr; } auto write() -> void { - uint32_t available = _bufferSize; - if(!_exclusive) { + uint32_t available = self.bufferSize; + if(!self.exclusive) { uint32_t padding = 0; - _audioClient->GetCurrentPadding(&padding); - available = _bufferSize - padding; + self.audioClient->GetCurrentPadding(&padding); + available = self.bufferSize - padding; } - uint32_t length = min(available, _queue.count); + uint32_t length = min(available, self.queue.count); uint8_t* buffer = nullptr; - if(_renderClient->GetBuffer(length, &buffer) == S_OK) { + if(self.renderClient->GetBuffer(length, &buffer) == S_OK) { uint bufferFlags = 0; for(uint _ : range(length)) { double samples[8] = {}; - if(_queue.count) { - for(uint n : range(_channels)) { - samples[n] = _queue.samples[_queue.read][n]; + if(self.queue.count) { + for(uint n : range(self.channels)) { + samples[n] = self.queue.samples[self.queue.read][n]; } - _queue.read++; - _queue.count--; + self.queue.read++; + self.queue.count--; } - if(_mode == 1 && _precision == 16) { + if(self.mode == 1 && self.precision == 16) { auto output = (uint16_t*)buffer; - for(uint n : range(_channels)) *output++ = (uint16_t)sclamp<16>(samples[n] * (32768.0 - 1.0)); + for(uint n : range(self.channels)) *output++ = (uint16_t)sclamp<16>(samples[n] * (32768.0 - 1.0)); buffer = (uint8_t*)output; - } else if(_mode == 1 && _precision == 32) { + } else if(self.mode == 1 && self.precision == 32) { auto output = (uint32_t*)buffer; - for(uint n : range(_channels)) *output++ = (uint32_t)sclamp<32>(samples[n] * (65536.0 * 32768.0 - 1.0)); + for(uint n : range(self.channels)) *output++ = (uint32_t)sclamp<32>(samples[n] * (65536.0 * 32768.0 - 1.0)); buffer = (uint8_t*)output; - } else if(_mode == 3 && _precision == 32) { + } else if(self.mode == 3 && self.precision == 32) { auto output = (float*)buffer; - for(uint n : range(_channels)) *output++ = float(max(-1.0, min(+1.0, samples[n]))); + for(uint n : range(self.channels)) *output++ = float(max(-1.0, min(+1.0, samples[n]))); buffer = (uint8_t*)output; } else { //output silence for unsupported sample formats @@ -199,29 +207,34 @@ private: break; } } - _renderClient->ReleaseBuffer(length, bufferFlags); + self.renderClient->ReleaseBuffer(length, bufferFlags); } } - bool _ready = false; + bool isReady = false; - uint _mode = 0; - uint _precision = 0; + uint mode = 0; + uint precision = 0; + + struct Device { + string name; + IMMDevice* device; + }; struct Queue { double samples[65536][8]; uint16_t read; uint16_t write; uint16_t count; - } _queue; + } queue; - IMMDeviceEnumerator* _enumerator = nullptr; - vector _devices; - IMMDevice* _audioDevice = nullptr; - IAudioClient* _audioClient = nullptr; - IAudioRenderClient* _renderClient = nullptr; - HANDLE _eventHandle = nullptr; - HANDLE _taskHandle = nullptr; - REFERENCE_TIME _devicePeriod = 0; - uint32_t _bufferSize = 0; //in frames + IMMDeviceEnumerator* enumerator = nullptr; + vector devices; + IMMDevice* audioDevice = nullptr; + IAudioClient* audioClient = nullptr; + IAudioRenderClient* renderClient = nullptr; + HANDLE eventHandle = nullptr; + HANDLE taskHandle = nullptr; + REFERENCE_TIME devicePeriod = 0; + uint32_t bufferSize = 0; //in frames }; diff --git a/ruby/audio/xaudio2.cpp b/ruby/audio/xaudio2.cpp index 5f75a7fb..b8058e7e 100644 --- a/ruby/audio/xaudio2.cpp +++ b/ruby/audio/xaudio2.cpp @@ -7,6 +7,7 @@ struct AudioXAudio2 : AudioDriver, public IXAudio2VoiceCallback { ~AudioXAudio2() { terminate(); } auto create() -> bool override { + super.setChannels(2); super.setFrequency(48000); super.setLatency(40); return initialize(); @@ -85,11 +86,11 @@ private: if(deviceDetails.Role & DefaultGameDevice) deviceID = deviceIndex; } - if(FAILED(_interface->CreateMasteringVoice(&_masterVoice, _channels, self.frequency, 0, deviceID, nullptr))) return terminate(), false; + if(FAILED(_interface->CreateMasteringVoice(&_masterVoice, self.channels, self.frequency, 0, deviceID, nullptr))) return terminate(), false; WAVEFORMATEX waveFormat; waveFormat.wFormatTag = WAVE_FORMAT_PCM; - waveFormat.nChannels = _channels; + waveFormat.nChannels = self.channels; waveFormat.nSamplesPerSec = self.frequency; waveFormat.nBlockAlign = 4; waveFormat.wBitsPerSample = 16; diff --git a/ruby/input/windows.cpp b/ruby/input/windows.cpp index 0e5b9ea3..3055e15a 100644 --- a/ruby/input/windows.cpp +++ b/ruby/input/windows.cpp @@ -10,7 +10,7 @@ struct InputWindows : InputDriver { InputWindows& self = *this; - InputWindows(Input& driver) : InputDriver(super), keyboard(super), mouse(super), joypadXInput(super), joypadDirectInput(super) {} + InputWindows(Input& super) : InputDriver(super), keyboard(super), mouse(super), joypadXInput(super), joypadDirectInput(super) {} ~InputWindows() { terminate(); } auto create() -> bool override { @@ -48,6 +48,7 @@ private: terminate(); if(!self.context) return false; + //TODO: this won't work if Input is recreated post-initialization; nor will it work with multiple Input instances if(!rawinput.initialized) { rawinput.initialized = true; rawinput.mutex = CreateMutex(nullptr, false, nullptr); diff --git a/ruby/video/direct3d.cpp b/ruby/video/direct3d.cpp index 4258d9fc..e5342016 100644 --- a/ruby/video/direct3d.cpp +++ b/ruby/video/direct3d.cpp @@ -56,7 +56,7 @@ struct VideoDirect3D : VideoDriver { //if output size changed, driver must be re-initialized. //failure to do so causes scaling issues on some video drivers. RECT rectangle; - GetClientRect((HWND)_context, &rectangle); + GetClientRect((HWND)self.context, &rectangle); if(_windowWidth != rectangle.right || _windowHeight != rectangle.bottom) initialize(); if(width != _inputWidth || height != _inputHeight) { @@ -84,7 +84,7 @@ struct VideoDirect3D : VideoDriver { _device->BeginScene(); uint x = 0, y = 0; - if(_exclusive) { + if(self.exclusive) { //center output in exclusive mode fullscreen window x = (_monitorWidth - _windowWidth) / 2; y = (_monitorHeight - _windowHeight) / 2; @@ -94,7 +94,7 @@ struct VideoDirect3D : VideoDriver { _device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); _device->EndScene(); - if(_blocking) { + if(self.blocking) { D3DRASTER_STATUS status; while(true) { //wait for a previous vblank to finish, if necessary _device->GetRasterStatus(0, &status); @@ -169,7 +169,7 @@ private: if(!_device) return false; if(_lost && !recover()) return false; - auto filter = !_smooth ? D3DTEXF_POINT : D3DTEXF_LINEAR; + auto filter = !self.smooth ? D3DTEXF_POINT : D3DTEXF_LINEAR; _device->SetSamplerState(0, D3DSAMP_MINFILTER, filter); _device->SetSamplerState(0, D3DSAMP_MAGFILTER, filter); return true; @@ -209,9 +209,9 @@ private: auto initialize() -> bool { terminate(); - if(!_context) return false; + if(!self.context) return false; - HMONITOR monitor = MonitorFromWindow((HWND)_context, MONITOR_DEFAULTTOPRIMARY); + HMONITOR monitor = MonitorFromWindow((HWND)self.context, MONITOR_DEFAULTTOPRIMARY); MONITORINFOEX information = {}; information.cbSize = sizeof(MONITORINFOEX); GetMonitorInfo(monitor, &information); @@ -236,7 +236,7 @@ private: nullptr, nullptr, GetModuleHandle(0), nullptr); RECT rectangle; - GetClientRect((HWND)_context, &rectangle); + GetClientRect((HWND)self.context, &rectangle); _windowWidth = rectangle.right; _windowHeight = rectangle.bottom; @@ -253,15 +253,15 @@ private: _presentation.AutoDepthStencilFormat = D3DFMT_UNKNOWN; _presentation.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; - if(!_exclusive) { - _presentation.hDeviceWindow = (HWND)_context; + if(!self.exclusive) { + _presentation.hDeviceWindow = (HWND)self.context; _presentation.Windowed = true; _presentation.BackBufferFormat = D3DFMT_UNKNOWN; _presentation.BackBufferWidth = 0; _presentation.BackBufferHeight = 0; ShowWindow((HWND)_exclusiveContext, SW_HIDE); - if(_instance->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, (HWND)_context, + if(_instance->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, (HWND)self.context, D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &_presentation, &_device) != D3D_OK) { return false; }