/* ------------------------------------------------------------------
 * GEM - Graphics Environment for Multimedia
 *
 * SPDX-FileCopyrightText: © 2003, James Tittle II and the GEM contributors
 * SPDX-License-Identifier: GPL-2.0-or-later
 *
 * ------------------------------------------------------------------
 */

#ifndef _INCLUDE__GEM_PIXES_PIX_HALFTONE_H_
#define _INCLUDE__GEM_PIXES_PIX_HALFTONE_H_

#include "Base/GemPixObj.h"
#include "Utils/GemMath.h"

enum {
  eRoundStyle,
  eLineStyle,
  eDiamondStyle,
  eEuclideanStyle,
  ePSDiamond
};

const int nMaxCellSize = 32;
unsigned char g_pDotFuncTable[nMaxCellSize*nMaxCellSize];
unsigned char g_pGreyScaleTable[512];
const int nFPShift=16;
const int nFPMult=(1<<nFPShift);

/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
    pix_halftone

    View pix as halftone (like in newspaper-prints)

KEYWORDS
    pix

DESCRIPTION


-----------------------------------------------------------------*/
class GEM_EXTERN pix_halftone : public GemPixObj
{
  CPPEXTERN_HEADER(pix_halftone, GemPixObj);

public:

  //////////
  // Constructor
  pix_halftone();

protected:

  //////////
  // Destructor
  virtual ~pix_halftone();

  //////////
  // Do the processing
  virtual void    processRGBAImage(imageStruct &image);
  virtual void    processYUVImage(imageStruct &image);
  virtual void        processGrayImage(imageStruct &image);

  //////////
  //
  imageStruct    myImage;

  int     m_CellSize;
  int     m_Style;
  float   m_Angle;
  int     m_Smoothing;
  int     init;

  struct SPete_HalfTone_Point {
    int nX;
    int nY;
  };

  struct SPete_HalfTone_Vertex {
    SPete_HalfTone_Point Pos;
    SPete_HalfTone_Point TexCoords;
  };

  int RoundDotFunc(float X,float Y, float scale);
  int LineDotFunc(float X,float Y, float scale);
  int DiamondDotFunc(float X,float Y, float scale);
  int EuclideanDotFunc(float X,float Y, float scale);
  int PSDiamondDotFunc(float X,float Y, float scale);
  int Init(int nWidth, int nHeight);
  void Pete_HalfTone_DeInit();
  void Rotate(SPete_HalfTone_Point* pinPoint,SPete_HalfTone_Point* poutPoint,
              float Angle);
  void Pete_HalfTone_MakeDotFuncTable(unsigned char* pDotFuncTableStart,
                                      int nCellSize,int nStyle, float scale);
  void Pete_HalfTone_CalcCorners(int nWidth,int nHeight,float AngleRadians,
                                 int nCellSize,
                                 SPete_HalfTone_Point* poutLeft,
                                 SPete_HalfTone_Point* poutRight,
                                 SPete_HalfTone_Point* poutTop,
                                 SPete_HalfTone_Point* poutBottom);
  void GetRasterizationPoints(
    SPete_HalfTone_Point* pinPoints,
    SPete_HalfTone_Point* poutLeft,
    SPete_HalfTone_Point* poutRight,
    SPete_HalfTone_Point* poutTop,
    SPete_HalfTone_Point* poutBottom);
  void HeightSortPoints(SPete_HalfTone_Point* pPoints,int nPointCount);
  void Pete_HalfTone_CalcSpanEnds(
    SPete_HalfTone_Point* pinLeft,
    SPete_HalfTone_Point* pinRight,
    SPete_HalfTone_Point* pinTop,
    SPete_HalfTone_Point* pinBottom,
    int nY,int* poutLeftX,int* poutRightX);
  void LerpAlongEdges(
    SPete_HalfTone_Point* pStart,
    SPete_HalfTone_Point* pMiddle,
    SPete_HalfTone_Point* pEnd,
    int nY,int* poutX);
  void RotateMultiple(SPete_HalfTone_Point* pinPoints,
                      SPete_HalfTone_Point* poutPoints,
                      int nPointCount,
                      float Angle);
  void Pete_HalfTone_CalcSpanEnds_Vertex(
    SPete_HalfTone_Vertex* pinLeft,
    SPete_HalfTone_Vertex* pinRight,
    SPete_HalfTone_Vertex* pinTop,
    SPete_HalfTone_Vertex* pinBottom,
    int nY,
    SPete_HalfTone_Vertex* poutLeft,
    SPete_HalfTone_Vertex* poutRight);
  void Pete_HalfTone_LerpAlongEdges_Vertex(
    SPete_HalfTone_Vertex* pStart,
    SPete_HalfTone_Vertex* pMiddle,
    SPete_HalfTone_Vertex* pEnd,
    int nY,
    SPete_HalfTone_Vertex* poutVertex);
  void Pete_HalfTone_GetRasterizationVertices(
    SPete_HalfTone_Vertex* pinVertices,
    SPete_HalfTone_Vertex* poutLeft,
    SPete_HalfTone_Vertex* poutRight,
    SPete_HalfTone_Vertex* poutTop,
    SPete_HalfTone_Vertex* poutBottom);
  int Pete_HalfTone_GetLowestVertex(SPete_HalfTone_Vertex* pVertices,
                                    int nVertexCount);
  void Pete_HalfTone_RotateMultipleVertices(SPete_HalfTone_Vertex*
      pinVertices,
      SPete_HalfTone_Vertex* poutVertices,
      int nVertexCount,
      float Angle);
  void Pete_HalfTone_MakeGreyScaleTable(unsigned char* pGreyScaleTableStart,
                                        int nSmoothingThreshold);
  void YUV_MakeGreyScaleTable(unsigned char* pGreyScaleTableStart,
                              int nSmoothingThreshold);
  U32     Pete_GetImageAreaAverage(int nLeftX,int nTopY,int nDeltaX,
                                   int nDeltaY,U32* pImageData,int nImageWidth,int nImageHeight);
  U32     GetImageAreaAverageLuma(int nLeftX,int nTopY,int nDeltaX,
                                  int nDeltaY,U32* pImageData,int nImageWidth,int nImageHeight);
  unsigned char   Pete_GetImageAreaAverageGray(int nLeftX,int nTopY,
      int nDeltaX,int nDeltaY,unsigned char* pImageData,int nImageWidth,
      int nImageHeight);

private:
  //////////
  // Static member functions
  static void     sizeCallback(void *data, t_float m_CellSize);
  static void     styleCallback(void *data, t_float m_Style);
  static void     smoothCallback(void *data, t_float m_Smoothing);
  static void     angleCallback(void *data, t_float m_Angle); // 0..2pi
  /* callbacks for normalized values: smooth=0..1; angle=0..360 */
  static void smoothNCallback(void *data, t_float m_Smoothing);
  static void angleDEGCallback(void *data, t_float m_Angle);
};

#endif  // for header file
