TGSdemo: C++ Version

TGSdemo uses a C++ class named VB to hold the code and data required to manage a virtual buffer. It includes a private data item for the virtual buffer handle, a constructor, a destructor, and one member function:

class VB {
private:
   int hVB;                     // virtual buffer handle
public:
   VB(int, int, int init=FALSE);// constructor function
   ~VB();                       // destructor function
   int handle();                // member function (get VB handle)
};

The constructor function creates a virtual buffer with the specified dimensions, makes it the active virtual buffer, and assigns the logical palette colors to the virtual buffer. Its optional third parameter provides a way to initialize Fastgraph's virtual buffer environment, which we must do the first time we create a VB object:

VB::VB(int Width, int Height, int Init) 
{
   if (Init) fg_vbinit();
   hVB = fg_vballoc(Width,Height);
   fg_vbopen(hVB);
   fg_vbcolors();
}

The destructor function closes the active virtual buffer and releases the virtual buffer memory. If all virtual buffers (that is, all VB objects) have been freed, fg_vbfin() releases any remaining virtual buffer resources:

VB::~VB()
{
   fg_vbclose();
   fg_vbfree(hVB);
   fg_vbfin();
}

Finally, the VB class includes a member function to return the handle by which Fastgraph references the virtual buffer:

int VB::handle(void) 
{
   return(hVB);
}

The TGSdemo WinMain() function creates two virtual buffer objects from the VB class:

VB Workspace(320,200,TRUE); // 320x200 workspace virtual buffer object
VB Background(1600,200);    // 1600x200 background virtual buffer object
WorkVB = &Workspace;        // global pointer to workspace VB object
BackVB = &Background;       // global pointer to background VB object

We use the optional third parameter to make the constructor call fg_vbinit() when we create the workspace object. Because the VB objects retain their scope only within WinMain(), we set up two global pointers to the objects:

VB *WorkVB;                 // global pointer to workspace VB
VB *BackVB;                 // global pointer to background VB

These pointers are declared outside WinMain() immediately after the VB class declarations.

In the examples we've presented so far, the WM_CREATE and WM_DESTROY message handlers respectively perform the virtual buffer initialization and shutdown tasks. In TGSdemo, the VB constructor and destructor functions handle these details. We can't create the VB objects in the WM_CREATE handler because they would lose scope when it returns, thus destroying any VB objects we just created. As we've seen, the solution is to let WinMain() create the VB objects once CreateWindow() returns and then reference them through the global pointers. Note also that the WM_DESTROY handler doesn't call fg_vbclose(), fg_vbfree(), and fg_vbfin(), as we've moved these calls into the destructor.


