⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 graphics.cpp

📁 由一个古老的BASIC解释器改进而成, 保留了ANSI C固有的艺术美感.
💻 CPP
📖 第 1 页 / 共 5 页
字号:
#endif

void graphics::circle (int x, int y, int radius)
{
	requiregraphics ();
	activecolor (pforeground);

	lastx= x + radius;
	lasty= y;

	transform_y (y);

	if (radius == 0)
	{
		impl_plot_mask (x, y);
		return;
	}

	// sq2_2 is sin (pi/4)
	#ifdef M_SQRT2
	static const double sq2_2= M_SQRT2 / 2.0;
	#else
	static const double sq2_2= sqrt (2.0) / 2.0;
	#endif
	//int r= int (radius * sq2_2 + .5) + 1;
	int r= int (radius * sq2_2 + 1.0);
	int rr= int (sqrt (radius * radius - r * r) + .5);
	int dim= r;
	if (rr >= r) ++dim;

	#ifdef DEBUG_CIRCLE
	cerr << "Circle: " << radius << ", " << r << endl;
	#endif

	util::auto_buffer <int> p (dim);

	// Bresenham algorithm.
	for (int i= 0, j= radius, d= 1 - radius; i < dim; ++i)
	{
		p [i]= j;
		if (d < 0)
			d+= 2 * i + 3;
		else
		{
			d+= 2 * (i - j) + 5;
			--j;
		}
	}

	rr= p [r - 1] - 1;
	ASSERT (rr <= dim - 1);

	// The first point in each quadrant is plotted independently.
	// In the first quadrant is omitted, we plot it at the end.
	#ifdef DEBUG_CIRCLE
	graphics::setcolor (4);
	#endif
	for (int j= 1; j < r; ++j)
	{
		//do_line (x + p [j], y - j);
		impl_plot_mask (x + p [j], y - j);
		pausec ();
	}
	#ifdef DEBUG_CIRCLE
	graphics::setcolor (0);
	#endif
	for (int i= rr; i > 0; --i)
	{
		//do_line (x + i, y - p [i] );
		impl_plot_mask (x + i, y - p [i] );
		pausec ();
	}

	//do_line (x, y - radius);
	#ifdef DEBUG_CIRCLE
	graphics::setcolor (4);
	#endif
	impl_plot_mask (x, y - radius);
	for (int i= 1; i < r; ++i)
	{
		//do_line (x - i, y - p [i] );
		impl_plot_mask (x - i, y - p [i] );
		pausec ();
	}
	#ifdef DEBUG_CIRCLE
	graphics::setcolor (0);
	#endif
	for (int j= rr; j > 0; --j)
	{
		//do_line (x - p [j], y - j);
		impl_plot_mask (x - p [j], y - j);
		pausec ();
	}

	//do_line (x - radius, y);
	#ifdef DEBUG_CIRCLE
	graphics::setcolor (4);
	#endif
	impl_plot_mask (x - radius, y);
	for (int j= 1; j < r; ++j)
	{
		//do_line (x - p [j], y + j);
		impl_plot_mask (x - p [j], y + j);
		pausec ();
	}
	#ifdef DEBUG_CIRCLE
	graphics::setcolor (0);
	#endif
	for (int i= rr; i > 0; --i)
	{
		//do_line (x - i, y + p [i] );
		impl_plot_mask (x - i, y + p [i] );
		pausec ();
	}

	//do_line (x, y + radius);
	impl_plot_mask (x, y + radius);
	#ifdef DEBUG_CIRCLE
	graphics::setcolor (4);
	#endif
	for (int i= 1; i < r; ++i)
	{
		//do_line (x + i, y + p [i] );
		impl_plot_mask (x + i, y + p [i] );
		pausec ();
	}
	#ifdef DEBUG_CIRCLE
	graphics::setcolor (0);
	#endif
	for (int j= rr; j > 0; --j)
	{
		//do_line (x + p [j], y + j);
		impl_plot_mask (x + p [j], y + j);
		pausec ();
	}
	//do_line (x + radius, y);
	#ifdef DEBUG_CIRCLE
	graphics::setcolor (4);
	#endif
	impl_plot_mask (x + radius, y);
}

namespace {

inline void get_point_on_arc (int r, BlNumber a, int & out_x, int & out_y)
{
	BlNumber s= sin (a) * r, c= cos (a) * r;
	out_x= static_cast <int> (c < 0 ? c - .5 : c + .5);
	out_y= static_cast <int> (s < 0 ? s - .5 : s + .5);
}

inline int get_quadrant (int x, int y)
{
	if (x >= 0)
	{
		if (y >= 0)
			return 0;
		else
			return 3;
	}
	else
	{
		if (y > 0)
			return 1;
		else
			return 2;
	}
}

}

