//================================================================
// libE3D
//
// Core 3DWindow header file
//
// AUTHOR:  Gabor Nagy
// DATE:    2025-Jul-23 23:35:53
//
// Copyright (C) 1996-2026 By Gabor Nagy. All rights reserved.
//================================================================
#ifndef _E3D_Window_h
#define _E3D_Window_h


#ifndef _E3D_Camera_h
#include <E3D/Camera.h>
#endif

#include <Xe/XeTypes.h>

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


enum { CSSTEREO_ONE_ZERO = 0, CSSTEREO_ONE_ONE };

// 3D stereoscopic modes
//
enum
{
	E3dStereoNONE = 0,
	E3dStereoANAGLYPH,
	E3dStereoSHUTTER,
	E3dStereoSPLIT_HORIZONTAL,
	E3dStereoSPLIT_VERTICAL,
	E3dStereoPOLARIZED,
};

#define E3dWF_NONE       0x0000
#define E3dWF_CREATED    0x0001
#define E3dWF_MANAGED    0x0002
#define E3dWF_ALIVE      0x0004
#define E3dWF_ALL        0x0007

#define E3dZOOM          0x0008
#define E3dZOOMHORIZ     0x0010
#define E3dZOOMVERT      0x0020

#define	E3dWF_DRAWABLE   (E3dWF_CREATED|E3dWF_MANAGED|E3dWF_ALIVE)

typedef struct E3dViewClass_S  E3dViewClass;
typedef struct E3dWindow_S     E3dWindow;
typedef struct E3dWindow_S*    E3dWindowPtr;
EList_t(E3dWindowPtr);

// 3DWindow settings
//
typedef struct
{
	E3dCoord3  GridSnapSize;
	E3dCoord3  GridDisplaySize;
	E3dCoord3  SubGridSizeDisplay;
	EInt32_3   GridCount;
	EBool      GridSnapToX, GridSnapToY, GridSnapToZ;
} E3dGridSettings;


typedef struct
{
	E3dWindow*  Window;
	EInt32_2    RectAreaStart;
} E3dUserInputContext;


typedef struct
{
	EListA(,E3dNode*, Nodes);
	EList(,EObject*, Objects);
} E3dPickGlobals;


#define E3dViewCore\
	EObjectCore(E3dView);\
	E3dCamera*          VCamera;E3dModel*  CameraModel;\
	E3dCamera*          LastVCamera;E3dModel*  LastCameraModel;\
	E3dCoordinate       MagMin, MagMax;\
	E3dOverlaySettings  Overlay;\
	void*               GridGLData  /* Graphics library-specific (OpenGL, Vulkan etc.) data for drawing grids */


typedef struct
{
	E3dViewCore;
} E3dView, *E3dViewPtr;
EList_t(E3dViewPtr);

// View flags for selective redraws
//
#define E3dVM_FRONT        0x0001
#define E3dVM_LEFT         0x0002
#define E3dVM_RIGHT        0x0004
#define E3dVM_TOP          0x0008
#define E3dVM_BOTTOM       0x0010
#define E3dVM_PERSPECTIVE  0x0020
#define E3dVM_SCHEMATICS   0x0040
#define E3dVM_TEXTURE      0x0100
#define E3dVM_ANIMATION    0x1000
#define E3dVM_SHADEGRAPH   0x2000
#define E3dVM_ALL          0x31FF

#define E3dVM_NORMAL3D  (E3dVM_FRONT|E3dVM_LEFT|E3dVM_RIGHT|E3dVM_TOP|E3dVM_BOTTOM|E3dVM_PERSPECTIVE|E3dVM_TEXTURE)


typedef EChangeFlags (*E3dButtonEventFunc)(E3dWindow* P3DWindow, const EIndex PPtrX, const EIndex PPtrY,  const int PButton, const int PAction, const unsigned int PModifiers, E3dUserInputContext* PUserInputContext);
typedef EChangeFlags (*E3dPointerMoveFunc)(E3dWindow* P3DWindow, const EIndex PPtrX, const EIndex PPtrY,  const unsigned int PState, E3dUserInputContext* PUserInputContext);
typedef EChangeFlags (*E3dKeyEventFunc)(E3dWindow* P3DWindow,  const XeKeySym PKeySym, const int PAction, XeModifiers PModifiers,  const EIndex PPtrX, const EIndex PPtrY);


struct E3dViewClass_S
{
	ECoreClassCore(E3dView);

// These must be in this order (Init(), Copy(), Free()) to match EBaseObject
	void    (*Init)(E3dWindow* P3DWindow, E3dView* PView);
	void    (*Copy)(const E3dWindow* PSrc3DWindow, E3dView* PSrcView,  const E3dWindow* PDst3DWindow, E3dView* PDstView);
	void    (*Free)(E3dWindow* P3DWindow, E3dView* PView);

	void    (*ClassFree)(void);

	EIndex  (*SelectionBBox)(E3dScene* PScene, const uint32_t PWhatToInclude,  E3dBBox* PBBox);
	int     (*DrawScene)(E3dWindow* P3DWindow, const E3dDrawContext* PDrawContext,  E3dScene* PScene, E3dCamera* PCamera, E3dModel* PCameraModel, EChangeFlags PSceneChangeFlags, EChangeFlags PRendererChangeFlags);
	void    (*DrawSceneForPick)(E3dWindow* P3DWindow, E3dScene* PScene, E3dCamera* PCamera,  const unsigned int PTargets,  const E3dMatrix PWorldToViewerMatrix, const E3dMatrix PWorldToClipMatrix,  E3dPickGlobals* PPickGlobals);

