Imports the current Win32 source for the pod-racing game 'Red Planet', built on the MUNGA engine and its L4 (Win32/DirectX) platform layer: - MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend - RP / RP_L4: Red Planet game logic and Win32 application - DivLoader, Setup1: asset loader and installer project - lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies Removed stale Subversion metadata and added .gitignore/.gitattributes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3104 lines
62 KiB
C++
3104 lines
62 KiB
C++
#include "munga.h"
|
|
#pragma hdrstop
|
|
|
|
#include "graph2d.h"
|
|
#include "notation.h"
|
|
#include "namelist.h"
|
|
|
|
//#define DEBUG
|
|
|
|
struct PCXHeader
|
|
{
|
|
Byte manufacturer;
|
|
Byte version;
|
|
Byte encoding;
|
|
Byte bitsPerPixel;
|
|
Word xMin, yMin;
|
|
Word xMax, yMax;
|
|
Word hRes, vRes;
|
|
Byte palette16[48];
|
|
Byte reserved;
|
|
Byte colorPlanes;
|
|
Word bytesPerLine;
|
|
Word paletteType;
|
|
Byte filler[58];
|
|
};
|
|
|
|
Logical
|
|
PCXRead(
|
|
const char *file_name,
|
|
PCXHeader *header,
|
|
Byte **body_ptr,
|
|
Byte *palette_ptr
|
|
)
|
|
{
|
|
FILE
|
|
*fp;
|
|
|
|
Check_Pointer(file_name);
|
|
Verify(header != NULL);
|
|
|
|
fp = fopen(file_name, "rb");
|
|
if (fp == NULL)
|
|
{
|
|
Tell( "PCXRead: Cannot open file '" << file_name << "'\n");
|
|
return False;
|
|
}
|
|
if (fread (header, sizeof(PCXHeader), 1, fp) != 1)
|
|
{
|
|
Tell("PCXRead: Cannot read header from '" << file_name << "'\n");
|
|
fclose(fp);
|
|
return False;
|
|
}
|
|
if (
|
|
(header->manufacturer != 0x0A) || // flags 'PCX'-type file
|
|
(header->bitsPerPixel != 8) || // we require standard 8-bit
|
|
(header->encoding != 1) || // PCX is always encoded
|
|
(header->colorPlanes != 1) // 256-color ONLY!!!
|
|
)
|
|
{
|
|
Tell("PCXRead: '" << file_name <<
|
|
" 'either not a PCX file, or the wrong type!\n");
|
|
fclose(fp);
|
|
return False;
|
|
}
|
|
|
|
int
|
|
data_width(header->bytesPerLine),
|
|
width(header->xMax-header->xMin+1),
|
|
height(header->yMax-header->yMin+1),
|
|
x,
|
|
x2,
|
|
y,
|
|
count;
|
|
|
|
Byte
|
|
*dest;
|
|
|
|
Byte
|
|
c;
|
|
|
|
|
|
if (body_ptr == NULL)
|
|
{
|
|
fseek(fp, -769, SEEK_END); // seek to beginning of palette
|
|
}
|
|
else
|
|
{
|
|
if (*body_ptr != NULL)
|
|
{
|
|
Unregister_Pointer(*body_ptr);
|
|
delete *body_ptr;
|
|
*body_ptr = NULL;
|
|
}
|
|
*body_ptr = new Byte[width*height];
|
|
Register_Pointer(*body_ptr);
|
|
|
|
dest = *body_ptr;
|
|
for(y=height; y>0; --y)
|
|
{
|
|
x2 = width;
|
|
for (x=data_width; x > 0; )
|
|
{
|
|
c = (Byte) fgetc(fp);
|
|
|
|
if (ferror(fp))
|
|
{
|
|
Tell("PCXRead: File error reading '" << file_name << "'\n");
|
|
fclose(fp);
|
|
Unregister_Pointer(*body_ptr);
|
|
delete *body_ptr;
|
|
*body_ptr = NULL;
|
|
return False;
|
|
}
|
|
|
|
if ((c & 0xC0) == 0xC0)
|
|
{
|
|
count = c & 0x3F;
|
|
x -= count;
|
|
c = (Byte) fgetc(fp);
|
|
|
|
while (count--)
|
|
{
|
|
if (x2 > 0)
|
|
{
|
|
--x2;
|
|
*dest++ = c;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (x2 > 0)
|
|
{
|
|
--x2;
|
|
*dest++ = c;
|
|
}
|
|
--x;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (palette_ptr != NULL)
|
|
{
|
|
Byte
|
|
identifier;
|
|
|
|
if (fread (&identifier, 1, 1, fp) != 1)
|
|
{
|
|
Tell("PCXRead: Cannot read palette from '" << file_name << "'\n");
|
|
fclose(fp);
|
|
return False;
|
|
}
|
|
|
|
if (identifier != 0x0C)
|
|
{
|
|
Tell("PCXRead: Invalid palette in '" << file_name << "'\n");
|
|
fclose(fp);
|
|
return False;
|
|
}
|
|
|
|
if (fread (palette_ptr, (256*3), 1, fp) != 1)
|
|
{
|
|
Tell("PCXRead: Cannot read palette from '" << file_name << "'\n");
|
|
fclose(fp);
|
|
Check_Fpu();
|
|
return False;
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
Check_Fpu();
|
|
return True;
|
|
}
|
|
|
|
|
|
//########################################################################
|
|
//################################ BitMap ################################
|
|
//########################################################################
|
|
BitMap *
|
|
BitMap::Make(const char *name)
|
|
{
|
|
Check_Pointer(name);
|
|
|
|
char
|
|
file_name[80];
|
|
|
|
Str_Copy(file_name, "gauge\\", sizeof(file_name));
|
|
Str_Cat(file_name, name, sizeof(file_name));
|
|
|
|
BitMap
|
|
*bitmap = new BitMap(file_name);
|
|
Check_Pointer(bitmap);
|
|
if (bitmap->Data.MapPointer == NULL)
|
|
{
|
|
delete bitmap;
|
|
bitmap = NULL;
|
|
}
|
|
else
|
|
{
|
|
Check(bitmap);
|
|
}
|
|
Check_Fpu();
|
|
return bitmap;
|
|
}
|
|
|
|
BitMap *
|
|
BitMap::Make(ResourceDescription::ResourceID /*new_resource_id*/)
|
|
{
|
|
Check_Fpu();
|
|
return NULL; // not yet 'resourcified'
|
|
}
|
|
|
|
BitMap::BitMap(int width, int height)
|
|
{
|
|
Check_Pointer(this);
|
|
Verify(width >0);
|
|
Verify(height >0);
|
|
|
|
Data.WidthInWords = (width+15)>>4;
|
|
|
|
Data.MapPointer = new Word[Data.WidthInWords*height];
|
|
Register_Pointer(Data.MapPointer);
|
|
Data.Size.x = width;
|
|
Data.Size.y = height;
|
|
Check_Fpu();
|
|
}
|
|
|
|
BitMap::BitMap(int width, int height, Word *body)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Pointer(body);
|
|
|
|
Data.WidthInWords = 0;
|
|
Data.Size.x = 0;
|
|
Data.Size.y = 0;
|
|
|
|
if (width > 0)
|
|
{
|
|
if (height > 0)
|
|
{
|
|
int
|
|
word_width = (width+15)>>4;
|
|
|
|
Data.MapPointer = new Word[word_width * height];
|
|
Register_Pointer(Data.MapPointer);
|
|
Data.WidthInWords = word_width;
|
|
Data.Size.x = width;
|
|
Data.Size.y = height;
|
|
|
|
Mem_Copy(
|
|
Data.MapPointer,
|
|
body,
|
|
word_width * height * sizeof(Word),
|
|
word_width * height * sizeof(Word)
|
|
);
|
|
}
|
|
# if DEBUG_LEVEL > 0
|
|
else
|
|
{
|
|
Warn("BitMap::BitMap has illicit height");
|
|
}
|
|
# endif
|
|
}
|
|
# if DEBUG_LEVEL > 0
|
|
else
|
|
{
|
|
Warn("BitMap::BitMap has illicit width");
|
|
}
|
|
# endif
|
|
Check_Fpu();
|
|
}
|
|
|
|
BitMap::BitMap(const char *file_name)
|
|
{
|
|
Check_Pointer(file_name);
|
|
|
|
PCXHeader
|
|
header;
|
|
Byte
|
|
*temp(NULL);
|
|
|
|
Data.WidthInWords = 0;
|
|
Data.Size.x = 0;
|
|
Data.Size.y = 0;
|
|
Data.MapPointer = NULL;
|
|
|
|
if (PCXRead(file_name, &header, &temp, NULL) == True)
|
|
{
|
|
if (temp != NULL)
|
|
{
|
|
Data.Size.x = header.xMax - header.xMin + 1;
|
|
Data.Size.y = header.yMax - header.yMin + 1;
|
|
Data.WidthInWords = (Data.Size.x + 15) >> 4;
|
|
Data.MapPointer = new Word[Data.WidthInWords * Data.Size.y];
|
|
Check_Pointer(Data.MapPointer);
|
|
Register_Pointer(Data.MapPointer);
|
|
|
|
Byte
|
|
*source(temp);
|
|
Word
|
|
*dest(Data.MapPointer);
|
|
Word
|
|
bits(0),
|
|
bitmask(0x8000);
|
|
int
|
|
x,
|
|
y;
|
|
for (y=Data.Size.y; y>0; --y)
|
|
{
|
|
for (x=Data.Size.x; x>0; --x)
|
|
{
|
|
if (*source++ != 0)
|
|
{
|
|
bits |= bitmask;
|
|
}
|
|
bitmask >>= 1;
|
|
if (bitmask == 0)
|
|
{
|
|
*dest++ = bits;
|
|
bitmask = 0x8000;
|
|
bits = 0;
|
|
}
|
|
}
|
|
|
|
if (bitmask != 0x8000)
|
|
{
|
|
*dest++ = bits;
|
|
bitmask = 0x8000;
|
|
bits = 0;
|
|
}
|
|
}
|
|
Unregister_Pointer(temp);
|
|
delete temp;
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
BitMap::BitMap(NotationFile *notation_file, const char *page_name)
|
|
{
|
|
Check_Pointer(this);
|
|
Check(notation_file);
|
|
Check_Pointer(page_name);
|
|
|
|
int
|
|
x,
|
|
y,
|
|
width_in_words;
|
|
|
|
//-----------------------------------------
|
|
// Render bitmap benign in case of failure
|
|
//-----------------------------------------
|
|
Data.Size.x = 0;
|
|
Data.Size.y = 0;
|
|
Data.WidthInWords = 0;
|
|
Data.MapPointer = NULL;
|
|
//--------------------------------------------
|
|
// Attempt to read the x, y, and width values
|
|
//--------------------------------------------
|
|
if (!notation_file->GetEntry(page_name, "x", &x))
|
|
{
|
|
Warn("BitMap::BitMap notation file: 'x' not found!\n");
|
|
return;
|
|
}
|
|
Verify(x > 0);
|
|
|
|
if (!notation_file->GetEntry(page_name, "y", &y))
|
|
{
|
|
Warn("BitMap::BitMap notation file: 'y' not found!\n");
|
|
return;
|
|
}
|
|
Verify(y > 0);
|
|
|
|
if (!notation_file->GetEntry(page_name, "width", &width_in_words))
|
|
{
|
|
Warn("BitMap::BitMap notation file: 'width' not found!\n");
|
|
return;
|
|
}
|
|
//Tell("BitMap::BitMap x=" << x << ", y=" << y << ", width_in_words=" << width_in_words << "\n");
|
|
Verify(x <= (width_in_words << 4));
|
|
|
|
//--------------------------------------------
|
|
// Attempt to allocate the map
|
|
//--------------------------------------------
|
|
Data.MapPointer = new Word[width_in_words * y];
|
|
Register_Pointer(Data.MapPointer);
|
|
//--------------------------------------------
|
|
// So far, so good! Save the values
|
|
//--------------------------------------------
|
|
Data.Size.x = x;
|
|
Data.Size.y = y;
|
|
Data.WidthInWords = width_in_words;
|
|
//--------------------------------------------
|
|
// Read the map data
|
|
//--------------------------------------------
|
|
NameList *lines =
|
|
notation_file->MakeEntryList(page_name);
|
|
Check(lines);
|
|
Register_Object(lines);
|
|
|
|
NameList::Entry
|
|
*line_entry;
|
|
const char
|
|
*text;
|
|
int
|
|
collect = 0,
|
|
nybble,
|
|
nybble_count = 4;
|
|
Word
|
|
*destination = Data.MapPointer;
|
|
|
|
//--------------------------------------------
|
|
// Collect all the entries in the page
|
|
//--------------------------------------------
|
|
for (
|
|
line_entry = lines->GetFirstEntry();
|
|
line_entry != NULL;
|
|
line_entry = line_entry->GetNextEntry()
|
|
)
|
|
{
|
|
//--------------------------------------------
|
|
// Get the entry name
|
|
//--------------------------------------------
|
|
if ((text=line_entry->GetName()) != NULL)
|
|
{
|
|
//--------------------------------------------
|
|
// Process only if it's a 'bitmap' entry
|
|
//--------------------------------------------
|
|
if (strcmp(text, "bitmap") == 0)
|
|
{
|
|
//--------------------------------------------
|
|
// Get the entry text
|
|
//--------------------------------------------
|
|
text=line_entry->GetChar();
|
|
Verify(text != NULL);
|
|
//--------------------------------------------
|
|
// Parse the 'bitmap' entry
|
|
//--------------------------------------------
|
|
for ( ; *text != '\0'; ++text)
|
|
{
|
|
//--------------------------------------------
|
|
// Convert char to hex nybble
|
|
//--------------------------------------------
|
|
nybble = toupper(*text);
|
|
Verify(isxdigit(nybble));
|
|
|
|
if (nybble > '9')
|
|
{
|
|
nybble -= ('A' - '9' - 1);
|
|
}
|
|
nybble -= '0';
|
|
//--------------------------------------------
|
|
// Collect in a word
|
|
//--------------------------------------------
|
|
collect = (collect << 4) + nybble;
|
|
//--------------------------------------------
|
|
// If a full word is collected, save it
|
|
//--------------------------------------------
|
|
--nybble_count;
|
|
if (nybble_count <= 0)
|
|
{
|
|
//--------------------------------------------
|
|
// Verify that we've not gone too far
|
|
//--------------------------------------------
|
|
if ((destination-Data.MapPointer) >= (width_in_words*y))
|
|
{
|
|
Tell("BitMap::BitMap(notation file) attempted overrun");
|
|
break;
|
|
}
|
|
//--------------------------------------------
|
|
// Save it, set up for next word
|
|
//--------------------------------------------
|
|
*destination++ = (Word) collect;
|
|
nybble_count = 4;
|
|
collect = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Unregister_Object(lines);
|
|
delete lines;
|
|
//--------------------------------------------
|
|
// Make sure we collected the proper
|
|
// amount of data-
|
|
//--------------------------------------------
|
|
// Verify(nybble_count == 4);
|
|
// Verify(word_count == 0);
|
|
Check_Fpu();
|
|
}
|
|
|
|
BitMap::~BitMap()
|
|
{
|
|
Check(this);
|
|
|
|
if (Data.MapPointer != NULL)
|
|
{
|
|
Unregister_Pointer(Data.MapPointer);
|
|
delete Data.MapPointer;
|
|
Data.Size.x = 0; // safety code
|
|
Data.Size.y = 0;
|
|
Data.MapPointer = NULL;
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
Logical
|
|
BitMap::TestInstance() const
|
|
{
|
|
Verify(Data.Size.x > 0);
|
|
Verify(Data.Size.x < 8192); // unreasonably large
|
|
Verify(Data.Size.y > 0);
|
|
Verify(Data.Size.y < 8192); // unreasonably large
|
|
Verify(Data.WidthInWords == ((Data.Size.x + 15) >> 4));
|
|
Check_Pointer(Data.MapPointer);
|
|
Check_Fpu();
|
|
return True;
|
|
}
|
|
|
|
void
|
|
BitMap::ShowInstance(char * indent)
|
|
{
|
|
Check(this);
|
|
|
|
std::cout << indent << "BitMap:\n";
|
|
char
|
|
temp[80];
|
|
|
|
Str_Copy(temp, indent, 80);
|
|
Str_Cat(temp, "...", 80);
|
|
|
|
std::cout << temp << "Size =" << Data.Size << "\n";
|
|
std::cout << temp << "WidthInWords=" << Data.WidthInWords << "\n";
|
|
std::cout << temp << "MapPointer =" << (void *) Data.MapPointer << "\n";
|
|
std::cout << std::flush;
|
|
|
|
if (Data.MapPointer != NULL)
|
|
{
|
|
int
|
|
x,
|
|
y,
|
|
bits,
|
|
bitmask,
|
|
bitwidth;
|
|
|
|
Word
|
|
*source((Word *) Data.MapPointer);
|
|
|
|
for(y=Data.Size.y; y>0; y--)
|
|
{
|
|
std::cout << temp;
|
|
bitwidth=0;
|
|
for(x=Data.WidthInWords; x>0; --x)
|
|
{
|
|
bits = *source++;
|
|
|
|
for(bitmask=0x8000; bitmask!=0; bitmask>>=1)
|
|
{
|
|
if (++bitwidth > Data.Size.x)
|
|
{
|
|
std::cout << "-";
|
|
}
|
|
else if (bits & bitmask)
|
|
{
|
|
std::cout <<"#";
|
|
}
|
|
else
|
|
{
|
|
std::cout <<" ";
|
|
}
|
|
}
|
|
}
|
|
std::cout << "\n";
|
|
}
|
|
std::cout << "\n";
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//########################################################################
|
|
//############################### Palette8 ###############################
|
|
//########################################################################
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// Output stream operator
|
|
//------------------------------------------------------------------------
|
|
//
|
|
std::ostream& operator<<(std::ostream& Stream, const PaletteTriplet& p)
|
|
{
|
|
Check_Fpu();
|
|
return Stream << std::hex <<
|
|
(((int) p.Red) & 0xFF) << ':' <<
|
|
(((int) p.Green) & 0xFF) << ':' <<
|
|
(((int) p.Blue) & 0xFF) << std::dec;
|
|
}
|
|
|
|
Palette8::Palette8()
|
|
{
|
|
Check_Pointer(this);
|
|
Valid = False;
|
|
Check_Fpu();
|
|
}
|
|
|
|
Palette8 *
|
|
Palette8::Make(const char *name)
|
|
{
|
|
Check_Pointer(name);
|
|
|
|
char
|
|
file_name[80];
|
|
|
|
Str_Copy(file_name, "gauge\\", sizeof(file_name));
|
|
Str_Cat(file_name, name, sizeof(file_name));
|
|
|
|
|
|
Palette8
|
|
*palette = new Palette8(file_name);
|
|
Check_Pointer(palette);
|
|
if (!palette->Valid)
|
|
{
|
|
delete palette;
|
|
palette = NULL;
|
|
}
|
|
Check_Fpu();
|
|
return palette;
|
|
}
|
|
|
|
Palette8 *
|
|
Palette8::Make(ResourceDescription::ResourceID /*new_resource_id*/)
|
|
{
|
|
Check_Fpu();
|
|
return NULL; // not yet 'resourcified'
|
|
}
|
|
|
|
|
|
|
|
Palette8::Palette8(int count, PaletteTriplet *source)
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
int
|
|
i;
|
|
|
|
Check_Pointer(source);
|
|
Verify(count > 0);
|
|
Verify(count <= 256);
|
|
|
|
for(i=0; i<count; ++i)
|
|
{
|
|
Color[i] = *source++;
|
|
}
|
|
Valid = True;
|
|
Check_Fpu();
|
|
}
|
|
|
|
Palette8::Palette8(const char *file_name)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Pointer(file_name);
|
|
|
|
PCXHeader
|
|
header;
|
|
|
|
Valid = PCXRead(file_name, &header, NULL, (Byte *) Color);
|
|
Check_Fpu();
|
|
}
|
|
|
|
Palette8::~Palette8()
|
|
{
|
|
Check(this);
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
Palette8::SetColorRange(int start, int end, PaletteTriplet new_color)
|
|
{
|
|
Check(this);
|
|
|
|
Verify(start >= 0);
|
|
Verify(end < 256);
|
|
Verify(start <= end);
|
|
|
|
for( ; start <= end; ++start)
|
|
{
|
|
Color[start] = new_color;
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
Palette8::BuildColorRange(
|
|
int start,
|
|
int end,
|
|
PaletteTriplet first_color,
|
|
PaletteTriplet last_color
|
|
)
|
|
{
|
|
Check(this);
|
|
|
|
int
|
|
range,
|
|
rate_red,
|
|
rate_green,
|
|
rate_blue,
|
|
accum_red,
|
|
accum_green,
|
|
accum_blue;
|
|
|
|
Verify(start >= 0);
|
|
Verify(end < 256);
|
|
Verify(start <= end);
|
|
|
|
range = end - start;
|
|
|
|
if (range == 0)
|
|
{
|
|
Color[start] = first_color;
|
|
}
|
|
else
|
|
{
|
|
rate_red = (((int)(last_color.Red - first_color.Red) ) << 5)/range;
|
|
rate_green = (((int)(last_color.Green - first_color.Green)) << 5)/range;
|
|
rate_blue = (((int)(last_color.Blue - first_color.Blue) ) << 5)/range;
|
|
|
|
accum_red = ((int)first_color.Red) << 5;
|
|
accum_green = ((int)first_color.Green) << 5;
|
|
accum_blue = ((int)first_color.Blue) << 5;
|
|
|
|
for( ; start<=end; ++start)
|
|
{
|
|
Color[start].Red = (Byte) (accum_red >> 5);
|
|
Color[start].Green = (Byte) (accum_green >> 5);
|
|
Color[start].Blue = (Byte) (accum_blue >> 5);
|
|
|
|
accum_red += rate_red;
|
|
accum_green += rate_green;
|
|
accum_blue += rate_blue;
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
Logical
|
|
Palette8::TestInstance() const
|
|
{
|
|
return True;
|
|
}
|
|
|
|
void
|
|
Palette8::ShowInstance(char *indent)
|
|
{
|
|
Check(this);
|
|
|
|
char
|
|
temp[80],
|
|
buffer[32];
|
|
PaletteTriplet
|
|
*source;
|
|
int
|
|
x,
|
|
y;
|
|
|
|
std::cout << indent << "Palette8:\n";
|
|
|
|
Str_Copy(temp, indent, 80);
|
|
Str_Cat(temp, "...", 80);
|
|
|
|
std::cout << temp << "Valid =" << Valid << "\n";
|
|
|
|
if (Valid)
|
|
{
|
|
source = Color;
|
|
for(y=0; y<256; y+=4)
|
|
{
|
|
sprintf(buffer, "%02X= ", y);
|
|
std::cout << temp << buffer;
|
|
|
|
for(x=4; x>0; --x)
|
|
{
|
|
std::cout << *source++ << " ";
|
|
}
|
|
std::cout << "\n";
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//########################################################################
|
|
//############################## PixelMap8 ###############################
|
|
//########################################################################
|
|
PixelMap8 *
|
|
PixelMap8::Make(const char *name)
|
|
{
|
|
Check_Pointer(name);
|
|
|
|
char
|
|
file_name[80];
|
|
|
|
Str_Copy(file_name, "gauge\\", sizeof(file_name));
|
|
Str_Cat(file_name, name, sizeof(file_name));
|
|
|
|
PixelMap8
|
|
*pixelmap = new PixelMap8(file_name);
|
|
Check_Pointer(pixelmap);
|
|
if (pixelmap->Data.MapPointer == NULL)
|
|
{
|
|
delete pixelmap;
|
|
pixelmap = NULL;
|
|
}
|
|
else
|
|
{
|
|
Check(pixelmap);
|
|
}
|
|
Check_Fpu();
|
|
return pixelmap;
|
|
}
|
|
|
|
PixelMap8 *
|
|
PixelMap8::Make(ResourceDescription::ResourceID /*new_resource_id*/)
|
|
{
|
|
Check_Fpu();
|
|
return NULL; // not yet 'resourcified'
|
|
}
|
|
|
|
PixelMap8::PixelMap8(int width, int height)
|
|
{
|
|
Check_Pointer(this);
|
|
Verify(width >0);
|
|
Verify(height >0);
|
|
|
|
Data.Size.x = width;
|
|
Data.Size.y = height;
|
|
Data.MapPointer = new Byte[width*height];
|
|
Register_Pointer(Data.MapPointer);
|
|
Check_Fpu();
|
|
}
|
|
|
|
PixelMap8::PixelMap8(const char *file_name)
|
|
{
|
|
Check_Pointer(file_name);
|
|
PCXHeader
|
|
header;
|
|
|
|
Data.MapPointer = NULL;
|
|
|
|
if (PCXRead(file_name, &header, &Data.MapPointer, NULL) == True)
|
|
{
|
|
if (Data.MapPointer == NULL)
|
|
{
|
|
Data.Size.x = 0;
|
|
Data.Size.y = 0;
|
|
}
|
|
else
|
|
{
|
|
//Data.MapPointer already registered by PCXRead()
|
|
Data.Size.x = header.xMax - header.xMin + 1;
|
|
Data.Size.y = header.yMax - header.yMin + 1;
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
PixelMap8::~PixelMap8()
|
|
{
|
|
Check(this);
|
|
|
|
if (Data.MapPointer != NULL)
|
|
{
|
|
Unregister_Pointer(Data.MapPointer);
|
|
delete Data.MapPointer;
|
|
Data.Size.x = 0; // safety code
|
|
Data.Size.y = 0;
|
|
Data.MapPointer = NULL;
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
Logical
|
|
PixelMap8::TestInstance() const
|
|
{
|
|
Verify (Data.Size.x >0);
|
|
Verify (Data.Size.x < 8192); // an unreasonably large image!
|
|
Verify (Data.Size.y >0);
|
|
Verify (Data.Size.y < 8192); // an unreasonably large image!
|
|
Check_Pointer(Data.MapPointer);
|
|
Check_Fpu();
|
|
return True;
|
|
}
|
|
|
|
void
|
|
PixelMap8::ShowInstance(char *indent)
|
|
{
|
|
Check(this);
|
|
|
|
char
|
|
temp[80],
|
|
buffer[32];
|
|
Byte
|
|
*source;
|
|
int
|
|
x,
|
|
y;
|
|
|
|
std::cout << indent << "PixelMap8:\n";
|
|
|
|
Str_Copy(temp, indent, 80);
|
|
Str_Cat(temp, "...", 80);
|
|
|
|
std::cout << temp << "Size =" << Data.Size << "\n";
|
|
std::cout << temp << "MapPointer =" << (void *) Data.MapPointer << "\n";
|
|
|
|
source = Data.MapPointer;
|
|
if (source != NULL)
|
|
{
|
|
for(y=Data.Size.y; y>0; --y)
|
|
{
|
|
std::cout << temp;
|
|
for(x=Data.Size.x; x>0; --x)
|
|
{
|
|
sprintf(buffer, "%02X ",*source++);
|
|
std::cout << buffer;
|
|
}
|
|
std::cout << "\n";
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//########################################################################
|
|
//############################## PixelMap16 ##############################
|
|
//########################################################################
|
|
PixelMap16::PixelMap16(int width, int height)
|
|
{
|
|
Check_Pointer(this);
|
|
Verify(width >0);
|
|
Verify(height >0);
|
|
|
|
Data.Size.x = width;
|
|
Data.Size.y = height;
|
|
Data.MapPointer = new Word[width*height];
|
|
Register_Pointer(Data.MapPointer);
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
PixelMap16::PixelMap16(char *)
|
|
{
|
|
Fail("PixelMap16::PixelMap16(char *) UNIMPLEMENTED\n");
|
|
Data.MapPointer = NULL;
|
|
Data.Size.x = 0;
|
|
Data.Size.y = 0;
|
|
Check_Fpu();
|
|
}
|
|
|
|
PixelMap16::~PixelMap16()
|
|
{
|
|
Check(this);
|
|
|
|
if (Data.MapPointer != NULL)
|
|
{
|
|
Unregister_Pointer(Data.MapPointer);
|
|
delete Data.MapPointer;
|
|
Data.Size.x = 0; // safety code
|
|
Data.Size.y = 0;
|
|
Data.MapPointer = NULL;
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
Logical
|
|
PixelMap16::TestInstance() const
|
|
{
|
|
return True;
|
|
}
|
|
|
|
void
|
|
PixelMap16::ShowInstance(char *indent)
|
|
{
|
|
Check(this);
|
|
|
|
char
|
|
temp[80];
|
|
|
|
std::cout << indent << "PixelMap16:\n";
|
|
|
|
Str_Copy(temp, indent, 80);
|
|
Str_Cat(temp, "...", 80);
|
|
|
|
std::cout << temp << "Size =" << Data.Size << "\n";
|
|
std::cout << temp << "MapPointer =" << (void *) Data.MapPointer << "\n";
|
|
Check_Fpu();
|
|
}
|
|
|
|
//########################################################################
|
|
//########################### GraphicsDisplay ############################
|
|
//########################################################################
|
|
GraphicsDisplay::GraphicsDisplay(int x, int y)
|
|
{
|
|
Check_Pointer(this);
|
|
Verify(x >0);
|
|
Verify(y >0);
|
|
|
|
bounds.bottomLeft.x = 0;
|
|
bounds.bottomLeft.y = 0;
|
|
bounds.topRight.x = x-1;
|
|
bounds.topRight.y = y-1;
|
|
Check_Fpu();
|
|
}
|
|
|
|
GraphicsDisplay::~GraphicsDisplay()
|
|
{
|
|
Check(this);
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsDisplay::ShowInstance(char *indent)
|
|
{
|
|
Check(this);
|
|
std::cout << indent << "GraphicsDisplay:\n";
|
|
|
|
char
|
|
temp[80];
|
|
|
|
Str_Copy(temp, indent, 80);
|
|
Str_Cat(temp, "...", 80);
|
|
|
|
std::cout << temp << "bounds =" << bounds << "\n";
|
|
Check_Fpu();
|
|
}
|
|
|
|
Logical
|
|
GraphicsDisplay::TestInstance() const
|
|
{
|
|
return True;
|
|
}
|
|
|
|
Logical
|
|
GraphicsDisplay::Update(Logical)
|
|
{
|
|
// no-op for base class
|
|
return False; // always returns 'all done'
|
|
}
|
|
|
|
void
|
|
GraphicsDisplay::WaitForUpdate()
|
|
{
|
|
// no-op for base class: immediately returns
|
|
}
|
|
|
|
Rectangle2D
|
|
GraphicsDisplay::TextBounds(
|
|
Enumeration,
|
|
Logical,
|
|
GraphicsDisplay::Justification,
|
|
char *
|
|
)
|
|
{
|
|
Fail("GraphicsDisplay::TextBounds(...) is UNIMPLEMENTED\n");
|
|
|
|
Rectangle2D
|
|
r;
|
|
Check_Fpu();
|
|
return r;
|
|
}
|
|
|
|
void
|
|
GraphicsDisplay::DrawPoint(
|
|
int /*color*/,
|
|
int /*bitmask*/,
|
|
Enumeration /*operation*/,
|
|
int /*x*/,
|
|
int /*y*/
|
|
)
|
|
{
|
|
Fail("GraphicsDisplay::DrawPoint not overridden");
|
|
}
|
|
|
|
void
|
|
GraphicsDisplay::DrawLine(
|
|
int /*color*/,
|
|
int /*bitmask*/,
|
|
Enumeration /*operation*/,
|
|
int /*x1*/,
|
|
int /*y1*/,
|
|
int /*x2*/,
|
|
int /*y2*/,
|
|
Logical /*include_last_pixel*/
|
|
)
|
|
{
|
|
Fail("GraphicsDisplay::DrawLine not overridden");
|
|
}
|
|
|
|
void
|
|
GraphicsDisplay::DrawFilledRectangle(
|
|
int /*color*/,
|
|
int /*bitmask*/,
|
|
Enumeration /*operation*/,
|
|
int /*x1*/,
|
|
int /*y1*/,
|
|
int /*x2*/,
|
|
int /*y2*/
|
|
)
|
|
{
|
|
Fail("GraphicsDisplay::DrawFilledRectangle not overridden");
|
|
}
|
|
|
|
void
|
|
GraphicsDisplay::DrawText(
|
|
int /*color*/,
|
|
int /*bitmask*/,
|
|
Enumeration /*operation*/,
|
|
Logical /*opaque*/,
|
|
int /*rotation*/,
|
|
Enumeration /*fontNumber*/,
|
|
Logical /*vertical*/,
|
|
GraphicsDisplay::Justification /*justification*/,
|
|
Rectangle2D * /*clippingRectanglePtr*/,
|
|
char * /*stringPointer*/
|
|
)
|
|
{
|
|
Fail("GraphicsDisplay::DrawText not overridden");
|
|
}
|
|
|
|
void
|
|
GraphicsDisplay::DrawBitMap(
|
|
int /*color*/,
|
|
int /*bitmask*/,
|
|
Enumeration /*operation*/,
|
|
int /*rotation*/,
|
|
int /*x*/,
|
|
int /*y*/,
|
|
BitMap * /*bitmap*/,
|
|
int /*sx1*/,
|
|
int /*sy1*/,
|
|
int /*sx2*/,
|
|
int /*sy2*/ // these are SOURCE coordinates
|
|
)
|
|
{
|
|
Fail("GraphicsDisplay::DrawBitMap not overridden");
|
|
}
|
|
|
|
void
|
|
GraphicsDisplay::DrawBitMapOpaque(
|
|
int /*color*/,
|
|
int /*background*/,
|
|
int /*bitmask*/,
|
|
Enumeration /*operation*/,
|
|
int /*rotation*/,
|
|
int /*x*/,
|
|
int /*y*/,
|
|
BitMap * /*bitmap*/,
|
|
int /*sx1*/,
|
|
int /*sy1*/,
|
|
int /*sx2*/,
|
|
int /*sy2*/ // these are SOURCE coordinates
|
|
)
|
|
{
|
|
Fail("GraphicsDisplay::DrawBitMapOpaque not overridden");
|
|
}
|
|
|
|
void
|
|
GraphicsDisplay::DrawPixelMap8(
|
|
int * /*translation_table*/,
|
|
int /*bitmask*/,
|
|
Enumeration /*operation*/,
|
|
Logical /*opaque*/,
|
|
int /*rotation*/,
|
|
int /*x*/,
|
|
int /*y*/,
|
|
PixelMap8 * /*pixelmap*/,
|
|
int /*sx1*/,
|
|
int /*sy1*/,
|
|
int /*sx2*/,
|
|
int /*sy2*/ // these are SOURCE coordinates
|
|
)
|
|
{
|
|
Fail("GraphicsDisplay::DrawPixelMap8 not overridden");
|
|
}
|
|
|
|
void
|
|
GraphicsDisplay::DrawPixelMap8SingleColor(
|
|
int /*color*/,
|
|
int /*bitmask*/,
|
|
Enumeration /*operation*/,
|
|
int /*rotation*/,
|
|
int /*x*/,
|
|
int /*y*/,
|
|
PixelMap8 * /*pixelmap*/,
|
|
int /*sx1*/,
|
|
int /*sy1*/,
|
|
int /*sx2*/,
|
|
int /*sy2*/ // these are SOURCE coordinates
|
|
)
|
|
{
|
|
Fail("GraphicsDisplay::DrawPixelMap8SingleColor not overridden");
|
|
}
|
|
|
|
//########################################################################
|
|
//############################ GraphicsPort ##############################
|
|
//########################################################################
|
|
GraphicsPort::GraphicsPort(
|
|
GraphicsDisplay *graphics_display,
|
|
const char *new_name
|
|
)
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
if (graphics_display != NULL)
|
|
{
|
|
Check(graphics_display);
|
|
bounds = graphics_display->bounds;
|
|
}
|
|
else
|
|
{
|
|
bounds.bottomLeft.x = 0;
|
|
bounds.bottomLeft.y = 0;
|
|
bounds.topRight.x = 0;
|
|
bounds.topRight.y = 0;
|
|
}
|
|
graphicsDisplay = graphics_display;
|
|
|
|
Str_Copy(name, new_name, sizeof(name));
|
|
Check_Fpu();
|
|
}
|
|
|
|
GraphicsPort::~GraphicsPort()
|
|
{
|
|
Check(this);
|
|
Check_Fpu();
|
|
}
|
|
|
|
Logical
|
|
GraphicsPort::TestInstance() const
|
|
{
|
|
return True;
|
|
}
|
|
|
|
void
|
|
GraphicsPort::ShowInstance(char *indent)
|
|
{
|
|
Check(this);
|
|
|
|
std::cout << indent << "GraphicsPort:\n";
|
|
|
|
char
|
|
temp[80];
|
|
|
|
Str_Copy(temp, indent, 80);
|
|
Str_Cat(temp, "...", 80);
|
|
|
|
std::cout << temp << "bounds =" << bounds << "\n";
|
|
std::cout << temp << "graphicsDisplay=" << graphicsDisplay << "\n";
|
|
std::cout << std::flush;
|
|
Check_Fpu();
|
|
}
|
|
|
|
Rectangle2D
|
|
GraphicsPort::TextBounds(
|
|
Enumeration fontNumber,
|
|
Logical vertical,
|
|
GraphicsDisplay::Justification justification,
|
|
char *stringPointer
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(graphicsDisplay); // HACK!!!! Check for NULL!
|
|
|
|
Check_Fpu();
|
|
return
|
|
graphicsDisplay->
|
|
TextBounds(
|
|
fontNumber,
|
|
vertical,
|
|
justification,
|
|
stringPointer
|
|
);
|
|
}
|
|
|
|
void
|
|
GraphicsPort::SetColor(
|
|
PaletteTriplet * /*source_color*/,
|
|
int /*color_index*/
|
|
)
|
|
{
|
|
Fail("GraphicsPort::SetColor not overridden");
|
|
}
|
|
|
|
void
|
|
GraphicsPort::DrawPoint(
|
|
int /*color*/,
|
|
Enumeration /*operation*/,
|
|
int /*x*/,
|
|
int /*y*/
|
|
)
|
|
{
|
|
Fail("GraphicsPort::DrawPoint not overridden");
|
|
}
|
|
|
|
void
|
|
GraphicsPort::DrawLine(
|
|
int /*color*/,
|
|
Enumeration /*operation*/,
|
|
int /*x1*/,
|
|
int /*y1*/,
|
|
int /*x2*/,
|
|
int /*y2*/,
|
|
Logical /*include_last_pixel*/
|
|
)
|
|
{
|
|
Fail("GraphicsPort::DrawLine not overridden");
|
|
}
|
|
|
|
void
|
|
GraphicsPort::DrawFilledRectangle(
|
|
int /*color*/,
|
|
Enumeration /*operation*/,
|
|
int /*x1*/,
|
|
int /*y1*/,
|
|
int /*x2*/,
|
|
int /*y2*/
|
|
)
|
|
{
|
|
Fail("GraphicsPort::DrawFilledRectangle not overridden");
|
|
}
|
|
|
|
void
|
|
GraphicsPort::DrawText(
|
|
int /*color*/,
|
|
Enumeration /*operation*/,
|
|
Logical /*opaque*/,
|
|
int /*rotation*/,
|
|
Enumeration /*fontNumber*/,
|
|
Logical /*vertical*/,
|
|
GraphicsDisplay::Justification /*justification*/,
|
|
Rectangle2D * /*clippingRectanglePtr*/,
|
|
char * /*stringPointer*/
|
|
)
|
|
{
|
|
Fail("GraphicsPort::DrawText not overridden");
|
|
}
|
|
|
|
void
|
|
GraphicsPort::DrawBitMap(
|
|
int /*color*/,
|
|
Enumeration /*operation*/,
|
|
int /*rotation*/,
|
|
int /*x*/,
|
|
int /*y*/,
|
|
BitMap * /*bitmap*/,
|
|
int /*sx1*/,
|
|
int /*sy1*/,
|
|
int /*sx2*/,
|
|
int /*sy2*/ // these are SOURCE coordinates
|
|
)
|
|
{
|
|
Fail("GraphicsPort::DrawBitMap not overridden");
|
|
}
|
|
|
|
void
|
|
GraphicsPort::DrawBitMapOpaque(
|
|
int /*color*/,
|
|
int /*background*/,
|
|
Enumeration /*operation*/,
|
|
int /*rotation*/,
|
|
int /*x*/,
|
|
int /*y*/,
|
|
BitMap * /*bitmap*/,
|
|
int /*sx1*/,
|
|
int /*sy1*/,
|
|
int /*sx2*/,
|
|
int /*sy2*/ // these are SOURCE coordinates
|
|
)
|
|
{
|
|
Fail("GraphicsPort::DrawBitMapOpaque not overridden");
|
|
}
|
|
|
|
void
|
|
GraphicsPort::DrawPixelMap8(
|
|
Enumeration /*operation*/,
|
|
Logical /*opaque*/,
|
|
int /*rotation*/,
|
|
int /*x*/,
|
|
int /*y*/,
|
|
PixelMap8 * /*pixelmap*/,
|
|
int /*sx1*/,
|
|
int /*sy1*/,
|
|
int /*sx2*/,
|
|
int /*sy2*/ // these are SOURCE coordinates
|
|
)
|
|
{
|
|
Fail("GraphicsPort::DrawPixelMap8 not overridden");
|
|
}
|
|
|
|
void
|
|
GraphicsPort::DrawPixelMap8SingleColor(
|
|
int /*color*/,
|
|
Enumeration /*operation*/,
|
|
int /*rotation*/,
|
|
int /*x*/,
|
|
int /*y*/,
|
|
PixelMap8 * /*pixelmap*/,
|
|
int /*sx1*/,
|
|
int /*sy1*/,
|
|
int /*sx2*/,
|
|
int /*sy2*/ // these are SOURCE coordinates
|
|
)
|
|
{
|
|
Fail("GraphicsPort::DrawPixelMap8SingleColor not overridden");
|
|
}
|
|
|
|
//########################################################################
|
|
//######################### GraphicsViewRecord ###########################
|
|
//########################################################################
|
|
GraphicsViewRecord::GraphicsViewRecord()
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
commandListLength = 4096;
|
|
commandListIndex = 0;
|
|
commandList = new char[commandListLength];
|
|
Register_Pointer(commandList);
|
|
link = NULL;
|
|
Check_Fpu();
|
|
}
|
|
|
|
GraphicsViewRecord::~GraphicsViewRecord()
|
|
{
|
|
Check(this);
|
|
|
|
if (link != NULL)
|
|
{
|
|
Check(link);
|
|
Unregister_Object(link);
|
|
delete link;
|
|
link = NULL; // safety code
|
|
}
|
|
|
|
if (commandList != NULL)
|
|
{
|
|
Unregister_Pointer(commandList);
|
|
delete commandList;
|
|
commandList = NULL; // safety code
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
Logical
|
|
GraphicsViewRecord::TestInstance() const
|
|
{
|
|
return True;
|
|
}
|
|
|
|
void
|
|
GraphicsViewRecord::Clear()
|
|
{
|
|
Check(this);
|
|
|
|
if (link != NULL)
|
|
{
|
|
Check(link);
|
|
link->Clear();
|
|
}
|
|
|
|
commandListIndex = 0;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsViewRecord::Draw(GraphicsView *graphics_view, int forced_color)
|
|
{
|
|
Check(this);
|
|
|
|
GraphicsPort
|
|
*graphics_port(graphics_view->graphicsPort);
|
|
if (graphics_port == NULL)
|
|
{
|
|
Clear();
|
|
return;
|
|
}
|
|
|
|
PixelMap8
|
|
*pixelmap_pointer;
|
|
BitMap
|
|
*bitmap_pointer;
|
|
|
|
int
|
|
running=1,
|
|
color, bg,
|
|
op,
|
|
x1, y1, x2, y2,
|
|
sx1, sy1, sx2, sy2,
|
|
rot, q;
|
|
|
|
//--------------------------------------------------------------
|
|
// Mark end of list, rewind to beginning
|
|
//--------------------------------------------------------------
|
|
PutChar(GraphicsViewRecord::endCommand);
|
|
Clear();
|
|
//--------------------------------------------------------------
|
|
// Parse the command stream
|
|
//--------------------------------------------------------------
|
|
while(running)
|
|
{
|
|
switch(GetChar())
|
|
{
|
|
case endCommand:
|
|
running = 0;
|
|
break;
|
|
|
|
#define RECORDER_POINT(recorder, color, op, x1, y1) \
|
|
if (recorder != NULL) \
|
|
{ \
|
|
recorder->PutChar(GraphicsViewRecord::pointCommand); \
|
|
recorder->PutShort(color); \
|
|
recorder->PutChar(op); \
|
|
recorder->PutShort(x1); \
|
|
recorder->PutShort(y1); \
|
|
}
|
|
case pointCommand:
|
|
color = GetShort();
|
|
op = GetChar();
|
|
x1 = GetShort();
|
|
y1 = GetShort();
|
|
|
|
if (forced_color != -1)
|
|
{
|
|
color = forced_color;
|
|
}
|
|
graphics_port->DrawPoint(color, op, x1, y1);
|
|
break;
|
|
|
|
#define RECORDER_LINE(recorder, color, op, x1, y1, x2, y2, endpoint) \
|
|
if (recorder != NULL) \
|
|
{ \
|
|
recorder->PutChar(GraphicsViewRecord::lineCommand); \
|
|
recorder->PutShort(color); \
|
|
recorder->PutChar(op); \
|
|
recorder->PutShort(x1); \
|
|
recorder->PutShort(y1); \
|
|
recorder->PutShort(x2); \
|
|
recorder->PutShort(y2); \
|
|
recorder->PutLogical(endpoint); \
|
|
}
|
|
case lineCommand:
|
|
color = GetShort();
|
|
op = GetChar();
|
|
x1 = GetShort();
|
|
y1 = GetShort();
|
|
x2 = GetShort();
|
|
y2 = GetShort();
|
|
q = GetLogical();
|
|
|
|
if (forced_color != -1)
|
|
{
|
|
color = forced_color;
|
|
}
|
|
graphics_port->DrawLine(color, op, x1, y1, x2, y2, q);
|
|
break;
|
|
|
|
#define RECORDER_FRECT(recorder, color, op, x1, y1, x2, y2) \
|
|
if (recorder != NULL) \
|
|
{ \
|
|
recorder->PutChar(GraphicsViewRecord::frectCommand); \
|
|
recorder->PutShort(color); \
|
|
recorder->PutChar(op); \
|
|
recorder->PutShort(x1); \
|
|
recorder->PutShort(y1); \
|
|
recorder->PutShort(x2); \
|
|
recorder->PutShort(y2); \
|
|
}
|
|
case frectCommand:
|
|
color = GetShort();
|
|
op = GetChar();
|
|
x1 = GetShort();
|
|
y1 = GetShort();
|
|
x2 = GetShort();
|
|
y2 = GetShort();
|
|
|
|
if (forced_color != -1)
|
|
{
|
|
color = forced_color;
|
|
}
|
|
graphics_port->DrawFilledRectangle(color, op, x1, y1, x2, y2);
|
|
break;
|
|
|
|
#define RECORDER_BITMAP(r, color, op, rot, x1, y1, p, sx1, sy1, sx2, sy2) \
|
|
if (r != NULL) \
|
|
{ \
|
|
r->PutChar(GraphicsViewRecord::bitmapCommand); \
|
|
r->PutShort(color); \
|
|
r->PutChar(op); \
|
|
r->PutShort(rot); \
|
|
r->PutShort(x1); \
|
|
r->PutShort(y1); \
|
|
r->PutPointer(p); \
|
|
r->PutShort(sx1); \
|
|
r->PutShort(sy1); \
|
|
r->PutShort(sx2); \
|
|
r->PutShort(sy2); \
|
|
}
|
|
case bitmapCommand:
|
|
color = GetShort();
|
|
op = GetChar();
|
|
rot = GetShort();
|
|
x1 = GetShort();
|
|
y1 = GetShort();
|
|
bitmap_pointer = (BitMap *) GetPointer();
|
|
sx1 = GetShort();
|
|
sy1 = GetShort();
|
|
sx2 = GetShort();
|
|
sy2 = GetShort();
|
|
|
|
Check(bitmap_pointer);
|
|
|
|
if (forced_color != -1)
|
|
{
|
|
color = forced_color;
|
|
}
|
|
graphics_port->DrawBitMap(
|
|
color,
|
|
op,
|
|
rot,
|
|
x1, y1,
|
|
bitmap_pointer,
|
|
sx1, sy1, sx2, sy2
|
|
);
|
|
break;
|
|
|
|
#define RECORDER_BITMAP_OPAQUE( \
|
|
r, fg, bg, op, rot, x1, y1, p, sx1, sy1, sx2, sy2) \
|
|
if (r != NULL) \
|
|
{ \
|
|
r->PutChar(GraphicsViewRecord::bitmapOpaqueCommand); \
|
|
r->PutShort(fg); \
|
|
r->PutShort(bg); \
|
|
r->PutChar(op); \
|
|
r->PutShort(rot); \
|
|
r->PutShort(x1); \
|
|
r->PutShort(y1); \
|
|
r->PutPointer(p); \
|
|
r->PutShort(sx1); \
|
|
r->PutShort(sy1); \
|
|
r->PutShort(sx2); \
|
|
r->PutShort(sy2); \
|
|
}
|
|
case bitmapOpaqueCommand:
|
|
color = GetShort();
|
|
bg = GetShort();
|
|
op = GetChar();
|
|
rot = GetShort();
|
|
x1 = GetShort();
|
|
y1 = GetShort();
|
|
bitmap_pointer = (BitMap *) GetPointer();
|
|
sx1 = GetShort();
|
|
sy1 = GetShort();
|
|
sx2 = GetShort();
|
|
sy2 = GetShort();
|
|
|
|
Check(bitmap_pointer);
|
|
|
|
if (forced_color != -1)
|
|
{
|
|
color = forced_color;
|
|
}
|
|
graphics_port->DrawBitMapOpaque(
|
|
color,
|
|
bg,
|
|
op,
|
|
rot,
|
|
x1, y1,
|
|
bitmap_pointer,
|
|
sx1, sy1, sx2, sy2
|
|
);
|
|
break;
|
|
|
|
#define RECORDER_PIXELMAP( \
|
|
r, op, q, rot, x1, y1, p, sx1, sy1, sx2, sy2) \
|
|
if (r != NULL) \
|
|
{ \
|
|
r->PutChar(GraphicsViewRecord::pixelmap8Command); \
|
|
r->PutChar(op); \
|
|
r->PutShort(q); \
|
|
r->PutShort(rot); \
|
|
r->PutShort(x1); \
|
|
r->PutShort(y1); \
|
|
r->PutPointer(p); \
|
|
r->PutShort(sx1); \
|
|
r->PutShort(sy1); \
|
|
r->PutShort(sx2); \
|
|
r->PutShort(sy2); \
|
|
}
|
|
case pixelmap8Command:
|
|
op = GetChar();
|
|
q = GetShort();
|
|
rot = GetShort();
|
|
x1 = GetShort();
|
|
y1 = GetShort();
|
|
pixelmap_pointer = (PixelMap8 *) GetPointer();
|
|
sx1 = GetShort();
|
|
sy1 = GetShort();
|
|
sx2 = GetShort();
|
|
sy2 = GetShort();
|
|
|
|
Check(pixelmap_pointer);
|
|
|
|
if (forced_color != -1)
|
|
{
|
|
graphics_port->DrawPixelMap8SingleColor(
|
|
forced_color,
|
|
op,
|
|
rot,
|
|
x1, y1,
|
|
pixelmap_pointer,
|
|
sx1, sy1, sx2, sy2
|
|
);
|
|
}
|
|
else
|
|
{
|
|
graphics_port->DrawPixelMap8(
|
|
op,
|
|
q,
|
|
rot,
|
|
x1, y1,
|
|
pixelmap_pointer,
|
|
sx1, sy1, sx2, sy2
|
|
);
|
|
}
|
|
break;
|
|
|
|
#define RECORDER_PIXELMAP_SINGLE_COLOR( \
|
|
r, color, op, rot, x1, y1, p, sx1, sy1, sx2, sy2) \
|
|
if (r != NULL) \
|
|
{ \
|
|
r->PutChar(GraphicsViewRecord::pixelmap8SolidCommand); \
|
|
r->PutShort(color); \
|
|
r->PutChar(op); \
|
|
r->PutShort(rot); \
|
|
r->PutShort(x1); \
|
|
r->PutShort(y1); \
|
|
r->PutPointer(p); \
|
|
r->PutShort(sx1); \
|
|
r->PutShort(sy1); \
|
|
r->PutShort(sx2); \
|
|
r->PutShort(sy2); \
|
|
}
|
|
case pixelmap8SolidCommand:
|
|
color = GetShort();
|
|
op = GetChar();
|
|
rot = GetShort();
|
|
x1 = GetShort();
|
|
y1 = GetShort();
|
|
pixelmap_pointer = (PixelMap8 *) GetPointer();
|
|
sx1 = GetShort();
|
|
sy1 = GetShort();
|
|
sx2 = GetShort();
|
|
sy2 = GetShort();
|
|
|
|
Check(pixelmap_pointer);
|
|
|
|
if (forced_color != -1)
|
|
{
|
|
color = forced_color;
|
|
}
|
|
graphics_port->DrawPixelMap8SingleColor(
|
|
color,
|
|
op,
|
|
rot,
|
|
x1, y1,
|
|
pixelmap_pointer,
|
|
sx1, sy1, sx2, sy2
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsViewRecord::PutChar(int value)
|
|
{
|
|
Check(this);
|
|
//--------------------------------------------------------------
|
|
// If the buffer is not full, jam it in
|
|
//--------------------------------------------------------------
|
|
if (commandListIndex < commandListLength)
|
|
{
|
|
commandList[commandListIndex++] = (char) value;
|
|
}
|
|
//--------------------------------------------------------------
|
|
// If the buffer IS full, put it in the 'next' linked buffer
|
|
//--------------------------------------------------------------
|
|
else
|
|
{
|
|
//--------------------------------------------------------------
|
|
// If there is no linked buffer, create one
|
|
//--------------------------------------------------------------
|
|
if (link == NULL)
|
|
{
|
|
link = new GraphicsViewRecord();
|
|
Check(link);
|
|
Register_Object(link);
|
|
}
|
|
//--------------------------------------------------------------
|
|
// Give it to the linked buffer
|
|
//--------------------------------------------------------------
|
|
link->PutChar(value);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
int
|
|
GraphicsViewRecord::GetChar()
|
|
{
|
|
Check(this);
|
|
//--------------------------------------------------------------
|
|
// If the buffer is not empty, pull the char out
|
|
//--------------------------------------------------------------
|
|
if (commandListIndex < commandListLength)
|
|
{
|
|
Check_Fpu();
|
|
return (int) commandList[commandListIndex++];
|
|
}
|
|
//--------------------------------------------------------------
|
|
// If the buffer IS empty, get char from the 'next' linked buffer
|
|
//--------------------------------------------------------------
|
|
else
|
|
{
|
|
//--------------------------------------------------------------
|
|
// If there is no linked buffer, it's a catastrophe
|
|
//--------------------------------------------------------------
|
|
if (link == NULL)
|
|
{
|
|
Fail("GraphicsViewRecord::GetChar() has no link");
|
|
Check_Fpu();
|
|
return GraphicsViewRecord::endCommand;
|
|
}
|
|
//--------------------------------------------------------------
|
|
// Read from the linked buffer
|
|
//--------------------------------------------------------------
|
|
Check(link);
|
|
Check_Fpu();
|
|
return link->GetChar();
|
|
}
|
|
}
|
|
|
|
void
|
|
GraphicsViewRecord::PutLogical(Logical value)
|
|
{
|
|
Check(this);
|
|
if (value)
|
|
{
|
|
PutChar(1);
|
|
}
|
|
else
|
|
{
|
|
PutChar(0);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
Logical
|
|
GraphicsViewRecord::GetLogical()
|
|
{
|
|
Check(this);
|
|
Check_Fpu();
|
|
if (GetChar())
|
|
{
|
|
return True;
|
|
}
|
|
else
|
|
{
|
|
return False;
|
|
}
|
|
}
|
|
|
|
void
|
|
GraphicsViewRecord::PutShort(int value)
|
|
{
|
|
Check(this);
|
|
PutChar(value >> 8);
|
|
PutChar(value);
|
|
Check_Fpu();
|
|
}
|
|
|
|
int
|
|
GraphicsViewRecord::GetShort()
|
|
{
|
|
Check(this);
|
|
int
|
|
q;
|
|
|
|
q = GetChar() << 8;
|
|
q |= GetChar() & 0xFF;
|
|
|
|
if (q & 0x8000) // extend sign
|
|
{
|
|
q |= 0xFFFF0000;
|
|
}
|
|
|
|
Check_Fpu();
|
|
return q;
|
|
}
|
|
|
|
void
|
|
GraphicsViewRecord::PutPointer(void *pointer)
|
|
{
|
|
Check(this);
|
|
Verify(pointer != NULL);
|
|
union
|
|
{
|
|
void *pointer;
|
|
int value; // assumes 32-bit integer!
|
|
}
|
|
faker;
|
|
|
|
faker.pointer = pointer;
|
|
|
|
PutChar(faker.value >> 24);
|
|
PutChar(faker.value >> 16);
|
|
PutChar(faker.value >> 8);
|
|
PutChar(faker.value);
|
|
Check_Fpu();
|
|
}
|
|
|
|
|
|
void *
|
|
GraphicsViewRecord::GetPointer()
|
|
{
|
|
Check(this);
|
|
union
|
|
{
|
|
void *pointer;
|
|
int value; // assumes 32-bit integer!
|
|
}
|
|
faker;
|
|
|
|
faker.value = GetChar() << 24;
|
|
faker.value |= (GetChar() & 0xFF) << 16;
|
|
faker.value |= (GetChar() & 0xFF) << 8;
|
|
faker.value |= GetChar() & 0xFF;
|
|
|
|
Verify(faker.pointer != NULL);
|
|
Check_Fpu();
|
|
return faker.pointer;
|
|
}
|
|
|
|
//########################################################################
|
|
//############################ GraphicsView ##############################
|
|
//########################################################################
|
|
GraphicsView::GraphicsView(
|
|
GraphicsPort *graphics_port,
|
|
int x1, int y1, int x2, int y2
|
|
)
|
|
{
|
|
Check_Pointer(this);
|
|
// NOTE: graphics_port may be NULL!
|
|
|
|
//--------------------------------------------------------------
|
|
// Initialize values
|
|
//--------------------------------------------------------------
|
|
graphicsPort = graphics_port;
|
|
|
|
currentPosition.x = 0;
|
|
currentPosition.y = 0;
|
|
currentFontID = 0;
|
|
currentColor = 1;
|
|
currentOperation = GraphicsDisplay::Replace;
|
|
|
|
//--------------------------------------------------------------
|
|
// Set areaWithinPort
|
|
//--------------------------------------------------------------
|
|
if (graphics_port == NULL)
|
|
{
|
|
//--------------------------------------------------------------
|
|
// GraphicsPort doesn't exist, set areaWithinPort to safe value
|
|
//--------------------------------------------------------------
|
|
areaWithinPort.bottomLeft.x = 0;
|
|
areaWithinPort.bottomLeft.y = 0;
|
|
areaWithinPort.topRight.x = 0;
|
|
areaWithinPort.topRight.y = 0;
|
|
|
|
origin = areaWithinPort.bottomLeft;
|
|
}
|
|
else
|
|
{
|
|
//--------------------------------------------------------------
|
|
// Set areaWithinPort to given size
|
|
//--------------------------------------------------------------
|
|
areaWithinPort.bottomLeft.x = x1;
|
|
areaWithinPort.bottomLeft.y = y1;
|
|
areaWithinPort.topRight.x = x2;
|
|
areaWithinPort.topRight.y = y2;
|
|
//--------------------------------------------------------------
|
|
// Adjust area according to graphicsPort offset
|
|
//--------------------------------------------------------------
|
|
areaWithinPort.bottomLeft += graphicsPort->bounds.bottomLeft;
|
|
areaWithinPort.topRight += graphicsPort->bounds.bottomLeft;
|
|
//--------------------------------------------------------------
|
|
// Set origin to bottom left corner of area
|
|
//--------------------------------------------------------------
|
|
origin = areaWithinPort.bottomLeft;
|
|
//--------------------------------------------------------------
|
|
// Clip to graphicsPort bounds
|
|
//--------------------------------------------------------------
|
|
areaWithinPort.Intersection(areaWithinPort, graphicsPort->bounds);
|
|
}
|
|
//--------------------------------------------------------------
|
|
// Set clipping rectangle to size of view
|
|
//--------------------------------------------------------------
|
|
clippingRectangle = areaWithinPort;
|
|
//--------------------------------------------------------------
|
|
// Clear recorder pointer
|
|
//--------------------------------------------------------------
|
|
recorder = (GraphicsViewRecord *) NULL;
|
|
Check_Fpu();
|
|
}
|
|
|
|
GraphicsView::GraphicsView(GraphicsPort *graphics_port)
|
|
{
|
|
Check_Pointer(this);
|
|
|
|
// NOTE: graphics_port may be NULL!
|
|
//--------------------------------------------------------------
|
|
// Initialize values
|
|
//--------------------------------------------------------------
|
|
graphicsPort = graphics_port;
|
|
|
|
currentPosition.x = 0;
|
|
currentPosition.y = 0;
|
|
currentFontID = 0;
|
|
currentColor = 1;
|
|
currentOperation = GraphicsDisplay::Replace;
|
|
//--------------------------------------------------------------
|
|
// Set areaWithinPort
|
|
//--------------------------------------------------------------
|
|
if (graphics_port == NULL)
|
|
{
|
|
//--------------------------------------------------------------
|
|
// GraphicsPort doesn't exist, set areaWithinPort to safe value
|
|
//--------------------------------------------------------------
|
|
areaWithinPort.bottomLeft.x = 0;
|
|
areaWithinPort.bottomLeft.y = 0;
|
|
areaWithinPort.topRight.x = 0;
|
|
areaWithinPort.topRight.y = 0;
|
|
}
|
|
else
|
|
{
|
|
//--------------------------------------------------------------
|
|
// Set areaWithinPort to size of graphicsPort
|
|
//--------------------------------------------------------------
|
|
areaWithinPort = graphics_port->bounds;
|
|
}
|
|
//--------------------------------------------------------------
|
|
// Set origin to bottom left corner of area
|
|
//--------------------------------------------------------------
|
|
origin = areaWithinPort.bottomLeft;
|
|
//--------------------------------------------------------------
|
|
// Set clipping rectangle to size of view
|
|
//--------------------------------------------------------------
|
|
clippingRectangle = areaWithinPort;
|
|
//--------------------------------------------------------------
|
|
// Clear recorder pointer
|
|
//--------------------------------------------------------------
|
|
recorder = (GraphicsViewRecord *) NULL;
|
|
Check_Fpu();
|
|
}
|
|
|
|
GraphicsView::~GraphicsView()
|
|
{
|
|
Check(this);
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::SetPositionWithinPort(int x1, int y1, int x2, int y2)
|
|
{
|
|
# if defined(DEBUG)
|
|
Tell(
|
|
"GraphicsView::SetPositionWithinPort(" << x1 <<
|
|
"," << y1 <<
|
|
", " << x2 <<
|
|
"," << y2 <<
|
|
"\n"
|
|
);
|
|
# endif
|
|
Check(this);
|
|
Verify (x2 > x1);
|
|
Verify (y2 > y1);
|
|
|
|
if (graphicsPort != NULL)
|
|
{
|
|
//--------------------------------------------------------------
|
|
// Set the new area
|
|
//--------------------------------------------------------------
|
|
areaWithinPort.bottomLeft.x = x1;
|
|
areaWithinPort.bottomLeft.y = y1;
|
|
areaWithinPort.topRight.x = x2-1;
|
|
areaWithinPort.topRight.y = y2-1;
|
|
//--------------------------------------------------------------
|
|
// Adjust area according to graphicsPort offset
|
|
//--------------------------------------------------------------
|
|
areaWithinPort.bottomLeft += graphicsPort->bounds.bottomLeft;
|
|
areaWithinPort.topRight += graphicsPort->bounds.bottomLeft;
|
|
//--------------------------------------------------------------
|
|
// Set new origin
|
|
//--------------------------------------------------------------
|
|
origin = areaWithinPort.bottomLeft;
|
|
//--------------------------------------------------------------
|
|
// Clip to graphicsPort bounds
|
|
//--------------------------------------------------------------
|
|
areaWithinPort.Intersection(areaWithinPort, graphicsPort->bounds);
|
|
//--------------------------------------------------------------
|
|
// Set clipping rectangle to size of view
|
|
//--------------------------------------------------------------
|
|
clippingRectangle = areaWithinPort;
|
|
}
|
|
# if defined(DEBUG)
|
|
Tell(
|
|
"areaWithinPort=" << areaWithinPort <<
|
|
"\n"
|
|
);
|
|
# endif
|
|
Check_Fpu();
|
|
}
|
|
|
|
Logical
|
|
GraphicsView::TestInstance() const
|
|
{
|
|
return True;
|
|
}
|
|
|
|
void
|
|
GraphicsView::ShowInstance(char *indent)
|
|
{
|
|
Check(this);
|
|
|
|
std::cout << indent << "GraphicsView:\n";
|
|
|
|
char
|
|
temp[80];
|
|
|
|
Str_Copy(temp, indent, 80);
|
|
Str_Cat(temp, "...", 80);
|
|
|
|
std::cout << temp << "areaWithinPort =" << areaWithinPort << "\n";
|
|
std::cout << temp << "origin =" << origin << "\n";
|
|
std::cout << temp << "currentPosition =" << currentPosition << "\n";
|
|
std::cout << temp << "currentFontID =" << currentFontID << "\n";
|
|
std::cout << temp << "currentColor =" << currentColor << "\n";
|
|
std::cout << temp << "clippingRectangle =" << clippingRectangle << "\n";
|
|
std::cout << temp << "currentOperation =";
|
|
switch(currentOperation)
|
|
{
|
|
case GraphicsDisplay::And: std::cout << "AND\n"; break;
|
|
case GraphicsDisplay::Or: std::cout << "OR\n"; break;
|
|
case GraphicsDisplay::Replace: std::cout << "REPLACE\n"; break;
|
|
default: std::cout << "Unsupported type:" << currentOperation << "\n"; break;
|
|
}
|
|
std::cout << temp << "graphicsPort =" << graphicsPort << "\n";
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::SetOperation(GraphicsDisplay::Operation new_operation)
|
|
{
|
|
Check(this);
|
|
currentOperation = new_operation;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::SetOrigin(int x, int y)
|
|
{
|
|
# if defined(DEBUG)
|
|
Tell(
|
|
"GraphicsView::SetOrigin(" << x <<
|
|
"," << y <<
|
|
"\n"
|
|
);
|
|
# endif
|
|
Check(this);
|
|
//--------------------------------------------------------------
|
|
// Adjust the current position
|
|
//--------------------------------------------------------------
|
|
currentPosition -= origin;
|
|
//--------------------------------------------------------------
|
|
// Set the new origin
|
|
//--------------------------------------------------------------
|
|
origin.x = x + areaWithinPort.bottomLeft.x;
|
|
origin.y = y + areaWithinPort.bottomLeft.y;
|
|
//--------------------------------------------------------------
|
|
// Adjust the current position to the new location
|
|
//--------------------------------------------------------------
|
|
currentPosition += origin;
|
|
# if defined(DEBUG)
|
|
Tell(
|
|
"origin=" << origin <<
|
|
", currentPosition=" << currentPosition <<
|
|
"\n"
|
|
);
|
|
# endif
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::SetFont(Enumeration new_font_ID)
|
|
{
|
|
Check(this);
|
|
|
|
currentFontID = new_font_ID;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::SetColor(int new_color)
|
|
{
|
|
Check(this);
|
|
|
|
currentColor = new_color;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::SetClippingRectangle(Rectangle2D *clippingRectanglePtr)
|
|
{
|
|
Check(this);
|
|
Check(clippingRectanglePtr);
|
|
|
|
Rectangle2D r;
|
|
//--------------------------------------------------------------
|
|
// Get a copy of the requested clipping rectangle,
|
|
// add origin offset
|
|
//--------------------------------------------------------------
|
|
r = *clippingRectanglePtr;
|
|
r.bottomLeft += origin;
|
|
r.topRight += origin;
|
|
//--------------------------------------------------------------
|
|
// Limit it to the graphicsPort bounds, save the result
|
|
//--------------------------------------------------------------
|
|
if (graphicsPort != NULL)
|
|
{
|
|
clippingRectangle.Intersection(graphicsPort->bounds, r);
|
|
}
|
|
else
|
|
{
|
|
clippingRectangle.MakeEmpty();
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::ClearClippingRectangle()
|
|
{
|
|
Check(this);
|
|
|
|
clippingRectangle = areaWithinPort;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::MoveToAbsolute(int x, int y)
|
|
{
|
|
Check(this);
|
|
|
|
currentPosition.x = origin.x + x;
|
|
currentPosition.y = origin.y + y;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::MoveToRelative(int x, int y)
|
|
{
|
|
Check(this);
|
|
|
|
currentPosition.x += x;
|
|
currentPosition.y += y;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawPoint()
|
|
{
|
|
Check(this);
|
|
|
|
int code(BuildPointCode(currentPosition));
|
|
|
|
if (graphicsPort != NULL)
|
|
{
|
|
if (code == GraphicsView::IsWithin)
|
|
{
|
|
graphicsPort->
|
|
DrawPoint(
|
|
currentColor,
|
|
currentOperation,
|
|
currentPosition.x, currentPosition.y
|
|
);
|
|
|
|
RECORDER_POINT(
|
|
recorder,
|
|
currentColor,
|
|
currentOperation,
|
|
currentPosition.x, currentPosition.y
|
|
);
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawLineToAbsolute(int x, int y)
|
|
{
|
|
Check(this);
|
|
|
|
Vector2DOf<int>
|
|
end;
|
|
|
|
end.x = origin.x + x;
|
|
end.y = origin.y + y;
|
|
DrawLine(currentPosition, end, True);
|
|
currentPosition = end;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawLineToRelative(int x, int y)
|
|
{
|
|
Check(this);
|
|
|
|
Vector2DOf<int>
|
|
end;
|
|
|
|
end.x = currentPosition.x + x;
|
|
end.y = currentPosition.y + y;
|
|
DrawLine(currentPosition, end, True);
|
|
currentPosition = end;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawThickLineToAbsolute(int x, int y)
|
|
{
|
|
Check(this);
|
|
|
|
Vector2DOf<int>
|
|
end,
|
|
start,
|
|
stop;
|
|
|
|
end.x = origin.x + x;
|
|
end.y = origin.y + y;
|
|
|
|
start.x = currentPosition.x;
|
|
start.y = currentPosition.y;
|
|
stop.x = end.x;
|
|
stop.y = end.y;
|
|
DrawThickLine(start, stop);
|
|
|
|
currentPosition = end;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawThickLineToRelative(int x, int y)
|
|
{
|
|
Check(this);
|
|
|
|
Vector2DOf<int>
|
|
end,
|
|
start,
|
|
stop;
|
|
|
|
end.x = currentPosition.x + x;
|
|
end.y = currentPosition.y + y;
|
|
|
|
start.x = currentPosition.x;
|
|
start.y = currentPosition.y;
|
|
stop.x = end.x;
|
|
stop.y = end.y;
|
|
DrawThickLine(start, stop);
|
|
|
|
currentPosition = end;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawRectangleToAbsolute(int x, int y)
|
|
{
|
|
Check(this);
|
|
|
|
Vector2DOf<int>
|
|
home;
|
|
|
|
home = currentPosition;
|
|
home -= origin;
|
|
DrawLineToAbsolute(home.x, y);
|
|
DrawLineToAbsolute(x, y);
|
|
DrawLineToAbsolute(x, home.y);
|
|
DrawLineToAbsolute(home.x, home.y);
|
|
|
|
currentPosition.x = x;
|
|
currentPosition.y = y;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawRectangleToRelative(int x, int y)
|
|
{
|
|
Check(this);
|
|
|
|
Vector2DOf<int>
|
|
home;
|
|
|
|
home = currentPosition;
|
|
home -= origin;
|
|
DrawLineToRelative(0, y);
|
|
DrawLineToRelative(x, 0);
|
|
DrawLineToRelative(0, -y);
|
|
DrawLineToRelative(-x, 0);
|
|
|
|
currentPosition.x = home.x + x;
|
|
currentPosition.y = home.y + y;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawFilledRectangleToAbsolute(int x, int y)
|
|
{
|
|
Check(this);
|
|
|
|
Rectangle2D r;
|
|
|
|
r.bottomLeft = currentPosition;
|
|
r.topRight.x = origin.x + x;
|
|
r.topRight.y = origin.y + y;
|
|
|
|
DrawFilledRectangle(r);
|
|
|
|
currentPosition = r.topRight;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawFilledRectangleToRelative(int x, int y)
|
|
{
|
|
Check(this);
|
|
|
|
Rectangle2D r;
|
|
|
|
r.bottomLeft = currentPosition;
|
|
r.topRight.x = currentPosition.x + x;
|
|
r.topRight.y = currentPosition.y + y;
|
|
|
|
DrawFilledRectangle(r);
|
|
|
|
currentPosition = r.topRight;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawText(
|
|
Logical ,
|
|
Logical ,
|
|
GraphicsDisplay::Justification ,
|
|
Rectangle2D *,
|
|
char *
|
|
)
|
|
{
|
|
Check(this);
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawBitMap(
|
|
int rotation,
|
|
BitMap *bitmap,
|
|
int sx1, int sy1, int sx2, int sy2 // these are SOURCE coordinates
|
|
)
|
|
{
|
|
Check(this);
|
|
|
|
Rectangle2D sourceBounds(sx1, sy1, sx2, sy2);
|
|
Vector2DOf<int> position;
|
|
|
|
if (bitmap != NULL)
|
|
{
|
|
Check(bitmap);
|
|
|
|
if (ClipImage(&sourceBounds, &position, bitmap->Data.Size))
|
|
{
|
|
graphicsPort->
|
|
DrawBitMap(
|
|
currentColor,
|
|
currentOperation,
|
|
rotation,
|
|
position.x, position.y,
|
|
bitmap,
|
|
sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y,
|
|
sourceBounds.topRight.x, sourceBounds.topRight.y
|
|
);
|
|
RECORDER_BITMAP(
|
|
recorder,
|
|
currentColor,
|
|
currentOperation,
|
|
rotation,
|
|
position.x, position.y,
|
|
bitmap,
|
|
sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y,
|
|
sourceBounds.topRight.x, sourceBounds.topRight.y
|
|
);
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawBitMapOpaque(
|
|
int background,
|
|
int rotation,
|
|
BitMap *bitmap,
|
|
int sx1, int sy1, int sx2, int sy2 // these are SOURCE coordinates
|
|
)
|
|
{
|
|
Check(this);
|
|
|
|
Rectangle2D sourceBounds(sx1, sy1, sx2, sy2);
|
|
Vector2DOf<int> position;
|
|
|
|
if (bitmap != NULL)
|
|
{
|
|
Check(bitmap);
|
|
|
|
if (ClipImage(&sourceBounds, &position, bitmap->Data.Size))
|
|
{
|
|
graphicsPort->
|
|
DrawBitMapOpaque(
|
|
currentColor,
|
|
background,
|
|
currentOperation,
|
|
rotation,
|
|
position.x, position.y,
|
|
bitmap,
|
|
sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y,
|
|
sourceBounds.topRight.x, sourceBounds.topRight.y
|
|
);
|
|
RECORDER_BITMAP_OPAQUE(
|
|
recorder,
|
|
currentColor,
|
|
background,
|
|
currentOperation,
|
|
rotation,
|
|
position.x, position.y,
|
|
bitmap,
|
|
sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y,
|
|
sourceBounds.topRight.x, sourceBounds.topRight.y
|
|
);
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawPixelMap8(
|
|
Logical opaque,
|
|
int rotation,
|
|
PixelMap8 *pixelmap,
|
|
int sx1, int sy1, int sx2, int sy2 // these are SOURCE coordinates
|
|
)
|
|
{
|
|
Check(this);
|
|
|
|
Rectangle2D sourceBounds(sx1, sy1, sx2, sy2);
|
|
Vector2DOf<int> position;
|
|
|
|
if (pixelmap != NULL)
|
|
{
|
|
Check(pixelmap);
|
|
|
|
if (ClipImage(&sourceBounds, &position, pixelmap->Data.Size))
|
|
{
|
|
graphicsPort->
|
|
DrawPixelMap8(
|
|
currentOperation,
|
|
opaque,
|
|
rotation,
|
|
position.x, position.y,
|
|
pixelmap,
|
|
sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y,
|
|
sourceBounds.topRight.x, sourceBounds.topRight.y
|
|
);
|
|
RECORDER_PIXELMAP(
|
|
recorder,
|
|
currentOperation,
|
|
opaque,
|
|
rotation,
|
|
position.x, position.y,
|
|
pixelmap,
|
|
sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y,
|
|
sourceBounds.topRight.x, sourceBounds.topRight.y
|
|
);
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawPixelMap8SingleColor(
|
|
int rotation,
|
|
PixelMap8 *pixelmap,
|
|
int sx1, int sy1, int sx2, int sy2 // these are SOURCE coordinates
|
|
)
|
|
{
|
|
Check(this);
|
|
|
|
Rectangle2D sourceBounds(sx1, sy1, sx2, sy2);
|
|
Vector2DOf<int> position;
|
|
|
|
if (pixelmap != NULL)
|
|
{
|
|
Check(pixelmap);
|
|
|
|
if (ClipImage(&sourceBounds, &position, pixelmap->Data.Size))
|
|
{
|
|
graphicsPort->
|
|
DrawPixelMap8SingleColor(
|
|
currentColor,
|
|
currentOperation,
|
|
rotation,
|
|
position.x, position.y,
|
|
pixelmap,
|
|
sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y,
|
|
sourceBounds.topRight.x, sourceBounds.topRight.y
|
|
);
|
|
RECORDER_PIXELMAP_SINGLE_COLOR(
|
|
recorder,
|
|
currentColor,
|
|
currentOperation,
|
|
rotation,
|
|
position.x, position.y,
|
|
pixelmap,
|
|
sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y,
|
|
sourceBounds.topRight.x, sourceBounds.topRight.y
|
|
);
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::SetColor(
|
|
PaletteTriplet *source_color,
|
|
int color_index
|
|
)
|
|
{
|
|
Check(this);
|
|
Check_Pointer(source_color);
|
|
|
|
if (graphicsPort != NULL)
|
|
{
|
|
graphicsPort->SetColor(source_color, color_index);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::AttachRecorder(GraphicsViewRecord *graphics_view_record)
|
|
{
|
|
Check(this);
|
|
Verify(recorder == NULL);
|
|
Check(graphics_view_record);
|
|
recorder = graphics_view_record;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DetachRecorder()
|
|
{
|
|
Check(this);
|
|
recorder = NULL;
|
|
Check_Fpu();
|
|
}
|
|
|
|
int
|
|
GraphicsView::BuildPointCode(Vector2DOf<int> vector)
|
|
{
|
|
// This is static. Don't attempt to check for signature!
|
|
|
|
int result(0);
|
|
|
|
if (vector.x < clippingRectangle.bottomLeft.x)
|
|
{
|
|
result |= GraphicsView::IsLeft;
|
|
}
|
|
else if (vector.x > clippingRectangle.topRight.x)
|
|
{
|
|
result |= GraphicsView::IsRight;
|
|
}
|
|
|
|
if (vector.y < clippingRectangle.bottomLeft.y)
|
|
{
|
|
result |= GraphicsView::IsBelow;
|
|
}
|
|
else if (vector.y > clippingRectangle.topRight.y)
|
|
{
|
|
result |= GraphicsView::IsAbove;
|
|
}
|
|
Check_Fpu();
|
|
return result;
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawThickLine(
|
|
Vector2DOf<int> start,
|
|
Vector2DOf<int> stop
|
|
)
|
|
{
|
|
Check(this);
|
|
|
|
DrawLine(start, stop, True);
|
|
--start.x;
|
|
--stop.x;
|
|
DrawLine(start, stop, True);
|
|
++start.x;
|
|
++stop.x;
|
|
++start.y;
|
|
++stop.y;
|
|
DrawLine(start, stop, True);
|
|
++start.x;
|
|
++stop.x;
|
|
--start.y;
|
|
--stop.y;
|
|
DrawLine(start, stop, True);
|
|
--start.x;
|
|
--stop.x;
|
|
--start.y;
|
|
--stop.y;
|
|
DrawLine(start, stop, True);
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawLine(
|
|
Vector2DOf<int> start,
|
|
Vector2DOf<int> end,
|
|
Logical include_last_pixel
|
|
)
|
|
{
|
|
# if defined(DEBUG)
|
|
Tell(
|
|
"DrawLine(=" << start <<
|
|
", " << end <<
|
|
", " << include_last_pixel <<
|
|
")\n"
|
|
);
|
|
Tell(
|
|
"clippingRectangle=" << clippingRectangle <<
|
|
"\n"
|
|
);
|
|
# endif
|
|
Check(this);
|
|
|
|
int
|
|
start_code,
|
|
end_code;
|
|
|
|
Logical
|
|
swapped(False),
|
|
start_clipped(False),
|
|
end_clipped(False);
|
|
|
|
if (graphicsPort != NULL)
|
|
{
|
|
//----------------------------------------------------
|
|
// Generate endpoint codes
|
|
//----------------------------------------------------
|
|
start_code = BuildPointCode(start);
|
|
end_code = BuildPointCode(end);
|
|
# if defined(DEBUG)
|
|
Tell(
|
|
"start code=" << start_code <<
|
|
", end_code=" << end_code <<
|
|
"\n"
|
|
);
|
|
# endif
|
|
|
|
//----------------------------------------------------
|
|
// Loop until either both codes are zero
|
|
// or it's completely out of the display
|
|
//----------------------------------------------------
|
|
while(start_code | end_code)
|
|
{
|
|
# if defined(DEBUG)
|
|
Tell(
|
|
"Clipping, start=" << start <<
|
|
", end=" << end <<
|
|
"\n"
|
|
);
|
|
# endif
|
|
//----------------------------------------------------
|
|
// If the line is totally off the display, abandon it
|
|
//----------------------------------------------------
|
|
if ((start_code & end_code) != 0)
|
|
{
|
|
# if defined(DEBUG)
|
|
Tell("Abandoned\n");
|
|
# endif
|
|
return;
|
|
}
|
|
//----------------------------------------------------
|
|
// Make sure an out-of-bounds point is being clipped
|
|
//----------------------------------------------------
|
|
if (start_code == GraphicsView::IsWithin)
|
|
{
|
|
# if defined(DEBUG)
|
|
Tell("Swapping endpoints\n");
|
|
# endif
|
|
|
|
Vector2DOf<int>
|
|
temp_vector;
|
|
temp_vector = start;
|
|
start = end;
|
|
end = temp_vector;
|
|
|
|
int temp_code;
|
|
temp_code = start_code;
|
|
start_code = end_code;
|
|
end_code = temp_code;
|
|
|
|
Logical temp_flag;
|
|
temp_flag = start_clipped;
|
|
start_clipped = end_clipped;
|
|
end_clipped = temp_flag;
|
|
|
|
swapped ^= True;
|
|
}
|
|
//----------------------------------------------------
|
|
// Clip the starting segment
|
|
//----------------------------------------------------
|
|
if (start_code & GraphicsView::IsLeft)
|
|
{
|
|
# if defined(DEBUG)
|
|
Tell("Clip left\n");
|
|
# endif
|
|
Verify(end.x != start.x);
|
|
start.y += (end.y - start.y) *
|
|
(clippingRectangle.bottomLeft.x-start.x) / (end.x-start.x);
|
|
Check_Fpu();
|
|
start.x = clippingRectangle.bottomLeft.x;
|
|
|
|
start_clipped = True;
|
|
}
|
|
else if (start_code & GraphicsView::IsRight)
|
|
{
|
|
# if defined(DEBUG)
|
|
Tell("Clip right\n");
|
|
# endif
|
|
Verify(end.x != start.x);
|
|
start.y += (end.y - start.y) *
|
|
(clippingRectangle.topRight.x-start.x) / (end.x-start.x);
|
|
Check_Fpu();
|
|
start.x = clippingRectangle.topRight.x;
|
|
|
|
start_clipped = True;
|
|
}
|
|
else if (start_code & GraphicsView::IsAbove)
|
|
{
|
|
# if defined(DEBUG)
|
|
Tell("Clip above\n");
|
|
# endif
|
|
Verify(end.y != start.y);
|
|
start.x += (end.x - start.x) *
|
|
(clippingRectangle.topRight.y-start.y) / (end.y-start.y);
|
|
Check_Fpu();
|
|
start.y = clippingRectangle.topRight.y;
|
|
|
|
start_clipped = True;
|
|
}
|
|
else if (start_code & GraphicsView::IsBelow)
|
|
{
|
|
# if defined(DEBUG)
|
|
Tell("Clip below\n");
|
|
# endif
|
|
Verify(end.y != start.y);
|
|
start.x += (end.x - start.x) *
|
|
(clippingRectangle.bottomLeft.y-start.y) / (end.y-start.y);
|
|
Check_Fpu();
|
|
start.y = clippingRectangle.bottomLeft.y;
|
|
|
|
start_clipped = True;
|
|
}
|
|
//----------------------------------------------------
|
|
// Build a new point code for the starting point,
|
|
// loop until line is either in or out.
|
|
//----------------------------------------------------
|
|
start_code = BuildPointCode(start);
|
|
}
|
|
# if defined(DEBUG)
|
|
Tell(
|
|
"Clipping done, start=" << start <<
|
|
", end=" << end <<
|
|
"\n"
|
|
);
|
|
# endif
|
|
//----------------------------------------------------
|
|
// If swapped, flip them back
|
|
//----------------------------------------------------
|
|
if (swapped)
|
|
{
|
|
# if defined(DEBUG)
|
|
Tell("Swapping back\n");
|
|
# endif
|
|
Vector2DOf<int>
|
|
temp_vector;
|
|
temp_vector = start;
|
|
start = end;
|
|
end = temp_vector;
|
|
|
|
Logical temp_flag;
|
|
temp_flag = start_clipped;
|
|
start_clipped = end_clipped;
|
|
end_clipped = temp_flag;
|
|
}
|
|
//----------------------------------------------------
|
|
// If the endpoint was clipped, include the final pixel
|
|
//----------------------------------------------------
|
|
if (end_clipped)
|
|
{
|
|
# if defined(DEBUG)
|
|
Tell("End was clipped, including last pixel\n");
|
|
# endif
|
|
include_last_pixel = True;
|
|
}
|
|
//----------------------------------------------------
|
|
// Finally, draw the line!
|
|
//----------------------------------------------------
|
|
# if defined(DEBUG)
|
|
Tell(
|
|
"All done, start=" << start <<
|
|
", end=" << end <<
|
|
"\n"
|
|
);
|
|
# endif
|
|
|
|
Verify(BuildPointCode(start) == 0);
|
|
Verify(BuildPointCode(end) == 0);
|
|
|
|
graphicsPort->DrawLine(
|
|
currentColor,
|
|
currentOperation,
|
|
start.x, start.y,
|
|
end.x, end.y,
|
|
include_last_pixel
|
|
);
|
|
|
|
RECORDER_LINE(
|
|
recorder,
|
|
currentColor,
|
|
currentOperation,
|
|
start.x, start.y,
|
|
end.x, end.y,
|
|
include_last_pixel
|
|
);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
GraphicsView::DrawFilledRectangle(Rectangle2D r)
|
|
{
|
|
Check(this);
|
|
if (graphicsPort != NULL)
|
|
{
|
|
//
|
|
// Swap X positions if needed
|
|
//
|
|
if (r.bottomLeft.x > r.topRight.x)
|
|
{
|
|
int temp;
|
|
|
|
temp = r.bottomLeft.x;
|
|
r.bottomLeft.x = r.topRight.x;
|
|
r.topRight.x = temp;
|
|
}
|
|
//
|
|
// Swap Y positions if needed
|
|
//
|
|
if (r.bottomLeft.y > r.topRight.y)
|
|
{
|
|
int temp;
|
|
|
|
temp = r.bottomLeft.y;
|
|
r.bottomLeft.y = r.topRight.y;
|
|
r.topRight.y = temp;
|
|
}
|
|
//
|
|
// Clip to clipping rectangle
|
|
//
|
|
r.Intersection(clippingRectangle, r);
|
|
//
|
|
// Draw if non-empty
|
|
//
|
|
if (! r.IsEmpty())
|
|
{
|
|
graphicsPort->
|
|
DrawFilledRectangle(
|
|
currentColor,
|
|
currentOperation,
|
|
r.bottomLeft.x, r.bottomLeft.y, r.topRight.x, r.topRight.y
|
|
);
|
|
RECORDER_FRECT(
|
|
recorder,
|
|
currentColor,
|
|
currentOperation,
|
|
r.bottomLeft.x, r.bottomLeft.y, r.topRight.x, r.topRight.y
|
|
);
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
Logical
|
|
GraphicsView::ClipImage(
|
|
Rectangle2D *sourceRect,
|
|
Vector2DOf<int> *position,
|
|
Vector2DOf<int> imageLimits
|
|
)
|
|
{
|
|
Check(this);
|
|
|
|
if (graphicsPort != NULL)
|
|
{
|
|
Rectangle2D
|
|
destRect;
|
|
|
|
Vector2DOf<int>
|
|
source_origin,
|
|
source_size;
|
|
|
|
//
|
|
// clip sourceRect to image limits
|
|
//
|
|
if (sourceRect->bottomLeft.x < 0)
|
|
{
|
|
sourceRect->bottomLeft.x = 0;
|
|
}
|
|
if (sourceRect->topRight.x >= imageLimits.x)
|
|
{
|
|
sourceRect->topRight.x = imageLimits.x-1;
|
|
}
|
|
|
|
if (sourceRect->bottomLeft.y < 0)
|
|
{
|
|
sourceRect->bottomLeft.y = 0;
|
|
}
|
|
if (sourceRect->topRight.y >= imageLimits.y)
|
|
{
|
|
sourceRect->topRight.y = imageLimits.y-1;
|
|
}
|
|
|
|
source_origin = sourceRect->bottomLeft;
|
|
source_size = sourceRect->topRight;
|
|
source_size -= sourceRect->bottomLeft;
|
|
|
|
//
|
|
// build corresponding rectangle in port space
|
|
//
|
|
destRect.bottomLeft = currentPosition;
|
|
destRect.topRight = currentPosition;
|
|
destRect.topRight += source_size;
|
|
//
|
|
// now, clip the rectangle
|
|
//
|
|
Rectangle2D r;
|
|
r = destRect;
|
|
destRect.Intersection(r, clippingRectangle);
|
|
//
|
|
// draw if non-empty
|
|
//
|
|
if (! destRect.IsEmpty())
|
|
{
|
|
//
|
|
// Set position
|
|
//
|
|
*position = destRect.bottomLeft;
|
|
//
|
|
// return rectangle to image space
|
|
//
|
|
source_size = destRect.topRight;
|
|
source_size -= destRect.bottomLeft;
|
|
|
|
sourceRect->bottomLeft = source_origin;
|
|
sourceRect->topRight = source_origin;
|
|
sourceRect->topRight += source_size;
|
|
Check_Fpu();
|
|
return True;
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
return False;
|
|
}
|