2020-09-30 17:12:29 +02:00

543 lines
11 KiB
C

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
Work.c
Abstract:
Win32 application to demo multi-threded app.
Author:
Mike Hawash@Compaq (o-mikeh), 08-Mar-1992
Environment:
Win32
Revision History:
08-Mar-1992 Initial version
--*/
//
// set variable to define global variables
//
//#include <nt.h>
//#include <ntrtl.h>
//#include <nturtl.h>
#include <windows.h>
#include "calc.h" /* Defines a complex point */
#include "mandel.h" /* Specific to this program */
//#include "remote.h"
//#include "rmprot.h"
void SetNewCalc( CPOINT cptUL, double dPrec, RECT rc);
COLORREF MapColor(DWORD dwIter, DWORD dwThreshold);
CPOINT cptUL = { (double) -2.05, (double) 1.4 };
double dPrec = (double) .01;
// Picture information
int cPictureID = 0; // picture id, in case we reset in the middle
static CPOINT cptLL; // upper-left
double dPrecision; // precision of draw
static RECTL rclPicture; // rectangle defining client window
static DWORD dwCurrentLine; // next line to be drawn
DWORD dwThreshold; // threshold for iterations
// Do we do local work?
BOOL fLocalWork = TRUE;
BOOL fRemoteWork = FALSE;
int iLines = LINES;
/* Color conversion */
#define CLR_BLACK RGB(0,0,0)
#define CLR_DARKBLUE RGB(0,0,127)
#define CLR_BLUE RGB(0,0,255)
#define CLR_CYAN RGB(0,255,255)
#define CLR_DARKGREEN RGB(0,127,0)
#define CLR_GREEN RGB(0,255,0)
#define CLR_YELLOW RGB(255,255,0)
#define CLR_RED RGB(255,0,0)
#define CLR_DARKRED RGB(127,0,0)
#define CLR_WHITE RGB(255,255,255)
#define CLR_PALEGRAY RGB(194,194,194)
#define CLR_DARKGRAY RGB(127,127,127)
static COLORREF ColorMapTable[] = {
CLR_DARKBLUE,
CLR_BLUE,
CLR_CYAN,
CLR_DARKGREEN,
CLR_GREEN,
CLR_YELLOW,
CLR_RED,
CLR_DARKRED,
CLR_WHITE,
CLR_PALEGRAY,
CLR_DARKGRAY};
/*
* CalcThreshold --
*
* We need an iteration threshold beyond which we give up. We want it to
* increase the farther we zoom in. This code generates a threshold value
* based on the precision of drawing.
*
* RETURNS
*
* threshold calculated based on precision
*/
DWORD CalcThreshold(double precision)
{
DWORD thres = 25;
double multiplier = (double) 100;
/* for every 100, multiply by 2 */
while ( (precision *= multiplier) < (double)1)
thres *= 2;
return thres;
}
/*
* SetNewCalc --
*
* This sets up new information for a drawing and
* updates the drawing ID so any calculations in progress will not
* be mixed in.
*/
void SetNewCalc( CPOINT cptUL, double dPrec, RECT rc)
{
/*
* First, the base point. We need to translate from upper left to
* lower left.
*/
cptLL.real = cptUL.real;
cptLL.imag = cptUL.imag - (dPrec * (rc.bottom - rc.top));
// Now the precision
dPrecision = dPrec;
// The rectangle. Once again, translate.
rclPicture.left = (long) rc.left;
rclPicture.right = (long) rc.right;
rclPicture.bottom = (long) rc.top;
rclPicture.top = (long) rc.bottom;
// Current line, start of drawing
dwCurrentLine = rclPicture.left;
dwThreshold = CalcThreshold(dPrecision);
// Picture id incremented, to prevent confusion
cPictureID++;
}
extern HANDLE ThrdHandles[MAXTHREADS];
extern THREADTABLE ThrdTable [MAXTHREADS];
extern ULONG gulMaxThreads;
/*
* WorkThread --
*
* This function does our work for us. It does it in little pieces, and
* will schedule itself as it sees fit.
*/
void
WorkThread( HWND hWnd)
{
static int iPainting = 0;
int iWork;
THREADTABLE *pThrdTable;
while (TRUE)
{
if (WaitForSingleObject (hWorkEvent, -1L))
{
Beep (1000, 1000);
continue;
}
for (iWork=0; iWork < gulMaxThreads; iWork++)
{
pThrdTable = &(ThrdTable[iWork]);
if (pThrdTable->iStatus == SS_IDLE)
{
if ((long)dwCurrentLine > rclPicture.right)
break;
pThrdTable->rclDraw.left = dwCurrentLine;
pThrdTable->rclDraw.right = dwCurrentLine + iLines - 1;
pThrdTable->rclDraw.top = rclPicture.top;
pThrdTable->rclDraw.bottom = rclPicture.bottom;
pThrdTable->dblPrecision = dPrecision;
pThrdTable->dwThreshold = dwThreshold;
pThrdTable->cptLL = cptLL;
pThrdTable->cPicture = cPictureID;
pThrdTable->dwLine = dwCurrentLine;
pThrdTable->cLines = iLines;
pThrdTable->iStatus = SS_READPENDING;
dwCurrentLine += iLines;
SetEvent (pThrdTable->hMutex);
}
}
}/* while */
}/* WorkThread */
void
_WorkThread( HWND hWnd)
{
static int iPainting = 0;
int iWork;
CALCBUF cb;
while (TRUE)
{
if (iWork = WaitForSingleObject (hWorkEvent, -1L) )
break;
// Beep (5000, 200);
BreakPoint();
/* BUGBUG:
* Make sure that it is not an error. Maybe have a timer
* semaphore to kick it in as well. and the PaintDone Sem.
*/
iWork=iPainting;
do
{
switch (ThrdTable[iWork].iStatus)
{
case SS_IDLE:
if ((long)dwCurrentLine > rclPicture.right)
break;
cb.rclDraw.left = dwCurrentLine;
cb.rclDraw.right = dwCurrentLine + iLines - 1;
cb.rclDraw.top = rclPicture.top;
cb.rclDraw.bottom = rclPicture.bottom;
cb.dblPrecision = dPrecision;
cb.dwThreshold = dwThreshold;
cb.cptLL = cptLL;
memcpy (&(ThrdTable[iWork].cb), &cb, sizeof (CALCBUF));
BreakPoint();
SetEvent (ThrdTable[iWork].hMutex);
ThrdTable[iWork].iStatus = SS_READPENDING;
ThrdTable[iWork].cPicture = cPictureID;
ThrdTable[iWork].dwLine = dwCurrentLine;
ThrdTable[iWork].cLines = iLines;
dwCurrentLine += iLines;
break;
case SS_READPENDING:
// If we switched pictures, we're outta sync; skip it
if (ThrdTable[iWork].cPicture < cPictureID) {
break;
}
// If picture has changed, forget about it
if (cPictureID != ThrdTable[iWork].cPicture)
{
ThrdTable[iWork].iStatus = SS_IDLE;
break;
}
// Post a message so it will be painted
PostMessage(hWnd, WM_PAINTLINE,
(DWORD)(THREADTABLE *)&(ThrdTable[iWork]), 0L);
ThrdTable[iWork].iStatus = SS_PAINTING;
iPainting = iWork;
break;
}
iWork=(++iWork)%MAXTHREADS;
}while (iWork != iPainting);
}/* while */
return;
}
/*
* DrawRect --
*
* This function draws (or undraws) the zoom rectangle.
*/
void
DrawRect( HWND hwnd,
PRECT prc,
BOOL fDrawIt,
HDC hdcBM)
{
HDC hdc;
DWORD dwRop;
hdc = GetDC(hwnd);
if (fDrawIt)
dwRop = NOTSRCCOPY;
else
dwRop = SRCCOPY;
// top side
BitBlt(hdc, prc->left, prc->top, (prc->right - prc->left) + 1,
1, hdcBM, prc->left, prc->top, dwRop);
// bottom side
BitBlt(hdc, prc->left, prc->bottom, (prc->right - prc->left) + 1,
1, hdcBM, prc->left, prc->bottom, dwRop);
// left side
BitBlt(hdc,prc->left, prc->top, 1, (prc->bottom - prc->top) + 1,
hdcBM, prc->left, prc->top, dwRop);
// right side
BitBlt(hdc,prc->right, prc->top, 1, (prc->bottom - prc->top) + 1,
hdcBM, prc->right, prc->top, dwRop);
ReleaseDC(hwnd, hdc);
}
void PerfCount (BYTE bCode, BYTE bNum);
#define MapColor(x,y) ColorMapTable[((x>=y)? CLR_BLACK : (x/3) % 11)]
/*
* PaintLine --
*
* This function paints a buffer of data into the bitmap.
*/
void
PaintLine( HWND hwnd,
THREADTABLE *pThrdTable,
HDC hdcBM,
int cHeight)
{
PDWORD pdwDrawData;
int y;
int x;
DWORD dwThreshold;
RECT rc;
WORD lines = pThrdTable->cLines;
// {
// int i=pThrdTable->iNumber+1;
// Beep (i*1000, 100);
// }
// picture ID had better match, or else we skip it
if (CheckDrawingID(pThrdTable->cPicture))
{
// figure out our threshold
dwThreshold = QueryThreshold();
// get a pointer to the draw buffer
pdwDrawData = pThrdTable->pBuf;
// starting x coordinate
x = (int) pThrdTable->dwLine;
// now loop through the rectangle
while (lines-- > 0)
{
// bottom to top, since that's the order of the data in the buffer
y = (int) cHeight-1;
while (y >= 0) {
// draw a pixel
SetPixel(hdcBM, x,y, MapColor(*pdwDrawData, dwThreshold));
// now increment buffer pointer and y coord
y--;
pdwDrawData++;
}
x++; // increment X coordinate
}
// figure out the rectangle to invalidate
rc.top = 0;
rc.bottom = cHeight;
rc.left = (int)(pThrdTable->dwLine);
rc.right = (int)(pThrdTable->dwLine) + pThrdTable->cLines;
PerfCount (7, pThrdTable->iNumber);
// and invalidate it on the screen so we redraw it
InvalidateRect(hwnd, &rc, FALSE);
}
}
#if 0
/*
* MapColor --
*
* This function maps an iteration count into a corresponding RGB color.
*/
COLORREF
MapColor(DWORD dwIter,
DWORD dwThreshold)
{
// if it's beyond the threshold, call it black
if (dwIter >= dwThreshold)
return CLR_BLACK;
// get a modulus based on the number of colors
dwIter = (dwIter / 3) % 11;
// and return the appropriate color
return ColorMapTable[dwIter];
}
#endif
/*
* CheckDrawing --
*
* Just a sanity check here -- a function to check to make sure that we're
* on the right drawing
*/
BOOL
CheckDrawingID( int id)
{
return (id == cPictureID) ? TRUE : FALSE;
}
/*
* TakeDrawBuffer/ GetDrawBuffer/ FreeDrawBuffer / ReturnDrawBuffer
*
* These functions hide a handle to a buffer of memory.
*
* TakeDrawBuffer ensures only one pipe read at a time.
* GetDrawBuffer locks the handle and returns a pointer.
* FreeDrawBuffer unlocks the handle.
* ReturnDrawBuffer unlocks the handle and lets another pipe read go.
*/
static BOOL fBufferTaken = FALSE;
static HANDLE hSharedBuf = NULL;
BOOL
TakeDrawBuffer( void )
{
if (fBufferTaken)
{
Message("TakeDrawBuffer: conflict");
return FALSE;
}
if (hSharedBuf == NULL)
{
hSharedBuf = LocalAlloc(LMEM_MOVEABLE, MAX_BUFSIZE);
if (hSharedBuf == NULL)
return FALSE;
}
fBufferTaken = TRUE;
return TRUE;
}
PDWORD
GetDrawBuffer( void )
{
if (hSharedBuf == NULL)
return NULL;
return (PDWORD) LocalLock(hSharedBuf);
}
void
FreeDrawBuffer( void )
{
LocalUnlock(hSharedBuf);
}
void
ReturnDrawBuffer( void )
{
fBufferTaken = FALSE;
}
/*
* QueryThreshold --
*
* Callback for finding out what the current drawing's threshold is.
*/
DWORD QueryThreshold( void )
{
return dwThreshold;
}