#include "mungal4.h"
#pragma hdrstop

#include "l4vb8.h"

//########################################################################
//######################### Video8BitBuffered ###########################
//########################################################################
//
//NOTE: the application assumes that the origin is in the lower left
// corner of the display, and all parameters passed to these routines
// use the application's coordinate system.
//
// All of the methods here convert these values to the SCREEN
// coordinate system, with the origin in the UPPER LEFT corner of
// the display.
//

//===================================================================
// Creator
//===================================================================
Video8BitBuffered::Video8BitBuffered(int x, int y):
	GraphicsDisplay(x, y)
	{
#	if defined(DEBUG)
		Tell(
			"Video8BitBuffered::Video8BitBuffered()\n"
		);
#	endif
	int
		i;
	Word
		*line_dest;

   pixelBuffer = new PixelMap8(x, y);
	Check(pixelBuffer);
	Verify(pixelBuffer->Data.MapPointer != NULL);
	Register_Object(pixelBuffer);
	createdPixelmap = True;

	height = y;
	width = x;

	maximumY = height-1;
	maximumX = width-1;
	//---------------------------------------------------------
	// Create 'changedLine' array
	//---------------------------------------------------------
	changedLine = new Word[height];
	Register_Pointer(changedLine);
	valid = True;

	//---------------------------------------------------------
	// Clear the 'changedLine' array
	//---------------------------------------------------------
	for (i=height,line_dest=changedLine; i>0; --i,++line_dest)
	{
		*line_dest = 0;
	}
	Check_Fpu();
}

Video8BitBuffered::Video8BitBuffered(PixelMap8 *pixel_buffer):
	GraphicsDisplay(pixel_buffer->Data.Size.x, pixel_buffer->Data.Size.y)
{
#	if defined(DEBUG)
		Tell(
			"Video8BitBuffered::Video8BitBuffered()\n"
		);
#	endif
	int
		i;
	Word
		*line_dest;

	pixelBuffer = pixel_buffer;
	Verify(pixelBuffer->Data.MapPointer != NULL);
	createdPixelmap = False;

	height = pixelBuffer->Data.Size.y;
	width = pixelBuffer->Data.Size.x;

	maximumY = height-1;
	maximumX = width-1;
	//---------------------------------------------------------
	// Create 'changedLine' array
	//---------------------------------------------------------
	changedLine = new Word[height];
   Register_Pointer(changedLine);

#	if defined(DEBUG)
		Tell("changedLine=" << changedLine << "\n");
#	endif

	if (changedLine == NULL)
	{
#	if defined(DEBUG)
		Tell("INVALID!\n");
#	endif
		valid = False;
		return;
	}
	else
	{
		Register_Pointer(changedLine);
		valid = True;
	}
	//---------------------------------------------------------
	// Clear the 'changedLine' array
	//---------------------------------------------------------
	for (i=height,line_dest=changedLine; i>0; --i,++line_dest)
	{
		*line_dest = 0;
	}
	Check_Fpu();
}

//===================================================================
// Destructor
//===================================================================
Video8BitBuffered::~Video8BitBuffered()
{
	Check(this);

	if (changedLine != NULL)
	{
		Unregister_Pointer(changedLine);
		delete changedLine;
		changedLine = NULL;
	}

	if (createdPixelmap)
	{
		if (pixelBuffer != NULL)
		{
			Check(pixelBuffer);
			Unregister_Object(pixelBuffer);
			delete pixelBuffer;
			pixelBuffer = NULL;
		}
      createdPixelmap = False;
	}

	Check_Fpu();
}


//===================================================================
// TestInstance
//===================================================================
Logical
	Video8BitBuffered::TestInstance() const
{
	return True;
}

//===================================================================
// ShowInstance
//===================================================================
void
	Video8BitBuffered::ShowInstance(
		char *indent
	)
{
	std::cout << indent << "Video8BitBuffered:\n";

	Check(this);

	char
		temp[80];

	Str_Copy(temp,indent, 80);
	Str_Cat(temp,"...", 80);

	std::cout << temp << "width      =" << width << "\n";
	std::cout << temp << "height     =" << height << "\n";
	std::cout << temp << "maximumX   =" << maximumX << "\n";
	std::cout << temp << "maximumY   =" << maximumY << "\n";
	std::cout << temp << "changedLine=" << changedLine << "\n";

	pixelBuffer->ShowInstance(temp);
	GraphicsDisplay::ShowInstance(temp);
	Check_Fpu();
}


//===================================================================
// buildDestPointer
//===================================================================
void
	Video8BitBuffered::buildDestPointer(
		int screenX,
		int screenY,
		Byte **pixel_pointer
	)
{
	Verify(valid);

	Verify(pixel_pointer != NULL);

	Verify(screenX >= 0);
	Verify(screenX < width);
	Verify(screenY >= 0);
	Verify(screenY < height);

	*pixel_pointer = pixelBuffer->Data.MapPointer +
		screenX +
		(screenY * width);
	Verify(*pixel_pointer >= pixelBuffer->Data.MapPointer);
	Verify(*pixel_pointer < &pixelBuffer->Data.MapPointer[height*width]);

	Check_Fpu();
}
#define LEFT_DEST(pointer) --pointer
#define RIGHT_DEST(pointer) ++pointer
#define UP_DEST(pointer) pointer -= width
#define DOWN_DEST(pointer) pointer += width

#define LEFT_SOURCE(pointer,map) --pointer
#define RIGHT_SOURCE(pointer,map) ++pointer
#define UP_SOURCE(pointer,map) pointer -= map->Data.Size.x
#define DOWN_SOURCE(pointer,map) pointer += map->Data.Size.x

#define LEFT_BITMAP(pointer,bits) \
	bits <<= 1; \
	if (bits == 0) { --pointer; bits=0x0001; }

#define RIGHT_BITMAP(pointer, bits) \
	bits >>= 1; \
	if (bits == 0) { ++pointer; bits=0x8000; }

#define UP_BITMAP(pointer,map) pointer -= map->Data.WidthInWords
#define DOWN_BITMAP(pointer,map) pointer += map->Data.WidthInWords

#define WRITEPIXEL(dest_pointer, operation, color) \
	switch (operation) \
	{\
	case GraphicsDisplay::Replace:\
		*dest_pointer = (Byte)color;\
		break;\
	case GraphicsDisplay::And:\
		*dest_pointer &= (Byte) color;\
		break;\
	case GraphicsDisplay::Or:\
		*dest_pointer |= (Byte) color;\
		break;\
	case GraphicsDisplay::Xor:\
		*dest_pointer ^= (Byte) color;\
		break;\
	}

//===================================================================
// MarkChangedLines
//===================================================================
//
// Inputs are in DISPLAY COORDINATES, i.e., (0,0) in top left corner!
//
void
	Video8BitBuffered::MarkChangedLines(
		int start,
		int stop
	)
{
#	if defined(DEBUG)
		Tell(
			"Video8BitBuffered::MarkChangedLines(" << start << ", " << stop <<
			")\n"
		);
#	endif
	Check(this);

	if (start > stop)
	{
#		if defined(DEBUG)
			Tell("MarkChangedLines FLIPPING\n");
#		endif
		int	temp;

		temp = start;
		start = stop;
		stop = temp;
	}

	Verify(start >= 0);
	Verify(start <= maximumY);
	Verify(stop >= 0);
	Verify(stop <= maximumY);

	++changedLine[start];

	//
	// Always include at least one line
	//
	if (stop < maximumY)
	{
		--changedLine[stop+1];
	}

	Check_Fpu();
}

//===================================================================
// DrawPoint
//===================================================================
void
	Video8BitBuffered::DrawPoint(
		int color,
		int /*bitmask*/,
		Enumeration operation,
		int x, int y
	)
{
	Check(this);
	Verify(x >= bounds.bottomLeft.x);
	Verify(x <= bounds.topRight.x);
	Verify(y >= bounds.bottomLeft.y);
	Verify(y <= bounds.topRight.y);

	Byte
		*dest_pointer;
	//---------------------------------------------------------
	// If pixelbuffer is invalid, do nothing
	//---------------------------------------------------------
	if (!valid)
	{
		Check_Fpu();
		return;
	}
	//---------------------------------------------------------
	// Convert to screen co-ordinates
	//---------------------------------------------------------
	y = maximumY - y;

#	if defined(DEBUG)
		Tell("x=" << x << ", y=" << y << "\n");
#	endif

	Verify(x >= 0);
	Verify(x < width);
	Verify(y >= 0);
	Verify(y < height);
	//---------------------------------------------------------
	// Update changedLine array
	//---------------------------------------------------------
	MarkChangedLines(y, y);
	//---------------------------------------------------------
	// We really need inverse bitmap here
	//---------------------------------------------------------
//	bitmask = ~bitmask;
	//---------------------------------------------------------
	// Create pointers
	//---------------------------------------------------------
	buildDestPointer(
		x, y,
		&dest_pointer
	);
	//---------------------------------------------------------
	// Write the point
	//---------------------------------------------------------
	WRITEPIXEL(dest_pointer, operation, color)
	Check_Fpu();
}

