using System;
using System.Runtime.InteropServices;
using Tao.OpenGl;
using Tao.Platform.Windows;
using VJProjector;
using VJProjector.GFX.Immerse.Materials;
 
namespace VJProjector.GFX.Immerse.GPU
{
	/// <summary>
	/// Implements an easy way to access OpenGL PBuffers
	/// </summary>
  public class PBuffer : RenderingContext
  {
    protected IntPtr hPBufferDC;
    protected IntPtr hPBufferRC;
    protected IntPtr hPBuffer;
    protected bool isBindable;
    protected bool isLocked;
 
    public IntPtr HPBuffer { get { return hPBuffer; } }
    public IntPtr HPBufferDC { get { return hPBufferDC; } }
    public IntPtr HPBufferRC { get { return hPBufferRC; } }
 
    protected IntPtr lastDC;
    protected IntPtr lastRC;
 
    protected Texture uploadTexture;
    protected Bmp textureBitmap;
 
    protected int realWidth, realHeight;
 
    public Texture Texture { get { return uploadTexture; } } 
 
    public PBuffer() : base()
		{
      isBindable = false;
		}
 
    protected static int FindNextPOTD(int x) 
    {
      for(int i = 0; i < 32; i++) 
      {
        int p = 1<<i;
        if(p>=x) return p;
      }
      return x;
    }
    public override void CreateContext(IntPtr hDC, int width, int height, int ColorBits, int ZBufferBits, int StencilBits) 
    {
      CreateContext(hDC, width, height, ColorBits, ZBufferBits, StencilBits, isBindable, TextureFilter.Linear, TextureFilter.Linear);
    }
    public virtual void CreateContext(IntPtr hDC, int width, int height, int ColorBits, int ZBufferBits, int StencilBits, bool isBindable) 
    {
      CreateContext(hDC, width, height, ColorBits, ZBufferBits, StencilBits, isBindable, TextureFilter.Linear, TextureFilter.Linear);
    }
    public virtual void CreateContext(IntPtr hDC, int width, int height, int ColorBits, int ZBufferBits, int StencilBits, bool isBindable, TextureFilter magFilter, TextureFilter minFilter)
    {
      if(hDC == IntPtr.Zero) 
      {
        hDC = Wgl.wglGetCurrentDC();
      }
      this.hDC = hDC;
      this.isBindable = isBindable;
      this.width = width;
      this.height = height;
 
      hRC = Wgl.wglGetCurrentContext();
 
      const int MAX_PBUFFER_PFD_ATTRIBS = 50;
      const int MAX_PBUFFER_PB_ATTRIBS = 50;
      const int MAX_PBUFFER_PFD_FORMATS = 50;
 
      int [] iattributes = new int[2*MAX_PBUFFER_PFD_ATTRIBS];
      float [] fattributes = new float[2*MAX_PBUFFER_PFD_ATTRIBS];
      int [] pbattributes = new int[2*MAX_PBUFFER_PB_ATTRIBS];
      //int nfattribs = 0;
      int niattribs = 0;
      int npbattribs = 0;
 
      for(int i = 0; i < 2*MAX_PBUFFER_PFD_ATTRIBS; i++ ) 
      {
        iattributes[i] = 0;
        pbattributes[i] = 0;
        fattributes[i] = 0;
      }
      /*iattributes[2*niattribs ] = Wgl.WGL_SUPPORT_OPENGL_ARB;
      iattributes[2*niattribs+1] = Gl.GL_TRUE;
      niattribs++;*/
 
      iattributes[2*niattribs ] = Wgl.WGL_DRAW_TO_PBUFFER_ARB;
      iattributes[2*niattribs+1] = Gl.GL_TRUE;
      niattribs++;
 
      if(isBindable) 
      {
        iattributes[2*niattribs ] = ((ColorBits>24)?Wgl.WGL_BIND_TO_TEXTURE_RGBA_ARB:Wgl.WGL_BIND_TO_TEXTURE_RGB_ARB);
        iattributes[2*niattribs+1] = Gl.GL_TRUE;
        niattribs++;
      } 
      iattributes[2*niattribs ] = Wgl.WGL_DEPTH_BITS_ARB;
      iattributes[2*niattribs+1] = ZBufferBits;
      niattribs++;
 
      iattributes[2*niattribs ] = Wgl.WGL_STENCIL_BITS_ARB;
      iattributes[2*niattribs+1] = StencilBits;
      niattribs++;
 
      //if(isBindable) 
      //{
        iattributes[2*niattribs ] = Wgl.WGL_RED_BITS_ARB;
        iattributes[2*niattribs+1] = 8;
        niattribs++;
        iattributes[2*niattribs ] = Wgl.WGL_GREEN_BITS_ARB;
        iattributes[2*niattribs+1] = 8;
        niattribs++;
        iattributes[2*niattribs ] = Wgl.WGL_BLUE_BITS_ARB;
        iattributes[2*niattribs+1] = 8;
        niattribs++;
        iattributes[2*niattribs ] = Wgl.WGL_ALPHA_BITS_ARB;
        iattributes[2*niattribs+1] = ((ColorBits==32)?8:0);
        niattribs++;
/*      } 
      else 
      {*/
        iattributes[2*niattribs ] = Wgl.WGL_COLOR_BITS_ARB;
        iattributes[2*niattribs+1] = ColorBits;
        niattribs++;
      //}
 
      int [] pformat = new int[MAX_PBUFFER_PFD_FORMATS];
      uint nformats;
 
      if(Ext.wglChoosePixelFormatARB(hDC, iattributes, fattributes, MAX_PBUFFER_PFD_FORMATS, pformat, out nformats) == 0) 
      {
        throw new Exception("Couldn't find a suitable pixel format: pbuffer creation error");
      }
      if(nformats == 0) 
      {
        throw new Exception("Couldn't find a suitable pixel format: PBuffer creation error");
      }
 
      pbattributes[2*npbattribs ] = Wgl.WGL_PBUFFER_LARGEST_ARB;
      pbattributes[2*npbattribs+1] = Gl.GL_FALSE;
      npbattribs++;
      if(isBindable) 
      {
        pbattributes[2*npbattribs ] = Wgl.WGL_TEXTURE_TARGET_ARB;
        pbattributes[2*npbattribs+1] = Wgl.WGL_TEXTURE_2D_ARB;
        npbattribs++;
        pbattributes[2*npbattribs ] = Wgl.WGL_TEXTURE_FORMAT_ARB;
        pbattributes[2*npbattribs+1] = Wgl.WGL_TEXTURE_RGBA_ARB;
        npbattribs++;
        pbattributes[2*npbattribs ] = Wgl.WGL_MIPMAP_TEXTURE_ARB;
        pbattributes[2*npbattribs+1] = Gl.GL_FALSE;
        npbattribs++;        
      }
 
      //realWidth = FindNextPOTD(width);
      //realHeight = FindNextPOTD(height);
      realWidth = width;
      realHeight = height;
      hPBuffer = Ext.wglCreatePbufferARB(hDC, pformat[0], realWidth, realHeight, pbattributes);
      hPBufferDC = Ext.wglGetPbufferDCARB(hPBuffer);
      hPBufferRC = Wgl.wglCreateContext(hPBufferDC);
      Wgl.wglShareLists(hRC, hPBufferRC);
 
      Ext.wglQueryPbufferARB( hPBuffer, Wgl.WGL_PBUFFER_WIDTH_ARB, out this.realWidth);
      Ext.wglQueryPbufferARB( hPBuffer, Wgl.WGL_PBUFFER_HEIGHT_ARB, out this.realHeight);
 
      if(!isBindable) 
      {
        // Create a texture for uploading
        int tID = 0;
        textureBitmap = new Bmp("PBuffer Internal Texture Bitmap");
        textureBitmap.CreateBlank(realWidth, realHeight, ColorBits);
        textureBitmap.UsesMipmaps = false;    
        textureBitmap.MagFilter = magFilter;
        textureBitmap.MinFilter = minFilter;
        textureBitmap.TileType[0] = TextureTileTypes.ClampToEdge;
        textureBitmap.TileType[1] = TextureTileTypes.ClampToEdge;
        textureBitmap.InitializeOnHardware(ref tID);
        uploadTexture = new Texture("PBuffer Internal Texture",textureBitmap);                
        // Correct POTD
        //width = this.width = textureBitmap.Width;
        //height = this.height = textureBitmap.Height;
      } 
      else 
      {
        int tID = 0;
        textureBitmap = new Bmp("PBuffer Internal Texture Bitmap");
        textureBitmap.CreateBlank(realWidth, realHeight, ColorBits);
        textureBitmap.UsesMipmaps = false;    
        textureBitmap.MagFilter = magFilter;
        textureBitmap.MinFilter = minFilter;
        textureBitmap.TileType[0] = TextureTileTypes.ClampToEdge;
        textureBitmap.TileType[1] = TextureTileTypes.ClampToEdge;
        int w, h;
        w = textureBitmap.Width;
        h = textureBitmap.Height;
        for(int x = 0; x < w; x++) 
        {
          for(int y = 0; y < h; y++) 
          {
            textureBitmap.Data[x*(ColorBits/8)+y*w*(ColorBits/8)] = (byte)((x*y)%256);
            textureBitmap.Data[x*(ColorBits/8)+y*w*(ColorBits/8)+1] = (byte)((x*y)%256);
            textureBitmap.Data[x*(ColorBits/8)+y*w*(ColorBits/8)+2] = (byte)((x*y)%256);
            textureBitmap.Data[x*(ColorBits/8)+y*w*(ColorBits/8)+3] = (byte)((x*y)%256);
          }
        }
 
        textureBitmap.InitializeOnHardware(ref tID);
        uploadTexture = new Texture("PBuffer Internal Texture",textureBitmap);
//        uploadTexture = new BlankTexture("PBuffer Internal Bindable Texture");
      }
 
      initialized = true;
 
      MakeCurrent();
      Gl.glClearColor(0,0,0,1);
      Gl.glClear(Gl.GL_COLOR_BUFFER_BIT|Gl.GL_DEPTH_BUFFER_BIT);
      ReleaseCurrent();
      ContextHelper.MakeCurrent(hDC, hRC);
 
    }
 
