469 lines
11 KiB
C++
469 lines
11 KiB
C++
/*
|
|
* OpenTyrian Classic: A modern cross-platform port of Tyrian
|
|
* Copyright (C) 2007-2009 The OpenTyrian Development Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
#include "opentyr.h"
|
|
#include "backgrnd.h"
|
|
|
|
#include "config.h"
|
|
#include "varz.h"
|
|
#include "video.h"
|
|
|
|
#include <assert.h>
|
|
|
|
/*Special Background 2 and Background 3*/
|
|
|
|
/*Back Pos 3*/
|
|
JE_word backPos, backPos2, backPos3;
|
|
JE_word backMove, backMove2, backMove3;
|
|
|
|
/*Main Maps*/
|
|
JE_word mapX, mapY, mapX2, mapX3, mapY2, mapY3;
|
|
JE_byte **mapYPos, **mapY2Pos, **mapY3Pos;
|
|
JE_word mapXPos, oldMapXOfs, mapXOfs, mapX2Ofs, mapX2Pos, mapX3Pos, oldMapX3Ofs, mapX3Ofs, tempMapXOfs;
|
|
intptr_t mapXbpPos, mapX2bpPos, mapX3bpPos;
|
|
JE_byte map1YDelay, map1YDelayMax, map2YDelay, map2YDelayMax;
|
|
|
|
|
|
JE_boolean anySmoothies;
|
|
JE_byte smoothie_data[9]; /* [1..9] */
|
|
|
|
void JE_darkenBackground( JE_word neat ) /* wild detail level */
|
|
{
|
|
Uint8 *s = (Uint8 *)VGAScreen->pixels; /* screen pointer, 8-bit specific */
|
|
int x, y;
|
|
|
|
s += 24;
|
|
|
|
for (y = 184; y; y--)
|
|
{
|
|
for (x = 264; x; x--)
|
|
{
|
|
*s = ((((*s & 0x0f) << 4) - (*s & 0x0f) + ((((x - neat - y) >> 2) + *(s-2) + (y == 184 ? 0 : *(s-(VGAScreen->pitch-1)))) & 0x0f)) >> 4) | (*s & 0xf0);
|
|
s++;
|
|
}
|
|
s += VGAScreen->pitch - 264;
|
|
}
|
|
}
|
|
|
|
void blit_background_row( SDL_Surface *surface, int x, int y, Uint8 **map )
|
|
{
|
|
assert(surface->format->BitsPerPixel == 8);
|
|
|
|
Uint8 *pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x,
|
|
*pixels_ll = (Uint8 *)surface->pixels, // lower limit
|
|
*pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
|
|
|
|
for (int y = 0; y < 28; y++)
|
|
{
|
|
// not drawing on screen yet; skip y
|
|
if ((pixels + (12 * 24)) < pixels_ll)
|
|
{
|
|
pixels += surface->pitch;
|
|
continue;
|
|
}
|
|
|
|
for (int tile = 0; tile < 12; tile++)
|
|
{
|
|
Uint8 *data = *(map + tile);
|
|
|
|
// no tile; skip tile
|
|
if (data == NULL)
|
|
{
|
|
pixels += 24;
|
|
continue;
|
|
}
|
|
|
|
data += y * 24;
|
|
|
|
for (int x = 24; x; x--)
|
|
{
|
|
if (pixels >= pixels_ul)
|
|
return;
|
|
if (pixels >= pixels_ll && *data != 0)
|
|
*pixels = *data;
|
|
|
|
pixels++;
|
|
data++;
|
|
}
|
|
}
|
|
|
|
pixels += surface->pitch - 12 * 24;
|
|
}
|
|
}
|
|
|
|
void blit_background_row_blend( SDL_Surface *surface, int x, int y, Uint8 **map )
|
|
{
|
|
assert(surface->format->BitsPerPixel == 8);
|
|
|
|
Uint8 *pixels = (Uint8 *)surface->pixels + (y * surface->pitch) + x,
|
|
*pixels_ll = (Uint8 *)surface->pixels, // lower limit
|
|
*pixels_ul = (Uint8 *)surface->pixels + (surface->h * surface->pitch); // upper limit
|
|
|
|
for (int y = 0; y < 28; y++)
|
|
{
|
|
// not drawing on screen yet; skip y
|
|
if ((pixels + (12 * 24)) < pixels_ll)
|
|
{
|
|
pixels += surface->pitch;
|
|
continue;
|
|
}
|
|
|
|
for (int tile = 0; tile < 12; tile++)
|
|
{
|
|
Uint8 *data = *(map + tile);
|
|
|
|
// no tile; skip tile
|
|
if (data == NULL)
|
|
{
|
|
pixels += 24;
|
|
continue;
|
|
}
|
|
|
|
data += y * 24;
|
|
|
|
for (int x = 24; x; x--)
|
|
{
|
|
if (pixels >= pixels_ul)
|
|
return;
|
|
if (pixels >= pixels_ll && *data != 0)
|
|
*pixels = (*data & 0xf0) | (((*pixels & 0x0f) + (*data & 0x0f)) / 2);
|
|
|
|
pixels++;
|
|
data++;
|
|
}
|
|
}
|
|
|
|
pixels += surface->pitch - 12 * 24;
|
|
}
|
|
}
|
|
|
|
void draw_background_1( SDL_Surface *surface )
|
|
{
|
|
SDL_FillRect(surface, NULL, 0);
|
|
|
|
Uint8 **map = (Uint8 **)mapYPos + mapXbpPos - 12;
|
|
|
|
for (int i = -1; i < 7; i++)
|
|
{
|
|
blit_background_row(surface, mapXPos, (i * 28) + backPos, map);
|
|
|
|
map += 14;
|
|
}
|
|
}
|
|
|
|
void draw_background_2( SDL_Surface *surface )
|
|
{
|
|
if (map2YDelayMax > 1 && backMove2 < 2)
|
|
backMove2 = (map2YDelay == 1) ? 1 : 0;
|
|
|
|
if (background2 != 0)
|
|
{
|
|
// water effect combines background 1 and 2 by syncronizing the x coordinate
|
|
int x = smoothies[1] ? mapXPos : mapX2Pos;
|
|
|
|
Uint8 **map = (Uint8 **)mapY2Pos + (smoothies[1] ? mapXbpPos : mapX2bpPos) - 12;
|
|
|
|
for (int i = -1; i < 7; i++)
|
|
{
|
|
blit_background_row(surface, x, (i * 28) + backPos2, map);
|
|
|
|
map += 14;
|
|
}
|
|
}
|
|
|
|
/*Set Movement of background*/
|
|
if (--map2YDelay == 0)
|
|
{
|
|
map2YDelay = map2YDelayMax;
|
|
|
|
backPos2 += backMove2;
|
|
|
|
if (backPos2 > 27)
|
|
{
|
|
backPos2 -= 28;
|
|
mapY2--;
|
|
mapY2Pos -= 14; /*Map Width*/
|
|
}
|
|
}
|
|
}
|
|
|
|
void draw_background_2_blend( SDL_Surface *surface )
|
|
{
|
|
if (map2YDelayMax > 1 && backMove2 < 2)
|
|
backMove2 = (map2YDelay == 1) ? 1 : 0;
|
|
|
|
Uint8 **map = (Uint8 **)mapY2Pos + mapX2bpPos - 12;
|
|
|
|
for (int i = -1; i < 7; i++)
|
|
{
|
|
blit_background_row_blend(surface, mapX2Pos, (i * 28) + backPos2, map);
|
|
|
|
map += 14;
|
|
}
|
|
|
|
/*Set Movement of background*/
|
|
if (--map2YDelay == 0)
|
|
{
|
|
map2YDelay = map2YDelayMax;
|
|
|
|
backPos2 += backMove2;
|
|
|
|
if (backPos2 > 27)
|
|
{
|
|
backPos2 -= 28;
|
|
mapY2--;
|
|
mapY2Pos -= 14; /*Map Width*/
|
|
}
|
|
}
|
|
}
|
|
|
|
void draw_background_3( SDL_Surface *surface )
|
|
{
|
|
/* Movement of background */
|
|
backPos3 += backMove3;
|
|
|
|
if (backPos3 > 27)
|
|
{
|
|
backPos3 -= 28;
|
|
mapY3--;
|
|
mapY3Pos -= 15; /*Map Width*/
|
|
}
|
|
|
|
Uint8 **map = (Uint8 **)mapY3Pos + mapX3bpPos - 12;
|
|
|
|
for (int i = -1; i < 7; i++)
|
|
{
|
|
blit_background_row(surface, mapX3Pos, (i * 28) + backPos3, map);
|
|
|
|
map += 15;
|
|
}
|
|
}
|
|
|
|
void JE_filterScreen( JE_shortint col, JE_shortint int_)
|
|
{
|
|
Uint8 *s = NULL; /* screen pointer, 8-bit specific */
|
|
int x, y;
|
|
unsigned int temp;
|
|
|
|
if (filterFade)
|
|
{
|
|
levelBrightness += levelBrightnessChg;
|
|
if ((filterFadeStart && levelBrightness < -14) || levelBrightness > 14)
|
|
{
|
|
levelBrightnessChg = -levelBrightnessChg;
|
|
filterFadeStart = false;
|
|
levelFilter = levelFilterNew;
|
|
}
|
|
if (!filterFadeStart && levelBrightness == 0)
|
|
{
|
|
filterFade = false;
|
|
levelBrightness = -99;
|
|
}
|
|
}
|
|
|
|
if (col != -99 && filtrationAvail)
|
|
{
|
|
s = (Uint8 *)VGAScreen->pixels;
|
|
s += 24;
|
|
|
|
col <<= 4;
|
|
|
|
for (y = 184; y; y--)
|
|
{
|
|
for (x = 264; x; x--)
|
|
{
|
|
*s = col | (*s & 0x0f);
|
|
s++;
|
|
}
|
|
s += VGAScreen->pitch - 264;
|
|
}
|
|
}
|
|
|
|
if (int_ != -99 && explosionTransparent)
|
|
{
|
|
s = (Uint8 *)VGAScreen->pixels;
|
|
s += 24;
|
|
|
|
for (y = 184; y; y--)
|
|
{
|
|
for (x = 264; x; x--)
|
|
{
|
|
temp = (*s & 0x0f) + int_;
|
|
*s = (*s & 0xf0) | (temp >= 0x1f ? 0 : (temp >= 0x0f ? 0x0f : temp));
|
|
s++;
|
|
}
|
|
s += VGAScreen->pitch - 264;
|
|
}
|
|
}
|
|
}
|
|
|
|
void JE_checkSmoothies( void )
|
|
{
|
|
anySmoothies = (processorType > 2 && (smoothies[1-1] || smoothies[2-1])) || (processorType > 1 && (smoothies[3-1] || smoothies[4-1] || smoothies[5-1]));
|
|
}
|
|
|
|
void lava_filter( SDL_Surface *dst, SDL_Surface *src )
|
|
{
|
|
assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
|
|
|
|
/* we don't need to check for over-reading the pixel surfaces since we only
|
|
* read from the top 185+1 scanlines, and there should be 320 */
|
|
|
|
const int dst_pitch = dst->pitch;
|
|
Uint8 *dst_pixel = (Uint8 *)dst->pixels + (185 * dst_pitch);
|
|
const Uint8 * const dst_pixel_ll = (Uint8 *)dst->pixels; // lower limit
|
|
|
|
const int src_pitch = src->pitch;
|
|
const Uint8 *src_pixel = (Uint8 *)src->pixels + (185 * src->pitch);
|
|
const Uint8 * const src_pixel_ll = (Uint8 *)src->pixels; // lower limit
|
|
|
|
int w = 320 * 185 - 1;
|
|
|
|
for (int y = 185 - 1; y >= 0; --y)
|
|
{
|
|
dst_pixel -= (dst_pitch - 320); // in case pitch is not 320
|
|
src_pixel -= (src_pitch - 320); // in case pitch is not 320
|
|
|
|
for (int x = 320 - 1; x >= 0; x -= 8)
|
|
{
|
|
int waver = abs(((w >> 9) & 0x0f) - 8) - 1;
|
|
w -= 8;
|
|
|
|
for (int xi = 8 - 1; xi >= 0; --xi)
|
|
{
|
|
--dst_pixel;
|
|
--src_pixel;
|
|
|
|
// value is average value of source pixel (2x), destination pixel above, and destination pixel below (all with waver)
|
|
// hue is red
|
|
Uint8 value = 0;
|
|
|
|
if (src_pixel + waver >= src_pixel_ll)
|
|
value += (*(src_pixel + waver) & 0x0f) * 2;
|
|
value += *(dst_pixel + waver + dst_pitch) & 0x0f;
|
|
if (dst_pixel + waver - dst_pitch >= dst_pixel_ll)
|
|
value += *(dst_pixel + waver - dst_pitch) & 0x0f;
|
|
|
|
*dst_pixel = (value / 4) | 0x70;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void water_filter( SDL_Surface *dst, SDL_Surface *src )
|
|
{
|
|
assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
|
|
|
|
Uint8 hue = smoothie_data[1] << 4;
|
|
|
|
/* we don't need to check for over-reading the pixel surfaces since we only
|
|
* read from the top 185+1 scanlines, and there should be 320 */
|
|
|
|
const int dst_pitch = dst->pitch;
|
|
Uint8 *dst_pixel = (Uint8 *)dst->pixels + (185 * dst_pitch);
|
|
|
|
const Uint8 *src_pixel = (Uint8 *)src->pixels + (185 * src->pitch);
|
|
|
|
int w = 320 * 185 - 1;
|
|
|
|
for (int y = 185 - 1; y >= 0; --y)
|
|
{
|
|
dst_pixel -= (dst_pitch - 320); // in case pitch is not 320
|
|
src_pixel -= (src->pitch - 320); // in case pitch is not 320
|
|
|
|
for (int x = 320 - 1; x >= 0; x -= 8)
|
|
{
|
|
int waver = abs(((w >> 10) & 0x07) - 4) - 1;
|
|
w -= 8;
|
|
|
|
for (int xi = 8 - 1; xi >= 0; --xi)
|
|
{
|
|
--dst_pixel;
|
|
--src_pixel;
|
|
|
|
// pixel is copied from source if not blue
|
|
// otherwise, value is average of value of source pixel and destination pixel below (with waver)
|
|
if ((*src_pixel & 0x30) == 0)
|
|
{
|
|
*dst_pixel = *src_pixel;
|
|
}
|
|
else
|
|
{
|
|
Uint8 value = *src_pixel & 0x0f;
|
|
value += *(dst_pixel + waver + dst_pitch) & 0x0f;
|
|
*dst_pixel = (value / 2) | hue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void iced_blur_filter( SDL_Surface *dst, SDL_Surface *src )
|
|
{
|
|
assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
|
|
|
|
Uint8 *dst_pixel = (Uint8 *)dst->pixels;
|
|
const Uint8 *src_pixel = (Uint8 *)src->pixels;
|
|
|
|
for (int y = 0; y < 184; ++y)
|
|
{
|
|
for (int x = 0; x < 320; ++x)
|
|
{
|
|
// value is average value of source pixel and destination pixel
|
|
// hue is icy blue
|
|
|
|
const Uint8 value = (*src_pixel & 0x0f) + (*dst_pixel & 0x0f);
|
|
*dst_pixel = (value / 2) | 0x80;
|
|
|
|
++dst_pixel;
|
|
++src_pixel;
|
|
}
|
|
|
|
dst_pixel += (dst->pitch - 320); // in case pitch is not 320
|
|
src_pixel += (src->pitch - 320); // in case pitch is not 320
|
|
}
|
|
}
|
|
|
|
void blur_filter( SDL_Surface *dst, SDL_Surface *src )
|
|
{
|
|
assert(src->format->BitsPerPixel == 8 && dst->format->BitsPerPixel == 8);
|
|
|
|
Uint8 *dst_pixel = (Uint8 *)dst->pixels;
|
|
const Uint8 *src_pixel = (Uint8 *)src->pixels;
|
|
|
|
for (int y = 0; y < 184; ++y)
|
|
{
|
|
for (int x = 0; x < 320; ++x)
|
|
{
|
|
// value is average value of source pixel and destination pixel
|
|
// hue is source pixel hue
|
|
|
|
const Uint8 value = (*src_pixel & 0x0f) + (*dst_pixel & 0x0f);
|
|
*dst_pixel = (value / 2) | (*src_pixel & 0xf0);
|
|
|
|
++dst_pixel;
|
|
++src_pixel;
|
|
}
|
|
|
|
dst_pixel += (dst->pitch - 320); // in case pitch is not 320
|
|
src_pixel += (src->pitch - 320); // in case pitch is not 320
|
|
}
|
|
}
|
|
|
|
// kate: tab-width 4; vim: set noet:
|