//===================================================================
// DrawLine
//===================================================================
void
	Video8BitBuffered::DrawLine(
		int color,
		int /*bitmask*/,
		Enumeration operation,
		int x1, int y1,
		int x2, int y2,
		Logical include_last_pixel
	)
{
#	if defined(DEBUG)
		Tell(
			"Video8BitBuffered::DrawLine(" << color <<
			", " << bitmask <<
			", " << operation <<
			", " << x1 << "," << y1 << "," << x2 << "," << y2 <<
			", " << include_last_pixel <<
			"\n"
		);
#	endif

	Check(this);

	Verify(x1 >= bounds.bottomLeft.x);
	Verify(x1 <= bounds.topRight.x);
	Verify(y1 >= bounds.bottomLeft.y);
	Verify(y1 <= bounds.topRight.y);

	Verify(x2 >= bounds.bottomLeft.x);
	Verify(x2 <= bounds.topRight.x);
	Verify(y2 >= bounds.bottomLeft.y);
	Verify(y2 <= bounds.topRight.y);

	enum
	{
		negative_delta_x = 1,
		negative_delta_y = 2,
		delta_y_greater = 0,
		delta_x_greater = 4
	};

	long
		length,
		rate,
		accumulator;

	int
		octant,
		delta_x,
		delta_y;

	Byte
		*dest_pointer;
	//---------------------------------------------------------
	// If pixelbuffer is invalid, do nothing
	//---------------------------------------------------------
	if (!valid)
	{
		Check_Fpu();
		return;
	}
	//---------------------------------------------------------
	// Route to DrawPoint if single pixel
	//---------------------------------------------------------
	if (x1 == x2 && y1 == y2)
	{
		if (include_last_pixel)
		{
			DrawPoint(color, 0 /*bitmask*/, operation, x1, y1);
		}
		Check_Fpu();
		return;
	}
	//---------------------------------------------------------
	// Convert to screen co-ordinates
	//---------------------------------------------------------
	y1 = maximumY - y1;
	y2 = maximumY - y2;
	//---------------------------------------------------------
	// Ensure that endpoints are legitimate
	//---------------------------------------------------------
	Verify(x1 >= 0);
	Verify(x1 < width);
	Verify(x2 >= 0);
	Verify(x2 < width);

	Verify(y1 >= 0);
	Verify(y1 < height);
	Verify(y2 >= 0);
	Verify(y2 < height);

#	if defined(DEBUG)
		Tell(
			"Transformed coordinates=" << x1 << "," << y1 <<
			"," << x2 << "," << y2 <<
			"\n"
		);
#	endif
	//---------------------------------------------------------
	// Update changedLine array
	//---------------------------------------------------------
	MarkChangedLines(y1, y2);
	//---------------------------------------------------------
	// We really need inverse bitmap here
	//---------------------------------------------------------
//	bitmask = ~bitmask;
	//---------------------------------------------------------
	// Determine which octant to use
	//---------------------------------------------------------
	octant = 0;

	delta_x = x2 - x1;
	if (delta_x < 0)
	{
#		if defined(DEBUG)
			Tell("negative dx\n");
#		endif
		octant |= negative_delta_x;
		delta_x = - delta_x;
	}

	delta_y = y2 - y1;
	if (delta_y < 0)
	{
#		if defined(DEBUG)
			Tell("negative dy\n");
#		endif
		octant |= negative_delta_y;
		delta_y = - delta_y;
	}

	if (delta_x > delta_y)
	{
#		if defined(DEBUG)
			Tell("dx > dy\n");
#		endif
		octant |= delta_x_greater;
	}
#	if defined(DEBUG)
		Tell(
			"dx=" << delta_x <<
			", dy=" << delta_y <<
			", octant=" << octant <<
			", color=" << color <<
			"\n"
		);
#	endif
	//---------------------------------------------------------
	// Prepare to draw line
	//---------------------------------------------------------
	buildDestPointer(
		x1, y1,
		&dest_pointer
	);

	accumulator = 1024L;			// preset accumulator to 1/2 full
	//---------------------------------------------------------
	// Draw the line!
	//---------------------------------------------------------
	switch (octant)
	{
	case delta_y_greater:
		//-------------------------------------
		// delta y greater
		// positive delta x
		// positive delta y
		//
		//     +
		//      \  &
		//       \ &
		//-------------------------------------
		length = delta_y;
		if (!include_last_pixel)
		{
			-- length;
		}

		Verify(delta_y > 0);
		rate = (delta_x*2048L)/delta_y;

#		if defined(DEBUG)
			Tell(
				"delta_y_greater, length=" << length <<
				", rate=" << rate <<
				"\n"
			);
#		endif
		Verify(rate >= 0L);
		Verify(rate <= 2048L);
		for ( ; length>0; --length)
		{
			WRITEPIXEL(dest_pointer, operation, color)
#			if defined(DEBUG)
				Tell(
					length <<
					", accum=" << accumulator <<
					", dest_pointer=" << dest_pointer <<
					"\n"
				);
#			endif
			DOWN_DEST(dest_pointer);

			accumulator += rate;
			if (accumulator > 2048L)
			{
#				if defined(DEBUG)
					Tell("OVERFLOW\n");
#				endif
				accumulator -= 2048L;
				RIGHT_DEST(dest_pointer);
			}
		}
		break;

	case delta_y_greater+negative_delta_x:
		//-------------------------------------
		// delta y greater
		// negative delta x
		// positive delta y
		//
		//     +
		//    /
		//   /
		//-------------------------------------
		length = delta_y;
		if (!include_last_pixel)
		{
			-- length;
		}
		rate = (delta_x*2048L)/delta_y;

#		if defined(DEBUG)
			Tell(
				"delta_y_greater+negative_delta_x, length=" << length <<
				", rate=" << rate <<
				"\n"
			);
#		endif
		Verify(rate >= 0L);
		Verify(rate <= 2048L);
		Verify(length >= 0);
		for ( ; length>0; --length)
		{
			WRITEPIXEL(dest_pointer, operation, color)
#			if defined(DEBUG)
				Tell(
					length <<
					", accum=" << accumulator <<
					", dest_pointer=" << dest_pointer <<
					"\n"
				);
#			endif
			DOWN_DEST(dest_pointer);

			accumulator += rate;
			if (accumulator > 2048L)
			{
#				if defined(DEBUG)
					Tell("OVERFLOW\n");
#				endif
				accumulator -= 2048L;
				LEFT_DEST(dest_pointer);
			}
		}
		break;

	case delta_y_greater+negative_delta_y:
		//-------------------------------------
		// delta y greater
		// positive delta x
		// negative delta y
		//
		//     /
		//    /
		//   +
		//-------------------------------------
		length = delta_y;
		if (!include_last_pixel)
		{
			-- length;
		}
		rate = (delta_x*2048L)/delta_y;

#		if defined(DEBUG)
			Tell(
				"delta_y_greater+negative_delta_y, length=" << length <<
				", rate=" << rate <<
				"\n"
			);
#		endif
		Verify(rate >= 0L);
		Verify(rate <= 2048L);
		Verify(length >= 0);
		for ( ; length>0; --length)
		{
			WRITEPIXEL(dest_pointer, operation, color)
#			if defined(DEBUG)
				Tell(
					length <<
					", accum=" << accumulator <<
					", dest_pointer=" << dest_pointer <<
					"\n"
				);
#			endif
			UP_DEST(dest_pointer);

			accumulator += rate;
			if (accumulator > 2048L)
			{
#				if defined(DEBUG)
					Tell("OVERFLOW\n");
#				endif
				accumulator -= 2048L;
				RIGHT_DEST(dest_pointer);
			}
		}
		break;

	case delta_y_greater+negative_delta_x+negative_delta_y:
		//-------------------------------------
		// delta y greater
		// negative delta x
		// negative delta y
		//
		//  \	  &
		//   \  &
		//   +
		//-------------------------------------
		length = delta_y;
		if (!include_last_pixel)
		{
			-- length;
		}
		rate = (delta_x*2048L)/delta_y;

#		if defined(DEBUG)
			Tell(
				"delta_y_greater+negative_delta_x+negative_delta_y, length=" <<
				length <<
				", rate=" << rate <<
				"\n"
			);
#		endif
		Verify(rate >= 0L);
		Verify(rate <= 2048L);
		Verify(length >= 0);
		for ( ; length>0; --length)
		{
			WRITEPIXEL(dest_pointer, operation, color)
#			if defined(DEBUG)
				Tell(
					length <<
					", accum=" << accumulator <<
					", dest_pointer=" << dest_pointer <<
					"\n"
				);
#			endif
			UP_DEST(dest_pointer);

			accumulator += rate;
			if (accumulator > 2048L)
			{
#				if defined(DEBUG)
					Tell("OVERFLOW\n");
#				endif
				accumulator -= 2048L;
				LEFT_DEST(dest_pointer);
			}
		}
		break;

	case delta_x_greater:
		//-------------------------------------
		// delta x greater
		// positive delta x
		// positive delta y
		//
		//     +---___
		//
		//
		//-------------------------------------
		length = delta_x;
		if (!include_last_pixel)
		{
			-- length;
		}
		rate = (delta_y*2048L)/delta_x;

#		if defined(DEBUG)
			Tell(
				"delta_x_greater, length=" << length <<
				", rate=" << rate <<
				"\n"
			);
#		endif
		Verify(rate >= 0L);
		Verify(rate <= 2048L);
		Verify(length >= 0);
		for ( ; length>0; --length)
		{
			WRITEPIXEL(dest_pointer, operation, color)
#			if defined(DEBUG)
				Tell(
					length <<
					", accum=" << accumulator <<
					", dest_pointer=" << dest_pointer <<
					"\n"
				);
#			endif
			RIGHT_DEST(dest_pointer);

			accumulator += rate;
			if (accumulator > 2048L)
			{
#				if defined(DEBUG)
					Tell("OVERFLOW\n");
#				endif
				accumulator -= 2048L;
				DOWN_DEST(dest_pointer);
			}
		}
		break;

	case delta_x_greater+negative_delta_x:
		//-------------------------------------
		// delta x greater
		// negative delta x
		// positive delta y
		//
		// ___---+
		// 
		//
		//-------------------------------------
		length = delta_x;
		if (!include_last_pixel)
		{
			-- length;
		}
		rate = (delta_y*2048L)/delta_x;

#		if defined(DEBUG)
			Tell(
				"delta_x_greater+negative_delta_x, length=" << length <<
				", rate=" << rate <<
				"\n"
			);
#		endif
		Verify(rate >= 0L);
		Verify(rate <= 2048L);
		Verify(length >= 0);
		for ( ; length>0; --length)
		{
			WRITEPIXEL(dest_pointer, operation, color)
#			if defined(DEBUG)
				Tell(
					length <<
					", accum=" << accumulator <<
					", dest_pointer=" << dest_pointer <<
					"\n"
				);
#			endif
			LEFT_DEST(dest_pointer);

			accumulator += rate;
			if (accumulator > 2048L)
			{
#				if defined(DEBUG)
					Tell("OVERFLOW\n");
#				endif
				accumulator -= 2048L;
				DOWN_DEST(dest_pointer);
			}
		}
		break;

	case delta_x_greater+negative_delta_y:
		//-------------------------------------
		// delta x greater
		// positive delta x
		// negative delta y
		//
		//       +___---
		// 
		//
		//-------------------------------------
		length = delta_x;
		if (!include_last_pixel)
		{
			-- length;
		}
		rate = (delta_y*2048L)/delta_x;

#		if defined(DEBUG)
			Tell(
				"delta_x_greater+negative_delta_y, length=" << length <<
				", rate=" << rate <<
				"\n"
			);
#		endif
		Verify(rate >= 0L);
		Verify(rate <= 2048L);
		Verify(length >= 0);
		for ( ; length>0; --length)
		{
			WRITEPIXEL(dest_pointer, operation, color)
#			if defined(DEBUG)
				Tell(
					length <<
					", accum=" << accumulator <<
					", dest_pointer=" << dest_pointer <<
					"\n"
				);
#			endif
			RIGHT_DEST(dest_pointer);

			accumulator += rate;
			if (accumulator > 2048L)
			{
#				if defined(DEBUG)
					Tell("OVERFLOW\n");
#				endif
				accumulator -= 2048L;
				UP_DEST(dest_pointer);
			}
		}
		break;

	case delta_x_greater+negative_delta_x+negative_delta_y:
		//-------------------------------------
		// delta x greater
		// negative delta x
		// negative delta y
		//
		// ---___+
		// 
		//
		//-------------------------------------
		length = delta_x;
		if (!include_last_pixel)
		{
			-- length;
		}
		rate = (delta_y*2048L)/delta_x;

#		if defined(DEBUG)
			Tell(
				"delta_x_greater+negative_delta_x+negative_delta_y, length=" <<
				length <<
				", rate=" << rate <<
				"\n"
			);
#		endif
		Verify(rate >= 0L);
		Verify(rate <= 2048L);
		Verify(length >= 0);
		for ( ; length>0; --length)
		{
			WRITEPIXEL(dest_pointer, operation, color)
#			if defined(DEBUG)
				Tell(
					length <<
					", accum=" << accumulator <<
					", dest_pointer=" << dest_pointer <<
					"\n"
				);
#			endif
			LEFT_DEST(dest_pointer);

			accumulator += rate;
			if (accumulator > 2048L)
			{
#				if defined(DEBUG)
					Tell("OVERFLOW\n");
#				endif
				accumulator -= 2048L;
				UP_DEST(dest_pointer);
			}
		}
		break;
	}        
	Check_Fpu();
}

