我有一个简单的DirectX应用程序(实际上我正在遵循一些教程)。现在我想使用生成WM_TIMER
消息的计时器。
问题在于,如果我不处理WM_PAINT
(因为渲染是在主循环中完成的),WM_TIMER
永远不会被捕获,因为WM_PAINT
优先级较高且持续泛滥使用WM_PAINT
的消息处理程序。
我尝试调用BeginPaint()
和EndPaint()
来验证窗口,我也尝试调用ValidateRect()
,但问题是应用程序在1秒左右后总是关闭,返回码为101.如果没有WM_PAINT
的处理,它可以正常工作,但计时器永远不会被处理。
有什么问题?
#include "stdafx.h"
#include "TransformingVertices.h"
// define the screen resolution
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
// include the Direct3D Library file
#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")
// global declarations
HWND g_hWnd;
LPDIRECT3D9 d3d; // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev; // the pointer to the device class
LPDIRECT3DVERTEXBUFFER9 g_v_buffer;
int g_i = 0;
float g_angle = 0.0f;
// function prototypes
void initD3D(HWND hWnd); // sets up and initializes Direct3D
void init_graphics(int = 0); // copies vertex data to the VRAM
void render_frame(void); // renders a single frame
void cleanD3D(void); // closes Direct3D and releases memory
#define MAX_LOADSTRING 100
#define ID_10MILLIS 101
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_TRANSFORMINGVERTICES, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TRANSFORMINGVERTICES));
initD3D(g_hWnd);
init_graphics();
SetTimer(g_hWnd, // handle to main window
ID_10MILLIS, // timer identifier
100, // interval
(TIMERPROC)NULL); // no timer callback
// Main message loop:
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
render_frame();
}
cleanD3D();
return (int)msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TRANSFORMINGVERTICES));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_TRANSFORMINGVERTICES);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
g_hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
50, 50, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL);
if (!g_hWnd)
{
return FALSE;
}
ShowWindow(g_hWnd, nCmdShow);
UpdateWindow(g_hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
memset(&ps, 0, sizeof(ps));
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
//DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_MOUSEWHEEL:
g_i++;
//g_v_buffer->Release();
//init_graphics(g_i);
break;
case WM_PAINT:
//hdc = BeginPaint(hWnd, &ps);
//TODO: Add any drawing code here...
//EndPaint(hWnd, &ps);
ValidateRect(hWnd, 0);
break;
case WM_TIMER:
g_angle += 0.05;
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
// this function initializes and prepares Direct3D for use
void initD3D(HWND hWnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION); // create the Direct3D interface
D3DPRESENT_PARAMETERS d3dpp; // create a struct to hold various device information
ZeroMemory(&d3dpp, sizeof(d3dpp)); // clear out the struct for use
d3dpp.Windowed = TRUE; // program windowed, not fullscreen
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // discard old frames
d3dpp.hDeviceWindow = hWnd; // set the window to be used by Direct3D
// create a device class using this information and information from the d3dpp stuct
d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&d3ddev);
d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE);
d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
}
void init_graphics(int i)
{
// create three vertices using the CUSTOMVERTEX struct built earlier
CUSTOMVERTEX vertices[] =
{
{ 0.0f, -3.0f , 0.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.0f, 3.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -3.0f, 3.0f, 0.0f, D3DCOLOR_XRGB(255, 0, 0), },
};
d3ddev->CreateVertexBuffer(3 * sizeof(CUSTOMVERTEX), 0, CUSTOMFVF, D3DPOOL_MANAGED, &g_v_buffer, 0);
VOID* pVoid;
g_v_buffer->Lock(0, 0, &pVoid, 0);
memcpy(pVoid, vertices, 3 * sizeof(CUSTOMVERTEX));
g_v_buffer->Unlock();
}
// this is the function used to render a single frame
void render_frame(void)
{
// clear the window to a deep blue
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, g_i * 4, g_i * 10), 1.0f, 0);
d3ddev->BeginScene(); // begins the 3D scene
d3ddev->SetFVF(CUSTOMFVF);
d3ddev->SetStreamSource(0, g_v_buffer, 0, sizeof(CUSTOMVERTEX));
D3DXMATRIX transformation;
D3DXMATRIX rotation;
D3DXMatrixTranslation(&transformation, 4, 0, 0);
D3DXMatrixRotationY(&rotation, g_angle);
//d3ddev->SetTransform(D3DTS_WORLD, &rotation);
d3ddev->SetTransform(D3DTS_WORLD, &(rotation*transformation));
D3DXVECTOR3 from = { 0, 0, 10.0f },
at = { 0, 0, 0.0f },
up = { 0, -1, 0 };
D3DXMATRIX viewTransform;
D3DXMatrixLookAtLH(&viewTransform, &from, &at, &up);
d3ddev->SetTransform(D3DTS_VIEW, &viewTransform);
D3DXMATRIX perspective;
D3DXMatrixPerspectiveFovLH(&perspective, D3DX_PI/2.0f, ((float) SCREEN_WIDTH) / SCREEN_HEIGHT, 1.0f, 100.0f);
d3ddev->SetTransform(D3DTS_PROJECTION, &perspective);
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 1);
d3ddev->EndScene(); // ends the 3D scene
d3ddev->Present(NULL, NULL, NULL, NULL); // displays the created frame
}
// this is the function that cleans up Direct3D and COM
void cleanD3D(void)
{
g_v_buffer->Release();
d3ddev->Release(); // close and release the 3D device
d3d->Release(); // close and release Direct3D
}