File:  [OS/2 SDKs] / pmsdk / samples / linefrac / lfmsg.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 12:28:13 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: pmsdk-1988, HEAD
Microsoft OS/2 SDK PM 08-08-1988

/************************************************************************
*
*   lfmsg.c
*
*   Message handling subroutines for the LineFractal window class.
*
*   Created by Microsoft Corp., 1988
************************************************************************/

#define INCL_WIN
#define INCL_GPI
#define INCL_DOSPROCESS
#define INCL_DOSSEMAPHORES
#include <os2.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "linefrac.h"




/************************************************************************
*
*   Function prototypes.
*
*   These add some error checking to function calls, and prevent
*   forward references to functions of undefined return type.
*
************************************************************************/

VOID   MySetWindowUShort(HWND, USHORT, USHORT);
VOID   MySetWindowLong(HWND, USHORT, LONG);
USHORT MyGetWindowUShort(HWND, USHORT);
LONG   MyGetWindowLong(HWND, USHORT);




/************************************************************************
*
*   Global Variables
*
*
*   hAB 	Anchor block handle.  Needed only for some obscure mainframe
*		  compatability issue.
*   hwndLineFrac
*		Our main window handle.
*   hwndLineFracFrame
*		The handle to our window frame (to get at menus, etc.).
*
*   LineFracPS	Presentation Space for the background accumulation thread.
*   LineFracRc	Holds the dimensions of the bitmap we draw into.
*   LineFracBM	Handle to our bitmap.  Needed only during creation and
*		  destruction.
*   LineFracDC	Handle to the DC we've selected our bitmap into.  Needed
*		  only during creation and destruction.
*   fHaveBitmap TRUE ==> a bitmap was successfully created for the second
*		  thread to draw into.
*   fHaveAccumThread
*		TRUE ==> the point accumulation thread was successfully
*		  created.
*
*   tidAccumFrac
*		Thread ID for the point accumulation thread.
*   abAccumStack
*		Stack for the ...
*
*   usCurrentXform
*		The menu command id of the currently selected transform.
*   LineFracXform
*		The current similarity transform used when drawing.
*   usRecursion	The currently selected depth of recursion.
*   usPolygonSides
*		Number of sides to the polygonal frame of "unit
*		  intervals".  The fractal transformation is
*		  applied to each line segment of the frame.
*
*   lSemAccumulateFractal
*		Semaphore controlling the point accumulation thread.
*		Clear it to start another fractal.
*   fInterrupted
*		TRUE ==> abort current fractal.
*   fClearBetween
*		TRUE ==> clear drawing surface (bitmap) between fractals.
*   fAutoScale	TRUE ==> resize our bitmap to match the client rectangle.
*
*   xscale	These transform each point accumulated, so
*   yscale	that the drawing fits into the window,
*   xoff	with the original unit interval at the center.
*   yoff
*
*   lColorBack	Background color for fractal.
*   lColor	Line foreground color.
*   usStyle	Line style.
*   usMixMode	Line foreground mix mode.
*
*   XformFuncs	Array of built-in transform-defining functions.
*
************************************************************************/

#define CCHSTR	12		/* work buffer size for MyGetWindowLong, etc */

HAB	   hAB;
HWND	   hwndLineFrac;
HWND	   hwndLineFracFrame;

HPS	   LineFracPS = NULL;
RECTL	   LineFracRc = { 0L, 0L, 0L, 0L };
HBITMAP    LineFracBM = NULL;
HDC	   LineFracDC = NULL;
BOOL	   fHaveBitmap = FALSE;
BOOL	   fHaveAccumThread = FALSE;

#define SIZE_ACCUM_STACK	2048
TID	   tidAccumFrac;
CHAR	   abAccumStack[SIZE_ACCUM_STACK];

USHORT	   usCurrentXform = IDMSAWTOOTH;
PLINEFRAC  LineFracXform  = NULL;
USHORT	   usRecursion	  = 1;
USHORT	   usPolygonSides = 3;
USHORT	   cptMax = MAX_POINT_COUNT;

LONG	   lSemAccumulateFractal = NULL;
BOOL	   fInterrupted  = FALSE;
BOOL	   fClearBetween = TRUE;
BOOL	   fAutoScale	 = TRUE;

double	   xscale = 250.0;
double	   yscale = 220.0;
double	   xoff   = 30.0;
double	   yoff   = 30.0;

LONG	   lColorBack = CLR_BLACK;
LONG	   lColor = CLR_BLUE;
USHORT	   usStyle = LINETYPE_SOLID;
USHORT	   usMixMode = FM_OVERPAINT;

