blob: a90033549a00bb3341fa92da0aabf7c11af32774 [file] [log] [blame]
Pierre Ossman65ad3222014-03-07 13:48:29 +01001/* Copyright (C) 2000-2005 Constantin Kaplinsky. All Rights Reserved.
2 * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
3 * Copyright 2014 Pierre Ossman for Cendio AB
4 *
5 * This is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this software; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18 * USA.
19 */
20#ifndef __RFB_PALETTE_H__
21#define __RFB_PALETTE_H__
22
23#include <assert.h>
24#include <string.h>
25
26#include <rdr/types.h>
27
28namespace rfb {
29 class Palette {
30 public:
31 Palette() { clear(); }
32 ~Palette() {}
33
34 int size() const { return numColours; }
35
36 void clear() { numColours = 0; memset(hash, 0, sizeof(hash)); }
37
38 inline bool insert(rdr::U32 colour, int numPixels);
39 inline unsigned char lookup(rdr::U32 colour) const;
40 inline rdr::U32 getColour(unsigned char index) const;
41 inline int getCount(unsigned char index) const;
42
43 protected:
44 inline unsigned char genHash(rdr::U32 colour) const;
45
46 protected:
47 int numColours;
48
49 struct PaletteListNode {
50 PaletteListNode *next;
51 unsigned char idx;
52 rdr::U32 colour;
53 };
54
55 struct PaletteEntry {
56 PaletteListNode *listNode;
57 int numPixels;
58 };
59
60 // This is the raw list of colours, allocated from 0 and up
61 PaletteListNode list[256];
62 // Hash table for quick lookup into the list above
63 PaletteListNode *hash[256];
64 // Occurances of each colour, where the 0:th entry is the most common.
65 // Indices also refer to this array.
66 PaletteEntry entry[256];
67 };
68}
69
70inline bool rfb::Palette::insert(rdr::U32 colour, int numPixels)
71{
72 PaletteListNode* pnode;
73 PaletteListNode* prev_pnode;
74 unsigned char hash_key, idx;
75
76 hash_key = genHash(colour);
77
78 pnode = hash[hash_key];
79 prev_pnode = NULL;
80
81 // Do we already have an entry for this colour?
82 while (pnode != NULL) {
83 if (pnode->colour == colour) {
84 // Yup
85
86 idx = pnode->idx;
87 numPixels = entry[idx].numPixels + numPixels;
88
89 // The extra pixels might mean we have to adjust the sort list
90 while (idx > 0) {
91 if (entry[idx-1].numPixels >= numPixels)
92 break;
93 entry[idx] = entry[idx-1];
94 entry[idx].listNode->idx = idx;
95 idx--;
96 }
97
98 if (idx != pnode->idx) {
99 entry[idx].listNode = pnode;
100 pnode->idx = idx;
101 }
102
103 entry[idx].numPixels = numPixels;
104
105 return true;
106 }
107
108 prev_pnode = pnode;
109 pnode = pnode->next;
110 }
111
112 // Check if palette is full.
113 if (numColours == 256)
114 return false;
115
116 // Create a new colour entry
117 pnode = &list[numColours];
118 pnode->next = NULL;
119 pnode->idx = 0;
120 pnode->colour = colour;
121
122 // Add it to the hash table
123 if (prev_pnode != NULL)
124 prev_pnode->next = pnode;
125 else
126 hash[hash_key] = pnode;
127
128 // Move palette entries with lesser pixel counts.
129 idx = numColours;
130 while (idx > 0) {
131 if (entry[idx-1].numPixels >= numPixels)
132 break;
133 entry[idx] = entry[idx-1];
134 entry[idx].listNode->idx = idx;
135 idx--;
136 }
137
138 // And add it into the freed slot.
139 pnode->idx = idx;
140 entry[idx].listNode = pnode;
141 entry[idx].numPixels = numPixels;
142
143 numColours++;
144
145 return true;
146}
147
148inline unsigned char rfb::Palette::lookup(rdr::U32 colour) const
149{
150 unsigned char hash_key;
151 PaletteListNode* pnode;
152
153 hash_key = genHash(colour);
154 pnode = hash[hash_key];
155
156 while (pnode != NULL) {
157 if (pnode->colour == colour)
158 return pnode->idx;
159 pnode = pnode->next;
160 }
161
162 // We are being fed a bad colour
163 assert(false);
164
165 return 0;
166}
167
168inline rdr::U32 rfb::Palette::getColour(unsigned char index) const
169{
170 return entry[index].listNode->colour;
171}
172
173inline int rfb::Palette::getCount(unsigned char index) const
174{
175 return entry[index].numPixels;
176}
177
178inline unsigned char rfb::Palette::genHash(rdr::U32 colour) const
179{
180 unsigned char hash_key;
181
182 // djb2 hash function
183 hash_key = 5; // 5381 & 0xff
184 for (int i = 0; i < 32; i += 8)
185 hash_key = ((hash_key << 5) + hash_key) ^ (colour >> i);
186
187 return hash_key;
188}
189
190#endif