/*
* Seven Kingdoms: Ancient Adversaries
*
* Copyright 1997,1998 Enlight Software Ltd.
*
* 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, see .
*
*/
// Filename : OANLINE.CPP
// Description : animated line
// Onwership : Gilbert
#include
#include
#include
#include
// ----------- Define color table
unsigned char AnimLine::init_color_code[ANIMCOLOR_PERIOD][ANIMLINE_PERIOD] =
{
// { 0x90, 0x93, 0x98, 0x9c, 0x9f, 0x9c, 0x98, 0x93 },
// { 0x90, 0x93, 0x97, 0x9a, 0x9d, 0x9a, 0x97, 0x93 },
// { 0x90, 0x92, 0x95, 0x97, 0x9a, 0x97, 0x95, 0x92 },
// { 0x90, 0x92, 0x95, 0x97, 0x9a, 0x97, 0x95, 0x92 },
// { 0x90, 0x93, 0x97, 0x9a, 0x9d, 0x9a, 0x97, 0x93 },
// { 0x90, 0x93, 0x98, 0x9c, 0x9f, 0x9c, 0x98, 0x93 }
{ 0xa6, 0xa5, 0xa4, 0xa4, 0x9c, 0xa4, 0xa4, 0xa5 },
{ 0xa7, 0xa6, 0xa5, 0xa4, 0x9c, 0xa4, 0xa5, 0xa6 },
{ 0xc7, 0xa7, 0xa6, 0x9c, 0x9f, 0x9c, 0xa6, 0xa7 },
{ 0x90, 0x93, 0x98, 0x9c, 0x9f, 0x9c, 0x98, 0x93 },
{ 0xc7, 0xa7, 0xa6, 0x9c, 0x9f, 0x9c, 0xa6, 0xa7 },
{ 0xa7, 0xa6, 0xa5, 0xa4, 0x9c, 0xa4, 0xa5, 0xa6 }
};
unsigned char AnimLine::series_color_code[ANIMCOLOR_SERIES][ANIMLINE_PERIOD] =
{
{ 0x90, 0x93, 0x98, 0x9c, 0x9f, 0x9c, 0x98, 0x93 },
// { 0xa6, 0xa5, 0xa4, 0x9c, 0x9f, 0x9c, 0xa4, 0xa5 },
{ 0xA0, 0xA1, 0xA2, 0xA3, 0xC3, 0xA3, 0xA2, 0xA0 },
{ 0xA0, 0xC3, 0xA0, 0xC3, 0xA0, 0xC3, 0xA0, 0xC3 },
};
// ----------- Begin of function AnimLine::init ----------//
//
// x1, y1, x2, y2 defines corners of the display area
//
void AnimLine::init(short x1, short y1, short x2, short y2)
{
// set the boundary
bound_x1 = x1;
bound_y1 = y1;
bound_x2 = x2;
bound_y2 = y2;
phase = 0;
color_phase = 0;
}
// ----------- End of function AnimLine::init ----------//
// ----------- Begin of function AnimLine::inc_phase ----------//
//
// called after each display cycle
//
void AnimLine::inc_phase()
{
phase = (phase == 0 ? ANIMLINE_PERIOD : phase) - 1;
if( ++color_phase >= ANIMCOLOR_PERIOD*ANIMCOLOR_INNER_PERIOD )
color_phase = 0;
}
// ----------- End of function AnimLine::inc_phase ----------//
// ----------- Begin of function AnimLine::draw_line ----------//
//
// clip the line before calling basic_line, basic_hline or basic_vline to draw
// animatedFlag = TRUE for animated line, FALSE for stable line
//
// vgabuf destination vgabuf
// x1,y1,x2,y2 draw from (x1,y1) to (x2,y2) on the screen
// [int] animatedFlag whether the colors of the line is cycle (default:1 = animated)
// [int] effectFlag effect : -1=dimming B/W, 0=non-dimming B/W, 1=non-dimming series (default : 0)
//
void AnimLine::draw_line(VgaBuf *vgabuf, short x1, short y1, short x2, short y2, int animatedFlag, int effectFlag)
{
if( (x1 < bound_x1 && x2 < bound_x1) || ( x1 > bound_x2 && x2 > bound_x2) ||
(y1 < bound_y1 && y2 < bound_y1) || ( y1 > bound_y2 && y2 > bound_y2) )
return;
unsigned char* colorCode;
if( effectFlag == -1)
colorCode = init_color_code[color_phase/ANIMCOLOR_INNER_PERIOD];
else if( effectFlag >= 0 && effectFlag < ANIMCOLOR_SERIES)
colorCode = series_color_code[effectFlag];
else
{
err_here(); // invalid effectFlag
colorCode = init_color_code[0];
}
if( x1 >= bound_x1 && x1 <= bound_x2 && x2 >= bound_x1 && x2 <= bound_x2 &&
y1 >= bound_y1 && y1 <= bound_y2 && y2 >= bound_y1 && y2 <= bound_y2)
{
// already inside the screen
if( y1 == y2)
{
basic_hline(vgabuf, x1, x2, y2, animatedFlag, colorCode);
}
else if( x1 == x2)
{
basic_vline(vgabuf, x1, y1, y2, animatedFlag, colorCode);
}
else
{
basic_line(vgabuf, x1, y1, x2, y2, animatedFlag, colorCode);
}
}
else
{
if( y1 == y2)
{
// horizontal line
if( y1 < bound_y1 || y1 > bound_y2)
return;
if( x1 < bound_x1)
x1 = bound_x1;
else if( x1 > bound_x2)
x1 = bound_x2;
if( x2 < bound_x1)
x2 = bound_x1;
else if (x2 > bound_x2)
x2 = bound_x2;
basic_hline(vgabuf, x1, x2, y1, animatedFlag, colorCode);
}
else if( x1 == x2)
{
// vertical line
if( x1 < bound_x1 || x1 > bound_x2)
return;
if( y1 < bound_y1)
y1 = bound_y1;
else if( y1 > bound_y2)
y1 = bound_y2;
if( y2 < bound_y1)
y2 = bound_y1;
else if( y2 > bound_y2)
y2 = bound_y2;
basic_vline(vgabuf, x1, y1, y2, animatedFlag, colorCode);
}
else
{
// neither horizontal or vertical
int x1a, y1a, x1b, y1b;
int x2a, y2a, x2b, y2b;
// find intersection points for the first point
x1a = x1b = x1;
y1a = y1b = y1;
if( y1 < bound_y1)
{
y1a = bound_y1;
x1a = top_intercept( x1, y1, x2, y2);
}
if( y1 > bound_y2)
{
y1a = bound_y2;
x1a = bottom_intercept(x1, y1 ,x2, y2);
}
if( x1 < bound_x1)
{
x1b = bound_x1;
y1b = left_intercept(x1, y1, x2, y2);
}
if( x1 > bound_x2)
{
x1b = bound_x2;
y1b = right_intercept( x1, y1, x2, y2);
}
// find intersection points for the second point
x2a = x2b = x2;
y2a = y2b = y2;
if( y2 < bound_y1)
{
y2a = bound_y1;
x2a = top_intercept( x1, y1, x2, y2);
}
if( y2 > bound_y2)
{
y2a = bound_y2;
x2a = bottom_intercept(x1, y1 ,x2, y2);
}
if( x2 < bound_x1)
{
x2b = bound_x1;
y2b = left_intercept(x1, y1, x2, y2);
}
if( x2 > bound_x2)
{
x2b = bound_x2;
y2b = right_intercept( x1, y1, x2, y2);
}
// replace x1, y1
if( x1 < bound_x1 || x1 > bound_x2 || y1 < bound_y1 || y1 > bound_y2)
{
if( x1a < bound_x1 || x1a > bound_x2 || y1a < bound_y1 || y1a > bound_y2)
{
if( x1b < bound_x1 || x1b > bound_x2 || y1b < bound_y1 || y1b > bound_y2)
{
return;
}
else
{
x1 = x1b;
y1 = y1b;
}
}
else
{
x1 = x1a;
y1 = y1a;
}
}
// replace x2, y2
if( x2 < bound_x1 || x2 > bound_x2 || y2 < bound_y1 || y2 > bound_y2)
{
if( x2a < bound_x1 || x2a > bound_x2 || y2a < bound_y1 || y2a > bound_y2)
{
if( x2b < bound_x1 || x2b > bound_x2 || y2b < bound_y1 || y2b > bound_y2)
{
return;
}
else
{
x2 = x2b;
y2 = y2b;
}
}
else
{
x2 = x2a;
y2 = y2a;
}
}
// a segment may be horizontal or vertical, check again
// if( y1 == y2)
// basic_hline(vgabuf, x1, x2, y1, animatedFlag);
// else if( x1 == x2)
// basic_vline(vgabuf, x1, y1, y2, animatedFlag);
// else
basic_line(vgabuf, x1, y1, x2, y2, animatedFlag, colorCode);
}
}
}
// ----------- End of function AnimLine::draw_line ----------//
// ----------- Begin of function AnimLine::thick_line ----------//
//
// draw a thicker line
//
// vgabuf destination vgabuf
// x1,y1,x2,y2 draw from (x1,y1) to (x2,y2) on the screen
// [int] animatedFlag whether the colors of the line is cycle (default:1 = animated)
// [int] effectFlag effect : -1=dimming B/W, 0=non-dimming B/W, 1=non-dimming series (default : 0)
//
void AnimLine::thick_line(VgaBuf *vgabuf, short x1, short y1, short x2, short y2, int animatedFlag, int effectFlag)
{
if( abs(x2-x1) > abs(y2-y1) )
{
// likely to be horizontal, draw top, bottom and centre
draw_line( vgabuf, x1, y1-1, x2, y2-1, animatedFlag, effectFlag);
draw_line( vgabuf, x1, y1+1, x2, y2+1, animatedFlag, effectFlag);
}
else
{
// likely to be vertical, draw left right and centre
draw_line( vgabuf, x1-1, y1, x2-1, y2, animatedFlag, effectFlag);
draw_line( vgabuf, x1+1, y1, x2+1, y2, animatedFlag, effectFlag);
}
draw_line( vgabuf, x1, y1, x2, y2, animatedFlag, effectFlag);
}
// ----------- End of function AnimLine::thick_line ----------//
// ----------- Begin of function AnimLine::basic_line ----------//
//
// draw a clipped line
//
void AnimLine::basic_line(VgaBuf *vgabuf, short x1, short y1, short x2, short y2, int animatedFlag,
unsigned char *colorCode)
{
err_when( x1 < bound_x1 || x1 > bound_x2 );
err_when( x2 < bound_x1 || x2 > bound_x2 );
err_when( y1 < bound_y1 || y1 > bound_y2 );
err_when( y2 < bound_y1 || y2 > bound_y2 );
int dx = x2 - x1;
int dy = y2 - y1;
if( dy == 0)
{
basic_hline(vgabuf, x1, x2, y1, animatedFlag, colorCode);
return;
}
if( dx == 0)
{
basic_vline(vgabuf, x1, y1, y2, animatedFlag, colorCode);
return;
}
int d;
int inc_x = dx > 0 ? 1 : -1;
int inc_y = dy > 0 ? 1 : -1;
int lPitch = dy > 0 ? vgabuf->buf_pitch() : -vgabuf->buf_pitch();
unsigned char *bufPtr = (unsigned char *) vgabuf->buf_ptr(x1,y1);
short linePhase;
err_when( dx == 0 || dy == 0);
if( abs(dy) <= abs(dx) )
{
// draw gentle line
// use x as independent variable
dx = abs(dx);
dy = abs(dy);
d = 2 * dy - dx;
int x = x1-inc_x;
linePhase = animatedFlag ? phase : 0;
do
{
x += inc_x;
*bufPtr = colorCode[linePhase];
if(++linePhase >= ANIMLINE_PERIOD )
linePhase = 0;
bufPtr += inc_x;
if( d >= 0)
{
// y increase by 1
bufPtr += lPitch;
d += 2 * (dy - dx);
}
else
{
// y remain unchange;
d += 2 * dy;
}
} while ( x != x2);
}
else
{
// draw steep line
// use y as independent variable
dx = abs(dx);
dy = abs(dy);
d = 2 * dx - dy;
int y = y1 - inc_y;
linePhase = animatedFlag ? phase : 0;
do
{
y += inc_y;
*bufPtr = colorCode[linePhase];
if(++linePhase >= ANIMLINE_PERIOD )
linePhase = 0;
bufPtr += lPitch;
if( d >= 0)
{
// x increase by 1
bufPtr += inc_x;
d += 2 * (dx - dy);
}
else
{
// x remain unchange;
d += 2 * dx;
}
} while ( y != y2);
}
}
// ----------- End of function AnimLine::basic_line ----------//
// ----------- Begin of function AnimLine::basic_hline ----------//
//
// draw a clipped horizontal line
//
void AnimLine::basic_hline(VgaBuf *vgabuf, short x1, short x2, short y1, int animatedFlag,
unsigned char *colorCode)
{
err_when( x1 < bound_x1 || x1 > bound_x2 );
err_when( x2 < bound_x1 || x2 > bound_x2 );
err_when( y1 < bound_y1 || y1 > bound_y2 );
short linePhase = animatedFlag ? phase : 0;
unsigned char *bufPtr = (unsigned char *)vgabuf->buf_ptr(x1, y1);
if( x1 <= x2)
{
// from left to right
for(short x = x1; x <= x2; ++x, ++bufPtr)
{
*bufPtr = colorCode[linePhase];
if(++linePhase >= ANIMLINE_PERIOD )
linePhase = 0;
}
}
else
{
// from right to left
for( short x = x1; x >= x2; --x, --bufPtr)
{
*bufPtr = colorCode[linePhase];
if(++linePhase >= ANIMLINE_PERIOD )
linePhase = 0;
}
}
}
// ----------- End of function AnimLine::basic_hline ----------//
// ----------- Begin of function AnimLine::basic_vline ----------//
//
// draw a clipped vertical line
//
void AnimLine::basic_vline(VgaBuf *vgabuf, short x1, short y1, short y2, int animatedFlag,
unsigned char *colorCode)
{
err_when( x1 < bound_x1 || x1 > bound_x2 );
err_when( y1 < bound_y1 || y1 > bound_y2 );
err_when( y2 < bound_y1 || y2 > bound_y2 );
short linePhase = animatedFlag ? phase : 0;
unsigned char *bufPtr = (unsigned char *) vgabuf->buf_ptr(x1, y1);
int lPitch = vgabuf->buf_pitch();
if( y1 <= y2)
{
// from top to bottom
for(short y = y1; y <= y2; ++y, bufPtr += lPitch)
{
*bufPtr = colorCode[linePhase];
if(++linePhase >= ANIMLINE_PERIOD )
linePhase = 0;
}
}
else
{
// from bottom to top
for( short y = y1; y >= y2; --y, bufPtr -= lPitch)
{
*bufPtr = colorCode[linePhase];
if(++linePhase >= ANIMLINE_PERIOD )
linePhase = 0;
}
}
}
// ----------- End of function AnimLine::basic_vline ----------//
// ----------- Begin of function AnimLine::get_series_color_array ----------//
unsigned char *AnimLine::get_series_color_array(int effectFlag)
{
unsigned char *colorCode;
if( effectFlag == -1)
colorCode = init_color_code[color_phase/ANIMCOLOR_INNER_PERIOD];
else if( effectFlag >= 0 && effectFlag < ANIMCOLOR_SERIES)
colorCode = series_color_code[effectFlag];
else
{
err_here(); // invalid effectFlag
colorCode = init_color_code[0];
}
return colorCode;
}
// ----------- End of function AnimLine::get_series_color_array ----------//
// ----------- Begin of function AnimLine::top_intercept ----------//
short AnimLine::top_intercept( short x1, short y1, short x2, short y2)
{
return (bound_y1-y1) * (x2-x1) / (y2-y1) + x1;
}
// ----------- End of function AnimLine::top_intercept ----------//
// ----------- Begin of function AnimLine::bottom_intercept ----------//
short AnimLine::bottom_intercept( short x1, short y1, short x2, short y2)
{
return (bound_y2-y1) * (x2-x1) / (y2-y1) + x1;
}
// ----------- End of function AnimLine::bottom_intercept ----------//
// ----------- Begin of function AnimLine::left_intercept ----------//
short AnimLine::left_intercept( short x1, short y1, short x2, short y2)
{
return (bound_x1-x1) * (y2-y1) / (x2-x1) + y1;
}
// ----------- End of function AnimLine::left_intercept ----------//
// ----------- Begin of function AnimLine::right_intercept ----------//
short AnimLine::right_intercept( short x1, short y1, short x2, short y2)
{
return (bound_x2-x1) * (y2-y1) / (x2-x1) + y1;
}
// ----------- End of function AnimLine::right_intercept ----------//