1 /*
2  * This file is part of the Advance project.
3  *
4  * Copyright (C) 2003 Andrea Mazzoleni
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * In addition, as a special exception, Andrea Mazzoleni
21  * gives permission to link the code of this program with
22  * the MAME library (or with modified versions of MAME that use the
23  * same license as MAME), and distribute linked combinations including
24  * the two.  You must obey the GNU General Public License in all
25  * respects for all of the code used other than MAME.  If you modify
26  * this file, you may extend this exception to your version of the
27  * file, but you are not obligated to do so.  If you do not wish to
28  * do so, delete this exception statement from your version.
29  */
30 
31 #ifndef __INTERP_H
32 #define __INTERP_H
33 
34 #include "gfxtypes.h"
35 
36 /***************************************************************************/
37 /* Basic types */
38 
39 /***************************************************************************/
40 /* interpolation */
41 
42 static unsigned interp_mask[2];
43 static unsigned interp_bits_per_pixel;
44 
45 #define INTERP_16_MASK_1(v) (v & interp_mask[0])
46 #define INTERP_16_MASK_2(v) (v & interp_mask[1])
47 
interp_16_521(u16 p1,u16 p2,u16 p3)48 static inline u16 interp_16_521(u16 p1, u16 p2, u16 p3)
49 {
50   return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*5 + INTERP_16_MASK_1(p2)*2 + INTERP_16_MASK_1(p3)*1) / 8)
51 	| INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*5 + INTERP_16_MASK_2(p2)*2 + INTERP_16_MASK_2(p3)*1) / 8);
52 }
53 
interp_16_332(u16 p1,u16 p2,u16 p3)54 static inline u16 interp_16_332(u16 p1, u16 p2, u16 p3)
55 {
56   return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*3 + INTERP_16_MASK_1(p2)*3 + INTERP_16_MASK_1(p3)*2) / 8)
57 	| INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*3 + INTERP_16_MASK_2(p2)*3 + INTERP_16_MASK_2(p3)*2) / 8);
58 }
59 
interp_16_611(u16 p1,u16 p2,u16 p3)60 static inline u16 interp_16_611(u16 p1, u16 p2, u16 p3)
61 {
62   return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*6 + INTERP_16_MASK_1(p2) + INTERP_16_MASK_1(p3)) / 8)
63 	| INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*6 + INTERP_16_MASK_2(p2) + INTERP_16_MASK_2(p3)) / 8);
64 }
65 
interp_16_71(u16 p1,u16 p2)66 static inline u16 interp_16_71(u16 p1, u16 p2)
67 {
68   return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*7 + INTERP_16_MASK_1(p2)) / 8)
69 	| INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*7 + INTERP_16_MASK_2(p2)) / 8);
70 }
71 
interp_16_211(u16 p1,u16 p2,u16 p3)72 static inline u16 interp_16_211(u16 p1, u16 p2, u16 p3)
73 {
74   return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*2 + INTERP_16_MASK_1(p2) + INTERP_16_MASK_1(p3)) / 4)
75 	| INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*2 + INTERP_16_MASK_2(p2) + INTERP_16_MASK_2(p3)) / 4);
76 }
77 
interp_16_772(u16 p1,u16 p2,u16 p3)78 static inline u16 interp_16_772(u16 p1, u16 p2, u16 p3)
79 {
80   return INTERP_16_MASK_1(((INTERP_16_MASK_1(p1) + INTERP_16_MASK_1(p2))*7 + INTERP_16_MASK_1(p3)*2) / 16)
81 	| INTERP_16_MASK_2(((INTERP_16_MASK_2(p1) + INTERP_16_MASK_2(p2))*7 + INTERP_16_MASK_2(p3)*2) / 16);
82 }
83 
interp_16_11(u16 p1,u16 p2)84 static inline u16 interp_16_11(u16 p1, u16 p2)
85 {
86   return INTERP_16_MASK_1((INTERP_16_MASK_1(p1) + INTERP_16_MASK_1(p2)) / 2)
87 	| INTERP_16_MASK_2((INTERP_16_MASK_2(p1) + INTERP_16_MASK_2(p2)) / 2);
88 }
89 
interp_16_31(u16 p1,u16 p2)90 static inline u16 interp_16_31(u16 p1, u16 p2)
91 {
92   return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*3 + INTERP_16_MASK_1(p2)) / 4)
93 	| INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*3 + INTERP_16_MASK_2(p2)) / 4);
94 }
95 
interp_16_1411(u16 p1,u16 p2,u16 p3)96 static inline u16 interp_16_1411(u16 p1, u16 p2, u16 p3)
97 {
98   return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*14 + INTERP_16_MASK_1(p2) + INTERP_16_MASK_1(p3)) / 16)
99 	| INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*14 + INTERP_16_MASK_2(p2) + INTERP_16_MASK_2(p3)) / 16);
100 }
101 
interp_16_431(u16 p1,u16 p2,u16 p3)102 static inline u16 interp_16_431(u16 p1, u16 p2, u16 p3)
103 {
104   return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*4 + INTERP_16_MASK_1(p2)*3 + INTERP_16_MASK_1(p3)) / 8)
105 	| INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*4 + INTERP_16_MASK_2(p2)*3 + INTERP_16_MASK_2(p3)) / 8);
106 }
107 
interp_16_53(u16 p1,u16 p2)108 static inline u16 interp_16_53(u16 p1, u16 p2)
109 {
110   return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*5 + INTERP_16_MASK_1(p2)*3) / 8)
111 	| INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*5 + INTERP_16_MASK_2(p2)*3) / 8);
112 }
113 
interp_16_151(u16 p1,u16 p2)114 static inline u16 interp_16_151(u16 p1, u16 p2)
115 {
116   return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*15 + INTERP_16_MASK_1(p2)) / 16)
117 	| INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*15 + INTERP_16_MASK_2(p2)) / 16);
118 }
119 
interp_16_97(u16 p1,u16 p2)120 static inline u16 interp_16_97(u16 p1, u16 p2)
121 {
122   return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*9 + INTERP_16_MASK_1(p2)*7) / 16)
123 	| INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*9 + INTERP_16_MASK_2(p2)*7) / 16);
124 }
125 
126 #define INTERP_32_MASK_1(v) (v & 0xFF00FF)
127 #define INTERP_32_MASK_2(v) (v & 0x00FF00)
128 
interp_32_521(u32 p1,u32 p2,u32 p3)129 static inline u32 interp_32_521(u32 p1, u32 p2, u32 p3)
130 {
131   return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*5 + INTERP_32_MASK_1(p2)*2 + INTERP_32_MASK_1(p3)*1) / 8)
132 	| INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*5 + INTERP_32_MASK_2(p2)*2 + INTERP_32_MASK_2(p3)*1) / 8);
133 }
134 
interp_32_332(u32 p1,u32 p2,u32 p3)135 static inline u32 interp_32_332(u32 p1, u32 p2, u32 p3)
136 {
137   return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*3 + INTERP_32_MASK_1(p2)*3 + INTERP_32_MASK_1(p3)*2) / 8)
138 	| INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*3 + INTERP_32_MASK_2(p2)*3 + INTERP_32_MASK_2(p3)*2) / 8);
139 }
140 
interp_32_211(u32 p1,u32 p2,u32 p3)141 static inline u32 interp_32_211(u32 p1, u32 p2, u32 p3)
142 {
143   return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*2 + INTERP_32_MASK_1(p2) + INTERP_32_MASK_1(p3)) / 4)
144 	| INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*2 + INTERP_32_MASK_2(p2) + INTERP_32_MASK_2(p3)) / 4);
145 }
146 
interp_32_611(u32 p1,u32 p2,u32 p3)147 static inline u32 interp_32_611(u32 p1, u32 p2, u32 p3)
148 {
149   return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*6 + INTERP_32_MASK_1(p2) + INTERP_32_MASK_1(p3)) / 8)
150 	| INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*6 + INTERP_32_MASK_2(p2) + INTERP_32_MASK_2(p3)) / 8);
151 }
152 
interp_32_71(u32 p1,u32 p2)153 static inline u32 interp_32_71(u32 p1, u32 p2)
154 {
155   return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*7 + INTERP_32_MASK_1(p2)) / 8)
156 	| INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*7 + INTERP_32_MASK_2(p2)) / 8);
157 }
158 
interp_32_772(u32 p1,u32 p2,u32 p3)159 static inline u32 interp_32_772(u32 p1, u32 p2, u32 p3)
160 {
161   return INTERP_32_MASK_1(((INTERP_32_MASK_1(p1) + INTERP_32_MASK_1(p2))*7 + INTERP_32_MASK_1(p3)*2) / 16)
162 	| INTERP_32_MASK_2(((INTERP_32_MASK_2(p1) + INTERP_32_MASK_2(p2))*7 + INTERP_32_MASK_2(p3)*2) / 16);
163 }
164 
interp_32_11(u32 p1,u32 p2)165 static inline u32 interp_32_11(u32 p1, u32 p2)
166 {
167   return INTERP_32_MASK_1((INTERP_32_MASK_1(p1) + INTERP_32_MASK_1(p2)) / 2)
168 	| INTERP_32_MASK_2((INTERP_32_MASK_2(p1) + INTERP_32_MASK_2(p2)) / 2);
169 }
170 
interp_32_31(u32 p1,u32 p2)171 static inline u32 interp_32_31(u32 p1, u32 p2)
172 {
173   return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*3 + INTERP_32_MASK_1(p2)) / 4)
174 	| INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*3 + INTERP_32_MASK_2(p2)) / 4);
175 }
176 
interp_32_1411(u32 p1,u32 p2,u32 p3)177 static inline u32 interp_32_1411(u32 p1, u32 p2, u32 p3)
178 {
179   return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*14 + INTERP_32_MASK_1(p2) + INTERP_32_MASK_1(p3)) / 16)
180 	| INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*14 + INTERP_32_MASK_2(p2) + INTERP_32_MASK_2(p3)) / 16);
181 }
182 
interp_32_431(u32 p1,u32 p2,u32 p3)183 static inline u32 interp_32_431(u32 p1, u32 p2, u32 p3)
184 {
185   return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*4 + INTERP_32_MASK_1(p2)*3 + INTERP_32_MASK_1(p3)) / 8)
186 	| INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*4 + INTERP_32_MASK_2(p2)*3 + INTERP_32_MASK_2(p3)) / 8);
187 }
188 
interp_32_53(u32 p1,u32 p2)189 static inline u32 interp_32_53(u32 p1, u32 p2)
190 {
191   return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*5 + INTERP_32_MASK_1(p2)*3) / 8)
192 	| INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*5 + INTERP_32_MASK_2(p2)*3) / 8);
193 }
194 
interp_32_151(u32 p1,u32 p2)195 static inline u32 interp_32_151(u32 p1, u32 p2)
196 {
197   return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*15 + INTERP_32_MASK_1(p2)) / 16)
198 	| INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*15 + INTERP_32_MASK_2(p2)) / 16);
199 }
200 
interp_32_97(u32 p1,u32 p2)201 static inline u32 interp_32_97(u32 p1, u32 p2)
202 {
203   return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*9 + INTERP_32_MASK_1(p2)*7) / 16)
204 	| INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*9 + INTERP_32_MASK_2(p2)*7) / 16);
205 }
206 
207 /***************************************************************************/
208 /* diff */
209 
210 #define INTERP_Y_LIMIT (0x30*4)
211 #define INTERP_U_LIMIT (0x07*4)
212 #define INTERP_V_LIMIT (0x06*8)
213 
interp_16_diff(u16 p1,u16 p2)214 static int interp_16_diff(u16 p1, u16 p2)
215 {
216   int r, g, b;
217   int y, u, v;
218 
219   if (p1 == p2)
220 	return 0;
221 
222   if (interp_bits_per_pixel == 16) {
223 	b = (int)((p1 & 0x1F) - (p2 & 0x1F)) << 3;
224 	g = (int)((p1 & 0x7E0) - (p2 & 0x7E0)) >> 3;
225 	r = (int)((p1 & 0xF800) - (p2 & 0xF800)) >> 8;
226   } else {
227 	b = (int)((p1 & 0x1F) - (p2 & 0x1F)) << 3;
228 	g = (int)((p1 & 0x3E0) - (p2 & 0x3E0)) >> 2;
229 	r = (int)((p1 & 0x7C00) - (p2 & 0x7C00)) >> 7;
230   }
231 
232   y = r + g + b;
233   u = r - b;
234   v = -r + 2*g - b;
235 
236   if (y < -INTERP_Y_LIMIT || y > INTERP_Y_LIMIT)
237 	return 1;
238 
239   if (u < -INTERP_U_LIMIT || u > INTERP_U_LIMIT)
240 	return 1;
241 
242   if (v < -INTERP_V_LIMIT || v > INTERP_V_LIMIT)
243 	return 1;
244 
245   return 0;
246 }
247 
interp_32_diff(u32 p1,u32 p2)248 static int interp_32_diff(u32 p1, u32 p2)
249 {
250   int r, g, b;
251   int y, u, v;
252 
253   if ((p1 & 0xF8F8F8) == (p2 & 0xF8F8F8))
254 	return 0;
255 
256   b = (int)((p1 & 0xFF) - (p2 & 0xFF));
257   g = (int)((p1 & 0xFF00) - (p2 & 0xFF00)) >> 8;
258   r = (int)((p1 & 0xFF0000) - (p2 & 0xFF0000)) >> 16;
259 
260   y = r + g + b;
261   u = r - b;
262   v = -r + 2*g - b;
263 
264   if (y < -INTERP_Y_LIMIT || y > INTERP_Y_LIMIT)
265 	return 1;
266 
267   if (u < -INTERP_U_LIMIT || u > INTERP_U_LIMIT)
268 	return 1;
269 
270   if (v < -INTERP_V_LIMIT || v > INTERP_V_LIMIT)
271 	return 1;
272 
273   return 0;
274 }
275 
interp_set(unsigned bits_per_pixel)276 static void interp_set(unsigned bits_per_pixel)
277 {
278   interp_bits_per_pixel = bits_per_pixel;
279 
280   switch (bits_per_pixel) {
281   case 15 :
282 	interp_mask[0] = 0x7C1F;
283 	interp_mask[1] = 0x03E0;
284 	break;
285   case 16 :
286 	interp_mask[0] = 0xF81F;
287 	interp_mask[1] = 0x07E0;
288 	break;
289   case 32 :
290 	interp_mask[0] = 0xFF00FF;
291 	interp_mask[1] = 0x00FF00;
292 	break;
293   }
294 }
295 
296 #endif
297