
//
// jgrlil.h (John's graphing .bmp class)
//
// Written by John A deLaubenfels, https://www.adaptune.com/steg.htm .
// Permission granted to use freely in any non-fraudulent way.
//
//
//
//
//
//
// We ONLY support 24-bit color: one byte for each of R,G,B for each pixel.  
//
//
//
//


#ifndef JGRLIL_H
#define JGRLIL_H

#ifdef _WIN32
#include <windows.h>  // for CRITICAL_SECTION
#include <TCHAR.h>    // for TCHAR
#endif // _WIN32


#include "mt64.h"






// 09-27-03: fudge 768 down to 765:
const double fudgeDown = 0.99609375;   // 765/768


#define NADA (-1)
typedef unsigned char UCHAR;
typedef   signed char SCHAR;




#ifndef MAX
#define MAX(A, B)         ((A) > (B) ? (A) : (B))
#define MIN(A, B)         ((A) < (B) ? (A) : (B))
#endif

#define BITS_PER_BYTE  (8)

#ifndef ABS
#define ABS(x)    (((x) >= 0) ? (x) : (-(x)))
#define SGN(x)    (((x) > 0) ? (1) : (((x) < 0) ? (-1) : (0)))
#endif

#define MIN_BRITI       (0)
#define MAX_BRITI1    (255)
#define MAX_SQUARI1   (65025)      // 01-08-03
#define MAX_BRITI     (765)
#define MIN_BRITE       (0.0)
#define MAX_BRITE1    (255.0)      // 01-08-03
#define MAX_SQUARE1   (65025.0)    // 01-08-03
#define MAX_BRITE     (765.0)      // 12-25-01; was 768.00
#define MAX_BRIT2     (767.99)     // 07-26-08 (jdl)
#define TWO_PI        (6.283185307179586)
#define SQRT3         (1.732050807568877)
#define THREE23       (2.080083823051904)
#define THREE34       (2.279507056954778)
#define HLOG_DFACT    (92.33248261689366)  // 04-10-04: 64.0 / log(2.0)
#define HLOG_DOFFS    (-101.437600046154)  // 04-10-04: 512.0 - log(768.0) * dFact
#define LN_TWO        (0.693147180559945)  // 05-29-04
#define LOG2(x)       (log(x) / LN_TWO)    // 05-29-04

// 08-25-03, for keeping some restraint in scale changes:
#define FIVE_MEGA_PIXEL  (5242880.0)
#define HUND_MEGA_PIXEL  (104857600.0)


// 12-28-07:
#define COL_RED       (0)
#define COL_GRN       (1)
#define COL_BLU       (2)
#define COL_TOT       (3)      // for(i=0; i<COL_TOT; i++)...


class jColor;
class jGraph;

class jTile;        // 12-22-01: average and std deviation of rectangle.

class ShapingAnch;  // 01-26-02




enum eCombineRule {COMBINE_OVERWRITE, COMBINE_ADD, COMBINE_SUBTRACT, COMBINE_EOR};



// qxoneXYlocation

struct oneXYlocation {
   double Xlocation;
   double Ylocation;
   oneXYlocation() : Xlocation(0.0), Ylocation(0.0) {}
   oneXYlocation(double x, double y) : Xlocation(x), Ylocation(y) {}
   double getLoc(int iAxis) const {return ((iAxis==0) ? (Xlocation) : (Ylocation));}
   void   getLoc(double &dL, double &dR) const {dL=Xlocation; dR=Ylocation;}
   void   setLoc(int iAxis, double dNew) {((iAxis==0) ? (Xlocation=dNew) : (Ylocation=dNew));}
   void   setLoc(double dLeft, double dRigt) {Xlocation=dLeft; Ylocation=dRigt;}
   void   chgLoc(int iAxis, double dChg) {((iAxis==0) ? (Xlocation+=dChg) : (Ylocation+=dChg));}
}; // end of oneXYlocation...





// qxjColor

class jColor {
private:
   UCHAR       m_redVal;
   UCHAR       m_grnVal;
   UCHAR       m_bluVal;

public:
   jColor();
   jColor(int oldColor);
   jColor(int iRed, int iGrn, int iBlu);
   jColor(const jColor& rs);  // copy constructor...
   ~jColor();
   const jColor& operator=(const jColor&);
   const jColor& operator+=(const jColor&);
   bool operator==(const jColor &rs) const {return ((m_redVal==rs.m_redVal) && (m_grnVal==rs.m_grnVal) && (m_bluVal==rs.m_bluVal));}
   jColor *dup_me();

