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