|
| 1 | +#include <windows.h> |
| 2 | +#include <ddraw.h> |
| 3 | +#include <d3d.h> |
| 4 | +#include <math.h> |
| 5 | + |
| 6 | +typedef struct VTX7 |
| 7 | +{ |
| 8 | + float x, y, z; |
| 9 | + float nx, ny, nz; |
| 10 | + DWORD diffuse; |
| 11 | +} VTX7; |
| 12 | + |
| 13 | +#define FVF_VTX7 (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE) |
| 14 | + |
| 15 | +static int g_running = 1; |
| 16 | + |
| 17 | +static void MatIdentity(D3DMATRIX *m) |
| 18 | +{ |
| 19 | + ZeroMemory(m, sizeof(*m)); |
| 20 | + m->_11 = 1.0f; m->_22 = 1.0f; m->_33 = 1.0f; m->_44 = 1.0f; |
| 21 | +} |
| 22 | + |
| 23 | +static void MatMul(D3DMATRIX *out, const D3DMATRIX *a, const D3DMATRIX *b) |
| 24 | +{ |
| 25 | + D3DMATRIX r; |
| 26 | + const float *am = (const float *)&a->_11; |
| 27 | + const float *bm = (const float *)&b->_11; |
| 28 | + float *rm = (float *)&r._11; |
| 29 | + int row, col; |
| 30 | + for (row = 0; row < 4; row++) |
| 31 | + { |
| 32 | + for (col = 0; col < 4; col++) |
| 33 | + { |
| 34 | + rm[row * 4 + col] = |
| 35 | + am[row * 4 + 0] * bm[0 * 4 + col] + |
| 36 | + am[row * 4 + 1] * bm[1 * 4 + col] + |
| 37 | + am[row * 4 + 2] * bm[2 * 4 + col] + |
| 38 | + am[row * 4 + 3] * bm[3 * 4 + col]; |
| 39 | + } |
| 40 | + } |
| 41 | + *out = r; |
| 42 | +} |
| 43 | + |
| 44 | +static void MatRotationYawPitch(D3DMATRIX *m, float yaw, float pitch) |
| 45 | +{ |
| 46 | + float cy = (float)cos(yaw), sy = (float)sin(yaw); |
| 47 | + float cx = (float)cos(pitch), sx = (float)sin(pitch); |
| 48 | + |
| 49 | + D3DMATRIX ry, rx, r; |
| 50 | + MatIdentity(&ry); |
| 51 | + MatIdentity(&rx); |
| 52 | + |
| 53 | + ry._11 = cy; ry._13 = sy; |
| 54 | + ry._31 = -sy; ry._33 = cy; |
| 55 | + |
| 56 | + rx._22 = cx; rx._23 = -sx; |
| 57 | + rx._32 = sx; rx._33 = cx; |
| 58 | + |
| 59 | + MatMul(&r, &rx, &ry); |
| 60 | + *m = r; |
| 61 | +} |
| 62 | + |
| 63 | +static void MatLookAtLH(D3DMATRIX *m, |
| 64 | + float ex, float ey, float ez, |
| 65 | + float ax, float ay, float az, |
| 66 | + float ux, float uy, float uz) |
| 67 | +{ |
| 68 | + float zx = ax - ex, zy = ay - ey, zz = az - ez; |
| 69 | + float zlen = (float)sqrt(zx*zx + zy*zy + zz*zz); |
| 70 | + if (zlen > 0.0f) { zx /= zlen; zy /= zlen; zz /= zlen; } |
| 71 | + |
| 72 | + float xx = uy*zz - uz*zy; |
| 73 | + float xy = uz*zx - ux*zz; |
| 74 | + float xz = ux*zy - uy*zx; |
| 75 | + float xlen = (float)sqrt(xx*xx + xy*xy + xz*xz); |
| 76 | + if (xlen > 0.0f) { xx /= xlen; xy /= xlen; xz /= xlen; } |
| 77 | + |
| 78 | + float yx = zy*xz - zz*xy; |
| 79 | + float yy = zz*xx - zx*xz; |
| 80 | + float yz = zx*xy - zy*xx; |
| 81 | + |
| 82 | + MatIdentity(m); |
| 83 | + |
| 84 | + m->_11 = xx; m->_12 = yx; m->_13 = zx; |
| 85 | + m->_21 = xy; m->_22 = yy; m->_23 = zy; |
| 86 | + m->_31 = xz; m->_32 = yz; m->_33 = zz; |
| 87 | + |
| 88 | + m->_41 = -(xx*ex + xy*ey + xz*ez); |
| 89 | + m->_42 = -(yx*ex + yy*ey + yz*ez); |
| 90 | + m->_43 = -(zx*ex + zy*ey + zz*ez); |
| 91 | +} |
| 92 | + |
| 93 | +static void MatPerspectiveFovLH(D3DMATRIX *m, float fovy, float aspect, float zn, float zf) |
| 94 | +{ |
| 95 | + float yScale = 1.0f / (float)tan(fovy * 0.5f); |
| 96 | + float xScale = yScale / aspect; |
| 97 | + ZeroMemory(m, sizeof(*m)); |
| 98 | + m->_11 = xScale; |
| 99 | + m->_22 = yScale; |
| 100 | + m->_33 = zf / (zf - zn); |
| 101 | + m->_34 = 1.0f; |
| 102 | + m->_43 = (-zn * zf) / (zf - zn); |
| 103 | +} |
| 104 | + |
| 105 | +static const VTX7 g_cube[36] = |
| 106 | +{ |
| 107 | + /* +Z (red) */ |
| 108 | + {-1,-1, 1, 0,0,1, 0xFFFF0000}, { 1,-1, 1, 0,0,1, 0xFFFF0000}, { 1, 1, 1, 0,0,1, 0xFFFF0000}, |
| 109 | + {-1,-1, 1, 0,0,1, 0xFFFF0000}, { 1, 1, 1, 0,0,1, 0xFFFF0000}, {-1, 1, 1, 0,0,1, 0xFFFF0000}, |
| 110 | + /* -Z (green) */ |
| 111 | + { 1,-1,-1, 0,0,-1, 0xFF00FF00}, {-1,-1,-1, 0,0,-1, 0xFF00FF00}, {-1, 1,-1, 0,0,-1, 0xFF00FF00}, |
| 112 | + { 1,-1,-1, 0,0,-1, 0xFF00FF00}, {-1, 1,-1, 0,0,-1, 0xFF00FF00}, { 1, 1,-1, 0,0,-1, 0xFF00FF00}, |
| 113 | + /* +X (blue) */ |
| 114 | + { 1,-1, 1, 1,0,0, 0xFF0000FF}, { 1,-1,-1, 1,0,0, 0xFF0000FF}, { 1, 1,-1, 1,0,0, 0xFF0000FF}, |
| 115 | + { 1,-1, 1, 1,0,0, 0xFF0000FF}, { 1, 1,-1, 1,0,0, 0xFF0000FF}, { 1, 1, 1, 1,0,0, 0xFF0000FF}, |
| 116 | + /* -X (yellow) */ |
| 117 | + {-1,-1,-1, -1,0,0, 0xFFFFFF00}, {-1,-1, 1, -1,0,0, 0xFFFFFF00}, {-1, 1, 1, -1,0,0, 0xFFFFFF00}, |
| 118 | + {-1,-1,-1, -1,0,0, 0xFFFFFF00}, {-1, 1, 1, -1,0,0, 0xFFFFFF00}, {-1, 1,-1, -1,0,0, 0xFFFFFF00}, |
| 119 | + /* +Y (cyan) */ |
| 120 | + {-1, 1, 1, 0,1,0, 0xFF00FFFF}, { 1, 1, 1, 0,1,0, 0xFF00FFFF}, { 1, 1,-1, 0,1,0, 0xFF00FFFF}, |
| 121 | + {-1, 1, 1, 0,1,0, 0xFF00FFFF}, { 1, 1,-1, 0,1,0, 0xFF00FFFF}, {-1, 1,-1, 0,1,0, 0xFF00FFFF}, |
| 122 | + /* -Y (magenta) */ |
| 123 | + {-1,-1,-1, 0,-1,0, 0xFFFF00FF}, { 1,-1,-1, 0,-1,0, 0xFFFF00FF}, { 1,-1, 1, 0,-1,0, 0xFFFF00FF}, |
| 124 | + {-1,-1,-1, 0,-1,0, 0xFFFF00FF}, { 1,-1, 1, 0,-1,0, 0xFFFF00FF}, {-1,-1, 1, 0,-1,0, 0xFFFF00FF}, |
| 125 | +}; |
| 126 | + |
| 127 | +static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) |
| 128 | +{ |
| 129 | + switch (msg) |
| 130 | + { |
| 131 | + case WM_CLOSE: |
| 132 | + DestroyWindow(hwnd); |
| 133 | + return 0; |
| 134 | + case WM_DESTROY: |
| 135 | + g_running = 0; |
| 136 | + PostQuitMessage(0); |
| 137 | + return 0; |
| 138 | + case WM_KEYDOWN: |
| 139 | + if (wParam == VK_ESCAPE) |
| 140 | + { |
| 141 | + DestroyWindow(hwnd); |
| 142 | + return 0; |
| 143 | + } |
| 144 | + return 0; |
| 145 | + default: |
| 146 | + return DefWindowProcW(hwnd, msg, wParam, lParam); |
| 147 | + } |
| 148 | +} |
| 149 | + |
| 150 | +static HRESULT CreateZBuffer(IDirectDraw7 *ddraw, DWORD w, DWORD h, IDirectDrawSurface7 **outZ) |
| 151 | +{ |
| 152 | + DDSURFACEDESC2 desc; |
| 153 | + ZeroMemory(&desc, sizeof(desc)); |
| 154 | + desc.dwSize = sizeof(desc); |
| 155 | + desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; |
| 156 | + desc.dwWidth = w; |
| 157 | + desc.dwHeight = h; |
| 158 | + desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY; |
| 159 | + desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat); |
| 160 | + desc.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER; |
| 161 | + desc.ddpfPixelFormat.dwZBufferBitDepth = 16; |
| 162 | + return IDirectDraw7_CreateSurface(ddraw, &desc, outZ, NULL); |
| 163 | +} |
| 164 | + |
| 165 | +static void ShowHr(HWND hwnd, const wchar_t *what, HRESULT hr) |
| 166 | +{ |
| 167 | + wchar_t buf[256]; |
| 168 | + wsprintfW(buf, L"%s failed (hr=0x%08lx)", what, (DWORD)hr); |
| 169 | + MessageBoxW(hwnd, buf, L"d3d7test", MB_ICONERROR); |
| 170 | +} |
| 171 | + |
| 172 | +int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) |
| 173 | +{ |
| 174 | + WNDCLASSW wc; |
| 175 | + HWND hwnd; |
| 176 | + MSG msg; |
| 177 | + HRESULT hr; |
| 178 | + |
| 179 | + IDirectDraw7 *ddraw = NULL; |
| 180 | + IDirectDrawSurface7 *primary = NULL; |
| 181 | + IDirectDrawSurface7 *back = NULL; |
| 182 | + IDirectDrawSurface7 *zbuf = NULL; |
| 183 | + IDirect3D7 *d3d = NULL; |
| 184 | + IDirect3DDevice7 *dev = NULL; |
| 185 | + DDSURFACEDESC2 sdesc; |
| 186 | + |
| 187 | + RECT rc; |
| 188 | + DWORD W, H; |
| 189 | + DWORD tickStart; |
| 190 | + |
| 191 | + (void)hPrevInstance; |
| 192 | + (void)lpCmdLine; |
| 193 | + |
| 194 | + ZeroMemory(&wc, sizeof(wc)); |
| 195 | + wc.lpfnWndProc = WndProc; |
| 196 | + wc.hInstance = hInstance; |
| 197 | + wc.hCursor = LoadCursorW(NULL, IDC_ARROW); |
| 198 | + wc.lpszClassName = L"D3D7TestWindow"; |
| 199 | + if (!RegisterClassW(&wc)) |
| 200 | + return 1; |
| 201 | + |
| 202 | + hwnd = CreateWindowW(wc.lpszClassName, L"D3D7 Cube Test", |
| 203 | + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, |
| 204 | + NULL, NULL, hInstance, NULL); |
| 205 | + if (!hwnd) |
| 206 | + return 1; |
| 207 | + |
| 208 | + ShowWindow(hwnd, nCmdShow); |
| 209 | + UpdateWindow(hwnd); |
| 210 | + |
| 211 | + GetClientRect(hwnd, &rc); |
| 212 | + W = (DWORD)(rc.right - rc.left); |
| 213 | + H = (DWORD)(rc.bottom - rc.top); |
| 214 | + if (!W) W = 640; |
| 215 | + if (!H) H = 480; |
| 216 | + |
| 217 | + hr = DirectDrawCreateEx(NULL, (VOID **)&ddraw, &IID_IDirectDraw7, NULL); |
| 218 | + if (FAILED(hr)) |
| 219 | + { |
| 220 | + ShowHr(hwnd, L"DirectDrawCreateEx", hr); |
| 221 | + return 1; |
| 222 | + } |
| 223 | + |
| 224 | + hr = IDirectDraw7_SetCooperativeLevel(ddraw, hwnd, DDSCL_NORMAL); |
| 225 | + if (FAILED(hr)) |
| 226 | + { |
| 227 | + ShowHr(hwnd, L"SetCooperativeLevel", hr); |
| 228 | + goto Cleanup; |
| 229 | + } |
| 230 | + |
| 231 | + ZeroMemory(&sdesc, sizeof(sdesc)); |
| 232 | + sdesc.dwSize = sizeof(sdesc); |
| 233 | + sdesc.dwFlags = DDSD_CAPS; |
| 234 | + sdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; |
| 235 | + |
| 236 | + hr = IDirectDraw7_CreateSurface(ddraw, &sdesc, &primary, NULL); |
| 237 | + if (FAILED(hr)) |
| 238 | + { |
| 239 | + ShowHr(hwnd, L"Create primary surface", hr); |
| 240 | + goto Cleanup; |
| 241 | + } |
| 242 | + |
| 243 | + /* Create an offscreen render target in windowed mode */ |
| 244 | + ZeroMemory(&sdesc, sizeof(sdesc)); |
| 245 | + sdesc.dwSize = sizeof(sdesc); |
| 246 | + sdesc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; |
| 247 | + sdesc.dwWidth = W; |
| 248 | + sdesc.dwHeight = H; |
| 249 | + sdesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; |
| 250 | + hr = IDirectDraw7_CreateSurface(ddraw, &sdesc, &back, NULL); |
| 251 | + if (FAILED(hr)) |
| 252 | + { |
| 253 | + ShowHr(hwnd, L"Create offscreen render surface", hr); |
| 254 | + goto Cleanup; |
| 255 | + } |
| 256 | + |
| 257 | + hr = IDirectDraw7_QueryInterface(ddraw, &IID_IDirect3D7, (VOID **)&d3d); |
| 258 | + if (FAILED(hr)) |
| 259 | + { |
| 260 | + ShowHr(hwnd, L"QueryInterface(IDirect3D7)", hr); |
| 261 | + goto Cleanup; |
| 262 | + } |
| 263 | + |
| 264 | + hr = CreateZBuffer(ddraw, W, H, &zbuf); |
| 265 | + if (SUCCEEDED(hr)) |
| 266 | + IDirectDrawSurface7_AddAttachedSurface(back, zbuf); |
| 267 | + |
| 268 | + hr = IDirect3D7_CreateDevice(d3d, &IID_IDirect3DHALDevice, back, &dev); |
| 269 | + if (FAILED(hr)) |
| 270 | + hr = IDirect3D7_CreateDevice(d3d, &IID_IDirect3DRGBDevice, back, &dev); |
| 271 | + if (FAILED(hr)) |
| 272 | + { |
| 273 | + ShowHr(hwnd, L"CreateDevice", hr); |
| 274 | + goto Cleanup; |
| 275 | + } |
| 276 | + |
| 277 | + { |
| 278 | + D3DVIEWPORT7 vp; |
| 279 | + vp.dwX = 0; |
| 280 | + vp.dwY = 0; |
| 281 | + vp.dwWidth = W; |
| 282 | + vp.dwHeight = H; |
| 283 | + vp.dvMinZ = 0.0f; |
| 284 | + vp.dvMaxZ = 1.0f; |
| 285 | + IDirect3DDevice7_SetViewport(dev, &vp); |
| 286 | + } |
| 287 | + |
| 288 | + IDirect3DDevice7_SetRenderState(dev, D3DRENDERSTATE_ZENABLE, D3DZB_TRUE); |
| 289 | + IDirect3DDevice7_SetRenderState(dev, D3DRENDERSTATE_LIGHTING, FALSE); |
| 290 | + IDirect3DDevice7_SetRenderState(dev, D3DRENDERSTATE_CULLMODE, D3DCULL_CCW); |
| 291 | + |
| 292 | + tickStart = GetTickCount(); |
| 293 | + |
| 294 | + while (g_running) |
| 295 | + { |
| 296 | + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) |
| 297 | + { |
| 298 | + TranslateMessage(&msg); |
| 299 | + DispatchMessageW(&msg); |
| 300 | + } |
| 301 | + |
| 302 | + { |
| 303 | + float t = (GetTickCount() - tickStart) * 0.001f; |
| 304 | + D3DMATRIX world, view, proj; |
| 305 | + MatRotationYawPitch(&world, t, t * 0.7f); |
| 306 | + MatLookAtLH(&view, 0.0f, 0.0f, -5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); |
| 307 | + MatPerspectiveFovLH(&proj, 3.1415926f / 4.0f, (float)W / (float)H, 0.1f, 100.0f); |
| 308 | + |
| 309 | + IDirect3DDevice7_SetTransform(dev, D3DTRANSFORMSTATE_WORLD, &world); |
| 310 | + IDirect3DDevice7_SetTransform(dev, D3DTRANSFORMSTATE_VIEW, &view); |
| 311 | + IDirect3DDevice7_SetTransform(dev, D3DTRANSFORMSTATE_PROJECTION, &proj); |
| 312 | + |
| 313 | + IDirect3DDevice7_Clear(dev, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00202040, 1.0f, 0); |
| 314 | + |
| 315 | + if (SUCCEEDED(IDirect3DDevice7_BeginScene(dev))) |
| 316 | + { |
| 317 | + IDirect3DDevice7_DrawPrimitive(dev, D3DPT_TRIANGLELIST, FVF_VTX7, (LPVOID)g_cube, 36, 0); |
| 318 | + IDirect3DDevice7_EndScene(dev); |
| 319 | + } |
| 320 | + } |
| 321 | + |
| 322 | + /* Present (blit) the offscreen surface to the primary */ |
| 323 | + ZeroMemory(&rc, sizeof(rc)); |
| 324 | + GetClientRect(hwnd, &rc); |
| 325 | + hr = IDirectDrawSurface7_Blt(primary, &rc, back, NULL, DDBLT_WAIT, NULL); |
| 326 | + if (hr == DDERR_SURFACELOST) |
| 327 | + { |
| 328 | + IDirectDrawSurface7_Restore(primary); |
| 329 | + IDirectDrawSurface7_Restore(back); |
| 330 | + if (zbuf) IDirectDrawSurface7_Restore(zbuf); |
| 331 | + } |
| 332 | + |
| 333 | + Sleep(1); |
| 334 | + } |
| 335 | + |
| 336 | +Cleanup: |
| 337 | + if (dev) IDirect3DDevice7_Release(dev); |
| 338 | + if (zbuf) IDirectDrawSurface7_Release(zbuf); |
| 339 | + if (d3d) IDirect3D7_Release(d3d); |
| 340 | + if (back) IDirectDrawSurface7_Release(back); |
| 341 | + if (primary) IDirectDrawSurface7_Release(primary); |
| 342 | + if (ddraw) |
| 343 | + { |
| 344 | + IDirectDraw7_SetCooperativeLevel(ddraw, hwnd, DDSCL_NORMAL); |
| 345 | + IDirectDraw7_Release(ddraw); |
| 346 | + } |
| 347 | + return 0; |
| 348 | +} |
| 349 | + |
0 commit comments