

/* 
A* -------------------------------------------------------------------
B* This file contains source code for the PyMOL computer program
C* Copyright (c) Schrodinger, LLC. 
D* -------------------------------------------------------------------
E* It is unlawful to modify or remove this copyright notice.
F* -------------------------------------------------------------------
G* Please see the accompanying LICENSE file for further information. 
H* -------------------------------------------------------------------
I* Additional authors of this source file include:
-* 
-* 
-*
Z* -------------------------------------------------------------------
*/

#include "Pixmap.h"
#include "MemoryDebug.h"
#include "Util.h"

void PixmapInit(PyMOLGlobals * G, CPixmap * I, int width, int height)
{
  UtilZeroMem(I, sizeof(CPixmap));
  I->G = G;
  I->height = height;
  I->width = width;
  if((height >= 0) && (width >= 0)) {
    I->buffer = pymol::malloc<unsigned char>(4 * height * width);
  }
}

CPixmap *PixmapNew(PyMOLGlobals * G, int width, int height)
{
  auto I = new CPixmap();
  PixmapInit(G, I, width, height);
  return I;
}

void PixmapInitFromBitmap(PyMOLGlobals * G, CPixmap * I, int width, int height,
                          unsigned char *bitmap, unsigned char *rgba, int sampling)
{
  if(I) {

    int x, y, bit_cnt;
    unsigned char cur = 0;
    unsigned char *src;
    unsigned char *dst;
    unsigned char red, blue, green, alpha;
    PixmapInit(G, I, width * sampling, height * sampling);
    red = rgba[0];
    green = rgba[1];
    blue = rgba[2];
    alpha = rgba[3];
    UtilZeroMem(I->buffer, 4 * width * height);
    src = bitmap;
    dst = I->buffer;
    for(y = 0; y < height; y++) {
      bit_cnt = 7;
      for(x = 0; x < width; x++) {
        bit_cnt++;
        if(bit_cnt > 7) {
          cur = *(src++);
          bit_cnt = 0;
        }
        if(cur & 0x80) {
          *(dst++) = red;
          *(dst++) = green;
          *(dst++) = blue;
          *(dst++) = alpha;
        } else {
          *(dst++) = 0;
          *(dst++) = 0;
          *(dst++) = 0;
          *(dst++) = 0;
        }
        cur <<= 1;
      }
    }
    if(sampling > 1) {
      unsigned int *p, *pp, *q, *row;
      int row_cnt, col_cnt, width_sampling = width * sampling;

      p = (unsigned int *) (I->buffer + 4 * width * height);
      q = (unsigned int *) (I->buffer + 4 * width * height * sampling * sampling);
      while(p > (unsigned int *) I->buffer) {
        row_cnt = sampling - 1;
        row = q;
        for(x = 0; x < width; x++) {    /* first row */
          col_cnt = sampling;
          p--;
          while(col_cnt--) {
            *(--q) = *p;
          }
        }
        if(row_cnt) {
          while(row_cnt--) {    /* remaining rows */
            pp = row;
            for(x = 0; x < width_sampling; x++) {
              *(--q) = *(--pp);
            }
          }
        }
      }
    }
  }
}

void PixmapInitFromBytemap(PyMOLGlobals * G, CPixmap * I,
                           int width,
                           int height,
                           int pitch,
                           unsigned char *bytemap,
                           unsigned char *rgba, unsigned char *outline_rgb, int flat)
{
  if(I) {

    int x, y;
    unsigned char *src, *sa, alp;
    unsigned char *dst;
    unsigned char red, blue, green, alpha, no_alpha;
    unsigned char ored = 0, oblue = 0, ogreen = 0;
    if(!outline_rgb[3])
      outline_rgb = NULL;
    else {
      ored = outline_rgb[0];
      ogreen = outline_rgb[1];
      oblue = outline_rgb[2];
    }
    PixmapInit(G, I, width, height);
    red = rgba[0];
    green = rgba[1];
    blue = rgba[2];
    alpha = rgba[3];
    UtilZeroMem(I->buffer, 4 * width * height);
    src = bytemap;
    dst = I->buffer;
    no_alpha = flat;
    for(y = 0; y < height; y++) {
      sa = src;
      if(no_alpha) {
        for(x = 0; x < width; x++) {
          alp = *(sa++);
          if(alp) {
            *(dst++) = red;
            *(dst++) = green;
            *(dst++) = blue;
            *(dst++) = 0xFF;
          } else {
            *(dst++) = 0;
            *(dst++) = 0;
            *(dst++) = 0;
            *(dst++) = 0;
          }
        }
      } else {
        for(x = 0; x < width; x++) {
          if(outline_rgb) {
            unsigned char amax = 0, amin;
            if(y > 0) {
              alp = 255 - *(sa - pitch);
            } else {
              alp = 255;
            }
            if(amax < alp)
              amax = alp;
            if(y < (height - 1)) {
              alp = 255 - *(sa + pitch);
            } else {
              alp = 255;
            }
            if(amax < alp)
              amax = alp;
            if(x > 0) {
              alp = 255 - *(sa - 1);
            } else {
              alp = 255;
            }
            if(amax < alp)
              amax = alp;
            if(x < (width - 1)) {
              alp = 255 - *(sa + 1);
            } else {
              alp = 255;
            }
            if(amax < alp)
              amax = alp;
            amin = 255 - amax;
            alp = *(sa++);
            if(alp) {
              *(dst++) = (red * amin + ored * amax) / 255;
              *(dst++) = (green * amin + ogreen * amax) / 255;
              *(dst++) = (blue * amin + oblue * amax) / 255;
              *(dst++) = (alpha * alp) / 255;
            } else {
              *(dst++) = 0;
              *(dst++) = 0;
              *(dst++) = 0;
              *(dst++) = 0;
            }
          } else {
            alp = *(sa++);
            if(alp) {
              *(dst++) = red;
              *(dst++) = green;
              *(dst++) = blue;
              *(dst++) = (alpha * alp) >> 8;
            } else {
              *(dst++) = 0;
              *(dst++) = 0;
              *(dst++) = 0;
              *(dst++) = 0;
            }
          }

        }
      }
      src += pitch;
    }
  }
}

void PixmapPurge(CPixmap * I)
{
  if(I) {
    FreeP(I->buffer);
  }
}

void PixmapFreeP(CPixmap * I)
{
  PixmapPurge(I);
  DeleteP(I);
}