//===================================================================
// DrawFilledRectangle
//===================================================================
void
	Video8BitBuffered::DrawFilledRectangle(
		int color,
		int /*bitmask*/,
		Enumeration operation,
		int x1, int y1,
		int x2, int y2
	)
{
#	if defined(DEBUG)
		Tell("Video8BitBuffered::DrawFilledRectangle(" <<
		color << ", " <<
		std::hex << bitmask << ", " << std::dec <<
		operation << ", " <<
		x1 << ", " <<
		y1 << ", " <<
		x2 << ", " <<
		y2 << ", " <<
		")\n");
#	endif
	Check(this);
	Verify(x1 >= bounds.bottomLeft.x);
	Verify(x1 <= bounds.topRight.x);
	Verify(y1 >= bounds.bottomLeft.y);
	Verify(y1 <= bounds.topRight.y);

	Verify(x2 >= bounds.bottomLeft.x);
	Verify(x2 <= bounds.topRight.x);
	Verify(y2 >= bounds.bottomLeft.y);
	Verify(y2 <= bounds.topRight.y);

	Byte
		*dest_pointer;
	int
		x,
		dest_fixup,
		rect_width,
		rect_height;

	//---------------------------------------------------------
	// If pixelbuffer is invalid, do nothing
	//---------------------------------------------------------
	if (!valid)
	{
		Check_Fpu();
		return;
	}
	//---------------------------------------------------------
	// Convert to screen co-ordinates
	//---------------------------------------------------------
	y1 = maximumY - y1;
	y2 = maximumY - y2;
	//---------------------------------------------------------
	// Ensure that rectangle is properly specified
	//---------------------------------------------------------
	if (x2 < x1)
	{
		int temp;

		temp = x1;
		x1 = x2;
		x2 = temp;
	}

	if (y2 < y1)
	{
		int temp;

		temp = y1;
		y1 = y2;
		y2 = temp;
	}
	//---------------------------------------------------------
	// Verify that values are legitimate
	//---------------------------------------------------------
	Verify(pixelBuffer->Data.MapPointer != NULL);

	Verify(x1 >= 0);
	Verify(x1 <= x2);
	Verify(x2 < width);

	Verify(y1 >= 0);
	Verify(y1 <= y2);
	Verify(y2 < height);
	//---------------------------------------------------------
	// Update changedLine array
	//---------------------------------------------------------
	MarkChangedLines(y1, y2);
	//---------------------------------------------------------
	// We really need inverse bitmap here
	//---------------------------------------------------------
//	bitmask = ~bitmask;
	//---------------------------------------------------------
	// Prepare to fill
	//---------------------------------------------------------
#	if defined(DEBUG)
		Tell(
			"x1=" << x1 << ", " << "y1=" << y1 << "\n" <<
			"x2=" << x2 << ", " << "y2=" << y2 << "\n" <<
			std::flush
		);
#	endif
	buildDestPointer(x1, y1, &dest_pointer);

	rect_height = y2 - y1 + 1;
	rect_width  = x2 - x1 + 1;
	dest_fixup = width - rect_width;

#	if defined(DEBUG)
		Tell(
			"rect_height=" << rect_height << "\n" <<
			"rect_width=" << rect_width << "\n" <<
			"dest_fixup=" << dest_fixup << "\n" <<
			std::flush
		);
#	endif
	//---------------------------------------------------------
	// Fill the rectangle
	//---------------------------------------------------------
	switch(operation)
	{
	case GraphicsDisplay::Replace:
		for( ; rect_height>0; --rect_height)
		{
			for(x=rect_width; x>0; --x)
			{
				*dest_pointer = (Byte) color;
				dest_pointer++;
			}
			dest_pointer += dest_fixup;
		}
		break;

	case GraphicsDisplay::And:
		for( ; rect_height>0; --rect_height)
		{
			for(x=rect_width; x>0; --x)
			{
				*dest_pointer++ &= (Byte) color;
			}
			dest_pointer += dest_fixup;
		}
		break;

	case GraphicsDisplay::Or:
		for( ; rect_height>0; --rect_height)
		{
			for(x=rect_width; x>0; --x)
			{
				*dest_pointer++ |= (Byte) color;
			}
			dest_pointer += dest_fixup;
		}
		break;

	case GraphicsDisplay::Xor:
		for( ; rect_height>0; --rect_height)
		{
			for(x=rect_width; x>0; --x)
			{
				*dest_pointer++ ^= (Byte) color;
			}
			dest_pointer += dest_fixup;
		}
		break;
	}        
	Check_Fpu();
}


void
	Video8BitBuffered::DrawText(
		int /*color*/,
		int /*bitmask*/,
		Enumeration /*operation*/,
		Logical /*opaque*/,
		int /*rotation*/,
		Enumeration /*fontNumber*/,
		Logical /*vertical*/,
		GraphicsDisplay::Justification /*justification*/,
		Rectangle2D	*/*clippingRectanglepointer*/,
		char */*stringPointer*/
	)
{
#	if defined(DEBUG)
		Tell("Video8BitBuffered::DrawText()\n");
#	endif
	Check(this);
	//---------------------------------------------------------
	// If pixelbuffer is invalid, do nothing
	//---------------------------------------------------------
	Check_Fpu();
	if (!valid)
	{
		return;
	}
}