/****************************************************************************\
*                                                                            *
*  TGSdemo.cpp                                                               *
*                                                                            *
*  This program displays a scaled image (a logo) against a background of     *
*  scrolling clouds. The background and logo images are stored in PCX files  *
*  with identical palettes that do not use the Windows system colors.        *
*                                                                            *
*  TGSdemo is based on an original program by Michael Miller.                *
*                                                                            *
\****************************************************************************/
#include <fgwin.h>
LRESULT CALLBACK WindowProc(HWND,UINT,WPARAM,LPARAM);
void MoveBackground();
char DataPath[256];
/****************************************************************************\
*                                                                            *
*  Virtual Buffer class and function declarations                            *
*                                                                            *
\****************************************************************************/
class VB {
private:
   int hVB;                             // virtual buffer handle
public:
   VB(int, int, int init=FALSE);        // constructor function
   ~VB();                               // destructor function
   int handle();                        // member function (get VB handle)
};
VB::VB(int Width, int Height, int Init) // constructor
{
   if (Init) fg_vbinit();
   hVB = fg_vballoc(Width,Height);
   fg_vbopen(hVB);
   fg_vbcolors();
}
VB::~VB()                               // destructor
{
   fg_vbclose();
   fg_vbfree(hVB);
   fg_vbfin();
}
int VB::handle(void)                    // member function to get the VB handle
{
   return(hVB);
}
VB *WorkVB;                             // global pointer to workspace VB
VB *BackVB;                             // global pointer to background VB
/****************************************************************************\
*                                                                            *
*  Image Buffer class and function declarations                              *
*                                                                            *
\****************************************************************************/
class IMAGE
{
private:
   int ImageWidth, ImageHeight;
   int xCenter, yLoc;
   BYTE *ImageData;
   BYTE *ScaleData;
public:
   IMAGE(char *PCXfile, int Width, int Height, int yPos);
   ~IMAGE();
   void Show(int);
};
// constructor
IMAGE::IMAGE(char *PCXfile, int Width, int Height, int yPos)
{
   char FileName[256];
   lstrcpy(FileName,DataPath);
   lstrcat(FileName,PCXfile);
   // assign ImageWidth and ImageHeight
   ImageWidth  = Width;
   ImageHeight = Height;
   yLoc = yPos;
   // find page center coordinates
   xCenter = (320 - ImageWidth) / 2;
   // dynamically allocate memory for ImageData and scaling
   ImageData = new BYTE [fg_imagesiz(ImageWidth,ImageHeight)];
   ScaleData = new BYTE [fg_imagesiz(ImageWidth,ImageHeight)];
   // load the actual image from the PCX file
   fg_vbopen(WorkVB->handle());
   fg_showpcx(FileName,FG_KEEPCOLORS);
   // retrieve the image as a 256-color bitmap
   fg_move(0,ImageHeight-1);
   fg_getimage(ImageData,ImageWidth,ImageHeight);
};
// destructor
IMAGE::~IMAGE()
{
   delete[] ImageData;
   delete[] ScaleData;
}
// member function to display the scaled object
void IMAGE::Show(int Scale)
{
   if (Scale <= 0)
      return;
   // image is scaled down
   else if (Scale < 10)
   {
      int dWidth  = (ImageWidth  * Scale) / 10;
      int dHeight = (ImageHeight * Scale) / 10;
      int xLoc = (320 - dWidth) / 2;
      fg_scale(ImageData,ScaleData,ImageWidth,ImageHeight,dWidth,dHeight);
      fg_move(xLoc,yLoc);
      fg_drwimage(ScaleData,dWidth,dHeight);
   }
   // image is displayed at full size
   else
   {
      fg_move(xCenter,yLoc);
      fg_drwimage(ImageData,ImageWidth,ImageHeight);
   }
}
/****************************************************************************\
*                                                                            *
*  WinMain                                                                   *
*                                                                            *
\****************************************************************************/
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdParam, int iCmdShow)
{
   static char szAppName[] = "FGtgsdemo";
   HWND        hWnd;
   MSG         msg;
   WNDCLASSEX  wndclass;
   char FileName[256];
   register int i, j;
   wndclass.cbSize        = sizeof(wndclass);
   wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
   wndclass.lpfnWndProc   = WindowProc;
   wndclass.cbClsExtra    = 0;
   wndclass.cbWndExtra    = 0;
   wndclass.hInstance     = hInstance;
   wndclass.hIcon         = LoadIcon(NULL,IDI_APPLICATION);
   wndclass.hCursor       = LoadCursor(NULL,IDC_ARROW);
   wndclass.hbrBackground = NULL;
   wndclass.lpszMenuName  = NULL;
   wndclass.lpszClassName = szAppName;
   wndclass.hIconSm       = LoadIcon(NULL,IDI_APPLICATION);
   RegisterClassEx(&wndclass);
   hWnd = CreateWindow(
      szAppName,               // window class name
      "Scaling and Scrolling", // window caption
      WS_OVERLAPPEDWINDOW,     // window style
      CW_USEDEFAULT,           // initial x position
      CW_USEDEFAULT,           // initial y position
      CW_USEDEFAULT,           // initial x size
      CW_USEDEFAULT,           // initial y size
      NULL,                    // parent window handle
      NULL,                    // window menu handle
      hInstance,               // program instance handle
      NULL);                   // creation parameters
   VB Workspace(320,200,TRUE); // 320x200 workspace virtual buffer object
   VB Background(1600,200);    // 1600x200 background virtual buffer object
   WorkVB = &Workspace;        // global pointer to workspace VB object
   BackVB = &Background;       // global pointer to background VB object
   ShowWindow(hWnd,iCmdShow);
   UpdateWindow(hWnd);
   GetModuleFileName(hInstance,DataPath,255);
   for (i = lstrlen(DataPath); i >= 0; i--)
   {
      if (DataPath[i] == '\\')
      {
         DataPath[i+1] = 0;
         break;
      }
   }
   lstrcpy(FileName,DataPath);
   lstrcat(FileName,"Sky.pcx");
   fg_vbopen(BackVB->handle());
   fg_showpcx(FileName,FG_KEEPCOLORS);
   // copy the first 640 columns onto the next 640 columns, in
   // reverse order (make a mirror image)
   for (i = 639; i >= 0; i--)
   {
      j = 1279 - i;
      fg_vbcopy(i,i,0,199,j,199,BackVB->handle(),BackVB->handle());
   }
   // make another copy of first 320 columns
   fg_vbcopy(0,319,0,199,1280,199,BackVB->handle(),BackVB->handle());
   // work buffer is currently open for pasting
   fg_vbopen(WorkVB->handle());
   // handle messags while scrolling background
   while (TRUE)
   {
      if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
      {
         if (msg.message == WM_QUIT)
            break;
         else
         {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
         }
      }
      else
         MoveBackground();
   }
   return msg.wParam;
}
/****************************************************************************\
*                                                                            *
*  WindowProc()                                                              *
*                                                                            *
\****************************************************************************/
HDC      hDC;
HPALETTE hPal;
UINT     cxClient, cyClient;
LRESULT CALLBACK WindowProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
   PAINTSTRUCT ps;
   switch (iMsg)
   {
      case WM_CREATE:
         hDC = GetDC(hWnd);
         fg_setdc(hDC);
         hPal = fg_defpal();
         fg_realize(hPal);
         return 0;
      case WM_PAINT:
         BeginPaint(hWnd,&ps);
         fg_vbscale(0,319,0,199,0,cxClient-1,0,cyClient-1);
         EndPaint(hWnd,&ps);
         return 0;
      case WM_SETFOCUS:
         fg_realize(hPal);
         InvalidateRect(hWnd,NULL,TRUE);
         return 0;
      case WM_SIZE:
         cxClient = LOWORD(lParam);
         cyClient = HIWORD(lParam);
         return 0;
      case WM_DESTROY:
         DeleteObject(hPal);
         ReleaseDC(hWnd,hDC);
         PostQuitMessage(0);
         return 0;
   }
   return DefWindowProc(hWnd,iMsg,wParam,lParam);
}
/****************************************************************************\
*                                                                            *
*  MoveBackground()                                                          *
*                                                                            *
*  Build the next frame and display it in the client area.                   *
*                                                                            *
\****************************************************************************/
void MoveBackground()
{
   static IMAGE Logo1 = IMAGE("Logo1.pcx",264,40,160);
   static IMAGE Logo2 = IMAGE("Logo2.pcx",264,40,80);
   static int hBack = BackVB->handle();
   static int hWork = WorkVB->handle();
   static int x = 0;
   // increment storage virtual buffer starting x coordinate
   x += 8;
   if (x >= 1280) x = 0;
   // copy part of background image to workspace buffer
   fg_vbcopy(x,x+319,0,199,0,199,hBack,hWork);
   // add the logo
   if (x <= 240)
      Logo2.Show(x/10);
   else
   {
      Logo1.Show((x-240)/10);
      Logo2.Show(10);
   }
   // display the frame in the client area
   fg_vbscale(0,319,0,199,0,cxClient-1,0,cyClient-1);
}

<< Prev

Next >>

Contents
Fastgraph Home Page

 

copyright 2001 Ted Gruber Software, Inc.