typedef PLINEFRAC (* PFPLF)();	/* "ptr to func returning ptr to LINEFRAC" */
PFPLF XformFuncs[] =
{
    DefineSharkTooth,
    DefineSawTooth,
    DefineKochIsland,
    DefineStovePipe,
    DefineEsses
};




/************************************************************************
*
*   LineFracInit
*
*   Set up a bitmap for the second thread to draw into.  Then set
*   up the second thread itself.  Set the flag so we don't do this
*   twice. Lower the priority of the background thread to IDLETIME,
*   so that it won't slow down user-interface response.
*
*   Initialize the current transform.  Post a message to cause the
*   transform to actually be defined.
*
************************************************************************/

VOID
LineFracInit(hWnd)
HWND hWnd;
{
    if (fHaveBitmap = ResizeBitmap(hWnd))
    {
	DosSemSet( &lSemAccumulateFractal );
	if (fHaveAccumThread = !DosCreateThread( AccumulateLineFractal,
				   &tidAccumFrac,
				   abAccumStack + sizeof(abAccumStack)));
	    DosSetPrty(PRTYS_THREAD, PRTYC_IDLETIME, 0, tidAccumFrac);
	WinPostMsg(hWnd, WM_COMMAND, (MPARAM)usCurrentXform, (MPARAM)0L);
    }
}




/************************************************************************
*
*   LineFracExit
*
*   If we have a bitmap lying around, delete it.
*
************************************************************************/

VOID
LineFracExit()
{
    if (fHaveBitmap)
    {
	GpiSetBitmap(LineFracPS, NULL);
	GpiDeleteBitmap(LineFracBM);
	GpiDestroyPS(LineFracPS);
	DevCloseDC(LineFracDC);
    }
}




/************************************************************************
*
*   ResizeBitmap
*
*   Destroy the current bitmap and create a new one the size of the
*   current client rectangle.
*
************************************************************************/

BOOL
ResizeBitmap(hWnd)
HWND hWnd;
{
    SIZEL size;
    BITMAPINFOHEADER bminfo;


    if (fHaveBitmap)
    {
	GpiSetBitmap(LineFracPS, NULL);
	GpiDeleteBitmap(LineFracBM);
	GpiDestroyPS(LineFracPS);
	DevCloseDC(LineFracDC);
    }

    LineFracDC = DevOpenDC(hAB, OD_MEMORY, "*", 0L, NULL, NULL);
    if (!LineFracDC)
	return FALSE;

    size.cx = 0L;
    size.cy = 0L;
    LineFracPS = GpiCreatePS(hAB, LineFracDC, &size,
			     PU_PELS|GPIT_MICRO|GPIA_ASSOC);
    if (!LineFracPS)
    {
	DevCloseDC(LineFracDC);
	return FALSE;
    }


    bminfo.cbFix = sizeof(BITMAPINFOHEADER);
    WinQueryWindowRect(hWnd, &LineFracRc);
    bminfo.cx = (USHORT) (LineFracRc.xRight  - LineFracRc.xLeft);
    bminfo.cy = (USHORT) (LineFracRc.yTop - LineFracRc.yBottom);
    bminfo.cPlanes = 1;
    bminfo.cBitCount = 4;
    LineFracBM = GpiCreateBitmap(LineFracPS, &bminfo, 0L, 0L, 0L);
    if (!LineFracBM)
    {
	GpiDestroyPS(LineFracPS);
	DevCloseDC(LineFracDC);
	return FALSE;
    }

    GpiSetBitmap(LineFracPS, LineFracBM);
    WinFillRect(LineFracPS, &LineFracRc, lColorBack);


    /* Compute the scale and translation parameters from the
     * current client rectangle.
     */

    xoff   = (LineFracRc.xRight - LineFracRc.xLeft) * 0.125;
    yoff   = (LineFracRc.yTop - LineFracRc.yBottom) * 0.5;
    xscale = xoff * 6.0;
    yscale = (LineFracRc.yTop - LineFracRc.yBottom) * 0.75;

    return TRUE;
}




/************************************************************************
*
*   LineFracCommand
*
*   Process menu commands related to line fractals.
*
************************************************************************/