void graphics::arccircle (int x, int y, int radius,
	BlNumber arcbeg, BlNumber arcend)
{
	/*
		The code for this function and his auxiliarys
		is taken from the Allegro library.
		Many thanks.
	*/

	requiregraphics ();
	activecolor (pforeground);

	//#define DEBUG_ARCCIRCLE

	#ifdef DEBUG_ARCCIRCLE
	cerr << "arccircle: " << x << ", " << y << ", " << radius << ", " <<
		arcbeg << ", " << arcend << endl;
	#endif

	transform_y (y);

	int px, py; // Current position and auxiliary.
	get_point_on_arc (radius, arcend, px, py);
	const int ex= px, ey= py; // End position.
	get_point_on_arc (radius, arcbeg, px, py);
	const int sx= px, sy= py; // Start position.
	// Current position start at start position.

	const int sq= get_quadrant (sx, sy); // Start quadrant.
	// Calculate end quadrant, considering that end point
	// must be after start point.
	int q= get_quadrant (ex, ey);
	if (sq > q)
		// Quadrant end must be greater or equal.
		q+= 4;
	else if (sq == q && arcbeg > arcend)
		// If equal, consider the angle.
		q+= 4;
	const int qe= q;
	q= sq; // Current cuadrant.
	#ifdef DEBUG_ARCCIRCLE
	cerr << "Quadrant from " << sq << " to " << qe << endl;
	#endif

	// Direction of movement.
	int dy = ( ( (q + 1) & 2) == 0) ? 1 : -1;
	int dx= ( (q & 2) == 0) ? -1 : 1;

	const int rr= radius * radius;
	int xx= px * px;
	int yy= py * py - rr;

	while (true)
	{
		// Change quadrant when needed, adjusting directions.
		if ( (q & 1) == 0)
		{
			if (px == 0)
			{
				if (qe == q)
					break;
				++q;
				dy= -dy;
			}
		}
		else
		{
			if (py == 0)
			{
				if (qe == q)
					break;
				++q;
				dx= -dx;
			}
		}
		// If we are in the end quadrant, check if at the end position.
		if (qe == q)
		{
			int det= 0;
			if (dy > 0)
			{
				if (py >= ey)
					++det;
			}
			else
			{
				if (py <= ey)
					++det;
			}
			if (dx > 0)
			{
				if (px >= ex)
					++det;
			}
			else
			{
				if (px <= ex)
					++det;
			}
			if (det == 2)
				break;
		}

		impl_plot_mask (x + px, y - py);

		int xx_new= (px + dx) * (px + dx);
		int yy_new= (py + dy) * (py + dy) - rr;
		int rr1= xx_new + yy;
		int rr2= xx_new + yy_new;
		int rr3= xx + yy_new;
		if (rr1 < 0) rr1= -rr1;
		if (rr2 < 0) rr2= -rr2;
		if (rr3 < 0) rr3= -rr3;
		if (rr3 >= std::min (rr1, rr2) )
		{
			px+= dx;
			xx= xx_new;
		}
		if (rr1 > std::min (rr2, rr3) )
		{
			py+= dy;
			yy= yy_new;
		}
	}
	if (px != sx || py != sy || sq == qe)
		impl_plot_mask (x + px, y - py);
}

void graphics::mask (int m)
{
	requiregraphics ();
	maskvalue= static_cast <unsigned char> (m);
	maskpos= 0;
}

void graphics::maskdrawfirstpoint (bool f)
{
	requiregraphics ();
	maskdrawfirst= f;
}

namespace {

char skipblank (const char * & s)
{
	char c;
	while ( (c= * s) == ' ' || c == '\t')
		++s;
	return c;
}

int getnum (const char * & s)
{
	int r= 0;
	char c;
	if (! isdigit (* s) )
		throw ErrSyntax;
	while ( isdigit (c= * s) )
	{
		r*= 10;
		r+= c - '0';
		++s;
	}
	//cerr << r;
	return r;
}

enum TypeMove { MoveAbs, MovePos, MoveNeg };

TypeMove gettypemove (const char * & s)
{
	TypeMove tm= MoveAbs;
	char c= skipblank (s);
	switch (c)
	{
	case '+':
		//cerr << '+';
		tm= MovePos;
		++s;
		skipblank (s);
		break;
	case '-':
		//cerr << '-';
		tm= MoveNeg;
		++s;
		skipblank (s);
		break;
	}
	return tm;
}

inline void adjust (int & value, TypeMove t, int last)
{
	switch (t)
	{
	case MoveAbs:
		break;
	case MovePos:
		value= last + value;
		break;
	case MoveNeg:
		value= last - value;
		break;
	}
}

} // namespace

