// (c) Kankowski Peter, 2004-2005. kankowski@narod.ru
#include "tech.h"
#define WM_MOUSEWHEEL 0x20A
#define TIMER_ZOOMIN 100
#define TIMER_ZOOMOUT 101
LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);
HWND hWnd = NULL, hDlg = NULL, hToolbar = NULL;
const char classname[] = "kankowski_fractals";
WNDCLASS wc = {CS_HREDRAW|CS_VREDRAW |CS_DBLCLKS, (WNDPROC)WndProc, 0, 0,
NULL, NULL, NULL, NULL, NULL, classname};
WNDPROC OldProc; HACCEL hAccel;
BITMAPINFOHEADER bi = {sizeof(BITMAPINFOHEADER), 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0};
BITMAPINFOHEADER bis = {sizeof(BITMAPINFOHEADER), 0, 0, 1, 32, BI_RGB, 0, 0, 0, 0, 0};
HBITMAP hBMP, hsBMP;
long *bits=0, *sbits;
char buff[4096];
const double LEFTm = -2.375, RIGHTm = 0.775, TOPm = -1.1, BOTTOMm = 1.1;
const double LEFTj = -1.575, RIGHTj = 1.575, TOPj = -1.1, BOTTOMj = 1.1;
//const double LEFTm = -0.84, RIGHTm = -0.79, TOPm = 0.18, BOTTOMm = 0.21;
//const double LEFTj = -0.897, RIGHTj = -0.894, TOPj = 0.673, BOTTOMj = 0.675;
double LEFT = LEFTj, RIGHT = RIGHTj,
TOP = TOPj, BOTTOM = BOTTOMj;
#define zoomspeed 400
int SSEmode=1, SSEsupported=0, SSE2supported=0, ms=zoomspeed;
#define ITER 64
COLORREF a[ITER+1];
LARGE_INTEGER freq;
DWORD bz; RECT clientrect = {0, 0, 0, 0};
HBITMAP holdBMP; HDC hmem;
LPDIRECTDRAW DD = 0;
LPDIRECTDRAWSURFACE PrimarySurface = 0;
LPDIRECTDRAWSURFACE OffscreenSurface = 0;
LPDIRECTDRAWCLIPPER Clipper = 0;
WPARAM WindowActive;
int DDsupported = 1, DDmode = 1, movadd = 1;
typedef HRESULT (WINAPI *DIRECTDRAWCREATE)(GUID*, LPDIRECTDRAW*, IUnknown*);
HMODULE ddraw = 0;
struct MYRGNDATA {
RGNDATAHEADER rdh;
RECT r[4];
};
extern "C" void PaintJuliaMandelSSE(int w, int h, float dx, float dy, long* bits,
COLORREF* a, float left, float top, float px, float py, int piw,
int type, int bw);
extern "C" void PaintJuliaMandelSSE2(int w, int h, double dx, double dy, long* bits,
COLORREF* a, double left, double top, double px, double py, int piw,
int type, int bw);
extern "C" int IsSSE();
extern "C" int IsSSE2();
extern "C" int IsMovAdd();
#define ID_ARROW 100
#define ID_ZOOM 101
#define ID_PIP 102
#define ID_MANDEL 103
#define ID_JULIA 104
#define ID_BW 105
#define ID_AXIS 106
#define ID_SSE 107
#define ID_HOME 108
#define IDC_TOOLBAR 666
char* tooltips[] = {"Table and graph of iterates for the selected point (F2)",
"Zoom (F3)", "Picture in picture: correspondence between Mandelbrot and Julia sets (F4)",
"Mandelbrot set (Space to toggle)", "Julia set (Space to toggle)",
"Color on/off (F5)", "Axes on/off (F6)", "Drawing mode (F7)", "Back to initial size (F8)"};
ACCEL accel[] = {
{FNOINVERT | FVIRTKEY, VK_F2, ID_ARROW},
{FNOINVERT | FVIRTKEY, VK_F3, ID_ZOOM},
{FNOINVERT | FVIRTKEY, VK_F4, ID_PIP},
{FNOINVERT | FVIRTKEY, VK_F5, ID_BW},
{FNOINVERT | FVIRTKEY, VK_F6, ID_AXIS},
{FNOINVERT | FVIRTKEY, VK_F7, ID_SSE},
{FNOINVERT | FVIRTKEY, VK_F8, ID_HOME}
};
int mode=ID_ARROW, type=ID_JULIA, bw = 0, axis = 0, fired, oldtype, beep=0;
HMENU menu, popup;
double PX = -0.12, PY = 0.74, X0 = 0, Y0 = 0;
const TBBUTTON toolbar[] = {
{0, ID_ARROW, TBSTATE_ENABLED | TBSTATE_CHECKED, TBSTYLE_BUTTON, 0},
{1, ID_ZOOM, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0},
{2, ID_PIP, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0},
{-1, 0, 0, TBSTYLE_SEP, 0},
{3, ID_JULIA, TBSTATE_ENABLED | TBSTATE_CHECKED, TBSTYLE_BUTTON, 0},
{4, ID_MANDEL, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0},
{-1, 0, 0, TBSTYLE_SEP, 0},
{5, ID_BW, TBSTATE_ENABLED | TBSTATE_CHECKED, TBSTYLE_BUTTON, 0},
{6, ID_AXIS, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0},
{-1, 0, 0, TBSTYLE_SEP, 0},
{7, ID_SSE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0},
{8, ID_HOME, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0}
};
void PaintMandelbrotFPU(int w, int h, double dx, double dy, long* b, double left, double first, int piw) {
int x, y, i; double x2, y2, px, py, zx, zy;
py = first;
if(bw) {
for(y = 0; y < h; ++y) {
px = left;
for(x = 0; x < w; ++x) {
zx = px, zy = py;
for(i = 0; i < ITER; ++i) {
x2 = zx * zx, y2 = zy * zy;
if(x2 + y2 > 4.0) {
*b++ = 0x808080;
goto NEXT;
}
zy = zx * zy * 2 + py;
zx = x2 - y2 + px;
}
*b++ = 0;
NEXT: px += dx;
}
b += piw / 4;
py += dy;
}
}
else {
for(y = 0; y < h; ++y) {
px = left;
for(x = 0; x < w; ++x) {
zx = px, zy = py;
for(i = 0; i < ITER; ++i) {
x2 = zx * zx, y2 = zy * zy;
if(x2 + y2 > 4.0)
break;
zy = zx * zy * 2 + py;
zx = x2 - y2 + px;
}
*b++ = a[i];
px += dx;
}
b += piw / 4;
py += dy;
}
}
}
void PaintJuliaFPU(int w, int h, double dx, double dy, long* b, double left, double first, int piw) {
int x, y, i; double x2, y2, zx2, zy2, zx, zy;
zy2 = first;
if(bw) {
for(y = 0; y < h; ++y) {
zx2 = left;
for(x = 0; x < w; ++x) {
zx = zx2, zy = zy2;
for(i = 0; i < ITER; ++i) {
x2 = zx * zx, y2 = zy * zy;
if(x2 + y2 > 4.0) {
*b++ = 0x808080;
goto NEXT;
}
zy = zx * zy * 2 + PY;
zx = x2 - y2 + PX;
}
*b++ = 0;
NEXT: zx2 += dx;
}
b += piw / 4;
zy2 += dy;
}
}
else {
for(y = 0; y < h; ++y) {
zx2 = left;
for(x = 0; x < w; ++x) {
zx = zx2, zy = zy2;
for(i = 0; i < ITER; ++i) {
x2 = zx * zx, y2 = zy * zy;
if(x2 + y2 > 4.0)
break;
zy = zx * zy * 2 + PY;
zx = x2 - y2 + PX;
}
*b++ = a[i];
zx2 += dx;
}
b += piw / 4;
zy2 += dy;
}
}
}
double atod(char*& p) { // String to double
unsigned sign = 0, v; double d = 0.0, factor = 0.1; int exp = 0; char *a = p;
while(' ' == *a) // Skip leading spaces
a++;
if('+' == *a) a++;
if('-' == *a) a++, sign = 1;
while((v = *a - '0') <= 9) // Integer part
a++, d = 10.0 * d + v;
if('.' == *a || ',' == *a) { // Fractional part
a++;
while((v = *a - '0') <= 9)
a++, d += v * factor, factor *= 0.1;
}
if((*a & 0xDF) == 'E') { // Exponent
a++;
if('+' == *a) a++, factor = 10;
if('-' == *a) a++, factor = 0.1;
while((v = *a - '0') <= 9)
a++, exp = 10 * exp + v;
while(exp) {
if(exp & 1)
d *= factor;
exp >>= 1;
factor *= factor; // factor = factor ^ 2
}
}
p = a;
return sign ? -d : d;
}
void __forceinline atox(char* a, double& x, double&y) { // String to complex number
while(' ' == *a) // Skip spaces
a++;
if('i' == *a) { // i without number = 1 * i
y = 1, x = 0;
return;
}
x = atod(a); // Real part
while(' ' == *a) // Skip spaces
a++;
if('i' == *a) { // Imaginary part goes first
a++, y = x, x = atod(a);
if('i' == *a)
x = 0;
return;
}
y = atod(a); // Imaginary part
if('i' != *a)
y = 0;
}
double ceil(double x) {
__asm {
FLD x
FRNDINT
// FISTP QWORD PTR [TEMP]
// FILD QWORD PTR [TEMP]
}
}
unsigned inline dtou(double x) {
int y;
__asm {
FLD x
FISTP y
MOV eax, DWORD PTR y
}
}
int inline dtoi(double x) {
int y;
__asm {
FLD x
FISTP y
MOV eax, DWORD PTR y
}
}
void dtoa(double x, char*& a) { // Double to string
unsigned v, i; char *p = a;
if(x < 0)
x = -x, *p++ = '-';
v = dtou(x); // Get integer part to v
do {
*p++ = char('0' + (v % 10)); // Output integer part
v /= 10;
} while(v);
x = x - ceil(x); // Leave only fractional part
if(x) {
x *= 10;
*p++ = '.';
for(i = 7; i && x; i--)
v = dtou(x), *p++ = char('0' + v), x = x - ceil(x), x *= 10;
}
*p = '\0';
a = p;
}
char* xtoa(char* a, double x, double y) {
dtoa(x, a);
if(y >= 0)
*a++ = '+';
dtoa(y, a);
set2ch(a, 'i', '\0');
return a+1;
}
inline char* xxxtoa(int x, char* a) { // Iteration number
*a++ = 'Z';
if(x / 10) // If the is the second figure
*a++ = char(x / 10 + '0');
*a++ = char(x % 10 + '0'); // The first figure
*a++ = '=';
return a;
}
void EnableDisable(WPARAM id1, WPARAM id2, WPARAM id3) {
SendMessage(hToolbar, TB_SETSTATE, id1, TBSTATE_CHECKED | TBSTATE_ENABLED);
SendMessage(hToolbar, TB_SETSTATE, id2, TBSTATE_ENABLED);
SendMessage(hToolbar, TB_SETSTATE, id3, TBSTATE_ENABLED);
}
void CheckUncheck(int id1, int id2, int id3) {
CheckMenuItem(popup, id1, MF_BYCOMMAND | MF_CHECKED);
CheckMenuItem(popup, id2, MF_BYCOMMAND | MF_UNCHECKED);
CheckMenuItem(popup, id3, MF_BYCOMMAND | MF_UNCHECKED);
}
double flp2(double x) { // ��������� ���� �� ��������� ������� 2
unsigned a[2];
a[0] = *(unsigned*)&x;
a[1] = *((unsigned*)&x+1);
a[0] = 0;
a[1] &= 0xFFF00000;
return *(double*)a;
}
// From complex plane coordinates to screen coordinates
inline void plane2screen(double X, double Y, int& x, int& y, int right, int bottom) {
x = dtoi(((X - LEFT) * (double)right) / (RIGHT - LEFT));
y = dtoi(((Y - BOTTOM) * (double)bottom) / (TOP - BOTTOM));
}
inline void plane2screendx(double X, double Y, int& x, int& y, int right, int bottom) {
x = dtoi((X * (double)right) / (RIGHT - LEFT));
y = dtoi((Y * (double)bottom) / (TOP - BOTTOM));
}
inline void screen2plane(double& X, double& Y, int x, int y, int right, int bottom) {
X = x * (RIGHT - LEFT) / right + LEFT;
Y = y * (TOP - BOTTOM) / bottom + BOTTOM;
}
void SetZoomPos() {
char *a = buff;
set4ch(a, 'x',' ','f','r'); a+=4;
set4ch(a, 'o','m',' ',0); a+=3;
dtoa(LEFT, a);
set4ch(a,' ','t','o',' '); a+=4;
dtoa(RIGHT, a);
set2ch(a, 0x0D, 0x0A); a+=2;
set4ch(a,'y',' ','f','r'); a+=4;
set4ch(a,'o','m',' ',0); a+=3;
dtoa(TOP, a);
set4ch(a,' ','t','o',' '); a+=4;
dtoa(BOTTOM, a);
*a = '\0';
SendDlgItemMessage(hDlg, IDC_X1, WM_SETTEXT, 0, (LPARAM)buff);
}
void __forceinline DrawPolyline(HDC hdc, RECT r) {
int x, y, i; double ZX, ZY, X2, Y2, DX, DY;
plane2screen(X0, Y0, x, y, r.right, r.bottom);
char*p = xtoa(buff, X0, Y0);
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, RGB(0xFF, 0xFF, 0xFF));
TextOut(hdc, x, y, buff, p - buff);
MoveToEx(hdc, x, y, NULL);
//SetROP2(hdc, R2_NOT);
SelectObject(hdc, GetStockObject(WHITE_PEN));
p = buff;
if(ID_JULIA == type)
ZX = X0, ZY = Y0, DX = PX, DY = PY;
else // ID_MANDEL
ZX = 0, ZY = 0, DX = X0, DY = Y0;
for(i = 0; i < ITER; ++i) {
X2 = ZX * ZX, Y2 = ZY * ZY;
if(X2 + Y2 > 4.0)
goto STOP;
ZY = ZX * ZY * 2 + DY;
ZX = X2 - Y2 + DX;
plane2screen(ZX, ZY, x, y, r.right, r.bottom);
LineTo(hdc, x, y);
if(i < 13) {
p = xxxtoa(i + 1, p);
p = xtoa(p, ZX, ZY);
*(short*)p = 0x0A0D;
p+=2;
}
}
set4ch(p,'.','.','.',0xD); p+=4;
*p++ = 0xA;
p = xxxtoa(ITER, p);
p = xtoa(p, ZX, ZY);
STOP:
*p = '\0';
SendDlgItemMessage(hDlg, IDC_X1, WM_SETTEXT, 0, (LPARAM)buff);
}
void __forceinline DrawAxis(HDC hmem, RECT r) {
int x, y, dx, dy, xorigin, yorigin;
double X, Y, DX, DY;
// Get screen coordinates of the origin
plane2screen(0, 0, xorigin, yorigin, r.right, r.bottom);
SetTextColor(hmem, RGB(0, 0xFF, 0));
SetBkMode(hmem, TRANSPARENT);
HPEN hPen = CreatePen(PS_SOLID, 0, RGB(0, 0xFF, 0));
HPEN hOldPen = (HPEN) SelectObject(hmem, hPen);
// Draw axis
MoveToEx(hmem, xorigin, 0, NULL);
LineTo(hmem, xorigin, r.bottom);
MoveToEx(hmem, 0, yorigin, NULL);
LineTo(hmem, r.right, yorigin);
// Draw numbers
DX = flp2(RIGHT - LEFT) / 4;
DY = flp2(BOTTOM - TOP) / 4;
X = ceil(LEFT / DX) * DX;
Y = ceil(BOTTOM / DY) * DY;
plane2screendx(DX, DY, dx, dy, r.right, r.bottom);
plane2screen ( X, Y, x, y, r.right, r.bottom);
SIZE size;
for(; x < r.right; x += dx, X += DX) {
char* p = buff;
dtoa(X, p);
if(X) {
GetTextExtentPoint(hmem, buff, p - buff, &size);
MoveToEx(hmem, x, yorigin-1, NULL);
LineTo(hmem, x, yorigin+2);
TextOut(hmem, x - size.cx / 2, yorigin, buff, p - buff);
}
}
size.cy /= 2;
for(; y < r.bottom; y -= dy, Y -= DY) {
char* p = buff;
dtoa(Y, p);
MoveToEx(hmem, xorigin-1, y, NULL);
LineTo(hmem, xorigin+2, y);
TextOut(hmem, xorigin + 4, y - size.cy, buff, p - buff);
}
SelectObject(hmem, hOldPen);
DeleteObject(hPen);
}
void __forceinline DrawOrangePoint(HDC hdc, RECT r) {
int x,y;
SelectObject(hdc, GetStockObject(WHITE_PEN));
HBRUSH brush = CreateSolidBrush(RGB(0xFF, 0xA5, 0x00));
HBRUSH oldbrush = (HBRUSH) SelectObject(hdc, brush);
plane2screen(PX, PY, x, y, r.right, r.bottom);
Ellipse(hdc, x - 3, y - 3, x + 3, y + 3);
SelectObject(hdc, oldbrush);
DeleteObject(brush);
}
void ReDraw() {
LARGE_INTEGER t, t2; int w, h, piw; long* b; HDC hdc; double dx, dy, first;
#ifdef FPSdisplay
__asm{
XOR eax, eax
CPUID
RDTSC
MOV bz, eax
}
#endif
if(DDmode) {
DDSURFACEDESC sdesc;
sdesc.dwSize = sizeof sdesc;
if(DD_OK != OffscreenSurface->Lock(NULL, &sdesc, DDLOCK_WAIT | DDLOCK_NOSYSLOCK |
DDLOCK_WRITEONLY | DDLOCK_SURFACEMEMORYPTR, NULL)) {
DDmode = DDsupported = 0;
return;
}
assert(sdesc.ddpfPixelFormat.dwFlags | DDPF_RGB);
assert(sdesc.ddpfPixelFormat.dwRGBBitCount == 32);
w = sdesc.dwWidth, h = sdesc.dwHeight;
b = (long*)sdesc.lpSurface;
piw = sdesc.lPitch - sdesc.dwWidth * 4;
dx = (RIGHT - LEFT) / w;
dy = (TOP - BOTTOM) / h;
first = BOTTOM;
}
else { // GDI
w = ceil(clientrect.right, 4), h = clientrect.bottom,
b = ceil(bits, 16), piw = 0,
dx = (RIGHT - LEFT) / w,
dy = (BOTTOM - TOP) / h,
first = TOP;
if(!w || !h)
return;
}
QueryPerformanceCounter(&t);
if(SSEmode == 1)
PaintJuliaMandelSSE(w, h, float(dx), float(dy), b, a, float(LEFT), float(first),
float(PX), float(PY), piw, type - ID_MANDEL, bw);
else if(SSEmode == 2)
PaintJuliaMandelSSE2(w, h, dx, dy, b, a, LEFT, first,
PX, PY, piw, type - ID_MANDEL, bw);
else {
if(ID_JULIA == type)
PaintJuliaFPU(w, h, dx, dy, b, LEFT, first, piw);
else
PaintMandelbrotFPU(w, h, dx, dy, b, LEFT, first, piw);
}
if(QueryPerformanceCounter(&t2)) {
ms = int(((t2.QuadPart - t.QuadPart) * 1000) / freq.QuadPart) / 4;
}
if(DDmode) {
OffscreenSurface->Unlock(NULL);
OffscreenSurface->GetDC(&hdc);
}
else {
SetDIBits(hmem, hBMP, 0, clientrect.bottom, b,
(BITMAPINFO*)&bi, DIB_RGB_COLORS);
hdc = hmem;
}
if(axis)
DrawAxis(hdc, clientrect);
if(ID_MANDEL == type) // Orange point
DrawOrangePoint(hdc, clientrect);
if(DDmode)
OffscreenSurface->ReleaseDC(hdc);
#ifdef FPSdisplay
__asm{
XOR eax, eax
CPUID
RDTSC
SUB eax, bz
MOV bz, eax
}
#endif
if(mode == ID_ZOOM)
SetZoomPos();
}
void SetModes() {
TCHAR *p = buff;
set4ch(p, 'F','r','a','c'); p += 4;
set4ch(p, 't','a','l','s'); p += 4;
set4ch(p, ' ','(','\0','\0'); p += 2;
if(!SSEmode) {
set4ch(p, 'F','P','U',','); p += 4; }
else {
if(SSEmode == 1) {
set4ch(p, 'S','S','E',','); p += 4; }
else if(SSEmode == 2) {
set4ch(p, 'S','S','E','2'); p += 4;
*p++ = ','; }
if(movadd) {
set4ch(p, 'M','o','v','A'); p += 4;
set4ch(p, 'd','d',',','\0'); p += 3; }
else {
set4ch(p, 'V','o','d',','); p += 4; }
}
if(DDmode) {
set4ch(p, 'D','i','r','e'); p += 4;
set4ch(p, 'c','t','D','r'); p += 4;
set4ch(p, 'a','w',')','\0'); p += 3; }
else {
set4ch(p, 'G','D','I',')'); p += 4;
*p = '\0'; }
SetWindowText(hWnd, buff);
}
LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) {
PAINTSTRUCT ps; HDC hdc; double a;
#ifdef FPSdisplay
DWORD b2;
#endif
switch (msg) {
case WM_CREATE: {
menu = LoadMenu(wc.hInstance, (LPCSTR)IDR_MENU);
popup = GetSubMenu(menu, 0);
ddraw = LoadLibrary(TEXT("ddraw.dll"));
const short cw = 0xF7F; const unsigned mxcsr = 0x9F80;
SSEsupported = IsSSE();
if(SSEsupported) {
__asm {
LDMXCSR mxcsr ; set Flush-To-Zero mode
}
movadd = IsMovAdd();
SSE2supported = IsSSE2();
if(!SSE2supported)
EnableMenuItem(popup, ID_C_SSE2, MF_BYCOMMAND | MF_GRAYED);
}
else {
SSEmode = 0;
EnableMenuItem(popup, ID_C_SSE, MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem(popup, ID_C_SSE2, MF_BYCOMMAND | MF_GRAYED);
CheckUncheck(ID_C_FPU, ID_C_SSE, ID_C_SSE2);
}
__asm {
FLDCW cw ; set rounding mode toward zero (truncate)
}
DIRECTDRAWCREATE directdrawcreate =
(DIRECTDRAWCREATE)GetProcAddress(ddraw, TEXT("DirectDrawCreate"));
if(!directdrawcreate) {
DDERR: DDsupported = DDmode = 0;
EnableMenuItem(popup, ID_C_DIRECTDRAW, MF_BYCOMMAND | MF_GRAYED);
CheckMenuItem(popup, ID_C_DIRECTDRAW, MF_BYCOMMAND | MF_UNCHECKED);
return 0;
}
if(DD_OK != directdrawcreate(NULL, &DD, NULL)) goto DDERR;
DD->SetCooperativeLevel(hWnd, DDSCL_NORMAL | DDSCL_FPUSETUP);
DDSURFACEDESC sdesc;
sdesc.dwSize = sizeof sdesc;
sdesc.dwFlags = DDSD_CAPS;
sdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
if(DD_OK != DD->CreateSurface(&sdesc, &PrimarySurface, NULL)) goto DDERR;
sdesc.ddpfPixelFormat.dwSize = sizeof sdesc.ddpfPixelFormat;
if(DD_OK != PrimarySurface->GetPixelFormat(&sdesc.ddpfPixelFormat)) goto DDERR;
if((sdesc.ddpfPixelFormat.dwFlags & DDPF_RGB) == 0 ||
sdesc.ddpfPixelFormat.dwRGBBitCount != 32) goto DDERR;
if(DD_OK != DD->CreateClipper(0, &Clipper, NULL)) goto DDERR;
if(DD_OK != Clipper->SetHWnd(0, hWnd)) goto DDERR;
return 0;
}
case WM_DESTROY:
if(Clipper)
Clipper->Release();
if(PrimarySurface)
PrimarySurface->Release();
if(OffscreenSurface)
OffscreenSurface->Release();
if(DD)
DD->Release();
free(bits);
SelectObject(hmem, holdBMP);
DeleteDC(hmem);
DeleteObject(hBMP);
FreeLibrary(ddraw);
DestroyMenu(menu);
DestroyAcceleratorTable(hAccel);
PostQuitMessage(0);
return 0;
case WM_ACTIVATEAPP:
WindowActive = wParam;
return 0;
case WM_SIZE:
if(DDmode) {
if(LOWORD(lParam) == 0 || HIWORD(lParam) == 0)
return 0;
clientrect.right = LOWORD(lParam), clientrect.bottom = HIWORD(lParam);
if(OffscreenSurface) {
OffscreenSurface->Release();
OffscreenSurface = NULL;
}
DDSURFACEDESC sdesc;
sdesc.dwSize = sizeof sdesc;
sdesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
sdesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
sdesc.dwWidth = ceil(clientrect.right, 4), sdesc.dwHeight = clientrect.bottom;
if(DD_OK != DD->CreateSurface(&sdesc, &OffscreenSurface, NULL)) goto DDERR;
if(DD_OK != PrimarySurface->SetClipper(Clipper)) goto DDERR;
}
else {
hdc = GetDC(hWnd);
if(hBMP) {
SelectObject(hmem, holdBMP);
DeleteObject(hBMP);
DeleteDC(hmem);
}
hBMP = CreateCompatibleBitmap(hdc, ceil(LOWORD(lParam),4), HIWORD(lParam));
bi.biWidth = ceil(LOWORD(lParam),4), bi.biHeight = HIWORD(lParam),
bi.biSizeImage = bi.biWidth * bi.biHeight * 4;
// bi.biBitCount = GetDeviceCaps(hdc, BITSPIXEL);
bits = (long*)realloc(bits, bi.biSizeImage + 16 * 3);
hmem = CreateCompatibleDC(hdc);
holdBMP = (HBITMAP) SelectObject(hmem, hBMP);
ReleaseDC(hWnd, hdc);
}
clientrect.right = LOWORD(lParam), clientrect.bottom = HIWORD(lParam);
ReDraw();
return 0;
case WM_PAINT:
#ifdef FPSdisplay
__asm{
XOR eax, eax
CPUID
RDTSC
MOV b2, eax
}
#endif
if(DDmode) {
RECT r = {0, 0, clientrect.right, clientrect.bottom};
ClientToScreen(hWnd, (LPPOINT)&r);
r.right += r.left, r.bottom += r.top;
for(;;) {
if(DDERR_SURFACELOST != PrimarySurface->Blt(&r, OffscreenSurface,
NULL, DDBLT_WAIT, 0))
break;
if(DD_OK != PrimarySurface->Restore())
break;
ReDraw();
}
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
}
else {
hdc = BeginPaint(hWnd, &ps);
BitBlt(hdc, 0, 0, clientrect.right, clientrect.bottom, hmem, 0, 0, SRCCOPY);
}
#ifdef FPSdisplay
__asm{
XOR eax, eax
CPUID
RDTSC
SUB eax, b2
MOV b2, eax
}
b2 = wsprintf(buff, "%10d %10d %10d ms", bz, b2, ms);
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, RGB(0xFF, 0xFF, 0xFF));
TextOut(hdc, 0, 0, buff, b2);
#endif
if(ID_ARROW == mode) // Draw polyline
DrawPolyline(hdc, clientrect);
EndPaint(hWnd, &ps);
return 0;
case WM_KEYUP:
switch(wParam) {
case VK_PRIOR:
a = (TOP - BOTTOM); TOP -= a, BOTTOM -= a;
goto REDRAW;
case VK_NEXT:
a = (TOP - BOTTOM); TOP += a, BOTTOM += a;
goto REDRAW;
case VK_HOME:
a = (RIGHT - LEFT); LEFT -= a, RIGHT -= a;
goto REDRAW;
case VK_END:
a = (RIGHT - LEFT); LEFT += a, RIGHT += a;
goto REDRAW;
case VK_UP:
a = (TOP - BOTTOM)/16; TOP -= a, BOTTOM -= a;
goto REDRAW;
case VK_DOWN:
a = (TOP - BOTTOM)/16; TOP += a, BOTTOM += a;
goto REDRAW;
case VK_LEFT:
a = (RIGHT - LEFT)/16; LEFT -= a, RIGHT -= a;
goto REDRAW;
case VK_RIGHT:
a = (RIGHT - LEFT)/16; LEFT += a, RIGHT += a;
goto REDRAW;
case VK_RETURN: // Enter
ShowWindow(hDlg, SW_SHOW);
SetFocus(hDlg);
break;
case VK_SPACE: {
if(mode == ID_PIP)
break;
oldtype = type;
type = type == ID_MANDEL ? ID_JULIA : ID_MANDEL;
if(ID_MANDEL == type)
LEFT = LEFTm, RIGHT = RIGHTm, TOP = TOPm, BOTTOM = BOTTOMm;
else
LEFT = LEFTj, RIGHT = RIGHTj, TOP = TOPj, BOTTOM = BOTTOMj;
EnableDisable(type, oldtype, oldtype);
ReDraw();
InvalidateRect(hWnd, NULL, FALSE);
break;
}
}
return 0;
case WM_CHAR:
if(wParam == 27) SendMessage(hWnd,WM_CLOSE,0,0);
else if(wParam == '+') {
a = (TOP - BOTTOM) / 3;
TOP -= a, BOTTOM += a;
a = (RIGHT - LEFT) / 3;
RIGHT -= a, LEFT += a;
goto REDRAW;
}
else if(wParam == '-') {
if(RIGHT - LEFT > 2.0) {
if(beep < 2)
Beep(0x100, 100);
beep++;
return 0;
}
beep = 0;
a = (TOP - BOTTOM);
TOP += a, BOTTOM -= a;
a = (RIGHT - LEFT);
RIGHT += a, LEFT -= a;
REDRAW: ReDraw();
InvalidateRect(hWnd, NULL, FALSE);
}
return 0;
case WM_MOUSEWHEEL:
a = ((TOP - BOTTOM)/8) * double((signed short)HIWORD(wParam) / 120);
TOP -= a, BOTTOM -= a;
ReDraw();
InvalidateRect(hWnd, NULL, FALSE);
return 0;
case WM_MOUSEMOVE:
if(0 == (wParam & MK_LBUTTON) || ID_ARROW != mode)
return 0;
case WM_LBUTTONDOWN:
if(ID_ARROW == mode) {
screen2plane(X0, Y0, LOWORD(lParam), HIWORD(lParam), clientrect.right, clientrect.bottom);
InvalidateRect(hWnd, NULL, FALSE);
return 0;
}
else {// if ID_ZOOM
fired = 0;
SetTimer(hWnd, TIMER_ZOOMIN, ms, NULL);
}
return 0;
case WM_RBUTTONDOWN: {
if (ID_ARROW == mode) {
if(type == ID_MANDEL) { // Switch to Julia
screen2plane(PX, PY, LOWORD(lParam), HIWORD(lParam), clientrect.right, clientrect.bottom);
type = ID_JULIA;
X0 = PX, Y0 = PY;
xtoa(buff, PX, PY);
SendDlgItemMessage(hDlg, IDC_C, WM_SETTEXT, 0, (LPARAM)buff);
EnableDisable(ID_JULIA, ID_MANDEL, ID_MANDEL);
ReDraw();
InvalidateRect(hWnd, NULL, FALSE);
}
else { // if ID_JULIA
type = ID_MANDEL;
X0 = PX, Y0 = PY;
EnableDisable(ID_MANDEL, ID_JULIA, ID_JULIA);
ReDraw();
InvalidateRect(hWnd, NULL, FALSE);
}
}
else {
fired = 0;
SetTimer(hWnd, TIMER_ZOOMOUT, ms, NULL);
}
return 0;
}
case WM_TIMER: {
TIMER: POINT p; GetCursorPos(&p);
ScreenToClient(hWnd, &p);
double X, Y, scale;
screen2plane(X, Y, p.x, p.y, clientrect.right, clientrect.bottom);
if(wParam == TIMER_ZOOMIN) {
scale = zoomspeed / double(ms + zoomspeed);
if(scale >= 1)
scale = 0.9;
}
else {
if(RIGHT - LEFT > 2.0)
return 0;
scale = double(ms + zoomspeed) / zoomspeed;
if(scale <= 1)
scale = 1.1;
}
a = (BOTTOM - TOP) * scale;
TOP = Y - (Y - TOP)* scale, BOTTOM = TOP + a;
a = (RIGHT - LEFT) * scale;
LEFT = X - (X - LEFT) * scale, RIGHT = LEFT + a;
ReDraw();
InvalidateRect(hWnd, NULL, FALSE);
if(fired)
SetTimer(hWnd, wParam, ms, NULL);
fired = 1;
return 0;
}
case WM_LBUTTONUP:
if(ID_ARROW != mode) {
KillTimer(hWnd, TIMER_ZOOMIN);
if(!fired) {
wParam = TIMER_ZOOMIN;
goto TIMER;
}
}
return 0;
case WM_RBUTTONUP:
if(ID_ARROW != mode) {
KillTimer(hWnd, TIMER_ZOOMOUT);
if(!fired) {
wParam = TIMER_ZOOMOUT;
goto TIMER;
}
}
return 0;
case WM_SETCURSOR:
if(mode != ID_ARROW) {
POINT pt; GetCursorPos(&pt);
RECT r = clientrect;
ClientToScreen(hWnd, (LPPOINT)&r);
ClientToScreen(hWnd, (LPPOINT)&r.right);
if(!PtInRect(&r, pt))
return DefWindowProc(hWnd,msg,wParam,lParam);
SetCursor(LoadCursor(wc.hInstance, (LPCSTR)IDC_ZOOM));
return 0;
}
default:
return DefWindowProc(hWnd,msg,wParam,lParam);
}
}
LRESULT APIENTRY SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (uMsg == WM_KEYUP) {
switch(wParam) {
case VK_ESCAPE:
SendMessage(hDlg, WM_CLOSE, 0, 0);
SetFocus(hWnd);
return 0;
case VK_RETURN:
SetFocus(hWnd);
return 0;
}
}
return CallWindowProc(OldProc, hwnd, uMsg, wParam, lParam);
}
void RecoverPiP() {
if(mode == ID_PIP) {
SendMessage(hToolbar, TB_SETSTATE, ID_JULIA, oldtype == ID_JULIA ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED);
SendMessage(hToolbar, TB_SETSTATE, ID_MANDEL, oldtype == ID_MANDEL ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED);
if(type != oldtype) {
type = oldtype;
ReDraw();
InvalidateRect(hWnd, NULL, FALSE);
}
}
}
const char* strings[] = {"0.1+0.7i (Fatu's dust)", "-0.74543+0.11301i (sea-horse)",
"-0.74543-0.11301i (sea-horse)", "-0.481762+0.531657i (\"comb\")",
"-0.123175+0.56508i (deformed circle)", "-0.12+0.74i (Duadi's rabbit)",
"-0.15652-1.03225i (\"nucleus of a cell\")", "-0.194+0.6557i (\"rivers and lakes\")",
"0.3325+0.5753176i (tree)", "-0.6203+0.416i (\"exotic flower\")",
"-1.7568+0.0065i (\"constellation\")", "-1.1416+0.2434i (\"rabbits\")",
"0.2617+0.0014i (\"helix\")", "0.3760+0.1481i (\"palm\")",
"-0.7725+0.0014i (\"potatoes\")", "0.40566+0.33679i (\"mandagora\")",
"-0.3737+0.6597i (\"crab claws\")", "-0.3559+0.6577i (\"swirl\")"
};
const double left = -2.0, right = 0.5, top = -1.0, bottom = 1.0;
BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_INITDIALOG: {
HWND hC = GetDlgItem(hDlg, IDC_C);
POINT p = {5, 5};
hC = ChildWindowFromPoint(hC, p);
OldProc = (WNDPROC) SetWindowLong(hC,
GWL_WNDPROC, (LONG)SubclassProc); // Subclassing
hToolbar = CreateToolbarEx(hDlg, WS_CHILD | CCS_TOP | TBSTYLE_TOOLTIPS | WS_VISIBLE,
IDC_TOOLBAR, 12, wc.hInstance, IDR_TOOLBAR, &toolbar[0],
sizeof(toolbar) / sizeof(TBBUTTON), 16, 16, 16, 16, sizeof(TBBUTTON));
SendMessage(hToolbar, TB_SETSTATE, ID_ARROW,
TBSTATE_CHECKED | TBSTATE_ENABLED);
SendMessage(hToolbar, TB_SETSTATE, ID_JULIA,
TBSTATE_CHECKED | TBSTATE_ENABLED);
for(int i = 0; i < sizeof(strings) / sizeof(char*); ++i)
SendDlgItemMessage(hDlg, IDC_C, CB_ADDSTRING, 0, (LPARAM)strings[i]);
SendDlgItemMessage(hDlg, IDC_C, CB_SETCURSEL, 1, 0);
HWND hswnd = GetDlgItem(hDlg, IDC_X1);
HDC hdc = GetDC(hswnd); // Create bitmap for the small picture of the Mandelbrot set
RECT r; GetClientRect(hswnd, &r);
hsBMP = CreateCompatibleBitmap(hdc, r.right, r.bottom);
bis.biWidth = r.right, bis.biHeight = r.bottom;
bis.biSizeImage = r.right * r.bottom * 4;
// bi.biBitCount = GetDeviceCaps(hdc, BITSPIXEL);
sbits = (long*) malloc(bis.biSizeImage + 16 * 3);
const double left = -2.0, right = 0.5, top = -1.0, bottom = 1.0;
double DX = (right - left) / r.right;
double DY = (bottom - top) / r.bottom;
PaintMandelbrotFPU(r.right, r.bottom, DX, DY, ceil(sbits, 16), left, top, 0);
SetDIBits(hdc, hsBMP, 0, r.bottom, ceil(sbits, 16),
(BITMAPINFO*)&bis, DIB_RGB_COLORS);
ReleaseDC(hswnd, hdc);
return TRUE;
}
case WM_DESTROY: {
HWND hC = GetDlgItem(hDlg, IDC_C);
POINT p = {5, 5};
hC = ChildWindowFromPoint(hC, p);
SetWindowLong(hC, GWL_WNDPROC, (LONG)OldProc);
free(sbits);
DeleteObject(hsBMP);
return TRUE;
}
case WM_CLOSE:
ShowWindow(hDlg, SW_HIDE);
return TRUE;
case WM_SETCURSOR:
if(mode != ID_PIP)
break;
RECT r;
POINT pt; GetCursorPos(&pt);
GetWindowRect(GetDlgItem(hDlg, IDC_X1), &r); // Absolute coordinates to client
if(!PtInRect(&r, pt))
break;
SetCursor(LoadCursor(NULL, IDC_CROSS));
return TRUE;
case WM_PAINT: // The small picture of the Mandelbrot set
if(mode == ID_PIP) {
PAINTSTRUCT ps; RECT r;
HWND hw = GetDlgItem(hDlg, IDC_X1);
HDC hdc = BeginPaint(hw, &ps);
GetClientRect(hw, &r);
SelectClipRgn(hdc, CreateRectRgn(r.left, r.top, r.right, r.bottom));
HDC hmem = CreateCompatibleDC(hdc);
HBITMAP holdBMP = (HBITMAP) SelectObject(hmem, hsBMP);
BitBlt(hdc, 0, 0, r.right, r.bottom, hmem, 0, 0, SRCCOPY);
// Orange point
int x,y;
SelectObject(hdc, GetStockObject(WHITE_PEN));
HBRUSH brush = CreateSolidBrush(RGB(0xFF, 0xA5, 0x00));
HBRUSH oldbrush = (HBRUSH) SelectObject(hdc, brush);
x = dtoi(((PX - left) * double(r.right)) / (right - left)); // From complex plane coordinates to screen coordinates
y = dtoi(((PY - bottom) * double(r.bottom)) / (top - bottom));
Ellipse(hdc, x - 2, y - 2, x + 2, y + 2);
// Destroying objects
SelectObject(hdc, oldbrush);
DeleteObject(brush);
SelectObject(hmem, holdBMP);
EndPaint(hWnd, &ps);
DeleteDC(hmem);
}
break;
case WM_MOUSEMOVE:
if(0 == (wParam & MK_LBUTTON))
break;
case WM_LBUTTONUP: // Clicking the small picture
if(mode == ID_PIP) {
RECT r;
POINT pt; GetCursorPos(&pt);
GetWindowRect(GetDlgItem(hDlg, IDC_X1), &r); // Absolute coordinates to client coordinates
if(!PtInRect(&r, pt))
break;
r.right -= r.left;
r.bottom -= r.top;
PX = double(pt.x - r.left) * (right - left) / r.right + left;
PY = double(pt.y - r.top) * (top - bottom) / r.bottom + bottom;
xtoa(buff, PX, PY);
SendDlgItemMessage(hDlg, IDC_C, WM_SETTEXT, 0, (LPARAM)buff);
ReDraw();
InvalidateRect(hWnd, NULL, FALSE);
InvalidateRect(hDlg, NULL, FALSE);
}
break;
case WM_NOTIFY:
if( ((NMHDR *)lParam) ->code == TTN_NEEDTEXT )
((TOOLTIPTEXT *)lParam) ->lpszText = tooltips[((NMHDR *)lParam) ->idFrom - ID_ARROW];
break;
case WM_COMMAND:
switch (wParam) {
case MAKEWPARAM(IDC_C, CBN_EDITCHANGE):
SendDlgItemMessage(hDlg, IDC_C, WM_GETTEXT, sizeof(buff), (LPARAM)buff);
goto SK;
case MAKEWPARAM(IDC_C, CBN_SELENDOK):
SendDlgItemMessage(hDlg, IDC_C, CB_GETLBTEXT,
SendDlgItemMessage(hDlg, IDC_C, CB_GETCURSEL, 0, 0), (LPARAM)buff);
SK: atox(buff, PX, PY);
if(type == ID_MANDEL)
X0 = PX, Y0 = PY;
ReDraw();
InvalidateRect(hWnd, NULL, FALSE);
InvalidateRect(hDlg, NULL, FALSE);
return FALSE;
}
switch(LOWORD(wParam)) {
case ID_MANDEL:
EnableDisable(ID_MANDEL, ID_JULIA, ID_JULIA);
//ShowWindow(GetDlgItem(hDlg, IDC_C), SW_HIDE);
//ShowWindow(GetDlgItem(hDlg, IDC_CSTATIC), SW_HIDE);
LEFT = LEFTm, RIGHT = RIGHTm, TOP = TOPm, BOTTOM = BOTTOMm;
goto REDRAW;
case ID_JULIA:
EnableDisable(ID_JULIA, ID_MANDEL, ID_MANDEL);
LEFT = LEFTj, RIGHT = RIGHTj, TOP = TOPj, BOTTOM = BOTTOMj;
//ShowWindow(GetDlgItem(hDlg, IDC_C), SW_SHOW);
//ShowWindow(GetDlgItem(hDlg, IDC_CSTATIC), SW_SHOW);
REDRAW: type = LOWORD(wParam);
ReDraw();
InvalidateRect(hWnd, NULL, FALSE);
break;
case ID_ARROW:
RecoverPiP();
mode = ID_ARROW;
EnableDisable(ID_ARROW, ID_ZOOM, ID_PIP);
InvalidateRect(hWnd, NULL, FALSE);
break;
case ID_ZOOM:
RecoverPiP();
mode = ID_ZOOM;
EnableDisable(ID_ZOOM, ID_ARROW, ID_PIP);
InvalidateRect(hWnd, NULL, FALSE);
SetZoomPos();
break;
case ID_PIP:
mode = ID_PIP;
SendMessage(hToolbar, TB_SETSTATE, ID_JULIA, type == ID_JULIA ? TBSTATE_CHECKED : 0);
SendMessage(hToolbar, TB_SETSTATE, ID_MANDEL, type == ID_MANDEL ? TBSTATE_CHECKED : 0);
oldtype = type, type = ID_JULIA;
EnableDisable(ID_PIP, ID_ARROW, ID_ZOOM);
LEFT = LEFTj, RIGHT = RIGHTj, TOP = TOPj, BOTTOM = BOTTOMj;
ReDraw();
InvalidateRect(hWnd, NULL, FALSE);
InvalidateRect(hDlg, NULL, FALSE);
break;
case ID_BW: {
bw = !bw;
SendMessage(hToolbar, TB_SETSTATE, ID_BW, bw ? TBSTATE_ENABLED : TBSTATE_CHECKED | TBSTATE_ENABLED);
ReDraw();
InvalidateRect(hWnd, NULL, FALSE);
// Redraw the small picture
HWND hswnd = GetDlgItem(hDlg, IDC_X1);
HDC hdc = GetDC(hswnd);
RECT r; GetClientRect(hswnd, &r);
const double left = -2.0, right = 0.5, top = -1.0, bottom = 1.0;
double DX = (right - left) / r.right;
double DY = (bottom - top) / r.bottom;
PaintMandelbrotFPU(r.right, r.bottom, DX, DY, ceil(sbits, 16), left, top, 0);
bis.biWidth = r.right, bis.biHeight = r.bottom;
SetDIBits(hdc, hsBMP, 0, r.bottom, ceil(sbits,16),
(BITMAPINFO*)&bis, DIB_RGB_COLORS);
ReleaseDC(hswnd, hdc);
InvalidateRect(hDlg, NULL, FALSE);
break;
}
case ID_AXIS:
axis = !axis;
SendMessage(hToolbar, TB_SETSTATE, ID_AXIS, axis ?
TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED);
ReDraw();
InvalidateRect(hWnd, NULL, FALSE);
break;
case ID_HOME:
if(type == ID_MANDEL)
LEFT = LEFTm, RIGHT = RIGHTm, TOP = TOPm, BOTTOM = BOTTOMm;
else
LEFT = LEFTj, RIGHT = RIGHTj, TOP = TOPj, BOTTOM = BOTTOMj;
ReDraw();
InvalidateRect(hWnd, NULL, FALSE);
break;
case ID_SSE: {
RECT r; SendMessage(hToolbar, TB_GETITEMRECT, 10, (LPARAM)&r);
ClientToScreen(hDlg, (LPPOINT)&r.right);
r.bottom += GetSystemMetrics(SM_CYEDGE);
TrackPopupMenu(popup, TPM_RIGHTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
r.right, r.bottom, 0, hDlg, NULL);
break;
}
case ID_C_DIRECTDRAW:
if(DDsupported) {
DDmode = !DDmode;
CheckMenuItem(popup, ID_C_DIRECTDRAW,
DDmode ? (MF_BYCOMMAND | MF_CHECKED) : (MF_BYCOMMAND | MF_UNCHECKED));
SendMessage(hWnd, WM_SIZE, SIZE_RESTORED,
MAKELPARAM(clientrect.right, clientrect.bottom));
InvalidateRect(hWnd, NULL, FALSE);
SetModes();
}
break;
case ID_C_FPU:
SSEmode = 0;
CheckUncheck(ID_C_FPU, ID_C_SSE, ID_C_SSE2);
goto SSEM;
case ID_C_SSE:
if(SSEsupported) {
SSEmode = 1;
CheckUncheck(ID_C_SSE, ID_C_FPU, ID_C_SSE2);
SSEM: ReDraw();
InvalidateRect(hWnd, NULL, FALSE);
SetModes();
}
break;
case ID_C_SSE2:
if(SSE2supported) {
SSEmode = 2;
CheckUncheck(ID_C_SSE2, ID_C_FPU, ID_C_SSE);
goto SSEM;
}
break;
}
}
return FALSE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow) {
hInstance; hPrevInstance; nCmdShow; lpCmdLine;
MSG msg;
InitCommonControls();
_CrtSetDbgFlag( // Locating memory leaks and GPFs
_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) |
_CRTDBG_CHECK_ALWAYS_DF |
_CRTDBG_LEAK_CHECK_DF
);
//heap = GetProcessHeap();
GetSystemInfo(&si);
QueryPerformanceFrequency(&freq);
int addR = 3 << 16, addG = 4 << 8, addB = -2, r = 50 << 16, g = 50 << 8, b = 50;
for(unsigned i=0; i < ITER; ++i) {
a[i] = r | g | b;
r += addR, g += addG, b += addB;
if (r < 0)
addR = -addR, r = -r;
else if (r > (0xF0 << 16))
addR = -addR, r += addR;
if (g < 0)
addG = -addG, g = -g;
else if (g > (0xF0 << 8))
addG = -addG, g += addG;
if (b < 0)
addB = -addB, b = -b;
else if (b > 0xF0)
addB = -addB, b += addB;
}
a[ITER] = 0;
wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = LoadIcon(wc.hInstance,(LPCSTR)IDI_FRACTALS);
if(!RegisterClass(&wc))
return 0;
hWnd = CreateWindow(classname, "Fractals", WS_OVERLAPPEDWINDOW | WS_MAXIMIZE,
CW_USEDEFAULT,0,455,195,
NULL, NULL, wc.hInstance, NULL);
SetModes();
hDlg = CreateDialogParam(wc.hInstance, MAKEINTRESOURCE(IDD_PARAMS),
hWnd, DlgProc, 0);
hAccel = CreateAcceleratorTable(accel, sizeof(accel) / sizeof(ACCEL));
// Set Options dialog position
RECT rwnd, rdlg;
GetWindowRect(hDlg, &rdlg);
GetWindowRect(hWnd, &rwnd);
rwnd.bottom -= (rdlg.bottom - rdlg.top);
SetWindowPos(hDlg, NULL, 20, rwnd.bottom - 20, 0, 0, SWP_NOOWNERZORDER |
SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
ShowWindow(hWnd,SW_SHOWMAXIMIZED);
SetFocus(hDlg);
while(GetMessage(&msg,NULL,0,0)) {
if(!TranslateAccelerator(hDlg, hAccel, &msg)) {
if(!IsDialogMessage(hDlg, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
return msg.wParam;
}