/*
 *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
 *
 *  This is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This software is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this software; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 *  USA.
 */

/*
 * hextile.c - handle hextile encoding.
 *
 * This file shouldn't be compiled directly.  It is included multiple times by
 * rfbproto.c, each time with a different definition of the macro BPP.  For
 * each value of BPP, this file defines a function which handles a hextile
 * encoded rectangle with BPP bits per pixel.
 */


/*
 * alternative hextile coding of 16x16 pixels rectangle
 * flag byte followed by optional data
 * flag byte:
 *        bit 0 set           bg colour included
 *        bit 1..3            coding type
 *                            0         hextile
 *                            1         raw
 *        bit 4 set           1x1 data included (hextile coding)
 *        bit 5 set           1x2 data included (hextile coding)
 *        bit 6 set           2x1 data included (hextile coding)
 *        bit 7 set           any size rectangle data included (hextile coding)
 *        bit 4..6            no. of bits per pixel (raw coding)
 *                            0         native
 *                            1         1bpp with palette
 *                            2         2bpp with palette
 *                            3         4bpp with palette
 *                            4         6bpp RGB222
 *                            5         8bpp RGB332
 *
 * if bit 0 set, first data byte(s) holds new bgcolour
 * if hextile coding is used, 1x1 data comes first (if any), then 1x2 etc.
 *
 * 1x1 data:
 *    byte 0  1x1 status byte
 *        bit 0 set           first data byte(s) holds new fg colour
 *        bit 1 set           there's another 1x1 status byte after the data
 *        bit 2..7            no. of subrectangles - 1
 *    followed by 4 bit X and 4 bit Y coordinates for each 1x1 rectangle
 * 1x2 data:
 *    byte 0  1x2 status byte
 *        bit 0 set           first data byte(s) holds new fg colour
 *        bit 1 set           there's another 1x2 status byte after the data
 *        bit 2..7            no. of sub rectangles - 1
 *    followed by 4 bit X and 4 bit Y coordinates for each 1x2 rectangle
 * 2x1 data:
 *    byte 0  2x1 status byte
 *        bit 0 set           first data byte(s) holds new fg colour
 *        bit 1 set           there's another 2x1 status byte after the data
 *        bit 2..7            no. of sub rectangles - 1
 *    followed by 4 bit X and 4 bit Y coordinates for each 2x1 rectangle
 * any size rectangle data:
 *    byte 0  status byte
 *        bit 0 set           first data byte(s) holds new fg colour
 *        bit 1 set           there's another status byte after the data
 *        bit 2..7            no. of sub rectangles - 1
 *    followed by 4 bit X and 4 bit Y coordinates and 4 bit
 *    width and 4 bit height for each rectangle
 * raw coding:
 *    followed by palette (if bpp = 1, 2 or 4)
 *    followed by raw data
 *
 * How to:
 *  1) modify testColours() to count the no. of colours (bad idea for > 8bpp):
 *        if (!(colourmask[*data>>3] & (1<<(*data &7))))
 *          ncolours++;
 *          colourmask[*data>>3] |= (1<<(*data &7))
 *  2)  find subrectangles as usual but store differently
 *        if (thew==1 && theh==1)
 *           *subrects_1x1++ = rfbHextilePackXY(thex, they)
 *           *subrects_1x1++ = colour
 *           nsubrects_1x1++;
 *           estimated_size++;
 *           if (colour != prevcolour)  prevcolour=colour, estimated_size++;
 *        likewise for 1x2, 2x1 and any size
 *  3) when outputting hextile coded data:
 *     output all 1x1 then all 1x2 etc.
 */

static Bool HandleHextile8 (int rx, int ry, int rw, int rh)
{
  CARD8 bg, fg;
  int i;
  CARD8 *ptr;
  int x, y, w, h;
  int sx, sy, sw, sh;
  CARD8 subencoding;
  CARD8 nSubrects;

  for (y = ry; y < ry+rh; y += 16) {
    for (x = rx; x < rx+rw; x += 16) {
      w = h = 16;
      if (rx+rw - x < 16)
	w = rx+rw - x;
      if (ry+rh - y < 16)
	h = ry+rh - y;

      if (!ReadFromRFBServer((char *)&subencoding, 1))
	return False;

      if (subencoding & rfbHextileRaw) {
	if (!ReadFromRFBServer(buffer, w * h * (BPP / 8)))
	  return False;

        display_raw(x, y, w, h, buffer, 0);
	continue;
      }

      if (subencoding & rfbHextileBackgroundSpecified)
	if (!ReadFromRFBServer((char *)&bg, sizeof(bg)))
	  return False;

      display_fillrectangle(x, y, w, h, rgb332_rgb555_table[bg]);

      if (subencoding & rfbHextileForegroundSpecified)
	if (!ReadFromRFBServer((char *)&fg, sizeof(fg)))
	  return False;

      if (!(subencoding & rfbHextileAnySubrects)) {
	continue;
      }

      if (!ReadFromRFBServer((char *)&nSubrects, 1))
	return False;

      ptr = (CARD8 *)buffer;

      if (subencoding & rfbHextileSubrectsColoured) {
	if (!ReadFromRFBServer(buffer, nSubrects * (2 + (BPP / 8))))
	  return False;
        subrect += nSubrects;

	for (i = 0; i < nSubrects; i++) {
	  fg = ptr[0];
	  ptr += 1;
	  sx = rfbHextileExtractX(*ptr);
	  sy = rfbHextileExtractY(*ptr);
	  ptr++;
	  sw = rfbHextileExtractW(*ptr);
	  sh = rfbHextileExtractH(*ptr);
	  ptr++;
          display_fillrectangle(x+sx, y+sy, sw, sh, rgb332_rgb555_table[fg]);
	}

      } else {
	if (!ReadFromRFBServer(buffer, nSubrects * 2))
	  return False;
        subrect += nSubrects;

	for (i = 0; i < nSubrects; i++) {
	  sx = rfbHextileExtractX(*ptr);
	  sy = rfbHextileExtractY(*ptr);
	  ptr++;
	  sw = rfbHextileExtractW(*ptr);
	  sh = rfbHextileExtractH(*ptr);
	  ptr++;
          display_fillrectangle(x+sx, y+sy, sw, sh, rgb332_rgb555_table[fg]);
	}
      }
    }
  }

  return True;
}
