//================================================================
// E3D library
//
// Camera header file
//
// AUTHOR:  Gabor Nagy
// DATE:    2024-Oct-10 03:22:48
//
// Copyright (C) 1996-2026 by Gabor Nagy. All rights reserved.
//================================================================
#ifndef _E3D_Camera_h
#define _E3D_Camera_h


#ifndef _E3D_Model_h
#include <E3D/Model.h>
#endif

#ifndef _E3D_Ray_h
#include <E3D/Ray.h>
#endif

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


// Display formats
//
enum
{
	E3dNTSC = 0,
	E3dPAL,
	E3dVESA640x480,
};


typedef struct E3dCamera_S  E3dCamera;


typedef struct
{
	E3dCoord2  Vertex0, Vertex1, Vertex2, Edge1, Edge2;
	EIndex     Index;
} E3d2DRTriangle;


typedef struct
{
	EList_i32(, E3d2DRTriangle*, Triangles);
} E3dGridCell;



typedef struct
{
	E3dCoordinate  AspectRatio, FOVMul,
	               FocalDistance, LensDiameter;

// Internal variables for precomputations
//
	E3dCoord2      RayStart;  // For perspective
	E3dCoord2      RayStep;   // For perspective lens
	E3dCoord2      Pixel_d;   // Pixel partial derivatives

	E3dCoord2      SizeInv;   // For fish-eye lens

	EIndex2        PixelPosition;

// For light-maps
//
	E3dRPolyGroup*              RPolyGroup;
	E3d2DRTriangle*             TextureSpaceRTriangles;
	E3dTextureMapperSTTo3DFunc  InvMapPoint;
	int*                        FirstHitIDImage;
	E3dGridCell*                Grid;    // Kind of like voxels, but in 2D...
	int                         GridCountX, GridCountY;
	E3dCoord2                   VoxelSize, VoxelSizeInv, BBoxMin;
	ERandomState                RandomState[5];
} E3dOptics;


typedef int  E3dPixelCoordinate;


typedef  int    (*E3dOpticsInitFunc)(E3dScene* PScene, const E3dRenderer* PRenderer, E3dRenderer_thread* PThread, const E3dCamera* PCamera, const E3dModel* PCameraModel);
typedef  EBool  (*E3dOpticsFunc)(const E3dRenderer* PRenderer, E3dRenderer_thread* PThread, const E3dCamera* PCamera, const E3dMatrix PViewerToWorldMatrix,  const E3dPixelCoordinate PX, const E3dPixelCoordinate PY,  const E3dPixelCoordinate PImageSizeX, const E3dPixelCoordinate PImageSizeY,  const E3dCoordinate PSubX, const E3dCoordinate PSubY, E3dDRay* PRay);
typedef  void   (*E3dOpticsClearFunc)(const E3dCamera* PCamera);

typedef struct
{
	ECoreClassCore(EObject);

	E3dOpticsInitFunc   Init;

	E3dOpticsFunc       Compute;
	E3dOpticsClearFunc  Clear;
} E3dOpticsClass;


// Focusing mode
enum
{
	E3dFOCUS_AT_AIMPOINT = 1
};

struct E3dCamera_S
{
	E3dObjectCore;


	E3dCoordinate    FieldOfView;  // Field of view in degrees
	E3dCoordinate    ZNear, ZFar,
	                 EyeDistance;     // 3D eye-distance for stereoscopic camera
	E3dCoord2        Mag;             // Magnification for orthogonal views

	float            ShutterTime;


// Optics
//
	EBool            DepthOfFieldOn;
	E3dCoordinate    FocalLength,    // Focal length
	                 Aperture,       // "f" number
	                 LensDiameter,
	                 FocalDistance;  // Distance to focal plane.

	E3dOptics*       Optics;
	E3dOpticsClass*  OpticsClass;
	int              FocusingMode;   // 0: manual (use FocalDistance), E3dFOCUS_AT_AIMPOINT : use AimDistance


// Image sensor (e.g. film)
//
	E3dCoord2    SensorSize;         // E.g. 36 mm film : 0.036 x 0.024  (36mm x 24mm)
	float        GlowThreshold, GlowRadius;
	EBool        Glow;

