//----------------------------------------------------------------------------- // File: FlyingObjects.cpp // // Desc: Fun screen saver // // Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include "d3dsaver.h" #include "FlyingObjects.h" #include "mesh.h" #include "Resource.h" #include "dxutil.h" extern void updateStripScene(int flags, FLOAT fElapsedTime); extern void updateDropScene(int flags, FLOAT fElapsedTime); extern void updateLemScene(int flags, FLOAT fElapsedTime); extern void updateExplodeScene(int flags, FLOAT fElapsedTime); extern void updateWinScene(int flags, FLOAT fElapsedTime); extern void updateWin2Scene(int flags, FLOAT fElapsedTime); extern void updateTexScene(int flags, FLOAT fElapsedTime); extern BOOL initStripScene(void); extern BOOL initDropScene(void); extern BOOL initLemScene(void); extern BOOL initExplodeScene(void); extern BOOL initWinScene(void); extern BOOL initWin2Scene(void); extern BOOL initTexScene(void); extern void delStripScene(void); extern void delDropScene(void); extern void delLemScene(void); extern void delExplodeScene(void); extern void delWinScene(void); extern void delWin2Scene(void); extern void delTexScene(void); typedef void (*PTRUPDATE)(int flags, FLOAT fElapsedTime); typedef void (*ptrdel)(); typedef BOOL (*ptrinit)(); // Each screen saver style puts its hook functions into the function // arrays below. A consistent ordering of the functions is required. static PTRUPDATE updateFuncs[] = {/*updateWinScene,*/ updateWin2Scene, updateExplodeScene,updateStripScene, updateStripScene, updateDropScene, updateLemScene, updateTexScene}; static ptrdel delFuncs[] = {/*delWinScene,*/ delWin2Scene, delExplodeScene, delStripScene, delStripScene, delDropScene, delLemScene, delTexScene}; static ptrinit initFuncs[] = {/*initWinScene,*/ initWin2Scene, initExplodeScene, initStripScene, initStripScene, initDropScene, initLemScene, initTexScene}; static int idsStyles[] = {IDS_LOGO, IDS_EXPLODE, IDS_RIBBON, IDS_2RIBBON, IDS_SPLASH, IDS_TWIST, IDS_FLAG}; #define MAX_TYPE ( sizeof(initFuncs) / sizeof(ptrinit) - 1 ) // Each screen saver style can choose which dialog box controls it wants // to use. These flags enable each of the controls. Controls not choosen // will be disabled. #define OPT_COLOR_CYCLE 0x00000001 #define OPT_SMOOTH_SHADE 0x00000002 #define OPT_TESSEL 0x00000008 #define OPT_SIZE 0x00000010 #define OPT_TEXTURE 0x00000020 #define OPT_STD ( OPT_COLOR_CYCLE | OPT_SMOOTH_SHADE | OPT_TESSEL | OPT_SIZE ) static ULONG gflConfigOpt[] = { // OPT_STD, // Windows logo 0, // New Windows logo OPT_STD, // Explode OPT_STD, // Strip OPT_STD, // Strip OPT_STD, // Drop OPT_STD, // Twist (lemniscate) OPT_SMOOTH_SHADE | OPT_TESSEL | OPT_SIZE | OPT_TEXTURE // Texture mapped flag }; static void updateDialogControls(HWND hDlg); CFlyingObjectsScreensaver* g_pMyFlyingObjectsScreensaver = NULL; INT g_xScreenOrigin = 0; INT g_yScreenOrigin = 0; INT g_iDevice = -1; FLOATRECT* g_pFloatRect = NULL; BOOL gbBounce = FALSE; // floating window bounce off side // Global message loop variables. D3DMATERIAL8 Material[16]; #ifdef MEMDEBUG ULONG totalMem = 0; #endif void (*updateSceneFunc)(int flags, FLOAT fElapsedTime); // current screen saver update function void (*delSceneFunc)(void); // current screen saver deletion function BOOL bColorCycle = FALSE; // color cycling flag DeviceObjects* g_pDeviceObjects = NULL; BOOL g_bMoveToOrigin = FALSE; BOOL g_bAtOrigin = FALSE; BOOL bSmoothShading = TRUE; // smooth shading flag UINT uSize = 100; // object size float fTesselFact = 2.0f; // object tessalation int UpdateFlags = 0; // extra data sent to update function int Type = 0; // screen saver index (into function arrays) LPDIRECT3DDEVICE8 m_pd3dDevice = NULL; LPDIRECT3DINDEXBUFFER8 m_pIB = NULL; LPDIRECT3DVERTEXBUFFER8 m_pVB = NULL; LPDIRECT3DVERTEXBUFFER8 m_pVB2 = NULL; // Texture file information TEXFILE gTexFile = {0}; // Lighting properties. static const RGBA lightAmbient = {0.21f, 0.21f, 0.21f, 1.0f}; static const RGBA light0Ambient = {0.0f, 0.0f, 0.0f, 1.0f}; static const RGBA light0Diffuse = {0.7f, 0.7f, 0.7f, 1.0f}; static const RGBA light0Specular = {1.0f, 1.0f, 1.0f, 1.0f}; static const FLOAT light0Pos[] = {100.0f, 100.0f, 100.0f, 0.0f}; // Material properties. static RGBA matlColors[7] = {{1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 1.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 0.0f, 1.0f}, {0.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 1.0f, 1.0f}, {0.235f, 0.0f, 0.78f, 1.0f}, }; static D3DMATERIAL8 s_mtrl = { 1.0f, 1.0f, 1.0f, 1.0f, // Diffuse 1.0f, 1.0f, 1.0f, 1.0f, // Ambient 1.0f, 1.0f, 1.0f, 1.0f, // Specular 0.0f, 0.0f, 0.0f, 0.0f, // Emissive 30.0f // Power }; #define BUF_SIZE 255 TCHAR g_szSectName[BUF_SIZE]; TCHAR g_szFname[BUF_SIZE]; //----------------------------------------------------------------------------- // Name: myglMaterialfv() // Desc: //----------------------------------------------------------------------------- VOID myglMaterialfv(INT face, INT pname, FLOAT* params) { if( pname == GL_AMBIENT_AND_DIFFUSE) { s_mtrl.Ambient.r = s_mtrl.Diffuse.r = params[0]; s_mtrl.Ambient.g = s_mtrl.Diffuse.g = params[1]; s_mtrl.Ambient.b = s_mtrl.Diffuse.b = params[2]; s_mtrl.Ambient.a = s_mtrl.Diffuse.a = params[3]; } else if( pname == GL_SPECULAR ) { s_mtrl.Specular.r = params[0]; s_mtrl.Specular.g = params[1]; s_mtrl.Specular.b = params[2]; s_mtrl.Specular.a = params[3]; } else if( pname == GL_SHININESS ) { s_mtrl.Power = params[0]; } m_pd3dDevice->SetMaterial(&s_mtrl); } //----------------------------------------------------------------------------- // Name: myglMaterialf() // Desc: //----------------------------------------------------------------------------- VOID myglMaterialf(INT face, INT pname, FLOAT param) { if( pname == GL_SHININESS ) { s_mtrl.Power = param; } m_pd3dDevice->SetMaterial(&s_mtrl); } /******************************Public*Routine******************************\ * HsvToRgb * * HSV to RGB color space conversion. From pg. 593 of Foley & van Dam. * \**************************************************************************/ void ss_HsvToRgb(float h, float s, float v, RGBA *color ) { float i, f, p, q, t; // set alpha value, so caller doesn't have to worry about undefined value color->a = 1.0f; if (s == 0.0f) // assume h is undefined color->r = color->g = color->b = v; else { if (h >= 360.0f) h = 0.0f; h = h / 60.0f; i = (float) floor(h); f = h - i; p = v * (1.0f - s); q = v * (1.0f - (s * f)); t = v * (1.0f - (s * (1.0f - f))); switch ((int)i) { case 0: color->r = v; color->g = t; color->b = p; break; case 1: color->r = q; color->g = v; color->b = p; break; case 2: color->r = p; color->g = v; color->b = t; break; case 3: color->r = p; color->g = q; color->b = v; break; case 4: color->r = t; color->g = p; color->b = v; break; case 5: color->r = v; color->g = p; color->b = q; break; default: break; } } } void *SaverAlloc(ULONG size) { void *mPtr; mPtr = malloc(size); #ifdef MEMDEBUG totalMem += size; xprintf("malloc'd %x, size %d\n", mPtr, size); #endif return mPtr; } void SaverFree(void *pMem) { #ifdef MEMDEBUG totalMem -= _msize(pMem); xprintf("free %x, size = %d, total = %d\n", pMem, _msize(pMem), totalMem); #endif free(pMem); } // Minimum and maximum image sizes #define MINIMAGESIZE 10 #define MAXIMAGESIZE 100 // A slider range typedef struct _RANGE { int min_val; int max_val; int step; int page_step; } RANGE; RANGE complexity_range = {MINSUBDIV, MAXSUBDIV, 1, 2}; RANGE image_size_range = {MINIMAGESIZE, MAXIMAGESIZE, 1, 10}; /******************************Public*Routine******************************\ * initMaterial * * Initialize the material properties. * \**************************************************************************/ void initMaterial(int id, float r, float g, float b, float a) { Material[id].Ambient.r = r; Material[id].Ambient.g = g; Material[id].Ambient.b = b; Material[id].Ambient.a = a; Material[id].Diffuse.r = r; Material[id].Diffuse.g = g; Material[id].Diffuse.b = b; Material[id].Diffuse.a = a; Material[id].Specular.r = 1.0f; Material[id].Specular.g = 1.0f; Material[id].Specular.b = 1.0f; Material[id].Specular.a = 1.0f; Material[id].Power = 128.0f; } /******************************Public*Routine******************************\ * _3dfo_Init * \**************************************************************************/ BOOL CFlyingObjectsScreensaver::_3dfo_Init(void *data) { int i; for (i = 0; i < 7; i++) initMaterial(i, matlColors[i].r, matlColors[i].g, matlColors[i].b, matlColors[i].a); /* // Set the OpenGL clear color to black. glClearColor(0.0f, 0.0f, 0.0f, 0.0f); #ifdef SS_DEBUG glClearColor(0.2f, 0.2f, 0.2f, 0.0f); #endif // Enable the z-buffer. glEnable(GL_DEPTH_TEST); */ // Select the shading model. if (bSmoothShading) { m_pd3dDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD ); } else { m_pd3dDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT ); } /* // Setup the OpenGL matrices. glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // Setup the lighting. glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (FLOAT *) &lightAmbient); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE); glLightfv(GL_LIGHT0, GL_AMBIENT, (FLOAT *) &light0Ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, (FLOAT *) &light0Diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, (FLOAT *) &light0Specular); glLightfv(GL_LIGHT0, GL_POSITION, light0Pos); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); */ // m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, D3DCOLOR_COLORVALUE(lightAmbient.r, // lightAmbient.g, lightAmbient.b, lightAmbient.a ) ); D3DLIGHT8 light; ZeroMemory( &light, sizeof(D3DLIGHT8) ); light.Type = D3DLIGHT_POINT; light.Range = 1000.0f; light.Position.x = light0Pos[0]; light.Position.y = light0Pos[1]; light.Position.z = light0Pos[2]; light.Ambient.r = lightAmbient.r; light.Ambient.g = lightAmbient.g; light.Ambient.b = lightAmbient.b; light.Ambient.a = light0Ambient.a; light.Diffuse.r = light0Diffuse.r; light.Diffuse.g = light0Diffuse.g; light.Diffuse.b = light0Diffuse.b; light.Diffuse.a = light0Diffuse.a; light.Specular.r = light0Specular.r; light.Specular.g = light0Specular.g; light.Specular.b = light0Specular.b; light.Specular.a = light0Specular.a; light.Attenuation0 = 1.0f; light.Attenuation1 = 0.0f; light.Attenuation2 = 0.0f; m_pd3dDevice->SetLight(0, &light); m_pd3dDevice->LightEnable(0, TRUE); // m_pd3dDevice->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE); // Setup the material properties. m_pd3dDevice->SetMaterial( &Material[0] ); /* glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (FLOAT *) &Material[0].ks); glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, (FLOAT *) &Material[0].specExp); */ // call specific objects init func if (! (*initFuncs[Type])() ) return FALSE; updateSceneFunc = updateFuncs[Type]; return TRUE; } /******************************Public*Routine******************************\ * WriteSettings * * Save the screen saver configuration option to the .INI file/registry. * * History: * 10-May-1994 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ VOID CFlyingObjectsScreensaver::WriteSettings(HWND hDlg) { HKEY hkey; if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, m_strRegPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) ) { int pos, options; int optMask = 1; bSmoothShading = IsDlgButtonChecked(hDlg, DLG_SETUP_SMOOTH); bColorCycle = IsDlgButtonChecked(hDlg, DLG_SETUP_CYCLE); options = bColorCycle; options <<= 1; options |= bSmoothShading; DXUtil_WriteIntRegKey( hkey, TEXT("Options"), options ); Type = (int)SendDlgItemMessage(hDlg, DLG_SETUP_TYPES, CB_GETCURSEL, 0, 0); DXUtil_WriteIntRegKey( hkey, TEXT("Type"), Type ); pos = ss_GetTrackbarPos( hDlg, DLG_SETUP_TESSEL ); DXUtil_WriteIntRegKey( hkey, TEXT("Tesselation"), pos ); pos = ss_GetTrackbarPos( hDlg, DLG_SETUP_SIZE ); DXUtil_WriteIntRegKey( hkey, TEXT("Size"), pos ); DXUtil_WriteStringRegKey( hkey, TEXT("Texture"), gTexFile.szPathName ); DXUtil_WriteIntRegKey( hkey, TEXT("TextureFileOffset"), gTexFile.nOffset ); WriteScreenSettings( hkey ); RegCloseKey( hkey ); } } /******************************Public*Routine******************************\ * SetupTrackbar * * Setup a common control trackbar \**************************************************************************/ void ss_SetupTrackbar( HWND hDlg, int item, int lo, int hi, int lineSize, int pageSize, int pos ) { SendDlgItemMessage( hDlg, item, TBM_SETRANGE, (WPARAM) TRUE, (LPARAM) MAKELONG( lo, hi ) ); SendDlgItemMessage( hDlg, item, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) pos ); SendDlgItemMessage( hDlg, item, TBM_SETPAGESIZE, (WPARAM) 0, (LPARAM) pageSize ); SendDlgItemMessage( hDlg, item, TBM_SETLINESIZE, (WPARAM) 0, (LPARAM) lineSize ); } /******************************Public*Routine******************************\ * GetTrackbarPos * * Get the current position of a common control trackbar \**************************************************************************/ int ss_GetTrackbarPos( HWND hDlg, int item ) { return (int)SendDlgItemMessage( hDlg, item, TBM_GETPOS, 0, 0 ); } /******************************Public*Routine******************************\ * setupDialogControls * * Setup the dialog controls initially. * \**************************************************************************/ static void setupDialogControls(HWND hDlg) { int pos; InitCommonControls(); if (fTesselFact <= 1.0f) pos = (int)(fTesselFact * 100.0f); else pos = 100 + (int) ((fTesselFact - 1.0f) * 100.0f); ss_SetupTrackbar( hDlg, DLG_SETUP_TESSEL, 0, 200, 1, 10, pos ); ss_SetupTrackbar( hDlg, DLG_SETUP_SIZE, 0, 100, 1, 10, uSize ); updateDialogControls( hDlg ); } /******************************Public*Routine******************************\ * updateDialogControls * * Update the dialog controls based on the current global state. * \**************************************************************************/ static void updateDialogControls(HWND hDlg) { CheckDlgButton(hDlg, DLG_SETUP_SMOOTH, bSmoothShading); CheckDlgButton(hDlg, DLG_SETUP_CYCLE, bColorCycle); EnableWindow(GetDlgItem(hDlg, DLG_SETUP_SMOOTH), gflConfigOpt[Type] & OPT_SMOOTH_SHADE ); EnableWindow(GetDlgItem(hDlg, DLG_SETUP_CYCLE), gflConfigOpt[Type] & OPT_COLOR_CYCLE ); EnableWindow(GetDlgItem(hDlg, DLG_SETUP_TESSEL), gflConfigOpt[Type] & OPT_TESSEL); EnableWindow(GetDlgItem(hDlg, IDC_STATIC_TESS), gflConfigOpt[Type] & OPT_TESSEL); EnableWindow(GetDlgItem(hDlg, IDC_STATIC_TESS_MIN), gflConfigOpt[Type] & OPT_TESSEL); EnableWindow(GetDlgItem(hDlg, IDC_STATIC_TESS_MAX), gflConfigOpt[Type] & OPT_TESSEL); EnableWindow(GetDlgItem(hDlg, DLG_SETUP_SIZE), gflConfigOpt[Type] & OPT_SIZE); EnableWindow(GetDlgItem(hDlg, IDC_STATIC_SIZE), gflConfigOpt[Type] & OPT_SIZE); EnableWindow(GetDlgItem(hDlg, IDC_STATIC_SIZE_MIN), gflConfigOpt[Type] & OPT_SIZE); EnableWindow(GetDlgItem(hDlg, IDC_STATIC_SIZE_MAX), gflConfigOpt[Type] & OPT_SIZE); EnableWindow(GetDlgItem(hDlg, DLG_SETUP_TEXTURE), gflConfigOpt[Type] & OPT_TEXTURE); } /******************************Public*Routine******************************\ * * ScreenSaverConfigureDialog * * Standard screensaver hook * * History: * Wed Jul 19 14:56:41 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ INT_PTR CALLBACK CFlyingObjectsScreensaver::ScreenSaverConfigureDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { int wTmp; TCHAR szString[GEN_STRING_SIZE]; switch (message) { case WM_INITDIALOG: g_pMyFlyingObjectsScreensaver->ReadSettings(); setupDialogControls(hDlg); for (wTmp = 0; wTmp <= MAX_TYPE; wTmp++) { LoadString(NULL, idsStyles[wTmp], szString, GEN_STRING_SIZE); SendDlgItemMessage(hDlg, DLG_SETUP_TYPES, CB_ADDSTRING, 0, (LPARAM) szString); } SendDlgItemMessage(hDlg, DLG_SETUP_TYPES, CB_SETCURSEL, Type, 0); return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case DLG_SETUP_TYPES: switch (HIWORD(wParam)) { case CBN_EDITCHANGE: case CBN_SELCHANGE: Type = (int)SendDlgItemMessage(hDlg, DLG_SETUP_TYPES, CB_GETCURSEL, 0, 0); updateDialogControls(hDlg); break; default: break; } return FALSE; case DLG_SETUP_TEXTURE: ss_SelectTextureFile( hDlg, &gTexFile ); break; case DLG_SETUP_MONITORSETTINGS: g_pMyFlyingObjectsScreensaver->DoScreenSettingsDialog( hDlg ); break; case IDOK: g_pMyFlyingObjectsScreensaver->WriteSettings( hDlg ); EndDialog(hDlg, TRUE); break; case IDCANCEL: EndDialog(hDlg, FALSE); break; case DLG_SETUP_SMOOTH: case DLG_SETUP_CYCLE: default: break; } return TRUE; break; default: return 0; } return 0; } //----------------------------------------------------------------------------- // Name: WinMain() // Desc: Entry point to the program. Initializes everything, and goes into a // message-processing loop. Idle time is used to render the scene. //----------------------------------------------------------------------------- INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT ) { HRESULT hr; CFlyingObjectsScreensaver flyingobjectsSS; if( FAILED( hr = flyingobjectsSS.Create( hInst ) ) ) { flyingobjectsSS.DisplayErrorMsg( hr ); return 0; } return flyingobjectsSS.Run(); } //----------------------------------------------------------------------------- // Name: CFlyingObjectsScreensaver() // Desc: Constructor //----------------------------------------------------------------------------- CFlyingObjectsScreensaver::CFlyingObjectsScreensaver( ) { g_pMyFlyingObjectsScreensaver = this; g_pFloatRect = &m_floatrect; ZeroMemory( m_DeviceObjectsArray, sizeof(m_DeviceObjectsArray) ); m_pDeviceObjects = NULL; LoadString( NULL, IDS_DESCRIPTION, m_strWindowTitle, 200 ); m_bUseDepthBuffer = TRUE; lstrcpy( m_strRegPath, TEXT("Software\\Microsoft\\Screensavers\\Flying Objects") ); m_floatrect.xSize = 0.0f; InitCommonControls(); bSmoothShading = FALSE; bColorCycle = FALSE; UpdateFlags = (bColorCycle << 1); Type = 0; fTesselFact = 2.0f; uSize = 50; ss_GetDefaultBmpFile( gTexFile.szPathName ); gTexFile.nOffset = 0; ss_LoadTextureResourceStrings(); srand((UINT)time(NULL)); // seed random number generator } //----------------------------------------------------------------------------- // Name: RegisterSoftwareDevice() // Desc: This can register the D3D8RGBRasterizer or any other // pluggable software rasterizer. //----------------------------------------------------------------------------- HRESULT CFlyingObjectsScreensaver::RegisterSoftwareDevice() { m_pD3D->RegisterSoftwareDevice( D3D8RGBRasterizer ); return S_OK; } //----------------------------------------------------------------------------- // Name: SetMaterialColor() // Desc: //----------------------------------------------------------------------------- HRESULT CFlyingObjectsScreensaver::SetMaterialColor(FLOAT* pfColors) { D3DMATERIAL8 mtrl; ZeroMemory( &mtrl, sizeof(mtrl) ); mtrl.Diffuse.r = mtrl.Ambient.r = pfColors[0]; mtrl.Diffuse.g = mtrl.Ambient.g = pfColors[1]; mtrl.Diffuse.b = mtrl.Ambient.b = pfColors[2]; mtrl.Diffuse.a = mtrl.Ambient.a = pfColors[3]; mtrl.Specular.r = 1.0f; mtrl.Specular.g = 1.0f; mtrl.Specular.b = 1.0f; mtrl.Specular.a = 1.0f; mtrl.Power = 30.0f; return m_pd3dDevice->SetMaterial(&mtrl); } //----------------------------------------------------------------------------- // Name: FrameMove() // Desc: Called once per frame, the call is the entry point for animating // the scene. //----------------------------------------------------------------------------- HRESULT CFlyingObjectsScreensaver::FrameMove() { // update floatrect RECT rcBounceBounds; if( m_floatrect.xSize == 0.0f ) { // Initialize floatrect RECT rcBounds; DWORD dwParentWidth; DWORD dwParentHeight; rcBounds = m_rcRenderTotal; dwParentWidth = rcBounds.right - rcBounds.left; dwParentHeight = rcBounds.bottom - rcBounds.top; FLOAT sizeFact; FLOAT sizeScale; DWORD size; sizeScale = (FLOAT)uSize / 150.0f; // sizeFact = 0.25f + (0.5f * sizeScale); // range 25-75% // size = (DWORD) (sizeFact * ( ((FLOAT)(dwParentWidth + dwParentHeight)) / 2.0f )); // sizeFact = 0.25f + (0.75f * sizeScale); // range 25-100% // Note: there are bouncing problems when size is 100% (gbBounce is always // true) -- things "jitter" too much. So limit size to 95% for this screensaver. sizeFact = 0.25f + (0.70f * sizeScale); // range 25-95% size = (DWORD) (sizeFact * ( dwParentWidth > dwParentHeight ? dwParentHeight : dwParentWidth ) ); if( size > dwParentWidth ) size = dwParentWidth; if( size > dwParentHeight ) size = dwParentHeight; // Start floatrect centered on first RenderUnit's screen if( !m_bWindowed ) { INT iMonitor = m_RenderUnits[0].iMonitor; rcBounds = m_Monitors[iMonitor].rcScreen; } m_floatrect.xMin = rcBounds.left + ((rcBounds.right - rcBounds.left) - size) / 2.0f; m_floatrect.yMin = rcBounds.top + ((rcBounds.bottom - rcBounds.top) - size) / 2.0f; m_floatrect.xOrigin = m_floatrect.xMin; m_floatrect.yOrigin = m_floatrect.yMin; m_floatrect.xSize = (FLOAT)size; m_floatrect.ySize = (FLOAT)size; m_floatrect.xVel = 0.01f * (FLOAT) size; if( rand() % 2 == 0 ) m_floatrect.xVel = -m_floatrect.xVel; m_floatrect.yVel = 0.01f * (FLOAT) size; if( rand() % 2 == 0 ) m_floatrect.yVel = -m_floatrect.yVel; m_floatrect.xVelMax = m_floatrect.xVel; m_floatrect.yVelMax = m_floatrect.yVel; } rcBounceBounds = m_rcRenderTotal; FLOAT xMinOld = m_floatrect.xMin; FLOAT yMinOld = m_floatrect.yMin; if( g_bMoveToOrigin ) { if( m_floatrect.xVel < 0 && m_floatrect.xMin < m_floatrect.xOrigin || m_floatrect.xVel > 0 && m_floatrect.xMin > m_floatrect.xOrigin ) { m_floatrect.xVel = -m_floatrect.xVel; } if( m_floatrect.yVel < 0 && m_floatrect.yMin < m_floatrect.yOrigin || m_floatrect.yVel > 0 && m_floatrect.yMin > m_floatrect.yOrigin ) { m_floatrect.yVel = -m_floatrect.yVel; } m_floatrect.xMin += m_floatrect.xVel * 20.0f * m_fElapsedTime; m_floatrect.yMin += m_floatrect.yVel * 20.0f * m_fElapsedTime; if( m_floatrect.xVel < 0 && m_floatrect.xMin < m_floatrect.xOrigin || m_floatrect.xVel > 0 && m_floatrect.xMin > m_floatrect.xOrigin ) { m_floatrect.xMin = m_floatrect.xOrigin; m_floatrect.xVel = 0.0f; } if( m_floatrect.yVel < 0 && m_floatrect.yMin < m_floatrect.yOrigin || m_floatrect.yVel > 0 && m_floatrect.yMin > m_floatrect.yOrigin ) { m_floatrect.yMin = m_floatrect.yOrigin; m_floatrect.yVel = 0.0f; } if( m_floatrect.xMin == m_floatrect.xOrigin && m_floatrect.yMin == m_floatrect.yOrigin ) { g_bAtOrigin = TRUE; } } else { g_bAtOrigin = FALSE; if( m_floatrect.xVel == 0.0f ) { m_floatrect.xVel = m_floatrect.xVelMax; if( rand() % 2 == 0 ) m_floatrect.xVel = -m_floatrect.xVel; } if( m_floatrect.yVel == 0.0f ) { m_floatrect.yVel = m_floatrect.yVelMax; if( rand() % 2 == 0 ) m_floatrect.yVel = -m_floatrect.yVel; } m_floatrect.xMin += m_floatrect.xVel * 20.0f * m_fElapsedTime; m_floatrect.yMin += m_floatrect.yVel * 20.0f * m_fElapsedTime; if( m_floatrect.xVel < 0 && m_floatrect.xMin < rcBounceBounds.left || m_floatrect.xVel > 0 && (m_floatrect.xMin + m_floatrect.xSize) > rcBounceBounds.right ) { gbBounce = TRUE; m_floatrect.xMin = xMinOld; // undo last move m_floatrect.xVel = -m_floatrect.xVel; // change direction } if( m_floatrect.yVel < 0 && m_floatrect.yMin < rcBounceBounds.top || m_floatrect.yVel > 0 && (m_floatrect.yMin + m_floatrect.ySize) > rcBounceBounds.bottom ) { gbBounce = TRUE; m_floatrect.yMin = yMinOld; // undo last move m_floatrect.yVel = -m_floatrect.yVel; // change direction } } return S_OK; } VOID SetProjectionMatrixInfo( BOOL bOrtho, FLOAT fWidth, FLOAT fHeight, FLOAT fNear, FLOAT fFar ) { g_pMyFlyingObjectsScreensaver->m_bOrtho = bOrtho; g_pMyFlyingObjectsScreensaver->m_fWidth = fWidth; g_pMyFlyingObjectsScreensaver->m_fHeight = fHeight; g_pMyFlyingObjectsScreensaver->m_fNear = fNear; g_pMyFlyingObjectsScreensaver->m_fFar = fFar; } //----------------------------------------------------------------------------- // Name: Render() // Desc: Called once per frame, the call is the entry point for 3d // rendering. This function sets up render states, clears the // viewport, and renders the scene. //----------------------------------------------------------------------------- HRESULT CFlyingObjectsScreensaver::Render() { D3DVIEWPORT8 vp; // First, clear the entire back buffer to the background color vp.X = 0; vp.Y = 0; vp.Width = m_rcRenderCurDevice.right - m_rcRenderCurDevice.left; vp.Height = m_rcRenderCurDevice.bottom - m_rcRenderCurDevice.top; vp.MinZ = 0.0f; vp.MaxZ = 1.0f; m_pd3dDevice->SetViewport( &vp ); m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff000000, 1.0f, 0L ); // Now determine what part of the floatrect, if any, intersects the current screen RECT rcFloatThisScreen; RECT rcFloatThisScreenClipped; rcFloatThisScreen.left = (INT)m_floatrect.xMin; rcFloatThisScreen.top = (INT)m_floatrect.yMin; rcFloatThisScreen.right = rcFloatThisScreen.left + (INT)m_floatrect.xSize; rcFloatThisScreen.bottom = rcFloatThisScreen.top + (INT)m_floatrect.ySize; if( !IntersectRect(&rcFloatThisScreenClipped, &rcFloatThisScreen, &m_rcRenderCurDevice) ) { return S_OK; // no intersection, so nothing further to render on this screen } // Convert rcFloatThisScreen from screen to window coordinates OffsetRect(&rcFloatThisScreen, -m_rcRenderCurDevice.left, -m_rcRenderCurDevice.top); OffsetRect(&rcFloatThisScreenClipped, -m_rcRenderCurDevice.left, -m_rcRenderCurDevice.top); // Now set up the viewport to render to the clipped rect vp.X = rcFloatThisScreenClipped.left; vp.Y = rcFloatThisScreenClipped.top; vp.Width = rcFloatThisScreenClipped.right - rcFloatThisScreenClipped.left; vp.Height = rcFloatThisScreenClipped.bottom - rcFloatThisScreenClipped.top; vp.MinZ = 0.0f; vp.MaxZ = 1.0f; m_pd3dDevice->SetViewport( &vp ); // m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff000080, 1.0f, 0L ); // Now set up the projection matrix to only render the onscreen part of the // rect to the viewport D3DXMATRIX matProj; FLOAT l,r,b,t; l = -m_fWidth / 2; r = m_fWidth / 2; b = -m_fHeight / 2; t = m_fHeight / 2; FLOAT cxUnclipped = (rcFloatThisScreen.right + rcFloatThisScreen.left) / 2.0f; FLOAT cyUnclipped = (rcFloatThisScreen.bottom + rcFloatThisScreen.top) / 2.0f; l *= (rcFloatThisScreenClipped.left - cxUnclipped) / (rcFloatThisScreen.left - cxUnclipped); r *= (rcFloatThisScreenClipped.right - cxUnclipped) / (rcFloatThisScreen.right - cxUnclipped); t *= (rcFloatThisScreenClipped.top - cyUnclipped) / (rcFloatThisScreen.top - cyUnclipped); b *= (rcFloatThisScreenClipped.bottom - cyUnclipped) / (rcFloatThisScreen.bottom - cyUnclipped); if( m_bOrtho ) { D3DXMatrixOrthoOffCenterLH( &matProj, l, r, b, t, m_fNear, m_fFar ); } else { D3DXMatrixPerspectiveOffCenterLH( &matProj, l, r, b, t, m_fNear, m_fFar ); } m_pd3dDevice->SetTransform( D3DTS_PROJECTION , &matProj ); // Make elapsed time be zero unless time has really advanced since // the last call, so things don't move faster in multimon situations. // The right way to do this would be to separate the animation code from // the rendering code. FLOAT fElapsedTime; static FLOAT s_fTimeLast = 0.0f; if( m_fTime == s_fTimeLast ) fElapsedTime = 0.0f; else fElapsedTime = m_fElapsedTime; s_fTimeLast = m_fTime; // Begin the scene if( SUCCEEDED( m_pd3dDevice->BeginScene() ) ) { ::m_pd3dDevice = m_pd3dDevice; ::m_pIB = m_pDeviceObjects->m_pIB; ::m_pVB = m_pDeviceObjects->m_pVB; ::m_pVB2 = m_pDeviceObjects->m_pVB2; updateSceneFunc( UpdateFlags, fElapsedTime ); // End the scene. m_pd3dDevice->EndScene(); } return S_OK; } //----------------------------------------------------------------------------- // Name: SetDevice() // Desc: //----------------------------------------------------------------------------- VOID CFlyingObjectsScreensaver::SetDevice( UINT iDevice ) { m_pDeviceObjects = &m_DeviceObjectsArray[iDevice]; g_pDeviceObjects = m_pDeviceObjects; INT iMonitor = m_RenderUnits[iDevice].iMonitor; g_xScreenOrigin = m_Monitors[iMonitor].rcScreen.left; g_yScreenOrigin = m_Monitors[iMonitor].rcScreen.top; g_iDevice = iDevice; } //----------------------------------------------------------------------------- // Name: LoadTextureFromResource() // Desc: //----------------------------------------------------------------------------- HRESULT LoadTextureFromResource( LPDIRECT3DDEVICE8 pd3dDevice, TCHAR* strRes, TCHAR* strResType, LPDIRECT3DTEXTURE8* ppTex ) { HRESULT hr; HMODULE hModule = NULL; HRSRC rsrc; HGLOBAL hgData; LPVOID pvData; DWORD cbData; rsrc = FindResource( hModule, strRes, strResType ); if( rsrc != NULL ) { cbData = SizeofResource( hModule, rsrc ); if( cbData > 0 ) { hgData = LoadResource( hModule, rsrc ); if( hgData != NULL ) { pvData = LockResource( hgData ); if( pvData != NULL ) { if( FAILED( hr = D3DXCreateTextureFromFileInMemory( pd3dDevice, pvData, cbData, ppTex ) ) ) { return hr; } } } } } if( *ppTex == NULL) return E_FAIL; return S_OK; } //----------------------------------------------------------------------------- // Name: RestoreDeviceObjects() // Desc: //----------------------------------------------------------------------------- HRESULT CFlyingObjectsScreensaver::RestoreDeviceObjects() { if( m_pd3dDevice == NULL ) return S_OK; ::m_pd3dDevice = m_pd3dDevice; /* D3DLIGHT8 light; D3DUtil_InitLight( light, D3DLIGHT_POINT, 2.0, 2.0, 10.0 ); light.Specular.r = 1.0f; light.Specular.g = 1.0f; light.Specular.b = 1.0f; light.Specular.a = 1.0f; light.Attenuation0 = 1.0f; m_pd3dDevice->SetLight(0, &light); m_pd3dDevice->LightEnable(0, TRUE); */ // Set some basic renderstates m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE , TRUE ); m_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE , TRUE ); m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, D3DCOLOR(0x20202020) ); /* if( config.two_sided == GL_FRONT_AND_BACK ) m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); else m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW ); */ m_pd3dDevice->SetTextureStageState( 0 , D3DTSS_COLOROP , D3DTOP_SELECTARG1 ); m_pd3dDevice->SetTextureStageState( 0 , D3DTSS_COLORARG1 , D3DTA_DIFFUSE ); m_pd3dDevice->SetTextureStageState( 0 , D3DTSS_COLORARG2 , D3DTA_DIFFUSE ); m_pd3dDevice->SetTextureStageState( 0 , D3DTSS_ALPHAOP , D3DTOP_DISABLE ); m_pd3dDevice->SetTextureStageState( 1 , D3DTSS_COLOROP , D3DTOP_DISABLE ); m_pd3dDevice->SetTextureStageState( 1 , D3DTSS_ALPHAOP , D3DTOP_DISABLE ); D3DMATERIAL8 mtrl; ZeroMemory( &mtrl, sizeof(mtrl) ); mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f; mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f; mtrl.Diffuse.b = mtrl.Ambient.b = 1.0f; mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f; m_pd3dDevice->SetMaterial(&mtrl); if( !_3dfo_Init(NULL) ) return E_FAIL; if( Type == 6 ) { if( FAILED( D3DXCreateTextureFromFile( m_pd3dDevice, gTexFile.szPathName, &m_pDeviceObjects->m_pTexture ) ) ) { LoadTextureFromResource( m_pd3dDevice, MAKEINTRESOURCE(IDB_DEFTEX), TEXT("JPG"), &m_pDeviceObjects->m_pTexture ); } } else if( Type == 0 ) { LoadTextureFromResource( m_pd3dDevice, MAKEINTRESOURCE(IDR_FLATFLAG), TEXT("DDS"), &m_pDeviceObjects->m_pTexture ); LoadTextureFromResource( m_pd3dDevice, MAKEINTRESOURCE(IDR_WINLOGO), TEXT("PNG"), &m_pDeviceObjects->m_pTexture2 ); } m_pd3dDevice->SetTexture( 0, m_pDeviceObjects->m_pTexture ); if( FAILED( m_pd3dDevice->CreateIndexBuffer( MAX_INDICES * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &m_pDeviceObjects->m_pIB ) ) ) { return E_FAIL; } if( FAILED( m_pd3dDevice->CreateVertexBuffer( MAX_VERTICES * sizeof(MYVERTEX), D3DUSAGE_WRITEONLY, D3DFVF_MYVERTEX, D3DPOOL_MANAGED, &m_pDeviceObjects->m_pVB ) ) ) { return E_FAIL; } if( FAILED( m_pd3dDevice->CreateVertexBuffer( MAX_VERTICES * sizeof(MYVERTEX2), D3DUSAGE_WRITEONLY, D3DFVF_MYVERTEX2, D3DPOOL_MANAGED, &m_pDeviceObjects->m_pVB2 ) ) ) { return E_FAIL; } return S_OK; } //----------------------------------------------------------------------------- // Name: InvalidateDeviceObjects() // Desc: //----------------------------------------------------------------------------- HRESULT CFlyingObjectsScreensaver::InvalidateDeviceObjects() { SAFE_RELEASE( m_pDeviceObjects->m_pTexture ); SAFE_RELEASE( m_pDeviceObjects->m_pTexture2 ); SAFE_RELEASE( m_pDeviceObjects->m_pIB ); SAFE_RELEASE( m_pDeviceObjects->m_pVB ); SAFE_RELEASE( m_pDeviceObjects->m_pVB2 ); return S_OK; } //----------------------------------------------------------------------------- // Name: ReadSettings() // Desc: //----------------------------------------------------------------------------- VOID CFlyingObjectsScreensaver::ReadSettings() { int options; int optMask = 1; int tessel=0; // Read OpenGL settings first, so OS upgrade cases work ss_ReadSettings(); HKEY hkey; if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, m_strRegPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) ) { options = bSmoothShading | bColorCycle<<1; DXUtil_ReadIntRegKey( hkey, TEXT("Options"), (DWORD*)&options, options ); if (options >= 0) { bSmoothShading = ((options & optMask) != 0); optMask <<= 1; bColorCycle = ((options & optMask) != 0); UpdateFlags = (bColorCycle << 1); } DXUtil_ReadIntRegKey( hkey, TEXT("Type"), (DWORD*)&Type, Type ); // Sanity check Type. Don't want to index into function arrays // with a bad index! Type = (int)min(Type, MAX_TYPE); // Set flag so that updateStripScene will do two strips instead // of one. if (Type == 3) UpdateFlags |= 0x4; tessel = (int) (fTesselFact * 100); DXUtil_ReadIntRegKey( hkey, TEXT("Tesselation"), (DWORD*)&tessel, tessel ); SS_CLAMP_TO_RANGE2( tessel, 0, 200 ); if (tessel <= 100) fTesselFact = (float)tessel / 100.0f; else fTesselFact = 1.0f + (((float)tessel - 100.0f) / 100.0f); DXUtil_ReadIntRegKey( hkey, TEXT("Size"), (DWORD*)&uSize, uSize ); if (uSize > 100) uSize = 100; // Static size for new winlogo if (Type == 0) { uSize = 75; bSmoothShading = TRUE; } // SS_CLAMP_TO_RANGE2( uSize, 0, 100 ); /* can't be less than zero since it is a UINT */ // Is there a texture specified in the registry that overrides the // default? DXUtil_ReadStringRegKey( hkey, TEXT("Texture"), (TCHAR*)&gTexFile.szPathName, MAX_PATH, gTexFile.szPathName ); DXUtil_ReadIntRegKey( hkey, TEXT("TextureFileOffset"), (DWORD*)&gTexFile.nOffset, gTexFile.nOffset ); ReadScreenSettings( hkey ); RegCloseKey( hkey ); } } //----------------------------------------------------------------------------- // Name: ss_ReadSettings() // Desc: //----------------------------------------------------------------------------- VOID CFlyingObjectsScreensaver::ss_ReadSettings() { int options; int optMask = 1; TCHAR szDefaultBitmap[MAX_PATH]; int tessel=0; if( ss_RegistrySetup( IDS_SAVERNAME, IDS_INIFILE ) ) { options = ss_GetRegistryInt( IDS_OPTIONS, -1 ); if (options >= 0) { bSmoothShading = ((options & optMask) != 0); optMask <<= 1; bColorCycle = ((options & optMask) != 0); UpdateFlags = (bColorCycle << 1); } Type = ss_GetRegistryInt( IDS_OBJTYPE, 0 ); // Sanity check Type. Don't want to index into function arrays // with a bad index! Type = (int)min(Type, MAX_TYPE); // Set flag so that updateStripScene will do two strips instead // of one. if (Type == 3) UpdateFlags |= 0x4; tessel = ss_GetRegistryInt( IDS_TESSELATION, 100 ); SS_CLAMP_TO_RANGE2( tessel, 0, 200 ); if (tessel <= 100) fTesselFact = (float)tessel / 100.0f; else fTesselFact = 1.0f + (((float)tessel - 100.0f) / 100.0f); uSize = ss_GetRegistryInt( IDS_SIZE, 50 ); if (uSize > 100) uSize = 100; // SS_CLAMP_TO_RANGE2( uSize, 0, 100 ); /* can't be less than zero since it is a UINT */ // Determine the default .bmp file ss_GetDefaultBmpFile( szDefaultBitmap ); // Is there a texture specified in the registry that overrides the // default? ss_GetRegistryString( IDS_TEXTURE, szDefaultBitmap, gTexFile.szPathName, MAX_PATH); gTexFile.nOffset = ss_GetRegistryInt( IDS_TEXTURE_FILE_OFFSET, 0 ); } } //----------------------------------------------------------------------------- // Name: ss_GetRegistryString() // Desc: //----------------------------------------------------------------------------- BOOL CFlyingObjectsScreensaver::ss_RegistrySetup( int section, int file ) { if( LoadString(m_hInstance, section, g_szSectName, BUF_SIZE) && LoadString(m_hInstance, file, g_szFname, BUF_SIZE) ) { TCHAR pBuffer[100]; DWORD dwRealSize = GetPrivateProfileSection( g_szSectName, pBuffer, 100, g_szFname ); if( dwRealSize > 0 ) return TRUE; } return FALSE; } //----------------------------------------------------------------------------- // Name: ss_GetRegistryString() // Desc: //----------------------------------------------------------------------------- int CFlyingObjectsScreensaver::ss_GetRegistryInt( int name, int iDefault ) { TCHAR szItemName[BUF_SIZE]; if( LoadString( m_hInstance, name, szItemName, BUF_SIZE ) ) return GetPrivateProfileInt(g_szSectName, szItemName, iDefault, g_szFname); return 0; } //----------------------------------------------------------------------------- // Name: ss_GetRegistryString() // Desc: //----------------------------------------------------------------------------- VOID CFlyingObjectsScreensaver::ss_GetRegistryString( int name, LPTSTR lpDefault, LPTSTR lpDest, int bufSize ) { TCHAR szItemName[BUF_SIZE]; if( LoadString( m_hInstance, name, szItemName, BUF_SIZE ) ) GetPrivateProfileString(g_szSectName, szItemName, lpDefault, lpDest, bufSize, g_szFname); return; } //----------------------------------------------------------------------------- // Name: DoConfig() // Desc: //----------------------------------------------------------------------------- VOID CFlyingObjectsScreensaver::DoConfig() { if( IDOK == DialogBox( NULL, MAKEINTRESOURCE( DLG_SCRNSAVECONFIGURE ), m_hWndParent, ScreenSaverConfigureDialog ) ) { } } //----------------------------------------------------------------------------- // Name: ConfirmDevice() // Desc: //----------------------------------------------------------------------------- HRESULT CFlyingObjectsScreensaver::ConfirmDevice(D3DCAPS8* pCaps, DWORD dwBehavior, D3DFORMAT fmtBackBuffer) { if( dwBehavior & D3DCREATE_PUREDEVICE ) return E_FAIL; return S_OK; }