#include once "window9.bi"
#include once "GL/gl.bi"

sub Perspective(byval fov as double, byval ratio as double, byval zNear as double, byval zFar as double) Export
	dim as double fH = tan( fov / 360.0 * 3.1415926535897932384626433832795 ) * zNear
	dim as double fW = fH * ratio
	glFrustum(-fW,fW,-fH,fH,zNear,zFar)
end sub

sub LookAt(byval ex as double, byval ey as double, byval ez as double, _
			byval lx as double, byval ly as double, byval lz as double, _
			byval ux as double, byval uy as double, byval uz as double ) Export
	dim as double z(2) = {ex-lx,ey-ly,ez-lz}
	dim as double l=z(0)*z(0)+z(1)*z(1)+z(2)*z(2)
	if (l) then
		l=1.0/sqr(l):z(0)*=l:z(1)*=l:z(2)*=l
	end if
	dim as double x(2)={uy*z(2)-uz*z(1), _
	-ux*z(2)+uz*z(0), _
	ux*z(1)-uy*z(0)}
	l=x(0)*x(0)+x(1)*x(1)+x(2)*x(2)
	if (l) then
		l=1.0/sqr(l):x(0)*=l:x(1)*=l:x(2)*=l
	end if
	dim as double y(2)={z(1)*x(2)-z(2)*x(1), _
	-z(0)*x(2)+z(2)*x(0), _
	z(0)*x(1)-z(1)*x(0)}
	
	l=y(0)*y(0)+y(1)*y(1)+y(2)*y(2)
	if (l) then
		l=1.0/sqr(l):y(0)*=l:y(1)*=l:y(2)*=l
	end if
	dim as double m4x4(15)=>{x(0),y(0),z(0),0, _
	x(1),y(1),z(1),0, _
	x(2),y(2),z(2),0, _
	0,   0,   0,1}
	glMultMatrixd @m4x4(0)
	glTranslated -ex,-ey,-ez
end sub


'  OpenGLGadget(id,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


' get or set OpenGL render context
private sub RenderContext(byval gadget as integer, byref dc as HDC, byref rc as HGLRC, byval 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)
		if pGLList=0 then exit sub
		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(byval dc as HDC, byval cBits as integer, byval dBits as integer, byval sBits as integer, byval 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(ByVal gadget as Long, _
					ByVal x as Long, ByVal y as Long, _
					ByVal w as Long, ByVal h as Long, _
					ByVal cBits as Long, _
					byval dBits as Long, _
					byval sBits as Long, _
					byval aBits as Long) As HWND Export
	
	if cBits=0 then cBits=24
	if dBits>0 andalso dBits<16 then dBits=16
	
	
	if cBits<24 then
		cBits=16
	elseif cBits<32 then
		cBits=24
	elseif cBits>24 then
		cBits=32
	end if
	
	' depth buffer is optional
	if dBits<16 then
		dBits=0
	elseif dBits<24 then
		dBits=16
	elseif dBits<32 then
		dBits=24
	else
		dBits=32
	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 = win9GetCurrent()
	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,CInt(gadget)), 0, 0)
	if (wnd=NULL) then
		DPRINT("error: CreateWindowEx() wnd=0 !")
		return NULL
	end if
	' put gadget and handle in list
	win9AddNewGadget(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)
		Perspective(65.0, ratio, 0.1,1000.0)
		glEnable(GL_DEPTH_TEST)
		glMatrixMode(GL_MODELVIEW)
		glLoadIdentity()
	else
		' 2D
		glOrtho (0, w, h, 0, -1, 1)
		glMatrixMode(GL_MODELVIEW)
		glLoadIdentity()
		glDisable(GL_DEPTH_TEST)
		glTranslatef(0.375, 0.375, 0)
	end if
	
	' set background color
	glClearColor(0,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)
	SwapBuffers(dc)
	glClear(buffers)
	SwapBuffers(dc)
	Return wnd
End Function

' select this gatget as current OpenGL render context
sub OpenGLGadgetMakeCurrent(ByVal gadget As Long) Export
	' get device and render context from gadget
	dim as HGLRC rc
	dim as HDC   dc
	RenderContext(gadget,dc,rc,0)
	if (rc=NULL) orelse (dc=NULL) then Exit Sub
	
	' make it as current
	wglMakeCurrent(dc,rc)
	
end Sub

' swap the buffers from gadget
sub OpenGLGadgetSwapBuffers(ByVal gadget As Long)  Export
	' get render context from gadget
	dim as HGLRC rc
	dim as HDC   dc
	RenderContext(gadget,dc,rc,0)
	if (rc=NULL) orelse (dc=NULL) then Exit Sub
	
	SwapBuffers(dc)
	
End sub
