Commit | Line | Data |
---|---|---|
cf76e892 JPM |
1 | // OpenGL implementation in Qt |
2 | // Parts of this are blantantly ripped off from BSNES (thanks Byuu!) | |
3 | // | |
4 | // by James Hammons | |
5 | // (C) 2010 Underground Software | |
6 | // | |
7 | // JLH = James Hammons <jlhamm@acm.org> | |
8 | // JPM = Jean-Paul Mari <djipi.mari@gmail.com> | |
9 | // | |
10 | // Who When What | |
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 | |
15 | // | |
16 | ||
17 | #include "glwidget.h" | |
18 | ||
19 | #include "jaguar.h" | |
20 | #include "settings.h" | |
21 | #include "tom.h" | |
22 | ||
23 | #if defined(__GCCWIN32__) || defined(_MSC_VER) | |
24 | #if defined(_MSC_VER) | |
25 | #include <GL/gl.h> | |
26 | #endif | |
27 | // Apparently on win32, various OpenGL constants aren't pulled in. | |
28 | #include <GL/glext.h> | |
29 | #endif | |
30 | ||
31 | ||
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) | |
35 | { | |
36 | // Screen pitch has to be the texture width (in 32-bit pixels)... | |
37 | JaguarSetScreenPitch(1024); | |
38 | setMouseTracking(true); | |
39 | } | |
40 | ||
41 | ||
42 | GLWidget::~GLWidget() | |
43 | { | |
44 | if (buffer) | |
45 | delete[] buffer; | |
46 | } | |
47 | ||
48 | ||
49 | void GLWidget::initializeGL() | |
50 | { | |
51 | format().setDoubleBuffer(true); | |
52 | resizeGL(rasterWidth, rasterHeight); | |
53 | ||
54 | glDisable(GL_ALPHA_TEST); | |
55 | glDisable(GL_BLEND); | |
56 | glDisable(GL_DEPTH_TEST); | |
57 | glDisable(GL_POLYGON_SMOOTH); | |
58 | glDisable(GL_STENCIL_TEST); | |
59 | glEnable(GL_DITHER); | |
60 | glEnable(GL_TEXTURE_2D); | |
61 | glClearColor(0.0, 0.0, 0.0, 0.0); | |
62 | ||
63 | CreateTextures(); | |
64 | } | |
65 | ||
66 | ||
67 | void GLWidget::paintGL() | |
68 | { | |
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. | |
74 | ||
75 | if (!fullscreen) | |
76 | outputWidth = width(); | |
77 | ||
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(); | |
81 | ||
82 | glMatrixMode(GL_PROJECTION); | |
83 | glLoadIdentity(); | |
84 | glOrtho(0, outputWidth, 0, outputHeight, -1.0, 1.0); | |
85 | glViewport(0 + offset, 0, outputWidth, outputHeight); | |
86 | ||
87 | glMatrixMode(GL_MODELVIEW); | |
88 | glLoadIdentity(); | |
89 | ||
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); | |
93 | ||
94 | double w = (double)TOMGetVideoModeWidth() / (double)textureWidth; | |
95 | double h = ((double)rasterHeight * multiplier) / (double)textureHeight; | |
96 | unsigned u = outputWidth; | |
97 | unsigned v = outputHeight; | |
98 | ||
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); | |
104 | glEnd(); | |
105 | } | |
106 | ||
107 | ||
108 | void GLWidget::resizeGL(int /*width*/, int /*height*/) | |
109 | { | |
110 | //kludge [No, this is where it belongs!] | |
111 | rasterHeight = (vjs.hardwareTypeNTSC ? VIRTUAL_SCREEN_HEIGHT_NTSC : VIRTUAL_SCREEN_HEIGHT_PAL); | |
112 | ||
113 | return; | |
114 | } | |
115 | ||
116 | ||
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) | |
122 | { | |
123 | // Seems that power of 2 sizes are still mandatory... | |
124 | textureWidth = 1024; | |
125 | textureHeight = 512; | |
126 | buffer = new uint32_t[textureWidth * textureHeight]; | |
127 | JaguarSetScreenBuffer(buffer); | |
128 | ||
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); | |
135 | } | |
136 | ||
137 | ||
138 | void GLWidget::HandleMouseHiding(void) | |
139 | { | |
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) | |
145 | hideMouseTimeout--; | |
146 | else if (hideMouseTimeout == 0) | |
147 | { | |
148 | hideMouseTimeout--; | |
149 | setCursor(Qt::BlankCursor); | |
150 | } | |
151 | } | |
152 | ||
153 | ||
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) | |
157 | { | |
158 | // Has the mouse been hidden? (-1 means mouse was hidden) | |
159 | if (hideMouseTimeout == -1) | |
160 | setCursor(Qt::ArrowCursor); | |
161 | ||
162 | hideMouseTimeout = 60; | |
163 | } | |
164 | ||
165 | ||
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*/) | |
169 | { | |
170 | CheckAndRestoreMouseCursor(); | |
171 | } | |
172 | ||
173 | ||
174 | #if 0 | |
175 | class RubyGLWidget: public QGLWidget | |
176 | { | |
177 | public: | |
178 | GLuint texture; | |
179 | unsigned textureWidth, textureHeight; | |
180 | ||
181 | uint32_t * buffer; | |
182 | unsigned rasterWidth, rasterHeight; | |
183 | ||
184 | bool synchronize; | |
185 | unsigned filter; | |
186 | ||
187 | void updateSynchronization() { | |
188 | #ifdef __APPLE__ | |
189 | makeCurrent(); | |
190 | CGLContextObj context = CGLGetCurrentContext(); | |
191 | GLint value = synchronize; //0 = draw immediately (no vsync), 1 = draw once per frame (vsync) | |
192 | CGLSetParameter(context, kCGLCPSwapInterval, &value); | |
193 | #endif | |
194 | } | |
195 | } * widget; | |
196 | #endif |