1 /*
2 * OpenTyrian: A modern cross-platform port of Tyrian
3 * Copyright (C) 2007-2010 The OpenTyrian Development Team
4 *
5 * Scale2x, Scale3x
6 * Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23 #include "video_scale.h"
24
25 #include "palette.h"
26 #include "video.h"
27
28 #include <assert.h>
29
30 static void no_scale( SDL_Surface *src_surface, SDL_Surface *dst_surface );
31 static void nn_32( SDL_Surface *src_surface, SDL_Surface *dst_surface );
32 static void nn_16( SDL_Surface *src_surface, SDL_Surface *dst_surface );
33
34 static void scale2x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface );
35 static void scale2x_16( SDL_Surface *src_surface, SDL_Surface *dst_surface );
36 static void scale3x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface );
37 static void scale3x_16( SDL_Surface *src_surface, SDL_Surface *dst_surface );
38
39 void hq2x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface );
40 void hq3x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface );
41 void hq4x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface );
42
43 uint scaler;
44
45 const struct Scalers scalers[] =
46 {
47 #if defined(TARGET_GP2X) || defined(TARGET_DINGUX)
48 { 320, 240, no_scale, nn_16, nn_32, "None" },
49 #else
50 { 1 * vga_width, 1 * vga_height, no_scale, nn_16, nn_32, "None" },
51 { 2 * vga_width, 2 * vga_height, NULL, nn_16, nn_32, "2x" },
52 { 2 * vga_width, 2 * vga_height, NULL, scale2x_16, scale2x_32, "Scale2x" },
53 { 2 * vga_width, 2 * vga_height, NULL, NULL, hq2x_32, "hq2x" },
54 { 3 * vga_width, 3 * vga_height, NULL, nn_16, nn_32, "3x" },
55 { 3 * vga_width, 3 * vga_height, NULL, scale3x_16, scale3x_32, "Scale3x" },
56 { 3 * vga_width, 3 * vga_height, NULL, NULL, hq3x_32, "hq3x" },
57 { 4 * vga_width, 4 * vga_height, NULL, nn_16, nn_32, "4x" },
58 { 4 * vga_width, 4 * vga_height, NULL, NULL, hq4x_32, "hq4x" },
59 #endif
60 };
61 const uint scalers_count = COUNTOF(scalers);
62
set_scaler_by_name(const char * name)63 void set_scaler_by_name( const char *name )
64 {
65 for (uint i = 0; i < scalers_count; ++i)
66 {
67 if (strcmp(name, scalers[i].name) == 0)
68 {
69 scaler = i;
70 break;
71 }
72 }
73 }
74
75 #if defined(TARGET_GP2X) || defined(TARGET_DINGUX)
76 #define VGA_CENTERED
77 #endif
78
no_scale(SDL_Surface * src_surface,SDL_Surface * dst_surface)79 void no_scale( SDL_Surface *src_surface, SDL_Surface *dst_surface )
80 {
81 Uint8 *src = src_surface->pixels,
82 *dst = dst_surface->pixels;
83
84 #ifdef VGA_CENTERED
85 size_t blank = (dst_surface->h - src_surface->h) / 2 * dst_surface->pitch;
86 memset(dst, 0, blank);
87 dst += blank;
88 #endif
89
90 memcpy(dst, src, src_surface->pitch * src_surface->h);
91
92 #ifdef VGA_CENTERED
93 dst += src_surface->pitch * src_surface->h;
94 memset(dst, 0, blank);
95 #endif
96 }
97
98
nn_32(SDL_Surface * src_surface,SDL_Surface * dst_surface)99 void nn_32( SDL_Surface *src_surface, SDL_Surface *dst_surface )
100 {
101 Uint8 *src = src_surface->pixels, *src_temp,
102 *dst = dst_surface->pixels, *dst_temp;
103 int src_pitch = src_surface->pitch,
104 dst_pitch = dst_surface->pitch;
105 const int dst_Bpp = 4; // dst_surface->format->BytesPerPixel
106
107 const int height = vga_height, // src_surface->h
108 width = vga_width, // src_surface->w
109 scale = dst_surface->w / width;
110 assert(scale == dst_surface->h / height);
111
112 #ifdef VGA_CENTERED
113 size_t blank = (dst_surface->h - src_surface->h) / 2 * dst_surface->pitch;
114 memset(dst, 0, blank);
115 dst += blank;
116 #endif
117
118 for (int y = height; y > 0; y--)
119 {
120 src_temp = src;
121 dst_temp = dst;
122
123 for (int x = width; x > 0; x--)
124 {
125 for (int z = scale; z > 0; z--)
126 {
127 *(Uint32 *)dst = rgb_palette[*src];
128 dst += dst_Bpp;
129 }
130 src++;
131 }
132
133 src = src_temp + src_pitch;
134 dst = dst_temp + dst_pitch;
135
136 for (int z = scale; z > 1; z--)
137 {
138 memcpy(dst, dst_temp, dst_pitch);
139 dst += dst_pitch;
140 }
141 }
142
143 #ifdef VGA_CENTERED
144 memset(dst, 0, blank);
145 #endif
146 }
147
nn_16(SDL_Surface * src_surface,SDL_Surface * dst_surface)148 void nn_16( SDL_Surface *src_surface, SDL_Surface *dst_surface )
149 {
150 Uint8 *src = src_surface->pixels, *src_temp,
151 *dst = dst_surface->pixels, *dst_temp;
152 int src_pitch = src_surface->pitch,
153 dst_pitch = dst_surface->pitch;
154 const int dst_Bpp = 2; // dst_surface->format->BytesPerPixel
155
156 const int height = vga_height, // src_surface->h
157 width = vga_width, // src_surface->w
158 scale = dst_surface->w / width;
159 assert(scale == dst_surface->h / height);
160
161 #ifdef VGA_CENTERED
162 size_t blank = (dst_surface->h - src_surface->h) / 2 * dst_surface->pitch;
163 memset(dst, 0, blank);
164 dst += blank;
165 #endif
166
167 for (int y = height; y > 0; y--)
168 {
169 src_temp = src;
170 dst_temp = dst;
171
172 for (int x = width; x > 0; x--)
173 {
174 for (int z = scale; z > 0; z--)
175 {
176 *(Uint16 *)dst = rgb_palette[*src];
177 dst += dst_Bpp;
178 }
179 src++;
180 }
181
182 src = src_temp + src_pitch;
183 dst = dst_temp + dst_pitch;
184
185 for (int z = scale; z > 1; z--)
186 {
187 memcpy(dst, dst_temp, dst_pitch);
188 dst += dst_pitch;
189 }
190 }
191
192 #ifdef VGA_CENTERED
193 memset(dst, 0, blank);
194 #endif
195 }
196
197
scale2x_32(SDL_Surface * src_surface,SDL_Surface * dst_surface)198 void scale2x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface )
199 {
200 Uint8 *src = src_surface->pixels, *src_temp,
201 *dst = dst_surface->pixels, *dst_temp;
202 int src_pitch = src_surface->pitch,
203 dst_pitch = dst_surface->pitch;
204 const int dst_Bpp = 4; // dst_surface->format->BytesPerPixel
205
206 const int height = vga_height, // src_surface->h
207 width = vga_width; // src_surface->w
208
209 int prevline, nextline;
210
211 Uint32 E0, E1, E2, E3, B, D, E, F, H;
212 for (int y = 0; y < height; y++)
213 {
214 src_temp = src;
215 dst_temp = dst;
216
217 prevline = (y > 0) ? -src_pitch : 0;
218 nextline = (y < height - 1) ? src_pitch : 0;
219
220 for (int x = 0; x < width; x++)
221 {
222 B = rgb_palette[*(src + prevline)];
223 D = rgb_palette[*(x > 0 ? src - 1 : src)];
224 E = rgb_palette[*src];
225 F = rgb_palette[*(x < width - 1 ? src + 1 : src)];
226 H = rgb_palette[*(src + nextline)];
227
228 if (B != H && D != F) {
229 E0 = D == B ? D : E;
230 E1 = B == F ? F : E;
231 E2 = D == H ? D : E;
232 E3 = H == F ? F : E;
233 } else {
234 E0 = E1 = E2 = E3 = E;
235 }
236
237 *(Uint32 *)dst = E0;
238 *(Uint32 *)(dst + dst_Bpp) = E1;
239 *(Uint32 *)(dst + dst_pitch) = E2;
240 *(Uint32 *)(dst + dst_pitch + dst_Bpp) = E3;
241
242 src++;
243 dst += 2 * dst_Bpp;
244 }
245
246 src = src_temp + src_pitch;
247 dst = dst_temp + 2 * dst_pitch;
248 }
249 }
250
scale2x_16(SDL_Surface * src_surface,SDL_Surface * dst_surface)251 void scale2x_16( SDL_Surface *src_surface, SDL_Surface *dst_surface )
252 {
253 Uint8 *src = src_surface->pixels, *src_temp,
254 *dst = dst_surface->pixels, *dst_temp;
255 int src_pitch = src_surface->pitch,
256 dst_pitch = dst_surface->pitch;
257 const int dst_Bpp = 2; // dst_surface->format->BytesPerPixel
258
259 const int height = vga_height, // src_surface->h
260 width = vga_width; // src_surface->w
261
262 int prevline, nextline;
263
264 Uint16 E0, E1, E2, E3, B, D, E, F, H;
265 for (int y = 0; y < height; y++)
266 {
267 src_temp = src;
268 dst_temp = dst;
269
270 prevline = (y > 0) ? -src_pitch : 0;
271 nextline = (y < height - 1) ? src_pitch : 0;
272
273 for (int x = 0; x < width; x++)
274 {
275 B = rgb_palette[*(src + prevline)];
276 D = rgb_palette[*(x > 0 ? src - 1 : src)];
277 E = rgb_palette[*src];
278 F = rgb_palette[*(x < width - 1 ? src + 1 : src)];
279 H = rgb_palette[*(src + nextline)];
280
281 if (B != H && D != F) {
282 E0 = D == B ? D : E;
283 E1 = B == F ? F : E;
284 E2 = D == H ? D : E;
285 E3 = H == F ? F : E;
286 } else {
287 E0 = E1 = E2 = E3 = E;
288 }
289
290 *(Uint16 *)dst = E0;
291 *(Uint16 *)(dst + dst_Bpp) = E1;
292 *(Uint16 *)(dst + dst_pitch) = E2;
293 *(Uint16 *)(dst + dst_pitch + dst_Bpp) = E3;
294
295 src++;
296 dst += 2 * dst_Bpp;
297 }
298
299 src = src_temp + src_pitch;
300 dst = dst_temp + 2 * dst_pitch;
301 }
302 }
303
304
scale3x_32(SDL_Surface * src_surface,SDL_Surface * dst_surface)305 void scale3x_32( SDL_Surface *src_surface, SDL_Surface *dst_surface )
306 {
307 Uint8 *src = src_surface->pixels, *src_temp,
308 *dst = dst_surface->pixels, *dst_temp;
309 int src_pitch = src_surface->pitch,
310 dst_pitch = dst_surface->pitch;
311 const int dst_Bpp = 4; // dst_surface->format->BytesPerPixel
312
313 const int height = vga_height, // src_surface->h
314 width = vga_width; // src_surface->w
315
316 int prevline, nextline;
317
318 Uint32 E0, E1, E2, E3, E4, E5, E6, E7, E8, A, B, C, D, E, F, G, H, I;
319 for (int y = 0; y < height; y++)
320 {
321 src_temp = src;
322 dst_temp = dst;
323
324 prevline = (y > 0) ? -src_pitch : 0;
325 nextline = (y < height - 1) ? src_pitch : 0;
326
327 for (int x = 0; x < width; x++)
328 {
329 A = rgb_palette[*(src + prevline - (x > 0 ? 1 : 0))];
330 B = rgb_palette[*(src + prevline)];
331 C = rgb_palette[*(src + prevline + (x < width - 1 ? 1 : 0))];
332 D = rgb_palette[*(src - (x > 0 ? 1 : 0))];
333 E = rgb_palette[*src];
334 F = rgb_palette[*(src + (x < width - 1 ? 1 : 0))];
335 G = rgb_palette[*(src + nextline - (x > 0 ? 1 : 0))];
336 H = rgb_palette[*(src + nextline)];
337 I = rgb_palette[*(src + nextline + (x < width - 1 ? 1 : 0))];
338
339 if (B != H && D != F) {
340 E0 = D == B ? D : E;
341 E1 = (D == B && E != C) || (B == F && E != A) ? B : E;
342 E2 = B == F ? F : E;
343 E3 = (D == B && E != G) || (D == H && E != A) ? D : E;
344 E4 = E;
345 E5 = (B == F && E != I) || (H == F && E != C) ? F : E;
346 E6 = D == H ? D : E;
347 E7 = (D == H && E != I) || (H == F && E != G) ? H : E;
348 E8 = H == F ? F : E;
349 } else {
350 E0 = E1 = E2 = E3 = E4 = E5 = E6 = E7 = E8 = E;
351 }
352
353 *(Uint32 *)dst = E0;
354 *(Uint32 *)(dst + dst_Bpp) = E1;
355 *(Uint32 *)(dst + 2 * dst_Bpp) = E2;
356 *(Uint32 *)(dst + dst_pitch) = E3;
357 *(Uint32 *)(dst + dst_pitch + dst_Bpp) = E4;
358 *(Uint32 *)(dst + dst_pitch + 2 * dst_Bpp) = E5;
359 *(Uint32 *)(dst + 2 * dst_pitch) = E6;
360 *(Uint32 *)(dst + 2 * dst_pitch + dst_Bpp) = E7;
361 *(Uint32 *)(dst + 2 * dst_pitch + 2 * dst_Bpp) = E8;
362
363 src++;
364 dst += 3 * dst_Bpp;
365 }
366
367 src = src_temp + src_pitch;
368 dst = dst_temp + 3 * dst_pitch;
369 }
370 }
371
scale3x_16(SDL_Surface * src_surface,SDL_Surface * dst_surface)372 void scale3x_16( SDL_Surface *src_surface, SDL_Surface *dst_surface )
373 {
374 Uint8 *src = src_surface->pixels, *src_temp,
375 *dst = dst_surface->pixels, *dst_temp;
376 int src_pitch = src_surface->pitch,
377 dst_pitch = dst_surface->pitch;
378 const int dst_Bpp = 2; // dst_surface->format->BytesPerPixel
379
380 const int height = vga_height, // src_surface->h
381 width = vga_width; // src_surface->w
382
383 int prevline, nextline;
384
385 Uint16 E0, E1, E2, E3, E4, E5, E6, E7, E8, A, B, C, D, E, F, G, H, I;
386 for (int y = 0; y < height; y++)
387 {
388 src_temp = src;
389 dst_temp = dst;
390
391 prevline = (y > 0) ? -src_pitch : 0;
392 nextline = (y < height - 1) ? src_pitch : 0;
393
394 for (int x = 0; x < width; x++)
395 {
396 A = rgb_palette[*(src + prevline - (x > 0 ? 1 : 0))];
397 B = rgb_palette[*(src + prevline)];
398 C = rgb_palette[*(src + prevline + (x < width - 1 ? 1 : 0))];
399 D = rgb_palette[*(src - (x > 0 ? 1 : 0))];
400 E = rgb_palette[*src];
401 F = rgb_palette[*(src + (x < width - 1 ? 1 : 0))];
402 G = rgb_palette[*(src + nextline - (x > 0 ? 1 : 0))];
403 H = rgb_palette[*(src + nextline)];
404 I = rgb_palette[*(src + nextline + (x < width - 1 ? 1 : 0))];
405
406 if (B != H && D != F) {
407 E0 = D == B ? D : E;
408 E1 = (D == B && E != C) || (B == F && E != A) ? B : E;
409 E2 = B == F ? F : E;
410 E3 = (D == B && E != G) || (D == H && E != A) ? D : E;
411 E4 = E;
412 E5 = (B == F && E != I) || (H == F && E != C) ? F : E;
413 E6 = D == H ? D : E;
414 E7 = (D == H && E != I) || (H == F && E != G) ? H : E;
415 E8 = H == F ? F : E;
416 } else {
417 E0 = E1 = E2 = E3 = E4 = E5 = E6 = E7 = E8 = E;
418 }
419
420 *(Uint16 *)dst = E0;
421 *(Uint16 *)(dst + dst_Bpp) = E1;
422 *(Uint16 *)(dst + 2 * dst_Bpp) = E2;
423 *(Uint16 *)(dst + dst_pitch) = E3;
424 *(Uint16 *)(dst + dst_pitch + dst_Bpp) = E4;
425 *(Uint16 *)(dst + dst_pitch + 2 * dst_Bpp) = E5;
426 *(Uint16 *)(dst + 2 * dst_pitch) = E6;
427 *(Uint16 *)(dst + 2 * dst_pitch + dst_Bpp) = E7;
428 *(Uint16 *)(dst + 2 * dst_pitch + 2 * dst_Bpp) = E8;
429
430 src++;
431 dst += 3 * dst_Bpp;
432 }
433
434 src = src_temp + src_pitch;
435 dst = dst_temp + 3 * dst_pitch;
436 }
437 }
438
439