void graphics::draw (const std::string & str)
{
	requiregraphics ();
	const char * s= str.c_str ();
	char c;
	int i;
	while ( (c= skipblank (s) ) != '\0')
	{
		//cerr << c;
		++s;
		bool nopaint= false;
		if (c == 'B')
		{
			c= skipblank (s);
			//cerr << c;
			++s;
			nopaint= true;
		}
		switch (c)
		{
		case 'M':
			{
				TypeMove mx= gettypemove (s);
				int x= getnum (s);
				adjust (x, mx, lastx);
				c= skipblank (s);
				if (c != ',')
					throw ErrSyntax;
				//cerr << ',';
				++s;
				TypeMove my= gettypemove (s);
				int y= getnum (s);
				adjust (y, my, lasty);
				if (nopaint)
					graphics::move (x, y);
				else
					graphics::line (x, y);
			}
			break;
		case 'U':
			skipblank (s);
			i= getnum (s);
			if (nopaint)
				graphics::move (lastx, lasty - i);
			else
				graphics::line (lastx, lasty - i);
			break;
		case 'D':
			skipblank (s);
			i= getnum (s);
			if (nopaint)
				graphics::move (lastx, lasty + i);
			else
				graphics::line (lastx, lasty + i);
			break;
		case 'R':
			skipblank (s);
			i= getnum (s);
			if (nopaint)
				graphics::move (lastx + i, lasty);
			else
				graphics::line (lastx + i, lasty);
			break;
		case 'L':
			skipblank (s);
			i= getnum (s);
			if (nopaint)
				graphics::move (lastx - i, lasty);
			else
				graphics::line (lastx - i, lasty);
			break;
		case 'E':
			skipblank (s);
			i= getnum (s);
			if (nopaint)
				graphics::move (lastx + i, lasty - i);
			else
				graphics::line (lastx + i, lasty - i);
			break;
		case 'F':
			skipblank (s);
			i= getnum (s);
			if (nopaint)
				graphics::move (lastx + i, lasty + i);
			else
				graphics::line (lastx + i, lasty + i);
			break;
		case 'G':
			skipblank (s);
			i= getnum (s);
			if (nopaint)
				graphics::move (lastx - i, lasty + i);
			else
				graphics::line (lastx - i, lasty + i);
			break;
		case 'H':
			skipblank (s);
			i= getnum (s);
			if (nopaint)
				graphics::move (lastx - i, lasty - i);
			else
				graphics::line (lastx - i, lasty - i);
			break;
		case 'C':
			c= skipblank (s);
			if (! isdigit (c) )
				throw ErrSyntax;
			graphics::setcolor (c - '0');
			++s;
			break;
		case 'X':
			{
				std::string x;
				while ( (c= *s) != ';' && c != '\0')
				{
					x+= c;
					++s;
				}
				if (c != ';')
					throw ErrSyntax;
				++s;
				if (typeofvar (x) != VarString)
					throw ErrMismatch;
				std::string xx= evaluatevarstring (x);
				draw (xx);
			}
			break;
		case ';':
			break;
		default:
			throw ErrSyntax;
		}
	}
	//cerr << endl;
}

graphics::Point graphics::getlast ()
{
	return Point (lastx, lasty);
}

std::string graphics::getkey ()
{
        idle ();
        if (queuekey.empty () )
                return std::string ();
        #if 0
        std::string str= queuekey.front ();
        queuekey.pop ();
        return str;
        #else
        return queuekey.pop ();
        #endif
}

namespace {

int zone= 8;

class BlWindow {
public:
	BlWindow ()
	{
		setdefault ();
		defaultcolors ();
	}
	BlWindow (int x1, int x2, int y1, int y2)
	{
		set (x1, x2, y1, y2);
		defaultcolors ();
	}
	void setdefault ()
	{
		set (0, maxtcol - 1, 0, maxtrow - 1);
	}
	void set (int x1, int x2, int y1, int y2)
	{
		if (x1 > x2) std::swap (x1, x2);
		if (y1 > y2) std::swap (y1, y2);
		orgx= x1; orgy= y1;
		width= x2 - x1 + 1;
		height= y2 - y1 + 1;
		x= y= 0;
	}
	void defaultcolors ()
	{
		foreground= default_foreground;
		background= default_background;
	}
	int getwidth () { return width; }
	void gotoxy (int x, int y)
	{
		this->x= x; this->y= y;
	}
	void tab (size_t n)
	{
		int col (n - 1);
		if (x >= col)
		{
			do {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -