You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

hextileEncodeBetter.h 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
  2. * Copyright (C) 2005 Constantin Kaplinsky. All Rights Reserved.
  3. *
  4. * This is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this software; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  17. * USA.
  18. */
  19. //
  20. // Hextile encoding function.
  21. //
  22. // This file is #included after having set the following macro:
  23. // BPP - 8, 16 or 32
  24. #include <rdr/OutStream.h>
  25. #include <rfb/hextileConstants.h>
  26. #include <rfb/Palette.h>
  27. #include <assert.h>
  28. namespace rfb {
  29. // CONCAT2E concatenates its arguments, expanding them if they are macros
  30. #ifndef CONCAT2E
  31. #define CONCAT2(a,b) a##b
  32. #define CONCAT2E(a,b) CONCAT2(a,b)
  33. #endif
  34. #define PIXEL_T rdr::CONCAT2E(U,BPP)
  35. #define WRITE_PIXEL CONCAT2E(writeOpaque,BPP)
  36. #define HEXTILE_TILE CONCAT2E(HextileTile,BPP)
  37. #define HEXTILE_ENCODE CONCAT2E(hextileEncodeBetter,BPP)
  38. //
  39. // This class analyzes a separate tile and encodes its subrectangles.
  40. //
  41. class HEXTILE_TILE {
  42. public:
  43. HEXTILE_TILE ();
  44. //
  45. // Initialize existing object instance with new tile data.
  46. //
  47. void newTile(const PIXEL_T *src, int w, int h);
  48. //
  49. // Flags can include: hextileRaw, hextileAnySubrects and
  50. // hextileSubrectsColoured. Note that if hextileRaw is set, other
  51. // flags make no sense. Also, hextileSubrectsColoured is meaningful
  52. // only when hextileAnySubrects is set as well.
  53. //
  54. int getFlags() const { return m_flags; }
  55. //
  56. // Returns the size of encoded subrects data, including subrect count.
  57. // The size is zero if flags do not include hextileAnySubrects.
  58. //
  59. int getSize() const { return m_size; }
  60. //
  61. // Return optimal background.
  62. //
  63. int getBackground() const { return m_background; }
  64. //
  65. // Return foreground if flags include hextileSubrectsColoured.
  66. //
  67. int getForeground() const { return m_foreground; }
  68. //
  69. // Encode subrects. This function may be called only if
  70. // hextileAnySubrects bit is set in flags. The buffer size should be
  71. // big enough to store at least the number of bytes returned by the
  72. // getSize() method.
  73. //
  74. void encode(rdr::U8* dst) const;
  75. protected:
  76. //
  77. // Analyze the tile pixels, fill in all the data fields.
  78. //
  79. void analyze();
  80. const PIXEL_T *m_tile;
  81. int m_width;
  82. int m_height;
  83. int m_size;
  84. int m_flags;
  85. PIXEL_T m_background;
  86. PIXEL_T m_foreground;
  87. int m_numSubrects;
  88. rdr::U8 m_coords[256 * 2];
  89. PIXEL_T m_colors[256];
  90. private:
  91. bool m_processed[16][16];
  92. Palette m_pal;
  93. };
  94. HEXTILE_TILE::HEXTILE_TILE()
  95. : m_tile(NULL), m_width(0), m_height(0),
  96. m_size(0), m_flags(0), m_background(0), m_foreground(0),
  97. m_numSubrects(0)
  98. {
  99. }
  100. void HEXTILE_TILE::newTile(const PIXEL_T *src, int w, int h)
  101. {
  102. m_tile = src;
  103. m_width = w;
  104. m_height = h;
  105. analyze();
  106. }
  107. void HEXTILE_TILE::analyze()
  108. {
  109. assert(m_tile && m_width && m_height);
  110. const PIXEL_T *ptr = m_tile;
  111. const PIXEL_T *end = &m_tile[m_width * m_height];
  112. PIXEL_T color = *ptr++;
  113. while (ptr != end && *ptr == color)
  114. ptr++;
  115. // Handle solid tile
  116. if (ptr == end) {
  117. m_background = m_tile[0];
  118. m_flags = 0;
  119. m_size = 0;
  120. return;
  121. }
  122. // Compute number of complete rows of the same color, at the top
  123. int y = (ptr - m_tile) / m_width;
  124. PIXEL_T *colorsPtr = m_colors;
  125. rdr::U8 *coordsPtr = m_coords;
  126. m_pal.clear();
  127. m_numSubrects = 0;
  128. // Have we found the first subrect already?
  129. if (y > 0) {
  130. *colorsPtr++ = color;
  131. *coordsPtr++ = 0;
  132. *coordsPtr++ = (rdr::U8)(((m_width - 1) << 4) | ((y - 1) & 0x0F));
  133. m_pal.insert(color, 1);
  134. m_numSubrects++;
  135. }
  136. memset(m_processed, 0, 16 * 16 * sizeof(bool));
  137. int x, sx, sy, sw, sh, max_x;
  138. for (; y < m_height; y++) {
  139. for (x = 0; x < m_width; x++) {
  140. // Skip pixels that were processed earlier
  141. if (m_processed[y][x]) {
  142. continue;
  143. }
  144. // Determine dimensions of the horizontal subrect
  145. color = m_tile[y * m_width + x];
  146. for (sx = x + 1; sx < m_width; sx++) {
  147. if (m_tile[y * m_width + sx] != color)
  148. break;
  149. }
  150. sw = sx - x;
  151. max_x = sx;
  152. for (sy = y + 1; sy < m_height; sy++) {
  153. for (sx = x; sx < max_x; sx++) {
  154. if (m_tile[sy * m_width + sx] != color)
  155. goto done;
  156. }
  157. }
  158. done:
  159. sh = sy - y;
  160. // Save properties of this subrect
  161. *colorsPtr++ = color;
  162. *coordsPtr++ = (rdr::U8)((x << 4) | (y & 0x0F));
  163. *coordsPtr++ = (rdr::U8)(((sw - 1) << 4) | ((sh - 1) & 0x0F));
  164. if (!m_pal.insert(color, 1) || (m_pal.size() > (48 + 2 * BPP))) {
  165. // Handle palette overflow
  166. m_flags = hextileRaw;
  167. m_size = 0;
  168. return;
  169. }
  170. m_numSubrects++;
  171. // Mark pixels of this subrect as processed, below this row
  172. for (sy = y + 1; sy < y + sh; sy++) {
  173. for (sx = x; sx < x + sw; sx++)
  174. m_processed[sy][sx] = true;
  175. }
  176. // Skip processed pixels of this row
  177. x += (sw - 1);
  178. }
  179. }
  180. // Save number of colors in this tile (should be no less than 2)
  181. int numColors = m_pal.size();
  182. assert(numColors >= 2);
  183. m_background = (PIXEL_T)m_pal.getColour(0);
  184. m_flags = hextileAnySubrects;
  185. int numSubrects = m_numSubrects - m_pal.getCount(0);
  186. if (numColors == 2) {
  187. // Monochrome tile
  188. m_foreground = (PIXEL_T)m_pal.getColour(1);
  189. m_size = 1 + 2 * numSubrects;
  190. } else {
  191. // Colored tile
  192. m_flags |= hextileSubrectsColoured;
  193. m_size = 1 + (2 + (BPP/8)) * numSubrects;
  194. }
  195. }
  196. void HEXTILE_TILE::encode(rdr::U8 *dst) const
  197. {
  198. assert(m_numSubrects && (m_flags & hextileAnySubrects));
  199. // Zero subrects counter
  200. rdr::U8 *numSubrectsPtr = dst;
  201. *dst++ = 0;
  202. for (int i = 0; i < m_numSubrects; i++) {
  203. if (m_colors[i] == m_background)
  204. continue;
  205. if (m_flags & hextileSubrectsColoured) {
  206. #if (BPP == 8)
  207. *dst++ = m_colors[i];
  208. #elif (BPP == 16)
  209. *dst++ = ((rdr::U8*)&m_colors[i])[0];
  210. *dst++ = ((rdr::U8*)&m_colors[i])[1];
  211. #elif (BPP == 32)
  212. *dst++ = ((rdr::U8*)&m_colors[i])[0];
  213. *dst++ = ((rdr::U8*)&m_colors[i])[1];
  214. *dst++ = ((rdr::U8*)&m_colors[i])[2];
  215. *dst++ = ((rdr::U8*)&m_colors[i])[3];
  216. #endif
  217. }
  218. *dst++ = m_coords[i * 2];
  219. *dst++ = m_coords[i * 2 + 1];
  220. (*numSubrectsPtr)++;
  221. }
  222. assert(dst - numSubrectsPtr == m_size);
  223. }
  224. //
  225. // Main encoding function.
  226. //
  227. void HEXTILE_ENCODE(rdr::OutStream* os, const PixelBuffer* pb)
  228. {
  229. Rect t;
  230. PIXEL_T buf[256];
  231. PIXEL_T oldBg = 0, oldFg = 0;
  232. bool oldBgValid = false;
  233. bool oldFgValid = false;
  234. rdr::U8 encoded[256*(BPP/8)];
  235. HEXTILE_TILE tile;
  236. for (t.tl.y = 0; t.tl.y < pb->height(); t.tl.y += 16) {
  237. t.br.y = __rfbmin(pb->height(), t.tl.y + 16);
  238. for (t.tl.x = 0; t.tl.x < pb->width(); t.tl.x += 16) {
  239. t.br.x = __rfbmin(pb->width(), t.tl.x + 16);
  240. pb->getImage(buf, t);
  241. tile.newTile(buf, t.width(), t.height());
  242. int tileType = tile.getFlags();
  243. int encodedLen = tile.getSize();
  244. if ( (tileType & hextileRaw) != 0 ||
  245. encodedLen >= t.width() * t.height() * (BPP/8)) {
  246. os->writeU8(hextileRaw);
  247. os->writeBytes(buf, t.width() * t.height() * (BPP/8));
  248. oldBgValid = oldFgValid = false;
  249. continue;
  250. }
  251. PIXEL_T bg = tile.getBackground();
  252. PIXEL_T fg = 0;
  253. if (!oldBgValid || oldBg != bg) {
  254. tileType |= hextileBgSpecified;
  255. oldBg = bg;
  256. oldBgValid = true;
  257. }
  258. if (tileType & hextileAnySubrects) {
  259. if (tileType & hextileSubrectsColoured) {
  260. oldFgValid = false;
  261. } else {
  262. fg = tile.getForeground();
  263. if (!oldFgValid || oldFg != fg) {
  264. tileType |= hextileFgSpecified;
  265. oldFg = fg;
  266. oldFgValid = true;
  267. }
  268. }
  269. tile.encode(encoded);
  270. }
  271. os->writeU8(tileType);
  272. if (tileType & hextileBgSpecified) os->WRITE_PIXEL(bg);
  273. if (tileType & hextileFgSpecified) os->WRITE_PIXEL(fg);
  274. if (tileType & hextileAnySubrects) os->writeBytes(encoded, encodedLen);
  275. }
  276. }
  277. }
  278. #undef PIXEL_T
  279. #undef WRITE_PIXEL
  280. #undef HEXTILE_TILE
  281. #undef HEXTILE_ENCODE
  282. }