//===================================================================
// DrawBitMap
//===================================================================
void
	Video8BitBuffered::DrawBitMap(
		int color,
		int /*bitmask*/,
		Enumeration operation,
		int rotation,
		int x, int y,
		BitMap *bitmap,
		int sLeft, int sBottom, int sRight, int sTop
	)
{
#	if defined(DEBUG)
		Tell(
			"Video8BitBuffered::DrawBitMap(<" <<
			x << ", " <<
			y << ">,<" <<
			sLeft << ", " <<
			sBottom << ", " <<
			sRight << ", " <<
			sTop << ">" <<
			")\n"
		);
#	endif
	Check(this);
	Verify(x >= bounds.bottomLeft.x);
	Verify(x <= bounds.topRight.x);
	Verify(y >= bounds.bottomLeft.y);
	Verify(y <= bounds.topRight.y);

	int
		map_width,
		map_height,
		map_max_y,
		bits,
		bit_test,
		first_bit_test;

	Word
		*source_pointer_begin,
		*source_pointer;
	Byte
		*dest_pointer_begin,
		*dest_pointer;

	//---------------------------------------------------------
	// If pixelbuffer is invalid, do nothing
	//---------------------------------------------------------
	if (!valid)
	{
		Check_Fpu();
		return;
	}
	//---------------------------------------------------------
	// Ensure that source rectangle is properly specified
	//---------------------------------------------------------
	Verify(bitmap != NULL);

	Verify(sLeft >= 0);
	Verify(sLeft <= sRight);
	Verify(sRight < bitmap->Data.Size.x);

	Verify(sBottom >= 0);
	Verify(sBottom <= sTop);
	Verify(sTop < bitmap->Data.Size.y);
	//---------------------------------------------------------
	// Convert to screen co-ordinates
	//---------------------------------------------------------
	y = maximumY - y;

	map_max_y = bitmap->Data.Size.y-1; 
	sTop    = map_max_y - sTop;
	sBottom = map_max_y - sBottom;

	map_width = sRight - sLeft + 1;
	map_height = sBottom - sTop + 1;

#	if defined(DEBUG)
		Tell("x=" << x << ", y=" << y << "\n");
		Tell("sTop=" << sTop << ", sBottom=" << sBottom << "\n");
		Tell("map_width=" << map_width << ", map_height=" << map_height << "\n");
#	endif

	Verify(map_width > 0);
	Verify(map_width <= bitmap->Data.Size.x);
	Verify(map_height > 0);
	Verify(map_height <= bitmap->Data.Size.y);

	Verify(x >= 0);
	Verify(x < width);
	Verify(y >= 0);
	Verify(y < height);

	//---------------------------------------------------------
	// We really need inverse bitmap here
	//---------------------------------------------------------
//	bitmask = ~bitmask;
	//---------------------------------------------------------
	// Prepare to draw bitmap
	//---------------------------------------------------------
	Verify(pixelBuffer->Data.MapPointer != NULL);

	source_pointer_begin =
		bitmap->Data.MapPointer +
		(sLeft >> 4) +
		(sBottom * bitmap->Data.WidthInWords);

	first_bit_test = 1 << (15-(sLeft & 15));

	buildDestPointer(
		x, y,
		&dest_pointer_begin
	);

	switch (rotation)
	{
	default:
		//--------------------------------------------
		// transparent bitmap, zero degrees
		//   .-----.
		//   |     |
		//   |     |
		//   Y     |
		//   #X----.
		//--------------------------------------------
#		if defined(DEBUG)
			Tell("zero: xp=" << (x+map_width-1) << ", yp=" << (y-map_height+1) << "\n");
#		endif
		Verify(x+map_width-1 >= 0);
		Verify(x+map_width-1 < width);
		Verify(y-map_height+1 >= 0);
		Verify(y-map_height+1 < height);

		MarkChangedLines(y-map_height+1, y);

		for(y=map_height; y>0; --y)
		{
			source_pointer = source_pointer_begin;
			dest_pointer = dest_pointer_begin;

			UP_BITMAP(source_pointer_begin, bitmap);
			UP_DEST(dest_pointer_begin);

			bit_test = first_bit_test;
			bits = *source_pointer++;
			for(x=map_width; x>0; --x,bit_test>>=1)
			{
				Verify(dest_pointer >= pixelBuffer->Data.MapPointer);
				Verify(dest_pointer < pixelBuffer->Data.MapPointer+
					(width*height));

				if (bit_test == 0)
				{
					bit_test = 0x8000;
					bits = *source_pointer++;
				}

				if (bits & bit_test)
				{
					WRITEPIXEL(dest_pointer, operation, color)
				}
				RIGHT_DEST(dest_pointer);
			}
		}
		break;

	case 90:
		//--------------------------------------------
		// Transparent bitmap, 90 degrees
		//   #Y----.
		//   X     |
		//   |     |
		//   |     |
		//   .-----.
		//--------------------------------------------
#		if defined(DEBUG)
			Tell("90 xp=" << (x+map_height) << ", yp=" << (y+map_width) << "\n");
#		endif
		Verify(x+map_height >= 0);
		Verify(x+map_height < width);
		Verify(y+map_width >= 0);
		Verify(y+map_width < height);

		MarkChangedLines(y, y+map_width);

		for(y=map_height; y>0; --y)
		{
			source_pointer = source_pointer_begin;
			dest_pointer = dest_pointer_begin;

			UP_BITMAP(source_pointer_begin, bitmap);
			RIGHT_DEST(dest_pointer_begin);
															 
			bit_test = first_bit_test;
			bits = *source_pointer++;

			for(x=map_width; x>0; --x,bit_test>>=1)
			{
				Verify(dest_pointer >= pixelBuffer->Data.MapPointer);
				Verify(dest_pointer < pixelBuffer->Data.MapPointer+
					(width*height));

				if (bit_test == 0)
				{
					bit_test = 0x8000;
					bits = *source_pointer++;
				}

				if (bits & bit_test)
				{
					WRITEPIXEL(dest_pointer, operation, color)
				}
				DOWN_DEST(dest_pointer);
			}
		}
		break;

	case 180:
		//--------------------------------------------
		// Transparent bitmap, 180 degrees
		//   .----X#
		//   |     Y
		//   |     |
		//   |     |
		//   .-----.
		//--------------------------------------------
#		if defined(DEBUG)
			Tell("xp=" << (x-map_width+1) << ", yp=" << (y+map_height) << "\n");
#		endif
		Verify(x-map_width+1 >= 0);
		Verify(x-map_width+1 < width);
		Verify(y+map_height >= 0);
		Verify(y+map_height < height);

		MarkChangedLines(y, y+map_height);

		for(y=map_height; y>0; --y)
		{
			source_pointer = source_pointer_begin;
			dest_pointer = dest_pointer_begin;

			UP_BITMAP(source_pointer_begin, bitmap);
			DOWN_DEST(dest_pointer_begin);

			bit_test = first_bit_test;
			bits = *source_pointer++;

			for(x=map_width; x>0; --x,bit_test>>=1)
			{
				Verify(dest_pointer >= pixelBuffer->Data.MapPointer);
				Verify(dest_pointer < pixelBuffer->Data.MapPointer+
					(width*height));

				if (bit_test == 0)
				{
					bit_test = 0x8000;
					bits = *source_pointer++;
				}

				if (bits & bit_test)
				{
					WRITEPIXEL(dest_pointer, operation, color)
				}
				LEFT_DEST(dest_pointer);
			}
		}
		break;

	case 270:
		//--------------------------------------------
		// Transparent bitmap, 270 degrees
		//   .-----.
		//   |     |
		//   |     X
		//   |     |
		//   .--Y--#
		//--------------------------------------------
#		if defined(DEBUG)
			Tell("xp=" << (x-map_height) << ", yp=" << (y-(map_width-1)) << "\n");
#		endif

		Verify(x-map_height >= 0);
		Verify(x-map_height < width);
		Verify(y-(map_width-1) >= 0);
		Verify(y-(map_width-1) < height);

		MarkChangedLines(y-(map_width-1), y);

		for(y=map_height; y>0; --y)
		{
			source_pointer = source_pointer_begin;
			dest_pointer = dest_pointer_begin;

			UP_BITMAP(source_pointer_begin, bitmap);
			LEFT_DEST(dest_pointer_begin);

			bit_test = first_bit_test;
			bits = *source_pointer++;

			for(x=map_width; x>0; --x,bit_test>>=1)
			{
				Verify(dest_pointer >= pixelBuffer->Data.MapPointer);
				Verify(dest_pointer < pixelBuffer->Data.MapPointer+
					(width*height));

				if (bit_test == 0)
				{
					bit_test = 0x8000;
					bits = *source_pointer++;
				}

				if (bits & bit_test)
				{
					WRITEPIXEL(dest_pointer, operation, color)
				}
				UP_DEST(dest_pointer);
			}
		}
		break;
	}
	Check_Fpu();
}

