#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= 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 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 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 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 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 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 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 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 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 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 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 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 start, Vector2DOf 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 start, Vector2DOf 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 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 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 *position, Vector2DOf imageLimits ) { Check(this); if (graphicsPort != NULL) { Rectangle2D destRect; Vector2DOf 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; }