   int getRed(void) const {return (int)m_redVal;}
   int getGrn(void) const {return (int)m_grnVal;}
   int getBlu(void) const {return (int)m_bluVal;}
   int getCol(int iCol) const;                                                                        // 12-28-07
   double getTotBrite(int doSqrTot=0, double fractTwo=0.0, double slopeRed=1.0, double slopeGrn=1.0, double slopeBlu=1.0) const; 

   int setTotBrite(double newVal, double unSaturate=0.0, int doFixOverS=1, int doSqrTot=0, double fractFilt=0.0, double fractFilu=-1.0, double *pRedOut=NULL, double *pGrnOut=NULL, double *pBluOut=NULL, int logOnly=0, double fractTwo=0.0, double slopeRed=1.0, double slopeGrn=1.0, double slopeBlu=1.0, double oldValIn=-1.0, double prebFactIn=1.0);

   int setTotBrit2(double newVal, double unSaturate=-1.0, int doFixOverS=1, int doSqrTot=0, double *pRedOut=NULL, double *pGrnOut=NULL, double *pBluOut=NULL, double fractTwo=0.0, double slopeRed=1.0, double slopeGrn=1.0, double slopeBlu=1.0, double oldValIn=-1, double prebFactIn=1.0); 

   void getColors(int &iRed, int &iGrn, int &iBlu) const {iRed=getRed(); iGrn=getGrn(); iBlu=getBlu();}

   void setRed(int newVal) {m_redVal = (UCHAR)(RANGE(newVal, 0, 255));}
   void setGrn(int newVal) {m_grnVal = (UCHAR)(RANGE(newVal, 0, 255));}
   void setBlu(int newVal) {m_bluVal = (UCHAR)(RANGE(newVal, 0, 255));}
   void setCol(int iCol, int newVal);                                                                 // 12-28-07
   void chgCol(int iCol, int chgVal);
   void setColors(int iRed, int iGrn, int iBlu) {setRed(iRed); setGrn(iGrn); setBlu(iBlu);}
   void setColorFromOld(int oldColor);
   int  nOverBright(int minOver=255) const;                                                           // 12-28-07

};  // end of jColor





//
// new 05-26-12 (jdl), from jColor.  In place of UCHAR, we use double.
//
//
//
//
//
//
// qxdColor

class dColor {
private:
   double      m_redVal;
   double      m_grnVal;
   double      m_bluVal;

public:
   dColor();
   // dColor(int oldColor);
   dColor(double dRed, double dGrn, double dBlu);
   dColor(const dColor& rs);  // copy constructor...
   ~dColor();
   const dColor& operator=(const dColor&);
   const dColor& operator+=(const dColor&);
   bool operator==(const dColor &rs) const {return ((m_redVal==rs.m_redVal) && (m_grnVal==rs.m_grnVal) && (m_bluVal==rs.m_bluVal));}  // qxl, qxfix: some tolerance in the double world.
   dColor *dup_me();

   double getRed(void) const {return m_redVal;}
   double getGrn(void) const {return m_grnVal;}
   double getBlu(void) const {return m_bluVal;}
   double getCol(int iCol) const;                                                                        // 12-28-07

   void getColors(double &dRed, double &dGrn, double &dBlu) const {dRed=getRed(); dGrn=getGrn(); dBlu=getBlu();}

   void setRed(double newVal) {m_redVal = newVal;}
   void setGrn(double newVal) {m_grnVal = newVal;}
   void setBlu(double newVal) {m_bluVal = newVal;}
   void setCol(int iCol, double newVal);
   void chgCol(int iCol, double chgVal);
   void setColors(double dRed, double dGrn, double dBlu) {setRed(dRed); setGrn(dGrn); setBlu(dBlu);}
};  // end of dColor








// qxjLoc

class jLoc {
private:
   int m_iH;
   int m_iV;
   double m_badness;
public:
   jLoc();
   jLoc(const jLoc& rs);  // copy constructor...
   ~jLoc();
   const jLoc& operator=(const jLoc&);

   int     iH() const {return m_iH;}
   void iH(int newVal) {m_iH = newVal;}

   int     iV() const {return m_iV;}
   void iV(int newVal) {m_iV = newVal;}

   double  badness() const {return m_badness;}
   void badness(double newVal) {m_badness = newVal;}

