Has anyone used the Adafruit GFX library to... ? [SOLVED]

I'm trying to setup a library for drawing to an offscreen bitmap. I've written a virtual display class using Adafruit_GFX as a base class, and pretty much everything works. Except.. Text.

For the life of me I can't figure out how they output the bits for text. Everything uses Adafruit_GFX drawPixel() to draw to the screen, but I see nothing coming out of drawPixel() when I write out text.

I'm sure if anyone has used this to create drivers for some screen hardware they've run into this issue.

For those that will ask.

offscreen.h

#ifndef offscreen_h
#define offscreen_h

#include "bitmap.h"
#include "displayObj.h"
#include "Adafruit_GFX.h"


class mapDisplay :  public Adafruit_GFX {
  
  public :
            mapDisplay(bitmap* inMap,int ofsX,int ofsY);
            ~mapDisplay(void);
          
            bool  dispObjBegin(void);
    virtual void  drawPixel(int16_t x, int16_t y, uint16_t color);
    virtual void  writePixel(int16_t x, int16_t y, uint16_t color);
            void  setFColor(colorObj* inColor);
            void  setBColor(colorObj* inColor);
            void  setTransp(bool transp);

  protected :
  				int		offsetX;
				int		offsetY;
            colorObj	mFColor;
            colorObj	mBColor;
            bool		mTransp;
            bitmap*	mBitmap;
};



class offscreen : public displayObj {

  public :
				offscreen(void);
				~offscreen(void);

				bool  dispObjBegin(void);
				void  beginDraw(bitmap* inMap,int inOffsetX=0,int inOffsetY=0);
				void  endDraw(void);

	virtual   void  setRotation(byte inRotation);
	virtual   void  setTextColor(colorObj* tColor);
	virtual   void  setTextColor(colorObj* tColor,colorObj* bColor);
	virtual   void  setTextSize(byte inSize);
	virtual   void  setTextWrap(boolean wrap);
	virtual   void  setFont(const GFXfont* font);
	virtual   void  setCursor(int x,int y);
	virtual   void  drawText(char* inText);
	virtual   void  drawChar(int x,int y,char inChar,colorObj* fColor,colorObj* bColor,int size);
	virtual   void  fillScreen(colorObj* inColor);
	virtual   void  fillRect(int x,int y,int width,int height,colorObj* inColor);
	virtual   void  fillRect(rect* aRect,colorObj* inColor);
	virtual   void  drawRect(int x,int y,int width,int height,colorObj* inColor);
	virtual   void  drawRect(rect* aRect,colorObj* inColor);
	virtual   void  fillRoundRect(int x,int y,int width,int height,int radius,colorObj* inColor);
	virtual   void  fillRoundRect(rect* aRect,int radius,colorObj* inColor);
	virtual   void  drawRoundRect(int x,int y,int width,int height,int radius,colorObj* inColor);
	virtual   void  drawRoundRect(rect* aRect,int radius,colorObj* inColor);
	virtual   void  drawCircle(int x,int y,int diam, colorObj* inColor);
	virtual   void  fillCircle(int x,int y,int diam, colorObj* inColor);
	virtual   void  drawVLine(int x,int y,int height,colorObj* inColor);
	virtual   void  drawHLine(int x,int y,int width,colorObj* inColor);
	virtual   void  drawLine(int x,int y,int x2,int y2,colorObj* inColor);
	virtual   void  drawPixel(int x,int y,colorObj* inColor);

		
		bool        mDrawing;
		mapDisplay* mDisplay;
		displayObj* oldScreen;
};


#endif

And offscreen.cpp fkile

#include "offscreen.h"
#include "screen.h"


// ***************************************************************
// mapDisplay : Mimics a display to catch the drawing.
// ***************************************************************

// Constructor is only used by the offscreen class and it'll do the
// sanity checking before calling.
mapDisplay::mapDisplay(bitmap* inMap, int ofsX, int ofsY)
  : Adafruit_GFX((int16_t)inMap->getWidth(), (int16_t)inMap->getHeight()) {

  mBitmap = inMap;
  offsetX = ofsX;
  offsetY = ofsY;
}


mapDisplay::~mapDisplay(void) {  }


