From 65f35702871fe06c0f872faf383ddb067718f59f Mon Sep 17 00:00:00 2001 From: bgk Date: Fri, 25 Apr 2008 08:42:43 +0000 Subject: [PATCH] GTK GUI : - Added an OpenGL output module and enabled it by default. - Filters can now be applied with a zoom level != 2 (Xv and OpenGL only). git-svn-id: https://svn.code.sf.net/p/vbam/code/trunk@494 a31d4220-a93d-0410-bf67-fe4944624d44 --- CMakeLists.txt | 6 +- src/gtk/main.cpp | 8 ++ src/gtk/screenarea-opengl.cpp | 178 ++++++++++++++++++++++++++++++++++ src/gtk/screenarea-opengl.h | 59 +++++++++++ src/gtk/screenarea-xvideo.cpp | 2 +- src/gtk/screenarea.cpp | 10 +- src/gtk/window.cpp | 61 ++++++++---- src/gtk/window.h | 9 ++ 8 files changed, 308 insertions(+), 25 deletions(-) create mode 100644 src/gtk/screenarea-opengl.cpp create mode 100644 src/gtk/screenarea-opengl.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d0a6341..1dda9115 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ PKG_CHECK_MODULES ( GLADEMM libglademm-2.4 ) PKG_CHECK_MODULES ( PORTAUDIO portaudio-2.0 ) PKG_CHECK_MODULES ( SDL sdl ) PKG_CHECK_MODULES ( XV xv ) +PKG_CHECK_MODULES ( GTKGLMM gtkglextmm-x11-1.2 ) IF( SDL_FOUND ) SET( CAN_BUILD_VBAM 1 ) @@ -143,6 +144,7 @@ SET(SRC_GTK src/gtk/screenarea.cpp src/gtk/screenarea-gtk.cpp src/gtk/screenarea-xvideo.cpp + src/gtk/screenarea-opengl.cpp src/gtk/tools.cpp src/gtk/window.cpp src/gtk/sndPortAudio.cpp @@ -157,7 +159,8 @@ ENDIF(CMAKE_ASM_COMPILER_LOADED AND USEASM) include_directories( ${GTKMM_INCLUDE_DIRS} ${GLADEMM_INCLUDE_DIRS} - ${SDL_INCLUDE_DIR} + ${SDL_INCLUDE_DIRS} + ${GTKGLMM_INCLUDE_DIRS} ) ADD_LIBRARY ( @@ -210,6 +213,7 @@ IF( CAN_BUILD_GVBAM ) ${GLADEMM_LIBRARIES} ${PORTAUDIO_LIBRARIES} ${XV_LIBRARIES} + ${GTKGLMM_LIBRARIES} ) INSTALL(PROGRAMS gvbam DESTINATION bin) diff --git a/src/gtk/main.cpp b/src/gtk/main.cpp index 4104004a..7a655006 100644 --- a/src/gtk/main.cpp +++ b/src/gtk/main.cpp @@ -24,6 +24,10 @@ #include #include +#ifdef USE_OPENGL +#include +#endif // USE_OPENGL + #include "window.h" #include "intl.h" @@ -43,6 +47,10 @@ int main(int argc, char * argv[]) Gtk::Main oKit(argc, argv); +#ifdef USE_OPENGL + Gtk::GL::init(argc, argv); +#endif // USE_OPENGL + Glib::OptionContext oContext; Glib::OptionGroup oGroup("main_group", _("Main VBA-M options")); diff --git a/src/gtk/screenarea-opengl.cpp b/src/gtk/screenarea-opengl.cpp new file mode 100644 index 00000000..3d6253b7 --- /dev/null +++ b/src/gtk/screenarea-opengl.cpp @@ -0,0 +1,178 @@ +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "screenarea-opengl.h" + +#include + +namespace VBA +{ + +template T min( T x, T y ) { return x < y ? x : y; } +template T max( T x, T y ) { return x > y ? x : y; } + +ScreenAreaGl::ScreenAreaGl(int _iWidth, int _iHeight, int _iScale) : + ScreenArea(_iWidth, _iHeight, _iScale), + m_puiPixels(NULL), + m_puiDelta(NULL), + m_iScaledWidth(_iWidth), + m_iScaledHeight(_iHeight) +{ + Glib::RefPtr glconfig; + + glconfig = Gdk::GL::Config::create(Gdk::GL::MODE_RGB | + // Gdk::GL::MODE_DEPTH | + Gdk::GL::MODE_DOUBLE); + if (!glconfig) + { + fprintf(stderr, "*** OpenGL : Cannot open display.\n"); + throw std::exception(); + } + + set_gl_capability(glconfig); + + vUpdateSize(); +} + +void ScreenAreaGl::on_realize() +{ + Gtk::DrawingArea::on_realize(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glOrtho(0.0, 1.0, 1.0, 0.0, 0.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glClearColor(0.0, 0.0, 0.0, 1.0); +} + +ScreenAreaGl::~ScreenAreaGl() +{ + if (m_puiPixels) + { + delete[] m_puiPixels; + } + + if (m_puiDelta) + { + delete[] m_puiDelta; + } +} + +void ScreenAreaGl::vDrawPixels(u8 * _puiData) +{ + const int iSrcPitch = (m_iWidth + 1) * sizeof(u32); + const int iScaledPitch = (m_iScaledWidth + 1) * sizeof(u32); + + if (m_vFilterIB != NULL) + { + m_vFilterIB(_puiData + iSrcPitch, + iSrcPitch, + m_iWidth, + m_iHeight); + } + + if (m_vFilter2x != NULL) + { + m_vFilter2x(_puiData + iSrcPitch, + iSrcPitch, + m_puiDelta, + (u8 *)m_puiPixels, + iScaledPitch, + m_iWidth, + m_iHeight); + } + else + { + memcpy(m_puiPixels, _puiData + iSrcPitch, m_iHeight * iSrcPitch); + } + + queue_draw_area(0, 0, get_width(), get_height()); +} + +void ScreenAreaGl::vDrawBlackScreen() +{ + if (m_puiPixels && is_realized()) + { + memset(m_puiPixels, 0, m_iHeight * (m_iWidth + 1) * sizeof(u32)); + queue_draw_area(0, 0, get_width(), get_height()); + } +} + +void ScreenAreaGl::vUpdateSize() +{ + if (m_puiPixels) + { + delete[] m_puiPixels; + } + + if (m_puiDelta) + { + delete[] m_puiDelta; + } + + m_iScaledWidth = m_iFilterScale * m_iWidth; + m_iScaledHeight = m_iFilterScale * m_iHeight; + + vOnWidgetResize(); + + m_puiPixels = new u32[(m_iScaledWidth + 1) * m_iScaledHeight]; + m_puiDelta = new u8[(m_iWidth + 2) * (m_iHeight + 2) * sizeof(u32)]; + memset(m_puiDelta, 255, (m_iWidth + 2) * (m_iHeight + 2) * sizeof(u32)); + + set_size_request(m_iScale * m_iWidth, m_iScale * m_iHeight); +} + +void ScreenAreaGl::vOnWidgetResize() +{ + m_dScaleFactor = min(get_height() / (double)m_iScaledHeight, get_width() / (double)m_iScaledWidth); + glViewport(0, 0, get_width(), get_height()); + + m_dAreaTop = 1 - m_dScaleFactor * m_iScaledHeight / (double)get_height(); + m_dAreaLeft = 1 - m_dScaleFactor * m_iScaledWidth / (double)get_width(); +} + +bool ScreenAreaGl::on_configure_event(GdkEventConfigure * event) +{ + vOnWidgetResize(); +} + +bool ScreenAreaGl::on_expose_event(GdkEventExpose * _pstEvent) +{ + Glib::RefPtr glwindow = get_gl_window(); + + glRasterPos2f(-1.0f + m_dAreaLeft, 1.0f - m_dAreaTop); + glPixelZoom(m_dScaleFactor, -m_dScaleFactor); + glPixelStorei(GL_UNPACK_ROW_LENGTH, m_iScaledWidth + 1); + + if (!glwindow->gl_begin(get_gl_context())) + return false; + + glClear( GL_COLOR_BUFFER_BIT ); + + glDrawPixels(m_iScaledWidth, m_iScaledHeight, GL_RGBA, GL_UNSIGNED_BYTE, m_puiPixels); + + glwindow->swap_buffers(); + + glwindow->gl_end(); +} + +} // namespace VBA diff --git a/src/gtk/screenarea-opengl.h b/src/gtk/screenarea-opengl.h new file mode 100644 index 00000000..0e96cd92 --- /dev/null +++ b/src/gtk/screenarea-opengl.h @@ -0,0 +1,59 @@ +// -*- C++ -*- +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifndef __VBA_SCREENAREA_OPENGL_H__ +#define __VBA_SCREENAREA_OPENGL_H__ + +#include "screenarea.h" +#include + +namespace VBA +{ + +class ScreenAreaGl : public ScreenArea, + public Gtk::GL::Widget +{ +public: + ScreenAreaGl(int _iWidth, int _iHeight, int _iScale = 1); + virtual ~ScreenAreaGl(); + void vDrawPixels(u8 * _puiData); + void vDrawBlackScreen(); + +protected: + void on_realize(); + bool on_expose_event(GdkEventExpose * _pstEvent); + bool on_configure_event(GdkEventConfigure * event); + +private: + double m_dAreaTop; + double m_dAreaLeft; + double m_dScaleFactor; + int m_iScaledWidth; + int m_iScaledHeight; + u32 * m_puiPixels; + u8 * m_puiDelta; + + void vUpdateSize(); + void vOnWidgetResize(); +}; + +} // namespace VBA + + +#endif // __VBA_SCREENAREA_OPENGL_H__ diff --git a/src/gtk/screenarea-xvideo.cpp b/src/gtk/screenarea-xvideo.cpp index 8b304476..b9c145f3 100644 --- a/src/gtk/screenarea-xvideo.cpp +++ b/src/gtk/screenarea-xvideo.cpp @@ -141,7 +141,7 @@ void ScreenAreaXv::vDrawPixels(u8 * _puiData) m_iHeight); } - if (m_iScale == 2 && m_vFilter2x != NULL) + if (m_vFilter2x != NULL) { m_vFilter2x(_puiData + iSrcPitch, iSrcPitch, diff --git a/src/gtk/screenarea.cpp b/src/gtk/screenarea.cpp index 139cb7cf..ccd5c707 100644 --- a/src/gtk/screenarea.cpp +++ b/src/gtk/screenarea.cpp @@ -76,11 +76,13 @@ void ScreenArea::vSetScale(int _iScale) { g_return_if_fail(_iScale >= 1); - if (_iScale != m_iScale) + if (_iScale == 1) { - m_iScale = _iScale; - vUpdateSize(); + vSetFilter2x(FilterNone); } + + m_iScale = _iScale; + vUpdateSize(); } void ScreenArea::vSetFilter2x(EFilter2x _eFilter2x) @@ -88,7 +90,7 @@ void ScreenArea::vSetFilter2x(EFilter2x _eFilter2x) m_vFilter2x = pvGetFilter2x(_eFilter2x, FilterDepth32); m_iFilterScale = 1; - if (m_iScale == 2 && m_vFilter2x != NULL) + if (m_vFilter2x != NULL) { m_iFilterScale = 2; } diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index cd56aed8..91c568fd 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -36,6 +36,10 @@ #include "screenarea-gtk.h" #include "screenarea-xvideo.h" +#ifdef USE_OPENGL +#include "screenarea-opengl.h" +#endif // USE_OPENGL + extern int systemRenderedFrames; extern int systemFPS; extern bool debugger; @@ -84,7 +88,9 @@ Window::Window(GtkWindow * _pstWindow, const Glib::RefPtr & _poXml) : m_iFilterIBMin (FirstFilterIB), m_iFilterIBMax (LastFilterIB), m_iJoypadMin (1), - m_iJoypadMax (4) + m_iJoypadMax (4), + m_iVideoOutputMin (OutputGtk), + m_iVideoOutputMax (OutputXvideo) { m_poXml = _poXml; m_poFileOpenDialog = NULL; @@ -858,32 +864,37 @@ Window::~Window() void Window::vInitScreenArea() { Gtk::Alignment * poC; - bool bUseXv; - + poC = dynamic_cast(m_poXml->get_widget("ScreenContainer")); poC->set(Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER, 0.0, 0.0); - bUseXv = m_poDisplayConfig->oGetKey("use_Xv"); - - if (bUseXv) - { - try - { - m_poScreenArea = Gtk::manage(new ScreenAreaXv(m_iScreenWidth, m_iScreenHeight)); + EVideoOutput eVideoOutput = (EVideoOutput)m_poDisplayConfig->oGetKey("output"); - // The Xv screen area can handle resizes - poC->set(Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER, 1.0, 1.0); - } - catch (std::exception e) + try + { + switch (eVideoOutput) { - fprintf(stderr, "Unable to initialise Xv output, falling back to GTK+\n"); - m_poScreenArea = Gtk::manage(new ScreenAreaGtk(m_iScreenWidth, m_iScreenHeight)); +#ifdef USE_OPENGL + case OutputOpenGL: + m_poScreenArea = Gtk::manage(new ScreenAreaGl(m_iScreenWidth, m_iScreenHeight)); + poC->set(Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER, 1.0, 1.0); + break; +#endif // USE_OPENGL + case OutputXvideo: + m_poScreenArea = Gtk::manage(new ScreenAreaXv(m_iScreenWidth, m_iScreenHeight)); + poC->set(Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER, 1.0, 1.0); + break; + case OutputGtk: + default: + m_poScreenArea = Gtk::manage(new ScreenAreaGtk(m_iScreenWidth, m_iScreenHeight)); + break; } } - else + catch (std::exception e) { + fprintf(stderr, "Unable to initialise output, falling back to GTK+\n"); m_poScreenArea = Gtk::manage(new ScreenAreaGtk(m_iScreenWidth, m_iScreenHeight)); } - + poC->add(*m_poScreenArea); vDrawDefaultScreen(); m_poScreenArea->show(); @@ -1000,7 +1011,12 @@ void Window::vInitConfig() m_poDisplayConfig->vSetKey("pause_when_inactive", true ); m_poDisplayConfig->vSetKey("filter2x", FilterNone ); m_poDisplayConfig->vSetKey("filterIB", FilterIBNone ); - m_poDisplayConfig->vSetKey("use_Xv", false ); +#ifdef USE_OPENGL + m_poDisplayConfig->vSetKey("output", OutputOpenGL ); +#else + m_poDisplayConfig->vSetKey("output", OutputGtk ); +#endif // USE_OPENGL + // Sound section // @@ -1173,6 +1189,13 @@ void Window::vCheckConfig() m_poDisplayConfig->vSetKey("filterIB", iAdjusted); } + iValue = m_poDisplayConfig->oGetKey("output"); + iAdjusted = CLAMP(iValue, m_iVideoOutputMin, m_iVideoOutputMax); + if (iValue != iAdjusted) + { + m_poDisplayConfig->vSetKey("output", iAdjusted); + } + // Sound section // sValue = m_poSoundConfig->sGetKey("status"); diff --git a/src/gtk/window.h b/src/gtk/window.h index 819bf35c..23f29a90 100644 --- a/src/gtk/window.h +++ b/src/gtk/window.h @@ -131,6 +131,13 @@ protected: EmulatorSGB2 }; + enum EVideoOutput + { + OutputGtk, + OutputOpenGL, + OutputXvideo + }; + virtual void vOnFileOpen(); virtual void vOnFileLoad(); virtual void vOnFileSave(); @@ -215,6 +222,8 @@ private: const int m_iFilterIBMax; const int m_iJoypadMin; const int m_iJoypadMax; + const int m_iVideoOutputMin; + const int m_iVideoOutputMax; static Window * m_poInstance;