PlayerStatus (dirty-gated, blits an 8-bit pixmap -- but the widget map for a DIRTY run contains no playerStatus at all; it belongs to cameraInit and never exists in a mech cockpit) and heat-driven redraw (a BT_FORCE_FIRE run came back clean). Seven hypotheses killed by measurement so far. It is a heisenbug: dirty on ~3 runs in 25, and every run since instrumenting has been clean. The pattern tracks STARTUP LOG VOLUME -- the three dirty runs all had the lighter conf, and a chatty trace slows init enough to suppress it. The blit trace is therefore narrowed to fire only for pixmaps landing on a non-palette port, which is near-silent when nothing is wrong. That narrowed trace caught real traffic: 17x17 PixelMap8 blits onto Mfd1/2/3 -- 8-bit pixmaps on single-bit planes. They render correctly, so the library thresholds them; not the culprit but the right bug class. Also banked a hunting recipe, because two detector traps cost runs: Eng1 == 0 means the cockpit is not up (not dirty), and an early capture during mission start caught a full 3-D cockpit frame with the gauges at pod positions (Eng1 62927) that did not recur over the next minute. BTDPL.INI is in the mount and DPLRenderer is linked, so the dPL path may emit a frame during launch even with L4VIDEO=OFF -- first evidence the 3-D path produces anything, and explicitly NOT a claim that btl4vid works. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3149 lines
66 KiB
C++
3149 lines
66 KiB
C++
# if !defined(MUNGA_HPP)
|
|
# include <munga.hpp>
|
|
# endif
|
|
#pragma hdrstop
|
|
|
|
# if !defined(GRAPH2D_HPP)
|
|
# include <graph2d.hpp>
|
|
# endif
|
|
# if !defined(NOTATION_HPP)
|
|
# include <notation.hpp>
|
|
# endif
|
|
# if !defined(NAMELIST_HPP)
|
|
# include <namelist.hpp>
|
|
# endif
|
|
|
|
//#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);
|
|
|
|
cout << indent << "BitMap:\n";
|
|
char
|
|
temp[80];
|
|
|
|
Str_Copy(temp, indent, 80);
|
|
Str_Cat(temp, "...", 80);
|
|
|
|
cout << temp << "Size =" << Data.Size << "\n";
|
|
cout << temp << "WidthInWords=" << Data.WidthInWords << "\n";
|
|
cout << temp << "MapPointer =" << (void *) Data.MapPointer << "\n";
|
|
cout << flush;
|
|
|
|
if (Data.MapPointer != NULL)
|
|
{
|
|
int
|
|
x,
|
|
y,
|
|
bits,
|
|
bitmask,
|
|
bitwidth;
|
|
|
|
Word
|
|
*source((Word *) Data.MapPointer);
|
|
|
|
for(y=Data.Size.y; y>0; y--)
|
|
{
|
|
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)
|
|
{
|
|
cout << "-";
|
|
}
|
|
else if (bits & bitmask)
|
|
{
|
|
cout <<"#";
|
|
}
|
|
else
|
|
{
|
|
cout <<" ";
|
|
}
|
|
}
|
|
}
|
|
cout << "\n";
|
|
}
|
|
cout << "\n";
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//########################################################################
|
|
//############################### Palette8 ###############################
|
|
//########################################################################
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// Output stream operator
|
|
//------------------------------------------------------------------------
|
|
//
|
|
ostream& operator<<(ostream& Stream, const PaletteTriplet& p)
|
|
{
|
|
Check_Fpu();
|
|
return Stream << hex <<
|
|
(((int) p.Red) & 0xFF) << ':' <<
|
|
(((int) p.Green) & 0xFF) << ':' <<
|
|
(((int) p.Blue) & 0xFF) << 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;
|
|
|
|
cout << indent << "Palette8:\n";
|
|
|
|
Str_Copy(temp, indent, 80);
|
|
Str_Cat(temp, "...", 80);
|
|
|
|
cout << temp << "Valid =" << Valid << "\n";
|
|
|
|
if (Valid)
|
|
{
|
|
source = Color;
|
|
for(y=0; y<256; y+=4)
|
|
{
|
|
sprintf(buffer, "%02X= ", y);
|
|
cout << temp << buffer;
|
|
|
|
for(x=4; x>0; --x)
|
|
{
|
|
cout << *source++ << " ";
|
|
}
|
|
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;
|
|
|
|
cout << indent << "PixelMap8:\n";
|
|
|
|
Str_Copy(temp, indent, 80);
|
|
Str_Cat(temp, "...", 80);
|
|
|
|
cout << temp << "Size =" << Data.Size << "\n";
|
|
cout << temp << "MapPointer =" << (void *) Data.MapPointer << "\n";
|
|
|
|
source = Data.MapPointer;
|
|
if (source != NULL)
|
|
{
|
|
for(y=Data.Size.y; y>0; --y)
|
|
{
|
|
cout << temp;
|
|
for(x=Data.Size.x; x>0; --x)
|
|
{
|
|
sprintf(buffer, "%02X ",*source++);
|
|
cout << buffer;
|
|
}
|
|
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];
|
|
|
|
cout << indent << "PixelMap16:\n";
|
|
|
|
Str_Copy(temp, indent, 80);
|
|
Str_Cat(temp, "...", 80);
|
|
|
|
cout << temp << "Size =" << Data.Size << "\n";
|
|
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);
|
|
cout << indent << "GraphicsDisplay:\n";
|
|
|
|
char
|
|
temp[80];
|
|
|
|
Str_Copy(temp, indent, 80);
|
|
Str_Cat(temp, "...", 80);
|
|
|
|
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);
|
|
|
|
cout << indent << "GraphicsPort:\n";
|
|
|
|
char
|
|
temp[80];
|
|
|
|
Str_Copy(temp, indent, 80);
|
|
Str_Cat(temp, "...", 80);
|
|
|
|
cout << temp << "bounds =" << bounds << "\n";
|
|
cout << temp << "graphicsDisplay=" << graphicsDisplay << "\n";
|
|
cout << 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);
|
|
|
|
cout << indent << "GraphicsView:\n";
|
|
|
|
char
|
|
temp[80];
|
|
|
|
Str_Copy(temp, indent, 80);
|
|
Str_Cat(temp, "...", 80);
|
|
|
|
cout << temp << "areaWithinPort =" << areaWithinPort << "\n";
|
|
cout << temp << "origin =" << origin << "\n";
|
|
cout << temp << "currentPosition =" << currentPosition << "\n";
|
|
cout << temp << "currentFontID =" << currentFontID << "\n";
|
|
cout << temp << "currentColor =" << currentColor << "\n";
|
|
cout << temp << "clippingRectangle =" << clippingRectangle << "\n";
|
|
cout << temp << "currentOperation =";
|
|
switch(currentOperation)
|
|
{
|
|
case GraphicsDisplay::And: cout << "AND\n"; break;
|
|
case GraphicsDisplay::Or: cout << "OR\n"; break;
|
|
case GraphicsDisplay::Replace: cout << "REPLACE\n"; break;
|
|
default: cout << "Unsupported type:" << currentOperation << "\n"; break;
|
|
}
|
|
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))
|
|
{
|
|
//
|
|
// BLIT TRACE (env BT_VIS_BLIT): every 8-bit pixmap that reaches
|
|
// a port, with the port it lands on and the rect it covers.
|
|
// Hunting the write that puts raw packed bytes into the
|
|
// plane-packed gauge buffer.
|
|
//
|
|
//
|
|
// Log ONLY pixmap blits landing on a port that is NOT one of the
|
|
// two palette ports (sec / overlay). An 8-bit pixmap reaching a
|
|
// single-bit plane is the thing being hunted, and filtering here
|
|
// keeps the trace near-silent -- which matters, because the
|
|
// defect is a STARTUP TIMING race and a chatty trace suppresses
|
|
// it (six consecutive clean runs once logging was added).
|
|
//
|
|
if (getenv("BT_VIS_BLIT") != NULL
|
|
&& graphicsPort != NULL && graphicsPort->name != NULL
|
|
&& stricmp(graphicsPort->name, "sec") != 0
|
|
&& stricmp(graphicsPort->name, "overlay") != 0)
|
|
{
|
|
static int blitSamples = 0;
|
|
if (blitSamples < 400)
|
|
{
|
|
++blitSamples;
|
|
DEBUG_STREAM << "[blit] port='"
|
|
<< ((graphicsPort != NULL && graphicsPort->name != NULL)
|
|
? graphicsPort->name : "(null)")
|
|
<< "' at " << position.x << "," << position.y
|
|
<< " src " << sourceBounds.bottomLeft.x << ","
|
|
<< sourceBounds.bottomLeft.y << ".."
|
|
<< sourceBounds.topRight.x << ","
|
|
<< sourceBounds.topRight.y
|
|
<< " size " << pixelmap->Data.Size.x << "x"
|
|
<< pixelmap->Data.Size.y
|
|
<< " opaque=" << (opaque ? 1 : 0)
|
|
<< " rot=" << rotation << "\n" << flush;
|
|
}
|
|
}
|
|
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;
|
|
}
|