| 1 | /****************************************************************************** |
| 2 | * Arachnoid Graphics Plugin for Mupen64Plus |
| 3 | * http://bitbucket.org/wahrhaft/mupen64plus-video-arachnoid/ |
| 4 | * |
| 5 | * Copyright (C) 2007 Kristofer Karlsson, Rickard Niklasson |
| 6 | * |
| 7 | * This program is free software; you can redistribute it and/or |
| 8 | * modify it under the terms of the GNU General Public License |
| 9 | * as published by the Free Software Foundation; either version 2 |
| 10 | * of the License, or (at your option) any later version. |
| 11 | * |
| 12 | * This program is distributed in the hope that it will be useful, |
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | * GNU General Public License for more details. |
| 16 | * |
| 17 | * You should have received a copy of the GNU General Public License |
| 18 | * along with this program; if not, write to the Free Software |
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 20 | *****************************************************************************/ |
| 21 | |
| 22 | #include "FrameBuffer.h" |
| 23 | #include "m64p.h" |
| 24 | #include "OpenGL.h" |
| 25 | |
| 26 | #ifndef GL_GLEXT_VERSION |
| 27 | #ifndef HAVE_GLES |
| 28 | //----------------------------------------------------------------------------- |
| 29 | //OpenGL Texture Definitions |
| 30 | //----------------------------------------------------------------------------- |
| 31 | typedef GLvoid (APIENTRY *PFNGLACTIVETEXTUREPROC) (GLenum texture); |
| 32 | PFNGLACTIVETEXTUREPROC glActiveTexture = NULL; |
| 33 | #endif |
| 34 | #endif |
| 35 | |
| 36 | #ifndef GL_TEXTURE0 |
| 37 | #define GL_TEXTURE0 0x84C0 |
| 38 | #endif |
| 39 | #ifndef GL_CLAMP_TO_EDGE |
| 40 | #define GL_CLAMP_TO_EDGE 0x812F |
| 41 | #endif |
| 42 | |
| 43 | //----------------------------------------------------------------------------- |
| 44 | //! Constructor |
| 45 | //----------------------------------------------------------------------------- |
| 46 | FrameBuffer::FrameBuffer() |
| 47 | { |
| 48 | m_id = ~0U; |
| 49 | } |
| 50 | |
| 51 | //----------------------------------------------------------------------------- |
| 52 | //! Destructor |
| 53 | //----------------------------------------------------------------------------- |
| 54 | FrameBuffer::~FrameBuffer() |
| 55 | { |
| 56 | |
| 57 | } |
| 58 | |
| 59 | //----------------------------------------------------------------------------- |
| 60 | //* Initialize |
| 61 | //! @param width Width of framebuffer, usually equal to window-client-width |
| 62 | //! @param height Height of framebuffer, usually equal to window-client-height |
| 63 | //----------------------------------------------------------------------------- |
| 64 | void FrameBuffer::initialize(int width, int height) |
| 65 | { |
| 66 | //Save parameters |
| 67 | m_width = width; |
| 68 | m_height = height; |
| 69 | int channels = 3; //!< RGB=3 or RGBA=4 |
| 70 | |
| 71 | //Allocate memory |
| 72 | unsigned char* data = new unsigned char[width * height * channels]; |
| 73 | memset(data, 0, width * height * channels * sizeof(unsigned char)); |
| 74 | |
| 75 | //Register the texture with OpenGL and bind it to the texture ID |
| 76 | glGenTextures(1, &m_id); |
| 77 | glBindTexture(GL_TEXTURE_2D, m_id); |
| 78 | |
| 79 | //Create the texture and store it on the video card |
| 80 | #ifdef HAVE_GLES |
| 81 | if (channels == 3) |
| 82 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); |
| 83 | else |
| 84 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); |
| 85 | #else |
| 86 | glTexImage2D(GL_TEXTURE_2D, 0, channels, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); |
| 87 | #endif |
| 88 | |
| 89 | //No texure filtering |
| 90 | //glPixelStorei(GL_UNPACK_ALIGNMENT, 1 ); |
| 91 | //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| 92 | //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| 93 | |
| 94 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 95 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| 96 | |
| 97 | //Clamp texture to edges |
| 98 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 99 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 100 | |
| 101 | //Delete data (no need for it when it is stored in video card) |
| 102 | delete[] data; |
| 103 | data = 0; |
| 104 | } |
| 105 | |
| 106 | //----------------------------------------------------------------------------- |
| 107 | // Dispose |
| 108 | //----------------------------------------------------------------------------- |
| 109 | void FrameBuffer::dispose() |
| 110 | { |
| 111 | if ( m_id != ~0U ) |
| 112 | { |
| 113 | glDeleteTextures(1, &m_id); |
| 114 | m_id = -1; |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | //----------------------------------------------------------------------------- |
| 119 | // Resize |
| 120 | //----------------------------------------------------------------------------- |
| 121 | void FrameBuffer::resize(int width, int height) |
| 122 | { |
| 123 | dispose(); |
| 124 | initialize(width, height); |
| 125 | } |
| 126 | |
| 127 | //----------------------------------------------------------------------------- |
| 128 | //* Begin Rendering |
| 129 | //! |
| 130 | //----------------------------------------------------------------------------- |
| 131 | void FrameBuffer::beginRendering() |
| 132 | { |
| 133 | //Get viewport |
| 134 | glGetIntegerv(GL_VIEWPORT, m_oldViewport); |
| 135 | |
| 136 | //Set new viewport for texture |
| 137 | //glViewport(0, 20, m_width, m_height); |
| 138 | |
| 139 | //glClearColor(0.0f, 0.0f, 1.0f, 1.0f); |
| 140 | //glClear(GL_COLOR_BUFFER_BIT); |
| 141 | //glClearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| 142 | |
| 143 | //Clear Buffers |
| 144 | // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| 145 | } |
| 146 | |
| 147 | //----------------------------------------------------------------------------- |
| 148 | //* End Rendering |
| 149 | //! Will save all rendering to a texture |
| 150 | //----------------------------------------------------------------------------- |
| 151 | void FrameBuffer::endRendering() |
| 152 | { |
| 153 | //Activate texture |
| 154 | _activate(); |
| 155 | |
| 156 | //Render to Texture |
| 157 | glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 20, m_width, m_height ); |
| 158 | |
| 159 | //TODO Deactivate texture? |
| 160 | //_deactivate(); |
| 161 | |
| 162 | //Reset Viewport |
| 163 | //glViewport(m_oldViewport[0], m_oldViewport[1], m_oldViewport[2], m_oldViewport[3]); |
| 164 | |
| 165 | //Clear Buffers |
| 166 | //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| 167 | } |
| 168 | |
| 169 | //----------------------------------------------------------------------------- |
| 170 | //* Render |
| 171 | //! Will render frame buffer to screen. |
| 172 | //----------------------------------------------------------------------------- |
| 173 | void FrameBuffer::render() |
| 174 | { |
| 175 | //Push states |
| 176 | glMatrixMode(GL_PROJECTION); |
| 177 | glPushMatrix(); |
| 178 | glLoadIdentity(); |
| 179 | //glOrtho( 0, m_width, 0, m_height, -1.0f, 1.0f ); |
| 180 | //glViewport( 0, 0, m_width, m_height ); |
| 181 | glMatrixMode(GL_MODELVIEW); |
| 182 | glPushMatrix(); |
| 183 | glLoadIdentity(); |
| 184 | //glPushAttrib(GL_LIGHTING_BIT); |
| 185 | glDisable(GL_LIGHTING); |
| 186 | |
| 187 | //Render QUAD (using framebuffer texture) |
| 188 | _activate(); |
| 189 | { |
| 190 | #ifdef HAVE_GLES |
| 191 | GLfloat tex[] = { |
| 192 | 0, 0, |
| 193 | 1, 0, |
| 194 | 1, 1, |
| 195 | 0, 1 |
| 196 | }; |
| 197 | GLfloat vtx[] = { |
| 198 | -1, -1, 0, |
| 199 | 0, -1, 0, |
| 200 | 0, 0, 0, |
| 201 | -1, 0, 0 |
| 202 | }; |
| 203 | glColor4f(0.0f, 0.0f, 1.0f, 1.0f); |
| 204 | |
| 205 | GLboolean glcol = glIsEnabled(GL_COLOR_ARRAY); |
| 206 | if (glcol) glDisableClientState(GL_COLOR_ARRAY); |
| 207 | GLboolean glvtx = glIsEnabled(GL_VERTEX_ARRAY); |
| 208 | if (!glvtx) |
| 209 | glEnableClientState(GL_VERTEX_ARRAY); |
| 210 | glVertexPointer(3,GL_FLOAT, 0,&vtx); |
| 211 | glActiveTexture( GL_TEXTURE1 ); |
| 212 | GLboolean gltex1 = glIsEnabled(GL_TEXTURE_2D); |
| 213 | if (gltex1) glDisable(GL_TEXTURE_2D); |
| 214 | glActiveTexture( GL_TEXTURE0 ); |
| 215 | glClientActiveTexture( GL_TEXTURE0 ); |
| 216 | glTexCoordPointer(2, GL_FLOAT, 0, &tex); |
| 217 | // draw |
| 218 | glDrawArrays(GL_TRIANGLE_FAN,0,4); |
| 219 | // restaure |
| 220 | if (glcol) glEnableClientState(GL_COLOR_ARRAY); |
| 221 | glActiveTexture( GL_TEXTURE1 ); |
| 222 | if (gltex1) glEnable(GL_TEXTURE_2D); |
| 223 | if (!glvtx) |
| 224 | glDisableClientState(GL_VERTEX_ARRAY); |
| 225 | else |
| 226 | glVertexPointer(glsav_vtx_size, glsav_vtx_type, glsav_vtx_stride, glsav_vtx_array ); |
| 227 | glActiveTexture( GL_TEXTURE0 ); |
| 228 | glTexCoordPointer( glsav_tex_size, glsav_tex_type, glsav_tex_stride, glsav_tex_array ); |
| 229 | |
| 230 | glColor4f(1.0f, 1.0f, 1.0f, 1.0f); |
| 231 | #else |
| 232 | glBegin(GL_QUADS); |
| 233 | { |
| 234 | glColor3f(0.0f, 0.0f, 1.0f); |
| 235 | glTexCoord2f(0,0); |
| 236 | glVertex3f(-1,-1,0); |
| 237 | glTexCoord2f(1,0); |
| 238 | glVertex3f( 0,-1,0); |
| 239 | glTexCoord2f(1,1); |
| 240 | glVertex3f( 0, 0,0); |
| 241 | glTexCoord2f(0,1); |
| 242 | glVertex3f(-1, 0,0); |
| 243 | glColor3f(1.0f, 1.0f, 1.0f); |
| 244 | } |
| 245 | glEnd(); |
| 246 | #endif |
| 247 | } |
| 248 | _deactivate(); |
| 249 | |
| 250 | //Pop states |
| 251 | //glPopAttrib(); |
| 252 | glMatrixMode(GL_MODELVIEW); |
| 253 | glPopMatrix(); |
| 254 | glMatrixMode(GL_PROJECTION); |
| 255 | glPopMatrix(); |
| 256 | } |
| 257 | |
| 258 | //----------------------------------------------------------------------------- |
| 259 | //* Render |
| 260 | //! Will render frame buffer to screen. |
| 261 | //----------------------------------------------------------------------------- |
| 262 | void FrameBuffer::render2() |
| 263 | { |
| 264 | //Push states |
| 265 | glMatrixMode(GL_PROJECTION); |
| 266 | glPushMatrix(); |
| 267 | glLoadIdentity(); |
| 268 | //glOrtho( 0, m_width, 0, m_height, -1.0f, 1.0f ); |
| 269 | //glViewport( 0, 0, m_width, m_height ); |
| 270 | glMatrixMode(GL_MODELVIEW); |
| 271 | glPushMatrix(); |
| 272 | glLoadIdentity(); |
| 273 | //glPushAttrib(GL_LIGHTING_BIT); |
| 274 | glDisable(GL_LIGHTING); |
| 275 | |
| 276 | //Render QUAD (using framebuffer texture) |
| 277 | _activate(); |
| 278 | { |
| 279 | #ifdef HAVE_GLES |
| 280 | GLfloat tex[] = { |
| 281 | 0, 0, |
| 282 | 1, 0, |
| 283 | 1, 1, |
| 284 | 0, 1 |
| 285 | }; |
| 286 | GLfloat vtx[] = { |
| 287 | -1, -1, 0, |
| 288 | 0, -1, 0, |
| 289 | 0, 0, 0, |
| 290 | -1, 0, 0 |
| 291 | }; |
| 292 | |
| 293 | GLboolean glcol = glIsEnabled(GL_COLOR_ARRAY); |
| 294 | if (glcol) glDisableClientState(GL_COLOR_ARRAY); |
| 295 | GLboolean glvtx = glIsEnabled(GL_VERTEX_ARRAY); |
| 296 | if (!glvtx) |
| 297 | glEnableClientState(GL_VERTEX_ARRAY); |
| 298 | glVertexPointer(3,GL_FLOAT, 0,&vtx); |
| 299 | glActiveTexture( GL_TEXTURE1 ); |
| 300 | GLboolean gltex1 = glIsEnabled(GL_TEXTURE_2D); |
| 301 | if (gltex1) glDisable(GL_TEXTURE_2D); |
| 302 | glActiveTexture( GL_TEXTURE0 ); |
| 303 | glClientActiveTexture( GL_TEXTURE0 ); |
| 304 | glTexCoordPointer(2, GL_FLOAT, 0, &tex); |
| 305 | // draw |
| 306 | glDrawArrays(GL_TRIANGLE_FAN,0,4); |
| 307 | // restaure |
| 308 | if (glcol) glEnableClientState(GL_COLOR_ARRAY); |
| 309 | glActiveTexture( GL_TEXTURE1 ); |
| 310 | if (gltex1) glEnable(GL_TEXTURE_2D); |
| 311 | if (!glvtx) |
| 312 | glDisableClientState(GL_VERTEX_ARRAY); |
| 313 | else |
| 314 | glVertexPointer(glsav_vtx_size, glsav_vtx_type, glsav_vtx_stride, glsav_vtx_array ); |
| 315 | glActiveTexture( GL_TEXTURE0 ); |
| 316 | glTexCoordPointer( glsav_tex_size, glsav_tex_type, glsav_tex_stride, glsav_tex_array ); |
| 317 | |
| 318 | glColor4f(1.0f, 1.0f, 1.0f, 1.0f); |
| 319 | #else |
| 320 | glBegin(GL_QUADS); |
| 321 | { |
| 322 | glTexCoord2f(0,0); |
| 323 | glVertex3f(-1,-1,0); |
| 324 | glTexCoord2f(1,0); |
| 325 | glVertex3f( 1,-1,0); |
| 326 | glTexCoord2f(1,1); |
| 327 | glVertex3f( 1, 1,0); |
| 328 | glTexCoord2f(0,1); |
| 329 | glVertex3f(-1, 1,0); |
| 330 | glColor3f(1.0f, 1.0f, 1.0f); |
| 331 | } |
| 332 | glEnd(); |
| 333 | #endif |
| 334 | } |
| 335 | _deactivate(); |
| 336 | |
| 337 | //Pop states |
| 338 | //glPopAttrib(); |
| 339 | glMatrixMode(GL_MODELVIEW); |
| 340 | glPopMatrix(); |
| 341 | glMatrixMode(GL_PROJECTION); |
| 342 | glPopMatrix(); |
| 343 | } |
| 344 | |
| 345 | //----------------------------------------------------------------------------- |
| 346 | // Activate |
| 347 | //----------------------------------------------------------------------------- |
| 348 | void FrameBuffer::_activate() |
| 349 | { |
| 350 | //Activate Texture (so we can copy to it) |
| 351 | #ifndef GL_GLEXT_VERSION |
| 352 | #ifndef HAVE_GLES |
| 353 | if ( glActiveTexture == 0 ) { |
| 354 | glActiveTexture = (PFNGLACTIVETEXTUREPROC) CoreVideo_GL_GetProcAddress("glActiveTexture"); |
| 355 | } |
| 356 | #endif |
| 357 | #endif |
| 358 | glActiveTexture(GL_TEXTURE0); |
| 359 | glEnable(GL_TEXTURE_2D); |
| 360 | glBindTexture(GL_TEXTURE_2D, m_id); |
| 361 | } |
| 362 | |
| 363 | //----------------------------------------------------------------------------- |
| 364 | // Deactivate |
| 365 | //----------------------------------------------------------------------------- |
| 366 | void FrameBuffer::_deactivate() |
| 367 | { |
| 368 | glActiveTexture((GLuint)GL_TEXTURE0); |
| 369 | glDisable(GL_TEXTURE_2D); |
| 370 | glBindTexture(GL_TEXTURE_2D, 0); |
| 371 | } |