VOID
LineFracCommand(hWnd, id)
HWND hWnd;
USHORT id;
{
    switch (id)
    {
    case IDMABOUT:
	WinDlgBox( HWND_DESKTOP, hWnd, (PFNWP)AboutDlg, NULL,
		       IDD_ABOUT, NULL );
	break;

    case IDMFRACATTRS:
	WinDlgBox( HWND_DESKTOP, hWnd, (PFNWP)LineFracDlg, NULL,
		       IDD_LINEFRAC, NULL );
	break;

    case IDMCLEARBITMAP:
	if (fHaveBitmap)
	{
	    WinFillRect(LineFracPS, &LineFracRc, lColorBack);
	    WinInvalidateRect(hwndLineFrac, &LineFracRc, FALSE);
	}
	break;

    case IDMAUTOSCALE:
	fAutoScale = !fAutoScale;
	WinSendDlgItemMsg( hwndLineFracFrame, FID_MENU,
		MM_SETITEMATTR, MPFROM2SHORT(IDMAUTOSCALE, TRUE),
		MPFROM2SHORT(MIA_CHECKED, fAutoScale ? MIA_CHECKED : NULL));
	break;

    case IDMSHARKTOOTH:
    case IDMSAWTOOTH:
    case IDMKOCH:
    case IDMSTOVE:
    case IDMESSES:
	LineFracXform = (*(XformFuncs[id - IDMSHARKTOOTH]))();
	WinSendDlgItemMsg( hwndLineFracFrame, FID_MENU,
		MM_SETITEMATTR, MPFROM2SHORT(usCurrentXform, TRUE),
		MPFROM2SHORT(MIA_CHECKED, NULL));
	usCurrentXform = id;
	WinSendDlgItemMsg( hwndLineFracFrame, FID_MENU,
		MM_SETITEMATTR, MPFROM2SHORT(usCurrentXform, TRUE),
		MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED));

    case IDMREDRAW:
	DosSemClear(&lSemAccumulateFractal);

    case IDMABORT:
	fInterrupted = TRUE;		/* suicide flag for pt accumulation */
	break;
    }
}




/************************************************************************
*
*   LineFracPaint
*
*   If we have a bitmap, blit it to the screen, no matter what state
*   it's in.
*
************************************************************************/

VOID
LineFracPaint(hPS)
HPS  hPS;
{
    POINTL bbp[4];

    if (fHaveBitmap)
    {
	bbp[0].x = 0L; bbp[0].y = 0L;
	bbp[1].x = LineFracRc.xRight; bbp[1].y = LineFracRc.yTop;
	bbp[2].x = 0L; bbp[2].y = 0L;

	GpiBitBlt(hPS, LineFracPS, 3L, bbp, ROP_SRCCOPY, (LONG)NULL);
    }
}




/************************************************************************
*
*   DefineSharkTooth
*
*   Set up the similarity transform for the following linefractal,
*   which looks roughly like:
*
*
*				 *
*		     ===>      *   *
*			     *	     *
*   ***************	   *	       *
*
************************************************************************/

PLINEFRAC
DefineSharkTooth()
{
    double ang;
    double len;
    static LINEFRAC shark[3];

    ang = PI / 6.0;
    len = 1.0 / sqrt(3.0);


    shark[0].angle  = ang;
    shark[0].length = len;
    shark[0].flip   = FALSE;
    shark[0].next   = &(shark[1]);

    shark[1].angle  = -ang * 2.0;
    shark[1].length = len;
    shark[1].flip   = FALSE;
    shark[1].next   = EOLIST;

    return &(shark[0]);
}




/************************************************************************
*
*   DefineSawTooth
*
*   Set up the similarity transform for the following linefractal,
*   which looks roughly like:
*
*
*
*		     ===>      *
*			     *	 *
*   ***************	   *	   *	   *
*				     *	 *
*				       *
*
************************************************************************/

PLINEFRAC
DefineSawTooth()
{
    double ang;
    double len;
    static LINEFRAC saw[3];

    ang =  PI / 4.0;
    len = 1.0 / sqrt(2.0);


    saw[0].angle  = ang;
    saw[0].length = len / 2.0;
    saw[0].flip   = FALSE;
    saw[0].next   = &(saw[1]);

    saw[1].angle  = -ang * 2.0;
    saw[1].length = len;
    saw[1].flip   = FALSE;
    saw[1].next   = &(saw[2]);

    saw[2].angle  = ang * 2.0;
    saw[2].length = len / 2.0;
    saw[2].flip   = FALSE;
    saw[2].next   = EOLIST;

    return &(saw[0]);
}




/************************************************************************
*
*   DefineKochIsland
*
*   Set up the similarity transform for the following linefractal,
*   which looks roughly like:
*
*   This is known as the Koch, or snowflake, transform.
*
*
*			          *
*		     ===>        * *
*			        *   *
*   ***************	   *****     *****
*
************************************************************************/

