1 // OpenGL implementation in Qt
2 // Parts of this are blantantly ripped off from BSNES (thanks Byuu!)
5 // (C) 2010 Underground Software
7 // JLH = James Hammons <jlhamm@acm.org>
8 // JPM = Jean-Paul Mari <djipi.mari@gmail.com>
11 // --- ---------- -------------------------------------------------------------
12 // JLH 01/14/2010 Created this file
13 // JLH 02/03/2013 Added "centered" fullscreen mode with correct aspect ratio
14 // JPM 06/06/2016 Visual Studio support
23 #if defined(__GCCWIN32__) || defined(_MSC_VER)
27 // Apparently on win32, various OpenGL constants aren't pulled in.
32 GLWidget::GLWidget(QWidget
* parent
/*= 0*/): QGLWidget(parent
), texture(0),
33 textureWidth(0), textureHeight(0), buffer(0), rasterWidth(326), rasterHeight(240),
34 offset(0), hideMouseTimeout(60)
36 // Screen pitch has to be the texture width (in 32-bit pixels)...
37 JaguarSetScreenPitch(1024);
38 setMouseTracking(true);
49 void GLWidget::initializeGL()
51 format().setDoubleBuffer(true);
52 resizeGL(rasterWidth
, rasterHeight
);
54 glDisable(GL_ALPHA_TEST
);
56 glDisable(GL_DEPTH_TEST
);
57 glDisable(GL_POLYGON_SMOOTH
);
58 glDisable(GL_STENCIL_TEST
);
60 glEnable(GL_TEXTURE_2D
);
61 glClearColor(0.0, 0.0, 0.0, 0.0);
67 void GLWidget::paintGL()
69 // If we're in fullscreen mode, we take the value of the screen width as
70 // set by MainWin, since it may be wider than what our aspect ratio allows.
71 // In that case, we adjust the viewport over so that it's centered on the
72 // screen. Otherwise, we simply take the width from our width() funtion
73 // which will always be correct in windowed mode.
76 outputWidth
= width();
78 // Bit 0 in VP is interlace flag. 0 = interlace, 1 = non-interlaced
79 double multiplier
= (TOMGetVP() & 0x0001 ? 1.0 : 2.0);
80 unsigned outputHeight
= height();
82 glMatrixMode(GL_PROJECTION
);
84 glOrtho(0, outputWidth
, 0, outputHeight
, -1.0, 1.0);
85 glViewport(0 + offset
, 0, outputWidth
, outputHeight
);
87 glMatrixMode(GL_MODELVIEW
);
90 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, (vjs
.glFilter
? GL_LINEAR
: GL_NEAREST
));
91 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, (vjs
.glFilter
? GL_LINEAR
: GL_NEAREST
));
92 glTexSubImage2D(GL_TEXTURE_2D
, 0, 0, 0, TOMGetVideoModeWidth(), rasterHeight
* multiplier
, GL_RGBA
, GL_UNSIGNED_INT_8_8_8_8
, buffer
);
94 double w
= (double)TOMGetVideoModeWidth() / (double)textureWidth
;
95 double h
= ((double)rasterHeight
* multiplier
) / (double)textureHeight
;
96 unsigned u
= outputWidth
;
97 unsigned v
= outputHeight
;
99 glBegin(GL_TRIANGLE_STRIP
);
100 glTexCoord2f(0, 0); glVertex3i(0, v
, 0);
101 glTexCoord2f(w
, 0); glVertex3i(u
, v
, 0);
102 glTexCoord2f(0, h
); glVertex3i(0, 0, 0);
103 glTexCoord2f(w
, h
); glVertex3i(u
, 0, 0);
108 void GLWidget::resizeGL(int /*width*/, int /*height*/)
110 //kludge [No, this is where it belongs!]
111 rasterHeight
= (vjs
.hardwareTypeNTSC
? VIRTUAL_SCREEN_HEIGHT_NTSC
: VIRTUAL_SCREEN_HEIGHT_PAL
);
117 // At some point, we'll have to create more than one texture to handle
118 // cases like Doom. Or have another go at TV type rendering; it will
119 // require a 2048x512 texture though. (Note that 512 is the correct height for
120 // interlaced screens; we won't have to change much here to support it.)
121 void GLWidget::CreateTextures(void)
123 // Seems that power of 2 sizes are still mandatory...
126 buffer
= new uint32_t[textureWidth
* textureHeight
];
127 JaguarSetScreenBuffer(buffer
);
129 glGenTextures(1, &texture
);
130 glBindTexture(GL_TEXTURE_2D
, texture
);
131 glPixelStorei(GL_UNPACK_ROW_LENGTH
, textureWidth
);
132 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
133 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
134 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGB
, textureWidth
, textureHeight
, 0, GL_RGBA
, GL_UNSIGNED_INT_8_8_8_8
, NULL
);
138 void GLWidget::HandleMouseHiding(void)
140 // Mouse watchdog timer handling. Basically, if the timeout value is
141 // greater than zero, decrement it. Otherwise, check for zero, if so, then
142 // hide the mouse and set the hideMouseTimeout value to -1 to signal that
143 // the mouse has been hidden.
144 if (hideMouseTimeout
> 0)
146 else if (hideMouseTimeout
== 0)
149 setCursor(Qt::BlankCursor
);
154 // We use this as part of a watchdog system for hiding/unhiding the mouse. This
155 // part shows the mouse (if hidden) and resets the watchdog timer.
156 void GLWidget::CheckAndRestoreMouseCursor(void)
158 // Has the mouse been hidden? (-1 means mouse was hidden)
159 if (hideMouseTimeout
== -1)
160 setCursor(Qt::ArrowCursor
);
162 hideMouseTimeout
= 60;
166 // We check here for mouse movement; if there is any, show the mouse and reset
167 // the watchdog timer.
168 void GLWidget::mouseMoveEvent(QMouseEvent
* /*event*/)
170 CheckAndRestoreMouseCursor();
175 class RubyGLWidget
: public QGLWidget
179 unsigned textureWidth
, textureHeight
;
182 unsigned rasterWidth
, rasterHeight
;
187 void updateSynchronization() {
190 CGLContextObj context
= CGLGetCurrentContext();
191 GLint value
= synchronize
; //0 = draw immediately (no vsync), 1 = draw once per frame (vsync)
192 CGLSetParameter(context
, kCGLCPSwapInterval
, &value
);