/* 浜様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様融 � � � Product: Fractal Fern Generator � � Version: 1.0 � � � � Source: WINFERN.C � � Revison: 1.0 � � Description: Fractal Fern Generator based on code from the "Fractal � � Programming in C" book by a very qualified author � � (who's name I don't remember since I wrote this a year ago � � and have since packed the book away somewhere) � � Group: Generator code � � � � Author: Ren� Schuchter, TouchGo(tm) Studios � � � � Date: April 22, 1991 (BBS version) � � � � This code is placed in the public domain. Any issues of copyright related � � to using these examples from "Fractals Prograamming in C" for commercial � � or other purposes is the sole responsibility of the person using this � � code. � � � � This notice MUST remain with any versions of this code ditributed on a � � BBS. � � � � The folowing files should be included with any distributed version: � � � � WINFERN.EXE � � WINFERN.C � � WINFERN.H � � WINFERN.RC � � WINFERN.DEF � � WINFERN.ICO � � WFABOUT.BMP � � WFABOUT.RL4 (4 bpp RLE of original BMP ) � � WINFERN � � � � For any questions or comments I can be reached at (916) 739-0100. � � � 藩様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様夕 */ #include #include #include #include "winfern.h" char szAppName[] = "Fractal Fern Generator v1.0", szMsg[ 256 ]; DWORD dwFernColors[ 4 ] = { RGB( 255, 0, 0 ), RGB( 0, 255, 0 ), RGB( 0, 0, 255 ), RGB( 255, 255, 0 ) }; HANDLE hInst; HWND hWndAbout; int PASCAL WinMain( HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow ) { HWND hWnd; MSG msg; WNDCLASS wndclass; if ( hPrevInstance ) return FALSE; hInst = hInstance; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInst; wndclass.hIcon = LoadIcon( hInst, "WFIcon" ); wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); wndclass.hbrBackground = GetStockObject( WHITE_BRUSH ); wndclass.lpszMenuName = (LPSTR)"WFMenu"; wndclass.lpszClassName = szAppName; if ( !RegisterClass( &wndclass ) ) return FALSE; wndclass.lpfnWndProc = AboutWndProc; wndclass.hIcon = NULL; wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); wndclass.hbrBackground = GetStockObject( WHITE_BRUSH ); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = "ABOUTCLASS"; if ( !RegisterClass( &wndclass ) ) return FALSE; hWnd = CreateWindow( szAppName, /* Class */ szAppName, /* Title */ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL ); ShowWindow( hWnd, nCmdShow ); UpdateWindow( hWnd ); while ( GetMessage( &msg, NULL, 0, 0 ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } return msg.wParam; } long FAR PASCAL WndProc( HWND hWnd, WORD wMessage, WORD wParam, LONG lParam ) { HDC hDC; PAINTSTRUCT ps; switch ( wMessage ) { case WM_COMMAND: switch ( wParam ) { case IDM_DRAW: InvalidateRect( hWnd, NULL, TRUE ); UpdateWindow( hWnd ); DrawFern( hWnd, RGB( 255, 0, 0 ) ); break; case IDM_DRAW3D: InvalidateRect( hWnd, NULL, TRUE ); UpdateWindow( hWnd ); Draw3DFern( hWnd, 4, dwFernColors ); break; case IDM_ABOUT: About( hWnd ); break; } break; case WM_PAINT: hDC = BeginPaint( hWnd, &ps ); EndPaint( hWnd, &ps ); break; case WM_DESTROY: PostQuitMessage( 0 ); break; default: return DefWindowProc( hWnd, wMessage, wParam, lParam ); } return 0L; } void NEAR PASCAL DrawFern( HWND hWnd, DWORD dwColor ) { double a[ 4 ], b[ 4 ], c[ 4 ], d[ 4 ], e[ 4 ], f[ 4 ], newx, dXScreenVGARatio, dYScreenVGARatio, x, y; HCURSOR hCursor; HDC hDC; int i, j, k, nClientWidth, nClientHeight, nXScreenSize, nYScreenSize, p[ 4 ], px, py, xoffset, xscale, yoffset, yscale; RECT rRect; /* constants optimized for VGA */ #define convert(x,y) {x = (x + 319); y = (175 - ((93*y) >> 7));} hCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) ); a[0] = (double)0.0; a[1] = (double) 0.2; a[2] = (double)-0.15; a[3] = (double) 0.85; b[0] = (double)0.0; b[1] = (double)-0.26; b[2] = (double) 0.28; b[3] = (double) 0.04; c[0] = (double)0.0; c[1] = (double) 0.23; c[2] = (double) 0.26; c[3] = (double)-0.04; d[0] = (double)0.16; d[1] = (double) 0.22; d[2] = (double) 0.24; d[3] = (double) 0.85; e[0] = (double)0.0; e[1] = (double) 0.0; e[2] = (double) 0.0; e[3] = (double) 0.0; f[0] = (double)0.0; f[1] = (double) 0.2; f[2] = (double) 0.2; f[3] = (double) 0.2; p[0] = 328; p[1] = 2621; p[2] = 4915; GetClientRect( hWnd, &rRect ); nClientWidth = rRect.right - rRect.left + 1; nClientHeight = rRect.bottom - rRect.top + 1; nXScreenSize = GetSystemMetrics( SM_CXSCREEN ); nYScreenSize = GetSystemMetrics( SM_CYSCREEN ); dXScreenVGARatio = (double)nXScreenSize / (double)640; dYScreenVGARatio = (double)nYScreenSize / (double)480; xscale = (int)( (double)300 * dXScreenVGARatio ); yscale = (int)( (double)300 * dYScreenVGARatio ); xoffset = (int)( (double) -50 * dXScreenVGARatio ); yoffset = (int)( (double)-180 * dYScreenVGARatio ); x = (double)0.0; y = (double)0.0; /* image offset for centering optimzed manually for VGA so adjust offset constants ( 16 and 6 ) for screen size */ hDC = GetDC( hWnd ); SetMapMode( hDC, MM_ANISOTROPIC ); SetWindowOrg( hDC, -(int)( (double)( nXScreenSize / 16 ) * pow( (double)dXScreenVGARatio, (double)2.0 ) ), -(int)( (double)( nYScreenSize / 6 ) * pow( (double)dYScreenVGARatio, (double)2.0 ) ) ); SetWindowExt( hDC, nXScreenSize, nYScreenSize ); SetViewportExt( hDC, nClientWidth, nClientHeight ); for ( i = 1; i <= 10000; i++ ) { j = rand(); k = ( j < p[0] ) ? 0 : ( ( j < p[1] ) ? 1 : ( ( j < p[2] ) ? 2 : 3 ) ); newx = ( ( a[k] * x ) + ( b[k] * y ) + e[k] ); y = ( ( c[k] * x ) + ( d[k] * y ) + f[k] ); x = newx; px = (int)( x * (double)xscale ) + xoffset; py = (int)( y * (double)yscale ) + yoffset; if ( ( px >= -( nXScreenSize / 2 ) ) && ( px < ( nXScreenSize / 2 ) ) && ( py >= -( nYScreenSize / 2 ) ) && ( py < ( nYScreenSize / 2 ) ) ) { convert( px, py); SetPixel( hDC, px, py, dwColor ); } } ReleaseDC( hWnd, hDC ); SetCursor( hCursor ); } void NEAR PASCAL Draw3DFern( HWND hWnd, int nFernCount, DWORD *dwColor ) { #define MAX_FERN_COUNT 4 static double alpha[ MAX_FERN_COUNT ] = { (double)30.0, (double)45.0, (double)15.0, (double)95.0 }, beta[ MAX_FERN_COUNT ] = { (double)115.0, (double)105.0, (double)70.0, (double)40.0 }, gamma[ MAX_FERN_COUNT ] = { (double)25.0, (double)70.0, (double)20.0, (double)-30.0 }; double a[ 4 ], b[ 4 ], c[ 4 ], d[ 4 ], e[ 4 ], f[ 4 ], g[ 4 ], h[ 4 ], m[ 4 ], n[ 4 ], q[ 4 ], r[ 4 ], ca, cb, cg, sa, sb, sg, x, y, z, dXScreenVGARatio, dYScreenVGARatio, newx, newy, vx, vy; HCURSOR hCursor; HDC hDC; int i, j, k, index, nClientWidth, nClientHeight, nXScreenSize, nYScreenSize, xscale, yscale, xoffset, yoffset, p[ 4 ], px, py; RECT rRect; /* constants optimized for VGA */ #define convert(x,y) {x = (x + 319); y = (175 - ((93*y) >> 7));} hCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) ); a[0] = (double)0.0; a[1] = (double) 0.83; a[2] = (double) 0.22; a[3] = (double)-0.22; b[0] = (double)0.0; b[1] = (double) 0.0; b[2] = (double)-0.023; b[3] = (double) 0.23; c[0] = (double)0.0; c[1] = (double) 0.0; c[2] = (double) 0.0; c[3] = (double) 0.0; d[0] = (double)0.0; d[1] = (double) 0.0; d[2] = (double) 0.24; d[3] = (double) 0.24; e[0] = (double)0.18; e[1] = (double) 0.86; e[2] = (double) 0.22; e[3] = (double) 0.22; f[0] = (double)0.0; f[1] = (double) 0.1; f[2] = (double) 0.0; f[3] = (double) 0.0; g[0] = (double)0.0; g[1] = (double) 0.0; g[2] = (double) 0.0; g[3] = (double) 0.0; h[0] = (double)0.0; h[1] = (double)-0.12; h[2] = (double) 0.0; h[3] = (double) 0.0; m[0] = (double)0.0; m[1] = (double) 0.84; m[2] = (double) 0.32; m[3] = (double) 0.32; n[0] = (double)0.0; n[1] = (double) 0.0; n[2] = (double) 0.0; n[3] = (double) 0.0; q[0] = (double)0.0; q[1] = (double) 1.62; q[2] = (double) 0.82; q[3] = (double) 0.82; r[0] = (double)0.0; r[1] = (double) 0.0; r[2] = (double) 0.0; r[3] = (double) 0.0; p[0] = 328; p[1] = 27879 ; p[2] = 30173; GetClientRect( hWnd, &rRect ); nClientWidth = rRect.right - rRect.left + 1; nClientHeight = rRect.bottom - rRect.top + 1; nXScreenSize = GetSystemMetrics( SM_CXSCREEN ); nYScreenSize = GetSystemMetrics( SM_CYSCREEN ); dXScreenVGARatio = (double)nXScreenSize / (double)640; dYScreenVGARatio = (double)nYScreenSize / (double)480; xscale = (int)( (double)40 * dXScreenVGARatio ); yscale = (int)( (double)50 * dYScreenVGARatio ); xoffset = (int)( (double) 60 * dXScreenVGARatio ); yoffset = (int)( (double)-180 * dYScreenVGARatio ); /* image offset for centering optimzed manually for VGA so adjust offset constants ( 16 and 6 ) for screen size */ hDC = GetDC( hWnd ); SetMapMode( hDC, MM_ANISOTROPIC ); SetWindowOrg( hDC, -(int)( (double)( nXScreenSize / 16 ) * pow( (double)dXScreenVGARatio, (double)2.0 ) ), -(int)( (double)( nYScreenSize / 6 ) * pow( (double)dYScreenVGARatio, (double)2.0 ) ) ); SetWindowExt( hDC, nXScreenSize, nYScreenSize ); SetViewportExt( hDC, nClientWidth, nClientHeight ); for ( index = 0; index < nFernCount && index < MAX_FERN_COUNT; index++ ) { ca = cos( alpha[ index ] * (double)0.0174533 ); cb = cos( beta[ index ] * (double)0.0174533 ); cg = cos( gamma[ index ] * (double)0.0174533 ); sa = sin( alpha[ index ] * (double)0.0174533 ); sb = sin( beta[ index ] * (double)0.0174533 ); sg = sin( gamma[ index ] * (double)0.0174533 ); x = (double)0.0; y = (double)0.0; z = (double)0.0; for ( i = 1; i <= 10000; i++ ) { j = rand(); k = ( j < p[0] ) ? 0 : ( ( j < p[1] ) ? 1 : ( ( j < p[2] ) ? 2 : 3 ) ); newx = ( a[k] * x ) + ( b[k] * y ) + ( c[k] * z ) + n[k]; newy = ( d[k] * x ) + ( e[k] * y ) + ( f[k] * z ) + q[k]; z = g[k] * x + h[k] * y + m[k] * z + r[k]; x = newx; y = newy; vx = ( x * ca ) + ( y * cb ) + ( z * cg ); px = (int)( ( vx * (double)xscale ) + (double)xoffset ); vy = ( x * sa ) + ( y * sb ) + ( z * sg ); py = (int)( ( vy * (double)yscale ) + (double)yoffset ); if ( ( px >= -( nXScreenSize / 2 ) ) && ( px < ( nXScreenSize / 2 ) ) && ( py >= -( nYScreenSize / 2 ) ) && ( py < ( nYScreenSize / 2 ) ) ) { convert( px, py ); SetPixel( hDC, px, py, dwColor[ index ] ); } } } ReleaseDC( hWnd, hDC ); SetCursor( hCursor ); } BOOL NEAR PASCAL About( HWND hWndParent ) { BITMAP Bitmap; char szAboutName[ MAXIMAGENAMELEN + 1 ]; HBITMAP hbmAboutImage; int nAboutHeight, nAboutWidth; POINT ptAbout; RECT rRectClient; if ( hWndAbout ) return TRUE; lstrcpy( szAboutName, "ABOUT" ); if ( NULL == ( hbmAboutImage = LoadBitmap( hInst, szAboutName ) ) ) { MessageBox( hWndParent, "Could not load about image", szAppName, MB_OK ); return FALSE; } GetObject( hbmAboutImage, 16, (LPSTR)&Bitmap); DeleteObject( hbmAboutImage ); nAboutWidth = Bitmap.bmWidth + 2; nAboutHeight = Bitmap.bmHeight + 2 + GetSystemMetrics( SM_CYCAPTION ); GetClientRect( hWndParent, &rRectClient ); ptAbout.x = ( ( rRectClient.right - rRectClient.left + 1 ) / 2 ) - ( nAboutWidth / 2 ); ptAbout.y = ( ( rRectClient.bottom - rRectClient.top + 1 ) / 2 ) - ( nAboutHeight / 2 ); ptAbout.x = max( ptAbout.x, 0 ); ptAbout.y = max( ptAbout.y, 0 ); nAboutWidth = max( nAboutWidth, 0 ); nAboutHeight = max( nAboutHeight, 0 ); hWndAbout = CreateWindow( "ABOUTCLASS", "About Fractal Fern Generator", WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN | WS_VISIBLE, ptAbout.x, ptAbout.y, nAboutWidth, nAboutHeight, hWndParent, NULL, hInst, NULL ); if ( !hWndAbout ) { MessageBox( hWndParent, "Could not create about window", szAppName, MB_OK ); return FALSE; } return TRUE; } long FAR PASCAL AboutWndProc( HWND hWnd, WORD wMessage, WORD wParam, LONG lParam ) { static BOOL bOkButtonShowing = FALSE; static char szAboutName[ MAXIMAGENAMELEN + 1 ], szOKText[ 4 ] = "&OK"; static HWND hBtnAbout; BITMAP Bitmap; BOOL bShowImage; HBITMAP hbmAboutImage, hbmOld; HDC hDC, hDCMem; PAINTSTRUCT ps; switch ( wMessage ) { case WM_CREATE: lstrcpy( szAboutName, "ABOUT" ); bOkButtonShowing = FALSE; break; case WM_PAINT: hDC = BeginPaint( hWnd, &ps ); if ( NULL == ( hbmAboutImage = LoadBitmap( hInst, szAboutName ) ) ) { bShowImage = FALSE; MessageBox( hWnd, "Could not load about image", szAppName, MB_OK ); } else { bShowImage = TRUE; hDCMem = CreateCompatibleDC( hDC ); hbmOld = SelectObject( hDCMem, hbmAboutImage ); GetObject( hbmAboutImage, 16, (LPSTR)&Bitmap); BitBlt( hDC, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, hDCMem, 0, 0, SRCCOPY ); SelectObject( hDCMem, hbmOld ); DeleteDC( hDCMem ); DeleteObject( hbmAboutImage ); if ( !bOkButtonShowing ) { hBtnAbout = CreateWindow( "button", szOKText, WS_CHILD | WS_VISIBLE, 309, 284, 100, 34, hWnd, IDC_ABOUTOK, hInst, NULL ); SetFocus( hBtnAbout ); bOkButtonShowing = TRUE; } else SetFocus( hBtnAbout ); } EndPaint( hWnd, &ps ); break; case WM_COMMAND: switch ( wParam ) { case IDC_ABOUTOK: PostMessage( hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L ); break; } if ( hBtnAbout ) SetFocus( hBtnAbout ); break; case WM_DESTROY: if ( hBtnAbout ) { DestroyWindow( hBtnAbout ); hBtnAbout = 0; bOkButtonShowing = FALSE; } hWndAbout = 0; break; default: return DefWindowProc( hWnd, wMessage, wParam, lParam ); } return 0L; }