PLINEFRAC
DefineKochIsland()
{
    double ang;
    double len;
    static LINEFRAC koch[4];

    ang =  PI / 3.0;
    len = 1.0 / 3.0;


    koch[0].angle  = 0.0;
    koch[0].length = len;
    koch[0].flip   = FALSE;
    koch[0].next   = &(koch[1]);

    koch[1].angle  = ang;
    koch[1].length = len;
    koch[1].flip   = FALSE;
    koch[1].next   = &(koch[2]);

    koch[2].angle  = -2.0 * ang;
    koch[2].length = len;
    koch[2].flip   = FALSE;
    koch[2].next   = &(koch[3]);

    koch[3].angle  = ang;
    koch[3].length = len;
    koch[3].flip   = FALSE;
    koch[3].next   = EOLIST;

    return &(koch[0]);
}




/************************************************************************
*
*   DefineStovePipe
*
*   Set up the similarity transform for the following linefractal,
*   which looks roughly like:
*
*   This is sometimes known as the stovepipe transform.
*
*
*			       ******
*			       *    *
*		     ===>      *    *
*			       *    *
*   **************	   *****    *****
*
************************************************************************/

PLINEFRAC
DefineStovePipe()
{
    double ang;
    double len;
    static LINEFRAC Stove[5];


    ang =  PI / 2.0;
    len = 1.0 / 3.0;


    Stove[0].angle  = 0.0;
    Stove[0].length = len;
    Stove[0].flip   = FALSE;
    Stove[0].next   = &(Stove[1]);

    Stove[1].angle  =  ang;
    Stove[1].length = len;
    Stove[1].flip   = FALSE;
    Stove[1].next   = &(Stove[2]);

    Stove[2].angle  = -ang;
    Stove[2].length = len;
    Stove[2].flip   = FALSE;
    Stove[2].next   = &(Stove[3]);

    Stove[3].angle  = -ang;
    Stove[3].length = len;
    Stove[3].flip   = FALSE;
    Stove[3].next   = &(Stove[4]);

    Stove[4].angle  =  ang;
    Stove[4].length = len;
    Stove[4].flip   = FALSE;
    Stove[4].next   = EOLIST;

    return &(Stove[0]);
}





/************************************************************************
*
*   DefineEsses
*
*   Set up the similarity transform for the following linefractal,
*   which looks roughly like:
*
*
*			   ******
*			   *	*
*   **************   ===>  *	*    *
*				*    *
*				******
*
************************************************************************/

PLINEFRAC
DefineEsses()
{
    double ang;
    static LINEFRAC Esses[5];


    ang =  PI / 2.0;


    Esses[0].angle  =  ang;
    Esses[0].length = 0.25;
    Esses[0].flip   = FALSE;
    Esses[0].next   = &(Esses[1]);

    Esses[1].angle  = -ang;
    Esses[1].length = 0.5;
    Esses[1].flip   = FALSE;
    Esses[1].next   = &(Esses[2]);

    Esses[2].angle  = -ang;
    Esses[2].length = 0.5;
    Esses[2].flip   = FALSE;
    Esses[2].next   = &(Esses[3]);

    Esses[3].angle  =  ang;
    Esses[3].length = 0.5;
    Esses[3].flip   = FALSE;
    Esses[3].next   = &(Esses[4]);

    Esses[4].angle  =  ang;
    Esses[4].length = 0.25;
    Esses[4].flip   = FALSE;
    Esses[4].next   = EOLIST;

    return &(Esses[0]);
}




/************************************************************************
*
*   LineFracDlg
*
*   Process messages for the fractal attributes dialog box.
*
************************************************************************/