//===================================================================
// DrawBitMapOpaque
//===================================================================
void
	Video8BitBuffered::DrawBitMapOpaque(
		int foreground,
		int background,
		int /*bitmask*/,
		Enumeration operation,
		int rotation,
		int x, int y,
		BitMap *bitmap,
		int sLeft, int sBottom, int sRight, int sTop
	)
{
#	if defined(DEBUG)
		Tell(
			"Video8BitBuffered::DrawBitMapOpaque(<" <<
			x << ", " <<
			y << ">,<" <<
			sLeft << ", " <<
			sBottom << ", " <<
			sRight << ", " <<
			sTop << ">" <<
			")\n"
		);
#	endif
	Check(this);
	Verify(x >= bounds.bottomLeft.x);
	Verify(x <= bounds.topRight.x);
	Verify(y >= bounds.bottomLeft.y);
	Verify(y <= bounds.topRight.y);

	int
		map_width,
		map_height,
      map_max_y,
		bits,
		bit_test,
		first_bit_test;

	Word
		*source_pointer_begin,
		*source_pointer;
	Byte
		*dest_pointer_begin,
		*dest_pointer;
	Byte
		color;

	//---------------------------------------------------------
	// If pixelbuffer is invalid, do nothing
	//---------------------------------------------------------
	if (!valid)
	{
		Check_Fpu();
		return;
	}
	//---------------------------------------------------------
	// Ensure that source rectangle is properly specified
	//---------------------------------------------------------
	Verify(bitmap != NULL);

	Verify(sLeft >= 0);
	Verify(sLeft <= sRight);
	Verify(sRight < bitmap->Data.Size.x);

	Verify(sBottom >= 0);
	Verify(sBottom <= sTop);
	Verify(sTop < bitmap->Data.Size.y);
	//---------------------------------------------------------
	// Convert to screen co-ordinates
	//---------------------------------------------------------
	y = maximumY - y;

	map_max_y = bitmap->Data.Size.y-1; 
	sTop    = map_max_y - sTop;
	sBottom = map_max_y - sBottom;

	map_width = sRight - sLeft + 1;
	map_height = sBottom - sTop + 1;

#	if defined(DEBUG)
		Tell("x=" << x << ", y=" << y << "\n");
		Tell("sTop=" << sTop << ", sBottom=" << sBottom << "\n");
		Tell("map_width=" << map_width << ", map_height=" << map_height << "\n");
#	endif

	Verify(map_width > 0);
	Verify(map_width <= bitmap->Data.Size.x);
	Verify(map_height > 0);
	Verify(map_height <= bitmap->Data.Size.y);

	Verify(x >= 0);
	Verify(x < width);
	Verify(y >= 0);
	Verify(y < height);

	//---------------------------------------------------------
	// We really need inverse bitmap here
	//---------------------------------------------------------
//	bitmask = ~bitmask;
	//---------------------------------------------------------
	// Prepare to draw bitmap
	//---------------------------------------------------------
	Verify(pixelBuffer->Data.MapPointer != NULL);

	source_pointer_begin =
		bitmap->Data.MapPointer +
		(sLeft >> 4) +
		(sBottom * bitmap->Data.WidthInWords);

	first_bit_test = 1 << (15-(sLeft & 15));

	buildDestPointer(
		x, y,
		&dest_pointer_begin
	);

	switch (rotation)
	{
	default:
		//--------------------------------------------
		// opaque bitmap, zero degrees
		//   .-----.
		//   |     |
		//   |     |
		//   Y     |
		//   #X----.
		//--------------------------------------------
#		if defined(DEBUG)
			Tell("zero: xp=" << (x+map_width) << ", yp=" << (y-map_height+1) << "\n");
#		endif
		Verify(x+map_width >= 0);
		Verify(x+map_width <= width);				// HACK? <, or <=?
		Verify(y-map_height+1 >= 0);
		Verify(y-map_height+1 < height);

		MarkChangedLines(y-map_height+1, y);

		for(y=map_height; y>0; --y)
		{
			source_pointer = source_pointer_begin;
			dest_pointer = dest_pointer_begin;

			UP_BITMAP(source_pointer_begin, bitmap);
			UP_DEST(dest_pointer_begin);

			bit_test = first_bit_test;
			bits = *source_pointer++;

			for(x=map_width; x>0; --x,bit_test>>=1)
			{
				if (bit_test == 0)
				{
					bit_test = 0x8000;
					bits = *source_pointer++;
				}

				if (bits & bit_test)
				{
					color = (Byte) foreground; 
				}
				else
				{
					color = (Byte) background; 
				}
				WRITEPIXEL(dest_pointer, operation, color)
				RIGHT_DEST(dest_pointer);
			}
		}
		break;

	case 90:
		//--------------------------------------------
		// opaque bitmap, 90 degrees
		//   #Y----.
		//   X     |
		//   |     |
		//   |     |
		//   .-----.
		//--------------------------------------------
#		if defined(DEBUG)
			Tell("90 xp=" << (x+map_height) << ", yp=" << (y+map_width) << "\n");
#		endif
		Verify(x+map_height >= 0);
		Verify(x+map_height < width);
		Verify(y+map_width >= 0);
		Verify(y+map_width < height);

		MarkChangedLines(y, y+map_width);

		for(y=map_height; y>0; --y)
		{
			source_pointer = source_pointer_begin;
			dest_pointer = dest_pointer_begin;

			UP_BITMAP(source_pointer_begin, bitmap);
			RIGHT_DEST(dest_pointer_begin);
															 
			bit_test = first_bit_test;
			bits = *source_pointer++;

			for(x=map_width; x>0; --x,bit_test>>=1)
			{
				if (bit_test == 0)
				{
					bit_test = 0x8000;
					bits = *source_pointer++;
				}

				if (bits & bit_test)
				{
					color = (Byte) foreground; 
				}
				else
				{
					color = (Byte) background; 
				}
				WRITEPIXEL(dest_pointer, operation, color)
				DOWN_DEST(dest_pointer);
			}
		}
		break;

	case 180:
		//--------------------------------------------
		// opaque bitmap, 180 degrees
		//   .----X#
		//   |     Y
		//   |     |
		//   |     |
		//   .-----.
		//--------------------------------------------
#		if defined(DEBUG)
			Tell("xp=" << (x-map_width+1) << ", yp=" << (y+map_height) << "\n");
#		endif
		Verify(x-map_width+1 >= 0);
		Verify(x-map_width+1 < width);
		Verify(y+map_height >= 0);
		Verify(y+map_height < height);

		MarkChangedLines(y, y+map_height);

		for(y=map_height; y>0; --y)
		{
			source_pointer = source_pointer_begin;
			dest_pointer = dest_pointer_begin;

			UP_BITMAP(source_pointer_begin, bitmap);
			DOWN_DEST(dest_pointer_begin);

			bit_test = first_bit_test;
			bits = *source_pointer++;

			for(x=map_width; x>0; --x,bit_test>>=1)
			{
				if (bit_test == 0)
				{
					bit_test = 0x8000;
					bits = *source_pointer++;
				}

				if (bits & bit_test)
				{
					color = (Byte) foreground; 
				}
				else
				{
					color = (Byte) background; 
				}
				WRITEPIXEL(dest_pointer, operation, color)
				LEFT_DEST(dest_pointer);
			}
		}
		break;

	case 270:
		//--------------------------------------------
		// opaque bitmap, 270 degrees
		//   .-----.
		//   |     |
		//   |     X
		//   |     |
		//   .--Y--#
		//--------------------------------------------
#		if defined(DEBUG)
			Tell("xp=" << (x-map_height+1) << ", yp=" << (y-(map_width-1)) << "\n");
#		endif

		Verify(x-map_height >= 0);
		Verify(x-map_height < width);
		Verify(y-(map_width-1) >= 0);
		Verify(y-(map_width-1) < height);

		MarkChangedLines(y-(map_width-1), y);

		for(y=map_height; y>0; --y)
		{
			source_pointer = source_pointer_begin;
			dest_pointer = dest_pointer_begin;

			UP_BITMAP(source_pointer_begin, bitmap);
			LEFT_DEST(dest_pointer_begin);

			bit_test = first_bit_test;
			bits = *source_pointer++;

			for(x=map_width; x>0; --x,bit_test>>=1)
			{
				Verify(dest_pointer >= pixelBuffer->Data.MapPointer);
				Verify(dest_pointer < pixelBuffer->Data.MapPointer+
					(width*height));

				if (bit_test == 0)
				{
					bit_test = 0x8000;
					bits = *source_pointer++;
				}

				if (bits & bit_test)
				{
					color = (Byte) foreground; 
				}
				else
				{
					color = (Byte) background; 
				}
				WRITEPIXEL(dest_pointer, operation, color)
				UP_DEST(dest_pointer);
			}
		}
		break;
	}
	Check_Fpu();
}