    public override void MakeCurrent()
    {
      CheckInitialized();
      lastDC = ContextHelper.CurrentDC;
      lastRC = ContextHelper.CurrentRC;
      if(isBindable) 
      {
        if(!isLocked) 
        {
          uploadTexture.SetTexture();
          Ext.wglReleaseTexImageARB(this.HPBuffer, Wgl.WGL_FRONT_LEFT_ARB);
        }
        isLocked = true;
      }
      ContextHelper.MakeCurrent(hPBufferDC, hPBufferRC);
    }
 
    public void ReleaseCurrent() 
    {
      ReleaseCurrent(true);
    }
    public void ReleaseCurrent(bool uploadFrame) 
    {
      CheckInitialized();
 
      if(!isBindable) 
      {
        if(uploadFrame) 
        {
          ((Bmp)uploadTexture.Bitmap).CopyFrameToHardware(uploadTexture.Bitmap.TextureID, width, height);
        }
      } 
      ContextHelper.MakeCurrent(lastDC, lastRC);
      if(isBindable)
      {  
        if(isLocked) 
        {
          uploadTexture.SetTexture();
          Ext.wglBindTexImageARB(this.HPBuffer, Wgl.WGL_FRONT_LEFT_ARB);
        }
        isLocked = false;
      }
    }
    public void Bind() 
    {
      CheckInitialized();
      if(!isBindable || (isBindable && !isLocked))
      {
        uploadTexture.SetTexture();
        if(isBindable)
          Ext.wglBindTexImageARB(this.HPBuffer, Wgl.WGL_FRONT_LEFT_ARB);
      }
    }
 
    public void Unbind() 
    {
      CheckInitialized();
      if(isBindable && !isLocked) 
      {
        Ext.wglReleaseTexImageARB(this.HPBuffer, Wgl.WGL_FRONT_LEFT_ARB);
      }
    }
	}
}
 

Download pbuffer.cs pbuffer.cs - 9.6 KB