   static jLoc *makeCircle(double rHctr, double rVctr, int nPixel);
   static int qcmp_jLoc(const void *jl0, const void *jl1);

};  // end of jLoc






// qxjgrLil


class jgrLil {
private:
   int         m_nHoriz;
   int         m_nVert;
   int         m_rowBytes;        // rounded up to multiple of 4
   int         m_totBytes;        // in theData...
   int         m_doFixOverS;      // new var 01-01-02; 0 gets old code.
   int         m_doSqrTot;        // 04-23-02: affects total brightness.
   int         m_oorResp;         // 06-04-02: out-of-range response
   int         m_jpgQual;         // 12-22-06: for freeImage saving.
   int         m_pngQual;         // 07-20-25: for freeImage saving.
   int         m_iHFrom;          // 08-07-10: for line drawing.
   int         m_iVFrom;          // 08-07-10: for line drawing.
   bool        m_bJustMoved;      // 01-26-20: to avoid changing pixels twice at endpoints.
   eCombineRule m_combineRule;    // 12-13-10 (jdl): for adding to pixels during draw.
   unsigned int m_OtherOwned:  1; // 12-11-05: when data is shared with some openCV kinda guy...
   double      m_fractFilt;       // 04-17-03: extent of filter brightness
   double      m_fractFilu;       // 08-26-02: possible "up" filter extent, if different from overall.
   double      m_fractBrfix;      // 04-12-04: 0.0 (default): old overflow method; 1.0: nobody overflows.
   double      m_prebFact;        // 07-26-08: 1.0 (default): no pre-brightening; larger causes pre-brightening.
   double      m_fractTwo;        // 09-04-04: mix of doSqrTot 1 and 2 (actually 1 and 3).
   double      m_slopeRed;        // 03-26-05: if less than 1.0, dark is represented lighter to discourage brightening.
   double      m_slopeGrn;        // 03-26-05: if less than 1.0, dark is represented lighter to discourage brightening.
   double      m_slopeBlu;        // 03-26-05: if less than 1.0, dark is represented lighter to discourage brightening.
   double      m_inclRed;         // 05-08-09: if less than 1.0, reduce target brightness somewhat.
   double      m_inclGrn;         // 05-08-09: if less than 1.0, reduce target brightness somewhat.
   double      m_inclBlu;         // 05-08-09: if less than 1.0, reduce target brightness somewhat.
   double      m_xScale;          // 08-14-10: for line-drawing.
   double      m_xOffset;         // 08-14-10: for line-drawing.
   double      m_yScale;          // 08-14-10: for line-drawing.
   double      m_yOffset;         // 08-14-10: for line-drawing.


   jColor      m_colBackground;
   jColor      m_colDrawPen;
   UCHAR       *m_theData;
   char        *m_sourceFileName; // 07-07-03
   mutable int *m_histBig;        // 08-30-08 (jdl): full histogram w/ 256 slots.
   mutable int *m_histLil;        // 08-30-08 (jdl): little histogram, 8 slots, representing highest bit set.
   mutable int *m_histLi2;        // 07-04-13 (jdl): little histogram, 8 slots, reduced by pegged considerations.
   mutable int *m_histp;          // 07-05-13 (jdl): for brightnesses under 0x40.
   mutable int *m_histq;          // 07-05-13 (jdl): for brightnesses 0x40 and over.

   double      (jGraph::*m_calc1BrFunc)(int iHoriz, int iVert, double &unSaturate, const jTile *jtpUse);

public:
   jgrLil();
   jgrLil(const jgrLil& rs);                   // copy constructor...
   jgrLil(const jgrLil& rs, double multFact);  // copy constructor with scale change
   jgrLil(const jgrLil& rs, int ixLo, int ixTooHi, int iyLo, int iyTooHi);   // crop, clip.


   virtual ~jgrLil();
   const jgrLil& operator=(const jgrLil&);
   const jgrLil& operator+=(const jgrLil&);
   int   cpyChgSize(const jgrLil &rs);         // use the dimensions of "this" with the data of rs.
   void clear();
   virtual const char *myName(void) const {return "jgrLil";}

   virtual jgrLil *dup_me();
   virtual int memoryUnderMySway() const;

   int isSameSize(const jgrLil&);

   int nHoriz() const {return m_nHoriz;}
   int nVert()  const {return m_nVert;}
   const UCHAR *theData() const {return m_theData;}
   UCHAR       *theData()       {return m_theData;}


