1 /*
2 * OpenTyrian: A modern cross-platform port of Tyrian
3 * Copyright (C) 2007-2009 The OpenTyrian Development Team
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program 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 program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19 #include "opentyr.h"
20 #include "backgrnd.h"
21
22 #include "config.h"
23 #include "mtrand.h"
24 #include "varz.h"
25 #include "video.h"
26
27 #include <assert.h>
28
29 /*Special Background 2 and Background 3*/
30
31 /*Back Pos 3*/
32 JE_word backPos, backPos2, backPos3;
33 JE_word backMove, backMove2, backMove3;
34
35 /*Main Maps*/
36 JE_word mapX, mapY, mapX2, mapX3, mapY2, mapY3;
37 JE_byte **mapYPos, **mapY2Pos, **mapY3Pos;
38 JE_word mapXPos, oldMapXOfs, mapXOfs, mapX2Ofs, mapX2Pos, mapX3Pos, oldMapX3Ofs, mapX3Ofs, tempMapXOfs;
39 intptr_t mapXbpPos, mapX2bpPos, mapX3bpPos;
40 JE_byte map1YDelay, map1YDelayMax, map2YDelay, map2YDelayMax;
41
42
43 JE_boolean anySmoothies;
44 JE_byte smoothie_data[9]; /* [1..9] */
45
JE_darkenBackground(JE_word neat)46 void JE_darkenBackground( JE_word neat ) /* wild detail level */
47 {
48 Uint8 *s = VGAScreen->pixels; /* screen pointer, 8-bit specific */
49 int x, y;
50
51 s += 24;
52
53 for (y = 184; y; y--)
54 {
55 for (x = 264; x; x--)
56 {
57 *s = ((((*s & 0x0f) << 4) - (*s & 0x0f) + ((((x - neat - y) >> 2) + *(s-2) + (y == 184 ? 0 : *(s-(VGAScreen->pitch-1)))) & 0x0f)) >> 4) | (*s & 0xf0);
58 s++;
59 }
60 s += VGAScreen->pitch - 264;
61 }
62 }
63
blit_background_row(SDL_Surface * surface,int x,int y,Uint8 ** map)64 void blit_background_row( SDL_Surface *surface, int x, int y, Uint8 **map )
65 {
66 assert(surface->format->BitsPerPixel == 8);
67
68 Uint8 *pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x,
69 *pixels_ll = (Uint8 *)surface->pixels, // lower limit
70 *pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
71
72 for (int y = 0; y < 28; y++)
73 {
74 // not drawing on screen yet; skip y
75 if ((pixels + (12 * 24)) < pixels_ll)
76 {
77 pixels += surface->pitch;
78 continue;
79 }
80
81 for (int tile = 0; tile < 12; tile++)
82 {
83 Uint8 *data = *(map + tile);
84
85 // no tile; skip tile
86 if (data == NULL)
87 {
88 pixels += 24;
89 continue;
90 }
91
92 data += y * 24;
93
94 for (int x = 24; x; x--)
95 {
96 if (pixels >= pixels_ul)
97 return;
98 if (pixels >= pixels_ll && *data != 0)
99 *pixels = *data;
100
101 pixels++;
102 data++;
103 }
104 }
105
106 pixels += surface->pitch - 12 * 24;
107 }
108 }
109
blit_background_row_blend(SDL_Surface * surface,int x,int y,Uint8 ** map)110 void blit_background_row_blend( SDL_Surface *surface, int x, int y, Uint8 **map )
111 {
112 assert(surface->format->BitsPerPixel == 8);
113
114 Uint8 *pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x,
115 *pixels_ll = (Uint8 *)surface->pixels, // lower limit
116 *pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
117
118 for (int y = 0; y < 28; y++)
119 {
120 // not drawing on screen yet; skip y
121 if ((pixels + (12 * 24)) < pixels_ll)
122 {
123 pixels += surface->pitch;
124 continue;
125 }
126
127 for (int tile = 0; tile < 12; tile++)
128 {
129 Uint8 *data = *(map + tile);
130
131 // no tile; skip tile
132 if (data == NULL)
133 {
134 pixels += 24;
135 continue;
136 }
137
138 data += y * 24;
139
140 for (int x = 24; x; x--)
141 {
142 if (pixels >= pixels_ul)
143 return;
144 if (pixels >= pixels_ll && *data != 0)
145 *pixels = (*data & 0xf0) | (((*pixels & 0x0f) + (*data & 0x0f)) / 2);
146
147 pixels++;
148 data++;
149 }
150 }
151
152 pixels += surface->pitch - 12 * 24;
153 }
154 }
155
draw_background_1(SDL_Surface * surface)156 void draw_background_1( SDL_Surface *surface )
157 {
158 SDL_FillRect(surface, NULL, 0);
159
160 Uint8 **map = (Uint8 **)mapYPos + mapXbpPos - 12;
161
162 for (int i = -1; i < 7; i++)
163 {
164 blit_background_row(surface, mapXPos, (i * 28) + backPos, map);
165
166 map += 14;
167 }
168 }
169
draw_background_2(SDL_Surface * surface)170 void draw_background_2( SDL_Surface *surface )
171 {
172 if (map2YDelayMax > 1 && backMove2 < 2)
173 backMove2 = (map2YDelay == 1) ? 1 : 0;
174
175 if (background2 != 0)
176 {
177 // water effect combines background 1 and 2 by syncronizing the x coordinate
178 int x = smoothies[1] ? mapXPos : mapX2Pos;
179
180 Uint8 **map = (Uint8 **)mapY2Pos + (smoothies[1] ? mapXbpPos : mapX2bpPos) - 12;
181
182 for (int i = -1; i < 7; i++)
183 {
184 blit_background_row(surface, x, (i * 28) + backPos2, map);
185
186 map += 14;
187 }
188 }
189
190 /*Set Movement of background*/
191 if (--map2YDelay == 0)
192 {
193 map2YDelay = map2YDelayMax;
194
195 backPos2 += backMove2;
196
197 if (backPos2 > 27)
198 {
199 backPos2 -= 28;
200 mapY2--;
201 mapY2Pos -= 14; /*Map Width*/
202 }
203 }
204 }
205
draw_background_2_blend(SDL_Surface * surface)206 void draw_background_2_blend( SDL_Surface *surface )
207 {
208 if (map2YDelayMax > 1 && backMove2 < 2)
209 backMove2 = (map2YDelay == 1) ? 1 : 0;
210
211 Uint8 **map = (Uint8 **)mapY2Pos + mapX2bpPos - 12;
212
213 for (int i = -1; i < 7; i++)
214 {
215 blit_background_row_blend(surface, mapX2Pos, (i * 28) + backPos2, map);
216
217 map += 14;
218 }
219
220 /*Set Movement of background*/
221 if (--map2YDelay == 0)
222 {
223 map2YDelay = map2YDelayMax;
224
225 backPos2 += backMove2;
226
227 if (backPos2 > 27)
228 {
229 backPos2 -= 28;
230 mapY2--;
231 mapY2Pos -= 14; /*Map Width*/
232 }
233 }
234 }
235
draw_background_3(SDL_Surface * surface)236 void draw_background_3( SDL_Surface *surface )
237 {
238 /* Movement of background */
239 backPos3 += backMove3;
240
241 if (backPos3 > 27)
242 {
243 backPos3 -= 28;
244 mapY3--;
245 mapY3Pos -= 15; /*Map Width*/
246 }
247
248 Uint8 **map = (Uint8 **)mapY3Pos + mapX3bpPos - 12;
249
250 for (int i = -1; i < 7; i++)
251 {
252 blit_background_row(surface, mapX3Pos, (i * 28) + backPos3, map);
253
254 map += 15;
255 }
256 }
257
JE_filterScreen(JE_shortint col,JE_shortint int_)258 void JE_filterScreen( JE_shortint col, JE_shortint int_)
259 {
260 Uint8 *s = NULL; /* screen pointer, 8-bit specific */
261 int x, y;
262 unsigned int temp;
263
264 if (filterFade)
265 {
266 levelBrightness += levelBrightnessChg;
267 if ((filterFadeStart && levelBrightness < -14) || levelBrightness > 14)
268 {
269 levelBrightnessChg = -levelBrightnessChg;
270 filterFadeStart = false;
271 levelFilter = levelFilterNew;
272 }
273 if (!filterFadeStart && levelBrightness == 0)
274 {
275 filterFade = false;
276 levelBrightness = -99;
277 }
278 }
279
280 if (col != -99 && filtrationAvail)
281 {
282 s = VGAScreen->pixels;
283 s += 24;
284
285 col <<= 4;
286
287 for (y = 184; y; y--)
288 {
289 for (x = 264; x; x--)
290 {
291 *s = col | (*s & 0x0f);
292 s++;
293 }
294 s += VGAScreen->pitch - 264;
295 }
296 }
297
298 if (int_ != -99 && explosionTransparent)
299 {
300 s = VGAScreen->pixels;
301 s += 24;
302
303 for (y = 184; y; y--)
304 {
305 for (x = 264; x; x--)
306 {
307 temp = (*s & 0x0f) + int_;
308 *s = (*s & 0xf0) | (temp >= 0x1f ? 0 : (temp >= 0x0f ? 0x0f : temp));
309 s++;
310 }
311 s += VGAScreen->pitch - 264;
312 }
313 }
314 }
315
JE_checkSmoothies(void)316 void JE_checkSmoothies( void )
317 {
318 anySmoothies = (processorType > 2 && (smoothies[1-1] || smoothies[2-1])) || (processorType > 1 && (smoothies[3-1] || smoothies[4-1] || smoothies[5-1]));
319 }
320
lava_filter(SDL_Surface * dst,SDL_Surface * src)321 void lava_filter( SDL_Surface *dst, SDL_Surface *src )
322 {
323 assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
324
325 /* we don't need to check for over-reading the pixel surfaces since we only
326 * read from the top 185+1 scanlines, and there should be 320 */
327
328 const int dst_pitch = dst->pitch;
329 Uint8 *dst_pixel = (Uint8 *)dst->pixels + (185 * dst_pitch);
330 const Uint8 * const dst_pixel_ll = (Uint8 *)dst->pixels; // lower limit
331
332 const int src_pitch = src->pitch;
333 const Uint8 *src_pixel = (Uint8 *)src->pixels + (185 * src->pitch);
334 const Uint8 * const src_pixel_ll = (Uint8 *)src->pixels; // lower limit
335
336 int w = 320 * 185 - 1;
337
338 for (int y = 185 - 1; y >= 0; --y)
339 {
340 dst_pixel -= (dst_pitch - 320); // in case pitch is not 320
341 src_pixel -= (src_pitch - 320); // in case pitch is not 320
342
343 for (int x = 320 - 1; x >= 0; x -= 8)
344 {
345 int waver = abs(((w >> 9) & 0x0f) - 8) - 1;
346 w -= 8;
347
348 for (int xi = 8 - 1; xi >= 0; --xi)
349 {
350 --dst_pixel;
351 --src_pixel;
352
353 // value is average value of source pixel (2x), destination pixel above, and destination pixel below (all with waver)
354 // hue is red
355 Uint8 value = 0;
356
357 if (src_pixel + waver >= src_pixel_ll)
358 value += (*(src_pixel + waver) & 0x0f) * 2;
359 value += *(dst_pixel + waver + dst_pitch) & 0x0f;
360 if (dst_pixel + waver - dst_pitch >= dst_pixel_ll)
361 value += *(dst_pixel + waver - dst_pitch) & 0x0f;
362
363 *dst_pixel = (value / 4) | 0x70;
364 }
365 }
366 }
367 }
368
water_filter(SDL_Surface * dst,SDL_Surface * src)369 void water_filter( SDL_Surface *dst, SDL_Surface *src )
370 {
371 assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
372
373 Uint8 hue = smoothie_data[1] << 4;
374
375 /* we don't need to check for over-reading the pixel surfaces since we only
376 * read from the top 185+1 scanlines, and there should be 320 */
377
378 const int dst_pitch = dst->pitch;
379 Uint8 *dst_pixel = (Uint8 *)dst->pixels + (185 * dst_pitch);
380
381 const Uint8 *src_pixel = (Uint8 *)src->pixels + (185 * src->pitch);
382
383 int w = 320 * 185 - 1;
384
385 for (int y = 185 - 1; y >= 0; --y)
386 {
387 dst_pixel -= (dst_pitch - 320); // in case pitch is not 320
388 src_pixel -= (src->pitch - 320); // in case pitch is not 320
389
390 for (int x = 320 - 1; x >= 0; x -= 8)
391 {
392 int waver = abs(((w >> 10) & 0x07) - 4) - 1;
393 w -= 8;
394
395 for (int xi = 8 - 1; xi >= 0; --xi)
396 {
397 --dst_pixel;
398 --src_pixel;
399
400 // pixel is copied from source if not blue
401 // otherwise, value is average of value of source pixel and destination pixel below (with waver)
402 if ((*src_pixel & 0x30) == 0)
403 {
404 *dst_pixel = *src_pixel;
405 }
406 else
407 {
408 Uint8 value = *src_pixel & 0x0f;
409 value += *(dst_pixel + waver + dst_pitch) & 0x0f;
410 *dst_pixel = (value / 2) | hue;
411 }
412 }
413 }
414 }
415 }
416
iced_blur_filter(SDL_Surface * dst,SDL_Surface * src)417 void iced_blur_filter( SDL_Surface *dst, SDL_Surface *src )
418 {
419 assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
420
421 Uint8 *dst_pixel = dst->pixels;
422 const Uint8 *src_pixel = src->pixels;
423
424 for (int y = 0; y < 184; ++y)
425 {
426 for (int x = 0; x < 320; ++x)
427 {
428 // value is average value of source pixel and destination pixel
429 // hue is icy blue
430
431 const Uint8 value = (*src_pixel & 0x0f) + (*dst_pixel & 0x0f);
432 *dst_pixel = (value / 2) | 0x80;
433
434 ++dst_pixel;
435 ++src_pixel;
436 }
437
438 dst_pixel += (dst->pitch - 320); // in case pitch is not 320
439 src_pixel += (src->pitch - 320); // in case pitch is not 320
440 }
441 }
442
blur_filter(SDL_Surface * dst,SDL_Surface * src)443 void blur_filter( SDL_Surface *dst, SDL_Surface *src )
444 {
445 assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
446
447 Uint8 *dst_pixel = dst->pixels;
448 const Uint8 *src_pixel = src->pixels;
449
450 for (int y = 0; y < 184; ++y)
451 {
452 for (int x = 0; x < 320; ++x)
453 {
454 // value is average value of source pixel and destination pixel
455 // hue is source pixel hue
456
457 const Uint8 value = (*src_pixel & 0x0f) + (*dst_pixel & 0x0f);
458 *dst_pixel = (value / 2) | (*src_pixel & 0xf0);
459
460 ++dst_pixel;
461 ++src_pixel;
462 }
463
464 dst_pixel += (dst->pitch - 320); // in case pitch is not 320
465 src_pixel += (src->pitch - 320); // in case pitch is not 320
466 }
467 }
468
469
470 /* Background Starfield */
471 typedef struct
472 {
473 Uint8 color;
474 JE_word position; // relies on overflow wrap-around
475 int speed;
476 } StarfieldStar;
477
478 #define MAX_STARS 100
479 #define STARFIELD_HUE 0x90
480 static StarfieldStar starfield_stars[MAX_STARS];
481 int starfield_speed;
482
initialize_starfield(void)483 void initialize_starfield( void )
484 {
485 for (int i = MAX_STARS-1; i >= 0; --i)
486 {
487 starfield_stars[i].position = mt_rand() % 320 + mt_rand() % 200 * VGAScreen->pitch;
488 starfield_stars[i].speed = mt_rand() % 3 + 2;
489 starfield_stars[i].color = mt_rand() % 16 + STARFIELD_HUE;
490 }
491 }
492
update_and_draw_starfield(SDL_Surface * surface,int move_speed)493 void update_and_draw_starfield( SDL_Surface* surface, int move_speed )
494 {
495 Uint8* p = (Uint8*)surface->pixels;
496
497 for (int i = MAX_STARS-1; i >= 0; --i)
498 {
499 StarfieldStar* star = &starfield_stars[i];
500
501 star->position += (star->speed + move_speed) * surface->pitch;
502
503 if (star->position < 177 * surface->pitch)
504 {
505 if (p[star->position] == 0)
506 {
507 p[star->position] = star->color;
508 }
509
510 // If star is bright enough, draw surrounding pixels
511 if (star->color - 4 >= STARFIELD_HUE)
512 {
513 if (p[star->position + 1] == 0)
514 p[star->position + 1] = star->color - 4;
515
516 if (star->position > 0 && p[star->position - 1] == 0)
517 p[star->position - 1] = star->color - 4;
518
519 if (p[star->position + surface->pitch] == 0)
520 p[star->position + surface->pitch] = star->color - 4;
521
522 if (star->position >= surface->pitch && p[star->position - surface->pitch] == 0)
523 p[star->position - surface->pitch] = star->color - 4;
524 }
525 }
526 }
527 }
528