diff --git a/V01/Demo.aps b/V01/Demo.aps
new file mode 100644
index 0000000..685c861
Binary files /dev/null and b/V01/Demo.aps differ
diff --git a/V01/Demo.cpp b/V01/Demo.cpp
new file mode 100644
index 0000000..a75efd8
--- /dev/null
+++ b/V01/Demo.cpp
@@ -0,0 +1,113 @@
+# include
+# include
+# include
+# include
+# include "ddutil.h"
+# include "dsutil.h"
+# include "resource.h"
+
+const int ultris_nettobreite = 360; // Breite des Inneren des Haupfensters
+const int ultris_nettohoehe = 520; // Hoehe des Inneren des Hauptfensters
+int ultris_bruttobreite; // Breite des gesamten Haupfensters (incl. Rahmen)
+int ultris_bruttohoehe; // Hoehe des gesamten Haupfensters (incl. Rahmen)
+
+HINSTANCE ultris_instance; // Instanz der Ultris Applikation
+HWND ultris_window; // Das Hauptfenster von Ultris
+HMENU ultris_menu; // Das Menu von Ultris
+
+/*
+** ultris_windowhandler
+*/
+LRESULT CALLBACK ultris_windowhandler( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+ {
+ switch(msg)
+ {
+ case WM_COMMAND:
+ switch( LOWORD( wParam))
+ {
+ case IDM_EXIT:
+ PostMessage( hWnd, WM_CLOSE, 0, 0);
+ return 0;
+ }
+ break;
+ case WM_GETMINMAXINFO:
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.x = ((MINMAXINFO *)lParam)->ptMaxTrackSize.x = ultris_bruttobreite;
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.y = ((MINMAXINFO *)lParam)->ptMaxTrackSize.y = ultris_bruttohoehe;
+ return 0;
+ case WM_DESTROY:
+ PostQuitMessage( 0);
+ return 0;
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+ }
+
+/*
+** WinMain
+*/
+int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow)
+ {
+ MSG msg;
+ HACCEL acc;
+ WNDCLASSEX wcx;
+
+ ultris_instance = hInst;
+
+ wcx.cbSize = sizeof( wcx);
+ wcx.lpszClassName = TEXT( "Ultris");
+ wcx.lpfnWndProc = ultris_windowhandler;
+ wcx.style = CS_VREDRAW | CS_HREDRAW;
+ wcx.hInstance = hInst;
+ wcx.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hIconSm = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hCursor = LoadCursor( NULL, IDC_ARROW);
+ wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wcx.lpszMenuName = MAKEINTRESOURCE( IDR_MENU);
+ wcx.cbClsExtra = 0;
+ wcx.cbWndExtra = 0;
+
+ if( !RegisterClassEx( &wcx))
+ return 0;
+
+ acc = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_ACCEL));
+
+ ultris_bruttohoehe = ultris_nettohoehe + 2*GetSystemMetrics( SM_CYSIZEFRAME)
+ + GetSystemMetrics( SM_CYMENU)
+ + GetSystemMetrics( SM_CYCAPTION);
+ ultris_bruttobreite = ultris_nettobreite + 2*GetSystemMetrics( SM_CXSIZEFRAME);
+
+ ultris_window = CreateWindowEx( 0, TEXT( "Ultris"), TEXT( "Ultris"), WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ ultris_bruttobreite, ultris_bruttohoehe, NULL, NULL, hInst, NULL);
+ if( !ultris_window)
+ return 0;
+
+ ultris_menu = GetMenu( ultris_window);
+
+ MoveWindow( ultris_window, (GetSystemMetrics(SM_CXSCREEN)-ultris_bruttobreite)/2,
+ (GetSystemMetrics(SM_CYSCREEN)-ultris_bruttohoehe)/2,
+ ultris_bruttobreite, ultris_bruttohoehe, TRUE);
+
+ ShowWindow( ultris_window, nCmdShow);
+
+ while( TRUE)
+ {
+ if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE))
+ {
+ if( GetMessage( &msg, NULL, 0, 0 ) == 0)
+ return 0; // Message ist WM_QUIT
+
+ if( TranslateAccelerator( ultris_window, acc, &msg) == 0)
+ {
+ TranslateMessage( &msg);
+ DispatchMessage( &msg);
+ }
+ }
+ else
+ {
+ // Hier koennen wir uns um das Spiel kuemmern
+ }
+ }
+ }
+
+
+
diff --git a/V01/Demo.h b/V01/Demo.h
new file mode 100644
index 0000000..a19fa69
--- /dev/null
+++ b/V01/Demo.h
@@ -0,0 +1,12 @@
+
+#if !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
+#define AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "resource.h"
+
+
+#endif // !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
diff --git a/V01/Demo.ncb b/V01/Demo.ncb
new file mode 100644
index 0000000..049f11d
Binary files /dev/null and b/V01/Demo.ncb differ
diff --git a/V01/Demo.rc b/V01/Demo.rc
new file mode 100644
index 0000000..99afe80
--- /dev/null
+++ b/V01/Demo.rc
@@ -0,0 +1,109 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include
+#include
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Deutsch (Deutschland) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+#ifdef _WIN32
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU MENU DISCARDABLE
+BEGIN
+ POPUP "Ultris"
+ BEGIN
+ MENUITEM "Ende", IDM_EXIT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MAIN ICON DISCARDABLE "Icon.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCEL ACCELERATORS DISCARDABLE
+BEGIN
+ VK_ESCAPE, IDM_EXIT, VIRTKEY, NOINVERT
+END
+
+#endif // Deutsch (Deutschland) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Englisch (USA) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include \r\n"
+ "#include \0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Englisch (USA) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/V01/Demo.sln b/V01/Demo.sln
new file mode 100644
index 0000000..a8cd38c
--- /dev/null
+++ b/V01/Demo.sln
@@ -0,0 +1,19 @@
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo.vcproj", "{706BAF73-83F9-4402-B5BE-F0D9F045363D}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {706BAF73-83F9-4402-B5BE-F0D9F045363D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {706BAF73-83F9-4402-B5BE-F0D9F045363D}.Debug|Win32.Build.0 = Debug|Win32
+ {706BAF73-83F9-4402-B5BE-F0D9F045363D}.Release|Win32.ActiveCfg = Release|Win32
+ {706BAF73-83F9-4402-B5BE-F0D9F045363D}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/V01/Demo.sln.old b/V01/Demo.sln.old
new file mode 100644
index 0000000..dd19edf
--- /dev/null
+++ b/V01/Demo.sln.old
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo.vcproj", "{706BAF73-83F9-4402-B5BE-F0D9F045363D}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {706BAF73-83F9-4402-B5BE-F0D9F045363D}.Debug.ActiveCfg = Debug|Win32
+ {706BAF73-83F9-4402-B5BE-F0D9F045363D}.Debug.Build.0 = Debug|Win32
+ {706BAF73-83F9-4402-B5BE-F0D9F045363D}.Release.ActiveCfg = Release|Win32
+ {706BAF73-83F9-4402-B5BE-F0D9F045363D}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/V01/Demo.suo b/V01/Demo.suo
new file mode 100644
index 0000000..167f271
Binary files /dev/null and b/V01/Demo.suo differ
diff --git a/V01/Demo.suo.old b/V01/Demo.suo.old
new file mode 100644
index 0000000..94151eb
Binary files /dev/null and b/V01/Demo.suo.old differ
diff --git a/V01/Demo.vcproj b/V01/Demo.vcproj
new file mode 100644
index 0000000..c753190
--- /dev/null
+++ b/V01/Demo.vcproj
@@ -0,0 +1,300 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V01/Demo.vcproj.7.10.old b/V01/Demo.vcproj.7.10.old
new file mode 100644
index 0000000..98ce341
--- /dev/null
+++ b/V01/Demo.vcproj.7.10.old
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V01/Demo.vcproj.SASCHA.Sasch.user b/V01/Demo.vcproj.SASCHA.Sasch.user
new file mode 100644
index 0000000..86f2a09
--- /dev/null
+++ b/V01/Demo.vcproj.SASCHA.Sasch.user
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V01/Icon.ico b/V01/Icon.ico
new file mode 100644
index 0000000..7a53f63
Binary files /dev/null and b/V01/Icon.ico differ
diff --git a/V01/UpgradeLog.XML b/V01/UpgradeLog.XML
new file mode 100644
index 0000000..e60875d
--- /dev/null
+++ b/V01/UpgradeLog.XML
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/V01/_UpgradeReport_Files/UpgradeReport.css b/V01/_UpgradeReport_Files/UpgradeReport.css
new file mode 100644
index 0000000..3411f63
--- /dev/null
+++ b/V01/_UpgradeReport_Files/UpgradeReport.css
@@ -0,0 +1,207 @@
+BODY
+{
+ BACKGROUND-COLOR: white;
+ FONT-FAMILY: "Verdana", sans-serif;
+ FONT-SIZE: 100%;
+ MARGIN-LEFT: 0px;
+ MARGIN-TOP: 0px
+}
+P
+{
+ FONT-FAMILY: "Verdana", sans-serif;
+ FONT-SIZE: 70%;
+ LINE-HEIGHT: 12pt;
+ MARGIN-BOTTOM: 0px;
+ MARGIN-LEFT: 10px;
+ MARGIN-TOP: 10px
+}
+.note
+{
+ BACKGROUND-COLOR: #ffffff;
+ COLOR: #336699;
+ FONT-FAMILY: "Verdana", sans-serif;
+ FONT-SIZE: 100%;
+ MARGIN-BOTTOM: 0px;
+ MARGIN-LEFT: 0px;
+ MARGIN-TOP: 0px;
+ PADDING-RIGHT: 10px
+}
+.infotable
+{
+ BACKGROUND-COLOR: #f0f0e0;
+ BORDER-BOTTOM: #ffffff 0px solid;
+ BORDER-COLLAPSE: collapse;
+ BORDER-LEFT: #ffffff 0px solid;
+ BORDER-RIGHT: #ffffff 0px solid;
+ BORDER-TOP: #ffffff 0px solid;
+ FONT-SIZE: 70%;
+ MARGIN-LEFT: 10px
+}
+.issuetable
+{
+ BACKGROUND-COLOR: #ffffe8;
+ BORDER-COLLAPSE: collapse;
+ COLOR: #000000;
+ FONT-SIZE: 100%;
+ MARGIN-BOTTOM: 10px;
+ MARGIN-LEFT: 13px;
+ MARGIN-TOP: 0px
+}
+.issuetitle
+{
+ BACKGROUND-COLOR: #ffffff;
+ BORDER-BOTTOM: #dcdcdc 1px solid;
+ BORDER-TOP: #dcdcdc 1px;
+ COLOR: #003366;
+ FONT-WEIGHT: normal
+}
+.header
+{
+ BACKGROUND-COLOR: #cecf9c;
+ BORDER-BOTTOM: #ffffff 1px solid;
+ BORDER-LEFT: #ffffff 1px solid;
+ BORDER-RIGHT: #ffffff 1px solid;
+ BORDER-TOP: #ffffff 1px solid;
+ COLOR: #000000;
+ FONT-WEIGHT: bold
+}
+.issuehdr
+{
+ BACKGROUND-COLOR: #E0EBF5;
+ BORDER-BOTTOM: #dcdcdc 1px solid;
+ BORDER-TOP: #dcdcdc 1px solid;
+ COLOR: #000000;
+ FONT-WEIGHT: normal
+}
+.issuenone
+{
+ BACKGROUND-COLOR: #ffffff;
+ BORDER-BOTTOM: 0px;
+ BORDER-LEFT: 0px;
+ BORDER-RIGHT: 0px;
+ BORDER-TOP: 0px;
+ COLOR: #000000;
+ FONT-WEIGHT: normal
+}
+.content
+{
+ BACKGROUND-COLOR: #e7e7ce;
+ BORDER-BOTTOM: #ffffff 1px solid;
+ BORDER-LEFT: #ffffff 1px solid;
+ BORDER-RIGHT: #ffffff 1px solid;
+ BORDER-TOP: #ffffff 1px solid;
+ PADDING-LEFT: 3px
+}
+.issuecontent
+{
+ BACKGROUND-COLOR: #ffffff;
+ BORDER-BOTTOM: #dcdcdc 1px solid;
+ BORDER-TOP: #dcdcdc 1px solid;
+ PADDING-LEFT: 3px
+}
+A:link
+{
+ COLOR: #cc6633;
+ TEXT-DECORATION: underline
+}
+A:visited
+{
+ COLOR: #cc6633;
+}
+A:active
+{
+ COLOR: #cc6633;
+}
+A:hover
+{
+ COLOR: #cc3300;
+ TEXT-DECORATION: underline
+}
+H1
+{
+ BACKGROUND-COLOR: #003366;
+ BORDER-BOTTOM: #336699 6px solid;
+ COLOR: #ffffff;
+ FONT-SIZE: 130%;
+ FONT-WEIGHT: normal;
+ MARGIN: 0em 0em 0em -20px;
+ PADDING-BOTTOM: 8px;
+ PADDING-LEFT: 30px;
+ PADDING-TOP: 16px
+}
+H2
+{
+ COLOR: #000000;
+ FONT-SIZE: 80%;
+ FONT-WEIGHT: bold;
+ MARGIN-BOTTOM: 3px;
+ MARGIN-LEFT: 10px;
+ MARGIN-TOP: 20px;
+ PADDING-LEFT: 0px
+}
+H3
+{
+ COLOR: #000000;
+ FONT-SIZE: 80%;
+ FONT-WEIGHT: bold;
+ MARGIN-BOTTOM: -5px;
+ MARGIN-LEFT: 10px;
+ MARGIN-TOP: 20px
+}
+H4
+{
+ COLOR: #000000;
+ FONT-SIZE: 70%;
+ FONT-WEIGHT: bold;
+ MARGIN-BOTTOM: 0px;
+ MARGIN-TOP: 15px;
+ PADDING-BOTTOM: 0px
+}
+UL
+{
+ COLOR: #000000;
+ FONT-SIZE: 70%;
+ LIST-STYLE: square;
+ MARGIN-BOTTOM: 0pt;
+ MARGIN-TOP: 0pt
+}
+OL
+{
+ COLOR: #000000;
+ FONT-SIZE: 70%;
+ LIST-STYLE: square;
+ MARGIN-BOTTOM: 0pt;
+ MARGIN-TOP: 0pt
+}
+LI
+{
+ LIST-STYLE: square;
+ MARGIN-LEFT: 0px
+}
+.expandable
+{
+ CURSOR: hand
+}
+.expanded
+{
+ color: black
+}
+.collapsed
+{
+ DISPLAY: none
+}
+.foot
+{
+BACKGROUND-COLOR: #ffffff;
+BORDER-BOTTOM: #cecf9c 1px solid;
+BORDER-TOP: #cecf9c 2px solid
+}
+.settings
+{
+MARGIN-LEFT: 25PX;
+}
+.help
+{
+TEXT-ALIGN: right;
+margin-right: 10px;
+}
diff --git a/V01/_UpgradeReport_Files/UpgradeReport.xslt b/V01/_UpgradeReport_Files/UpgradeReport.xslt
new file mode 100644
index 0000000..6fb44ed
--- /dev/null
+++ b/V01/_UpgradeReport_Files/UpgradeReport.xslt
@@ -0,0 +1,232 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ : |
+
+
+
+
+
+
+
+
+ Konvertierungsbericht
+
+
+
+
+
+
+
+ Konvertierungsbericht -
+
+
+ Konvertierungsdauer:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Konvertierungseinstellungen
+ |
+
+
+
+
+
+
+
diff --git a/V01/_UpgradeReport_Files/UpgradeReport_Minus.gif b/V01/_UpgradeReport_Files/UpgradeReport_Minus.gif
new file mode 100644
index 0000000..17751cb
Binary files /dev/null and b/V01/_UpgradeReport_Files/UpgradeReport_Minus.gif differ
diff --git a/V01/_UpgradeReport_Files/UpgradeReport_Plus.gif b/V01/_UpgradeReport_Files/UpgradeReport_Plus.gif
new file mode 100644
index 0000000..f6009ca
Binary files /dev/null and b/V01/_UpgradeReport_Files/UpgradeReport_Plus.gif differ
diff --git a/V01/ddutil.cpp b/V01/ddutil.cpp
new file mode 100644
index 0000000..faccc24
--- /dev/null
+++ b/V01/ddutil.cpp
@@ -0,0 +1,1035 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: DirectDraw framewark classes. Feel free to use this class as a
+// starting point for adding extra functionality.
+//
+//
+// Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include
+#include "ddutil.h"
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::CDisplay()
+{
+ m_pDD = NULL;
+ m_pddsFrontBuffer = NULL;
+ m_pddsBackBuffer = NULL;
+ m_pddsBackBufferLeft = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ~CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::~CDisplay()
+{
+ DestroyObjects();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DestroyObjects()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::DestroyObjects()
+{
+ SAFE_RELEASE( m_pddsBackBufferLeft );
+ SAFE_RELEASE( m_pddsBackBuffer );
+ SAFE_RELEASE( m_pddsFrontBuffer );
+
+ if( m_pDD )
+ m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL );
+
+ SAFE_RELEASE( m_pDD );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateFullScreenDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth,
+ DWORD dwHeight, DWORD dwBPP )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ // Set the display mode
+ if( FAILED( m_pDD->SetDisplayMode( dwWidth, dwHeight, dwBPP, 0, 0 ) ) )
+ return E_FAIL;
+
+ // Create primary surface (with backbuffer attached)
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
+ DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE;
+ ddsd.dwBackBufferCount = 1;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer,
+ NULL ) ) )
+ return E_FAIL;
+
+ // Get a pointer to the back buffer
+ DDSCAPS2 ddscaps;
+ ZeroMemory( &ddscaps, sizeof( ddscaps ) );
+ ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
+
+ if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
+ &m_pddsBackBuffer ) ) )
+ return E_FAIL;
+
+ m_pddsBackBuffer->AddRef();
+
+ m_hWnd = hWnd;
+ m_bWindowed = FALSE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateWindowedDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_NORMAL );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ RECT rcWork;
+ RECT rc;
+ DWORD dwStyle;
+
+ // If we are still a WS_POPUP window we should convert to a normal app
+ // window so we look like a windows app.
+ dwStyle = GetWindowStyle( hWnd );
+ dwStyle &= ~WS_POPUP;
+ dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
+ SetWindowLong( hWnd, GWL_STYLE, dwStyle );
+
+ // Aet window size
+ SetRect( &rc, 0, 0, dwWidth, dwHeight );
+
+ AdjustWindowRectEx( &rc, GetWindowStyle(hWnd), GetMenu(hWnd) != NULL,
+ GetWindowExStyle(hWnd) );
+
+ SetWindowPos( hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
+ SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
+
+ // Make sure our window does not hang outside of the work area
+ SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWork, 0 );
+ GetWindowRect( hWnd, &rc );
+ if( rc.left < rcWork.left ) rc.left = rcWork.left;
+ if( rc.top < rcWork.top ) rc.top = rcWork.top;
+ SetWindowPos( hWnd, NULL, rc.left, rc.top, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ LPDIRECTDRAWCLIPPER pcClipper;
+
+ // Create the primary surface
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+ if( FAILED( m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
+ return E_FAIL;
+
+ // Create the backbuffer surface
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = pcClipper->SetHWnd( 0, hWnd ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pcClipper ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ // Done with clipper
+ pcClipper->Release();
+
+ m_hWnd = hWnd;
+ m_bWindowed = TRUE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurface( CSurface** ppSurface,
+ DWORD dwWidth, DWORD dwHeight )
+{
+ if( NULL == m_pDD )
+ return E_POINTER;
+ if( NULL == ppSurface )
+ return E_INVALIDARG;
+
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromBitmap()
+// Desc: Create a DirectDrawSurface from a bitmap resource or bitmap file.
+// Use MAKEINTRESOURCE() to pass a constant into strBMP.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromBitmap( CSurface** ppSurface,
+ TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight )
+{
+ HRESULT hr;
+ HBITMAP hBMP = NULL;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+
+ if( m_pDD == NULL || strBMP == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = bmp.bmWidth;
+ ddsd.dwHeight = bmp.bmHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = (*ppSurface)->DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromText()
+// Desc: Creates a DirectDrawSurface from a text string using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromText( CSurface** ppSurface,
+ HFONT hFont, TCHAR* strText,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ LPDIRECTDRAWSURFACE7 pDDS = NULL;
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ SIZE sizeText;
+
+ if( m_pDD == NULL || strText == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ hDC = GetDC( NULL );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ GetTextExtentPoint32( hDC, strText, _tcslen(strText), &sizeText );
+ ReleaseDC( NULL, hDC );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = sizeText.cx;
+ ddsd.dwHeight = sizeText.cy;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ if( FAILED( hr = (*ppSurface)->DrawText( hFont, strText, 0, 0,
+ crBackground, crForeground ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Present()
+{
+ HRESULT hr;
+
+ if( NULL == m_pddsFrontBuffer && NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ while( 1 )
+ {
+ if( m_bWindowed )
+ hr = m_pddsFrontBuffer->Blt( &m_rcWindow, m_pddsBackBuffer,
+ NULL, DDBLT_WAIT, NULL );
+ else
+ hr = m_pddsFrontBuffer->Flip( NULL, 0 );
+
+ if( hr == DDERR_SURFACELOST )
+ {
+ m_pddsFrontBuffer->Restore();
+ m_pddsBackBuffer->Restore();
+ }
+
+ if( hr != DDERR_WASSTILLDRAWING )
+ return hr;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer || NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Set the palette before loading the bitmap
+ if( pPalette )
+ m_pddsFrontBuffer->SetPalette( pPalette );
+
+ CSurface backBuffer;
+ backBuffer.Create( m_pddsBackBuffer );
+
+ if( FAILED( backBuffer.DrawBitmap( hbm, 0, 0, 0, 0 ) ) )
+ return E_FAIL;
+
+ return Present();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, DDBLTFAST_SRCCOLORKEY );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds, RECT* prc,
+ DWORD dwFlags )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc )
+{
+ if( NULL == pSurface )
+ return E_INVALIDARG;
+
+ if( pSurface->IsColorKeyed() )
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, DDBLTFAST_SRCCOLORKEY );
+ else
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Clear( DWORD dwColor )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Erase the background
+ DDBLTFX ddbltfx;
+ ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
+ ddbltfx.dwSize = sizeof(ddbltfx);
+ ddbltfx.dwFillColor = dwColor;
+
+ return m_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::SetPalette( LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer )
+ return E_POINTER;
+
+ return m_pddsFrontBuffer->SetPalette( pPalette );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette,
+ const TCHAR* strBMP )
+{
+ HRSRC hResource = NULL;
+ RGBQUAD* pRGB = NULL;
+ BITMAPINFOHEADER* pbi = NULL;
+ PALETTEENTRY aPalette[256];
+ HANDLE hFile = NULL;
+ DWORD iColor;
+ DWORD dwColors;
+ BITMAPFILEHEADER bf;
+ BITMAPINFOHEADER bi;
+ DWORD dwBytesRead;
+
+ if( m_pDD == NULL || strBMP == NULL || ppPalette == NULL )
+ return E_INVALIDARG;
+
+ *ppPalette = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hResource = FindResource( NULL, strBMP, RT_BITMAP );
+ if( hResource )
+ {
+ pbi = (LPBITMAPINFOHEADER) LockResource( LoadResource( NULL, hResource ) );
+ if( NULL == pbi )
+ return E_FAIL;
+
+ pRGB = (RGBQUAD*) ( (BYTE*) pbi + pbi->biSize );
+
+ // Figure out how many colors there are
+ if( pbi == NULL || pbi->biSize < sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if( pbi->biBitCount > 8 )
+ dwColors = 0;
+ else if( pbi->biClrUsed == 0 )
+ dwColors = 1 << pbi->biBitCount;
+ else
+ dwColors = pbi->biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around.
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ aPalette[iColor].peRed = pRGB[iColor].rgbRed;
+ aPalette[iColor].peGreen = pRGB[iColor].rgbGreen;
+ aPalette[iColor].peBlue = pRGB[iColor].rgbBlue;
+ aPalette[iColor].peFlags = 0;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+ }
+
+ // Attempt to load bitmap as a file
+ hFile = CreateFile( strBMP, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
+ if( NULL == hFile )
+ return E_FAIL;
+
+ // Read the BITMAPFILEHEADER
+ ReadFile( hFile, &bf, sizeof(bf), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bf) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the BITMAPINFOHEADER
+ ReadFile( hFile, &bi, sizeof(bi), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bi) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the PALETTEENTRY
+ ReadFile( hFile, aPalette, sizeof(aPalette), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(aPalette) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ CloseHandle( hFile );
+
+ // Figure out how many colors there are
+ if( bi.biSize != sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if (bi.biBitCount > 8)
+ dwColors = 0;
+ else if (bi.biClrUsed == 0)
+ dwColors = 1 << bi.biBitCount;
+ else
+ dwColors = bi.biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around since DirectDraw uses RGB
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ BYTE r = aPalette[iColor].peRed;
+ aPalette[iColor].peRed = aPalette[iColor].peBlue;
+ aPalette[iColor].peBlue = r;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::UpdateBounds()
+{
+ if( m_bWindowed )
+ {
+ GetClientRect( m_hWnd, &m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow+1 );
+ }
+ else
+ {
+ SetRect( &m_rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN) );
+ }
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::InitClipper
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::InitClipper()
+{
+ LPDIRECTDRAWCLIPPER pClipper;
+ HRESULT hr;
+
+ // Create a clipper when using GDI to draw on the primary surface
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pClipper, NULL ) ) )
+ return hr;
+
+ pClipper->SetHWnd( 0, m_hWnd );
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pClipper ) ) )
+ return hr;
+
+ // We can release the clipper now since g_pDDSPrimary
+ // now maintains a ref count on the clipper
+ SAFE_RELEASE( pClipper );
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::CSurface()
+{
+ m_pdds = NULL;
+ m_bColorKeyed = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::~CSurface()
+{
+ SAFE_RELEASE( m_pdds );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAWSURFACE7 pdds )
+{
+ m_pdds = pdds;
+
+ if( m_pdds )
+ {
+ m_pdds->AddRef();
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_ddsd.dwSize = sizeof(m_ddsd);
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd )
+{
+ HRESULT hr;
+
+ // Create the DDraw surface
+ if( FAILED( hr = pDD->CreateSurface( pddsd, &m_pdds, NULL ) ) )
+ return hr;
+
+ // Prepare the DDSURFACEDESC structure
+ m_ddsd.dwSize = sizeof(m_ddsd);
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Destroy()
+{
+ SAFE_RELEASE( m_pdds );
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawBitmap()
+// Desc: Draws a bitmap over an entire DirectDrawSurface, stretching the
+// bitmap if nessasary
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( HBITMAP hBMP,
+ DWORD dwBMPOriginX, DWORD dwBMPOriginY,
+ DWORD dwBMPWidth, DWORD dwBMPHeight )
+{
+ HDC hDCImage;
+ HDC hDC;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ if( hBMP == NULL || m_pdds == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ // Get the surface.description
+ ddsd.dwSize = sizeof(ddsd);
+ m_pdds->GetSurfaceDesc( &ddsd );
+
+ if( ddsd.ddpfPixelFormat.dwFlags == DDPF_FOURCC )
+ return E_NOTIMPL;
+
+ // Select bitmap into a memoryDC so we can use it.
+ hDCImage = CreateCompatibleDC( NULL );
+ if( NULL == hDCImage )
+ return E_FAIL;
+
+ SelectObject( hDCImage, hBMP );
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Use the passed size, unless zero
+ dwBMPWidth = ( dwBMPWidth == 0 ) ? bmp.bmWidth : dwBMPWidth;
+ dwBMPHeight = ( dwBMPHeight == 0 ) ? bmp.bmHeight : dwBMPHeight;
+
+ // Stretch the bitmap to cover this surface
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ StretchBlt( hDC, 0, 0,
+ ddsd.dwWidth, ddsd.dwHeight,
+ hDCImage, dwBMPOriginX, dwBMPOriginY,
+ dwBMPWidth, dwBMPHeight, SRCCOPY );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ DeleteDC( hDCImage );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawText()
+// Desc: Draws a text string on a DirectDraw surface using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawText( HFONT hFont, TCHAR* strText,
+ DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strText == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ // Set the background and foreground color
+ SetBkColor( hDC, crBackground );
+ SetTextColor( hDC, crForeground );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ // Use GDI to draw the text on the surface
+ TextOut( hDC, dwOriginX, dwOriginY, strText, _tcslen(strText) );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ReDrawBitmapOnSurface()
+// Desc: Load a bitmap from a file or resource into a DirectDraw surface.
+// normaly used to re-load a surface after a restore.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( TCHAR* strBMP,
+ DWORD dwDesiredWidth, DWORD dwDesiredHeight )
+{
+ HBITMAP hBMP;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strBMP == NULL )
+ return E_INVALIDARG;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP, IMAGE_BITMAP,
+ dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::SetColorKey( DWORD dwColorKey )
+{
+ if( NULL == m_pdds )
+ return E_POINTER;
+
+ m_bColorKeyed = TRUE;
+
+ DDCOLORKEY ddck;
+ ddck.dwColorSpaceLowValue = ConvertGDIColor( dwColorKey );
+ ddck.dwColorSpaceHighValue = ConvertGDIColor( dwColorKey );
+
+ return m_pdds->SetColorKey( DDCKEY_SRCBLT, &ddck );
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ConvertGDIColor()
+// Desc: Converts a GDI color (0x00bbggrr) into the equivalent color on a
+// DirectDrawSurface using its pixel format.
+//-----------------------------------------------------------------------------
+DWORD CSurface::ConvertGDIColor( COLORREF dwGDIColor )
+{
+ if( m_pdds == NULL )
+ return 0x00000000;
+
+ COLORREF rgbT;
+ HDC hdc;
+ DWORD dw = CLR_INVALID;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ // Use GDI SetPixel to color match for us
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK)
+ {
+ rgbT = GetPixel(hdc, 0, 0); // Save current pixel value
+ SetPixel(hdc, 0, 0, dwGDIColor); // Set our value
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ // Now lock the surface so we can read back the converted color
+ ddsd.dwSize = sizeof(ddsd);
+ hr = m_pdds->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
+ if( hr == DD_OK)
+ {
+ dw = *(DWORD *) ddsd.lpSurface;
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount < 32 ) // Mask it to bpp
+ dw &= ( 1 << ddsd.ddpfPixelFormat.dwRGBBitCount ) - 1;
+ m_pdds->Unlock(NULL);
+ }
+
+ // Now put the color that was there back.
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK )
+ {
+ SetPixel( hdc, 0, 0, rgbT );
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ return dw;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::GetBitMaskInfo()
+// Desc: Returns the number of bits and the shift in the bit mask
+//-----------------------------------------------------------------------------
+HRESULT CSurface::GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits )
+{
+ DWORD dwShift = 0;
+ DWORD dwBits = 0;
+
+ if( pdwShift == NULL || pdwBits == NULL )
+ return E_INVALIDARG;
+
+ if( dwBitMask )
+ {
+ while( (dwBitMask & 1) == 0 )
+ {
+ dwShift++;
+ dwBitMask >>= 1;
+ }
+ }
+
+ while( (dwBitMask & 1) != 0 )
+ {
+ dwBits++;
+ dwBitMask >>= 1;
+ }
+
+ *pdwShift = dwShift;
+ *pdwBits = dwBits;
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V01/ddutil.h b/V01/ddutil.h
new file mode 100644
index 0000000..61fb0be
--- /dev/null
+++ b/V01/ddutil.h
@@ -0,0 +1,140 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: Routines for loading bitmap and palettes from resources
+//
+// Copyright (C) 1998-1999 Microsoft Corporation. All Rights Reserved.
+//-----------------------------------------------------------------------------
+#ifndef DDUTIL_H
+#define DDUTIL_H
+
+#include
+#include
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes defined in this header file
+//-----------------------------------------------------------------------------
+class CDisplay;
+class CSurface;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Flags for the CDisplay and CSurface methods
+//-----------------------------------------------------------------------------
+#define DSURFACELOCK_READ
+#define DSURFACELOCK_WRITE
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CDisplay
+// Desc: Class to handle all DDraw aspects of a display, including creation of
+// front and back buffers, creating offscreen surfaces and palettes,
+// and blitting surface and displaying bitmaps.
+//-----------------------------------------------------------------------------
+class CDisplay
+{
+protected:
+ LPDIRECTDRAW7 m_pDD;
+ LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBufferLeft; // For stereo modes
+
+ HWND m_hWnd;
+ RECT m_rcWindow;
+ BOOL m_bWindowed;
+ BOOL m_bStereo;
+
+public:
+ CDisplay();
+ ~CDisplay();
+
+ // Access functions
+ HWND GetHWnd() { return m_hWnd; }
+ LPDIRECTDRAW7 GetDirectDraw() { return m_pDD; }
+ LPDIRECTDRAWSURFACE7 GetFrontBuffer() { return m_pddsFrontBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBuffer() { return m_pddsBackBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBufferLEft() { return m_pddsBackBufferLeft; }
+
+ // Status functions
+ BOOL IsWindowed() { return m_bWindowed; }
+ BOOL IsStereo() { return m_bStereo; }
+
+ // Creation/destruction methods
+ HRESULT CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight,
+ DWORD dwBPP );
+ HRESULT CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight );
+ HRESULT InitClipper();
+ HRESULT UpdateBounds();
+ virtual HRESULT DestroyObjects();
+
+ // Methods to create child objects
+ HRESULT CreateSurface( CSurface** ppSurface, DWORD dwWidth,
+ DWORD dwHeight );
+ HRESULT CreateSurfaceFromBitmap( CSurface** ppSurface, TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight );
+ HRESULT CreateSurfaceFromText( CSurface** ppSurface, HFONT hFont,
+ TCHAR* strText,
+ COLORREF crBackground,
+ COLORREF crForeground );
+ HRESULT CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette, const TCHAR* strBMP );
+
+ // Display methods
+ HRESULT Clear( DWORD dwColor = 0L );
+ HRESULT ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc = NULL );
+ HRESULT Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc=NULL, DWORD dwFlags=0 );
+ HRESULT Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc = NULL );
+ HRESULT ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette=NULL );
+ HRESULT SetPalette( LPDIRECTDRAWPALETTE pPalette );
+ HRESULT Present();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSurface
+// Desc: Class to handle aspects of a DirectDrawSurface.
+//-----------------------------------------------------------------------------
+class CSurface
+{
+ LPDIRECTDRAWSURFACE7 m_pdds;
+ DDSURFACEDESC2 m_ddsd;
+ BOOL m_bColorKeyed;
+
+public:
+ LPDIRECTDRAWSURFACE7 GetDDrawSurface() { return m_pdds; }
+ BOOL IsColorKeyed() { return m_bColorKeyed; }
+
+ HRESULT DrawBitmap( HBITMAP hBMP, DWORD dwBMPOriginX = 0, DWORD dwBMPOriginY = 0,
+ DWORD dwBMPWidth = 0, DWORD dwBMPHeight = 0 );
+ HRESULT DrawBitmap( TCHAR* strBMP, DWORD dwDesiredWidth, DWORD dwDesiredHeight );
+ HRESULT DrawText( HFONT hFont, TCHAR* strText, DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground );
+
+ HRESULT SetColorKey( DWORD dwColorKey );
+ DWORD ConvertGDIColor( COLORREF dwGDIColor );
+ static HRESULT GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits );
+
+ HRESULT Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd );
+ HRESULT Create( LPDIRECTDRAWSURFACE7 pdds );
+ HRESULT Destroy();
+
+ CSurface();
+ ~CSurface();
+};
+
+
+
+
+#endif // DDUTIL_H
+
diff --git a/V01/dsutil.cpp b/V01/dsutil.cpp
new file mode 100644
index 0000000..83c1512
--- /dev/null
+++ b/V01/dsutil.cpp
@@ -0,0 +1,1546 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.cpp
+//
+// Desc: DirectSound framework classes for reading and writing wav files and
+// playing them in DirectSound buffers. Feel free to use this class
+// as a starting point for adding extra functionality.
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CSoundManager()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSoundManager::CSoundManager()
+{
+ m_pDS = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::~CSoundManager()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSoundManager::~CSoundManager()
+{
+ SAFE_RELEASE( m_pDS );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Initialize()
+// Desc: Initializes the IDirectSound object and also sets the primary buffer
+// format. This function must be called before any others.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Initialize( HWND hWnd,
+ DWORD dwCoopLevel,
+ DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ SAFE_RELEASE( m_pDS );
+
+ // Create IDirectSound using the primary sound device
+ if( FAILED( hr = DirectSoundCreate8( NULL, &m_pDS, NULL ) ) )
+ return DXTRACE_ERR( TEXT("DirectSoundCreate8"), hr );
+
+ // Set DirectSound coop level
+ if( FAILED( hr = m_pDS->SetCooperativeLevel( hWnd, dwCoopLevel ) ) )
+ return DXTRACE_ERR( TEXT("SetCooperativeLevel"), hr );
+
+ // Set primary buffer format
+ SetPrimaryBufferFormat( dwPrimaryChannels, dwPrimaryFreq, dwPrimaryBitRate );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::SetPrimaryBufferFormat()
+// Desc: Set primary buffer to a specified format
+// For example, to set the primary buffer format to 22kHz stereo, 16-bit
+// then: dwPrimaryChannels = 2
+// dwPrimaryFreq = 22050,
+// dwPrimaryBitRate = 16
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::SetPrimaryBufferFormat( DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Get the primary buffer
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
+ dsbd.dwBufferBytes = 0;
+ dsbd.lpwfxFormat = NULL;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ WAVEFORMATEX wfx;
+ ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = (WORD) dwPrimaryChannels;
+ wfx.nSamplesPerSec = dwPrimaryFreq;
+ wfx.wBitsPerSample = (WORD) dwPrimaryBitRate;
+ wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+ if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )
+ return DXTRACE_ERR( TEXT("SetFormat"), hr );
+
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Get3DListenerInterface()
+// Desc: Returns the 3D listener interface associated with primary buffer.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener )
+{
+ HRESULT hr;
+ DSBUFFERDESC dsbdesc;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( ppDSListener == NULL )
+ return E_INVALIDARG;
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ *ppDSListener = NULL;
+
+ // Obtain primary buffer, asking it for 3D control
+ ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
+ dsbdesc.dwSize = sizeof(DSBUFFERDESC);
+ dsbdesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ if( FAILED( hr = pDSBPrimary->QueryInterface( IID_IDirectSound3DListener,
+ (VOID**)ppDSListener ) ) )
+ {
+ SAFE_RELEASE( pDSBPrimary );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ // Release the primary buffer, since it is not need anymore
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Create()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Create( CSound** ppSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ HRESULT hrRet = S_OK;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ if( pWaveFile->GetSize() == 0 )
+ {
+ // Wave is blank, so don't create it.
+ hr = E_FAIL;
+ goto LFail;
+ }
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = pWaveFile->GetSize();
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ // DirectSound is only guarenteed to play PCM data. Other
+ // formats may or may not work depending the sound card driver.
+ hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL );
+
+ // Be sure to return this error code if it occurs so the
+ // callers knows this happened.
+ if( hr == DS_NO_VIRTUALIZATION )
+ hrRet = DS_NO_VIRTUALIZATION;
+
+ if( FAILED(hr) )
+ {
+ // DSERR_BUFFERTOOSMALL will be returned if the buffer is
+ // less than DSBSIZE_FX_MIN (100ms) and the buffer is created
+ // with DSBCAPS_CTRLFX.
+ if( hr != DSERR_BUFFERTOOSMALL )
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return hrRet;
+
+LFail:
+ // Cleanup
+ SAFE_DELETE( pWaveFile );
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateFromMemory()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateFromMemory( CSound** ppSound,
+ BYTE* pbData,
+ ULONG ulDataSize,
+ LPWAVEFORMATEX pwfx,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbData == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->OpenFromMemory( pbData,ulDataSize, pwfx, WAVEFILE_READ );
+
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = ulDataSize;
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL ) ) )
+ {
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return S_OK;
+
+LFail:
+ // Cleanup
+
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateStreaming()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateStreaming( CStreamingSound** ppStreamingSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNotifyCount,
+ DWORD dwNotifySize,
+ HANDLE hNotifyEvent )
+{
+ HRESULT hr;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppStreamingSound == NULL || hNotifyEvent == NULL )
+ return E_INVALIDARG;
+
+ LPDIRECTSOUNDBUFFER pDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+ DSBPOSITIONNOTIFY* aPosNotify = NULL;
+ LPDIRECTSOUNDNOTIFY pDSNotify = NULL;
+
+ pWaveFile = new CWaveFile();
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ // Figure out how big the DSound buffer should be
+ dwDSBufferSize = dwNotifySize * dwNotifyCount;
+
+ // Set up the direct sound buffer. Request the NOTIFY flag, so
+ // that we are notified as the sound buffer plays. Note, that using this flag
+ // may limit the amount of hardware acceleration that can occur.
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags |
+ DSBCAPS_CTRLPOSITIONNOTIFY |
+ DSBCAPS_GETCURRENTPOSITION2;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBuffer, NULL ) ) )
+ {
+ // If wave format isn't then it will return
+ // either DSERR_BADFORMAT or E_INVALIDARG
+ if( hr == DSERR_BADFORMAT || hr == E_INVALIDARG )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("CreateSoundBuffer"), hr );
+
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ }
+
+ // Create the notification events, so that we know when to fill
+ // the buffer as the sound plays.
+ if( FAILED( hr = pDSBuffer->QueryInterface( IID_IDirectSoundNotify,
+ (VOID**)&pDSNotify ) ) )
+ {
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ];
+ if( aPosNotify == NULL )
+ return E_OUTOFMEMORY;
+
+ for( DWORD i = 0; i < dwNotifyCount; i++ )
+ {
+ aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
+ aPosNotify[i].hEventNotify = hNotifyEvent;
+ }
+
+ // Tell DirectSound when to notify us. The notification will come in the from
+ // of signaled events that are handled in WinMain()
+ if( FAILED( hr = pDSNotify->SetNotificationPositions( dwNotifyCount,
+ aPosNotify ) ) )
+ {
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("SetNotificationPositions"), hr );
+ }
+
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+
+ // Create the sound
+ *ppStreamingSound = new CStreamingSound( pDSBuffer, dwDSBufferSize, pWaveFile, dwNotifySize );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::CSound()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSound::CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize,
+ DWORD dwNumBuffers, CWaveFile* pWaveFile )
+{
+ DWORD i;
+
+ m_apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ for( i=0; iSetCurrentPosition(0);
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::~CSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSound::~CSound()
+{
+ for( DWORD i=0; iLock( 0, m_dwDSBufferSize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ NULL, NULL, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // Reset the wave file to the beginning
+ m_pWaveFile->ResetFile();
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwWavDataRead ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ if( dwWavDataRead == 0 )
+ {
+ // Wav is blank, so just fill with silence
+ FillMemory( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ else if( dwWavDataRead < dwDSLockedBufferSize )
+ {
+ // If the wav file was smaller than the DirectSound buffer,
+ // we need to fill the remainder of the buffer with data
+ if( bRepeatWavIfBufferLarger )
+ {
+ // Reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwWavDataRead; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full
+ // for very short files
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwWavDataRead );
+ if( FAILED(hr) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwWavDataRead;
+ }
+ }
+ else
+ {
+ // Don't repeat the wav file, just fill in silence
+ FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead,
+ dwDSLockedBufferSize - dwWavDataRead,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ }
+
+ // Unlock the buffer, we don't need it anymore.
+ pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::RestoreBuffer()
+// Desc: Restores the lost buffer. *pbWasRestored returns TRUE if the buffer was
+// restored. It can also NULL if the information is not needed.
+//-----------------------------------------------------------------------------
+HRESULT CSound::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored )
+{
+ HRESULT hr;
+
+ if( pDSB == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbWasRestored )
+ *pbWasRestored = FALSE;
+
+ DWORD dwStatus;
+ if( FAILED( hr = pDSB->GetStatus( &dwStatus ) ) )
+ return DXTRACE_ERR( TEXT("GetStatus"), hr );
+
+ if( dwStatus & DSBSTATUS_BUFFERLOST )
+ {
+ // Since the app could have just been activated, then
+ // DirectSound may not be giving us control yet, so
+ // the restoring the buffer may fail.
+ // If it does, sleep until DirectSound gives us control.
+ do
+ {
+ hr = pDSB->Restore();
+ if( hr == DSERR_BUFFERLOST )
+ Sleep( 10 );
+ }
+ while( hr = pDSB->Restore() );
+
+ if( pbWasRestored != NULL )
+ *pbWasRestored = TRUE;
+
+ return S_OK;
+ }
+ else
+ {
+ return S_FALSE;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetFreeBuffer()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetFreeBuffer()
+{
+ BOOL bIsPlaying = FALSE;
+ DWORD i;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( i=0; iGetStatus( &dwStatus );
+ if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
+ break;
+ }
+ }
+
+ if( i != m_dwNumBuffers )
+ return m_apDSBuffer[ i ];
+ else
+ return m_apDSBuffer[ rand() % m_dwNumBuffers ];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetBuffer()
+// Desc:
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetBuffer( DWORD dwIndex )
+{
+ if( m_apDSBuffer == NULL )
+ return NULL;
+ if( dwIndex >= m_dwNumBuffers )
+ return NULL;
+
+ return m_apDSBuffer[dwIndex];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Get3DBufferInterface()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSound::Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer )
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( dwIndex >= m_dwNumBuffers )
+ return E_INVALIDARG;
+
+ *ppDS3DBuffer = NULL;
+
+ return m_apDSBuffer[dwIndex]->QueryInterface( IID_IDirectSound3DBuffer,
+ (VOID**)ppDS3DBuffer );
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Play()
+// Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING
+// in the dwFlags to loop the sound
+//-----------------------------------------------------------------------------
+HRESULT CSound::Play( DWORD dwPriority, DWORD dwFlags )
+{
+ HRESULT hr;
+ BOOL bRestored;
+
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();
+
+ if( pDSB == NULL )
+ return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL );
+
+ // Restore the buffer if it was lost
+ if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+
+ // Make DirectSound do pre-processing on sound effects
+ Reset();
+ }
+
+ return pDSB->Play( 0, dwPriority, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Stop()
+// Desc: Stops the sound from playing
+//-----------------------------------------------------------------------------
+HRESULT CSound::Stop()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iStop();
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Reset()
+// Desc: Reset all of the sound buffers
+//-----------------------------------------------------------------------------
+HRESULT CSound::Reset()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iSetCurrentPosition( 0 );
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::IsSoundPlaying()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+BOOL CSound::IsSoundPlaying()
+{
+ BOOL bIsPlaying = FALSE;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( DWORD i=0; iGetStatus( &dwStatus );
+ bIsPlaying |= ( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );
+ }
+ }
+
+ return bIsPlaying;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::CStreamingSound()
+// Desc: Setups up a buffer so data can be streamed from the wave file into
+// buffer. This is very useful for large wav files that would take a
+// while to load. The buffer is initially filled with data, then
+// as sound is played the notification events are signaled and more data
+// is written into the buffer by calling HandleWaveStreamNotification()
+//-----------------------------------------------------------------------------
+CStreamingSound::CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize,
+ CWaveFile* pWaveFile, DWORD dwNotifySize )
+ : CSound( &pDSBuffer, dwDSBufferSize, 1, pWaveFile )
+{
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNotifySize = dwNotifySize;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::~CStreamingSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CStreamingSound::~CStreamingSound()
+{
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::HandleWaveStreamNotification()
+// Desc: Handle the notification that tell us to put more wav data in the
+// circular buffer
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::HandleWaveStreamNotification( BOOL bLoopedPlay )
+{
+ HRESULT hr;
+ DWORD dwCurrentPlayPos;
+ DWORD dwPlayDelta;
+ DWORD dwBytesWrittenToBuffer;
+ VOID* pDSLockedBuffer = NULL;
+ VOID* pDSLockedBuffer2 = NULL;
+ DWORD dwDSLockedBufferSize;
+ DWORD dwDSLockedBufferSize2;
+
+ if( m_apDSBuffer == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ return S_OK;
+ }
+
+ // Lock the DirectSound buffer
+ if( FAILED( hr = m_apDSBuffer[0]->Lock( m_dwNextWriteOffset, m_dwNotifySize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // m_dwDSBufferSize and m_dwNextWriteOffset are both multiples of m_dwNotifySize,
+ // it should the second buffer should never be valid
+ if( pDSLockedBuffer2 != NULL )
+ return E_UNEXPECTED;
+
+ if( !m_bFillNextNotificationWithSilence )
+ {
+ // Fill the DirectSound buffer with wav data
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+ }
+ else
+ {
+ // Fill the DirectSound buffer with silence
+ FillMemory( pDSLockedBuffer, dwDSLockedBufferSize,
+ (BYTE)( m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ dwBytesWrittenToBuffer = dwDSLockedBufferSize;
+ }
+
+ // If the number of bytes written is less than the
+ // amount we requested, we have a short file.
+ if( dwBytesWrittenToBuffer < dwDSLockedBufferSize )
+ {
+ if( !bLoopedPlay )
+ {
+ // Fill in silence for the rest of the buffer.
+ FillMemory( (BYTE*) pDSLockedBuffer + dwBytesWrittenToBuffer,
+ dwDSLockedBufferSize - dwBytesWrittenToBuffer,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+
+ // Any future notifications should just fill the buffer with silence
+ m_bFillNextNotificationWithSilence = TRUE;
+ }
+ else
+ {
+ // We are looping, so reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwBytesWrittenToBuffer; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full (for very short files).
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwBytesWrittenToBuffer;
+ }
+ }
+ }
+
+ // Unlock the DirectSound buffer
+ m_apDSBuffer[0]->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ // Figure out how much data has been played so far. When we have played
+ // passed the end of the file, we will either need to start filling the
+ // buffer with silence or starting reading from the beginning of the file,
+ // depending if the user wants to loop the sound
+ if( FAILED( hr = m_apDSBuffer[0]->GetCurrentPosition( &dwCurrentPlayPos, NULL ) ) )
+ return DXTRACE_ERR( TEXT("GetCurrentPosition"), hr );
+
+ // Check to see if the position counter looped
+ if( dwCurrentPlayPos < m_dwLastPlayPos )
+ dwPlayDelta = ( m_dwDSBufferSize - m_dwLastPlayPos ) + dwCurrentPlayPos;
+ else
+ dwPlayDelta = dwCurrentPlayPos - m_dwLastPlayPos;
+
+ m_dwPlayProgress += dwPlayDelta;
+ m_dwLastPlayPos = dwCurrentPlayPos;
+
+ // If we are now filling the buffer with silence, then we have found the end so
+ // check to see if the entire sound has played, if it has then stop the buffer.
+ if( m_bFillNextNotificationWithSilence )
+ {
+ // We don't want to cut off the sound before it's done playing.
+ if( m_dwPlayProgress >= m_pWaveFile->GetSize() )
+ {
+ m_apDSBuffer[0]->Stop();
+ }
+ }
+
+ // Update where the buffer will lock (for next time)
+ m_dwNextWriteOffset += dwDSLockedBufferSize;
+ m_dwNextWriteOffset %= m_dwDSBufferSize; // Circular buffer
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::Reset()
+// Desc: Resets the sound so it will begin playing at the beginning
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::Reset()
+{
+ HRESULT hr;
+
+ if( m_apDSBuffer[0] == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ }
+
+ m_pWaveFile->ResetFile();
+
+ return m_apDSBuffer[0]->SetCurrentPosition( 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::CWaveFile()
+// Desc: Constructs the class. Call Open() to open a wave file for reading.
+// Then call Read() as needed. Calling the destructor or Close()
+// will close the file.
+//-----------------------------------------------------------------------------
+CWaveFile::CWaveFile()
+{
+ m_pwfx = NULL;
+ m_hmmio = NULL;
+ m_dwSize = 0;
+ m_bIsReadingFromMemory = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::~CWaveFile()
+// Desc: Destructs the class
+//-----------------------------------------------------------------------------
+CWaveFile::~CWaveFile()
+{
+ Close();
+
+ if( !m_bIsReadingFromMemory )
+ SAFE_DELETE_ARRAY( m_pwfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Open()
+// Desc: Opens a wave file for reading
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ HRESULT hr;
+
+ m_dwFlags = dwFlags;
+ m_bIsReadingFromMemory = FALSE;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ if( strFileName == NULL )
+ return E_INVALIDARG;
+ SAFE_DELETE_ARRAY( m_pwfx );
+
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );
+
+ if( NULL == m_hmmio )
+ {
+ HRSRC hResInfo;
+ HGLOBAL hResData;
+ DWORD dwSize;
+ VOID* pvRes;
+
+ // Loading it as a file failed, so try it as a resource
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAVE") ) ) )
+ {
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAV") ) ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("FindResource"), E_FAIL );
+ }
+
+ if( NULL == ( hResData = LoadResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("LoadResource"), E_FAIL );
+
+ if( 0 == ( dwSize = SizeofResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("SizeofResource"), E_FAIL );
+
+ if( NULL == ( pvRes = LockResource( hResData ) ) )
+ return DXTRACE_ERR( TEXT("LockResource"), E_FAIL );
+
+ CHAR* pData = new CHAR[ dwSize ];
+ memcpy( pData, pvRes, dwSize );
+
+ MMIOINFO mmioInfo;
+ ZeroMemory( &mmioInfo, sizeof(mmioInfo) );
+ mmioInfo.fccIOProc = FOURCC_MEM;
+ mmioInfo.cchBuffer = dwSize;
+ mmioInfo.pchBuffer = (CHAR*) pData;
+
+ m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );
+ }
+
+ if( FAILED( hr = ReadMMIO() ) )
+ {
+ // ReadMMIO will fail if its an not a wave file
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR_NOMSGBOX( TEXT("ReadMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ // After the reset, the size of the wav file is m_ck.cksize so store it now
+ m_dwSize = m_ck.cksize;
+ }
+ else
+ {
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF |
+ MMIO_READWRITE |
+ MMIO_CREATE );
+ if( NULL == m_hmmio )
+ return DXTRACE_ERR( TEXT("mmioOpen"), E_FAIL );
+
+ if( FAILED( hr = WriteMMIO( pwfx ) ) )
+ {
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR( TEXT("WriteMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+ }
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::OpenFromMemory()
+// Desc: copy data to CWaveFile member variable from memory
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::OpenFromMemory( BYTE* pbData, ULONG ulDataSize,
+ WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ m_pwfx = pwfx;
+ m_ulDataSize = ulDataSize;
+ m_pbData = pbData;
+ m_pbDataCur = m_pbData;
+ m_bIsReadingFromMemory = TRUE;
+
+ if( dwFlags != WAVEFILE_READ )
+ return E_NOTIMPL;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ReadMMIO()
+// Desc: Support function for reading from a multimedia I/O stream.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_pwfx.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ReadMMIO()
+{
+ MMCKINFO ckIn; // chunk info. for general use.
+ PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in.
+
+ m_pwfx = NULL;
+
+ if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Check to make sure this is a valid wave file
+ if( (m_ckRiff.ckid != FOURCC_RIFF) ||
+ (m_ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("mmioFOURCC"), E_FAIL );
+
+ // Search the input file for for the 'fmt ' chunk.
+ ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Expect the 'fmt' chunk to be at least as large as ;
+ // if there are extra parameters at the end, we'll ignore them
+ if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) )
+ return DXTRACE_ERR( TEXT("sizeof(PCMWAVEFORMAT)"), E_FAIL );
+
+ // Read the 'fmt ' chunk into .
+ if( mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat,
+ sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ // Allocate the waveformatex, but if its not pcm format, read the next
+ // word, and thats how many extra bytes to allocate.
+ if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )
+ {
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("m_pwfx"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = 0;
+ }
+ else
+ {
+ // Read in length of extra bytes.
+ WORD cbExtraBytes = 0L;
+ if( mmioRead( m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("new"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = cbExtraBytes;
+
+ // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
+ if( mmioRead( m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize))+sizeof(WORD)),
+ cbExtraBytes ) != cbExtraBytes )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+ }
+ }
+
+ // Ascend the input file out of the 'fmt ' chunk.
+ if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::GetSize()
+// Desc: Retuns the size of the read access wave file
+//-----------------------------------------------------------------------------
+DWORD CWaveFile::GetSize()
+{
+ return m_dwSize;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ResetFile()
+// Desc: Resets the internal m_ck pointer so reading starts from the
+// beginning of the file again
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ResetFile()
+{
+ if( m_bIsReadingFromMemory )
+ {
+ m_pbDataCur = m_pbData;
+ }
+ else
+ {
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ // Seek to the data
+ if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),
+ SEEK_SET ) )
+ return DXTRACE_ERR( TEXT("mmioSeek"), E_FAIL );
+
+ // Search the input file for the 'data' chunk.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ if( 0 != mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+ }
+ else
+ {
+ // Create the 'data' chunk that holds the waveform samples.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ m_ck.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( 0 != mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Read()
+// Desc: Reads section of data from a wave file into pBuffer and returns
+// how much read in pdwSizeRead, reading not more than dwSizeToRead.
+// This uses m_ck to determine where to start reading from. So
+// subsequent calls will be continue where the last left off unless
+// Reset() is called.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )
+{
+ if( m_bIsReadingFromMemory )
+ {
+ if( m_pbDataCur == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( (BYTE*)(m_pbDataCur + dwSizeToRead) >
+ (BYTE*)(m_pbData + m_ulDataSize) )
+ {
+ dwSizeToRead = m_ulDataSize - (DWORD)(m_pbDataCur - m_pbData);
+ }
+
+ CopyMemory( pBuffer, m_pbDataCur, dwSizeToRead );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = dwSizeToRead;
+
+ return S_OK;
+ }
+ else
+ {
+ MMIOINFO mmioinfoIn; // current status of m_hmmio
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pBuffer == NULL || pdwSizeRead == NULL )
+ return E_INVALIDARG;
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+
+ UINT cbDataIn = dwSizeToRead;
+ if( cbDataIn > m_ck.cksize )
+ cbDataIn = m_ck.cksize;
+
+ m_ck.cksize -= cbDataIn;
+
+ for( DWORD cT = 0; cT < cbDataIn; cT++ )
+ {
+ // Copy the bytes from the io to the buffer.
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ {
+ if( 0 != mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ return DXTRACE_ERR( TEXT("mmioinfoIn.pchNext"), E_FAIL );
+ }
+
+ // Actual copy.
+ *((BYTE*)pBuffer+cT) = *((BYTE*)mmioinfoIn.pchNext);
+ mmioinfoIn.pchNext++;
+ }
+
+ if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = cbDataIn;
+
+ return S_OK;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Close()
+// Desc: Closes the wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Close()
+{
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+ else
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( 0 != mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ // Ascend the output file out of the 'data' chunk -- this will cause
+ // the chunk size of the 'data' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Do this here instead...
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioSeek( m_hmmio, 0, SEEK_SET );
+
+ if( 0 != (INT)mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ m_ck.ckid = mmioFOURCC('f', 'a', 'c', 't');
+
+ if( 0 == mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ {
+ DWORD dwSamples = 0;
+ mmioWrite( m_hmmio, (HPSTR)&dwSamples, sizeof(DWORD) );
+ mmioAscend( m_hmmio, &m_ck, 0 );
+ }
+
+ // Ascend the output file out of the 'RIFF' chunk -- this will cause
+ // the chunk size of the 'RIFF' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::WriteMMIO()
+// Desc: Support function for reading from a multimedia I/O stream
+// pwfxDest is the WAVEFORMATEX for this new wave file.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_ck.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::WriteMMIO( WAVEFORMATEX *pwfxDest )
+{
+ DWORD dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile.
+ MMCKINFO ckOut1;
+
+ dwFactChunk = (DWORD)-1;
+
+ // Create the output file RIFF chunk of form type 'WAVE'.
+ m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');
+ m_ckRiff.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // We are now descended into the 'RIFF' chunk we just created.
+ // Now create the 'fmt ' chunk. Since we know the size of this chunk,
+ // specify it in the MMCKINFO structure so MMIO doesn't have to seek
+ // back and set the chunk size after ascending from the chunk.
+ m_ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ m_ck.cksize = sizeof(PCMWAVEFORMAT);
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type.
+ if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM )
+ {
+ if( mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+ else
+ {
+ // Write the variable length size.
+ if( (UINT)mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(*pwfxDest) + pwfxDest->cbSize ) !=
+ ( sizeof(*pwfxDest) + pwfxDest->cbSize ) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+
+ // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Now create the fact chunk, not required for PCM but nice to have. This is filled
+ // in when the close routine is called.
+ ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't');
+ ckOut1.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( mmioWrite( m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) !=
+ sizeof(dwFactChunk) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+
+ // Now ascend out of the fact chunk...
+ if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Write()
+// Desc: Writes data to the open wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Write( UINT nSizeToWrite, BYTE* pbSrcData, UINT* pnSizeWrote )
+{
+ UINT cT;
+
+ if( m_bIsReadingFromMemory )
+ return E_NOTIMPL;
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pnSizeWrote == NULL || pbSrcData == NULL )
+ return E_INVALIDARG;
+
+ *pnSizeWrote = 0;
+
+ for( cT = 0; cT < nSizeToWrite; cT++ )
+ {
+ if( m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite )
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+ if( 0 != mmioAdvance( m_hmmio, &m_mmioinfoOut, MMIO_WRITE ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+ }
+
+ *((BYTE*)m_mmioinfoOut.pchNext) = *((BYTE*)pbSrcData+cT);
+ (BYTE*)m_mmioinfoOut.pchNext++;
+
+ (*pnSizeWrote)++;
+ }
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V01/dsutil.h b/V01/dsutil.h
new file mode 100644
index 0000000..57d26df
--- /dev/null
+++ b/V01/dsutil.h
@@ -0,0 +1,170 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.h
+//
+// Desc:
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#ifndef DSUTIL_H
+#define DSUTIL_H
+
+#include
+#include
+#include
+#include
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes used by this header
+//-----------------------------------------------------------------------------
+class CSoundManager;
+class CSound;
+class CStreamingSound;
+class CWaveFile;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Typing macros
+//-----------------------------------------------------------------------------
+#define WAVEFILE_READ 1
+#define WAVEFILE_WRITE 2
+
+#define DSUtil_StopSound(s) { if(s) s->Stop(); }
+#define DSUtil_PlaySound(s) { if(s) s->Play( 0, 0 ); }
+#define DSUtil_PlaySoundLooping(s) { if(s) s->Play( 0, DSBPLAY_LOOPING ); }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSoundManager
+// Desc:
+//-----------------------------------------------------------------------------
+class CSoundManager
+{
+protected:
+ LPDIRECTSOUND8 m_pDS;
+
+public:
+ CSoundManager();
+ ~CSoundManager();
+
+ HRESULT Initialize( HWND hWnd, DWORD dwCoopLevel, DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate );
+ inline LPDIRECTSOUND GetDirectSound() { return m_pDS; }
+ HRESULT SetPrimaryBufferFormat( DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate );
+ HRESULT Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener );
+
+ HRESULT Create( CSound** ppSound, LPTSTR strWaveFileName, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
+ HRESULT CreateFromMemory( CSound** ppSound, BYTE* pbData, ULONG ulDataSize, LPWAVEFORMATEX pwfx, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
+ HRESULT CreateStreaming( CStreamingSound** ppStreamingSound, LPTSTR strWaveFileName, DWORD dwCreationFlags, GUID guid3DAlgorithm, DWORD dwNotifyCount, DWORD dwNotifySize, HANDLE hNotifyEvent );
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSound
+// Desc: Encapsulates functionality of a DirectSound buffer.
+//-----------------------------------------------------------------------------
+class CSound
+{
+protected:
+ LPDIRECTSOUNDBUFFER* m_apDSBuffer;
+ DWORD m_dwDSBufferSize;
+ CWaveFile* m_pWaveFile;
+ DWORD m_dwNumBuffers;
+
+ HRESULT RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored );
+
+public:
+ CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize, DWORD dwNumBuffers, CWaveFile* pWaveFile );
+ virtual ~CSound();
+
+ HRESULT Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer );
+ HRESULT FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger );
+ LPDIRECTSOUNDBUFFER GetFreeBuffer();
+ LPDIRECTSOUNDBUFFER GetBuffer( DWORD dwIndex );
+
+ HRESULT Play( DWORD dwPriority, DWORD dwFlags );
+ HRESULT Stop();
+ HRESULT Reset();
+ BOOL IsSoundPlaying();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CStreamingSound
+// Desc: Encapsulates functionality to play a wave file with DirectSound.
+// The Create() method loads a chunk of wave file into the buffer,
+// and as sound plays more is written to the buffer by calling
+// HandleWaveStreamNotification() whenever hNotifyEvent is signaled.
+//-----------------------------------------------------------------------------
+class CStreamingSound : public CSound
+{
+protected:
+ DWORD m_dwLastPlayPos;
+ DWORD m_dwPlayProgress;
+ DWORD m_dwNotifySize;
+ DWORD m_dwNextWriteOffset;
+ BOOL m_bFillNextNotificationWithSilence;
+
+public:
+ CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize, CWaveFile* pWaveFile, DWORD dwNotifySize );
+ ~CStreamingSound();
+
+ HRESULT HandleWaveStreamNotification( BOOL bLoopedPlay );
+ HRESULT Reset();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CWaveFile
+// Desc: Encapsulates reading or writing sound data to or from a wave file
+//-----------------------------------------------------------------------------
+class CWaveFile
+{
+public:
+ WAVEFORMATEX* m_pwfx; // Pointer to WAVEFORMATEX structure
+ HMMIO m_hmmio; // MM I/O handle for the WAVE
+ MMCKINFO m_ck; // Multimedia RIFF chunk
+ MMCKINFO m_ckRiff; // Use in opening a WAVE file
+ DWORD m_dwSize; // The size of the wave file
+ MMIOINFO m_mmioinfoOut;
+ DWORD m_dwFlags;
+ BOOL m_bIsReadingFromMemory;
+ BYTE* m_pbData;
+ BYTE* m_pbDataCur;
+ ULONG m_ulDataSize;
+
+protected:
+ HRESULT ReadMMIO();
+ HRESULT WriteMMIO( WAVEFORMATEX *pwfxDest );
+
+public:
+ CWaveFile();
+ ~CWaveFile();
+
+ HRESULT Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags );
+ HRESULT OpenFromMemory( BYTE* pbData, ULONG ulDataSize, WAVEFORMATEX* pwfx, DWORD dwFlags );
+ HRESULT Close();
+
+ HRESULT Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead );
+ HRESULT Write( UINT nSizeToWrite, BYTE* pbData, UINT* pnSizeWrote );
+
+ DWORD GetSize();
+ HRESULT ResetFile();
+ WAVEFORMATEX* GetFormat() { return m_pwfx; };
+};
+
+
+
+
+#endif // DSUTIL_H
diff --git a/V01/resource.h b/V01/resource.h
new file mode 100644
index 0000000..338f739
--- /dev/null
+++ b/V01/resource.h
@@ -0,0 +1,21 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Demo.rc
+//
+#define IDI_MAIN 101
+#define IDR_MENU 102
+#define IDR_ACCEL 103
+#define IDM_EXIT 1001
+#define ID_OTTO_OTTO1 40024
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 132
+#define _APS_NEXT_COMMAND_VALUE 40025
+#define _APS_NEXT_CONTROL_VALUE 1019
+#define _APS_NEXT_SYMED_VALUE 104
+#endif
+#endif
diff --git a/V02/Debug/BuildLog.htm b/V02/Debug/BuildLog.htm
new file mode 100644
index 0000000..c95b7bb
Binary files /dev/null and b/V02/Debug/BuildLog.htm differ
diff --git a/V02/Debug/Demo.obj b/V02/Debug/Demo.obj
new file mode 100644
index 0000000..961aa5f
Binary files /dev/null and b/V02/Debug/Demo.obj differ
diff --git a/V02/Debug/Demo.res b/V02/Debug/Demo.res
new file mode 100644
index 0000000..b67fe70
Binary files /dev/null and b/V02/Debug/Demo.res differ
diff --git a/V02/Debug/Ultris.exe b/V02/Debug/Ultris.exe
new file mode 100644
index 0000000..5e45b81
Binary files /dev/null and b/V02/Debug/Ultris.exe differ
diff --git a/V02/Debug/Ultris.exe.intermediate.manifest b/V02/Debug/Ultris.exe.intermediate.manifest
new file mode 100644
index 0000000..1c06b61
--- /dev/null
+++ b/V02/Debug/Ultris.exe.intermediate.manifest
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/V02/Debug/Ultris.pdb b/V02/Debug/Ultris.pdb
new file mode 100644
index 0000000..f535cd7
Binary files /dev/null and b/V02/Debug/Ultris.pdb differ
diff --git a/V02/Debug/ddutil.obj b/V02/Debug/ddutil.obj
new file mode 100644
index 0000000..c729bd9
Binary files /dev/null and b/V02/Debug/ddutil.obj differ
diff --git a/V02/Debug/dsutil.obj b/V02/Debug/dsutil.obj
new file mode 100644
index 0000000..fcacc99
Binary files /dev/null and b/V02/Debug/dsutil.obj differ
diff --git a/V02/Debug/mt.dep b/V02/Debug/mt.dep
new file mode 100644
index 0000000..51533a5
--- /dev/null
+++ b/V02/Debug/mt.dep
@@ -0,0 +1 @@
+ die Manifestressource wurde zuletzt um 13:58:27,17 am 18.02.2010 aktualisiert
diff --git a/V02/Debug/vc90.idb b/V02/Debug/vc90.idb
new file mode 100644
index 0000000..2488f87
Binary files /dev/null and b/V02/Debug/vc90.idb differ
diff --git a/V02/Debug/vc90.pdb b/V02/Debug/vc90.pdb
new file mode 100644
index 0000000..d7b7224
Binary files /dev/null and b/V02/Debug/vc90.pdb differ
diff --git a/V02/Demo.aps b/V02/Demo.aps
new file mode 100644
index 0000000..c4f4825
Binary files /dev/null and b/V02/Demo.aps differ
diff --git a/V02/Demo.cpp b/V02/Demo.cpp
new file mode 100644
index 0000000..f5e47c5
--- /dev/null
+++ b/V02/Demo.cpp
@@ -0,0 +1,224 @@
+# include
+# include
+# include
+# include
+# include "ddutil.h"
+# include "dsutil.h"
+# include "resource.h"
+
+const int ultris_nettobreite = 360; // Breite des Inneren des Haupfensters
+const int ultris_nettohoehe = 520; // Hoehe des Inneren des Hauptfensters
+int ultris_bruttobreite; // Breite des gesamten Haupfensters (incl. Rahmen)
+int ultris_bruttohoehe; // Hoehe des gesamten Haupfensters (incl. Rahmen)
+
+HINSTANCE ultris_instance; // Instanz der Ultris Applikation
+HWND ultris_window; // Das Hauptfenster von Ultris
+HMENU ultris_menu; // Das Menu von Ultris
+
+// V2 Beginn
+const int sound_start = 0; // Sound fuer neues Spiel
+const int sound_dreh = 1; // Sound bei Drehung
+const int sound_move = 2; // Sound bei rechts/links Bewegung
+const int sound_down = 3; // Sound bei Aufprall
+const int sound_row1 = 4; // Sound bei Abraeumen einer Reihe
+const int sound_row2 = 5; // Sound bei Abraeumen von mehreren Reihen
+const int sound_ende = 6; // Sound bei Spielende
+const int sound_win = 7; // Sound bei Eintrag in Highscore Tabelle
+const int anzahl_sounds = 8; // Anzahl Sounds
+
+char *soundfiles[anzahl_sounds] =
+ {
+ "ul_start.wav",
+ "ul_dreh.wav",
+ "ul_move.wav",
+ "ul_down.wav",
+ "ul_row1.wav",
+ "ul_row2.wav",
+ "ul_ende.wav",
+ "ul_win.wav"
+ };
+
+class sounds
+ {
+ private:
+ CSoundManager smgr;
+ CSound *snd[anzahl_sounds];
+ public:
+ int on;
+ sounds();
+ int init( HWND wnd);
+ void play( int snr);
+ ~sounds();
+ };
+
+sounds::sounds()
+ {
+ int i;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ snd[i] = 0;
+ on = 1;
+ }
+
+int sounds::init( HWND wnd)
+ {
+ HRESULT ret;
+ int i;
+
+ ret = smgr.Initialize( wnd, DSSCL_PRIORITY, 2, 22050, 16);
+ if( ret < 0)
+ return ret;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ {
+ ret = smgr.Create( snd+i, soundfiles[i]);
+ if( ret < 0)
+ return ret;
+ }
+ return S_OK;
+ }
+
+sounds::~sounds()
+ {
+ int i;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ {
+ if( snd[i])
+ delete snd[i];
+ }
+ }
+
+void sounds::play( int i)
+ {
+ if( !on)
+ return;
+ if( snd[i]->IsSoundPlaying())
+ {
+ snd[i]->Stop();
+ snd[i]->Reset();
+ }
+ snd[i]->Play(0,0);
+ }
+
+sounds ultris_sounds;
+// V2 Ende
+
+
+
+/*
+** ultris_windowhandler
+*/
+LRESULT CALLBACK ultris_windowhandler( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+ {
+ switch(msg)
+ {
+ case WM_COMMAND:
+ switch( LOWORD( wParam))
+ {
+ case IDM_EXIT:
+ PostMessage( hWnd, WM_CLOSE, 0, 0);
+ return 0;
+// V2 Beginn
+ case ID_ULTRIS_SOUND:
+ ultris_sounds.on = !ultris_sounds.on;
+ CheckMenuItem( ultris_menu, ID_ULTRIS_SOUND, ultris_sounds.on ? MF_CHECKED:MF_UNCHECKED);
+ return 0;
+ case IDM_TEST: // Testcode
+ static int testno = 0;
+ ultris_sounds.play( testno % anzahl_sounds);
+ testno++;
+ return 0;
+// V2 Ende
+ }
+ break;
+ case WM_GETMINMAXINFO:
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.x = ((MINMAXINFO *)lParam)->ptMaxTrackSize.x = ultris_bruttobreite;
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.y = ((MINMAXINFO *)lParam)->ptMaxTrackSize.y = ultris_bruttohoehe;
+ return 0;
+ case WM_DESTROY:
+ PostQuitMessage( 0);
+ return 0;
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+ }
+
+/*
+** WinMain
+*/
+int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow)
+ {
+ MSG msg;
+ HACCEL acc;
+ WNDCLASSEX wcx;
+
+ ultris_instance = hInst;
+
+ wcx.cbSize = sizeof( wcx);
+ wcx.lpszClassName = TEXT( "Ultris");
+ wcx.lpfnWndProc = ultris_windowhandler;
+ wcx.style = CS_VREDRAW | CS_HREDRAW;
+ wcx.hInstance = hInst;
+ wcx.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hIconSm = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hCursor = LoadCursor( NULL, IDC_ARROW);
+ wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wcx.lpszMenuName = MAKEINTRESOURCE( IDR_MENU);
+ wcx.cbClsExtra = 0;
+ wcx.cbWndExtra = 0;
+
+ if( !RegisterClassEx( &wcx))
+ return 0;
+
+ acc = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_ACCEL));
+
+ ultris_bruttohoehe = ultris_nettohoehe + 2*GetSystemMetrics( SM_CYSIZEFRAME)
+ + GetSystemMetrics( SM_CYMENU)
+ + GetSystemMetrics( SM_CYCAPTION);
+ ultris_bruttobreite = ultris_nettobreite + 2*GetSystemMetrics( SM_CXSIZEFRAME);
+
+ ultris_window = CreateWindowEx( 0, TEXT( "Ultris"), TEXT( "Ultris"), WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ ultris_bruttobreite, ultris_bruttohoehe, NULL, NULL, hInst, NULL);
+ if( !ultris_window)
+ return 0;
+
+ ultris_menu = GetMenu( ultris_window);
+
+// V2 Beginn
+ if( ultris_sounds.init( ultris_window) < 0)
+ {
+ MessageBox( ultris_window, "Fehler beim Initialisieren der Sounds", "Ultris-Fehlermeldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
+ return 0;
+ }
+ CheckMenuItem( ultris_menu, ID_ULTRIS_SOUND, ultris_sounds.on ? MF_CHECKED:MF_UNCHECKED);
+// V2 Ende
+
+ MoveWindow( ultris_window, (GetSystemMetrics(SM_CXSCREEN)-ultris_bruttobreite)/2,
+ (GetSystemMetrics(SM_CYSCREEN)-ultris_bruttohoehe)/2,
+ ultris_bruttobreite, ultris_bruttohoehe, TRUE);
+
+ ShowWindow( ultris_window, nCmdShow);
+
+ while( TRUE)
+ {
+ if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE))
+ {
+ if( GetMessage( &msg, NULL, 0, 0 ) == 0)
+ return 0; // Message ist WM_QUIT
+
+ if( TranslateAccelerator( ultris_window, acc, &msg) == 0)
+ {
+ TranslateMessage( &msg);
+ DispatchMessage( &msg);
+ }
+ }
+ else
+ {
+ // Hier koennen wir uns um das Spiel kuemmern
+ }
+ }
+ }
+
+
+
diff --git a/V02/Demo.h b/V02/Demo.h
new file mode 100644
index 0000000..a19fa69
--- /dev/null
+++ b/V02/Demo.h
@@ -0,0 +1,12 @@
+
+#if !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
+#define AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "resource.h"
+
+
+#endif // !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
diff --git a/V02/Demo.ncb b/V02/Demo.ncb
new file mode 100644
index 0000000..39b204b
Binary files /dev/null and b/V02/Demo.ncb differ
diff --git a/V02/Demo.rc b/V02/Demo.rc
new file mode 100644
index 0000000..2d4c8ed
--- /dev/null
+++ b/V02/Demo.rc
@@ -0,0 +1,115 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include
+#include
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Deutsch (Deutschland) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+#ifdef _WIN32
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU MENU DISCARDABLE
+BEGIN
+ POPUP "Ultris"
+ BEGIN
+ MENUITEM "Neues Spiel", ID_ULTRIS_NEUESSPIEL
+ MENUITEM "Pause", ID_ULTRIS_PAUSE
+ MENUITEM "Sound", ID_ULTRIS_SOUND
+ MENUITEM SEPARATOR
+ MENUITEM "Ende", IDM_EXIT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MAIN ICON DISCARDABLE "Icon.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCEL ACCELERATORS DISCARDABLE
+BEGIN
+ "T", IDM_TEST, VIRTKEY, CONTROL, NOINVERT
+ VK_ESCAPE, IDM_EXIT, VIRTKEY, NOINVERT
+ VK_F5, ID_ULTRIS_SOUND, VIRTKEY, NOINVERT
+END
+
+#endif // Deutsch (Deutschland) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Englisch (USA) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include \r\n"
+ "#include \0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Englisch (USA) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/V02/Demo.sln b/V02/Demo.sln
new file mode 100644
index 0000000..b89675c
--- /dev/null
+++ b/V02/Demo.sln
@@ -0,0 +1,19 @@
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo.vcproj", "{04396D0D-D714-427C-8628-CBB24A64786F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {04396D0D-D714-427C-8628-CBB24A64786F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {04396D0D-D714-427C-8628-CBB24A64786F}.Debug|Win32.Build.0 = Debug|Win32
+ {04396D0D-D714-427C-8628-CBB24A64786F}.Release|Win32.ActiveCfg = Release|Win32
+ {04396D0D-D714-427C-8628-CBB24A64786F}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/V02/Demo.sln.old b/V02/Demo.sln.old
new file mode 100644
index 0000000..3d7120f
--- /dev/null
+++ b/V02/Demo.sln.old
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo.vcproj", "{04396D0D-D714-427C-8628-CBB24A64786F}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {04396D0D-D714-427C-8628-CBB24A64786F}.Debug.ActiveCfg = Debug|Win32
+ {04396D0D-D714-427C-8628-CBB24A64786F}.Debug.Build.0 = Debug|Win32
+ {04396D0D-D714-427C-8628-CBB24A64786F}.Release.ActiveCfg = Release|Win32
+ {04396D0D-D714-427C-8628-CBB24A64786F}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/V02/Demo.suo b/V02/Demo.suo
new file mode 100644
index 0000000..6b9b58a
Binary files /dev/null and b/V02/Demo.suo differ
diff --git a/V02/Demo.suo.old b/V02/Demo.suo.old
new file mode 100644
index 0000000..5c0eb23
Binary files /dev/null and b/V02/Demo.suo.old differ
diff --git a/V02/Demo.vcproj b/V02/Demo.vcproj
new file mode 100644
index 0000000..3db9719
--- /dev/null
+++ b/V02/Demo.vcproj
@@ -0,0 +1,300 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V02/Demo.vcproj.7.10.old b/V02/Demo.vcproj.7.10.old
new file mode 100644
index 0000000..98ce341
--- /dev/null
+++ b/V02/Demo.vcproj.7.10.old
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V02/Demo.vcproj.SASCHA.Sasch.user b/V02/Demo.vcproj.SASCHA.Sasch.user
new file mode 100644
index 0000000..86f2a09
--- /dev/null
+++ b/V02/Demo.vcproj.SASCHA.Sasch.user
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V02/Icon.ico b/V02/Icon.ico
new file mode 100644
index 0000000..7a53f63
Binary files /dev/null and b/V02/Icon.ico differ
diff --git a/V02/UpgradeLog.XML b/V02/UpgradeLog.XML
new file mode 100644
index 0000000..0b6aa62
--- /dev/null
+++ b/V02/UpgradeLog.XML
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/V02/_UpgradeReport_Files/UpgradeReport.css b/V02/_UpgradeReport_Files/UpgradeReport.css
new file mode 100644
index 0000000..3411f63
--- /dev/null
+++ b/V02/_UpgradeReport_Files/UpgradeReport.css
@@ -0,0 +1,207 @@
+BODY
+{
+ BACKGROUND-COLOR: white;
+ FONT-FAMILY: "Verdana", sans-serif;
+ FONT-SIZE: 100%;
+ MARGIN-LEFT: 0px;
+ MARGIN-TOP: 0px
+}
+P
+{
+ FONT-FAMILY: "Verdana", sans-serif;
+ FONT-SIZE: 70%;
+ LINE-HEIGHT: 12pt;
+ MARGIN-BOTTOM: 0px;
+ MARGIN-LEFT: 10px;
+ MARGIN-TOP: 10px
+}
+.note
+{
+ BACKGROUND-COLOR: #ffffff;
+ COLOR: #336699;
+ FONT-FAMILY: "Verdana", sans-serif;
+ FONT-SIZE: 100%;
+ MARGIN-BOTTOM: 0px;
+ MARGIN-LEFT: 0px;
+ MARGIN-TOP: 0px;
+ PADDING-RIGHT: 10px
+}
+.infotable
+{
+ BACKGROUND-COLOR: #f0f0e0;
+ BORDER-BOTTOM: #ffffff 0px solid;
+ BORDER-COLLAPSE: collapse;
+ BORDER-LEFT: #ffffff 0px solid;
+ BORDER-RIGHT: #ffffff 0px solid;
+ BORDER-TOP: #ffffff 0px solid;
+ FONT-SIZE: 70%;
+ MARGIN-LEFT: 10px
+}
+.issuetable
+{
+ BACKGROUND-COLOR: #ffffe8;
+ BORDER-COLLAPSE: collapse;
+ COLOR: #000000;
+ FONT-SIZE: 100%;
+ MARGIN-BOTTOM: 10px;
+ MARGIN-LEFT: 13px;
+ MARGIN-TOP: 0px
+}
+.issuetitle
+{
+ BACKGROUND-COLOR: #ffffff;
+ BORDER-BOTTOM: #dcdcdc 1px solid;
+ BORDER-TOP: #dcdcdc 1px;
+ COLOR: #003366;
+ FONT-WEIGHT: normal
+}
+.header
+{
+ BACKGROUND-COLOR: #cecf9c;
+ BORDER-BOTTOM: #ffffff 1px solid;
+ BORDER-LEFT: #ffffff 1px solid;
+ BORDER-RIGHT: #ffffff 1px solid;
+ BORDER-TOP: #ffffff 1px solid;
+ COLOR: #000000;
+ FONT-WEIGHT: bold
+}
+.issuehdr
+{
+ BACKGROUND-COLOR: #E0EBF5;
+ BORDER-BOTTOM: #dcdcdc 1px solid;
+ BORDER-TOP: #dcdcdc 1px solid;
+ COLOR: #000000;
+ FONT-WEIGHT: normal
+}
+.issuenone
+{
+ BACKGROUND-COLOR: #ffffff;
+ BORDER-BOTTOM: 0px;
+ BORDER-LEFT: 0px;
+ BORDER-RIGHT: 0px;
+ BORDER-TOP: 0px;
+ COLOR: #000000;
+ FONT-WEIGHT: normal
+}
+.content
+{
+ BACKGROUND-COLOR: #e7e7ce;
+ BORDER-BOTTOM: #ffffff 1px solid;
+ BORDER-LEFT: #ffffff 1px solid;
+ BORDER-RIGHT: #ffffff 1px solid;
+ BORDER-TOP: #ffffff 1px solid;
+ PADDING-LEFT: 3px
+}
+.issuecontent
+{
+ BACKGROUND-COLOR: #ffffff;
+ BORDER-BOTTOM: #dcdcdc 1px solid;
+ BORDER-TOP: #dcdcdc 1px solid;
+ PADDING-LEFT: 3px
+}
+A:link
+{
+ COLOR: #cc6633;
+ TEXT-DECORATION: underline
+}
+A:visited
+{
+ COLOR: #cc6633;
+}
+A:active
+{
+ COLOR: #cc6633;
+}
+A:hover
+{
+ COLOR: #cc3300;
+ TEXT-DECORATION: underline
+}
+H1
+{
+ BACKGROUND-COLOR: #003366;
+ BORDER-BOTTOM: #336699 6px solid;
+ COLOR: #ffffff;
+ FONT-SIZE: 130%;
+ FONT-WEIGHT: normal;
+ MARGIN: 0em 0em 0em -20px;
+ PADDING-BOTTOM: 8px;
+ PADDING-LEFT: 30px;
+ PADDING-TOP: 16px
+}
+H2
+{
+ COLOR: #000000;
+ FONT-SIZE: 80%;
+ FONT-WEIGHT: bold;
+ MARGIN-BOTTOM: 3px;
+ MARGIN-LEFT: 10px;
+ MARGIN-TOP: 20px;
+ PADDING-LEFT: 0px
+}
+H3
+{
+ COLOR: #000000;
+ FONT-SIZE: 80%;
+ FONT-WEIGHT: bold;
+ MARGIN-BOTTOM: -5px;
+ MARGIN-LEFT: 10px;
+ MARGIN-TOP: 20px
+}
+H4
+{
+ COLOR: #000000;
+ FONT-SIZE: 70%;
+ FONT-WEIGHT: bold;
+ MARGIN-BOTTOM: 0px;
+ MARGIN-TOP: 15px;
+ PADDING-BOTTOM: 0px
+}
+UL
+{
+ COLOR: #000000;
+ FONT-SIZE: 70%;
+ LIST-STYLE: square;
+ MARGIN-BOTTOM: 0pt;
+ MARGIN-TOP: 0pt
+}
+OL
+{
+ COLOR: #000000;
+ FONT-SIZE: 70%;
+ LIST-STYLE: square;
+ MARGIN-BOTTOM: 0pt;
+ MARGIN-TOP: 0pt
+}
+LI
+{
+ LIST-STYLE: square;
+ MARGIN-LEFT: 0px
+}
+.expandable
+{
+ CURSOR: hand
+}
+.expanded
+{
+ color: black
+}
+.collapsed
+{
+ DISPLAY: none
+}
+.foot
+{
+BACKGROUND-COLOR: #ffffff;
+BORDER-BOTTOM: #cecf9c 1px solid;
+BORDER-TOP: #cecf9c 2px solid
+}
+.settings
+{
+MARGIN-LEFT: 25PX;
+}
+.help
+{
+TEXT-ALIGN: right;
+margin-right: 10px;
+}
diff --git a/V02/_UpgradeReport_Files/UpgradeReport.xslt b/V02/_UpgradeReport_Files/UpgradeReport.xslt
new file mode 100644
index 0000000..6fb44ed
--- /dev/null
+++ b/V02/_UpgradeReport_Files/UpgradeReport.xslt
@@ -0,0 +1,232 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ : |
+
+
+
+
+
+
+
+
+ Konvertierungsbericht
+
+
+
+
+
+
+
+ Konvertierungsbericht -
+
+
+ Konvertierungsdauer:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Konvertierungseinstellungen
+ |
+
+
+
+
+
+
+
diff --git a/V02/_UpgradeReport_Files/UpgradeReport_Minus.gif b/V02/_UpgradeReport_Files/UpgradeReport_Minus.gif
new file mode 100644
index 0000000..17751cb
Binary files /dev/null and b/V02/_UpgradeReport_Files/UpgradeReport_Minus.gif differ
diff --git a/V02/_UpgradeReport_Files/UpgradeReport_Plus.gif b/V02/_UpgradeReport_Files/UpgradeReport_Plus.gif
new file mode 100644
index 0000000..f6009ca
Binary files /dev/null and b/V02/_UpgradeReport_Files/UpgradeReport_Plus.gif differ
diff --git a/V02/ddutil.cpp b/V02/ddutil.cpp
new file mode 100644
index 0000000..faccc24
--- /dev/null
+++ b/V02/ddutil.cpp
@@ -0,0 +1,1035 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: DirectDraw framewark classes. Feel free to use this class as a
+// starting point for adding extra functionality.
+//
+//
+// Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include
+#include "ddutil.h"
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::CDisplay()
+{
+ m_pDD = NULL;
+ m_pddsFrontBuffer = NULL;
+ m_pddsBackBuffer = NULL;
+ m_pddsBackBufferLeft = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ~CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::~CDisplay()
+{
+ DestroyObjects();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DestroyObjects()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::DestroyObjects()
+{
+ SAFE_RELEASE( m_pddsBackBufferLeft );
+ SAFE_RELEASE( m_pddsBackBuffer );
+ SAFE_RELEASE( m_pddsFrontBuffer );
+
+ if( m_pDD )
+ m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL );
+
+ SAFE_RELEASE( m_pDD );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateFullScreenDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth,
+ DWORD dwHeight, DWORD dwBPP )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ // Set the display mode
+ if( FAILED( m_pDD->SetDisplayMode( dwWidth, dwHeight, dwBPP, 0, 0 ) ) )
+ return E_FAIL;
+
+ // Create primary surface (with backbuffer attached)
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
+ DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE;
+ ddsd.dwBackBufferCount = 1;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer,
+ NULL ) ) )
+ return E_FAIL;
+
+ // Get a pointer to the back buffer
+ DDSCAPS2 ddscaps;
+ ZeroMemory( &ddscaps, sizeof( ddscaps ) );
+ ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
+
+ if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
+ &m_pddsBackBuffer ) ) )
+ return E_FAIL;
+
+ m_pddsBackBuffer->AddRef();
+
+ m_hWnd = hWnd;
+ m_bWindowed = FALSE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateWindowedDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_NORMAL );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ RECT rcWork;
+ RECT rc;
+ DWORD dwStyle;
+
+ // If we are still a WS_POPUP window we should convert to a normal app
+ // window so we look like a windows app.
+ dwStyle = GetWindowStyle( hWnd );
+ dwStyle &= ~WS_POPUP;
+ dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
+ SetWindowLong( hWnd, GWL_STYLE, dwStyle );
+
+ // Aet window size
+ SetRect( &rc, 0, 0, dwWidth, dwHeight );
+
+ AdjustWindowRectEx( &rc, GetWindowStyle(hWnd), GetMenu(hWnd) != NULL,
+ GetWindowExStyle(hWnd) );
+
+ SetWindowPos( hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
+ SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
+
+ // Make sure our window does not hang outside of the work area
+ SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWork, 0 );
+ GetWindowRect( hWnd, &rc );
+ if( rc.left < rcWork.left ) rc.left = rcWork.left;
+ if( rc.top < rcWork.top ) rc.top = rcWork.top;
+ SetWindowPos( hWnd, NULL, rc.left, rc.top, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ LPDIRECTDRAWCLIPPER pcClipper;
+
+ // Create the primary surface
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+ if( FAILED( m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
+ return E_FAIL;
+
+ // Create the backbuffer surface
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = pcClipper->SetHWnd( 0, hWnd ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pcClipper ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ // Done with clipper
+ pcClipper->Release();
+
+ m_hWnd = hWnd;
+ m_bWindowed = TRUE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurface( CSurface** ppSurface,
+ DWORD dwWidth, DWORD dwHeight )
+{
+ if( NULL == m_pDD )
+ return E_POINTER;
+ if( NULL == ppSurface )
+ return E_INVALIDARG;
+
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromBitmap()
+// Desc: Create a DirectDrawSurface from a bitmap resource or bitmap file.
+// Use MAKEINTRESOURCE() to pass a constant into strBMP.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromBitmap( CSurface** ppSurface,
+ TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight )
+{
+ HRESULT hr;
+ HBITMAP hBMP = NULL;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+
+ if( m_pDD == NULL || strBMP == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = bmp.bmWidth;
+ ddsd.dwHeight = bmp.bmHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = (*ppSurface)->DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromText()
+// Desc: Creates a DirectDrawSurface from a text string using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromText( CSurface** ppSurface,
+ HFONT hFont, TCHAR* strText,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ LPDIRECTDRAWSURFACE7 pDDS = NULL;
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ SIZE sizeText;
+
+ if( m_pDD == NULL || strText == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ hDC = GetDC( NULL );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ GetTextExtentPoint32( hDC, strText, _tcslen(strText), &sizeText );
+ ReleaseDC( NULL, hDC );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = sizeText.cx;
+ ddsd.dwHeight = sizeText.cy;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ if( FAILED( hr = (*ppSurface)->DrawText( hFont, strText, 0, 0,
+ crBackground, crForeground ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Present()
+{
+ HRESULT hr;
+
+ if( NULL == m_pddsFrontBuffer && NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ while( 1 )
+ {
+ if( m_bWindowed )
+ hr = m_pddsFrontBuffer->Blt( &m_rcWindow, m_pddsBackBuffer,
+ NULL, DDBLT_WAIT, NULL );
+ else
+ hr = m_pddsFrontBuffer->Flip( NULL, 0 );
+
+ if( hr == DDERR_SURFACELOST )
+ {
+ m_pddsFrontBuffer->Restore();
+ m_pddsBackBuffer->Restore();
+ }
+
+ if( hr != DDERR_WASSTILLDRAWING )
+ return hr;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer || NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Set the palette before loading the bitmap
+ if( pPalette )
+ m_pddsFrontBuffer->SetPalette( pPalette );
+
+ CSurface backBuffer;
+ backBuffer.Create( m_pddsBackBuffer );
+
+ if( FAILED( backBuffer.DrawBitmap( hbm, 0, 0, 0, 0 ) ) )
+ return E_FAIL;
+
+ return Present();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, DDBLTFAST_SRCCOLORKEY );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds, RECT* prc,
+ DWORD dwFlags )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc )
+{
+ if( NULL == pSurface )
+ return E_INVALIDARG;
+
+ if( pSurface->IsColorKeyed() )
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, DDBLTFAST_SRCCOLORKEY );
+ else
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Clear( DWORD dwColor )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Erase the background
+ DDBLTFX ddbltfx;
+ ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
+ ddbltfx.dwSize = sizeof(ddbltfx);
+ ddbltfx.dwFillColor = dwColor;
+
+ return m_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::SetPalette( LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer )
+ return E_POINTER;
+
+ return m_pddsFrontBuffer->SetPalette( pPalette );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette,
+ const TCHAR* strBMP )
+{
+ HRSRC hResource = NULL;
+ RGBQUAD* pRGB = NULL;
+ BITMAPINFOHEADER* pbi = NULL;
+ PALETTEENTRY aPalette[256];
+ HANDLE hFile = NULL;
+ DWORD iColor;
+ DWORD dwColors;
+ BITMAPFILEHEADER bf;
+ BITMAPINFOHEADER bi;
+ DWORD dwBytesRead;
+
+ if( m_pDD == NULL || strBMP == NULL || ppPalette == NULL )
+ return E_INVALIDARG;
+
+ *ppPalette = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hResource = FindResource( NULL, strBMP, RT_BITMAP );
+ if( hResource )
+ {
+ pbi = (LPBITMAPINFOHEADER) LockResource( LoadResource( NULL, hResource ) );
+ if( NULL == pbi )
+ return E_FAIL;
+
+ pRGB = (RGBQUAD*) ( (BYTE*) pbi + pbi->biSize );
+
+ // Figure out how many colors there are
+ if( pbi == NULL || pbi->biSize < sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if( pbi->biBitCount > 8 )
+ dwColors = 0;
+ else if( pbi->biClrUsed == 0 )
+ dwColors = 1 << pbi->biBitCount;
+ else
+ dwColors = pbi->biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around.
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ aPalette[iColor].peRed = pRGB[iColor].rgbRed;
+ aPalette[iColor].peGreen = pRGB[iColor].rgbGreen;
+ aPalette[iColor].peBlue = pRGB[iColor].rgbBlue;
+ aPalette[iColor].peFlags = 0;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+ }
+
+ // Attempt to load bitmap as a file
+ hFile = CreateFile( strBMP, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
+ if( NULL == hFile )
+ return E_FAIL;
+
+ // Read the BITMAPFILEHEADER
+ ReadFile( hFile, &bf, sizeof(bf), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bf) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the BITMAPINFOHEADER
+ ReadFile( hFile, &bi, sizeof(bi), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bi) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the PALETTEENTRY
+ ReadFile( hFile, aPalette, sizeof(aPalette), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(aPalette) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ CloseHandle( hFile );
+
+ // Figure out how many colors there are
+ if( bi.biSize != sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if (bi.biBitCount > 8)
+ dwColors = 0;
+ else if (bi.biClrUsed == 0)
+ dwColors = 1 << bi.biBitCount;
+ else
+ dwColors = bi.biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around since DirectDraw uses RGB
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ BYTE r = aPalette[iColor].peRed;
+ aPalette[iColor].peRed = aPalette[iColor].peBlue;
+ aPalette[iColor].peBlue = r;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::UpdateBounds()
+{
+ if( m_bWindowed )
+ {
+ GetClientRect( m_hWnd, &m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow+1 );
+ }
+ else
+ {
+ SetRect( &m_rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN) );
+ }
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::InitClipper
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::InitClipper()
+{
+ LPDIRECTDRAWCLIPPER pClipper;
+ HRESULT hr;
+
+ // Create a clipper when using GDI to draw on the primary surface
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pClipper, NULL ) ) )
+ return hr;
+
+ pClipper->SetHWnd( 0, m_hWnd );
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pClipper ) ) )
+ return hr;
+
+ // We can release the clipper now since g_pDDSPrimary
+ // now maintains a ref count on the clipper
+ SAFE_RELEASE( pClipper );
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::CSurface()
+{
+ m_pdds = NULL;
+ m_bColorKeyed = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::~CSurface()
+{
+ SAFE_RELEASE( m_pdds );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAWSURFACE7 pdds )
+{
+ m_pdds = pdds;
+
+ if( m_pdds )
+ {
+ m_pdds->AddRef();
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_ddsd.dwSize = sizeof(m_ddsd);
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd )
+{
+ HRESULT hr;
+
+ // Create the DDraw surface
+ if( FAILED( hr = pDD->CreateSurface( pddsd, &m_pdds, NULL ) ) )
+ return hr;
+
+ // Prepare the DDSURFACEDESC structure
+ m_ddsd.dwSize = sizeof(m_ddsd);
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Destroy()
+{
+ SAFE_RELEASE( m_pdds );
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawBitmap()
+// Desc: Draws a bitmap over an entire DirectDrawSurface, stretching the
+// bitmap if nessasary
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( HBITMAP hBMP,
+ DWORD dwBMPOriginX, DWORD dwBMPOriginY,
+ DWORD dwBMPWidth, DWORD dwBMPHeight )
+{
+ HDC hDCImage;
+ HDC hDC;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ if( hBMP == NULL || m_pdds == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ // Get the surface.description
+ ddsd.dwSize = sizeof(ddsd);
+ m_pdds->GetSurfaceDesc( &ddsd );
+
+ if( ddsd.ddpfPixelFormat.dwFlags == DDPF_FOURCC )
+ return E_NOTIMPL;
+
+ // Select bitmap into a memoryDC so we can use it.
+ hDCImage = CreateCompatibleDC( NULL );
+ if( NULL == hDCImage )
+ return E_FAIL;
+
+ SelectObject( hDCImage, hBMP );
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Use the passed size, unless zero
+ dwBMPWidth = ( dwBMPWidth == 0 ) ? bmp.bmWidth : dwBMPWidth;
+ dwBMPHeight = ( dwBMPHeight == 0 ) ? bmp.bmHeight : dwBMPHeight;
+
+ // Stretch the bitmap to cover this surface
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ StretchBlt( hDC, 0, 0,
+ ddsd.dwWidth, ddsd.dwHeight,
+ hDCImage, dwBMPOriginX, dwBMPOriginY,
+ dwBMPWidth, dwBMPHeight, SRCCOPY );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ DeleteDC( hDCImage );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawText()
+// Desc: Draws a text string on a DirectDraw surface using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawText( HFONT hFont, TCHAR* strText,
+ DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strText == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ // Set the background and foreground color
+ SetBkColor( hDC, crBackground );
+ SetTextColor( hDC, crForeground );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ // Use GDI to draw the text on the surface
+ TextOut( hDC, dwOriginX, dwOriginY, strText, _tcslen(strText) );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ReDrawBitmapOnSurface()
+// Desc: Load a bitmap from a file or resource into a DirectDraw surface.
+// normaly used to re-load a surface after a restore.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( TCHAR* strBMP,
+ DWORD dwDesiredWidth, DWORD dwDesiredHeight )
+{
+ HBITMAP hBMP;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strBMP == NULL )
+ return E_INVALIDARG;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP, IMAGE_BITMAP,
+ dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::SetColorKey( DWORD dwColorKey )
+{
+ if( NULL == m_pdds )
+ return E_POINTER;
+
+ m_bColorKeyed = TRUE;
+
+ DDCOLORKEY ddck;
+ ddck.dwColorSpaceLowValue = ConvertGDIColor( dwColorKey );
+ ddck.dwColorSpaceHighValue = ConvertGDIColor( dwColorKey );
+
+ return m_pdds->SetColorKey( DDCKEY_SRCBLT, &ddck );
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ConvertGDIColor()
+// Desc: Converts a GDI color (0x00bbggrr) into the equivalent color on a
+// DirectDrawSurface using its pixel format.
+//-----------------------------------------------------------------------------
+DWORD CSurface::ConvertGDIColor( COLORREF dwGDIColor )
+{
+ if( m_pdds == NULL )
+ return 0x00000000;
+
+ COLORREF rgbT;
+ HDC hdc;
+ DWORD dw = CLR_INVALID;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ // Use GDI SetPixel to color match for us
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK)
+ {
+ rgbT = GetPixel(hdc, 0, 0); // Save current pixel value
+ SetPixel(hdc, 0, 0, dwGDIColor); // Set our value
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ // Now lock the surface so we can read back the converted color
+ ddsd.dwSize = sizeof(ddsd);
+ hr = m_pdds->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
+ if( hr == DD_OK)
+ {
+ dw = *(DWORD *) ddsd.lpSurface;
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount < 32 ) // Mask it to bpp
+ dw &= ( 1 << ddsd.ddpfPixelFormat.dwRGBBitCount ) - 1;
+ m_pdds->Unlock(NULL);
+ }
+
+ // Now put the color that was there back.
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK )
+ {
+ SetPixel( hdc, 0, 0, rgbT );
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ return dw;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::GetBitMaskInfo()
+// Desc: Returns the number of bits and the shift in the bit mask
+//-----------------------------------------------------------------------------
+HRESULT CSurface::GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits )
+{
+ DWORD dwShift = 0;
+ DWORD dwBits = 0;
+
+ if( pdwShift == NULL || pdwBits == NULL )
+ return E_INVALIDARG;
+
+ if( dwBitMask )
+ {
+ while( (dwBitMask & 1) == 0 )
+ {
+ dwShift++;
+ dwBitMask >>= 1;
+ }
+ }
+
+ while( (dwBitMask & 1) != 0 )
+ {
+ dwBits++;
+ dwBitMask >>= 1;
+ }
+
+ *pdwShift = dwShift;
+ *pdwBits = dwBits;
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V02/ddutil.h b/V02/ddutil.h
new file mode 100644
index 0000000..61fb0be
--- /dev/null
+++ b/V02/ddutil.h
@@ -0,0 +1,140 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: Routines for loading bitmap and palettes from resources
+//
+// Copyright (C) 1998-1999 Microsoft Corporation. All Rights Reserved.
+//-----------------------------------------------------------------------------
+#ifndef DDUTIL_H
+#define DDUTIL_H
+
+#include
+#include
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes defined in this header file
+//-----------------------------------------------------------------------------
+class CDisplay;
+class CSurface;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Flags for the CDisplay and CSurface methods
+//-----------------------------------------------------------------------------
+#define DSURFACELOCK_READ
+#define DSURFACELOCK_WRITE
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CDisplay
+// Desc: Class to handle all DDraw aspects of a display, including creation of
+// front and back buffers, creating offscreen surfaces and palettes,
+// and blitting surface and displaying bitmaps.
+//-----------------------------------------------------------------------------
+class CDisplay
+{
+protected:
+ LPDIRECTDRAW7 m_pDD;
+ LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBufferLeft; // For stereo modes
+
+ HWND m_hWnd;
+ RECT m_rcWindow;
+ BOOL m_bWindowed;
+ BOOL m_bStereo;
+
+public:
+ CDisplay();
+ ~CDisplay();
+
+ // Access functions
+ HWND GetHWnd() { return m_hWnd; }
+ LPDIRECTDRAW7 GetDirectDraw() { return m_pDD; }
+ LPDIRECTDRAWSURFACE7 GetFrontBuffer() { return m_pddsFrontBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBuffer() { return m_pddsBackBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBufferLEft() { return m_pddsBackBufferLeft; }
+
+ // Status functions
+ BOOL IsWindowed() { return m_bWindowed; }
+ BOOL IsStereo() { return m_bStereo; }
+
+ // Creation/destruction methods
+ HRESULT CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight,
+ DWORD dwBPP );
+ HRESULT CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight );
+ HRESULT InitClipper();
+ HRESULT UpdateBounds();
+ virtual HRESULT DestroyObjects();
+
+ // Methods to create child objects
+ HRESULT CreateSurface( CSurface** ppSurface, DWORD dwWidth,
+ DWORD dwHeight );
+ HRESULT CreateSurfaceFromBitmap( CSurface** ppSurface, TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight );
+ HRESULT CreateSurfaceFromText( CSurface** ppSurface, HFONT hFont,
+ TCHAR* strText,
+ COLORREF crBackground,
+ COLORREF crForeground );
+ HRESULT CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette, const TCHAR* strBMP );
+
+ // Display methods
+ HRESULT Clear( DWORD dwColor = 0L );
+ HRESULT ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc = NULL );
+ HRESULT Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc=NULL, DWORD dwFlags=0 );
+ HRESULT Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc = NULL );
+ HRESULT ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette=NULL );
+ HRESULT SetPalette( LPDIRECTDRAWPALETTE pPalette );
+ HRESULT Present();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSurface
+// Desc: Class to handle aspects of a DirectDrawSurface.
+//-----------------------------------------------------------------------------
+class CSurface
+{
+ LPDIRECTDRAWSURFACE7 m_pdds;
+ DDSURFACEDESC2 m_ddsd;
+ BOOL m_bColorKeyed;
+
+public:
+ LPDIRECTDRAWSURFACE7 GetDDrawSurface() { return m_pdds; }
+ BOOL IsColorKeyed() { return m_bColorKeyed; }
+
+ HRESULT DrawBitmap( HBITMAP hBMP, DWORD dwBMPOriginX = 0, DWORD dwBMPOriginY = 0,
+ DWORD dwBMPWidth = 0, DWORD dwBMPHeight = 0 );
+ HRESULT DrawBitmap( TCHAR* strBMP, DWORD dwDesiredWidth, DWORD dwDesiredHeight );
+ HRESULT DrawText( HFONT hFont, TCHAR* strText, DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground );
+
+ HRESULT SetColorKey( DWORD dwColorKey );
+ DWORD ConvertGDIColor( COLORREF dwGDIColor );
+ static HRESULT GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits );
+
+ HRESULT Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd );
+ HRESULT Create( LPDIRECTDRAWSURFACE7 pdds );
+ HRESULT Destroy();
+
+ CSurface();
+ ~CSurface();
+};
+
+
+
+
+#endif // DDUTIL_H
+
diff --git a/V02/dsutil.cpp b/V02/dsutil.cpp
new file mode 100644
index 0000000..83c1512
--- /dev/null
+++ b/V02/dsutil.cpp
@@ -0,0 +1,1546 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.cpp
+//
+// Desc: DirectSound framework classes for reading and writing wav files and
+// playing them in DirectSound buffers. Feel free to use this class
+// as a starting point for adding extra functionality.
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CSoundManager()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSoundManager::CSoundManager()
+{
+ m_pDS = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::~CSoundManager()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSoundManager::~CSoundManager()
+{
+ SAFE_RELEASE( m_pDS );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Initialize()
+// Desc: Initializes the IDirectSound object and also sets the primary buffer
+// format. This function must be called before any others.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Initialize( HWND hWnd,
+ DWORD dwCoopLevel,
+ DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ SAFE_RELEASE( m_pDS );
+
+ // Create IDirectSound using the primary sound device
+ if( FAILED( hr = DirectSoundCreate8( NULL, &m_pDS, NULL ) ) )
+ return DXTRACE_ERR( TEXT("DirectSoundCreate8"), hr );
+
+ // Set DirectSound coop level
+ if( FAILED( hr = m_pDS->SetCooperativeLevel( hWnd, dwCoopLevel ) ) )
+ return DXTRACE_ERR( TEXT("SetCooperativeLevel"), hr );
+
+ // Set primary buffer format
+ SetPrimaryBufferFormat( dwPrimaryChannels, dwPrimaryFreq, dwPrimaryBitRate );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::SetPrimaryBufferFormat()
+// Desc: Set primary buffer to a specified format
+// For example, to set the primary buffer format to 22kHz stereo, 16-bit
+// then: dwPrimaryChannels = 2
+// dwPrimaryFreq = 22050,
+// dwPrimaryBitRate = 16
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::SetPrimaryBufferFormat( DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Get the primary buffer
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
+ dsbd.dwBufferBytes = 0;
+ dsbd.lpwfxFormat = NULL;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ WAVEFORMATEX wfx;
+ ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = (WORD) dwPrimaryChannels;
+ wfx.nSamplesPerSec = dwPrimaryFreq;
+ wfx.wBitsPerSample = (WORD) dwPrimaryBitRate;
+ wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+ if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )
+ return DXTRACE_ERR( TEXT("SetFormat"), hr );
+
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Get3DListenerInterface()
+// Desc: Returns the 3D listener interface associated with primary buffer.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener )
+{
+ HRESULT hr;
+ DSBUFFERDESC dsbdesc;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( ppDSListener == NULL )
+ return E_INVALIDARG;
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ *ppDSListener = NULL;
+
+ // Obtain primary buffer, asking it for 3D control
+ ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
+ dsbdesc.dwSize = sizeof(DSBUFFERDESC);
+ dsbdesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ if( FAILED( hr = pDSBPrimary->QueryInterface( IID_IDirectSound3DListener,
+ (VOID**)ppDSListener ) ) )
+ {
+ SAFE_RELEASE( pDSBPrimary );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ // Release the primary buffer, since it is not need anymore
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Create()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Create( CSound** ppSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ HRESULT hrRet = S_OK;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ if( pWaveFile->GetSize() == 0 )
+ {
+ // Wave is blank, so don't create it.
+ hr = E_FAIL;
+ goto LFail;
+ }
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = pWaveFile->GetSize();
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ // DirectSound is only guarenteed to play PCM data. Other
+ // formats may or may not work depending the sound card driver.
+ hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL );
+
+ // Be sure to return this error code if it occurs so the
+ // callers knows this happened.
+ if( hr == DS_NO_VIRTUALIZATION )
+ hrRet = DS_NO_VIRTUALIZATION;
+
+ if( FAILED(hr) )
+ {
+ // DSERR_BUFFERTOOSMALL will be returned if the buffer is
+ // less than DSBSIZE_FX_MIN (100ms) and the buffer is created
+ // with DSBCAPS_CTRLFX.
+ if( hr != DSERR_BUFFERTOOSMALL )
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return hrRet;
+
+LFail:
+ // Cleanup
+ SAFE_DELETE( pWaveFile );
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateFromMemory()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateFromMemory( CSound** ppSound,
+ BYTE* pbData,
+ ULONG ulDataSize,
+ LPWAVEFORMATEX pwfx,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbData == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->OpenFromMemory( pbData,ulDataSize, pwfx, WAVEFILE_READ );
+
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = ulDataSize;
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL ) ) )
+ {
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return S_OK;
+
+LFail:
+ // Cleanup
+
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateStreaming()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateStreaming( CStreamingSound** ppStreamingSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNotifyCount,
+ DWORD dwNotifySize,
+ HANDLE hNotifyEvent )
+{
+ HRESULT hr;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppStreamingSound == NULL || hNotifyEvent == NULL )
+ return E_INVALIDARG;
+
+ LPDIRECTSOUNDBUFFER pDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+ DSBPOSITIONNOTIFY* aPosNotify = NULL;
+ LPDIRECTSOUNDNOTIFY pDSNotify = NULL;
+
+ pWaveFile = new CWaveFile();
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ // Figure out how big the DSound buffer should be
+ dwDSBufferSize = dwNotifySize * dwNotifyCount;
+
+ // Set up the direct sound buffer. Request the NOTIFY flag, so
+ // that we are notified as the sound buffer plays. Note, that using this flag
+ // may limit the amount of hardware acceleration that can occur.
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags |
+ DSBCAPS_CTRLPOSITIONNOTIFY |
+ DSBCAPS_GETCURRENTPOSITION2;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBuffer, NULL ) ) )
+ {
+ // If wave format isn't then it will return
+ // either DSERR_BADFORMAT or E_INVALIDARG
+ if( hr == DSERR_BADFORMAT || hr == E_INVALIDARG )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("CreateSoundBuffer"), hr );
+
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ }
+
+ // Create the notification events, so that we know when to fill
+ // the buffer as the sound plays.
+ if( FAILED( hr = pDSBuffer->QueryInterface( IID_IDirectSoundNotify,
+ (VOID**)&pDSNotify ) ) )
+ {
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ];
+ if( aPosNotify == NULL )
+ return E_OUTOFMEMORY;
+
+ for( DWORD i = 0; i < dwNotifyCount; i++ )
+ {
+ aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
+ aPosNotify[i].hEventNotify = hNotifyEvent;
+ }
+
+ // Tell DirectSound when to notify us. The notification will come in the from
+ // of signaled events that are handled in WinMain()
+ if( FAILED( hr = pDSNotify->SetNotificationPositions( dwNotifyCount,
+ aPosNotify ) ) )
+ {
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("SetNotificationPositions"), hr );
+ }
+
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+
+ // Create the sound
+ *ppStreamingSound = new CStreamingSound( pDSBuffer, dwDSBufferSize, pWaveFile, dwNotifySize );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::CSound()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSound::CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize,
+ DWORD dwNumBuffers, CWaveFile* pWaveFile )
+{
+ DWORD i;
+
+ m_apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ for( i=0; iSetCurrentPosition(0);
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::~CSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSound::~CSound()
+{
+ for( DWORD i=0; iLock( 0, m_dwDSBufferSize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ NULL, NULL, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // Reset the wave file to the beginning
+ m_pWaveFile->ResetFile();
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwWavDataRead ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ if( dwWavDataRead == 0 )
+ {
+ // Wav is blank, so just fill with silence
+ FillMemory( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ else if( dwWavDataRead < dwDSLockedBufferSize )
+ {
+ // If the wav file was smaller than the DirectSound buffer,
+ // we need to fill the remainder of the buffer with data
+ if( bRepeatWavIfBufferLarger )
+ {
+ // Reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwWavDataRead; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full
+ // for very short files
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwWavDataRead );
+ if( FAILED(hr) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwWavDataRead;
+ }
+ }
+ else
+ {
+ // Don't repeat the wav file, just fill in silence
+ FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead,
+ dwDSLockedBufferSize - dwWavDataRead,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ }
+
+ // Unlock the buffer, we don't need it anymore.
+ pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::RestoreBuffer()
+// Desc: Restores the lost buffer. *pbWasRestored returns TRUE if the buffer was
+// restored. It can also NULL if the information is not needed.
+//-----------------------------------------------------------------------------
+HRESULT CSound::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored )
+{
+ HRESULT hr;
+
+ if( pDSB == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbWasRestored )
+ *pbWasRestored = FALSE;
+
+ DWORD dwStatus;
+ if( FAILED( hr = pDSB->GetStatus( &dwStatus ) ) )
+ return DXTRACE_ERR( TEXT("GetStatus"), hr );
+
+ if( dwStatus & DSBSTATUS_BUFFERLOST )
+ {
+ // Since the app could have just been activated, then
+ // DirectSound may not be giving us control yet, so
+ // the restoring the buffer may fail.
+ // If it does, sleep until DirectSound gives us control.
+ do
+ {
+ hr = pDSB->Restore();
+ if( hr == DSERR_BUFFERLOST )
+ Sleep( 10 );
+ }
+ while( hr = pDSB->Restore() );
+
+ if( pbWasRestored != NULL )
+ *pbWasRestored = TRUE;
+
+ return S_OK;
+ }
+ else
+ {
+ return S_FALSE;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetFreeBuffer()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetFreeBuffer()
+{
+ BOOL bIsPlaying = FALSE;
+ DWORD i;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( i=0; iGetStatus( &dwStatus );
+ if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
+ break;
+ }
+ }
+
+ if( i != m_dwNumBuffers )
+ return m_apDSBuffer[ i ];
+ else
+ return m_apDSBuffer[ rand() % m_dwNumBuffers ];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetBuffer()
+// Desc:
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetBuffer( DWORD dwIndex )
+{
+ if( m_apDSBuffer == NULL )
+ return NULL;
+ if( dwIndex >= m_dwNumBuffers )
+ return NULL;
+
+ return m_apDSBuffer[dwIndex];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Get3DBufferInterface()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSound::Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer )
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( dwIndex >= m_dwNumBuffers )
+ return E_INVALIDARG;
+
+ *ppDS3DBuffer = NULL;
+
+ return m_apDSBuffer[dwIndex]->QueryInterface( IID_IDirectSound3DBuffer,
+ (VOID**)ppDS3DBuffer );
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Play()
+// Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING
+// in the dwFlags to loop the sound
+//-----------------------------------------------------------------------------
+HRESULT CSound::Play( DWORD dwPriority, DWORD dwFlags )
+{
+ HRESULT hr;
+ BOOL bRestored;
+
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();
+
+ if( pDSB == NULL )
+ return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL );
+
+ // Restore the buffer if it was lost
+ if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+
+ // Make DirectSound do pre-processing on sound effects
+ Reset();
+ }
+
+ return pDSB->Play( 0, dwPriority, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Stop()
+// Desc: Stops the sound from playing
+//-----------------------------------------------------------------------------
+HRESULT CSound::Stop()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iStop();
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Reset()
+// Desc: Reset all of the sound buffers
+//-----------------------------------------------------------------------------
+HRESULT CSound::Reset()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iSetCurrentPosition( 0 );
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::IsSoundPlaying()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+BOOL CSound::IsSoundPlaying()
+{
+ BOOL bIsPlaying = FALSE;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( DWORD i=0; iGetStatus( &dwStatus );
+ bIsPlaying |= ( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );
+ }
+ }
+
+ return bIsPlaying;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::CStreamingSound()
+// Desc: Setups up a buffer so data can be streamed from the wave file into
+// buffer. This is very useful for large wav files that would take a
+// while to load. The buffer is initially filled with data, then
+// as sound is played the notification events are signaled and more data
+// is written into the buffer by calling HandleWaveStreamNotification()
+//-----------------------------------------------------------------------------
+CStreamingSound::CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize,
+ CWaveFile* pWaveFile, DWORD dwNotifySize )
+ : CSound( &pDSBuffer, dwDSBufferSize, 1, pWaveFile )
+{
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNotifySize = dwNotifySize;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::~CStreamingSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CStreamingSound::~CStreamingSound()
+{
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::HandleWaveStreamNotification()
+// Desc: Handle the notification that tell us to put more wav data in the
+// circular buffer
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::HandleWaveStreamNotification( BOOL bLoopedPlay )
+{
+ HRESULT hr;
+ DWORD dwCurrentPlayPos;
+ DWORD dwPlayDelta;
+ DWORD dwBytesWrittenToBuffer;
+ VOID* pDSLockedBuffer = NULL;
+ VOID* pDSLockedBuffer2 = NULL;
+ DWORD dwDSLockedBufferSize;
+ DWORD dwDSLockedBufferSize2;
+
+ if( m_apDSBuffer == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ return S_OK;
+ }
+
+ // Lock the DirectSound buffer
+ if( FAILED( hr = m_apDSBuffer[0]->Lock( m_dwNextWriteOffset, m_dwNotifySize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // m_dwDSBufferSize and m_dwNextWriteOffset are both multiples of m_dwNotifySize,
+ // it should the second buffer should never be valid
+ if( pDSLockedBuffer2 != NULL )
+ return E_UNEXPECTED;
+
+ if( !m_bFillNextNotificationWithSilence )
+ {
+ // Fill the DirectSound buffer with wav data
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+ }
+ else
+ {
+ // Fill the DirectSound buffer with silence
+ FillMemory( pDSLockedBuffer, dwDSLockedBufferSize,
+ (BYTE)( m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ dwBytesWrittenToBuffer = dwDSLockedBufferSize;
+ }
+
+ // If the number of bytes written is less than the
+ // amount we requested, we have a short file.
+ if( dwBytesWrittenToBuffer < dwDSLockedBufferSize )
+ {
+ if( !bLoopedPlay )
+ {
+ // Fill in silence for the rest of the buffer.
+ FillMemory( (BYTE*) pDSLockedBuffer + dwBytesWrittenToBuffer,
+ dwDSLockedBufferSize - dwBytesWrittenToBuffer,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+
+ // Any future notifications should just fill the buffer with silence
+ m_bFillNextNotificationWithSilence = TRUE;
+ }
+ else
+ {
+ // We are looping, so reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwBytesWrittenToBuffer; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full (for very short files).
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwBytesWrittenToBuffer;
+ }
+ }
+ }
+
+ // Unlock the DirectSound buffer
+ m_apDSBuffer[0]->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ // Figure out how much data has been played so far. When we have played
+ // passed the end of the file, we will either need to start filling the
+ // buffer with silence or starting reading from the beginning of the file,
+ // depending if the user wants to loop the sound
+ if( FAILED( hr = m_apDSBuffer[0]->GetCurrentPosition( &dwCurrentPlayPos, NULL ) ) )
+ return DXTRACE_ERR( TEXT("GetCurrentPosition"), hr );
+
+ // Check to see if the position counter looped
+ if( dwCurrentPlayPos < m_dwLastPlayPos )
+ dwPlayDelta = ( m_dwDSBufferSize - m_dwLastPlayPos ) + dwCurrentPlayPos;
+ else
+ dwPlayDelta = dwCurrentPlayPos - m_dwLastPlayPos;
+
+ m_dwPlayProgress += dwPlayDelta;
+ m_dwLastPlayPos = dwCurrentPlayPos;
+
+ // If we are now filling the buffer with silence, then we have found the end so
+ // check to see if the entire sound has played, if it has then stop the buffer.
+ if( m_bFillNextNotificationWithSilence )
+ {
+ // We don't want to cut off the sound before it's done playing.
+ if( m_dwPlayProgress >= m_pWaveFile->GetSize() )
+ {
+ m_apDSBuffer[0]->Stop();
+ }
+ }
+
+ // Update where the buffer will lock (for next time)
+ m_dwNextWriteOffset += dwDSLockedBufferSize;
+ m_dwNextWriteOffset %= m_dwDSBufferSize; // Circular buffer
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::Reset()
+// Desc: Resets the sound so it will begin playing at the beginning
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::Reset()
+{
+ HRESULT hr;
+
+ if( m_apDSBuffer[0] == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ }
+
+ m_pWaveFile->ResetFile();
+
+ return m_apDSBuffer[0]->SetCurrentPosition( 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::CWaveFile()
+// Desc: Constructs the class. Call Open() to open a wave file for reading.
+// Then call Read() as needed. Calling the destructor or Close()
+// will close the file.
+//-----------------------------------------------------------------------------
+CWaveFile::CWaveFile()
+{
+ m_pwfx = NULL;
+ m_hmmio = NULL;
+ m_dwSize = 0;
+ m_bIsReadingFromMemory = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::~CWaveFile()
+// Desc: Destructs the class
+//-----------------------------------------------------------------------------
+CWaveFile::~CWaveFile()
+{
+ Close();
+
+ if( !m_bIsReadingFromMemory )
+ SAFE_DELETE_ARRAY( m_pwfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Open()
+// Desc: Opens a wave file for reading
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ HRESULT hr;
+
+ m_dwFlags = dwFlags;
+ m_bIsReadingFromMemory = FALSE;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ if( strFileName == NULL )
+ return E_INVALIDARG;
+ SAFE_DELETE_ARRAY( m_pwfx );
+
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );
+
+ if( NULL == m_hmmio )
+ {
+ HRSRC hResInfo;
+ HGLOBAL hResData;
+ DWORD dwSize;
+ VOID* pvRes;
+
+ // Loading it as a file failed, so try it as a resource
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAVE") ) ) )
+ {
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAV") ) ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("FindResource"), E_FAIL );
+ }
+
+ if( NULL == ( hResData = LoadResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("LoadResource"), E_FAIL );
+
+ if( 0 == ( dwSize = SizeofResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("SizeofResource"), E_FAIL );
+
+ if( NULL == ( pvRes = LockResource( hResData ) ) )
+ return DXTRACE_ERR( TEXT("LockResource"), E_FAIL );
+
+ CHAR* pData = new CHAR[ dwSize ];
+ memcpy( pData, pvRes, dwSize );
+
+ MMIOINFO mmioInfo;
+ ZeroMemory( &mmioInfo, sizeof(mmioInfo) );
+ mmioInfo.fccIOProc = FOURCC_MEM;
+ mmioInfo.cchBuffer = dwSize;
+ mmioInfo.pchBuffer = (CHAR*) pData;
+
+ m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );
+ }
+
+ if( FAILED( hr = ReadMMIO() ) )
+ {
+ // ReadMMIO will fail if its an not a wave file
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR_NOMSGBOX( TEXT("ReadMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ // After the reset, the size of the wav file is m_ck.cksize so store it now
+ m_dwSize = m_ck.cksize;
+ }
+ else
+ {
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF |
+ MMIO_READWRITE |
+ MMIO_CREATE );
+ if( NULL == m_hmmio )
+ return DXTRACE_ERR( TEXT("mmioOpen"), E_FAIL );
+
+ if( FAILED( hr = WriteMMIO( pwfx ) ) )
+ {
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR( TEXT("WriteMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+ }
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::OpenFromMemory()
+// Desc: copy data to CWaveFile member variable from memory
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::OpenFromMemory( BYTE* pbData, ULONG ulDataSize,
+ WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ m_pwfx = pwfx;
+ m_ulDataSize = ulDataSize;
+ m_pbData = pbData;
+ m_pbDataCur = m_pbData;
+ m_bIsReadingFromMemory = TRUE;
+
+ if( dwFlags != WAVEFILE_READ )
+ return E_NOTIMPL;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ReadMMIO()
+// Desc: Support function for reading from a multimedia I/O stream.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_pwfx.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ReadMMIO()
+{
+ MMCKINFO ckIn; // chunk info. for general use.
+ PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in.
+
+ m_pwfx = NULL;
+
+ if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Check to make sure this is a valid wave file
+ if( (m_ckRiff.ckid != FOURCC_RIFF) ||
+ (m_ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("mmioFOURCC"), E_FAIL );
+
+ // Search the input file for for the 'fmt ' chunk.
+ ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Expect the 'fmt' chunk to be at least as large as ;
+ // if there are extra parameters at the end, we'll ignore them
+ if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) )
+ return DXTRACE_ERR( TEXT("sizeof(PCMWAVEFORMAT)"), E_FAIL );
+
+ // Read the 'fmt ' chunk into .
+ if( mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat,
+ sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ // Allocate the waveformatex, but if its not pcm format, read the next
+ // word, and thats how many extra bytes to allocate.
+ if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )
+ {
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("m_pwfx"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = 0;
+ }
+ else
+ {
+ // Read in length of extra bytes.
+ WORD cbExtraBytes = 0L;
+ if( mmioRead( m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("new"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = cbExtraBytes;
+
+ // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
+ if( mmioRead( m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize))+sizeof(WORD)),
+ cbExtraBytes ) != cbExtraBytes )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+ }
+ }
+
+ // Ascend the input file out of the 'fmt ' chunk.
+ if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::GetSize()
+// Desc: Retuns the size of the read access wave file
+//-----------------------------------------------------------------------------
+DWORD CWaveFile::GetSize()
+{
+ return m_dwSize;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ResetFile()
+// Desc: Resets the internal m_ck pointer so reading starts from the
+// beginning of the file again
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ResetFile()
+{
+ if( m_bIsReadingFromMemory )
+ {
+ m_pbDataCur = m_pbData;
+ }
+ else
+ {
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ // Seek to the data
+ if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),
+ SEEK_SET ) )
+ return DXTRACE_ERR( TEXT("mmioSeek"), E_FAIL );
+
+ // Search the input file for the 'data' chunk.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ if( 0 != mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+ }
+ else
+ {
+ // Create the 'data' chunk that holds the waveform samples.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ m_ck.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( 0 != mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Read()
+// Desc: Reads section of data from a wave file into pBuffer and returns
+// how much read in pdwSizeRead, reading not more than dwSizeToRead.
+// This uses m_ck to determine where to start reading from. So
+// subsequent calls will be continue where the last left off unless
+// Reset() is called.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )
+{
+ if( m_bIsReadingFromMemory )
+ {
+ if( m_pbDataCur == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( (BYTE*)(m_pbDataCur + dwSizeToRead) >
+ (BYTE*)(m_pbData + m_ulDataSize) )
+ {
+ dwSizeToRead = m_ulDataSize - (DWORD)(m_pbDataCur - m_pbData);
+ }
+
+ CopyMemory( pBuffer, m_pbDataCur, dwSizeToRead );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = dwSizeToRead;
+
+ return S_OK;
+ }
+ else
+ {
+ MMIOINFO mmioinfoIn; // current status of m_hmmio
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pBuffer == NULL || pdwSizeRead == NULL )
+ return E_INVALIDARG;
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+
+ UINT cbDataIn = dwSizeToRead;
+ if( cbDataIn > m_ck.cksize )
+ cbDataIn = m_ck.cksize;
+
+ m_ck.cksize -= cbDataIn;
+
+ for( DWORD cT = 0; cT < cbDataIn; cT++ )
+ {
+ // Copy the bytes from the io to the buffer.
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ {
+ if( 0 != mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ return DXTRACE_ERR( TEXT("mmioinfoIn.pchNext"), E_FAIL );
+ }
+
+ // Actual copy.
+ *((BYTE*)pBuffer+cT) = *((BYTE*)mmioinfoIn.pchNext);
+ mmioinfoIn.pchNext++;
+ }
+
+ if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = cbDataIn;
+
+ return S_OK;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Close()
+// Desc: Closes the wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Close()
+{
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+ else
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( 0 != mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ // Ascend the output file out of the 'data' chunk -- this will cause
+ // the chunk size of the 'data' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Do this here instead...
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioSeek( m_hmmio, 0, SEEK_SET );
+
+ if( 0 != (INT)mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ m_ck.ckid = mmioFOURCC('f', 'a', 'c', 't');
+
+ if( 0 == mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ {
+ DWORD dwSamples = 0;
+ mmioWrite( m_hmmio, (HPSTR)&dwSamples, sizeof(DWORD) );
+ mmioAscend( m_hmmio, &m_ck, 0 );
+ }
+
+ // Ascend the output file out of the 'RIFF' chunk -- this will cause
+ // the chunk size of the 'RIFF' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::WriteMMIO()
+// Desc: Support function for reading from a multimedia I/O stream
+// pwfxDest is the WAVEFORMATEX for this new wave file.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_ck.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::WriteMMIO( WAVEFORMATEX *pwfxDest )
+{
+ DWORD dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile.
+ MMCKINFO ckOut1;
+
+ dwFactChunk = (DWORD)-1;
+
+ // Create the output file RIFF chunk of form type 'WAVE'.
+ m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');
+ m_ckRiff.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // We are now descended into the 'RIFF' chunk we just created.
+ // Now create the 'fmt ' chunk. Since we know the size of this chunk,
+ // specify it in the MMCKINFO structure so MMIO doesn't have to seek
+ // back and set the chunk size after ascending from the chunk.
+ m_ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ m_ck.cksize = sizeof(PCMWAVEFORMAT);
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type.
+ if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM )
+ {
+ if( mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+ else
+ {
+ // Write the variable length size.
+ if( (UINT)mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(*pwfxDest) + pwfxDest->cbSize ) !=
+ ( sizeof(*pwfxDest) + pwfxDest->cbSize ) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+
+ // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Now create the fact chunk, not required for PCM but nice to have. This is filled
+ // in when the close routine is called.
+ ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't');
+ ckOut1.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( mmioWrite( m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) !=
+ sizeof(dwFactChunk) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+
+ // Now ascend out of the fact chunk...
+ if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Write()
+// Desc: Writes data to the open wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Write( UINT nSizeToWrite, BYTE* pbSrcData, UINT* pnSizeWrote )
+{
+ UINT cT;
+
+ if( m_bIsReadingFromMemory )
+ return E_NOTIMPL;
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pnSizeWrote == NULL || pbSrcData == NULL )
+ return E_INVALIDARG;
+
+ *pnSizeWrote = 0;
+
+ for( cT = 0; cT < nSizeToWrite; cT++ )
+ {
+ if( m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite )
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+ if( 0 != mmioAdvance( m_hmmio, &m_mmioinfoOut, MMIO_WRITE ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+ }
+
+ *((BYTE*)m_mmioinfoOut.pchNext) = *((BYTE*)pbSrcData+cT);
+ (BYTE*)m_mmioinfoOut.pchNext++;
+
+ (*pnSizeWrote)++;
+ }
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V02/dsutil.h b/V02/dsutil.h
new file mode 100644
index 0000000..57d26df
--- /dev/null
+++ b/V02/dsutil.h
@@ -0,0 +1,170 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.h
+//
+// Desc:
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#ifndef DSUTIL_H
+#define DSUTIL_H
+
+#include
+#include
+#include
+#include
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes used by this header
+//-----------------------------------------------------------------------------
+class CSoundManager;
+class CSound;
+class CStreamingSound;
+class CWaveFile;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Typing macros
+//-----------------------------------------------------------------------------
+#define WAVEFILE_READ 1
+#define WAVEFILE_WRITE 2
+
+#define DSUtil_StopSound(s) { if(s) s->Stop(); }
+#define DSUtil_PlaySound(s) { if(s) s->Play( 0, 0 ); }
+#define DSUtil_PlaySoundLooping(s) { if(s) s->Play( 0, DSBPLAY_LOOPING ); }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSoundManager
+// Desc:
+//-----------------------------------------------------------------------------
+class CSoundManager
+{
+protected:
+ LPDIRECTSOUND8 m_pDS;
+
+public:
+ CSoundManager();
+ ~CSoundManager();
+
+ HRESULT Initialize( HWND hWnd, DWORD dwCoopLevel, DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate );
+ inline LPDIRECTSOUND GetDirectSound() { return m_pDS; }
+ HRESULT SetPrimaryBufferFormat( DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate );
+ HRESULT Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener );
+
+ HRESULT Create( CSound** ppSound, LPTSTR strWaveFileName, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
+ HRESULT CreateFromMemory( CSound** ppSound, BYTE* pbData, ULONG ulDataSize, LPWAVEFORMATEX pwfx, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
+ HRESULT CreateStreaming( CStreamingSound** ppStreamingSound, LPTSTR strWaveFileName, DWORD dwCreationFlags, GUID guid3DAlgorithm, DWORD dwNotifyCount, DWORD dwNotifySize, HANDLE hNotifyEvent );
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSound
+// Desc: Encapsulates functionality of a DirectSound buffer.
+//-----------------------------------------------------------------------------
+class CSound
+{
+protected:
+ LPDIRECTSOUNDBUFFER* m_apDSBuffer;
+ DWORD m_dwDSBufferSize;
+ CWaveFile* m_pWaveFile;
+ DWORD m_dwNumBuffers;
+
+ HRESULT RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored );
+
+public:
+ CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize, DWORD dwNumBuffers, CWaveFile* pWaveFile );
+ virtual ~CSound();
+
+ HRESULT Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer );
+ HRESULT FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger );
+ LPDIRECTSOUNDBUFFER GetFreeBuffer();
+ LPDIRECTSOUNDBUFFER GetBuffer( DWORD dwIndex );
+
+ HRESULT Play( DWORD dwPriority, DWORD dwFlags );
+ HRESULT Stop();
+ HRESULT Reset();
+ BOOL IsSoundPlaying();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CStreamingSound
+// Desc: Encapsulates functionality to play a wave file with DirectSound.
+// The Create() method loads a chunk of wave file into the buffer,
+// and as sound plays more is written to the buffer by calling
+// HandleWaveStreamNotification() whenever hNotifyEvent is signaled.
+//-----------------------------------------------------------------------------
+class CStreamingSound : public CSound
+{
+protected:
+ DWORD m_dwLastPlayPos;
+ DWORD m_dwPlayProgress;
+ DWORD m_dwNotifySize;
+ DWORD m_dwNextWriteOffset;
+ BOOL m_bFillNextNotificationWithSilence;
+
+public:
+ CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize, CWaveFile* pWaveFile, DWORD dwNotifySize );
+ ~CStreamingSound();
+
+ HRESULT HandleWaveStreamNotification( BOOL bLoopedPlay );
+ HRESULT Reset();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CWaveFile
+// Desc: Encapsulates reading or writing sound data to or from a wave file
+//-----------------------------------------------------------------------------
+class CWaveFile
+{
+public:
+ WAVEFORMATEX* m_pwfx; // Pointer to WAVEFORMATEX structure
+ HMMIO m_hmmio; // MM I/O handle for the WAVE
+ MMCKINFO m_ck; // Multimedia RIFF chunk
+ MMCKINFO m_ckRiff; // Use in opening a WAVE file
+ DWORD m_dwSize; // The size of the wave file
+ MMIOINFO m_mmioinfoOut;
+ DWORD m_dwFlags;
+ BOOL m_bIsReadingFromMemory;
+ BYTE* m_pbData;
+ BYTE* m_pbDataCur;
+ ULONG m_ulDataSize;
+
+protected:
+ HRESULT ReadMMIO();
+ HRESULT WriteMMIO( WAVEFORMATEX *pwfxDest );
+
+public:
+ CWaveFile();
+ ~CWaveFile();
+
+ HRESULT Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags );
+ HRESULT OpenFromMemory( BYTE* pbData, ULONG ulDataSize, WAVEFORMATEX* pwfx, DWORD dwFlags );
+ HRESULT Close();
+
+ HRESULT Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead );
+ HRESULT Write( UINT nSizeToWrite, BYTE* pbData, UINT* pnSizeWrote );
+
+ DWORD GetSize();
+ HRESULT ResetFile();
+ WAVEFORMATEX* GetFormat() { return m_pwfx; };
+};
+
+
+
+
+#endif // DSUTIL_H
diff --git a/V02/resource.h b/V02/resource.h
new file mode 100644
index 0000000..b65a9ae
--- /dev/null
+++ b/V02/resource.h
@@ -0,0 +1,25 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Demo.rc
+//
+#define IDI_MAIN 101
+#define IDR_MENU 102
+#define IDR_ACCEL 103
+#define IDM_EXIT 1001
+#define IDM_TEST 40024
+#define ID_ULTRIS_NEUESSPIEL 40025
+#define ID_ULTRIS_PAUSE 40026
+#define ID_ULTRIS_SOUND 40027
+#define otto 40028
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 132
+#define _APS_NEXT_COMMAND_VALUE 40029
+#define _APS_NEXT_CONTROL_VALUE 1019
+#define _APS_NEXT_SYMED_VALUE 104
+#endif
+#endif
diff --git a/V02/ul_adeck.bmp b/V02/ul_adeck.bmp
new file mode 100644
index 0000000..5f3b867
Binary files /dev/null and b/V02/ul_adeck.bmp differ
diff --git a/V02/ul_down.wav b/V02/ul_down.wav
new file mode 100644
index 0000000..84cf9e1
Binary files /dev/null and b/V02/ul_down.wav differ
diff --git a/V02/ul_dreh.WAV b/V02/ul_dreh.WAV
new file mode 100644
index 0000000..790ef8c
Binary files /dev/null and b/V02/ul_dreh.WAV differ
diff --git a/V02/ul_ende.WAV b/V02/ul_ende.WAV
new file mode 100644
index 0000000..43c73f0
Binary files /dev/null and b/V02/ul_ende.WAV differ
diff --git a/V02/ul_feld.bmp b/V02/ul_feld.bmp
new file mode 100644
index 0000000..3225b6b
Binary files /dev/null and b/V02/ul_feld.bmp differ
diff --git a/V02/ul_hgrnd.bmp b/V02/ul_hgrnd.bmp
new file mode 100644
index 0000000..c33b077
Binary files /dev/null and b/V02/ul_hgrnd.bmp differ
diff --git a/V02/ul_move.WAV b/V02/ul_move.WAV
new file mode 100644
index 0000000..22b2a99
Binary files /dev/null and b/V02/ul_move.WAV differ
diff --git a/V02/ul_prev.bmp b/V02/ul_prev.bmp
new file mode 100644
index 0000000..c791074
Binary files /dev/null and b/V02/ul_prev.bmp differ
diff --git a/V02/ul_row1.WAV b/V02/ul_row1.WAV
new file mode 100644
index 0000000..ab5bfca
Binary files /dev/null and b/V02/ul_row1.WAV differ
diff --git a/V02/ul_row2.WAV b/V02/ul_row2.WAV
new file mode 100644
index 0000000..671fc71
Binary files /dev/null and b/V02/ul_row2.WAV differ
diff --git a/V02/ul_start.WAV b/V02/ul_start.WAV
new file mode 100644
index 0000000..f66bfef
Binary files /dev/null and b/V02/ul_start.WAV differ
diff --git a/V02/ul_stein.bmp b/V02/ul_stein.bmp
new file mode 100644
index 0000000..dadb7a0
Binary files /dev/null and b/V02/ul_stein.bmp differ
diff --git a/V02/ul_win.wav b/V02/ul_win.wav
new file mode 100644
index 0000000..e11c880
Binary files /dev/null and b/V02/ul_win.wav differ
diff --git a/V02/ul_z0.bmp b/V02/ul_z0.bmp
new file mode 100644
index 0000000..10fe8a6
Binary files /dev/null and b/V02/ul_z0.bmp differ
diff --git a/V02/ul_z1.bmp b/V02/ul_z1.bmp
new file mode 100644
index 0000000..1ce2939
Binary files /dev/null and b/V02/ul_z1.bmp differ
diff --git a/V02/ul_z2.bmp b/V02/ul_z2.bmp
new file mode 100644
index 0000000..9006084
Binary files /dev/null and b/V02/ul_z2.bmp differ
diff --git a/V02/ul_z3.bmp b/V02/ul_z3.bmp
new file mode 100644
index 0000000..5710c67
Binary files /dev/null and b/V02/ul_z3.bmp differ
diff --git a/V02/ul_z4.bmp b/V02/ul_z4.bmp
new file mode 100644
index 0000000..11306ed
Binary files /dev/null and b/V02/ul_z4.bmp differ
diff --git a/V02/ul_z5.bmp b/V02/ul_z5.bmp
new file mode 100644
index 0000000..b4a22b5
Binary files /dev/null and b/V02/ul_z5.bmp differ
diff --git a/V02/ul_z6.bmp b/V02/ul_z6.bmp
new file mode 100644
index 0000000..62616d4
Binary files /dev/null and b/V02/ul_z6.bmp differ
diff --git a/V02/ul_z7.bmp b/V02/ul_z7.bmp
new file mode 100644
index 0000000..d9178df
Binary files /dev/null and b/V02/ul_z7.bmp differ
diff --git a/V02/ul_z8.bmp b/V02/ul_z8.bmp
new file mode 100644
index 0000000..98e1a18
Binary files /dev/null and b/V02/ul_z8.bmp differ
diff --git a/V02/ul_z9.bmp b/V02/ul_z9.bmp
new file mode 100644
index 0000000..e6245a3
Binary files /dev/null and b/V02/ul_z9.bmp differ
diff --git a/V03/Debug/BuildLog.htm b/V03/Debug/BuildLog.htm
new file mode 100644
index 0000000..ca33e11
Binary files /dev/null and b/V03/Debug/BuildLog.htm differ
diff --git a/V03/Debug/Demo.obj b/V03/Debug/Demo.obj
new file mode 100644
index 0000000..3102e21
Binary files /dev/null and b/V03/Debug/Demo.obj differ
diff --git a/V03/Debug/Demo.res b/V03/Debug/Demo.res
new file mode 100644
index 0000000..b67fe70
Binary files /dev/null and b/V03/Debug/Demo.res differ
diff --git a/V03/Debug/Ultris.exe b/V03/Debug/Ultris.exe
new file mode 100644
index 0000000..9584915
Binary files /dev/null and b/V03/Debug/Ultris.exe differ
diff --git a/V03/Debug/Ultris.exe.intermediate.manifest b/V03/Debug/Ultris.exe.intermediate.manifest
new file mode 100644
index 0000000..1c06b61
--- /dev/null
+++ b/V03/Debug/Ultris.exe.intermediate.manifest
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/V03/Debug/Ultris.pdb b/V03/Debug/Ultris.pdb
new file mode 100644
index 0000000..51aea47
Binary files /dev/null and b/V03/Debug/Ultris.pdb differ
diff --git a/V03/Debug/ddutil.obj b/V03/Debug/ddutil.obj
new file mode 100644
index 0000000..625ae4c
Binary files /dev/null and b/V03/Debug/ddutil.obj differ
diff --git a/V03/Debug/dsutil.obj b/V03/Debug/dsutil.obj
new file mode 100644
index 0000000..489cbd6
Binary files /dev/null and b/V03/Debug/dsutil.obj differ
diff --git a/V03/Debug/mt.dep b/V03/Debug/mt.dep
new file mode 100644
index 0000000..8e76a3c
--- /dev/null
+++ b/V03/Debug/mt.dep
@@ -0,0 +1 @@
+ die Manifestressource wurde zuletzt um 15:15:25,76 am 19.02.2010 aktualisiert
diff --git a/V03/Debug/vc90.idb b/V03/Debug/vc90.idb
new file mode 100644
index 0000000..fcc8185
Binary files /dev/null and b/V03/Debug/vc90.idb differ
diff --git a/V03/Debug/vc90.pdb b/V03/Debug/vc90.pdb
new file mode 100644
index 0000000..bde69d0
Binary files /dev/null and b/V03/Debug/vc90.pdb differ
diff --git a/V03/Demo.aps b/V03/Demo.aps
new file mode 100644
index 0000000..ed0edd6
Binary files /dev/null and b/V03/Demo.aps differ
diff --git a/V03/Demo.cpp b/V03/Demo.cpp
new file mode 100644
index 0000000..361fd0d
--- /dev/null
+++ b/V03/Demo.cpp
@@ -0,0 +1,409 @@
+# include
+# include
+# include
+# include
+# include "ddutil.h"
+# include "dsutil.h"
+# include "resource.h"
+
+const int ultris_nettobreite = 360; // Breite des Inneren des Haupfensters
+const int ultris_nettohoehe = 520; // Hoehe des Inneren des Hauptfensters
+int ultris_bruttobreite; // Breite des gesamten Haupfensters (incl. Rahmen)
+int ultris_bruttohoehe; // Hoehe des gesamten Haupfensters (incl. Rahmen)
+
+HINSTANCE ultris_instance; // Instanz der Ultris Applikation
+HWND ultris_window; // Das Hauptfenster von Ultris
+HMENU ultris_menu; // Das Menu von Ultris
+
+const int sound_start = 0; // Sound fuer neues Spiel
+const int sound_dreh = 1; // Sound bei Drehung
+const int sound_move = 2; // Sound bei rechts/links Bewegung
+const int sound_down = 3; // Sound bei Aufprall
+const int sound_row1 = 4; // Sound bei Abraeumen einer Reihe
+const int sound_row2 = 5; // Sound bei Abraeumen von mehreren Reihen
+const int sound_ende = 6; // Sound bei Spielende
+const int sound_win = 7; // Sound bei Eintrag in Highscore Tabelle
+const int anzahl_sounds = 8; // Anzahl Sounds
+
+char *soundfiles[anzahl_sounds] =
+ {
+ "ul_start.wav",
+ "ul_dreh.wav",
+ "ul_move.wav",
+ "ul_down.wav",
+ "ul_row1.wav",
+ "ul_row2.wav",
+ "ul_ende.wav",
+ "ul_win.wav"
+ };
+
+class sounds
+ {
+ private:
+ CSoundManager smgr;
+ CSound *snd[anzahl_sounds];
+ public:
+ int on;
+ sounds();
+ int init( HWND wnd);
+ void play( int snr);
+ ~sounds();
+ };
+
+sounds::sounds()
+ {
+ int i;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ snd[i] = 0;
+ on = 1;
+ }
+
+int sounds::init( HWND wnd)
+ {
+ HRESULT ret;
+ int i;
+
+ ret = smgr.Initialize( wnd, DSSCL_PRIORITY, 2, 22050, 16);
+ if( ret < 0)
+ return ret;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ {
+ ret = smgr.Create( snd+i, soundfiles[i]);
+ if( ret < 0)
+ return ret;
+ }
+ return S_OK;
+ }
+
+sounds::~sounds()
+ {
+ int i;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ {
+ if( snd[i])
+ delete snd[i];
+ }
+ }
+
+void sounds::play( int i)
+ {
+ if( !on)
+ return;
+ if( snd[i]->IsSoundPlaying())
+ {
+ snd[i]->Stop();
+ snd[i]->Reset();
+ }
+ snd[i]->Play(0,0);
+ }
+
+sounds ultris_sounds;
+
+
+// V3 Beginn
+class display
+ {
+ private:
+ CDisplay dsply;
+ CSurface *hgrnd;
+ CSurface *fldst;
+ CSurface *fllst;
+ CSurface *prvst;
+ CSurface *deckel;
+ CSurface *ziff[10];
+ public:
+ display();
+ void free_all();
+ ~display() {free_all();}
+ HRESULT init( HWND wnd);
+ void hintergrund() { dsply.Blt( 0, 0, hgrnd);}
+ void abdeckung() { dsply.Blt( 60, 0, deckel);}
+ void ziffer( int pos, int val) { dsply.Blt( 120+pos*20, 50, ziff[val]);}
+ void feldstein( int z, int s) { dsply.Blt( 80+s*20, 100+z*20, fldst);}
+ void fallstein( int z, int s, int offset) { dsply.Blt( 80+s*20, 100+z*20+offset, fllst);}
+ void prevstein( int p, int z, int s, int b, int h){ dsply.Blt( 290+s*15+(4-b)*15/2, 410-p*70+z*15+(4-h)*15/2, prvst);}
+ void update(){ dsply.UpdateBounds();}
+ HRESULT cooperative(){return dsply.GetDirectDraw()->TestCooperativeLevel();}
+ HRESULT restore();
+ HRESULT present();
+ };
+
+display::display()
+ {
+ int i;
+
+ hgrnd = 0;
+ fldst = 0;
+ fllst = 0;
+ prvst = 0;
+ deckel = 0;
+ for( i = 0; i < 10; i++)
+ ziff[i] = 0;
+ }
+
+void display::free_all()
+ {
+ int i;
+
+ if( hgrnd)
+ delete hgrnd;
+ if( fldst)
+ delete fldst;
+ if( fllst)
+ delete fllst;
+ if( prvst)
+ delete prvst;
+ if( deckel)
+ delete deckel;
+ for( i = 0; i < 10; i++)
+ {
+ if( ziff[i])
+ delete ziff[i];
+ }
+ }
+
+HRESULT display::init( HWND wnd)
+ {
+ HRESULT hr;
+ int i;
+ char fname[20];
+
+ hr = dsply.CreateWindowedDisplay( wnd, ultris_nettobreite, ultris_nettohoehe );
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &hgrnd, "ul_hgrnd.bmp", ultris_nettobreite, ultris_nettohoehe);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &fldst, "ul_feld.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &fllst, "ul_stein.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &prvst, "ul_prev.bmp", 15, 15);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &deckel, "ul_adeck.bmp", 240, 100);
+ if( hr < 0)
+ return hr;
+ for( i = 0; i < 10; i++)
+ {
+ sprintf( fname, "ul_z%d.bmp", i);
+ hr = dsply.CreateSurfaceFromBitmap( &ziff[i], fname, 20, 40);
+ if( hr < 0)
+ return hr;
+ }
+ return S_OK;
+ }
+
+
+HRESULT display::restore()
+ {
+ HRESULT hr;
+ int i;
+ char fname[20];
+ LPDIRECTDRAWPALETTE pal = 0;
+
+ hr = dsply.GetDirectDraw()->RestoreAllSurfaces();
+ if( hr < 0)
+ return hr;
+ hr = hgrnd->DrawBitmap( "ul_hgrnd.bmp", ultris_nettobreite, ultris_nettohoehe);
+ if( hr < 0)
+ return hr;
+ hr = fldst->DrawBitmap( "ul_feld.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = fllst->DrawBitmap( "ul_stein.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = prvst->DrawBitmap( "ul_prev.bmp", 15, 15);
+ if( hr < 0)
+ return hr;
+ hr = deckel->DrawBitmap( "ul_adeck.bmp", 240, 100);
+ if( hr < 0)
+ return hr;
+
+ for( i = 0; i < 10; i++)
+ {
+ sprintf( fname, "ul_z%d.bmp", i);
+ hr = ziff[i]->DrawBitmap( fname, 20, 40);
+ if( hr < 0)
+ return hr;
+ }
+ return S_OK;
+ }
+
+HRESULT display::present()
+ {
+ HRESULT hr;
+
+ hr = dsply.Present();
+ if( hr == DDERR_SURFACELOST )
+ return restore();
+ return hr;
+ }
+
+display ultris_display;
+
+// V3 Ende
+/*
+** ultris_windowhandler
+*/
+LRESULT CALLBACK ultris_windowhandler( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+ {
+ switch(msg)
+ {
+ case WM_COMMAND:
+ switch( LOWORD( wParam))
+ {
+ case IDM_EXIT:
+ PostMessage( hWnd, WM_CLOSE, 0, 0);
+ return 0;
+ case ID_ULTRIS_SOUND:
+ ultris_sounds.on = !ultris_sounds.on;
+ CheckMenuItem( ultris_menu, ID_ULTRIS_SOUND, ultris_sounds.on ? MF_CHECKED:MF_UNCHECKED);
+ return 0;
+ case IDM_TEST: // Testcode
+ return 0;
+ }
+ break;
+ case WM_GETMINMAXINFO:
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.x = ((MINMAXINFO *)lParam)->ptMaxTrackSize.x = ultris_bruttobreite;
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.y = ((MINMAXINFO *)lParam)->ptMaxTrackSize.y = ultris_bruttohoehe;
+ return 0;
+ case WM_DESTROY:
+ PostQuitMessage( 0);
+ return 0;
+// V3 Beginn
+ case WM_MOVE:
+ ultris_display.update();
+ return 0;
+ case WM_PAINT:
+ int i;
+
+ ultris_display.hintergrund();
+ ultris_display.abdeckung();
+ for( i = 0; i < 6; i++)
+ ultris_display.ziffer( i, i+1);
+ for( i = 0; i < 10; i++)
+ ultris_display.feldstein( 19-i, i);
+ for( i = 0; i < 10; i++)
+ ultris_display.fallstein( 1, i, 2*i);
+ for( i = 0; i < 4; i++)
+ ultris_display.prevstein( 3, 0, i, 4, 1);
+ ultris_display.present();
+ break;
+// V3 Ende
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+ }
+
+/*
+** WinMain
+*/
+int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow)
+ {
+ MSG msg;
+ HACCEL acc;
+ WNDCLASSEX wcx;
+
+ ultris_instance = hInst;
+
+ wcx.cbSize = sizeof( wcx);
+ wcx.lpszClassName = TEXT( "Ultris");
+ wcx.lpfnWndProc = ultris_windowhandler;
+ wcx.style = CS_VREDRAW | CS_HREDRAW;
+ wcx.hInstance = hInst;
+ wcx.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hIconSm = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hCursor = LoadCursor( NULL, IDC_ARROW);
+ wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wcx.lpszMenuName = MAKEINTRESOURCE( IDR_MENU);
+ wcx.cbClsExtra = 0;
+ wcx.cbWndExtra = 0;
+
+ if( !RegisterClassEx( &wcx))
+ return 0;
+
+ acc = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_ACCEL));
+
+ ultris_bruttohoehe = ultris_nettohoehe + 2*GetSystemMetrics( SM_CYSIZEFRAME)
+ + GetSystemMetrics( SM_CYMENU)
+ + GetSystemMetrics( SM_CYCAPTION);
+ ultris_bruttobreite = ultris_nettobreite + 2*GetSystemMetrics( SM_CXSIZEFRAME);
+
+ ultris_window = CreateWindowEx( 0, TEXT( "Ultris"), TEXT( "Ultris"), WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ ultris_bruttobreite, ultris_bruttohoehe, NULL, NULL, hInst, NULL);
+ if( !ultris_window)
+ return 0;
+
+ ultris_menu = GetMenu( ultris_window);
+
+ if( ultris_sounds.init( ultris_window) < 0)
+ {
+ MessageBox( ultris_window, "Fehler beim Initialisieren der Sounds", "Ultris-Fehlermeldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
+ return 0;
+ }
+ CheckMenuItem( ultris_menu, ID_ULTRIS_SOUND, ultris_sounds.on ? MF_CHECKED:MF_UNCHECKED);
+
+// V3 Beginn
+ if( ultris_display.init( ultris_window) < 0)
+ {
+ MessageBox( ultris_window, "Fehler beim Initialisieren der Grafik", "Ultris-Fehlermeldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
+ return 0;
+ }
+// V3 Ende
+
+ MoveWindow( ultris_window, (GetSystemMetrics(SM_CXSCREEN)-ultris_bruttobreite)/2,
+ (GetSystemMetrics(SM_CYSCREEN)-ultris_bruttohoehe)/2,
+ ultris_bruttobreite, ultris_bruttohoehe, TRUE);
+
+ ShowWindow( ultris_window, nCmdShow);
+
+ while( TRUE)
+ {
+ if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE))
+ {
+ if( GetMessage( &msg, NULL, 0, 0 ) == 0)
+ return 0; // Message ist WM_QUIT
+
+ if( TranslateAccelerator( ultris_window, acc, &msg) == 0)
+ {
+ TranslateMessage( &msg);
+ DispatchMessage( &msg);
+ }
+ }
+ else
+ {
+// V3 Beginn
+ HRESULT hr;
+ hr = ultris_display.cooperative();
+ if( hr < 0)
+ {
+ switch( hr )
+ {
+ case DDERR_EXCLUSIVEMODEALREADYSET:
+ Sleep(10);
+ break;
+ case DDERR_WRONGMODE:
+ ultris_display.free_all();
+ ultris_display.init( ultris_window);
+ PostMessage( ultris_window, WM_PAINT, 0, 0);
+ break;
+ }
+ }
+ else
+ {
+ // Hier koennen wir uns um das Spiel kuemmern
+ }
+// V3 Ende
+ }
+ }
+ }
+
+
+
diff --git a/V03/Demo.h b/V03/Demo.h
new file mode 100644
index 0000000..a19fa69
--- /dev/null
+++ b/V03/Demo.h
@@ -0,0 +1,12 @@
+
+#if !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
+#define AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "resource.h"
+
+
+#endif // !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
diff --git a/V03/Demo.ncb b/V03/Demo.ncb
new file mode 100644
index 0000000..32eb411
Binary files /dev/null and b/V03/Demo.ncb differ
diff --git a/V03/Demo.plg b/V03/Demo.plg
new file mode 100644
index 0000000..e44be48
--- /dev/null
+++ b/V03/Demo.plg
@@ -0,0 +1,48 @@
+
+
+
+Erstellungsprotokoll
+
+--------------------Konfiguration: Demo - Win32 Debug--------------------
+
+Befehlszeilen
+Creating command line "rc.exe /l 0x407 /fo"Debug/Demo.res" /d "_DEBUG" "C:\uk\FHG\Vorlesungen\GSP\Programme\Ultris\V03\Demo.rc""
+Erstellen der temporären Datei "C:\DOKUME~1\uk\LOKALE~1\Temp\RSP6.tmp" mit Inhalten
+[
+/nologo /MLd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FR"Debug/" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c
+"C:\uk\FHG\Vorlesungen\GSP\Programme\Ultris\V03\Demo.cpp"
+"C:\uk\FHG\Vorlesungen\GSP\Programme\Ultris\V03\ddutil.cpp"
+"C:\uk\FHG\Vorlesungen\GSP\Programme\Ultris\V03\dsutil.cpp"
+"C:\uk\FHG\Vorlesungen\GSP\Programme\Ultris\V03\dxutil.cpp"
+]
+Creating command line "cl.exe @C:\DOKUME~1\uk\LOKALE~1\Temp\RSP6.tmp"
+Erstellen der temporären Datei "C:\DOKUME~1\uk\LOKALE~1\Temp\RSP7.tmp" mit Inhalten
+[
+winmm.lib dxguid.lib dxerr8.lib ddraw.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib dsound.lib /nologo /subsystem:windows /incremental:yes /pdb:"Debug/Ultris.pdb" /debug /machine:I386 /out:"Debug/Ultris.exe" /pdbtype:sept
+.\Debug\Demo.obj
+.\Debug\ddutil.obj
+.\Debug\dsutil.obj
+.\Debug\dxutil.obj
+.\Debug\Demo.res
+]
+Erstellen der Befehlzeile "link.exe @C:\DOKUME~1\uk\LOKALE~1\Temp\RSP7.tmp"
+Ausgabefenster
+Ressourcen werden kompiliert...
+Kompilierung läuft...
+Demo.cpp
+ddutil.cpp
+dsutil.cpp
+dxutil.cpp
+Generieren von Code...
+Linker-Vorgang läuft...
+Erstellen der Befehlzeile "bscmake.exe /nologo /o"Debug/Demo.bsc" .\Debug\Demo.sbr .\Debug\ddutil.sbr .\Debug\dsutil.sbr .\Debug\dxutil.sbr"
+Browse-Informationsdatei wird erstellt...
+Ausgabefenster
+
+
+
+Ergebnisse
+Ultris.exe - 0 Fehler, 0 Warnung(en)
+
+
+
diff --git a/V03/Demo.rc b/V03/Demo.rc
new file mode 100644
index 0000000..2d4c8ed
--- /dev/null
+++ b/V03/Demo.rc
@@ -0,0 +1,115 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include
+#include
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Deutsch (Deutschland) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+#ifdef _WIN32
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU MENU DISCARDABLE
+BEGIN
+ POPUP "Ultris"
+ BEGIN
+ MENUITEM "Neues Spiel", ID_ULTRIS_NEUESSPIEL
+ MENUITEM "Pause", ID_ULTRIS_PAUSE
+ MENUITEM "Sound", ID_ULTRIS_SOUND
+ MENUITEM SEPARATOR
+ MENUITEM "Ende", IDM_EXIT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MAIN ICON DISCARDABLE "Icon.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCEL ACCELERATORS DISCARDABLE
+BEGIN
+ "T", IDM_TEST, VIRTKEY, CONTROL, NOINVERT
+ VK_ESCAPE, IDM_EXIT, VIRTKEY, NOINVERT
+ VK_F5, ID_ULTRIS_SOUND, VIRTKEY, NOINVERT
+END
+
+#endif // Deutsch (Deutschland) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Englisch (USA) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include \r\n"
+ "#include \0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Englisch (USA) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/V03/Demo.sln b/V03/Demo.sln
new file mode 100644
index 0000000..a190765
--- /dev/null
+++ b/V03/Demo.sln
@@ -0,0 +1,19 @@
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo.vcproj", "{EF6643BF-F016-4942-A188-0478C19AB31F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {EF6643BF-F016-4942-A188-0478C19AB31F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {EF6643BF-F016-4942-A188-0478C19AB31F}.Debug|Win32.Build.0 = Debug|Win32
+ {EF6643BF-F016-4942-A188-0478C19AB31F}.Release|Win32.ActiveCfg = Release|Win32
+ {EF6643BF-F016-4942-A188-0478C19AB31F}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/V03/Demo.sln.old b/V03/Demo.sln.old
new file mode 100644
index 0000000..5033808
--- /dev/null
+++ b/V03/Demo.sln.old
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo.vcproj", "{EF6643BF-F016-4942-A188-0478C19AB31F}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {EF6643BF-F016-4942-A188-0478C19AB31F}.Debug.ActiveCfg = Debug|Win32
+ {EF6643BF-F016-4942-A188-0478C19AB31F}.Debug.Build.0 = Debug|Win32
+ {EF6643BF-F016-4942-A188-0478C19AB31F}.Release.ActiveCfg = Release|Win32
+ {EF6643BF-F016-4942-A188-0478C19AB31F}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/V03/Demo.suo b/V03/Demo.suo
new file mode 100644
index 0000000..a7d6603
Binary files /dev/null and b/V03/Demo.suo differ
diff --git a/V03/Demo.suo.old b/V03/Demo.suo.old
new file mode 100644
index 0000000..f4e2393
Binary files /dev/null and b/V03/Demo.suo.old differ
diff --git a/V03/Demo.vcproj b/V03/Demo.vcproj
new file mode 100644
index 0000000..d18cfb7
--- /dev/null
+++ b/V03/Demo.vcproj
@@ -0,0 +1,300 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V03/Demo.vcproj.7.10.old b/V03/Demo.vcproj.7.10.old
new file mode 100644
index 0000000..98ce341
--- /dev/null
+++ b/V03/Demo.vcproj.7.10.old
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V03/Demo.vcproj.SASCHA.Sasch.user b/V03/Demo.vcproj.SASCHA.Sasch.user
new file mode 100644
index 0000000..86f2a09
--- /dev/null
+++ b/V03/Demo.vcproj.SASCHA.Sasch.user
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V03/Icon.ico b/V03/Icon.ico
new file mode 100644
index 0000000..7a53f63
Binary files /dev/null and b/V03/Icon.ico differ
diff --git a/V03/UpgradeLog.XML b/V03/UpgradeLog.XML
new file mode 100644
index 0000000..3b0d64f
--- /dev/null
+++ b/V03/UpgradeLog.XML
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/V03/_UpgradeReport_Files/UpgradeReport.css b/V03/_UpgradeReport_Files/UpgradeReport.css
new file mode 100644
index 0000000..3411f63
--- /dev/null
+++ b/V03/_UpgradeReport_Files/UpgradeReport.css
@@ -0,0 +1,207 @@
+BODY
+{
+ BACKGROUND-COLOR: white;
+ FONT-FAMILY: "Verdana", sans-serif;
+ FONT-SIZE: 100%;
+ MARGIN-LEFT: 0px;
+ MARGIN-TOP: 0px
+}
+P
+{
+ FONT-FAMILY: "Verdana", sans-serif;
+ FONT-SIZE: 70%;
+ LINE-HEIGHT: 12pt;
+ MARGIN-BOTTOM: 0px;
+ MARGIN-LEFT: 10px;
+ MARGIN-TOP: 10px
+}
+.note
+{
+ BACKGROUND-COLOR: #ffffff;
+ COLOR: #336699;
+ FONT-FAMILY: "Verdana", sans-serif;
+ FONT-SIZE: 100%;
+ MARGIN-BOTTOM: 0px;
+ MARGIN-LEFT: 0px;
+ MARGIN-TOP: 0px;
+ PADDING-RIGHT: 10px
+}
+.infotable
+{
+ BACKGROUND-COLOR: #f0f0e0;
+ BORDER-BOTTOM: #ffffff 0px solid;
+ BORDER-COLLAPSE: collapse;
+ BORDER-LEFT: #ffffff 0px solid;
+ BORDER-RIGHT: #ffffff 0px solid;
+ BORDER-TOP: #ffffff 0px solid;
+ FONT-SIZE: 70%;
+ MARGIN-LEFT: 10px
+}
+.issuetable
+{
+ BACKGROUND-COLOR: #ffffe8;
+ BORDER-COLLAPSE: collapse;
+ COLOR: #000000;
+ FONT-SIZE: 100%;
+ MARGIN-BOTTOM: 10px;
+ MARGIN-LEFT: 13px;
+ MARGIN-TOP: 0px
+}
+.issuetitle
+{
+ BACKGROUND-COLOR: #ffffff;
+ BORDER-BOTTOM: #dcdcdc 1px solid;
+ BORDER-TOP: #dcdcdc 1px;
+ COLOR: #003366;
+ FONT-WEIGHT: normal
+}
+.header
+{
+ BACKGROUND-COLOR: #cecf9c;
+ BORDER-BOTTOM: #ffffff 1px solid;
+ BORDER-LEFT: #ffffff 1px solid;
+ BORDER-RIGHT: #ffffff 1px solid;
+ BORDER-TOP: #ffffff 1px solid;
+ COLOR: #000000;
+ FONT-WEIGHT: bold
+}
+.issuehdr
+{
+ BACKGROUND-COLOR: #E0EBF5;
+ BORDER-BOTTOM: #dcdcdc 1px solid;
+ BORDER-TOP: #dcdcdc 1px solid;
+ COLOR: #000000;
+ FONT-WEIGHT: normal
+}
+.issuenone
+{
+ BACKGROUND-COLOR: #ffffff;
+ BORDER-BOTTOM: 0px;
+ BORDER-LEFT: 0px;
+ BORDER-RIGHT: 0px;
+ BORDER-TOP: 0px;
+ COLOR: #000000;
+ FONT-WEIGHT: normal
+}
+.content
+{
+ BACKGROUND-COLOR: #e7e7ce;
+ BORDER-BOTTOM: #ffffff 1px solid;
+ BORDER-LEFT: #ffffff 1px solid;
+ BORDER-RIGHT: #ffffff 1px solid;
+ BORDER-TOP: #ffffff 1px solid;
+ PADDING-LEFT: 3px
+}
+.issuecontent
+{
+ BACKGROUND-COLOR: #ffffff;
+ BORDER-BOTTOM: #dcdcdc 1px solid;
+ BORDER-TOP: #dcdcdc 1px solid;
+ PADDING-LEFT: 3px
+}
+A:link
+{
+ COLOR: #cc6633;
+ TEXT-DECORATION: underline
+}
+A:visited
+{
+ COLOR: #cc6633;
+}
+A:active
+{
+ COLOR: #cc6633;
+}
+A:hover
+{
+ COLOR: #cc3300;
+ TEXT-DECORATION: underline
+}
+H1
+{
+ BACKGROUND-COLOR: #003366;
+ BORDER-BOTTOM: #336699 6px solid;
+ COLOR: #ffffff;
+ FONT-SIZE: 130%;
+ FONT-WEIGHT: normal;
+ MARGIN: 0em 0em 0em -20px;
+ PADDING-BOTTOM: 8px;
+ PADDING-LEFT: 30px;
+ PADDING-TOP: 16px
+}
+H2
+{
+ COLOR: #000000;
+ FONT-SIZE: 80%;
+ FONT-WEIGHT: bold;
+ MARGIN-BOTTOM: 3px;
+ MARGIN-LEFT: 10px;
+ MARGIN-TOP: 20px;
+ PADDING-LEFT: 0px
+}
+H3
+{
+ COLOR: #000000;
+ FONT-SIZE: 80%;
+ FONT-WEIGHT: bold;
+ MARGIN-BOTTOM: -5px;
+ MARGIN-LEFT: 10px;
+ MARGIN-TOP: 20px
+}
+H4
+{
+ COLOR: #000000;
+ FONT-SIZE: 70%;
+ FONT-WEIGHT: bold;
+ MARGIN-BOTTOM: 0px;
+ MARGIN-TOP: 15px;
+ PADDING-BOTTOM: 0px
+}
+UL
+{
+ COLOR: #000000;
+ FONT-SIZE: 70%;
+ LIST-STYLE: square;
+ MARGIN-BOTTOM: 0pt;
+ MARGIN-TOP: 0pt
+}
+OL
+{
+ COLOR: #000000;
+ FONT-SIZE: 70%;
+ LIST-STYLE: square;
+ MARGIN-BOTTOM: 0pt;
+ MARGIN-TOP: 0pt
+}
+LI
+{
+ LIST-STYLE: square;
+ MARGIN-LEFT: 0px
+}
+.expandable
+{
+ CURSOR: hand
+}
+.expanded
+{
+ color: black
+}
+.collapsed
+{
+ DISPLAY: none
+}
+.foot
+{
+BACKGROUND-COLOR: #ffffff;
+BORDER-BOTTOM: #cecf9c 1px solid;
+BORDER-TOP: #cecf9c 2px solid
+}
+.settings
+{
+MARGIN-LEFT: 25PX;
+}
+.help
+{
+TEXT-ALIGN: right;
+margin-right: 10px;
+}
diff --git a/V03/_UpgradeReport_Files/UpgradeReport.xslt b/V03/_UpgradeReport_Files/UpgradeReport.xslt
new file mode 100644
index 0000000..6fb44ed
--- /dev/null
+++ b/V03/_UpgradeReport_Files/UpgradeReport.xslt
@@ -0,0 +1,232 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ : |
+
+
+
+
+
+
+
+
+ Konvertierungsbericht
+
+
+
+
+
+
+
+ Konvertierungsbericht -
+
+
+ Konvertierungsdauer:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Konvertierungseinstellungen
+ |
+
+
+
+
+
+
+
diff --git a/V03/_UpgradeReport_Files/UpgradeReport_Minus.gif b/V03/_UpgradeReport_Files/UpgradeReport_Minus.gif
new file mode 100644
index 0000000..17751cb
Binary files /dev/null and b/V03/_UpgradeReport_Files/UpgradeReport_Minus.gif differ
diff --git a/V03/_UpgradeReport_Files/UpgradeReport_Plus.gif b/V03/_UpgradeReport_Files/UpgradeReport_Plus.gif
new file mode 100644
index 0000000..f6009ca
Binary files /dev/null and b/V03/_UpgradeReport_Files/UpgradeReport_Plus.gif differ
diff --git a/V03/ddutil.cpp b/V03/ddutil.cpp
new file mode 100644
index 0000000..faccc24
--- /dev/null
+++ b/V03/ddutil.cpp
@@ -0,0 +1,1035 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: DirectDraw framewark classes. Feel free to use this class as a
+// starting point for adding extra functionality.
+//
+//
+// Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include
+#include "ddutil.h"
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::CDisplay()
+{
+ m_pDD = NULL;
+ m_pddsFrontBuffer = NULL;
+ m_pddsBackBuffer = NULL;
+ m_pddsBackBufferLeft = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ~CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::~CDisplay()
+{
+ DestroyObjects();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DestroyObjects()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::DestroyObjects()
+{
+ SAFE_RELEASE( m_pddsBackBufferLeft );
+ SAFE_RELEASE( m_pddsBackBuffer );
+ SAFE_RELEASE( m_pddsFrontBuffer );
+
+ if( m_pDD )
+ m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL );
+
+ SAFE_RELEASE( m_pDD );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateFullScreenDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth,
+ DWORD dwHeight, DWORD dwBPP )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ // Set the display mode
+ if( FAILED( m_pDD->SetDisplayMode( dwWidth, dwHeight, dwBPP, 0, 0 ) ) )
+ return E_FAIL;
+
+ // Create primary surface (with backbuffer attached)
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
+ DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE;
+ ddsd.dwBackBufferCount = 1;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer,
+ NULL ) ) )
+ return E_FAIL;
+
+ // Get a pointer to the back buffer
+ DDSCAPS2 ddscaps;
+ ZeroMemory( &ddscaps, sizeof( ddscaps ) );
+ ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
+
+ if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
+ &m_pddsBackBuffer ) ) )
+ return E_FAIL;
+
+ m_pddsBackBuffer->AddRef();
+
+ m_hWnd = hWnd;
+ m_bWindowed = FALSE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateWindowedDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_NORMAL );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ RECT rcWork;
+ RECT rc;
+ DWORD dwStyle;
+
+ // If we are still a WS_POPUP window we should convert to a normal app
+ // window so we look like a windows app.
+ dwStyle = GetWindowStyle( hWnd );
+ dwStyle &= ~WS_POPUP;
+ dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
+ SetWindowLong( hWnd, GWL_STYLE, dwStyle );
+
+ // Aet window size
+ SetRect( &rc, 0, 0, dwWidth, dwHeight );
+
+ AdjustWindowRectEx( &rc, GetWindowStyle(hWnd), GetMenu(hWnd) != NULL,
+ GetWindowExStyle(hWnd) );
+
+ SetWindowPos( hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
+ SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
+
+ // Make sure our window does not hang outside of the work area
+ SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWork, 0 );
+ GetWindowRect( hWnd, &rc );
+ if( rc.left < rcWork.left ) rc.left = rcWork.left;
+ if( rc.top < rcWork.top ) rc.top = rcWork.top;
+ SetWindowPos( hWnd, NULL, rc.left, rc.top, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ LPDIRECTDRAWCLIPPER pcClipper;
+
+ // Create the primary surface
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+ if( FAILED( m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
+ return E_FAIL;
+
+ // Create the backbuffer surface
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = pcClipper->SetHWnd( 0, hWnd ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pcClipper ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ // Done with clipper
+ pcClipper->Release();
+
+ m_hWnd = hWnd;
+ m_bWindowed = TRUE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurface( CSurface** ppSurface,
+ DWORD dwWidth, DWORD dwHeight )
+{
+ if( NULL == m_pDD )
+ return E_POINTER;
+ if( NULL == ppSurface )
+ return E_INVALIDARG;
+
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromBitmap()
+// Desc: Create a DirectDrawSurface from a bitmap resource or bitmap file.
+// Use MAKEINTRESOURCE() to pass a constant into strBMP.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromBitmap( CSurface** ppSurface,
+ TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight )
+{
+ HRESULT hr;
+ HBITMAP hBMP = NULL;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+
+ if( m_pDD == NULL || strBMP == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = bmp.bmWidth;
+ ddsd.dwHeight = bmp.bmHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = (*ppSurface)->DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromText()
+// Desc: Creates a DirectDrawSurface from a text string using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromText( CSurface** ppSurface,
+ HFONT hFont, TCHAR* strText,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ LPDIRECTDRAWSURFACE7 pDDS = NULL;
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ SIZE sizeText;
+
+ if( m_pDD == NULL || strText == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ hDC = GetDC( NULL );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ GetTextExtentPoint32( hDC, strText, _tcslen(strText), &sizeText );
+ ReleaseDC( NULL, hDC );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = sizeText.cx;
+ ddsd.dwHeight = sizeText.cy;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ if( FAILED( hr = (*ppSurface)->DrawText( hFont, strText, 0, 0,
+ crBackground, crForeground ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Present()
+{
+ HRESULT hr;
+
+ if( NULL == m_pddsFrontBuffer && NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ while( 1 )
+ {
+ if( m_bWindowed )
+ hr = m_pddsFrontBuffer->Blt( &m_rcWindow, m_pddsBackBuffer,
+ NULL, DDBLT_WAIT, NULL );
+ else
+ hr = m_pddsFrontBuffer->Flip( NULL, 0 );
+
+ if( hr == DDERR_SURFACELOST )
+ {
+ m_pddsFrontBuffer->Restore();
+ m_pddsBackBuffer->Restore();
+ }
+
+ if( hr != DDERR_WASSTILLDRAWING )
+ return hr;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer || NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Set the palette before loading the bitmap
+ if( pPalette )
+ m_pddsFrontBuffer->SetPalette( pPalette );
+
+ CSurface backBuffer;
+ backBuffer.Create( m_pddsBackBuffer );
+
+ if( FAILED( backBuffer.DrawBitmap( hbm, 0, 0, 0, 0 ) ) )
+ return E_FAIL;
+
+ return Present();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, DDBLTFAST_SRCCOLORKEY );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds, RECT* prc,
+ DWORD dwFlags )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc )
+{
+ if( NULL == pSurface )
+ return E_INVALIDARG;
+
+ if( pSurface->IsColorKeyed() )
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, DDBLTFAST_SRCCOLORKEY );
+ else
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Clear( DWORD dwColor )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Erase the background
+ DDBLTFX ddbltfx;
+ ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
+ ddbltfx.dwSize = sizeof(ddbltfx);
+ ddbltfx.dwFillColor = dwColor;
+
+ return m_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::SetPalette( LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer )
+ return E_POINTER;
+
+ return m_pddsFrontBuffer->SetPalette( pPalette );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette,
+ const TCHAR* strBMP )
+{
+ HRSRC hResource = NULL;
+ RGBQUAD* pRGB = NULL;
+ BITMAPINFOHEADER* pbi = NULL;
+ PALETTEENTRY aPalette[256];
+ HANDLE hFile = NULL;
+ DWORD iColor;
+ DWORD dwColors;
+ BITMAPFILEHEADER bf;
+ BITMAPINFOHEADER bi;
+ DWORD dwBytesRead;
+
+ if( m_pDD == NULL || strBMP == NULL || ppPalette == NULL )
+ return E_INVALIDARG;
+
+ *ppPalette = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hResource = FindResource( NULL, strBMP, RT_BITMAP );
+ if( hResource )
+ {
+ pbi = (LPBITMAPINFOHEADER) LockResource( LoadResource( NULL, hResource ) );
+ if( NULL == pbi )
+ return E_FAIL;
+
+ pRGB = (RGBQUAD*) ( (BYTE*) pbi + pbi->biSize );
+
+ // Figure out how many colors there are
+ if( pbi == NULL || pbi->biSize < sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if( pbi->biBitCount > 8 )
+ dwColors = 0;
+ else if( pbi->biClrUsed == 0 )
+ dwColors = 1 << pbi->biBitCount;
+ else
+ dwColors = pbi->biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around.
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ aPalette[iColor].peRed = pRGB[iColor].rgbRed;
+ aPalette[iColor].peGreen = pRGB[iColor].rgbGreen;
+ aPalette[iColor].peBlue = pRGB[iColor].rgbBlue;
+ aPalette[iColor].peFlags = 0;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+ }
+
+ // Attempt to load bitmap as a file
+ hFile = CreateFile( strBMP, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
+ if( NULL == hFile )
+ return E_FAIL;
+
+ // Read the BITMAPFILEHEADER
+ ReadFile( hFile, &bf, sizeof(bf), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bf) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the BITMAPINFOHEADER
+ ReadFile( hFile, &bi, sizeof(bi), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bi) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the PALETTEENTRY
+ ReadFile( hFile, aPalette, sizeof(aPalette), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(aPalette) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ CloseHandle( hFile );
+
+ // Figure out how many colors there are
+ if( bi.biSize != sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if (bi.biBitCount > 8)
+ dwColors = 0;
+ else if (bi.biClrUsed == 0)
+ dwColors = 1 << bi.biBitCount;
+ else
+ dwColors = bi.biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around since DirectDraw uses RGB
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ BYTE r = aPalette[iColor].peRed;
+ aPalette[iColor].peRed = aPalette[iColor].peBlue;
+ aPalette[iColor].peBlue = r;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::UpdateBounds()
+{
+ if( m_bWindowed )
+ {
+ GetClientRect( m_hWnd, &m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow+1 );
+ }
+ else
+ {
+ SetRect( &m_rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN) );
+ }
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::InitClipper
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::InitClipper()
+{
+ LPDIRECTDRAWCLIPPER pClipper;
+ HRESULT hr;
+
+ // Create a clipper when using GDI to draw on the primary surface
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pClipper, NULL ) ) )
+ return hr;
+
+ pClipper->SetHWnd( 0, m_hWnd );
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pClipper ) ) )
+ return hr;
+
+ // We can release the clipper now since g_pDDSPrimary
+ // now maintains a ref count on the clipper
+ SAFE_RELEASE( pClipper );
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::CSurface()
+{
+ m_pdds = NULL;
+ m_bColorKeyed = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::~CSurface()
+{
+ SAFE_RELEASE( m_pdds );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAWSURFACE7 pdds )
+{
+ m_pdds = pdds;
+
+ if( m_pdds )
+ {
+ m_pdds->AddRef();
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_ddsd.dwSize = sizeof(m_ddsd);
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd )
+{
+ HRESULT hr;
+
+ // Create the DDraw surface
+ if( FAILED( hr = pDD->CreateSurface( pddsd, &m_pdds, NULL ) ) )
+ return hr;
+
+ // Prepare the DDSURFACEDESC structure
+ m_ddsd.dwSize = sizeof(m_ddsd);
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Destroy()
+{
+ SAFE_RELEASE( m_pdds );
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawBitmap()
+// Desc: Draws a bitmap over an entire DirectDrawSurface, stretching the
+// bitmap if nessasary
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( HBITMAP hBMP,
+ DWORD dwBMPOriginX, DWORD dwBMPOriginY,
+ DWORD dwBMPWidth, DWORD dwBMPHeight )
+{
+ HDC hDCImage;
+ HDC hDC;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ if( hBMP == NULL || m_pdds == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ // Get the surface.description
+ ddsd.dwSize = sizeof(ddsd);
+ m_pdds->GetSurfaceDesc( &ddsd );
+
+ if( ddsd.ddpfPixelFormat.dwFlags == DDPF_FOURCC )
+ return E_NOTIMPL;
+
+ // Select bitmap into a memoryDC so we can use it.
+ hDCImage = CreateCompatibleDC( NULL );
+ if( NULL == hDCImage )
+ return E_FAIL;
+
+ SelectObject( hDCImage, hBMP );
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Use the passed size, unless zero
+ dwBMPWidth = ( dwBMPWidth == 0 ) ? bmp.bmWidth : dwBMPWidth;
+ dwBMPHeight = ( dwBMPHeight == 0 ) ? bmp.bmHeight : dwBMPHeight;
+
+ // Stretch the bitmap to cover this surface
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ StretchBlt( hDC, 0, 0,
+ ddsd.dwWidth, ddsd.dwHeight,
+ hDCImage, dwBMPOriginX, dwBMPOriginY,
+ dwBMPWidth, dwBMPHeight, SRCCOPY );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ DeleteDC( hDCImage );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawText()
+// Desc: Draws a text string on a DirectDraw surface using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawText( HFONT hFont, TCHAR* strText,
+ DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strText == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ // Set the background and foreground color
+ SetBkColor( hDC, crBackground );
+ SetTextColor( hDC, crForeground );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ // Use GDI to draw the text on the surface
+ TextOut( hDC, dwOriginX, dwOriginY, strText, _tcslen(strText) );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ReDrawBitmapOnSurface()
+// Desc: Load a bitmap from a file or resource into a DirectDraw surface.
+// normaly used to re-load a surface after a restore.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( TCHAR* strBMP,
+ DWORD dwDesiredWidth, DWORD dwDesiredHeight )
+{
+ HBITMAP hBMP;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strBMP == NULL )
+ return E_INVALIDARG;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP, IMAGE_BITMAP,
+ dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::SetColorKey( DWORD dwColorKey )
+{
+ if( NULL == m_pdds )
+ return E_POINTER;
+
+ m_bColorKeyed = TRUE;
+
+ DDCOLORKEY ddck;
+ ddck.dwColorSpaceLowValue = ConvertGDIColor( dwColorKey );
+ ddck.dwColorSpaceHighValue = ConvertGDIColor( dwColorKey );
+
+ return m_pdds->SetColorKey( DDCKEY_SRCBLT, &ddck );
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ConvertGDIColor()
+// Desc: Converts a GDI color (0x00bbggrr) into the equivalent color on a
+// DirectDrawSurface using its pixel format.
+//-----------------------------------------------------------------------------
+DWORD CSurface::ConvertGDIColor( COLORREF dwGDIColor )
+{
+ if( m_pdds == NULL )
+ return 0x00000000;
+
+ COLORREF rgbT;
+ HDC hdc;
+ DWORD dw = CLR_INVALID;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ // Use GDI SetPixel to color match for us
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK)
+ {
+ rgbT = GetPixel(hdc, 0, 0); // Save current pixel value
+ SetPixel(hdc, 0, 0, dwGDIColor); // Set our value
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ // Now lock the surface so we can read back the converted color
+ ddsd.dwSize = sizeof(ddsd);
+ hr = m_pdds->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
+ if( hr == DD_OK)
+ {
+ dw = *(DWORD *) ddsd.lpSurface;
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount < 32 ) // Mask it to bpp
+ dw &= ( 1 << ddsd.ddpfPixelFormat.dwRGBBitCount ) - 1;
+ m_pdds->Unlock(NULL);
+ }
+
+ // Now put the color that was there back.
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK )
+ {
+ SetPixel( hdc, 0, 0, rgbT );
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ return dw;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::GetBitMaskInfo()
+// Desc: Returns the number of bits and the shift in the bit mask
+//-----------------------------------------------------------------------------
+HRESULT CSurface::GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits )
+{
+ DWORD dwShift = 0;
+ DWORD dwBits = 0;
+
+ if( pdwShift == NULL || pdwBits == NULL )
+ return E_INVALIDARG;
+
+ if( dwBitMask )
+ {
+ while( (dwBitMask & 1) == 0 )
+ {
+ dwShift++;
+ dwBitMask >>= 1;
+ }
+ }
+
+ while( (dwBitMask & 1) != 0 )
+ {
+ dwBits++;
+ dwBitMask >>= 1;
+ }
+
+ *pdwShift = dwShift;
+ *pdwBits = dwBits;
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V03/ddutil.h b/V03/ddutil.h
new file mode 100644
index 0000000..61fb0be
--- /dev/null
+++ b/V03/ddutil.h
@@ -0,0 +1,140 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: Routines for loading bitmap and palettes from resources
+//
+// Copyright (C) 1998-1999 Microsoft Corporation. All Rights Reserved.
+//-----------------------------------------------------------------------------
+#ifndef DDUTIL_H
+#define DDUTIL_H
+
+#include
+#include
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes defined in this header file
+//-----------------------------------------------------------------------------
+class CDisplay;
+class CSurface;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Flags for the CDisplay and CSurface methods
+//-----------------------------------------------------------------------------
+#define DSURFACELOCK_READ
+#define DSURFACELOCK_WRITE
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CDisplay
+// Desc: Class to handle all DDraw aspects of a display, including creation of
+// front and back buffers, creating offscreen surfaces and palettes,
+// and blitting surface and displaying bitmaps.
+//-----------------------------------------------------------------------------
+class CDisplay
+{
+protected:
+ LPDIRECTDRAW7 m_pDD;
+ LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBufferLeft; // For stereo modes
+
+ HWND m_hWnd;
+ RECT m_rcWindow;
+ BOOL m_bWindowed;
+ BOOL m_bStereo;
+
+public:
+ CDisplay();
+ ~CDisplay();
+
+ // Access functions
+ HWND GetHWnd() { return m_hWnd; }
+ LPDIRECTDRAW7 GetDirectDraw() { return m_pDD; }
+ LPDIRECTDRAWSURFACE7 GetFrontBuffer() { return m_pddsFrontBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBuffer() { return m_pddsBackBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBufferLEft() { return m_pddsBackBufferLeft; }
+
+ // Status functions
+ BOOL IsWindowed() { return m_bWindowed; }
+ BOOL IsStereo() { return m_bStereo; }
+
+ // Creation/destruction methods
+ HRESULT CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight,
+ DWORD dwBPP );
+ HRESULT CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight );
+ HRESULT InitClipper();
+ HRESULT UpdateBounds();
+ virtual HRESULT DestroyObjects();
+
+ // Methods to create child objects
+ HRESULT CreateSurface( CSurface** ppSurface, DWORD dwWidth,
+ DWORD dwHeight );
+ HRESULT CreateSurfaceFromBitmap( CSurface** ppSurface, TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight );
+ HRESULT CreateSurfaceFromText( CSurface** ppSurface, HFONT hFont,
+ TCHAR* strText,
+ COLORREF crBackground,
+ COLORREF crForeground );
+ HRESULT CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette, const TCHAR* strBMP );
+
+ // Display methods
+ HRESULT Clear( DWORD dwColor = 0L );
+ HRESULT ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc = NULL );
+ HRESULT Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc=NULL, DWORD dwFlags=0 );
+ HRESULT Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc = NULL );
+ HRESULT ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette=NULL );
+ HRESULT SetPalette( LPDIRECTDRAWPALETTE pPalette );
+ HRESULT Present();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSurface
+// Desc: Class to handle aspects of a DirectDrawSurface.
+//-----------------------------------------------------------------------------
+class CSurface
+{
+ LPDIRECTDRAWSURFACE7 m_pdds;
+ DDSURFACEDESC2 m_ddsd;
+ BOOL m_bColorKeyed;
+
+public:
+ LPDIRECTDRAWSURFACE7 GetDDrawSurface() { return m_pdds; }
+ BOOL IsColorKeyed() { return m_bColorKeyed; }
+
+ HRESULT DrawBitmap( HBITMAP hBMP, DWORD dwBMPOriginX = 0, DWORD dwBMPOriginY = 0,
+ DWORD dwBMPWidth = 0, DWORD dwBMPHeight = 0 );
+ HRESULT DrawBitmap( TCHAR* strBMP, DWORD dwDesiredWidth, DWORD dwDesiredHeight );
+ HRESULT DrawText( HFONT hFont, TCHAR* strText, DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground );
+
+ HRESULT SetColorKey( DWORD dwColorKey );
+ DWORD ConvertGDIColor( COLORREF dwGDIColor );
+ static HRESULT GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits );
+
+ HRESULT Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd );
+ HRESULT Create( LPDIRECTDRAWSURFACE7 pdds );
+ HRESULT Destroy();
+
+ CSurface();
+ ~CSurface();
+};
+
+
+
+
+#endif // DDUTIL_H
+
diff --git a/V03/dsutil.cpp b/V03/dsutil.cpp
new file mode 100644
index 0000000..83c1512
--- /dev/null
+++ b/V03/dsutil.cpp
@@ -0,0 +1,1546 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.cpp
+//
+// Desc: DirectSound framework classes for reading and writing wav files and
+// playing them in DirectSound buffers. Feel free to use this class
+// as a starting point for adding extra functionality.
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CSoundManager()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSoundManager::CSoundManager()
+{
+ m_pDS = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::~CSoundManager()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSoundManager::~CSoundManager()
+{
+ SAFE_RELEASE( m_pDS );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Initialize()
+// Desc: Initializes the IDirectSound object and also sets the primary buffer
+// format. This function must be called before any others.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Initialize( HWND hWnd,
+ DWORD dwCoopLevel,
+ DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ SAFE_RELEASE( m_pDS );
+
+ // Create IDirectSound using the primary sound device
+ if( FAILED( hr = DirectSoundCreate8( NULL, &m_pDS, NULL ) ) )
+ return DXTRACE_ERR( TEXT("DirectSoundCreate8"), hr );
+
+ // Set DirectSound coop level
+ if( FAILED( hr = m_pDS->SetCooperativeLevel( hWnd, dwCoopLevel ) ) )
+ return DXTRACE_ERR( TEXT("SetCooperativeLevel"), hr );
+
+ // Set primary buffer format
+ SetPrimaryBufferFormat( dwPrimaryChannels, dwPrimaryFreq, dwPrimaryBitRate );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::SetPrimaryBufferFormat()
+// Desc: Set primary buffer to a specified format
+// For example, to set the primary buffer format to 22kHz stereo, 16-bit
+// then: dwPrimaryChannels = 2
+// dwPrimaryFreq = 22050,
+// dwPrimaryBitRate = 16
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::SetPrimaryBufferFormat( DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Get the primary buffer
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
+ dsbd.dwBufferBytes = 0;
+ dsbd.lpwfxFormat = NULL;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ WAVEFORMATEX wfx;
+ ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = (WORD) dwPrimaryChannels;
+ wfx.nSamplesPerSec = dwPrimaryFreq;
+ wfx.wBitsPerSample = (WORD) dwPrimaryBitRate;
+ wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+ if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )
+ return DXTRACE_ERR( TEXT("SetFormat"), hr );
+
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Get3DListenerInterface()
+// Desc: Returns the 3D listener interface associated with primary buffer.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener )
+{
+ HRESULT hr;
+ DSBUFFERDESC dsbdesc;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( ppDSListener == NULL )
+ return E_INVALIDARG;
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ *ppDSListener = NULL;
+
+ // Obtain primary buffer, asking it for 3D control
+ ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
+ dsbdesc.dwSize = sizeof(DSBUFFERDESC);
+ dsbdesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ if( FAILED( hr = pDSBPrimary->QueryInterface( IID_IDirectSound3DListener,
+ (VOID**)ppDSListener ) ) )
+ {
+ SAFE_RELEASE( pDSBPrimary );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ // Release the primary buffer, since it is not need anymore
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Create()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Create( CSound** ppSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ HRESULT hrRet = S_OK;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ if( pWaveFile->GetSize() == 0 )
+ {
+ // Wave is blank, so don't create it.
+ hr = E_FAIL;
+ goto LFail;
+ }
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = pWaveFile->GetSize();
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ // DirectSound is only guarenteed to play PCM data. Other
+ // formats may or may not work depending the sound card driver.
+ hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL );
+
+ // Be sure to return this error code if it occurs so the
+ // callers knows this happened.
+ if( hr == DS_NO_VIRTUALIZATION )
+ hrRet = DS_NO_VIRTUALIZATION;
+
+ if( FAILED(hr) )
+ {
+ // DSERR_BUFFERTOOSMALL will be returned if the buffer is
+ // less than DSBSIZE_FX_MIN (100ms) and the buffer is created
+ // with DSBCAPS_CTRLFX.
+ if( hr != DSERR_BUFFERTOOSMALL )
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return hrRet;
+
+LFail:
+ // Cleanup
+ SAFE_DELETE( pWaveFile );
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateFromMemory()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateFromMemory( CSound** ppSound,
+ BYTE* pbData,
+ ULONG ulDataSize,
+ LPWAVEFORMATEX pwfx,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbData == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->OpenFromMemory( pbData,ulDataSize, pwfx, WAVEFILE_READ );
+
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = ulDataSize;
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL ) ) )
+ {
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return S_OK;
+
+LFail:
+ // Cleanup
+
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateStreaming()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateStreaming( CStreamingSound** ppStreamingSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNotifyCount,
+ DWORD dwNotifySize,
+ HANDLE hNotifyEvent )
+{
+ HRESULT hr;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppStreamingSound == NULL || hNotifyEvent == NULL )
+ return E_INVALIDARG;
+
+ LPDIRECTSOUNDBUFFER pDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+ DSBPOSITIONNOTIFY* aPosNotify = NULL;
+ LPDIRECTSOUNDNOTIFY pDSNotify = NULL;
+
+ pWaveFile = new CWaveFile();
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ // Figure out how big the DSound buffer should be
+ dwDSBufferSize = dwNotifySize * dwNotifyCount;
+
+ // Set up the direct sound buffer. Request the NOTIFY flag, so
+ // that we are notified as the sound buffer plays. Note, that using this flag
+ // may limit the amount of hardware acceleration that can occur.
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags |
+ DSBCAPS_CTRLPOSITIONNOTIFY |
+ DSBCAPS_GETCURRENTPOSITION2;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBuffer, NULL ) ) )
+ {
+ // If wave format isn't then it will return
+ // either DSERR_BADFORMAT or E_INVALIDARG
+ if( hr == DSERR_BADFORMAT || hr == E_INVALIDARG )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("CreateSoundBuffer"), hr );
+
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ }
+
+ // Create the notification events, so that we know when to fill
+ // the buffer as the sound plays.
+ if( FAILED( hr = pDSBuffer->QueryInterface( IID_IDirectSoundNotify,
+ (VOID**)&pDSNotify ) ) )
+ {
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ];
+ if( aPosNotify == NULL )
+ return E_OUTOFMEMORY;
+
+ for( DWORD i = 0; i < dwNotifyCount; i++ )
+ {
+ aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
+ aPosNotify[i].hEventNotify = hNotifyEvent;
+ }
+
+ // Tell DirectSound when to notify us. The notification will come in the from
+ // of signaled events that are handled in WinMain()
+ if( FAILED( hr = pDSNotify->SetNotificationPositions( dwNotifyCount,
+ aPosNotify ) ) )
+ {
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("SetNotificationPositions"), hr );
+ }
+
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+
+ // Create the sound
+ *ppStreamingSound = new CStreamingSound( pDSBuffer, dwDSBufferSize, pWaveFile, dwNotifySize );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::CSound()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSound::CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize,
+ DWORD dwNumBuffers, CWaveFile* pWaveFile )
+{
+ DWORD i;
+
+ m_apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ for( i=0; iSetCurrentPosition(0);
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::~CSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSound::~CSound()
+{
+ for( DWORD i=0; iLock( 0, m_dwDSBufferSize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ NULL, NULL, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // Reset the wave file to the beginning
+ m_pWaveFile->ResetFile();
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwWavDataRead ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ if( dwWavDataRead == 0 )
+ {
+ // Wav is blank, so just fill with silence
+ FillMemory( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ else if( dwWavDataRead < dwDSLockedBufferSize )
+ {
+ // If the wav file was smaller than the DirectSound buffer,
+ // we need to fill the remainder of the buffer with data
+ if( bRepeatWavIfBufferLarger )
+ {
+ // Reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwWavDataRead; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full
+ // for very short files
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwWavDataRead );
+ if( FAILED(hr) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwWavDataRead;
+ }
+ }
+ else
+ {
+ // Don't repeat the wav file, just fill in silence
+ FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead,
+ dwDSLockedBufferSize - dwWavDataRead,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ }
+
+ // Unlock the buffer, we don't need it anymore.
+ pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::RestoreBuffer()
+// Desc: Restores the lost buffer. *pbWasRestored returns TRUE if the buffer was
+// restored. It can also NULL if the information is not needed.
+//-----------------------------------------------------------------------------
+HRESULT CSound::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored )
+{
+ HRESULT hr;
+
+ if( pDSB == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbWasRestored )
+ *pbWasRestored = FALSE;
+
+ DWORD dwStatus;
+ if( FAILED( hr = pDSB->GetStatus( &dwStatus ) ) )
+ return DXTRACE_ERR( TEXT("GetStatus"), hr );
+
+ if( dwStatus & DSBSTATUS_BUFFERLOST )
+ {
+ // Since the app could have just been activated, then
+ // DirectSound may not be giving us control yet, so
+ // the restoring the buffer may fail.
+ // If it does, sleep until DirectSound gives us control.
+ do
+ {
+ hr = pDSB->Restore();
+ if( hr == DSERR_BUFFERLOST )
+ Sleep( 10 );
+ }
+ while( hr = pDSB->Restore() );
+
+ if( pbWasRestored != NULL )
+ *pbWasRestored = TRUE;
+
+ return S_OK;
+ }
+ else
+ {
+ return S_FALSE;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetFreeBuffer()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetFreeBuffer()
+{
+ BOOL bIsPlaying = FALSE;
+ DWORD i;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( i=0; iGetStatus( &dwStatus );
+ if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
+ break;
+ }
+ }
+
+ if( i != m_dwNumBuffers )
+ return m_apDSBuffer[ i ];
+ else
+ return m_apDSBuffer[ rand() % m_dwNumBuffers ];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetBuffer()
+// Desc:
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetBuffer( DWORD dwIndex )
+{
+ if( m_apDSBuffer == NULL )
+ return NULL;
+ if( dwIndex >= m_dwNumBuffers )
+ return NULL;
+
+ return m_apDSBuffer[dwIndex];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Get3DBufferInterface()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSound::Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer )
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( dwIndex >= m_dwNumBuffers )
+ return E_INVALIDARG;
+
+ *ppDS3DBuffer = NULL;
+
+ return m_apDSBuffer[dwIndex]->QueryInterface( IID_IDirectSound3DBuffer,
+ (VOID**)ppDS3DBuffer );
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Play()
+// Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING
+// in the dwFlags to loop the sound
+//-----------------------------------------------------------------------------
+HRESULT CSound::Play( DWORD dwPriority, DWORD dwFlags )
+{
+ HRESULT hr;
+ BOOL bRestored;
+
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();
+
+ if( pDSB == NULL )
+ return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL );
+
+ // Restore the buffer if it was lost
+ if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+
+ // Make DirectSound do pre-processing on sound effects
+ Reset();
+ }
+
+ return pDSB->Play( 0, dwPriority, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Stop()
+// Desc: Stops the sound from playing
+//-----------------------------------------------------------------------------
+HRESULT CSound::Stop()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iStop();
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Reset()
+// Desc: Reset all of the sound buffers
+//-----------------------------------------------------------------------------
+HRESULT CSound::Reset()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iSetCurrentPosition( 0 );
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::IsSoundPlaying()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+BOOL CSound::IsSoundPlaying()
+{
+ BOOL bIsPlaying = FALSE;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( DWORD i=0; iGetStatus( &dwStatus );
+ bIsPlaying |= ( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );
+ }
+ }
+
+ return bIsPlaying;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::CStreamingSound()
+// Desc: Setups up a buffer so data can be streamed from the wave file into
+// buffer. This is very useful for large wav files that would take a
+// while to load. The buffer is initially filled with data, then
+// as sound is played the notification events are signaled and more data
+// is written into the buffer by calling HandleWaveStreamNotification()
+//-----------------------------------------------------------------------------
+CStreamingSound::CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize,
+ CWaveFile* pWaveFile, DWORD dwNotifySize )
+ : CSound( &pDSBuffer, dwDSBufferSize, 1, pWaveFile )
+{
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNotifySize = dwNotifySize;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::~CStreamingSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CStreamingSound::~CStreamingSound()
+{
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::HandleWaveStreamNotification()
+// Desc: Handle the notification that tell us to put more wav data in the
+// circular buffer
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::HandleWaveStreamNotification( BOOL bLoopedPlay )
+{
+ HRESULT hr;
+ DWORD dwCurrentPlayPos;
+ DWORD dwPlayDelta;
+ DWORD dwBytesWrittenToBuffer;
+ VOID* pDSLockedBuffer = NULL;
+ VOID* pDSLockedBuffer2 = NULL;
+ DWORD dwDSLockedBufferSize;
+ DWORD dwDSLockedBufferSize2;
+
+ if( m_apDSBuffer == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ return S_OK;
+ }
+
+ // Lock the DirectSound buffer
+ if( FAILED( hr = m_apDSBuffer[0]->Lock( m_dwNextWriteOffset, m_dwNotifySize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // m_dwDSBufferSize and m_dwNextWriteOffset are both multiples of m_dwNotifySize,
+ // it should the second buffer should never be valid
+ if( pDSLockedBuffer2 != NULL )
+ return E_UNEXPECTED;
+
+ if( !m_bFillNextNotificationWithSilence )
+ {
+ // Fill the DirectSound buffer with wav data
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+ }
+ else
+ {
+ // Fill the DirectSound buffer with silence
+ FillMemory( pDSLockedBuffer, dwDSLockedBufferSize,
+ (BYTE)( m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ dwBytesWrittenToBuffer = dwDSLockedBufferSize;
+ }
+
+ // If the number of bytes written is less than the
+ // amount we requested, we have a short file.
+ if( dwBytesWrittenToBuffer < dwDSLockedBufferSize )
+ {
+ if( !bLoopedPlay )
+ {
+ // Fill in silence for the rest of the buffer.
+ FillMemory( (BYTE*) pDSLockedBuffer + dwBytesWrittenToBuffer,
+ dwDSLockedBufferSize - dwBytesWrittenToBuffer,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+
+ // Any future notifications should just fill the buffer with silence
+ m_bFillNextNotificationWithSilence = TRUE;
+ }
+ else
+ {
+ // We are looping, so reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwBytesWrittenToBuffer; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full (for very short files).
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwBytesWrittenToBuffer;
+ }
+ }
+ }
+
+ // Unlock the DirectSound buffer
+ m_apDSBuffer[0]->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ // Figure out how much data has been played so far. When we have played
+ // passed the end of the file, we will either need to start filling the
+ // buffer with silence or starting reading from the beginning of the file,
+ // depending if the user wants to loop the sound
+ if( FAILED( hr = m_apDSBuffer[0]->GetCurrentPosition( &dwCurrentPlayPos, NULL ) ) )
+ return DXTRACE_ERR( TEXT("GetCurrentPosition"), hr );
+
+ // Check to see if the position counter looped
+ if( dwCurrentPlayPos < m_dwLastPlayPos )
+ dwPlayDelta = ( m_dwDSBufferSize - m_dwLastPlayPos ) + dwCurrentPlayPos;
+ else
+ dwPlayDelta = dwCurrentPlayPos - m_dwLastPlayPos;
+
+ m_dwPlayProgress += dwPlayDelta;
+ m_dwLastPlayPos = dwCurrentPlayPos;
+
+ // If we are now filling the buffer with silence, then we have found the end so
+ // check to see if the entire sound has played, if it has then stop the buffer.
+ if( m_bFillNextNotificationWithSilence )
+ {
+ // We don't want to cut off the sound before it's done playing.
+ if( m_dwPlayProgress >= m_pWaveFile->GetSize() )
+ {
+ m_apDSBuffer[0]->Stop();
+ }
+ }
+
+ // Update where the buffer will lock (for next time)
+ m_dwNextWriteOffset += dwDSLockedBufferSize;
+ m_dwNextWriteOffset %= m_dwDSBufferSize; // Circular buffer
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::Reset()
+// Desc: Resets the sound so it will begin playing at the beginning
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::Reset()
+{
+ HRESULT hr;
+
+ if( m_apDSBuffer[0] == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ }
+
+ m_pWaveFile->ResetFile();
+
+ return m_apDSBuffer[0]->SetCurrentPosition( 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::CWaveFile()
+// Desc: Constructs the class. Call Open() to open a wave file for reading.
+// Then call Read() as needed. Calling the destructor or Close()
+// will close the file.
+//-----------------------------------------------------------------------------
+CWaveFile::CWaveFile()
+{
+ m_pwfx = NULL;
+ m_hmmio = NULL;
+ m_dwSize = 0;
+ m_bIsReadingFromMemory = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::~CWaveFile()
+// Desc: Destructs the class
+//-----------------------------------------------------------------------------
+CWaveFile::~CWaveFile()
+{
+ Close();
+
+ if( !m_bIsReadingFromMemory )
+ SAFE_DELETE_ARRAY( m_pwfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Open()
+// Desc: Opens a wave file for reading
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ HRESULT hr;
+
+ m_dwFlags = dwFlags;
+ m_bIsReadingFromMemory = FALSE;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ if( strFileName == NULL )
+ return E_INVALIDARG;
+ SAFE_DELETE_ARRAY( m_pwfx );
+
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );
+
+ if( NULL == m_hmmio )
+ {
+ HRSRC hResInfo;
+ HGLOBAL hResData;
+ DWORD dwSize;
+ VOID* pvRes;
+
+ // Loading it as a file failed, so try it as a resource
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAVE") ) ) )
+ {
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAV") ) ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("FindResource"), E_FAIL );
+ }
+
+ if( NULL == ( hResData = LoadResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("LoadResource"), E_FAIL );
+
+ if( 0 == ( dwSize = SizeofResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("SizeofResource"), E_FAIL );
+
+ if( NULL == ( pvRes = LockResource( hResData ) ) )
+ return DXTRACE_ERR( TEXT("LockResource"), E_FAIL );
+
+ CHAR* pData = new CHAR[ dwSize ];
+ memcpy( pData, pvRes, dwSize );
+
+ MMIOINFO mmioInfo;
+ ZeroMemory( &mmioInfo, sizeof(mmioInfo) );
+ mmioInfo.fccIOProc = FOURCC_MEM;
+ mmioInfo.cchBuffer = dwSize;
+ mmioInfo.pchBuffer = (CHAR*) pData;
+
+ m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );
+ }
+
+ if( FAILED( hr = ReadMMIO() ) )
+ {
+ // ReadMMIO will fail if its an not a wave file
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR_NOMSGBOX( TEXT("ReadMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ // After the reset, the size of the wav file is m_ck.cksize so store it now
+ m_dwSize = m_ck.cksize;
+ }
+ else
+ {
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF |
+ MMIO_READWRITE |
+ MMIO_CREATE );
+ if( NULL == m_hmmio )
+ return DXTRACE_ERR( TEXT("mmioOpen"), E_FAIL );
+
+ if( FAILED( hr = WriteMMIO( pwfx ) ) )
+ {
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR( TEXT("WriteMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+ }
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::OpenFromMemory()
+// Desc: copy data to CWaveFile member variable from memory
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::OpenFromMemory( BYTE* pbData, ULONG ulDataSize,
+ WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ m_pwfx = pwfx;
+ m_ulDataSize = ulDataSize;
+ m_pbData = pbData;
+ m_pbDataCur = m_pbData;
+ m_bIsReadingFromMemory = TRUE;
+
+ if( dwFlags != WAVEFILE_READ )
+ return E_NOTIMPL;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ReadMMIO()
+// Desc: Support function for reading from a multimedia I/O stream.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_pwfx.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ReadMMIO()
+{
+ MMCKINFO ckIn; // chunk info. for general use.
+ PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in.
+
+ m_pwfx = NULL;
+
+ if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Check to make sure this is a valid wave file
+ if( (m_ckRiff.ckid != FOURCC_RIFF) ||
+ (m_ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("mmioFOURCC"), E_FAIL );
+
+ // Search the input file for for the 'fmt ' chunk.
+ ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Expect the 'fmt' chunk to be at least as large as ;
+ // if there are extra parameters at the end, we'll ignore them
+ if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) )
+ return DXTRACE_ERR( TEXT("sizeof(PCMWAVEFORMAT)"), E_FAIL );
+
+ // Read the 'fmt ' chunk into .
+ if( mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat,
+ sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ // Allocate the waveformatex, but if its not pcm format, read the next
+ // word, and thats how many extra bytes to allocate.
+ if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )
+ {
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("m_pwfx"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = 0;
+ }
+ else
+ {
+ // Read in length of extra bytes.
+ WORD cbExtraBytes = 0L;
+ if( mmioRead( m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("new"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = cbExtraBytes;
+
+ // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
+ if( mmioRead( m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize))+sizeof(WORD)),
+ cbExtraBytes ) != cbExtraBytes )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+ }
+ }
+
+ // Ascend the input file out of the 'fmt ' chunk.
+ if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::GetSize()
+// Desc: Retuns the size of the read access wave file
+//-----------------------------------------------------------------------------
+DWORD CWaveFile::GetSize()
+{
+ return m_dwSize;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ResetFile()
+// Desc: Resets the internal m_ck pointer so reading starts from the
+// beginning of the file again
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ResetFile()
+{
+ if( m_bIsReadingFromMemory )
+ {
+ m_pbDataCur = m_pbData;
+ }
+ else
+ {
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ // Seek to the data
+ if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),
+ SEEK_SET ) )
+ return DXTRACE_ERR( TEXT("mmioSeek"), E_FAIL );
+
+ // Search the input file for the 'data' chunk.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ if( 0 != mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+ }
+ else
+ {
+ // Create the 'data' chunk that holds the waveform samples.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ m_ck.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( 0 != mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Read()
+// Desc: Reads section of data from a wave file into pBuffer and returns
+// how much read in pdwSizeRead, reading not more than dwSizeToRead.
+// This uses m_ck to determine where to start reading from. So
+// subsequent calls will be continue where the last left off unless
+// Reset() is called.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )
+{
+ if( m_bIsReadingFromMemory )
+ {
+ if( m_pbDataCur == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( (BYTE*)(m_pbDataCur + dwSizeToRead) >
+ (BYTE*)(m_pbData + m_ulDataSize) )
+ {
+ dwSizeToRead = m_ulDataSize - (DWORD)(m_pbDataCur - m_pbData);
+ }
+
+ CopyMemory( pBuffer, m_pbDataCur, dwSizeToRead );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = dwSizeToRead;
+
+ return S_OK;
+ }
+ else
+ {
+ MMIOINFO mmioinfoIn; // current status of m_hmmio
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pBuffer == NULL || pdwSizeRead == NULL )
+ return E_INVALIDARG;
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+
+ UINT cbDataIn = dwSizeToRead;
+ if( cbDataIn > m_ck.cksize )
+ cbDataIn = m_ck.cksize;
+
+ m_ck.cksize -= cbDataIn;
+
+ for( DWORD cT = 0; cT < cbDataIn; cT++ )
+ {
+ // Copy the bytes from the io to the buffer.
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ {
+ if( 0 != mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ return DXTRACE_ERR( TEXT("mmioinfoIn.pchNext"), E_FAIL );
+ }
+
+ // Actual copy.
+ *((BYTE*)pBuffer+cT) = *((BYTE*)mmioinfoIn.pchNext);
+ mmioinfoIn.pchNext++;
+ }
+
+ if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = cbDataIn;
+
+ return S_OK;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Close()
+// Desc: Closes the wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Close()
+{
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+ else
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( 0 != mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ // Ascend the output file out of the 'data' chunk -- this will cause
+ // the chunk size of the 'data' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Do this here instead...
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioSeek( m_hmmio, 0, SEEK_SET );
+
+ if( 0 != (INT)mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ m_ck.ckid = mmioFOURCC('f', 'a', 'c', 't');
+
+ if( 0 == mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ {
+ DWORD dwSamples = 0;
+ mmioWrite( m_hmmio, (HPSTR)&dwSamples, sizeof(DWORD) );
+ mmioAscend( m_hmmio, &m_ck, 0 );
+ }
+
+ // Ascend the output file out of the 'RIFF' chunk -- this will cause
+ // the chunk size of the 'RIFF' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::WriteMMIO()
+// Desc: Support function for reading from a multimedia I/O stream
+// pwfxDest is the WAVEFORMATEX for this new wave file.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_ck.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::WriteMMIO( WAVEFORMATEX *pwfxDest )
+{
+ DWORD dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile.
+ MMCKINFO ckOut1;
+
+ dwFactChunk = (DWORD)-1;
+
+ // Create the output file RIFF chunk of form type 'WAVE'.
+ m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');
+ m_ckRiff.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // We are now descended into the 'RIFF' chunk we just created.
+ // Now create the 'fmt ' chunk. Since we know the size of this chunk,
+ // specify it in the MMCKINFO structure so MMIO doesn't have to seek
+ // back and set the chunk size after ascending from the chunk.
+ m_ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ m_ck.cksize = sizeof(PCMWAVEFORMAT);
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type.
+ if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM )
+ {
+ if( mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+ else
+ {
+ // Write the variable length size.
+ if( (UINT)mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(*pwfxDest) + pwfxDest->cbSize ) !=
+ ( sizeof(*pwfxDest) + pwfxDest->cbSize ) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+
+ // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Now create the fact chunk, not required for PCM but nice to have. This is filled
+ // in when the close routine is called.
+ ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't');
+ ckOut1.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( mmioWrite( m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) !=
+ sizeof(dwFactChunk) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+
+ // Now ascend out of the fact chunk...
+ if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Write()
+// Desc: Writes data to the open wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Write( UINT nSizeToWrite, BYTE* pbSrcData, UINT* pnSizeWrote )
+{
+ UINT cT;
+
+ if( m_bIsReadingFromMemory )
+ return E_NOTIMPL;
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pnSizeWrote == NULL || pbSrcData == NULL )
+ return E_INVALIDARG;
+
+ *pnSizeWrote = 0;
+
+ for( cT = 0; cT < nSizeToWrite; cT++ )
+ {
+ if( m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite )
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+ if( 0 != mmioAdvance( m_hmmio, &m_mmioinfoOut, MMIO_WRITE ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+ }
+
+ *((BYTE*)m_mmioinfoOut.pchNext) = *((BYTE*)pbSrcData+cT);
+ (BYTE*)m_mmioinfoOut.pchNext++;
+
+ (*pnSizeWrote)++;
+ }
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V03/dsutil.h b/V03/dsutil.h
new file mode 100644
index 0000000..57d26df
--- /dev/null
+++ b/V03/dsutil.h
@@ -0,0 +1,170 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.h
+//
+// Desc:
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#ifndef DSUTIL_H
+#define DSUTIL_H
+
+#include
+#include
+#include
+#include
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes used by this header
+//-----------------------------------------------------------------------------
+class CSoundManager;
+class CSound;
+class CStreamingSound;
+class CWaveFile;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Typing macros
+//-----------------------------------------------------------------------------
+#define WAVEFILE_READ 1
+#define WAVEFILE_WRITE 2
+
+#define DSUtil_StopSound(s) { if(s) s->Stop(); }
+#define DSUtil_PlaySound(s) { if(s) s->Play( 0, 0 ); }
+#define DSUtil_PlaySoundLooping(s) { if(s) s->Play( 0, DSBPLAY_LOOPING ); }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSoundManager
+// Desc:
+//-----------------------------------------------------------------------------
+class CSoundManager
+{
+protected:
+ LPDIRECTSOUND8 m_pDS;
+
+public:
+ CSoundManager();
+ ~CSoundManager();
+
+ HRESULT Initialize( HWND hWnd, DWORD dwCoopLevel, DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate );
+ inline LPDIRECTSOUND GetDirectSound() { return m_pDS; }
+ HRESULT SetPrimaryBufferFormat( DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate );
+ HRESULT Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener );
+
+ HRESULT Create( CSound** ppSound, LPTSTR strWaveFileName, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
+ HRESULT CreateFromMemory( CSound** ppSound, BYTE* pbData, ULONG ulDataSize, LPWAVEFORMATEX pwfx, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
+ HRESULT CreateStreaming( CStreamingSound** ppStreamingSound, LPTSTR strWaveFileName, DWORD dwCreationFlags, GUID guid3DAlgorithm, DWORD dwNotifyCount, DWORD dwNotifySize, HANDLE hNotifyEvent );
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSound
+// Desc: Encapsulates functionality of a DirectSound buffer.
+//-----------------------------------------------------------------------------
+class CSound
+{
+protected:
+ LPDIRECTSOUNDBUFFER* m_apDSBuffer;
+ DWORD m_dwDSBufferSize;
+ CWaveFile* m_pWaveFile;
+ DWORD m_dwNumBuffers;
+
+ HRESULT RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored );
+
+public:
+ CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize, DWORD dwNumBuffers, CWaveFile* pWaveFile );
+ virtual ~CSound();
+
+ HRESULT Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer );
+ HRESULT FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger );
+ LPDIRECTSOUNDBUFFER GetFreeBuffer();
+ LPDIRECTSOUNDBUFFER GetBuffer( DWORD dwIndex );
+
+ HRESULT Play( DWORD dwPriority, DWORD dwFlags );
+ HRESULT Stop();
+ HRESULT Reset();
+ BOOL IsSoundPlaying();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CStreamingSound
+// Desc: Encapsulates functionality to play a wave file with DirectSound.
+// The Create() method loads a chunk of wave file into the buffer,
+// and as sound plays more is written to the buffer by calling
+// HandleWaveStreamNotification() whenever hNotifyEvent is signaled.
+//-----------------------------------------------------------------------------
+class CStreamingSound : public CSound
+{
+protected:
+ DWORD m_dwLastPlayPos;
+ DWORD m_dwPlayProgress;
+ DWORD m_dwNotifySize;
+ DWORD m_dwNextWriteOffset;
+ BOOL m_bFillNextNotificationWithSilence;
+
+public:
+ CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize, CWaveFile* pWaveFile, DWORD dwNotifySize );
+ ~CStreamingSound();
+
+ HRESULT HandleWaveStreamNotification( BOOL bLoopedPlay );
+ HRESULT Reset();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CWaveFile
+// Desc: Encapsulates reading or writing sound data to or from a wave file
+//-----------------------------------------------------------------------------
+class CWaveFile
+{
+public:
+ WAVEFORMATEX* m_pwfx; // Pointer to WAVEFORMATEX structure
+ HMMIO m_hmmio; // MM I/O handle for the WAVE
+ MMCKINFO m_ck; // Multimedia RIFF chunk
+ MMCKINFO m_ckRiff; // Use in opening a WAVE file
+ DWORD m_dwSize; // The size of the wave file
+ MMIOINFO m_mmioinfoOut;
+ DWORD m_dwFlags;
+ BOOL m_bIsReadingFromMemory;
+ BYTE* m_pbData;
+ BYTE* m_pbDataCur;
+ ULONG m_ulDataSize;
+
+protected:
+ HRESULT ReadMMIO();
+ HRESULT WriteMMIO( WAVEFORMATEX *pwfxDest );
+
+public:
+ CWaveFile();
+ ~CWaveFile();
+
+ HRESULT Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags );
+ HRESULT OpenFromMemory( BYTE* pbData, ULONG ulDataSize, WAVEFORMATEX* pwfx, DWORD dwFlags );
+ HRESULT Close();
+
+ HRESULT Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead );
+ HRESULT Write( UINT nSizeToWrite, BYTE* pbData, UINT* pnSizeWrote );
+
+ DWORD GetSize();
+ HRESULT ResetFile();
+ WAVEFORMATEX* GetFormat() { return m_pwfx; };
+};
+
+
+
+
+#endif // DSUTIL_H
diff --git a/V03/resource.h b/V03/resource.h
new file mode 100644
index 0000000..23c118f
--- /dev/null
+++ b/V03/resource.h
@@ -0,0 +1,24 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Demo.rc
+//
+#define IDI_MAIN 101
+#define IDR_MENU 102
+#define IDR_ACCEL 103
+#define IDM_EXIT 1001
+#define IDM_TEST 40024
+#define ID_ULTRIS_NEUESSPIEL 40025
+#define ID_ULTRIS_PAUSE 40026
+#define ID_ULTRIS_SOUND 40027
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 134
+#define _APS_NEXT_COMMAND_VALUE 40028
+#define _APS_NEXT_CONTROL_VALUE 1019
+#define _APS_NEXT_SYMED_VALUE 104
+#endif
+#endif
diff --git a/V03/ul_adeck.bmp b/V03/ul_adeck.bmp
new file mode 100644
index 0000000..5f3b867
Binary files /dev/null and b/V03/ul_adeck.bmp differ
diff --git a/V03/ul_down.wav b/V03/ul_down.wav
new file mode 100644
index 0000000..84cf9e1
Binary files /dev/null and b/V03/ul_down.wav differ
diff --git a/V03/ul_dreh.WAV b/V03/ul_dreh.WAV
new file mode 100644
index 0000000..790ef8c
Binary files /dev/null and b/V03/ul_dreh.WAV differ
diff --git a/V03/ul_ende.WAV b/V03/ul_ende.WAV
new file mode 100644
index 0000000..43c73f0
Binary files /dev/null and b/V03/ul_ende.WAV differ
diff --git a/V03/ul_feld.bmp b/V03/ul_feld.bmp
new file mode 100644
index 0000000..3225b6b
Binary files /dev/null and b/V03/ul_feld.bmp differ
diff --git a/V03/ul_hgrnd.bmp b/V03/ul_hgrnd.bmp
new file mode 100644
index 0000000..c33b077
Binary files /dev/null and b/V03/ul_hgrnd.bmp differ
diff --git a/V03/ul_move.WAV b/V03/ul_move.WAV
new file mode 100644
index 0000000..22b2a99
Binary files /dev/null and b/V03/ul_move.WAV differ
diff --git a/V03/ul_prev.bmp b/V03/ul_prev.bmp
new file mode 100644
index 0000000..c791074
Binary files /dev/null and b/V03/ul_prev.bmp differ
diff --git a/V03/ul_row1.WAV b/V03/ul_row1.WAV
new file mode 100644
index 0000000..ab5bfca
Binary files /dev/null and b/V03/ul_row1.WAV differ
diff --git a/V03/ul_row2.WAV b/V03/ul_row2.WAV
new file mode 100644
index 0000000..671fc71
Binary files /dev/null and b/V03/ul_row2.WAV differ
diff --git a/V03/ul_start.WAV b/V03/ul_start.WAV
new file mode 100644
index 0000000..f66bfef
Binary files /dev/null and b/V03/ul_start.WAV differ
diff --git a/V03/ul_stein.bmp b/V03/ul_stein.bmp
new file mode 100644
index 0000000..dadb7a0
Binary files /dev/null and b/V03/ul_stein.bmp differ
diff --git a/V03/ul_win.wav b/V03/ul_win.wav
new file mode 100644
index 0000000..e11c880
Binary files /dev/null and b/V03/ul_win.wav differ
diff --git a/V03/ul_z0.bmp b/V03/ul_z0.bmp
new file mode 100644
index 0000000..10fe8a6
Binary files /dev/null and b/V03/ul_z0.bmp differ
diff --git a/V03/ul_z1.bmp b/V03/ul_z1.bmp
new file mode 100644
index 0000000..1ce2939
Binary files /dev/null and b/V03/ul_z1.bmp differ
diff --git a/V03/ul_z2.bmp b/V03/ul_z2.bmp
new file mode 100644
index 0000000..9006084
Binary files /dev/null and b/V03/ul_z2.bmp differ
diff --git a/V03/ul_z3.bmp b/V03/ul_z3.bmp
new file mode 100644
index 0000000..5710c67
Binary files /dev/null and b/V03/ul_z3.bmp differ
diff --git a/V03/ul_z4.bmp b/V03/ul_z4.bmp
new file mode 100644
index 0000000..11306ed
Binary files /dev/null and b/V03/ul_z4.bmp differ
diff --git a/V03/ul_z5.bmp b/V03/ul_z5.bmp
new file mode 100644
index 0000000..b4a22b5
Binary files /dev/null and b/V03/ul_z5.bmp differ
diff --git a/V03/ul_z6.bmp b/V03/ul_z6.bmp
new file mode 100644
index 0000000..62616d4
Binary files /dev/null and b/V03/ul_z6.bmp differ
diff --git a/V03/ul_z7.bmp b/V03/ul_z7.bmp
new file mode 100644
index 0000000..d9178df
Binary files /dev/null and b/V03/ul_z7.bmp differ
diff --git a/V03/ul_z8.bmp b/V03/ul_z8.bmp
new file mode 100644
index 0000000..98e1a18
Binary files /dev/null and b/V03/ul_z8.bmp differ
diff --git a/V03/ul_z9.bmp b/V03/ul_z9.bmp
new file mode 100644
index 0000000..e6245a3
Binary files /dev/null and b/V03/ul_z9.bmp differ
diff --git a/V04/Demo.aps b/V04/Demo.aps
new file mode 100644
index 0000000..507ce09
Binary files /dev/null and b/V04/Demo.aps differ
diff --git a/V04/Demo.cpp b/V04/Demo.cpp
new file mode 100644
index 0000000..ef8310e
--- /dev/null
+++ b/V04/Demo.cpp
@@ -0,0 +1,834 @@
+# include
+# include
+# include
+# include
+# include "ddutil.h"
+# include "dsutil.h"
+# include "resource.h"
+
+const int ultris_nettobreite = 360; // Breite des Inneren des Haupfensters
+const int ultris_nettohoehe = 520; // Hoehe des Inneren des Hauptfensters
+int ultris_bruttobreite; // Breite des gesamten Haupfensters (incl. Rahmen)
+int ultris_bruttohoehe; // Hoehe des gesamten Haupfensters (incl. Rahmen)
+
+HINSTANCE ultris_instance; // Instanz der Ultris Applikation
+HWND ultris_window; // Das Hauptfenster von Ultris
+HMENU ultris_menu; // Das Menu von Ultris
+
+const int sound_start = 0; // Sound fuer neues Spiel
+const int sound_dreh = 1; // Sound bei Drehung
+const int sound_move = 2; // Sound bei rechts/links Bewegung
+const int sound_down = 3; // Sound bei Aufprall
+const int sound_row1 = 4; // Sound bei Abraeumen einer Reihe
+const int sound_row2 = 5; // Sound bei Abraeumen von mehreren Reihen
+const int sound_ende = 6; // Sound bei Spielende
+const int sound_win = 7; // Sound bei Eintrag in Highscore Tabelle
+const int anzahl_sounds = 8; // Anzahl Sounds
+
+char *soundfiles[anzahl_sounds] =
+ {
+ "ul_start.wav",
+ "ul_dreh.wav",
+ "ul_move.wav",
+ "ul_down.wav",
+ "ul_row1.wav",
+ "ul_row2.wav",
+ "ul_ende.wav",
+ "ul_win.wav"
+ };
+
+class sounds
+ {
+ private:
+ CSoundManager smgr;
+ CSound *snd[anzahl_sounds];
+ public:
+ int on;
+ sounds();
+ int init( HWND wnd);
+ void play( int snr);
+ ~sounds();
+ };
+
+sounds::sounds()
+ {
+ int i;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ snd[i] = 0;
+ on = 1;
+ }
+
+int sounds::init( HWND wnd)
+ {
+ HRESULT ret;
+ int i;
+
+ ret = smgr.Initialize( wnd, DSSCL_PRIORITY, 2, 22050, 16);
+ if( ret < 0)
+ return ret;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ {
+ ret = smgr.Create( snd+i, soundfiles[i]);
+ if( ret < 0)
+ return ret;
+ }
+ return S_OK;
+ }
+
+sounds::~sounds()
+ {
+ int i;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ {
+ if( snd[i])
+ delete snd[i];
+ }
+ }
+
+void sounds::play( int i)
+ {
+ if( !on)
+ return;
+ if( snd[i]->IsSoundPlaying())
+ {
+ snd[i]->Stop();
+ snd[i]->Reset();
+ }
+ snd[i]->Play(0,0);
+ }
+
+sounds ultris_sounds;
+
+class display
+ {
+ private:
+ CDisplay dsply;
+ CSurface *hgrnd;
+ CSurface *fldst;
+ CSurface *fllst;
+ CSurface *prvst;
+ CSurface *deckel;
+ CSurface *ziff[10];
+ public:
+ display();
+ void free_all();
+ ~display() {free_all();}
+ HRESULT init( HWND wnd);
+ void hintergrund() { dsply.Blt( 0, 0, hgrnd);}
+ void abdeckung() { dsply.Blt( 60, 0, deckel);}
+ void ziffer( int pos, int val) { dsply.Blt( 120+pos*20, 50, ziff[val]);}
+ void feldstein( int z, int s) { dsply.Blt( 80+s*20, 100+z*20, fldst);}
+ void fallstein( int z, int s, int offset) { dsply.Blt( 80+s*20, 100+z*20+offset, fllst);}
+ void prevstein( int p, int z, int s, int b, int h){ dsply.Blt( 290+s*15+(4-b)*15/2, 410-p*70+z*15+(4-h)*15/2, prvst);}
+ void update(){ dsply.UpdateBounds();}
+ HRESULT cooperative(){return dsply.GetDirectDraw()->TestCooperativeLevel();}
+ HRESULT restore();
+ HRESULT present();
+ };
+
+display::display()
+ {
+ int i;
+
+ hgrnd = 0;
+ fldst = 0;
+ fllst = 0;
+ prvst = 0;
+ deckel = 0;
+ for( i = 0; i < 10; i++)
+ ziff[i] = 0;
+ }
+
+void display::free_all()
+ {
+ int i;
+
+ if( hgrnd)
+ delete hgrnd;
+ if( fldst)
+ delete fldst;
+ if( fllst)
+ delete fllst;
+ if( prvst)
+ delete prvst;
+ if( deckel)
+ delete deckel;
+ for( i = 0; i < 10; i++)
+ {
+ if( ziff[i])
+ delete ziff[i];
+ }
+ }
+
+HRESULT display::init( HWND wnd)
+ {
+ HRESULT hr;
+ int i;
+ char fname[20];
+
+ hr = dsply.CreateWindowedDisplay( wnd, ultris_nettobreite, ultris_nettohoehe );
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &hgrnd, "ul_hgrnd.bmp", ultris_nettobreite, ultris_nettohoehe);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &fldst, "ul_feld.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &fllst, "ul_stein.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &prvst, "ul_prev.bmp", 15, 15);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &deckel, "ul_adeck.bmp", 240, 100);
+ if( hr < 0)
+ return hr;
+ for( i = 0; i < 10; i++)
+ {
+ sprintf( fname, "ul_z%d.bmp", i);
+ hr = dsply.CreateSurfaceFromBitmap( &ziff[i], fname, 20, 40);
+ if( hr < 0)
+ return hr;
+ }
+ return S_OK;
+ }
+
+HRESULT display::restore()
+ {
+ HRESULT hr;
+ int i;
+ char fname[20];
+
+ hr = dsply.GetDirectDraw()->RestoreAllSurfaces();
+ if( hr < 0)
+ return hr;
+ hr = hgrnd->DrawBitmap( "ul_hgrnd.bmp", ultris_nettobreite, ultris_nettohoehe);
+ if( hr < 0)
+ return hr;
+ hr = fldst->DrawBitmap( "ul_feld.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = fllst->DrawBitmap( "ul_stein.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = prvst->DrawBitmap( "ul_prev.bmp", 15, 15);
+ if( hr < 0)
+ return hr;
+ hr = deckel->DrawBitmap( "ul_adeck.bmp", 240, 100);
+ if( hr < 0)
+ return hr;
+
+ for( i = 0; i < 10; i++)
+ {
+ sprintf( fname, "ul_z%d.bmp", i);
+ hr = ziff[i]->DrawBitmap( fname, 20, 40);
+ if( hr < 0)
+ return hr;
+ }
+ return S_OK;
+ }
+
+HRESULT display::present()
+ {
+ HRESULT hr;
+
+ hr = dsply.Present();
+ if( hr == DDERR_SURFACELOST )
+ return restore();
+ return hr;
+ }
+
+display ultris_display;
+
+
+// V4 Beginn
+
+const int anzahl_formen = 35; // Anzahl der Formen
+
+//
+// Datenstruktur für die Formen
+//
+struct form
+ {
+ char h; // Hoehe
+ char b; // Breite
+ char data[4][4]; // Vorhandene Segmente
+ };
+
+// Form 1 in allen Drehvarianten
+//
+// *** * * *
+// * ** *** **
+// * *
+const form s_01_1 = {2, 3, {{1,1,1}, {0,1,0}}};
+const form s_01_2 = {3, 2, {{1,0}, {1,1}, {1,0}}};
+const form s_01_3 = {2, 3, {{0,1,0}, {1,1,1}}};
+const form s_01_4 = {3, 2, {{0,1}, {1,1}, {0,1}}};
+
+// Form 2 in allen Drehvarianten
+//
+// ** * ** *
+// ** ** ** **
+// * *
+const form s_02_1 = {2, 3, {{1,1,0}, {0,1,1}}};
+const form s_02_2 = {3, 2, {{0,1}, {1,1}, {1,0}}};
+const form s_02_3 = {2, 3, {{1,1,0}, {0,1,1}}};
+const form s_02_4 = {3, 2, {{0,1}, {1,1}, {1,0}}};
+
+// Form 3 in allen Drehvarianten
+//
+// ** * ** *
+// ** ** ** **
+// * *
+const form s_03_1 = {2, 3, {{0,1,1}, {1,1,0}}};
+const form s_03_2 = {3, 2, {{1,0}, {1,1}, {0,1}}};
+const form s_03_3 = {2, 3, {{0,1,1}, {1,1,0}}};
+const form s_03_4 = {3, 2, {{1,0}, {1,1}, {0,1}}};
+
+// Form 4 in allen Drehvarianten
+//
+// *** ** * *
+// * * *** *
+// * **
+const form s_04_1 = {2, 3, {{1,1,1}, {0,0,1}}};
+const form s_04_2 = {3, 2, {{1,1}, {1,0}, {1,0}}};
+const form s_04_3 = {2, 3, {{1,0,0}, {1,1,1}}};
+const form s_04_4 = {3, 2, {{0,1}, {0,1}, {1,1}}};
+
+// Form 5 in allen Drehvarianten
+//
+// * ** *** *
+// *** * * *
+// * **
+const form s_05_1 = {2, 3, {{0,0,1}, {1,1,1}}};
+const form s_05_2 = {3, 2, {{1,1}, {0,1}, {0,1}}};
+const form s_05_3 = {2, 3, {{1,1,1}, {1,0,0}}};
+const form s_05_4 = {3, 2, {{1,0}, {1,0}, {1,1}}};
+
+// Form 6 in allen Drehvarianten
+//
+// ** ** ** **
+// ** ** ** **
+//
+const form s_06_1 = {2, 2, {{1,1}, {1,1}}};
+const form s_06_2 = {2, 2, {{1,1}, {1,1}}};
+const form s_06_3 = {2, 2, {{1,1}, {1,1}}};
+const form s_06_4 = {2, 2, {{1,1}, {1,1}}};
+
+// Form 7 in allen Drehvarianten
+//
+// **** * **** *
+// * *
+// * *
+// * *
+const form s_07_1 = {1, 4, {{1,1,1,1}}};
+const form s_07_2 = {4, 1, {{1},{1},{1},{1}}};
+const form s_07_3 = {1, 4, {{1,1,1,1}}};
+const form s_07_4 = {4, 1, {{1},{1},{1},{1}}};
+
+// Form 8 in allen Drehvarianten
+//
+// *** ** * * **
+// * * * *** *
+// ** **
+const form s_08_1 = {2, 3, {{1,1,1}, {1,0,1}}};
+const form s_08_2 = {3, 2, {{1,1},{1,0},{1,1}}};
+const form s_08_3 = {2, 3, {{1,0,1}, {1,1,1}}};
+const form s_08_4 = {3, 2, {{1,1},{0,1},{1,1}}};
+
+// Form 9 in allen Drehvarianten
+//
+// ** * ** *
+// * *** * ***
+// ** * ** *
+const form s_09_1 = {3, 3, {{1,1,0}, {0,1,0}, {0,1,1}}};
+const form s_09_2 = {3, 3, {{0,0,1}, {1,1,1}, {1,0,0}}};
+const form s_09_3 = {3, 3, {{1,1,0}, {0,1,0}, {0,1,1}}};
+const form s_09_4 = {3, 3, {{0,0,1}, {1,1,1}, {1,0,0}}};
+
+// Form 10 in allen Drehvarianten
+//
+// ** ** * *
+// * * ** **
+//
+const form s_10_1 = {2, 2, {{1,1}, {0,1}}};
+const form s_10_2 = {2, 2, {{1,1}, {1,0}}};
+const form s_10_3 = {2, 2, {{1,0}, {1,1}}};
+const form s_10_4 = {2, 2, {{0,1}, {1,1}}};
+
+// Form 11 in allen Drehvarianten
+//
+// * * * *
+// *** *** *** ***
+// * * * *
+const form s_11_1 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+const form s_11_2 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+const form s_11_3 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+const form s_11_4 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+
+// Form 12 in allen Drehvarianten
+//
+// ** ** * ***
+// ** *** ** **
+// * **
+const form s_12_1 = {3, 2, {{1,1}, {1,1}, {1,0}}};
+const form s_12_2 = {2, 3, {{1,1,0}, {1,1,1}}};
+const form s_12_3 = {3, 2, {{0,1}, {1,1}, {1,1}}};
+const form s_12_4 = {2, 3, {{1,1,1}, {0,1,1}}};
+
+// Form 13 in allen Drehvarianten
+//
+// ** *** * **
+// ** ** ** ***
+// * **
+const form s_13_1 = {3, 2, {{1,1}, {1,1}, {0,1}}};
+const form s_13_2 = {2, 3, {{1,1,1}, {1,1,0}}};
+const form s_13_3 = {3, 2, {{1,0}, {1,1}, {1,1}}};
+const form s_13_4 = {2, 3, {{0,1,1}, {1,1,1}}};
+
+// Form 14 in allen Drehvarianten
+//
+// *** * * ***
+// * * * *
+// * *** *** *
+const form s_14_1 = {3, 3, {{1,1,1}, {1,0,0}, {1,0,0}}};
+const form s_14_2 = {3, 3, {{1,0,0}, {1,0,0}, {1,1,1}}};
+const form s_14_3 = {3, 3, {{0,0,1}, {0,0,1}, {1,1,1}}};
+const form s_14_4 = {3, 3, {{1,1,1}, {0,0,1}, {0,0,1}}};
+
+// Form 15 in allen Drehvarianten
+//
+// * * * *
+const form s_15_1 = {1, 1, {{1}}};
+const form s_15_2 = {1, 1, {{1}}};
+const form s_15_3 = {1, 1, {{1}}};
+const form s_15_4 = {1, 1, {{1}}};
+
+// Form 16 in allen Drehvarianten
+//
+// * * * *
+// * * * *
+const form s_16_1 = {2, 2, {{1,0}, {0,1}}};
+const form s_16_2 = {2, 2, {{0,1}, {1,0}}};
+const form s_16_3 = {2, 2, {{1,0}, {0,1}}};
+const form s_16_4 = {2, 2, {{0,1}, {1,0}}};
+
+// Form 17 in allen Drehvarianten
+//
+// * * * *
+// * * * *
+// * * * *
+const form s_17_1 = {3, 3, {{1,0,0}, {0,1,0}, {0,0,1}}};
+const form s_17_2 = {3, 3, {{0,0,1}, {0,1,0}, {1,0,0}}};
+const form s_17_3 = {3, 3, {{1,0,0}, {0,1,0}, {0,0,1}}};
+const form s_17_4 = {3, 3, {{0,0,1}, {0,1,0}, {1,0,0}}};
+
+// Form 18 in allen Drehvarianten
+//
+// * * * *
+// * * * * * * * *
+// * * * *
+const form s_18_1 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+const form s_18_2 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+const form s_18_3 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+const form s_18_4 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+
+// Form 19 in allen Drehvarianten
+//
+// * * * * *
+// * * * * *
+// * *
+const form s_19_1 = {2, 3, {{0,1,0}, {1,0,1}}};
+const form s_19_2 = {3, 2, {{0,1},{1,0},{0,1}}};
+const form s_19_3 = {2, 3, {{1,0,1}, {0,1,0}}};
+const form s_19_4 = {3, 2, {{1,0},{0,1},{1,0}}};
+
+// Form 20 in allen Drehvarianten
+//
+// *** * * *
+// * *** * ***
+// * * *** *
+const form s_20_1 = {3, 3, {{1,1,1}, {0,1,0}, {0,1,0}}};
+const form s_20_2 = {3, 3, {{1,0,0}, {1,1,1}, {1,0,0}}};
+const form s_20_3 = {3, 3, {{0,1,0}, {0,1,0}, {1,1,1}}};
+const form s_20_4 = {3, 3, {{0,0,1}, {1,1,1}, {0,0,1}}};
+
+// Form 21 in allen Drehvarianten
+//
+// * * * * *
+// * ** * **
+// * * * * *
+const form s_21_1 = {3, 3, {{1,0,1}, {0,1,0}, {0,1,0}}};
+const form s_21_2 = {3, 3, {{1,0,0}, {0,1,1}, {1,0,0}}};
+const form s_21_3 = {3, 3, {{0,1,0}, {0,1,0}, {1,0,1}}};
+const form s_21_4 = {3, 3, {{0,0,1}, {1,1,0}, {0,0,1}}};
+
+// Form 22 in allen Drehvarianten
+//
+// ** * ** *
+// * *
+//
+const form s_22_1 = {1, 2, {{1,1}}};
+const form s_22_2 = {2, 1, {{1},{1}}};
+const form s_22_3 = {1, 2, {{1,1}}};
+const form s_22_4 = {2, 1, {{1},{1}}};
+
+// Form 23 in allen Drehvarianten
+//
+// *** * *** *
+// * *
+// * *
+const form s_23_1 = {1, 3, {{1,1,1}}};
+const form s_23_2 = {3, 1, {{1},{1},{1}}};
+const form s_23_3 = {1, 3, {{1,1,1}}};
+const form s_23_4 = {3, 1, {{1},{1},{1}}};
+
+// Form 24 in allen Drehvarianten
+//
+// ** * * *
+// * * ** *
+// * *
+const form s_24_1 = {2, 3, {{1,1,0}, {0,0,1}}};
+const form s_24_2 = {3, 2, {{0,1}, {1,0}, {1,0}}};
+const form s_24_3 = {2, 3, {{1,0,0}, {0,1,1}}};
+const form s_24_4 = {3, 2, {{0,1}, {0,1}, {1,0}}};
+
+// Form 25 in allen Drehvarianten
+//
+// * * ** *
+// ** * * *
+// * *
+const form s_25_1 = {2, 3, {{0,0,1}, {1,1,0}}};
+const form s_25_2 = {3, 2, {{1,0}, {0,1}, {0,1}}};
+const form s_25_3 = {2, 3, {{0,1,1}, {1,0,0}}};
+const form s_25_4 = {3, 2, {{1,0}, {1,0}, {0,1}}};
+
+// Form 26 in allen Drehvarianten
+//
+// ** * ** *
+// ** * ** *
+// * *
+// * *
+const form s_26_1 = {2, 4, {{0,0,1,1}, {1,1,0,0}}};
+const form s_26_2 = {4, 2, {{1,0},{1,0},{0,1}, {0,1}}};
+const form s_26_3 = {2, 4, {{0,0,1,1}, {1,1,0,0}}};
+const form s_26_4 = {4, 2, {{1,0},{1,0},{0,1}, {0,1}}};
+
+// Form 27 in allen Drehvarianten
+//
+// ** * ** *
+// ** * ** *
+// * *
+// * *
+const form s_27_1 = {2, 4, {{1,1,0,0},{0,0,1,1}}};
+const form s_27_2 = {4, 2, {{0,1},{0,1},{1,0},{1,0}}};
+const form s_27_3 = {2, 4, {{1,1,0,0},{0,0,1,1}}};
+const form s_27_4 = {4, 2, {{0,1},{0,1},{1,0},{1,0}}};
+
+// Form 28 in allen Drehvarianten
+//
+// * * * ** *
+// ** * * * *
+// * *
+// * *
+const form s_28_1 = {2, 4, {{1,0,0,1},{0,1,1,0}}};
+const form s_28_2 = {4, 2, {{1,0},{0,1},{0,1},{1,0}}};
+const form s_28_3 = {2, 4, {{0,1,1,0},{1,0,0,1}}};
+const form s_28_4 = {4, 2, {{0,1},{1,0},{1,0},{0,1}}};
+
+// Form 29 in allen Drehvarianten
+//
+// ** * * **
+// * * * *
+// * ** ** *
+const form s_29_1 = {3, 3, {{0,1,1}, {1,0,0}, {1,0,0}}};
+const form s_29_2 = {3, 3, {{1,0,0}, {1,0,0}, {0,1,1}}};
+const form s_29_3 = {3, 3, {{0,0,1}, {0,0,1}, {1,1,0}}};
+const form s_29_4 = {3, 3, {{1,1,0}, {0,0,1}, {0,0,1}}};
+
+// Form 30 in allen Drehvarianten
+//
+// * ** * * **
+// * * * * * *
+// * * ** * **
+const form s_30_1 = {3, 3, {{0,1,0}, {1,0,1}, {1,0,1}}};
+const form s_30_2 = {3, 3, {{0,1,1}, {1,0,0}, {0,1,1}}};
+const form s_30_3 = {3, 3, {{1,0,1}, {1,0,1}, {0,1,0}}};
+const form s_30_4 = {3, 3, {{1,1,0}, {0,0,1}, {1,1,0}}};
+
+// Form 31 in allen Drehvarianten
+//
+// *** * * *
+// * * *** *
+// * *
+// * *
+const form s_31_1 = {2, 4, {{1,1,1,0},{0,0,0,1}}};
+const form s_31_2 = {4, 2, {{0,1},{1,0},{1,0},{1,0}}};
+const form s_31_3 = {2, 4, {{1,0,0,0},{0,1,1,1}}};
+const form s_31_4 = {4, 2, {{0,1},{0,1},{0,1},{1,0}}};
+
+// Form 32 in allen Drehvarianten
+//
+// * * *** *
+// *** * * *
+// * *
+// * *
+const form s_32_1 = {2, 4, {{0,0,0,1},{1,1,1,0}}};
+const form s_32_2 = {4, 2, {{1,0},{0,1},{0,1},{0,1}}};
+const form s_32_3 = {2, 4, {{0,1,1,1},{1,0,0,0}}};
+const form s_32_4 = {4, 2, {{1,0},{1,0},{1,0},{0,1}}};
+
+// Form 33 in allen Drehvarianten
+//
+// ** *** ** ***
+// ** *** ** ***
+// ** **
+const form s_33_1 = {3, 2, {{1,1}, {1,1}, {1,1}}};
+const form s_33_2 = {2, 3, {{1,1,1}, {1,1,1}}};
+const form s_33_3 = {3, 2, {{1,1}, {1,1}, {1,1}}};
+const form s_33_4 = {2, 3, {{1,1,1}, {1,1,1}}};
+
+// Form 34 in allen Drehvarianten
+//
+// **** * ** *
+// ** ** **** **
+// ** **
+// * *
+const form s_34_1 = {2, 4, {{1,1,1,1},{0,1,1,0}}};
+const form s_34_2 = {4, 2, {{1,0},{1,1},{1,1},{1,0}}};
+const form s_34_3 = {2, 4, {{0,1,1,0},{1,1,1,1}}};
+const form s_34_4 = {4, 2, {{0,1},{1,1},{1,1},{0,1}}};
+
+// Form 35 in allen Drehvarianten
+//
+// ** * ** *
+// * *** * ***
+// ** * ** *
+const form s_35_1 = {3, 3, {{0,1,1}, {0,1,0}, {1,1,0}}};
+const form s_35_2 = {3, 3, {{1,0,0}, {1,1,1}, {0,0,1}}};
+const form s_35_3 = {3, 3, {{0,1,1}, {0,1,0}, {1,1,0}}};
+const form s_35_4 = {3, 3, {{1,0,0}, {1,1,1}, {0,0,1}}};
+
+// Array mit allen Steinformen in allen Drehvarianten
+// Zugriff in der Form
+//
+// ultris_form[ steinform][ drehvariante]
+//
+// mit 0 <= steinform < 35 und 0 <= drehvariante <= 4
+
+const form *ultris_form[anzahl_formen][4] =
+ {
+ { &s_01_1, &s_01_2, &s_01_3, &s_01_4},
+ { &s_02_1, &s_02_2, &s_02_3, &s_02_4},
+ { &s_03_1, &s_03_2, &s_03_3, &s_03_4},
+ { &s_04_1, &s_04_2, &s_04_3, &s_04_4},
+ { &s_05_1, &s_05_2, &s_05_3, &s_05_4},
+ { &s_06_1, &s_06_2, &s_06_3, &s_06_4},
+ { &s_07_1, &s_07_2, &s_07_3, &s_07_4},
+ { &s_08_1, &s_08_2, &s_08_3, &s_08_4},
+ { &s_09_1, &s_09_2, &s_09_3, &s_09_4},
+ { &s_10_1, &s_10_2, &s_10_3, &s_10_4},
+ { &s_11_1, &s_11_2, &s_11_3, &s_11_4},
+ { &s_12_1, &s_12_2, &s_12_3, &s_12_4},
+ { &s_13_1, &s_13_2, &s_13_3, &s_13_4},
+ { &s_14_1, &s_14_2, &s_14_3, &s_14_4},
+ { &s_15_1, &s_15_2, &s_15_3, &s_15_4},
+ { &s_16_1, &s_16_2, &s_16_3, &s_16_4},
+ { &s_17_1, &s_17_2, &s_17_3, &s_17_4},
+ { &s_18_1, &s_18_2, &s_18_3, &s_18_4},
+ { &s_19_1, &s_19_2, &s_19_3, &s_19_4},
+ { &s_20_1, &s_20_2, &s_20_3, &s_20_4},
+ { &s_21_1, &s_21_2, &s_21_3, &s_21_4},
+ { &s_22_1, &s_22_2, &s_22_3, &s_22_4},
+ { &s_23_1, &s_23_2, &s_23_3, &s_23_4},
+ { &s_24_1, &s_24_2, &s_24_3, &s_24_4},
+ { &s_25_1, &s_25_2, &s_25_3, &s_25_4},
+ { &s_26_1, &s_26_2, &s_26_3, &s_26_4},
+ { &s_27_1, &s_27_2, &s_27_3, &s_27_4},
+ { &s_28_1, &s_28_2, &s_28_3, &s_28_4},
+ { &s_29_1, &s_29_2, &s_29_3, &s_29_4},
+ { &s_30_1, &s_30_2, &s_30_3, &s_30_4},
+ { &s_31_1, &s_31_2, &s_31_3, &s_31_4},
+ { &s_32_1, &s_32_2, &s_32_3, &s_32_4},
+ { &s_33_1, &s_33_2, &s_33_3, &s_33_4},
+ { &s_34_1, &s_34_2, &s_34_3, &s_34_4},
+ { &s_35_1, &s_35_2, &s_35_3, &s_35_4}
+ };
+
+// V4 Ende
+
+/*
+** ultris_windowhandler
+*/
+
+// V4 Beginn
+int testform = 0;
+// V4 Ende
+
+LRESULT CALLBACK ultris_windowhandler( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+ {
+ switch(msg)
+ {
+ case WM_COMMAND:
+ switch( LOWORD( wParam))
+ {
+ case IDM_EXIT:
+ PostMessage( hWnd, WM_CLOSE, 0, 0);
+ return 0;
+ case ID_ULTRIS_SOUND:
+ ultris_sounds.on = !ultris_sounds.on;
+ CheckMenuItem( ultris_menu, ID_ULTRIS_SOUND, ultris_sounds.on ? MF_CHECKED:MF_UNCHECKED);
+ return 0;
+// V4 Beginn
+ case IDM_TEST: // Testcode
+ testform = (testform + 1) % anzahl_formen;
+ PostMessage( hWnd, WM_PAINT, 0, 0);
+ return 0;
+// V4 Ende
+ }
+ break;
+ case WM_GETMINMAXINFO:
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.x = ((MINMAXINFO *)lParam)->ptMaxTrackSize.x = ultris_bruttobreite;
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.y = ((MINMAXINFO *)lParam)->ptMaxTrackSize.y = ultris_bruttohoehe;
+ return 0;
+ case WM_DESTROY:
+ PostQuitMessage( 0);
+ return 0;
+ case WM_MOVE:
+ ultris_display.update();
+ return 0;
+// V4 Beginn
+ case WM_PAINT:
+ int variante;
+ int z, s, x, y;
+ const form *f;
+
+ ultris_display.hintergrund();
+
+ for( variante = 0; variante < 4; variante++)
+ {
+ z = 1 + 5*variante;
+ s = 3;
+ f = ultris_form[testform][variante];
+ for( x = 0; x < f->b; x++)
+ {
+ for( y = 0; y < f->h; y++)
+ {
+ if( f->data[y][x])
+ ultris_display.fallstein(z+y,s+x,0);
+ }
+ }
+ }
+ ultris_display.present();
+ break;
+ }
+// V4 Ende
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+ }
+
+/*
+** WinMain
+*/
+int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow)
+ {
+ MSG msg;
+ HACCEL acc;
+ WNDCLASSEX wcx;
+
+ ultris_instance = hInst;
+
+ wcx.cbSize = sizeof( wcx);
+ wcx.lpszClassName = TEXT( "Ultris");
+ wcx.lpfnWndProc = ultris_windowhandler;
+ wcx.style = CS_VREDRAW | CS_HREDRAW;
+ wcx.hInstance = hInst;
+ wcx.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hIconSm = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hCursor = LoadCursor( NULL, IDC_ARROW);
+ wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wcx.lpszMenuName = MAKEINTRESOURCE( IDR_MENU);
+ wcx.cbClsExtra = 0;
+ wcx.cbWndExtra = 0;
+
+ if( !RegisterClassEx( &wcx))
+ return 0;
+
+ acc = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_ACCEL));
+
+ ultris_bruttohoehe = ultris_nettohoehe + 2*GetSystemMetrics( SM_CYSIZEFRAME)
+ + GetSystemMetrics( SM_CYMENU)
+ + GetSystemMetrics( SM_CYCAPTION);
+ ultris_bruttobreite = ultris_nettobreite + 2*GetSystemMetrics( SM_CXSIZEFRAME);
+
+ ultris_window = CreateWindowEx( 0, TEXT( "Ultris"), TEXT( "Ultris"), WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ ultris_bruttobreite, ultris_bruttohoehe, NULL, NULL, hInst, NULL);
+ if( !ultris_window)
+ return 0;
+
+ ultris_menu = GetMenu( ultris_window);
+
+ if( ultris_sounds.init( ultris_window) < 0)
+ {
+ MessageBox( ultris_window, "Fehler beim Initialisieren der Sounds", "Ultris-Fehlermeldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
+ return 0;
+ }
+ CheckMenuItem( ultris_menu, ID_ULTRIS_SOUND, ultris_sounds.on ? MF_CHECKED:MF_UNCHECKED);
+
+ if( ultris_display.init( ultris_window) < 0)
+ {
+ MessageBox( ultris_window, "Fehler beim Initialisieren der Grafik", "Ultris-Fehlermeldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
+ return 0;
+ }
+
+ MoveWindow( ultris_window, (GetSystemMetrics(SM_CXSCREEN)-ultris_bruttobreite)/2,
+ (GetSystemMetrics(SM_CYSCREEN)-ultris_bruttohoehe)/2,
+ ultris_bruttobreite, ultris_bruttohoehe, TRUE);
+
+ ShowWindow( ultris_window, nCmdShow);
+
+ while( TRUE)
+ {
+ if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE))
+ {
+ if( GetMessage( &msg, NULL, 0, 0 ) == 0)
+ return 0; // Message ist WM_QUIT
+
+ if( TranslateAccelerator( ultris_window, acc, &msg) == 0)
+ {
+ TranslateMessage( &msg);
+ DispatchMessage( &msg);
+ }
+ }
+ else
+ {
+ HRESULT hr;
+ hr = ultris_display.cooperative();
+ if( hr < 0)
+ {
+ switch( hr )
+ {
+ case DDERR_EXCLUSIVEMODEALREADYSET:
+ Sleep(10);
+ break;
+ case DDERR_WRONGMODE:
+ ultris_display.free_all();
+ ultris_display.init( ultris_window);
+ PostMessage( ultris_window, WM_PAINT, 0, 0);
+ break;
+ }
+ }
+ else
+ {
+ // Hier koennen wir uns um das Spiel kuemmern
+ }
+ }
+ }
+ }
+
+
+
diff --git a/V04/Demo.h b/V04/Demo.h
new file mode 100644
index 0000000..a19fa69
--- /dev/null
+++ b/V04/Demo.h
@@ -0,0 +1,12 @@
+
+#if !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
+#define AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "resource.h"
+
+
+#endif // !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
diff --git a/V04/Demo.ncb b/V04/Demo.ncb
new file mode 100644
index 0000000..a6a970d
Binary files /dev/null and b/V04/Demo.ncb differ
diff --git a/V04/Demo.rc b/V04/Demo.rc
new file mode 100644
index 0000000..2d4c8ed
--- /dev/null
+++ b/V04/Demo.rc
@@ -0,0 +1,115 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include
+#include
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Deutsch (Deutschland) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+#ifdef _WIN32
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU MENU DISCARDABLE
+BEGIN
+ POPUP "Ultris"
+ BEGIN
+ MENUITEM "Neues Spiel", ID_ULTRIS_NEUESSPIEL
+ MENUITEM "Pause", ID_ULTRIS_PAUSE
+ MENUITEM "Sound", ID_ULTRIS_SOUND
+ MENUITEM SEPARATOR
+ MENUITEM "Ende", IDM_EXIT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MAIN ICON DISCARDABLE "Icon.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCEL ACCELERATORS DISCARDABLE
+BEGIN
+ "T", IDM_TEST, VIRTKEY, CONTROL, NOINVERT
+ VK_ESCAPE, IDM_EXIT, VIRTKEY, NOINVERT
+ VK_F5, ID_ULTRIS_SOUND, VIRTKEY, NOINVERT
+END
+
+#endif // Deutsch (Deutschland) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Englisch (USA) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include \r\n"
+ "#include \0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Englisch (USA) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/V04/Demo.sln b/V04/Demo.sln
new file mode 100644
index 0000000..67d59f5
--- /dev/null
+++ b/V04/Demo.sln
@@ -0,0 +1,19 @@
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo.vcproj", "{03EE9EF4-D248-41BC-98D7-43F16FE8AD16}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {03EE9EF4-D248-41BC-98D7-43F16FE8AD16}.Debug|Win32.ActiveCfg = Debug|Win32
+ {03EE9EF4-D248-41BC-98D7-43F16FE8AD16}.Debug|Win32.Build.0 = Debug|Win32
+ {03EE9EF4-D248-41BC-98D7-43F16FE8AD16}.Release|Win32.ActiveCfg = Release|Win32
+ {03EE9EF4-D248-41BC-98D7-43F16FE8AD16}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/V04/Demo.sln.old b/V04/Demo.sln.old
new file mode 100644
index 0000000..f619333
--- /dev/null
+++ b/V04/Demo.sln.old
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo.vcproj", "{03EE9EF4-D248-41BC-98D7-43F16FE8AD16}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {03EE9EF4-D248-41BC-98D7-43F16FE8AD16}.Debug.ActiveCfg = Debug|Win32
+ {03EE9EF4-D248-41BC-98D7-43F16FE8AD16}.Debug.Build.0 = Debug|Win32
+ {03EE9EF4-D248-41BC-98D7-43F16FE8AD16}.Release.ActiveCfg = Release|Win32
+ {03EE9EF4-D248-41BC-98D7-43F16FE8AD16}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/V04/Demo.suo b/V04/Demo.suo
new file mode 100644
index 0000000..2668043
Binary files /dev/null and b/V04/Demo.suo differ
diff --git a/V04/Demo.suo.old b/V04/Demo.suo.old
new file mode 100644
index 0000000..98e84da
Binary files /dev/null and b/V04/Demo.suo.old differ
diff --git a/V04/Demo.vcproj b/V04/Demo.vcproj
new file mode 100644
index 0000000..fb0ec93
--- /dev/null
+++ b/V04/Demo.vcproj
@@ -0,0 +1,300 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V04/Demo.vcproj.7.10.old b/V04/Demo.vcproj.7.10.old
new file mode 100644
index 0000000..98ce341
--- /dev/null
+++ b/V04/Demo.vcproj.7.10.old
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V04/Demo.vcproj.SASCHA.Sasch.user b/V04/Demo.vcproj.SASCHA.Sasch.user
new file mode 100644
index 0000000..86f2a09
--- /dev/null
+++ b/V04/Demo.vcproj.SASCHA.Sasch.user
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V04/Icon.ico b/V04/Icon.ico
new file mode 100644
index 0000000..7a53f63
Binary files /dev/null and b/V04/Icon.ico differ
diff --git a/V04/UpgradeLog.XML b/V04/UpgradeLog.XML
new file mode 100644
index 0000000..1ac1c14
--- /dev/null
+++ b/V04/UpgradeLog.XML
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/V04/_UpgradeReport_Files/UpgradeReport.css b/V04/_UpgradeReport_Files/UpgradeReport.css
new file mode 100644
index 0000000..3411f63
--- /dev/null
+++ b/V04/_UpgradeReport_Files/UpgradeReport.css
@@ -0,0 +1,207 @@
+BODY
+{
+ BACKGROUND-COLOR: white;
+ FONT-FAMILY: "Verdana", sans-serif;
+ FONT-SIZE: 100%;
+ MARGIN-LEFT: 0px;
+ MARGIN-TOP: 0px
+}
+P
+{
+ FONT-FAMILY: "Verdana", sans-serif;
+ FONT-SIZE: 70%;
+ LINE-HEIGHT: 12pt;
+ MARGIN-BOTTOM: 0px;
+ MARGIN-LEFT: 10px;
+ MARGIN-TOP: 10px
+}
+.note
+{
+ BACKGROUND-COLOR: #ffffff;
+ COLOR: #336699;
+ FONT-FAMILY: "Verdana", sans-serif;
+ FONT-SIZE: 100%;
+ MARGIN-BOTTOM: 0px;
+ MARGIN-LEFT: 0px;
+ MARGIN-TOP: 0px;
+ PADDING-RIGHT: 10px
+}
+.infotable
+{
+ BACKGROUND-COLOR: #f0f0e0;
+ BORDER-BOTTOM: #ffffff 0px solid;
+ BORDER-COLLAPSE: collapse;
+ BORDER-LEFT: #ffffff 0px solid;
+ BORDER-RIGHT: #ffffff 0px solid;
+ BORDER-TOP: #ffffff 0px solid;
+ FONT-SIZE: 70%;
+ MARGIN-LEFT: 10px
+}
+.issuetable
+{
+ BACKGROUND-COLOR: #ffffe8;
+ BORDER-COLLAPSE: collapse;
+ COLOR: #000000;
+ FONT-SIZE: 100%;
+ MARGIN-BOTTOM: 10px;
+ MARGIN-LEFT: 13px;
+ MARGIN-TOP: 0px
+}
+.issuetitle
+{
+ BACKGROUND-COLOR: #ffffff;
+ BORDER-BOTTOM: #dcdcdc 1px solid;
+ BORDER-TOP: #dcdcdc 1px;
+ COLOR: #003366;
+ FONT-WEIGHT: normal
+}
+.header
+{
+ BACKGROUND-COLOR: #cecf9c;
+ BORDER-BOTTOM: #ffffff 1px solid;
+ BORDER-LEFT: #ffffff 1px solid;
+ BORDER-RIGHT: #ffffff 1px solid;
+ BORDER-TOP: #ffffff 1px solid;
+ COLOR: #000000;
+ FONT-WEIGHT: bold
+}
+.issuehdr
+{
+ BACKGROUND-COLOR: #E0EBF5;
+ BORDER-BOTTOM: #dcdcdc 1px solid;
+ BORDER-TOP: #dcdcdc 1px solid;
+ COLOR: #000000;
+ FONT-WEIGHT: normal
+}
+.issuenone
+{
+ BACKGROUND-COLOR: #ffffff;
+ BORDER-BOTTOM: 0px;
+ BORDER-LEFT: 0px;
+ BORDER-RIGHT: 0px;
+ BORDER-TOP: 0px;
+ COLOR: #000000;
+ FONT-WEIGHT: normal
+}
+.content
+{
+ BACKGROUND-COLOR: #e7e7ce;
+ BORDER-BOTTOM: #ffffff 1px solid;
+ BORDER-LEFT: #ffffff 1px solid;
+ BORDER-RIGHT: #ffffff 1px solid;
+ BORDER-TOP: #ffffff 1px solid;
+ PADDING-LEFT: 3px
+}
+.issuecontent
+{
+ BACKGROUND-COLOR: #ffffff;
+ BORDER-BOTTOM: #dcdcdc 1px solid;
+ BORDER-TOP: #dcdcdc 1px solid;
+ PADDING-LEFT: 3px
+}
+A:link
+{
+ COLOR: #cc6633;
+ TEXT-DECORATION: underline
+}
+A:visited
+{
+ COLOR: #cc6633;
+}
+A:active
+{
+ COLOR: #cc6633;
+}
+A:hover
+{
+ COLOR: #cc3300;
+ TEXT-DECORATION: underline
+}
+H1
+{
+ BACKGROUND-COLOR: #003366;
+ BORDER-BOTTOM: #336699 6px solid;
+ COLOR: #ffffff;
+ FONT-SIZE: 130%;
+ FONT-WEIGHT: normal;
+ MARGIN: 0em 0em 0em -20px;
+ PADDING-BOTTOM: 8px;
+ PADDING-LEFT: 30px;
+ PADDING-TOP: 16px
+}
+H2
+{
+ COLOR: #000000;
+ FONT-SIZE: 80%;
+ FONT-WEIGHT: bold;
+ MARGIN-BOTTOM: 3px;
+ MARGIN-LEFT: 10px;
+ MARGIN-TOP: 20px;
+ PADDING-LEFT: 0px
+}
+H3
+{
+ COLOR: #000000;
+ FONT-SIZE: 80%;
+ FONT-WEIGHT: bold;
+ MARGIN-BOTTOM: -5px;
+ MARGIN-LEFT: 10px;
+ MARGIN-TOP: 20px
+}
+H4
+{
+ COLOR: #000000;
+ FONT-SIZE: 70%;
+ FONT-WEIGHT: bold;
+ MARGIN-BOTTOM: 0px;
+ MARGIN-TOP: 15px;
+ PADDING-BOTTOM: 0px
+}
+UL
+{
+ COLOR: #000000;
+ FONT-SIZE: 70%;
+ LIST-STYLE: square;
+ MARGIN-BOTTOM: 0pt;
+ MARGIN-TOP: 0pt
+}
+OL
+{
+ COLOR: #000000;
+ FONT-SIZE: 70%;
+ LIST-STYLE: square;
+ MARGIN-BOTTOM: 0pt;
+ MARGIN-TOP: 0pt
+}
+LI
+{
+ LIST-STYLE: square;
+ MARGIN-LEFT: 0px
+}
+.expandable
+{
+ CURSOR: hand
+}
+.expanded
+{
+ color: black
+}
+.collapsed
+{
+ DISPLAY: none
+}
+.foot
+{
+BACKGROUND-COLOR: #ffffff;
+BORDER-BOTTOM: #cecf9c 1px solid;
+BORDER-TOP: #cecf9c 2px solid
+}
+.settings
+{
+MARGIN-LEFT: 25PX;
+}
+.help
+{
+TEXT-ALIGN: right;
+margin-right: 10px;
+}
diff --git a/V04/_UpgradeReport_Files/UpgradeReport.xslt b/V04/_UpgradeReport_Files/UpgradeReport.xslt
new file mode 100644
index 0000000..6fb44ed
--- /dev/null
+++ b/V04/_UpgradeReport_Files/UpgradeReport.xslt
@@ -0,0 +1,232 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ : |
+
+
+
+
+
+
+
+
+ Konvertierungsbericht
+
+
+
+
+
+
+
+ Konvertierungsbericht -
+
+
+ Konvertierungsdauer:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Konvertierungseinstellungen
+ |
+
+
+
+
+
+
+
diff --git a/V04/_UpgradeReport_Files/UpgradeReport_Minus.gif b/V04/_UpgradeReport_Files/UpgradeReport_Minus.gif
new file mode 100644
index 0000000..17751cb
Binary files /dev/null and b/V04/_UpgradeReport_Files/UpgradeReport_Minus.gif differ
diff --git a/V04/_UpgradeReport_Files/UpgradeReport_Plus.gif b/V04/_UpgradeReport_Files/UpgradeReport_Plus.gif
new file mode 100644
index 0000000..f6009ca
Binary files /dev/null and b/V04/_UpgradeReport_Files/UpgradeReport_Plus.gif differ
diff --git a/V04/ddutil.cpp b/V04/ddutil.cpp
new file mode 100644
index 0000000..faccc24
--- /dev/null
+++ b/V04/ddutil.cpp
@@ -0,0 +1,1035 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: DirectDraw framewark classes. Feel free to use this class as a
+// starting point for adding extra functionality.
+//
+//
+// Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include
+#include "ddutil.h"
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::CDisplay()
+{
+ m_pDD = NULL;
+ m_pddsFrontBuffer = NULL;
+ m_pddsBackBuffer = NULL;
+ m_pddsBackBufferLeft = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ~CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::~CDisplay()
+{
+ DestroyObjects();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DestroyObjects()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::DestroyObjects()
+{
+ SAFE_RELEASE( m_pddsBackBufferLeft );
+ SAFE_RELEASE( m_pddsBackBuffer );
+ SAFE_RELEASE( m_pddsFrontBuffer );
+
+ if( m_pDD )
+ m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL );
+
+ SAFE_RELEASE( m_pDD );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateFullScreenDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth,
+ DWORD dwHeight, DWORD dwBPP )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ // Set the display mode
+ if( FAILED( m_pDD->SetDisplayMode( dwWidth, dwHeight, dwBPP, 0, 0 ) ) )
+ return E_FAIL;
+
+ // Create primary surface (with backbuffer attached)
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
+ DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE;
+ ddsd.dwBackBufferCount = 1;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer,
+ NULL ) ) )
+ return E_FAIL;
+
+ // Get a pointer to the back buffer
+ DDSCAPS2 ddscaps;
+ ZeroMemory( &ddscaps, sizeof( ddscaps ) );
+ ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
+
+ if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
+ &m_pddsBackBuffer ) ) )
+ return E_FAIL;
+
+ m_pddsBackBuffer->AddRef();
+
+ m_hWnd = hWnd;
+ m_bWindowed = FALSE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateWindowedDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_NORMAL );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ RECT rcWork;
+ RECT rc;
+ DWORD dwStyle;
+
+ // If we are still a WS_POPUP window we should convert to a normal app
+ // window so we look like a windows app.
+ dwStyle = GetWindowStyle( hWnd );
+ dwStyle &= ~WS_POPUP;
+ dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
+ SetWindowLong( hWnd, GWL_STYLE, dwStyle );
+
+ // Aet window size
+ SetRect( &rc, 0, 0, dwWidth, dwHeight );
+
+ AdjustWindowRectEx( &rc, GetWindowStyle(hWnd), GetMenu(hWnd) != NULL,
+ GetWindowExStyle(hWnd) );
+
+ SetWindowPos( hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
+ SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
+
+ // Make sure our window does not hang outside of the work area
+ SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWork, 0 );
+ GetWindowRect( hWnd, &rc );
+ if( rc.left < rcWork.left ) rc.left = rcWork.left;
+ if( rc.top < rcWork.top ) rc.top = rcWork.top;
+ SetWindowPos( hWnd, NULL, rc.left, rc.top, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ LPDIRECTDRAWCLIPPER pcClipper;
+
+ // Create the primary surface
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+ if( FAILED( m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
+ return E_FAIL;
+
+ // Create the backbuffer surface
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = pcClipper->SetHWnd( 0, hWnd ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pcClipper ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ // Done with clipper
+ pcClipper->Release();
+
+ m_hWnd = hWnd;
+ m_bWindowed = TRUE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurface( CSurface** ppSurface,
+ DWORD dwWidth, DWORD dwHeight )
+{
+ if( NULL == m_pDD )
+ return E_POINTER;
+ if( NULL == ppSurface )
+ return E_INVALIDARG;
+
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromBitmap()
+// Desc: Create a DirectDrawSurface from a bitmap resource or bitmap file.
+// Use MAKEINTRESOURCE() to pass a constant into strBMP.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromBitmap( CSurface** ppSurface,
+ TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight )
+{
+ HRESULT hr;
+ HBITMAP hBMP = NULL;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+
+ if( m_pDD == NULL || strBMP == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = bmp.bmWidth;
+ ddsd.dwHeight = bmp.bmHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = (*ppSurface)->DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromText()
+// Desc: Creates a DirectDrawSurface from a text string using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromText( CSurface** ppSurface,
+ HFONT hFont, TCHAR* strText,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ LPDIRECTDRAWSURFACE7 pDDS = NULL;
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ SIZE sizeText;
+
+ if( m_pDD == NULL || strText == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ hDC = GetDC( NULL );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ GetTextExtentPoint32( hDC, strText, _tcslen(strText), &sizeText );
+ ReleaseDC( NULL, hDC );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = sizeText.cx;
+ ddsd.dwHeight = sizeText.cy;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ if( FAILED( hr = (*ppSurface)->DrawText( hFont, strText, 0, 0,
+ crBackground, crForeground ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Present()
+{
+ HRESULT hr;
+
+ if( NULL == m_pddsFrontBuffer && NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ while( 1 )
+ {
+ if( m_bWindowed )
+ hr = m_pddsFrontBuffer->Blt( &m_rcWindow, m_pddsBackBuffer,
+ NULL, DDBLT_WAIT, NULL );
+ else
+ hr = m_pddsFrontBuffer->Flip( NULL, 0 );
+
+ if( hr == DDERR_SURFACELOST )
+ {
+ m_pddsFrontBuffer->Restore();
+ m_pddsBackBuffer->Restore();
+ }
+
+ if( hr != DDERR_WASSTILLDRAWING )
+ return hr;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer || NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Set the palette before loading the bitmap
+ if( pPalette )
+ m_pddsFrontBuffer->SetPalette( pPalette );
+
+ CSurface backBuffer;
+ backBuffer.Create( m_pddsBackBuffer );
+
+ if( FAILED( backBuffer.DrawBitmap( hbm, 0, 0, 0, 0 ) ) )
+ return E_FAIL;
+
+ return Present();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, DDBLTFAST_SRCCOLORKEY );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds, RECT* prc,
+ DWORD dwFlags )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc )
+{
+ if( NULL == pSurface )
+ return E_INVALIDARG;
+
+ if( pSurface->IsColorKeyed() )
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, DDBLTFAST_SRCCOLORKEY );
+ else
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Clear( DWORD dwColor )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Erase the background
+ DDBLTFX ddbltfx;
+ ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
+ ddbltfx.dwSize = sizeof(ddbltfx);
+ ddbltfx.dwFillColor = dwColor;
+
+ return m_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::SetPalette( LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer )
+ return E_POINTER;
+
+ return m_pddsFrontBuffer->SetPalette( pPalette );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette,
+ const TCHAR* strBMP )
+{
+ HRSRC hResource = NULL;
+ RGBQUAD* pRGB = NULL;
+ BITMAPINFOHEADER* pbi = NULL;
+ PALETTEENTRY aPalette[256];
+ HANDLE hFile = NULL;
+ DWORD iColor;
+ DWORD dwColors;
+ BITMAPFILEHEADER bf;
+ BITMAPINFOHEADER bi;
+ DWORD dwBytesRead;
+
+ if( m_pDD == NULL || strBMP == NULL || ppPalette == NULL )
+ return E_INVALIDARG;
+
+ *ppPalette = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hResource = FindResource( NULL, strBMP, RT_BITMAP );
+ if( hResource )
+ {
+ pbi = (LPBITMAPINFOHEADER) LockResource( LoadResource( NULL, hResource ) );
+ if( NULL == pbi )
+ return E_FAIL;
+
+ pRGB = (RGBQUAD*) ( (BYTE*) pbi + pbi->biSize );
+
+ // Figure out how many colors there are
+ if( pbi == NULL || pbi->biSize < sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if( pbi->biBitCount > 8 )
+ dwColors = 0;
+ else if( pbi->biClrUsed == 0 )
+ dwColors = 1 << pbi->biBitCount;
+ else
+ dwColors = pbi->biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around.
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ aPalette[iColor].peRed = pRGB[iColor].rgbRed;
+ aPalette[iColor].peGreen = pRGB[iColor].rgbGreen;
+ aPalette[iColor].peBlue = pRGB[iColor].rgbBlue;
+ aPalette[iColor].peFlags = 0;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+ }
+
+ // Attempt to load bitmap as a file
+ hFile = CreateFile( strBMP, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
+ if( NULL == hFile )
+ return E_FAIL;
+
+ // Read the BITMAPFILEHEADER
+ ReadFile( hFile, &bf, sizeof(bf), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bf) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the BITMAPINFOHEADER
+ ReadFile( hFile, &bi, sizeof(bi), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bi) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the PALETTEENTRY
+ ReadFile( hFile, aPalette, sizeof(aPalette), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(aPalette) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ CloseHandle( hFile );
+
+ // Figure out how many colors there are
+ if( bi.biSize != sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if (bi.biBitCount > 8)
+ dwColors = 0;
+ else if (bi.biClrUsed == 0)
+ dwColors = 1 << bi.biBitCount;
+ else
+ dwColors = bi.biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around since DirectDraw uses RGB
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ BYTE r = aPalette[iColor].peRed;
+ aPalette[iColor].peRed = aPalette[iColor].peBlue;
+ aPalette[iColor].peBlue = r;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::UpdateBounds()
+{
+ if( m_bWindowed )
+ {
+ GetClientRect( m_hWnd, &m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow+1 );
+ }
+ else
+ {
+ SetRect( &m_rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN) );
+ }
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::InitClipper
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::InitClipper()
+{
+ LPDIRECTDRAWCLIPPER pClipper;
+ HRESULT hr;
+
+ // Create a clipper when using GDI to draw on the primary surface
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pClipper, NULL ) ) )
+ return hr;
+
+ pClipper->SetHWnd( 0, m_hWnd );
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pClipper ) ) )
+ return hr;
+
+ // We can release the clipper now since g_pDDSPrimary
+ // now maintains a ref count on the clipper
+ SAFE_RELEASE( pClipper );
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::CSurface()
+{
+ m_pdds = NULL;
+ m_bColorKeyed = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::~CSurface()
+{
+ SAFE_RELEASE( m_pdds );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAWSURFACE7 pdds )
+{
+ m_pdds = pdds;
+
+ if( m_pdds )
+ {
+ m_pdds->AddRef();
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_ddsd.dwSize = sizeof(m_ddsd);
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd )
+{
+ HRESULT hr;
+
+ // Create the DDraw surface
+ if( FAILED( hr = pDD->CreateSurface( pddsd, &m_pdds, NULL ) ) )
+ return hr;
+
+ // Prepare the DDSURFACEDESC structure
+ m_ddsd.dwSize = sizeof(m_ddsd);
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Destroy()
+{
+ SAFE_RELEASE( m_pdds );
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawBitmap()
+// Desc: Draws a bitmap over an entire DirectDrawSurface, stretching the
+// bitmap if nessasary
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( HBITMAP hBMP,
+ DWORD dwBMPOriginX, DWORD dwBMPOriginY,
+ DWORD dwBMPWidth, DWORD dwBMPHeight )
+{
+ HDC hDCImage;
+ HDC hDC;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ if( hBMP == NULL || m_pdds == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ // Get the surface.description
+ ddsd.dwSize = sizeof(ddsd);
+ m_pdds->GetSurfaceDesc( &ddsd );
+
+ if( ddsd.ddpfPixelFormat.dwFlags == DDPF_FOURCC )
+ return E_NOTIMPL;
+
+ // Select bitmap into a memoryDC so we can use it.
+ hDCImage = CreateCompatibleDC( NULL );
+ if( NULL == hDCImage )
+ return E_FAIL;
+
+ SelectObject( hDCImage, hBMP );
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Use the passed size, unless zero
+ dwBMPWidth = ( dwBMPWidth == 0 ) ? bmp.bmWidth : dwBMPWidth;
+ dwBMPHeight = ( dwBMPHeight == 0 ) ? bmp.bmHeight : dwBMPHeight;
+
+ // Stretch the bitmap to cover this surface
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ StretchBlt( hDC, 0, 0,
+ ddsd.dwWidth, ddsd.dwHeight,
+ hDCImage, dwBMPOriginX, dwBMPOriginY,
+ dwBMPWidth, dwBMPHeight, SRCCOPY );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ DeleteDC( hDCImage );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawText()
+// Desc: Draws a text string on a DirectDraw surface using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawText( HFONT hFont, TCHAR* strText,
+ DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strText == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ // Set the background and foreground color
+ SetBkColor( hDC, crBackground );
+ SetTextColor( hDC, crForeground );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ // Use GDI to draw the text on the surface
+ TextOut( hDC, dwOriginX, dwOriginY, strText, _tcslen(strText) );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ReDrawBitmapOnSurface()
+// Desc: Load a bitmap from a file or resource into a DirectDraw surface.
+// normaly used to re-load a surface after a restore.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( TCHAR* strBMP,
+ DWORD dwDesiredWidth, DWORD dwDesiredHeight )
+{
+ HBITMAP hBMP;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strBMP == NULL )
+ return E_INVALIDARG;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP, IMAGE_BITMAP,
+ dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::SetColorKey( DWORD dwColorKey )
+{
+ if( NULL == m_pdds )
+ return E_POINTER;
+
+ m_bColorKeyed = TRUE;
+
+ DDCOLORKEY ddck;
+ ddck.dwColorSpaceLowValue = ConvertGDIColor( dwColorKey );
+ ddck.dwColorSpaceHighValue = ConvertGDIColor( dwColorKey );
+
+ return m_pdds->SetColorKey( DDCKEY_SRCBLT, &ddck );
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ConvertGDIColor()
+// Desc: Converts a GDI color (0x00bbggrr) into the equivalent color on a
+// DirectDrawSurface using its pixel format.
+//-----------------------------------------------------------------------------
+DWORD CSurface::ConvertGDIColor( COLORREF dwGDIColor )
+{
+ if( m_pdds == NULL )
+ return 0x00000000;
+
+ COLORREF rgbT;
+ HDC hdc;
+ DWORD dw = CLR_INVALID;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ // Use GDI SetPixel to color match for us
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK)
+ {
+ rgbT = GetPixel(hdc, 0, 0); // Save current pixel value
+ SetPixel(hdc, 0, 0, dwGDIColor); // Set our value
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ // Now lock the surface so we can read back the converted color
+ ddsd.dwSize = sizeof(ddsd);
+ hr = m_pdds->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
+ if( hr == DD_OK)
+ {
+ dw = *(DWORD *) ddsd.lpSurface;
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount < 32 ) // Mask it to bpp
+ dw &= ( 1 << ddsd.ddpfPixelFormat.dwRGBBitCount ) - 1;
+ m_pdds->Unlock(NULL);
+ }
+
+ // Now put the color that was there back.
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK )
+ {
+ SetPixel( hdc, 0, 0, rgbT );
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ return dw;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::GetBitMaskInfo()
+// Desc: Returns the number of bits and the shift in the bit mask
+//-----------------------------------------------------------------------------
+HRESULT CSurface::GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits )
+{
+ DWORD dwShift = 0;
+ DWORD dwBits = 0;
+
+ if( pdwShift == NULL || pdwBits == NULL )
+ return E_INVALIDARG;
+
+ if( dwBitMask )
+ {
+ while( (dwBitMask & 1) == 0 )
+ {
+ dwShift++;
+ dwBitMask >>= 1;
+ }
+ }
+
+ while( (dwBitMask & 1) != 0 )
+ {
+ dwBits++;
+ dwBitMask >>= 1;
+ }
+
+ *pdwShift = dwShift;
+ *pdwBits = dwBits;
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V04/ddutil.h b/V04/ddutil.h
new file mode 100644
index 0000000..61fb0be
--- /dev/null
+++ b/V04/ddutil.h
@@ -0,0 +1,140 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: Routines for loading bitmap and palettes from resources
+//
+// Copyright (C) 1998-1999 Microsoft Corporation. All Rights Reserved.
+//-----------------------------------------------------------------------------
+#ifndef DDUTIL_H
+#define DDUTIL_H
+
+#include
+#include
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes defined in this header file
+//-----------------------------------------------------------------------------
+class CDisplay;
+class CSurface;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Flags for the CDisplay and CSurface methods
+//-----------------------------------------------------------------------------
+#define DSURFACELOCK_READ
+#define DSURFACELOCK_WRITE
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CDisplay
+// Desc: Class to handle all DDraw aspects of a display, including creation of
+// front and back buffers, creating offscreen surfaces and palettes,
+// and blitting surface and displaying bitmaps.
+//-----------------------------------------------------------------------------
+class CDisplay
+{
+protected:
+ LPDIRECTDRAW7 m_pDD;
+ LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBufferLeft; // For stereo modes
+
+ HWND m_hWnd;
+ RECT m_rcWindow;
+ BOOL m_bWindowed;
+ BOOL m_bStereo;
+
+public:
+ CDisplay();
+ ~CDisplay();
+
+ // Access functions
+ HWND GetHWnd() { return m_hWnd; }
+ LPDIRECTDRAW7 GetDirectDraw() { return m_pDD; }
+ LPDIRECTDRAWSURFACE7 GetFrontBuffer() { return m_pddsFrontBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBuffer() { return m_pddsBackBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBufferLEft() { return m_pddsBackBufferLeft; }
+
+ // Status functions
+ BOOL IsWindowed() { return m_bWindowed; }
+ BOOL IsStereo() { return m_bStereo; }
+
+ // Creation/destruction methods
+ HRESULT CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight,
+ DWORD dwBPP );
+ HRESULT CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight );
+ HRESULT InitClipper();
+ HRESULT UpdateBounds();
+ virtual HRESULT DestroyObjects();
+
+ // Methods to create child objects
+ HRESULT CreateSurface( CSurface** ppSurface, DWORD dwWidth,
+ DWORD dwHeight );
+ HRESULT CreateSurfaceFromBitmap( CSurface** ppSurface, TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight );
+ HRESULT CreateSurfaceFromText( CSurface** ppSurface, HFONT hFont,
+ TCHAR* strText,
+ COLORREF crBackground,
+ COLORREF crForeground );
+ HRESULT CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette, const TCHAR* strBMP );
+
+ // Display methods
+ HRESULT Clear( DWORD dwColor = 0L );
+ HRESULT ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc = NULL );
+ HRESULT Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc=NULL, DWORD dwFlags=0 );
+ HRESULT Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc = NULL );
+ HRESULT ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette=NULL );
+ HRESULT SetPalette( LPDIRECTDRAWPALETTE pPalette );
+ HRESULT Present();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSurface
+// Desc: Class to handle aspects of a DirectDrawSurface.
+//-----------------------------------------------------------------------------
+class CSurface
+{
+ LPDIRECTDRAWSURFACE7 m_pdds;
+ DDSURFACEDESC2 m_ddsd;
+ BOOL m_bColorKeyed;
+
+public:
+ LPDIRECTDRAWSURFACE7 GetDDrawSurface() { return m_pdds; }
+ BOOL IsColorKeyed() { return m_bColorKeyed; }
+
+ HRESULT DrawBitmap( HBITMAP hBMP, DWORD dwBMPOriginX = 0, DWORD dwBMPOriginY = 0,
+ DWORD dwBMPWidth = 0, DWORD dwBMPHeight = 0 );
+ HRESULT DrawBitmap( TCHAR* strBMP, DWORD dwDesiredWidth, DWORD dwDesiredHeight );
+ HRESULT DrawText( HFONT hFont, TCHAR* strText, DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground );
+
+ HRESULT SetColorKey( DWORD dwColorKey );
+ DWORD ConvertGDIColor( COLORREF dwGDIColor );
+ static HRESULT GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits );
+
+ HRESULT Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd );
+ HRESULT Create( LPDIRECTDRAWSURFACE7 pdds );
+ HRESULT Destroy();
+
+ CSurface();
+ ~CSurface();
+};
+
+
+
+
+#endif // DDUTIL_H
+
diff --git a/V04/dsutil.cpp b/V04/dsutil.cpp
new file mode 100644
index 0000000..83c1512
--- /dev/null
+++ b/V04/dsutil.cpp
@@ -0,0 +1,1546 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.cpp
+//
+// Desc: DirectSound framework classes for reading and writing wav files and
+// playing them in DirectSound buffers. Feel free to use this class
+// as a starting point for adding extra functionality.
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CSoundManager()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSoundManager::CSoundManager()
+{
+ m_pDS = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::~CSoundManager()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSoundManager::~CSoundManager()
+{
+ SAFE_RELEASE( m_pDS );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Initialize()
+// Desc: Initializes the IDirectSound object and also sets the primary buffer
+// format. This function must be called before any others.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Initialize( HWND hWnd,
+ DWORD dwCoopLevel,
+ DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ SAFE_RELEASE( m_pDS );
+
+ // Create IDirectSound using the primary sound device
+ if( FAILED( hr = DirectSoundCreate8( NULL, &m_pDS, NULL ) ) )
+ return DXTRACE_ERR( TEXT("DirectSoundCreate8"), hr );
+
+ // Set DirectSound coop level
+ if( FAILED( hr = m_pDS->SetCooperativeLevel( hWnd, dwCoopLevel ) ) )
+ return DXTRACE_ERR( TEXT("SetCooperativeLevel"), hr );
+
+ // Set primary buffer format
+ SetPrimaryBufferFormat( dwPrimaryChannels, dwPrimaryFreq, dwPrimaryBitRate );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::SetPrimaryBufferFormat()
+// Desc: Set primary buffer to a specified format
+// For example, to set the primary buffer format to 22kHz stereo, 16-bit
+// then: dwPrimaryChannels = 2
+// dwPrimaryFreq = 22050,
+// dwPrimaryBitRate = 16
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::SetPrimaryBufferFormat( DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Get the primary buffer
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
+ dsbd.dwBufferBytes = 0;
+ dsbd.lpwfxFormat = NULL;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ WAVEFORMATEX wfx;
+ ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = (WORD) dwPrimaryChannels;
+ wfx.nSamplesPerSec = dwPrimaryFreq;
+ wfx.wBitsPerSample = (WORD) dwPrimaryBitRate;
+ wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+ if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )
+ return DXTRACE_ERR( TEXT("SetFormat"), hr );
+
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Get3DListenerInterface()
+// Desc: Returns the 3D listener interface associated with primary buffer.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener )
+{
+ HRESULT hr;
+ DSBUFFERDESC dsbdesc;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( ppDSListener == NULL )
+ return E_INVALIDARG;
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ *ppDSListener = NULL;
+
+ // Obtain primary buffer, asking it for 3D control
+ ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
+ dsbdesc.dwSize = sizeof(DSBUFFERDESC);
+ dsbdesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ if( FAILED( hr = pDSBPrimary->QueryInterface( IID_IDirectSound3DListener,
+ (VOID**)ppDSListener ) ) )
+ {
+ SAFE_RELEASE( pDSBPrimary );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ // Release the primary buffer, since it is not need anymore
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Create()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Create( CSound** ppSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ HRESULT hrRet = S_OK;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ if( pWaveFile->GetSize() == 0 )
+ {
+ // Wave is blank, so don't create it.
+ hr = E_FAIL;
+ goto LFail;
+ }
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = pWaveFile->GetSize();
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ // DirectSound is only guarenteed to play PCM data. Other
+ // formats may or may not work depending the sound card driver.
+ hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL );
+
+ // Be sure to return this error code if it occurs so the
+ // callers knows this happened.
+ if( hr == DS_NO_VIRTUALIZATION )
+ hrRet = DS_NO_VIRTUALIZATION;
+
+ if( FAILED(hr) )
+ {
+ // DSERR_BUFFERTOOSMALL will be returned if the buffer is
+ // less than DSBSIZE_FX_MIN (100ms) and the buffer is created
+ // with DSBCAPS_CTRLFX.
+ if( hr != DSERR_BUFFERTOOSMALL )
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return hrRet;
+
+LFail:
+ // Cleanup
+ SAFE_DELETE( pWaveFile );
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateFromMemory()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateFromMemory( CSound** ppSound,
+ BYTE* pbData,
+ ULONG ulDataSize,
+ LPWAVEFORMATEX pwfx,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbData == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->OpenFromMemory( pbData,ulDataSize, pwfx, WAVEFILE_READ );
+
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = ulDataSize;
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL ) ) )
+ {
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return S_OK;
+
+LFail:
+ // Cleanup
+
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateStreaming()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateStreaming( CStreamingSound** ppStreamingSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNotifyCount,
+ DWORD dwNotifySize,
+ HANDLE hNotifyEvent )
+{
+ HRESULT hr;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppStreamingSound == NULL || hNotifyEvent == NULL )
+ return E_INVALIDARG;
+
+ LPDIRECTSOUNDBUFFER pDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+ DSBPOSITIONNOTIFY* aPosNotify = NULL;
+ LPDIRECTSOUNDNOTIFY pDSNotify = NULL;
+
+ pWaveFile = new CWaveFile();
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ // Figure out how big the DSound buffer should be
+ dwDSBufferSize = dwNotifySize * dwNotifyCount;
+
+ // Set up the direct sound buffer. Request the NOTIFY flag, so
+ // that we are notified as the sound buffer plays. Note, that using this flag
+ // may limit the amount of hardware acceleration that can occur.
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags |
+ DSBCAPS_CTRLPOSITIONNOTIFY |
+ DSBCAPS_GETCURRENTPOSITION2;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBuffer, NULL ) ) )
+ {
+ // If wave format isn't then it will return
+ // either DSERR_BADFORMAT or E_INVALIDARG
+ if( hr == DSERR_BADFORMAT || hr == E_INVALIDARG )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("CreateSoundBuffer"), hr );
+
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ }
+
+ // Create the notification events, so that we know when to fill
+ // the buffer as the sound plays.
+ if( FAILED( hr = pDSBuffer->QueryInterface( IID_IDirectSoundNotify,
+ (VOID**)&pDSNotify ) ) )
+ {
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ];
+ if( aPosNotify == NULL )
+ return E_OUTOFMEMORY;
+
+ for( DWORD i = 0; i < dwNotifyCount; i++ )
+ {
+ aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
+ aPosNotify[i].hEventNotify = hNotifyEvent;
+ }
+
+ // Tell DirectSound when to notify us. The notification will come in the from
+ // of signaled events that are handled in WinMain()
+ if( FAILED( hr = pDSNotify->SetNotificationPositions( dwNotifyCount,
+ aPosNotify ) ) )
+ {
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("SetNotificationPositions"), hr );
+ }
+
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+
+ // Create the sound
+ *ppStreamingSound = new CStreamingSound( pDSBuffer, dwDSBufferSize, pWaveFile, dwNotifySize );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::CSound()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSound::CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize,
+ DWORD dwNumBuffers, CWaveFile* pWaveFile )
+{
+ DWORD i;
+
+ m_apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ for( i=0; iSetCurrentPosition(0);
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::~CSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSound::~CSound()
+{
+ for( DWORD i=0; iLock( 0, m_dwDSBufferSize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ NULL, NULL, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // Reset the wave file to the beginning
+ m_pWaveFile->ResetFile();
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwWavDataRead ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ if( dwWavDataRead == 0 )
+ {
+ // Wav is blank, so just fill with silence
+ FillMemory( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ else if( dwWavDataRead < dwDSLockedBufferSize )
+ {
+ // If the wav file was smaller than the DirectSound buffer,
+ // we need to fill the remainder of the buffer with data
+ if( bRepeatWavIfBufferLarger )
+ {
+ // Reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwWavDataRead; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full
+ // for very short files
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwWavDataRead );
+ if( FAILED(hr) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwWavDataRead;
+ }
+ }
+ else
+ {
+ // Don't repeat the wav file, just fill in silence
+ FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead,
+ dwDSLockedBufferSize - dwWavDataRead,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ }
+
+ // Unlock the buffer, we don't need it anymore.
+ pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::RestoreBuffer()
+// Desc: Restores the lost buffer. *pbWasRestored returns TRUE if the buffer was
+// restored. It can also NULL if the information is not needed.
+//-----------------------------------------------------------------------------
+HRESULT CSound::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored )
+{
+ HRESULT hr;
+
+ if( pDSB == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbWasRestored )
+ *pbWasRestored = FALSE;
+
+ DWORD dwStatus;
+ if( FAILED( hr = pDSB->GetStatus( &dwStatus ) ) )
+ return DXTRACE_ERR( TEXT("GetStatus"), hr );
+
+ if( dwStatus & DSBSTATUS_BUFFERLOST )
+ {
+ // Since the app could have just been activated, then
+ // DirectSound may not be giving us control yet, so
+ // the restoring the buffer may fail.
+ // If it does, sleep until DirectSound gives us control.
+ do
+ {
+ hr = pDSB->Restore();
+ if( hr == DSERR_BUFFERLOST )
+ Sleep( 10 );
+ }
+ while( hr = pDSB->Restore() );
+
+ if( pbWasRestored != NULL )
+ *pbWasRestored = TRUE;
+
+ return S_OK;
+ }
+ else
+ {
+ return S_FALSE;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetFreeBuffer()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetFreeBuffer()
+{
+ BOOL bIsPlaying = FALSE;
+ DWORD i;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( i=0; iGetStatus( &dwStatus );
+ if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
+ break;
+ }
+ }
+
+ if( i != m_dwNumBuffers )
+ return m_apDSBuffer[ i ];
+ else
+ return m_apDSBuffer[ rand() % m_dwNumBuffers ];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetBuffer()
+// Desc:
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetBuffer( DWORD dwIndex )
+{
+ if( m_apDSBuffer == NULL )
+ return NULL;
+ if( dwIndex >= m_dwNumBuffers )
+ return NULL;
+
+ return m_apDSBuffer[dwIndex];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Get3DBufferInterface()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSound::Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer )
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( dwIndex >= m_dwNumBuffers )
+ return E_INVALIDARG;
+
+ *ppDS3DBuffer = NULL;
+
+ return m_apDSBuffer[dwIndex]->QueryInterface( IID_IDirectSound3DBuffer,
+ (VOID**)ppDS3DBuffer );
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Play()
+// Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING
+// in the dwFlags to loop the sound
+//-----------------------------------------------------------------------------
+HRESULT CSound::Play( DWORD dwPriority, DWORD dwFlags )
+{
+ HRESULT hr;
+ BOOL bRestored;
+
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();
+
+ if( pDSB == NULL )
+ return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL );
+
+ // Restore the buffer if it was lost
+ if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+
+ // Make DirectSound do pre-processing on sound effects
+ Reset();
+ }
+
+ return pDSB->Play( 0, dwPriority, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Stop()
+// Desc: Stops the sound from playing
+//-----------------------------------------------------------------------------
+HRESULT CSound::Stop()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iStop();
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Reset()
+// Desc: Reset all of the sound buffers
+//-----------------------------------------------------------------------------
+HRESULT CSound::Reset()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iSetCurrentPosition( 0 );
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::IsSoundPlaying()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+BOOL CSound::IsSoundPlaying()
+{
+ BOOL bIsPlaying = FALSE;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( DWORD i=0; iGetStatus( &dwStatus );
+ bIsPlaying |= ( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );
+ }
+ }
+
+ return bIsPlaying;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::CStreamingSound()
+// Desc: Setups up a buffer so data can be streamed from the wave file into
+// buffer. This is very useful for large wav files that would take a
+// while to load. The buffer is initially filled with data, then
+// as sound is played the notification events are signaled and more data
+// is written into the buffer by calling HandleWaveStreamNotification()
+//-----------------------------------------------------------------------------
+CStreamingSound::CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize,
+ CWaveFile* pWaveFile, DWORD dwNotifySize )
+ : CSound( &pDSBuffer, dwDSBufferSize, 1, pWaveFile )
+{
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNotifySize = dwNotifySize;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::~CStreamingSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CStreamingSound::~CStreamingSound()
+{
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::HandleWaveStreamNotification()
+// Desc: Handle the notification that tell us to put more wav data in the
+// circular buffer
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::HandleWaveStreamNotification( BOOL bLoopedPlay )
+{
+ HRESULT hr;
+ DWORD dwCurrentPlayPos;
+ DWORD dwPlayDelta;
+ DWORD dwBytesWrittenToBuffer;
+ VOID* pDSLockedBuffer = NULL;
+ VOID* pDSLockedBuffer2 = NULL;
+ DWORD dwDSLockedBufferSize;
+ DWORD dwDSLockedBufferSize2;
+
+ if( m_apDSBuffer == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ return S_OK;
+ }
+
+ // Lock the DirectSound buffer
+ if( FAILED( hr = m_apDSBuffer[0]->Lock( m_dwNextWriteOffset, m_dwNotifySize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // m_dwDSBufferSize and m_dwNextWriteOffset are both multiples of m_dwNotifySize,
+ // it should the second buffer should never be valid
+ if( pDSLockedBuffer2 != NULL )
+ return E_UNEXPECTED;
+
+ if( !m_bFillNextNotificationWithSilence )
+ {
+ // Fill the DirectSound buffer with wav data
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+ }
+ else
+ {
+ // Fill the DirectSound buffer with silence
+ FillMemory( pDSLockedBuffer, dwDSLockedBufferSize,
+ (BYTE)( m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ dwBytesWrittenToBuffer = dwDSLockedBufferSize;
+ }
+
+ // If the number of bytes written is less than the
+ // amount we requested, we have a short file.
+ if( dwBytesWrittenToBuffer < dwDSLockedBufferSize )
+ {
+ if( !bLoopedPlay )
+ {
+ // Fill in silence for the rest of the buffer.
+ FillMemory( (BYTE*) pDSLockedBuffer + dwBytesWrittenToBuffer,
+ dwDSLockedBufferSize - dwBytesWrittenToBuffer,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+
+ // Any future notifications should just fill the buffer with silence
+ m_bFillNextNotificationWithSilence = TRUE;
+ }
+ else
+ {
+ // We are looping, so reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwBytesWrittenToBuffer; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full (for very short files).
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwBytesWrittenToBuffer;
+ }
+ }
+ }
+
+ // Unlock the DirectSound buffer
+ m_apDSBuffer[0]->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ // Figure out how much data has been played so far. When we have played
+ // passed the end of the file, we will either need to start filling the
+ // buffer with silence or starting reading from the beginning of the file,
+ // depending if the user wants to loop the sound
+ if( FAILED( hr = m_apDSBuffer[0]->GetCurrentPosition( &dwCurrentPlayPos, NULL ) ) )
+ return DXTRACE_ERR( TEXT("GetCurrentPosition"), hr );
+
+ // Check to see if the position counter looped
+ if( dwCurrentPlayPos < m_dwLastPlayPos )
+ dwPlayDelta = ( m_dwDSBufferSize - m_dwLastPlayPos ) + dwCurrentPlayPos;
+ else
+ dwPlayDelta = dwCurrentPlayPos - m_dwLastPlayPos;
+
+ m_dwPlayProgress += dwPlayDelta;
+ m_dwLastPlayPos = dwCurrentPlayPos;
+
+ // If we are now filling the buffer with silence, then we have found the end so
+ // check to see if the entire sound has played, if it has then stop the buffer.
+ if( m_bFillNextNotificationWithSilence )
+ {
+ // We don't want to cut off the sound before it's done playing.
+ if( m_dwPlayProgress >= m_pWaveFile->GetSize() )
+ {
+ m_apDSBuffer[0]->Stop();
+ }
+ }
+
+ // Update where the buffer will lock (for next time)
+ m_dwNextWriteOffset += dwDSLockedBufferSize;
+ m_dwNextWriteOffset %= m_dwDSBufferSize; // Circular buffer
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::Reset()
+// Desc: Resets the sound so it will begin playing at the beginning
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::Reset()
+{
+ HRESULT hr;
+
+ if( m_apDSBuffer[0] == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ }
+
+ m_pWaveFile->ResetFile();
+
+ return m_apDSBuffer[0]->SetCurrentPosition( 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::CWaveFile()
+// Desc: Constructs the class. Call Open() to open a wave file for reading.
+// Then call Read() as needed. Calling the destructor or Close()
+// will close the file.
+//-----------------------------------------------------------------------------
+CWaveFile::CWaveFile()
+{
+ m_pwfx = NULL;
+ m_hmmio = NULL;
+ m_dwSize = 0;
+ m_bIsReadingFromMemory = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::~CWaveFile()
+// Desc: Destructs the class
+//-----------------------------------------------------------------------------
+CWaveFile::~CWaveFile()
+{
+ Close();
+
+ if( !m_bIsReadingFromMemory )
+ SAFE_DELETE_ARRAY( m_pwfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Open()
+// Desc: Opens a wave file for reading
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ HRESULT hr;
+
+ m_dwFlags = dwFlags;
+ m_bIsReadingFromMemory = FALSE;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ if( strFileName == NULL )
+ return E_INVALIDARG;
+ SAFE_DELETE_ARRAY( m_pwfx );
+
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );
+
+ if( NULL == m_hmmio )
+ {
+ HRSRC hResInfo;
+ HGLOBAL hResData;
+ DWORD dwSize;
+ VOID* pvRes;
+
+ // Loading it as a file failed, so try it as a resource
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAVE") ) ) )
+ {
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAV") ) ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("FindResource"), E_FAIL );
+ }
+
+ if( NULL == ( hResData = LoadResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("LoadResource"), E_FAIL );
+
+ if( 0 == ( dwSize = SizeofResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("SizeofResource"), E_FAIL );
+
+ if( NULL == ( pvRes = LockResource( hResData ) ) )
+ return DXTRACE_ERR( TEXT("LockResource"), E_FAIL );
+
+ CHAR* pData = new CHAR[ dwSize ];
+ memcpy( pData, pvRes, dwSize );
+
+ MMIOINFO mmioInfo;
+ ZeroMemory( &mmioInfo, sizeof(mmioInfo) );
+ mmioInfo.fccIOProc = FOURCC_MEM;
+ mmioInfo.cchBuffer = dwSize;
+ mmioInfo.pchBuffer = (CHAR*) pData;
+
+ m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );
+ }
+
+ if( FAILED( hr = ReadMMIO() ) )
+ {
+ // ReadMMIO will fail if its an not a wave file
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR_NOMSGBOX( TEXT("ReadMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ // After the reset, the size of the wav file is m_ck.cksize so store it now
+ m_dwSize = m_ck.cksize;
+ }
+ else
+ {
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF |
+ MMIO_READWRITE |
+ MMIO_CREATE );
+ if( NULL == m_hmmio )
+ return DXTRACE_ERR( TEXT("mmioOpen"), E_FAIL );
+
+ if( FAILED( hr = WriteMMIO( pwfx ) ) )
+ {
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR( TEXT("WriteMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+ }
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::OpenFromMemory()
+// Desc: copy data to CWaveFile member variable from memory
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::OpenFromMemory( BYTE* pbData, ULONG ulDataSize,
+ WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ m_pwfx = pwfx;
+ m_ulDataSize = ulDataSize;
+ m_pbData = pbData;
+ m_pbDataCur = m_pbData;
+ m_bIsReadingFromMemory = TRUE;
+
+ if( dwFlags != WAVEFILE_READ )
+ return E_NOTIMPL;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ReadMMIO()
+// Desc: Support function for reading from a multimedia I/O stream.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_pwfx.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ReadMMIO()
+{
+ MMCKINFO ckIn; // chunk info. for general use.
+ PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in.
+
+ m_pwfx = NULL;
+
+ if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Check to make sure this is a valid wave file
+ if( (m_ckRiff.ckid != FOURCC_RIFF) ||
+ (m_ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("mmioFOURCC"), E_FAIL );
+
+ // Search the input file for for the 'fmt ' chunk.
+ ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Expect the 'fmt' chunk to be at least as large as ;
+ // if there are extra parameters at the end, we'll ignore them
+ if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) )
+ return DXTRACE_ERR( TEXT("sizeof(PCMWAVEFORMAT)"), E_FAIL );
+
+ // Read the 'fmt ' chunk into .
+ if( mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat,
+ sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ // Allocate the waveformatex, but if its not pcm format, read the next
+ // word, and thats how many extra bytes to allocate.
+ if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )
+ {
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("m_pwfx"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = 0;
+ }
+ else
+ {
+ // Read in length of extra bytes.
+ WORD cbExtraBytes = 0L;
+ if( mmioRead( m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("new"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = cbExtraBytes;
+
+ // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
+ if( mmioRead( m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize))+sizeof(WORD)),
+ cbExtraBytes ) != cbExtraBytes )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+ }
+ }
+
+ // Ascend the input file out of the 'fmt ' chunk.
+ if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::GetSize()
+// Desc: Retuns the size of the read access wave file
+//-----------------------------------------------------------------------------
+DWORD CWaveFile::GetSize()
+{
+ return m_dwSize;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ResetFile()
+// Desc: Resets the internal m_ck pointer so reading starts from the
+// beginning of the file again
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ResetFile()
+{
+ if( m_bIsReadingFromMemory )
+ {
+ m_pbDataCur = m_pbData;
+ }
+ else
+ {
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ // Seek to the data
+ if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),
+ SEEK_SET ) )
+ return DXTRACE_ERR( TEXT("mmioSeek"), E_FAIL );
+
+ // Search the input file for the 'data' chunk.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ if( 0 != mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+ }
+ else
+ {
+ // Create the 'data' chunk that holds the waveform samples.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ m_ck.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( 0 != mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Read()
+// Desc: Reads section of data from a wave file into pBuffer and returns
+// how much read in pdwSizeRead, reading not more than dwSizeToRead.
+// This uses m_ck to determine where to start reading from. So
+// subsequent calls will be continue where the last left off unless
+// Reset() is called.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )
+{
+ if( m_bIsReadingFromMemory )
+ {
+ if( m_pbDataCur == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( (BYTE*)(m_pbDataCur + dwSizeToRead) >
+ (BYTE*)(m_pbData + m_ulDataSize) )
+ {
+ dwSizeToRead = m_ulDataSize - (DWORD)(m_pbDataCur - m_pbData);
+ }
+
+ CopyMemory( pBuffer, m_pbDataCur, dwSizeToRead );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = dwSizeToRead;
+
+ return S_OK;
+ }
+ else
+ {
+ MMIOINFO mmioinfoIn; // current status of m_hmmio
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pBuffer == NULL || pdwSizeRead == NULL )
+ return E_INVALIDARG;
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+
+ UINT cbDataIn = dwSizeToRead;
+ if( cbDataIn > m_ck.cksize )
+ cbDataIn = m_ck.cksize;
+
+ m_ck.cksize -= cbDataIn;
+
+ for( DWORD cT = 0; cT < cbDataIn; cT++ )
+ {
+ // Copy the bytes from the io to the buffer.
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ {
+ if( 0 != mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ return DXTRACE_ERR( TEXT("mmioinfoIn.pchNext"), E_FAIL );
+ }
+
+ // Actual copy.
+ *((BYTE*)pBuffer+cT) = *((BYTE*)mmioinfoIn.pchNext);
+ mmioinfoIn.pchNext++;
+ }
+
+ if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = cbDataIn;
+
+ return S_OK;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Close()
+// Desc: Closes the wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Close()
+{
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+ else
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( 0 != mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ // Ascend the output file out of the 'data' chunk -- this will cause
+ // the chunk size of the 'data' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Do this here instead...
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioSeek( m_hmmio, 0, SEEK_SET );
+
+ if( 0 != (INT)mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ m_ck.ckid = mmioFOURCC('f', 'a', 'c', 't');
+
+ if( 0 == mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ {
+ DWORD dwSamples = 0;
+ mmioWrite( m_hmmio, (HPSTR)&dwSamples, sizeof(DWORD) );
+ mmioAscend( m_hmmio, &m_ck, 0 );
+ }
+
+ // Ascend the output file out of the 'RIFF' chunk -- this will cause
+ // the chunk size of the 'RIFF' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::WriteMMIO()
+// Desc: Support function for reading from a multimedia I/O stream
+// pwfxDest is the WAVEFORMATEX for this new wave file.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_ck.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::WriteMMIO( WAVEFORMATEX *pwfxDest )
+{
+ DWORD dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile.
+ MMCKINFO ckOut1;
+
+ dwFactChunk = (DWORD)-1;
+
+ // Create the output file RIFF chunk of form type 'WAVE'.
+ m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');
+ m_ckRiff.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // We are now descended into the 'RIFF' chunk we just created.
+ // Now create the 'fmt ' chunk. Since we know the size of this chunk,
+ // specify it in the MMCKINFO structure so MMIO doesn't have to seek
+ // back and set the chunk size after ascending from the chunk.
+ m_ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ m_ck.cksize = sizeof(PCMWAVEFORMAT);
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type.
+ if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM )
+ {
+ if( mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+ else
+ {
+ // Write the variable length size.
+ if( (UINT)mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(*pwfxDest) + pwfxDest->cbSize ) !=
+ ( sizeof(*pwfxDest) + pwfxDest->cbSize ) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+
+ // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Now create the fact chunk, not required for PCM but nice to have. This is filled
+ // in when the close routine is called.
+ ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't');
+ ckOut1.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( mmioWrite( m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) !=
+ sizeof(dwFactChunk) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+
+ // Now ascend out of the fact chunk...
+ if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Write()
+// Desc: Writes data to the open wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Write( UINT nSizeToWrite, BYTE* pbSrcData, UINT* pnSizeWrote )
+{
+ UINT cT;
+
+ if( m_bIsReadingFromMemory )
+ return E_NOTIMPL;
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pnSizeWrote == NULL || pbSrcData == NULL )
+ return E_INVALIDARG;
+
+ *pnSizeWrote = 0;
+
+ for( cT = 0; cT < nSizeToWrite; cT++ )
+ {
+ if( m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite )
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+ if( 0 != mmioAdvance( m_hmmio, &m_mmioinfoOut, MMIO_WRITE ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+ }
+
+ *((BYTE*)m_mmioinfoOut.pchNext) = *((BYTE*)pbSrcData+cT);
+ (BYTE*)m_mmioinfoOut.pchNext++;
+
+ (*pnSizeWrote)++;
+ }
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V04/dsutil.h b/V04/dsutil.h
new file mode 100644
index 0000000..57d26df
--- /dev/null
+++ b/V04/dsutil.h
@@ -0,0 +1,170 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.h
+//
+// Desc:
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#ifndef DSUTIL_H
+#define DSUTIL_H
+
+#include
+#include
+#include
+#include
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes used by this header
+//-----------------------------------------------------------------------------
+class CSoundManager;
+class CSound;
+class CStreamingSound;
+class CWaveFile;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Typing macros
+//-----------------------------------------------------------------------------
+#define WAVEFILE_READ 1
+#define WAVEFILE_WRITE 2
+
+#define DSUtil_StopSound(s) { if(s) s->Stop(); }
+#define DSUtil_PlaySound(s) { if(s) s->Play( 0, 0 ); }
+#define DSUtil_PlaySoundLooping(s) { if(s) s->Play( 0, DSBPLAY_LOOPING ); }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSoundManager
+// Desc:
+//-----------------------------------------------------------------------------
+class CSoundManager
+{
+protected:
+ LPDIRECTSOUND8 m_pDS;
+
+public:
+ CSoundManager();
+ ~CSoundManager();
+
+ HRESULT Initialize( HWND hWnd, DWORD dwCoopLevel, DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate );
+ inline LPDIRECTSOUND GetDirectSound() { return m_pDS; }
+ HRESULT SetPrimaryBufferFormat( DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate );
+ HRESULT Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener );
+
+ HRESULT Create( CSound** ppSound, LPTSTR strWaveFileName, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
+ HRESULT CreateFromMemory( CSound** ppSound, BYTE* pbData, ULONG ulDataSize, LPWAVEFORMATEX pwfx, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
+ HRESULT CreateStreaming( CStreamingSound** ppStreamingSound, LPTSTR strWaveFileName, DWORD dwCreationFlags, GUID guid3DAlgorithm, DWORD dwNotifyCount, DWORD dwNotifySize, HANDLE hNotifyEvent );
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSound
+// Desc: Encapsulates functionality of a DirectSound buffer.
+//-----------------------------------------------------------------------------
+class CSound
+{
+protected:
+ LPDIRECTSOUNDBUFFER* m_apDSBuffer;
+ DWORD m_dwDSBufferSize;
+ CWaveFile* m_pWaveFile;
+ DWORD m_dwNumBuffers;
+
+ HRESULT RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored );
+
+public:
+ CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize, DWORD dwNumBuffers, CWaveFile* pWaveFile );
+ virtual ~CSound();
+
+ HRESULT Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer );
+ HRESULT FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger );
+ LPDIRECTSOUNDBUFFER GetFreeBuffer();
+ LPDIRECTSOUNDBUFFER GetBuffer( DWORD dwIndex );
+
+ HRESULT Play( DWORD dwPriority, DWORD dwFlags );
+ HRESULT Stop();
+ HRESULT Reset();
+ BOOL IsSoundPlaying();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CStreamingSound
+// Desc: Encapsulates functionality to play a wave file with DirectSound.
+// The Create() method loads a chunk of wave file into the buffer,
+// and as sound plays more is written to the buffer by calling
+// HandleWaveStreamNotification() whenever hNotifyEvent is signaled.
+//-----------------------------------------------------------------------------
+class CStreamingSound : public CSound
+{
+protected:
+ DWORD m_dwLastPlayPos;
+ DWORD m_dwPlayProgress;
+ DWORD m_dwNotifySize;
+ DWORD m_dwNextWriteOffset;
+ BOOL m_bFillNextNotificationWithSilence;
+
+public:
+ CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize, CWaveFile* pWaveFile, DWORD dwNotifySize );
+ ~CStreamingSound();
+
+ HRESULT HandleWaveStreamNotification( BOOL bLoopedPlay );
+ HRESULT Reset();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CWaveFile
+// Desc: Encapsulates reading or writing sound data to or from a wave file
+//-----------------------------------------------------------------------------
+class CWaveFile
+{
+public:
+ WAVEFORMATEX* m_pwfx; // Pointer to WAVEFORMATEX structure
+ HMMIO m_hmmio; // MM I/O handle for the WAVE
+ MMCKINFO m_ck; // Multimedia RIFF chunk
+ MMCKINFO m_ckRiff; // Use in opening a WAVE file
+ DWORD m_dwSize; // The size of the wave file
+ MMIOINFO m_mmioinfoOut;
+ DWORD m_dwFlags;
+ BOOL m_bIsReadingFromMemory;
+ BYTE* m_pbData;
+ BYTE* m_pbDataCur;
+ ULONG m_ulDataSize;
+
+protected:
+ HRESULT ReadMMIO();
+ HRESULT WriteMMIO( WAVEFORMATEX *pwfxDest );
+
+public:
+ CWaveFile();
+ ~CWaveFile();
+
+ HRESULT Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags );
+ HRESULT OpenFromMemory( BYTE* pbData, ULONG ulDataSize, WAVEFORMATEX* pwfx, DWORD dwFlags );
+ HRESULT Close();
+
+ HRESULT Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead );
+ HRESULT Write( UINT nSizeToWrite, BYTE* pbData, UINT* pnSizeWrote );
+
+ DWORD GetSize();
+ HRESULT ResetFile();
+ WAVEFORMATEX* GetFormat() { return m_pwfx; };
+};
+
+
+
+
+#endif // DSUTIL_H
diff --git a/V04/resource.h b/V04/resource.h
new file mode 100644
index 0000000..e35bf2f
--- /dev/null
+++ b/V04/resource.h
@@ -0,0 +1,24 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Demo.rc
+//
+#define IDI_MAIN 101
+#define IDR_MENU 102
+#define IDR_ACCEL 103
+#define IDM_EXIT 1001
+#define IDM_TEST 40024
+#define ID_ULTRIS_NEUESSPIEL 40025
+#define ID_ULTRIS_PAUSE 40026
+#define ID_ULTRIS_SOUND 40027
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 132
+#define _APS_NEXT_COMMAND_VALUE 40028
+#define _APS_NEXT_CONTROL_VALUE 1019
+#define _APS_NEXT_SYMED_VALUE 104
+#endif
+#endif
diff --git a/V04/ul_adeck.bmp b/V04/ul_adeck.bmp
new file mode 100644
index 0000000..5f3b867
Binary files /dev/null and b/V04/ul_adeck.bmp differ
diff --git a/V04/ul_down.wav b/V04/ul_down.wav
new file mode 100644
index 0000000..84cf9e1
Binary files /dev/null and b/V04/ul_down.wav differ
diff --git a/V04/ul_dreh.WAV b/V04/ul_dreh.WAV
new file mode 100644
index 0000000..790ef8c
Binary files /dev/null and b/V04/ul_dreh.WAV differ
diff --git a/V04/ul_ende.WAV b/V04/ul_ende.WAV
new file mode 100644
index 0000000..43c73f0
Binary files /dev/null and b/V04/ul_ende.WAV differ
diff --git a/V04/ul_feld.bmp b/V04/ul_feld.bmp
new file mode 100644
index 0000000..3225b6b
Binary files /dev/null and b/V04/ul_feld.bmp differ
diff --git a/V04/ul_hgrnd.bmp b/V04/ul_hgrnd.bmp
new file mode 100644
index 0000000..c33b077
Binary files /dev/null and b/V04/ul_hgrnd.bmp differ
diff --git a/V04/ul_move.WAV b/V04/ul_move.WAV
new file mode 100644
index 0000000..22b2a99
Binary files /dev/null and b/V04/ul_move.WAV differ
diff --git a/V04/ul_prev.bmp b/V04/ul_prev.bmp
new file mode 100644
index 0000000..c791074
Binary files /dev/null and b/V04/ul_prev.bmp differ
diff --git a/V04/ul_row1.WAV b/V04/ul_row1.WAV
new file mode 100644
index 0000000..ab5bfca
Binary files /dev/null and b/V04/ul_row1.WAV differ
diff --git a/V04/ul_row2.WAV b/V04/ul_row2.WAV
new file mode 100644
index 0000000..671fc71
Binary files /dev/null and b/V04/ul_row2.WAV differ
diff --git a/V04/ul_start.WAV b/V04/ul_start.WAV
new file mode 100644
index 0000000..f66bfef
Binary files /dev/null and b/V04/ul_start.WAV differ
diff --git a/V04/ul_stein.bmp b/V04/ul_stein.bmp
new file mode 100644
index 0000000..dadb7a0
Binary files /dev/null and b/V04/ul_stein.bmp differ
diff --git a/V04/ul_win.wav b/V04/ul_win.wav
new file mode 100644
index 0000000..e11c880
Binary files /dev/null and b/V04/ul_win.wav differ
diff --git a/V04/ul_z0.bmp b/V04/ul_z0.bmp
new file mode 100644
index 0000000..10fe8a6
Binary files /dev/null and b/V04/ul_z0.bmp differ
diff --git a/V04/ul_z1.bmp b/V04/ul_z1.bmp
new file mode 100644
index 0000000..1ce2939
Binary files /dev/null and b/V04/ul_z1.bmp differ
diff --git a/V04/ul_z2.bmp b/V04/ul_z2.bmp
new file mode 100644
index 0000000..9006084
Binary files /dev/null and b/V04/ul_z2.bmp differ
diff --git a/V04/ul_z3.bmp b/V04/ul_z3.bmp
new file mode 100644
index 0000000..5710c67
Binary files /dev/null and b/V04/ul_z3.bmp differ
diff --git a/V04/ul_z4.bmp b/V04/ul_z4.bmp
new file mode 100644
index 0000000..11306ed
Binary files /dev/null and b/V04/ul_z4.bmp differ
diff --git a/V04/ul_z5.bmp b/V04/ul_z5.bmp
new file mode 100644
index 0000000..b4a22b5
Binary files /dev/null and b/V04/ul_z5.bmp differ
diff --git a/V04/ul_z6.bmp b/V04/ul_z6.bmp
new file mode 100644
index 0000000..62616d4
Binary files /dev/null and b/V04/ul_z6.bmp differ
diff --git a/V04/ul_z7.bmp b/V04/ul_z7.bmp
new file mode 100644
index 0000000..d9178df
Binary files /dev/null and b/V04/ul_z7.bmp differ
diff --git a/V04/ul_z8.bmp b/V04/ul_z8.bmp
new file mode 100644
index 0000000..98e1a18
Binary files /dev/null and b/V04/ul_z8.bmp differ
diff --git a/V04/ul_z9.bmp b/V04/ul_z9.bmp
new file mode 100644
index 0000000..e6245a3
Binary files /dev/null and b/V04/ul_z9.bmp differ
diff --git a/V05/Demo.aps b/V05/Demo.aps
new file mode 100644
index 0000000..573262e
Binary files /dev/null and b/V05/Demo.aps differ
diff --git a/V05/Demo.cpp b/V05/Demo.cpp
new file mode 100644
index 0000000..acfc324
--- /dev/null
+++ b/V05/Demo.cpp
@@ -0,0 +1,843 @@
+# include
+# include
+# include
+# include
+# include "ddutil.h"
+# include "dsutil.h"
+# include "resource.h"
+
+const int ultris_nettobreite = 360; // Breite des Inneren des Haupfensters
+const int ultris_nettohoehe = 520; // Hoehe des Inneren des Hauptfensters
+int ultris_bruttobreite; // Breite des gesamten Haupfensters (incl. Rahmen)
+int ultris_bruttohoehe; // Hoehe des gesamten Haupfensters (incl. Rahmen)
+
+HINSTANCE ultris_instance; // Instanz der Ultris Applikation
+HWND ultris_window; // Das Hauptfenster von Ultris
+HMENU ultris_menu; // Das Menu von Ultris
+
+const int sound_start = 0; // Sound fuer neues Spiel
+const int sound_dreh = 1; // Sound bei Drehung
+const int sound_move = 2; // Sound bei rechts/links Bewegung
+const int sound_down = 3; // Sound bei Aufprall
+const int sound_row1 = 4; // Sound bei Abraeumen einer Reihe
+const int sound_row2 = 5; // Sound bei Abraeumen von mehreren Reihen
+const int sound_ende = 6; // Sound bei Spielende
+const int sound_win = 7; // Sound bei Eintrag in Highscore Tabelle
+const int anzahl_sounds = 8; // Anzahl Sounds
+
+char *soundfiles[anzahl_sounds] =
+ {
+ "ul_start.wav",
+ "ul_dreh.wav",
+ "ul_move.wav",
+ "ul_down.wav",
+ "ul_row1.wav",
+ "ul_row2.wav",
+ "ul_ende.wav",
+ "ul_win.wav"
+ };
+
+class sounds
+ {
+ private:
+ CSoundManager smgr;
+ CSound *snd[anzahl_sounds];
+ public:
+ int on;
+ sounds();
+ int init( HWND wnd);
+ void play( int snr);
+ ~sounds();
+ };
+
+sounds::sounds()
+ {
+ int i;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ snd[i] = 0;
+ on = 1;
+ }
+
+int sounds::init( HWND wnd)
+ {
+ HRESULT ret;
+ int i;
+
+ ret = smgr.Initialize( wnd, DSSCL_PRIORITY, 2, 22050, 16);
+ if( ret < 0)
+ return ret;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ {
+ ret = smgr.Create( snd+i, soundfiles[i]);
+ if( ret < 0)
+ return ret;
+ }
+ return S_OK;
+ }
+
+sounds::~sounds()
+ {
+ int i;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ {
+ if( snd[i])
+ delete snd[i];
+ }
+ }
+
+void sounds::play( int i)
+ {
+ if( !on)
+ return;
+ if( snd[i]->IsSoundPlaying())
+ {
+ snd[i]->Stop();
+ snd[i]->Reset();
+ }
+ snd[i]->Play(0,0);
+ }
+
+sounds ultris_sounds;
+
+class display
+ {
+ private:
+ CDisplay dsply;
+ CSurface *hgrnd;
+ CSurface *fldst;
+ CSurface *fllst;
+ CSurface *prvst;
+ CSurface *deckel;
+ CSurface *ziff[10];
+ public:
+ display();
+ void free_all();
+ ~display() {free_all();}
+ HRESULT init( HWND wnd);
+ void hintergrund() { dsply.Blt( 0, 0, hgrnd);}
+ void abdeckung() { dsply.Blt( 60, 0, deckel);}
+ void ziffer( int pos, int val) { dsply.Blt( 120+pos*20, 50, ziff[val]);}
+ void feldstein( int z, int s) { dsply.Blt( 80+s*20, 100+z*20, fldst);}
+ void fallstein( int z, int s, int offset) { dsply.Blt( 80+s*20, 100+z*20+offset, fllst);}
+ void prevstein( int p, int z, int s, int b, int h){ dsply.Blt( 290+s*15+(4-b)*15/2, 410-p*70+z*15+(4-h)*15/2, prvst);}
+ void update(){ dsply.UpdateBounds();}
+ HRESULT cooperative(){return dsply.GetDirectDraw()->TestCooperativeLevel();}
+ HRESULT restore();
+ HRESULT present();
+ };
+
+display::display()
+ {
+ int i;
+
+ hgrnd = 0;
+ fldst = 0;
+ fllst = 0;
+ prvst = 0;
+ deckel = 0;
+ for( i = 0; i < 10; i++)
+ ziff[i] = 0;
+ }
+
+void display::free_all()
+ {
+ int i;
+
+ if( hgrnd)
+ delete hgrnd;
+ if( fldst)
+ delete fldst;
+ if( fllst)
+ delete fllst;
+ if( prvst)
+ delete prvst;
+ if( deckel)
+ delete deckel;
+ for( i = 0; i < 10; i++)
+ {
+ if( ziff[i])
+ delete ziff[i];
+ }
+ }
+
+HRESULT display::init( HWND wnd)
+ {
+ HRESULT hr;
+ int i;
+ char fname[20];
+
+ hr = dsply.CreateWindowedDisplay( wnd, ultris_nettobreite, ultris_nettohoehe );
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &hgrnd, "ul_hgrnd.bmp", ultris_nettobreite, ultris_nettohoehe);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &fldst, "ul_feld.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &fllst, "ul_stein.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &prvst, "ul_prev.bmp", 15, 15);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &deckel, "ul_adeck.bmp", 240, 100);
+ if( hr < 0)
+ return hr;
+ for( i = 0; i < 10; i++)
+ {
+ sprintf( fname, "ul_z%d.bmp", i);
+ hr = dsply.CreateSurfaceFromBitmap( &ziff[i], fname, 20, 40);
+ if( hr < 0)
+ return hr;
+ }
+ return S_OK;
+ }
+
+HRESULT display::restore()
+ {
+ HRESULT hr;
+ int i;
+ char fname[20];
+
+ hr = dsply.GetDirectDraw()->RestoreAllSurfaces();
+ if( hr < 0)
+ return hr;
+ hr = hgrnd->DrawBitmap( "ul_hgrnd.bmp", ultris_nettobreite, ultris_nettohoehe);
+ if( hr < 0)
+ return hr;
+ hr = fldst->DrawBitmap( "ul_feld.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = fllst->DrawBitmap( "ul_stein.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = prvst->DrawBitmap( "ul_prev.bmp", 15, 15);
+ if( hr < 0)
+ return hr;
+ hr = deckel->DrawBitmap( "ul_adeck.bmp", 240, 100);
+ if( hr < 0)
+ return hr;
+
+ for( i = 0; i < 10; i++)
+ {
+ sprintf( fname, "ul_z%d.bmp", i);
+ hr = ziff[i]->DrawBitmap( fname, 20, 40);
+ if( hr < 0)
+ return hr;
+ }
+ return S_OK;
+ }
+
+HRESULT display::present()
+ {
+ HRESULT hr;
+
+ hr = dsply.Present();
+ if( hr == DDERR_SURFACELOST )
+ return restore();
+ return hr;
+ }
+
+display ultris_display;
+
+const int anzahl_formen = 35; // Anzahl der Formen
+
+//
+// Datenstruktur für die Formen
+//
+struct form
+ {
+ char h; // Hoehe
+ char b; // Breite
+ char data[4][4]; // Vorhandene Segmente
+ };
+
+// Form 1 in allen Drehvarianten
+//
+// *** * * *
+// * ** *** **
+// * *
+const form s_01_1 = {2, 3, {{1,1,1}, {0,1,0}}};
+const form s_01_2 = {3, 2, {{1,0}, {1,1}, {1,0}}};
+const form s_01_3 = {2, 3, {{0,1,0}, {1,1,1}}};
+const form s_01_4 = {3, 2, {{0,1}, {1,1}, {0,1}}};
+
+// Form 2 in allen Drehvarianten
+//
+// ** * ** *
+// ** ** ** **
+// * *
+const form s_02_1 = {2, 3, {{1,1,0}, {0,1,1}}};
+const form s_02_2 = {3, 2, {{0,1}, {1,1}, {1,0}}};
+const form s_02_3 = {2, 3, {{1,1,0}, {0,1,1}}};
+const form s_02_4 = {3, 2, {{0,1}, {1,1}, {1,0}}};
+
+// Form 3 in allen Drehvarianten
+//
+// ** * ** *
+// ** ** ** **
+// * *
+const form s_03_1 = {2, 3, {{0,1,1}, {1,1,0}}};
+const form s_03_2 = {3, 2, {{1,0}, {1,1}, {0,1}}};
+const form s_03_3 = {2, 3, {{0,1,1}, {1,1,0}}};
+const form s_03_4 = {3, 2, {{1,0}, {1,1}, {0,1}}};
+
+// Form 4 in allen Drehvarianten
+//
+// *** ** * *
+// * * *** *
+// * **
+const form s_04_1 = {2, 3, {{1,1,1}, {0,0,1}}};
+const form s_04_2 = {3, 2, {{1,1}, {1,0}, {1,0}}};
+const form s_04_3 = {2, 3, {{1,0,0}, {1,1,1}}};
+const form s_04_4 = {3, 2, {{0,1}, {0,1}, {1,1}}};
+
+// Form 5 in allen Drehvarianten
+//
+// * ** *** *
+// *** * * *
+// * **
+const form s_05_1 = {2, 3, {{0,0,1}, {1,1,1}}};
+const form s_05_2 = {3, 2, {{1,1}, {0,1}, {0,1}}};
+const form s_05_3 = {2, 3, {{1,1,1}, {1,0,0}}};
+const form s_05_4 = {3, 2, {{1,0}, {1,0}, {1,1}}};
+
+// Form 6 in allen Drehvarianten
+//
+// ** ** ** **
+// ** ** ** **
+//
+const form s_06_1 = {2, 2, {{1,1}, {1,1}}};
+const form s_06_2 = {2, 2, {{1,1}, {1,1}}};
+const form s_06_3 = {2, 2, {{1,1}, {1,1}}};
+const form s_06_4 = {2, 2, {{1,1}, {1,1}}};
+
+// Form 7 in allen Drehvarianten
+//
+// **** * **** *
+// * *
+// * *
+// * *
+const form s_07_1 = {1, 4, {{1,1,1,1}}};
+const form s_07_2 = {4, 1, {{1},{1},{1},{1}}};
+const form s_07_3 = {1, 4, {{1,1,1,1}}};
+const form s_07_4 = {4, 1, {{1},{1},{1},{1}}};
+
+// Form 8 in allen Drehvarianten
+//
+// *** ** * * **
+// * * * *** *
+// ** **
+const form s_08_1 = {2, 3, {{1,1,1}, {1,0,1}}};
+const form s_08_2 = {3, 2, {{1,1},{1,0},{1,1}}};
+const form s_08_3 = {2, 3, {{1,0,1}, {1,1,1}}};
+const form s_08_4 = {3, 2, {{1,1},{0,1},{1,1}}};
+
+// Form 9 in allen Drehvarianten
+//
+// ** * ** *
+// * *** * ***
+// ** * ** *
+const form s_09_1 = {3, 3, {{1,1,0}, {0,1,0}, {0,1,1}}};
+const form s_09_2 = {3, 3, {{0,0,1}, {1,1,1}, {1,0,0}}};
+const form s_09_3 = {3, 3, {{1,1,0}, {0,1,0}, {0,1,1}}};
+const form s_09_4 = {3, 3, {{0,0,1}, {1,1,1}, {1,0,0}}};
+
+// Form 10 in allen Drehvarianten
+//
+// ** ** * *
+// * * ** **
+//
+const form s_10_1 = {2, 2, {{1,1}, {0,1}}};
+const form s_10_2 = {2, 2, {{1,1}, {1,0}}};
+const form s_10_3 = {2, 2, {{1,0}, {1,1}}};
+const form s_10_4 = {2, 2, {{0,1}, {1,1}}};
+
+// Form 11 in allen Drehvarianten
+//
+// * * * *
+// *** *** *** ***
+// * * * *
+const form s_11_1 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+const form s_11_2 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+const form s_11_3 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+const form s_11_4 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+
+// Form 12 in allen Drehvarianten
+//
+// ** ** * ***
+// ** *** ** **
+// * **
+const form s_12_1 = {3, 2, {{1,1}, {1,1}, {1,0}}};
+const form s_12_2 = {2, 3, {{1,1,0}, {1,1,1}}};
+const form s_12_3 = {3, 2, {{0,1}, {1,1}, {1,1}}};
+const form s_12_4 = {2, 3, {{1,1,1}, {0,1,1}}};
+
+// Form 13 in allen Drehvarianten
+//
+// ** *** * **
+// ** ** ** ***
+// * **
+const form s_13_1 = {3, 2, {{1,1}, {1,1}, {0,1}}};
+const form s_13_2 = {2, 3, {{1,1,1}, {1,1,0}}};
+const form s_13_3 = {3, 2, {{1,0}, {1,1}, {1,1}}};
+const form s_13_4 = {2, 3, {{0,1,1}, {1,1,1}}};
+
+// Form 14 in allen Drehvarianten
+//
+// *** * * ***
+// * * * *
+// * *** *** *
+const form s_14_1 = {3, 3, {{1,1,1}, {1,0,0}, {1,0,0}}};
+const form s_14_2 = {3, 3, {{1,0,0}, {1,0,0}, {1,1,1}}};
+const form s_14_3 = {3, 3, {{0,0,1}, {0,0,1}, {1,1,1}}};
+const form s_14_4 = {3, 3, {{1,1,1}, {0,0,1}, {0,0,1}}};
+
+// Form 15 in allen Drehvarianten
+//
+// * * * *
+const form s_15_1 = {1, 1, {{1}}};
+const form s_15_2 = {1, 1, {{1}}};
+const form s_15_3 = {1, 1, {{1}}};
+const form s_15_4 = {1, 1, {{1}}};
+
+// Form 16 in allen Drehvarianten
+//
+// * * * *
+// * * * *
+const form s_16_1 = {2, 2, {{1,0}, {0,1}}};
+const form s_16_2 = {2, 2, {{0,1}, {1,0}}};
+const form s_16_3 = {2, 2, {{1,0}, {0,1}}};
+const form s_16_4 = {2, 2, {{0,1}, {1,0}}};
+
+// Form 17 in allen Drehvarianten
+//
+// * * * *
+// * * * *
+// * * * *
+const form s_17_1 = {3, 3, {{1,0,0}, {0,1,0}, {0,0,1}}};
+const form s_17_2 = {3, 3, {{0,0,1}, {0,1,0}, {1,0,0}}};
+const form s_17_3 = {3, 3, {{1,0,0}, {0,1,0}, {0,0,1}}};
+const form s_17_4 = {3, 3, {{0,0,1}, {0,1,0}, {1,0,0}}};
+
+// Form 18 in allen Drehvarianten
+//
+// * * * *
+// * * * * * * * *
+// * * * *
+const form s_18_1 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+const form s_18_2 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+const form s_18_3 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+const form s_18_4 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+
+// Form 19 in allen Drehvarianten
+//
+// * * * * *
+// * * * * *
+// * *
+const form s_19_1 = {2, 3, {{0,1,0}, {1,0,1}}};
+const form s_19_2 = {3, 2, {{0,1},{1,0},{0,1}}};
+const form s_19_3 = {2, 3, {{1,0,1}, {0,1,0}}};
+const form s_19_4 = {3, 2, {{1,0},{0,1},{1,0}}};
+
+// Form 20 in allen Drehvarianten
+//
+// *** * * *
+// * *** * ***
+// * * *** *
+const form s_20_1 = {3, 3, {{1,1,1}, {0,1,0}, {0,1,0}}};
+const form s_20_2 = {3, 3, {{1,0,0}, {1,1,1}, {1,0,0}}};
+const form s_20_3 = {3, 3, {{0,1,0}, {0,1,0}, {1,1,1}}};
+const form s_20_4 = {3, 3, {{0,0,1}, {1,1,1}, {0,0,1}}};
+
+// Form 21 in allen Drehvarianten
+//
+// * * * * *
+// * ** * **
+// * * * * *
+const form s_21_1 = {3, 3, {{1,0,1}, {0,1,0}, {0,1,0}}};
+const form s_21_2 = {3, 3, {{1,0,0}, {0,1,1}, {1,0,0}}};
+const form s_21_3 = {3, 3, {{0,1,0}, {0,1,0}, {1,0,1}}};
+const form s_21_4 = {3, 3, {{0,0,1}, {1,1,0}, {0,0,1}}};
+
+// Form 22 in allen Drehvarianten
+//
+// ** * ** *
+// * *
+//
+const form s_22_1 = {1, 2, {{1,1}}};
+const form s_22_2 = {2, 1, {{1},{1}}};
+const form s_22_3 = {1, 2, {{1,1}}};
+const form s_22_4 = {2, 1, {{1},{1}}};
+
+// Form 23 in allen Drehvarianten
+//
+// *** * *** *
+// * *
+// * *
+const form s_23_1 = {1, 3, {{1,1,1}}};
+const form s_23_2 = {3, 1, {{1},{1},{1}}};
+const form s_23_3 = {1, 3, {{1,1,1}}};
+const form s_23_4 = {3, 1, {{1},{1},{1}}};
+
+// Form 24 in allen Drehvarianten
+//
+// ** * * *
+// * * ** *
+// * *
+const form s_24_1 = {2, 3, {{1,1,0}, {0,0,1}}};
+const form s_24_2 = {3, 2, {{0,1}, {1,0}, {1,0}}};
+const form s_24_3 = {2, 3, {{1,0,0}, {0,1,1}}};
+const form s_24_4 = {3, 2, {{0,1}, {0,1}, {1,0}}};
+
+// Form 25 in allen Drehvarianten
+//
+// * * ** *
+// ** * * *
+// * *
+const form s_25_1 = {2, 3, {{0,0,1}, {1,1,0}}};
+const form s_25_2 = {3, 2, {{1,0}, {0,1}, {0,1}}};
+const form s_25_3 = {2, 3, {{0,1,1}, {1,0,0}}};
+const form s_25_4 = {3, 2, {{1,0}, {1,0}, {0,1}}};
+
+// Form 26 in allen Drehvarianten
+//
+// ** * ** *
+// ** * ** *
+// * *
+// * *
+const form s_26_1 = {2, 4, {{0,0,1,1}, {1,1,0,0}}};
+const form s_26_2 = {4, 2, {{1,0},{1,0},{0,1}, {0,1}}};
+const form s_26_3 = {2, 4, {{0,0,1,1}, {1,1,0,0}}};
+const form s_26_4 = {4, 2, {{1,0},{1,0},{0,1}, {0,1}}};
+
+// Form 27 in allen Drehvarianten
+//
+// ** * ** *
+// ** * ** *
+// * *
+// * *
+const form s_27_1 = {2, 4, {{1,1,0,0},{0,0,1,1}}};
+const form s_27_2 = {4, 2, {{0,1},{0,1},{1,0},{1,0}}};
+const form s_27_3 = {2, 4, {{1,1,0,0},{0,0,1,1}}};
+const form s_27_4 = {4, 2, {{0,1},{0,1},{1,0},{1,0}}};
+
+// Form 28 in allen Drehvarianten
+//
+// * * * ** *
+// ** * * * *
+// * *
+// * *
+const form s_28_1 = {2, 4, {{1,0,0,1},{0,1,1,0}}};
+const form s_28_2 = {4, 2, {{1,0},{0,1},{0,1},{1,0}}};
+const form s_28_3 = {2, 4, {{0,1,1,0},{1,0,0,1}}};
+const form s_28_4 = {4, 2, {{0,1},{1,0},{1,0},{0,1}}};
+
+// Form 29 in allen Drehvarianten
+//
+// ** * * **
+// * * * *
+// * ** ** *
+const form s_29_1 = {3, 3, {{0,1,1}, {1,0,0}, {1,0,0}}};
+const form s_29_2 = {3, 3, {{1,0,0}, {1,0,0}, {0,1,1}}};
+const form s_29_3 = {3, 3, {{0,0,1}, {0,0,1}, {1,1,0}}};
+const form s_29_4 = {3, 3, {{1,1,0}, {0,0,1}, {0,0,1}}};
+
+// Form 30 in allen Drehvarianten
+//
+// * ** * * **
+// * * * * * *
+// * * ** * **
+const form s_30_1 = {3, 3, {{0,1,0}, {1,0,1}, {1,0,1}}};
+const form s_30_2 = {3, 3, {{0,1,1}, {1,0,0}, {0,1,1}}};
+const form s_30_3 = {3, 3, {{1,0,1}, {1,0,1}, {0,1,0}}};
+const form s_30_4 = {3, 3, {{1,1,0}, {0,0,1}, {1,1,0}}};
+
+// Form 31 in allen Drehvarianten
+//
+// *** * * *
+// * * *** *
+// * *
+// * *
+const form s_31_1 = {2, 4, {{1,1,1,0},{0,0,0,1}}};
+const form s_31_2 = {4, 2, {{0,1},{1,0},{1,0},{1,0}}};
+const form s_31_3 = {2, 4, {{1,0,0,0},{0,1,1,1}}};
+const form s_31_4 = {4, 2, {{0,1},{0,1},{0,1},{1,0}}};
+
+// Form 32 in allen Drehvarianten
+//
+// * * *** *
+// *** * * *
+// * *
+// * *
+const form s_32_1 = {2, 4, {{0,0,0,1},{1,1,1,0}}};
+const form s_32_2 = {4, 2, {{1,0},{0,1},{0,1},{0,1}}};
+const form s_32_3 = {2, 4, {{0,1,1,1},{1,0,0,0}}};
+const form s_32_4 = {4, 2, {{1,0},{1,0},{1,0},{0,1}}};
+
+// Form 33 in allen Drehvarianten
+//
+// ** *** ** ***
+// ** *** ** ***
+// ** **
+const form s_33_1 = {3, 2, {{1,1}, {1,1}, {1,1}}};
+const form s_33_2 = {2, 3, {{1,1,1}, {1,1,1}}};
+const form s_33_3 = {3, 2, {{1,1}, {1,1}, {1,1}}};
+const form s_33_4 = {2, 3, {{1,1,1}, {1,1,1}}};
+
+// Form 34 in allen Drehvarianten
+//
+// **** * ** *
+// ** ** **** **
+// ** **
+// * *
+const form s_34_1 = {2, 4, {{1,1,1,1},{0,1,1,0}}};
+const form s_34_2 = {4, 2, {{1,0},{1,1},{1,1},{1,0}}};
+const form s_34_3 = {2, 4, {{0,1,1,0},{1,1,1,1}}};
+const form s_34_4 = {4, 2, {{0,1},{1,1},{1,1},{0,1}}};
+
+// Form 35 in allen Drehvarianten
+//
+// ** * ** *
+// * *** * ***
+// ** * ** *
+const form s_35_1 = {3, 3, {{0,1,1}, {0,1,0}, {1,1,0}}};
+const form s_35_2 = {3, 3, {{1,0,0}, {1,1,1}, {0,0,1}}};
+const form s_35_3 = {3, 3, {{0,1,1}, {0,1,0}, {1,1,0}}};
+const form s_35_4 = {3, 3, {{1,0,0}, {1,1,1}, {0,0,1}}};
+
+// Array mit allen Steinformen in allen Drehvarianten
+// Zugriff in der Form
+//
+// ultris_form[ steinform][ drehvariante]
+//
+// mit 0 <= steinform < 35 und 0 <= drehvariante <= 4
+
+const form *ultris_form[anzahl_formen][4] =
+ {
+ { &s_01_1, &s_01_2, &s_01_3, &s_01_4},
+ { &s_02_1, &s_02_2, &s_02_3, &s_02_4},
+ { &s_03_1, &s_03_2, &s_03_3, &s_03_4},
+ { &s_04_1, &s_04_2, &s_04_3, &s_04_4},
+ { &s_05_1, &s_05_2, &s_05_3, &s_05_4},
+ { &s_06_1, &s_06_2, &s_06_3, &s_06_4},
+ { &s_07_1, &s_07_2, &s_07_3, &s_07_4},
+ { &s_08_1, &s_08_2, &s_08_3, &s_08_4},
+ { &s_09_1, &s_09_2, &s_09_3, &s_09_4},
+ { &s_10_1, &s_10_2, &s_10_3, &s_10_4},
+ { &s_11_1, &s_11_2, &s_11_3, &s_11_4},
+ { &s_12_1, &s_12_2, &s_12_3, &s_12_4},
+ { &s_13_1, &s_13_2, &s_13_3, &s_13_4},
+ { &s_14_1, &s_14_2, &s_14_3, &s_14_4},
+ { &s_15_1, &s_15_2, &s_15_3, &s_15_4},
+ { &s_16_1, &s_16_2, &s_16_3, &s_16_4},
+ { &s_17_1, &s_17_2, &s_17_3, &s_17_4},
+ { &s_18_1, &s_18_2, &s_18_3, &s_18_4},
+ { &s_19_1, &s_19_2, &s_19_3, &s_19_4},
+ { &s_20_1, &s_20_2, &s_20_3, &s_20_4},
+ { &s_21_1, &s_21_2, &s_21_3, &s_21_4},
+ { &s_22_1, &s_22_2, &s_22_3, &s_22_4},
+ { &s_23_1, &s_23_2, &s_23_3, &s_23_4},
+ { &s_24_1, &s_24_2, &s_24_3, &s_24_4},
+ { &s_25_1, &s_25_2, &s_25_3, &s_25_4},
+ { &s_26_1, &s_26_2, &s_26_3, &s_26_4},
+ { &s_27_1, &s_27_2, &s_27_3, &s_27_4},
+ { &s_28_1, &s_28_2, &s_28_3, &s_28_4},
+ { &s_29_1, &s_29_2, &s_29_3, &s_29_4},
+ { &s_30_1, &s_30_2, &s_30_3, &s_30_4},
+ { &s_31_1, &s_31_2, &s_31_3, &s_31_4},
+ { &s_32_1, &s_32_2, &s_32_3, &s_32_4},
+ { &s_33_1, &s_33_2, &s_33_3, &s_33_4},
+ { &s_34_1, &s_34_2, &s_34_3, &s_34_4},
+ { &s_35_1, &s_35_2, &s_35_3, &s_35_4}
+ };
+
+
+// V5 Beginn
+BOOL CALLBACK hilfedialog( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ switch (uMsg)
+ {
+ case WM_COMMAND:
+ if((wParam == IDOK)||(wParam == IDCANCEL))
+ {
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+BOOL CALLBACK ultrisdialog( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ switch (uMsg)
+ {
+ case WM_COMMAND:
+ if( wParam == IDC_WEITERE_INFO)
+ {
+ ShellExecute(NULL, "open", "http://www-et.bocholt.fh-gelsenkirchen.de", NULL, NULL, SW_SHOWNORMAL);
+ return TRUE;
+ }
+ if((wParam == IDOK)||(wParam == IDCANCEL))
+ {
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+// V5 Ende
+
+
+/*
+** ultris_windowhandler
+*/
+
+LRESULT CALLBACK ultris_windowhandler( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+ {
+ switch(msg)
+ {
+ case WM_COMMAND:
+ switch( LOWORD( wParam))
+ {
+ case IDM_EXIT:
+ PostMessage( hWnd, WM_CLOSE, 0, 0);
+ return 0;
+ case ID_ULTRIS_SOUND:
+ ultris_sounds.on = !ultris_sounds.on;
+ CheckMenuItem( ultris_menu, ID_ULTRIS_SOUND, ultris_sounds.on ? MF_CHECKED:MF_UNCHECKED);
+ return 0;
+// V5 Beginn
+ case ID_INFO_HILFE:
+ DialogBox( ultris_instance, MAKEINTRESOURCE( IDD_HILFE), ultris_window, hilfedialog);
+ return 0;
+ case ID_INFO_ULTRIS:
+ DialogBox( ultris_instance, MAKEINTRESOURCE( IDD_ULTRIS), ultris_window, ultrisdialog);
+ return 0;
+// V5 Ende
+ case IDM_TEST: // Testcode
+ return 0;
+ }
+ break;
+ case WM_GETMINMAXINFO:
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.x = ((MINMAXINFO *)lParam)->ptMaxTrackSize.x = ultris_bruttobreite;
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.y = ((MINMAXINFO *)lParam)->ptMaxTrackSize.y = ultris_bruttohoehe;
+ return 0;
+ case WM_DESTROY:
+ PostQuitMessage( 0);
+ return 0;
+ case WM_MOVE:
+ ultris_display.update();
+ return 0;
+ case WM_PAINT:
+ break;
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+ }
+
+/*
+** WinMain
+*/
+int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow)
+ {
+ MSG msg;
+ HACCEL acc;
+ WNDCLASSEX wcx;
+
+ ultris_instance = hInst;
+
+ wcx.cbSize = sizeof( wcx);
+ wcx.lpszClassName = TEXT( "Ultris");
+ wcx.lpfnWndProc = ultris_windowhandler;
+ wcx.style = CS_VREDRAW | CS_HREDRAW;
+ wcx.hInstance = hInst;
+ wcx.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hIconSm = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hCursor = LoadCursor( NULL, IDC_ARROW);
+ wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wcx.lpszMenuName = MAKEINTRESOURCE( IDR_MENU);
+ wcx.cbClsExtra = 0;
+ wcx.cbWndExtra = 0;
+
+ if( !RegisterClassEx( &wcx))
+ return 0;
+
+ acc = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_ACCEL));
+
+ ultris_bruttohoehe = ultris_nettohoehe + 2*GetSystemMetrics( SM_CYSIZEFRAME)
+ + GetSystemMetrics( SM_CYMENU)
+ + GetSystemMetrics( SM_CYCAPTION);
+ ultris_bruttobreite = ultris_nettobreite + 2*GetSystemMetrics( SM_CXSIZEFRAME);
+
+ ultris_window = CreateWindowEx( 0, TEXT( "Ultris"), TEXT( "Ultris"), WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ ultris_bruttobreite, ultris_bruttohoehe, NULL, NULL, hInst, NULL);
+ if( !ultris_window)
+ return 0;
+
+ ultris_menu = GetMenu( ultris_window);
+
+ if( ultris_sounds.init( ultris_window) < 0)
+ {
+ MessageBox( ultris_window, "Fehler beim Initialisieren der Sounds", "Ultris-Fehlermeldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
+ return 0;
+ }
+ CheckMenuItem( ultris_menu, ID_ULTRIS_SOUND, ultris_sounds.on ? MF_CHECKED:MF_UNCHECKED);
+
+ if( ultris_display.init( ultris_window) < 0)
+ {
+ MessageBox( ultris_window, "Fehler beim Initialisieren der Grafik", "Ultris-Fehlermeldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
+ return 0;
+ }
+
+ MoveWindow( ultris_window, (GetSystemMetrics(SM_CXSCREEN)-ultris_bruttobreite)/2,
+ (GetSystemMetrics(SM_CYSCREEN)-ultris_bruttohoehe)/2,
+ ultris_bruttobreite, ultris_bruttohoehe, TRUE);
+
+ ShowWindow( ultris_window, nCmdShow);
+
+ while( TRUE)
+ {
+ if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE))
+ {
+ if( GetMessage( &msg, NULL, 0, 0 ) == 0)
+ return 0; // Message ist WM_QUIT
+
+ if( TranslateAccelerator( ultris_window, acc, &msg) == 0)
+ {
+ TranslateMessage( &msg);
+ DispatchMessage( &msg);
+ }
+ }
+ else
+ {
+ HRESULT hr;
+ hr = ultris_display.cooperative();
+ if( hr < 0)
+ {
+ switch( hr )
+ {
+ case DDERR_EXCLUSIVEMODEALREADYSET:
+ Sleep(10);
+ break;
+ case DDERR_WRONGMODE:
+ ultris_display.free_all();
+ ultris_display.init( ultris_window);
+ PostMessage( ultris_window, WM_PAINT, 0, 0);
+ break;
+ }
+ }
+ else
+ {
+ // Hier koennen wir uns um das Spiel kuemmern
+ }
+ }
+ }
+ }
+
+
+
diff --git a/V05/Demo.h b/V05/Demo.h
new file mode 100644
index 0000000..a19fa69
--- /dev/null
+++ b/V05/Demo.h
@@ -0,0 +1,12 @@
+
+#if !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
+#define AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "resource.h"
+
+
+#endif // !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
diff --git a/V05/Demo.ncb b/V05/Demo.ncb
new file mode 100644
index 0000000..564ba37
Binary files /dev/null and b/V05/Demo.ncb differ
diff --git a/V05/Demo.rc b/V05/Demo.rc
new file mode 100644
index 0000000..43ccb57
--- /dev/null
+++ b/V05/Demo.rc
@@ -0,0 +1,202 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include
+#include
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Deutsch (Deutschland) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+#ifdef _WIN32
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU MENU DISCARDABLE
+BEGIN
+ POPUP "Ultris"
+ BEGIN
+ MENUITEM "Neues Spiel", ID_ULTRIS_NEUESSPIEL
+ MENUITEM "Pause", ID_ULTRIS_PAUSE
+ MENUITEM "Sound", ID_ULTRIS_SOUND
+ MENUITEM SEPARATOR
+ MENUITEM "Ende", IDM_EXIT
+ END
+ POPUP "Einstellungen"
+ BEGIN
+ MENUITEM "Konfiguration", ID_EINSTELLUNGEN_KONFIGURATION
+
+ END
+ POPUP "Info"
+ BEGIN
+ MENUITEM "Hilfe", ID_INFO_HILFE
+ MENUITEM "Highscores", ID_INFO_HIGHSCORES
+ MENUITEM "Ultris", ID_INFO_ULTRIS
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MAIN ICON DISCARDABLE "Icon.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCEL ACCELERATORS DISCARDABLE
+BEGIN
+ "T", IDM_TEST, VIRTKEY, CONTROL, NOINVERT
+ VK_ESCAPE, IDM_EXIT, VIRTKEY, NOINVERT
+ VK_F5, ID_ULTRIS_SOUND, VIRTKEY, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_HILFE DIALOG DISCARDABLE 0, 0, 302, 107
+STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Hilfe"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,245,90,50,14
+ LTEXT "F1: Neues Spiel",IDC_STATIC,15,22,130,8
+ LTEXT "F2: Pause (ein/aus)",IDC_STATIC,15,34,130,8
+ LTEXT "F3: Schneller",IDC_STATIC,15,46,130,8
+ LTEXT "F4: Langsamer",IDC_STATIC,15,58,130,8
+ LTEXT "F5: Sound (ein/aus)",IDC_STATIC,15,70,130,8
+ GROUPBOX "Steuerung des Spiels",IDC_STATIC,7,7,142,78
+ GROUPBOX "Steuerung der Steine",IDC_STATIC,153,7,142,78
+ LTEXT "J oder Cursor left: Links",IDC_STATIC,159,22,131,8
+ LTEXT "L oder Cursor right: Rechts",IDC_STATIC,159,34,131,8
+ LTEXT "K oder Cursor down: Linksdrehung",IDC_STATIC,159,46,131,
+ 8
+ LTEXT "I oder Cursor up: Rechtsdrehung",IDC_STATIC,159,58,131,
+ 8
+ LTEXT "Space: Stein fallen lassen",IDC_STATIC,159,70,126,8
+END
+
+IDD_ULTRIS DIALOG DISCARDABLE 0, 0, 204, 142
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Über Ultris"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,150,125,50,14
+ CONTROL 130,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_SUNKEN | WS_BORDER,7,7,190,78
+ CTEXT "Demoprogramm\rzur Vorlesung\rGrafik und Spieleprogrammierung",
+ IDC_STATIC,7,92,195,28
+ PUSHBUTTON "Weitere Informationen",IDC_WEITERE_INFO,5,125,140,14
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_HILFE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 295
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 100
+ END
+
+ IDD_ULTRIS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 197
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 135
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_ULTRIS BITMAP DISCARDABLE "bmp00001.bmp"
+#endif // Deutsch (Deutschland) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Englisch (USA) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include \r\n"
+ "#include \0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Englisch (USA) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/V05/Demo.sln b/V05/Demo.sln
new file mode 100644
index 0000000..737efb7
--- /dev/null
+++ b/V05/Demo.sln
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo.vcproj", "{E4D498D1-702B-4430-8EA5-1A667B2BD793}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {E4D498D1-702B-4430-8EA5-1A667B2BD793}.Debug.ActiveCfg = Debug|Win32
+ {E4D498D1-702B-4430-8EA5-1A667B2BD793}.Debug.Build.0 = Debug|Win32
+ {E4D498D1-702B-4430-8EA5-1A667B2BD793}.Release.ActiveCfg = Release|Win32
+ {E4D498D1-702B-4430-8EA5-1A667B2BD793}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/V05/Demo.suo b/V05/Demo.suo
new file mode 100644
index 0000000..3f5f215
Binary files /dev/null and b/V05/Demo.suo differ
diff --git a/V05/Demo.vcproj b/V05/Demo.vcproj
new file mode 100644
index 0000000..98ce341
--- /dev/null
+++ b/V05/Demo.vcproj
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V05/Icon.ico b/V05/Icon.ico
new file mode 100644
index 0000000..7a53f63
Binary files /dev/null and b/V05/Icon.ico differ
diff --git a/V05/bmp00001.bmp b/V05/bmp00001.bmp
new file mode 100644
index 0000000..12d2027
Binary files /dev/null and b/V05/bmp00001.bmp differ
diff --git a/V05/ddutil.cpp b/V05/ddutil.cpp
new file mode 100644
index 0000000..faccc24
--- /dev/null
+++ b/V05/ddutil.cpp
@@ -0,0 +1,1035 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: DirectDraw framewark classes. Feel free to use this class as a
+// starting point for adding extra functionality.
+//
+//
+// Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include
+#include "ddutil.h"
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::CDisplay()
+{
+ m_pDD = NULL;
+ m_pddsFrontBuffer = NULL;
+ m_pddsBackBuffer = NULL;
+ m_pddsBackBufferLeft = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ~CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::~CDisplay()
+{
+ DestroyObjects();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DestroyObjects()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::DestroyObjects()
+{
+ SAFE_RELEASE( m_pddsBackBufferLeft );
+ SAFE_RELEASE( m_pddsBackBuffer );
+ SAFE_RELEASE( m_pddsFrontBuffer );
+
+ if( m_pDD )
+ m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL );
+
+ SAFE_RELEASE( m_pDD );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateFullScreenDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth,
+ DWORD dwHeight, DWORD dwBPP )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ // Set the display mode
+ if( FAILED( m_pDD->SetDisplayMode( dwWidth, dwHeight, dwBPP, 0, 0 ) ) )
+ return E_FAIL;
+
+ // Create primary surface (with backbuffer attached)
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
+ DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE;
+ ddsd.dwBackBufferCount = 1;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer,
+ NULL ) ) )
+ return E_FAIL;
+
+ // Get a pointer to the back buffer
+ DDSCAPS2 ddscaps;
+ ZeroMemory( &ddscaps, sizeof( ddscaps ) );
+ ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
+
+ if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
+ &m_pddsBackBuffer ) ) )
+ return E_FAIL;
+
+ m_pddsBackBuffer->AddRef();
+
+ m_hWnd = hWnd;
+ m_bWindowed = FALSE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateWindowedDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_NORMAL );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ RECT rcWork;
+ RECT rc;
+ DWORD dwStyle;
+
+ // If we are still a WS_POPUP window we should convert to a normal app
+ // window so we look like a windows app.
+ dwStyle = GetWindowStyle( hWnd );
+ dwStyle &= ~WS_POPUP;
+ dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
+ SetWindowLong( hWnd, GWL_STYLE, dwStyle );
+
+ // Aet window size
+ SetRect( &rc, 0, 0, dwWidth, dwHeight );
+
+ AdjustWindowRectEx( &rc, GetWindowStyle(hWnd), GetMenu(hWnd) != NULL,
+ GetWindowExStyle(hWnd) );
+
+ SetWindowPos( hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
+ SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
+
+ // Make sure our window does not hang outside of the work area
+ SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWork, 0 );
+ GetWindowRect( hWnd, &rc );
+ if( rc.left < rcWork.left ) rc.left = rcWork.left;
+ if( rc.top < rcWork.top ) rc.top = rcWork.top;
+ SetWindowPos( hWnd, NULL, rc.left, rc.top, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ LPDIRECTDRAWCLIPPER pcClipper;
+
+ // Create the primary surface
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+ if( FAILED( m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
+ return E_FAIL;
+
+ // Create the backbuffer surface
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = pcClipper->SetHWnd( 0, hWnd ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pcClipper ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ // Done with clipper
+ pcClipper->Release();
+
+ m_hWnd = hWnd;
+ m_bWindowed = TRUE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurface( CSurface** ppSurface,
+ DWORD dwWidth, DWORD dwHeight )
+{
+ if( NULL == m_pDD )
+ return E_POINTER;
+ if( NULL == ppSurface )
+ return E_INVALIDARG;
+
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromBitmap()
+// Desc: Create a DirectDrawSurface from a bitmap resource or bitmap file.
+// Use MAKEINTRESOURCE() to pass a constant into strBMP.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromBitmap( CSurface** ppSurface,
+ TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight )
+{
+ HRESULT hr;
+ HBITMAP hBMP = NULL;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+
+ if( m_pDD == NULL || strBMP == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = bmp.bmWidth;
+ ddsd.dwHeight = bmp.bmHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = (*ppSurface)->DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromText()
+// Desc: Creates a DirectDrawSurface from a text string using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromText( CSurface** ppSurface,
+ HFONT hFont, TCHAR* strText,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ LPDIRECTDRAWSURFACE7 pDDS = NULL;
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ SIZE sizeText;
+
+ if( m_pDD == NULL || strText == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ hDC = GetDC( NULL );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ GetTextExtentPoint32( hDC, strText, _tcslen(strText), &sizeText );
+ ReleaseDC( NULL, hDC );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = sizeText.cx;
+ ddsd.dwHeight = sizeText.cy;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ if( FAILED( hr = (*ppSurface)->DrawText( hFont, strText, 0, 0,
+ crBackground, crForeground ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Present()
+{
+ HRESULT hr;
+
+ if( NULL == m_pddsFrontBuffer && NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ while( 1 )
+ {
+ if( m_bWindowed )
+ hr = m_pddsFrontBuffer->Blt( &m_rcWindow, m_pddsBackBuffer,
+ NULL, DDBLT_WAIT, NULL );
+ else
+ hr = m_pddsFrontBuffer->Flip( NULL, 0 );
+
+ if( hr == DDERR_SURFACELOST )
+ {
+ m_pddsFrontBuffer->Restore();
+ m_pddsBackBuffer->Restore();
+ }
+
+ if( hr != DDERR_WASSTILLDRAWING )
+ return hr;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer || NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Set the palette before loading the bitmap
+ if( pPalette )
+ m_pddsFrontBuffer->SetPalette( pPalette );
+
+ CSurface backBuffer;
+ backBuffer.Create( m_pddsBackBuffer );
+
+ if( FAILED( backBuffer.DrawBitmap( hbm, 0, 0, 0, 0 ) ) )
+ return E_FAIL;
+
+ return Present();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, DDBLTFAST_SRCCOLORKEY );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds, RECT* prc,
+ DWORD dwFlags )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc )
+{
+ if( NULL == pSurface )
+ return E_INVALIDARG;
+
+ if( pSurface->IsColorKeyed() )
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, DDBLTFAST_SRCCOLORKEY );
+ else
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Clear( DWORD dwColor )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Erase the background
+ DDBLTFX ddbltfx;
+ ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
+ ddbltfx.dwSize = sizeof(ddbltfx);
+ ddbltfx.dwFillColor = dwColor;
+
+ return m_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::SetPalette( LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer )
+ return E_POINTER;
+
+ return m_pddsFrontBuffer->SetPalette( pPalette );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette,
+ const TCHAR* strBMP )
+{
+ HRSRC hResource = NULL;
+ RGBQUAD* pRGB = NULL;
+ BITMAPINFOHEADER* pbi = NULL;
+ PALETTEENTRY aPalette[256];
+ HANDLE hFile = NULL;
+ DWORD iColor;
+ DWORD dwColors;
+ BITMAPFILEHEADER bf;
+ BITMAPINFOHEADER bi;
+ DWORD dwBytesRead;
+
+ if( m_pDD == NULL || strBMP == NULL || ppPalette == NULL )
+ return E_INVALIDARG;
+
+ *ppPalette = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hResource = FindResource( NULL, strBMP, RT_BITMAP );
+ if( hResource )
+ {
+ pbi = (LPBITMAPINFOHEADER) LockResource( LoadResource( NULL, hResource ) );
+ if( NULL == pbi )
+ return E_FAIL;
+
+ pRGB = (RGBQUAD*) ( (BYTE*) pbi + pbi->biSize );
+
+ // Figure out how many colors there are
+ if( pbi == NULL || pbi->biSize < sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if( pbi->biBitCount > 8 )
+ dwColors = 0;
+ else if( pbi->biClrUsed == 0 )
+ dwColors = 1 << pbi->biBitCount;
+ else
+ dwColors = pbi->biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around.
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ aPalette[iColor].peRed = pRGB[iColor].rgbRed;
+ aPalette[iColor].peGreen = pRGB[iColor].rgbGreen;
+ aPalette[iColor].peBlue = pRGB[iColor].rgbBlue;
+ aPalette[iColor].peFlags = 0;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+ }
+
+ // Attempt to load bitmap as a file
+ hFile = CreateFile( strBMP, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
+ if( NULL == hFile )
+ return E_FAIL;
+
+ // Read the BITMAPFILEHEADER
+ ReadFile( hFile, &bf, sizeof(bf), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bf) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the BITMAPINFOHEADER
+ ReadFile( hFile, &bi, sizeof(bi), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bi) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the PALETTEENTRY
+ ReadFile( hFile, aPalette, sizeof(aPalette), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(aPalette) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ CloseHandle( hFile );
+
+ // Figure out how many colors there are
+ if( bi.biSize != sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if (bi.biBitCount > 8)
+ dwColors = 0;
+ else if (bi.biClrUsed == 0)
+ dwColors = 1 << bi.biBitCount;
+ else
+ dwColors = bi.biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around since DirectDraw uses RGB
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ BYTE r = aPalette[iColor].peRed;
+ aPalette[iColor].peRed = aPalette[iColor].peBlue;
+ aPalette[iColor].peBlue = r;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::UpdateBounds()
+{
+ if( m_bWindowed )
+ {
+ GetClientRect( m_hWnd, &m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow+1 );
+ }
+ else
+ {
+ SetRect( &m_rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN) );
+ }
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::InitClipper
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::InitClipper()
+{
+ LPDIRECTDRAWCLIPPER pClipper;
+ HRESULT hr;
+
+ // Create a clipper when using GDI to draw on the primary surface
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pClipper, NULL ) ) )
+ return hr;
+
+ pClipper->SetHWnd( 0, m_hWnd );
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pClipper ) ) )
+ return hr;
+
+ // We can release the clipper now since g_pDDSPrimary
+ // now maintains a ref count on the clipper
+ SAFE_RELEASE( pClipper );
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::CSurface()
+{
+ m_pdds = NULL;
+ m_bColorKeyed = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::~CSurface()
+{
+ SAFE_RELEASE( m_pdds );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAWSURFACE7 pdds )
+{
+ m_pdds = pdds;
+
+ if( m_pdds )
+ {
+ m_pdds->AddRef();
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_ddsd.dwSize = sizeof(m_ddsd);
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd )
+{
+ HRESULT hr;
+
+ // Create the DDraw surface
+ if( FAILED( hr = pDD->CreateSurface( pddsd, &m_pdds, NULL ) ) )
+ return hr;
+
+ // Prepare the DDSURFACEDESC structure
+ m_ddsd.dwSize = sizeof(m_ddsd);
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Destroy()
+{
+ SAFE_RELEASE( m_pdds );
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawBitmap()
+// Desc: Draws a bitmap over an entire DirectDrawSurface, stretching the
+// bitmap if nessasary
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( HBITMAP hBMP,
+ DWORD dwBMPOriginX, DWORD dwBMPOriginY,
+ DWORD dwBMPWidth, DWORD dwBMPHeight )
+{
+ HDC hDCImage;
+ HDC hDC;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ if( hBMP == NULL || m_pdds == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ // Get the surface.description
+ ddsd.dwSize = sizeof(ddsd);
+ m_pdds->GetSurfaceDesc( &ddsd );
+
+ if( ddsd.ddpfPixelFormat.dwFlags == DDPF_FOURCC )
+ return E_NOTIMPL;
+
+ // Select bitmap into a memoryDC so we can use it.
+ hDCImage = CreateCompatibleDC( NULL );
+ if( NULL == hDCImage )
+ return E_FAIL;
+
+ SelectObject( hDCImage, hBMP );
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Use the passed size, unless zero
+ dwBMPWidth = ( dwBMPWidth == 0 ) ? bmp.bmWidth : dwBMPWidth;
+ dwBMPHeight = ( dwBMPHeight == 0 ) ? bmp.bmHeight : dwBMPHeight;
+
+ // Stretch the bitmap to cover this surface
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ StretchBlt( hDC, 0, 0,
+ ddsd.dwWidth, ddsd.dwHeight,
+ hDCImage, dwBMPOriginX, dwBMPOriginY,
+ dwBMPWidth, dwBMPHeight, SRCCOPY );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ DeleteDC( hDCImage );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawText()
+// Desc: Draws a text string on a DirectDraw surface using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawText( HFONT hFont, TCHAR* strText,
+ DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strText == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ // Set the background and foreground color
+ SetBkColor( hDC, crBackground );
+ SetTextColor( hDC, crForeground );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ // Use GDI to draw the text on the surface
+ TextOut( hDC, dwOriginX, dwOriginY, strText, _tcslen(strText) );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ReDrawBitmapOnSurface()
+// Desc: Load a bitmap from a file or resource into a DirectDraw surface.
+// normaly used to re-load a surface after a restore.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( TCHAR* strBMP,
+ DWORD dwDesiredWidth, DWORD dwDesiredHeight )
+{
+ HBITMAP hBMP;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strBMP == NULL )
+ return E_INVALIDARG;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP, IMAGE_BITMAP,
+ dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::SetColorKey( DWORD dwColorKey )
+{
+ if( NULL == m_pdds )
+ return E_POINTER;
+
+ m_bColorKeyed = TRUE;
+
+ DDCOLORKEY ddck;
+ ddck.dwColorSpaceLowValue = ConvertGDIColor( dwColorKey );
+ ddck.dwColorSpaceHighValue = ConvertGDIColor( dwColorKey );
+
+ return m_pdds->SetColorKey( DDCKEY_SRCBLT, &ddck );
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ConvertGDIColor()
+// Desc: Converts a GDI color (0x00bbggrr) into the equivalent color on a
+// DirectDrawSurface using its pixel format.
+//-----------------------------------------------------------------------------
+DWORD CSurface::ConvertGDIColor( COLORREF dwGDIColor )
+{
+ if( m_pdds == NULL )
+ return 0x00000000;
+
+ COLORREF rgbT;
+ HDC hdc;
+ DWORD dw = CLR_INVALID;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ // Use GDI SetPixel to color match for us
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK)
+ {
+ rgbT = GetPixel(hdc, 0, 0); // Save current pixel value
+ SetPixel(hdc, 0, 0, dwGDIColor); // Set our value
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ // Now lock the surface so we can read back the converted color
+ ddsd.dwSize = sizeof(ddsd);
+ hr = m_pdds->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
+ if( hr == DD_OK)
+ {
+ dw = *(DWORD *) ddsd.lpSurface;
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount < 32 ) // Mask it to bpp
+ dw &= ( 1 << ddsd.ddpfPixelFormat.dwRGBBitCount ) - 1;
+ m_pdds->Unlock(NULL);
+ }
+
+ // Now put the color that was there back.
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK )
+ {
+ SetPixel( hdc, 0, 0, rgbT );
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ return dw;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::GetBitMaskInfo()
+// Desc: Returns the number of bits and the shift in the bit mask
+//-----------------------------------------------------------------------------
+HRESULT CSurface::GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits )
+{
+ DWORD dwShift = 0;
+ DWORD dwBits = 0;
+
+ if( pdwShift == NULL || pdwBits == NULL )
+ return E_INVALIDARG;
+
+ if( dwBitMask )
+ {
+ while( (dwBitMask & 1) == 0 )
+ {
+ dwShift++;
+ dwBitMask >>= 1;
+ }
+ }
+
+ while( (dwBitMask & 1) != 0 )
+ {
+ dwBits++;
+ dwBitMask >>= 1;
+ }
+
+ *pdwShift = dwShift;
+ *pdwBits = dwBits;
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V05/ddutil.h b/V05/ddutil.h
new file mode 100644
index 0000000..61fb0be
--- /dev/null
+++ b/V05/ddutil.h
@@ -0,0 +1,140 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: Routines for loading bitmap and palettes from resources
+//
+// Copyright (C) 1998-1999 Microsoft Corporation. All Rights Reserved.
+//-----------------------------------------------------------------------------
+#ifndef DDUTIL_H
+#define DDUTIL_H
+
+#include
+#include
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes defined in this header file
+//-----------------------------------------------------------------------------
+class CDisplay;
+class CSurface;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Flags for the CDisplay and CSurface methods
+//-----------------------------------------------------------------------------
+#define DSURFACELOCK_READ
+#define DSURFACELOCK_WRITE
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CDisplay
+// Desc: Class to handle all DDraw aspects of a display, including creation of
+// front and back buffers, creating offscreen surfaces and palettes,
+// and blitting surface and displaying bitmaps.
+//-----------------------------------------------------------------------------
+class CDisplay
+{
+protected:
+ LPDIRECTDRAW7 m_pDD;
+ LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBufferLeft; // For stereo modes
+
+ HWND m_hWnd;
+ RECT m_rcWindow;
+ BOOL m_bWindowed;
+ BOOL m_bStereo;
+
+public:
+ CDisplay();
+ ~CDisplay();
+
+ // Access functions
+ HWND GetHWnd() { return m_hWnd; }
+ LPDIRECTDRAW7 GetDirectDraw() { return m_pDD; }
+ LPDIRECTDRAWSURFACE7 GetFrontBuffer() { return m_pddsFrontBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBuffer() { return m_pddsBackBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBufferLEft() { return m_pddsBackBufferLeft; }
+
+ // Status functions
+ BOOL IsWindowed() { return m_bWindowed; }
+ BOOL IsStereo() { return m_bStereo; }
+
+ // Creation/destruction methods
+ HRESULT CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight,
+ DWORD dwBPP );
+ HRESULT CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight );
+ HRESULT InitClipper();
+ HRESULT UpdateBounds();
+ virtual HRESULT DestroyObjects();
+
+ // Methods to create child objects
+ HRESULT CreateSurface( CSurface** ppSurface, DWORD dwWidth,
+ DWORD dwHeight );
+ HRESULT CreateSurfaceFromBitmap( CSurface** ppSurface, TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight );
+ HRESULT CreateSurfaceFromText( CSurface** ppSurface, HFONT hFont,
+ TCHAR* strText,
+ COLORREF crBackground,
+ COLORREF crForeground );
+ HRESULT CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette, const TCHAR* strBMP );
+
+ // Display methods
+ HRESULT Clear( DWORD dwColor = 0L );
+ HRESULT ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc = NULL );
+ HRESULT Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc=NULL, DWORD dwFlags=0 );
+ HRESULT Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc = NULL );
+ HRESULT ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette=NULL );
+ HRESULT SetPalette( LPDIRECTDRAWPALETTE pPalette );
+ HRESULT Present();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSurface
+// Desc: Class to handle aspects of a DirectDrawSurface.
+//-----------------------------------------------------------------------------
+class CSurface
+{
+ LPDIRECTDRAWSURFACE7 m_pdds;
+ DDSURFACEDESC2 m_ddsd;
+ BOOL m_bColorKeyed;
+
+public:
+ LPDIRECTDRAWSURFACE7 GetDDrawSurface() { return m_pdds; }
+ BOOL IsColorKeyed() { return m_bColorKeyed; }
+
+ HRESULT DrawBitmap( HBITMAP hBMP, DWORD dwBMPOriginX = 0, DWORD dwBMPOriginY = 0,
+ DWORD dwBMPWidth = 0, DWORD dwBMPHeight = 0 );
+ HRESULT DrawBitmap( TCHAR* strBMP, DWORD dwDesiredWidth, DWORD dwDesiredHeight );
+ HRESULT DrawText( HFONT hFont, TCHAR* strText, DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground );
+
+ HRESULT SetColorKey( DWORD dwColorKey );
+ DWORD ConvertGDIColor( COLORREF dwGDIColor );
+ static HRESULT GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits );
+
+ HRESULT Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd );
+ HRESULT Create( LPDIRECTDRAWSURFACE7 pdds );
+ HRESULT Destroy();
+
+ CSurface();
+ ~CSurface();
+};
+
+
+
+
+#endif // DDUTIL_H
+
diff --git a/V05/dsutil.cpp b/V05/dsutil.cpp
new file mode 100644
index 0000000..83c1512
--- /dev/null
+++ b/V05/dsutil.cpp
@@ -0,0 +1,1546 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.cpp
+//
+// Desc: DirectSound framework classes for reading and writing wav files and
+// playing them in DirectSound buffers. Feel free to use this class
+// as a starting point for adding extra functionality.
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CSoundManager()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSoundManager::CSoundManager()
+{
+ m_pDS = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::~CSoundManager()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSoundManager::~CSoundManager()
+{
+ SAFE_RELEASE( m_pDS );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Initialize()
+// Desc: Initializes the IDirectSound object and also sets the primary buffer
+// format. This function must be called before any others.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Initialize( HWND hWnd,
+ DWORD dwCoopLevel,
+ DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ SAFE_RELEASE( m_pDS );
+
+ // Create IDirectSound using the primary sound device
+ if( FAILED( hr = DirectSoundCreate8( NULL, &m_pDS, NULL ) ) )
+ return DXTRACE_ERR( TEXT("DirectSoundCreate8"), hr );
+
+ // Set DirectSound coop level
+ if( FAILED( hr = m_pDS->SetCooperativeLevel( hWnd, dwCoopLevel ) ) )
+ return DXTRACE_ERR( TEXT("SetCooperativeLevel"), hr );
+
+ // Set primary buffer format
+ SetPrimaryBufferFormat( dwPrimaryChannels, dwPrimaryFreq, dwPrimaryBitRate );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::SetPrimaryBufferFormat()
+// Desc: Set primary buffer to a specified format
+// For example, to set the primary buffer format to 22kHz stereo, 16-bit
+// then: dwPrimaryChannels = 2
+// dwPrimaryFreq = 22050,
+// dwPrimaryBitRate = 16
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::SetPrimaryBufferFormat( DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Get the primary buffer
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
+ dsbd.dwBufferBytes = 0;
+ dsbd.lpwfxFormat = NULL;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ WAVEFORMATEX wfx;
+ ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = (WORD) dwPrimaryChannels;
+ wfx.nSamplesPerSec = dwPrimaryFreq;
+ wfx.wBitsPerSample = (WORD) dwPrimaryBitRate;
+ wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+ if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )
+ return DXTRACE_ERR( TEXT("SetFormat"), hr );
+
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Get3DListenerInterface()
+// Desc: Returns the 3D listener interface associated with primary buffer.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener )
+{
+ HRESULT hr;
+ DSBUFFERDESC dsbdesc;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( ppDSListener == NULL )
+ return E_INVALIDARG;
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ *ppDSListener = NULL;
+
+ // Obtain primary buffer, asking it for 3D control
+ ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
+ dsbdesc.dwSize = sizeof(DSBUFFERDESC);
+ dsbdesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ if( FAILED( hr = pDSBPrimary->QueryInterface( IID_IDirectSound3DListener,
+ (VOID**)ppDSListener ) ) )
+ {
+ SAFE_RELEASE( pDSBPrimary );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ // Release the primary buffer, since it is not need anymore
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Create()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Create( CSound** ppSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ HRESULT hrRet = S_OK;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ if( pWaveFile->GetSize() == 0 )
+ {
+ // Wave is blank, so don't create it.
+ hr = E_FAIL;
+ goto LFail;
+ }
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = pWaveFile->GetSize();
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ // DirectSound is only guarenteed to play PCM data. Other
+ // formats may or may not work depending the sound card driver.
+ hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL );
+
+ // Be sure to return this error code if it occurs so the
+ // callers knows this happened.
+ if( hr == DS_NO_VIRTUALIZATION )
+ hrRet = DS_NO_VIRTUALIZATION;
+
+ if( FAILED(hr) )
+ {
+ // DSERR_BUFFERTOOSMALL will be returned if the buffer is
+ // less than DSBSIZE_FX_MIN (100ms) and the buffer is created
+ // with DSBCAPS_CTRLFX.
+ if( hr != DSERR_BUFFERTOOSMALL )
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return hrRet;
+
+LFail:
+ // Cleanup
+ SAFE_DELETE( pWaveFile );
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateFromMemory()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateFromMemory( CSound** ppSound,
+ BYTE* pbData,
+ ULONG ulDataSize,
+ LPWAVEFORMATEX pwfx,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbData == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->OpenFromMemory( pbData,ulDataSize, pwfx, WAVEFILE_READ );
+
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = ulDataSize;
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL ) ) )
+ {
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return S_OK;
+
+LFail:
+ // Cleanup
+
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateStreaming()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateStreaming( CStreamingSound** ppStreamingSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNotifyCount,
+ DWORD dwNotifySize,
+ HANDLE hNotifyEvent )
+{
+ HRESULT hr;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppStreamingSound == NULL || hNotifyEvent == NULL )
+ return E_INVALIDARG;
+
+ LPDIRECTSOUNDBUFFER pDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+ DSBPOSITIONNOTIFY* aPosNotify = NULL;
+ LPDIRECTSOUNDNOTIFY pDSNotify = NULL;
+
+ pWaveFile = new CWaveFile();
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ // Figure out how big the DSound buffer should be
+ dwDSBufferSize = dwNotifySize * dwNotifyCount;
+
+ // Set up the direct sound buffer. Request the NOTIFY flag, so
+ // that we are notified as the sound buffer plays. Note, that using this flag
+ // may limit the amount of hardware acceleration that can occur.
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags |
+ DSBCAPS_CTRLPOSITIONNOTIFY |
+ DSBCAPS_GETCURRENTPOSITION2;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBuffer, NULL ) ) )
+ {
+ // If wave format isn't then it will return
+ // either DSERR_BADFORMAT or E_INVALIDARG
+ if( hr == DSERR_BADFORMAT || hr == E_INVALIDARG )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("CreateSoundBuffer"), hr );
+
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ }
+
+ // Create the notification events, so that we know when to fill
+ // the buffer as the sound plays.
+ if( FAILED( hr = pDSBuffer->QueryInterface( IID_IDirectSoundNotify,
+ (VOID**)&pDSNotify ) ) )
+ {
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ];
+ if( aPosNotify == NULL )
+ return E_OUTOFMEMORY;
+
+ for( DWORD i = 0; i < dwNotifyCount; i++ )
+ {
+ aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
+ aPosNotify[i].hEventNotify = hNotifyEvent;
+ }
+
+ // Tell DirectSound when to notify us. The notification will come in the from
+ // of signaled events that are handled in WinMain()
+ if( FAILED( hr = pDSNotify->SetNotificationPositions( dwNotifyCount,
+ aPosNotify ) ) )
+ {
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("SetNotificationPositions"), hr );
+ }
+
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+
+ // Create the sound
+ *ppStreamingSound = new CStreamingSound( pDSBuffer, dwDSBufferSize, pWaveFile, dwNotifySize );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::CSound()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSound::CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize,
+ DWORD dwNumBuffers, CWaveFile* pWaveFile )
+{
+ DWORD i;
+
+ m_apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ for( i=0; iSetCurrentPosition(0);
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::~CSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSound::~CSound()
+{
+ for( DWORD i=0; iLock( 0, m_dwDSBufferSize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ NULL, NULL, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // Reset the wave file to the beginning
+ m_pWaveFile->ResetFile();
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwWavDataRead ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ if( dwWavDataRead == 0 )
+ {
+ // Wav is blank, so just fill with silence
+ FillMemory( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ else if( dwWavDataRead < dwDSLockedBufferSize )
+ {
+ // If the wav file was smaller than the DirectSound buffer,
+ // we need to fill the remainder of the buffer with data
+ if( bRepeatWavIfBufferLarger )
+ {
+ // Reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwWavDataRead; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full
+ // for very short files
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwWavDataRead );
+ if( FAILED(hr) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwWavDataRead;
+ }
+ }
+ else
+ {
+ // Don't repeat the wav file, just fill in silence
+ FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead,
+ dwDSLockedBufferSize - dwWavDataRead,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ }
+
+ // Unlock the buffer, we don't need it anymore.
+ pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::RestoreBuffer()
+// Desc: Restores the lost buffer. *pbWasRestored returns TRUE if the buffer was
+// restored. It can also NULL if the information is not needed.
+//-----------------------------------------------------------------------------
+HRESULT CSound::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored )
+{
+ HRESULT hr;
+
+ if( pDSB == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbWasRestored )
+ *pbWasRestored = FALSE;
+
+ DWORD dwStatus;
+ if( FAILED( hr = pDSB->GetStatus( &dwStatus ) ) )
+ return DXTRACE_ERR( TEXT("GetStatus"), hr );
+
+ if( dwStatus & DSBSTATUS_BUFFERLOST )
+ {
+ // Since the app could have just been activated, then
+ // DirectSound may not be giving us control yet, so
+ // the restoring the buffer may fail.
+ // If it does, sleep until DirectSound gives us control.
+ do
+ {
+ hr = pDSB->Restore();
+ if( hr == DSERR_BUFFERLOST )
+ Sleep( 10 );
+ }
+ while( hr = pDSB->Restore() );
+
+ if( pbWasRestored != NULL )
+ *pbWasRestored = TRUE;
+
+ return S_OK;
+ }
+ else
+ {
+ return S_FALSE;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetFreeBuffer()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetFreeBuffer()
+{
+ BOOL bIsPlaying = FALSE;
+ DWORD i;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( i=0; iGetStatus( &dwStatus );
+ if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
+ break;
+ }
+ }
+
+ if( i != m_dwNumBuffers )
+ return m_apDSBuffer[ i ];
+ else
+ return m_apDSBuffer[ rand() % m_dwNumBuffers ];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetBuffer()
+// Desc:
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetBuffer( DWORD dwIndex )
+{
+ if( m_apDSBuffer == NULL )
+ return NULL;
+ if( dwIndex >= m_dwNumBuffers )
+ return NULL;
+
+ return m_apDSBuffer[dwIndex];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Get3DBufferInterface()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSound::Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer )
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( dwIndex >= m_dwNumBuffers )
+ return E_INVALIDARG;
+
+ *ppDS3DBuffer = NULL;
+
+ return m_apDSBuffer[dwIndex]->QueryInterface( IID_IDirectSound3DBuffer,
+ (VOID**)ppDS3DBuffer );
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Play()
+// Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING
+// in the dwFlags to loop the sound
+//-----------------------------------------------------------------------------
+HRESULT CSound::Play( DWORD dwPriority, DWORD dwFlags )
+{
+ HRESULT hr;
+ BOOL bRestored;
+
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();
+
+ if( pDSB == NULL )
+ return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL );
+
+ // Restore the buffer if it was lost
+ if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+
+ // Make DirectSound do pre-processing on sound effects
+ Reset();
+ }
+
+ return pDSB->Play( 0, dwPriority, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Stop()
+// Desc: Stops the sound from playing
+//-----------------------------------------------------------------------------
+HRESULT CSound::Stop()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iStop();
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Reset()
+// Desc: Reset all of the sound buffers
+//-----------------------------------------------------------------------------
+HRESULT CSound::Reset()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iSetCurrentPosition( 0 );
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::IsSoundPlaying()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+BOOL CSound::IsSoundPlaying()
+{
+ BOOL bIsPlaying = FALSE;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( DWORD i=0; iGetStatus( &dwStatus );
+ bIsPlaying |= ( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );
+ }
+ }
+
+ return bIsPlaying;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::CStreamingSound()
+// Desc: Setups up a buffer so data can be streamed from the wave file into
+// buffer. This is very useful for large wav files that would take a
+// while to load. The buffer is initially filled with data, then
+// as sound is played the notification events are signaled and more data
+// is written into the buffer by calling HandleWaveStreamNotification()
+//-----------------------------------------------------------------------------
+CStreamingSound::CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize,
+ CWaveFile* pWaveFile, DWORD dwNotifySize )
+ : CSound( &pDSBuffer, dwDSBufferSize, 1, pWaveFile )
+{
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNotifySize = dwNotifySize;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::~CStreamingSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CStreamingSound::~CStreamingSound()
+{
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::HandleWaveStreamNotification()
+// Desc: Handle the notification that tell us to put more wav data in the
+// circular buffer
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::HandleWaveStreamNotification( BOOL bLoopedPlay )
+{
+ HRESULT hr;
+ DWORD dwCurrentPlayPos;
+ DWORD dwPlayDelta;
+ DWORD dwBytesWrittenToBuffer;
+ VOID* pDSLockedBuffer = NULL;
+ VOID* pDSLockedBuffer2 = NULL;
+ DWORD dwDSLockedBufferSize;
+ DWORD dwDSLockedBufferSize2;
+
+ if( m_apDSBuffer == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ return S_OK;
+ }
+
+ // Lock the DirectSound buffer
+ if( FAILED( hr = m_apDSBuffer[0]->Lock( m_dwNextWriteOffset, m_dwNotifySize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // m_dwDSBufferSize and m_dwNextWriteOffset are both multiples of m_dwNotifySize,
+ // it should the second buffer should never be valid
+ if( pDSLockedBuffer2 != NULL )
+ return E_UNEXPECTED;
+
+ if( !m_bFillNextNotificationWithSilence )
+ {
+ // Fill the DirectSound buffer with wav data
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+ }
+ else
+ {
+ // Fill the DirectSound buffer with silence
+ FillMemory( pDSLockedBuffer, dwDSLockedBufferSize,
+ (BYTE)( m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ dwBytesWrittenToBuffer = dwDSLockedBufferSize;
+ }
+
+ // If the number of bytes written is less than the
+ // amount we requested, we have a short file.
+ if( dwBytesWrittenToBuffer < dwDSLockedBufferSize )
+ {
+ if( !bLoopedPlay )
+ {
+ // Fill in silence for the rest of the buffer.
+ FillMemory( (BYTE*) pDSLockedBuffer + dwBytesWrittenToBuffer,
+ dwDSLockedBufferSize - dwBytesWrittenToBuffer,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+
+ // Any future notifications should just fill the buffer with silence
+ m_bFillNextNotificationWithSilence = TRUE;
+ }
+ else
+ {
+ // We are looping, so reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwBytesWrittenToBuffer; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full (for very short files).
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwBytesWrittenToBuffer;
+ }
+ }
+ }
+
+ // Unlock the DirectSound buffer
+ m_apDSBuffer[0]->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ // Figure out how much data has been played so far. When we have played
+ // passed the end of the file, we will either need to start filling the
+ // buffer with silence or starting reading from the beginning of the file,
+ // depending if the user wants to loop the sound
+ if( FAILED( hr = m_apDSBuffer[0]->GetCurrentPosition( &dwCurrentPlayPos, NULL ) ) )
+ return DXTRACE_ERR( TEXT("GetCurrentPosition"), hr );
+
+ // Check to see if the position counter looped
+ if( dwCurrentPlayPos < m_dwLastPlayPos )
+ dwPlayDelta = ( m_dwDSBufferSize - m_dwLastPlayPos ) + dwCurrentPlayPos;
+ else
+ dwPlayDelta = dwCurrentPlayPos - m_dwLastPlayPos;
+
+ m_dwPlayProgress += dwPlayDelta;
+ m_dwLastPlayPos = dwCurrentPlayPos;
+
+ // If we are now filling the buffer with silence, then we have found the end so
+ // check to see if the entire sound has played, if it has then stop the buffer.
+ if( m_bFillNextNotificationWithSilence )
+ {
+ // We don't want to cut off the sound before it's done playing.
+ if( m_dwPlayProgress >= m_pWaveFile->GetSize() )
+ {
+ m_apDSBuffer[0]->Stop();
+ }
+ }
+
+ // Update where the buffer will lock (for next time)
+ m_dwNextWriteOffset += dwDSLockedBufferSize;
+ m_dwNextWriteOffset %= m_dwDSBufferSize; // Circular buffer
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::Reset()
+// Desc: Resets the sound so it will begin playing at the beginning
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::Reset()
+{
+ HRESULT hr;
+
+ if( m_apDSBuffer[0] == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ }
+
+ m_pWaveFile->ResetFile();
+
+ return m_apDSBuffer[0]->SetCurrentPosition( 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::CWaveFile()
+// Desc: Constructs the class. Call Open() to open a wave file for reading.
+// Then call Read() as needed. Calling the destructor or Close()
+// will close the file.
+//-----------------------------------------------------------------------------
+CWaveFile::CWaveFile()
+{
+ m_pwfx = NULL;
+ m_hmmio = NULL;
+ m_dwSize = 0;
+ m_bIsReadingFromMemory = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::~CWaveFile()
+// Desc: Destructs the class
+//-----------------------------------------------------------------------------
+CWaveFile::~CWaveFile()
+{
+ Close();
+
+ if( !m_bIsReadingFromMemory )
+ SAFE_DELETE_ARRAY( m_pwfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Open()
+// Desc: Opens a wave file for reading
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ HRESULT hr;
+
+ m_dwFlags = dwFlags;
+ m_bIsReadingFromMemory = FALSE;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ if( strFileName == NULL )
+ return E_INVALIDARG;
+ SAFE_DELETE_ARRAY( m_pwfx );
+
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );
+
+ if( NULL == m_hmmio )
+ {
+ HRSRC hResInfo;
+ HGLOBAL hResData;
+ DWORD dwSize;
+ VOID* pvRes;
+
+ // Loading it as a file failed, so try it as a resource
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAVE") ) ) )
+ {
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAV") ) ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("FindResource"), E_FAIL );
+ }
+
+ if( NULL == ( hResData = LoadResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("LoadResource"), E_FAIL );
+
+ if( 0 == ( dwSize = SizeofResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("SizeofResource"), E_FAIL );
+
+ if( NULL == ( pvRes = LockResource( hResData ) ) )
+ return DXTRACE_ERR( TEXT("LockResource"), E_FAIL );
+
+ CHAR* pData = new CHAR[ dwSize ];
+ memcpy( pData, pvRes, dwSize );
+
+ MMIOINFO mmioInfo;
+ ZeroMemory( &mmioInfo, sizeof(mmioInfo) );
+ mmioInfo.fccIOProc = FOURCC_MEM;
+ mmioInfo.cchBuffer = dwSize;
+ mmioInfo.pchBuffer = (CHAR*) pData;
+
+ m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );
+ }
+
+ if( FAILED( hr = ReadMMIO() ) )
+ {
+ // ReadMMIO will fail if its an not a wave file
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR_NOMSGBOX( TEXT("ReadMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ // After the reset, the size of the wav file is m_ck.cksize so store it now
+ m_dwSize = m_ck.cksize;
+ }
+ else
+ {
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF |
+ MMIO_READWRITE |
+ MMIO_CREATE );
+ if( NULL == m_hmmio )
+ return DXTRACE_ERR( TEXT("mmioOpen"), E_FAIL );
+
+ if( FAILED( hr = WriteMMIO( pwfx ) ) )
+ {
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR( TEXT("WriteMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+ }
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::OpenFromMemory()
+// Desc: copy data to CWaveFile member variable from memory
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::OpenFromMemory( BYTE* pbData, ULONG ulDataSize,
+ WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ m_pwfx = pwfx;
+ m_ulDataSize = ulDataSize;
+ m_pbData = pbData;
+ m_pbDataCur = m_pbData;
+ m_bIsReadingFromMemory = TRUE;
+
+ if( dwFlags != WAVEFILE_READ )
+ return E_NOTIMPL;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ReadMMIO()
+// Desc: Support function for reading from a multimedia I/O stream.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_pwfx.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ReadMMIO()
+{
+ MMCKINFO ckIn; // chunk info. for general use.
+ PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in.
+
+ m_pwfx = NULL;
+
+ if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Check to make sure this is a valid wave file
+ if( (m_ckRiff.ckid != FOURCC_RIFF) ||
+ (m_ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("mmioFOURCC"), E_FAIL );
+
+ // Search the input file for for the 'fmt ' chunk.
+ ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Expect the 'fmt' chunk to be at least as large as ;
+ // if there are extra parameters at the end, we'll ignore them
+ if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) )
+ return DXTRACE_ERR( TEXT("sizeof(PCMWAVEFORMAT)"), E_FAIL );
+
+ // Read the 'fmt ' chunk into .
+ if( mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat,
+ sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ // Allocate the waveformatex, but if its not pcm format, read the next
+ // word, and thats how many extra bytes to allocate.
+ if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )
+ {
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("m_pwfx"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = 0;
+ }
+ else
+ {
+ // Read in length of extra bytes.
+ WORD cbExtraBytes = 0L;
+ if( mmioRead( m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("new"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = cbExtraBytes;
+
+ // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
+ if( mmioRead( m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize))+sizeof(WORD)),
+ cbExtraBytes ) != cbExtraBytes )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+ }
+ }
+
+ // Ascend the input file out of the 'fmt ' chunk.
+ if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::GetSize()
+// Desc: Retuns the size of the read access wave file
+//-----------------------------------------------------------------------------
+DWORD CWaveFile::GetSize()
+{
+ return m_dwSize;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ResetFile()
+// Desc: Resets the internal m_ck pointer so reading starts from the
+// beginning of the file again
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ResetFile()
+{
+ if( m_bIsReadingFromMemory )
+ {
+ m_pbDataCur = m_pbData;
+ }
+ else
+ {
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ // Seek to the data
+ if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),
+ SEEK_SET ) )
+ return DXTRACE_ERR( TEXT("mmioSeek"), E_FAIL );
+
+ // Search the input file for the 'data' chunk.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ if( 0 != mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+ }
+ else
+ {
+ // Create the 'data' chunk that holds the waveform samples.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ m_ck.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( 0 != mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Read()
+// Desc: Reads section of data from a wave file into pBuffer and returns
+// how much read in pdwSizeRead, reading not more than dwSizeToRead.
+// This uses m_ck to determine where to start reading from. So
+// subsequent calls will be continue where the last left off unless
+// Reset() is called.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )
+{
+ if( m_bIsReadingFromMemory )
+ {
+ if( m_pbDataCur == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( (BYTE*)(m_pbDataCur + dwSizeToRead) >
+ (BYTE*)(m_pbData + m_ulDataSize) )
+ {
+ dwSizeToRead = m_ulDataSize - (DWORD)(m_pbDataCur - m_pbData);
+ }
+
+ CopyMemory( pBuffer, m_pbDataCur, dwSizeToRead );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = dwSizeToRead;
+
+ return S_OK;
+ }
+ else
+ {
+ MMIOINFO mmioinfoIn; // current status of m_hmmio
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pBuffer == NULL || pdwSizeRead == NULL )
+ return E_INVALIDARG;
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+
+ UINT cbDataIn = dwSizeToRead;
+ if( cbDataIn > m_ck.cksize )
+ cbDataIn = m_ck.cksize;
+
+ m_ck.cksize -= cbDataIn;
+
+ for( DWORD cT = 0; cT < cbDataIn; cT++ )
+ {
+ // Copy the bytes from the io to the buffer.
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ {
+ if( 0 != mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ return DXTRACE_ERR( TEXT("mmioinfoIn.pchNext"), E_FAIL );
+ }
+
+ // Actual copy.
+ *((BYTE*)pBuffer+cT) = *((BYTE*)mmioinfoIn.pchNext);
+ mmioinfoIn.pchNext++;
+ }
+
+ if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = cbDataIn;
+
+ return S_OK;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Close()
+// Desc: Closes the wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Close()
+{
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+ else
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( 0 != mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ // Ascend the output file out of the 'data' chunk -- this will cause
+ // the chunk size of the 'data' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Do this here instead...
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioSeek( m_hmmio, 0, SEEK_SET );
+
+ if( 0 != (INT)mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ m_ck.ckid = mmioFOURCC('f', 'a', 'c', 't');
+
+ if( 0 == mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ {
+ DWORD dwSamples = 0;
+ mmioWrite( m_hmmio, (HPSTR)&dwSamples, sizeof(DWORD) );
+ mmioAscend( m_hmmio, &m_ck, 0 );
+ }
+
+ // Ascend the output file out of the 'RIFF' chunk -- this will cause
+ // the chunk size of the 'RIFF' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::WriteMMIO()
+// Desc: Support function for reading from a multimedia I/O stream
+// pwfxDest is the WAVEFORMATEX for this new wave file.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_ck.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::WriteMMIO( WAVEFORMATEX *pwfxDest )
+{
+ DWORD dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile.
+ MMCKINFO ckOut1;
+
+ dwFactChunk = (DWORD)-1;
+
+ // Create the output file RIFF chunk of form type 'WAVE'.
+ m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');
+ m_ckRiff.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // We are now descended into the 'RIFF' chunk we just created.
+ // Now create the 'fmt ' chunk. Since we know the size of this chunk,
+ // specify it in the MMCKINFO structure so MMIO doesn't have to seek
+ // back and set the chunk size after ascending from the chunk.
+ m_ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ m_ck.cksize = sizeof(PCMWAVEFORMAT);
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type.
+ if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM )
+ {
+ if( mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+ else
+ {
+ // Write the variable length size.
+ if( (UINT)mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(*pwfxDest) + pwfxDest->cbSize ) !=
+ ( sizeof(*pwfxDest) + pwfxDest->cbSize ) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+
+ // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Now create the fact chunk, not required for PCM but nice to have. This is filled
+ // in when the close routine is called.
+ ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't');
+ ckOut1.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( mmioWrite( m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) !=
+ sizeof(dwFactChunk) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+
+ // Now ascend out of the fact chunk...
+ if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Write()
+// Desc: Writes data to the open wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Write( UINT nSizeToWrite, BYTE* pbSrcData, UINT* pnSizeWrote )
+{
+ UINT cT;
+
+ if( m_bIsReadingFromMemory )
+ return E_NOTIMPL;
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pnSizeWrote == NULL || pbSrcData == NULL )
+ return E_INVALIDARG;
+
+ *pnSizeWrote = 0;
+
+ for( cT = 0; cT < nSizeToWrite; cT++ )
+ {
+ if( m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite )
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+ if( 0 != mmioAdvance( m_hmmio, &m_mmioinfoOut, MMIO_WRITE ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+ }
+
+ *((BYTE*)m_mmioinfoOut.pchNext) = *((BYTE*)pbSrcData+cT);
+ (BYTE*)m_mmioinfoOut.pchNext++;
+
+ (*pnSizeWrote)++;
+ }
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V05/dsutil.h b/V05/dsutil.h
new file mode 100644
index 0000000..57d26df
--- /dev/null
+++ b/V05/dsutil.h
@@ -0,0 +1,170 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.h
+//
+// Desc:
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#ifndef DSUTIL_H
+#define DSUTIL_H
+
+#include
+#include
+#include
+#include
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes used by this header
+//-----------------------------------------------------------------------------
+class CSoundManager;
+class CSound;
+class CStreamingSound;
+class CWaveFile;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Typing macros
+//-----------------------------------------------------------------------------
+#define WAVEFILE_READ 1
+#define WAVEFILE_WRITE 2
+
+#define DSUtil_StopSound(s) { if(s) s->Stop(); }
+#define DSUtil_PlaySound(s) { if(s) s->Play( 0, 0 ); }
+#define DSUtil_PlaySoundLooping(s) { if(s) s->Play( 0, DSBPLAY_LOOPING ); }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSoundManager
+// Desc:
+//-----------------------------------------------------------------------------
+class CSoundManager
+{
+protected:
+ LPDIRECTSOUND8 m_pDS;
+
+public:
+ CSoundManager();
+ ~CSoundManager();
+
+ HRESULT Initialize( HWND hWnd, DWORD dwCoopLevel, DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate );
+ inline LPDIRECTSOUND GetDirectSound() { return m_pDS; }
+ HRESULT SetPrimaryBufferFormat( DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate );
+ HRESULT Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener );
+
+ HRESULT Create( CSound** ppSound, LPTSTR strWaveFileName, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
+ HRESULT CreateFromMemory( CSound** ppSound, BYTE* pbData, ULONG ulDataSize, LPWAVEFORMATEX pwfx, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
+ HRESULT CreateStreaming( CStreamingSound** ppStreamingSound, LPTSTR strWaveFileName, DWORD dwCreationFlags, GUID guid3DAlgorithm, DWORD dwNotifyCount, DWORD dwNotifySize, HANDLE hNotifyEvent );
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSound
+// Desc: Encapsulates functionality of a DirectSound buffer.
+//-----------------------------------------------------------------------------
+class CSound
+{
+protected:
+ LPDIRECTSOUNDBUFFER* m_apDSBuffer;
+ DWORD m_dwDSBufferSize;
+ CWaveFile* m_pWaveFile;
+ DWORD m_dwNumBuffers;
+
+ HRESULT RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored );
+
+public:
+ CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize, DWORD dwNumBuffers, CWaveFile* pWaveFile );
+ virtual ~CSound();
+
+ HRESULT Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer );
+ HRESULT FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger );
+ LPDIRECTSOUNDBUFFER GetFreeBuffer();
+ LPDIRECTSOUNDBUFFER GetBuffer( DWORD dwIndex );
+
+ HRESULT Play( DWORD dwPriority, DWORD dwFlags );
+ HRESULT Stop();
+ HRESULT Reset();
+ BOOL IsSoundPlaying();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CStreamingSound
+// Desc: Encapsulates functionality to play a wave file with DirectSound.
+// The Create() method loads a chunk of wave file into the buffer,
+// and as sound plays more is written to the buffer by calling
+// HandleWaveStreamNotification() whenever hNotifyEvent is signaled.
+//-----------------------------------------------------------------------------
+class CStreamingSound : public CSound
+{
+protected:
+ DWORD m_dwLastPlayPos;
+ DWORD m_dwPlayProgress;
+ DWORD m_dwNotifySize;
+ DWORD m_dwNextWriteOffset;
+ BOOL m_bFillNextNotificationWithSilence;
+
+public:
+ CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize, CWaveFile* pWaveFile, DWORD dwNotifySize );
+ ~CStreamingSound();
+
+ HRESULT HandleWaveStreamNotification( BOOL bLoopedPlay );
+ HRESULT Reset();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CWaveFile
+// Desc: Encapsulates reading or writing sound data to or from a wave file
+//-----------------------------------------------------------------------------
+class CWaveFile
+{
+public:
+ WAVEFORMATEX* m_pwfx; // Pointer to WAVEFORMATEX structure
+ HMMIO m_hmmio; // MM I/O handle for the WAVE
+ MMCKINFO m_ck; // Multimedia RIFF chunk
+ MMCKINFO m_ckRiff; // Use in opening a WAVE file
+ DWORD m_dwSize; // The size of the wave file
+ MMIOINFO m_mmioinfoOut;
+ DWORD m_dwFlags;
+ BOOL m_bIsReadingFromMemory;
+ BYTE* m_pbData;
+ BYTE* m_pbDataCur;
+ ULONG m_ulDataSize;
+
+protected:
+ HRESULT ReadMMIO();
+ HRESULT WriteMMIO( WAVEFORMATEX *pwfxDest );
+
+public:
+ CWaveFile();
+ ~CWaveFile();
+
+ HRESULT Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags );
+ HRESULT OpenFromMemory( BYTE* pbData, ULONG ulDataSize, WAVEFORMATEX* pwfx, DWORD dwFlags );
+ HRESULT Close();
+
+ HRESULT Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead );
+ HRESULT Write( UINT nSizeToWrite, BYTE* pbData, UINT* pnSizeWrote );
+
+ DWORD GetSize();
+ HRESULT ResetFile();
+ WAVEFORMATEX* GetFormat() { return m_pwfx; };
+};
+
+
+
+
+#endif // DSUTIL_H
diff --git a/V05/resource.h b/V05/resource.h
new file mode 100644
index 0000000..c041f0c
--- /dev/null
+++ b/V05/resource.h
@@ -0,0 +1,32 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Demo.rc
+//
+#define IDI_MAIN 101
+#define IDR_MENU 102
+#define IDR_ACCEL 103
+#define IDD_HILFE 124
+#define IDD_ULTRIS 129
+#define IDB_ULTRIS 130
+#define IDM_EXIT 1001
+#define IDC_WEITERE_INFO 1018
+#define IDM_TEST 40024
+#define ID_ULTRIS_NEUESSPIEL 40025
+#define ID_ULTRIS_PAUSE 40026
+#define ID_ULTRIS_SOUND 40027
+#define ID_EINSTELLUNGEN_KONFIGURATION 40028
+#define ID_INFO_HILFE 40029
+#define ID_INFO_HIGHSCORES 40030
+#define ID_INFO_ULTRIS 40031
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 132
+#define _APS_NEXT_COMMAND_VALUE 40032
+#define _APS_NEXT_CONTROL_VALUE 1019
+#define _APS_NEXT_SYMED_VALUE 104
+#endif
+#endif
diff --git a/V05/ul_adeck.bmp b/V05/ul_adeck.bmp
new file mode 100644
index 0000000..5f3b867
Binary files /dev/null and b/V05/ul_adeck.bmp differ
diff --git a/V05/ul_down.wav b/V05/ul_down.wav
new file mode 100644
index 0000000..84cf9e1
Binary files /dev/null and b/V05/ul_down.wav differ
diff --git a/V05/ul_dreh.WAV b/V05/ul_dreh.WAV
new file mode 100644
index 0000000..790ef8c
Binary files /dev/null and b/V05/ul_dreh.WAV differ
diff --git a/V05/ul_ende.WAV b/V05/ul_ende.WAV
new file mode 100644
index 0000000..43c73f0
Binary files /dev/null and b/V05/ul_ende.WAV differ
diff --git a/V05/ul_feld.bmp b/V05/ul_feld.bmp
new file mode 100644
index 0000000..3225b6b
Binary files /dev/null and b/V05/ul_feld.bmp differ
diff --git a/V05/ul_hgrnd.bmp b/V05/ul_hgrnd.bmp
new file mode 100644
index 0000000..c33b077
Binary files /dev/null and b/V05/ul_hgrnd.bmp differ
diff --git a/V05/ul_move.WAV b/V05/ul_move.WAV
new file mode 100644
index 0000000..22b2a99
Binary files /dev/null and b/V05/ul_move.WAV differ
diff --git a/V05/ul_prev.bmp b/V05/ul_prev.bmp
new file mode 100644
index 0000000..c791074
Binary files /dev/null and b/V05/ul_prev.bmp differ
diff --git a/V05/ul_row1.WAV b/V05/ul_row1.WAV
new file mode 100644
index 0000000..ab5bfca
Binary files /dev/null and b/V05/ul_row1.WAV differ
diff --git a/V05/ul_row2.WAV b/V05/ul_row2.WAV
new file mode 100644
index 0000000..671fc71
Binary files /dev/null and b/V05/ul_row2.WAV differ
diff --git a/V05/ul_start.WAV b/V05/ul_start.WAV
new file mode 100644
index 0000000..f66bfef
Binary files /dev/null and b/V05/ul_start.WAV differ
diff --git a/V05/ul_stein.bmp b/V05/ul_stein.bmp
new file mode 100644
index 0000000..dadb7a0
Binary files /dev/null and b/V05/ul_stein.bmp differ
diff --git a/V05/ul_win.wav b/V05/ul_win.wav
new file mode 100644
index 0000000..e11c880
Binary files /dev/null and b/V05/ul_win.wav differ
diff --git a/V05/ul_z0.bmp b/V05/ul_z0.bmp
new file mode 100644
index 0000000..10fe8a6
Binary files /dev/null and b/V05/ul_z0.bmp differ
diff --git a/V05/ul_z1.bmp b/V05/ul_z1.bmp
new file mode 100644
index 0000000..1ce2939
Binary files /dev/null and b/V05/ul_z1.bmp differ
diff --git a/V05/ul_z2.bmp b/V05/ul_z2.bmp
new file mode 100644
index 0000000..9006084
Binary files /dev/null and b/V05/ul_z2.bmp differ
diff --git a/V05/ul_z3.bmp b/V05/ul_z3.bmp
new file mode 100644
index 0000000..5710c67
Binary files /dev/null and b/V05/ul_z3.bmp differ
diff --git a/V05/ul_z4.bmp b/V05/ul_z4.bmp
new file mode 100644
index 0000000..11306ed
Binary files /dev/null and b/V05/ul_z4.bmp differ
diff --git a/V05/ul_z5.bmp b/V05/ul_z5.bmp
new file mode 100644
index 0000000..b4a22b5
Binary files /dev/null and b/V05/ul_z5.bmp differ
diff --git a/V05/ul_z6.bmp b/V05/ul_z6.bmp
new file mode 100644
index 0000000..62616d4
Binary files /dev/null and b/V05/ul_z6.bmp differ
diff --git a/V05/ul_z7.bmp b/V05/ul_z7.bmp
new file mode 100644
index 0000000..d9178df
Binary files /dev/null and b/V05/ul_z7.bmp differ
diff --git a/V05/ul_z8.bmp b/V05/ul_z8.bmp
new file mode 100644
index 0000000..98e1a18
Binary files /dev/null and b/V05/ul_z8.bmp differ
diff --git a/V05/ul_z9.bmp b/V05/ul_z9.bmp
new file mode 100644
index 0000000..e6245a3
Binary files /dev/null and b/V05/ul_z9.bmp differ
diff --git a/V06/Demo.cpp b/V06/Demo.cpp
new file mode 100644
index 0000000..40daa7b
--- /dev/null
+++ b/V06/Demo.cpp
@@ -0,0 +1,938 @@
+# include
+# include
+# include
+# include
+# include "ddutil.h"
+# include "dsutil.h"
+# include "resource.h"
+
+const int ultris_nettobreite = 360; // Breite des Inneren des Haupfensters
+const int ultris_nettohoehe = 520; // Hoehe des Inneren des Hauptfensters
+int ultris_bruttobreite; // Breite des gesamten Haupfensters (incl. Rahmen)
+int ultris_bruttohoehe; // Hoehe des gesamten Haupfensters (incl. Rahmen)
+
+HINSTANCE ultris_instance; // Instanz der Ultris Applikation
+HWND ultris_window; // Das Hauptfenster von Ultris
+HMENU ultris_menu; // Das Menu von Ultris
+
+const int sound_start = 0; // Sound fuer neues Spiel
+const int sound_dreh = 1; // Sound bei Drehung
+const int sound_move = 2; // Sound bei rechts/links Bewegung
+const int sound_down = 3; // Sound bei Aufprall
+const int sound_row1 = 4; // Sound bei Abraeumen einer Reihe
+const int sound_row2 = 5; // Sound bei Abraeumen von mehreren Reihen
+const int sound_ende = 6; // Sound bei Spielende
+const int sound_win = 7; // Sound bei Eintrag in Highscore Tabelle
+const int anzahl_sounds = 8; // Anzahl Sounds
+
+char *soundfiles[anzahl_sounds] =
+ {
+ "ul_start.wav",
+ "ul_dreh.wav",
+ "ul_move.wav",
+ "ul_down.wav",
+ "ul_row1.wav",
+ "ul_row2.wav",
+ "ul_ende.wav",
+ "ul_win.wav"
+ };
+
+class sounds
+ {
+ private:
+ CSoundManager smgr;
+ CSound *snd[anzahl_sounds];
+ public:
+ int on;
+ sounds();
+ int init( HWND wnd);
+ void play( int snr);
+ ~sounds();
+ };
+
+sounds::sounds()
+ {
+ int i;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ snd[i] = 0;
+ on = 1;
+ }
+
+int sounds::init( HWND wnd)
+ {
+ HRESULT ret;
+ int i;
+
+ ret = smgr.Initialize( wnd, DSSCL_PRIORITY, 2, 22050, 16);
+ if( ret < 0)
+ return ret;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ {
+ ret = smgr.Create( snd+i, soundfiles[i]);
+ if( ret < 0)
+ return ret;
+ }
+ return S_OK;
+ }
+
+sounds::~sounds()
+ {
+ int i;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ {
+ if( snd[i])
+ delete snd[i];
+ }
+ }
+
+void sounds::play( int i)
+ {
+ if( !on)
+ return;
+ if( snd[i]->IsSoundPlaying())
+ {
+ snd[i]->Stop();
+ snd[i]->Reset();
+ }
+ snd[i]->Play(0,0);
+ }
+
+sounds ultris_sounds;
+
+class display
+ {
+ private:
+ CDisplay dsply;
+ CSurface *hgrnd;
+ CSurface *fldst;
+ CSurface *fllst;
+ CSurface *prvst;
+ CSurface *deckel;
+ CSurface *ziff[10];
+ public:
+ display();
+ void free_all();
+ ~display() {free_all();}
+ HRESULT init( HWND wnd);
+ void hintergrund() { dsply.Blt( 0, 0, hgrnd);}
+ void abdeckung() { dsply.Blt( 60, 0, deckel);}
+ void ziffer( int pos, int val) { dsply.Blt( 120+pos*20, 50, ziff[val]);}
+ void feldstein( int z, int s) { dsply.Blt( 80+s*20, 100+z*20, fldst);}
+ void fallstein( int z, int s, int offset) { dsply.Blt( 80+s*20, 100+z*20+offset, fllst);}
+ void prevstein( int p, int z, int s, int b, int h){ dsply.Blt( 290+s*15+(4-b)*15/2, 410-p*70+z*15+(4-h)*15/2, prvst);}
+ void update(){ dsply.UpdateBounds();}
+ HRESULT cooperative(){return dsply.GetDirectDraw()->TestCooperativeLevel();}
+ HRESULT restore();
+ HRESULT present();
+ };
+
+display::display()
+ {
+ int i;
+
+ hgrnd = 0;
+ fldst = 0;
+ fllst = 0;
+ prvst = 0;
+ deckel = 0;
+ for( i = 0; i < 10; i++)
+ ziff[i] = 0;
+ }
+
+void display::free_all()
+ {
+ int i;
+
+ if( hgrnd)
+ delete hgrnd;
+ if( fldst)
+ delete fldst;
+ if( fllst)
+ delete fllst;
+ if( prvst)
+ delete prvst;
+ if( deckel)
+ delete deckel;
+ for( i = 0; i < 10; i++)
+ {
+ if( ziff[i])
+ delete ziff[i];
+ }
+ }
+
+HRESULT display::init( HWND wnd)
+ {
+ HRESULT hr;
+ int i;
+ char fname[20];
+
+ hr = dsply.CreateWindowedDisplay( wnd, ultris_nettobreite, ultris_nettohoehe );
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &hgrnd, "ul_hgrnd.bmp", ultris_nettobreite, ultris_nettohoehe);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &fldst, "ul_feld.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &fllst, "ul_stein.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &prvst, "ul_prev.bmp", 15, 15);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &deckel, "ul_adeck.bmp", 240, 100);
+ if( hr < 0)
+ return hr;
+ for( i = 0; i < 10; i++)
+ {
+ sprintf( fname, "ul_z%d.bmp", i);
+ hr = dsply.CreateSurfaceFromBitmap( &ziff[i], fname, 20, 40);
+ if( hr < 0)
+ return hr;
+ }
+ return S_OK;
+ }
+
+HRESULT display::restore()
+ {
+ HRESULT hr;
+ int i;
+ char fname[20];
+
+ hr = dsply.GetDirectDraw()->RestoreAllSurfaces();
+ if( hr < 0)
+ return hr;
+ hr = hgrnd->DrawBitmap( "ul_hgrnd.bmp", ultris_nettobreite, ultris_nettohoehe);
+ if( hr < 0)
+ return hr;
+ hr = fldst->DrawBitmap( "ul_feld.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = fllst->DrawBitmap( "ul_stein.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = prvst->DrawBitmap( "ul_prev.bmp", 15, 15);
+ if( hr < 0)
+ return hr;
+ hr = deckel->DrawBitmap( "ul_adeck.bmp", 240, 100);
+ if( hr < 0)
+ return hr;
+
+ for( i = 0; i < 10; i++)
+ {
+ sprintf( fname, "ul_z%d.bmp", i);
+ hr = ziff[i]->DrawBitmap( fname, 20, 40);
+ if( hr < 0)
+ return hr;
+ }
+ return S_OK;
+ }
+
+HRESULT display::present()
+ {
+ HRESULT hr;
+
+ hr = dsply.Present();
+ if( hr == DDERR_SURFACELOST )
+ return restore();
+ return hr;
+ }
+
+display ultris_display;
+
+const int anzahl_formen = 35; // Anzahl der Formen
+
+//
+// Datenstruktur für die Formen
+//
+struct form
+ {
+ char h; // Hoehe
+ char b; // Breite
+ char data[4][4]; // Vorhandene Segmente
+ };
+
+// Form 1 in allen Drehvarianten
+//
+// *** * * *
+// * ** *** **
+// * *
+const form s_01_1 = {2, 3, {{1,1,1}, {0,1,0}}};
+const form s_01_2 = {3, 2, {{1,0}, {1,1}, {1,0}}};
+const form s_01_3 = {2, 3, {{0,1,0}, {1,1,1}}};
+const form s_01_4 = {3, 2, {{0,1}, {1,1}, {0,1}}};
+
+// Form 2 in allen Drehvarianten
+//
+// ** * ** *
+// ** ** ** **
+// * *
+const form s_02_1 = {2, 3, {{1,1,0}, {0,1,1}}};
+const form s_02_2 = {3, 2, {{0,1}, {1,1}, {1,0}}};
+const form s_02_3 = {2, 3, {{1,1,0}, {0,1,1}}};
+const form s_02_4 = {3, 2, {{0,1}, {1,1}, {1,0}}};
+
+// Form 3 in allen Drehvarianten
+//
+// ** * ** *
+// ** ** ** **
+// * *
+const form s_03_1 = {2, 3, {{0,1,1}, {1,1,0}}};
+const form s_03_2 = {3, 2, {{1,0}, {1,1}, {0,1}}};
+const form s_03_3 = {2, 3, {{0,1,1}, {1,1,0}}};
+const form s_03_4 = {3, 2, {{1,0}, {1,1}, {0,1}}};
+
+// Form 4 in allen Drehvarianten
+//
+// *** ** * *
+// * * *** *
+// * **
+const form s_04_1 = {2, 3, {{1,1,1}, {0,0,1}}};
+const form s_04_2 = {3, 2, {{1,1}, {1,0}, {1,0}}};
+const form s_04_3 = {2, 3, {{1,0,0}, {1,1,1}}};
+const form s_04_4 = {3, 2, {{0,1}, {0,1}, {1,1}}};
+
+// Form 5 in allen Drehvarianten
+//
+// * ** *** *
+// *** * * *
+// * **
+const form s_05_1 = {2, 3, {{0,0,1}, {1,1,1}}};
+const form s_05_2 = {3, 2, {{1,1}, {0,1}, {0,1}}};
+const form s_05_3 = {2, 3, {{1,1,1}, {1,0,0}}};
+const form s_05_4 = {3, 2, {{1,0}, {1,0}, {1,1}}};
+
+// Form 6 in allen Drehvarianten
+//
+// ** ** ** **
+// ** ** ** **
+//
+const form s_06_1 = {2, 2, {{1,1}, {1,1}}};
+const form s_06_2 = {2, 2, {{1,1}, {1,1}}};
+const form s_06_3 = {2, 2, {{1,1}, {1,1}}};
+const form s_06_4 = {2, 2, {{1,1}, {1,1}}};
+
+// Form 7 in allen Drehvarianten
+//
+// **** * **** *
+// * *
+// * *
+// * *
+const form s_07_1 = {1, 4, {{1,1,1,1}}};
+const form s_07_2 = {4, 1, {{1},{1},{1},{1}}};
+const form s_07_3 = {1, 4, {{1,1,1,1}}};
+const form s_07_4 = {4, 1, {{1},{1},{1},{1}}};
+
+// Form 8 in allen Drehvarianten
+//
+// *** ** * * **
+// * * * *** *
+// ** **
+const form s_08_1 = {2, 3, {{1,1,1}, {1,0,1}}};
+const form s_08_2 = {3, 2, {{1,1},{1,0},{1,1}}};
+const form s_08_3 = {2, 3, {{1,0,1}, {1,1,1}}};
+const form s_08_4 = {3, 2, {{1,1},{0,1},{1,1}}};
+
+// Form 9 in allen Drehvarianten
+//
+// ** * ** *
+// * *** * ***
+// ** * ** *
+const form s_09_1 = {3, 3, {{1,1,0}, {0,1,0}, {0,1,1}}};
+const form s_09_2 = {3, 3, {{0,0,1}, {1,1,1}, {1,0,0}}};
+const form s_09_3 = {3, 3, {{1,1,0}, {0,1,0}, {0,1,1}}};
+const form s_09_4 = {3, 3, {{0,0,1}, {1,1,1}, {1,0,0}}};
+
+// Form 10 in allen Drehvarianten
+//
+// ** ** * *
+// * * ** **
+//
+const form s_10_1 = {2, 2, {{1,1}, {0,1}}};
+const form s_10_2 = {2, 2, {{1,1}, {1,0}}};
+const form s_10_3 = {2, 2, {{1,0}, {1,1}}};
+const form s_10_4 = {2, 2, {{0,1}, {1,1}}};
+
+// Form 11 in allen Drehvarianten
+//
+// * * * *
+// *** *** *** ***
+// * * * *
+const form s_11_1 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+const form s_11_2 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+const form s_11_3 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+const form s_11_4 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+
+// Form 12 in allen Drehvarianten
+//
+// ** ** * ***
+// ** *** ** **
+// * **
+const form s_12_1 = {3, 2, {{1,1}, {1,1}, {1,0}}};
+const form s_12_2 = {2, 3, {{1,1,0}, {1,1,1}}};
+const form s_12_3 = {3, 2, {{0,1}, {1,1}, {1,1}}};
+const form s_12_4 = {2, 3, {{1,1,1}, {0,1,1}}};
+
+// Form 13 in allen Drehvarianten
+//
+// ** *** * **
+// ** ** ** ***
+// * **
+const form s_13_1 = {3, 2, {{1,1}, {1,1}, {0,1}}};
+const form s_13_2 = {2, 3, {{1,1,1}, {1,1,0}}};
+const form s_13_3 = {3, 2, {{1,0}, {1,1}, {1,1}}};
+const form s_13_4 = {2, 3, {{0,1,1}, {1,1,1}}};
+
+// Form 14 in allen Drehvarianten
+//
+// *** * * ***
+// * * * *
+// * *** *** *
+const form s_14_1 = {3, 3, {{1,1,1}, {1,0,0}, {1,0,0}}};
+const form s_14_2 = {3, 3, {{1,0,0}, {1,0,0}, {1,1,1}}};
+const form s_14_3 = {3, 3, {{0,0,1}, {0,0,1}, {1,1,1}}};
+const form s_14_4 = {3, 3, {{1,1,1}, {0,0,1}, {0,0,1}}};
+
+// Form 15 in allen Drehvarianten
+//
+// * * * *
+const form s_15_1 = {1, 1, {{1}}};
+const form s_15_2 = {1, 1, {{1}}};
+const form s_15_3 = {1, 1, {{1}}};
+const form s_15_4 = {1, 1, {{1}}};
+
+// Form 16 in allen Drehvarianten
+//
+// * * * *
+// * * * *
+const form s_16_1 = {2, 2, {{1,0}, {0,1}}};
+const form s_16_2 = {2, 2, {{0,1}, {1,0}}};
+const form s_16_3 = {2, 2, {{1,0}, {0,1}}};
+const form s_16_4 = {2, 2, {{0,1}, {1,0}}};
+
+// Form 17 in allen Drehvarianten
+//
+// * * * *
+// * * * *
+// * * * *
+const form s_17_1 = {3, 3, {{1,0,0}, {0,1,0}, {0,0,1}}};
+const form s_17_2 = {3, 3, {{0,0,1}, {0,1,0}, {1,0,0}}};
+const form s_17_3 = {3, 3, {{1,0,0}, {0,1,0}, {0,0,1}}};
+const form s_17_4 = {3, 3, {{0,0,1}, {0,1,0}, {1,0,0}}};
+
+// Form 18 in allen Drehvarianten
+//
+// * * * *
+// * * * * * * * *
+// * * * *
+const form s_18_1 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+const form s_18_2 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+const form s_18_3 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+const form s_18_4 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+
+// Form 19 in allen Drehvarianten
+//
+// * * * * *
+// * * * * *
+// * *
+const form s_19_1 = {2, 3, {{0,1,0}, {1,0,1}}};
+const form s_19_2 = {3, 2, {{0,1},{1,0},{0,1}}};
+const form s_19_3 = {2, 3, {{1,0,1}, {0,1,0}}};
+const form s_19_4 = {3, 2, {{1,0},{0,1},{1,0}}};
+
+// Form 20 in allen Drehvarianten
+//
+// *** * * *
+// * *** * ***
+// * * *** *
+const form s_20_1 = {3, 3, {{1,1,1}, {0,1,0}, {0,1,0}}};
+const form s_20_2 = {3, 3, {{1,0,0}, {1,1,1}, {1,0,0}}};
+const form s_20_3 = {3, 3, {{0,1,0}, {0,1,0}, {1,1,1}}};
+const form s_20_4 = {3, 3, {{0,0,1}, {1,1,1}, {0,0,1}}};
+
+// Form 21 in allen Drehvarianten
+//
+// * * * * *
+// * ** * **
+// * * * * *
+const form s_21_1 = {3, 3, {{1,0,1}, {0,1,0}, {0,1,0}}};
+const form s_21_2 = {3, 3, {{1,0,0}, {0,1,1}, {1,0,0}}};
+const form s_21_3 = {3, 3, {{0,1,0}, {0,1,0}, {1,0,1}}};
+const form s_21_4 = {3, 3, {{0,0,1}, {1,1,0}, {0,0,1}}};
+
+// Form 22 in allen Drehvarianten
+//
+// ** * ** *
+// * *
+//
+const form s_22_1 = {1, 2, {{1,1}}};
+const form s_22_2 = {2, 1, {{1},{1}}};
+const form s_22_3 = {1, 2, {{1,1}}};
+const form s_22_4 = {2, 1, {{1},{1}}};
+
+// Form 23 in allen Drehvarianten
+//
+// *** * *** *
+// * *
+// * *
+const form s_23_1 = {1, 3, {{1,1,1}}};
+const form s_23_2 = {3, 1, {{1},{1},{1}}};
+const form s_23_3 = {1, 3, {{1,1,1}}};
+const form s_23_4 = {3, 1, {{1},{1},{1}}};
+
+// Form 24 in allen Drehvarianten
+//
+// ** * * *
+// * * ** *
+// * *
+const form s_24_1 = {2, 3, {{1,1,0}, {0,0,1}}};
+const form s_24_2 = {3, 2, {{0,1}, {1,0}, {1,0}}};
+const form s_24_3 = {2, 3, {{1,0,0}, {0,1,1}}};
+const form s_24_4 = {3, 2, {{0,1}, {0,1}, {1,0}}};
+
+// Form 25 in allen Drehvarianten
+//
+// * * ** *
+// ** * * *
+// * *
+const form s_25_1 = {2, 3, {{0,0,1}, {1,1,0}}};
+const form s_25_2 = {3, 2, {{1,0}, {0,1}, {0,1}}};
+const form s_25_3 = {2, 3, {{0,1,1}, {1,0,0}}};
+const form s_25_4 = {3, 2, {{1,0}, {1,0}, {0,1}}};
+
+// Form 26 in allen Drehvarianten
+//
+// ** * ** *
+// ** * ** *
+// * *
+// * *
+const form s_26_1 = {2, 4, {{0,0,1,1}, {1,1,0,0}}};
+const form s_26_2 = {4, 2, {{1,0},{1,0},{0,1}, {0,1}}};
+const form s_26_3 = {2, 4, {{0,0,1,1}, {1,1,0,0}}};
+const form s_26_4 = {4, 2, {{1,0},{1,0},{0,1}, {0,1}}};
+
+// Form 27 in allen Drehvarianten
+//
+// ** * ** *
+// ** * ** *
+// * *
+// * *
+const form s_27_1 = {2, 4, {{1,1,0,0},{0,0,1,1}}};
+const form s_27_2 = {4, 2, {{0,1},{0,1},{1,0},{1,0}}};
+const form s_27_3 = {2, 4, {{1,1,0,0},{0,0,1,1}}};
+const form s_27_4 = {4, 2, {{0,1},{0,1},{1,0},{1,0}}};
+
+// Form 28 in allen Drehvarianten
+//
+// * * * ** *
+// ** * * * *
+// * *
+// * *
+const form s_28_1 = {2, 4, {{1,0,0,1},{0,1,1,0}}};
+const form s_28_2 = {4, 2, {{1,0},{0,1},{0,1},{1,0}}};
+const form s_28_3 = {2, 4, {{0,1,1,0},{1,0,0,1}}};
+const form s_28_4 = {4, 2, {{0,1},{1,0},{1,0},{0,1}}};
+
+// Form 29 in allen Drehvarianten
+//
+// ** * * **
+// * * * *
+// * ** ** *
+const form s_29_1 = {3, 3, {{0,1,1}, {1,0,0}, {1,0,0}}};
+const form s_29_2 = {3, 3, {{1,0,0}, {1,0,0}, {0,1,1}}};
+const form s_29_3 = {3, 3, {{0,0,1}, {0,0,1}, {1,1,0}}};
+const form s_29_4 = {3, 3, {{1,1,0}, {0,0,1}, {0,0,1}}};
+
+// Form 30 in allen Drehvarianten
+//
+// * ** * * **
+// * * * * * *
+// * * ** * **
+const form s_30_1 = {3, 3, {{0,1,0}, {1,0,1}, {1,0,1}}};
+const form s_30_2 = {3, 3, {{0,1,1}, {1,0,0}, {0,1,1}}};
+const form s_30_3 = {3, 3, {{1,0,1}, {1,0,1}, {0,1,0}}};
+const form s_30_4 = {3, 3, {{1,1,0}, {0,0,1}, {1,1,0}}};
+
+// Form 31 in allen Drehvarianten
+//
+// *** * * *
+// * * *** *
+// * *
+// * *
+const form s_31_1 = {2, 4, {{1,1,1,0},{0,0,0,1}}};
+const form s_31_2 = {4, 2, {{0,1},{1,0},{1,0},{1,0}}};
+const form s_31_3 = {2, 4, {{1,0,0,0},{0,1,1,1}}};
+const form s_31_4 = {4, 2, {{0,1},{0,1},{0,1},{1,0}}};
+
+// Form 32 in allen Drehvarianten
+//
+// * * *** *
+// *** * * *
+// * *
+// * *
+const form s_32_1 = {2, 4, {{0,0,0,1},{1,1,1,0}}};
+const form s_32_2 = {4, 2, {{1,0},{0,1},{0,1},{0,1}}};
+const form s_32_3 = {2, 4, {{0,1,1,1},{1,0,0,0}}};
+const form s_32_4 = {4, 2, {{1,0},{1,0},{1,0},{0,1}}};
+
+// Form 33 in allen Drehvarianten
+//
+// ** *** ** ***
+// ** *** ** ***
+// ** **
+const form s_33_1 = {3, 2, {{1,1}, {1,1}, {1,1}}};
+const form s_33_2 = {2, 3, {{1,1,1}, {1,1,1}}};
+const form s_33_3 = {3, 2, {{1,1}, {1,1}, {1,1}}};
+const form s_33_4 = {2, 3, {{1,1,1}, {1,1,1}}};
+
+// Form 34 in allen Drehvarianten
+//
+// **** * ** *
+// ** ** **** **
+// ** **
+// * *
+const form s_34_1 = {2, 4, {{1,1,1,1},{0,1,1,0}}};
+const form s_34_2 = {4, 2, {{1,0},{1,1},{1,1},{1,0}}};
+const form s_34_3 = {2, 4, {{0,1,1,0},{1,1,1,1}}};
+const form s_34_4 = {4, 2, {{0,1},{1,1},{1,1},{0,1}}};
+
+// Form 35 in allen Drehvarianten
+//
+// ** * ** *
+// * *** * ***
+// ** * ** *
+const form s_35_1 = {3, 3, {{0,1,1}, {0,1,0}, {1,1,0}}};
+const form s_35_2 = {3, 3, {{1,0,0}, {1,1,1}, {0,0,1}}};
+const form s_35_3 = {3, 3, {{0,1,1}, {0,1,0}, {1,1,0}}};
+const form s_35_4 = {3, 3, {{1,0,0}, {1,1,1}, {0,0,1}}};
+
+// Array mit allen Steinformen in allen Drehvarianten
+// Zugriff in der Form
+//
+// ultris_form[ steinform][ drehvariante]
+//
+// mit 0 <= steinform < 35 und 0 <= drehvariante <= 4
+
+const form *ultris_form[anzahl_formen][4] =
+ {
+ { &s_01_1, &s_01_2, &s_01_3, &s_01_4},
+ { &s_02_1, &s_02_2, &s_02_3, &s_02_4},
+ { &s_03_1, &s_03_2, &s_03_3, &s_03_4},
+ { &s_04_1, &s_04_2, &s_04_3, &s_04_4},
+ { &s_05_1, &s_05_2, &s_05_3, &s_05_4},
+ { &s_06_1, &s_06_2, &s_06_3, &s_06_4},
+ { &s_07_1, &s_07_2, &s_07_3, &s_07_4},
+ { &s_08_1, &s_08_2, &s_08_3, &s_08_4},
+ { &s_09_1, &s_09_2, &s_09_3, &s_09_4},
+ { &s_10_1, &s_10_2, &s_10_3, &s_10_4},
+ { &s_11_1, &s_11_2, &s_11_3, &s_11_4},
+ { &s_12_1, &s_12_2, &s_12_3, &s_12_4},
+ { &s_13_1, &s_13_2, &s_13_3, &s_13_4},
+ { &s_14_1, &s_14_2, &s_14_3, &s_14_4},
+ { &s_15_1, &s_15_2, &s_15_3, &s_15_4},
+ { &s_16_1, &s_16_2, &s_16_3, &s_16_4},
+ { &s_17_1, &s_17_2, &s_17_3, &s_17_4},
+ { &s_18_1, &s_18_2, &s_18_3, &s_18_4},
+ { &s_19_1, &s_19_2, &s_19_3, &s_19_4},
+ { &s_20_1, &s_20_2, &s_20_3, &s_20_4},
+ { &s_21_1, &s_21_2, &s_21_3, &s_21_4},
+ { &s_22_1, &s_22_2, &s_22_3, &s_22_4},
+ { &s_23_1, &s_23_2, &s_23_3, &s_23_4},
+ { &s_24_1, &s_24_2, &s_24_3, &s_24_4},
+ { &s_25_1, &s_25_2, &s_25_3, &s_25_4},
+ { &s_26_1, &s_26_2, &s_26_3, &s_26_4},
+ { &s_27_1, &s_27_2, &s_27_3, &s_27_4},
+ { &s_28_1, &s_28_2, &s_28_3, &s_28_4},
+ { &s_29_1, &s_29_2, &s_29_3, &s_29_4},
+ { &s_30_1, &s_30_2, &s_30_3, &s_30_4},
+ { &s_31_1, &s_31_2, &s_31_3, &s_31_4},
+ { &s_32_1, &s_32_2, &s_32_3, &s_32_4},
+ { &s_33_1, &s_33_2, &s_33_3, &s_33_4},
+ { &s_34_1, &s_34_2, &s_34_3, &s_34_4},
+ { &s_35_1, &s_35_2, &s_35_3, &s_35_4}
+ };
+
+// V6 Beginn
+
+// Array mit den aktuell im Spiel aktivierten Steinformen
+// Zu Programmstart sind dies die ueblichen Tetris Spielsteine (0-6)
+char aktive_formen[anzahl_formen] =
+ {
+ 1,1,1,1,1,1,1,
+ 0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0
+ };
+
+// Anzahl der aktuell aktivierten Steinformen
+int anz_aktive_formen = 7;
+
+class ultris
+ {
+ private:
+ int vorbelegung; // Anzahl der bei Spielbeginn vorzubelegenden Zeilen
+ int vorschau; // Anzahl der Formen in der Vorschau
+ public:
+ ultris(){ vorbelegung = 0; vorschau = 1;}
+ int get_vorbelegung() { return vorbelegung;}
+ void set_vorbelegung( int v) {if( v < 0) v = 0; if( v > 20) v = 20; vorbelegung = v;}
+ int get_vorschau() { return vorschau;}
+ void set_vorschau( int v) {if( v < 0) v = 0; if(v > 5) v = 5; vorschau = v;}
+ };
+
+ultris mein_spiel;
+// V6 Ende
+
+
+BOOL CALLBACK hilfedialog( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ switch (uMsg)
+ {
+ case WM_COMMAND:
+ if((wParam == IDOK)||(wParam == IDCANCEL))
+ {
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+BOOL CALLBACK ultrisdialog( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ switch (uMsg)
+ {
+ case WM_COMMAND:
+ if( wParam == IDC_WEITERE_INFO)
+ {
+ ShellExecute(NULL, "open", "http://www-et.bocholt.fh-gelsenkirchen.de", NULL, NULL, SW_SHOWNORMAL);
+ return TRUE;
+ }
+ if((wParam == IDOK)||(wParam == IDCANCEL))
+ {
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+// V6 Beginn
+BOOL CALLBACK konfigurationsdialog( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ int i;
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ for( i = 0; i < anzahl_formen; i++)
+ CheckDlgButton( hwndDlg, 5000+i, aktive_formen[i] ? BST_CHECKED : BST_UNCHECKED);
+ SetDlgItemInt( hwndDlg, IDC_VORBELEGUNG, mein_spiel.get_vorbelegung(), FALSE);
+ SetDlgItemInt( hwndDlg, IDC_VORSCHAU, mein_spiel.get_vorschau(), FALSE);
+ return TRUE;
+ case WM_COMMAND:
+ if(wParam == IDOK)
+ {
+ for( i = 0, anz_aktive_formen = 0; i < anzahl_formen; i++)
+ {
+ aktive_formen[i] = 0;
+ if(IsDlgButtonChecked( hwndDlg, 5000+i) == BST_CHECKED)
+ {
+ aktive_formen[i] = 1;
+ anz_aktive_formen++;
+ }
+ }
+ if( anz_aktive_formen == 0)
+ {
+ aktive_formen[0] = 1;
+ anz_aktive_formen = 1;
+ }
+ mein_spiel.set_vorbelegung( GetDlgItemInt( hwndDlg, IDC_VORBELEGUNG, NULL, FALSE));
+ mein_spiel.set_vorschau( GetDlgItemInt( hwndDlg, IDC_VORSCHAU, NULL, FALSE));
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ }
+ if(wParam == IDCANCEL)
+ {
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ }
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ switch( LOWORD(wParam))
+ {
+ case IDC_LOESCHEN:
+ for( i = 0; i < anzahl_formen; i++)
+ CheckDlgButton( hwndDlg, 5000+i, BST_UNCHECKED);
+ return TRUE;
+ case IDC_ALLE:
+ for( i = 0; i < anzahl_formen; i++)
+ CheckDlgButton( hwndDlg, 5000+i, BST_CHECKED);
+ return TRUE;
+ case IDC_STANDARD:
+ for( i = 0; i < anzahl_formen; i++)
+ CheckDlgButton( hwndDlg, 5000+i, i < 7 ? BST_CHECKED:BST_UNCHECKED);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+ }
+// V6 Ende
+
+/*
+** ultris_windowhandler
+*/
+
+LRESULT CALLBACK ultris_windowhandler( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+ {
+ switch(msg)
+ {
+ case WM_COMMAND:
+ switch( LOWORD( wParam))
+ {
+ case IDM_EXIT:
+ PostMessage( hWnd, WM_CLOSE, 0, 0);
+ return 0;
+ case ID_ULTRIS_SOUND:
+ ultris_sounds.on = !ultris_sounds.on;
+ CheckMenuItem( ultris_menu, ID_ULTRIS_SOUND, ultris_sounds.on ? MF_CHECKED:MF_UNCHECKED);
+ return 0;
+ case ID_INFO_HILFE:
+ DialogBox( ultris_instance, MAKEINTRESOURCE( IDD_HILFE), ultris_window, hilfedialog);
+ return 0;
+ case ID_INFO_ULTRIS:
+ DialogBox( ultris_instance, MAKEINTRESOURCE( IDD_ULTRIS), ultris_window, ultrisdialog);
+ return 0;
+// V6 Beginn
+ case ID_EINSTELLUNGEN_KONFIGURATION:
+ DialogBox( ultris_instance, MAKEINTRESOURCE( IDD_KONFIGURATION), ultris_window, konfigurationsdialog);
+ return 0;
+// V6 Ende
+ case IDM_TEST: // Testcode
+ return 0;
+ }
+ break;
+ case WM_GETMINMAXINFO:
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.x = ((MINMAXINFO *)lParam)->ptMaxTrackSize.x = ultris_bruttobreite;
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.y = ((MINMAXINFO *)lParam)->ptMaxTrackSize.y = ultris_bruttohoehe;
+ return 0;
+ case WM_DESTROY:
+ PostQuitMessage( 0);
+ return 0;
+ case WM_MOVE:
+ ultris_display.update();
+ return 0;
+ case WM_PAINT:
+ break;
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+ }
+
+/*
+** WinMain
+*/
+int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow)
+ {
+ MSG msg;
+ HACCEL acc;
+ WNDCLASSEX wcx;
+
+ ultris_instance = hInst;
+
+ wcx.cbSize = sizeof( wcx);
+ wcx.lpszClassName = TEXT( "Ultris");
+ wcx.lpfnWndProc = ultris_windowhandler;
+ wcx.style = CS_VREDRAW | CS_HREDRAW;
+ wcx.hInstance = hInst;
+ wcx.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hIconSm = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hCursor = LoadCursor( NULL, IDC_ARROW);
+ wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wcx.lpszMenuName = MAKEINTRESOURCE( IDR_MENU);
+ wcx.cbClsExtra = 0;
+ wcx.cbWndExtra = 0;
+
+ if( !RegisterClassEx( &wcx))
+ return 0;
+
+ acc = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_ACCEL));
+
+ ultris_bruttohoehe = ultris_nettohoehe + 2*GetSystemMetrics( SM_CYSIZEFRAME)
+ + GetSystemMetrics( SM_CYMENU)
+ + GetSystemMetrics( SM_CYCAPTION);
+ ultris_bruttobreite = ultris_nettobreite + 2*GetSystemMetrics( SM_CXSIZEFRAME);
+
+ ultris_window = CreateWindowEx( 0, TEXT( "Ultris"), TEXT( "Ultris"), WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ ultris_bruttobreite, ultris_bruttohoehe, NULL, NULL, hInst, NULL);
+ if( !ultris_window)
+ return 0;
+
+ ultris_menu = GetMenu( ultris_window);
+
+ if( ultris_sounds.init( ultris_window) < 0)
+ {
+ MessageBox( ultris_window, "Fehler beim Initialisieren der Sounds", "Ultris-Fehlermeldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
+ return 0;
+ }
+ CheckMenuItem( ultris_menu, ID_ULTRIS_SOUND, ultris_sounds.on ? MF_CHECKED:MF_UNCHECKED);
+
+ if( ultris_display.init( ultris_window) < 0)
+ {
+ MessageBox( ultris_window, "Fehler beim Initialisieren der Grafik", "Ultris-Fehlermeldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
+ return 0;
+ }
+
+ MoveWindow( ultris_window, (GetSystemMetrics(SM_CXSCREEN)-ultris_bruttobreite)/2,
+ (GetSystemMetrics(SM_CYSCREEN)-ultris_bruttohoehe)/2,
+ ultris_bruttobreite, ultris_bruttohoehe, TRUE);
+
+ ShowWindow( ultris_window, nCmdShow);
+
+ while( TRUE)
+ {
+ if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE))
+ {
+ if( GetMessage( &msg, NULL, 0, 0 ) == 0)
+ return 0; // Message ist WM_QUIT
+
+ if( TranslateAccelerator( ultris_window, acc, &msg) == 0)
+ {
+ TranslateMessage( &msg);
+ DispatchMessage( &msg);
+ }
+ }
+ else
+ {
+ HRESULT hr;
+ hr = ultris_display.cooperative();
+ if( hr < 0)
+ {
+ switch( hr )
+ {
+ case DDERR_EXCLUSIVEMODEALREADYSET:
+ Sleep(10);
+ break;
+ case DDERR_WRONGMODE:
+ ultris_display.free_all();
+ ultris_display.init( ultris_window);
+ PostMessage( ultris_window, WM_PAINT, 0, 0);
+ break;
+ }
+ }
+ else
+ {
+ // Hier koennen wir uns um das Spiel kuemmern
+ }
+ }
+ }
+ }
+
+
+
diff --git a/V06/Demo.h b/V06/Demo.h
new file mode 100644
index 0000000..a19fa69
--- /dev/null
+++ b/V06/Demo.h
@@ -0,0 +1,12 @@
+
+#if !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
+#define AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "resource.h"
+
+
+#endif // !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
diff --git a/V06/Demo.ncb b/V06/Demo.ncb
new file mode 100644
index 0000000..bc6a80f
Binary files /dev/null and b/V06/Demo.ncb differ
diff --git a/V06/Demo.rc b/V06/Demo.rc
new file mode 100644
index 0000000..0b839f4
--- /dev/null
+++ b/V06/Demo.rc
@@ -0,0 +1,686 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include
+#include
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Deutsch (Deutschland) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+#ifdef _WIN32
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU MENU DISCARDABLE
+BEGIN
+ POPUP "Ultris"
+ BEGIN
+ MENUITEM "Neues Spiel", ID_ULTRIS_NEUESSPIEL
+ MENUITEM "Pause", ID_ULTRIS_PAUSE
+ MENUITEM "Sound", ID_ULTRIS_SOUND
+ MENUITEM SEPARATOR
+ MENUITEM "Ende", IDM_EXIT
+ END
+ POPUP "Einstellungen"
+ BEGIN
+ MENUITEM "Konfiguration", ID_EINSTELLUNGEN_KONFIGURATION
+
+ END
+ POPUP "Info"
+ BEGIN
+ MENUITEM "Hilfe", ID_INFO_HILFE
+ MENUITEM "Highscores", ID_INFO_HIGHSCORES
+ MENUITEM "Ultris", ID_INFO_ULTRIS
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MAIN ICON DISCARDABLE "Icon.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCEL ACCELERATORS DISCARDABLE
+BEGIN
+ "T", IDM_TEST, VIRTKEY, CONTROL, NOINVERT
+ VK_ESCAPE, IDM_EXIT, VIRTKEY, NOINVERT
+ VK_F5, ID_ULTRIS_SOUND, VIRTKEY, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_HILFE DIALOG DISCARDABLE 0, 0, 302, 107
+STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Hilfe"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,245,90,50,14
+ LTEXT "F1: Neues Spiel",IDC_STATIC,15,22,130,8
+ LTEXT "F2: Pause (ein/aus)",IDC_STATIC,15,34,130,8
+ LTEXT "F3: Schneller",IDC_STATIC,15,46,130,8
+ LTEXT "F4: Langsamer",IDC_STATIC,15,58,130,8
+ LTEXT "F5: Sound (ein/aus)",IDC_STATIC,15,70,130,8
+ GROUPBOX "Steuerung des Spiels",IDC_STATIC,7,7,142,78
+ GROUPBOX "Steuerung der Steine",IDC_STATIC,153,7,142,78
+ LTEXT "J oder Cursor left: Links",IDC_STATIC,159,22,131,8
+ LTEXT "L oder Cursor right: Rechts",IDC_STATIC,159,34,131,8
+ LTEXT "K oder Cursor down: Linksdrehung",IDC_STATIC,159,46,131,
+ 8
+ LTEXT "I oder Cursor up: Rechtsdrehung",IDC_STATIC,159,58,131,
+ 8
+ LTEXT "Space: Stein fallen lassen",IDC_STATIC,159,70,126,8
+END
+
+IDD_ULTRIS DIALOG DISCARDABLE 0, 0, 204, 142
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Über Ultris"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,150,125,50,14
+ CONTROL 130,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_SUNKEN | WS_BORDER,7,7,190,78
+ CTEXT "Demoprogramm\rzur Vorlesung\rGrafik und Spieleprogrammierung",
+ IDC_STATIC,7,92,195,28
+ PUSHBUTTON "Weitere Informationen",IDC_WEITERE_INFO,5,125,140,14
+END
+
+IDD_KONFIGURATION DIALOGEX 0, 0, 289, 297
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Einstellungen"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,235,280,50,14
+ PUSHBUTTON "Abbrechen",IDCANCEL,180,280,50,14
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,10,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,30,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,20,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,20,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE | WS_BORDER,50,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE | WS_BORDER,60,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE | WS_BORDER,60,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE | WS_BORDER,70,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,110,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,90,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,150,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,170,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,180,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,190,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,190,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,215,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,225,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,215,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,225,30,10,10
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,40,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,10,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,50,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,60,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,70,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,70,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,20,65,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,95,65,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,105,65,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,95,75,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,10,65,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,30,65,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,10,75,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,30,75,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,50,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,150,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,230,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,25,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,215,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,225,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,215,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,225,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,225,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,55,125,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,65,115,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,110,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,185,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,90,130,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,130,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,185,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,20,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,150,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,130,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,170,125,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,180,115,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,190,125,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,70,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,210,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,130,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,230,160,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,190,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,50,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,60,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,170,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,110,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,90,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,15,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,180,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,150,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,230,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,190,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,170,160,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,180,190,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,160,10,10
+ CONTROL "",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,
+ 43,8,8
+ CONTROL "",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,74,
+ 43,8,8
+ CONTROL "",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,
+ 43,8,8
+ CONTROL "10",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 154,43,8,8
+ CONTROL "",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,
+ 43,8,8
+ CONTROL "",IDC_CHECK6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,234,
+ 43,8,8
+ CONTROL "6",IDC_CHECK7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,274,
+ 43,8,8
+ CONTROL "",IDC_CHECK8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,
+ 93,8,8
+ CONTROL "",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,74,
+ 93,8,8
+ CONTROL "",IDC_CHECK10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,
+ 93,8,8
+ CONTROL "",IDC_CHECK11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,
+ 93,8,8
+ CONTROL "",IDC_CHECK12,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,
+ 93,8,8
+ CONTROL "",IDC_CHECK13,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,234,
+ 93,8,8
+ CONTROL "20",IDC_CHECK14,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 274,93,8,8
+ CONTROL "",IDC_CHECK15,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,
+ 143,8,8
+ CONTROL "",IDC_CHECK16,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,74,
+ 143,8,8
+ CONTROL "",IDC_CHECK17,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,
+ 143,8,8
+ CONTROL "",IDC_CHECK18,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,
+ 143,8,8
+ CONTROL "",IDC_CHECK19,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,
+ 143,8,8
+ CONTROL "",IDC_CHECK20,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,234,
+ 143,8,8
+ CONTROL "",IDC_CHECK21,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,274,
+ 143,8,8
+ CONTROL "",IDC_CHECK22,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,
+ 193,8,8
+ CONTROL "",IDC_CHECK23,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,74,
+ 193,8,8
+ CONTROL "",IDC_CHECK24,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,
+ 193,8,8
+ CONTROL "",IDC_CHECK25,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,
+ 193,8,8
+ CONTROL "",IDC_CHECK26,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,
+ 193,8,8
+ CONTROL "",IDC_CHECK27,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,234,
+ 193,8,8
+ CONTROL "",IDC_CHECK28,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,274,
+ 193,8,8
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,45,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,85,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,125,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,165,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,205,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,245,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,45,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,85,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,125,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,165,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,205,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,245,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,45,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,85,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,125,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,165,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,205,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,245,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,45,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,85,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,125,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,165,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,205,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,245,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,30,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,50,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,185,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,10,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,10,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,110,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,50,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,70,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,185,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,70,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,240,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,20,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,185,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,240,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,210,10,10
+ CONTROL "",IDC_CHECK29,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,
+ 243,8,8
+ CONTROL "",IDC_CHECK30,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,74,
+ 243,8,8
+ CONTROL "",IDC_CHECK31,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,
+ 243,8,8
+ CONTROL "",IDC_CHECK32,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,
+ 243,8,8
+ CONTROL "",IDC_CHECK33,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,
+ 243,8,8
+ CONTROL "",IDC_CHECK34,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,234,
+ 243,8,8
+ CONTROL "",IDC_CHECK35,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,274,
+ 243,8,8
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,45,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,85,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,125,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,165,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,205,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,245,205,40,50,
+ WS_EX_DLGMODALFRAME
+ PUSHBUTTON "Alle auswählen",IDC_ALLE,235,260,50,14
+ PUSHBUTTON "Standard",IDC_STANDARD,180,260,50,14
+ PUSHBUTTON "Alle Löschen",IDC_LOESCHEN,125,260,50,14
+ EDITTEXT IDC_VORBELEGUNG,105,260,15,14,ES_RIGHT | ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "Vorbelegte Zeilen bei Spielstart:",IDC_STATIC,5,260,95,
+ 13,SS_CENTERIMAGE
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,240,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,230,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,230,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,60,210,10,10
+ LTEXT "1",IDC_STATIC,11,143,8,8
+ LTEXT "2",IDC_STATIC,10,193,8,8
+ LTEXT "4",IDC_STATIC,50,193,8,8
+ LTEXT "6",IDC_STATIC,250,43,8,8
+ LTEXT "8",IDC_STATIC,10,43,8,8
+ LTEXT "10",IDC_STATIC,130,43,8,8
+ LTEXT "10",IDC_STATIC,170,43,8,8
+ LTEXT "12",IDC_STATIC,50,43,8,8
+ LTEXT "12",IDC_STATIC,90,43,8,8
+ LTEXT "10",IDC_STATIC,210,43,8,8
+ LTEXT "25",IDC_STATIC,10,93,8,8
+ LTEXT "25",IDC_STATIC,50,93,8,8
+ LTEXT "4",IDC_STATIC,90,93,8,8
+ LTEXT "20",IDC_STATIC,130,93,8,8
+ LTEXT "10",IDC_STATIC,170,93,8,8
+ LTEXT "10",IDC_STATIC,210,93,8,8
+ LTEXT "20",IDC_STATIC,250,93,8,8
+ LTEXT "8",IDC_STATIC,50,143,8,8
+ LTEXT "25",IDC_STATIC,90,143,8,8
+ LTEXT "40",IDC_STATIC,130,143,8,8
+ LTEXT "15",IDC_STATIC,170,143,8,8
+ LTEXT "25",IDC_STATIC,210,143,8,8
+ LTEXT "35",IDC_STATIC,250,143,8,8
+ LTEXT "10",IDC_STATIC,90,193,8,8
+ LTEXT "10",IDC_STATIC,130,193,8,8
+ LTEXT "20",IDC_STATIC,170,193,8,8
+ LTEXT "20",IDC_STATIC,210,193,8,8
+ LTEXT "25",IDC_STATIC,250,193,8,8
+ LTEXT "25",IDC_STATIC,10,243,8,8
+ LTEXT "30",IDC_STATIC,50,243,8,8
+ LTEXT "25",IDC_STATIC,90,243,8,8
+ LTEXT "25",IDC_STATIC,130,243,8,8
+ LTEXT "10",IDC_STATIC,170,243,8,8
+ LTEXT "15",IDC_STATIC,210,243,8,8
+ LTEXT "25",IDC_STATIC,250,243,8,8
+ EDITTEXT IDC_VORSCHAU,105,280,15,14,ES_RIGHT | ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "Steine in der Vorschau:",IDC_STATIC,5,280,95,13,
+ SS_CENTERIMAGE
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_HILFE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 295
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 100
+ END
+
+ IDD_ULTRIS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 197
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 135
+ END
+
+ IDD_KONFIGURATION, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 282
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 290
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_ULTRIS BITMAP DISCARDABLE "bmp00001.bmp"
+IDB_STEIN BITMAP DISCARDABLE "bmp00002.bmp"
+#endif // Deutsch (Deutschland) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Englisch (USA) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include \r\n"
+ "#include \0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Englisch (USA) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/V06/Demo.sln b/V06/Demo.sln
new file mode 100644
index 0000000..8778ada
--- /dev/null
+++ b/V06/Demo.sln
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo.vcproj", "{E366BFA4-48AF-49A5-B855-06CE431A7FFD}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {E366BFA4-48AF-49A5-B855-06CE431A7FFD}.Debug.ActiveCfg = Debug|Win32
+ {E366BFA4-48AF-49A5-B855-06CE431A7FFD}.Debug.Build.0 = Debug|Win32
+ {E366BFA4-48AF-49A5-B855-06CE431A7FFD}.Release.ActiveCfg = Release|Win32
+ {E366BFA4-48AF-49A5-B855-06CE431A7FFD}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/V06/Demo.suo b/V06/Demo.suo
new file mode 100644
index 0000000..c538610
Binary files /dev/null and b/V06/Demo.suo differ
diff --git a/V06/Demo.vcproj b/V06/Demo.vcproj
new file mode 100644
index 0000000..98ce341
--- /dev/null
+++ b/V06/Demo.vcproj
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V06/Icon.ico b/V06/Icon.ico
new file mode 100644
index 0000000..7a53f63
Binary files /dev/null and b/V06/Icon.ico differ
diff --git a/V06/bmp00001.bmp b/V06/bmp00001.bmp
new file mode 100644
index 0000000..12d2027
Binary files /dev/null and b/V06/bmp00001.bmp differ
diff --git a/V06/bmp00002.bmp b/V06/bmp00002.bmp
new file mode 100644
index 0000000..92b8396
Binary files /dev/null and b/V06/bmp00002.bmp differ
diff --git a/V06/ddutil.cpp b/V06/ddutil.cpp
new file mode 100644
index 0000000..faccc24
--- /dev/null
+++ b/V06/ddutil.cpp
@@ -0,0 +1,1035 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: DirectDraw framewark classes. Feel free to use this class as a
+// starting point for adding extra functionality.
+//
+//
+// Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include
+#include "ddutil.h"
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::CDisplay()
+{
+ m_pDD = NULL;
+ m_pddsFrontBuffer = NULL;
+ m_pddsBackBuffer = NULL;
+ m_pddsBackBufferLeft = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ~CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::~CDisplay()
+{
+ DestroyObjects();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DestroyObjects()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::DestroyObjects()
+{
+ SAFE_RELEASE( m_pddsBackBufferLeft );
+ SAFE_RELEASE( m_pddsBackBuffer );
+ SAFE_RELEASE( m_pddsFrontBuffer );
+
+ if( m_pDD )
+ m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL );
+
+ SAFE_RELEASE( m_pDD );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateFullScreenDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth,
+ DWORD dwHeight, DWORD dwBPP )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ // Set the display mode
+ if( FAILED( m_pDD->SetDisplayMode( dwWidth, dwHeight, dwBPP, 0, 0 ) ) )
+ return E_FAIL;
+
+ // Create primary surface (with backbuffer attached)
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
+ DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE;
+ ddsd.dwBackBufferCount = 1;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer,
+ NULL ) ) )
+ return E_FAIL;
+
+ // Get a pointer to the back buffer
+ DDSCAPS2 ddscaps;
+ ZeroMemory( &ddscaps, sizeof( ddscaps ) );
+ ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
+
+ if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
+ &m_pddsBackBuffer ) ) )
+ return E_FAIL;
+
+ m_pddsBackBuffer->AddRef();
+
+ m_hWnd = hWnd;
+ m_bWindowed = FALSE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateWindowedDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_NORMAL );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ RECT rcWork;
+ RECT rc;
+ DWORD dwStyle;
+
+ // If we are still a WS_POPUP window we should convert to a normal app
+ // window so we look like a windows app.
+ dwStyle = GetWindowStyle( hWnd );
+ dwStyle &= ~WS_POPUP;
+ dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
+ SetWindowLong( hWnd, GWL_STYLE, dwStyle );
+
+ // Aet window size
+ SetRect( &rc, 0, 0, dwWidth, dwHeight );
+
+ AdjustWindowRectEx( &rc, GetWindowStyle(hWnd), GetMenu(hWnd) != NULL,
+ GetWindowExStyle(hWnd) );
+
+ SetWindowPos( hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
+ SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
+
+ // Make sure our window does not hang outside of the work area
+ SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWork, 0 );
+ GetWindowRect( hWnd, &rc );
+ if( rc.left < rcWork.left ) rc.left = rcWork.left;
+ if( rc.top < rcWork.top ) rc.top = rcWork.top;
+ SetWindowPos( hWnd, NULL, rc.left, rc.top, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ LPDIRECTDRAWCLIPPER pcClipper;
+
+ // Create the primary surface
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+ if( FAILED( m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
+ return E_FAIL;
+
+ // Create the backbuffer surface
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = pcClipper->SetHWnd( 0, hWnd ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pcClipper ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ // Done with clipper
+ pcClipper->Release();
+
+ m_hWnd = hWnd;
+ m_bWindowed = TRUE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurface( CSurface** ppSurface,
+ DWORD dwWidth, DWORD dwHeight )
+{
+ if( NULL == m_pDD )
+ return E_POINTER;
+ if( NULL == ppSurface )
+ return E_INVALIDARG;
+
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromBitmap()
+// Desc: Create a DirectDrawSurface from a bitmap resource or bitmap file.
+// Use MAKEINTRESOURCE() to pass a constant into strBMP.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromBitmap( CSurface** ppSurface,
+ TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight )
+{
+ HRESULT hr;
+ HBITMAP hBMP = NULL;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+
+ if( m_pDD == NULL || strBMP == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = bmp.bmWidth;
+ ddsd.dwHeight = bmp.bmHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = (*ppSurface)->DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromText()
+// Desc: Creates a DirectDrawSurface from a text string using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromText( CSurface** ppSurface,
+ HFONT hFont, TCHAR* strText,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ LPDIRECTDRAWSURFACE7 pDDS = NULL;
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ SIZE sizeText;
+
+ if( m_pDD == NULL || strText == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ hDC = GetDC( NULL );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ GetTextExtentPoint32( hDC, strText, _tcslen(strText), &sizeText );
+ ReleaseDC( NULL, hDC );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = sizeText.cx;
+ ddsd.dwHeight = sizeText.cy;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ if( FAILED( hr = (*ppSurface)->DrawText( hFont, strText, 0, 0,
+ crBackground, crForeground ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Present()
+{
+ HRESULT hr;
+
+ if( NULL == m_pddsFrontBuffer && NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ while( 1 )
+ {
+ if( m_bWindowed )
+ hr = m_pddsFrontBuffer->Blt( &m_rcWindow, m_pddsBackBuffer,
+ NULL, DDBLT_WAIT, NULL );
+ else
+ hr = m_pddsFrontBuffer->Flip( NULL, 0 );
+
+ if( hr == DDERR_SURFACELOST )
+ {
+ m_pddsFrontBuffer->Restore();
+ m_pddsBackBuffer->Restore();
+ }
+
+ if( hr != DDERR_WASSTILLDRAWING )
+ return hr;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer || NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Set the palette before loading the bitmap
+ if( pPalette )
+ m_pddsFrontBuffer->SetPalette( pPalette );
+
+ CSurface backBuffer;
+ backBuffer.Create( m_pddsBackBuffer );
+
+ if( FAILED( backBuffer.DrawBitmap( hbm, 0, 0, 0, 0 ) ) )
+ return E_FAIL;
+
+ return Present();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, DDBLTFAST_SRCCOLORKEY );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds, RECT* prc,
+ DWORD dwFlags )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc )
+{
+ if( NULL == pSurface )
+ return E_INVALIDARG;
+
+ if( pSurface->IsColorKeyed() )
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, DDBLTFAST_SRCCOLORKEY );
+ else
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Clear( DWORD dwColor )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Erase the background
+ DDBLTFX ddbltfx;
+ ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
+ ddbltfx.dwSize = sizeof(ddbltfx);
+ ddbltfx.dwFillColor = dwColor;
+
+ return m_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::SetPalette( LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer )
+ return E_POINTER;
+
+ return m_pddsFrontBuffer->SetPalette( pPalette );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette,
+ const TCHAR* strBMP )
+{
+ HRSRC hResource = NULL;
+ RGBQUAD* pRGB = NULL;
+ BITMAPINFOHEADER* pbi = NULL;
+ PALETTEENTRY aPalette[256];
+ HANDLE hFile = NULL;
+ DWORD iColor;
+ DWORD dwColors;
+ BITMAPFILEHEADER bf;
+ BITMAPINFOHEADER bi;
+ DWORD dwBytesRead;
+
+ if( m_pDD == NULL || strBMP == NULL || ppPalette == NULL )
+ return E_INVALIDARG;
+
+ *ppPalette = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hResource = FindResource( NULL, strBMP, RT_BITMAP );
+ if( hResource )
+ {
+ pbi = (LPBITMAPINFOHEADER) LockResource( LoadResource( NULL, hResource ) );
+ if( NULL == pbi )
+ return E_FAIL;
+
+ pRGB = (RGBQUAD*) ( (BYTE*) pbi + pbi->biSize );
+
+ // Figure out how many colors there are
+ if( pbi == NULL || pbi->biSize < sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if( pbi->biBitCount > 8 )
+ dwColors = 0;
+ else if( pbi->biClrUsed == 0 )
+ dwColors = 1 << pbi->biBitCount;
+ else
+ dwColors = pbi->biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around.
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ aPalette[iColor].peRed = pRGB[iColor].rgbRed;
+ aPalette[iColor].peGreen = pRGB[iColor].rgbGreen;
+ aPalette[iColor].peBlue = pRGB[iColor].rgbBlue;
+ aPalette[iColor].peFlags = 0;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+ }
+
+ // Attempt to load bitmap as a file
+ hFile = CreateFile( strBMP, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
+ if( NULL == hFile )
+ return E_FAIL;
+
+ // Read the BITMAPFILEHEADER
+ ReadFile( hFile, &bf, sizeof(bf), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bf) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the BITMAPINFOHEADER
+ ReadFile( hFile, &bi, sizeof(bi), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bi) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the PALETTEENTRY
+ ReadFile( hFile, aPalette, sizeof(aPalette), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(aPalette) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ CloseHandle( hFile );
+
+ // Figure out how many colors there are
+ if( bi.biSize != sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if (bi.biBitCount > 8)
+ dwColors = 0;
+ else if (bi.biClrUsed == 0)
+ dwColors = 1 << bi.biBitCount;
+ else
+ dwColors = bi.biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around since DirectDraw uses RGB
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ BYTE r = aPalette[iColor].peRed;
+ aPalette[iColor].peRed = aPalette[iColor].peBlue;
+ aPalette[iColor].peBlue = r;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::UpdateBounds()
+{
+ if( m_bWindowed )
+ {
+ GetClientRect( m_hWnd, &m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow+1 );
+ }
+ else
+ {
+ SetRect( &m_rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN) );
+ }
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::InitClipper
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::InitClipper()
+{
+ LPDIRECTDRAWCLIPPER pClipper;
+ HRESULT hr;
+
+ // Create a clipper when using GDI to draw on the primary surface
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pClipper, NULL ) ) )
+ return hr;
+
+ pClipper->SetHWnd( 0, m_hWnd );
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pClipper ) ) )
+ return hr;
+
+ // We can release the clipper now since g_pDDSPrimary
+ // now maintains a ref count on the clipper
+ SAFE_RELEASE( pClipper );
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::CSurface()
+{
+ m_pdds = NULL;
+ m_bColorKeyed = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::~CSurface()
+{
+ SAFE_RELEASE( m_pdds );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAWSURFACE7 pdds )
+{
+ m_pdds = pdds;
+
+ if( m_pdds )
+ {
+ m_pdds->AddRef();
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_ddsd.dwSize = sizeof(m_ddsd);
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd )
+{
+ HRESULT hr;
+
+ // Create the DDraw surface
+ if( FAILED( hr = pDD->CreateSurface( pddsd, &m_pdds, NULL ) ) )
+ return hr;
+
+ // Prepare the DDSURFACEDESC structure
+ m_ddsd.dwSize = sizeof(m_ddsd);
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Destroy()
+{
+ SAFE_RELEASE( m_pdds );
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawBitmap()
+// Desc: Draws a bitmap over an entire DirectDrawSurface, stretching the
+// bitmap if nessasary
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( HBITMAP hBMP,
+ DWORD dwBMPOriginX, DWORD dwBMPOriginY,
+ DWORD dwBMPWidth, DWORD dwBMPHeight )
+{
+ HDC hDCImage;
+ HDC hDC;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ if( hBMP == NULL || m_pdds == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ // Get the surface.description
+ ddsd.dwSize = sizeof(ddsd);
+ m_pdds->GetSurfaceDesc( &ddsd );
+
+ if( ddsd.ddpfPixelFormat.dwFlags == DDPF_FOURCC )
+ return E_NOTIMPL;
+
+ // Select bitmap into a memoryDC so we can use it.
+ hDCImage = CreateCompatibleDC( NULL );
+ if( NULL == hDCImage )
+ return E_FAIL;
+
+ SelectObject( hDCImage, hBMP );
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Use the passed size, unless zero
+ dwBMPWidth = ( dwBMPWidth == 0 ) ? bmp.bmWidth : dwBMPWidth;
+ dwBMPHeight = ( dwBMPHeight == 0 ) ? bmp.bmHeight : dwBMPHeight;
+
+ // Stretch the bitmap to cover this surface
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ StretchBlt( hDC, 0, 0,
+ ddsd.dwWidth, ddsd.dwHeight,
+ hDCImage, dwBMPOriginX, dwBMPOriginY,
+ dwBMPWidth, dwBMPHeight, SRCCOPY );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ DeleteDC( hDCImage );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawText()
+// Desc: Draws a text string on a DirectDraw surface using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawText( HFONT hFont, TCHAR* strText,
+ DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strText == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ // Set the background and foreground color
+ SetBkColor( hDC, crBackground );
+ SetTextColor( hDC, crForeground );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ // Use GDI to draw the text on the surface
+ TextOut( hDC, dwOriginX, dwOriginY, strText, _tcslen(strText) );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ReDrawBitmapOnSurface()
+// Desc: Load a bitmap from a file or resource into a DirectDraw surface.
+// normaly used to re-load a surface after a restore.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( TCHAR* strBMP,
+ DWORD dwDesiredWidth, DWORD dwDesiredHeight )
+{
+ HBITMAP hBMP;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strBMP == NULL )
+ return E_INVALIDARG;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP, IMAGE_BITMAP,
+ dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::SetColorKey( DWORD dwColorKey )
+{
+ if( NULL == m_pdds )
+ return E_POINTER;
+
+ m_bColorKeyed = TRUE;
+
+ DDCOLORKEY ddck;
+ ddck.dwColorSpaceLowValue = ConvertGDIColor( dwColorKey );
+ ddck.dwColorSpaceHighValue = ConvertGDIColor( dwColorKey );
+
+ return m_pdds->SetColorKey( DDCKEY_SRCBLT, &ddck );
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ConvertGDIColor()
+// Desc: Converts a GDI color (0x00bbggrr) into the equivalent color on a
+// DirectDrawSurface using its pixel format.
+//-----------------------------------------------------------------------------
+DWORD CSurface::ConvertGDIColor( COLORREF dwGDIColor )
+{
+ if( m_pdds == NULL )
+ return 0x00000000;
+
+ COLORREF rgbT;
+ HDC hdc;
+ DWORD dw = CLR_INVALID;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ // Use GDI SetPixel to color match for us
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK)
+ {
+ rgbT = GetPixel(hdc, 0, 0); // Save current pixel value
+ SetPixel(hdc, 0, 0, dwGDIColor); // Set our value
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ // Now lock the surface so we can read back the converted color
+ ddsd.dwSize = sizeof(ddsd);
+ hr = m_pdds->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
+ if( hr == DD_OK)
+ {
+ dw = *(DWORD *) ddsd.lpSurface;
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount < 32 ) // Mask it to bpp
+ dw &= ( 1 << ddsd.ddpfPixelFormat.dwRGBBitCount ) - 1;
+ m_pdds->Unlock(NULL);
+ }
+
+ // Now put the color that was there back.
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK )
+ {
+ SetPixel( hdc, 0, 0, rgbT );
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ return dw;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::GetBitMaskInfo()
+// Desc: Returns the number of bits and the shift in the bit mask
+//-----------------------------------------------------------------------------
+HRESULT CSurface::GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits )
+{
+ DWORD dwShift = 0;
+ DWORD dwBits = 0;
+
+ if( pdwShift == NULL || pdwBits == NULL )
+ return E_INVALIDARG;
+
+ if( dwBitMask )
+ {
+ while( (dwBitMask & 1) == 0 )
+ {
+ dwShift++;
+ dwBitMask >>= 1;
+ }
+ }
+
+ while( (dwBitMask & 1) != 0 )
+ {
+ dwBits++;
+ dwBitMask >>= 1;
+ }
+
+ *pdwShift = dwShift;
+ *pdwBits = dwBits;
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V06/ddutil.h b/V06/ddutil.h
new file mode 100644
index 0000000..61fb0be
--- /dev/null
+++ b/V06/ddutil.h
@@ -0,0 +1,140 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: Routines for loading bitmap and palettes from resources
+//
+// Copyright (C) 1998-1999 Microsoft Corporation. All Rights Reserved.
+//-----------------------------------------------------------------------------
+#ifndef DDUTIL_H
+#define DDUTIL_H
+
+#include
+#include
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes defined in this header file
+//-----------------------------------------------------------------------------
+class CDisplay;
+class CSurface;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Flags for the CDisplay and CSurface methods
+//-----------------------------------------------------------------------------
+#define DSURFACELOCK_READ
+#define DSURFACELOCK_WRITE
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CDisplay
+// Desc: Class to handle all DDraw aspects of a display, including creation of
+// front and back buffers, creating offscreen surfaces and palettes,
+// and blitting surface and displaying bitmaps.
+//-----------------------------------------------------------------------------
+class CDisplay
+{
+protected:
+ LPDIRECTDRAW7 m_pDD;
+ LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBufferLeft; // For stereo modes
+
+ HWND m_hWnd;
+ RECT m_rcWindow;
+ BOOL m_bWindowed;
+ BOOL m_bStereo;
+
+public:
+ CDisplay();
+ ~CDisplay();
+
+ // Access functions
+ HWND GetHWnd() { return m_hWnd; }
+ LPDIRECTDRAW7 GetDirectDraw() { return m_pDD; }
+ LPDIRECTDRAWSURFACE7 GetFrontBuffer() { return m_pddsFrontBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBuffer() { return m_pddsBackBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBufferLEft() { return m_pddsBackBufferLeft; }
+
+ // Status functions
+ BOOL IsWindowed() { return m_bWindowed; }
+ BOOL IsStereo() { return m_bStereo; }
+
+ // Creation/destruction methods
+ HRESULT CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight,
+ DWORD dwBPP );
+ HRESULT CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight );
+ HRESULT InitClipper();
+ HRESULT UpdateBounds();
+ virtual HRESULT DestroyObjects();
+
+ // Methods to create child objects
+ HRESULT CreateSurface( CSurface** ppSurface, DWORD dwWidth,
+ DWORD dwHeight );
+ HRESULT CreateSurfaceFromBitmap( CSurface** ppSurface, TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight );
+ HRESULT CreateSurfaceFromText( CSurface** ppSurface, HFONT hFont,
+ TCHAR* strText,
+ COLORREF crBackground,
+ COLORREF crForeground );
+ HRESULT CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette, const TCHAR* strBMP );
+
+ // Display methods
+ HRESULT Clear( DWORD dwColor = 0L );
+ HRESULT ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc = NULL );
+ HRESULT Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc=NULL, DWORD dwFlags=0 );
+ HRESULT Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc = NULL );
+ HRESULT ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette=NULL );
+ HRESULT SetPalette( LPDIRECTDRAWPALETTE pPalette );
+ HRESULT Present();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSurface
+// Desc: Class to handle aspects of a DirectDrawSurface.
+//-----------------------------------------------------------------------------
+class CSurface
+{
+ LPDIRECTDRAWSURFACE7 m_pdds;
+ DDSURFACEDESC2 m_ddsd;
+ BOOL m_bColorKeyed;
+
+public:
+ LPDIRECTDRAWSURFACE7 GetDDrawSurface() { return m_pdds; }
+ BOOL IsColorKeyed() { return m_bColorKeyed; }
+
+ HRESULT DrawBitmap( HBITMAP hBMP, DWORD dwBMPOriginX = 0, DWORD dwBMPOriginY = 0,
+ DWORD dwBMPWidth = 0, DWORD dwBMPHeight = 0 );
+ HRESULT DrawBitmap( TCHAR* strBMP, DWORD dwDesiredWidth, DWORD dwDesiredHeight );
+ HRESULT DrawText( HFONT hFont, TCHAR* strText, DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground );
+
+ HRESULT SetColorKey( DWORD dwColorKey );
+ DWORD ConvertGDIColor( COLORREF dwGDIColor );
+ static HRESULT GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits );
+
+ HRESULT Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd );
+ HRESULT Create( LPDIRECTDRAWSURFACE7 pdds );
+ HRESULT Destroy();
+
+ CSurface();
+ ~CSurface();
+};
+
+
+
+
+#endif // DDUTIL_H
+
diff --git a/V06/dsutil.cpp b/V06/dsutil.cpp
new file mode 100644
index 0000000..83c1512
--- /dev/null
+++ b/V06/dsutil.cpp
@@ -0,0 +1,1546 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.cpp
+//
+// Desc: DirectSound framework classes for reading and writing wav files and
+// playing them in DirectSound buffers. Feel free to use this class
+// as a starting point for adding extra functionality.
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CSoundManager()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSoundManager::CSoundManager()
+{
+ m_pDS = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::~CSoundManager()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSoundManager::~CSoundManager()
+{
+ SAFE_RELEASE( m_pDS );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Initialize()
+// Desc: Initializes the IDirectSound object and also sets the primary buffer
+// format. This function must be called before any others.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Initialize( HWND hWnd,
+ DWORD dwCoopLevel,
+ DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ SAFE_RELEASE( m_pDS );
+
+ // Create IDirectSound using the primary sound device
+ if( FAILED( hr = DirectSoundCreate8( NULL, &m_pDS, NULL ) ) )
+ return DXTRACE_ERR( TEXT("DirectSoundCreate8"), hr );
+
+ // Set DirectSound coop level
+ if( FAILED( hr = m_pDS->SetCooperativeLevel( hWnd, dwCoopLevel ) ) )
+ return DXTRACE_ERR( TEXT("SetCooperativeLevel"), hr );
+
+ // Set primary buffer format
+ SetPrimaryBufferFormat( dwPrimaryChannels, dwPrimaryFreq, dwPrimaryBitRate );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::SetPrimaryBufferFormat()
+// Desc: Set primary buffer to a specified format
+// For example, to set the primary buffer format to 22kHz stereo, 16-bit
+// then: dwPrimaryChannels = 2
+// dwPrimaryFreq = 22050,
+// dwPrimaryBitRate = 16
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::SetPrimaryBufferFormat( DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Get the primary buffer
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
+ dsbd.dwBufferBytes = 0;
+ dsbd.lpwfxFormat = NULL;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ WAVEFORMATEX wfx;
+ ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = (WORD) dwPrimaryChannels;
+ wfx.nSamplesPerSec = dwPrimaryFreq;
+ wfx.wBitsPerSample = (WORD) dwPrimaryBitRate;
+ wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+ if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )
+ return DXTRACE_ERR( TEXT("SetFormat"), hr );
+
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Get3DListenerInterface()
+// Desc: Returns the 3D listener interface associated with primary buffer.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener )
+{
+ HRESULT hr;
+ DSBUFFERDESC dsbdesc;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( ppDSListener == NULL )
+ return E_INVALIDARG;
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ *ppDSListener = NULL;
+
+ // Obtain primary buffer, asking it for 3D control
+ ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
+ dsbdesc.dwSize = sizeof(DSBUFFERDESC);
+ dsbdesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ if( FAILED( hr = pDSBPrimary->QueryInterface( IID_IDirectSound3DListener,
+ (VOID**)ppDSListener ) ) )
+ {
+ SAFE_RELEASE( pDSBPrimary );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ // Release the primary buffer, since it is not need anymore
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Create()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Create( CSound** ppSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ HRESULT hrRet = S_OK;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ if( pWaveFile->GetSize() == 0 )
+ {
+ // Wave is blank, so don't create it.
+ hr = E_FAIL;
+ goto LFail;
+ }
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = pWaveFile->GetSize();
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ // DirectSound is only guarenteed to play PCM data. Other
+ // formats may or may not work depending the sound card driver.
+ hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL );
+
+ // Be sure to return this error code if it occurs so the
+ // callers knows this happened.
+ if( hr == DS_NO_VIRTUALIZATION )
+ hrRet = DS_NO_VIRTUALIZATION;
+
+ if( FAILED(hr) )
+ {
+ // DSERR_BUFFERTOOSMALL will be returned if the buffer is
+ // less than DSBSIZE_FX_MIN (100ms) and the buffer is created
+ // with DSBCAPS_CTRLFX.
+ if( hr != DSERR_BUFFERTOOSMALL )
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return hrRet;
+
+LFail:
+ // Cleanup
+ SAFE_DELETE( pWaveFile );
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateFromMemory()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateFromMemory( CSound** ppSound,
+ BYTE* pbData,
+ ULONG ulDataSize,
+ LPWAVEFORMATEX pwfx,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbData == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->OpenFromMemory( pbData,ulDataSize, pwfx, WAVEFILE_READ );
+
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = ulDataSize;
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL ) ) )
+ {
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return S_OK;
+
+LFail:
+ // Cleanup
+
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateStreaming()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateStreaming( CStreamingSound** ppStreamingSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNotifyCount,
+ DWORD dwNotifySize,
+ HANDLE hNotifyEvent )
+{
+ HRESULT hr;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppStreamingSound == NULL || hNotifyEvent == NULL )
+ return E_INVALIDARG;
+
+ LPDIRECTSOUNDBUFFER pDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+ DSBPOSITIONNOTIFY* aPosNotify = NULL;
+ LPDIRECTSOUNDNOTIFY pDSNotify = NULL;
+
+ pWaveFile = new CWaveFile();
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ // Figure out how big the DSound buffer should be
+ dwDSBufferSize = dwNotifySize * dwNotifyCount;
+
+ // Set up the direct sound buffer. Request the NOTIFY flag, so
+ // that we are notified as the sound buffer plays. Note, that using this flag
+ // may limit the amount of hardware acceleration that can occur.
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags |
+ DSBCAPS_CTRLPOSITIONNOTIFY |
+ DSBCAPS_GETCURRENTPOSITION2;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBuffer, NULL ) ) )
+ {
+ // If wave format isn't then it will return
+ // either DSERR_BADFORMAT or E_INVALIDARG
+ if( hr == DSERR_BADFORMAT || hr == E_INVALIDARG )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("CreateSoundBuffer"), hr );
+
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ }
+
+ // Create the notification events, so that we know when to fill
+ // the buffer as the sound plays.
+ if( FAILED( hr = pDSBuffer->QueryInterface( IID_IDirectSoundNotify,
+ (VOID**)&pDSNotify ) ) )
+ {
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ];
+ if( aPosNotify == NULL )
+ return E_OUTOFMEMORY;
+
+ for( DWORD i = 0; i < dwNotifyCount; i++ )
+ {
+ aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
+ aPosNotify[i].hEventNotify = hNotifyEvent;
+ }
+
+ // Tell DirectSound when to notify us. The notification will come in the from
+ // of signaled events that are handled in WinMain()
+ if( FAILED( hr = pDSNotify->SetNotificationPositions( dwNotifyCount,
+ aPosNotify ) ) )
+ {
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("SetNotificationPositions"), hr );
+ }
+
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+
+ // Create the sound
+ *ppStreamingSound = new CStreamingSound( pDSBuffer, dwDSBufferSize, pWaveFile, dwNotifySize );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::CSound()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSound::CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize,
+ DWORD dwNumBuffers, CWaveFile* pWaveFile )
+{
+ DWORD i;
+
+ m_apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ for( i=0; iSetCurrentPosition(0);
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::~CSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSound::~CSound()
+{
+ for( DWORD i=0; iLock( 0, m_dwDSBufferSize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ NULL, NULL, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // Reset the wave file to the beginning
+ m_pWaveFile->ResetFile();
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwWavDataRead ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ if( dwWavDataRead == 0 )
+ {
+ // Wav is blank, so just fill with silence
+ FillMemory( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ else if( dwWavDataRead < dwDSLockedBufferSize )
+ {
+ // If the wav file was smaller than the DirectSound buffer,
+ // we need to fill the remainder of the buffer with data
+ if( bRepeatWavIfBufferLarger )
+ {
+ // Reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwWavDataRead; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full
+ // for very short files
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwWavDataRead );
+ if( FAILED(hr) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwWavDataRead;
+ }
+ }
+ else
+ {
+ // Don't repeat the wav file, just fill in silence
+ FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead,
+ dwDSLockedBufferSize - dwWavDataRead,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ }
+
+ // Unlock the buffer, we don't need it anymore.
+ pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::RestoreBuffer()
+// Desc: Restores the lost buffer. *pbWasRestored returns TRUE if the buffer was
+// restored. It can also NULL if the information is not needed.
+//-----------------------------------------------------------------------------
+HRESULT CSound::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored )
+{
+ HRESULT hr;
+
+ if( pDSB == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbWasRestored )
+ *pbWasRestored = FALSE;
+
+ DWORD dwStatus;
+ if( FAILED( hr = pDSB->GetStatus( &dwStatus ) ) )
+ return DXTRACE_ERR( TEXT("GetStatus"), hr );
+
+ if( dwStatus & DSBSTATUS_BUFFERLOST )
+ {
+ // Since the app could have just been activated, then
+ // DirectSound may not be giving us control yet, so
+ // the restoring the buffer may fail.
+ // If it does, sleep until DirectSound gives us control.
+ do
+ {
+ hr = pDSB->Restore();
+ if( hr == DSERR_BUFFERLOST )
+ Sleep( 10 );
+ }
+ while( hr = pDSB->Restore() );
+
+ if( pbWasRestored != NULL )
+ *pbWasRestored = TRUE;
+
+ return S_OK;
+ }
+ else
+ {
+ return S_FALSE;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetFreeBuffer()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetFreeBuffer()
+{
+ BOOL bIsPlaying = FALSE;
+ DWORD i;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( i=0; iGetStatus( &dwStatus );
+ if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
+ break;
+ }
+ }
+
+ if( i != m_dwNumBuffers )
+ return m_apDSBuffer[ i ];
+ else
+ return m_apDSBuffer[ rand() % m_dwNumBuffers ];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetBuffer()
+// Desc:
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetBuffer( DWORD dwIndex )
+{
+ if( m_apDSBuffer == NULL )
+ return NULL;
+ if( dwIndex >= m_dwNumBuffers )
+ return NULL;
+
+ return m_apDSBuffer[dwIndex];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Get3DBufferInterface()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSound::Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer )
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( dwIndex >= m_dwNumBuffers )
+ return E_INVALIDARG;
+
+ *ppDS3DBuffer = NULL;
+
+ return m_apDSBuffer[dwIndex]->QueryInterface( IID_IDirectSound3DBuffer,
+ (VOID**)ppDS3DBuffer );
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Play()
+// Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING
+// in the dwFlags to loop the sound
+//-----------------------------------------------------------------------------
+HRESULT CSound::Play( DWORD dwPriority, DWORD dwFlags )
+{
+ HRESULT hr;
+ BOOL bRestored;
+
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();
+
+ if( pDSB == NULL )
+ return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL );
+
+ // Restore the buffer if it was lost
+ if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+
+ // Make DirectSound do pre-processing on sound effects
+ Reset();
+ }
+
+ return pDSB->Play( 0, dwPriority, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Stop()
+// Desc: Stops the sound from playing
+//-----------------------------------------------------------------------------
+HRESULT CSound::Stop()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iStop();
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Reset()
+// Desc: Reset all of the sound buffers
+//-----------------------------------------------------------------------------
+HRESULT CSound::Reset()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iSetCurrentPosition( 0 );
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::IsSoundPlaying()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+BOOL CSound::IsSoundPlaying()
+{
+ BOOL bIsPlaying = FALSE;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( DWORD i=0; iGetStatus( &dwStatus );
+ bIsPlaying |= ( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );
+ }
+ }
+
+ return bIsPlaying;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::CStreamingSound()
+// Desc: Setups up a buffer so data can be streamed from the wave file into
+// buffer. This is very useful for large wav files that would take a
+// while to load. The buffer is initially filled with data, then
+// as sound is played the notification events are signaled and more data
+// is written into the buffer by calling HandleWaveStreamNotification()
+//-----------------------------------------------------------------------------
+CStreamingSound::CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize,
+ CWaveFile* pWaveFile, DWORD dwNotifySize )
+ : CSound( &pDSBuffer, dwDSBufferSize, 1, pWaveFile )
+{
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNotifySize = dwNotifySize;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::~CStreamingSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CStreamingSound::~CStreamingSound()
+{
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::HandleWaveStreamNotification()
+// Desc: Handle the notification that tell us to put more wav data in the
+// circular buffer
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::HandleWaveStreamNotification( BOOL bLoopedPlay )
+{
+ HRESULT hr;
+ DWORD dwCurrentPlayPos;
+ DWORD dwPlayDelta;
+ DWORD dwBytesWrittenToBuffer;
+ VOID* pDSLockedBuffer = NULL;
+ VOID* pDSLockedBuffer2 = NULL;
+ DWORD dwDSLockedBufferSize;
+ DWORD dwDSLockedBufferSize2;
+
+ if( m_apDSBuffer == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ return S_OK;
+ }
+
+ // Lock the DirectSound buffer
+ if( FAILED( hr = m_apDSBuffer[0]->Lock( m_dwNextWriteOffset, m_dwNotifySize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // m_dwDSBufferSize and m_dwNextWriteOffset are both multiples of m_dwNotifySize,
+ // it should the second buffer should never be valid
+ if( pDSLockedBuffer2 != NULL )
+ return E_UNEXPECTED;
+
+ if( !m_bFillNextNotificationWithSilence )
+ {
+ // Fill the DirectSound buffer with wav data
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+ }
+ else
+ {
+ // Fill the DirectSound buffer with silence
+ FillMemory( pDSLockedBuffer, dwDSLockedBufferSize,
+ (BYTE)( m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ dwBytesWrittenToBuffer = dwDSLockedBufferSize;
+ }
+
+ // If the number of bytes written is less than the
+ // amount we requested, we have a short file.
+ if( dwBytesWrittenToBuffer < dwDSLockedBufferSize )
+ {
+ if( !bLoopedPlay )
+ {
+ // Fill in silence for the rest of the buffer.
+ FillMemory( (BYTE*) pDSLockedBuffer + dwBytesWrittenToBuffer,
+ dwDSLockedBufferSize - dwBytesWrittenToBuffer,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+
+ // Any future notifications should just fill the buffer with silence
+ m_bFillNextNotificationWithSilence = TRUE;
+ }
+ else
+ {
+ // We are looping, so reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwBytesWrittenToBuffer; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full (for very short files).
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwBytesWrittenToBuffer;
+ }
+ }
+ }
+
+ // Unlock the DirectSound buffer
+ m_apDSBuffer[0]->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ // Figure out how much data has been played so far. When we have played
+ // passed the end of the file, we will either need to start filling the
+ // buffer with silence or starting reading from the beginning of the file,
+ // depending if the user wants to loop the sound
+ if( FAILED( hr = m_apDSBuffer[0]->GetCurrentPosition( &dwCurrentPlayPos, NULL ) ) )
+ return DXTRACE_ERR( TEXT("GetCurrentPosition"), hr );
+
+ // Check to see if the position counter looped
+ if( dwCurrentPlayPos < m_dwLastPlayPos )
+ dwPlayDelta = ( m_dwDSBufferSize - m_dwLastPlayPos ) + dwCurrentPlayPos;
+ else
+ dwPlayDelta = dwCurrentPlayPos - m_dwLastPlayPos;
+
+ m_dwPlayProgress += dwPlayDelta;
+ m_dwLastPlayPos = dwCurrentPlayPos;
+
+ // If we are now filling the buffer with silence, then we have found the end so
+ // check to see if the entire sound has played, if it has then stop the buffer.
+ if( m_bFillNextNotificationWithSilence )
+ {
+ // We don't want to cut off the sound before it's done playing.
+ if( m_dwPlayProgress >= m_pWaveFile->GetSize() )
+ {
+ m_apDSBuffer[0]->Stop();
+ }
+ }
+
+ // Update where the buffer will lock (for next time)
+ m_dwNextWriteOffset += dwDSLockedBufferSize;
+ m_dwNextWriteOffset %= m_dwDSBufferSize; // Circular buffer
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::Reset()
+// Desc: Resets the sound so it will begin playing at the beginning
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::Reset()
+{
+ HRESULT hr;
+
+ if( m_apDSBuffer[0] == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ }
+
+ m_pWaveFile->ResetFile();
+
+ return m_apDSBuffer[0]->SetCurrentPosition( 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::CWaveFile()
+// Desc: Constructs the class. Call Open() to open a wave file for reading.
+// Then call Read() as needed. Calling the destructor or Close()
+// will close the file.
+//-----------------------------------------------------------------------------
+CWaveFile::CWaveFile()
+{
+ m_pwfx = NULL;
+ m_hmmio = NULL;
+ m_dwSize = 0;
+ m_bIsReadingFromMemory = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::~CWaveFile()
+// Desc: Destructs the class
+//-----------------------------------------------------------------------------
+CWaveFile::~CWaveFile()
+{
+ Close();
+
+ if( !m_bIsReadingFromMemory )
+ SAFE_DELETE_ARRAY( m_pwfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Open()
+// Desc: Opens a wave file for reading
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ HRESULT hr;
+
+ m_dwFlags = dwFlags;
+ m_bIsReadingFromMemory = FALSE;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ if( strFileName == NULL )
+ return E_INVALIDARG;
+ SAFE_DELETE_ARRAY( m_pwfx );
+
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );
+
+ if( NULL == m_hmmio )
+ {
+ HRSRC hResInfo;
+ HGLOBAL hResData;
+ DWORD dwSize;
+ VOID* pvRes;
+
+ // Loading it as a file failed, so try it as a resource
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAVE") ) ) )
+ {
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAV") ) ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("FindResource"), E_FAIL );
+ }
+
+ if( NULL == ( hResData = LoadResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("LoadResource"), E_FAIL );
+
+ if( 0 == ( dwSize = SizeofResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("SizeofResource"), E_FAIL );
+
+ if( NULL == ( pvRes = LockResource( hResData ) ) )
+ return DXTRACE_ERR( TEXT("LockResource"), E_FAIL );
+
+ CHAR* pData = new CHAR[ dwSize ];
+ memcpy( pData, pvRes, dwSize );
+
+ MMIOINFO mmioInfo;
+ ZeroMemory( &mmioInfo, sizeof(mmioInfo) );
+ mmioInfo.fccIOProc = FOURCC_MEM;
+ mmioInfo.cchBuffer = dwSize;
+ mmioInfo.pchBuffer = (CHAR*) pData;
+
+ m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );
+ }
+
+ if( FAILED( hr = ReadMMIO() ) )
+ {
+ // ReadMMIO will fail if its an not a wave file
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR_NOMSGBOX( TEXT("ReadMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ // After the reset, the size of the wav file is m_ck.cksize so store it now
+ m_dwSize = m_ck.cksize;
+ }
+ else
+ {
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF |
+ MMIO_READWRITE |
+ MMIO_CREATE );
+ if( NULL == m_hmmio )
+ return DXTRACE_ERR( TEXT("mmioOpen"), E_FAIL );
+
+ if( FAILED( hr = WriteMMIO( pwfx ) ) )
+ {
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR( TEXT("WriteMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+ }
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::OpenFromMemory()
+// Desc: copy data to CWaveFile member variable from memory
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::OpenFromMemory( BYTE* pbData, ULONG ulDataSize,
+ WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ m_pwfx = pwfx;
+ m_ulDataSize = ulDataSize;
+ m_pbData = pbData;
+ m_pbDataCur = m_pbData;
+ m_bIsReadingFromMemory = TRUE;
+
+ if( dwFlags != WAVEFILE_READ )
+ return E_NOTIMPL;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ReadMMIO()
+// Desc: Support function for reading from a multimedia I/O stream.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_pwfx.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ReadMMIO()
+{
+ MMCKINFO ckIn; // chunk info. for general use.
+ PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in.
+
+ m_pwfx = NULL;
+
+ if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Check to make sure this is a valid wave file
+ if( (m_ckRiff.ckid != FOURCC_RIFF) ||
+ (m_ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("mmioFOURCC"), E_FAIL );
+
+ // Search the input file for for the 'fmt ' chunk.
+ ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Expect the 'fmt' chunk to be at least as large as ;
+ // if there are extra parameters at the end, we'll ignore them
+ if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) )
+ return DXTRACE_ERR( TEXT("sizeof(PCMWAVEFORMAT)"), E_FAIL );
+
+ // Read the 'fmt ' chunk into .
+ if( mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat,
+ sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ // Allocate the waveformatex, but if its not pcm format, read the next
+ // word, and thats how many extra bytes to allocate.
+ if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )
+ {
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("m_pwfx"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = 0;
+ }
+ else
+ {
+ // Read in length of extra bytes.
+ WORD cbExtraBytes = 0L;
+ if( mmioRead( m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("new"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = cbExtraBytes;
+
+ // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
+ if( mmioRead( m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize))+sizeof(WORD)),
+ cbExtraBytes ) != cbExtraBytes )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+ }
+ }
+
+ // Ascend the input file out of the 'fmt ' chunk.
+ if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::GetSize()
+// Desc: Retuns the size of the read access wave file
+//-----------------------------------------------------------------------------
+DWORD CWaveFile::GetSize()
+{
+ return m_dwSize;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ResetFile()
+// Desc: Resets the internal m_ck pointer so reading starts from the
+// beginning of the file again
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ResetFile()
+{
+ if( m_bIsReadingFromMemory )
+ {
+ m_pbDataCur = m_pbData;
+ }
+ else
+ {
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ // Seek to the data
+ if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),
+ SEEK_SET ) )
+ return DXTRACE_ERR( TEXT("mmioSeek"), E_FAIL );
+
+ // Search the input file for the 'data' chunk.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ if( 0 != mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+ }
+ else
+ {
+ // Create the 'data' chunk that holds the waveform samples.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ m_ck.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( 0 != mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Read()
+// Desc: Reads section of data from a wave file into pBuffer and returns
+// how much read in pdwSizeRead, reading not more than dwSizeToRead.
+// This uses m_ck to determine where to start reading from. So
+// subsequent calls will be continue where the last left off unless
+// Reset() is called.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )
+{
+ if( m_bIsReadingFromMemory )
+ {
+ if( m_pbDataCur == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( (BYTE*)(m_pbDataCur + dwSizeToRead) >
+ (BYTE*)(m_pbData + m_ulDataSize) )
+ {
+ dwSizeToRead = m_ulDataSize - (DWORD)(m_pbDataCur - m_pbData);
+ }
+
+ CopyMemory( pBuffer, m_pbDataCur, dwSizeToRead );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = dwSizeToRead;
+
+ return S_OK;
+ }
+ else
+ {
+ MMIOINFO mmioinfoIn; // current status of m_hmmio
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pBuffer == NULL || pdwSizeRead == NULL )
+ return E_INVALIDARG;
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+
+ UINT cbDataIn = dwSizeToRead;
+ if( cbDataIn > m_ck.cksize )
+ cbDataIn = m_ck.cksize;
+
+ m_ck.cksize -= cbDataIn;
+
+ for( DWORD cT = 0; cT < cbDataIn; cT++ )
+ {
+ // Copy the bytes from the io to the buffer.
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ {
+ if( 0 != mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ return DXTRACE_ERR( TEXT("mmioinfoIn.pchNext"), E_FAIL );
+ }
+
+ // Actual copy.
+ *((BYTE*)pBuffer+cT) = *((BYTE*)mmioinfoIn.pchNext);
+ mmioinfoIn.pchNext++;
+ }
+
+ if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = cbDataIn;
+
+ return S_OK;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Close()
+// Desc: Closes the wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Close()
+{
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+ else
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( 0 != mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ // Ascend the output file out of the 'data' chunk -- this will cause
+ // the chunk size of the 'data' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Do this here instead...
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioSeek( m_hmmio, 0, SEEK_SET );
+
+ if( 0 != (INT)mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ m_ck.ckid = mmioFOURCC('f', 'a', 'c', 't');
+
+ if( 0 == mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ {
+ DWORD dwSamples = 0;
+ mmioWrite( m_hmmio, (HPSTR)&dwSamples, sizeof(DWORD) );
+ mmioAscend( m_hmmio, &m_ck, 0 );
+ }
+
+ // Ascend the output file out of the 'RIFF' chunk -- this will cause
+ // the chunk size of the 'RIFF' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::WriteMMIO()
+// Desc: Support function for reading from a multimedia I/O stream
+// pwfxDest is the WAVEFORMATEX for this new wave file.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_ck.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::WriteMMIO( WAVEFORMATEX *pwfxDest )
+{
+ DWORD dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile.
+ MMCKINFO ckOut1;
+
+ dwFactChunk = (DWORD)-1;
+
+ // Create the output file RIFF chunk of form type 'WAVE'.
+ m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');
+ m_ckRiff.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // We are now descended into the 'RIFF' chunk we just created.
+ // Now create the 'fmt ' chunk. Since we know the size of this chunk,
+ // specify it in the MMCKINFO structure so MMIO doesn't have to seek
+ // back and set the chunk size after ascending from the chunk.
+ m_ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ m_ck.cksize = sizeof(PCMWAVEFORMAT);
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type.
+ if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM )
+ {
+ if( mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+ else
+ {
+ // Write the variable length size.
+ if( (UINT)mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(*pwfxDest) + pwfxDest->cbSize ) !=
+ ( sizeof(*pwfxDest) + pwfxDest->cbSize ) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+
+ // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Now create the fact chunk, not required for PCM but nice to have. This is filled
+ // in when the close routine is called.
+ ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't');
+ ckOut1.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( mmioWrite( m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) !=
+ sizeof(dwFactChunk) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+
+ // Now ascend out of the fact chunk...
+ if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Write()
+// Desc: Writes data to the open wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Write( UINT nSizeToWrite, BYTE* pbSrcData, UINT* pnSizeWrote )
+{
+ UINT cT;
+
+ if( m_bIsReadingFromMemory )
+ return E_NOTIMPL;
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pnSizeWrote == NULL || pbSrcData == NULL )
+ return E_INVALIDARG;
+
+ *pnSizeWrote = 0;
+
+ for( cT = 0; cT < nSizeToWrite; cT++ )
+ {
+ if( m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite )
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+ if( 0 != mmioAdvance( m_hmmio, &m_mmioinfoOut, MMIO_WRITE ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+ }
+
+ *((BYTE*)m_mmioinfoOut.pchNext) = *((BYTE*)pbSrcData+cT);
+ (BYTE*)m_mmioinfoOut.pchNext++;
+
+ (*pnSizeWrote)++;
+ }
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V06/dsutil.h b/V06/dsutil.h
new file mode 100644
index 0000000..57d26df
--- /dev/null
+++ b/V06/dsutil.h
@@ -0,0 +1,170 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.h
+//
+// Desc:
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#ifndef DSUTIL_H
+#define DSUTIL_H
+
+#include
+#include
+#include
+#include
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes used by this header
+//-----------------------------------------------------------------------------
+class CSoundManager;
+class CSound;
+class CStreamingSound;
+class CWaveFile;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Typing macros
+//-----------------------------------------------------------------------------
+#define WAVEFILE_READ 1
+#define WAVEFILE_WRITE 2
+
+#define DSUtil_StopSound(s) { if(s) s->Stop(); }
+#define DSUtil_PlaySound(s) { if(s) s->Play( 0, 0 ); }
+#define DSUtil_PlaySoundLooping(s) { if(s) s->Play( 0, DSBPLAY_LOOPING ); }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSoundManager
+// Desc:
+//-----------------------------------------------------------------------------
+class CSoundManager
+{
+protected:
+ LPDIRECTSOUND8 m_pDS;
+
+public:
+ CSoundManager();
+ ~CSoundManager();
+
+ HRESULT Initialize( HWND hWnd, DWORD dwCoopLevel, DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate );
+ inline LPDIRECTSOUND GetDirectSound() { return m_pDS; }
+ HRESULT SetPrimaryBufferFormat( DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate );
+ HRESULT Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener );
+
+ HRESULT Create( CSound** ppSound, LPTSTR strWaveFileName, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
+ HRESULT CreateFromMemory( CSound** ppSound, BYTE* pbData, ULONG ulDataSize, LPWAVEFORMATEX pwfx, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
+ HRESULT CreateStreaming( CStreamingSound** ppStreamingSound, LPTSTR strWaveFileName, DWORD dwCreationFlags, GUID guid3DAlgorithm, DWORD dwNotifyCount, DWORD dwNotifySize, HANDLE hNotifyEvent );
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSound
+// Desc: Encapsulates functionality of a DirectSound buffer.
+//-----------------------------------------------------------------------------
+class CSound
+{
+protected:
+ LPDIRECTSOUNDBUFFER* m_apDSBuffer;
+ DWORD m_dwDSBufferSize;
+ CWaveFile* m_pWaveFile;
+ DWORD m_dwNumBuffers;
+
+ HRESULT RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored );
+
+public:
+ CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize, DWORD dwNumBuffers, CWaveFile* pWaveFile );
+ virtual ~CSound();
+
+ HRESULT Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer );
+ HRESULT FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger );
+ LPDIRECTSOUNDBUFFER GetFreeBuffer();
+ LPDIRECTSOUNDBUFFER GetBuffer( DWORD dwIndex );
+
+ HRESULT Play( DWORD dwPriority, DWORD dwFlags );
+ HRESULT Stop();
+ HRESULT Reset();
+ BOOL IsSoundPlaying();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CStreamingSound
+// Desc: Encapsulates functionality to play a wave file with DirectSound.
+// The Create() method loads a chunk of wave file into the buffer,
+// and as sound plays more is written to the buffer by calling
+// HandleWaveStreamNotification() whenever hNotifyEvent is signaled.
+//-----------------------------------------------------------------------------
+class CStreamingSound : public CSound
+{
+protected:
+ DWORD m_dwLastPlayPos;
+ DWORD m_dwPlayProgress;
+ DWORD m_dwNotifySize;
+ DWORD m_dwNextWriteOffset;
+ BOOL m_bFillNextNotificationWithSilence;
+
+public:
+ CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize, CWaveFile* pWaveFile, DWORD dwNotifySize );
+ ~CStreamingSound();
+
+ HRESULT HandleWaveStreamNotification( BOOL bLoopedPlay );
+ HRESULT Reset();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CWaveFile
+// Desc: Encapsulates reading or writing sound data to or from a wave file
+//-----------------------------------------------------------------------------
+class CWaveFile
+{
+public:
+ WAVEFORMATEX* m_pwfx; // Pointer to WAVEFORMATEX structure
+ HMMIO m_hmmio; // MM I/O handle for the WAVE
+ MMCKINFO m_ck; // Multimedia RIFF chunk
+ MMCKINFO m_ckRiff; // Use in opening a WAVE file
+ DWORD m_dwSize; // The size of the wave file
+ MMIOINFO m_mmioinfoOut;
+ DWORD m_dwFlags;
+ BOOL m_bIsReadingFromMemory;
+ BYTE* m_pbData;
+ BYTE* m_pbDataCur;
+ ULONG m_ulDataSize;
+
+protected:
+ HRESULT ReadMMIO();
+ HRESULT WriteMMIO( WAVEFORMATEX *pwfxDest );
+
+public:
+ CWaveFile();
+ ~CWaveFile();
+
+ HRESULT Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags );
+ HRESULT OpenFromMemory( BYTE* pbData, ULONG ulDataSize, WAVEFORMATEX* pwfx, DWORD dwFlags );
+ HRESULT Close();
+
+ HRESULT Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead );
+ HRESULT Write( UINT nSizeToWrite, BYTE* pbData, UINT* pnSizeWrote );
+
+ DWORD GetSize();
+ HRESULT ResetFile();
+ WAVEFORMATEX* GetFormat() { return m_pwfx; };
+};
+
+
+
+
+#endif // DSUTIL_H
diff --git a/V06/resource.h b/V06/resource.h
new file mode 100644
index 0000000..4043885
--- /dev/null
+++ b/V06/resource.h
@@ -0,0 +1,74 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Demo.rc
+//
+#define IDI_MAIN 101
+#define IDR_MENU 102
+#define IDR_ACCEL 103
+#define IDD_HILFE 124
+#define IDD_KONFIGURATION 125
+#define IDB_STEIN 126
+#define IDD_ULTRIS 129
+#define IDB_ULTRIS 130
+#define IDM_EXIT 1001
+#define IDC_ALLE 1005
+#define IDC_STANDARD 1006
+#define IDC_LOESCHEN 1007
+#define IDC_VORBELEGUNG 1008
+#define IDC_VORSCHAU 1009
+#define IDC_WEITERE_INFO 1018
+#define IDC_CHECK1 5000
+#define IDC_CHECK2 5001
+#define IDC_CHECK3 5002
+#define IDC_CHECK4 5003
+#define IDC_CHECK5 5004
+#define IDC_CHECK6 5005
+#define IDC_CHECK7 5006
+#define IDC_CHECK8 5007
+#define IDC_CHECK9 5008
+#define IDC_CHECK10 5009
+#define IDC_CHECK11 5010
+#define IDC_CHECK12 5011
+#define IDC_CHECK13 5012
+#define IDC_CHECK14 5013
+#define IDC_CHECK15 5014
+#define IDC_CHECK16 5015
+#define IDC_CHECK17 5016
+#define IDC_CHECK18 5017
+#define IDC_CHECK19 5018
+#define IDC_CHECK20 5019
+#define IDC_CHECK21 5020
+#define IDC_CHECK22 5021
+#define IDC_CHECK23 5022
+#define IDC_CHECK24 5023
+#define IDC_CHECK25 5024
+#define IDC_CHECK26 5025
+#define IDC_CHECK27 5026
+#define IDC_CHECK28 5027
+#define IDC_CHECK29 5028
+#define IDC_CHECK30 5029
+#define IDC_CHECK31 5030
+#define IDC_CHECK32 5031
+#define IDC_CHECK33 5032
+#define IDC_CHECK34 5033
+#define IDC_CHECK35 5034
+#define IDM_TEST 40024
+#define ID_ULTRIS_NEUESSPIEL 40025
+#define ID_ULTRIS_PAUSE 40026
+#define ID_ULTRIS_SOUND 40027
+#define ID_EINSTELLUNGEN_KONFIGURATION 40028
+#define ID_INFO_HILFE 40029
+#define ID_INFO_HIGHSCORES 40030
+#define ID_INFO_ULTRIS 40031
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 132
+#define _APS_NEXT_COMMAND_VALUE 40032
+#define _APS_NEXT_CONTROL_VALUE 1019
+#define _APS_NEXT_SYMED_VALUE 104
+#endif
+#endif
diff --git a/V06/ul_adeck.bmp b/V06/ul_adeck.bmp
new file mode 100644
index 0000000..5f3b867
Binary files /dev/null and b/V06/ul_adeck.bmp differ
diff --git a/V06/ul_down.wav b/V06/ul_down.wav
new file mode 100644
index 0000000..84cf9e1
Binary files /dev/null and b/V06/ul_down.wav differ
diff --git a/V06/ul_dreh.WAV b/V06/ul_dreh.WAV
new file mode 100644
index 0000000..790ef8c
Binary files /dev/null and b/V06/ul_dreh.WAV differ
diff --git a/V06/ul_ende.WAV b/V06/ul_ende.WAV
new file mode 100644
index 0000000..43c73f0
Binary files /dev/null and b/V06/ul_ende.WAV differ
diff --git a/V06/ul_feld.bmp b/V06/ul_feld.bmp
new file mode 100644
index 0000000..3225b6b
Binary files /dev/null and b/V06/ul_feld.bmp differ
diff --git a/V06/ul_hgrnd.bmp b/V06/ul_hgrnd.bmp
new file mode 100644
index 0000000..c33b077
Binary files /dev/null and b/V06/ul_hgrnd.bmp differ
diff --git a/V06/ul_move.WAV b/V06/ul_move.WAV
new file mode 100644
index 0000000..22b2a99
Binary files /dev/null and b/V06/ul_move.WAV differ
diff --git a/V06/ul_prev.bmp b/V06/ul_prev.bmp
new file mode 100644
index 0000000..c791074
Binary files /dev/null and b/V06/ul_prev.bmp differ
diff --git a/V06/ul_row1.WAV b/V06/ul_row1.WAV
new file mode 100644
index 0000000..ab5bfca
Binary files /dev/null and b/V06/ul_row1.WAV differ
diff --git a/V06/ul_row2.WAV b/V06/ul_row2.WAV
new file mode 100644
index 0000000..671fc71
Binary files /dev/null and b/V06/ul_row2.WAV differ
diff --git a/V06/ul_start.WAV b/V06/ul_start.WAV
new file mode 100644
index 0000000..f66bfef
Binary files /dev/null and b/V06/ul_start.WAV differ
diff --git a/V06/ul_stein.bmp b/V06/ul_stein.bmp
new file mode 100644
index 0000000..dadb7a0
Binary files /dev/null and b/V06/ul_stein.bmp differ
diff --git a/V06/ul_win.wav b/V06/ul_win.wav
new file mode 100644
index 0000000..e11c880
Binary files /dev/null and b/V06/ul_win.wav differ
diff --git a/V06/ul_z0.bmp b/V06/ul_z0.bmp
new file mode 100644
index 0000000..10fe8a6
Binary files /dev/null and b/V06/ul_z0.bmp differ
diff --git a/V06/ul_z1.bmp b/V06/ul_z1.bmp
new file mode 100644
index 0000000..1ce2939
Binary files /dev/null and b/V06/ul_z1.bmp differ
diff --git a/V06/ul_z2.bmp b/V06/ul_z2.bmp
new file mode 100644
index 0000000..9006084
Binary files /dev/null and b/V06/ul_z2.bmp differ
diff --git a/V06/ul_z3.bmp b/V06/ul_z3.bmp
new file mode 100644
index 0000000..5710c67
Binary files /dev/null and b/V06/ul_z3.bmp differ
diff --git a/V06/ul_z4.bmp b/V06/ul_z4.bmp
new file mode 100644
index 0000000..11306ed
Binary files /dev/null and b/V06/ul_z4.bmp differ
diff --git a/V06/ul_z5.bmp b/V06/ul_z5.bmp
new file mode 100644
index 0000000..b4a22b5
Binary files /dev/null and b/V06/ul_z5.bmp differ
diff --git a/V06/ul_z6.bmp b/V06/ul_z6.bmp
new file mode 100644
index 0000000..62616d4
Binary files /dev/null and b/V06/ul_z6.bmp differ
diff --git a/V06/ul_z7.bmp b/V06/ul_z7.bmp
new file mode 100644
index 0000000..d9178df
Binary files /dev/null and b/V06/ul_z7.bmp differ
diff --git a/V06/ul_z8.bmp b/V06/ul_z8.bmp
new file mode 100644
index 0000000..98e1a18
Binary files /dev/null and b/V06/ul_z8.bmp differ
diff --git a/V06/ul_z9.bmp b/V06/ul_z9.bmp
new file mode 100644
index 0000000..e6245a3
Binary files /dev/null and b/V06/ul_z9.bmp differ
diff --git a/V07/Demo.aps b/V07/Demo.aps
new file mode 100644
index 0000000..4cd726b
Binary files /dev/null and b/V07/Demo.aps differ
diff --git a/V07/Demo.cpp b/V07/Demo.cpp
new file mode 100644
index 0000000..ba884fb
--- /dev/null
+++ b/V07/Demo.cpp
@@ -0,0 +1,1031 @@
+# include
+# include
+# include
+# include
+# include "ddutil.h"
+# include "dsutil.h"
+# include "resource.h"
+
+const int ultris_nettobreite = 360; // Breite des Inneren des Haupfensters
+const int ultris_nettohoehe = 520; // Hoehe des Inneren des Hauptfensters
+int ultris_bruttobreite; // Breite des gesamten Haupfensters (incl. Rahmen)
+int ultris_bruttohoehe; // Hoehe des gesamten Haupfensters (incl. Rahmen)
+
+HINSTANCE ultris_instance; // Instanz der Ultris Applikation
+HWND ultris_window; // Das Hauptfenster von Ultris
+HMENU ultris_menu; // Das Menu von Ultris
+
+const int sound_start = 0; // Sound fuer neues Spiel
+const int sound_dreh = 1; // Sound bei Drehung
+const int sound_move = 2; // Sound bei rechts/links Bewegung
+const int sound_down = 3; // Sound bei Aufprall
+const int sound_row1 = 4; // Sound bei Abraeumen einer Reihe
+const int sound_row2 = 5; // Sound bei Abraeumen von mehreren Reihen
+const int sound_ende = 6; // Sound bei Spielende
+const int sound_win = 7; // Sound bei Eintrag in Highscore Tabelle
+const int anzahl_sounds = 8; // Anzahl Sounds
+
+char *soundfiles[anzahl_sounds] =
+ {
+ "ul_start.wav",
+ "ul_dreh.wav",
+ "ul_move.wav",
+ "ul_down.wav",
+ "ul_row1.wav",
+ "ul_row2.wav",
+ "ul_ende.wav",
+ "ul_win.wav"
+ };
+
+class sounds
+ {
+ private:
+ CSoundManager smgr;
+ CSound *snd[anzahl_sounds];
+ public:
+ int on;
+ sounds();
+ int init( HWND wnd);
+ void play( int snr);
+ ~sounds();
+ };
+
+sounds::sounds()
+ {
+ int i;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ snd[i] = 0;
+ on = 1;
+ }
+
+int sounds::init( HWND wnd)
+ {
+ HRESULT ret;
+ int i;
+
+ ret = smgr.Initialize( wnd, DSSCL_PRIORITY, 2, 22050, 16);
+ if( ret < 0)
+ return ret;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ {
+ ret = smgr.Create( snd+i, soundfiles[i]);
+ if( ret < 0)
+ return ret;
+ }
+ return S_OK;
+ }
+
+sounds::~sounds()
+ {
+ int i;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ {
+ if( snd[i])
+ delete snd[i];
+ }
+ }
+
+void sounds::play( int i)
+ {
+ if( !on)
+ return;
+ if( snd[i]->IsSoundPlaying())
+ {
+ snd[i]->Stop();
+ snd[i]->Reset();
+ }
+ snd[i]->Play(0,0);
+ }
+
+sounds ultris_sounds;
+
+class display
+ {
+ private:
+ CDisplay dsply;
+ CSurface *hgrnd;
+ CSurface *fldst;
+ CSurface *fllst;
+ CSurface *prvst;
+ CSurface *deckel;
+ CSurface *ziff[10];
+ public:
+ display();
+ void free_all();
+ ~display() {free_all();}
+ HRESULT init( HWND wnd);
+ void hintergrund() { dsply.Blt( 0, 0, hgrnd);}
+ void abdeckung() { dsply.Blt( 60, 0, deckel);}
+ void ziffer( int pos, int val) { dsply.Blt( 120+pos*20, 50, ziff[val]);}
+ void feldstein( int z, int s) { dsply.Blt( 80+s*20, 100+z*20, fldst);}
+ void fallstein( int z, int s, int offset) { dsply.Blt( 80+s*20, 100+z*20+offset, fllst);}
+ void prevstein( int p, int z, int s, int b, int h){ dsply.Blt( 290+s*15+(4-b)*15/2, 410-p*70+z*15+(4-h)*15/2, prvst);}
+ void update(){ dsply.UpdateBounds();}
+ HRESULT cooperative(){return dsply.GetDirectDraw()->TestCooperativeLevel();}
+ HRESULT restore();
+ HRESULT present();
+ };
+
+display::display()
+ {
+ int i;
+
+ hgrnd = 0;
+ fldst = 0;
+ fllst = 0;
+ prvst = 0;
+ deckel = 0;
+ for( i = 0; i < 10; i++)
+ ziff[i] = 0;
+ }
+
+void display::free_all()
+ {
+ int i;
+
+ if( hgrnd)
+ delete hgrnd;
+ if( fldst)
+ delete fldst;
+ if( fllst)
+ delete fllst;
+ if( prvst)
+ delete prvst;
+ if( deckel)
+ delete deckel;
+ for( i = 0; i < 10; i++)
+ {
+ if( ziff[i])
+ delete ziff[i];
+ }
+ }
+
+HRESULT display::init( HWND wnd)
+ {
+ HRESULT hr;
+ int i;
+ char fname[20];
+
+ hr = dsply.CreateWindowedDisplay( wnd, ultris_nettobreite, ultris_nettohoehe );
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &hgrnd, "ul_hgrnd.bmp", ultris_nettobreite, ultris_nettohoehe);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &fldst, "ul_feld.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &fllst, "ul_stein.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &prvst, "ul_prev.bmp", 15, 15);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &deckel, "ul_adeck.bmp", 240, 100);
+ if( hr < 0)
+ return hr;
+ for( i = 0; i < 10; i++)
+ {
+ sprintf( fname, "ul_z%d.bmp", i);
+ hr = dsply.CreateSurfaceFromBitmap( &ziff[i], fname, 20, 40);
+ if( hr < 0)
+ return hr;
+ }
+ return S_OK;
+ }
+
+HRESULT display::restore()
+ {
+ HRESULT hr;
+ int i;
+ char fname[20];
+
+ hr = dsply.GetDirectDraw()->RestoreAllSurfaces();
+ if( hr < 0)
+ return hr;
+ hr = hgrnd->DrawBitmap( "ul_hgrnd.bmp", ultris_nettobreite, ultris_nettohoehe);
+ if( hr < 0)
+ return hr;
+ hr = fldst->DrawBitmap( "ul_feld.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = fllst->DrawBitmap( "ul_stein.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = prvst->DrawBitmap( "ul_prev.bmp", 15, 15);
+ if( hr < 0)
+ return hr;
+ hr = deckel->DrawBitmap( "ul_adeck.bmp", 240, 100);
+ if( hr < 0)
+ return hr;
+
+ for( i = 0; i < 10; i++)
+ {
+ sprintf( fname, "ul_z%d.bmp", i);
+ hr = ziff[i]->DrawBitmap( fname, 20, 40);
+ if( hr < 0)
+ return hr;
+ }
+ MessageBox( ultris_window, "Surfaces restauriert", "Ultris-Fehlermeldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
+ return S_OK;
+ }
+
+HRESULT display::present()
+ {
+ HRESULT hr;
+
+ hr = dsply.Present();
+ if( hr == DDERR_SURFACELOST )
+ return restore();
+ return hr;
+ }
+
+display ultris_display;
+
+const int anzahl_formen = 35; // Anzahl der Formen
+
+//
+// Datenstruktur für die Formen
+//
+struct form
+ {
+ char h; // Hoehe
+ char b; // Breite
+ char data[4][4]; // Vorhandene Segmente
+ };
+
+// Form 1 in allen Drehvarianten
+//
+// *** * * *
+// * ** *** **
+// * *
+const form s_01_1 = {2, 3, {{1,1,1}, {0,1,0}}};
+const form s_01_2 = {3, 2, {{1,0}, {1,1}, {1,0}}};
+const form s_01_3 = {2, 3, {{0,1,0}, {1,1,1}}};
+const form s_01_4 = {3, 2, {{0,1}, {1,1}, {0,1}}};
+
+// Form 2 in allen Drehvarianten
+//
+// ** * ** *
+// ** ** ** **
+// * *
+const form s_02_1 = {2, 3, {{1,1,0}, {0,1,1}}};
+const form s_02_2 = {3, 2, {{0,1}, {1,1}, {1,0}}};
+const form s_02_3 = {2, 3, {{1,1,0}, {0,1,1}}};
+const form s_02_4 = {3, 2, {{0,1}, {1,1}, {1,0}}};
+
+// Form 3 in allen Drehvarianten
+//
+// ** * ** *
+// ** ** ** **
+// * *
+const form s_03_1 = {2, 3, {{0,1,1}, {1,1,0}}};
+const form s_03_2 = {3, 2, {{1,0}, {1,1}, {0,1}}};
+const form s_03_3 = {2, 3, {{0,1,1}, {1,1,0}}};
+const form s_03_4 = {3, 2, {{1,0}, {1,1}, {0,1}}};
+
+// Form 4 in allen Drehvarianten
+//
+// *** ** * *
+// * * *** *
+// * **
+const form s_04_1 = {2, 3, {{1,1,1}, {0,0,1}}};
+const form s_04_2 = {3, 2, {{1,1}, {1,0}, {1,0}}};
+const form s_04_3 = {2, 3, {{1,0,0}, {1,1,1}}};
+const form s_04_4 = {3, 2, {{0,1}, {0,1}, {1,1}}};
+
+// Form 5 in allen Drehvarianten
+//
+// * ** *** *
+// *** * * *
+// * **
+const form s_05_1 = {2, 3, {{0,0,1}, {1,1,1}}};
+const form s_05_2 = {3, 2, {{1,1}, {0,1}, {0,1}}};
+const form s_05_3 = {2, 3, {{1,1,1}, {1,0,0}}};
+const form s_05_4 = {3, 2, {{1,0}, {1,0}, {1,1}}};
+
+// Form 6 in allen Drehvarianten
+//
+// ** ** ** **
+// ** ** ** **
+//
+const form s_06_1 = {2, 2, {{1,1}, {1,1}}};
+const form s_06_2 = {2, 2, {{1,1}, {1,1}}};
+const form s_06_3 = {2, 2, {{1,1}, {1,1}}};
+const form s_06_4 = {2, 2, {{1,1}, {1,1}}};
+
+// Form 7 in allen Drehvarianten
+//
+// **** * **** *
+// * *
+// * *
+// * *
+const form s_07_1 = {1, 4, {{1,1,1,1}}};
+const form s_07_2 = {4, 1, {{1},{1},{1},{1}}};
+const form s_07_3 = {1, 4, {{1,1,1,1}}};
+const form s_07_4 = {4, 1, {{1},{1},{1},{1}}};
+
+// Form 8 in allen Drehvarianten
+//
+// *** ** * * **
+// * * * *** *
+// ** **
+const form s_08_1 = {2, 3, {{1,1,1}, {1,0,1}}};
+const form s_08_2 = {3, 2, {{1,1},{1,0},{1,1}}};
+const form s_08_3 = {2, 3, {{1,0,1}, {1,1,1}}};
+const form s_08_4 = {3, 2, {{1,1},{0,1},{1,1}}};
+
+// Form 9 in allen Drehvarianten
+//
+// ** * ** *
+// * *** * ***
+// ** * ** *
+const form s_09_1 = {3, 3, {{1,1,0}, {0,1,0}, {0,1,1}}};
+const form s_09_2 = {3, 3, {{0,0,1}, {1,1,1}, {1,0,0}}};
+const form s_09_3 = {3, 3, {{1,1,0}, {0,1,0}, {0,1,1}}};
+const form s_09_4 = {3, 3, {{0,0,1}, {1,1,1}, {1,0,0}}};
+
+// Form 10 in allen Drehvarianten
+//
+// ** ** * *
+// * * ** **
+//
+const form s_10_1 = {2, 2, {{1,1}, {0,1}}};
+const form s_10_2 = {2, 2, {{1,1}, {1,0}}};
+const form s_10_3 = {2, 2, {{1,0}, {1,1}}};
+const form s_10_4 = {2, 2, {{0,1}, {1,1}}};
+
+// Form 11 in allen Drehvarianten
+//
+// * * * *
+// *** *** *** ***
+// * * * *
+const form s_11_1 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+const form s_11_2 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+const form s_11_3 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+const form s_11_4 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+
+// Form 12 in allen Drehvarianten
+//
+// ** ** * ***
+// ** *** ** **
+// * **
+const form s_12_1 = {3, 2, {{1,1}, {1,1}, {1,0}}};
+const form s_12_2 = {2, 3, {{1,1,0}, {1,1,1}}};
+const form s_12_3 = {3, 2, {{0,1}, {1,1}, {1,1}}};
+const form s_12_4 = {2, 3, {{1,1,1}, {0,1,1}}};
+
+// Form 13 in allen Drehvarianten
+//
+// ** *** * **
+// ** ** ** ***
+// * **
+const form s_13_1 = {3, 2, {{1,1}, {1,1}, {0,1}}};
+const form s_13_2 = {2, 3, {{1,1,1}, {1,1,0}}};
+const form s_13_3 = {3, 2, {{1,0}, {1,1}, {1,1}}};
+const form s_13_4 = {2, 3, {{0,1,1}, {1,1,1}}};
+
+// Form 14 in allen Drehvarianten
+//
+// *** * * ***
+// * * * *
+// * *** *** *
+const form s_14_1 = {3, 3, {{1,1,1}, {1,0,0}, {1,0,0}}};
+const form s_14_2 = {3, 3, {{1,0,0}, {1,0,0}, {1,1,1}}};
+const form s_14_3 = {3, 3, {{0,0,1}, {0,0,1}, {1,1,1}}};
+const form s_14_4 = {3, 3, {{1,1,1}, {0,0,1}, {0,0,1}}};
+
+// Form 15 in allen Drehvarianten
+//
+// * * * *
+const form s_15_1 = {1, 1, {{1}}};
+const form s_15_2 = {1, 1, {{1}}};
+const form s_15_3 = {1, 1, {{1}}};
+const form s_15_4 = {1, 1, {{1}}};
+
+// Form 16 in allen Drehvarianten
+//
+// * * * *
+// * * * *
+const form s_16_1 = {2, 2, {{1,0}, {0,1}}};
+const form s_16_2 = {2, 2, {{0,1}, {1,0}}};
+const form s_16_3 = {2, 2, {{1,0}, {0,1}}};
+const form s_16_4 = {2, 2, {{0,1}, {1,0}}};
+
+// Form 17 in allen Drehvarianten
+//
+// * * * *
+// * * * *
+// * * * *
+const form s_17_1 = {3, 3, {{1,0,0}, {0,1,0}, {0,0,1}}};
+const form s_17_2 = {3, 3, {{0,0,1}, {0,1,0}, {1,0,0}}};
+const form s_17_3 = {3, 3, {{1,0,0}, {0,1,0}, {0,0,1}}};
+const form s_17_4 = {3, 3, {{0,0,1}, {0,1,0}, {1,0,0}}};
+
+// Form 18 in allen Drehvarianten
+//
+// * * * *
+// * * * * * * * *
+// * * * *
+const form s_18_1 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+const form s_18_2 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+const form s_18_3 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+const form s_18_4 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+
+// Form 19 in allen Drehvarianten
+//
+// * * * * *
+// * * * * *
+// * *
+const form s_19_1 = {2, 3, {{0,1,0}, {1,0,1}}};
+const form s_19_2 = {3, 2, {{0,1},{1,0},{0,1}}};
+const form s_19_3 = {2, 3, {{1,0,1}, {0,1,0}}};
+const form s_19_4 = {3, 2, {{1,0},{0,1},{1,0}}};
+
+// Form 20 in allen Drehvarianten
+//
+// *** * * *
+// * *** * ***
+// * * *** *
+const form s_20_1 = {3, 3, {{1,1,1}, {0,1,0}, {0,1,0}}};
+const form s_20_2 = {3, 3, {{1,0,0}, {1,1,1}, {1,0,0}}};
+const form s_20_3 = {3, 3, {{0,1,0}, {0,1,0}, {1,1,1}}};
+const form s_20_4 = {3, 3, {{0,0,1}, {1,1,1}, {0,0,1}}};
+
+// Form 21 in allen Drehvarianten
+//
+// * * * * *
+// * ** * **
+// * * * * *
+const form s_21_1 = {3, 3, {{1,0,1}, {0,1,0}, {0,1,0}}};
+const form s_21_2 = {3, 3, {{1,0,0}, {0,1,1}, {1,0,0}}};
+const form s_21_3 = {3, 3, {{0,1,0}, {0,1,0}, {1,0,1}}};
+const form s_21_4 = {3, 3, {{0,0,1}, {1,1,0}, {0,0,1}}};
+
+// Form 22 in allen Drehvarianten
+//
+// ** * ** *
+// * *
+//
+const form s_22_1 = {1, 2, {{1,1}}};
+const form s_22_2 = {2, 1, {{1},{1}}};
+const form s_22_3 = {1, 2, {{1,1}}};
+const form s_22_4 = {2, 1, {{1},{1}}};
+
+// Form 23 in allen Drehvarianten
+//
+// *** * *** *
+// * *
+// * *
+const form s_23_1 = {1, 3, {{1,1,1}}};
+const form s_23_2 = {3, 1, {{1},{1},{1}}};
+const form s_23_3 = {1, 3, {{1,1,1}}};
+const form s_23_4 = {3, 1, {{1},{1},{1}}};
+
+// Form 24 in allen Drehvarianten
+//
+// ** * * *
+// * * ** *
+// * *
+const form s_24_1 = {2, 3, {{1,1,0}, {0,0,1}}};
+const form s_24_2 = {3, 2, {{0,1}, {1,0}, {1,0}}};
+const form s_24_3 = {2, 3, {{1,0,0}, {0,1,1}}};
+const form s_24_4 = {3, 2, {{0,1}, {0,1}, {1,0}}};
+
+// Form 25 in allen Drehvarianten
+//
+// * * ** *
+// ** * * *
+// * *
+const form s_25_1 = {2, 3, {{0,0,1}, {1,1,0}}};
+const form s_25_2 = {3, 2, {{1,0}, {0,1}, {0,1}}};
+const form s_25_3 = {2, 3, {{0,1,1}, {1,0,0}}};
+const form s_25_4 = {3, 2, {{1,0}, {1,0}, {0,1}}};
+
+// Form 26 in allen Drehvarianten
+//
+// ** * ** *
+// ** * ** *
+// * *
+// * *
+const form s_26_1 = {2, 4, {{0,0,1,1}, {1,1,0,0}}};
+const form s_26_2 = {4, 2, {{1,0},{1,0},{0,1}, {0,1}}};
+const form s_26_3 = {2, 4, {{0,0,1,1}, {1,1,0,0}}};
+const form s_26_4 = {4, 2, {{1,0},{1,0},{0,1}, {0,1}}};
+
+// Form 27 in allen Drehvarianten
+//
+// ** * ** *
+// ** * ** *
+// * *
+// * *
+const form s_27_1 = {2, 4, {{1,1,0,0},{0,0,1,1}}};
+const form s_27_2 = {4, 2, {{0,1},{0,1},{1,0},{1,0}}};
+const form s_27_3 = {2, 4, {{1,1,0,0},{0,0,1,1}}};
+const form s_27_4 = {4, 2, {{0,1},{0,1},{1,0},{1,0}}};
+
+// Form 28 in allen Drehvarianten
+//
+// * * * ** *
+// ** * * * *
+// * *
+// * *
+const form s_28_1 = {2, 4, {{1,0,0,1},{0,1,1,0}}};
+const form s_28_2 = {4, 2, {{1,0},{0,1},{0,1},{1,0}}};
+const form s_28_3 = {2, 4, {{0,1,1,0},{1,0,0,1}}};
+const form s_28_4 = {4, 2, {{0,1},{1,0},{1,0},{0,1}}};
+
+// Form 29 in allen Drehvarianten
+//
+// ** * * **
+// * * * *
+// * ** ** *
+const form s_29_1 = {3, 3, {{0,1,1}, {1,0,0}, {1,0,0}}};
+const form s_29_2 = {3, 3, {{1,0,0}, {1,0,0}, {0,1,1}}};
+const form s_29_3 = {3, 3, {{0,0,1}, {0,0,1}, {1,1,0}}};
+const form s_29_4 = {3, 3, {{1,1,0}, {0,0,1}, {0,0,1}}};
+
+// Form 30 in allen Drehvarianten
+//
+// * ** * * **
+// * * * * * *
+// * * ** * **
+const form s_30_1 = {3, 3, {{0,1,0}, {1,0,1}, {1,0,1}}};
+const form s_30_2 = {3, 3, {{0,1,1}, {1,0,0}, {0,1,1}}};
+const form s_30_3 = {3, 3, {{1,0,1}, {1,0,1}, {0,1,0}}};
+const form s_30_4 = {3, 3, {{1,1,0}, {0,0,1}, {1,1,0}}};
+
+// Form 31 in allen Drehvarianten
+//
+// *** * * *
+// * * *** *
+// * *
+// * *
+const form s_31_1 = {2, 4, {{1,1,1,0},{0,0,0,1}}};
+const form s_31_2 = {4, 2, {{0,1},{1,0},{1,0},{1,0}}};
+const form s_31_3 = {2, 4, {{1,0,0,0},{0,1,1,1}}};
+const form s_31_4 = {4, 2, {{0,1},{0,1},{0,1},{1,0}}};
+
+// Form 32 in allen Drehvarianten
+//
+// * * *** *
+// *** * * *
+// * *
+// * *
+const form s_32_1 = {2, 4, {{0,0,0,1},{1,1,1,0}}};
+const form s_32_2 = {4, 2, {{1,0},{0,1},{0,1},{0,1}}};
+const form s_32_3 = {2, 4, {{0,1,1,1},{1,0,0,0}}};
+const form s_32_4 = {4, 2, {{1,0},{1,0},{1,0},{0,1}}};
+
+// Form 33 in allen Drehvarianten
+//
+// ** *** ** ***
+// ** *** ** ***
+// ** **
+const form s_33_1 = {3, 2, {{1,1}, {1,1}, {1,1}}};
+const form s_33_2 = {2, 3, {{1,1,1}, {1,1,1}}};
+const form s_33_3 = {3, 2, {{1,1}, {1,1}, {1,1}}};
+const form s_33_4 = {2, 3, {{1,1,1}, {1,1,1}}};
+
+// Form 34 in allen Drehvarianten
+//
+// **** * ** *
+// ** ** **** **
+// ** **
+// * *
+const form s_34_1 = {2, 4, {{1,1,1,1},{0,1,1,0}}};
+const form s_34_2 = {4, 2, {{1,0},{1,1},{1,1},{1,0}}};
+const form s_34_3 = {2, 4, {{0,1,1,0},{1,1,1,1}}};
+const form s_34_4 = {4, 2, {{0,1},{1,1},{1,1},{0,1}}};
+
+// Form 35 in allen Drehvarianten
+//
+// ** * ** *
+// * *** * ***
+// ** * ** *
+const form s_35_1 = {3, 3, {{0,1,1}, {0,1,0}, {1,1,0}}};
+const form s_35_2 = {3, 3, {{1,0,0}, {1,1,1}, {0,0,1}}};
+const form s_35_3 = {3, 3, {{0,1,1}, {0,1,0}, {1,1,0}}};
+const form s_35_4 = {3, 3, {{1,0,0}, {1,1,1}, {0,0,1}}};
+
+// Array mit allen Steinformen in allen Drehvarianten
+// Zugriff in der Form
+//
+// ultris_form[ steinform][ drehvariante]
+//
+// mit 0 <= steinform < 35 und 0 <= drehvariante <= 4
+
+const form *ultris_form[anzahl_formen][4] =
+ {
+ { &s_01_1, &s_01_2, &s_01_3, &s_01_4},
+ { &s_02_1, &s_02_2, &s_02_3, &s_02_4},
+ { &s_03_1, &s_03_2, &s_03_3, &s_03_4},
+ { &s_04_1, &s_04_2, &s_04_3, &s_04_4},
+ { &s_05_1, &s_05_2, &s_05_3, &s_05_4},
+ { &s_06_1, &s_06_2, &s_06_3, &s_06_4},
+ { &s_07_1, &s_07_2, &s_07_3, &s_07_4},
+ { &s_08_1, &s_08_2, &s_08_3, &s_08_4},
+ { &s_09_1, &s_09_2, &s_09_3, &s_09_4},
+ { &s_10_1, &s_10_2, &s_10_3, &s_10_4},
+ { &s_11_1, &s_11_2, &s_11_3, &s_11_4},
+ { &s_12_1, &s_12_2, &s_12_3, &s_12_4},
+ { &s_13_1, &s_13_2, &s_13_3, &s_13_4},
+ { &s_14_1, &s_14_2, &s_14_3, &s_14_4},
+ { &s_15_1, &s_15_2, &s_15_3, &s_15_4},
+ { &s_16_1, &s_16_2, &s_16_3, &s_16_4},
+ { &s_17_1, &s_17_2, &s_17_3, &s_17_4},
+ { &s_18_1, &s_18_2, &s_18_3, &s_18_4},
+ { &s_19_1, &s_19_2, &s_19_3, &s_19_4},
+ { &s_20_1, &s_20_2, &s_20_3, &s_20_4},
+ { &s_21_1, &s_21_2, &s_21_3, &s_21_4},
+ { &s_22_1, &s_22_2, &s_22_3, &s_22_4},
+ { &s_23_1, &s_23_2, &s_23_3, &s_23_4},
+ { &s_24_1, &s_24_2, &s_24_3, &s_24_4},
+ { &s_25_1, &s_25_2, &s_25_3, &s_25_4},
+ { &s_26_1, &s_26_2, &s_26_3, &s_26_4},
+ { &s_27_1, &s_27_2, &s_27_3, &s_27_4},
+ { &s_28_1, &s_28_2, &s_28_3, &s_28_4},
+ { &s_29_1, &s_29_2, &s_29_3, &s_29_4},
+ { &s_30_1, &s_30_2, &s_30_3, &s_30_4},
+ { &s_31_1, &s_31_2, &s_31_3, &s_31_4},
+ { &s_32_1, &s_32_2, &s_32_3, &s_32_4},
+ { &s_33_1, &s_33_2, &s_33_3, &s_33_4},
+ { &s_34_1, &s_34_2, &s_34_3, &s_34_4},
+ { &s_35_1, &s_35_2, &s_35_3, &s_35_4}
+ };
+
+
+// Array mit den aktuell im Spiel aktivierten Steinformen
+// Zu Programmstart sind dies die ueblichen Tetris Spielsteine (0-6)
+char aktive_formen[anzahl_formen] =
+ {
+ 1,1,1,1,1,1,1,
+ 0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0
+ };
+
+// Anzahl der aktuell aktivierten Steinformen
+int anz_aktive_formen = 7;
+
+
+// V7 Beginn
+class ultris
+ {
+ private:
+ int vorbelegung; // Anzahl der bei Spielbeginn vorzubelegenden Zeilen
+ int vorschau; // Anzahl der Formen in der Vorschau
+ int spielfeld[20][10]; // Das Spielfeld
+ int fuellstand[20]; // Der Fuellstand einer Reihe (= Anzahl Segmente in der Reihe)
+ int punktestand; // Der aktuelle Punktestand
+ void initialisieren();
+ void vorbelegen();
+ void display_spielfeld();
+ void display_punktestand();
+ public:
+ int spiel_laeuft; // Indikator, dass das Spiel laeuft
+ ultris(){ srand( GetTickCount()); initialisieren(); vorbelegung = 0; vorschau = 1;}
+ int get_vorbelegung() { return vorbelegung;}
+ void set_vorbelegung( int v) {if( v < 0) v = 0; if( v > 20) v = 20; vorbelegung = v;}
+ int get_vorschau() { return vorschau;}
+ void set_vorschau( int v) {if( v < 0) v = 0; if(v > 5) v = 5; vorschau = v;}
+ void start();
+ void display();
+ };
+
+void ultris::initialisieren()
+ {
+ int z, s;
+
+ for( z = 0; z < 20; z++)
+ {
+ fuellstand[z] = 0;
+ for( s = 0; s < 10; s++)
+ spielfeld[z][s] = 0;
+ }
+ spiel_laeuft = 0;
+ punktestand = 0;
+ }
+
+void ultris::vorbelegen()
+ {
+ int z, s, i;
+
+ for( i = 0; i < vorbelegung*5; i++)
+ {
+ z = 19-rand()%vorbelegung;
+ s = rand()%10;
+ if( !spielfeld[z][s])
+ {
+ spielfeld[z][s] = 1;
+ fuellstand[z]++;
+ }
+ }
+ punktestand = vorbelegung * 2500;
+ }
+
+void ultris::start()
+ {
+ ultris_sounds.play( sound_start);
+ initialisieren();
+ vorbelegen();
+ spiel_laeuft = 1;
+ }
+
+void ultris::display_spielfeld()
+ {
+ int z, s;
+
+ for( z = 0; z < 20; z++)
+ {
+ for( s = 0; s < 10; s++)
+ {
+ if( spielfeld[z][s])
+ ultris_display.feldstein( z, s);
+ }
+ }
+ }
+
+void ultris::display_punktestand()
+ {
+ int i, z, p;
+
+ for( i = 5, p = punktestand; i >= 0; i--, p/= 10)
+ {
+ z = p % 10;
+ ultris_display.ziffer( i, z);
+ }
+ }
+
+void ultris::display()
+ {
+ ultris_display.hintergrund();
+ display_spielfeld();
+ ultris_display.abdeckung();
+ display_punktestand();
+ ultris_display.present();
+ }
+
+
+// V7 Ende
+
+ultris mein_spiel;
+
+
+BOOL CALLBACK hilfedialog( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ switch (uMsg)
+ {
+ case WM_COMMAND:
+ if((wParam == IDOK)||(wParam == IDCANCEL))
+ {
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+BOOL CALLBACK ultrisdialog( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ switch (uMsg)
+ {
+ case WM_COMMAND:
+ if( wParam == IDC_WEITERE_INFO)
+ {
+ ShellExecute(NULL, "open", "http://www-et.bocholt.fh-gelsenkirchen.de", NULL, NULL, SW_SHOWNORMAL);
+ return TRUE;
+ }
+ if((wParam == IDOK)||(wParam == IDCANCEL))
+ {
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+BOOL CALLBACK konfigurationsdialog( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ int i;
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ for( i = 0; i < anzahl_formen; i++)
+ CheckDlgButton( hwndDlg, 5000+i, aktive_formen[i] ? BST_CHECKED : BST_UNCHECKED);
+ SetDlgItemInt( hwndDlg, IDC_VORBELEGUNG, mein_spiel.get_vorbelegung(), FALSE);
+ SetDlgItemInt( hwndDlg, IDC_VORSCHAU, mein_spiel.get_vorschau(), FALSE);
+ return TRUE;
+ case WM_COMMAND:
+ if(wParam == IDOK)
+ {
+ for( i = 0, anz_aktive_formen = 0; i < anzahl_formen; i++)
+ {
+ aktive_formen[i] = 0;
+ if(IsDlgButtonChecked( hwndDlg, 5000+i) == BST_CHECKED)
+ {
+ aktive_formen[i] = 1;
+ anz_aktive_formen++;
+ }
+ }
+ if( anz_aktive_formen == 0)
+ {
+ aktive_formen[0] = 1;
+ anz_aktive_formen = 1;
+ }
+ mein_spiel.set_vorbelegung( GetDlgItemInt( hwndDlg, IDC_VORBELEGUNG, NULL, FALSE));
+ mein_spiel.set_vorschau( GetDlgItemInt( hwndDlg, IDC_VORSCHAU, NULL, FALSE));
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ }
+ if(wParam == IDCANCEL)
+ {
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ }
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ switch( LOWORD(wParam))
+ {
+ case IDC_LOESCHEN:
+ for( i = 0; i < anzahl_formen; i++)
+ CheckDlgButton( hwndDlg, 5000+i, BST_UNCHECKED);
+ return TRUE;
+ case IDC_ALLE:
+ for( i = 0; i < anzahl_formen; i++)
+ CheckDlgButton( hwndDlg, 5000+i, BST_CHECKED);
+ return TRUE;
+ case IDC_STANDARD:
+ for( i = 0; i < anzahl_formen; i++)
+ CheckDlgButton( hwndDlg, 5000+i, i < 7 ? BST_CHECKED:BST_UNCHECKED);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+ }
+
+/*
+** ultris_windowhandler
+*/
+
+LRESULT CALLBACK ultris_windowhandler( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+ {
+ switch(msg)
+ {
+ case WM_COMMAND:
+ switch( LOWORD( wParam))
+ {
+ case IDM_EXIT:
+ PostMessage( hWnd, WM_CLOSE, 0, 0);
+ return 0;
+ case ID_ULTRIS_SOUND:
+ ultris_sounds.on = !ultris_sounds.on;
+ CheckMenuItem( ultris_menu, ID_ULTRIS_SOUND, ultris_sounds.on ? MF_CHECKED:MF_UNCHECKED);
+ return 0;
+ case ID_INFO_HILFE:
+ DialogBox( ultris_instance, MAKEINTRESOURCE( IDD_HILFE), ultris_window, hilfedialog);
+ return 0;
+ case ID_INFO_ULTRIS:
+ DialogBox( ultris_instance, MAKEINTRESOURCE( IDD_ULTRIS), ultris_window, ultrisdialog);
+ return 0;
+ case ID_EINSTELLUNGEN_KONFIGURATION:
+ DialogBox( ultris_instance, MAKEINTRESOURCE( IDD_KONFIGURATION), ultris_window, konfigurationsdialog);
+ return 0;
+// V7 Beginn
+ case ID_ULTRIS_NEUESSPIEL:
+ mein_spiel.start();
+ CheckMenuItem( ultris_menu, ID_ULTRIS_PAUSE, MF_UNCHECKED);
+ PostMessage( ultris_window, WM_PAINT, 0, 0);
+ break;
+// V7 Ende
+ case IDM_TEST: // Testcode
+ return 0;
+ }
+ break;
+ case WM_GETMINMAXINFO:
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.x = ((MINMAXINFO *)lParam)->ptMaxTrackSize.x = ultris_bruttobreite;
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.y = ((MINMAXINFO *)lParam)->ptMaxTrackSize.y = ultris_bruttohoehe;
+ return 0;
+ case WM_DESTROY:
+ PostQuitMessage( 0);
+ return 0;
+ case WM_MOVE:
+ ultris_display.update();
+ return 0;
+ case WM_PAINT:
+// V7 Beginn
+ mein_spiel.display();
+// V7 Ende
+ break;
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+ }
+
+/*
+** WinMain
+*/
+int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow)
+ {
+ MSG msg;
+ HACCEL acc;
+ WNDCLASSEX wcx;
+
+ ultris_instance = hInst;
+
+ wcx.cbSize = sizeof( wcx);
+ wcx.lpszClassName = TEXT( "Ultris");
+ wcx.lpfnWndProc = ultris_windowhandler;
+ wcx.style = CS_VREDRAW | CS_HREDRAW;
+ wcx.hInstance = hInst;
+ wcx.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hIconSm = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hCursor = LoadCursor( NULL, IDC_ARROW);
+ wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wcx.lpszMenuName = MAKEINTRESOURCE( IDR_MENU);
+ wcx.cbClsExtra = 0;
+ wcx.cbWndExtra = 0;
+
+ if( !RegisterClassEx( &wcx))
+ return 0;
+
+ acc = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_ACCEL));
+
+ ultris_bruttohoehe = ultris_nettohoehe + 2*GetSystemMetrics( SM_CYSIZEFRAME)
+ + GetSystemMetrics( SM_CYMENU)
+ + GetSystemMetrics( SM_CYCAPTION);
+ ultris_bruttobreite = ultris_nettobreite + 2*GetSystemMetrics( SM_CXSIZEFRAME);
+
+ ultris_window = CreateWindowEx( 0, TEXT( "Ultris"), TEXT( "Ultris"), WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ ultris_bruttobreite, ultris_bruttohoehe, NULL, NULL, hInst, NULL);
+ if( !ultris_window)
+ return 0;
+
+ ultris_menu = GetMenu( ultris_window);
+
+ if( ultris_sounds.init( ultris_window) < 0)
+ {
+ MessageBox( ultris_window, "Fehler beim Initialisieren der Sounds", "Ultris-Fehlermeldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
+ return 0;
+ }
+ CheckMenuItem( ultris_menu, ID_ULTRIS_SOUND, ultris_sounds.on ? MF_CHECKED:MF_UNCHECKED);
+
+ if( ultris_display.init( ultris_window) < 0)
+ {
+ MessageBox( ultris_window, "Fehler beim Initialisieren der Grafik", "Ultris-Fehlermeldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
+ return 0;
+ }
+
+ MoveWindow( ultris_window, (GetSystemMetrics(SM_CXSCREEN)-ultris_bruttobreite)/2,
+ (GetSystemMetrics(SM_CYSCREEN)-ultris_bruttohoehe)/2,
+ ultris_bruttobreite, ultris_bruttohoehe, TRUE);
+
+ ShowWindow( ultris_window, nCmdShow);
+
+ while( TRUE)
+ {
+ if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE))
+ {
+ if( GetMessage( &msg, NULL, 0, 0 ) == 0)
+ return 0; // Message ist WM_QUIT
+
+ if( TranslateAccelerator( ultris_window, acc, &msg) == 0)
+ {
+ TranslateMessage( &msg);
+ DispatchMessage( &msg);
+ }
+ }
+ else
+ {
+ HRESULT hr;
+ hr = ultris_display.cooperative();
+ if( hr < 0)
+ {
+ switch( hr )
+ {
+ case DDERR_EXCLUSIVEMODEALREADYSET:
+ Sleep(10);
+ break;
+ case DDERR_WRONGMODE:
+ ultris_display.free_all();
+ ultris_display.init( ultris_window);
+ PostMessage( ultris_window, WM_PAINT, 0, 0);
+ break;
+ }
+ }
+ else
+ {
+ // Hier koennen wir uns um das Spiel kuemmern
+ }
+ }
+ }
+ }
+
+
+
diff --git a/V07/Demo.h b/V07/Demo.h
new file mode 100644
index 0000000..a19fa69
--- /dev/null
+++ b/V07/Demo.h
@@ -0,0 +1,12 @@
+
+#if !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
+#define AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "resource.h"
+
+
+#endif // !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
diff --git a/V07/Demo.ncb b/V07/Demo.ncb
new file mode 100644
index 0000000..84ecc29
Binary files /dev/null and b/V07/Demo.ncb differ
diff --git a/V07/Demo.rc b/V07/Demo.rc
new file mode 100644
index 0000000..0425332
--- /dev/null
+++ b/V07/Demo.rc
@@ -0,0 +1,687 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include
+#include
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Deutsch (Deutschland) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+#ifdef _WIN32
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU MENU DISCARDABLE
+BEGIN
+ POPUP "Ultris"
+ BEGIN
+ MENUITEM "Neues Spiel", ID_ULTRIS_NEUESSPIEL
+ MENUITEM "Pause", ID_ULTRIS_PAUSE
+ MENUITEM "Sound", ID_ULTRIS_SOUND
+ MENUITEM SEPARATOR
+ MENUITEM "Ende", IDM_EXIT
+ END
+ POPUP "Einstellungen"
+ BEGIN
+ MENUITEM "Konfiguration", ID_EINSTELLUNGEN_KONFIGURATION
+
+ END
+ POPUP "Info"
+ BEGIN
+ MENUITEM "Hilfe", ID_INFO_HILFE
+ MENUITEM "Highscores", ID_INFO_HIGHSCORES
+ MENUITEM "Ultris", ID_INFO_ULTRIS
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MAIN ICON DISCARDABLE "Icon.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCEL ACCELERATORS DISCARDABLE
+BEGIN
+ "T", IDM_TEST, VIRTKEY, CONTROL, NOINVERT
+ VK_ESCAPE, IDM_EXIT, VIRTKEY, NOINVERT
+ VK_F1, ID_ULTRIS_NEUESSPIEL, VIRTKEY, NOINVERT
+ VK_F5, ID_ULTRIS_SOUND, VIRTKEY, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_HILFE DIALOG DISCARDABLE 0, 0, 302, 107
+STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Hilfe"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,245,90,50,14
+ LTEXT "F1: Neues Spiel",IDC_STATIC,15,22,130,8
+ LTEXT "F2: Pause (ein/aus)",IDC_STATIC,15,34,130,8
+ LTEXT "F3: Schneller",IDC_STATIC,15,46,130,8
+ LTEXT "F4: Langsamer",IDC_STATIC,15,58,130,8
+ LTEXT "F5: Sound (ein/aus)",IDC_STATIC,15,70,130,8
+ GROUPBOX "Steuerung des Spiels",IDC_STATIC,7,7,142,78
+ GROUPBOX "Steuerung der Steine",IDC_STATIC,153,7,142,78
+ LTEXT "J oder Cursor left: Links",IDC_STATIC,159,22,131,8
+ LTEXT "L oder Cursor right: Rechts",IDC_STATIC,159,34,131,8
+ LTEXT "K oder Cursor down: Linksdrehung",IDC_STATIC,159,46,131,
+ 8
+ LTEXT "I oder Cursor up: Rechtsdrehung",IDC_STATIC,159,58,131,
+ 8
+ LTEXT "Space: Stein fallen lassen",IDC_STATIC,159,70,126,8
+END
+
+IDD_ULTRIS DIALOG DISCARDABLE 0, 0, 204, 142
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Über Ultris"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,150,125,50,14
+ CONTROL 130,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_SUNKEN | WS_BORDER,7,7,190,78
+ CTEXT "Demoprogramm\rzur Vorlesung\rGrafik und Spieleprogrammierung",
+ IDC_STATIC,7,92,195,28
+ PUSHBUTTON "Weitere Informationen",IDC_WEITERE_INFO,5,125,140,14
+END
+
+IDD_KONFIGURATION DIALOGEX 0, 0, 289, 297
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Einstellungen"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,235,280,50,14
+ PUSHBUTTON "Abbrechen",IDCANCEL,180,280,50,14
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,10,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,30,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,20,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,20,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE | WS_BORDER,50,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE | WS_BORDER,60,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE | WS_BORDER,60,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE | WS_BORDER,70,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,110,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,90,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,150,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,170,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,180,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,190,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,190,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,215,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,225,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,215,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,225,30,10,10
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,40,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,10,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,50,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,60,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,70,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,70,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,20,65,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,95,65,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,105,65,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,95,75,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,10,65,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,30,65,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,10,75,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,30,75,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,50,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,150,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,230,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,25,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,215,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,225,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,215,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,225,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,225,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,55,125,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,65,115,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,110,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,185,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,90,130,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,130,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,185,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,20,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,150,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,130,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,170,125,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,180,115,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,190,125,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,70,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,210,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,130,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,230,160,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,190,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,50,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,60,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,170,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,110,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,90,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,15,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,180,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,150,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,230,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,190,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,170,160,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,180,190,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,160,10,10
+ CONTROL "",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,
+ 43,8,8
+ CONTROL "",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,74,
+ 43,8,8
+ CONTROL "",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,
+ 43,8,8
+ CONTROL "10",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 154,43,8,8
+ CONTROL "",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,
+ 43,8,8
+ CONTROL "",IDC_CHECK6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,234,
+ 43,8,8
+ CONTROL "6",IDC_CHECK7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,274,
+ 43,8,8
+ CONTROL "",IDC_CHECK8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,
+ 93,8,8
+ CONTROL "",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,74,
+ 93,8,8
+ CONTROL "",IDC_CHECK10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,
+ 93,8,8
+ CONTROL "",IDC_CHECK11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,
+ 93,8,8
+ CONTROL "",IDC_CHECK12,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,
+ 93,8,8
+ CONTROL "",IDC_CHECK13,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,234,
+ 93,8,8
+ CONTROL "20",IDC_CHECK14,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 274,93,8,8
+ CONTROL "",IDC_CHECK15,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,
+ 143,8,8
+ CONTROL "",IDC_CHECK16,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,74,
+ 143,8,8
+ CONTROL "",IDC_CHECK17,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,
+ 143,8,8
+ CONTROL "",IDC_CHECK18,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,
+ 143,8,8
+ CONTROL "",IDC_CHECK19,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,
+ 143,8,8
+ CONTROL "",IDC_CHECK20,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,234,
+ 143,8,8
+ CONTROL "",IDC_CHECK21,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,274,
+ 143,8,8
+ CONTROL "",IDC_CHECK22,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,
+ 193,8,8
+ CONTROL "",IDC_CHECK23,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,74,
+ 193,8,8
+ CONTROL "",IDC_CHECK24,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,
+ 193,8,8
+ CONTROL "",IDC_CHECK25,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,
+ 193,8,8
+ CONTROL "",IDC_CHECK26,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,
+ 193,8,8
+ CONTROL "",IDC_CHECK27,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,234,
+ 193,8,8
+ CONTROL "",IDC_CHECK28,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,274,
+ 193,8,8
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,45,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,85,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,125,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,165,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,205,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,245,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,45,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,85,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,125,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,165,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,205,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,245,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,45,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,85,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,125,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,165,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,205,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,245,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,45,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,85,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,125,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,165,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,205,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,245,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,30,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,50,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,185,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,10,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,10,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,110,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,50,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,70,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,185,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,70,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,240,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,20,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,185,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,240,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,210,10,10
+ CONTROL "",IDC_CHECK29,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,
+ 243,8,8
+ CONTROL "",IDC_CHECK30,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,74,
+ 243,8,8
+ CONTROL "",IDC_CHECK31,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,
+ 243,8,8
+ CONTROL "",IDC_CHECK32,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,
+ 243,8,8
+ CONTROL "",IDC_CHECK33,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,
+ 243,8,8
+ CONTROL "",IDC_CHECK34,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,234,
+ 243,8,8
+ CONTROL "",IDC_CHECK35,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,274,
+ 243,8,8
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,45,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,85,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,125,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,165,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,205,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,245,205,40,50,
+ WS_EX_DLGMODALFRAME
+ PUSHBUTTON "Alle auswählen",IDC_ALLE,235,260,50,14
+ PUSHBUTTON "Standard",IDC_STANDARD,180,260,50,14
+ PUSHBUTTON "Alle Löschen",IDC_LOESCHEN,125,260,50,14
+ EDITTEXT IDC_VORBELEGUNG,105,260,15,14,ES_RIGHT | ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "Vorbelegte Zeilen bei Spielstart:",IDC_STATIC,5,260,95,
+ 13,SS_CENTERIMAGE
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,240,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,230,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,230,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,60,210,10,10
+ LTEXT "1",IDC_STATIC,11,143,8,8
+ LTEXT "2",IDC_STATIC,10,193,8,8
+ LTEXT "4",IDC_STATIC,50,193,8,8
+ LTEXT "6",IDC_STATIC,250,43,8,8
+ LTEXT "8",IDC_STATIC,10,43,8,8
+ LTEXT "10",IDC_STATIC,130,43,8,8
+ LTEXT "10",IDC_STATIC,170,43,8,8
+ LTEXT "12",IDC_STATIC,50,43,8,8
+ LTEXT "12",IDC_STATIC,90,43,8,8
+ LTEXT "10",IDC_STATIC,210,43,8,8
+ LTEXT "25",IDC_STATIC,10,93,8,8
+ LTEXT "25",IDC_STATIC,50,93,8,8
+ LTEXT "4",IDC_STATIC,90,93,8,8
+ LTEXT "20",IDC_STATIC,130,93,8,8
+ LTEXT "10",IDC_STATIC,170,93,8,8
+ LTEXT "10",IDC_STATIC,210,93,8,8
+ LTEXT "20",IDC_STATIC,250,93,8,8
+ LTEXT "8",IDC_STATIC,50,143,8,8
+ LTEXT "25",IDC_STATIC,90,143,8,8
+ LTEXT "40",IDC_STATIC,130,143,8,8
+ LTEXT "15",IDC_STATIC,170,143,8,8
+ LTEXT "25",IDC_STATIC,210,143,8,8
+ LTEXT "35",IDC_STATIC,250,143,8,8
+ LTEXT "10",IDC_STATIC,90,193,8,8
+ LTEXT "10",IDC_STATIC,130,193,8,8
+ LTEXT "20",IDC_STATIC,170,193,8,8
+ LTEXT "20",IDC_STATIC,210,193,8,8
+ LTEXT "25",IDC_STATIC,250,193,8,8
+ LTEXT "25",IDC_STATIC,10,243,8,8
+ LTEXT "30",IDC_STATIC,50,243,8,8
+ LTEXT "25",IDC_STATIC,90,243,8,8
+ LTEXT "25",IDC_STATIC,130,243,8,8
+ LTEXT "10",IDC_STATIC,170,243,8,8
+ LTEXT "15",IDC_STATIC,210,243,8,8
+ LTEXT "25",IDC_STATIC,250,243,8,8
+ EDITTEXT IDC_VORSCHAU,105,280,15,14,ES_RIGHT | ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "Steine in der Vorschau:",IDC_STATIC,5,280,95,13,
+ SS_CENTERIMAGE
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_HILFE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 295
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 100
+ END
+
+ IDD_ULTRIS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 197
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 135
+ END
+
+ IDD_KONFIGURATION, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 282
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 290
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_ULTRIS BITMAP DISCARDABLE "bmp00001.bmp"
+IDB_STEIN BITMAP DISCARDABLE "bmp00002.bmp"
+#endif // Deutsch (Deutschland) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Englisch (USA) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include \r\n"
+ "#include \0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Englisch (USA) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/V07/Demo.sln b/V07/Demo.sln
new file mode 100644
index 0000000..7980bdf
--- /dev/null
+++ b/V07/Demo.sln
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo.vcproj", "{48CC8A7D-E3EA-4AAD-9E36-3DB12B1919C0}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {48CC8A7D-E3EA-4AAD-9E36-3DB12B1919C0}.Debug.ActiveCfg = Debug|Win32
+ {48CC8A7D-E3EA-4AAD-9E36-3DB12B1919C0}.Debug.Build.0 = Debug|Win32
+ {48CC8A7D-E3EA-4AAD-9E36-3DB12B1919C0}.Release.ActiveCfg = Release|Win32
+ {48CC8A7D-E3EA-4AAD-9E36-3DB12B1919C0}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/V07/Demo.suo b/V07/Demo.suo
new file mode 100644
index 0000000..70048d4
Binary files /dev/null and b/V07/Demo.suo differ
diff --git a/V07/Demo.vcproj b/V07/Demo.vcproj
new file mode 100644
index 0000000..98ce341
--- /dev/null
+++ b/V07/Demo.vcproj
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V07/Icon.ico b/V07/Icon.ico
new file mode 100644
index 0000000..7a53f63
Binary files /dev/null and b/V07/Icon.ico differ
diff --git a/V07/bmp00001.bmp b/V07/bmp00001.bmp
new file mode 100644
index 0000000..12d2027
Binary files /dev/null and b/V07/bmp00001.bmp differ
diff --git a/V07/bmp00002.bmp b/V07/bmp00002.bmp
new file mode 100644
index 0000000..92b8396
Binary files /dev/null and b/V07/bmp00002.bmp differ
diff --git a/V07/ddutil.cpp b/V07/ddutil.cpp
new file mode 100644
index 0000000..faccc24
--- /dev/null
+++ b/V07/ddutil.cpp
@@ -0,0 +1,1035 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: DirectDraw framewark classes. Feel free to use this class as a
+// starting point for adding extra functionality.
+//
+//
+// Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include
+#include "ddutil.h"
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::CDisplay()
+{
+ m_pDD = NULL;
+ m_pddsFrontBuffer = NULL;
+ m_pddsBackBuffer = NULL;
+ m_pddsBackBufferLeft = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ~CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::~CDisplay()
+{
+ DestroyObjects();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DestroyObjects()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::DestroyObjects()
+{
+ SAFE_RELEASE( m_pddsBackBufferLeft );
+ SAFE_RELEASE( m_pddsBackBuffer );
+ SAFE_RELEASE( m_pddsFrontBuffer );
+
+ if( m_pDD )
+ m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL );
+
+ SAFE_RELEASE( m_pDD );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateFullScreenDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth,
+ DWORD dwHeight, DWORD dwBPP )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ // Set the display mode
+ if( FAILED( m_pDD->SetDisplayMode( dwWidth, dwHeight, dwBPP, 0, 0 ) ) )
+ return E_FAIL;
+
+ // Create primary surface (with backbuffer attached)
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
+ DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE;
+ ddsd.dwBackBufferCount = 1;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer,
+ NULL ) ) )
+ return E_FAIL;
+
+ // Get a pointer to the back buffer
+ DDSCAPS2 ddscaps;
+ ZeroMemory( &ddscaps, sizeof( ddscaps ) );
+ ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
+
+ if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
+ &m_pddsBackBuffer ) ) )
+ return E_FAIL;
+
+ m_pddsBackBuffer->AddRef();
+
+ m_hWnd = hWnd;
+ m_bWindowed = FALSE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateWindowedDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_NORMAL );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ RECT rcWork;
+ RECT rc;
+ DWORD dwStyle;
+
+ // If we are still a WS_POPUP window we should convert to a normal app
+ // window so we look like a windows app.
+ dwStyle = GetWindowStyle( hWnd );
+ dwStyle &= ~WS_POPUP;
+ dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
+ SetWindowLong( hWnd, GWL_STYLE, dwStyle );
+
+ // Aet window size
+ SetRect( &rc, 0, 0, dwWidth, dwHeight );
+
+ AdjustWindowRectEx( &rc, GetWindowStyle(hWnd), GetMenu(hWnd) != NULL,
+ GetWindowExStyle(hWnd) );
+
+ SetWindowPos( hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
+ SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
+
+ // Make sure our window does not hang outside of the work area
+ SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWork, 0 );
+ GetWindowRect( hWnd, &rc );
+ if( rc.left < rcWork.left ) rc.left = rcWork.left;
+ if( rc.top < rcWork.top ) rc.top = rcWork.top;
+ SetWindowPos( hWnd, NULL, rc.left, rc.top, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ LPDIRECTDRAWCLIPPER pcClipper;
+
+ // Create the primary surface
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+ if( FAILED( m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
+ return E_FAIL;
+
+ // Create the backbuffer surface
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = pcClipper->SetHWnd( 0, hWnd ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pcClipper ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ // Done with clipper
+ pcClipper->Release();
+
+ m_hWnd = hWnd;
+ m_bWindowed = TRUE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurface( CSurface** ppSurface,
+ DWORD dwWidth, DWORD dwHeight )
+{
+ if( NULL == m_pDD )
+ return E_POINTER;
+ if( NULL == ppSurface )
+ return E_INVALIDARG;
+
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromBitmap()
+// Desc: Create a DirectDrawSurface from a bitmap resource or bitmap file.
+// Use MAKEINTRESOURCE() to pass a constant into strBMP.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromBitmap( CSurface** ppSurface,
+ TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight )
+{
+ HRESULT hr;
+ HBITMAP hBMP = NULL;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+
+ if( m_pDD == NULL || strBMP == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = bmp.bmWidth;
+ ddsd.dwHeight = bmp.bmHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = (*ppSurface)->DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromText()
+// Desc: Creates a DirectDrawSurface from a text string using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromText( CSurface** ppSurface,
+ HFONT hFont, TCHAR* strText,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ LPDIRECTDRAWSURFACE7 pDDS = NULL;
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ SIZE sizeText;
+
+ if( m_pDD == NULL || strText == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ hDC = GetDC( NULL );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ GetTextExtentPoint32( hDC, strText, _tcslen(strText), &sizeText );
+ ReleaseDC( NULL, hDC );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = sizeText.cx;
+ ddsd.dwHeight = sizeText.cy;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ if( FAILED( hr = (*ppSurface)->DrawText( hFont, strText, 0, 0,
+ crBackground, crForeground ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Present()
+{
+ HRESULT hr;
+
+ if( NULL == m_pddsFrontBuffer && NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ while( 1 )
+ {
+ if( m_bWindowed )
+ hr = m_pddsFrontBuffer->Blt( &m_rcWindow, m_pddsBackBuffer,
+ NULL, DDBLT_WAIT, NULL );
+ else
+ hr = m_pddsFrontBuffer->Flip( NULL, 0 );
+
+ if( hr == DDERR_SURFACELOST )
+ {
+ m_pddsFrontBuffer->Restore();
+ m_pddsBackBuffer->Restore();
+ }
+
+ if( hr != DDERR_WASSTILLDRAWING )
+ return hr;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer || NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Set the palette before loading the bitmap
+ if( pPalette )
+ m_pddsFrontBuffer->SetPalette( pPalette );
+
+ CSurface backBuffer;
+ backBuffer.Create( m_pddsBackBuffer );
+
+ if( FAILED( backBuffer.DrawBitmap( hbm, 0, 0, 0, 0 ) ) )
+ return E_FAIL;
+
+ return Present();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, DDBLTFAST_SRCCOLORKEY );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds, RECT* prc,
+ DWORD dwFlags )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc )
+{
+ if( NULL == pSurface )
+ return E_INVALIDARG;
+
+ if( pSurface->IsColorKeyed() )
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, DDBLTFAST_SRCCOLORKEY );
+ else
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Clear( DWORD dwColor )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Erase the background
+ DDBLTFX ddbltfx;
+ ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
+ ddbltfx.dwSize = sizeof(ddbltfx);
+ ddbltfx.dwFillColor = dwColor;
+
+ return m_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::SetPalette( LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer )
+ return E_POINTER;
+
+ return m_pddsFrontBuffer->SetPalette( pPalette );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette,
+ const TCHAR* strBMP )
+{
+ HRSRC hResource = NULL;
+ RGBQUAD* pRGB = NULL;
+ BITMAPINFOHEADER* pbi = NULL;
+ PALETTEENTRY aPalette[256];
+ HANDLE hFile = NULL;
+ DWORD iColor;
+ DWORD dwColors;
+ BITMAPFILEHEADER bf;
+ BITMAPINFOHEADER bi;
+ DWORD dwBytesRead;
+
+ if( m_pDD == NULL || strBMP == NULL || ppPalette == NULL )
+ return E_INVALIDARG;
+
+ *ppPalette = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hResource = FindResource( NULL, strBMP, RT_BITMAP );
+ if( hResource )
+ {
+ pbi = (LPBITMAPINFOHEADER) LockResource( LoadResource( NULL, hResource ) );
+ if( NULL == pbi )
+ return E_FAIL;
+
+ pRGB = (RGBQUAD*) ( (BYTE*) pbi + pbi->biSize );
+
+ // Figure out how many colors there are
+ if( pbi == NULL || pbi->biSize < sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if( pbi->biBitCount > 8 )
+ dwColors = 0;
+ else if( pbi->biClrUsed == 0 )
+ dwColors = 1 << pbi->biBitCount;
+ else
+ dwColors = pbi->biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around.
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ aPalette[iColor].peRed = pRGB[iColor].rgbRed;
+ aPalette[iColor].peGreen = pRGB[iColor].rgbGreen;
+ aPalette[iColor].peBlue = pRGB[iColor].rgbBlue;
+ aPalette[iColor].peFlags = 0;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+ }
+
+ // Attempt to load bitmap as a file
+ hFile = CreateFile( strBMP, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
+ if( NULL == hFile )
+ return E_FAIL;
+
+ // Read the BITMAPFILEHEADER
+ ReadFile( hFile, &bf, sizeof(bf), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bf) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the BITMAPINFOHEADER
+ ReadFile( hFile, &bi, sizeof(bi), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bi) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the PALETTEENTRY
+ ReadFile( hFile, aPalette, sizeof(aPalette), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(aPalette) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ CloseHandle( hFile );
+
+ // Figure out how many colors there are
+ if( bi.biSize != sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if (bi.biBitCount > 8)
+ dwColors = 0;
+ else if (bi.biClrUsed == 0)
+ dwColors = 1 << bi.biBitCount;
+ else
+ dwColors = bi.biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around since DirectDraw uses RGB
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ BYTE r = aPalette[iColor].peRed;
+ aPalette[iColor].peRed = aPalette[iColor].peBlue;
+ aPalette[iColor].peBlue = r;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::UpdateBounds()
+{
+ if( m_bWindowed )
+ {
+ GetClientRect( m_hWnd, &m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow+1 );
+ }
+ else
+ {
+ SetRect( &m_rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN) );
+ }
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::InitClipper
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::InitClipper()
+{
+ LPDIRECTDRAWCLIPPER pClipper;
+ HRESULT hr;
+
+ // Create a clipper when using GDI to draw on the primary surface
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pClipper, NULL ) ) )
+ return hr;
+
+ pClipper->SetHWnd( 0, m_hWnd );
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pClipper ) ) )
+ return hr;
+
+ // We can release the clipper now since g_pDDSPrimary
+ // now maintains a ref count on the clipper
+ SAFE_RELEASE( pClipper );
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::CSurface()
+{
+ m_pdds = NULL;
+ m_bColorKeyed = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::~CSurface()
+{
+ SAFE_RELEASE( m_pdds );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAWSURFACE7 pdds )
+{
+ m_pdds = pdds;
+
+ if( m_pdds )
+ {
+ m_pdds->AddRef();
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_ddsd.dwSize = sizeof(m_ddsd);
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd )
+{
+ HRESULT hr;
+
+ // Create the DDraw surface
+ if( FAILED( hr = pDD->CreateSurface( pddsd, &m_pdds, NULL ) ) )
+ return hr;
+
+ // Prepare the DDSURFACEDESC structure
+ m_ddsd.dwSize = sizeof(m_ddsd);
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Destroy()
+{
+ SAFE_RELEASE( m_pdds );
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawBitmap()
+// Desc: Draws a bitmap over an entire DirectDrawSurface, stretching the
+// bitmap if nessasary
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( HBITMAP hBMP,
+ DWORD dwBMPOriginX, DWORD dwBMPOriginY,
+ DWORD dwBMPWidth, DWORD dwBMPHeight )
+{
+ HDC hDCImage;
+ HDC hDC;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ if( hBMP == NULL || m_pdds == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ // Get the surface.description
+ ddsd.dwSize = sizeof(ddsd);
+ m_pdds->GetSurfaceDesc( &ddsd );
+
+ if( ddsd.ddpfPixelFormat.dwFlags == DDPF_FOURCC )
+ return E_NOTIMPL;
+
+ // Select bitmap into a memoryDC so we can use it.
+ hDCImage = CreateCompatibleDC( NULL );
+ if( NULL == hDCImage )
+ return E_FAIL;
+
+ SelectObject( hDCImage, hBMP );
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Use the passed size, unless zero
+ dwBMPWidth = ( dwBMPWidth == 0 ) ? bmp.bmWidth : dwBMPWidth;
+ dwBMPHeight = ( dwBMPHeight == 0 ) ? bmp.bmHeight : dwBMPHeight;
+
+ // Stretch the bitmap to cover this surface
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ StretchBlt( hDC, 0, 0,
+ ddsd.dwWidth, ddsd.dwHeight,
+ hDCImage, dwBMPOriginX, dwBMPOriginY,
+ dwBMPWidth, dwBMPHeight, SRCCOPY );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ DeleteDC( hDCImage );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawText()
+// Desc: Draws a text string on a DirectDraw surface using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawText( HFONT hFont, TCHAR* strText,
+ DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strText == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ // Set the background and foreground color
+ SetBkColor( hDC, crBackground );
+ SetTextColor( hDC, crForeground );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ // Use GDI to draw the text on the surface
+ TextOut( hDC, dwOriginX, dwOriginY, strText, _tcslen(strText) );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ReDrawBitmapOnSurface()
+// Desc: Load a bitmap from a file or resource into a DirectDraw surface.
+// normaly used to re-load a surface after a restore.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( TCHAR* strBMP,
+ DWORD dwDesiredWidth, DWORD dwDesiredHeight )
+{
+ HBITMAP hBMP;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strBMP == NULL )
+ return E_INVALIDARG;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP, IMAGE_BITMAP,
+ dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::SetColorKey( DWORD dwColorKey )
+{
+ if( NULL == m_pdds )
+ return E_POINTER;
+
+ m_bColorKeyed = TRUE;
+
+ DDCOLORKEY ddck;
+ ddck.dwColorSpaceLowValue = ConvertGDIColor( dwColorKey );
+ ddck.dwColorSpaceHighValue = ConvertGDIColor( dwColorKey );
+
+ return m_pdds->SetColorKey( DDCKEY_SRCBLT, &ddck );
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ConvertGDIColor()
+// Desc: Converts a GDI color (0x00bbggrr) into the equivalent color on a
+// DirectDrawSurface using its pixel format.
+//-----------------------------------------------------------------------------
+DWORD CSurface::ConvertGDIColor( COLORREF dwGDIColor )
+{
+ if( m_pdds == NULL )
+ return 0x00000000;
+
+ COLORREF rgbT;
+ HDC hdc;
+ DWORD dw = CLR_INVALID;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ // Use GDI SetPixel to color match for us
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK)
+ {
+ rgbT = GetPixel(hdc, 0, 0); // Save current pixel value
+ SetPixel(hdc, 0, 0, dwGDIColor); // Set our value
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ // Now lock the surface so we can read back the converted color
+ ddsd.dwSize = sizeof(ddsd);
+ hr = m_pdds->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
+ if( hr == DD_OK)
+ {
+ dw = *(DWORD *) ddsd.lpSurface;
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount < 32 ) // Mask it to bpp
+ dw &= ( 1 << ddsd.ddpfPixelFormat.dwRGBBitCount ) - 1;
+ m_pdds->Unlock(NULL);
+ }
+
+ // Now put the color that was there back.
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK )
+ {
+ SetPixel( hdc, 0, 0, rgbT );
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ return dw;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::GetBitMaskInfo()
+// Desc: Returns the number of bits and the shift in the bit mask
+//-----------------------------------------------------------------------------
+HRESULT CSurface::GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits )
+{
+ DWORD dwShift = 0;
+ DWORD dwBits = 0;
+
+ if( pdwShift == NULL || pdwBits == NULL )
+ return E_INVALIDARG;
+
+ if( dwBitMask )
+ {
+ while( (dwBitMask & 1) == 0 )
+ {
+ dwShift++;
+ dwBitMask >>= 1;
+ }
+ }
+
+ while( (dwBitMask & 1) != 0 )
+ {
+ dwBits++;
+ dwBitMask >>= 1;
+ }
+
+ *pdwShift = dwShift;
+ *pdwBits = dwBits;
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V07/ddutil.h b/V07/ddutil.h
new file mode 100644
index 0000000..61fb0be
--- /dev/null
+++ b/V07/ddutil.h
@@ -0,0 +1,140 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: Routines for loading bitmap and palettes from resources
+//
+// Copyright (C) 1998-1999 Microsoft Corporation. All Rights Reserved.
+//-----------------------------------------------------------------------------
+#ifndef DDUTIL_H
+#define DDUTIL_H
+
+#include
+#include
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes defined in this header file
+//-----------------------------------------------------------------------------
+class CDisplay;
+class CSurface;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Flags for the CDisplay and CSurface methods
+//-----------------------------------------------------------------------------
+#define DSURFACELOCK_READ
+#define DSURFACELOCK_WRITE
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CDisplay
+// Desc: Class to handle all DDraw aspects of a display, including creation of
+// front and back buffers, creating offscreen surfaces and palettes,
+// and blitting surface and displaying bitmaps.
+//-----------------------------------------------------------------------------
+class CDisplay
+{
+protected:
+ LPDIRECTDRAW7 m_pDD;
+ LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBufferLeft; // For stereo modes
+
+ HWND m_hWnd;
+ RECT m_rcWindow;
+ BOOL m_bWindowed;
+ BOOL m_bStereo;
+
+public:
+ CDisplay();
+ ~CDisplay();
+
+ // Access functions
+ HWND GetHWnd() { return m_hWnd; }
+ LPDIRECTDRAW7 GetDirectDraw() { return m_pDD; }
+ LPDIRECTDRAWSURFACE7 GetFrontBuffer() { return m_pddsFrontBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBuffer() { return m_pddsBackBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBufferLEft() { return m_pddsBackBufferLeft; }
+
+ // Status functions
+ BOOL IsWindowed() { return m_bWindowed; }
+ BOOL IsStereo() { return m_bStereo; }
+
+ // Creation/destruction methods
+ HRESULT CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight,
+ DWORD dwBPP );
+ HRESULT CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight );
+ HRESULT InitClipper();
+ HRESULT UpdateBounds();
+ virtual HRESULT DestroyObjects();
+
+ // Methods to create child objects
+ HRESULT CreateSurface( CSurface** ppSurface, DWORD dwWidth,
+ DWORD dwHeight );
+ HRESULT CreateSurfaceFromBitmap( CSurface** ppSurface, TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight );
+ HRESULT CreateSurfaceFromText( CSurface** ppSurface, HFONT hFont,
+ TCHAR* strText,
+ COLORREF crBackground,
+ COLORREF crForeground );
+ HRESULT CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette, const TCHAR* strBMP );
+
+ // Display methods
+ HRESULT Clear( DWORD dwColor = 0L );
+ HRESULT ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc = NULL );
+ HRESULT Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc=NULL, DWORD dwFlags=0 );
+ HRESULT Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc = NULL );
+ HRESULT ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette=NULL );
+ HRESULT SetPalette( LPDIRECTDRAWPALETTE pPalette );
+ HRESULT Present();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSurface
+// Desc: Class to handle aspects of a DirectDrawSurface.
+//-----------------------------------------------------------------------------
+class CSurface
+{
+ LPDIRECTDRAWSURFACE7 m_pdds;
+ DDSURFACEDESC2 m_ddsd;
+ BOOL m_bColorKeyed;
+
+public:
+ LPDIRECTDRAWSURFACE7 GetDDrawSurface() { return m_pdds; }
+ BOOL IsColorKeyed() { return m_bColorKeyed; }
+
+ HRESULT DrawBitmap( HBITMAP hBMP, DWORD dwBMPOriginX = 0, DWORD dwBMPOriginY = 0,
+ DWORD dwBMPWidth = 0, DWORD dwBMPHeight = 0 );
+ HRESULT DrawBitmap( TCHAR* strBMP, DWORD dwDesiredWidth, DWORD dwDesiredHeight );
+ HRESULT DrawText( HFONT hFont, TCHAR* strText, DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground );
+
+ HRESULT SetColorKey( DWORD dwColorKey );
+ DWORD ConvertGDIColor( COLORREF dwGDIColor );
+ static HRESULT GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits );
+
+ HRESULT Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd );
+ HRESULT Create( LPDIRECTDRAWSURFACE7 pdds );
+ HRESULT Destroy();
+
+ CSurface();
+ ~CSurface();
+};
+
+
+
+
+#endif // DDUTIL_H
+
diff --git a/V07/dsutil.cpp b/V07/dsutil.cpp
new file mode 100644
index 0000000..83c1512
--- /dev/null
+++ b/V07/dsutil.cpp
@@ -0,0 +1,1546 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.cpp
+//
+// Desc: DirectSound framework classes for reading and writing wav files and
+// playing them in DirectSound buffers. Feel free to use this class
+// as a starting point for adding extra functionality.
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CSoundManager()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSoundManager::CSoundManager()
+{
+ m_pDS = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::~CSoundManager()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSoundManager::~CSoundManager()
+{
+ SAFE_RELEASE( m_pDS );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Initialize()
+// Desc: Initializes the IDirectSound object and also sets the primary buffer
+// format. This function must be called before any others.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Initialize( HWND hWnd,
+ DWORD dwCoopLevel,
+ DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ SAFE_RELEASE( m_pDS );
+
+ // Create IDirectSound using the primary sound device
+ if( FAILED( hr = DirectSoundCreate8( NULL, &m_pDS, NULL ) ) )
+ return DXTRACE_ERR( TEXT("DirectSoundCreate8"), hr );
+
+ // Set DirectSound coop level
+ if( FAILED( hr = m_pDS->SetCooperativeLevel( hWnd, dwCoopLevel ) ) )
+ return DXTRACE_ERR( TEXT("SetCooperativeLevel"), hr );
+
+ // Set primary buffer format
+ SetPrimaryBufferFormat( dwPrimaryChannels, dwPrimaryFreq, dwPrimaryBitRate );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::SetPrimaryBufferFormat()
+// Desc: Set primary buffer to a specified format
+// For example, to set the primary buffer format to 22kHz stereo, 16-bit
+// then: dwPrimaryChannels = 2
+// dwPrimaryFreq = 22050,
+// dwPrimaryBitRate = 16
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::SetPrimaryBufferFormat( DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Get the primary buffer
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
+ dsbd.dwBufferBytes = 0;
+ dsbd.lpwfxFormat = NULL;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ WAVEFORMATEX wfx;
+ ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = (WORD) dwPrimaryChannels;
+ wfx.nSamplesPerSec = dwPrimaryFreq;
+ wfx.wBitsPerSample = (WORD) dwPrimaryBitRate;
+ wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+ if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )
+ return DXTRACE_ERR( TEXT("SetFormat"), hr );
+
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Get3DListenerInterface()
+// Desc: Returns the 3D listener interface associated with primary buffer.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener )
+{
+ HRESULT hr;
+ DSBUFFERDESC dsbdesc;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( ppDSListener == NULL )
+ return E_INVALIDARG;
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ *ppDSListener = NULL;
+
+ // Obtain primary buffer, asking it for 3D control
+ ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
+ dsbdesc.dwSize = sizeof(DSBUFFERDESC);
+ dsbdesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ if( FAILED( hr = pDSBPrimary->QueryInterface( IID_IDirectSound3DListener,
+ (VOID**)ppDSListener ) ) )
+ {
+ SAFE_RELEASE( pDSBPrimary );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ // Release the primary buffer, since it is not need anymore
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Create()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Create( CSound** ppSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ HRESULT hrRet = S_OK;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ if( pWaveFile->GetSize() == 0 )
+ {
+ // Wave is blank, so don't create it.
+ hr = E_FAIL;
+ goto LFail;
+ }
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = pWaveFile->GetSize();
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ // DirectSound is only guarenteed to play PCM data. Other
+ // formats may or may not work depending the sound card driver.
+ hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL );
+
+ // Be sure to return this error code if it occurs so the
+ // callers knows this happened.
+ if( hr == DS_NO_VIRTUALIZATION )
+ hrRet = DS_NO_VIRTUALIZATION;
+
+ if( FAILED(hr) )
+ {
+ // DSERR_BUFFERTOOSMALL will be returned if the buffer is
+ // less than DSBSIZE_FX_MIN (100ms) and the buffer is created
+ // with DSBCAPS_CTRLFX.
+ if( hr != DSERR_BUFFERTOOSMALL )
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return hrRet;
+
+LFail:
+ // Cleanup
+ SAFE_DELETE( pWaveFile );
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateFromMemory()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateFromMemory( CSound** ppSound,
+ BYTE* pbData,
+ ULONG ulDataSize,
+ LPWAVEFORMATEX pwfx,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbData == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->OpenFromMemory( pbData,ulDataSize, pwfx, WAVEFILE_READ );
+
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = ulDataSize;
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL ) ) )
+ {
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return S_OK;
+
+LFail:
+ // Cleanup
+
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateStreaming()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateStreaming( CStreamingSound** ppStreamingSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNotifyCount,
+ DWORD dwNotifySize,
+ HANDLE hNotifyEvent )
+{
+ HRESULT hr;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppStreamingSound == NULL || hNotifyEvent == NULL )
+ return E_INVALIDARG;
+
+ LPDIRECTSOUNDBUFFER pDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+ DSBPOSITIONNOTIFY* aPosNotify = NULL;
+ LPDIRECTSOUNDNOTIFY pDSNotify = NULL;
+
+ pWaveFile = new CWaveFile();
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ // Figure out how big the DSound buffer should be
+ dwDSBufferSize = dwNotifySize * dwNotifyCount;
+
+ // Set up the direct sound buffer. Request the NOTIFY flag, so
+ // that we are notified as the sound buffer plays. Note, that using this flag
+ // may limit the amount of hardware acceleration that can occur.
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags |
+ DSBCAPS_CTRLPOSITIONNOTIFY |
+ DSBCAPS_GETCURRENTPOSITION2;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBuffer, NULL ) ) )
+ {
+ // If wave format isn't then it will return
+ // either DSERR_BADFORMAT or E_INVALIDARG
+ if( hr == DSERR_BADFORMAT || hr == E_INVALIDARG )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("CreateSoundBuffer"), hr );
+
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ }
+
+ // Create the notification events, so that we know when to fill
+ // the buffer as the sound plays.
+ if( FAILED( hr = pDSBuffer->QueryInterface( IID_IDirectSoundNotify,
+ (VOID**)&pDSNotify ) ) )
+ {
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ];
+ if( aPosNotify == NULL )
+ return E_OUTOFMEMORY;
+
+ for( DWORD i = 0; i < dwNotifyCount; i++ )
+ {
+ aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
+ aPosNotify[i].hEventNotify = hNotifyEvent;
+ }
+
+ // Tell DirectSound when to notify us. The notification will come in the from
+ // of signaled events that are handled in WinMain()
+ if( FAILED( hr = pDSNotify->SetNotificationPositions( dwNotifyCount,
+ aPosNotify ) ) )
+ {
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("SetNotificationPositions"), hr );
+ }
+
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+
+ // Create the sound
+ *ppStreamingSound = new CStreamingSound( pDSBuffer, dwDSBufferSize, pWaveFile, dwNotifySize );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::CSound()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSound::CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize,
+ DWORD dwNumBuffers, CWaveFile* pWaveFile )
+{
+ DWORD i;
+
+ m_apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ for( i=0; iSetCurrentPosition(0);
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::~CSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSound::~CSound()
+{
+ for( DWORD i=0; iLock( 0, m_dwDSBufferSize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ NULL, NULL, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // Reset the wave file to the beginning
+ m_pWaveFile->ResetFile();
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwWavDataRead ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ if( dwWavDataRead == 0 )
+ {
+ // Wav is blank, so just fill with silence
+ FillMemory( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ else if( dwWavDataRead < dwDSLockedBufferSize )
+ {
+ // If the wav file was smaller than the DirectSound buffer,
+ // we need to fill the remainder of the buffer with data
+ if( bRepeatWavIfBufferLarger )
+ {
+ // Reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwWavDataRead; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full
+ // for very short files
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwWavDataRead );
+ if( FAILED(hr) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwWavDataRead;
+ }
+ }
+ else
+ {
+ // Don't repeat the wav file, just fill in silence
+ FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead,
+ dwDSLockedBufferSize - dwWavDataRead,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ }
+
+ // Unlock the buffer, we don't need it anymore.
+ pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::RestoreBuffer()
+// Desc: Restores the lost buffer. *pbWasRestored returns TRUE if the buffer was
+// restored. It can also NULL if the information is not needed.
+//-----------------------------------------------------------------------------
+HRESULT CSound::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored )
+{
+ HRESULT hr;
+
+ if( pDSB == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbWasRestored )
+ *pbWasRestored = FALSE;
+
+ DWORD dwStatus;
+ if( FAILED( hr = pDSB->GetStatus( &dwStatus ) ) )
+ return DXTRACE_ERR( TEXT("GetStatus"), hr );
+
+ if( dwStatus & DSBSTATUS_BUFFERLOST )
+ {
+ // Since the app could have just been activated, then
+ // DirectSound may not be giving us control yet, so
+ // the restoring the buffer may fail.
+ // If it does, sleep until DirectSound gives us control.
+ do
+ {
+ hr = pDSB->Restore();
+ if( hr == DSERR_BUFFERLOST )
+ Sleep( 10 );
+ }
+ while( hr = pDSB->Restore() );
+
+ if( pbWasRestored != NULL )
+ *pbWasRestored = TRUE;
+
+ return S_OK;
+ }
+ else
+ {
+ return S_FALSE;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetFreeBuffer()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetFreeBuffer()
+{
+ BOOL bIsPlaying = FALSE;
+ DWORD i;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( i=0; iGetStatus( &dwStatus );
+ if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
+ break;
+ }
+ }
+
+ if( i != m_dwNumBuffers )
+ return m_apDSBuffer[ i ];
+ else
+ return m_apDSBuffer[ rand() % m_dwNumBuffers ];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetBuffer()
+// Desc:
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetBuffer( DWORD dwIndex )
+{
+ if( m_apDSBuffer == NULL )
+ return NULL;
+ if( dwIndex >= m_dwNumBuffers )
+ return NULL;
+
+ return m_apDSBuffer[dwIndex];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Get3DBufferInterface()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSound::Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer )
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( dwIndex >= m_dwNumBuffers )
+ return E_INVALIDARG;
+
+ *ppDS3DBuffer = NULL;
+
+ return m_apDSBuffer[dwIndex]->QueryInterface( IID_IDirectSound3DBuffer,
+ (VOID**)ppDS3DBuffer );
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Play()
+// Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING
+// in the dwFlags to loop the sound
+//-----------------------------------------------------------------------------
+HRESULT CSound::Play( DWORD dwPriority, DWORD dwFlags )
+{
+ HRESULT hr;
+ BOOL bRestored;
+
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();
+
+ if( pDSB == NULL )
+ return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL );
+
+ // Restore the buffer if it was lost
+ if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+
+ // Make DirectSound do pre-processing on sound effects
+ Reset();
+ }
+
+ return pDSB->Play( 0, dwPriority, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Stop()
+// Desc: Stops the sound from playing
+//-----------------------------------------------------------------------------
+HRESULT CSound::Stop()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iStop();
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Reset()
+// Desc: Reset all of the sound buffers
+//-----------------------------------------------------------------------------
+HRESULT CSound::Reset()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iSetCurrentPosition( 0 );
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::IsSoundPlaying()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+BOOL CSound::IsSoundPlaying()
+{
+ BOOL bIsPlaying = FALSE;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( DWORD i=0; iGetStatus( &dwStatus );
+ bIsPlaying |= ( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );
+ }
+ }
+
+ return bIsPlaying;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::CStreamingSound()
+// Desc: Setups up a buffer so data can be streamed from the wave file into
+// buffer. This is very useful for large wav files that would take a
+// while to load. The buffer is initially filled with data, then
+// as sound is played the notification events are signaled and more data
+// is written into the buffer by calling HandleWaveStreamNotification()
+//-----------------------------------------------------------------------------
+CStreamingSound::CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize,
+ CWaveFile* pWaveFile, DWORD dwNotifySize )
+ : CSound( &pDSBuffer, dwDSBufferSize, 1, pWaveFile )
+{
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNotifySize = dwNotifySize;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::~CStreamingSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CStreamingSound::~CStreamingSound()
+{
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::HandleWaveStreamNotification()
+// Desc: Handle the notification that tell us to put more wav data in the
+// circular buffer
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::HandleWaveStreamNotification( BOOL bLoopedPlay )
+{
+ HRESULT hr;
+ DWORD dwCurrentPlayPos;
+ DWORD dwPlayDelta;
+ DWORD dwBytesWrittenToBuffer;
+ VOID* pDSLockedBuffer = NULL;
+ VOID* pDSLockedBuffer2 = NULL;
+ DWORD dwDSLockedBufferSize;
+ DWORD dwDSLockedBufferSize2;
+
+ if( m_apDSBuffer == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ return S_OK;
+ }
+
+ // Lock the DirectSound buffer
+ if( FAILED( hr = m_apDSBuffer[0]->Lock( m_dwNextWriteOffset, m_dwNotifySize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // m_dwDSBufferSize and m_dwNextWriteOffset are both multiples of m_dwNotifySize,
+ // it should the second buffer should never be valid
+ if( pDSLockedBuffer2 != NULL )
+ return E_UNEXPECTED;
+
+ if( !m_bFillNextNotificationWithSilence )
+ {
+ // Fill the DirectSound buffer with wav data
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+ }
+ else
+ {
+ // Fill the DirectSound buffer with silence
+ FillMemory( pDSLockedBuffer, dwDSLockedBufferSize,
+ (BYTE)( m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ dwBytesWrittenToBuffer = dwDSLockedBufferSize;
+ }
+
+ // If the number of bytes written is less than the
+ // amount we requested, we have a short file.
+ if( dwBytesWrittenToBuffer < dwDSLockedBufferSize )
+ {
+ if( !bLoopedPlay )
+ {
+ // Fill in silence for the rest of the buffer.
+ FillMemory( (BYTE*) pDSLockedBuffer + dwBytesWrittenToBuffer,
+ dwDSLockedBufferSize - dwBytesWrittenToBuffer,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+
+ // Any future notifications should just fill the buffer with silence
+ m_bFillNextNotificationWithSilence = TRUE;
+ }
+ else
+ {
+ // We are looping, so reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwBytesWrittenToBuffer; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full (for very short files).
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwBytesWrittenToBuffer;
+ }
+ }
+ }
+
+ // Unlock the DirectSound buffer
+ m_apDSBuffer[0]->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ // Figure out how much data has been played so far. When we have played
+ // passed the end of the file, we will either need to start filling the
+ // buffer with silence or starting reading from the beginning of the file,
+ // depending if the user wants to loop the sound
+ if( FAILED( hr = m_apDSBuffer[0]->GetCurrentPosition( &dwCurrentPlayPos, NULL ) ) )
+ return DXTRACE_ERR( TEXT("GetCurrentPosition"), hr );
+
+ // Check to see if the position counter looped
+ if( dwCurrentPlayPos < m_dwLastPlayPos )
+ dwPlayDelta = ( m_dwDSBufferSize - m_dwLastPlayPos ) + dwCurrentPlayPos;
+ else
+ dwPlayDelta = dwCurrentPlayPos - m_dwLastPlayPos;
+
+ m_dwPlayProgress += dwPlayDelta;
+ m_dwLastPlayPos = dwCurrentPlayPos;
+
+ // If we are now filling the buffer with silence, then we have found the end so
+ // check to see if the entire sound has played, if it has then stop the buffer.
+ if( m_bFillNextNotificationWithSilence )
+ {
+ // We don't want to cut off the sound before it's done playing.
+ if( m_dwPlayProgress >= m_pWaveFile->GetSize() )
+ {
+ m_apDSBuffer[0]->Stop();
+ }
+ }
+
+ // Update where the buffer will lock (for next time)
+ m_dwNextWriteOffset += dwDSLockedBufferSize;
+ m_dwNextWriteOffset %= m_dwDSBufferSize; // Circular buffer
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::Reset()
+// Desc: Resets the sound so it will begin playing at the beginning
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::Reset()
+{
+ HRESULT hr;
+
+ if( m_apDSBuffer[0] == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ }
+
+ m_pWaveFile->ResetFile();
+
+ return m_apDSBuffer[0]->SetCurrentPosition( 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::CWaveFile()
+// Desc: Constructs the class. Call Open() to open a wave file for reading.
+// Then call Read() as needed. Calling the destructor or Close()
+// will close the file.
+//-----------------------------------------------------------------------------
+CWaveFile::CWaveFile()
+{
+ m_pwfx = NULL;
+ m_hmmio = NULL;
+ m_dwSize = 0;
+ m_bIsReadingFromMemory = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::~CWaveFile()
+// Desc: Destructs the class
+//-----------------------------------------------------------------------------
+CWaveFile::~CWaveFile()
+{
+ Close();
+
+ if( !m_bIsReadingFromMemory )
+ SAFE_DELETE_ARRAY( m_pwfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Open()
+// Desc: Opens a wave file for reading
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ HRESULT hr;
+
+ m_dwFlags = dwFlags;
+ m_bIsReadingFromMemory = FALSE;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ if( strFileName == NULL )
+ return E_INVALIDARG;
+ SAFE_DELETE_ARRAY( m_pwfx );
+
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );
+
+ if( NULL == m_hmmio )
+ {
+ HRSRC hResInfo;
+ HGLOBAL hResData;
+ DWORD dwSize;
+ VOID* pvRes;
+
+ // Loading it as a file failed, so try it as a resource
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAVE") ) ) )
+ {
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAV") ) ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("FindResource"), E_FAIL );
+ }
+
+ if( NULL == ( hResData = LoadResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("LoadResource"), E_FAIL );
+
+ if( 0 == ( dwSize = SizeofResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("SizeofResource"), E_FAIL );
+
+ if( NULL == ( pvRes = LockResource( hResData ) ) )
+ return DXTRACE_ERR( TEXT("LockResource"), E_FAIL );
+
+ CHAR* pData = new CHAR[ dwSize ];
+ memcpy( pData, pvRes, dwSize );
+
+ MMIOINFO mmioInfo;
+ ZeroMemory( &mmioInfo, sizeof(mmioInfo) );
+ mmioInfo.fccIOProc = FOURCC_MEM;
+ mmioInfo.cchBuffer = dwSize;
+ mmioInfo.pchBuffer = (CHAR*) pData;
+
+ m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );
+ }
+
+ if( FAILED( hr = ReadMMIO() ) )
+ {
+ // ReadMMIO will fail if its an not a wave file
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR_NOMSGBOX( TEXT("ReadMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ // After the reset, the size of the wav file is m_ck.cksize so store it now
+ m_dwSize = m_ck.cksize;
+ }
+ else
+ {
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF |
+ MMIO_READWRITE |
+ MMIO_CREATE );
+ if( NULL == m_hmmio )
+ return DXTRACE_ERR( TEXT("mmioOpen"), E_FAIL );
+
+ if( FAILED( hr = WriteMMIO( pwfx ) ) )
+ {
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR( TEXT("WriteMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+ }
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::OpenFromMemory()
+// Desc: copy data to CWaveFile member variable from memory
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::OpenFromMemory( BYTE* pbData, ULONG ulDataSize,
+ WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ m_pwfx = pwfx;
+ m_ulDataSize = ulDataSize;
+ m_pbData = pbData;
+ m_pbDataCur = m_pbData;
+ m_bIsReadingFromMemory = TRUE;
+
+ if( dwFlags != WAVEFILE_READ )
+ return E_NOTIMPL;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ReadMMIO()
+// Desc: Support function for reading from a multimedia I/O stream.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_pwfx.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ReadMMIO()
+{
+ MMCKINFO ckIn; // chunk info. for general use.
+ PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in.
+
+ m_pwfx = NULL;
+
+ if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Check to make sure this is a valid wave file
+ if( (m_ckRiff.ckid != FOURCC_RIFF) ||
+ (m_ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("mmioFOURCC"), E_FAIL );
+
+ // Search the input file for for the 'fmt ' chunk.
+ ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Expect the 'fmt' chunk to be at least as large as ;
+ // if there are extra parameters at the end, we'll ignore them
+ if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) )
+ return DXTRACE_ERR( TEXT("sizeof(PCMWAVEFORMAT)"), E_FAIL );
+
+ // Read the 'fmt ' chunk into .
+ if( mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat,
+ sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ // Allocate the waveformatex, but if its not pcm format, read the next
+ // word, and thats how many extra bytes to allocate.
+ if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )
+ {
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("m_pwfx"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = 0;
+ }
+ else
+ {
+ // Read in length of extra bytes.
+ WORD cbExtraBytes = 0L;
+ if( mmioRead( m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("new"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = cbExtraBytes;
+
+ // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
+ if( mmioRead( m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize))+sizeof(WORD)),
+ cbExtraBytes ) != cbExtraBytes )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+ }
+ }
+
+ // Ascend the input file out of the 'fmt ' chunk.
+ if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::GetSize()
+// Desc: Retuns the size of the read access wave file
+//-----------------------------------------------------------------------------
+DWORD CWaveFile::GetSize()
+{
+ return m_dwSize;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ResetFile()
+// Desc: Resets the internal m_ck pointer so reading starts from the
+// beginning of the file again
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ResetFile()
+{
+ if( m_bIsReadingFromMemory )
+ {
+ m_pbDataCur = m_pbData;
+ }
+ else
+ {
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ // Seek to the data
+ if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),
+ SEEK_SET ) )
+ return DXTRACE_ERR( TEXT("mmioSeek"), E_FAIL );
+
+ // Search the input file for the 'data' chunk.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ if( 0 != mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+ }
+ else
+ {
+ // Create the 'data' chunk that holds the waveform samples.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ m_ck.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( 0 != mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Read()
+// Desc: Reads section of data from a wave file into pBuffer and returns
+// how much read in pdwSizeRead, reading not more than dwSizeToRead.
+// This uses m_ck to determine where to start reading from. So
+// subsequent calls will be continue where the last left off unless
+// Reset() is called.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )
+{
+ if( m_bIsReadingFromMemory )
+ {
+ if( m_pbDataCur == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( (BYTE*)(m_pbDataCur + dwSizeToRead) >
+ (BYTE*)(m_pbData + m_ulDataSize) )
+ {
+ dwSizeToRead = m_ulDataSize - (DWORD)(m_pbDataCur - m_pbData);
+ }
+
+ CopyMemory( pBuffer, m_pbDataCur, dwSizeToRead );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = dwSizeToRead;
+
+ return S_OK;
+ }
+ else
+ {
+ MMIOINFO mmioinfoIn; // current status of m_hmmio
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pBuffer == NULL || pdwSizeRead == NULL )
+ return E_INVALIDARG;
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+
+ UINT cbDataIn = dwSizeToRead;
+ if( cbDataIn > m_ck.cksize )
+ cbDataIn = m_ck.cksize;
+
+ m_ck.cksize -= cbDataIn;
+
+ for( DWORD cT = 0; cT < cbDataIn; cT++ )
+ {
+ // Copy the bytes from the io to the buffer.
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ {
+ if( 0 != mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ return DXTRACE_ERR( TEXT("mmioinfoIn.pchNext"), E_FAIL );
+ }
+
+ // Actual copy.
+ *((BYTE*)pBuffer+cT) = *((BYTE*)mmioinfoIn.pchNext);
+ mmioinfoIn.pchNext++;
+ }
+
+ if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = cbDataIn;
+
+ return S_OK;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Close()
+// Desc: Closes the wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Close()
+{
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+ else
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( 0 != mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ // Ascend the output file out of the 'data' chunk -- this will cause
+ // the chunk size of the 'data' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Do this here instead...
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioSeek( m_hmmio, 0, SEEK_SET );
+
+ if( 0 != (INT)mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ m_ck.ckid = mmioFOURCC('f', 'a', 'c', 't');
+
+ if( 0 == mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ {
+ DWORD dwSamples = 0;
+ mmioWrite( m_hmmio, (HPSTR)&dwSamples, sizeof(DWORD) );
+ mmioAscend( m_hmmio, &m_ck, 0 );
+ }
+
+ // Ascend the output file out of the 'RIFF' chunk -- this will cause
+ // the chunk size of the 'RIFF' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::WriteMMIO()
+// Desc: Support function for reading from a multimedia I/O stream
+// pwfxDest is the WAVEFORMATEX for this new wave file.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_ck.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::WriteMMIO( WAVEFORMATEX *pwfxDest )
+{
+ DWORD dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile.
+ MMCKINFO ckOut1;
+
+ dwFactChunk = (DWORD)-1;
+
+ // Create the output file RIFF chunk of form type 'WAVE'.
+ m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');
+ m_ckRiff.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // We are now descended into the 'RIFF' chunk we just created.
+ // Now create the 'fmt ' chunk. Since we know the size of this chunk,
+ // specify it in the MMCKINFO structure so MMIO doesn't have to seek
+ // back and set the chunk size after ascending from the chunk.
+ m_ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ m_ck.cksize = sizeof(PCMWAVEFORMAT);
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type.
+ if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM )
+ {
+ if( mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+ else
+ {
+ // Write the variable length size.
+ if( (UINT)mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(*pwfxDest) + pwfxDest->cbSize ) !=
+ ( sizeof(*pwfxDest) + pwfxDest->cbSize ) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+
+ // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Now create the fact chunk, not required for PCM but nice to have. This is filled
+ // in when the close routine is called.
+ ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't');
+ ckOut1.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( mmioWrite( m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) !=
+ sizeof(dwFactChunk) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+
+ // Now ascend out of the fact chunk...
+ if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Write()
+// Desc: Writes data to the open wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Write( UINT nSizeToWrite, BYTE* pbSrcData, UINT* pnSizeWrote )
+{
+ UINT cT;
+
+ if( m_bIsReadingFromMemory )
+ return E_NOTIMPL;
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pnSizeWrote == NULL || pbSrcData == NULL )
+ return E_INVALIDARG;
+
+ *pnSizeWrote = 0;
+
+ for( cT = 0; cT < nSizeToWrite; cT++ )
+ {
+ if( m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite )
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+ if( 0 != mmioAdvance( m_hmmio, &m_mmioinfoOut, MMIO_WRITE ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+ }
+
+ *((BYTE*)m_mmioinfoOut.pchNext) = *((BYTE*)pbSrcData+cT);
+ (BYTE*)m_mmioinfoOut.pchNext++;
+
+ (*pnSizeWrote)++;
+ }
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V07/dsutil.h b/V07/dsutil.h
new file mode 100644
index 0000000..57d26df
--- /dev/null
+++ b/V07/dsutil.h
@@ -0,0 +1,170 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.h
+//
+// Desc:
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#ifndef DSUTIL_H
+#define DSUTIL_H
+
+#include
+#include
+#include
+#include
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes used by this header
+//-----------------------------------------------------------------------------
+class CSoundManager;
+class CSound;
+class CStreamingSound;
+class CWaveFile;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Typing macros
+//-----------------------------------------------------------------------------
+#define WAVEFILE_READ 1
+#define WAVEFILE_WRITE 2
+
+#define DSUtil_StopSound(s) { if(s) s->Stop(); }
+#define DSUtil_PlaySound(s) { if(s) s->Play( 0, 0 ); }
+#define DSUtil_PlaySoundLooping(s) { if(s) s->Play( 0, DSBPLAY_LOOPING ); }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSoundManager
+// Desc:
+//-----------------------------------------------------------------------------
+class CSoundManager
+{
+protected:
+ LPDIRECTSOUND8 m_pDS;
+
+public:
+ CSoundManager();
+ ~CSoundManager();
+
+ HRESULT Initialize( HWND hWnd, DWORD dwCoopLevel, DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate );
+ inline LPDIRECTSOUND GetDirectSound() { return m_pDS; }
+ HRESULT SetPrimaryBufferFormat( DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate );
+ HRESULT Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener );
+
+ HRESULT Create( CSound** ppSound, LPTSTR strWaveFileName, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
+ HRESULT CreateFromMemory( CSound** ppSound, BYTE* pbData, ULONG ulDataSize, LPWAVEFORMATEX pwfx, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
+ HRESULT CreateStreaming( CStreamingSound** ppStreamingSound, LPTSTR strWaveFileName, DWORD dwCreationFlags, GUID guid3DAlgorithm, DWORD dwNotifyCount, DWORD dwNotifySize, HANDLE hNotifyEvent );
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSound
+// Desc: Encapsulates functionality of a DirectSound buffer.
+//-----------------------------------------------------------------------------
+class CSound
+{
+protected:
+ LPDIRECTSOUNDBUFFER* m_apDSBuffer;
+ DWORD m_dwDSBufferSize;
+ CWaveFile* m_pWaveFile;
+ DWORD m_dwNumBuffers;
+
+ HRESULT RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored );
+
+public:
+ CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize, DWORD dwNumBuffers, CWaveFile* pWaveFile );
+ virtual ~CSound();
+
+ HRESULT Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer );
+ HRESULT FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger );
+ LPDIRECTSOUNDBUFFER GetFreeBuffer();
+ LPDIRECTSOUNDBUFFER GetBuffer( DWORD dwIndex );
+
+ HRESULT Play( DWORD dwPriority, DWORD dwFlags );
+ HRESULT Stop();
+ HRESULT Reset();
+ BOOL IsSoundPlaying();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CStreamingSound
+// Desc: Encapsulates functionality to play a wave file with DirectSound.
+// The Create() method loads a chunk of wave file into the buffer,
+// and as sound plays more is written to the buffer by calling
+// HandleWaveStreamNotification() whenever hNotifyEvent is signaled.
+//-----------------------------------------------------------------------------
+class CStreamingSound : public CSound
+{
+protected:
+ DWORD m_dwLastPlayPos;
+ DWORD m_dwPlayProgress;
+ DWORD m_dwNotifySize;
+ DWORD m_dwNextWriteOffset;
+ BOOL m_bFillNextNotificationWithSilence;
+
+public:
+ CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize, CWaveFile* pWaveFile, DWORD dwNotifySize );
+ ~CStreamingSound();
+
+ HRESULT HandleWaveStreamNotification( BOOL bLoopedPlay );
+ HRESULT Reset();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CWaveFile
+// Desc: Encapsulates reading or writing sound data to or from a wave file
+//-----------------------------------------------------------------------------
+class CWaveFile
+{
+public:
+ WAVEFORMATEX* m_pwfx; // Pointer to WAVEFORMATEX structure
+ HMMIO m_hmmio; // MM I/O handle for the WAVE
+ MMCKINFO m_ck; // Multimedia RIFF chunk
+ MMCKINFO m_ckRiff; // Use in opening a WAVE file
+ DWORD m_dwSize; // The size of the wave file
+ MMIOINFO m_mmioinfoOut;
+ DWORD m_dwFlags;
+ BOOL m_bIsReadingFromMemory;
+ BYTE* m_pbData;
+ BYTE* m_pbDataCur;
+ ULONG m_ulDataSize;
+
+protected:
+ HRESULT ReadMMIO();
+ HRESULT WriteMMIO( WAVEFORMATEX *pwfxDest );
+
+public:
+ CWaveFile();
+ ~CWaveFile();
+
+ HRESULT Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags );
+ HRESULT OpenFromMemory( BYTE* pbData, ULONG ulDataSize, WAVEFORMATEX* pwfx, DWORD dwFlags );
+ HRESULT Close();
+
+ HRESULT Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead );
+ HRESULT Write( UINT nSizeToWrite, BYTE* pbData, UINT* pnSizeWrote );
+
+ DWORD GetSize();
+ HRESULT ResetFile();
+ WAVEFORMATEX* GetFormat() { return m_pwfx; };
+};
+
+
+
+
+#endif // DSUTIL_H
diff --git a/V07/resource.h b/V07/resource.h
new file mode 100644
index 0000000..ca05021
--- /dev/null
+++ b/V07/resource.h
@@ -0,0 +1,74 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Demo.rc
+//
+#define IDI_MAIN 101
+#define IDR_MENU 102
+#define IDR_ACCEL 103
+#define IDD_HILFE 124
+#define IDD_KONFIGURATION 125
+#define IDB_STEIN 126
+#define IDD_ULTRIS 129
+#define IDB_ULTRIS 130
+#define IDM_EXIT 1001
+#define IDC_ALLE 1005
+#define IDC_STANDARD 1006
+#define IDC_LOESCHEN 1007
+#define IDC_VORBELEGUNG 1008
+#define IDC_VORSCHAU 1009
+#define IDC_WEITERE_INFO 1018
+#define IDC_CHECK1 5000
+#define IDC_CHECK2 5001
+#define IDC_CHECK3 5002
+#define IDC_CHECK4 5003
+#define IDC_CHECK5 5004
+#define IDC_CHECK6 5005
+#define IDC_CHECK7 5006
+#define IDC_CHECK8 5007
+#define IDC_CHECK9 5008
+#define IDC_CHECK10 5009
+#define IDC_CHECK11 5010
+#define IDC_CHECK12 5011
+#define IDC_CHECK13 5012
+#define IDC_CHECK14 5013
+#define IDC_CHECK15 5014
+#define IDC_CHECK16 5015
+#define IDC_CHECK17 5016
+#define IDC_CHECK18 5017
+#define IDC_CHECK19 5018
+#define IDC_CHECK20 5019
+#define IDC_CHECK21 5020
+#define IDC_CHECK22 5021
+#define IDC_CHECK23 5022
+#define IDC_CHECK24 5023
+#define IDC_CHECK25 5024
+#define IDC_CHECK26 5025
+#define IDC_CHECK27 5026
+#define IDC_CHECK28 5027
+#define IDC_CHECK29 5028
+#define IDC_CHECK30 5029
+#define IDC_CHECK31 5030
+#define IDC_CHECK32 5031
+#define IDC_CHECK33 5032
+#define IDC_CHECK34 5033
+#define IDC_CHECK35 5034
+#define IDM_TEST 40024
+#define ID_ULTRIS_NEUESSPIEL 40025
+#define ID_ULTRIS_PAUSE 40026
+#define ID_ULTRIS_SOUND 40027
+#define ID_EINSTELLUNGEN_KONFIGURATION 40028
+#define ID_INFO_HILFE 40029
+#define ID_INFO_HIGHSCORES 40030
+#define ID_INFO_ULTRIS 40031
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 132
+#define _APS_NEXT_COMMAND_VALUE 40033
+#define _APS_NEXT_CONTROL_VALUE 1019
+#define _APS_NEXT_SYMED_VALUE 104
+#endif
+#endif
diff --git a/V07/ul_adeck.bmp b/V07/ul_adeck.bmp
new file mode 100644
index 0000000..5f3b867
Binary files /dev/null and b/V07/ul_adeck.bmp differ
diff --git a/V07/ul_down.wav b/V07/ul_down.wav
new file mode 100644
index 0000000..84cf9e1
Binary files /dev/null and b/V07/ul_down.wav differ
diff --git a/V07/ul_dreh.WAV b/V07/ul_dreh.WAV
new file mode 100644
index 0000000..790ef8c
Binary files /dev/null and b/V07/ul_dreh.WAV differ
diff --git a/V07/ul_ende.WAV b/V07/ul_ende.WAV
new file mode 100644
index 0000000..43c73f0
Binary files /dev/null and b/V07/ul_ende.WAV differ
diff --git a/V07/ul_feld.bmp b/V07/ul_feld.bmp
new file mode 100644
index 0000000..3225b6b
Binary files /dev/null and b/V07/ul_feld.bmp differ
diff --git a/V07/ul_hgrnd.bmp b/V07/ul_hgrnd.bmp
new file mode 100644
index 0000000..c33b077
Binary files /dev/null and b/V07/ul_hgrnd.bmp differ
diff --git a/V07/ul_move.WAV b/V07/ul_move.WAV
new file mode 100644
index 0000000..22b2a99
Binary files /dev/null and b/V07/ul_move.WAV differ
diff --git a/V07/ul_prev.bmp b/V07/ul_prev.bmp
new file mode 100644
index 0000000..c791074
Binary files /dev/null and b/V07/ul_prev.bmp differ
diff --git a/V07/ul_row1.WAV b/V07/ul_row1.WAV
new file mode 100644
index 0000000..ab5bfca
Binary files /dev/null and b/V07/ul_row1.WAV differ
diff --git a/V07/ul_row2.WAV b/V07/ul_row2.WAV
new file mode 100644
index 0000000..671fc71
Binary files /dev/null and b/V07/ul_row2.WAV differ
diff --git a/V07/ul_start.WAV b/V07/ul_start.WAV
new file mode 100644
index 0000000..f66bfef
Binary files /dev/null and b/V07/ul_start.WAV differ
diff --git a/V07/ul_stein.bmp b/V07/ul_stein.bmp
new file mode 100644
index 0000000..dadb7a0
Binary files /dev/null and b/V07/ul_stein.bmp differ
diff --git a/V07/ul_win.wav b/V07/ul_win.wav
new file mode 100644
index 0000000..e11c880
Binary files /dev/null and b/V07/ul_win.wav differ
diff --git a/V07/ul_z0.bmp b/V07/ul_z0.bmp
new file mode 100644
index 0000000..10fe8a6
Binary files /dev/null and b/V07/ul_z0.bmp differ
diff --git a/V07/ul_z1.bmp b/V07/ul_z1.bmp
new file mode 100644
index 0000000..1ce2939
Binary files /dev/null and b/V07/ul_z1.bmp differ
diff --git a/V07/ul_z2.bmp b/V07/ul_z2.bmp
new file mode 100644
index 0000000..9006084
Binary files /dev/null and b/V07/ul_z2.bmp differ
diff --git a/V07/ul_z3.bmp b/V07/ul_z3.bmp
new file mode 100644
index 0000000..5710c67
Binary files /dev/null and b/V07/ul_z3.bmp differ
diff --git a/V07/ul_z4.bmp b/V07/ul_z4.bmp
new file mode 100644
index 0000000..11306ed
Binary files /dev/null and b/V07/ul_z4.bmp differ
diff --git a/V07/ul_z5.bmp b/V07/ul_z5.bmp
new file mode 100644
index 0000000..b4a22b5
Binary files /dev/null and b/V07/ul_z5.bmp differ
diff --git a/V07/ul_z6.bmp b/V07/ul_z6.bmp
new file mode 100644
index 0000000..62616d4
Binary files /dev/null and b/V07/ul_z6.bmp differ
diff --git a/V07/ul_z7.bmp b/V07/ul_z7.bmp
new file mode 100644
index 0000000..d9178df
Binary files /dev/null and b/V07/ul_z7.bmp differ
diff --git a/V07/ul_z8.bmp b/V07/ul_z8.bmp
new file mode 100644
index 0000000..98e1a18
Binary files /dev/null and b/V07/ul_z8.bmp differ
diff --git a/V07/ul_z9.bmp b/V07/ul_z9.bmp
new file mode 100644
index 0000000..e6245a3
Binary files /dev/null and b/V07/ul_z9.bmp differ
diff --git a/V08/Demo.aps b/V08/Demo.aps
new file mode 100644
index 0000000..86b0759
Binary files /dev/null and b/V08/Demo.aps differ
diff --git a/V08/Demo.cpp b/V08/Demo.cpp
new file mode 100644
index 0000000..3f91ccc
--- /dev/null
+++ b/V08/Demo.cpp
@@ -0,0 +1,1137 @@
+# include
+# include
+# include
+# include
+# include "ddutil.h"
+# include "dsutil.h"
+# include "resource.h"
+
+const int ultris_nettobreite = 360; // Breite des Inneren des Haupfensters
+const int ultris_nettohoehe = 520; // Hoehe des Inneren des Hauptfensters
+int ultris_bruttobreite; // Breite des gesamten Haupfensters (incl. Rahmen)
+int ultris_bruttohoehe; // Hoehe des gesamten Haupfensters (incl. Rahmen)
+
+HINSTANCE ultris_instance; // Instanz der Ultris Applikation
+HWND ultris_window; // Das Hauptfenster von Ultris
+HMENU ultris_menu; // Das Menu von Ultris
+
+const int sound_start = 0; // Sound fuer neues Spiel
+const int sound_dreh = 1; // Sound bei Drehung
+const int sound_move = 2; // Sound bei rechts/links Bewegung
+const int sound_down = 3; // Sound bei Aufprall
+const int sound_row1 = 4; // Sound bei Abraeumen einer Reihe
+const int sound_row2 = 5; // Sound bei Abraeumen von mehreren Reihen
+const int sound_ende = 6; // Sound bei Spielende
+const int sound_win = 7; // Sound bei Eintrag in Highscore Tabelle
+const int anzahl_sounds = 8; // Anzahl Sounds
+
+char *soundfiles[anzahl_sounds] =
+ {
+ "ul_start.wav",
+ "ul_dreh.wav",
+ "ul_move.wav",
+ "ul_down.wav",
+ "ul_row1.wav",
+ "ul_row2.wav",
+ "ul_ende.wav",
+ "ul_win.wav"
+ };
+
+class sounds
+ {
+ private:
+ CSoundManager smgr;
+ CSound *snd[anzahl_sounds];
+ public:
+ int on;
+ sounds();
+ int init( HWND wnd);
+ void play( int snr);
+ ~sounds();
+ };
+
+sounds::sounds()
+ {
+ int i;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ snd[i] = 0;
+ on = 1;
+ }
+
+int sounds::init( HWND wnd)
+ {
+ HRESULT ret;
+ int i;
+
+ ret = smgr.Initialize( wnd, DSSCL_PRIORITY, 2, 22050, 16);
+ if( ret < 0)
+ return ret;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ {
+ ret = smgr.Create( snd+i, soundfiles[i]);
+ if( ret < 0)
+ return ret;
+ }
+ return S_OK;
+ }
+
+sounds::~sounds()
+ {
+ int i;
+
+ for( i = 0; i < anzahl_sounds; i++)
+ {
+ if( snd[i])
+ delete snd[i];
+ }
+ }
+
+void sounds::play( int i)
+ {
+ if( !on)
+ return;
+ if( snd[i]->IsSoundPlaying())
+ {
+ snd[i]->Stop();
+ snd[i]->Reset();
+ }
+ snd[i]->Play(0,0);
+ }
+
+sounds ultris_sounds;
+
+class display
+ {
+ private:
+ CDisplay dsply;
+ CSurface *hgrnd;
+ CSurface *fldst;
+ CSurface *fllst;
+ CSurface *prvst;
+ CSurface *deckel;
+ CSurface *ziff[10];
+ public:
+ display();
+ void free_all();
+ ~display() {free_all();}
+ HRESULT init( HWND wnd);
+ void hintergrund() { dsply.Blt( 0, 0, hgrnd);}
+ void abdeckung() { dsply.Blt( 60, 0, deckel);}
+ void ziffer( int pos, int val) { dsply.Blt( 120+pos*20, 50, ziff[val]);}
+ void feldstein( int z, int s) { dsply.Blt( 80+s*20, 100+z*20, fldst);}
+ void fallstein( int z, int s, int offset) { dsply.Blt( 80+s*20, 100+z*20+offset, fllst);}
+ void prevstein( int p, int z, int s, int b, int h){ dsply.Blt( 290+s*15+(4-b)*15/2, 410-p*70+z*15+(4-h)*15/2, prvst);}
+ void update(){ dsply.UpdateBounds();}
+ HRESULT cooperative(){return dsply.GetDirectDraw()->TestCooperativeLevel();}
+ HRESULT restore();
+ HRESULT present();
+ };
+
+display::display()
+ {
+ int i;
+
+ hgrnd = 0;
+ fldst = 0;
+ fllst = 0;
+ prvst = 0;
+ deckel = 0;
+ for( i = 0; i < 10; i++)
+ ziff[i] = 0;
+ }
+
+void display::free_all()
+ {
+ int i;
+
+ if( hgrnd)
+ delete hgrnd;
+ if( fldst)
+ delete fldst;
+ if( fllst)
+ delete fllst;
+ if( prvst)
+ delete prvst;
+ if( deckel)
+ delete deckel;
+ for( i = 0; i < 10; i++)
+ {
+ if( ziff[i])
+ delete ziff[i];
+ }
+ }
+
+HRESULT display::init( HWND wnd)
+ {
+ HRESULT hr;
+ int i;
+ char fname[20];
+
+ hr = dsply.CreateWindowedDisplay( wnd, ultris_nettobreite, ultris_nettohoehe );
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &hgrnd, "ul_hgrnd.bmp", ultris_nettobreite, ultris_nettohoehe);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &fldst, "ul_feld.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &fllst, "ul_stein.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &prvst, "ul_prev.bmp", 15, 15);
+ if( hr < 0)
+ return hr;
+ hr = dsply.CreateSurfaceFromBitmap( &deckel, "ul_adeck.bmp", 240, 100);
+ if( hr < 0)
+ return hr;
+ for( i = 0; i < 10; i++)
+ {
+ sprintf( fname, "ul_z%d.bmp", i);
+ hr = dsply.CreateSurfaceFromBitmap( &ziff[i], fname, 20, 40);
+ if( hr < 0)
+ return hr;
+ }
+ return S_OK;
+ }
+
+HRESULT display::restore()
+ {
+ HRESULT hr;
+ int i;
+ char fname[20];
+
+ hr = dsply.GetDirectDraw()->RestoreAllSurfaces();
+ if( hr < 0)
+ return hr;
+ hr = hgrnd->DrawBitmap( "ul_hgrnd.bmp", ultris_nettobreite, ultris_nettohoehe);
+ if( hr < 0)
+ return hr;
+ hr = fldst->DrawBitmap( "ul_feld.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = fllst->DrawBitmap( "ul_stein.bmp", 20, 20);
+ if( hr < 0)
+ return hr;
+ hr = prvst->DrawBitmap( "ul_prev.bmp", 15, 15);
+ if( hr < 0)
+ return hr;
+ hr = deckel->DrawBitmap( "ul_adeck.bmp", 240, 100);
+ if( hr < 0)
+ return hr;
+
+ for( i = 0; i < 10; i++)
+ {
+ sprintf( fname, "ul_z%d.bmp", i);
+ hr = ziff[i]->DrawBitmap( fname, 20, 40);
+ if( hr < 0)
+ return hr;
+ }
+ MessageBox( ultris_window, "Surfaces restauriert", "Ultris-Fehlermeldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
+ return S_OK;
+ }
+
+HRESULT display::present()
+ {
+ HRESULT hr;
+
+ hr = dsply.Present();
+ if( hr == DDERR_SURFACELOST )
+ return restore();
+ return hr;
+ }
+
+display ultris_display;
+
+const int anzahl_formen = 35; // Anzahl der Formen
+
+//
+// Datenstruktur für die Formen
+//
+struct form
+ {
+ char h; // Hoehe
+ char b; // Breite
+ char data[4][4]; // Vorhandene Segmente
+ };
+
+// Form 1 in allen Drehvarianten
+//
+// *** * * *
+// * ** *** **
+// * *
+const form s_01_1 = {2, 3, {{1,1,1}, {0,1,0}}};
+const form s_01_2 = {3, 2, {{1,0}, {1,1}, {1,0}}};
+const form s_01_3 = {2, 3, {{0,1,0}, {1,1,1}}};
+const form s_01_4 = {3, 2, {{0,1}, {1,1}, {0,1}}};
+
+// Form 2 in allen Drehvarianten
+//
+// ** * ** *
+// ** ** ** **
+// * *
+const form s_02_1 = {2, 3, {{1,1,0}, {0,1,1}}};
+const form s_02_2 = {3, 2, {{0,1}, {1,1}, {1,0}}};
+const form s_02_3 = {2, 3, {{1,1,0}, {0,1,1}}};
+const form s_02_4 = {3, 2, {{0,1}, {1,1}, {1,0}}};
+
+// Form 3 in allen Drehvarianten
+//
+// ** * ** *
+// ** ** ** **
+// * *
+const form s_03_1 = {2, 3, {{0,1,1}, {1,1,0}}};
+const form s_03_2 = {3, 2, {{1,0}, {1,1}, {0,1}}};
+const form s_03_3 = {2, 3, {{0,1,1}, {1,1,0}}};
+const form s_03_4 = {3, 2, {{1,0}, {1,1}, {0,1}}};
+
+// Form 4 in allen Drehvarianten
+//
+// *** ** * *
+// * * *** *
+// * **
+const form s_04_1 = {2, 3, {{1,1,1}, {0,0,1}}};
+const form s_04_2 = {3, 2, {{1,1}, {1,0}, {1,0}}};
+const form s_04_3 = {2, 3, {{1,0,0}, {1,1,1}}};
+const form s_04_4 = {3, 2, {{0,1}, {0,1}, {1,1}}};
+
+// Form 5 in allen Drehvarianten
+//
+// * ** *** *
+// *** * * *
+// * **
+const form s_05_1 = {2, 3, {{0,0,1}, {1,1,1}}};
+const form s_05_2 = {3, 2, {{1,1}, {0,1}, {0,1}}};
+const form s_05_3 = {2, 3, {{1,1,1}, {1,0,0}}};
+const form s_05_4 = {3, 2, {{1,0}, {1,0}, {1,1}}};
+
+// Form 6 in allen Drehvarianten
+//
+// ** ** ** **
+// ** ** ** **
+//
+const form s_06_1 = {2, 2, {{1,1}, {1,1}}};
+const form s_06_2 = {2, 2, {{1,1}, {1,1}}};
+const form s_06_3 = {2, 2, {{1,1}, {1,1}}};
+const form s_06_4 = {2, 2, {{1,1}, {1,1}}};
+
+// Form 7 in allen Drehvarianten
+//
+// **** * **** *
+// * *
+// * *
+// * *
+const form s_07_1 = {1, 4, {{1,1,1,1}}};
+const form s_07_2 = {4, 1, {{1},{1},{1},{1}}};
+const form s_07_3 = {1, 4, {{1,1,1,1}}};
+const form s_07_4 = {4, 1, {{1},{1},{1},{1}}};
+
+// Form 8 in allen Drehvarianten
+//
+// *** ** * * **
+// * * * *** *
+// ** **
+const form s_08_1 = {2, 3, {{1,1,1}, {1,0,1}}};
+const form s_08_2 = {3, 2, {{1,1},{1,0},{1,1}}};
+const form s_08_3 = {2, 3, {{1,0,1}, {1,1,1}}};
+const form s_08_4 = {3, 2, {{1,1},{0,1},{1,1}}};
+
+// Form 9 in allen Drehvarianten
+//
+// ** * ** *
+// * *** * ***
+// ** * ** *
+const form s_09_1 = {3, 3, {{1,1,0}, {0,1,0}, {0,1,1}}};
+const form s_09_2 = {3, 3, {{0,0,1}, {1,1,1}, {1,0,0}}};
+const form s_09_3 = {3, 3, {{1,1,0}, {0,1,0}, {0,1,1}}};
+const form s_09_4 = {3, 3, {{0,0,1}, {1,1,1}, {1,0,0}}};
+
+// Form 10 in allen Drehvarianten
+//
+// ** ** * *
+// * * ** **
+//
+const form s_10_1 = {2, 2, {{1,1}, {0,1}}};
+const form s_10_2 = {2, 2, {{1,1}, {1,0}}};
+const form s_10_3 = {2, 2, {{1,0}, {1,1}}};
+const form s_10_4 = {2, 2, {{0,1}, {1,1}}};
+
+// Form 11 in allen Drehvarianten
+//
+// * * * *
+// *** *** *** ***
+// * * * *
+const form s_11_1 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+const form s_11_2 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+const form s_11_3 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+const form s_11_4 = {3, 3, {{0,1,0}, {1,1,1}, {0,1,0}}};
+
+// Form 12 in allen Drehvarianten
+//
+// ** ** * ***
+// ** *** ** **
+// * **
+const form s_12_1 = {3, 2, {{1,1}, {1,1}, {1,0}}};
+const form s_12_2 = {2, 3, {{1,1,0}, {1,1,1}}};
+const form s_12_3 = {3, 2, {{0,1}, {1,1}, {1,1}}};
+const form s_12_4 = {2, 3, {{1,1,1}, {0,1,1}}};
+
+// Form 13 in allen Drehvarianten
+//
+// ** *** * **
+// ** ** ** ***
+// * **
+const form s_13_1 = {3, 2, {{1,1}, {1,1}, {0,1}}};
+const form s_13_2 = {2, 3, {{1,1,1}, {1,1,0}}};
+const form s_13_3 = {3, 2, {{1,0}, {1,1}, {1,1}}};
+const form s_13_4 = {2, 3, {{0,1,1}, {1,1,1}}};
+
+// Form 14 in allen Drehvarianten
+//
+// *** * * ***
+// * * * *
+// * *** *** *
+const form s_14_1 = {3, 3, {{1,1,1}, {1,0,0}, {1,0,0}}};
+const form s_14_2 = {3, 3, {{1,0,0}, {1,0,0}, {1,1,1}}};
+const form s_14_3 = {3, 3, {{0,0,1}, {0,0,1}, {1,1,1}}};
+const form s_14_4 = {3, 3, {{1,1,1}, {0,0,1}, {0,0,1}}};
+
+// Form 15 in allen Drehvarianten
+//
+// * * * *
+const form s_15_1 = {1, 1, {{1}}};
+const form s_15_2 = {1, 1, {{1}}};
+const form s_15_3 = {1, 1, {{1}}};
+const form s_15_4 = {1, 1, {{1}}};
+
+// Form 16 in allen Drehvarianten
+//
+// * * * *
+// * * * *
+const form s_16_1 = {2, 2, {{1,0}, {0,1}}};
+const form s_16_2 = {2, 2, {{0,1}, {1,0}}};
+const form s_16_3 = {2, 2, {{1,0}, {0,1}}};
+const form s_16_4 = {2, 2, {{0,1}, {1,0}}};
+
+// Form 17 in allen Drehvarianten
+//
+// * * * *
+// * * * *
+// * * * *
+const form s_17_1 = {3, 3, {{1,0,0}, {0,1,0}, {0,0,1}}};
+const form s_17_2 = {3, 3, {{0,0,1}, {0,1,0}, {1,0,0}}};
+const form s_17_3 = {3, 3, {{1,0,0}, {0,1,0}, {0,0,1}}};
+const form s_17_4 = {3, 3, {{0,0,1}, {0,1,0}, {1,0,0}}};
+
+// Form 18 in allen Drehvarianten
+//
+// * * * *
+// * * * * * * * *
+// * * * *
+const form s_18_1 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+const form s_18_2 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+const form s_18_3 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+const form s_18_4 = {3, 3, {{0,1,0}, {1,0,1}, {0,1,0}}};
+
+// Form 19 in allen Drehvarianten
+//
+// * * * * *
+// * * * * *
+// * *
+const form s_19_1 = {2, 3, {{0,1,0}, {1,0,1}}};
+const form s_19_2 = {3, 2, {{0,1},{1,0},{0,1}}};
+const form s_19_3 = {2, 3, {{1,0,1}, {0,1,0}}};
+const form s_19_4 = {3, 2, {{1,0},{0,1},{1,0}}};
+
+// Form 20 in allen Drehvarianten
+//
+// *** * * *
+// * *** * ***
+// * * *** *
+const form s_20_1 = {3, 3, {{1,1,1}, {0,1,0}, {0,1,0}}};
+const form s_20_2 = {3, 3, {{1,0,0}, {1,1,1}, {1,0,0}}};
+const form s_20_3 = {3, 3, {{0,1,0}, {0,1,0}, {1,1,1}}};
+const form s_20_4 = {3, 3, {{0,0,1}, {1,1,1}, {0,0,1}}};
+
+// Form 21 in allen Drehvarianten
+//
+// * * * * *
+// * ** * **
+// * * * * *
+const form s_21_1 = {3, 3, {{1,0,1}, {0,1,0}, {0,1,0}}};
+const form s_21_2 = {3, 3, {{1,0,0}, {0,1,1}, {1,0,0}}};
+const form s_21_3 = {3, 3, {{0,1,0}, {0,1,0}, {1,0,1}}};
+const form s_21_4 = {3, 3, {{0,0,1}, {1,1,0}, {0,0,1}}};
+
+// Form 22 in allen Drehvarianten
+//
+// ** * ** *
+// * *
+//
+const form s_22_1 = {1, 2, {{1,1}}};
+const form s_22_2 = {2, 1, {{1},{1}}};
+const form s_22_3 = {1, 2, {{1,1}}};
+const form s_22_4 = {2, 1, {{1},{1}}};
+
+// Form 23 in allen Drehvarianten
+//
+// *** * *** *
+// * *
+// * *
+const form s_23_1 = {1, 3, {{1,1,1}}};
+const form s_23_2 = {3, 1, {{1},{1},{1}}};
+const form s_23_3 = {1, 3, {{1,1,1}}};
+const form s_23_4 = {3, 1, {{1},{1},{1}}};
+
+// Form 24 in allen Drehvarianten
+//
+// ** * * *
+// * * ** *
+// * *
+const form s_24_1 = {2, 3, {{1,1,0}, {0,0,1}}};
+const form s_24_2 = {3, 2, {{0,1}, {1,0}, {1,0}}};
+const form s_24_3 = {2, 3, {{1,0,0}, {0,1,1}}};
+const form s_24_4 = {3, 2, {{0,1}, {0,1}, {1,0}}};
+
+// Form 25 in allen Drehvarianten
+//
+// * * ** *
+// ** * * *
+// * *
+const form s_25_1 = {2, 3, {{0,0,1}, {1,1,0}}};
+const form s_25_2 = {3, 2, {{1,0}, {0,1}, {0,1}}};
+const form s_25_3 = {2, 3, {{0,1,1}, {1,0,0}}};
+const form s_25_4 = {3, 2, {{1,0}, {1,0}, {0,1}}};
+
+// Form 26 in allen Drehvarianten
+//
+// ** * ** *
+// ** * ** *
+// * *
+// * *
+const form s_26_1 = {2, 4, {{0,0,1,1}, {1,1,0,0}}};
+const form s_26_2 = {4, 2, {{1,0},{1,0},{0,1}, {0,1}}};
+const form s_26_3 = {2, 4, {{0,0,1,1}, {1,1,0,0}}};
+const form s_26_4 = {4, 2, {{1,0},{1,0},{0,1}, {0,1}}};
+
+// Form 27 in allen Drehvarianten
+//
+// ** * ** *
+// ** * ** *
+// * *
+// * *
+const form s_27_1 = {2, 4, {{1,1,0,0},{0,0,1,1}}};
+const form s_27_2 = {4, 2, {{0,1},{0,1},{1,0},{1,0}}};
+const form s_27_3 = {2, 4, {{1,1,0,0},{0,0,1,1}}};
+const form s_27_4 = {4, 2, {{0,1},{0,1},{1,0},{1,0}}};
+
+// Form 28 in allen Drehvarianten
+//
+// * * * ** *
+// ** * * * *
+// * *
+// * *
+const form s_28_1 = {2, 4, {{1,0,0,1},{0,1,1,0}}};
+const form s_28_2 = {4, 2, {{1,0},{0,1},{0,1},{1,0}}};
+const form s_28_3 = {2, 4, {{0,1,1,0},{1,0,0,1}}};
+const form s_28_4 = {4, 2, {{0,1},{1,0},{1,0},{0,1}}};
+
+// Form 29 in allen Drehvarianten
+//
+// ** * * **
+// * * * *
+// * ** ** *
+const form s_29_1 = {3, 3, {{0,1,1}, {1,0,0}, {1,0,0}}};
+const form s_29_2 = {3, 3, {{1,0,0}, {1,0,0}, {0,1,1}}};
+const form s_29_3 = {3, 3, {{0,0,1}, {0,0,1}, {1,1,0}}};
+const form s_29_4 = {3, 3, {{1,1,0}, {0,0,1}, {0,0,1}}};
+
+// Form 30 in allen Drehvarianten
+//
+// * ** * * **
+// * * * * * *
+// * * ** * **
+const form s_30_1 = {3, 3, {{0,1,0}, {1,0,1}, {1,0,1}}};
+const form s_30_2 = {3, 3, {{0,1,1}, {1,0,0}, {0,1,1}}};
+const form s_30_3 = {3, 3, {{1,0,1}, {1,0,1}, {0,1,0}}};
+const form s_30_4 = {3, 3, {{1,1,0}, {0,0,1}, {1,1,0}}};
+
+// Form 31 in allen Drehvarianten
+//
+// *** * * *
+// * * *** *
+// * *
+// * *
+const form s_31_1 = {2, 4, {{1,1,1,0},{0,0,0,1}}};
+const form s_31_2 = {4, 2, {{0,1},{1,0},{1,0},{1,0}}};
+const form s_31_3 = {2, 4, {{1,0,0,0},{0,1,1,1}}};
+const form s_31_4 = {4, 2, {{0,1},{0,1},{0,1},{1,0}}};
+
+// Form 32 in allen Drehvarianten
+//
+// * * *** *
+// *** * * *
+// * *
+// * *
+const form s_32_1 = {2, 4, {{0,0,0,1},{1,1,1,0}}};
+const form s_32_2 = {4, 2, {{1,0},{0,1},{0,1},{0,1}}};
+const form s_32_3 = {2, 4, {{0,1,1,1},{1,0,0,0}}};
+const form s_32_4 = {4, 2, {{1,0},{1,0},{1,0},{0,1}}};
+
+// Form 33 in allen Drehvarianten
+//
+// ** *** ** ***
+// ** *** ** ***
+// ** **
+const form s_33_1 = {3, 2, {{1,1}, {1,1}, {1,1}}};
+const form s_33_2 = {2, 3, {{1,1,1}, {1,1,1}}};
+const form s_33_3 = {3, 2, {{1,1}, {1,1}, {1,1}}};
+const form s_33_4 = {2, 3, {{1,1,1}, {1,1,1}}};
+
+// Form 34 in allen Drehvarianten
+//
+// **** * ** *
+// ** ** **** **
+// ** **
+// * *
+const form s_34_1 = {2, 4, {{1,1,1,1},{0,1,1,0}}};
+const form s_34_2 = {4, 2, {{1,0},{1,1},{1,1},{1,0}}};
+const form s_34_3 = {2, 4, {{0,1,1,0},{1,1,1,1}}};
+const form s_34_4 = {4, 2, {{0,1},{1,1},{1,1},{0,1}}};
+
+// Form 35 in allen Drehvarianten
+//
+// ** * ** *
+// * *** * ***
+// ** * ** *
+const form s_35_1 = {3, 3, {{0,1,1}, {0,1,0}, {1,1,0}}};
+const form s_35_2 = {3, 3, {{1,0,0}, {1,1,1}, {0,0,1}}};
+const form s_35_3 = {3, 3, {{0,1,1}, {0,1,0}, {1,1,0}}};
+const form s_35_4 = {3, 3, {{1,0,0}, {1,1,1}, {0,0,1}}};
+
+// Array mit allen Steinformen in allen Drehvarianten
+// Zugriff in der Form
+//
+// ultris_form[ steinform][ drehvariante]
+//
+// mit 0 <= steinform < 35 und 0 <= drehvariante <= 4
+
+const form *ultris_form[anzahl_formen][4] =
+ {
+ { &s_01_1, &s_01_2, &s_01_3, &s_01_4},
+ { &s_02_1, &s_02_2, &s_02_3, &s_02_4},
+ { &s_03_1, &s_03_2, &s_03_3, &s_03_4},
+ { &s_04_1, &s_04_2, &s_04_3, &s_04_4},
+ { &s_05_1, &s_05_2, &s_05_3, &s_05_4},
+ { &s_06_1, &s_06_2, &s_06_3, &s_06_4},
+ { &s_07_1, &s_07_2, &s_07_3, &s_07_4},
+ { &s_08_1, &s_08_2, &s_08_3, &s_08_4},
+ { &s_09_1, &s_09_2, &s_09_3, &s_09_4},
+ { &s_10_1, &s_10_2, &s_10_3, &s_10_4},
+ { &s_11_1, &s_11_2, &s_11_3, &s_11_4},
+ { &s_12_1, &s_12_2, &s_12_3, &s_12_4},
+ { &s_13_1, &s_13_2, &s_13_3, &s_13_4},
+ { &s_14_1, &s_14_2, &s_14_3, &s_14_4},
+ { &s_15_1, &s_15_2, &s_15_3, &s_15_4},
+ { &s_16_1, &s_16_2, &s_16_3, &s_16_4},
+ { &s_17_1, &s_17_2, &s_17_3, &s_17_4},
+ { &s_18_1, &s_18_2, &s_18_3, &s_18_4},
+ { &s_19_1, &s_19_2, &s_19_3, &s_19_4},
+ { &s_20_1, &s_20_2, &s_20_3, &s_20_4},
+ { &s_21_1, &s_21_2, &s_21_3, &s_21_4},
+ { &s_22_1, &s_22_2, &s_22_3, &s_22_4},
+ { &s_23_1, &s_23_2, &s_23_3, &s_23_4},
+ { &s_24_1, &s_24_2, &s_24_3, &s_24_4},
+ { &s_25_1, &s_25_2, &s_25_3, &s_25_4},
+ { &s_26_1, &s_26_2, &s_26_3, &s_26_4},
+ { &s_27_1, &s_27_2, &s_27_3, &s_27_4},
+ { &s_28_1, &s_28_2, &s_28_3, &s_28_4},
+ { &s_29_1, &s_29_2, &s_29_3, &s_29_4},
+ { &s_30_1, &s_30_2, &s_30_3, &s_30_4},
+ { &s_31_1, &s_31_2, &s_31_3, &s_31_4},
+ { &s_32_1, &s_32_2, &s_32_3, &s_32_4},
+ { &s_33_1, &s_33_2, &s_33_3, &s_33_4},
+ { &s_34_1, &s_34_2, &s_34_3, &s_34_4},
+ { &s_35_1, &s_35_2, &s_35_3, &s_35_4}
+ };
+
+
+// Array mit den aktuell im Spiel aktivierten Steinformen
+// Zu Programmstart sind dies die ueblichen Tetris Spielsteine (0-6)
+char aktive_formen[anzahl_formen] =
+ {
+ 1,1,1,1,1,1,1,
+ 0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0
+ };
+
+// Anzahl der aktuell aktivierten Steinformen
+int anz_aktive_formen = 7;
+
+// V8 Beginn
+// Punktwerte aller Steinformen
+const int formwert[anzahl_formen] =
+ {
+ 8,12,12,10,10,10, 6,
+ 25,25, 4,20,10,10,20,
+ 1, 8,25,40,15,25,35,
+ 2, 4,10,10,20,20,25,
+ 25,30,25,25,10,15,25
+ };
+
+class ultris
+ {
+ struct formwahl
+ {
+ int ix; // Index der Form
+ int dv; // Drehvariante der Form
+ };
+ private:
+ int vorbelegung; // Anzahl der bei Spielbeginn vorzubelegenden Zeilen
+ int vorschau; // Anzahl der Formen in der Vorschau
+ int spielfeld[20][10]; // Das Spielfeld
+ int fuellstand[20]; // Der Fuellstand einer Reihe (= Anzahl Segmente in der Reihe)
+ int punktestand; // Der aktuelle Punktestand
+ formwahl formen[6]; // 0 aktuelle Form, 1-5 Vorschau
+ int zeile;
+ int spalte;
+ int offset;
+ int sichtbar;
+ int zeige_dyn; // Zeige den dynamischen Anteil
+ void initialisieren();
+ void vorbelegen();
+ void display_spielfeld();
+ void display_punktestand();
+ void display_vorschau();
+ void display_form();
+ void naechste_form();
+ const form *aktuelle_form() {return ultris_form[formen[0].ix][formen[0].dv];}
+ public:
+ int spiel_laeuft; // Indikator, dass das Spiel laeuft
+ ultris(){ srand( GetTickCount()); initialisieren(); vorbelegung = 0; vorschau = 1;}
+ int get_vorbelegung() { return vorbelegung;}
+ void set_vorbelegung( int v) {if( v < 0) v = 0; if( v > 20) v = 20; vorbelegung = v;}
+ int get_vorschau() { return vorschau;}
+ void set_vorschau( int v) {if( v < 0) v = 0; if(v > 5) v = 5; vorschau = v;}
+ void start();
+ void display();
+ void neue_form();
+ };
+
+void ultris::initialisieren()
+ {
+ int z, s;
+
+ for( z = 0; z < 20; z++)
+ {
+ fuellstand[z] = 0;
+ for( s = 0; s < 10; s++)
+ spielfeld[z][s] = 0;
+ }
+ spiel_laeuft = 0;
+ zeige_dyn = 0;
+ punktestand = 0;
+ }
+// V8 Ende
+
+void ultris::vorbelegen()
+ {
+ int z, s, i;
+
+ for( i = 0; i < vorbelegung*5; i++)
+ {
+ z = 19-rand()%vorbelegung;
+ s = rand()%10;
+ if( !spielfeld[z][s])
+ {
+ spielfeld[z][s] = 1;
+ fuellstand[z]++;
+ }
+ }
+ punktestand = vorbelegung * 2500;
+ }
+
+// V8 Beginn
+void ultris::start()
+ {
+ ultris_sounds.play( sound_start);
+ initialisieren();
+ vorbelegen();
+ spiel_laeuft = 1;
+ naechste_form();
+ naechste_form();
+ naechste_form();
+ naechste_form();
+ naechste_form();
+ neue_form();
+ zeige_dyn = 1;
+ }
+// V8 Ende
+
+void ultris::display_spielfeld()
+ {
+ int z, s;
+
+ for( z = 0; z < 20; z++)
+ {
+ for( s = 0; s < 10; s++)
+ {
+ if( spielfeld[z][s])
+ ultris_display.feldstein( z, s);
+ }
+ }
+ }
+
+void ultris::display_punktestand()
+ {
+ int i, z, p;
+
+ for( i = 5, p = punktestand; i >= 0; i--, p/= 10)
+ {
+ z = p % 10;
+ ultris_display.ziffer( i, z);
+ }
+ }
+
+// V8 Beginn
+void ultris::display()
+ {
+ ultris_display.hintergrund();
+ display_spielfeld();
+ if( zeige_dyn)
+ {
+ display_vorschau();
+ display_form();
+ }
+// ultris_display.abdeckung();
+// display_punktestand();
+ ultris_display.present();
+ }
+
+void ultris::naechste_form()
+ {
+ int z, i, ix;
+
+ for( i = 0; i < 5; i++)
+ formen[i] = formen[i+1];
+
+ z = rand()%anz_aktive_formen+1;
+ for( ix = -1; z; z--)
+ {
+ while( !aktive_formen[++ix])
+ ;
+ }
+ formen[5].ix = ix;
+ formen[5].dv = rand()%4;
+ }
+
+void ultris::neue_form()
+ {
+ naechste_form();
+ zeile = -aktuelle_form()->h;
+ spalte = 5-(aktuelle_form()->b)/2;
+ offset = 0;
+ sichtbar = 0;
+ punktestand += formwert[formen[0].ix];
+ }
+
+void ultris::display_vorschau()
+ {
+ int z, s, p, y;
+ const form *f;
+
+ if( !sichtbar)
+ sichtbar = (zeile >= 0);
+
+ for( y = 0, p = sichtbar; y < vorschau; p++, y++)
+ {
+ f = ultris_form[formen[p].ix][formen[p].dv];
+ for( z = 0; z < f->h; z++)
+ {
+ for( s = 0; s < f->b; s++)
+ {
+ if( f->data[z][s])
+ ultris_display.prevstein(y, z, s, f->b, f->h);
+ }
+ }
+ }
+ }
+
+void ultris::display_form()
+ {
+ int z, s;
+
+ for( z = 0; z < aktuelle_form()->h; z++)
+ {
+ for( s = 0; s < aktuelle_form()->b; s++)
+ {
+ if( aktuelle_form()->data[z][s])
+ {
+ ultris_display.fallstein( zeile+z, spalte+s, offset);
+ }
+ }
+ }
+ }
+
+// V8 Ende
+
+ultris mein_spiel;
+
+
+BOOL CALLBACK hilfedialog( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ switch (uMsg)
+ {
+ case WM_COMMAND:
+ if((wParam == IDOK)||(wParam == IDCANCEL))
+ {
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+BOOL CALLBACK ultrisdialog( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ switch (uMsg)
+ {
+ case WM_COMMAND:
+ if( wParam == IDC_WEITERE_INFO)
+ {
+ ShellExecute(NULL, "open", "http://www-et.bocholt.fh-gelsenkirchen.de", NULL, NULL, SW_SHOWNORMAL);
+ return TRUE;
+ }
+ if((wParam == IDOK)||(wParam == IDCANCEL))
+ {
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+BOOL CALLBACK konfigurationsdialog( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+ {
+ int i;
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ for( i = 0; i < anzahl_formen; i++)
+ CheckDlgButton( hwndDlg, 5000+i, aktive_formen[i] ? BST_CHECKED : BST_UNCHECKED);
+ SetDlgItemInt( hwndDlg, IDC_VORBELEGUNG, mein_spiel.get_vorbelegung(), FALSE);
+ SetDlgItemInt( hwndDlg, IDC_VORSCHAU, mein_spiel.get_vorschau(), FALSE);
+ return TRUE;
+ case WM_COMMAND:
+ if(wParam == IDOK)
+ {
+ for( i = 0, anz_aktive_formen = 0; i < anzahl_formen; i++)
+ {
+ aktive_formen[i] = 0;
+ if(IsDlgButtonChecked( hwndDlg, 5000+i) == BST_CHECKED)
+ {
+ aktive_formen[i] = 1;
+ anz_aktive_formen++;
+ }
+ }
+ if( anz_aktive_formen == 0)
+ {
+ aktive_formen[0] = 1;
+ anz_aktive_formen = 1;
+ }
+ mein_spiel.set_vorbelegung( GetDlgItemInt( hwndDlg, IDC_VORBELEGUNG, NULL, FALSE));
+ mein_spiel.set_vorschau( GetDlgItemInt( hwndDlg, IDC_VORSCHAU, NULL, FALSE));
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ }
+ if(wParam == IDCANCEL)
+ {
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ }
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ switch( LOWORD(wParam))
+ {
+ case IDC_LOESCHEN:
+ for( i = 0; i < anzahl_formen; i++)
+ CheckDlgButton( hwndDlg, 5000+i, BST_UNCHECKED);
+ return TRUE;
+ case IDC_ALLE:
+ for( i = 0; i < anzahl_formen; i++)
+ CheckDlgButton( hwndDlg, 5000+i, BST_CHECKED);
+ return TRUE;
+ case IDC_STANDARD:
+ for( i = 0; i < anzahl_formen; i++)
+ CheckDlgButton( hwndDlg, 5000+i, i < 7 ? BST_CHECKED:BST_UNCHECKED);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+ }
+
+/*
+** ultris_windowhandler
+*/
+
+LRESULT CALLBACK ultris_windowhandler( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+ {
+ switch(msg)
+ {
+ case WM_COMMAND:
+ switch( LOWORD( wParam))
+ {
+ case IDM_EXIT:
+ PostMessage( hWnd, WM_CLOSE, 0, 0);
+ return 0;
+ case ID_ULTRIS_SOUND:
+ ultris_sounds.on = !ultris_sounds.on;
+ CheckMenuItem( ultris_menu, ID_ULTRIS_SOUND, ultris_sounds.on ? MF_CHECKED:MF_UNCHECKED);
+ return 0;
+ case ID_INFO_HILFE:
+ DialogBox( ultris_instance, MAKEINTRESOURCE( IDD_HILFE), ultris_window, hilfedialog);
+ return 0;
+ case ID_INFO_ULTRIS:
+ DialogBox( ultris_instance, MAKEINTRESOURCE( IDD_ULTRIS), ultris_window, ultrisdialog);
+ return 0;
+ case ID_EINSTELLUNGEN_KONFIGURATION:
+ DialogBox( ultris_instance, MAKEINTRESOURCE( IDD_KONFIGURATION), ultris_window, konfigurationsdialog);
+ return 0;
+ case ID_ULTRIS_NEUESSPIEL:
+ mein_spiel.start();
+ CheckMenuItem( ultris_menu, ID_ULTRIS_PAUSE, MF_UNCHECKED);
+ PostMessage( ultris_window, WM_PAINT, 0, 0);
+ break;
+ case IDM_TEST: // Testcode
+// V8 Beginn
+ mein_spiel.neue_form();
+ PostMessage( ultris_window, WM_PAINT, 0, 0);
+ return 0;
+// V8 Ende
+ }
+ break;
+ case WM_GETMINMAXINFO:
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.x = ((MINMAXINFO *)lParam)->ptMaxTrackSize.x = ultris_bruttobreite;
+ ((MINMAXINFO *)lParam)->ptMinTrackSize.y = ((MINMAXINFO *)lParam)->ptMaxTrackSize.y = ultris_bruttohoehe;
+ return 0;
+ case WM_DESTROY:
+ PostQuitMessage( 0);
+ return 0;
+ case WM_MOVE:
+ ultris_display.update();
+ return 0;
+ case WM_PAINT:
+ mein_spiel.display();
+ break;
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+ }
+
+/*
+** WinMain
+*/
+int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow)
+ {
+ MSG msg;
+ HACCEL acc;
+ WNDCLASSEX wcx;
+
+ ultris_instance = hInst;
+
+ wcx.cbSize = sizeof( wcx);
+ wcx.lpszClassName = TEXT( "Ultris");
+ wcx.lpfnWndProc = ultris_windowhandler;
+ wcx.style = CS_VREDRAW | CS_HREDRAW;
+ wcx.hInstance = hInst;
+ wcx.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hIconSm = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MAIN));
+ wcx.hCursor = LoadCursor( NULL, IDC_ARROW);
+ wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wcx.lpszMenuName = MAKEINTRESOURCE( IDR_MENU);
+ wcx.cbClsExtra = 0;
+ wcx.cbWndExtra = 0;
+
+ if( !RegisterClassEx( &wcx))
+ return 0;
+
+ acc = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_ACCEL));
+
+ ultris_bruttohoehe = ultris_nettohoehe + 2*GetSystemMetrics( SM_CYSIZEFRAME)
+ + GetSystemMetrics( SM_CYMENU)
+ + GetSystemMetrics( SM_CYCAPTION);
+ ultris_bruttobreite = ultris_nettobreite + 2*GetSystemMetrics( SM_CXSIZEFRAME);
+
+ ultris_window = CreateWindowEx( 0, TEXT( "Ultris"), TEXT( "Ultris"), WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ ultris_bruttobreite, ultris_bruttohoehe, NULL, NULL, hInst, NULL);
+ if( !ultris_window)
+ return 0;
+
+ ultris_menu = GetMenu( ultris_window);
+
+ if( ultris_sounds.init( ultris_window) < 0)
+ {
+ MessageBox( ultris_window, "Fehler beim Initialisieren der Sounds", "Ultris-Fehlermeldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
+ return 0;
+ }
+ CheckMenuItem( ultris_menu, ID_ULTRIS_SOUND, ultris_sounds.on ? MF_CHECKED:MF_UNCHECKED);
+
+ if( ultris_display.init( ultris_window) < 0)
+ {
+ MessageBox( ultris_window, "Fehler beim Initialisieren der Grafik", "Ultris-Fehlermeldung", MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
+ return 0;
+ }
+
+ MoveWindow( ultris_window, (GetSystemMetrics(SM_CXSCREEN)-ultris_bruttobreite)/2,
+ (GetSystemMetrics(SM_CYSCREEN)-ultris_bruttohoehe)/2,
+ ultris_bruttobreite, ultris_bruttohoehe, TRUE);
+
+ ShowWindow( ultris_window, nCmdShow);
+
+ while( TRUE)
+ {
+ if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE))
+ {
+ if( GetMessage( &msg, NULL, 0, 0 ) == 0)
+ return 0; // Message ist WM_QUIT
+
+ if( TranslateAccelerator( ultris_window, acc, &msg) == 0)
+ {
+ TranslateMessage( &msg);
+ DispatchMessage( &msg);
+ }
+ }
+ else
+ {
+ HRESULT hr;
+ hr = ultris_display.cooperative();
+ if( hr < 0)
+ {
+ switch( hr )
+ {
+ case DDERR_EXCLUSIVEMODEALREADYSET:
+ Sleep(10);
+ break;
+ case DDERR_WRONGMODE:
+ ultris_display.free_all();
+ ultris_display.init( ultris_window);
+ PostMessage( ultris_window, WM_PAINT, 0, 0);
+ break;
+ }
+ }
+ else
+ {
+ // Hier koennen wir uns um das Spiel kuemmern
+ }
+ }
+ }
+ }
+
+
+
diff --git a/V08/Demo.h b/V08/Demo.h
new file mode 100644
index 0000000..a19fa69
--- /dev/null
+++ b/V08/Demo.h
@@ -0,0 +1,12 @@
+
+#if !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
+#define AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "resource.h"
+
+
+#endif // !defined(AFX_DEMO_H__6F0BC346_A022_4D9B_B04C_63C781695029__INCLUDED_)
diff --git a/V08/Demo.ncb b/V08/Demo.ncb
new file mode 100644
index 0000000..00907f3
Binary files /dev/null and b/V08/Demo.ncb differ
diff --git a/V08/Demo.plg b/V08/Demo.plg
new file mode 100644
index 0000000..85bcc9b
--- /dev/null
+++ b/V08/Demo.plg
@@ -0,0 +1,36 @@
+
+
+
+Erstellungsprotokoll
+
+--------------------Konfiguration: Demo - Win32 Debug--------------------
+
+Befehlszeilen
+Erstellen der temporären Datei "C:\DOKUME~1\uk\LOKALE~1\Temp\RSP34.tmp" mit Inhalten
+[
+/nologo /MLd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c
+"C:\uk\FHG\Vorlesungen\GSP\Programme\Ultris\V08\Demo.cpp"
+]
+Creating command line "cl.exe @C:\DOKUME~1\uk\LOKALE~1\Temp\RSP34.tmp"
+Erstellen der temporären Datei "C:\DOKUME~1\uk\LOKALE~1\Temp\RSP35.tmp" mit Inhalten
+[
+winmm.lib dxguid.lib dxerr8.lib ddraw.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib dsound.lib /nologo /subsystem:windows /incremental:yes /pdb:"Debug/Ultris.pdb" /debug /machine:I386 /out:"Debug/Ultris.exe" /pdbtype:sept
+.\Debug\Demo.obj
+.\Debug\ddutil.obj
+.\Debug\dsutil.obj
+.\Debug\dxutil.obj
+.\Debug\Demo.res
+]
+Erstellen der Befehlzeile "link.exe @C:\DOKUME~1\uk\LOKALE~1\Temp\RSP35.tmp"
+Ausgabefenster
+Kompilierung läuft...
+Demo.cpp
+Linker-Vorgang läuft...
+
+
+
+Ergebnisse
+Ultris.exe - 0 Fehler, 0 Warnung(en)
+
+
+
diff --git a/V08/Demo.rc b/V08/Demo.rc
new file mode 100644
index 0000000..0425332
--- /dev/null
+++ b/V08/Demo.rc
@@ -0,0 +1,687 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include
+#include
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Deutsch (Deutschland) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
+#ifdef _WIN32
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU MENU DISCARDABLE
+BEGIN
+ POPUP "Ultris"
+ BEGIN
+ MENUITEM "Neues Spiel", ID_ULTRIS_NEUESSPIEL
+ MENUITEM "Pause", ID_ULTRIS_PAUSE
+ MENUITEM "Sound", ID_ULTRIS_SOUND
+ MENUITEM SEPARATOR
+ MENUITEM "Ende", IDM_EXIT
+ END
+ POPUP "Einstellungen"
+ BEGIN
+ MENUITEM "Konfiguration", ID_EINSTELLUNGEN_KONFIGURATION
+
+ END
+ POPUP "Info"
+ BEGIN
+ MENUITEM "Hilfe", ID_INFO_HILFE
+ MENUITEM "Highscores", ID_INFO_HIGHSCORES
+ MENUITEM "Ultris", ID_INFO_ULTRIS
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MAIN ICON DISCARDABLE "Icon.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCEL ACCELERATORS DISCARDABLE
+BEGIN
+ "T", IDM_TEST, VIRTKEY, CONTROL, NOINVERT
+ VK_ESCAPE, IDM_EXIT, VIRTKEY, NOINVERT
+ VK_F1, ID_ULTRIS_NEUESSPIEL, VIRTKEY, NOINVERT
+ VK_F5, ID_ULTRIS_SOUND, VIRTKEY, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_HILFE DIALOG DISCARDABLE 0, 0, 302, 107
+STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Hilfe"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,245,90,50,14
+ LTEXT "F1: Neues Spiel",IDC_STATIC,15,22,130,8
+ LTEXT "F2: Pause (ein/aus)",IDC_STATIC,15,34,130,8
+ LTEXT "F3: Schneller",IDC_STATIC,15,46,130,8
+ LTEXT "F4: Langsamer",IDC_STATIC,15,58,130,8
+ LTEXT "F5: Sound (ein/aus)",IDC_STATIC,15,70,130,8
+ GROUPBOX "Steuerung des Spiels",IDC_STATIC,7,7,142,78
+ GROUPBOX "Steuerung der Steine",IDC_STATIC,153,7,142,78
+ LTEXT "J oder Cursor left: Links",IDC_STATIC,159,22,131,8
+ LTEXT "L oder Cursor right: Rechts",IDC_STATIC,159,34,131,8
+ LTEXT "K oder Cursor down: Linksdrehung",IDC_STATIC,159,46,131,
+ 8
+ LTEXT "I oder Cursor up: Rechtsdrehung",IDC_STATIC,159,58,131,
+ 8
+ LTEXT "Space: Stein fallen lassen",IDC_STATIC,159,70,126,8
+END
+
+IDD_ULTRIS DIALOG DISCARDABLE 0, 0, 204, 142
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Über Ultris"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,150,125,50,14
+ CONTROL 130,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_SUNKEN | WS_BORDER,7,7,190,78
+ CTEXT "Demoprogramm\rzur Vorlesung\rGrafik und Spieleprogrammierung",
+ IDC_STATIC,7,92,195,28
+ PUSHBUTTON "Weitere Informationen",IDC_WEITERE_INFO,5,125,140,14
+END
+
+IDD_KONFIGURATION DIALOGEX 0, 0, 289, 297
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Einstellungen"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,235,280,50,14
+ PUSHBUTTON "Abbrechen",IDCANCEL,180,280,50,14
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,10,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,30,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,20,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,20,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE | WS_BORDER,50,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE | WS_BORDER,60,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE | WS_BORDER,60,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE | WS_BORDER,70,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,110,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,90,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,150,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,170,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,180,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,190,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,190,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,215,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,225,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,215,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,225,30,10,10
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,40,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,30,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,20,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,10,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,50,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,60,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,70,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,70,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,20,65,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,95,65,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,105,65,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,95,75,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,10,65,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,30,65,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,10,75,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,30,75,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,50,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,150,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,230,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,25,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,215,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,225,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,215,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,225,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,225,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,55,125,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,65,115,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,110,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,185,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,90,130,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,130,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,60,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,80,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,185,70,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,20,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,150,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,130,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,170,125,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,180,115,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,190,125,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,70,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,210,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,130,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,120,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,230,160,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,110,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,190,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,50,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,60,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,170,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,110,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,90,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,15,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,180,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,150,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,180,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,230,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,190,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,170,160,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,180,190,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,170,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,160,10,10
+ CONTROL "",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,
+ 43,8,8
+ CONTROL "",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,74,
+ 43,8,8
+ CONTROL "",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,
+ 43,8,8
+ CONTROL "10",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 154,43,8,8
+ CONTROL "",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,
+ 43,8,8
+ CONTROL "",IDC_CHECK6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,234,
+ 43,8,8
+ CONTROL "6",IDC_CHECK7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,274,
+ 43,8,8
+ CONTROL "",IDC_CHECK8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,
+ 93,8,8
+ CONTROL "",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,74,
+ 93,8,8
+ CONTROL "",IDC_CHECK10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,
+ 93,8,8
+ CONTROL "",IDC_CHECK11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,
+ 93,8,8
+ CONTROL "",IDC_CHECK12,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,
+ 93,8,8
+ CONTROL "",IDC_CHECK13,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,234,
+ 93,8,8
+ CONTROL "20",IDC_CHECK14,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 274,93,8,8
+ CONTROL "",IDC_CHECK15,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,
+ 143,8,8
+ CONTROL "",IDC_CHECK16,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,74,
+ 143,8,8
+ CONTROL "",IDC_CHECK17,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,
+ 143,8,8
+ CONTROL "",IDC_CHECK18,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,
+ 143,8,8
+ CONTROL "",IDC_CHECK19,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,
+ 143,8,8
+ CONTROL "",IDC_CHECK20,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,234,
+ 143,8,8
+ CONTROL "",IDC_CHECK21,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,274,
+ 143,8,8
+ CONTROL "",IDC_CHECK22,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,
+ 193,8,8
+ CONTROL "",IDC_CHECK23,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,74,
+ 193,8,8
+ CONTROL "",IDC_CHECK24,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,
+ 193,8,8
+ CONTROL "",IDC_CHECK25,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,
+ 193,8,8
+ CONTROL "",IDC_CHECK26,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,
+ 193,8,8
+ CONTROL "",IDC_CHECK27,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,234,
+ 193,8,8
+ CONTROL "",IDC_CHECK28,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,274,
+ 193,8,8
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,45,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,85,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,125,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,165,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,205,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,245,5,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,45,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,85,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,125,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,165,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,205,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,245,55,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,45,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,85,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,125,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,165,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,205,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,245,105,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,45,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,85,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,125,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,165,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,205,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,245,155,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,30,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,50,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,185,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,10,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,10,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,110,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,50,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,70,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,185,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,70,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,240,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,20,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,100,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,185,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,240,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,130,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,140,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,175,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,210,10,10
+ CONTROL "",IDC_CHECK29,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,
+ 243,8,8
+ CONTROL "",IDC_CHECK30,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,74,
+ 243,8,8
+ CONTROL "",IDC_CHECK31,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,
+ 243,8,8
+ CONTROL "",IDC_CHECK32,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,154,
+ 243,8,8
+ CONTROL "",IDC_CHECK33,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,194,
+ 243,8,8
+ CONTROL "",IDC_CHECK34,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,234,
+ 243,8,8
+ CONTROL "",IDC_CHECK35,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,274,
+ 243,8,8
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,5,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,45,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,85,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,125,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,165,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,205,205,40,50,
+ WS_EX_DLGMODALFRAME
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,245,205,40,50,
+ WS_EX_DLGMODALFRAME
+ PUSHBUTTON "Alle auswählen",IDC_ALLE,235,260,50,14
+ PUSHBUTTON "Standard",IDC_STANDARD,180,260,50,14
+ PUSHBUTTON "Alle Löschen",IDC_LOESCHEN,125,260,50,14
+ EDITTEXT IDC_VORBELEGUNG,105,260,15,14,ES_RIGHT | ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "Vorbelegte Zeilen bei Spielstart:",IDC_STATIC,5,260,95,
+ 13,SS_CENTERIMAGE
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,220,240,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,230,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,230,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,210,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,250,230,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,260,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,270,220,10,10
+ CONTROL 126,IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ WS_BORDER,60,210,10,10
+ LTEXT "1",IDC_STATIC,11,143,8,8
+ LTEXT "2",IDC_STATIC,10,193,8,8
+ LTEXT "4",IDC_STATIC,50,193,8,8
+ LTEXT "6",IDC_STATIC,250,43,8,8
+ LTEXT "8",IDC_STATIC,10,43,8,8
+ LTEXT "10",IDC_STATIC,130,43,8,8
+ LTEXT "10",IDC_STATIC,170,43,8,8
+ LTEXT "12",IDC_STATIC,50,43,8,8
+ LTEXT "12",IDC_STATIC,90,43,8,8
+ LTEXT "10",IDC_STATIC,210,43,8,8
+ LTEXT "25",IDC_STATIC,10,93,8,8
+ LTEXT "25",IDC_STATIC,50,93,8,8
+ LTEXT "4",IDC_STATIC,90,93,8,8
+ LTEXT "20",IDC_STATIC,130,93,8,8
+ LTEXT "10",IDC_STATIC,170,93,8,8
+ LTEXT "10",IDC_STATIC,210,93,8,8
+ LTEXT "20",IDC_STATIC,250,93,8,8
+ LTEXT "8",IDC_STATIC,50,143,8,8
+ LTEXT "25",IDC_STATIC,90,143,8,8
+ LTEXT "40",IDC_STATIC,130,143,8,8
+ LTEXT "15",IDC_STATIC,170,143,8,8
+ LTEXT "25",IDC_STATIC,210,143,8,8
+ LTEXT "35",IDC_STATIC,250,143,8,8
+ LTEXT "10",IDC_STATIC,90,193,8,8
+ LTEXT "10",IDC_STATIC,130,193,8,8
+ LTEXT "20",IDC_STATIC,170,193,8,8
+ LTEXT "20",IDC_STATIC,210,193,8,8
+ LTEXT "25",IDC_STATIC,250,193,8,8
+ LTEXT "25",IDC_STATIC,10,243,8,8
+ LTEXT "30",IDC_STATIC,50,243,8,8
+ LTEXT "25",IDC_STATIC,90,243,8,8
+ LTEXT "25",IDC_STATIC,130,243,8,8
+ LTEXT "10",IDC_STATIC,170,243,8,8
+ LTEXT "15",IDC_STATIC,210,243,8,8
+ LTEXT "25",IDC_STATIC,250,243,8,8
+ EDITTEXT IDC_VORSCHAU,105,280,15,14,ES_RIGHT | ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "Steine in der Vorschau:",IDC_STATIC,5,280,95,13,
+ SS_CENTERIMAGE
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_HILFE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 295
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 100
+ END
+
+ IDD_ULTRIS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 197
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 135
+ END
+
+ IDD_KONFIGURATION, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 282
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 290
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_ULTRIS BITMAP DISCARDABLE "bmp00001.bmp"
+IDB_STEIN BITMAP DISCARDABLE "bmp00002.bmp"
+#endif // Deutsch (Deutschland) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Englisch (USA) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include \r\n"
+ "#include \0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Englisch (USA) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/V08/Demo.sln b/V08/Demo.sln
new file mode 100644
index 0000000..c137588
--- /dev/null
+++ b/V08/Demo.sln
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Demo", "Demo.vcproj", "{E46624DC-B8A8-4BE8-8415-45D7319D1F9F}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {E46624DC-B8A8-4BE8-8415-45D7319D1F9F}.Debug.ActiveCfg = Debug|Win32
+ {E46624DC-B8A8-4BE8-8415-45D7319D1F9F}.Debug.Build.0 = Debug|Win32
+ {E46624DC-B8A8-4BE8-8415-45D7319D1F9F}.Release.ActiveCfg = Release|Win32
+ {E46624DC-B8A8-4BE8-8415-45D7319D1F9F}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/V08/Demo.suo b/V08/Demo.suo
new file mode 100644
index 0000000..eed695f
Binary files /dev/null and b/V08/Demo.suo differ
diff --git a/V08/Demo.vcproj b/V08/Demo.vcproj
new file mode 100644
index 0000000..98ce341
--- /dev/null
+++ b/V08/Demo.vcproj
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/V08/Icon.ico b/V08/Icon.ico
new file mode 100644
index 0000000..7a53f63
Binary files /dev/null and b/V08/Icon.ico differ
diff --git a/V08/bmp00001.bmp b/V08/bmp00001.bmp
new file mode 100644
index 0000000..12d2027
Binary files /dev/null and b/V08/bmp00001.bmp differ
diff --git a/V08/bmp00002.bmp b/V08/bmp00002.bmp
new file mode 100644
index 0000000..92b8396
Binary files /dev/null and b/V08/bmp00002.bmp differ
diff --git a/V08/ddutil.cpp b/V08/ddutil.cpp
new file mode 100644
index 0000000..faccc24
--- /dev/null
+++ b/V08/ddutil.cpp
@@ -0,0 +1,1035 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: DirectDraw framewark classes. Feel free to use this class as a
+// starting point for adding extra functionality.
+//
+//
+// Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include
+#include "ddutil.h"
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::CDisplay()
+{
+ m_pDD = NULL;
+ m_pddsFrontBuffer = NULL;
+ m_pddsBackBuffer = NULL;
+ m_pddsBackBufferLeft = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ~CDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+CDisplay::~CDisplay()
+{
+ DestroyObjects();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DestroyObjects()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::DestroyObjects()
+{
+ SAFE_RELEASE( m_pddsBackBufferLeft );
+ SAFE_RELEASE( m_pddsBackBuffer );
+ SAFE_RELEASE( m_pddsFrontBuffer );
+
+ if( m_pDD )
+ m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL );
+
+ SAFE_RELEASE( m_pDD );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateFullScreenDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth,
+ DWORD dwHeight, DWORD dwBPP )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ // Set the display mode
+ if( FAILED( m_pDD->SetDisplayMode( dwWidth, dwHeight, dwBPP, 0, 0 ) ) )
+ return E_FAIL;
+
+ // Create primary surface (with backbuffer attached)
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
+ DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE;
+ ddsd.dwBackBufferCount = 1;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer,
+ NULL ) ) )
+ return E_FAIL;
+
+ // Get a pointer to the back buffer
+ DDSCAPS2 ddscaps;
+ ZeroMemory( &ddscaps, sizeof( ddscaps ) );
+ ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
+
+ if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
+ &m_pddsBackBuffer ) ) )
+ return E_FAIL;
+
+ m_pddsBackBuffer->AddRef();
+
+ m_hWnd = hWnd;
+ m_bWindowed = FALSE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateWindowedDisplay()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight )
+{
+ HRESULT hr;
+
+ // Cleanup anything from a previous call
+ DestroyObjects();
+
+ // DDraw stuff begins here
+ if( FAILED( hr = DirectDrawCreateEx( NULL, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ return E_FAIL;
+
+ // Set cooperative level
+ hr = m_pDD->SetCooperativeLevel( hWnd, DDSCL_NORMAL );
+ if( FAILED(hr) )
+ return E_FAIL;
+
+ RECT rcWork;
+ RECT rc;
+ DWORD dwStyle;
+
+ // If we are still a WS_POPUP window we should convert to a normal app
+ // window so we look like a windows app.
+ dwStyle = GetWindowStyle( hWnd );
+ dwStyle &= ~WS_POPUP;
+ dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
+ SetWindowLong( hWnd, GWL_STYLE, dwStyle );
+
+ // Aet window size
+ SetRect( &rc, 0, 0, dwWidth, dwHeight );
+
+ AdjustWindowRectEx( &rc, GetWindowStyle(hWnd), GetMenu(hWnd) != NULL,
+ GetWindowExStyle(hWnd) );
+
+ SetWindowPos( hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
+ SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
+
+ // Make sure our window does not hang outside of the work area
+ SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWork, 0 );
+ GetWindowRect( hWnd, &rc );
+ if( rc.left < rcWork.left ) rc.left = rcWork.left;
+ if( rc.top < rcWork.top ) rc.top = rcWork.top;
+ SetWindowPos( hWnd, NULL, rc.left, rc.top, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
+
+ LPDIRECTDRAWCLIPPER pcClipper;
+
+ // Create the primary surface
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+ if( FAILED( m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
+ return E_FAIL;
+
+ // Create the backbuffer surface
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) )
+ return E_FAIL;
+
+ if( FAILED( hr = pcClipper->SetHWnd( 0, hWnd ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pcClipper ) ) )
+ {
+ pcClipper->Release();
+ return E_FAIL;
+ }
+
+ // Done with clipper
+ pcClipper->Release();
+
+ m_hWnd = hWnd;
+ m_bWindowed = TRUE;
+ UpdateBounds();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurface( CSurface** ppSurface,
+ DWORD dwWidth, DWORD dwHeight )
+{
+ if( NULL == m_pDD )
+ return E_POINTER;
+ if( NULL == ppSurface )
+ return E_INVALIDARG;
+
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof( ddsd ) );
+ ddsd.dwSize = sizeof( ddsd );
+ ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = dwWidth;
+ ddsd.dwHeight = dwHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromBitmap()
+// Desc: Create a DirectDrawSurface from a bitmap resource or bitmap file.
+// Use MAKEINTRESOURCE() to pass a constant into strBMP.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromBitmap( CSurface** ppSurface,
+ TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight )
+{
+ HRESULT hr;
+ HBITMAP hBMP = NULL;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+
+ if( m_pDD == NULL || strBMP == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = bmp.bmWidth;
+ ddsd.dwHeight = bmp.bmHeight;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = (*ppSurface)->DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::CreateSurfaceFromText()
+// Desc: Creates a DirectDrawSurface from a text string using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreateSurfaceFromText( CSurface** ppSurface,
+ HFONT hFont, TCHAR* strText,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ LPDIRECTDRAWSURFACE7 pDDS = NULL;
+ HRESULT hr;
+ DDSURFACEDESC2 ddsd;
+ SIZE sizeText;
+
+ if( m_pDD == NULL || strText == NULL || ppSurface == NULL )
+ return E_INVALIDARG;
+
+ *ppSurface = NULL;
+
+ hDC = GetDC( NULL );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ GetTextExtentPoint32( hDC, strText, _tcslen(strText), &sizeText );
+ ReleaseDC( NULL, hDC );
+
+ // Create a DirectDrawSurface for this bitmap
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ ddsd.dwWidth = sizeText.cx;
+ ddsd.dwHeight = sizeText.cy;
+
+ (*ppSurface) = new CSurface();
+ if( FAILED( hr = (*ppSurface)->Create( m_pDD, &ddsd ) ) )
+ {
+ delete (*ppSurface);
+ return hr;
+ }
+
+ if( FAILED( hr = (*ppSurface)->DrawText( hFont, strText, 0, 0,
+ crBackground, crForeground ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Present()
+{
+ HRESULT hr;
+
+ if( NULL == m_pddsFrontBuffer && NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ while( 1 )
+ {
+ if( m_bWindowed )
+ hr = m_pddsFrontBuffer->Blt( &m_rcWindow, m_pddsBackBuffer,
+ NULL, DDBLT_WAIT, NULL );
+ else
+ hr = m_pddsFrontBuffer->Flip( NULL, 0 );
+
+ if( hr == DDERR_SURFACELOST )
+ {
+ m_pddsFrontBuffer->Restore();
+ m_pddsBackBuffer->Restore();
+ }
+
+ if( hr != DDERR_WASSTILLDRAWING )
+ return hr;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer || NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Set the palette before loading the bitmap
+ if( pPalette )
+ m_pddsFrontBuffer->SetPalette( pPalette );
+
+ CSurface backBuffer;
+ backBuffer.Create( m_pddsBackBuffer );
+
+ if( FAILED( backBuffer.DrawBitmap( hbm, 0, 0, 0, 0 ) ) )
+ return E_FAIL;
+
+ return Present();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, DDBLTFAST_SRCCOLORKEY );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds, RECT* prc,
+ DWORD dwFlags )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ return m_pddsBackBuffer->BltFast( x, y, pdds, prc, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc )
+{
+ if( NULL == pSurface )
+ return E_INVALIDARG;
+
+ if( pSurface->IsColorKeyed() )
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, DDBLTFAST_SRCCOLORKEY );
+ else
+ return Blt( x, y, pSurface->GetDDrawSurface(), prc, 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::Clear( DWORD dwColor )
+{
+ if( NULL == m_pddsBackBuffer )
+ return E_POINTER;
+
+ // Erase the background
+ DDBLTFX ddbltfx;
+ ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
+ ddbltfx.dwSize = sizeof(ddbltfx);
+ ddbltfx.dwFillColor = dwColor;
+
+ return m_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL, &ddbltfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::SetPalette( LPDIRECTDRAWPALETTE pPalette )
+{
+ if( NULL == m_pddsFrontBuffer )
+ return E_POINTER;
+
+ return m_pddsFrontBuffer->SetPalette( pPalette );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette,
+ const TCHAR* strBMP )
+{
+ HRSRC hResource = NULL;
+ RGBQUAD* pRGB = NULL;
+ BITMAPINFOHEADER* pbi = NULL;
+ PALETTEENTRY aPalette[256];
+ HANDLE hFile = NULL;
+ DWORD iColor;
+ DWORD dwColors;
+ BITMAPFILEHEADER bf;
+ BITMAPINFOHEADER bi;
+ DWORD dwBytesRead;
+
+ if( m_pDD == NULL || strBMP == NULL || ppPalette == NULL )
+ return E_INVALIDARG;
+
+ *ppPalette = NULL;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hResource = FindResource( NULL, strBMP, RT_BITMAP );
+ if( hResource )
+ {
+ pbi = (LPBITMAPINFOHEADER) LockResource( LoadResource( NULL, hResource ) );
+ if( NULL == pbi )
+ return E_FAIL;
+
+ pRGB = (RGBQUAD*) ( (BYTE*) pbi + pbi->biSize );
+
+ // Figure out how many colors there are
+ if( pbi == NULL || pbi->biSize < sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if( pbi->biBitCount > 8 )
+ dwColors = 0;
+ else if( pbi->biClrUsed == 0 )
+ dwColors = 1 << pbi->biBitCount;
+ else
+ dwColors = pbi->biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around.
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ aPalette[iColor].peRed = pRGB[iColor].rgbRed;
+ aPalette[iColor].peGreen = pRGB[iColor].rgbGreen;
+ aPalette[iColor].peBlue = pRGB[iColor].rgbBlue;
+ aPalette[iColor].peFlags = 0;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+ }
+
+ // Attempt to load bitmap as a file
+ hFile = CreateFile( strBMP, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL );
+ if( NULL == hFile )
+ return E_FAIL;
+
+ // Read the BITMAPFILEHEADER
+ ReadFile( hFile, &bf, sizeof(bf), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bf) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the BITMAPINFOHEADER
+ ReadFile( hFile, &bi, sizeof(bi), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(bi) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ // Read the PALETTEENTRY
+ ReadFile( hFile, aPalette, sizeof(aPalette), &dwBytesRead, NULL );
+ if( dwBytesRead != sizeof(aPalette) )
+ {
+ CloseHandle( hFile );
+ return E_FAIL;
+ }
+
+ CloseHandle( hFile );
+
+ // Figure out how many colors there are
+ if( bi.biSize != sizeof(BITMAPINFOHEADER) )
+ dwColors = 0;
+ else if (bi.biBitCount > 8)
+ dwColors = 0;
+ else if (bi.biClrUsed == 0)
+ dwColors = 1 << bi.biBitCount;
+ else
+ dwColors = bi.biClrUsed;
+
+ // A DIB color table has its colors stored BGR not RGB
+ // so flip them around since DirectDraw uses RGB
+ for( iColor = 0; iColor < dwColors; iColor++ )
+ {
+ BYTE r = aPalette[iColor].peRed;
+ aPalette[iColor].peRed = aPalette[iColor].peBlue;
+ aPalette[iColor].peBlue = r;
+ }
+
+ return m_pDD->CreatePalette( DDPCAPS_8BIT, aPalette, ppPalette, NULL );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::UpdateBounds()
+{
+ if( m_bWindowed )
+ {
+ GetClientRect( m_hWnd, &m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcWindow+1 );
+ }
+ else
+ {
+ SetRect( &m_rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN) );
+ }
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CDisplay::InitClipper
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CDisplay::InitClipper()
+{
+ LPDIRECTDRAWCLIPPER pClipper;
+ HRESULT hr;
+
+ // Create a clipper when using GDI to draw on the primary surface
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pClipper, NULL ) ) )
+ return hr;
+
+ pClipper->SetHWnd( 0, m_hWnd );
+
+ if( FAILED( hr = m_pddsFrontBuffer->SetClipper( pClipper ) ) )
+ return hr;
+
+ // We can release the clipper now since g_pDDSPrimary
+ // now maintains a ref count on the clipper
+ SAFE_RELEASE( pClipper );
+
+ return S_OK;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::CSurface()
+{
+ m_pdds = NULL;
+ m_bColorKeyed = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+CSurface::~CSurface()
+{
+ SAFE_RELEASE( m_pdds );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAWSURFACE7 pdds )
+{
+ m_pdds = pdds;
+
+ if( m_pdds )
+ {
+ m_pdds->AddRef();
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_ddsd.dwSize = sizeof(m_ddsd);
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd )
+{
+ HRESULT hr;
+
+ // Create the DDraw surface
+ if( FAILED( hr = pDD->CreateSurface( pddsd, &m_pdds, NULL ) ) )
+ return hr;
+
+ // Prepare the DDSURFACEDESC structure
+ m_ddsd.dwSize = sizeof(m_ddsd);
+
+ // Get the DDSURFACEDESC structure for this surface
+ m_pdds->GetSurfaceDesc( &m_ddsd );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::Destroy()
+{
+ SAFE_RELEASE( m_pdds );
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawBitmap()
+// Desc: Draws a bitmap over an entire DirectDrawSurface, stretching the
+// bitmap if nessasary
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( HBITMAP hBMP,
+ DWORD dwBMPOriginX, DWORD dwBMPOriginY,
+ DWORD dwBMPWidth, DWORD dwBMPHeight )
+{
+ HDC hDCImage;
+ HDC hDC;
+ BITMAP bmp;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ if( hBMP == NULL || m_pdds == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ // Get the surface.description
+ ddsd.dwSize = sizeof(ddsd);
+ m_pdds->GetSurfaceDesc( &ddsd );
+
+ if( ddsd.ddpfPixelFormat.dwFlags == DDPF_FOURCC )
+ return E_NOTIMPL;
+
+ // Select bitmap into a memoryDC so we can use it.
+ hDCImage = CreateCompatibleDC( NULL );
+ if( NULL == hDCImage )
+ return E_FAIL;
+
+ SelectObject( hDCImage, hBMP );
+
+ // Get size of the bitmap
+ GetObject( hBMP, sizeof(bmp), &bmp );
+
+ // Use the passed size, unless zero
+ dwBMPWidth = ( dwBMPWidth == 0 ) ? bmp.bmWidth : dwBMPWidth;
+ dwBMPHeight = ( dwBMPHeight == 0 ) ? bmp.bmHeight : dwBMPHeight;
+
+ // Stretch the bitmap to cover this surface
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ StretchBlt( hDC, 0, 0,
+ ddsd.dwWidth, ddsd.dwHeight,
+ hDCImage, dwBMPOriginX, dwBMPOriginY,
+ dwBMPWidth, dwBMPHeight, SRCCOPY );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ DeleteDC( hDCImage );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::DrawText()
+// Desc: Draws a text string on a DirectDraw surface using hFont or the default
+// GDI font if hFont is NULL.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawText( HFONT hFont, TCHAR* strText,
+ DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground )
+{
+ HDC hDC = NULL;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strText == NULL )
+ return E_INVALIDARG;
+
+ // Make sure this surface is restored.
+ if( FAILED( hr = m_pdds->Restore() ) )
+ return hr;
+
+ if( FAILED( hr = m_pdds->GetDC( &hDC ) ) )
+ return hr;
+
+ // Set the background and foreground color
+ SetBkColor( hDC, crBackground );
+ SetTextColor( hDC, crForeground );
+
+ if( hFont )
+ SelectObject( hDC, hFont );
+
+ // Use GDI to draw the text on the surface
+ TextOut( hDC, dwOriginX, dwOriginY, strText, _tcslen(strText) );
+
+ if( FAILED( hr = m_pdds->ReleaseDC( hDC ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ReDrawBitmapOnSurface()
+// Desc: Load a bitmap from a file or resource into a DirectDraw surface.
+// normaly used to re-load a surface after a restore.
+//-----------------------------------------------------------------------------
+HRESULT CSurface::DrawBitmap( TCHAR* strBMP,
+ DWORD dwDesiredWidth, DWORD dwDesiredHeight )
+{
+ HBITMAP hBMP;
+ HRESULT hr;
+
+ if( m_pdds == NULL || strBMP == NULL )
+ return E_INVALIDARG;
+
+ // Try to load the bitmap as a resource, if that fails, try it as a file
+ hBMP = (HBITMAP) LoadImage( GetModuleHandle(NULL), strBMP,
+ IMAGE_BITMAP, dwDesiredWidth, dwDesiredHeight,
+ LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ {
+ hBMP = (HBITMAP) LoadImage( NULL, strBMP, IMAGE_BITMAP,
+ dwDesiredWidth, dwDesiredHeight,
+ LR_LOADFROMFILE | LR_CREATEDIBSECTION );
+ if( hBMP == NULL )
+ return E_FAIL;
+ }
+
+ // Draw the bitmap on this surface
+ if( FAILED( hr = DrawBitmap( hBMP, 0, 0, 0, 0 ) ) )
+ {
+ DeleteObject( hBMP );
+ return hr;
+ }
+
+ DeleteObject( hBMP );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name:
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSurface::SetColorKey( DWORD dwColorKey )
+{
+ if( NULL == m_pdds )
+ return E_POINTER;
+
+ m_bColorKeyed = TRUE;
+
+ DDCOLORKEY ddck;
+ ddck.dwColorSpaceLowValue = ConvertGDIColor( dwColorKey );
+ ddck.dwColorSpaceHighValue = ConvertGDIColor( dwColorKey );
+
+ return m_pdds->SetColorKey( DDCKEY_SRCBLT, &ddck );
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::ConvertGDIColor()
+// Desc: Converts a GDI color (0x00bbggrr) into the equivalent color on a
+// DirectDrawSurface using its pixel format.
+//-----------------------------------------------------------------------------
+DWORD CSurface::ConvertGDIColor( COLORREF dwGDIColor )
+{
+ if( m_pdds == NULL )
+ return 0x00000000;
+
+ COLORREF rgbT;
+ HDC hdc;
+ DWORD dw = CLR_INVALID;
+ DDSURFACEDESC2 ddsd;
+ HRESULT hr;
+
+ // Use GDI SetPixel to color match for us
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK)
+ {
+ rgbT = GetPixel(hdc, 0, 0); // Save current pixel value
+ SetPixel(hdc, 0, 0, dwGDIColor); // Set our value
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ // Now lock the surface so we can read back the converted color
+ ddsd.dwSize = sizeof(ddsd);
+ hr = m_pdds->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
+ if( hr == DD_OK)
+ {
+ dw = *(DWORD *) ddsd.lpSurface;
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount < 32 ) // Mask it to bpp
+ dw &= ( 1 << ddsd.ddpfPixelFormat.dwRGBBitCount ) - 1;
+ m_pdds->Unlock(NULL);
+ }
+
+ // Now put the color that was there back.
+ if( dwGDIColor != CLR_INVALID && m_pdds->GetDC(&hdc) == DD_OK )
+ {
+ SetPixel( hdc, 0, 0, rgbT );
+ m_pdds->ReleaseDC(hdc);
+ }
+
+ return dw;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSurface::GetBitMaskInfo()
+// Desc: Returns the number of bits and the shift in the bit mask
+//-----------------------------------------------------------------------------
+HRESULT CSurface::GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits )
+{
+ DWORD dwShift = 0;
+ DWORD dwBits = 0;
+
+ if( pdwShift == NULL || pdwBits == NULL )
+ return E_INVALIDARG;
+
+ if( dwBitMask )
+ {
+ while( (dwBitMask & 1) == 0 )
+ {
+ dwShift++;
+ dwBitMask >>= 1;
+ }
+ }
+
+ while( (dwBitMask & 1) != 0 )
+ {
+ dwBits++;
+ dwBitMask >>= 1;
+ }
+
+ *pdwShift = dwShift;
+ *pdwBits = dwBits;
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V08/ddutil.h b/V08/ddutil.h
new file mode 100644
index 0000000..61fb0be
--- /dev/null
+++ b/V08/ddutil.h
@@ -0,0 +1,140 @@
+//-----------------------------------------------------------------------------
+// File: ddutil.cpp
+//
+// Desc: Routines for loading bitmap and palettes from resources
+//
+// Copyright (C) 1998-1999 Microsoft Corporation. All Rights Reserved.
+//-----------------------------------------------------------------------------
+#ifndef DDUTIL_H
+#define DDUTIL_H
+
+#include
+#include
+
+
+
+
+//-----------------------------------------------------------------------------
+// Classes defined in this header file
+//-----------------------------------------------------------------------------
+class CDisplay;
+class CSurface;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Flags for the CDisplay and CSurface methods
+//-----------------------------------------------------------------------------
+#define DSURFACELOCK_READ
+#define DSURFACELOCK_WRITE
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CDisplay
+// Desc: Class to handle all DDraw aspects of a display, including creation of
+// front and back buffers, creating offscreen surfaces and palettes,
+// and blitting surface and displaying bitmaps.
+//-----------------------------------------------------------------------------
+class CDisplay
+{
+protected:
+ LPDIRECTDRAW7 m_pDD;
+ LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBuffer;
+ LPDIRECTDRAWSURFACE7 m_pddsBackBufferLeft; // For stereo modes
+
+ HWND m_hWnd;
+ RECT m_rcWindow;
+ BOOL m_bWindowed;
+ BOOL m_bStereo;
+
+public:
+ CDisplay();
+ ~CDisplay();
+
+ // Access functions
+ HWND GetHWnd() { return m_hWnd; }
+ LPDIRECTDRAW7 GetDirectDraw() { return m_pDD; }
+ LPDIRECTDRAWSURFACE7 GetFrontBuffer() { return m_pddsFrontBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBuffer() { return m_pddsBackBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBufferLEft() { return m_pddsBackBufferLeft; }
+
+ // Status functions
+ BOOL IsWindowed() { return m_bWindowed; }
+ BOOL IsStereo() { return m_bStereo; }
+
+ // Creation/destruction methods
+ HRESULT CreateFullScreenDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight,
+ DWORD dwBPP );
+ HRESULT CreateWindowedDisplay( HWND hWnd, DWORD dwWidth, DWORD dwHeight );
+ HRESULT InitClipper();
+ HRESULT UpdateBounds();
+ virtual HRESULT DestroyObjects();
+
+ // Methods to create child objects
+ HRESULT CreateSurface( CSurface** ppSurface, DWORD dwWidth,
+ DWORD dwHeight );
+ HRESULT CreateSurfaceFromBitmap( CSurface** ppSurface, TCHAR* strBMP,
+ DWORD dwDesiredWidth,
+ DWORD dwDesiredHeight );
+ HRESULT CreateSurfaceFromText( CSurface** ppSurface, HFONT hFont,
+ TCHAR* strText,
+ COLORREF crBackground,
+ COLORREF crForeground );
+ HRESULT CreatePaletteFromBitmap( LPDIRECTDRAWPALETTE* ppPalette, const TCHAR* strBMP );
+
+ // Display methods
+ HRESULT Clear( DWORD dwColor = 0L );
+ HRESULT ColorKeyBlt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc = NULL );
+ HRESULT Blt( DWORD x, DWORD y, LPDIRECTDRAWSURFACE7 pdds,
+ RECT* prc=NULL, DWORD dwFlags=0 );
+ HRESULT Blt( DWORD x, DWORD y, CSurface* pSurface, RECT* prc = NULL );
+ HRESULT ShowBitmap( HBITMAP hbm, LPDIRECTDRAWPALETTE pPalette=NULL );
+ HRESULT SetPalette( LPDIRECTDRAWPALETTE pPalette );
+ HRESULT Present();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: class CSurface
+// Desc: Class to handle aspects of a DirectDrawSurface.
+//-----------------------------------------------------------------------------
+class CSurface
+{
+ LPDIRECTDRAWSURFACE7 m_pdds;
+ DDSURFACEDESC2 m_ddsd;
+ BOOL m_bColorKeyed;
+
+public:
+ LPDIRECTDRAWSURFACE7 GetDDrawSurface() { return m_pdds; }
+ BOOL IsColorKeyed() { return m_bColorKeyed; }
+
+ HRESULT DrawBitmap( HBITMAP hBMP, DWORD dwBMPOriginX = 0, DWORD dwBMPOriginY = 0,
+ DWORD dwBMPWidth = 0, DWORD dwBMPHeight = 0 );
+ HRESULT DrawBitmap( TCHAR* strBMP, DWORD dwDesiredWidth, DWORD dwDesiredHeight );
+ HRESULT DrawText( HFONT hFont, TCHAR* strText, DWORD dwOriginX, DWORD dwOriginY,
+ COLORREF crBackground, COLORREF crForeground );
+
+ HRESULT SetColorKey( DWORD dwColorKey );
+ DWORD ConvertGDIColor( COLORREF dwGDIColor );
+ static HRESULT GetBitMaskInfo( DWORD dwBitMask, DWORD* pdwShift, DWORD* pdwBits );
+
+ HRESULT Create( LPDIRECTDRAW7 pDD, DDSURFACEDESC2* pddsd );
+ HRESULT Create( LPDIRECTDRAWSURFACE7 pdds );
+ HRESULT Destroy();
+
+ CSurface();
+ ~CSurface();
+};
+
+
+
+
+#endif // DDUTIL_H
+
diff --git a/V08/dsutil.cpp b/V08/dsutil.cpp
new file mode 100644
index 0000000..83c1512
--- /dev/null
+++ b/V08/dsutil.cpp
@@ -0,0 +1,1546 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.cpp
+//
+// Desc: DirectSound framework classes for reading and writing wav files and
+// playing them in DirectSound buffers. Feel free to use this class
+// as a starting point for adding extra functionality.
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#define STRICT
+#include
+#include
+#include
+#include
+#include "DSUtil.h"
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CSoundManager()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSoundManager::CSoundManager()
+{
+ m_pDS = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::~CSoundManager()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSoundManager::~CSoundManager()
+{
+ SAFE_RELEASE( m_pDS );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Initialize()
+// Desc: Initializes the IDirectSound object and also sets the primary buffer
+// format. This function must be called before any others.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Initialize( HWND hWnd,
+ DWORD dwCoopLevel,
+ DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ SAFE_RELEASE( m_pDS );
+
+ // Create IDirectSound using the primary sound device
+ if( FAILED( hr = DirectSoundCreate8( NULL, &m_pDS, NULL ) ) )
+ return DXTRACE_ERR( TEXT("DirectSoundCreate8"), hr );
+
+ // Set DirectSound coop level
+ if( FAILED( hr = m_pDS->SetCooperativeLevel( hWnd, dwCoopLevel ) ) )
+ return DXTRACE_ERR( TEXT("SetCooperativeLevel"), hr );
+
+ // Set primary buffer format
+ SetPrimaryBufferFormat( dwPrimaryChannels, dwPrimaryFreq, dwPrimaryBitRate );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::SetPrimaryBufferFormat()
+// Desc: Set primary buffer to a specified format
+// For example, to set the primary buffer format to 22kHz stereo, 16-bit
+// then: dwPrimaryChannels = 2
+// dwPrimaryFreq = 22050,
+// dwPrimaryBitRate = 16
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::SetPrimaryBufferFormat( DWORD dwPrimaryChannels,
+ DWORD dwPrimaryFreq,
+ DWORD dwPrimaryBitRate )
+{
+ HRESULT hr;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Get the primary buffer
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
+ dsbd.dwBufferBytes = 0;
+ dsbd.lpwfxFormat = NULL;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ WAVEFORMATEX wfx;
+ ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = (WORD) dwPrimaryChannels;
+ wfx.nSamplesPerSec = dwPrimaryFreq;
+ wfx.wBitsPerSample = (WORD) dwPrimaryBitRate;
+ wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+
+ if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )
+ return DXTRACE_ERR( TEXT("SetFormat"), hr );
+
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Get3DListenerInterface()
+// Desc: Returns the 3D listener interface associated with primary buffer.
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener )
+{
+ HRESULT hr;
+ DSBUFFERDESC dsbdesc;
+ LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
+
+ if( ppDSListener == NULL )
+ return E_INVALIDARG;
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ *ppDSListener = NULL;
+
+ // Obtain primary buffer, asking it for 3D control
+ ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
+ dsbdesc.dwSize = sizeof(DSBUFFERDESC);
+ dsbdesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) )
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ if( FAILED( hr = pDSBPrimary->QueryInterface( IID_IDirectSound3DListener,
+ (VOID**)ppDSListener ) ) )
+ {
+ SAFE_RELEASE( pDSBPrimary );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ // Release the primary buffer, since it is not need anymore
+ SAFE_RELEASE( pDSBPrimary );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::Create()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::Create( CSound** ppSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ HRESULT hrRet = S_OK;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ if( pWaveFile->GetSize() == 0 )
+ {
+ // Wave is blank, so don't create it.
+ hr = E_FAIL;
+ goto LFail;
+ }
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = pWaveFile->GetSize();
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ // DirectSound is only guarenteed to play PCM data. Other
+ // formats may or may not work depending the sound card driver.
+ hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL );
+
+ // Be sure to return this error code if it occurs so the
+ // callers knows this happened.
+ if( hr == DS_NO_VIRTUALIZATION )
+ hrRet = DS_NO_VIRTUALIZATION;
+
+ if( FAILED(hr) )
+ {
+ // DSERR_BUFFERTOOSMALL will be returned if the buffer is
+ // less than DSBSIZE_FX_MIN (100ms) and the buffer is created
+ // with DSBCAPS_CTRLFX.
+ if( hr != DSERR_BUFFERTOOSMALL )
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return hrRet;
+
+LFail:
+ // Cleanup
+ SAFE_DELETE( pWaveFile );
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateFromMemory()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateFromMemory( CSound** ppSound,
+ BYTE* pbData,
+ ULONG ulDataSize,
+ LPWAVEFORMATEX pwfx,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNumBuffers )
+{
+ HRESULT hr;
+ DWORD i;
+ LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbData == NULL || ppSound == NULL || dwNumBuffers < 1 )
+ return E_INVALIDARG;
+
+ apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ if( apDSBuffer == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile = new CWaveFile();
+ if( pWaveFile == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto LFail;
+ }
+
+ pWaveFile->OpenFromMemory( pbData,ulDataSize, pwfx, WAVEFILE_READ );
+
+
+ // Make the DirectSound buffer the same size as the wav file
+ dwDSBufferSize = ulDataSize;
+
+ // Create the direct sound buffer, and only request the flags needed
+ // since each requires some overhead and limits if the buffer can
+ // be hardware accelerated
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL ) ) )
+ {
+ DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ goto LFail;
+ }
+
+ for( i=1; iDuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer[i] ) ) )
+ {
+ DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
+ goto LFail;
+ }
+ }
+
+ // Create the sound
+ *ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile );
+
+ SAFE_DELETE( apDSBuffer );
+ return S_OK;
+
+LFail:
+ // Cleanup
+
+ SAFE_DELETE( apDSBuffer );
+ return hr;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSoundManager::CreateStreaming()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSoundManager::CreateStreaming( CStreamingSound** ppStreamingSound,
+ LPTSTR strWaveFileName,
+ DWORD dwCreationFlags,
+ GUID guid3DAlgorithm,
+ DWORD dwNotifyCount,
+ DWORD dwNotifySize,
+ HANDLE hNotifyEvent )
+{
+ HRESULT hr;
+
+ if( m_pDS == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( strWaveFileName == NULL || ppStreamingSound == NULL || hNotifyEvent == NULL )
+ return E_INVALIDARG;
+
+ LPDIRECTSOUNDBUFFER pDSBuffer = NULL;
+ DWORD dwDSBufferSize = NULL;
+ CWaveFile* pWaveFile = NULL;
+ DSBPOSITIONNOTIFY* aPosNotify = NULL;
+ LPDIRECTSOUNDNOTIFY pDSNotify = NULL;
+
+ pWaveFile = new CWaveFile();
+ pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );
+
+ // Figure out how big the DSound buffer should be
+ dwDSBufferSize = dwNotifySize * dwNotifyCount;
+
+ // Set up the direct sound buffer. Request the NOTIFY flag, so
+ // that we are notified as the sound buffer plays. Note, that using this flag
+ // may limit the amount of hardware acceleration that can occur.
+ DSBUFFERDESC dsbd;
+ ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
+ dsbd.dwSize = sizeof(DSBUFFERDESC);
+ dsbd.dwFlags = dwCreationFlags |
+ DSBCAPS_CTRLPOSITIONNOTIFY |
+ DSBCAPS_GETCURRENTPOSITION2;
+ dsbd.dwBufferBytes = dwDSBufferSize;
+ dsbd.guid3DAlgorithm = guid3DAlgorithm;
+ dsbd.lpwfxFormat = pWaveFile->m_pwfx;
+
+ if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBuffer, NULL ) ) )
+ {
+ // If wave format isn't then it will return
+ // either DSERR_BADFORMAT or E_INVALIDARG
+ if( hr == DSERR_BADFORMAT || hr == E_INVALIDARG )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("CreateSoundBuffer"), hr );
+
+ return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
+ }
+
+ // Create the notification events, so that we know when to fill
+ // the buffer as the sound plays.
+ if( FAILED( hr = pDSBuffer->QueryInterface( IID_IDirectSoundNotify,
+ (VOID**)&pDSNotify ) ) )
+ {
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("QueryInterface"), hr );
+ }
+
+ aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ];
+ if( aPosNotify == NULL )
+ return E_OUTOFMEMORY;
+
+ for( DWORD i = 0; i < dwNotifyCount; i++ )
+ {
+ aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
+ aPosNotify[i].hEventNotify = hNotifyEvent;
+ }
+
+ // Tell DirectSound when to notify us. The notification will come in the from
+ // of signaled events that are handled in WinMain()
+ if( FAILED( hr = pDSNotify->SetNotificationPositions( dwNotifyCount,
+ aPosNotify ) ) )
+ {
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+ return DXTRACE_ERR( TEXT("SetNotificationPositions"), hr );
+ }
+
+ SAFE_RELEASE( pDSNotify );
+ SAFE_DELETE( aPosNotify );
+
+ // Create the sound
+ *ppStreamingSound = new CStreamingSound( pDSBuffer, dwDSBufferSize, pWaveFile, dwNotifySize );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::CSound()
+// Desc: Constructs the class
+//-----------------------------------------------------------------------------
+CSound::CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize,
+ DWORD dwNumBuffers, CWaveFile* pWaveFile )
+{
+ DWORD i;
+
+ m_apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
+ for( i=0; iSetCurrentPosition(0);
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::~CSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CSound::~CSound()
+{
+ for( DWORD i=0; iLock( 0, m_dwDSBufferSize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ NULL, NULL, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // Reset the wave file to the beginning
+ m_pWaveFile->ResetFile();
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwWavDataRead ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ if( dwWavDataRead == 0 )
+ {
+ // Wav is blank, so just fill with silence
+ FillMemory( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ else if( dwWavDataRead < dwDSLockedBufferSize )
+ {
+ // If the wav file was smaller than the DirectSound buffer,
+ // we need to fill the remainder of the buffer with data
+ if( bRepeatWavIfBufferLarger )
+ {
+ // Reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwWavDataRead; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full
+ // for very short files
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwWavDataRead );
+ if( FAILED(hr) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwWavDataRead;
+ }
+ }
+ else
+ {
+ // Don't repeat the wav file, just fill in silence
+ FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead,
+ dwDSLockedBufferSize - dwWavDataRead,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ }
+ }
+
+ // Unlock the buffer, we don't need it anymore.
+ pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::RestoreBuffer()
+// Desc: Restores the lost buffer. *pbWasRestored returns TRUE if the buffer was
+// restored. It can also NULL if the information is not needed.
+//-----------------------------------------------------------------------------
+HRESULT CSound::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored )
+{
+ HRESULT hr;
+
+ if( pDSB == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pbWasRestored )
+ *pbWasRestored = FALSE;
+
+ DWORD dwStatus;
+ if( FAILED( hr = pDSB->GetStatus( &dwStatus ) ) )
+ return DXTRACE_ERR( TEXT("GetStatus"), hr );
+
+ if( dwStatus & DSBSTATUS_BUFFERLOST )
+ {
+ // Since the app could have just been activated, then
+ // DirectSound may not be giving us control yet, so
+ // the restoring the buffer may fail.
+ // If it does, sleep until DirectSound gives us control.
+ do
+ {
+ hr = pDSB->Restore();
+ if( hr == DSERR_BUFFERLOST )
+ Sleep( 10 );
+ }
+ while( hr = pDSB->Restore() );
+
+ if( pbWasRestored != NULL )
+ *pbWasRestored = TRUE;
+
+ return S_OK;
+ }
+ else
+ {
+ return S_FALSE;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetFreeBuffer()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetFreeBuffer()
+{
+ BOOL bIsPlaying = FALSE;
+ DWORD i;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( i=0; iGetStatus( &dwStatus );
+ if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
+ break;
+ }
+ }
+
+ if( i != m_dwNumBuffers )
+ return m_apDSBuffer[ i ];
+ else
+ return m_apDSBuffer[ rand() % m_dwNumBuffers ];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::GetBuffer()
+// Desc:
+//-----------------------------------------------------------------------------
+LPDIRECTSOUNDBUFFER CSound::GetBuffer( DWORD dwIndex )
+{
+ if( m_apDSBuffer == NULL )
+ return NULL;
+ if( dwIndex >= m_dwNumBuffers )
+ return NULL;
+
+ return m_apDSBuffer[dwIndex];
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Get3DBufferInterface()
+// Desc:
+//-----------------------------------------------------------------------------
+HRESULT CSound::Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer )
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( dwIndex >= m_dwNumBuffers )
+ return E_INVALIDARG;
+
+ *ppDS3DBuffer = NULL;
+
+ return m_apDSBuffer[dwIndex]->QueryInterface( IID_IDirectSound3DBuffer,
+ (VOID**)ppDS3DBuffer );
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Play()
+// Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING
+// in the dwFlags to loop the sound
+//-----------------------------------------------------------------------------
+HRESULT CSound::Play( DWORD dwPriority, DWORD dwFlags )
+{
+ HRESULT hr;
+ BOOL bRestored;
+
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();
+
+ if( pDSB == NULL )
+ return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL );
+
+ // Restore the buffer if it was lost
+ if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+
+ // Make DirectSound do pre-processing on sound effects
+ Reset();
+ }
+
+ return pDSB->Play( 0, dwPriority, dwFlags );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Stop()
+// Desc: Stops the sound from playing
+//-----------------------------------------------------------------------------
+HRESULT CSound::Stop()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iStop();
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::Reset()
+// Desc: Reset all of the sound buffers
+//-----------------------------------------------------------------------------
+HRESULT CSound::Reset()
+{
+ if( m_apDSBuffer == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ HRESULT hr = 0;
+
+ for( DWORD i=0; iSetCurrentPosition( 0 );
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CSound::IsSoundPlaying()
+// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
+//-----------------------------------------------------------------------------
+BOOL CSound::IsSoundPlaying()
+{
+ BOOL bIsPlaying = FALSE;
+
+ if( m_apDSBuffer == NULL )
+ return FALSE;
+
+ for( DWORD i=0; iGetStatus( &dwStatus );
+ bIsPlaying |= ( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );
+ }
+ }
+
+ return bIsPlaying;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::CStreamingSound()
+// Desc: Setups up a buffer so data can be streamed from the wave file into
+// buffer. This is very useful for large wav files that would take a
+// while to load. The buffer is initially filled with data, then
+// as sound is played the notification events are signaled and more data
+// is written into the buffer by calling HandleWaveStreamNotification()
+//-----------------------------------------------------------------------------
+CStreamingSound::CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize,
+ CWaveFile* pWaveFile, DWORD dwNotifySize )
+ : CSound( &pDSBuffer, dwDSBufferSize, 1, pWaveFile )
+{
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNotifySize = dwNotifySize;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::~CStreamingSound()
+// Desc: Destroys the class
+//-----------------------------------------------------------------------------
+CStreamingSound::~CStreamingSound()
+{
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::HandleWaveStreamNotification()
+// Desc: Handle the notification that tell us to put more wav data in the
+// circular buffer
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::HandleWaveStreamNotification( BOOL bLoopedPlay )
+{
+ HRESULT hr;
+ DWORD dwCurrentPlayPos;
+ DWORD dwPlayDelta;
+ DWORD dwBytesWrittenToBuffer;
+ VOID* pDSLockedBuffer = NULL;
+ VOID* pDSLockedBuffer2 = NULL;
+ DWORD dwDSLockedBufferSize;
+ DWORD dwDSLockedBufferSize2;
+
+ if( m_apDSBuffer == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ return S_OK;
+ }
+
+ // Lock the DirectSound buffer
+ if( FAILED( hr = m_apDSBuffer[0]->Lock( m_dwNextWriteOffset, m_dwNotifySize,
+ &pDSLockedBuffer, &dwDSLockedBufferSize,
+ &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L ) ) )
+ return DXTRACE_ERR( TEXT("Lock"), hr );
+
+ // m_dwDSBufferSize and m_dwNextWriteOffset are both multiples of m_dwNotifySize,
+ // it should the second buffer should never be valid
+ if( pDSLockedBuffer2 != NULL )
+ return E_UNEXPECTED;
+
+ if( !m_bFillNextNotificationWithSilence )
+ {
+ // Fill the DirectSound buffer with wav data
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
+ dwDSLockedBufferSize,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+ }
+ else
+ {
+ // Fill the DirectSound buffer with silence
+ FillMemory( pDSLockedBuffer, dwDSLockedBufferSize,
+ (BYTE)( m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+ dwBytesWrittenToBuffer = dwDSLockedBufferSize;
+ }
+
+ // If the number of bytes written is less than the
+ // amount we requested, we have a short file.
+ if( dwBytesWrittenToBuffer < dwDSLockedBufferSize )
+ {
+ if( !bLoopedPlay )
+ {
+ // Fill in silence for the rest of the buffer.
+ FillMemory( (BYTE*) pDSLockedBuffer + dwBytesWrittenToBuffer,
+ dwDSLockedBufferSize - dwBytesWrittenToBuffer,
+ (BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
+
+ // Any future notifications should just fill the buffer with silence
+ m_bFillNextNotificationWithSilence = TRUE;
+ }
+ else
+ {
+ // We are looping, so reset the file and fill the buffer with wav data
+ DWORD dwReadSoFar = dwBytesWrittenToBuffer; // From previous call above.
+ while( dwReadSoFar < dwDSLockedBufferSize )
+ {
+ // This will keep reading in until the buffer is full (for very short files).
+ if( FAILED( hr = m_pWaveFile->ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ if( FAILED( hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
+ dwDSLockedBufferSize - dwReadSoFar,
+ &dwBytesWrittenToBuffer ) ) )
+ return DXTRACE_ERR( TEXT("Read"), hr );
+
+ dwReadSoFar += dwBytesWrittenToBuffer;
+ }
+ }
+ }
+
+ // Unlock the DirectSound buffer
+ m_apDSBuffer[0]->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );
+
+ // Figure out how much data has been played so far. When we have played
+ // passed the end of the file, we will either need to start filling the
+ // buffer with silence or starting reading from the beginning of the file,
+ // depending if the user wants to loop the sound
+ if( FAILED( hr = m_apDSBuffer[0]->GetCurrentPosition( &dwCurrentPlayPos, NULL ) ) )
+ return DXTRACE_ERR( TEXT("GetCurrentPosition"), hr );
+
+ // Check to see if the position counter looped
+ if( dwCurrentPlayPos < m_dwLastPlayPos )
+ dwPlayDelta = ( m_dwDSBufferSize - m_dwLastPlayPos ) + dwCurrentPlayPos;
+ else
+ dwPlayDelta = dwCurrentPlayPos - m_dwLastPlayPos;
+
+ m_dwPlayProgress += dwPlayDelta;
+ m_dwLastPlayPos = dwCurrentPlayPos;
+
+ // If we are now filling the buffer with silence, then we have found the end so
+ // check to see if the entire sound has played, if it has then stop the buffer.
+ if( m_bFillNextNotificationWithSilence )
+ {
+ // We don't want to cut off the sound before it's done playing.
+ if( m_dwPlayProgress >= m_pWaveFile->GetSize() )
+ {
+ m_apDSBuffer[0]->Stop();
+ }
+ }
+
+ // Update where the buffer will lock (for next time)
+ m_dwNextWriteOffset += dwDSLockedBufferSize;
+ m_dwNextWriteOffset %= m_dwDSBufferSize; // Circular buffer
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CStreamingSound::Reset()
+// Desc: Resets the sound so it will begin playing at the beginning
+//-----------------------------------------------------------------------------
+HRESULT CStreamingSound::Reset()
+{
+ HRESULT hr;
+
+ if( m_apDSBuffer[0] == NULL || m_pWaveFile == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ m_dwLastPlayPos = 0;
+ m_dwPlayProgress = 0;
+ m_dwNextWriteOffset = 0;
+ m_bFillNextNotificationWithSilence = FALSE;
+
+ // Restore the buffer if it was lost
+ BOOL bRestored;
+ if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
+ return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );
+
+ if( bRestored )
+ {
+ // The buffer was restored, so we need to fill it with new data
+ if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
+ return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
+ }
+
+ m_pWaveFile->ResetFile();
+
+ return m_apDSBuffer[0]->SetCurrentPosition( 0L );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::CWaveFile()
+// Desc: Constructs the class. Call Open() to open a wave file for reading.
+// Then call Read() as needed. Calling the destructor or Close()
+// will close the file.
+//-----------------------------------------------------------------------------
+CWaveFile::CWaveFile()
+{
+ m_pwfx = NULL;
+ m_hmmio = NULL;
+ m_dwSize = 0;
+ m_bIsReadingFromMemory = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::~CWaveFile()
+// Desc: Destructs the class
+//-----------------------------------------------------------------------------
+CWaveFile::~CWaveFile()
+{
+ Close();
+
+ if( !m_bIsReadingFromMemory )
+ SAFE_DELETE_ARRAY( m_pwfx );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Open()
+// Desc: Opens a wave file for reading
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ HRESULT hr;
+
+ m_dwFlags = dwFlags;
+ m_bIsReadingFromMemory = FALSE;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ if( strFileName == NULL )
+ return E_INVALIDARG;
+ SAFE_DELETE_ARRAY( m_pwfx );
+
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );
+
+ if( NULL == m_hmmio )
+ {
+ HRSRC hResInfo;
+ HGLOBAL hResData;
+ DWORD dwSize;
+ VOID* pvRes;
+
+ // Loading it as a file failed, so try it as a resource
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAVE") ) ) )
+ {
+ if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAV") ) ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("FindResource"), E_FAIL );
+ }
+
+ if( NULL == ( hResData = LoadResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("LoadResource"), E_FAIL );
+
+ if( 0 == ( dwSize = SizeofResource( NULL, hResInfo ) ) )
+ return DXTRACE_ERR( TEXT("SizeofResource"), E_FAIL );
+
+ if( NULL == ( pvRes = LockResource( hResData ) ) )
+ return DXTRACE_ERR( TEXT("LockResource"), E_FAIL );
+
+ CHAR* pData = new CHAR[ dwSize ];
+ memcpy( pData, pvRes, dwSize );
+
+ MMIOINFO mmioInfo;
+ ZeroMemory( &mmioInfo, sizeof(mmioInfo) );
+ mmioInfo.fccIOProc = FOURCC_MEM;
+ mmioInfo.cchBuffer = dwSize;
+ mmioInfo.pchBuffer = (CHAR*) pData;
+
+ m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );
+ }
+
+ if( FAILED( hr = ReadMMIO() ) )
+ {
+ // ReadMMIO will fail if its an not a wave file
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR_NOMSGBOX( TEXT("ReadMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+
+ // After the reset, the size of the wav file is m_ck.cksize so store it now
+ m_dwSize = m_ck.cksize;
+ }
+ else
+ {
+ m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF |
+ MMIO_READWRITE |
+ MMIO_CREATE );
+ if( NULL == m_hmmio )
+ return DXTRACE_ERR( TEXT("mmioOpen"), E_FAIL );
+
+ if( FAILED( hr = WriteMMIO( pwfx ) ) )
+ {
+ mmioClose( m_hmmio, 0 );
+ return DXTRACE_ERR( TEXT("WriteMMIO"), hr );
+ }
+
+ if( FAILED( hr = ResetFile() ) )
+ return DXTRACE_ERR( TEXT("ResetFile"), hr );
+ }
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::OpenFromMemory()
+// Desc: copy data to CWaveFile member variable from memory
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::OpenFromMemory( BYTE* pbData, ULONG ulDataSize,
+ WAVEFORMATEX* pwfx, DWORD dwFlags )
+{
+ m_pwfx = pwfx;
+ m_ulDataSize = ulDataSize;
+ m_pbData = pbData;
+ m_pbDataCur = m_pbData;
+ m_bIsReadingFromMemory = TRUE;
+
+ if( dwFlags != WAVEFILE_READ )
+ return E_NOTIMPL;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ReadMMIO()
+// Desc: Support function for reading from a multimedia I/O stream.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_pwfx.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ReadMMIO()
+{
+ MMCKINFO ckIn; // chunk info. for general use.
+ PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in.
+
+ m_pwfx = NULL;
+
+ if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Check to make sure this is a valid wave file
+ if( (m_ckRiff.ckid != FOURCC_RIFF) ||
+ (m_ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) )
+ return DXTRACE_ERR_NOMSGBOX( TEXT("mmioFOURCC"), E_FAIL );
+
+ // Search the input file for for the 'fmt ' chunk.
+ ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ // Expect the 'fmt' chunk to be at least as large as ;
+ // if there are extra parameters at the end, we'll ignore them
+ if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) )
+ return DXTRACE_ERR( TEXT("sizeof(PCMWAVEFORMAT)"), E_FAIL );
+
+ // Read the 'fmt ' chunk into .
+ if( mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat,
+ sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ // Allocate the waveformatex, but if its not pcm format, read the next
+ // word, and thats how many extra bytes to allocate.
+ if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )
+ {
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("m_pwfx"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = 0;
+ }
+ else
+ {
+ // Read in length of extra bytes.
+ WORD cbExtraBytes = 0L;
+ if( mmioRead( m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) )
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+
+ m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];
+ if( NULL == m_pwfx )
+ return DXTRACE_ERR( TEXT("new"), E_FAIL );
+
+ // Copy the bytes from the pcm structure to the waveformatex structure
+ memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
+ m_pwfx->cbSize = cbExtraBytes;
+
+ // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
+ if( mmioRead( m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize))+sizeof(WORD)),
+ cbExtraBytes ) != cbExtraBytes )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
+ }
+ }
+
+ // Ascend the input file out of the 'fmt ' chunk.
+ if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )
+ {
+ SAFE_DELETE( m_pwfx );
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::GetSize()
+// Desc: Retuns the size of the read access wave file
+//-----------------------------------------------------------------------------
+DWORD CWaveFile::GetSize()
+{
+ return m_dwSize;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::ResetFile()
+// Desc: Resets the internal m_ck pointer so reading starts from the
+// beginning of the file again
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::ResetFile()
+{
+ if( m_bIsReadingFromMemory )
+ {
+ m_pbDataCur = m_pbData;
+ }
+ else
+ {
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ // Seek to the data
+ if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),
+ SEEK_SET ) )
+ return DXTRACE_ERR( TEXT("mmioSeek"), E_FAIL );
+
+ // Search the input file for the 'data' chunk.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ if( 0 != mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+ }
+ else
+ {
+ // Create the 'data' chunk that holds the waveform samples.
+ m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ m_ck.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( 0 != mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Read()
+// Desc: Reads section of data from a wave file into pBuffer and returns
+// how much read in pdwSizeRead, reading not more than dwSizeToRead.
+// This uses m_ck to determine where to start reading from. So
+// subsequent calls will be continue where the last left off unless
+// Reset() is called.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )
+{
+ if( m_bIsReadingFromMemory )
+ {
+ if( m_pbDataCur == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( (BYTE*)(m_pbDataCur + dwSizeToRead) >
+ (BYTE*)(m_pbData + m_ulDataSize) )
+ {
+ dwSizeToRead = m_ulDataSize - (DWORD)(m_pbDataCur - m_pbData);
+ }
+
+ CopyMemory( pBuffer, m_pbDataCur, dwSizeToRead );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = dwSizeToRead;
+
+ return S_OK;
+ }
+ else
+ {
+ MMIOINFO mmioinfoIn; // current status of m_hmmio
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pBuffer == NULL || pdwSizeRead == NULL )
+ return E_INVALIDARG;
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = 0;
+
+ if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
+
+ UINT cbDataIn = dwSizeToRead;
+ if( cbDataIn > m_ck.cksize )
+ cbDataIn = m_ck.cksize;
+
+ m_ck.cksize -= cbDataIn;
+
+ for( DWORD cT = 0; cT < cbDataIn; cT++ )
+ {
+ // Copy the bytes from the io to the buffer.
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ {
+ if( 0 != mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+
+ if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
+ return DXTRACE_ERR( TEXT("mmioinfoIn.pchNext"), E_FAIL );
+ }
+
+ // Actual copy.
+ *((BYTE*)pBuffer+cT) = *((BYTE*)mmioinfoIn.pchNext);
+ mmioinfoIn.pchNext++;
+ }
+
+ if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ if( pdwSizeRead != NULL )
+ *pdwSizeRead = cbDataIn;
+
+ return S_OK;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Close()
+// Desc: Closes the wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Close()
+{
+ if( m_dwFlags == WAVEFILE_READ )
+ {
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+ else
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+
+ if( 0 != mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );
+
+ // Ascend the output file out of the 'data' chunk -- this will cause
+ // the chunk size of the 'data' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Do this here instead...
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioSeek( m_hmmio, 0, SEEK_SET );
+
+ if( 0 != (INT)mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
+
+ m_ck.ckid = mmioFOURCC('f', 'a', 'c', 't');
+
+ if( 0 == mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
+ {
+ DWORD dwSamples = 0;
+ mmioWrite( m_hmmio, (HPSTR)&dwSamples, sizeof(DWORD) );
+ mmioAscend( m_hmmio, &m_ck, 0 );
+ }
+
+ // Ascend the output file out of the 'RIFF' chunk -- this will cause
+ // the chunk size of the 'RIFF' chunk to be written.
+ if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ mmioClose( m_hmmio, 0 );
+ m_hmmio = NULL;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::WriteMMIO()
+// Desc: Support function for reading from a multimedia I/O stream
+// pwfxDest is the WAVEFORMATEX for this new wave file.
+// m_hmmio must be valid before calling. This function uses it to
+// update m_ckRiff, and m_ck.
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::WriteMMIO( WAVEFORMATEX *pwfxDest )
+{
+ DWORD dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile.
+ MMCKINFO ckOut1;
+
+ dwFactChunk = (DWORD)-1;
+
+ // Create the output file RIFF chunk of form type 'WAVE'.
+ m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');
+ m_ckRiff.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // We are now descended into the 'RIFF' chunk we just created.
+ // Now create the 'fmt ' chunk. Since we know the size of this chunk,
+ // specify it in the MMCKINFO structure so MMIO doesn't have to seek
+ // back and set the chunk size after ascending from the chunk.
+ m_ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ m_ck.cksize = sizeof(PCMWAVEFORMAT);
+
+ if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type.
+ if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM )
+ {
+ if( mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+ else
+ {
+ // Write the variable length size.
+ if( (UINT)mmioWrite( m_hmmio, (HPSTR) pwfxDest,
+ sizeof(*pwfxDest) + pwfxDest->cbSize ) !=
+ ( sizeof(*pwfxDest) + pwfxDest->cbSize ) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+ }
+
+ // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
+ if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ // Now create the fact chunk, not required for PCM but nice to have. This is filled
+ // in when the close routine is called.
+ ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't');
+ ckOut1.cksize = 0;
+
+ if( 0 != mmioCreateChunk( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );
+
+ if( mmioWrite( m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) !=
+ sizeof(dwFactChunk) )
+ return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
+
+ // Now ascend out of the fact chunk...
+ if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) )
+ return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CWaveFile::Write()
+// Desc: Writes data to the open wave file
+//-----------------------------------------------------------------------------
+HRESULT CWaveFile::Write( UINT nSizeToWrite, BYTE* pbSrcData, UINT* pnSizeWrote )
+{
+ UINT cT;
+
+ if( m_bIsReadingFromMemory )
+ return E_NOTIMPL;
+ if( m_hmmio == NULL )
+ return CO_E_NOTINITIALIZED;
+ if( pnSizeWrote == NULL || pbSrcData == NULL )
+ return E_INVALIDARG;
+
+ *pnSizeWrote = 0;
+
+ for( cT = 0; cT < nSizeToWrite; cT++ )
+ {
+ if( m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite )
+ {
+ m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
+ if( 0 != mmioAdvance( m_hmmio, &m_mmioinfoOut, MMIO_WRITE ) )
+ return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
+ }
+
+ *((BYTE*)m_mmioinfoOut.pchNext) = *((BYTE*)pbSrcData+cT);
+ (BYTE*)m_mmioinfoOut.pchNext++;
+
+ (*pnSizeWrote)++;
+ }
+
+ return S_OK;
+}
+
+
+
+
diff --git a/V08/dsutil.h b/V08/dsutil.h
new file mode 100644
index 0000000..57d26df
--- /dev/null
+++ b/V08/dsutil.h
@@ -0,0 +1,170 @@
+//-----------------------------------------------------------------------------
+// File: DSUtil.h
+//
+// Desc:
+//
+// Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
+//-----------------------------------------------------------------------------
+#ifndef DSUTIL_H
+#define DSUTIL_H
+
+#include
+#include