//================================================================
// E3D library
//
// OpenGL basics
//
// AUTHOR:  Gabor Nagy
// DATE:    2025-Jul-23 23:36:42
//
// Copyright (C) 1996-2026 by Gabor Nagy. All rights reserved.
//================================================================
#ifndef _E3D_E3GL_h
#define _E3D_E3GL_h

#include <Xe/XeGL.h>

#include <E3D/GPU.h>

#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
extern "C" {
#endif

#ifdef EGLES
	#define  E3dGL_MatrixMode(p) do\
	{\
		switch(p)\
		{\
			case GL_MODELVIEW:   LGPUContext->MatrixStackIndex = E3dMatrixStackMODELVIEW;break;\
			case GL_PROJECTION:  LGPUContext->MatrixStackIndex = E3dMatrixStackPROJECTION;break;\
			default:\
				printf("%s() %s:%d  %sINVALID MATRIX MODE%s\n", __FUNCTION__, __FILE__, __LINE__, ECodeYellow, ECodeNormal);fflush(stdout);\
			break;\
		}\
	} while(0)
#else
	#define  E3dGL_MatrixMode  EpglMatrixMode
#endif

#if E3dGL_FLOAT_BITS == 64
	#define E3dGL_printf      XeGL_printfd
	#define E3dGL_printfML    XeGL_printfMLd
	#define E3dGL_wprintf     XeGL_wprintfd

	#define EpglLoadMatrix      EpglLoadMatrixd
	#define EpglMultMatrix      EpglMultMatrixd

	#define E3dGL_PushMatrix    EpglPushMatrix
	#define E3dGL_PopMatrix     EpglPopMatrix
	#define E3dGL_LoadIdentity  EpglLoadIdentity
	#define E3dGL_GetFloatv     EpglGetDoublev
	#define E3dGL_Translate     EpglTranslated
	#define E3dGL_Rotate        EpglRotated
	#define E3dGL_Scale         EpglScaled
	#define E3dGL_Ortho         EpglOrtho
	#define E3dGL_Frustum       EpglFrustum

	#define E3dGL_RasterPos2v  EpglRasterPos2dv

	#define E3dGL_Vertex2v     EpglVertex2dv
	#define E3dGL_Vertex3      EpglVertex3d
	#define E3dGL_Vertex3v     EpglVertex3dv
	#define E3dGL_Normal3      EpglNormal3d
	#define E3dGL_Normal3v     EpglNormal3dv
	#define E3dGL_TexCoord2    EpglTexCoord2d
	#define E3dGL_TexCoord2v   EpglTexCoord2dv
	#define E3dGL_RasterPos3   EpglRasterPos3d
	#define E3dGL_RasterPos3v  EpglRasterPos3dv
#else
	#if E3dGL_FLOAT_BITS == 32
		#define E3dGL_printf      XeGL_printff
		#define E3dGL_printfML    XeGL_printfMLf
		#define E3dGL_wprintf     XeGL_wprintff

		#define EpglLoadMatrix    EpglLoadMatrixf
		#define EpglMultMatrix    EpglMultMatrixf

#ifdef EGLES
		#define E3dGL_PushMatrix() do\
		{\
			const int  lIncrement = 16;\
			E3dMatrixStack*  lStack = LGPUContext->MatrixStacks + LGPUContext->MatrixStackIndex;\
			if(lStack->Pointer >= lStack->AllocatedDepth - 1) { EResizeNT(E3dMatrix, lStack->AllocatedDepth + lIncrement, lStack->Matrices);lStack->AllocatedDepth = lStack->AllocatedDepth + lIncrement; }\
			memcpy(lStack->Matrices[lStack->Pointer + 1], lStack->Matrices[lStack->Pointer], sizeof(E3dMatrix));\
			lStack->Pointer++;\
		} while(0)

		#define E3dGL_PopMatrix() do\
		{\
			E3dMatrixStack*  lStack = LGPUContext->MatrixStacks + LGPUContext->MatrixStackIndex;\
			if(lStack->Pointer > 0) lStack->Pointer--;\
		} while(0)

		#define E3dGL_LoadIdentity() do\
		{\
			E3dMatrixStack*  lStack = LGPUContext->MatrixStacks + LGPUContext->MatrixStackIndex;\
			E3dMatrix_LoadIdentity(lStack->Matrices[lStack->Pointer]);\
		} while(0)

		#define E3dGL_LoadMatrix(p) do\
		{\
			E3dMatrixStack*  lStack = LGPUContext->MatrixStacks + LGPUContext->MatrixStackIndex;\
			E3dMatrix_Copy(p, lStack->Matrices[lStack->Pointer]);\
		} while(0)

		#define E3dGL_MultMatrix(p) do\
		{\
			E3dMatrixStack*  lStack = LGPUContext->MatrixStacks + LGPUContext->MatrixStackIndex;\
			E3dMatrix_Mult4x4(p, lStack->Matrices[lStack->Pointer]);\
		} while(0)

		#define E3dGL_GetFloatv         EpglGetFloatv

		#define E3dGL_Translate(mX, mY, mZ) do\
		{\
			E3dMatrixStack*  lStack = LGPUContext->MatrixStacks + LGPUContext->MatrixStackIndex;\
			E3dMatrix_Translate(lStack->Matrices[lStack->Pointer],  mX, mY, mZ);\
		} while(0)

		#define E3dGL_Rotate(mA, mX, mY, mZ) do\
		{\
			E3dMatrixStack*  lStack = LGPUContext->MatrixStacks + LGPUContext->MatrixStackIndex;\
			E3dMatrix_Rotate(lStack->Matrices[lStack->Pointer],  mA,  mX, mY, mZ);\
		} while(0)

		#define E3dGL_Scale(mX, mY, mZ) do\
		{\
			E3dMatrixStack*  lStack = LGPUContext->MatrixStacks + LGPUContext->MatrixStackIndex;\
			E3dMatrix_Scale(lStack->Matrices[lStack->Pointer],  mX, mY, mZ);\
		} while(0)

		#define E3dGL_Ortho(mLeft, mRight, mBottom, mTop,  mZNear, mZFar) do\
		{\
			E3dMatrixStack*  lStack = LGPUContext->MatrixStacks + LGPUContext->MatrixStackIndex;\
			E3dMatrix_SetOrtho(lStack->Matrices[lStack->Pointer],  mLeft, mRight, mBottom, mTop,  mZNear, mZFar);\
		} while(0)

		#define E3dGL_Frustum(mLeft, mRight, mBottom, mTop,  mZNear, mZFar) do\
		{\
			E3dMatrixStack*  lStack = LGPUContext->MatrixStacks + LGPUContext->MatrixStackIndex;\
			E3dMatrix_SetFrustum(lStack->Matrices[lStack->Pointer],  mLeft, mRight, mBottom, mTop,  mZNear, mZFar);\
		} while(0)

#else
		#define E3dGL_PushMatrix    EpglPushMatrix
		#define E3dGL_PopMatrix     EpglPopMatrix
		#define E3dGL_LoadIdentity  EpglLoadIdentity

		#define E3dGL_GetFloatv     EpglGetFloatv
		#define E3dGL_Translate     EpglTranslatef
		#define E3dGL_Rotate        EpglRotatef
		#define E3dGL_Scale         EpglScalef
		#define E3dGL_Ortho         EpglOrtho
		#define E3dGL_Frustum       EpglFrustum
#endif

		#define EpglMultMatrix       EpglMultMatrixf

		#define E3dGL_RasterPos2v  EpglRasterPos2fv

		#define E3dGL_Vertex2v     EpglVertex2fv
		#define E3dGL_Vertex3      EpglVertex3f
		#define E3dGL_Vertex3v     EpglVertex3fv
		#define E3dGL_Normal3      EpglNormal3f
		#define E3dGL_Normal3v     EpglNormal3fv
		#define E3dGL_TexCoord2    EpglTexCoord2f
		#define E3dGL_TexCoord2v   EpglTexCoord2fv
		#define E3dGL_RasterPos3   EpglRasterPos3f
		#define E3dGL_RasterPos3v  EpglRasterPos3fv
	#else
		#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
		#else
			ERROR
		#endif
	#endif
#endif // DOUBLE_PRECISION


#ifndef EGLES
#if E3dGL_FLOAT_BITS == E3dFLOAT_BITS
		#define E3dGL_LoadMatrix(p)  EpglLoadMatrix(p)
		#define E3dGL_MultMatrix(p)  EpglMultMatrix(p)
#else
		#define E3dGL_LoadMatrix(p)  { E3dGLMatrix  lGLMatrix;E3dMatrix_ToGL(p, lGLMatrix);EpglLoadMatrix(lGLMatrix); }
		#define E3dGL_MultMatrix(p)  { E3dGLMatrix  lGLMatrix;E3dMatrix_ToGL(p, lGLMatrix);EpglMultMatrix(lGLMatrix); }
#endif
#endif


#define ME3dVertex3dot(v)  E3dGL_Vertex3((v).X, (v).Y, (v).Z)

#define ME3dVertex2i(v)  glVertex2i((v)[E3dX], (v)[E3dY])
#define ME3dVertex3i(v)  glVertex3i((v)[E3dX], (v)[E3dY], (v)[E3dZ])


#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
}	// Close scope of 'extern "C"' declaration
#endif

#endif	// _E3D_E3GL_h
