windows-nt/Source/XPSP1/NT/shell/osshell/control/scrnsave/bezier/ssbezier.c

1385 lines
34 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*
SSBEZIER.C
Bezier screensaver.
History:
10/14/91 kentd Wrote for Windows NT. Hacked from WinBez.
*/
#include <windows.h>
#include <commctrl.h>
#include <scrnsave.h>
#include "bezdlg.h"
#include "strings.h"
#include "uniconv.h"
#include "stdlib.h"
#undef OVERFLOW
#undef UNDERFLOW
#include "math.h"
#define INT int
#if !defined(_ALPHA_)
// floating point always initialized on ALPHA and ALPHA64
VOID _fltused(VOID) {}
#endif
// routines from bez.c
VOID vInitPoints();
VOID vRedraw();
VOID vNextBez();
LONG GetDlgItemLong(HWND hDlg, WORD wID, BOOL *pfTranslated, BOOL fSigned);
VOID GetIniEntries(VOID);
VOID vInitPalette(HDC);
VOID vNewColor(VOID);
LONG GetPrivateProfileLong(LPTSTR pszApp, LPTSTR pszKey, LONG lDefault);
typedef struct _STR
{
PSZ psz;
SIZE sz;
SHORT c;
BYTE f;
} STR;
typedef struct _inst
{
ULONG i;
POINT pt;
POINT ptVel;
LONG c;
} INST, *PINST;
typedef struct _WINDOW {
HWND hwnd;
HDC hdc;
HANDLE hWait;
int xsize;
int ysize;
HPALETTE hpalette;
// frame data
HBITMAP hbitmap;
HDC hdcBitmap;
PBYTE pdata;
RECT rcBlt;
RECT rcDraw;
int xDelta;
int yDelta;
// text data
HBITMAP hbitmapText;
HDC hdcText;
PBYTE pdataText;
} WINDOW, *PWINDOW;
PWINDOW gpwindow;
BOOL fRepaint = TRUE;
//
// Length is the number of beziers in each loop
// Width is the number of times each bezier loop is drawn
//
#define MINLENGTH 1
#define MAXLENGTH 10
#define DEF_LENGTH 4
#define MINWIDTH 1
#define MAXWIDTH 100
#define DEF_WIDTH 30
#define MINVEL 2
#define DEFVEL 10
#define MAXVEL 20
#define MAX(a, b) (((a) >= (b)) ? (a) : (b))
#define NEWVEL (ulRandom() % (MAXVEL / 2 - MINVEL) + MINVEL)
HDC ghdc;
HPEN ghpenBez;
HPEN ghpenErase;
HBRUSH ghbrushBack;
DWORD glSeed;
LONG gcxScreen;
LONG gcyScreen;
LONG gczScreen;
LONG gcPoints;
HDC hdcBM;
HBITMAP hbm;
PINST ainst;
BOOL gbPointsDrawn;
LONG giVelMax = DEFVEL;
LONG gcBez = DEF_WIDTH;
LONG gcRingLen = DEF_LENGTH;
STR *astr = NULL;
BOOL bInit = FALSE;
int cstr = 0;
ULONG ic = 0;
BYTE gf = 0xff;
BOOL gbCopy = TRUE;
BOOL gbPalette = FALSE;
HPALETTE ghpal = 0;
HPALETTE ghpalOld = 0;
#define NUM_PALETTE_ENTRIES 10
#define FADE_RESOLUTION 24
#define MAX_TICKS_WIMPY 1000
#define MAX_TICKS_COOL 100
PALETTEENTRY gapal[NUM_PALETTE_ENTRIES * FADE_RESOLUTION];
PALETTEENTRY gapalDefault[NUM_PALETTE_ENTRIES + 1] =
{ {255, 0, 0}, {128, 0, 0},
{0, 128, 0}, {128, 128, 0},
{0, 0, 128}, {128, 0, 128},
{0, 128, 128}, {128, 128, 128},
{192, 192, 192}, {255, 0, 0},
{0, 0, 0} };
LONG gipal;
LONG gcpal;
LONG gcTicker;
LONG gcMaxTicks;
// Structures:
typedef struct _BAND {
POINT apt[2];
} BAND;
typedef struct _BEZ {
BAND band[MAXLENGTH];
BOOL bDrawn;
} BEZ, *PBEZ;
BEZ bezbuf[MAXWIDTH];
PBEZ gpBez;
POINT aPts[MAXLENGTH * 3 + 1];
POINT aVel[MAXLENGTH][2];
TCHAR szLineSpeed [] = TEXT("LineSpeed"); // .INI Line Speed key
TCHAR szNumBez [] = TEXT("Width"); // .INI Width key
TCHAR szNumRings [] = TEXT("Length"); // .INI Length key
BOOL Init(HWND);
BYTE mask = 0;
//
// Help IDs
//
DWORD aBezDlgHelpIds[] = {
65535, ((DWORD) -1),
ID_LENGTH_LABEL, IDH_DISPLAY_SCREENSAVER_BEZIERS_LENGTH,
ID_LENGTH, IDH_DISPLAY_SCREENSAVER_BEZIERS_LENGTH,
ID_LENGTHARROW, IDH_DISPLAY_SCREENSAVER_BEZIERS_LENGTH,
ID_WIDTH_LABEL, IDH_DISPLAY_SCREENSAVER_BEZIERS_WIDTH,
ID_WIDTH, IDH_DISPLAY_SCREENSAVER_BEZIERS_WIDTH,
ID_WIDTHARROW, IDH_DISPLAY_SCREENSAVER_BEZIERS_WIDTH,
ID_VELOCITY, IDH_DISPLAY_SCREENSAVER_BEZIERS_SPEED,
ID_VELOCITY_SLOW, IDH_DISPLAY_SCREENSAVER_BEZIERS_SPEED,
ID_VELOCITY_FAST, IDH_DISPLAY_SCREENSAVER_BEZIERS_SPEED,
0,0
};
/* This is the main window procedure to be used when the screen saver is
activated in a screen saver mode ( as opposed to configure mode ). This
function must be declared as an EXPORT in the EXPORTS section of the
DEFinition file... */
LRESULT ScreenSaverProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static UINT_PTR wTimer;
TCHAR szTemp[20]; // Temporary string buffer
int i;
BYTE bit;
switch (message)
{
case WM_CREATE:
GetIniEntries ();
glSeed = GetCurrentTime (); // random number generator
ghdc = GetDC(hWnd);
gcxScreen = ((LPCREATESTRUCT)lParam)->cx;
gcyScreen = ((LPCREATESTRUCT)lParam)->cy;
vInitPoints();
if (gczScreen & (1 << 14)) {
Init(hWnd);
} else {
ghbrushBack = GetStockObject(BLACK_BRUSH);
ghpenBez = CreatePen(PS_SOLID, 0, 0xff);
ghpenErase = CreatePen(PS_SOLID, 0, 0);
SelectObject(ghdc,ghpenBez);
SelectObject(ghdc,ghbrushBack);
vInitPalette(ghdc);
wTimer = SetTimer (hWnd, 1, 1, NULL);
}
break;
case WM_SIZE:
gcxScreen = LOWORD(lParam);
gcyScreen = HIWORD(lParam);
break;
case WM_PALETTECHANGED:
RealizePalette(ghdc);
break;
case WM_QUERYNEWPALETTE:
if (ghpal != 0)
{
SelectPalette(ghdc, ghpal, FALSE);
RealizePalette(ghdc);
InvalidateRect(hWnd, NULL, TRUE);
return(TRUE);
}
else
return(FALSE);
case WM_PAINT:
if (gczScreen & (1 << 14)) {
PAINTSTRUCT paint;
BeginPaint(hWnd, &paint);
EndPaint(hWnd, &paint);
fRepaint = TRUE;
} else {
vRedraw();
}
break;
case WM_TIMER:
if (gczScreen & (1 << 14)) {
SetEvent(gpwindow->hWait);
} else {
vNextBez();
}
break;
case WM_DESTROY:
if (wTimer)
KillTimer (hWnd, wTimer);
if (ghpal != 0)
{
SelectPalette(ghdc, ghpalOld, FALSE);
DeleteObject(ghpal);
}
ReleaseDC(hWnd, ghdc);
break;
}
return (DefScreenSaverProc (hWnd, message, wParam, lParam));
}
//***************************************************************************
BOOL ScreenSaverConfigureDialog (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
BOOL fError; // Error flag
UINT wTemp;
TCHAR szTemp[20]; // Temporary string buffer
char szTemp2[20]; // Temporary string buffer
WORD nCtlId;
int nVal, nOldVal;
LONG *plState = (LONG *) szTemp2; // State buffer
static HWND hVelocity, // window handle of Speed scrollbar
hIDOK, // window handle of OK button
hSetPassword, // window handle of SetPassword button
hNumBeziers, // window handle of NumBezier EditControl
hNumRings; // window handle of NumBezier EditControl
switch (message)
{
case WM_INITDIALOG:
GetIniEntries (); // Get initial values
hVelocity = GetDlgItem (hDlg, ID_VELOCITY);
hIDOK = GetDlgItem (hDlg, IDOK);
hNumBeziers = GetDlgItem (hDlg, ID_WIDTH);
hNumRings = GetDlgItem (hDlg, ID_LENGTH);
SendMessage (hNumBeziers, EM_LIMITTEXT, 3, 0);
SendMessage (hNumRings, EM_LIMITTEXT, 3, 0);
SetScrollRange (hVelocity, SB_CTL, MINVEL, MAXVEL, FALSE);
SetScrollPos (hVelocity, SB_CTL, giVelMax, TRUE);
SetDlgItemInt (hDlg, ID_WIDTH, gcBez, FALSE);
SetDlgItemInt (hDlg, ID_LENGTH, gcRingLen, FALSE);
SendDlgItemMessage( hDlg, ID_LENGTHARROW, UDM_SETRANGE, 0, MAKELONG(MAXLENGTH, MINLENGTH));
SendDlgItemMessage( hDlg, ID_WIDTHARROW, UDM_SETRANGE, 0, MAKELONG(MAXWIDTH, MINWIDTH));
wsprintf (szTemp, TEXT("%d"), gcBez);
WritePrivateProfileString (szAppName, szNumBez, szTemp, szIniFile);
return TRUE;
case WM_HSCROLL:
switch (LOWORD(wParam))
{
case SB_PAGEUP:
--giVelMax;
break;
case SB_LINEUP:
--giVelMax;
break;
case SB_PAGEDOWN:
++giVelMax;
break;
case SB_LINEDOWN:
++giVelMax;
break;
case SB_THUMBPOSITION:
giVelMax = HIWORD (wParam);
break;
case SB_BOTTOM:
giVelMax = MAXVEL;
break;
case SB_TOP:
giVelMax = MINVEL;
break;
case SB_THUMBTRACK:
case SB_ENDSCROLL:
return TRUE;
break;
}
if ((int)giVelMax <= MINVEL)
giVelMax = MINVEL;
if ((int)giVelMax >= MAXVEL)
giVelMax = MAXVEL;
SetScrollPos ((HWND) lParam, SB_CTL, giVelMax, TRUE);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_LENGTH:
if (HIWORD(wParam) == EN_UPDATE)
{
wTemp = GetDlgItemInt (hDlg, ID_LENGTH, &fError, FALSE);
fError = ((wTemp <= MAXLENGTH) && (wTemp >= MINLENGTH));
EnableWindow (GetDlgItem (hDlg, ID_LENGTHARROW), fError);
EnableWindow (GetDlgItem (hDlg, IDOK), fError);
}
break;
case ID_WIDTH:
if (HIWORD(wParam) == EN_UPDATE)
{
wTemp = GetDlgItemInt (hDlg, ID_WIDTH, &fError, FALSE);
fError = ((wTemp <= MAXWIDTH) && (wTemp >= MINWIDTH));
EnableWindow (GetDlgItem (hDlg, ID_WIDTHARROW), fError);
EnableWindow (GetDlgItem (hDlg, IDOK), fError);
}
break;
case IDOK:
wTemp = GetDlgItemInt (hDlg, ID_WIDTH, &fError, FALSE);
wTemp |= GetPrivateProfileInt (szAppName, szNumBez, DEF_WIDTH, szIniFile) & (1 << 14);
wsprintf (szTemp, TEXT("%d"), wTemp);
WritePrivateProfileString (szAppName, szNumBez, szTemp, szIniFile);
wTemp = GetDlgItemInt (hDlg, ID_LENGTH, &fError, FALSE);
wsprintf (szTemp, TEXT("%d"), wTemp);
WritePrivateProfileString (szAppName, szNumRings, szTemp, szIniFile);
wsprintf (szTemp, TEXT("%d"), giVelMax);
WritePrivateProfileString (szAppName, szLineSpeed, szTemp, szIniFile);
case IDCANCEL:
EndDialog (hDlg, LOWORD(wParam) == IDOK);
return TRUE;
}
break;
case WM_HELP: // F1
WinHelp(
(HWND) ((LPHELPINFO) lParam)->hItemHandle,
szHelpFile,
HELP_WM_HELP,
(ULONG_PTR) (LPSTR) aBezDlgHelpIds
);
break;
case WM_CONTEXTMENU: // right mouse click
WinHelp(
(HWND) wParam,
szHelpFile,
HELP_CONTEXTMENU,
(ULONG_PTR) (LPSTR) aBezDlgHelpIds
);
break;
default:
break;
}
return FALSE;
}
/* This procedure is called right before the dialog box above is created in
order to register any child windows that are custom controls. If no
custom controls need to be registered, then simply return TRUE.
Otherwise, register the child controls however is convenient... */
BOOL RegisterDialogClasses (HANDLE hInst)
{
InitCommonControls();
return TRUE;
}
LONG GetDlgItemLong (HWND hDlg, WORD wID, BOOL *pfTranslated, BOOL fSigned)
{
TCHAR szTemp[20];
LPTSTR pszTemp;
LONG lTemp = 0l;
BOOL fNegative;
if (!GetDlgItemText (hDlg, wID, szTemp, CharSizeOf(szTemp)))
goto GetDlgItemLongError;
szTemp[19] = TEXT('\0');
pszTemp = szTemp;
while (*pszTemp == TEXT(' ') || *pszTemp == TEXT('\t'))
pszTemp++;
if ((!fSigned && *pszTemp == TEXT('-')) || !*pszTemp)
goto GetDlgItemLongError;
fNegative = (*pszTemp == TEXT('-')) ? TRUE : FALSE;
while (*pszTemp >= TEXT('0') && *pszTemp <= TEXT('9'))
lTemp = lTemp * 10l + (LONG)(*(pszTemp++) - TEXT('0'));
if (*pszTemp)
goto GetDlgItemLongError;
if (fNegative)
lTemp *= -1;
*pfTranslated = TRUE;
return lTemp;
GetDlgItemLongError:
*pfTranslated = FALSE;
return 0l;
}
LONG GetPrivateProfileLong (LPTSTR pszApp, LPTSTR pszKey, LONG lDefault)
{
LONG lTemp = 0l;
TCHAR szTemp[20];
LPTSTR pszTemp;
if (!GetPrivateProfileString (pszApp, pszKey, TEXT(""), szTemp, CharSizeOf(szTemp), szIniFile))
goto GetProfileLongError;
szTemp[19] = TEXT('\0');
pszTemp = szTemp;
while (*pszTemp >= TEXT('0') && *pszTemp <= TEXT('9'))
lTemp = lTemp * 10l + (LONG)(*(pszTemp++) - TEXT('0'));
if (*pszTemp)
goto GetProfileLongError;
return lTemp;
GetProfileLongError:
return lDefault;
}
VOID GetIniEntries (VOID)
{
LoadString (hMainInstance, idsName, szName, TITLEBARNAMELEN);
LoadString (hMainInstance, idsAppName, szAppName, APPNAMEBUFFERLEN);
//Load Common Strings from stringtable...
LoadString (hMainInstance, idsIniFile, szIniFile, MAXFILELEN);
LoadString (hMainInstance, idsScreenSaver, szScreenSaver, 22);
LoadString (hMainInstance, idsHelpFile, szHelpFile, MAXFILELEN);
LoadString (hMainInstance, idsNoHelpMemory, szNoHelpMemory, BUFFLEN);
giVelMax = GetPrivateProfileInt (szAppName, szLineSpeed, DEFVEL, szIniFile);
if (giVelMax > MAXVEL || giVelMax < MINVEL)
giVelMax = DEFVEL;
gcBez = GetPrivateProfileInt (szAppName, szNumBez, DEF_WIDTH, szIniFile);
gcBez = (gczScreen = gcBez) & ~(1 << 14);
if (gcBez > MAXWIDTH)
gcBez = MAXWIDTH;
if (gcBez < MINWIDTH)
gcBez = MINWIDTH;
gcRingLen = GetPrivateProfileInt (szAppName, szNumRings, DEF_LENGTH, szIniFile);
if (gcRingLen > MAXLENGTH)
gcRingLen = MAXLENGTH;
if (gcRingLen < MINLENGTH)
gcRingLen = MINLENGTH;
}
/************************************************************************
* Bezier code
*
* Created: 19-Oct-1990 10:18:45
* Author: Paul Butzi
*
* Copyright (c) 1990 Microsoft Corporation
*
* Generates random lines
* Hacked from arcs.c
\**************************************************************************/
DWORD ulRandom()
{
glSeed *= 69069;
glSeed++;
return(glSeed);
}
VOID vCLS()
{
PatBlt(ghdc, 0, 0, gcxScreen, gcyScreen, PATCOPY);
}
int iNewVel(INT i)
{
if ((gcRingLen != 1) || (i == 1) || (i == 2))
return(ulRandom() % (giVelMax + 1 / 3) + MINVEL);
else
return(ulRandom() % giVelMax + MINVEL);
}
VOID vInitPoints()
{
INT ii;
for (ii = 0; ii < MAXLENGTH; ii++)
{
bezbuf[0].band[ii].apt[0].x = gcxScreen ? ulRandom() % gcxScreen : 0;
bezbuf[0].band[ii].apt[0].y = gcyScreen ? ulRandom() % gcyScreen : 0;
bezbuf[0].band[ii].apt[1].x = gcxScreen ? ulRandom() % gcxScreen : 0;
bezbuf[0].band[ii].apt[1].y = gcyScreen ? ulRandom() % gcyScreen : 0;
aVel[ii][0].x = iNewVel(ii) * ((ulRandom() & 0x10) ? 1 : -1);
aVel[ii][0].y = iNewVel(ii) * ((ulRandom() & 0x10) ? 1 : -1);
aVel[ii][1].x = iNewVel(ii) * ((ulRandom() & 0x11) ? 1 : -1);
aVel[ii][1].y = iNewVel(ii) * ((ulRandom() & 0x10) ? 1 : -1);
}
gpBez = bezbuf;
}
VOID vRedraw()
{
INT j;
for ( j = 0; j < gcBez; j += 1 )
{
bezbuf[j].bDrawn = FALSE;
}
vCLS();
gpBez = bezbuf;
gbPointsDrawn = FALSE;
}
/******************************Public*Routine******************************\
* VOID vDrawBand(pbez)
*
* History:
* 14-Oct-1991 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID vDrawBand(PBEZ pbez)
{
INT ii;
INT iNext;
PPOINT ppt;
// If only drawing one Bezier, special case it:
if (gcRingLen == 1)
{
aPts[0] = pbez->band[0].apt[0];
aPts[1] = pbez->band[0].apt[1];
aPts[2] = pbez->band[1].apt[0];
aPts[3] = pbez->band[1].apt[1];
}
else
{
// Do the elastic band effect, with 2nd order continuity:
aPts[0].x = (pbez->band[0].apt[0].x + pbez->band[0].apt[1].x) >> 1;
aPts[0].y = (pbez->band[0].apt[0].y + pbez->band[0].apt[1].y) >> 1;
ppt = &aPts[1];
for (ii = 0; ii < gcRingLen; ii++)
{
iNext = (ii + 1) % gcRingLen;
*ppt++ = pbez->band[ii].apt[1];
*ppt++ = pbez->band[iNext].apt[0];
ppt->x = (pbez->band[iNext].apt[0].x + pbez->band[iNext].apt[1].x) >> 1;
ppt->y = (pbez->band[iNext].apt[0].y + pbez->band[iNext].apt[1].y) >> 1;
ppt++;
}
}
PolyBezier(ghdc, aPts, gcRingLen * 3 + 1);
}
/******************************Public*Routine******************************\
* VOID vNextBez()
*
\**************************************************************************/
VOID vNextBez()
{
INT ii;
INT jj;
PBEZ obp = gpBez++;
if ( gpBez >= &bezbuf[gcBez] )
gpBez = bezbuf;
// If bezier on screen, erase by redrawing:
if (gpBez->bDrawn)
{
if (gbCopy)
SelectObject(ghdc, ghpenErase);
vDrawBand(gpBez);
}
// Adjust points:
for (ii = 0; ii < MAX(gcRingLen, 2); ii++)
{
for (jj = 0; jj < 2; jj++)
{
register INT x, y;
x = obp->band[ii].apt[jj].x;
y = obp->band[ii].apt[jj].y;
x += aVel[ii][jj].x;
y += aVel[ii][jj].y;
if ( x >= gcxScreen )
{
x = gcxScreen - ((x - gcxScreen) + 1);
aVel[ii][jj].x = - iNewVel(ii);
}
if ( x < 0 )
{
x = - x;
aVel[ii][jj].x = iNewVel(ii);
}
if ( y >= gcyScreen )
{
y = gcyScreen - ((y - gcyScreen) + 1);
aVel[ii][jj].y = - iNewVel(ii);
}
if ( y < 0 )
{
y = - y;
aVel[ii][jj].y = iNewVel(ii);
}
gpBez->band[ii].apt[jj].x = x;
gpBez->band[ii].apt[jj].y = y;
}
}
vNewColor();
if (gbCopy)
SelectObject(ghdc, ghpenBez);
vDrawBand(gpBez);
gpBez->bDrawn = TRUE;
}
ULONG iGet()
{
static int i = 0;
int j;
if (++i >= cstr)
i = 1;
j = i;
while (astr[i].f == gf) {i = (i % (cstr - 1)) + 1; if (i == j) gf = ~gf;}
astr[i].f = ~astr[i].f;
return(i);
}
VOID vInitPalette(HDC hdc)
{
LOGPALETTE lp;
HPALETTE hpalOld = 0;
PALETTEENTRY *ppal;
LONG cBitsPerPel;
LONG i;
LONG j;
cBitsPerPel = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
gbPalette = (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) > 0;
if (gbPalette)
{
// Try and realize a palette with one palette entry reserved:
lp.palVersion = 0x300;
lp.palNumEntries = 1;
lp.palPalEntry[0].peFlags = PC_RESERVED;
ghpal = CreatePalette(&lp);
if (ghpal != 0)
{
ghpalOld = SelectPalette(hdc, ghpal, FALSE);
RealizePalette(ghdc);
}
}
if (!gbPalette && cBitsPerPel <= 4)
{
// If on a wimpy device, simply cycle through the 'dark' colors of
// its palette, skipping black because it's boring:
gcpal = GetSystemPaletteEntries(hdc, 1, NUM_PALETTE_ENTRIES, &gapal[0]);
if (gcpal == 0)
{
// Worst comes to worst, always use a white pen:
gcpal = 1;
gapal[0].peRed = 255;
gapal[0].peGreen = 255;
gapal[0].peBlue = 255;
gapal[0].peFlags = 0;
}
gipal = 8 % gcpal; // Start with red
gcMaxTicks = MAX_TICKS_WIMPY;
gcTicker = 0;
return;
}
// At this point, we either have a palette managed or high color device.
ppal = &gapal[0];
for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
{
for (j = 0; j < FADE_RESOLUTION; j++)
{
ppal->peRed = (BYTE)(gapalDefault[i].peRed +
(j * (gapalDefault[i + 1].peRed - gapalDefault[i].peRed))
/ FADE_RESOLUTION);
ppal->peGreen = (BYTE)(gapalDefault[i].peGreen +
(j * (gapalDefault[i + 1].peGreen - gapalDefault[i].peGreen))
/ FADE_RESOLUTION);
ppal->peBlue = (BYTE)(gapalDefault[i].peBlue +
(j * (gapalDefault[i + 1].peBlue - gapalDefault[i].peBlue))
/ FADE_RESOLUTION);
ppal->peFlags = PC_RESERVED;
ppal++;
}
}
gcpal = (NUM_PALETTE_ENTRIES - 1) * FADE_RESOLUTION;
gipal = 0;
gcMaxTicks = MAX_TICKS_COOL;
gcTicker = 0;
if (gbPalette)
{
// Create a pen that maps to logical palette index zero:
SelectObject(hdc, GetStockObject(BLACK_PEN));
DeleteObject(ghpenBez);
ghpenBez = CreatePen(0, 0, PALETTEINDEX(0));
SelectObject(hdc, ghpenBez);
}
return;
}
VOID vNewColor(VOID)
{
HPEN hpen;
if (--gcTicker <= 0)
{
if (gbPalette)
{
AnimatePalette(ghpal, 0, 1, &gapal[gipal]);
}
else
{
if (gbCopy)
{
hpen = CreatePen(0, 0, RGB(gapal[gipal].peRed,
gapal[gipal].peGreen,
gapal[gipal].peBlue));
SelectObject(ghdc, hpen);
DeleteObject(ghpenBez);
ghpenBez = hpen;
}
}
gcTicker = gcMaxTicks;
if (--gipal < 0)
gipal = gcpal - 1;
}
return;
}
/****************************************************************************/
typedef struct _DOT {
int xm, ym, zm;
int xn, yn, zn;
int color;
} DOT, *PDOT;
typedef struct _LIST *PLIST;
typedef struct _LIST {
PLIST pnext;
PLIST plistComplete;
PSZ psz;
} LIST;
#define MAXFIXED (65536)
#define AXISSIZE 150
#define XSIZE (gcxScreen)
#define YSIZE (gcyScreen)
#define XSIZE2 (XSIZE / 2)
#define YSIZE2 (YSIZE / 2)
#define SCANSIZE ((8 * XSIZE + 31) & ~31) / 8
#define PI (3.141529)
#define MAXANGLE (360 * 10)
/****************************************************************************/
int *icos;
int *isin;
/****************************************************************************/
void ClearRect(
PBYTE pstart,
PRECT prc)
{
PBYTE pdst;
int length, y;
pdst = pstart + SCANSIZE * prc->top + prc->left;
length = prc->right - prc->left;
for (y = prc->top; y < prc->bottom; y++) {
memset(pdst, 0, length);
pdst += SCANSIZE;
}
}
/****************************************************************************/
void UnionRects(
PRECT prcDest,
PRECT prc)
{
if (prc->left < prcDest->left) prcDest->left = prc->left;
if (prc->right > prcDest->right) prcDest->right = prc->right;
if (prc->top < prcDest->top) prcDest->top = prc->top;
if (prc->bottom > prcDest->bottom) prcDest->bottom = prc->bottom;
}
/****************************************************************************/
__inline int WrapPlus(
int deg,
int range)
{
return deg >= range
? deg - range
: deg;
}
__inline int WrapMinus(
int deg,
int range)
{
return deg < 0
? deg + range
: deg;
}
__inline int Bound(
int deg,
int range)
{
return WrapMinus(WrapPlus(deg, range), range);
}
/****************************************************************************/
int RandomInt(
int min,
int max)
{
int dx = max - min;
int mask = 1;
int value;
while (mask < dx) {
mask = (mask << 1) + 1;
}
while ((value = (rand() & mask) + min) > max) ;
return value;
}
/****************************************************************************/
#define NUMDOTS 1500
PDOT adot;
void InitDrawShaded(
PWINDOW pwindow)
{
int d0, d1;
int c0, c1, s0, s1;
int i;
int x, y, z;
pwindow->rcDraw.left = 0;
pwindow->rcDraw.right = 0;
pwindow->rcDraw.top = 0;
pwindow->rcDraw.bottom = 0;
for (i = 0; i < NUMDOTS; i++) {
PDOT pdot = adot + i;
pdot->xm = 1 * AXISSIZE / 4;
pdot->ym = 0;
pdot->zm = 0;
d0 = RandomInt(0, MAXANGLE / 2);
d1 = RandomInt(0, MAXANGLE - 1);
c0 = icos[d0];
s0 = isin[d0];
c1 = icos[d1];
s1 = isin[d1];
x = (pdot->zm * s0 + pdot->xm * c0) / MAXFIXED;
z = (pdot->zm * c0 - pdot->xm * s0) / MAXFIXED;
y = (z * s1 + pdot->ym * c1) / MAXFIXED;
z = (z * c1 - pdot->ym * s1) / MAXFIXED;
pdot->xm = x;
pdot->ym = y;
pdot->zm = z;
pdot->xn = 0;
pdot->yn = 0;
pdot->zn = 0;
}
}
/****************************************************************************/
#define DELTA0 47
#define DELTA1 30
#define DELTA2 40
void DrawFrameShaded(
PWINDOW pwindow)
{
static int deg0 = 0, deg1 = 0, deg2 = 0, deg3 = 0;
int i, j;
int c0, c1, sizetext;
int s0, s1, sizeball;
int x, y, z;
int xs, ys, zs;
PBYTE pdata = pwindow->pdata;
BYTE color;
int d0, d1, d2;
PRECT prc = &(pwindow->rcDraw);
ClearRect(pwindow->pdata, &(pwindow->rcDraw));
pwindow->rcBlt = pwindow->rcDraw;
prc->left = XSIZE;
prc->right = 0;
prc->top = YSIZE;
prc->bottom = 0;
//
// draw this frame
//
for (j = 0; j < 1; j++) {
d0 = WrapPlus(deg0 + j * DELTA0, MAXANGLE);
d0 = Bound((icos[d0] * MAXANGLE / 2) / MAXFIXED, MAXANGLE);
c0 = icos[d0];
s0 = isin[d0];
d1 = WrapPlus(deg1 + j * DELTA1, MAXANGLE);
c1 = icos[d1];
s1 = isin[d1];
d2 = WrapPlus(deg2 + MAXANGLE * 3 / 4, MAXANGLE);
sizeball = (icos[d2] + MAXFIXED) / 2;
sizetext = (isin[d2] + MAXFIXED) / 2;
color = 245;
/*
* rotate verticies
*/
for (i = 0; i < NUMDOTS; i++) {
PDOT pdot = adot + i;
PBYTE pbyte;
xs = pdot->xm;
ys = pdot->ym;
zs = pdot->zm;
x = (zs * s0 + xs * c0) / MAXFIXED;
z = (zs * c0 - xs * s0) / MAXFIXED;
y = (z * s1 + ys * c1) / MAXFIXED;
z = (z * c1 - ys * s1) / MAXFIXED;
x = (x * sizeball + pdot->xn * sizetext) / MAXFIXED;
y = (y * sizeball + pdot->yn * sizetext) / MAXFIXED;
z = (z * sizeball + pdot->zn * sizetext) / MAXFIXED;
x += XSIZE2;
y += YSIZE2;
if (x < 0) x = 0;
if (x > XSIZE - 2) x = XSIZE - 2;
if (y < 0) y = 0;
if (y > YSIZE - 2) y = YSIZE - 2;
if (x < prc->left) prc->left = x;
if (x+2 > prc->right) prc->right = x+2;
if (y < prc->top) prc->top = y;
if (y+2 > prc->bottom) prc->bottom = y+2;
pbyte = pdata + x + y * SCANSIZE;
pbyte[0] = color;
pbyte[1] = color;
pbyte[SCANSIZE] = color;
pbyte[SCANSIZE + 1] = color;
}
}
//
// next frame
//
deg0 = WrapPlus(deg0 + DELTA0, MAXANGLE);
deg1 = WrapPlus(deg1 + DELTA1, MAXANGLE);
deg2 -= DELTA2;
if (deg2 < 0) {
deg2 += MAXANGLE;
}
UnionRects(&(pwindow->rcBlt), &(pwindow->rcDraw));
pwindow->xDelta = pwindow->rcBlt.left;
pwindow->yDelta = pwindow->rcBlt.top;
}
/****************************************************************************/
void InitDrawingThread(
PWINDOW pwindow)
{
int i;
for (i = 0; i < MAXANGLE; i++) {
double rad = i * (2.0 * PI / MAXANGLE);
icos[i] = (int)(cos(rad) * MAXFIXED);
isin[i] = (int)(sin(rad) * MAXFIXED);
}
}
/****************************************************************************/
void BltThread(
PWINDOW pwindow)
{
PRECT prc = &(pwindow->rcBlt);
GdiSetBatchLimit(1);
InitDrawingThread(pwindow);
InitDrawShaded(pwindow);
while (TRUE) {
if (fRepaint) {
RECT rc;
rc.left = 0;
rc.right = pwindow->xsize;
rc.top = 0;
rc.bottom = pwindow->ysize;
FillRect(pwindow->hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
fRepaint = FALSE;
}
DrawFrameShaded(pwindow);
BitBlt(
pwindow->hdc,
prc->left, prc->top,
prc->right - prc->left, prc->bottom - prc->top,
pwindow->hdcBitmap,
pwindow->xDelta,
pwindow->yDelta, SRCCOPY);
WaitForSingleObject(pwindow->hWait, INFINITE);
}
}
/****************************************************************************/
void vCleanSystemPalette(HDC hdc)
{
HPALETTE hpal,hpalOld;
DWORD aTemp[257];
LPLOGPALETTE lpLogPal;
UCHAR iTemp;
lpLogPal = (LPLOGPALETTE) aTemp;
lpLogPal->palVersion = 0x300;
lpLogPal->palNumEntries = 256;
for (iTemp = 0; iTemp < 256; iTemp++)
{
lpLogPal->palPalEntry[iTemp].peRed = 0;
lpLogPal->palPalEntry[iTemp].peGreen = 0;
lpLogPal->palPalEntry[iTemp].peBlue = iTemp;
lpLogPal->palPalEntry[iTemp].peFlags = PC_RESERVED;
}
hpal = CreatePalette(lpLogPal);
hpalOld = SelectPalette(hdc, hpal, 0);
RealizePalette(hdc);
SelectPalette(hdc, hpalOld, 0);
DeleteObject(hpal);
}
/****************************************************************************/
BOOL InitDibSection(
PWINDOW pwindow,
RGBQUAD* ppal,
BOOL fSystemPalette)
{
LPLOGPALETTE plp = (LPLOGPALETTE)LocalAlloc(LPTR, sizeof(LOGPALETTE) + 4 * 256);
LPBITMAPINFO pbmi = (LPBITMAPINFO)LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER) + 4 * 256);
int i;
UCHAR iTemp;
PUSHORT pw;
LOGFONT lf;
HFONT hfont;
if(plp == NULL || pbmi == NULL)
{
return FALSE;
}
plp->palVersion = 0x300;
plp->palNumEntries = 256;
if (fSystemPalette) {
GetPaletteEntries((HPALETTE)GetStockObject(DEFAULT_PALETTE),
0, 1, plp->palPalEntry);
GetPaletteEntries((HPALETTE)GetStockObject(DEFAULT_PALETTE),
255, 1, &plp->palPalEntry[255]);
for (i = 1; i < 254; i++) {
plp->palPalEntry[i].peRed = ppal[i].rgbRed;
plp->palPalEntry[i].peGreen = ppal[i].rgbGreen;
plp->palPalEntry[i].peBlue = ppal[i].rgbBlue;
plp->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
}
SetSystemPaletteUse(pwindow->hdc, SYSPAL_NOSTATIC);
} else {
GetPaletteEntries((HPALETTE)GetStockObject(DEFAULT_PALETTE),
0, 10, plp->palPalEntry);
GetPaletteEntries((HPALETTE)GetStockObject(DEFAULT_PALETTE),
246, 10, &plp->palPalEntry[255]);
for (i = 10; i < 246; i++) {
plp->palPalEntry[i].peRed = ppal[i].rgbRed;
plp->palPalEntry[i].peGreen = ppal[i].rgbGreen;
plp->palPalEntry[i].peBlue = ppal[i].rgbBlue;
plp->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
}
}
pwindow->hpalette = CreatePalette(plp);
vCleanSystemPalette(pwindow->hdc);
SelectPalette(pwindow->hdc, pwindow->hpalette, FALSE);
RealizePalette(pwindow->hdc);
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = XSIZE;
pbmi->bmiHeader.biHeight = -YSIZE;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 8;
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage = 0;
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 0;
pbmi->bmiHeader.biClrImportant = 0;
pw = (PUSHORT)(pbmi->bmiColors);
for (iTemp=0; iTemp<256; iTemp++) {
pw[iTemp] = iTemp;
}
pwindow->hbitmap = CreateDIBSection(
pwindow->hdc, pbmi, DIB_PAL_COLORS,
(PVOID*)&(pwindow->pdata), 0, 0);
pwindow->hdcBitmap = CreateCompatibleDC(pwindow->hdc);
SelectObject(pwindow->hdcBitmap, pwindow->hbitmap);
lf.lfHeight = 30;
lf.lfWidth = 0;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
lf.lfWeight = 400;
lf.lfItalic = FALSE;
lf.lfUnderline = FALSE;
lf.lfStrikeOut = FALSE;
lf.lfCharSet = ANSI_CHARSET;
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfQuality = DEFAULT_QUALITY;
lf.lfPitchAndFamily = VARIABLE_PITCH | FF_DONTCARE;
lstrcpy(lf.lfFaceName, TEXT("Arial"));
hfont = CreateFontIndirect(&lf);
pwindow->hbitmapText = CreateDIBSection(
pwindow->hdc, pbmi, DIB_PAL_COLORS,
(PVOID*)&(pwindow->pdataText), 0, 0);
pwindow->hdcText = CreateCompatibleDC(pwindow->hdcText);
SelectObject(pwindow->hdcText, pwindow->hbitmapText);
SelectObject(pwindow->hdcText, hfont);
return TRUE;
}
/****************************************************************************/
BOOL Init(
HWND hwnd)
{
int i;
RGBQUAD apal[256];
DWORD tid;
srand(GetTickCount());
adot = (PDOT) LocalAlloc(LPTR, sizeof(DOT) * NUMDOTS);
isin = (int *) LocalAlloc(LPTR, sizeof(int) * MAXANGLE);
icos = (int *) LocalAlloc(LPTR, sizeof(int) * MAXANGLE);
gpwindow = (PWINDOW) LocalAlloc(LPTR, sizeof(WINDOW));
if(adot == NULL || isin == NULL || icos == NULL || gpwindow == NULL)
return FALSE;
gpwindow->hwnd = hwnd;
gpwindow->xsize = gcxScreen;
gpwindow->ysize = gcyScreen;
gpwindow->hdc = ghdc;
SetBkColor(gpwindow->hdc, 0);
SetTextColor(gpwindow->hdc, RGB(0xff, 0xff, 0xff));
gpwindow->hWait = CreateEvent(NULL, FALSE, FALSE, NULL);
SetTimer(gpwindow->hwnd, 1, 1000 / 20, NULL);
for (i = 0; i < 236; i++) {
apal[i + 10].rgbRed = (i * 255) / 235;
apal[i + 10].rgbGreen = (i * 255) / 235;
apal[i + 10].rgbBlue = (i * 255) / 235;
}
if(!InitDibSection(gpwindow, apal, FALSE))
return FALSE;
CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE)BltThread,
gpwindow,
0,
&tid);
return TRUE;
}