#include once "window9.bi"


'  OpenGLGadget(left,top,width,height,[,[cBits],[dBits],[sBits],[aBits]])
'
' cBits = ColorBits   (bits of pixel buffer 15,16,24 or 32)
' dBits = DepthBits   (optional bits of depth buffer)
' sBits = StencilBits (optional bits of stencil buffer)
' aBits = AccumBits   (optional bits of accum buffer)

#define DEBUG

#ifdef DEBUG
#define DPRINT(msg) : MessageBox(NULL,msg,"OpenGLGadget",MB_ICONERROR): end 
#else
#define DPRINT(msg) :
#endif

type OPENGLGADGETDATA
  as integer gadget
  as HDC   dc
  as HGLRC rc
end type

' return 15,16,24 or 32
private function MakeBits(Bits as integer) as integer
  Bits = abs(Bits)
  if Bits<16 then
    return 15
  elseif Bits<24 then
    return 16
  elseif Bits<32 then
    return 24
  else
    return 32
  end if
end function

' get or set OpenGL render context
private sub RenderContext(gadget as integer,byref dc as HDC,byref rc as HGLRC,set as integer)
  static as OPENGLGADGETDATA ptr pGLList=NULL
  static as integer              nGLList=0
  if (set<>0) then
    nGLList+=1
    pGLList=reallocate(pGLList,sizeof(OPENGLGADGETDATA)*nGLList)
    pGLList[nGLList-1].gadget = gadget
    pGLList[nGLList-1].dc     = dc
    pGLList[nGLList-1].rc     = rc
    return
  end if
  rc=NULL
  dc=NULL
  if nGLList>0 then
    for i as integer=0 to nGLList-1
      if pGLList[i].gadget=gadget then
        dc=pGLList[i].dc
        rc=pGLList[i].rc
        return
      end if
    next
  end if
end sub

' create OpenGL render context from device context
private function CreateRC(dc as HDC,cBits as integer,dBits as integer,sBits as integer,aBits as integer) as HGLRC 
  
  dim as PIXELFORMATDESCRIPTOR pfd

  with pfd
   .nSize        = SIZEOF(PIXELFORMATDESCRIPTOR)
   .nVersion     = 1
   .dwFlags      = PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER
   .iPixelType   = PFD_TYPE_RGBA
   .iLayerType   = PFD_MAIN_PLANE
   .cColorBits   = cBits
   .cDepthBits   = dBits
   .cStencilBits = sBits
   .cAccumBits   = aBits
  end with

  dim as integer cp = ChoosePixelFormat(dc,@pfd)
  if (cp<1) then
    DPRINT("error: in CreateRC() ChoosePixelFormat() !")
    return NULL
  end if

  if SetPixelFormat(dc , cp , @pfd)=0 then
    DPRINT("error: in CreateRC() SetPixelFormat() !")
    return NULL
  end if  
    
  dim as HGLRC rc = wglCreateContext(dc)
  if (rc=NULL) then
    DPRINT("error: in CreateRC() wglCreateContext() !")
  end if

  return rc
end function

' CreateOpenGL gadget
Function OpenGLGadget Alias "OpenGLGadget" (ByVal gadget As integer, ByVal x As Integer,ByVal y As Integer,ByVal w As Integer,ByVal h As Integer, _
                                            ByVal cBits  As integer,byval dBits as integer,byval sBits as integer,byval aBits as integer) As HWND Export
  
  ' must be 15,16,24 or 32
  cBits=MakeBits(cBits)
  ' depth buffer is optional
  if (dBits>0) then 
    dBits=MakeBits(dBits)
  end if
  
  ' stencil buffer is optional
  if sBits<1 then
    sBits=0
  elseif sBits>8 then
    sBits=8
  end if
  
  ' accum buffer is optional
  if aBits<1 then
    aBits=0
  elseif aBits>8 then
    aBits=8
  end if
  
  dim as HWND parent = GETGURRENTAL()
  if (parent=NULL) then
    DPRINT("error: no parent window!")
    return NULL
  end if
  ' WS_CLIPSIBLINGS or WS_CLIPCHILDREN
  dim as HWND wnd = CreateWindowEx( 0, "static", 0,WS_CLIPSIBLINGS or WS_CHILD or WS_VISIBLE, x, y, w, h, parent, Cast(HMENU,gadget), 0, 0)
  if (wnd=NULL) then
    DPRINT("error: CreateWindowEx() wnd=0 !")
    return NULL
  end if
  ADDIN9999(gadget,wnd)

  dim as HDC dc = GetDC(wnd)
  if (dc=NULL) then
    DPRINT("error: GetDC() !")
    return NULL
  end if

  dim as HGLRC rc = CreateRC(dc,cBits,dBits,sBits,aBits)
  if (rc=NULL) then 
    ReleaseDC(wnd,dc)
    DPRINT("error: rc=NULL !")
    return wnd
  end if
  
  ' save the rendercontext
  RenderContext(gadget,dc,rc,1)

  ' make it as the current render context
  wglMakeCurrent(dc,rc)
  
  ' set quality
  glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST)
  glHint(GL_FOG_HINT,GL_NICEST)
  glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST)
  glHint(GL_LINE_SMOOTH_HINT,GL_NICEST)
  glHint(GL_POINT_SMOOTH_HINT,GL_NICEST)
  
  ' resize the visible viewport
  glViewport(0,0,w,h)
  
  ' reset projection matrix
  glMatrixMode(GL_PROJECTION)
  glLoadIdentity()

  if (dBits>0) then
    ' 3D
    dim as double ratio = iif(w>h,w/h,h/w)
    gluPerspective(65.0, ratio, 0.1,1000.0)
    glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST)
    glEnable(GL_DEPTH_TEST)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
  else
    ' 2D
    glOrtho (0, w, h, 0, 0, 1)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    glDisable(GL_DEPTH_TEST)
    glTranslatef(0.375, 0.375, 0)
  end if
  
  ' set background color
  glClearColor(0.75,0.5,0.0,1)
  
  ' clear the buffers
  dim as integer buffers = GL_COLOR_BUFFER_BIT
  if (dBits>0) then buffers or=GL_DEPTH_BUFFER_BIT
  if (sBits>0) then buffers or=GL_STENCIL_BUFFER_BIT
  if (aBits>0) then buffers or=GL_ACCUM_BUFFER_BIT
  
  glClear(buffers)

  ' make it visible
  SwapBuffers(dc)

  Return wnd
End Function

' select this gatget as current OpenGL render context
function OpenGLGadgetMakeCurrent alias "OpenGLGadgetMakeCurrent" (ByVal gadget As Integer) As Integer Export
  ' get device and render context from gadget
  dim as HGLRC rc
  dim as HDC   dc
  RenderContext(gadget,dc,rc,0)
  if ((rc=NULL) or (dc=NULL)) then return 0 

  ' make it as current
  function = wglMakeCurrent(dc,rc)

end function

' swap the buffers from gadget 
function OpenGLGadgetSwapBuffers alias "OpenGLGadgetSwapBuffers" (ByVal gadget As Integer) As Integer Export
  ' get render context from gadget
  dim as HGLRC rc
  dim as HDC   dc 
  RenderContext(gadget,dc,rc,0)
  if ((rc=NULL) or (dc=NULL)) then return 0 

  SwapBuffers(dc)
  return 1
End Function