//===================================================================
// DrawPixelMap8
//===================================================================
void
	Video8BitBuffered::DrawPixelMap8(
		int */*translation_table*/,
		int /*bitmask*/,
		Enumeration operation,
		Logical opaque,
		int rotation,
		int x, int y,
		PixelMap8	*pixelmap,
		int sLeft, int sBottom, int sRight, int sTop
	)
{
#	if defined(DEBUG)
		Tell(
			"Video8BitBuffered::DrawPixelMap8(<" <<
			x << ", " <<
			y << ">,<" <<
			sLeft << ", " <<
			sBottom << ", " <<
			sRight << ", " <<
			sTop << ">" <<
			")\n"
		);
#	endif
	Check(this);
	Verify(x >= bounds.bottomLeft.x);
	Verify(x <= bounds.topRight.x);
	Verify(y >= bounds.bottomLeft.y);
	Verify(y <= bounds.topRight.y);

	int
		map_width,
		map_height,
		map_max_y;

	Byte
		color,
		*source_pointer_begin,
		*source_pointer,
		*dest_pointer_begin,
		*dest_pointer;

	//---------------------------------------------------------
	// If pixelbuffer is invalid, do nothing
	//---------------------------------------------------------
	if (!valid)
	{
		Check_Fpu();
		return;
	}
	//---------------------------------------------------------
	// Ensure that source rectangle is properly specified
	//---------------------------------------------------------
	Verify(pixelmap != NULL);

	Verify(sLeft >= 0);
	Verify(sLeft <= sRight);
	Verify(sRight < pixelmap->Data.Size.x);

	Verify(sBottom >= 0);
	Verify(sBottom <= sTop);
	Verify(sTop < pixelmap->Data.Size.y);
	//---------------------------------------------------------
	// Convert to screen co-ordinates
	//---------------------------------------------------------
	y = maximumY - y;

	map_max_y = pixelmap->Data.Size.y-1; 
	sTop    = map_max_y - sTop;
	sBottom = map_max_y - sBottom;

	map_width = sRight - sLeft + 1;
	map_height = sBottom - sTop + 1;

#	if defined(DEBUG)
		Tell("x=" << x << ", y=" << y << "\n");
		Tell("sTop=" << sTop << ", sBottom=" << sBottom << "\n");
		Tell("map_width=" << map_width << ", map_height=" << map_height << "\n");
#	endif

	Verify(map_width > 0);
	Verify(map_width <= pixelmap->Data.Size.x);
	Verify(map_height > 0);
	Verify(map_height <= pixelmap->Data.Size.y);

	Verify(x >= 0);
	Verify(x < width);
	Verify(y >= 0);
	Verify(y < height);

	//---------------------------------------------------------
	// We really need inverse bitmap here
	//---------------------------------------------------------
//	bitmask = ~bitmask;
	//---------------------------------------------------------
	// Prepare to draw bitmap
	//---------------------------------------------------------
	Verify(pixelBuffer->Data.MapPointer != NULL);

	source_pointer_begin =
		pixelmap->Data.MapPointer +
		sLeft +
		(sBottom * pixelmap->Data.Size.x);

	buildDestPointer(
		x, y,
		&dest_pointer_begin
	);

	if (opaque)
	{
		switch (rotation)
		{
		default:
			//--------------------------------------------
			// Opaque pixelmap, zero degrees
			//   .-----.
			//   |     |
			//   |     |
			//   Y     |
			//   #X----.
			//--------------------------------------------
#			if defined(DEBUG)
				Tell(
					"Opaque zero: xp=" << (x+map_width) <<
					", yp=" << (y-map_height+1) << "\n"
				);
#			endif
			Verify(x+map_width >= 0);
			Verify(x+map_width < width);
			Verify(y-map_height+1 >= 0);
			Verify(y-map_height+1 < height);

			MarkChangedLines(y-map_height+1, y);

			for(y=map_height; y>0; --y)
			{
				source_pointer = source_pointer_begin;
				dest_pointer = dest_pointer_begin;

				UP_SOURCE(source_pointer_begin, pixelmap);
				UP_DEST(dest_pointer_begin);

				for(x=map_width; x>0; --x)
				{
					color = *source_pointer++;		//SOURCE_RIGHT
					WRITEPIXEL(dest_pointer, operation, color)
					RIGHT_DEST(dest_pointer);
				}
			}
			break;

		case 90:
			//--------------------------------------------
			// Opaque pixelmap, 90 degrees
			//   #Y----.
			//   X     |
			//   |     |
			//   |     |
			//   .-----.
			//--------------------------------------------
#			if defined(DEBUG)
				Tell(
					"Opaque 90: xp=" << (x+map_height) <<
					", yp=" << (y+map_width) << "\n"
				);
#			endif
			Verify(x+map_height >= 0);
			Verify(x+map_height < width);
			Verify(y+map_width >= 0);
			Verify(y+map_width < height);

			MarkChangedLines(y, y+map_width);

			for(y=map_height; y>0; --y)
			{
				source_pointer = source_pointer_begin;
				dest_pointer = dest_pointer_begin;

				UP_SOURCE(source_pointer_begin, pixelmap);
				RIGHT_DEST(dest_pointer_begin);
															 
				for(x=map_width; x>0; --x)
				{
					color = *source_pointer++;		//SOURCE_RIGHT
					WRITEPIXEL(dest_pointer, operation, color)
					DOWN_DEST(dest_pointer);
				}
			}
			break;

		case 180:
			//--------------------------------------------
			// Opaque pixelmap, 180 degrees
			//   .----X#
			//   |     Y
			//   |     |
			//   |     |
			//   .-----.
			//--------------------------------------------
#			if defined(DEBUG)
				Tell(
					"Opaque 180: xp=" << (x-map_width+1) <<
					", yp=" << (y+map_height) << "\n"
				);
#			endif
			Verify(x-map_width+1 >= 0);
			Verify(x-map_width+1 < width);
			Verify(y+map_height >= 0);
			Verify(y+map_height < height);

			MarkChangedLines(y, y+map_height);

			for(y=map_height; y>0; --y)
			{
				source_pointer = source_pointer_begin;
				dest_pointer = dest_pointer_begin;

				UP_SOURCE(source_pointer_begin, pixelmap);
				DOWN_DEST(dest_pointer_begin);

				for(x=map_width; x>0; --x)
				{
					color = *source_pointer++;		//SOURCE_RIGHT
					WRITEPIXEL(dest_pointer, operation, color)
					LEFT_DEST(dest_pointer);
				}
			}
			break;

		case 270:
			//--------------------------------------------
			// Opaque pixelmap, 270 degrees
			//   .-----.
			//   |     |
			//   |     X
			//   |     |
			//   .--Y--#
			//--------------------------------------------
#			if defined(DEBUG)
				Tell("Opaque 270: x=" << x << ", y=" << y << "\n");
				Tell("xp=" << x-map_height << ", yp=" << y-(map_width-1) << "\n");
#			endif
			Verify(x-map_height >= 0);
			Verify(x-map_height < width);
			Verify(y-(map_width-1) >= 0);
			Verify(y-(map_width-1) < height);

			MarkChangedLines(y-(map_width-1), y);

			for(y=map_height ; y>0; --y)
			{
				source_pointer = source_pointer_begin;
				dest_pointer = dest_pointer_begin;

				UP_SOURCE(source_pointer_begin, pixelmap);
				LEFT_DEST(dest_pointer_begin);

				for(x=map_width; x>0; --x)
				{
					Verify(dest_pointer >= pixelBuffer->Data.MapPointer);
					Verify(dest_pointer < pixelBuffer->Data.MapPointer+
						(width*height));

					color = *source_pointer++;		//SOURCE_RIGHT
					WRITEPIXEL(dest_pointer, operation, color)
					UP_DEST(dest_pointer);
				}
			}
			break;
		}
	}
	else
	{
		switch (rotation)
		{
		default:
			//--------------------------------------------
			// Transparent pixelmap, zero degrees
			//   .-----.
			//   |     |
			//   |     |
			//   Y     |
			//   #X----.
			//--------------------------------------------
#			if defined(DEBUG)
				Tell(
					"transparent zero: xp=" << (x+map_width) <<
					", yp=" << (y-map_height+1) << "\n"
				);
#			endif
			Verify(x+map_width >= 0);
			Verify(x+map_width < width);
			Verify(y-map_height+1 >= 0);
			Verify(y-map_height+1 < height);

			MarkChangedLines(y-map_height+1, y);

			for(y=map_height; y>0; --y)
			{
				source_pointer = source_pointer_begin;
				dest_pointer = dest_pointer_begin;

				UP_SOURCE(source_pointer_begin, pixelmap);
				UP_DEST(dest_pointer_begin);

				for(x=map_width; x>0; --x)
				{
					color = *source_pointer++;		//SOURCE_RIGHT
					if (color)
					{
						WRITEPIXEL(dest_pointer, operation, color)
					}
					RIGHT_DEST(dest_pointer);
				}
			}
			break;

		case 90:
			//--------------------------------------------
			// Transparent pixelmap, 90 degrees
			//   #Y----.
			//   X     |
			//   |     |
			//   |     |
			//   .-----.
			//--------------------------------------------
#			if defined(DEBUG)
				Tell(
					"transparent 90: xp=" << (x+map_height) <<
					", yp=" << (y+map_width) << "\n"
				);
#			endif
			Verify(x+map_height >= 0);
			Verify(x+map_height < width);
			Verify(y+map_width >= 0);
			Verify(y+map_width < height);

			MarkChangedLines(y, y+map_width);

			for(y=map_height; y>0; --y)
			{
				source_pointer = source_pointer_begin;
				dest_pointer = dest_pointer_begin;

				UP_SOURCE(source_pointer_begin, pixelmap);
				RIGHT_DEST(dest_pointer_begin);
															 
				for(x=map_width; x>0; --x)
				{
					color = *source_pointer++;		//SOURCE_RIGHT
					if (color)
					{
						WRITEPIXEL(dest_pointer, operation, color)
					}
					DOWN_DEST(dest_pointer);
				}
			}
			break;

		case 180:
			//--------------------------------------------
			// Transparent pixelmap, 180 degrees
			//   .----X#
			//   |     Y
			//   |     |
			//   |     |
			//   .-----.
			//--------------------------------------------
#			if defined(DEBUG)
				Tell(
					"transparent 180: xp=" << (x-map_width+1) <<
					", yp=" << (y+map_height) << "\n"
				);
#			endif
			Verify(x-map_width+1 >= 0);
			Verify(x-map_width+1 < width);
			Verify(y+map_height >= 0);
			Verify(y+map_height < height);

			MarkChangedLines(y, y+map_height);

			for(y=map_height; y>0; --y)
			{
				source_pointer = source_pointer_begin;
				dest_pointer = dest_pointer_begin;

				UP_SOURCE(source_pointer_begin, pixelmap);
				DOWN_DEST(dest_pointer_begin);

				for(x=map_width; x>0; --x)
				{
					color = *source_pointer++;		//SOURCE_RIGHT
					if (color)
					{
						WRITEPIXEL(dest_pointer, operation, color)
					}
					LEFT_DEST(dest_pointer);
				}
			}
			break;

		case 270:
			//--------------------------------------------
			// Transparent pixelmap, 270 degrees
			//   .-----.
			//   |     |
			//   |     X
			//   |     |
			//   .--Y--#
			//--------------------------------------------
#			if defined(DEBUG)
				Tell("transparent 270: x=" << x << ", y=" << y << "\n");
				Tell("xp=" << x-map_height << ", yp=" << y-(map_width-1) << "\n");
#			endif
			Verify(x-map_height >= 0);
			Verify(x-map_height < width);
			Verify(y-(map_width-1) >= 0);
			Verify(y-(map_width-1) < height);

			MarkChangedLines(y-(map_width-1), y);

			for(y=map_height ; y>0; --y)
			{
				source_pointer = source_pointer_begin;
				dest_pointer = dest_pointer_begin;

				UP_SOURCE(source_pointer_begin, pixelmap);
				LEFT_DEST(dest_pointer_begin);

				for(x=map_width; x>0; --x)
				{
					Verify(dest_pointer >= pixelBuffer->Data.MapPointer);
					Verify(dest_pointer < pixelBuffer->Data.MapPointer+
						(width*height));

					color = *source_pointer++;		//SOURCE_RIGHT
					if (color)
					{
						WRITEPIXEL(dest_pointer, operation, color)
					}
					UP_DEST(dest_pointer);
				}
			}
			break;
		}
	}
	Check_Fpu();
}