	E3dMatrix    ProjectionMatrix;

// Stuff calculated internally
//
	E3dMatrix    LeftWorldToViewerMatrix,     // For stereoscopic Camera
	             LeftViewerToWorldCameraMatrix,
	             RightWorldToViewerMatrix,
	             RightViewerToWorldCameraMatrix;

	uint8_t      StereoMode;

	EList(, ECallbackRec, Callbacks);
};



//----------------------------------------------------------------
// Global variables
//----------------------------------------------------------------
extern E3dObjectClass  E3dCamera_class[];
extern E3dCoordinate   E3d_ZNearMin, E3d_ZFarMax;


extern E3dOpticsClass  E3dOptics_class[];
extern E3dOpticsClass  E3dOpticsPerspective_class[], E3dOpticsPerspectiveDOF_class[];
extern E3dOpticsClass  E3dOpticsOrthographic_class[];
extern E3dOpticsClass  E3dOpticsFishEye_class[];
extern E3dOpticsClass  E3dOpticsRearFishEye_class[];
extern E3dOpticsClass  E3dOpticsPanorama_class[];
extern E3dOpticsClass  E3dOpticsSpherical_class[];
extern E3dOpticsClass  E3dOpticsAngleMap_class[];
extern E3dOpticsClass  E3dOpticsCubeMap_class[], E3dOpticsCubeMapDOF_class[];
extern E3dOpticsClass  E3dOpticsTextureMap_class[];

EList(extern, E3dOpticsClass*, E3d_OpticsClasses);


//----------------------------------------------------------------
// E3D/Camera.c
//----------------------------------------------------------------
typedef struct
{
	E3dNodeComponentCore;

	char*     FileName;

	EpImage*  Image;
	EBool     Show;
} E3dBackgroundImageInfo;

extern E3dNodeComponentClass*  E3dBackgroundImageNodeComponent_class;

extern E3dCoordinate  E3d_Dolly(const E3dCoordinate PViewDistance, const E3dCoordinate PAmount);

extern void        E3dCamera_Init(E3dCamera* PCamera);

extern void        E3dCamera_UpdateProjectionMatrix(E3dCamera* PCamera, const E3dCoordinate PAspectRatio);
extern void        E3dCamera_LookAt(E3dScene* PScene, E3dCamera* PCamera, E3dModel* PCameraModel, const E3dCoord3* P3Position, const E3dCoord3* PAimPoint, const E3dCoord3* PUpVector, const E3dCoordinate PBankAngle);

extern E3dCamera*  E3dCamera_Copy(const E3dCamera* PSCamera, E3dCamera** PDCameraPtr);


extern void    E3dCamera_CallbackAdd(E3dCamera* PCamera, ECallbackFunc PCallbackFunc, EPointer PClientData);
extern void    E3dCamera_CallbackRemove(E3dCamera* PCamera, ECallbackFunc PCallbackFunc, EPointer PClientData);

extern void    E3dCamera_GetViewPlaneThroughPoint(const E3dModel* PCameraModel,  const E3dCoordinate PX, const E3dCoordinate PY, const E3dCoordinate PZ,  E3dPlane* PPlane);
extern int     E3d_CameraIntersectRayWithInterestPlane(E3dScene* PScene, E3dCamera* PCamera, E3dModel* PCameraModel, E3dRay* PRay, E3dCoord3* PResult);


//
// Optics.c
//
extern void    E3dOptics_ClassesInit(void);
extern void    E3dOptics_ClassesFree(void);

extern E3dOpticsClass*  E3dOptics_ClassByName(const char* PName);


//--------------------------------
// Panel/Camera.c
//--------------------------------
extern E3dCamera*  E3d_IsActiveCameraNode(const E3dNode* PNode);
extern E3dCamera*  E3d_IsActiveCameraInterestNode(const E3dNode* PNode);
extern void        E3dp_CameraInit(void);
extern void        E3dp_CameraFree(void);

extern EBool       E3dNode_IsCameraRig(E3dScene* PScene, E3dNode* PNode,  E3dCamera** PCameraP, E3dModel** PCameraModelP);



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

#endif	// _E3D_Camera_h