   static inline int colorBytesPerPixel(void) {return 3;}

   void setColBackground(jColor nuBackground) {m_colBackground = nuBackground;}
   void setColDrawPen(jColor nuDrawPen) {m_colDrawPen = nuDrawPen;}

   const jColor &getColBackground(void) const {return m_colBackground;}
   const jColor &getColDrawPen(void)    const {return m_colDrawPen;}

   void doFixOverS(int iNewVal) {m_doFixOverS = iNewVal;}
   int doFixOverS() const    {return m_doFixOverS;}
   void doSqrTot(int iNewVal) {m_doSqrTot = iNewVal;}
   int doSqrTot() const    {return m_doSqrTot;}
   void oorResp(int iNewVal) {m_oorResp = iNewVal;}
   int oorResp() const    {return m_oorResp;}

   void jpgQual(int iNewVal) {m_jpgQual = iNewVal;}
   int jpgQual() const    {return m_jpgQual;}
   void pngQual(int iNewVal) {m_pngQual = iNewVal;}
   int pngQual() const    {return m_pngQual;}
   void combineRule(eCombineRule iNewVal) {m_combineRule = iNewVal;}
   eCombineRule combineRule() const    {return m_combineRule;}
   int OtherOwned() const    {return m_OtherOwned;}

   void   fractFilt(double rNewVal) {m_fractFilt = rNewVal;}
   double fractFilt() const    {return m_fractFilt;}

   void   fractFilu(double rNewVal) {m_fractFilu = rNewVal;}
   double fractFilu() const    {return m_fractFilu;}

   void   fractBrfix(double rNewVal) {m_fractBrfix = rNewVal;}
   double fractBrfix() const    {return m_fractBrfix;}
   void   prebFact(double rNewVal) {m_prebFact = rNewVal;}
   double prebFact() const    {return m_prebFact;}
   void   fractTwo(double rNewVal) {m_fractTwo = rNewVal;}
   double fractTwo() const    {return m_fractTwo;}
   void   slopeRed(double rNewVal) {m_slopeRed = rNewVal;}
   double slopeRed() const    {return m_slopeRed;}

   void   slopeGrn(double rNewVal) {m_slopeGrn = rNewVal;}
   double slopeGrn() const    {return m_slopeGrn;}

   void   slopeBlu(double rNewVal) {m_slopeBlu = rNewVal;}
   double slopeBlu() const    {return m_slopeBlu;}

   void   inclRed(double rNewVal) {m_inclRed = rNewVal;}
   double inclRed() const    {return m_inclRed;}

   void   inclGrn(double rNewVal) {m_inclGrn = rNewVal;}
   double inclGrn() const    {return m_inclGrn;}

   void   inclBlu(double rNewVal) {m_inclBlu = rNewVal;}
   double inclBlu() const    {return m_inclBlu;}

   void sourceFileName(const char *newName);
   const char *sourceFileName() const;


   int histBig(int iSlot) const;
   int histLil(int iSlot) const;
   int histLi2(int iSlot) const;
   int histp(int iSlot)   const;
   int histq(int iSlot)   const;
   int makeHists()        const;
   int clrHists()         const;


   int setOnePixel(int iHoriz, int iVert, const jColor &aColor);
   int setOnePixel(int iHoriz, int iVert, int iRed, int iGrn, int iBlu);
   int chgOnePixel(int iHoriz, int iVert, const jColor &aColor);                                        // 12-13-10 (jdl)
   int addOnePixel(int iHoriz, int iVert, int iRed, int iGrn, int iBlu);
   int getOnePixel(int iHoriz, int iVert, jColor &aColor) const; // 12-22-01
   int getOnePixel(int iHoriz, int iVert, int &iRed, int &iGrn, int &iBlu) const;
   int getOnePixeld(double dHoriz, double dVert, double &dRed, double &dGrn, double &dBlu) const;
   int getOneColor(int iHoriz, int iVert, int iColor) const;                                            // 08-15-09
   int drawLine(double x0, double y0, double x1, double y1, int iRed, int iGrn, int iBlu, int iAdd=0);  // 01-29-02, 01-30-02
   int clrGraph(void); // renamed 08-25-03; was // int clrScreen(void);
   int clrGraph(int iRed, int iGrn, int iBlu);  // new overload 10-04-08 (jdl)
   bool isInXYrange(int iH, int iV) const {return ((iH>=0) && (iH<m_nHoriz) && (iV>=0) && (iV<m_nVert));}  // 08-07-10
   void moveTo(int iH, int iV) {m_iHFrom=iH; m_iVFrom=iV; m_bJustMoved=true;}
   int  lineTo(int iHtarg, int iVtarg);                                                                    // 08-07-10
   int  moli(int iH0, int iV0, int iH1, int iV1) {moveTo(iH0, iV0); return lineTo(iH1, iV1);}              // 10-17-10
   int  setScaleX(double graphXlow, double inputXlow, double graphXhigh, double inputXhigh);
   int  setScaleY(double graphYlow, double inputYlow, double graphYhigh, double inputYhigh);
   int  graphX(double dH) const {return (int)(dH * m_xScale + m_xOffset);}
   int  graphY(double dV) const {return (int)(dV * m_yScale + m_yOffset);}
   double  worldX(double grH) const {return ((grH - m_xOffset) / m_xScale);}
   double  worldY(double grV) const {return ((grV - m_yOffset) / m_yScale);}
   void moveTReal(double dH, double dV) {moveTo(graphX(dH), graphY(dV));}
   int  lineTReal(double dH, double dV) {return lineTo(graphX(dH), graphY(dV));}
   int  moliReal(double dH0, double dV0, double dH1, double dV1) {moveTReal(dH0, dV0); return lineTReal(dH1, dV1);}

