source: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/RenderTexture.cpp @ 2808

Revision 2808, 38.7 KB checked in by mattausch, 16 years ago (diff)
Line 
1//------------------------------------------------------------------------------
2// File : RenderTexture.cpp
3//------------------------------------------------------------------------------
4// Copyright 2002 Mark J. Harris and
5// The University of North Carolina at Chapel Hill
6//------------------------------------------------------------------------------
7// Permission to use, copy, modify, distribute and sell this software and its
8// documentation for any purpose is hereby granted without fee, provided that
9// the above copyright notice appear in all copies and that both that copyright
10// notice and this permission notice appear in supporting documentation.
11// Binaries may be compiled with this software without any royalties or
12// restrictions.
13//
14// The author(s) and The University of North Carolina at Chapel Hill make no
15// representations about the suitability of this software for any purpose.
16// It is provided "as is" without express or implied warranty.
17//
18// -----------------------------------------------------------------------------
19// Credits:
20// Original RenderTexture class: Mark J. Harris
21// Original Render-to-depth-texture support: Thorsten Scheuermann
22// Linux Copy-to-texture: Eric Werness
23// Various Bug Fixes: Daniel (Redge) Sperl
24//                    Bill Baxter
25//
26// -----------------------------------------------------------------------------
27/**
28 * @file RenderTexture.cpp
29 *
30 * Implementation of class RenderTexture.  A multi-format render to
31 * texture wrapper.
32 */
33#include "RenderTexture.h"
34#include <GL/glut.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <stdarg.h>
38#include <assert.h>
39
40//------------------------------------------------------------------------------
41// Function               : IsPowerOfTwo
42// Description      :
43//------------------------------------------------------------------------------
44/**
45 * @fn IsPowerOfTwo(int n)
46 * @brief Returns true if /param n is an integer power of 2.
47 *
48 * Taken from Steve Baker's Cute Code Collection.
49 */
50bool IsPowerOfTwo(int n)
51{
52  return ((n&(n-1))==0);
53}
54
55//------------------------------------------------------------------------------
56// Function      : RenderTexture::RenderTexture
57// Description   :
58//------------------------------------------------------------------------------
59/**
60 * @fn RenderTexture::RenderTexture()
61 * @brief Constructor.
62 */
63RenderTexture::RenderTexture(int iWidth, int iHeight, bool bIsTexture /* = true */,
64                                                         bool bIsDepthTexture /* = false */)
65: _iWidth(iWidth),
66  _iHeight(iHeight),
67  _bIsTexture(bIsTexture),
68  _bIsDepthTexture(bIsDepthTexture),
69  _bHasArbDepthTexture(true),            // [Redge]
70  _eUpdateMode(RT_RENDER_TO_TEXTURE),
71  _bInitialized(false),
72  _bFloat(false),
73  _bRectangle(false),
74  _bHasDepth(false),
75  _bHasStencil(false),
76  _bMipmap(false),
77  _bAnisoFilter(false),
78#ifdef _WIN32
79  _hDC(NULL),
80  _hGLContext(NULL),
81  _hPBuffer(NULL),
82  _hPreviousDC(0),
83  _hPreviousContext(0),
84#else
85  _pDpy(NULL),
86  _hGLContext(NULL),
87  _hPBuffer(0),
88  _hPreviousContext(0),
89  _hPreviousDrawable(0),
90#endif
91  _iTextureTarget(GL_NONE),
92  _iTextureID(0),
93  _pPoorDepthTexture(0) // [Redge]
94{
95  assert(iWidth > 0 && iHeight > 0);
96  _iBits[0] = _iBits[1] = _iBits[2] = _iBits[3] = 0;
97  _bRectangle = !(IsPowerOfTwo(iWidth) && IsPowerOfTwo(iHeight));
98}
99
100
101//------------------------------------------------------------------------------
102// Function               : RenderTexture::~RenderTexture
103// Description      :
104//------------------------------------------------------------------------------
105/**
106 * @fn RenderTexture::~RenderTexture()
107 * @brief Destructor.
108 */
109RenderTexture::~RenderTexture()
110{
111  _Invalidate();
112}
113
114
115//------------------------------------------------------------------------------
116// Function               : wglGetLastError
117// Description      :
118//------------------------------------------------------------------------------
119/**
120 * @fn wglGetLastError()
121 * @brief Returns the last windows error generated.
122 */
123#ifdef _WIN32
124void RenderTexture::_wglGetLastError()
125{
126#ifdef _DEBUG
127
128  DWORD err = GetLastError();
129  switch(err)
130  {
131  case ERROR_INVALID_PIXEL_FORMAT:
132    fprintf(stderr, "Win32 Error:  ERROR_INVALID_PIXEL_FORMAT\n");
133    break;
134  case ERROR_NO_SYSTEM_RESOURCES:
135    fprintf(stderr, "Win32 Error:  ERROR_NO_SYSTEM_RESOURCES\n");
136    break;
137  case ERROR_INVALID_DATA:
138    fprintf(stderr, "Win32 Error:  ERROR_INVALID_DATA\n");
139    break;
140  case ERROR_INVALID_WINDOW_HANDLE:
141    fprintf(stderr, "Win32 Error:  ERROR_INVALID_WINDOW_HANDLE\n");
142    break;
143  case ERROR_RESOURCE_TYPE_NOT_FOUND:
144    fprintf(stderr, "Win32 Error:  ERROR_RESOURCE_TYPE_NOT_FOUND\n");
145    break;
146  case ERROR_SUCCESS:
147    // no error
148    break;
149  default:
150    LPVOID lpMsgBuf;
151    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
152                  FORMAT_MESSAGE_FROM_SYSTEM |
153                  FORMAT_MESSAGE_IGNORE_INSERTS,
154                  NULL,
155                  err,
156                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
157                  (LPTSTR) &lpMsgBuf,
158                  0,
159                  NULL);
160   
161    fprintf(stderr, "Win32 Error %d: %s\n", err, lpMsgBuf);
162    LocalFree( lpMsgBuf );
163    break;
164  }
165  SetLastError(0);
166
167#endif // _DEBUG
168}
169#endif
170
171//------------------------------------------------------------------------------
172// Function               : PrintExtensionError
173// Description      :
174//------------------------------------------------------------------------------
175/**
176 * @fn PrintExtensionError( char* strMsg, ... )
177 * @brief Prints an error about missing OpenGL extensions.
178 */
179void PrintExtensionError( char* strMsg, ... )
180{
181  fprintf(stderr, "Error: RenderTexture requires the following unsupported "
182                  "OpenGL extensions: \n");
183  char strBuffer[512];
184  va_list args;
185  va_start(args, strMsg);
186#ifdef _WIN32
187  _vsnprintf( strBuffer, 512, strMsg, args );
188#else
189  vsnprintf( strBuffer, 512, strMsg, args );
190#endif
191  va_end(args);
192 
193  fprintf(stderr, strMsg);
194
195  exit(1);
196}
197
198
199//------------------------------------------------------------------------------
200// Function               : RenderTexture::Initialize
201// Description      :
202//------------------------------------------------------------------------------
203/**
204 * @fn RenderTexture::Initialize(bool bShare, bool bDepth, bool bStencil, bool bMipmap, bool bAnisoFilter, unsigned int iRBits, unsigned int iGBits, unsigned int iBBits, unsigned int iABits);
205 * @brief Initializes the RenderTexture, sharing display lists and textures if specified.
206 *
207 * This function actually does the creation of the p-buffer.  It can only be called
208 * once a GL context has already been created.  Note that if the texture is not
209 * power of two dimensioned, or has more than 8 bits per channel, enabling mipmapping
210 * or aniso filtering will cause an error.
211 */
212bool RenderTexture::Initialize(bool         bShare       /* = true */,
213                               bool         bDepth       /* = false */,
214                               bool         bStencil     /* = false */,
215                               bool         bMipmap      /* = false */,
216                               bool         bAnisoFilter /* = false */,
217                               unsigned int iRBits       /* = 8 */,
218                               unsigned int iGBits       /* = 8 */,
219                               unsigned int iBBits       /* = 8 */,
220                               unsigned int iABits       /* = 8 */,
221                               UpdateMode   updateMode   /* = RT_RENDER_TO_TEXTURE */)
222{
223#ifdef _WIN32
224  if (!WGLEW_ARB_pbuffer)
225  {
226    PrintExtensionError("WGL_ARB_pbuffer");
227    return false;
228  }
229  if (!WGLEW_ARB_pixel_format)
230  {
231    PrintExtensionError("WGL_ARB_pixel_format");
232    return false;
233  }
234  if (_bIsTexture && !WGLEW_ARB_render_texture)
235  {
236    PrintExtensionError("WGL_ARB_render_texture");
237    return false;
238  }
239  if (_bIsDepthTexture && !GLEW_ARB_depth_texture)
240  {
241    // [Redge]
242#if defined(_DEBUG) || defined(DEBUG)
243    fprintf(stderr, "Warning: OpenGL extension GL_ARB_depth_texture not available.\n"
244                    "         Using glReadPixels() to emulate behavior.\n");
245#endif   
246    _bHasArbDepthTexture = false;
247    //PrintExtensionError("GL_ARB_depth_texture");
248    //return false;
249    // [/Redge]
250  }
251  SetLastError(0);
252#else // _WIN32
253  if (!GLXEW_SGIX_pbuffer)
254  {
255    PrintExtensionError("GLX_SGIX_pbuffer");
256    return false;
257  }
258  if (!GLXEW_SGIX_fbconfig)
259  {
260    PrintExtensionError("GLX_SGIX_fbconfig");
261    return false;
262  }
263  if (_bIsDepthTexture)
264  {
265    PrintExtensionError("I don't know");
266    return false;
267  }
268  if (updateMode == RT_RENDER_TO_TEXTURE)
269  {
270    PrintExtensionError("Some GLX render texture extension");
271  }
272#endif // _WIN32
273
274  if (_bInitialized)
275    _Invalidate();
276 
277  _bFloat = (iRBits > 8 || iGBits > 8 || iBBits > 8 || iABits > 8);
278 
279  bool bNVIDIA = true;
280#ifdef _WIN32
281  if (_bFloat && !GLEW_NV_float_buffer)
282  {
283    bNVIDIA = false;
284    if (!WGLEW_ATI_pixel_format_float)
285    {
286      PrintExtensionError("GL_NV_float_buffer or GL_ATI_pixel_format_float");
287      return false;
288    }
289  }
290  if (_bFloat && _bIsTexture && !bNVIDIA && !GLEW_ATI_texture_float)
291  {
292          PrintExtensionError("NV_float_buffer or ATI_texture_float");
293  }
294#else // _WIN32
295  if (_bFloat && _bIsTexture && !GLXEW_NV_float_buffer)
296  {
297    PrintExtensionError("GLX_NV_float_buffer");
298    return false;
299  }
300#endif // _WIN32
301  if (!_bFloat && !GLEW_NV_texture_rectangle)
302  {
303    bNVIDIA = false;
304  }
305 
306  _bRectangle = _bRectangle || (_bFloat && bNVIDIA);
307
308  if(_bIsDepthTexture)
309    _bHasDepth  = true;    // we need depth for a depth texture...
310  else
311    _bHasDepth  = bDepth;
312
313  _bHasStencil  = bStencil;
314  _bMipmap      = false;   // until it is enabled.
315  _bAnisoFilter = false;   // until it is enabled.
316  _eUpdateMode  = updateMode;
317
318  GLuint iWGLTextureTarget = 0;
319  GLuint iBindTarget = 0;
320  GLuint iTextureFormat = 0;
321  GLuint iDepthBindTarget = 0;
322  GLuint iDepthTextureFormat = 0;
323
324  if (_bIsTexture)
325    glGenTextures(1, &_iTextureID);
326  if (_bIsDepthTexture)
327    glGenTextures(1, &_iDepthTextureID);
328 
329  // Determine the appropriate texture formats and filtering modes.
330  if (_bIsTexture)
331  {
332    if (_bFloat)
333    {     
334      if (!bNVIDIA && _bRectangle)
335      {
336        fprintf(stderr,
337                "RenderTexture Error: ATI textures must be power-of-two-dimensioned.\n");
338        return false;
339      }
340
341      if (bNVIDIA)
342        _iTextureTarget = GL_TEXTURE_RECTANGLE_NV;
343      else
344        _iTextureTarget = GL_TEXTURE_2D;
345   
346      glBindTexture(_iTextureTarget, _iTextureID); 
347   
348      // We'll use clamp to edge as the default texture wrap mode for all tex types
349      glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
350      glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
351      glTexParameteri( _iTextureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
352      glTexParameteri( _iTextureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
353   
354      if (bMipmap)
355      {
356        fprintf(stderr,
357                "RenderTexture Error: float textures do not support mipmaps\n");
358        return false;
359      }
360
361      if (RT_COPY_TO_TEXTURE == _eUpdateMode)
362      {
363        GLuint iInternalFormat;
364        GLuint iFormat;
365        if (iABits > 0)
366        {
367          if (bNVIDIA)
368            iInternalFormat = (iABits > 16) ? GL_FLOAT_RGBA32_NV : GL_FLOAT_RGBA16_NV;
369          else
370            iInternalFormat = (iABits > 16) ? GL_RGBA_FLOAT32_ATI : GL_RGBA_FLOAT16_ATI;
371          iFormat = GL_RGBA;
372        }
373        else if (iBBits > 0)
374        {
375          if (bNVIDIA)
376            iInternalFormat = (iBBits > 16) ? GL_FLOAT_RGB32_NV : GL_FLOAT_RGB16_NV;
377          else
378            iInternalFormat = (iBBits > 16) ? GL_RGB_FLOAT32_ATI : GL_RGB_FLOAT16_ATI;
379          iFormat = GL_RGB;
380        }
381        else if (iGBits > 0)
382        {
383          if (bNVIDIA)
384            iInternalFormat = (iGBits > 16) ? GL_FLOAT_RG32_NV : GL_FLOAT_RG16_NV;
385          else
386            iInternalFormat = (iGBits > 16) ? GL_LUMINANCE_ALPHA_FLOAT32_ATI :
387                                              GL_LUMINANCE_ALPHA_FLOAT16_ATI;
388          iFormat = GL_LUMINANCE_ALPHA;
389        }
390        else
391        {
392          if (bNVIDIA)
393            iInternalFormat = (iRBits > 16) ? GL_FLOAT_R32_NV : GL_FLOAT_R16_NV;
394          else
395            iInternalFormat = (iRBits > 16) ? GL_LUMINANCE_FLOAT32_ATI :
396                                              GL_LUMINANCE_FLOAT16_ATI;
397          iFormat = GL_LUMINANCE;
398        }
399        // Allocate the texture image (but pass it no data for now).
400        glTexImage2D(_iTextureTarget, 0, iInternalFormat, _iWidth, _iHeight,
401                     0, iFormat, GL_FLOAT, NULL);
402      }
403      else
404      {
405#ifdef _WIN32
406        if (bNVIDIA)
407          iWGLTextureTarget = WGL_TEXTURE_RECTANGLE_NV;
408        else
409          iWGLTextureTarget = WGL_TEXTURE_2D_ARB;
410
411        if (iABits > 0)
412        {
413          if (bNVIDIA)
414          {
415            iBindTarget    = WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV; 
416            iTextureFormat = WGL_TEXTURE_FLOAT_RGBA_NV;
417          }
418          else
419          {
420            iBindTarget    = WGL_BIND_TO_TEXTURE_RGBA_ARB; 
421            iTextureFormat = WGL_TEXTURE_RGBA_ARB;
422          }
423        }
424        else if (iBBits > 0)
425        {
426          if (bNVIDIA)
427          {
428            iBindTarget    = WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV; 
429            iTextureFormat = WGL_TEXTURE_FLOAT_RGB_NV;
430          }
431          else
432          {
433            iBindTarget    = WGL_BIND_TO_TEXTURE_RGB_ARB; 
434            iTextureFormat = WGL_TEXTURE_RGB_ARB;
435          }
436        }
437        else if (iGBits > 0)
438        {
439          if (bNVIDIA)
440          {
441            iBindTarget    = WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV; 
442            iTextureFormat = WGL_TEXTURE_FLOAT_RG_NV;
443          }
444          else
445          {
446            iBindTarget    = WGL_BIND_TO_TEXTURE_RGB_ARB; 
447            iTextureFormat = WGL_TEXTURE_RGB_ARB;
448          }
449        }
450        else
451        {
452          if (bNVIDIA)
453          {
454            iBindTarget    = WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV; 
455            iTextureFormat = WGL_TEXTURE_FLOAT_R_NV;
456          }
457          else
458          {
459            iBindTarget    = WGL_BIND_TO_TEXTURE_RGB_ARB; 
460            iTextureFormat = WGL_TEXTURE_RGB_ARB;
461          }
462        }
463#else // _WIN32
464#if defined(DEBUG) || defined(_DEBUG)
465        printf("RenderTexture Error: Render-to-Texture not supported in Linux\n");
466#endif
467#endif // _WIN32
468      }
469    }
470    else
471    {
472      if (!_bRectangle)
473      {
474        _iTextureTarget = GL_TEXTURE_2D;
475        glBindTexture(_iTextureTarget, _iTextureID);
476           
477        // We'll use clamp to edge as the default texture wrap mode for all tex types
478        glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
479        glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
480        glTexParameteri( _iTextureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
481     
482        if (bMipmap)
483        {
484          _bMipmap = true;
485          glTexParameteri( _iTextureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
486       
487          // Generate mipmap automatically if supported
488          if (GLEW_SGIS_generate_mipmap)
489          {
490            glTexParameteri( _iTextureTarget, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
491          }
492          else
493          {
494            PrintExtensionError("GL_SGIS_generate_mipmap");
495          }
496        }
497        else
498        {
499          glTexParameteri( _iTextureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
500        }
501     
502        // Set anisotropic filter to the max ratio
503        if (bAnisoFilter)
504        {
505          if (GLEW_EXT_texture_filter_anisotropic)
506          {
507            _bAnisoFilter = true;
508            float rMaxAniso;
509            glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &rMaxAniso);
510            glTexParameterf( _iTextureTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, rMaxAniso);
511          }
512        }
513
514        if (RT_COPY_TO_TEXTURE == _eUpdateMode)
515        {
516          GLuint iInternalFormat;
517          GLuint iFormat;
518          if (iABits > 0)
519          {
520            iInternalFormat = GL_RGBA8;
521            iFormat = GL_RGBA;
522          }
523          else
524          {
525            iInternalFormat = GL_RGB8;
526            iFormat = GL_RGB;
527          }
528          // Allocate the texture image (but pass it no data for now).
529          glTexImage2D(_iTextureTarget, 0, iInternalFormat, _iWidth, _iHeight,
530                       0, iFormat, GL_FLOAT, NULL);
531        }
532        else
533        {
534#ifdef _WIN32   
535          iWGLTextureTarget = WGL_TEXTURE_2D_ARB;
536          if (iABits > 0)
537          {
538            iBindTarget    = WGL_BIND_TO_TEXTURE_RGBA_ARB;
539            iTextureFormat = WGL_TEXTURE_RGBA_ARB;
540          }
541          else
542          {
543            iBindTarget    = WGL_BIND_TO_TEXTURE_RGB_ARB; 
544            iTextureFormat = WGL_TEXTURE_RGB_ARB;
545          }
546#endif
547        }
548      }
549      else
550      {
551        if (!bNVIDIA)
552        {
553          fprintf(stderr,
554                  "RenderTexture Error: ATI textures must be power-of-two-dimensioned.\n");
555          return false;
556        }
557       
558        _iTextureTarget = GL_TEXTURE_RECTANGLE_NV;
559       
560        glBindTexture(_iTextureTarget, _iTextureID);
561     
562        glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
563        glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
564        glTexParameteri( _iTextureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
565        glTexParameteri( _iTextureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
566       
567        if (bMipmap)
568        {
569
570          fprintf(stderr,
571                  "RenderTexture Error: rectangle textures do not support mipmaps\n");
572          return false;
573        }
574
575        if (RT_COPY_TO_TEXTURE == _eUpdateMode)
576        {
577          GLuint iInternalFormat;
578          GLuint iFormat;
579          if (iABits > 0)
580          {
581            iInternalFormat = GL_RGBA8;
582            iFormat = GL_RGBA;
583          }
584          else
585          {
586            iInternalFormat = GL_RGB8;
587            iFormat = GL_RGB;
588          }
589          // Allocate the texture image (but pass it no data for now).
590          glTexImage2D(_iTextureTarget, 0, iInternalFormat, _iWidth, _iHeight,
591                       0, iFormat, GL_FLOAT, NULL);
592        }
593        else
594        {
595#ifdef _WIN32
596          iWGLTextureTarget = WGL_TEXTURE_RECTANGLE_NV;
597          if (iABits > 0)
598          {
599            iBindTarget    = WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV;
600            iTextureFormat = WGL_TEXTURE_RGBA_ARB;
601          }
602          else
603          {
604            iBindTarget   = WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV;
605            iTextureFormat= WGL_TEXTURE_RGB_ARB;
606          }
607#endif
608        }
609      }
610    }
611  }
612
613  if (_bIsDepthTexture)
614  {
615    if (!bNVIDIA && _bRectangle)
616    {
617      fprintf(stderr,
618        "RenderTexture Error: ATI textures must be power-of-two-dimensioned.\n");
619      return false;
620    }
621
622    if (!_iTextureTarget)
623      _iTextureTarget = _bRectangle ? GL_TEXTURE_RECTANGLE_NV : GL_TEXTURE_2D;
624   
625    glBindTexture(_iTextureTarget, _iDepthTextureID); 
626   
627    // We'll use clamp to edge as the default texture wrap mode for all tex types
628    glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
629    glTexParameteri( _iTextureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
630    glTexParameteri( _iTextureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
631    glTexParameteri( _iTextureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
632   
633    // user will need to set up hardware shadow mapping himself (using ARB_shadow)
634       
635    if (RT_COPY_TO_TEXTURE == _eUpdateMode)
636    {
637      // [Redge]
638      if (_bHasArbDepthTexture)
639      {
640        // Allocate the texture image (but pass it no data for now).
641        glTexImage2D(_iTextureTarget, 0, GL_DEPTH_COMPONENT, _iWidth, _iHeight,
642                     0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
643      }
644      else
645      {
646        // allocate memory for depth texture
647        // Since this is slow, we warn the user in debug mode. (above)
648        _pPoorDepthTexture = new unsigned short[_iWidth * _iHeight];
649        glTexImage2D(_iTextureTarget, 0, GL_LUMINANCE16, _iWidth, _iHeight,
650                   0, GL_LUMINANCE, GL_UNSIGNED_SHORT, _pPoorDepthTexture);
651      }
652      // [/Redge]
653    }
654    else  // RENDER_TO_TEXTURE
655    {
656#ifdef _WIN32
657      if(_bRectangle)
658      {
659        if (!iWGLTextureTarget)  iWGLTextureTarget = WGL_TEXTURE_RECTANGLE_NV;
660        iDepthBindTarget    = WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV;
661        iDepthTextureFormat = WGL_TEXTURE_DEPTH_COMPONENT_NV;
662      }
663      else
664      {
665        if (!iWGLTextureTarget)  iWGLTextureTarget = WGL_TEXTURE_2D_ARB;
666        iDepthBindTarget    = WGL_BIND_TO_TEXTURE_DEPTH_NV;
667        iDepthTextureFormat = WGL_TEXTURE_DEPTH_COMPONENT_NV;
668      }
669#endif
670    }
671  }
672
673#if _WIN32
674  // Get the current context.
675  HDC hdc = wglGetCurrentDC();
676  if (NULL == hdc)
677    _wglGetLastError();
678  HGLRC hglrc = wglGetCurrentContext();
679  if (NULL == hglrc)
680    _wglGetLastError();
681 
682  int iFormat = 0;
683  unsigned int iNumFormats;
684  int attribChooseList[50];
685  int attribCreateList[50];
686  int attribChoose = 0;
687  int attribCreate = 0;
688 
689  // Setup the attrib list for wglChoosePixelFormat()
690 
691  attribChooseList[attribChoose++] = WGL_RED_BITS_ARB;
692  attribChooseList[attribChoose++] = iRBits;
693  attribChooseList[attribChoose++] = WGL_GREEN_BITS_ARB;
694  attribChooseList[attribChoose++] = iGBits;
695  attribChooseList[attribChoose++] = WGL_BLUE_BITS_ARB;
696  attribChooseList[attribChoose++] = iBBits;
697  attribChooseList[attribChoose++] = WGL_ALPHA_BITS_ARB;
698  attribChooseList[attribChoose++] = iABits;
699  if (_bFloat)
700  {
701    if (bNVIDIA)
702    {
703      attribChooseList[attribChoose++] = WGL_FLOAT_COMPONENTS_NV;
704      attribChooseList[attribChoose++] = GL_TRUE;
705    }
706    else
707    {
708      attribChooseList[attribChoose++] = WGL_PIXEL_TYPE_ARB;
709      attribChooseList[attribChoose++] = WGL_TYPE_RGBA_FLOAT_ATI;
710    }
711  }
712   
713  attribChooseList[attribChoose++] = WGL_STENCIL_BITS_ARB;
714  attribChooseList[attribChoose++] = (bStencil) ? 8 : 0;
715  attribChooseList[attribChoose++] = WGL_DEPTH_BITS_ARB;
716  attribChooseList[attribChoose++] = (bDepth) ? 24 : 0;
717  attribChooseList[attribChoose++] = WGL_DRAW_TO_PBUFFER_ARB;
718  attribChooseList[attribChoose++] = GL_TRUE;
719
720  if (_bIsTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode)
721  {
722    attribChooseList[attribChoose++] = iBindTarget;
723    attribChooseList[attribChoose++] = GL_TRUE;
724  }
725  if (_bIsDepthTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode)
726  {
727    attribChooseList[attribChoose++] = iDepthBindTarget;
728    attribChooseList[attribChoose++] = GL_TRUE;
729  }
730
731  attribChooseList[attribChoose++] = 0;
732
733  // Setup the attrib list for wglCreatePbuffer()
734  if ((_bIsTexture || _bIsDepthTexture) && RT_RENDER_TO_TEXTURE == _eUpdateMode)
735  {
736    attribCreateList[attribCreate++] = WGL_TEXTURE_TARGET_ARB;
737    attribCreateList[attribCreate++] = iWGLTextureTarget;
738  }
739  if (_bIsTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode)
740  {
741    attribCreateList[attribCreate++] = WGL_TEXTURE_FORMAT_ARB;
742    attribCreateList[attribCreate++] = iTextureFormat;
743    /*attribCreateList[attribCreate++] = WGL_TEXTURE_TARGET_ARB;
744    attribCreateList[attribCreate++] = iWGLTextureTarget;*/
745    attribCreateList[attribCreate++] = WGL_MIPMAP_TEXTURE_ARB;
746    attribCreateList[attribCreate++] = (bMipmap) ? GL_TRUE : GL_FALSE; 
747  }
748  if (_bIsDepthTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode)
749  {
750    attribCreateList[attribCreate++] = WGL_DEPTH_TEXTURE_FORMAT_NV;
751    attribCreateList[attribCreate++] = iDepthTextureFormat;
752  }
753  attribCreateList[attribCreate++] = WGL_PBUFFER_LARGEST_ARB;
754  attribCreateList[attribCreate++] = GL_FALSE;
755  attribCreateList[attribCreate++] = 0;
756
757  if (!wglChoosePixelFormatARB( hdc, attribChooseList, NULL, 1, &iFormat, &iNumFormats))
758  {
759    fprintf(stderr,
760            "RenderTexture::Initialize() creation error: wglChoosePixelFormatARB() failed.\n");
761    _wglGetLastError();
762    return false;
763  }
764  if ( iNumFormats <= 0 )
765  {
766    fprintf(stderr,
767            "RenderTexture::Initialize() creation error: Couldn't find a suitable pixel format.\n");
768    _wglGetLastError();
769    return false;
770  }
771
772  // Create the p-buffer.   
773  _hPBuffer = wglCreatePbufferARB( hdc, iFormat, _iWidth, _iHeight, attribCreateList );
774  if (!_hPBuffer)
775  {
776    fprintf(stderr, "RenderTexture::Initialize() pbuffer creation error: wglCreatePbufferARB() failed\n");
777    _wglGetLastError();
778    return false;
779  }
780 
781   // Get the device context.
782  _hDC = wglGetPbufferDCARB( _hPBuffer);
783  if ( !_hDC )
784  {
785    fprintf(stderr,
786            "RenderTexture::Initialize() creation error: wglGetGetPbufferDCARB() failed\n");
787    _wglGetLastError();
788    return false;
789  }
790 
791  // Create a gl context for the p-buffer.
792
793 
794  _hGLContext = wglCreateContext( _hDC );
795  if ( !_hGLContext )
796  {
797    fprintf(stderr, "RenderTexture::Initialize() creation error:  wglCreateContext() failed\n");
798    _wglGetLastError();
799    return false;
800  }
801 
802  // Share lists, texture objects, and program objects.
803  if( bShare )
804  {
805    if( !wglShareLists(hglrc, _hGLContext) )
806    {
807      fprintf(stderr, "RenderTexture::Initialize() creation error: wglShareLists() failed\n" );
808      _wglGetLastError();
809      return false;
810    }
811  }
812
813  // bind the pbuffer to the render texture object
814  if (_bIsTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode)
815  {
816    glBindTexture(_iTextureTarget, _iTextureID);
817    if (wglBindTexImageARB(_hPBuffer, WGL_FRONT_LEFT_ARB) == FALSE)
818    {
819      _wglGetLastError();
820      return false;
821    }
822  }
823  if (_bIsDepthTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode)
824  {
825    glBindTexture(_iTextureTarget, _iDepthTextureID);
826    if (wglBindTexImageARB(_hPBuffer, WGL_DEPTH_COMPONENT_NV) == FALSE)
827    {
828      _wglGetLastError();
829      return false;
830    }
831  }
832
833   // Determine the actual width and height we were able to create.
834  wglQueryPbufferARB( _hPBuffer, WGL_PBUFFER_WIDTH_ARB, &_iWidth );
835  wglQueryPbufferARB( _hPBuffer, WGL_PBUFFER_HEIGHT_ARB, &_iHeight );
836
837  _bInitialized = true;
838 
839  // get the actual number of bits allocated:
840  int attrib = WGL_RED_BITS_ARB;
841  int value;
842  _iBits[0] = (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value)) ? value : iRBits;
843  attrib = WGL_GREEN_BITS_ARB;
844  _iBits[1] = (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value)) ? value : iGBits;
845  attrib = WGL_BLUE_BITS_ARB;
846  _iBits[2] = (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value)) ? value : iBBits;
847  attrib = WGL_ALPHA_BITS_ARB;
848  _iBits[3] = (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value)) ? value : iABits;
849  attrib = WGL_DEPTH_BITS_ARB;
850  _iBits[4] = (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value)) ? value : 0;
851  attrib = WGL_STENCIL_BITS_ARB;
852  _iBits[5] = (wglGetPixelFormatAttribivARB(_hDC, iFormat, 0, 1, &attrib, &value)) ? value : 0;
853 
854#if defined(_DEBUG) || defined(DEBUG)
855  fprintf(stderr, "Created a %dx%d RenderTexture with BPP(%d, %d, %d, %d)",
856          _iWidth, _iHeight, _iBits[0], _iBits[1], _iBits[2], _iBits[3]);
857  if (_iBits[4]) fprintf(stderr, " depth=%d", _iBits[4]);
858  if (_iBits[5]) fprintf(stderr, " stencil=%d", _iBits[5]);
859  fprintf(stderr, "\n");
860#endif
861#else // _WIN32
862  _pDpy = glXGetCurrentDisplay();
863  GLXContext context = glXGetCurrentContext();
864  int screen = DefaultScreen(_pDpy);
865  XVisualInfo *visInfo;
866
867  int iFormat = 0;
868  int iNumFormats;
869  int fbAttribs[50];
870  int attrib = 0;
871
872  fbAttribs[attrib++] = GLX_RENDER_TYPE_SGIX;
873  fbAttribs[attrib++] = GLX_RGBA_BIT_SGIX;
874  fbAttribs[attrib++] = GLX_DRAWABLE_TYPE_SGIX;
875  fbAttribs[attrib++] = GLX_PBUFFER_BIT_SGIX;
876  fbAttribs[attrib++] = GLX_STENCIL_SIZE;
877  fbAttribs[attrib++] = (bStencil) ? 8 : 0;
878  fbAttribs[attrib++] = GLX_DEPTH_SIZE;
879  fbAttribs[attrib++] = (bDepth) ? 24 : 0;
880  if (_bFloat)
881  {
882    fbAttribs[attrib++] = GLX_RED_SIZE;
883    fbAttribs[attrib++] = iRBits;
884    fbAttribs[attrib++] = GLX_GREEN_SIZE;
885    fbAttribs[attrib++] = iGBits;
886    fbAttribs[attrib++] = GLX_BLUE_SIZE;
887    fbAttribs[attrib++] = iBBits;
888    fbAttribs[attrib++] = GLX_ALPHA_SIZE;
889    fbAttribs[attrib++] = iABits;
890    fbAttribs[attrib++] = GLX_FLOAT_COMPONENTS_NV;
891    fbAttribs[attrib++] = 1;   
892  }
893  fbAttribs[attrib++] = None;
894
895  GLXFBConfigSGIX *fbConfigs;
896  int nConfigs;
897
898  fbConfigs = glXChooseFBConfigSGIX(_pDpy, screen, fbAttribs, &nConfigs);
899
900  if (nConfigs == 0 || !fbConfigs) {
901    fprintf(stderr,
902            "RenderTexture::Initialize() creation error: Couldn't find a suitable pixel format\n");
903    return false;
904  }
905
906  // Pick the first returned format that will return a pbuffer
907  for (int i=0;i<nConfigs;i++)
908  {
909    _hPBuffer = glXCreateGLXPbufferSGIX(_pDpy, fbConfigs[i], _iWidth, _iHeight, NULL);
910    if (_hPBuffer) {
911      _hGLContext = glXCreateContextWithConfigSGIX(_pDpy, fbConfigs[i], GLX_RGBA_TYPE, bShare?context:NULL, True);
912      break;
913    }
914  }
915
916  if (!_hPBuffer)
917  {
918    fprintf(stderr, "RenderTexture::Initialize() pbuffer creation error: glXCreateGLXPbufferSGIX() failed\n");
919    return false;
920  }
921
922  if(!_hGLContext)
923  {
924      // Try indirect
925      _hGLContext = glXCreateContext(_pDpy, visInfo, bShare?context:NULL, False);
926      if ( !_hGLContext )
927      {
928        fprintf(stderr, "RenderTexture::Initialize() creation error:  glXCreateContext() failed\n");
929        return false;
930      }
931  }
932
933  glXQueryGLXPbufferSGIX(_pDpy, _hPBuffer, GLX_WIDTH_SGIX, (GLuint*)&_iWidth);
934  glXQueryGLXPbufferSGIX(_pDpy, _hPBuffer, GLX_HEIGHT_SGIX, (GLuint*)&_iHeight);
935
936  _bInitialized = true;
937
938  // XXX Query the color format
939
940#endif // _WIN32
941 
942  return true;
943}
944
945//------------------------------------------------------------------------------
946// Function               : RenderTexture::_Invalidate
947// Description      :
948//------------------------------------------------------------------------------
949/**
950 * @fn RenderTexture::_Invalidate()
951 * @brief Returns the pbuffer memory to the graphics device.
952 *
953 */
954bool RenderTexture::_Invalidate()
955{
956  _bFloat       = false;
957  _bRectangle   = false;
958  _bInitialized = false;
959  _bHasDepth    = false;
960  _bHasStencil  = false;
961  _bMipmap      = false;
962  _bAnisoFilter = false;
963  _iBits[0] = _iBits[1] = _iBits[2] = _iBits[3] = 0;
964
965  if (_bIsTexture)
966    glDeleteTextures(1, &_iTextureID);
967  if (_bIsDepthTexture) {
968      // [Redge]
969      if (!_bHasArbDepthTexture) delete[] _pPoorDepthTexture;
970      // [/Redge]
971      glDeleteTextures(1, &_iDepthTextureID);
972  }
973
974#if _WIN32
975  if ( _hPBuffer )
976  {
977    // Check if we are currently rendering in the pbuffer
978    if (wglGetCurrentContext() == _hGLContext)
979      wglMakeCurrent(0,0);
980    wglDeleteContext( _hGLContext);
981    wglReleasePbufferDCARB( _hPBuffer, _hDC);
982    wglDestroyPbufferARB( _hPBuffer );
983    _hPBuffer = 0;
984    return true;
985  }
986#else // _WIN32
987  if ( _hPBuffer )
988  {
989    if(glXGetCurrentContext() == _hGLContext)
990      // XXX I don't know if this is right at all
991      glXMakeCurrent(_pDpy, _hPBuffer, 0);
992    glXDestroyGLXPbufferSGIX(_pDpy, _hPBuffer);
993    _hPBuffer = 0;
994    return true;
995  }
996#endif // _WIN32
997  return false;
998}
999
1000
1001//------------------------------------------------------------------------------
1002// Function               : RenderTexture::Reset
1003// Description      :
1004//------------------------------------------------------------------------------
1005/**
1006 * @fn RenderTexture::Reset(int iWidth, int iHeight, unsigned int iMode, bool bIsTexture, bool bIsDepthTexture)
1007 * @brief Resets the resolution of the offscreen buffer.
1008 *
1009 * Causes the buffer to delete itself.  User must call Initialize() again
1010 * before use.
1011 */
1012bool RenderTexture::Reset(int iWidth, int iHeight, bool bIsTexture /* = true */,
1013                           bool bIsDepthTexture /* = false */)
1014{
1015  if (!_Invalidate())
1016  {
1017    fprintf(stderr, "RenderTexture::Reset(): failed to invalidate.\n");
1018    return false;
1019  }
1020  _iWidth     = iWidth;
1021  _iHeight    = iHeight;
1022  _bIsTexture = bIsTexture;
1023  _bIsDepthTexture = bIsDepthTexture;
1024 
1025  return true;
1026}
1027
1028
1029//------------------------------------------------------------------------------
1030// Function               : RenderTexture::BeginCapture
1031// Description      :
1032//------------------------------------------------------------------------------
1033/**
1034 * @fn RenderTexture::BeginCapture()
1035 * @brief Activates rendering to the RenderTexture.
1036 */
1037bool RenderTexture::BeginCapture()
1038{
1039  if (!_bInitialized)
1040  {
1041    fprintf(stderr, "RenderTexture::BeginCapture(): Texture is not initialized!\n");
1042    exit(1);
1043    return false;
1044  }
1045#ifdef _WIN32
1046  // cache the current context so we can reset it when EndCapture() is called.
1047  _hPreviousDC      = wglGetCurrentDC();
1048  if (NULL == _hPreviousDC)
1049    _wglGetLastError();
1050  _hPreviousContext = wglGetCurrentContext();
1051  if (NULL == _hPreviousContext)
1052    _wglGetLastError();
1053
1054  if (_bIsTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode)
1055  {
1056    glBindTexture(_iTextureTarget, _iTextureID);
1057
1058          // release the pbuffer from the render texture object
1059    if (FALSE == wglReleaseTexImageARB(_hPBuffer, WGL_FRONT_LEFT_ARB))
1060    {
1061      _wglGetLastError();
1062      return false;
1063    }
1064  }
1065
1066  if (_bIsDepthTexture && RT_RENDER_TO_TEXTURE == _eUpdateMode)
1067  {
1068    glBindTexture(_iTextureTarget, _iDepthTextureID);
1069
1070          // release the pbuffer from the render texture object
1071    if (FALSE == wglReleaseTexImageARB(_hPBuffer, WGL_DEPTH_COMPONENT_NV))
1072    {
1073      _wglGetLastError();
1074      return false;
1075    }
1076  }
1077
1078  // make the pbuffer's rendering context current.
1079  if (FALSE == wglMakeCurrent( _hDC, _hGLContext))
1080  {
1081    _wglGetLastError();
1082    return false;
1083  }
1084#else // _WIN32
1085  _hPreviousContext = glXGetCurrentContext();
1086  _hPreviousDrawable = glXGetCurrentDrawable();
1087
1088  if (False == glXMakeCurrent(_pDpy, _hPBuffer, _hGLContext)) {
1089    return false;
1090  }
1091#endif // _WIN32
1092 
1093  return true;
1094}
1095
1096
1097//------------------------------------------------------------------------------
1098// Function               : RenderTexture::EndCapture
1099// Description      :
1100//------------------------------------------------------------------------------
1101/**
1102 * @fn RenderTexture::EndCapture()
1103 * @brief Ends rendering to the RenderTexture.
1104 */
1105bool RenderTexture::EndCapture()
1106{
1107  bool bContextReset = false;
1108
1109  if (!_bInitialized)
1110  {
1111    fprintf(stderr, "RenderTexture::EndCapture(): Texture is not initialized!\n");
1112    return false;
1113  }
1114#ifdef _WIN32 
1115  if (_bIsTexture)
1116  {
1117    if (RT_RENDER_TO_TEXTURE == _eUpdateMode)
1118    {
1119      // make the previous rendering context current
1120      if (FALSE == wglMakeCurrent( _hPreviousDC, _hPreviousContext))
1121      {
1122        _wglGetLastError();
1123        return false;
1124      }
1125      bContextReset = true;
1126   
1127      // [Redge] moved binding completely to Bind()
1128      // [Mark] Can't do that, because it makes things difficult for Cg users.
1129      // bind the pbuffer to the render texture object     
1130      glBindTexture(_iTextureTarget, _iTextureID);
1131      if (FALSE == wglBindTexImageARB(_hPBuffer, WGL_FRONT_LEFT_ARB))
1132      {
1133        _wglGetLastError();
1134        return false;
1135      }
1136    }
1137    else
1138    {
1139      glBindTexture(_iTextureTarget, _iTextureID);
1140      glCopyTexSubImage2D(_iTextureTarget, 0, 0, 0, 0, 0, _iWidth, _iHeight);
1141    }
1142  }
1143  if (_bIsDepthTexture)
1144  {
1145    if (RT_RENDER_TO_TEXTURE == _eUpdateMode)
1146    {
1147      // make the previous rendering context current
1148      if(!bContextReset)
1149      {
1150        if (FALSE == wglMakeCurrent( _hPreviousDC, _hPreviousContext))
1151        {
1152          _wglGetLastError();
1153          return false;
1154        }
1155        bContextReset = true;
1156      }
1157
1158      // [Redge] moved binding completely to Bind()
1159      // [Mark] Can't do that, because it makes things difficult for Cg users.
1160      // bind the pbuffer to the render texture object
1161      glBindTexture(_iTextureTarget, _iDepthTextureID);
1162      if (FALSE == wglBindTexImageARB(_hPBuffer, WGL_DEPTH_COMPONENT_NV))
1163      {
1164        _wglGetLastError();
1165        return false;
1166      }
1167    }
1168    else
1169    {
1170      glBindTexture(_iTextureTarget, _iDepthTextureID);
1171      // HOW TO COPY DEPTH TEXTURE??? Supposedly this just magically works...
1172      // [Redge]
1173      if (_bHasArbDepthTexture)
1174      {
1175        glCopyTexSubImage2D(_iTextureTarget, 0, 0, 0, 0, 0, _iWidth, _iHeight);
1176      }
1177      else
1178      {
1179        // no 'real' depth texture available, so behavior has to be emulated
1180        // using glReadPixels (beware, this is (naturally) slow ...)
1181        glReadPixels(0, 0, _iWidth, _iHeight,
1182                     GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, _pPoorDepthTexture);
1183        glTexImage2D(_iTextureTarget, 0, GL_LUMINANCE16,
1184                     _iWidth, _iHeight,
1185                     0, GL_LUMINANCE, GL_UNSIGNED_SHORT, _pPoorDepthTexture);
1186      }
1187      // [/Redge]
1188    }
1189  }
1190 
1191  if(!bContextReset)
1192  {
1193    // make the previous rendering context current
1194    if (FALSE == wglMakeCurrent( _hPreviousDC, _hPreviousContext))
1195    {
1196      _wglGetLastError();
1197      return false;
1198    }
1199  }
1200#else // _WIN32
1201  assert(_bIsTexture);
1202  glBindTexture(_iTextureTarget, _iTextureID);
1203  glCopyTexSubImage2D(_iTextureTarget, 0, 0, 0, 0, 0, _iWidth, _iHeight);
1204
1205  if(!bContextReset)
1206  {
1207    if (False == glXMakeCurrent(_pDpy, _hPreviousDrawable, _hPreviousContext))
1208    {
1209      return false;
1210    }
1211  }
1212#endif // _WIN32
1213  return true;
1214}
1215
1216
1217
1218//------------------------------------------------------------------------------
1219// Function               : RenderTexture::Bind
1220// Description      :
1221//------------------------------------------------------------------------------
1222/**
1223 * @fn RenderTexture::Bind()
1224 * @brief Binds RGB texture.
1225 */
1226void RenderTexture::Bind() const
1227{
1228  if (_bInitialized) {
1229    glBindTexture(_iTextureTarget, _iTextureID);   
1230  }   
1231}
1232
1233
1234//------------------------------------------------------------------------------
1235// Function               : RenderTexture::BindDepth
1236// Description      :
1237//------------------------------------------------------------------------------
1238/**
1239 * @fn RenderTexture::BindDepth()
1240 * @brief Binds depth texture.
1241 */
1242void RenderTexture::BindDepth() const
1243{
1244  if (_bInitialized && _bIsDepthTexture) {
1245    glBindTexture(_iTextureTarget, _iDepthTextureID);
1246  }
1247}
Note: See TracBrowser for help on using the repository browser.