bool mapDisplay::dispObjBegin(void) {
  return true;
}


void mapDisplay::drawPixel(int16_t x, int16_t y, uint16_t color) {

  colorObj  aColor(color);
  //Serial.print("draw : ");Serial.print(x);Serial.print(", ");Serial.print(y);Serial.print(" ");Serial.println(color,BIN);
  mBitmap->setColor(x - offsetX, y - offsetY, &aColor);
}


void mapDisplay::writePixel(int16_t x, int16_t y, uint16_t color) {

  colorObj  aColor(color);
  //Serial.print("write : ");Serial.print(x);Serial.print(", ");Serial.print(y);Serial.print(" ");Serial.println(color,BIN);
  mBitmap->setColor(x - offsetX, y - offsetY, &aColor);
}


void mapDisplay::setFColor(colorObj* inColor) {
  mFColor.setColor(inColor);
}


void mapDisplay::setBColor(colorObj* inColor) {
  mBColor.setColor(inColor);
}


void mapDisplay::setTransp(bool transp) {
  mTransp = transp;
}



// ***************************************************************
// offscreen : The part the user interacts with.
// ***************************************************************


offscreen::offscreen(void)
  : displayObj(true, true, false, false, true) {

  oldScreen = NULL;
  mDisplay  = NULL;
  mDrawing  = false;
}


offscreen::~offscreen(void) {

  if (mDisplay) delete mDisplay;
}


// Accept a bitmap, sanity check eveerything. If everything
// is good, set up for drawing to it.
void offscreen::beginDraw(bitmap* inMap, int inOffsetX = 0, int inOffsetY = 0) {

  if (mDrawing) {                                       // We already drawing? Someone forgot to shut down?
    endDraw();                                          // Shut it down.
  }
  if (mDisplay) {                                       // If we have a display object..
    delete mDisplay;                                    // dump it.
    mDisplay = NULL;                                    // Note it's gone.
  }
  if (inMap) {                                          // Sanity. We got a bitmap?
    if (inMap->getHasMap()) {                           // And its RAM's been allocated?
      mDisplay  = new mapDisplay(inMap, inOffsetX, inOffsetY); // Create the display objecet with the bitmap.
      if (mDisplay) {                                   // Sanity. We got that display?
        oldScreen = screen;                             // Everything seems ok. Save off the screen pointer.
        screen = this;                                  // Replace it with us.
        mDrawing = true;                                // Note that we are now rerouting drawing calls.
      }
    }
  }
}


// ENOUGH! We're done drawing to the bitmap.
void offscreen::endDraw(void) {

  if (mDrawing) {     // Have we rerouted drawing calls?
    screen = oldScreen; // Undo the screen rerouting.
    oldScreen = NULL;   // Note this is done.
    mDrawing = false;   // Note that we are no longer rerouting drawing calls.
  }
}


// In case someone asks.
bool offscreen::dispObjBegin(void) {
  return true;
}



// The standard pass throughs.


void offscreen::setRotation(byte inRotation) {
  mDisplay->setRotation(inRotation);
}


void offscreen::setTextColor(colorObj* inColor) {
  mDisplay->setTextColor(inColor->getColor16());
}


void offscreen::setTextColor(colorObj* tColor, colorObj* bColor) {
  mDisplay->setTextColor(tColor->getColor16(), bColor->getColor16());
}


void offscreen::setTextSize(byte inSize) {
  mDisplay->setTextSize(inSize);
}


void offscreen::setTextWrap(boolean wrap) {
  mDisplay->setTextWrap(wrap);
}


void offscreen::setFont(const GFXfont* font) {
  mDisplay->setFont(font);
}


void offscreen::setCursor(int x, int y) {
  mDisplay->setCursor(gX(x), gY(y));
}


void offscreen::drawText(char* inText) {
  mDisplay->print(inText);
}


void offscreen::drawChar(int x, int y, char inChar, colorObj* fColor, colorObj* bColor, int size) {
  mDisplay->drawChar(gX(x), gY(y), inChar, fColor->getColor16(), bColor->getColor16(), size);
}


void offscreen::fillScreen(colorObj* inColor) {
  mDisplay->fillScreen(inColor->getColor16());
}