	E3dButtonEventFunc  ButtonEventFunc;
	E3dPointerMoveFunc  PointerMoveFunc;
	E3dKeyEventFunc     KeyEventFunc;

	void    (*WindowHeaderGUI)(E3dWindow* P3DWindow);
	void*   (*DialogBoxGUI)(E3dWindow* P3DWindow);

	uint32_t  IDFlag;
};


typedef struct
{
	EIndex2  Position, Size;
} E3dViewPort;

// Tiles represent sub-viewports
// 1: normal rendering, 2: stereo, 6: cubemap etc.
typedef struct
{
	EIndex2      Size;
	E3dViewPort  ViewPort;        // Tile's viewport Position and size in rendertarget, values multiplied by SSAA
	uint16_t     CameraFlag;      // E3dCameraLEFT, E3dCameraRIGHT
	uint16_t     ReorientFlags;   // EpROTATE_RIGHT, EpROTATE_LEFT OR-ed with EpFLIP_H or EpFLIP_V. Rotation will be performed before flip and H flip before V flip  */
} E3dWindowTile;


#define E3dWindowNTILES_MAX   6   // 1: normal rendering, 2: stereo, 6: cubemap...

#define E3dWindowCore\
	EObjectCore(EObject);\
\
	E3dView*         PerspectiveView;\
	EList_s(, E3dViewPtr, Views);\
\
	E3dView*         ViewMode;           /* The current View. E.g. Perspective, or Schematics  */\
\
	EIndex2          Size;               /* In pixels */\
	double           AspectRatio;\
	uint16_t         Visibility;         /* Unobscured, partially obscured, fully obscured     */\
	uint16_t         StatusFlags;        /* E3dWF_CREATED, E3dWF_MANAGED, E3dWF_ALIVE          */\
	E3dGridSettings  GridSettings;\
	E3dCoordinate    StereoEye2DOffset;     /* For horizontaly split stereo on single display panel HMDs (e.g. VisoR1, Oculus etc.), the images may not be centered in the left/right halves. */\
	uint8_t          StereoMode;            /* 0: no tiling. E3dStereoSPLIT_HORIZONTAL, E3dStereoSPLIT_VERTICAL etc. */\
	E3dWindowTile    Tiles[E3dWindowNTILES_MAX];  /* Tiles represent sub-viewports. 2: stereo, 6: cubemap etc. */\
	EIndex2          TotalRenderTargetSize; /* Includes SSAA resolution multiplier  */\
	uint8_t          CaptureMode;           /* Capture mode. 0 = no capture, E3dCaptureAABUFFER save SSAA buffer into file, E3dCaptureFINAL save final window to file */\
\
	E3dCoordinate    LensCorrection,     /* Lens correction (e.g. for VisoR1 HMD). 0.0: no effect, positive values: barrel correction (compensate for pincushion distortion) */\
	                 LensCorrectionR,    /* Lens correction difference for red (0.0 if there is no chromatic aberration correction)   */\
	                 LensCorrectionB;    /* Lens correction difference for blue (0.0 if there is no chromatic aberration correction)  */\
	E3dCoordinate    Magnification;      /* Magnification after lens correction                                                       */\
\
	EBool            NeedsSwapBuffers;\
	E3dGPUContext*   GPUContext


struct E3dWindow_S
{
	E3dWindowCore;
};


extern E3dWindow*  E3dWindow_New(const char* PName);
extern E3dView*    E3dWindow_ViewByClass(E3dWindow* P3DWindow, const E3dViewClass* PClass);
extern int         E3dWindow_ViewModeSetByClass(E3dWindow* P3DWindow, const E3dViewClass* PClass, E3dView** PWhich);
extern int         E3dWindow_ViewModeSetByID(E3dWindow* P3DWindow, const uint32_t PViewModeID, E3dView** PWhich);
extern int         E3dWindow_TilesLayout(E3dWindow* P3DWindow, const int PAAMult);
extern const E3dWindowTile*  E3dWindow_SubCameraGetTile(const E3dWindow* P3DWindow, const uint16_t PSubCameraID);

EList(extern, E3dViewClass*, E3dView_Classes);

extern E3dView*       E3dView_New(E3dWindow* P3DWindow, E3dViewClass* PClass);
extern E3dViewClass*  E3dView_ClassByName(const char* PName);
extern E3dViewClass*  E3dView_ClassRegister(E3dViewClass* PDescriptor);
extern void           E3dView_ClassDeactivate(E3dViewClass* PClass);
extern void           E3dView_ClassesFree(void);

extern void        E3dGridSettings_Init(E3dGridSettings* PSettings);

extern E3dCamera*  E3dCamera_NewWithModel(const char* PName, E3dModel** PModel);

extern void  E3dGL_CameraPerspective(E3dGPUContext* PGPUContext,  E3dCamera* PCamera, const E3dCoordinate PAspectRatio);

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

#endif	// _E3D_Window_h
