home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
VSCPPv8.zip
/
VACPP
/
IBMCPP
/
samples
/
TOOLKIT
/
PM
/
BMPSAMP
/
JIGSAW.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-11-17
|
90KB
|
2,411 lines
/******************************************************************************
*
* File Name : JIGSAW.C
*
* Description : main function and code for the Jigsaw application
*
* This program provides a jigsaw puzzle, based on a decomposition of an
* arbitrary bitmap loaded from a file. The user can jumble the pieces,
* then drag them individually by means of the mouse. The image can be
* zoomed in and out and scrolled up/down and left/right.
*
* JIGSAW uses GpiBitBlt with clip paths to create a collection of picture
* fragments which are the puzzle pieces. In earlier versions of the
* program, each of these pieces was associated with a single retain-mode
* graphics segment. The retain-mode technique, however, proved to be
* too slow, so subsequent versions of the program used retain-mode APIs
* for fewer and fewer operations. The current version eliminates
* retain-mode graphics altogether. Instead, the drawing data for each
* piece is stored in _SEGLIST data structure defined in JIGSAW.H.
* This structure contains all the data needed to draw a piece, including
* pointers to the previous and next pieces. The _SEGLIST nodes are
* arranged in drawing priority order, so the picture can be reconstructed
* by traversing the list in sequence, drawing each piece as its
* corresponding structure is encountered. Where the comments in the
* rest of the program refer to a "segment," they are simply referring to
* a piece of the puzzle as defined by a record in this data structure.
*
* To retain responsiveness to user requests, the real work is done in a
* second thread, with work requests transmitted from the main thread in
* the form of messages. This arrangement makes it possible for the user
* to override lengthy drawing operations with a higher-priority request
* (eg. program termination, magnification change, etc.).
*
* Individual pieces are made to "move" by changing their model transforms.
* Scrolling and zooming of the whole picture is done by changing the
* default viewing transform. The points in model space associated with
* each piece (control points for the bounding curve, corners of the
* bounding box, etc.) are converted via GpiConvert into points in device
* space prior to use with GpiBitBlt, etc.
*
* Concepts : Illustrates the use of GPI
* Illustrates the use of off-screen bitmaps
*
* Entry Points:
* CalcSize()
* CheckMenu()
* CheckPsl()
* CreatePicture()
* DispErrorMsg()
* DoHorzScroll()
* DosGetThreadInfo()
* DoVertScroll()
* DumpPicture()
* EnableMenu()
* NewThread()
* Finalize()
* Initialize()
* Jumble()
* LeftDown()
* LeftUp()
* Load()
* main()
* MouseMove()
* PrepareBitmap()
* ReadBitmap()
* ReportError()
* ResetScrollBars()
* SegListCheck()
* ToBottom()
* Zoom()
*
* API's : GpiBeginPath
* GpiEndPath
* GpiFillPath
* GpiSetClipPath
* GpiSetClipRegion
*
* GpiCreateBitmap
* GpiDeleteBitmap
* GpiSetBitmap
* GpiSetBitmapBits
* GpiBitBlt
*
* GpiConvert
*
* GpiCreateRegion
* GpiCombineRegion
* GpiSetRegion
* GpiDestroyRegion
* GpiQueryRegionBox
*
* GpiSetAttrMode
* GpiSetColor
*
* GpiQueryDefaultViewMatrix
* GpiSetDefaultViewMatrix
*
* Copyright (C) 1992 IBM Corporation
*
* DISCLAIMER OF WARRANTIES. The following [enclosed] code is
* sample code created by IBM Corporation. This sample code is not
* part of any standard or IBM product and is provided to you solely
* for the purpose of assisting you in the development of your
* applications. The code is provided "AS IS", without
* warranty of any kind. IBM shall not be liable for any damages
* arising out of your use of the sample code, even if they have been
* advised of the possibility of such damages. *
*
******************************************************************************/
#include "jigsaw.h"
#include "globals.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/******************************************************************************
*
* Name : main
*
* Description : Main thread will initialize the process for PM services and
* process the application message queue until a WM_QUIT message
* is received. It will then destroy all PM resources and
* terminate. Any error during initialization will be reported
* and the process terminated.
*
* Concepts :
*
* API's :
*
* Parameters : VOID
*
* Return :
*
******************************************************************************/
VOID main(VOID)
{
QMSG qmsg;
if( Initialize())
while( WinGetMsg( habMain, &qmsg, NULLHANDLE, 0, 0))
WinDispatchMsg( habMain, &qmsg);
else
ReportError( habMain);
Finalize();
} /* end main() */
/******************************************************************************
*
* Name : Initialize
*
* Description :
*
* The Initialize function will initialize the PM interface,
* create an application message queue, a standard frame window and a new
* thread to control drawing operations. It will also initialize static
* strings.
*
* Concepts :
*
* API's :
*
* Parameters : VOID
*
* Return : BOOL
*
******************************************************************************/
BOOL Initialize(VOID)
{
ULONG flCreate;
PID pid;
TID tid;
/*
* create all semaphores for mutual exclusion and event timing
*/
/* (anonomous, , private, reset) */
if (DosCreateEventSem( NULL, &hevDrawOn, 0, FALSE) ||
DosCreateEventSem( NULL, &hevMouse, 0, FALSE) ||
DosCreateEventSem( NULL, &hevLoadingBitmap, 0, FALSE) ||
DosCreateEventSem( NULL, &hevTerminate, 0, FALSE) ||
DosCreateEventSem( NULL, &hevKillDraw, 0, FALSE))
{
return (FALSE); /* failed to create a semaphore */
}
WinShowPointer( HWND_DESKTOP, TRUE);
habMain = WinInitialize( 0);
if( !habMain)
return( FALSE);
hmqMain = WinCreateMsgQueue( habMain,0);
if( !hmqMain)
return( FALSE);
WinLoadString( habMain, 0, IDS_TITLEBAR, sizeof(szTitle), szTitle);
WinLoadString( habMain, 0, IDS_ERROR_TITLE, sizeof(szErrorTitle), szErrorTitle);
if( !WinRegisterClass( habMain
, (PCH)szTitle
, ClientWndProc
, CS_SIZEREDRAW
, 0 ))
return( FALSE);
flCreate = (FCF_STANDARD | FCF_VERTSCROLL | FCF_HORZSCROLL)
& ~(ULONG)FCF_TASKLIST;
hwndFrame =
WinCreateStdWindow(
HWND_DESKTOP, /* handle of the parent window */
WS_VISIBLE, /* frame-window style */
&flCreate, /* creation flags */
szTitle, /* client-window class name */
szTitle, /* address of title-bar text */
WS_VISIBLE, /* client-window style */
0, /* handle of the resource module */
IDR_MAIN, /* frame-window identifier */
&hwndClient); /* address of client-window handle */
if( !hwndFrame)
return( FALSE);
sizlMaxClient.cx = WinQuerySysValue( HWND_DESKTOP, SV_CXFULLSCREEN);
sizlMaxClient.cy = WinQuerySysValue( HWND_DESKTOP, SV_CYFULLSCREEN);
lByteAlignX = WinQuerySysValue( HWND_DESKTOP, SV_CXBYTEALIGN);
lByteAlignY = WinQuerySysValue( HWND_DESKTOP, SV_CYBYTEALIGN);
hdcClient = WinOpenWindowDC( hwndClient);
hpsClient = GpiCreatePS( habMain
, hdcClient
, &sizlMaxClient
, GPIA_ASSOC | PU_PELS );
if( !hpsClient)
{
DispError(habMain,hwndClient);
return( TRUE);
}
if (GpiSetAttrMode( hpsClient, AM_PRESERVE) == GPI_ERROR)
DispError(habMain,hwndClient);
hwndHorzScroll = WinWindowFromID( hwndFrame, FID_HORZSCROLL);
hwndVertScroll = WinWindowFromID( hwndFrame, FID_VERTSCROLL);
if ((hpsPaint = GpiCreatePS( habMain, NULLHANDLE, &sizlMaxClient, PU_PELS)) == GPI_ERROR)
DispError(habMain,hwndClient);
hrgnInvalid = GpiCreateRegion( hpsClient, 0L, NULL);
WinQueryWindowProcess( hwndFrame, &pid, &tid);
swctl.hwnd = hwndFrame;
swctl.idProcess = pid;
strcpy( swctl.szSwtitle, szTitle);
hsw = WinAddSwitchEntry( &swctl);
hwndMenu = WinWindowFromID( hwndFrame, FID_MENU);
if(DosCreateThread(&tidAsync,
(PFNTHREAD) NewThread,
0,
0,
STACKSIZE )) {
return( FALSE);
} /* create async thread */
if( !CreateBitmapHdcHps( &hdcBitmapFile, &hpsBitmapFile))
return( FALSE);
if( !CreateBitmapHdcHps( &hdcBitmapSize, &hpsBitmapSize))
return( FALSE);
if( !CreateBitmapHdcHps( &hdcBitmapBuff, &hpsBitmapBuff))
return( FALSE);
if( !CreateBitmapHdcHps( &hdcBitmapSave, &hpsBitmapSave))
return( FALSE);
ResetScrollBars();
/*
* initialise help mechanism
*/
HelpInit();
return( TRUE);
} /* end Initialize() */
/******************************************************************************
*
* Name : Finalize
*
* Description :
*
* Finalize will destroy the asynchronous drawing thread, all Presentation
* Manager resources, and terminate the process.
*
* Concepts :
*
* API's :
*
* Parameters : VOID
*
* Return : VOID
*
******************************************************************************/
VOID Finalize(VOID)
{
ULONG ulPostCt;
if( tidAsync)
{
DosResetEventSem( hevDrawOn, &ulPostCt);
DosPostEventSem( hevKillDraw);
DosPostEventSem( hevTerminate);
SendCommand( UM_DIE, (MPARAM)NULL, (MPARAM)NULL);
}
while( pslHead != NULL )
{
if (GpiSetBitmap( pslHead->hpsFill, NULLHANDLE) == (HBITMAP)BMB_ERROR)
DispError(habMain,hwndClient);
if (GpiDeleteBitmap( pslHead->hbmFill) == GPI_ERROR)
DispError(habMain,hwndClient);
if (GpiDestroyPS( pslHead->hpsFill) == GPI_ERROR)
DispError(habMain,hwndClient);
DevCloseDC( pslHead->hdcFill);
if (GpiSetBitmap( pslHead->hpsHole, NULLHANDLE)== (HBITMAP)BMB_ERROR)
DispError(habMain,hwndClient);
if (GpiDeleteBitmap( pslHead->hbmHole) == GPI_ERROR)
DispError(habMain,hwndClient);
if (GpiDestroyPS( pslHead->hpsHole) == GPI_ERROR)
DispError(habMain,hwndClient);
DevCloseDC( pslHead->hdcHole);
SegListUpdate( DEL_SEG, pslHead);
}
if( hrgnInvalid)
GpiDestroyRegion( hpsClient, hrgnInvalid);
if( hpsClient)
{
GpiAssociate( hpsClient, NULLHANDLE);
GpiDestroyPS( hpsClient);
}
if( hpsPaint)
GpiDestroyPS( hpsPaint);
if( hpsBitmapFile)
{
GpiSetBitmap( hpsBitmapFile, NULLHANDLE);
GpiDeleteBitmap( hbmBitmapFile);
GpiDestroyPS( hpsBitmapFile);
DevCloseDC( hdcBitmapFile);
}
if( hpsBitmapSize)
{
GpiSetBitmap( hpsBitmapSize, NULLHANDLE);
GpiDeleteBitmap( hbmBitmapSize);
GpiDestroyPS( hpsBitmapSize);
DevCloseDC( hdcBitmapSize);
}
if( hpsBitmapBuff)
{
GpiSetBitmap( hpsBitmapBuff, NULLHANDLE);
GpiDeleteBitmap( hbmBitmapBuff);
GpiDestroyPS( hpsBitmapBuff);
DevCloseDC( hdcBitmapBuff);
}
if( hpsBitmapSave)
{
GpiSetBitmap( hpsBitmapSave, NULLHANDLE);
GpiDeleteBitmap( hbmBitmapSave);
GpiDestroyPS( hpsBitmapSave);
DevCloseDC( hdcBitmapSave);
}
DestroyHelpInstance();
if( hwndFrame)
WinDestroyWindow( hwndFrame);
if( hmqMain)
WinDestroyMsgQueue( hmqMain);
if( habMain)
WinTerminate( habMain);
DosExit( EXIT_PROCESS, 0);
} /* end Finalize() */
/******************************************************************************
*
* Name : ReportError
*
* Description :
*
* ReportError will display the latest error information for the required
* thread. No resources to be loaded if out of memory error.
*
* Concepts :
*
* API's :
*
* Parameters : HAB hab
*
* Return : VOID
*
******************************************************************************/
VOID ReportError(HAB hab)
{
PERRINFO perriBlk;
PSZ pszErrMsg;
PSZ pszOffSet;
if (!fErrMem){
if ((perriBlk = WinGetErrorInfo(hab)) != (PERRINFO)NULL){
pszOffSet = ((PSZ)perriBlk) + perriBlk->offaoffszMsg;
pszErrMsg = ((PSZ)perriBlk) + *((PULONG)pszOffSet);
WinMessageBox(HWND_DESKTOP,
hwndFrame,
(PSZ)(pszErrMsg),
(PSZ)szTitle,
0,
MB_MOVEABLE | MB_CUACRITICAL | MB_CANCEL );
WinFreeErrorInfo(perriBlk);
return;
}
} /* endif */
MessageBox( /* ERROR */
hwndFrame,
IDS_ERROR_OUTOFMEMORY,
MB_MOVEABLE | MB_CUACRITICAL | MB_CANCEL,
TRUE);
} /* end ReportError() */
/******************************************************************************
*
* Name : ResetScrollBars
*
* Description :
*
* Reset the scroll bars to be in the middle of their range
*
* Concepts :
*
* API's :
*
* Parameters : VOID
*
* Return : VOID
*
******************************************************************************/
VOID ResetScrollBars(VOID)
{
RECTL rclClient;
WinQueryWindowRect( hwndClient, &rclClient);
ptsScrollMax.x = (SHORT)(rclClient.xRight - rclClient.xLeft);
ptsHalfScrollMax.x = ptsScrollMax.x >> 1;
ptsScrollPage.x = ptsScrollMax.x >> 3;
ROUND_DOWN_MOD( ptsScrollPage.x, (SHORT)lByteAlignX);
ptsScrollLine.x = ptsScrollMax.x >> 5;
ROUND_DOWN_MOD( ptsScrollLine.x, (SHORT)lByteAlignX);
ptsScrollPos.x = ptsHalfScrollMax.x;
ptsOldScrollPos.x = ptsHalfScrollMax.x;
WinSendMsg( hwndHorzScroll
, SBM_SETSCROLLBAR
, MPFROMSHORT( ptsScrollPos.x)
, MPFROM2SHORT( 1, ptsScrollMax.x) );
ptsScrollMax.y = (SHORT)(rclClient.yTop - rclClient.yBottom);
ptsHalfScrollMax.y = ptsScrollMax.y >> 1;
ptsScrollPage.y = ptsScrollMax.y >> 3;
ROUND_DOWN_MOD( ptsScrollPage.y, (SHORT)lByteAlignY);
ptsScrollLine.y = ptsScrollMax.y >> 5;
ROUND_DOWN_MOD( ptsScrollLine.y, (SHORT)lByteAlignY);
ptsScrollPos.y = ptsHalfScrollMax.y;
ptsOldScrollPos.y = ptsHalfScrollMax.y;
WinSendMsg( hwndVertScroll
, SBM_SETSCROLLBAR
, MPFROMSHORT( ptsScrollPos.y)
, MPFROM2SHORT( 1, ptsScrollMax.y) );
WinSendMsg( hwndHorzScroll
, SBM_SETTHUMBSIZE
, MPFROM2SHORT(ptsScrollPage.x, ptsScrollMax.x)
, 0 );
WinSendMsg( hwndVertScroll
, SBM_SETTHUMBSIZE
, MPFROM2SHORT(ptsScrollPage.y, ptsScrollMax.y)
, NULL );
} /* end ResetScrollBars() */
/******************************************************************************
*
* Name : Load
*
* Description : Load a bitmap
*
* Parameters : PLOADINFO pli - pointer to file information (name, handle...)
*
* Return : VOID
*
******************************************************************************/
VOID Load(PLOADINFO pli)
{
ULONG ulPostCt;
PUCHAR pFilename;
UCHAR szWindowText[CCHMAXPATH];
DosResetEventSem( hevLoadingBitmap, &ulPostCt); /* begin loading bitmap */
/*
* Disable bitmap manipulation submenus
*/
EnableMenu(IDM_SIZE_MENU, FALSE);
EnableMenu(IDM_SIZE_SMALL, FALSE);
EnableMenu(IDM_SIZE_MEDIUM, FALSE);
EnableMenu(IDM_SIZE_LARGE, FALSE);
EnableMenu(IDM_SIZE_FULL, FALSE);
EnableMenu(IDM_JUMBLE, FALSE);
CheckMenu(Currentchecked, FALSE); /* uncheck old menu */
if( hbmBitmapFile)
{
if (GpiSetBitmap( hpsBitmapFile, NULLHANDLE) == (HBITMAP)BMB_ERROR)
DispError(habMain,hwndClient);
if (GpiDeleteBitmap( hbmBitmapFile) == GPI_ERROR)
DispError(habMain,hwndClient);
}
if (!ReadBitmap( pli->hf))
{
MessageBox(hwndClient, IDS_ERROR_READ, MB_OK | MB_ERROR, TRUE);
DosPostEventSem( hevLoadingBitmap); /* end loading bitmap */
if (!fFirstLoad)
{
/*
* Re-Enable bitmap manipulation submenus
*/
EnableMenu(IDM_SIZE_MENU, TRUE);
EnableMenu(IDM_SIZE_SMALL, TRUE);
EnableMenu(IDM_SIZE_MEDIUM, TRUE);
EnableMenu(IDM_SIZE_LARGE, TRUE);
EnableMenu(IDM_SIZE_FULL, TRUE);
EnableMenu(IDM_JUMBLE, TRUE);
CheckMenu(Currentchecked, TRUE); /* recheck old menu */
} /* end if (!fFirstLoad) */
return;
}
/*
* Change Title Bar text and Window List text to include filename.
*/
strcpy(swctl.szSwtitle, szTitle);
strcat(swctl.szSwtitle, " - ");
strcpy(szWindowText, swctl.szSwtitle); /* save duplicate part */
pFilename = strrchr(pli->szFileName, '\\'); /* contain pathname? */
if (pFilename == NULL)
pFilename = pli->szFileName; /* filename doesn't contain path */
else
++pFilename; /* point past last back-slash */
strcat( swctl.szSwtitle, pFilename);
WinChangeSwitchEntry( hsw, &swctl);
strcat(szWindowText, pli->szFileName); /* use full filename in window */
WinSetWindowText( hwndFrame, szWindowText);
ResetScrollBars();
if (fFirstLoad ||
(PBMP1(pbmp2BitmapFile)->cx > PBMP1(pbmp2BitmapFileRef)->cx ||
PBMP1(pbmp2BitmapFile)->cy > PBMP1(pbmp2BitmapFileRef)->cy ||
PBMP1(pbmp2BitmapFile)->cPlanes != PBMP1(pbmp2BitmapFileRef)->cPlanes ||
PBMP1(pbmp2BitmapFile)->cBitCount != PBMP1(pbmp2BitmapFileRef)->cBitCount))
{
if( !fFirstLoad)
DumpPicture();
if( !PrepareBitmap() )
{
MessageBox(hwndClient, IDS_ERROR_READ, MB_OK | MB_ERROR, TRUE);
DosPostEventSem( hevLoadingBitmap); /* end loading bitmap */
if (!fFirstLoad)
{
/*
* Re-Enable bitmap manipulation submenus
*/
EnableMenu(IDM_SIZE_MENU, TRUE);
EnableMenu(IDM_SIZE_SMALL, TRUE);
EnableMenu(IDM_SIZE_MEDIUM, TRUE);
EnableMenu(IDM_SIZE_LARGE, TRUE);
EnableMenu(IDM_SIZE_FULL, TRUE);
EnableMenu(IDM_JUMBLE, TRUE);
CheckMenu(Currentchecked, TRUE); /* recheck old menu */
} /* end if (!fFirstLoad) */
return;
}
CreatePicture( PICTURE_CREATE);
bmp2BitmapFileRef = bmp2BitmapFile;
} else
{
CreatePicture( PICTURE_UPDATE);
}
lScale = 0;
CalcBounds();
ptlScaleRef.x = ptlScaleRef.y = 0L;
CalcTransform( hwndClient);
DosPostEventSem( hevLoadingBitmap); /* end loading bitmap */
fFirstLoad = FALSE;
fPictureAssembled = TRUE;
BmpLoaded = TRUE;
/*
* Enable bitmap manipulation submenus
*/
EnableMenu(IDM_SIZE_MENU, TRUE);
EnableMenu(IDM_SIZE_SMALL, TRUE);
EnableMenu(IDM_SIZE_MEDIUM, TRUE);
EnableMenu(IDM_SIZE_LARGE, TRUE);
EnableMenu(IDM_SIZE_FULL, TRUE);
EnableMenu(IDM_JUMBLE, TRUE);
CheckMenu(IDM_SIZE_FULL, TRUE); /* check full size */
Currentchecked = IDM_SIZE_FULL;
} /* end Load() */
/******************************************************************************/
/* Throw the pieces around the screen. */
/******************************************************************************/
VOID Jumble(VOID)
{
LONG lWidth, lHeight;
DATETIME date;
POINTL ptl;
RECTL rclClient;
PSEGLIST psl;
if( WinQueryWindowRect( hwndClient, &rclClient) )
{
lWidth = rclClient.xRight - rclClient.xLeft;
lHeight = rclClient.yTop - rclClient.yBottom;
if( (lWidth > 0) && (lHeight > 0) )
{
DosGetDateTime( &date);
srand( (USHORT)date.hundredths);
for( psl = pslHead; psl != NULL; psl = psl->pslNext)
{
psl->pslNextIsland = psl; /* reset island pointer */
psl->fIslandMark = FALSE; /* clear island mark */
ptl.x = rclClient.xLeft + (rand() % lWidth);
ptl.y = rclClient.yBottom + (rand() % lHeight);
if (GpiConvert( hpsClient, CVTC_DEVICE, CVTC_MODEL, 1L, &ptl) == GPI_ERROR)
DispError(habMain,hwndClient);
ptl.x = 50 * (ptl.x / 50) - 250;
ptl.y = 50 * (ptl.y / 50) - 250;
psl->ptlModelXlate.x = ptl.x - psl->ptlLocation.x;
psl->ptlModelXlate.y = ptl.y - psl->ptlLocation.y;
SetRect( psl);
}
}
fPictureAssembled = FALSE;
}
}
/******************************************************************************/
/* */
/* */
/* */
/******************************************************************************/
VOID ToBottom( pslDown)
PSEGLIST pslDown;
{
BOOL fFirst;
PSEGLIST psl;
for( psl = pslDown, fFirst = TRUE
; (psl != pslDown) || fFirst
; psl = psl->pslNextIsland, fFirst = FALSE )
SegListUpdate( MAKE_HEAD_SEG, psl); /* at head => lowest priority */
}
/******************************************************************************/
/* */
/* NewThread is the asynchronous drawing thread. It is responsible for all */
/* drawing. It will initialize its PM interface and create an application */
/* message queue. It will then monitor its message queue and process any */
/* commands received. */
/* */
/******************************************************************************/
VOID NewThread(VOID)
{
QMSG qmsgAsync, qmsgPeek;
BOOL fDone;
POINTL aptlDraw[3];
USHORT usChar, fsKeyFlags;
PSEGLIST psl;
ULONG ulPostCt;
/****************************************************************************/
/* Initialize the PM interface. If it fails, terminate both threads. */
/****************************************************************************/
habAsync = WinInitialize( 0);
if( !habAsync)
{
WinPostMsg( hwndClient, WM_QUIT, NULL, NULL);
DosExit( EXIT_THREAD, 0);
}
/****************************************************************************/
/* Create a message queue. If it fails, terminate both threads. */
/****************************************************************************/
hmqAsync = WinCreateMsgQueue( habAsync, 150);
if( !hmqAsync)
{
WinPostMsg( hwndClient, WM_QUIT, NULL, NULL);
WinTerminate( habAsync);
DosExit( EXIT_THREAD, 0);
}
else
{
WinCancelShutdown( hmqAsync, TRUE); /* don't wait around for shutdown */
}
DosSetPriority( PRTYS_THREAD, PRTYC_NOCHANGE, sPrty, (TID)NULL);
while( TRUE)
{
WinGetMsg( habAsync, &qmsgAsync, NULLHANDLE, 0, 0);
/*
* If we're exiting, give that message highest priority.
*/
if( WinPeekMsg(habAsync, &qmsgPeek, NULLHANDLE, UM_DIE, UM_DIE, PM_NOREMOVE))
qmsgAsync = qmsgPeek;
/*
* Disallow drawing and mouse tracking as needed
*/
if( (qmsgAsync.msg < UM_SIZING) || (qmsgAsync.msg > UM_LOAD))
DosPostEventSem( hevMouse); /* enable mouse tracking */
else
DosResetEventSem( hevMouse, &ulPostCt); /* disable mouse tracking */
if( WinPeekMsg( habAsync, &qmsgPeek, NULLHANDLE, UM_SIZING, UM_LOAD, PM_NOREMOVE))
{
DosResetEventSem( hevDrawOn, &ulPostCt); /* disable drawing */
DosResetEventSem( hevMouse, &ulPostCt); /* disable mouse tracking */
}
else
{
DosPostEventSem( hevDrawOn); /* enable drawing */
DosPostEventSem( hevMouse); /* enable mouse tracking */
}
/**************************************************************************/
/* process the commands */
/**************************************************************************/
switch( qmsgAsync.msg)
{
/************************************************************************/
case UM_CHAR:
fsKeyFlags = (USHORT)SHORT1FROMMP(qmsgAsync.mp1);
usChar = (USHORT)SHORT1FROMMP(qmsgAsync.mp2);
if( (fsKeyFlags & KC_CHAR)
&& ((usChar == 'b') || (usChar == 'B')))
{
if( psl = Correlate( &ptlMouse))
{
ToBottom( psl);
Redraw();
}
}
break;
/************************************************************************/
case UM_LOAD:
Load( (PLOADINFO)qmsgAsync.mp1);
Redraw();
break;
/************************************************************************/
case UM_JUMBLE:
Jumble();
Redraw();
break;
/************************************************************************/
case UM_REDRAW:
Redraw();
break;
/************************************************************************/
/* DRAW will use the passed region containing the invalidated area of */
/* the screen, repaint it and then destroy the region. */
/************************************************************************/
case UM_DRAW:
if (!BmpLoaded)
break;
if( qmsgAsync.mp1)
{
DoDraw( hpsBitmapBuff, (HRGN)qmsgAsync.mp1, TRUE);
if (GpiQueryRegionBox( hpsClient, (HRGN)qmsgAsync.mp1, (PRECTL)aptlDraw) == RGN_ERROR)
DispError(habMain,hwndClient);
if (GpiDestroyRegion( hpsClient, (HRGN)qmsgAsync.mp1) == GPI_ERROR)
DispError(habMain,hwndClient);
WinMapWindowPoints( hwndClient, HWND_DESKTOP, aptlDraw, 3);
ROUND_DOWN_MOD( aptlDraw[0].x, lByteAlignX); /* round down */
ROUND_DOWN_MOD( aptlDraw[0].y, lByteAlignY); /* round down */
ROUND_UP_MOD( aptlDraw[1].x, lByteAlignX); /* round up */
ROUND_UP_MOD( aptlDraw[1].y, lByteAlignY); /* round up */
WinMapWindowPoints( HWND_DESKTOP, hwndClient, aptlDraw, 3);
aptlDraw[2] = aptlDraw[0];
if (GpiBitBlt( hpsClient
, hpsBitmapBuff
, 3L
, aptlDraw
, ROP_SRCCOPY
, BBO_IGNORE ) == GPI_ERROR)
DispError(habMain,hwndClient);
}
break;
/************************************************************************/
/* Get new scroll posn from command ( i.e. +/-1 +/-page) or new */
/* absolute position from parameter, update scroll posn, change the */
/* transform and update the thumb posn. Finally update the window. */
/************************************************************************/
case UM_HSCROLL:
switch( SHORT2FROMMP( qmsgAsync.mp1) )
{
case SB_LINEUP:
ptsScrollPos.x -= ptsScrollLine.x;
break;
case SB_LINEDOWN:
ptsScrollPos.x += ptsScrollLine.x;
break;
case SB_SLIDERTRACK:
case SB_SLIDERPOSITION:
for( fDone = FALSE; !fDone ;)
{
if( WinPeekMsg( habAsync
, &qmsgPeek
, NULLHANDLE
, UM_HSCROLL
, UM_HSCROLL
, PM_NOREMOVE))
if( (SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERTRACK)
||(SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERPOSITION))
WinPeekMsg( habAsync
, &qmsgAsync
, NULLHANDLE
, UM_HSCROLL
, UM_HSCROLL
, PM_REMOVE);
else
fDone = TRUE;
else
fDone = TRUE;
}
ptsScrollPos.x = SHORT1FROMMP( qmsgAsync.mp1);
ROUND_DOWN_MOD( ptsScrollPos.x, (SHORT)lByteAlignX);
break;
case SB_PAGEUP:
ptsScrollPos.x -= ptsScrollPage.x;
break;
case SB_PAGEDOWN:
ptsScrollPos.x += ptsScrollPage.x;
break;
case SB_ENDSCROLL:
break;
default:
break;
}
DoHorzScroll();
break;
case UM_VSCROLL:
switch( SHORT2FROMMP( qmsgAsync.mp1) )
{
case SB_LINEUP:
ptsScrollPos.y -= ptsScrollLine.y;
break;
case SB_LINEDOWN:
ptsScrollPos.y += ptsScrollLine.y;
break;
case SB_SLIDERTRACK:
case SB_SLIDERPOSITION:
for( fDone = FALSE; !fDone ;)
{
if( WinPeekMsg( habAsync
, &qmsgPeek
, NULLHANDLE
, UM_VSCROLL
, UM_VSCROLL
, PM_NOREMOVE))
if( (SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERTRACK)
||(SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERPOSITION))
WinPeekMsg( habAsync
, &qmsgAsync
, NULLHANDLE
, UM_VSCROLL
, UM_VSCROLL
, PM_REMOVE);
else
fDone = TRUE;
else
fDone = TRUE;
}
ptsScrollPos.y = SHORT1FROMMP( qmsgAsync.mp1);
ROUND_DOWN_MOD( ptsScrollPos.y, (SHORT)lByteAlignY);
break;
case SB_PAGEUP:
ptsScrollPos.y -= ptsScrollPage.y;
break;
case SB_PAGEDOWN:
ptsScrollPos.y += ptsScrollPage.y;
break;
case SB_ENDSCROLL:
break;
default:
break;
}
DoVertScroll();
break;
/************************************************************************/
/* the window is being resized */
/************************************************************************/
case UM_SIZING:
CalcBounds();
CalcTransform( hwndClient);
break;
/************************************************************************/
/* adjust zoom factor */
/************************************************************************/
case UM_ZOOM:
if( WinPeekMsg( habAsync
, &qmsgPeek
, NULLHANDLE
, UM_SIZING
, UM_LOAD
, PM_NOREMOVE))
DosResetEventSem( hevDrawOn, &ulPostCt);
else {
DosPostEventSem( hevDrawOn);
}
Zoom();
break;
/************************************************************************/
/* Button down will cause a correlate on the picture to test for a hit. */
/* Any selected segment will be highlighted and redrawn as dynamic. */
/************************************************************************/
case UM_LEFTDOWN:
if( !fButtonDownAsync)
{
fButtonDownAsync = TRUE;
if(!fPictureAssembled)
LeftDown( qmsgAsync.mp1);
}
break;
/************************************************************************/
/* if a segment is being dragged it will be redrawn in a new posn */
/************************************************************************/
case UM_MOUSEMOVE:
#ifdef fred
if( !fButtonDownAsync)
break;
#endif
for( fDone = FALSE; !fDone ;)
{
if( WinPeekMsg( habAsync /* look through first button-up */
, &qmsgPeek
, NULLHANDLE
, UM_MOUSEMOVE
, UM_LEFTUP
, PM_NOREMOVE))
if( qmsgPeek.msg == UM_MOUSEMOVE) /* only collapse move msgs */
WinPeekMsg( habAsync
, &qmsgAsync
, NULLHANDLE
, UM_MOUSEMOVE
, UM_MOUSEMOVE
, PM_REMOVE);
else
fDone = TRUE;
else
fDone = TRUE;
}
MouseMove( qmsgAsync.mp1); /* process last move before button-up */
break;
/************************************************************************/
/* if a segment is being dragged it will be redrawn as normal */
/************************************************************************/
case UM_LEFTUP:
if( fButtonDownAsync)
{
LeftUp();
fButtonDownAsync = FALSE;
}
break;
/************************************************************************/
/* destroy resources and terminate */
/************************************************************************/
case UM_DIE:
WinDestroyMsgQueue( hmqAsync);
WinTerminate( habAsync);
DosExit( EXIT_THREAD, 0);
break;
/************************************************************************/
default:
break;
}
}
}
/******************************************************************************/
/* */
/******************************************************************************/
VOID CalcSize( mp1, mp2)
MPARAM mp1;
MPARAM mp2;
{
ptsScrollMax.y = SHORT2FROMMP( mp2);
ptsHalfScrollMax.y = ptsScrollMax.y >> 1;
ptsScrollPage.x = ptsScrollMax.x >> 3;
ROUND_DOWN_MOD( ptsScrollPage.x, (SHORT)lByteAlignX);
ptsScrollLine.x = ptsScrollMax.x >> 5;
ROUND_DOWN_MOD( ptsScrollLine.x, (SHORT)lByteAlignX);
ptsScrollPos.y = (SHORT)(
( (LONG)ptsScrollPos.y
* (LONG)SHORT2FROMMP(mp2)
)/ (LONG)SHORT2FROMMP(mp1)
);
ptsOldScrollPos.y = (SHORT)(
( (LONG)ptsOldScrollPos.y
* (LONG)SHORT2FROMMP(mp2)
)/ (LONG)SHORT2FROMMP(mp1)
);
WinSendMsg( hwndVertScroll
, SBM_SETSCROLLBAR
, MPFROMSHORT( ptsScrollPos.y)
, MPFROM2SHORT( 1, ptsScrollMax.y) );
ptsScrollMax.x = SHORT1FROMMP( mp2);
ptsHalfScrollMax.x = ptsScrollMax.x >> 1;
ptsScrollPage.y = ptsScrollMax.y >> 3;
ROUND_DOWN_MOD( ptsScrollPage.y, (SHORT)lByteAlignY);
ptsScrollLine.y = ptsScrollMax.y >> 5;
ROUND_DOWN_MOD( ptsScrollLine.y, (SHORT)lByteAlignY);
ptsScrollPos.x = (SHORT)(
( (LONG)ptsScrollPos.x
* (LONG)SHORT1FROMMP(mp2)
)/(LONG)SHORT1FROMMP(mp1)
);
ptsOldScrollPos.x = (SHORT)(
( (LONG)ptsOldScrollPos.x
* (LONG)SHORT1FROMMP(mp2)
)/ (LONG)SHORT1FROMMP(mp1)
);
WinSendMsg( hwndHorzScroll
, SBM_SETSCROLLBAR
, MPFROMSHORT( ptsScrollPos.x)
, MPFROM2SHORT( 1, ptsScrollMax.x) );
WinSendMsg( hwndHorzScroll
, SBM_SETTHUMBSIZE
, MPFROM2SHORT(ptsScrollPage.x, ptsScrollMax.x)
, NULL );
WinSendMsg( hwndVertScroll
, SBM_SETTHUMBSIZE
, MPFROM2SHORT(ptsScrollPage.y, ptsScrollMax.y)
, NULL );
}
/******************************************************************************/
/* button down will cause one segment to be indicated and made dynamic */
/******************************************************************************/
VOID LeftDown(MPARAM mp)
{
POINTL ptl;
HRGN hrgn, hrgnUpdt, hrgnUpdtDrag;
RECTL rcl;
BOOL fFirst;
PSEGLIST psl;
ptl.x = (LONG)(SHORT)SHORT1FROMMP( mp);
ptl.y = (LONG)(SHORT)SHORT2FROMMP( mp);
/****************************************************************************/
pslPicked = Correlate( &ptl);
if( pslPicked)
lPickedSeg = pslPicked->lSegId;
else
{
fButtonDownAsync = FALSE;
return;
}
if( (lPickedSeg < 1) || (lPickedSeg > lLastSegId) )
{
#if defined(DEBUG)
{
CHAR szMsg[40];
sprintf( szMsg, "Segment id out of range: %x", lPickedSeg);
WinMessageBox(HWND_DESKTOP, hwndFrame, szMsg, szErrorTitle, 0,
MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
}
#endif
fButtonDownAsync = FALSE;
return;
}
/****************************************************************************/
ptlOffStart = pslPicked->ptlModelXlate;
ptlMoveStart = ptl;
if (GpiConvert( hpsClient, CVTC_DEVICE, CVTC_MODEL, 1L, &ptlMoveStart) == GPI_ERROR)
DispError(habMain,hwndClient);
ptlMoveStart.x = (ptlMoveStart.x / 50) * 50;
ptlMoveStart.y = (ptlMoveStart.y / 50) * 50;
ptlUpdtRef = ptlMoveStart;
if (GpiConvert( hpsClient, CVTC_MODEL, CVTC_DEVICE, 1L, &ptlUpdtRef) == GPI_ERROR)
DispError(habMain,hwndClient);
/****************************************************************************/
hrgnUpdt = GpiCreateRegion( hpsClient, 0L, NULL);
for( psl = pslPicked, fFirst = TRUE
; (psl != pslPicked) || fFirst
; psl = psl->pslNextIsland, fFirst = FALSE )
{
rcl = psl->rclCurrent; /* get model space bounding box of piece */
if (GpiConvert( hpsClient, CVTC_MODEL, CVTC_DEVICE, 2L, (PPOINTL)&rcl) == GPI_ERROR)
DispError(habMain,hwndClient);
rcl.xRight++; /* adjust rectangle for conversion to dev space */
rcl.yTop++;
rcl.xRight += 2; /* should not need */
rcl.yTop += 2; /* should not need */
rcl.xLeft -= 4; /* should not need */
rcl.yBottom -= 4; /* should not need */
hrgn = GpiCreateRegion( hpsClient, 1L, &rcl);
if (GpiCombineRegion( hpsClient, hrgnUpdt, hrgnUpdt, hrgn, CRGN_OR) == RGN_ERROR)
DispError(habMain,hwndClient);
if (GpiDestroyRegion( hpsClient, hrgn) == GPI_ERROR)
DispError(habMain,hwndClient);
psl->fVisible = FALSE;
}
if (GpiQueryRegionBox( hpsClient, hrgnUpdt, (PRECTL)aptlUpdt) == GPI_ERROR)
DispError(habMain,hwndClient);
WinMapWindowPoints( hwndClient, HWND_DESKTOP, aptlUpdt, 3);
ROUND_DOWN_MOD( aptlUpdt[0].x, lByteAlignX); /* round down */
ROUND_DOWN_MOD( aptlUpdt[0].y, lByteAlignY); /* round down */
ROUND_UP_MOD( aptlUpdt[1].x, lByteAlignX); /* round up */
ROUND_UP_MOD( aptlUpdt[1].y, lByteAlignY); /* round up */
WinMapWindowPoints( HWND_DESKTOP, hwndClient, aptlUpdt, 3);
hrgnUpdtDrag = GpiCreateRegion( hpsBitmapBuff, 1L, (PRECTL)aptlUpdt);
aptlUpdt[2] = aptlUpdt[0];
DoDraw( hpsBitmapBuff, hrgnUpdtDrag, TRUE);
if (GpiDestroyRegion( hpsClient, hrgnUpdt) == GPI_ERROR)
DispError(habMain,hwndClient);
if (GpiDestroyRegion( hpsBitmapBuff, hrgnUpdtDrag) == GPI_ERROR)
DispError(habMain,hwndClient);
if (GpiBitBlt( hpsBitmapSave
, hpsBitmapBuff
, 3L
, aptlUpdt
, ROP_SRCCOPY
, BBO_IGNORE ) == GPI_ERROR)
DispError(habMain,hwndClient);
/****************************************************************************/
for( psl = pslPicked, fFirst = TRUE
; (psl != pslPicked) || fFirst
; psl = psl->pslNextIsland, fFirst = FALSE )
{
psl->fVisible = TRUE;
DrawPiece( hpsBitmapBuff, psl, TRUE);
}
if (GpiBitBlt( hpsClient
, hpsBitmapBuff
, 3L
, aptlUpdt
, ROP_SRCCOPY
, BBO_IGNORE ) == GPI_ERROR)
DispError(habMain,hwndClient);
WinSetCapture( HWND_DESKTOP, hwndClient);
}
/******************************************************************************/
/* */
/* move the segment */
/* */
/******************************************************************************/
VOID MouseMove( mp)
MPARAM mp;
{
RECTL rcl;
POINTL ptl, ptlModel, ptlDevice;
POINTL aptlUpdtRef[3], aptlUpdtNew[3];
PSEGLIST psl;
BOOL fFirst;
ptl.x = (LONG)(SHORT)SHORT1FROMMP( mp);
ptl.y = (LONG)(SHORT)SHORT2FROMMP( mp);
/****************************************************************************/
/* clip mouse coords to client window */
/****************************************************************************/
WinQueryWindowRect( hwndClient, &rcl);
if (rcl.xLeft > ptl.x)
ptl.x = rcl.xLeft;
if (rcl.xRight <= ptl.x)
ptl.x = rcl.xRight;
if (rcl.yBottom > ptl.y)
ptl.y = rcl.yBottom;
if (rcl.yTop <= ptl.y)
ptl.y = rcl.yTop;
ptlMouse = ptl;
if( !lPickedSeg || !pslPicked || !fButtonDownAsync)
return;
ptlModel = ptl;
if (GpiConvert( hpsClient, CVTC_DEVICE, CVTC_MODEL, 1L, &ptlModel) == GPI_ERROR)
DispError(habMain,hwndClient);
ptlModel.x = 50 * (ptlModel.x / 50);
ptlModel.y = 50 * (ptlModel.y / 50);
if( (ptlModel.x == ptlOldMouse.x) && (ptlModel.y == ptlOldMouse.y))
return;
ptlOldMouse.x = ptlModel.x;
ptlOldMouse.y = ptlModel.y;
ptlDevice = ptlModel;
if (GpiConvert( hpsClient, CVTC_MODEL, CVTC_DEVICE, 1L, &ptlDevice) == GPI_ERROR)
DispError(habMain,hwndClient);
if (GpiBitBlt( hpsBitmapBuff
, hpsBitmapSave
, 3L
, aptlUpdt
, ROP_SRCCOPY
, BBO_IGNORE ) == GPI_ERROR)
DispError(habMain,hwndClient);
aptlUpdtRef[0] = aptlUpdt[0];
aptlUpdtRef[1] = aptlUpdt[1];
aptlUpdt[0].x += ptlDevice.x - ptlUpdtRef.x;
aptlUpdt[0].y += ptlDevice.y - ptlUpdtRef.y;
aptlUpdt[1].x += ptlDevice.x - ptlUpdtRef.x;
aptlUpdt[1].y += ptlDevice.y - ptlUpdtRef.y;
WinMapWindowPoints( hwndClient, HWND_DESKTOP, aptlUpdt, 3);
ROUND_DOWN_MOD( aptlUpdt[0].x, lByteAlignX); /* round down */
ROUND_DOWN_MOD( aptlUpdt[0].y, lByteAlignY); /* round down */
ROUND_UP_MOD( aptlUpdt[1].x, lByteAlignX); /* round up */
ROUND_UP_MOD( aptlUpdt[1].y, lByteAlignY); /* round up */
WinMapWindowPoints( HWND_DESKTOP, hwndClient, aptlUpdt, 3);
aptlUpdt[2] = aptlUpdt[0];
ptlUpdtRef = ptlDevice;
if (GpiBitBlt( hpsBitmapSave
, hpsBitmapBuff
, 3L
, aptlUpdt
, ROP_SRCCOPY
, BBO_IGNORE ) == GPI_ERROR)
DispError(habMain,hwndClient);
pslPicked->ptlModelXlate.x = ptlOffStart.x + ptlModel.x - ptlMoveStart.x;
pslPicked->ptlModelXlate.y = ptlOffStart.y + ptlModel.y - ptlMoveStart.y;
for( psl = pslPicked, fFirst = TRUE
; (psl != pslPicked) || fFirst
; psl = psl->pslNextIsland, fFirst = FALSE )
{
psl->ptlModelXlate = pslPicked->ptlModelXlate;
DrawPiece( hpsBitmapBuff, psl, TRUE);
}
WinUnionRect( habMain
, (PRECTL)aptlUpdtNew
, (PRECTL)aptlUpdt
, (PRECTL)aptlUpdtRef);
WinMapWindowPoints( hwndClient, HWND_DESKTOP, aptlUpdtNew, 2);
ROUND_DOWN_MOD( aptlUpdtNew[0].x, lByteAlignX); /* round down */
ROUND_DOWN_MOD( aptlUpdtNew[0].y, lByteAlignY); /* round down */
ROUND_UP_MOD( aptlUpdtNew[1].x, lByteAlignX); /* round up */
ROUND_UP_MOD( aptlUpdtNew[1].y, lByteAlignY); /* round up */
WinMapWindowPoints( HWND_DESKTOP, hwndClient, aptlUpdtNew, 2);
aptlUpdtNew[2] = aptlUpdtNew[0];
if (GpiBitBlt( hpsClient
, hpsBitmapBuff
, 3L
, aptlUpdtNew
, ROP_SRCCOPY
, BBO_IGNORE ) == GPI_ERROR)
DispError(habMain,hwndClient);
}
/******************************************************************************/
/* */
/* The dragged segment is being unselected. Return it to its normal state. */
/* */
/******************************************************************************/
VOID LeftUp(VOID)
{
PSEGLIST psl, pslTemp;
POINTL ptlShift;
BOOL fFirst;
LONG l;
if (!BmpLoaded)
{
MessageBox(hwndFrame, IDS_LOADBITMAP, MB_OK | MB_INFORMATION, TRUE);
return;
}
else if(fPictureAssembled)
{
MessageBox(hwndFrame, IDS_OPTIONJUMBLE, MB_OK | MB_INFORMATION, TRUE);
return;
}
if( !lPickedSeg || !pslPicked)
return;
for( psl = pslPicked, fFirst = TRUE
; (psl != pslPicked) || fFirst
; psl = psl->pslNextIsland, fFirst = FALSE )
{
SetRect( psl);
SegListUpdate( MAKE_TAIL_SEG, psl); /* at tail => highest priority */
psl->fIslandMark = TRUE; /* mark as island member */
}
ptlShift = pslPicked->ptlModelXlate;
for( psl = pslHead; psl != NULL; psl = psl->pslNext)
if( !psl->fIslandMark)
for( l = 0; l < 8; l++)
if( pslPicked->lAdjacent[l] == psl->lSegId)
if( (ptlShift.x == psl->ptlModelXlate.x)
&& (ptlShift.y == psl->ptlModelXlate.y))
{
DosBeep( 600, 100);
DosBeep( 1200, 50);
MarkIsland( psl, TRUE); /* mark the whole new island */
pslTemp = psl->pslNextIsland; /* swap island ptrs */
psl->pslNextIsland = pslPicked->pslNextIsland;
pslPicked->pslNextIsland = pslTemp;
}
MarkIsland( pslPicked, FALSE); /* unmark the island */
pslPicked = NULL;
lPickedSeg = 0;
WinSetCapture( HWND_DESKTOP, (HWND)NULL);
}
/******************************************************************************/
/* */
/* DoHorzScroll will horizontally scroll the current contents of */
/* the client area and redraw the invalidated area */
/* */
/******************************************************************************/
VOID DoHorzScroll(VOID)
{
POINTL aptlClient[3];
HRGN hrgn;
MATRIXLF matlf;
if( ptsScrollPos.x > ptsScrollMax.x) /* clip to range of scroll param */
ptsScrollPos.x = ptsScrollMax.x;
if( ptsScrollPos.x < 0)
ptsScrollPos.x = 0;
if( ptsOldScrollPos.x != ptsScrollPos.x) /* only process change in position */
WinSendMsg( hwndHorzScroll
, SBM_SETPOS
, MPFROM2SHORT( ptsScrollPos.x, 0)
, MPFROMLONG( NULL));
/****************************************************************************/
/* Scroll the window the reqd amount, using bitblt'ing (ScrollWindow) */
/* if any of the screen still in view, and paint into uncovered region; */
/* else repaint the whole client area. */
/****************************************************************************/
hrgn = GpiCreateRegion( hpsClient, 0L, NULL);
WinQueryWindowRect( hwndClient, (PRECTL)aptlClient);
if( abs( ptsScrollPos.x - ptsOldScrollPos.x) <= ptsScrollMax.x)
{
WinScrollWindow( hwndClient
, (SHORT) (ptsOldScrollPos.x - ptsScrollPos.x)
, (SHORT) 0
, (PRECTL) NULL
, (PRECTL) NULL
, (HRGN) hrgn
, (PRECTL) NULL
, 0);
} else
{
if (GpiSetRegion( hpsClient, hrgn, 1L, (PRECTL)aptlClient) == GPI_ERROR)
DispError(habMain,hwndClient);
}
/****************************************************************************/
/* adjust the default view matrix */
/****************************************************************************/
if (GpiQueryDefaultViewMatrix( hpsClient, 9L, &matlf ) == GPI_ERROR)
DispError(habMain,hwndClient);
matlf.lM31 -= ptsScrollPos.x - ptsOldScrollPos.x;
if (GpiSetDefaultViewMatrix( hpsClient, 9L, &matlf, TRANSFORM_REPLACE) == GPI_ERROR)
DispError(habMain,hwndClient);
DoDraw( hpsClient, hrgn, TRUE); /* paint into the client area */
ptsOldScrollPos.x = ptsScrollPos.x;
if (GpiDestroyRegion( hpsClient, hrgn) == GPI_ERROR)
DispError(habMain,hwndClient);
aptlClient[2] = aptlClient[0];
if (!fFirstLoad) /* don't bother if no bitmap was read in */
{
if (GpiBitBlt( hpsBitmapBuff /* update the off-screen client image */
, hpsClient
, 3L
, aptlClient
, ROP_SRCCOPY
, BBO_IGNORE ) == GPI_ERROR)
DispError(habMain,hwndClient);
} /* end if () */
}
/******************************************************************************/
/* */
/* DoVertScroll will vertically scroll the current contents of */
/* the client area and redraw the invalidated area */
/* */
/******************************************************************************/
VOID DoVertScroll(VOID)
{
POINTL aptlClient[3];
HRGN hrgn;
MATRIXLF matlf;
if( ptsScrollPos.y > ptsScrollMax.y)
ptsScrollPos.y = ptsScrollMax.y;
if( ptsScrollPos.y < 0)
ptsScrollPos.y = 0;
if( ptsOldScrollPos.y != ptsScrollPos.y)
WinSendMsg( hwndVertScroll
, SBM_SETPOS
, MPFROM2SHORT( ptsScrollPos.y, 0)
, MPFROMLONG( NULL));
/****************************************************************************/
/* Scroll the window the reqd amount, using bitblt'ing (ScrollWindow) */
/* if any of the screen still in view, and paint into uncovered region; */
/* else repaint the whole client area. */
/****************************************************************************/
hrgn = GpiCreateRegion( hpsClient, 0L, NULL);
WinQueryWindowRect( hwndClient, (PRECTL)aptlClient);
if( abs( ptsScrollPos.y - ptsOldScrollPos.y) <= ptsScrollMax.y)
{
WinScrollWindow( hwndClient
, 0
, (SHORT) (ptsScrollPos.y - ptsOldScrollPos.y)
, (PRECTL) NULL
, (PRECTL) NULL
, (HRGN) hrgn
, (PRECTL) NULL
, 0);
} else
{
if (GpiSetRegion( hpsClient, hrgn, 1L, (PRECTL)aptlClient) == GPI_ERROR)
DispError(habMain,hwndClient);
}
if (GpiQueryDefaultViewMatrix( hpsClient, 9L, &matlf ) == GPI_ERROR)
DispError(habMain,hwndClient);
matlf.lM32 += ptsScrollPos.y - ptsOldScrollPos.y;
if (GpiSetDefaultViewMatrix( hpsClient, 9L, &matlf, TRANSFORM_REPLACE) == GPI_ERROR)
DispError(habMain,hwndClient);
DoDraw( hpsClient, hrgn, TRUE);
ptsOldScrollPos.y = ptsScrollPos.y;
if (GpiDestroyRegion( hpsClient, hrgn) == GPI_ERROR)
DispError(habMain,hwndClient);
aptlClient[2] = aptlClient[0];
if (!fFirstLoad) /* don't bother if no bitmap was read in */
{
if (GpiBitBlt( hpsBitmapBuff
, hpsClient
, 3L
, aptlClient
, ROP_SRCCOPY
, BBO_IGNORE ) == GPI_ERROR)
DispError(habMain,hwndClient);
}
}
/******************************************************************************
*
* Name : EnableMenu
*
* Description : Enable/Disable bitmap size submenus
*
* Parameters : ULONG id - menu id (ASSUME: id = submenu of FID_MAIN
* BOOL fEnable - enable/disable?
*
* Return : VOID
*
******************************************************************************/
VOID EnableMenu(ULONG id, BOOL fEnable)
{
WinSendMsg(hwndMenu, /* global main menu handle */
MM_SETITEMATTR, /* set menu attribute */
MPFROM2SHORT(id, TRUE), /* menu id */
MPFROM2SHORT(MIA_DISABLED, /* mask = disable bit */
fEnable ? ~MIA_DISABLED : MIA_DISABLED)); /* turn off/on */
} /* end EnableMenu() */
/******************************************************************************
*
* Name : CheckMenu
*
* Description : Check/Uncheck bitmap size submenus
*
* Parameters : ULONG id - menu id (ASSUME: id = submenu of FID_MAIN
* BOOL fCheck - check/unckeck?
*
* Return : VOID
*
******************************************************************************/
VOID CheckMenu(ULONG id, BOOL fCheck)
{
WinSendMsg(hwndMenu, /* global main menu handle */
MM_SETITEMATTR, /* set menu attribute */
MPFROM2SHORT(id, TRUE), /* menu id */
MPFROM2SHORT(MIA_CHECKED, /* mask = check bit */
fCheck ? MIA_CHECKED : ~MIA_CHECKED)); /* turn on/off */
} /* end CheckMenu() */
/******************************************************************************/
/* */
/* adjust zoom factor and recalc the picture transform, then do a redraw of */
/* whole screen */
/* */
/******************************************************************************/
VOID Zoom( VOID )
{
ULONG ulPostKillDraw, ulPostCt;
DosQueryEventSem(hevKillDraw, &ulPostKillDraw);
CalcBounds();
DosQueryEventSem(hevKillDraw, &ulPostCt);
if (ulPostKillDraw != ulPostCt)
{
DosResetEventSem(hevKillDraw, &ulPostCt);
return;
}
CalcTransform( hwndClient);
DosQueryEventSem(hevKillDraw, &ulPostCt);
if (ulPostKillDraw != ulPostCt)
{
DosResetEventSem(hevKillDraw, &ulPostCt);
return;
}
Redraw();
}
/******************************************************************************/
/* */
/* Check the segment list for obvious errors. */
/* */
/******************************************************************************/
BOOL SegListCheck(INT iLoc)
{
PSEGLIST psl;
CHAR szMsg[50];
szMsg[0] = '\0';
for( psl = pslHead; psl != NULL; psl = psl->pslNext)
if( (psl->lSegId < 1) || (psl->lSegId > lLastSegId) )
{
#if defined(DEBUG)
sprintf( szMsg, "Bad head segment list, location %d", iLoc);
WinMessageBox(HWND_DESKTOP, hwndFrame, szMsg, szErrorTitle, 0,
MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
#endif
return( FALSE);
}
for( psl = pslTail; psl != NULL; psl = psl->pslPrev)
if( (psl->lSegId < 1) || (psl->lSegId > lLastSegId) )
{
#if defined(DEBUG)
sprintf( szMsg, "Bad head segment list, location %d", iLoc);
WinMessageBox(HWND_DESKTOP, hwndFrame, szMsg, szErrorTitle, 0,
MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
#endif
return( FALSE);
}
return( TRUE);
}
/******************************************************************************/
/* */
/* DumpPicture will free the list and segment store for the picture */
/* */
/******************************************************************************/
BOOL DumpPicture(VOID)
{
while( pslHead != NULL )
{
if (GpiSetBitmap( pslHead->hpsFill, NULLHANDLE) == (HBITMAP)BMB_ERROR)
DispError(habMain,hwndClient);
if (GpiDeleteBitmap( pslHead->hbmFill) == GPI_ERROR)
DispError(habMain,hwndClient);
if (GpiDestroyPS( pslHead->hpsFill) == GPI_ERROR)
DispError(habMain,hwndClient);
DevCloseDC( pslHead->hdcFill);
if (GpiSetBitmap( pslHead->hpsHole, NULLHANDLE) == (HBITMAP)BMB_ERROR)
DispError(habMain,hwndClient);
if (GpiDeleteBitmap( pslHead->hbmHole) == GPI_ERROR)
DispError(habMain,hwndClient);
if (GpiDestroyPS( pslHead->hpsHole) == GPI_ERROR)
DispError(habMain,hwndClient);
DevCloseDC( pslHead->hdcHole);
SegListUpdate( DEL_SEG, pslHead);
}
if( hbmBitmapSize)
{
if (GpiSetBitmap( hpsBitmapSize, NULLHANDLE) == (HBITMAP)BMB_ERROR)
DispError(habMain,hwndClient);
if (GpiDeleteBitmap( hbmBitmapSize) == GPI_ERROR)
DispError(habMain,hwndClient);
}
if( hbmBitmapBuff)
{
if (GpiSetBitmap( hpsBitmapBuff, NULLHANDLE) == (HBITMAP)BMB_ERROR)
DispError(habMain,hwndClient);
if (GpiDeleteBitmap( hbmBitmapBuff) == GPI_ERROR)
DispError(habMain,hwndClient);
}
if( hbmBitmapSave)
{
if (GpiSetBitmap( hpsBitmapSave, NULLHANDLE) == (HBITMAP)BMB_ERROR)
DispError(habMain,hwndClient);
if (GpiDeleteBitmap( hbmBitmapSave) == GPI_ERROR)
DispError(habMain,hwndClient);
}
return( TRUE);
}
/******************************************************************************/
/* */
/* Draw the picture into segment store. */
/* */
/******************************************************************************/
BOOL CreatePicture(SHORT sUpdate)
{
POINTL ptl, aptlSides[12], aptlControl[12];
SEGLIST sl;
PSEGLIST psl;
LONG l, lMinor, lNeighbor, alFuzz[36][4];
SIZEL sizl;
BITMAPINFOHEADER2 bmp2;
PBITMAPINFOHEADER2 pbmp2 = &bmp2;
DATETIME date;
ULONG ulPostCt;
/****************************************************************************/
/* compute some fuzz for the control points */
/****************************************************************************/
DosGetDateTime( &date);
srand( (USHORT)date.hundredths);
for( l = 0; l < 36; l++)
for( lMinor = 0; lMinor < 4; lMinor++)
alFuzz[l][lMinor] = 50 * (rand() % 10);
/****************************************************************************/
/* reset the default viewing transform to identity */
/****************************************************************************/
SetDVTransform( (FIXED)UNITY
, (FIXED)0
, (FIXED)0
, (FIXED)UNITY
, 0L
, 0L
, TRANSFORM_REPLACE);
/****************************************************************************/
/* draw the pieces */
/****************************************************************************/
lLastSegId = 0;
for( ptl.x = ptlBotLeft.x; ptl.x < ptlTopRight.x; ptl.x += 500)
{
DosQueryEventSem( hevTerminate, &ulPostCt);
if( ulPostCt)
break;
for( ptl.y = ptlBotLeft.y; ptl.y < ptlTopRight.y; ptl.y += 500)
{
DosQueryEventSem( hevTerminate, &ulPostCt);
if( ulPostCt)
break;
lLastSegId++;
/************************************************************************/
/* compute the piece outline control points */
/************************************************************************/
aptlControl[0].x = 250L;
aptlControl[0].y = 500L;
aptlControl[1].x = 250;
aptlControl[1].y = -500L;
aptlControl[2].x = 500L;
aptlControl[2].y = 0L;
aptlControl[3].x = 0L;
aptlControl[3].y = 250L;
aptlControl[4].x = 1000L;
aptlControl[4].y = 250L;
aptlControl[5].x = 500L;
aptlControl[5].y = 500L;
aptlControl[6].x = 250L;
aptlControl[6].y = 0L;
aptlControl[7].x = 250L;
aptlControl[7].y = 1000L;
aptlControl[8].x = 0L;
aptlControl[8].y = 500L;
aptlControl[9].x = 500L;
aptlControl[9].y = 250L;
aptlControl[10].x = -500L;
aptlControl[10].y = 250L;
aptlControl[11].x = 0L;
aptlControl[11].y = 0L;
if( ptl.y == ptlBotLeft.y)
{
aptlControl[0].y = 0L;
aptlControl[1].y = 0L;
}
if( (ptl.x + 500) == ptlTopRight.x)
{
aptlControl[3].x = 500L;
aptlControl[4].x = 500L;
}
if( (ptl.y + 500) == ptlTopRight.y)
{
aptlControl[6].y = 500L;
aptlControl[7].y = 500L;
}
if( ptl.x == ptlBotLeft.x)
{
aptlControl[ 9].x = 0L;
aptlControl[10].x = 0L;
}
/************************************************************************/
/* compute the adjacent segments */
/************************************************************************/
sl.lAdjacent[0] = lLastSegId - 7;
sl.lAdjacent[1] = lLastSegId - 6;
sl.lAdjacent[2] = lLastSegId - 5;
sl.lAdjacent[3] = lLastSegId - 1;
sl.lAdjacent[4] = lLastSegId + 1;
sl.lAdjacent[5] = lLastSegId + 5;
sl.lAdjacent[6] = lLastSegId + 6;
sl.lAdjacent[7] = lLastSegId + 7;
if( ptl.x == ptlBotLeft.x)
{
sl.lAdjacent[0] = 0;
sl.lAdjacent[1] = 0;
sl.lAdjacent[2] = 0;
}
if( ptl.y == ptlBotLeft.y)
{
sl.lAdjacent[0] = 0;
sl.lAdjacent[3] = 0;
sl.lAdjacent[5] = 0;
}
if( (ptl.x + 500) == ptlTopRight.x)
{
sl.lAdjacent[5] = 0;
sl.lAdjacent[6] = 0;
sl.lAdjacent[7] = 0;
}
if( (ptl.y + 500) == ptlTopRight.y)
{
sl.lAdjacent[2] = 0;
sl.lAdjacent[4] = 0;
sl.lAdjacent[7] = 0;
}
/************************************************************************/
/* throw in some fuzz */
/************************************************************************/
if( sl.lAdjacent[3])
{
aptlControl[0].y -= alFuzz[lLastSegId - 1][0];
aptlControl[1].y += alFuzz[lLastSegId - 1][1];
}
if( sl.lAdjacent[1])
{
aptlControl[9].x -= alFuzz[lLastSegId - 1][2];
aptlControl[10].x += alFuzz[lLastSegId - 1][3];
}
if( lNeighbor = sl.lAdjacent[4])
{
aptlControl[7].y -= alFuzz[lNeighbor - 1][0];
aptlControl[6].y += alFuzz[lNeighbor - 1][1];
}
if( lNeighbor = sl.lAdjacent[6])
{
aptlControl[4].x -= alFuzz[lNeighbor - 1][2];
aptlControl[3].x += alFuzz[lNeighbor - 1][3];
}
/************************************************************************/
/* compute the piece control points in world coordinates */
/************************************************************************/
for( l=0; l<12; l++)
{
aptlSides[l].x = ptl.x + aptlControl[l].x;
aptlSides[l].y = ptl.y + aptlControl[l].y;
sl.aptlSides[l] = aptlSides[l];
}
/************************************************************************/
/* compute the dimensions of the matching rects for BitBlt */
/************************************************************************/
sl.rclBitBlt.xLeft = ptl.x - 250;
sl.rclBitBlt.yBottom = ptl.y - 250;
sl.rclBitBlt.xRight = ptl.x + 750;
sl.rclBitBlt.yTop = ptl.y + 750;
if( ptl.x == ptlBotLeft.x)
sl.rclBitBlt.xLeft += 250;
if( ptl.y == ptlBotLeft.y)
sl.rclBitBlt.yBottom += 250;
if( (ptl.x + 500) == ptlTopRight.x)
sl.rclBitBlt.xRight -= 250;
if( (ptl.y + 500) == ptlTopRight.y)
sl.rclBitBlt.yTop -= 250;
/************************************************************************/
/* store the piece location */
/************************************************************************/
sl.ptlLocation = ptl;
/************************************************************************/
/* create the masks */
/************************************************************************/
if( sUpdate == PICTURE_CREATE)
{
bmp2 = bmp2BitmapFile;
if (bmp2.cbFix == sizeof(BITMAPINFOHEADER))
{
sizl.cx = 2 + ((PBITMAPINFOHEADER)pbmp2BitmapFile)->cx
* (sl.rclBitBlt.xRight - sl.rclBitBlt.xLeft)
/ (ptlTopRight.x - ptlBotLeft.x);
sizl.cy = 2 + ((PBITMAPINFOHEADER)pbmp2BitmapFile)->cy
* (sl.rclBitBlt.yTop - sl.rclBitBlt.yBottom)
/ (ptlTopRight.y - ptlBotLeft.y);
((PBITMAPINFOHEADER)pbmp2)->cx = LOUSHORT( sizl.cx);
((PBITMAPINFOHEADER)pbmp2)->cy = LOUSHORT( sizl.cy);
}
else
{
sizl.cx = 2 + ((pbmp2BitmapFile->cx
* (sl.rclBitBlt.xRight - sl.rclBitBlt.xLeft))
/ (ptlTopRight.x - ptlBotLeft.x));
sizl.cy = 2 + ((pbmp2BitmapFile->cy
* (sl.rclBitBlt.yTop - sl.rclBitBlt.yBottom))
/ (ptlTopRight.y - ptlBotLeft.y));
(pbmp2)->cx = LOUSHORT( sizl.cx);
(pbmp2)->cy = LOUSHORT( sizl.cy);
}
if ((sl.hdcHole = DevOpenDC( habMain
, OD_MEMORY
, "*"
, 3L
, (PDEVOPENDATA)&dop
, NULLHANDLE)) == DEV_ERROR)
DispError(habMain,hwndClient);
if ((sl.hpsHole = GpiCreatePS( habMain
, sl.hdcHole
, &sizl
, PU_PELS | GPIA_ASSOC | GPIT_MICRO )) == GPI_ERROR)
DispError(habMain,hwndClient);
if ((sl.hbmHole = GpiCreateBitmap( sl.hpsHole
, pbmp2
, 0L
, NULL
, NULL)) == (HBITMAP)GPI_ERROR)
DispError(habMain,hwndClient);
if ((GpiSetBitmap( sl.hpsHole, sl.hbmHole)) == (HBITMAP)BMB_ERROR)
DispError(habMain,hwndClient);
if ((sl.hdcFill = DevOpenDC( habMain
, OD_MEMORY
, "*"
, 3L
, (PDEVOPENDATA)&dop
, NULLHANDLE)) == DEV_ERROR)
DispError(habMain,hwndClient);
if ((sl.hpsFill = GpiCreatePS( habMain
, sl.hdcFill
, &sizl
, PU_PELS | GPIA_ASSOC | GPIT_MICRO )) == GPI_ERROR)
DispError(habMain,hwndClient);
if ((sl.hbmFill = GpiCreateBitmap( sl.hpsFill
, pbmp2
, 0L
, NULL
, NULL)) == (HBITMAP)GPI_ERROR)
DispError(habMain,hwndClient);
if ((GpiSetBitmap( sl.hpsFill, sl.hbmFill)) == (HBITMAP)BMB_ERROR)
DispError(habMain,hwndClient);
}
sl.fVisible = TRUE;
sl.lSegId = lLastSegId;
sl.fIslandMark = FALSE;
sl.ptlModelXlate.x = sl.ptlModelXlate.y = 0L;
if( sUpdate == PICTURE_CREATE)
{
sl.pslNext = NULL;
sl.pslPrev = NULL;
SetRect( &sl);
psl = SegListUpdate( ADD_TAIL_SEG, &sl);
} else
{
psl = SegListGet( lLastSegId);
psl->fIslandMark = FALSE;
for( l=0; l<12; l++)
psl->aptlSides[l] = aptlSides[l];
psl->ptlModelXlate = sl.ptlModelXlate;
SetRect( psl);
}
psl->pslNextIsland = psl; /* point to self ==> island of one */
}
}
if( ulPostCt)
SendCommand( UM_DIE, (MPARAM)NULL, (MPARAM)NULL);
return( TRUE);
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
VOID CheckPsl( psl)
PSEGLIST psl;
{
SHORT s;
for( s=2; s<12; s+=3)
if( !WinPtInRect( habAsync, &psl->rclBitBlt, &psl->aptlSides[s]))
break;
}
/******************************************************************************/
/* */
/* Create the Size, Save and Buff bitmaps. */
/* */
/******************************************************************************/
BOOL PrepareBitmap(VOID)
{
hbmBitmapSize = GpiCreateBitmap( hpsBitmapSize
, pbmp2BitmapFile
, 0L
, NULL
, NULL);
if( !hbmBitmapSize)
{
DispError(habMain,hwndClient);
return( FALSE);
}
if (GpiSetBitmap( hpsBitmapSize, hbmBitmapSize) == (HBITMAP)BMB_ERROR)
DispError(habMain,hwndClient);
bmp2BitmapSave = bmp2BitmapFile;
if (pbmp2BitmapSave->cbFix == sizeof(BITMAPINFOHEADER))
{
((PBITMAPINFOHEADER)pbmp2BitmapSave)->cx = LOUSHORT( sizlMaxClient.cx);
((PBITMAPINFOHEADER)pbmp2BitmapSave)->cy = LOUSHORT( sizlMaxClient.cy);
}
else
{
(pbmp2BitmapSave)->cx = LOUSHORT(sizlMaxClient.cx);
(pbmp2BitmapSave)->cy = LOUSHORT(sizlMaxClient.cy);
}
hbmBitmapSave = GpiCreateBitmap( hpsBitmapSave
, pbmp2BitmapSave
, 0L
, NULL
, NULL);
if( !hbmBitmapSave)
{
DispError(habMain,hwndClient);
return( FALSE);
}
if (GpiSetBitmap( hpsBitmapSave, hbmBitmapSave) == (HBITMAP)BMB_ERROR)
DispError(habMain,hwndClient);
hbmBitmapBuff = GpiCreateBitmap( hpsBitmapBuff
, pbmp2BitmapSave
, 0L
, NULL
, NULL);
if( !hbmBitmapBuff)
{
DispError(habMain,hwndClient);
return( FALSE);
}
if (GpiSetBitmap( hpsBitmapBuff, hbmBitmapBuff) == (HBITMAP)BMB_ERROR)
DispError(habMain,hwndClient);
return( TRUE);
}
/******************************************************************************
*
* Name : ReadBitmap
*
* Description :
*
* Get the bitmap from disk.
* Note that there are 2 formats for bitmap files, one of which is archaic.
* Both formats are supported here. All new bitmaps should follow the format
* in BITMAPFILEHEADER.
*
* Concepts :
*
* API's :
*
* Parameters : HFILE hfile
*
* Return : BOOL
*
* Notes:
*
* File Layout - size and layout of following map are dependent on the
* type of bitmap. The cbFix field of the structures is used to determine
* the size of the structures which in turn identifies them.
*
*
* SINGLE BITMAP FILE FORMAT
*
* ┌─────────────────────────────────────────┐ offset 0
* │ Bitmap File Header (bfh2) │ pbfh2->offBits contains data ─┐
* │ │ offset (from begin of file) │
* ├─────────────────────────────────────────┤ │
* │ Bitmap Information Header (bmp2) │ │
* ├─────────────────────────────────────────┤ │
* │ Color Table of RGB Structures (argb2) │ │
* ├─────────────────────────────────────────┤ <─────────────────────────────┘
* │ Bitmap Data (scan lines) │
* │ . │
* │ . │
* │ . │
* └─────────────────────────────────────────┘
*
*
* BITMAP-ARRAY FILE FORMAT
*
* ┌─────────────────────────────────────────┐ offset 0
* │ Bitmap Array File Header (baf2) │
* │ (only for bitmap arrays) │
* ├─────────────────────────────────────────┤
* │ Bitmap File Header (bfh2) │ pbfh2->offBits contains data ─┐
* │ │ offset (from begin of file) │
* ├─────────────────────────────────────────┤ │
* │ Bitmap Information Header (bmp2) │ │
* ├─────────────────────────────────────────┤ │
* │ Color Table of RGB Structures (argb2) │ │
* ├─────────────────────────────────────────┤ │
* │ next Bitmap Array File Header │ │
* │ . │ │
* │ . │ │
* │ . │ │
* ├─────────────────────────────────────────┤ <─────────────────────────────┘
* │ 1st Bitmap Data (scan lines) │
* │ │
* │ │
* ├─────────────────────────────────────────┤
* │ next Bitmap Data (scan lines) │
* │ . │
* │ . │
* │ . │
* └─────────────────────────────────────────┘
*
******************************************************************************/
BOOL ReadBitmap(HFILE hfile)
{
APIRET rc; /* API return code */
BOOL fRet = FALSE; /* Function return code. */
FILESTATUS fsts;
PBITMAPFILEHEADER2 pbfh2; /* can address any file types */
PBITMAPINFOHEADER2 pbmp2; /* address any info headers */
PBYTE pFileBegin = NULL; /* beginning of bitmap file data */
ULONG cbRead; /* Number of bytes read by DosRead. */
ULONG cScans, cScansRet; /* number of scan lines in bitmap (cy) */
/*
* Use Loop to avoid duplicate cleanup code. If any errors, a break
* statement will jump directly to error cleanup code.
*/
do
{
/*
* Find out how big the file is, allocate that much memory, and read
* in the entire bitmap.
*/
rc =
DosQueryFileInfo(hfile, 1, &fsts, sizeof(fsts));
if (rc)
break; /* jump to error code outside of loop */
rc =
DosAllocMem(
(PPVOID) &pFileBegin,
(ULONG) fsts.cbFile,
(ULONG) PAG_READ | PAG_WRITE | PAG_COMMIT);
if (rc)
break; /* jump to error code outside of loop */
if (DosRead( hfile, (PVOID)pFileBegin, fsts.cbFile, &cbRead))
break; /* jump to error code outside of loop */
/*
* If it's a bitmap-array, point to common file header. Otherwise,
* point to beginning of file.
*/
pbfh2 = (PBITMAPFILEHEADER2) pFileBegin;
pbmp2 = NULL; /* only set this when we validate type */
switch (pbfh2->usType)
{
case BFT_BITMAPARRAY:
/*
* If this is a Bitmap-Array, adjust pointer to the normal
* file header. We'll just use the first bitmap in the
* array and ignore other device forms.
*/
pbfh2 = &(((PBITMAPARRAYFILEHEADER2) pFileBegin)->bfh2);
pbmp2 = &pbfh2->bmp2; /* pointer to info header (readability) */
break;
case BFT_BMAP:
pbmp2 = &pbfh2->bmp2; /* pointer to info header (readability) */
break;
default: /* these formats aren't supported; don't set any ptrs */
case BFT_ICON:
case BFT_POINTER:
case BFT_COLORICON:
case BFT_COLORPOINTER:
break;
} /* end switch (pbfh2->usType) */
if (pbmp2 == NULL)
break; /* File format NOT SUPPORTED: break out to error code */
/*
* Check to see if BMP file has an old structure, a new structure, or
* Windows structure. Capture the common data and treat all bitmaps
* generically with pointer to new format. API's will determine format
* using cbFixed field.
*
* Windows bitmaps have the new format, but with less data fields
* than PM. The old strucuture has some different size fields,
* though the field names are the same.
*
*
* NOTE: bitmap data is located by offsetting the beginning of the file
* by the offset contained in pbfh2->offBits. This value is in
* the same relatie location for different format bitmap files.
*/
if (pbmp2->cbFix == sizeof(BITMAPINFOHEADER)) /* old format? */
{
cScans = (ULONG) ((PBITMAPINFOHEADER)pbmp2)->cy;
}
else /* new PM format, Windows, or other */
{
cScans = pbmp2->cy;
}
memcpy( /* copy bitmap info into global structure */
(PVOID) pbmp2BitmapFile,
(PVOID) pbmp2,
pbmp2->cbFix); /* only copy specified size (varies per format) */
hbmBitmapFile =
GpiCreateBitmap(
hpsBitmapFile, /* presentation-space handle */
pbmp2BitmapFile, /* address of structure for format data */
0L, /* options */
NULL, /* address of buffer of image data */
NULL); /* address of structure for color and format */
if (!hbmBitmapFile)
{
DispError(habMain,hwndClient);
break; /* jump to error code outside of loop */
}
if (GpiSetBitmap( hpsBitmapFile, hbmBitmapFile) == (HBITMAP)BMB_ERROR)
{
DispError(habMain,hwndClient);
break; /* jump to error code outside of loop */
}
/*
* Tell GPI to put the bits into the thread's PS. The function returns
* the number of scan lines of the bitmap that were copied. We want
* all of them at once.
*/
cScansRet =
GpiSetBitmapBits(
hpsBitmapFile, /* presentation-space handle */
0L, /* index of first scan line */
cScans, /* number of scan lines */
pFileBegin + pbfh2->offBits, /* address of bitmap data */
(PBITMAPINFO2) pbmp2); /* address of bitmap header table */
if (cScansRet != cScans) /* original # of scans? */
{
DispError(habMain,hwndClient);
break; /* jump to error code outside of loop */
}
DosFreeMem( pFileBegin);
DosClose( hfile);
return TRUE; /* function successful */
} while (FALSE); /* fall through loop first time */
/*
* Close the file, free the buffer space and leave. This is an error exit
* point from the function. Cleanup code is here to avoid duplicate code
* after each operation.
*/
if (pFileBegin != NULL)
DosFreeMem( pFileBegin);
DosClose( hfile);
return FALSE; /* function failed */
} /* end ReadBitmap() */
/**************************************************************************/
/* DispError -- report an error returned from an API service. */
/* */
/* The error message is displayed using a message box */
/* */
/**************************************************************************/
VOID DispErrorMsg(HAB hab, HWND hwndFrame, PCH FileName, LONG LineNum)
{
PERRINFO pErrInfoBlk;
PSZ pszOffSet, pszErrMsg;
ERRORID ErrorId;
PCH ErrorStr;
CHAR szbuff[125];
DosBeep(800,10);
#if defined(DEBUG)
DosBeep(800,10);
DosBeep(800,10);
DosBeep(800,10);
DosBeep(800,10);
DosBeep(800,10);
#endif /* defined(DEBUG) */
if (!hab)
{ /* Non-PM Error */
WinLoadString( habMain,0, IDS_UNKNOWNMSG, sizeof(szbuff), (PSZ)szbuff);
ErrorStr = malloc(strlen(szbuff)+strlen(FileName)+10);
sprintf(ErrorStr, szbuff, FileName, LineNum);
WinMessageBox(HWND_DESKTOP, /* Parent window is desk top */
hwndFrame, /* Owner window is our frame */
(PSZ)ErrorStr, /* PMWIN Error message */
szErrorTitle, /* Title bar message */
MSGBOXID, /* Message identifier */
MB_MOVEABLE | MB_CUACRITICAL | MB_CANCEL ); /* Flags */
free(ErrorStr);
return;
}
ErrorId = WinGetLastError(hab);
if ((pErrInfoBlk = WinGetErrorInfo(hab)) != (PERRINFO)NULL)
{
pszOffSet = ((PSZ)pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
pszErrMsg = ((PSZ)pErrInfoBlk) + *((PULONG)pszOffSet);
WinLoadString( habMain,0, IDS_ERRORMSG, sizeof(szbuff), (PSZ)szbuff);
ErrorStr = malloc(strlen(szbuff)+strlen(pszErrMsg)+strlen(FileName)+10);
sprintf(ErrorStr, szbuff, pszErrMsg, FileName, LineNum);
WinMessageBox(HWND_DESKTOP, /* Parent window is desk top */
hwndFrame, /* Owner window is our frame */
(PSZ)ErrorStr, /* PMWIN Error message */
szErrorTitle, /* Title bar message */
MSGBOXID, /* Message identifier */
MB_MOVEABLE | MB_CUACRITICAL | MB_CANCEL ); /* Flags */
free(ErrorStr);
WinFreeErrorInfo(pErrInfoBlk);
}
}
/********************************************************************/
/* DosGetThreadInfo Call Only Temp Call for the LX Toronto Compiler */
/********************************************************************/
APIRET DosGetThreadInfo(PTIB *pptib,PPIB *pppib)
{
return( DosGetInfoBlocks(pptib,pppib) );
}
/******************************* END JIGSAW.C ******************************/