//===================================================================
// DrawPixelMap8SingleColor
//===================================================================
void
	Video8BitBuffered::DrawPixelMap8SingleColor(
		int color,
		int /*bitmask*/,
		Enumeration operation,
		int rotation,
		int x, int y,
		PixelMap8	*pixelmap,
		int sLeft, int sBottom, int sRight, int sTop
	)
{
#	if defined(DEBUG)
		Tell(
			"Video8BitBuffered::DrawPixelMap8SingleColor(<" <<
			x << ", " <<
			y << ">,<" <<
			sLeft << ", " <<
			sBottom << ", " <<
			sRight << ", " <<
			sTop << ">" <<
			")\n"
		);
#	endif
	Check(this);
	Verify(x >= bounds.bottomLeft.x);
	Verify(x <= bounds.topRight.x);
	Verify(y >= bounds.bottomLeft.y);
	Verify(y <= bounds.topRight.y);

	int
		map_width,
		map_height,
		map_max_y;

	Byte
		source_data,
		*source_pointer_begin,
		*source_pointer,
		*dest_pointer_begin,
		*dest_pointer;

	//---------------------------------------------------------
	// If pixelbuffer is invalid, do nothing
	//---------------------------------------------------------
	if (!valid)
	{
		Check_Fpu();
		return;
	}
	//---------------------------------------------------------
	// Ensure that source rectangle is properly specified
	//---------------------------------------------------------
	Verify(pixelmap != NULL);

	Verify(sLeft >= 0);
	Verify(sLeft <= sRight);
	Verify(sRight < pixelmap->Data.Size.x);

	Verify(sBottom >= 0);
	Verify(sBottom <= sTop);
	Verify(sTop < pixelmap->Data.Size.y);
	//---------------------------------------------------------
	// Convert to screen co-ordinates
	//---------------------------------------------------------
	y = maximumY - y;

	map_max_y = pixelmap->Data.Size.y-1; 
	sTop    = map_max_y - sTop;
	sBottom = map_max_y - sBottom;

	map_width = sRight - sLeft + 1;
	map_height = sBottom - sTop + 1;

#	if defined(DEBUG)
		Tell("x=" << x << ", y=" << y << "\n");
		Tell("sTop=" << sTop << ", sBottom=" << sBottom << "\n");
		Tell("map_width=" << map_width << ", map_height=" << map_height << "\n");
#	endif

	Verify(map_width > 0);
	Verify(map_width <= pixelmap->Data.Size.x);
	Verify(map_height > 0);
	Verify(map_height <= pixelmap->Data.Size.y);

	Verify(x >= 0);
	Verify(x < width);
	Verify(y >= 0);
	Verify(y < height);

	//---------------------------------------------------------
	// We really need inverse bitmap here
	//---------------------------------------------------------
//	bitmask = ~bitmask;
	//---------------------------------------------------------
	// Prepare to draw bitmap
	//---------------------------------------------------------
	Verify(pixelBuffer->Data.MapPointer != NULL);

	source_pointer_begin =
		pixelmap->Data.MapPointer +
		sLeft +
		(sBottom * pixelmap->Data.Size.x);

	buildDestPointer(
		x, y,
		&dest_pointer_begin
	);

	{
		switch (rotation)
		{
		default:
			//--------------------------------------------
			// Single-color pixelmap, zero degrees
			//   .-----.
			//   |     |
			//   |     |
			//   Y     |
			//   #X----.
			//--------------------------------------------
#			if defined(DEBUG)
				Tell(
					"Single-color zero: xp=" << (x+map_width) <<
					", yp=" << (y-map_height+1) << "\n"
				);
#			endif
			Verify(x+map_width >= 0);
			Verify(x+map_width < width);
			Verify(y-map_height+1 >= 0);
			Verify(y-map_height+1 < height);

			MarkChangedLines(y-map_height+1, y);

			for(y=map_height; y>0; --y)
			{
				source_pointer = source_pointer_begin;
				dest_pointer = dest_pointer_begin;

				UP_SOURCE(source_pointer_begin, pixelmap);
				UP_DEST(dest_pointer_begin);

				for(x=map_width; x>0; --x)
				{
					source_data = *source_pointer++;		//SOURCE_RIGHT
					if (source_data)
					{
						WRITEPIXEL(dest_pointer, operation, color)
					}
					RIGHT_DEST(dest_pointer);
				}
			}
			break;

		case 90:
			//--------------------------------------------
			// Single-color pixelmap, 90 degrees
			//   #Y----.
			//   X     |
			//   |     |
			//   |     |
			//   .-----.
			//--------------------------------------------
#			if defined(DEBUG)
				Tell(
					"Single-color 90: xp=" << (x+map_height) <<
					", yp=" << (y+map_width) << "\n"
				);
#			endif
			Verify(x+map_height >= 0);
			Verify(x+map_height < width);
			Verify(y+map_width >= 0);
			Verify(y+map_width < height);

			MarkChangedLines(y, y+map_width);

			for(y=map_height; y>0; --y)
			{
				source_pointer = source_pointer_begin;
				dest_pointer = dest_pointer_begin;

				UP_SOURCE(source_pointer_begin, pixelmap);
				RIGHT_DEST(dest_pointer_begin);
															 
				for(x=map_width; x>0; --x)
				{
					source_data = *source_pointer++;		//SOURCE_RIGHT
					if (source_data)
					{
						WRITEPIXEL(dest_pointer, operation, color)
					}
					DOWN_DEST(dest_pointer);
				}
			}
			break;

		case 180:
			//--------------------------------------------
			// Single-color pixelmap, 180 degrees
			//   .----X#
			//   |     Y
			//   |     |
			//   |     |
			//   .-----.
			//--------------------------------------------
#			if defined(DEBUG)
				Tell(
					"Single-color 180: xp=" << (x-map_width+1) <<
					", yp=" << (y+map_height) << "\n"
				);
#			endif
			Verify(x-map_width+1 >= 0);
			Verify(x-map_width+1 < width);
			Verify(y+map_height >= 0);
			Verify(y+map_height < height);

			MarkChangedLines(y, y+map_height);

			for(y=map_height; y>0; --y)
			{
				source_pointer = source_pointer_begin;
				dest_pointer = dest_pointer_begin;

				UP_SOURCE(source_pointer_begin, pixelmap);
				DOWN_DEST(dest_pointer_begin);

				for(x=map_width; x>0; --x)
				{
					source_data = *source_pointer++;		//SOURCE_RIGHT
					if (source_data)
					{
						WRITEPIXEL(dest_pointer, operation, color)
					}
					LEFT_DEST(dest_pointer);
				}
			}
			break;

		case 270:
			//--------------------------------------------
			// Single-color pixelmap, 270 degrees
			//   .-----.
			//   |     |
			//   |     X
			//   |     |
			//   .--Y--#
			//--------------------------------------------
#			if defined(DEBUG)
				Tell("Single-color 270: x=" << x << ", y=" << y << "\n");
				Tell("xp=" << x-map_height << ", yp=" << y-map_width << "\n");
#			endif
			Verify(x-map_height >= 0);
			Verify(x-map_height < width);
			Verify(y-map_width >= 0);
			Verify(y-map_width < height);

			MarkChangedLines(y-map_width, y);

			for(y=map_height ; y>0; --y)
			{
				source_pointer = source_pointer_begin;
				dest_pointer = dest_pointer_begin;

				UP_SOURCE(source_pointer_begin, pixelmap);
				LEFT_DEST(dest_pointer_begin);

				for(x=map_width; x>0; --x)
				{
					Verify(dest_pointer >= pixelBuffer->Data.MapPointer);
					Verify(dest_pointer < pixelBuffer->Data.MapPointer+
						(width*height));

					source_data = *source_pointer++;		//SOURCE_RIGHT
					if (source_data)
					{
						WRITEPIXEL(dest_pointer, operation, color)
					}
					UP_DEST(dest_pointer);
				}
			}
			break;
		}
	}
	Check_Fpu();
}