void offscreen::fillRect(int x, int y, int width, int height, colorObj* inColor) {
  mDisplay->fillRect(gX(x), gY(y), width, height, inColor->getColor16());
}


void offscreen::fillRect(rect* aRect, colorObj* inColor) {
  mDisplay->fillRect(gX(aRect->x), gY(aRect->y), aRect->width, aRect->height, inColor->getColor16());
}


void offscreen::drawRect(int x, int y, int width, int height, colorObj* inColor) {
  mDisplay->drawRect(gX(x), gY(y), width, height, inColor->getColor16());
}


void offscreen::drawRect(rect* aRect, colorObj* inColor) {
  mDisplay->drawRect(gX(aRect->x), gY(aRect->y), aRect->width, aRect->height, inColor->getColor16());
}


void offscreen::fillRoundRect(int x, int y, int width, int height, int radius, colorObj* inColor) {
  mDisplay->fillRoundRect(gX(x), gY(y), width, height, radius, inColor->getColor16());
}


void offscreen::fillRoundRect(rect* aRect, int radius, colorObj* inColor) {
  mDisplay->fillRoundRect(gX(aRect->x), gY(aRect->y), aRect->width, aRect->height, radius, inColor->getColor16());
}


void offscreen::drawRoundRect(int x, int y, int width, int height, int radius, colorObj* inColor) {
  mDisplay->drawRoundRect(gX(x), gY(y), width, height, radius, inColor->getColor16());
}


void offscreen::drawRoundRect(rect* aRect, int radius, colorObj* inColor) {
  mDisplay->drawRoundRect(gX(aRect->x), gY(aRect->y), aRect->width, aRect->height, radius, inColor->getColor16());
}


void offscreen::drawCircle(int x, int y, int diam, colorObj* inColor) {
  drawRoundRect(gX(x), gY(y), diam, diam, diam / 2, inColor);
}


void offscreen::fillCircle(int x, int y, int diam, colorObj* inColor) {
  fillRoundRect(gX(x), gY(y), diam, diam, diam / 2, inColor);
}


void offscreen::drawVLine(int x, int y, int height, colorObj* inColor) {
  mDisplay->drawFastVLine(gX(x), gY(y), height, inColor->getColor16());
}


void offscreen::drawHLine(int x, int y, int width, colorObj* inColor) {
  mDisplay->drawFastHLine(gX(x), gY(y), width, inColor->getColor16());
}


void offscreen::drawLine(int x, int y, int x2, int y2, colorObj* inColor) {
  mDisplay->drawLine(gX(x), gY(y), gX(x2), gY(y2), inColor->getColor16());
}


void offscreen::drawPixel(int x, int y, colorObj* inColor) {
  mDisplay->drawPixel(gX(x), gY(y), inColor->getColor16());
}
[ / code]

@jimLee,

Yes, it still works perfectly in my library GxEPD2.
My template class that inherits from Adafruit_GFX only implements drawPixel(), but doesn't override any other method from Adafruit_GFX. This seems the difference to your code.

Your code is hard to read in a browser. Did you forget to auto-format it before posting?

Jean-Marc

Text rendering is via the Arduino built in print class and this calls the write() function which then renders the character.

See this rather badly written description.

Guys, thanks for the input!

@ZinggJM - Mine is a little different because all my drawing generates from a virtual display class. Very similar to Adafruit_GFX. This makes plugging in adafruit displays pretty easy. And, seeing the Adafruit code was designed for this kind of thing. It made, in theory, setting up an offscreen drawing tool quite easy as well.

As for formatting, I forgot to do that last bit there. I can't use the ArduinoIDE because it won't allow editing of library code. Silly thing. So I use text wrangler as an editor. Looks great on there. Ended up looking like hash here. I just ran it through the ArduinoIDE and reformatted it. I hope that looks better.

@bodmer - That is a GREAT writeup on how to extend the print command! That helps a lot. It should get me on the right path to seeing what in the world is going on with my stuff.

Thanks again!

-jimlee

I was misunderstanding how to set the bounds of the virtual display. Text didn't work because it looks like it was the only part of the code that checked. Once I gave it global max for each (From the drawing environment the drawing was coming from) everything was happy.

Thanks again for the help!

-jim lee