   int setSize(int nHoriz, int nVert, UCHAR *pOther=NULL);         // pOther 12-11-05

   int clrSize();                             // just purge out
   int totBytes() const {return m_totBytes;}


   int readBmp(const char *fileName);         // 12-21-01
   int writeBmp(const char *fileName) const;
   int readFile(const char *fileName);        // 02-05-04: will attempt to translate .jpg, etc.
   int writeFile(const char *fileName) const; // 02-05-04: will attempt to translate .jpg, etc.
   static int formatFixQty(UCHAR *ubuf_out, int iQty, int nBytes);
   static int writeFixQty(FILE *fp_out, int iQty, int nBytes);
   static int writeFixQtyLf(FILE *fp_out, int iQty, int nBytes);

   int doClip(double &x0, double &y0, double &x1, double &y1);  // for line drawing.
   bool isSquary() const {return ((m_doSqrTot != 0) && (m_doSqrTot != 2));}           // 12-28-07

   int getByteOffset(const UCHAR *ucWhere) const;

   const UCHAR *getBufFromOffset(int offset) const;
   inline UCHAR *getBufFromOffset(int offset) {return    (UCHAR *)(((const jgrLil *)this)->getBufFromOffset(offset));}

   const UCHAR *getNextBufLoc(const UCHAR *ucPrev, bool bBackward=false, int *pvOut=NULL, int *phOut=NULL, int *pcOut=NULL) const;
   inline UCHAR *getNextBufLoc(const UCHAR *ucPrev, bool bBackward=false, int *pvOut=NULL, int *phOut=NULL, int *pcOut=NULL) {return (UCHAR *)(((const jgrLil *)this)->getNextBufLoc(ucPrev, bBackward, pvOut, phOut, pcOut));}

   const UCHAR *getBaseBufLoc() const {return m_theData;}
   UCHAR       *getBaseBufLoc()       {return m_theData;}
   int bytesTot() const {return m_nHoriz * m_nVert * colorBytesPerPixel();}

   int calcAvgRGB(double &dRedLin, double &dGrnLin, double &dBluLin, double &dRedSqr, double &dGrnSqr, double &dBluSqr) const;

}; // end of jgrLil



double reMap(double xBotOld, double xTopOld, double xValOld, double xBotNew, double xTopNew);
int roundMe(double rawVal);
// static int roundy(double rawVal);      // 12-04-02; static 09-11-10 (jdl)
int unsatCorrect(double &dRed, double &dGrn, double &dBlu, double unSaturate, int doSqrTot, double fractTwo=0.0, int allowOverflow=0); // 02-12-03; fractTwo 09-04-04; allowOverflow 10-01-08 (jdl)

int fnMirrorOvf(int nInRange, int iVal);  // 04-23-03

double fnBrite(double dRedIn, double dGrnIn, double dBluIn, int doSqrTot, double fractTwo=0.0, double slopeRed=1.0, double slopeGrn=1.0, double slopeblu=1.0);    // fractTwo 09-04-04; slope guys 03-26-05.
double briteFix(double briteIn, double slopeIn);   // 03-26-05




#endif // ifndef JGRLIL_H