ULONG FAR PASCAL
LineFracDlg( hWndDlg, message, mp1, mp2 )
HWND   hWndDlg;
USHORT message;
MPARAM mp1;
MPARAM mp2;
{
    switch (message)
    {
    case WM_INITDLG:
	MySetWindowLong  (hWndDlg, IDDCOLORBK,	 lColorBack);
	MySetWindowLong  (hWndDlg, IDDCOLOR,	 lColor);
	MySetWindowUShort(hWndDlg, IDDSTYLE,	 usStyle);
	MySetWindowUShort(hWndDlg, IDDMIX,	 usMixMode);
	MySetWindowUShort(hWndDlg, IDDNUMSIDES,  usPolygonSides);
	MySetWindowUShort(hWndDlg, IDDCPTMAX,	 cptMax);
	MySetWindowUShort(hWndDlg, IDDRECURSION, usRecursion);

	WinSendDlgItemMsg( hWndDlg, IDDCLEARBETWEEN, BM_SETCHECK,
		MPFROM2SHORT(fClearBetween, 0), 0L );
	return FALSE;

    case WM_COMMAND:
	switch (SHORT1FROMMP(mp1))
        {
	case IDDOK:
	    lColorBack	   = MyGetWindowLong  (hWndDlg, IDDCOLORBK);
	    lColor	   = MyGetWindowLong  (hWndDlg, IDDCOLOR);
	    usStyle	   = MyGetWindowUShort(hWndDlg, IDDSTYLE);
	    usMixMode	   = MyGetWindowUShort(hWndDlg, IDDMIX);
	    usPolygonSides = MyGetWindowUShort(hWndDlg, IDDNUMSIDES);
	    cptMax	   = MyGetWindowUShort(hWndDlg, IDDCPTMAX);
	    usRecursion    = MyGetWindowUShort(hWndDlg, IDDRECURSION);

	    fClearBetween = (SHORT)WinSendDlgItemMsg( hWndDlg, IDDCLEARBETWEEN,
				BM_QUERYCHECK, 0L, 0L );

	    if (usPolygonSides == 0)
		usPolygonSides = 2;

	    if (cptMax == 0)
		cptMax = 1;
	    else if (cptMax > MAX_POINT_COUNT)
		cptMax = MAX_POINT_COUNT;


            WinDismissDlg( hWndDlg, TRUE );
            break;

	case IDDCANCEL:
            WinDismissDlg( hWndDlg, TRUE );
            break;

        default:
	    return FALSE;
        }
        break;

    default:
	return (ULONG) WinDefDlgProc( hWndDlg, message, mp1, mp2 );
    }
    return FALSE;
}




/************************************************************************
*
*   AboutDlg
*
*   Process messages for the About box.
*
************************************************************************/

ULONG FAR PASCAL
AboutDlg( hWndDlg, message, mp1, mp2 )
HWND   hWndDlg;
USHORT message;
MPARAM mp1;
MPARAM mp2;
{
    switch (message)
    {
    case WM_COMMAND:			/* the user has pressed a button */
	switch (SHORT1FROMMP(mp1))	/* which button? */
	{
	case DID_OK:
	case DID_CANCEL:
	    WinDismissDlg( hWndDlg, TRUE );
	    break;

	default:
	    return FALSE;
	}
	break;

    default:
	return (ULONG) WinDefDlgProc( hWndDlg, message, mp1, mp2 );
    }
    return FALSE;
}




/************************************************************************
*
*   MySetWindowUShort
*
*   Sets the given control id to the value specified.
*
*   Be careful!  The call to sprintf only works because our
*   stack segment is the same as our data segment.
*
************************************************************************/

VOID
MySetWindowUShort(hWnd, id, num)
HWND hWnd;
USHORT id;
USHORT num;
{
    char szStr[CCHSTR];

    sprintf((NPCH)szStr, "%u", num);
    WinSetWindowText(WinWindowFromID(hWnd, id), (PCH)szStr);
}




/************************************************************************
*
*   MySetWindowLong
*
*   Sets the given control id to the value specified.
*
*   Be careful!  The call to sprintf only works because our
*   stack segment is the same as our data segment.
*
************************************************************************/

VOID
MySetWindowLong(hWnd, id, num)
HWND hWnd;
USHORT id;
LONG num;
{
    char szStr[CCHSTR];

    sprintf((NPCH)szStr, "%ld", num);
    WinSetWindowText(WinWindowFromID(hWnd, id), (PCH)szStr);
}




/************************************************************************
*
*   MyGetWindowUShort
*
*   Returns the value from the given control id.
*
*   Be careful!  The call to atoi only works because our
*   stack segment is the same as our data segment.
*
************************************************************************/

USHORT
MyGetWindowUShort(hWnd, id)
HWND hWnd;
USHORT id;
{
    char szStr[CCHSTR];

    WinQueryWindowText(WinWindowFromID(hWnd, id), CCHSTR, (PCH)szStr);
    return atoi(szStr);
}




/************************************************************************
*
*   MyGetWindowLong
*
*   Returns the value from the given control id.
*
*   Be careful!  The call to atol only works because our
*   stack segment is the same as our data segment.
*
************************************************************************/

LONG
MyGetWindowLong(hWnd, id)
HWND hWnd;
USHORT id;
{
    char szStr[CCHSTR];

    WinQueryWindowText(WinWindowFromID(hWnd, id), CCHSTR, (PCH)szStr);
    return atol(szStr);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.