//########################################################################
//########################### L4BytePort #############################
//########################################################################

L4BytePort::L4BytePort(
	Video8BitBuffered *graphics_display,
	const char *name,
	int rotation
):GraphicsPort(graphics_display, name)
{
	//
	// Save the base rotation value
	//
	baseRotation = rotation;
	//
	// Initialize conversion constants
	//
	maximumX = bounds.topRight.x - bounds.bottomLeft.x;
	maximumY = bounds.topRight.y - bounds.bottomLeft.y;
	//
	// Overwrite the GraphicsPort::bounds data with rotated values
	// for GraphView's benefit
	//
	switch(baseRotation)
	{
	default:
		// do nothing
		break;

	case 90:
	case 270:
		if (graphics_display != NULL)
		{
			Check(graphics_display);
			bounds.bottomLeft.x = graphics_display->bounds.bottomLeft.y;
			bounds.bottomLeft.y = graphics_display->bounds.bottomLeft.x;
			bounds.topRight.x   = graphics_display->bounds.topRight.y;
			bounds.topRight.y   = graphics_display->bounds.topRight.x;
		}
		break;
	}
	Check_Fpu();
}

L4BytePort::~L4BytePort()
{
	Check(this);
	Check_Fpu();
}

Logical
	L4BytePort::TestInstance() const
{
	return True;
}

void
	L4BytePort::ShowInstance(char *indent)
{
	Check(this);

	std::cout << indent << "L4BytePort:\n";

	char
		temp[80];

	Str_Copy(temp,indent, 80);
	Str_Cat(temp,"...", 80);

	std::cout << temp << "baseRotation =" << baseRotation << "\n";
	std::cout << temp << "maximumX     =" << maximumX << "\n";
	std::cout << temp << "maximumY     =" << maximumY << "\n";
	std::cout << temp << "bounds       =" << bounds << "\n";
	std::cout << std::flush;
	GraphicsPort::ShowInstance(temp);
	Check_Fpu();
}

void
	L4BytePort::DrawPoint(
		int color,
		Enumeration operation,
		int x, int y
	)
{
	Check(this);

	if (graphicsDisplay == NULL)
	{
		Check_Fpu();
		return;
	}

	Check(graphicsDisplay);

	int
		xp, yp;

	convertPortPair(&xp, &yp, x, y);

	graphicsDisplay->
		DrawPoint(
			color,
			0,
			operation,
			xp+bounds.bottomLeft.x, yp+bounds.bottomLeft.y
		);
	Check_Fpu();
}

void
	L4BytePort::DrawLine(
		int color,
		Enumeration operation,
		int x1, int y1,
		int x2, int y2,
		Logical include_last_pixel
	)
{
	Check(this);

	if (graphicsDisplay == NULL)
	{
		Check_Fpu();
		return;
	}

	Check(graphicsDisplay);

	int
		x1p, y1p,
		x2p, y2p;

	convertPortPair(&x1p, &y1p, x1, y1);
	convertPortPair(&x2p, &y2p, x2, y2);

	graphicsDisplay->
		DrawLine(
			color,
			0,
			operation,
			x1p+bounds.bottomLeft.x, y1p+bounds.bottomLeft.y,
			x2p+bounds.bottomLeft.x, y2p+bounds.bottomLeft.y,
         include_last_pixel
		);
	Check_Fpu();
}

void
	L4BytePort::DrawFilledRectangle(
		int color,
		Enumeration operation,
		int x1, int y1,
		int x2, int y2
	)
{
	Check(this);

	if (graphicsDisplay == NULL)
	{
		Check_Fpu();
		return;
	}

	Check(graphicsDisplay);

	int
		x1p, y1p,
		x2p, y2p;

	convertPortPair(&x1p, &y1p, x1, y1);
	convertPortPair(&x2p, &y2p, x2, y2);

	graphicsDisplay->
		DrawFilledRectangle(
			color,
			0,
			operation,
			x1p+bounds.bottomLeft.x, y1p+bounds.bottomLeft.y,
			x2p+bounds.bottomLeft.x, y2p+bounds.bottomLeft.y
		);
	Check_Fpu();
}

void
	L4BytePort::DrawText(
		int /*color*/,
		Enumeration /*operation*/,
		Logical /*opaque*/,
		int /*rotation*/,
		Enumeration /*fontNumber*/,
		Logical /*vertical*/,
		GraphicsDisplay::Justification /*justification*/,
		Rectangle2D	*/*clippingRectanglepointer*/,
		char */*stringPointer*/
	)
{
}

void
	L4BytePort::DrawBitMap(
		int color,
		Enumeration operation,
		int rotation,
		int x, int y,
		BitMap *bitmap,
		int sLeft, int sBottom, int sRight, int sTop
	)
{
	Check(this);

	if (graphicsDisplay == NULL)
	{
		Check_Fpu();
		return;
	}

	Check(graphicsDisplay);

	if (bitmap == NULL)
	{
		Check_Fpu();
		return;
	}

	if (bitmap->Data.MapPointer == NULL)
	{
		Check_Fpu();
		return;
	}

	Check(bitmap);

	int
		xp, yp;

	convertPortPair(&xp, &yp, x, y);

	rotation += baseRotation;
	while (rotation <    0) { rotation += 360; }
	while (rotation >= 360) { rotation -= 360; }

	graphicsDisplay->
		DrawBitMap(
			color,
			0,
			operation,
			rotation,
			xp+bounds.bottomLeft.x, yp+bounds.bottomLeft.y,
			bitmap,
			sLeft, sBottom, sRight, sTop
		);
	Check_Fpu();
}

void
	L4BytePort::DrawBitMapOpaque(
		int color,
		int background,
		Enumeration operation,
		int rotation,
		int x, int y,
		BitMap *bitmap,
		int sLeft, int sBottom, int sRight, int sTop
	)
{
	Check(this);

	if (graphicsDisplay == NULL)
	{
		Check_Fpu();
		return;
	}

	Check(graphicsDisplay);

	if (bitmap == NULL)
	{
		Check_Fpu();
		return;
	}

	if (bitmap->Data.MapPointer == NULL)
	{
		Check_Fpu();
		return;
	}

	Check(bitmap);

	int
		xp, yp;

	convertPortPair(&xp, &yp, x, y);

	rotation += baseRotation;
	while (rotation <    0) { rotation += 360; }
	while (rotation >= 360) { rotation -= 360; }

	graphicsDisplay->
		DrawBitMapOpaque(
			color,
			background,
			0,
			operation,
			rotation,
			xp+bounds.bottomLeft.x, yp+bounds.bottomLeft.y,
			bitmap,
			sLeft, sBottom, sRight, sTop
		);
}

void
	L4BytePort::DrawPixelMap8(
		Enumeration operation,
		Logical opaque,
		int rotation,
		int x, int y,
		PixelMap8 *pixelmap,
		int sLeft, int sBottom, int sRight, int sTop
	)
{
	Check(this);

	if (graphicsDisplay == NULL)
	{
		Check_Fpu();
		return;
	}

	Check(graphicsDisplay);

	if (pixelmap == NULL)
	{
		Check_Fpu();
		return;
	}

	if (pixelmap->Data.MapPointer == NULL)
	{
		Check_Fpu();
		return;
	}

	Check(pixelmap);

	int
		xp, yp;

	convertPortPair(&xp, &yp, x, y);

	rotation += baseRotation;
	while (rotation <    0) { rotation += 360; }
	while (rotation >= 360) { rotation -= 360; }

	graphicsDisplay->
		DrawPixelMap8(
			NULL,
			0,
			operation,
			opaque,
			rotation,
			xp+bounds.bottomLeft.x, yp+bounds.bottomLeft.y,
			pixelmap,
			sLeft, sBottom, sRight, sTop
		);
	Check_Fpu();
}

void
	L4BytePort::DrawPixelMap8SingleColor(
		int color,
		Enumeration operation,
		int rotation,
		int x, int y,
		PixelMap8 *pixelmap,
		int sLeft, int sBottom, int sRight, int sTop
	)
{
	Check(this);

	if (graphicsDisplay == NULL)
	{
		Check_Fpu();
		return;
	}

	Check(graphicsDisplay);

	if (pixelmap == NULL)
	{
		Check_Fpu();
		return;
	}

	if (pixelmap->Data.MapPointer == NULL)
	{
		Check_Fpu();
		return;
	}

	Check(pixelmap);

	int
		xp, yp;

	convertPortPair(&xp, &yp, x, y);

	rotation += baseRotation;
	while (rotation <    0) { rotation += 360; }
	while (rotation >= 360) { rotation -= 360; }

	graphicsDisplay->
		DrawPixelMap8SingleColor(
			color,
			0,
			operation,
			rotation,
			xp+bounds.bottomLeft.x, yp+bounds.bottomLeft.y,
			pixelmap,
			sLeft, sBottom, sRight, sTop
		);
	Check_Fpu();
}

void
	L4BytePort::convertPortPair(
		int *xp,
		int *yp,
		int x,
		int y
	)
{
	switch(baseRotation)
	{
	default:
		*xp = x;
		*yp = y;
		break;

	case 90:
		*xp = y;
		*yp = maximumY - x;
		break;

	case 180:
		*xp = maximumX - x;
		*yp = maximumY - y;
		break;

	case 270:
		*xp = maximumX - y;
		*yp = x;
		break;
	}
	Check_Fpu();
}
