//----------------------------------------------------------------------------- // File: Matrices.cpp // // Desc: Now that we know how to create a device and render some 2D vertices, // this tutorial goes the next step and renders 3D geometry. To deal with // 3D geometry we need to introduce the use of 4x4 Matrices to transform // the geometry with translations, rotations, scaling, and setting up our // camera. // // Geometry is defined in model space. We can move it (translation), // rotate it (rotation), or stretch it (scaling) using a world transform. // The geometry is then said to be in world space. Next, we need to // position the camera, or eye point, somewhere to look at the geometry. // Another transform, via the view matrix, is used, to position and // rotate our view. With the geometry then in view space, our last // transform is the projection transform, which "projects" the 3D scene // into our 2D viewport. // // Note that in this tutorial, we are introducing the use of D3DX, which // is a set of helper utilities for D3D. In this case, we are using some // of D3DX's useful matrix initialization functions. To use D3DX, simply // include and link with d3dx9.lib. // // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- /* * This file was taken from RakNet 4.082. * Please see licenses/RakNet license.txt for the underlying license and related copyright. * * Modified work: Copyright (c) 2017-2020, SLikeSoft UG (haftungsbeschränkt) * * This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style * license found in the license.txt file in the root directory of this source tree. */ // RakNet: Logger includes. Include before Windows.h #include "SQLiteClientLoggerPlugin.h" #include "slikenet/PacketizedTCP.h" #include "DX9_BackbufferGrabber.h" #include #include #include #include // used for _T-macro #pragma warning( disable : 4996 ) // disable deprecated warning #include #pragma warning( default : 4996 ) //----------------------------------------------------------------------------- // Global variables //----------------------------------------------------------------------------- LPDIRECT3D9 g_pD3D = nullptr; // Used to create the D3DDevice LPDIRECT3DDEVICE9 g_pd3dDevice = nullptr; // Our rendering device LPDIRECT3DVERTEXBUFFER9 g_pVB = nullptr; // Buffer to hold vertices // A structure for our custom vertex type struct CUSTOMVERTEX { FLOAT x, y, z; // The untransformed, 3D position for the vertex DWORD color; // The vertex color }; // Our custom FVF, which describes our custom vertex structure #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE) //----------------------------------------------------------------------------- // Name: InitD3D() // Desc: Initializes Direct3D //----------------------------------------------------------------------------- HRESULT InitD3D( HWND hWnd ) { // Create the D3D object. if(nullptr == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ) return E_FAIL; // Set up the structure used to create the D3DDevice D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, sizeof( d3dpp ) ); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // KevinJ: Used known backbuffer format of 4 bytes per pixel, and let us lock the backbuffer d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; // D3DFMT_UNKNOWN; d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; // Create the D3DDevice if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ) ) ) { return E_FAIL; } // Turn off culling, so we see the front and back of the triangle g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); // Turn off D3D lighting, since we are providing our own vertex colors g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); return S_OK; } //----------------------------------------------------------------------------- // Name: InitGeometry() // Desc: Creates the scene geometry //----------------------------------------------------------------------------- HRESULT InitGeometry() { // Initialize three vertices for rendering a triangle // ARGB CUSTOMVERTEX g_Vertices[] = { { -1.0f,-1.0f, 0.0f, 0xffff0000, }, { 1.0f,-1.0f, 0.0f, 0xff0000ff, }, { 0.0f, 1.0f, 0.0f, 0xffffffff, }, // { -1.0f,-1.0f, 0.0f, 0xffff0000, }, // { 1.0f,-1.0f, 0.0f, 0xffff0000, }, // { 0.0f, 1.0f, 0.0f, 0xffff0000, }, }; // Create the vertex buffer. if( FAILED( g_pd3dDevice->CreateVertexBuffer( 3 * sizeof( CUSTOMVERTEX ), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, nullptr) ) ) { return E_FAIL; } // Fill the vertex buffer. VOID* pVertices; if( FAILED( g_pVB->Lock( 0, sizeof( g_Vertices ), ( void** )&pVertices, 0 ) ) ) return E_FAIL; memcpy( pVertices, g_Vertices, sizeof( g_Vertices ) ); g_pVB->Unlock(); return S_OK; } //----------------------------------------------------------------------------- // Name: Cleanup() // Desc: Releases all previously initialized objects //----------------------------------------------------------------------------- VOID Cleanup() { if( g_pVB != nullptr) g_pVB->Release(); if( g_pd3dDevice != nullptr) g_pd3dDevice->Release(); if( g_pD3D != nullptr) g_pD3D->Release(); } //----------------------------------------------------------------------------- // Name: SetupMatrices() // Desc: Sets up the world, view, and projection transform Matrices. //----------------------------------------------------------------------------- VOID SetupMatrices() { // For our world matrix, we will just rotate the object about the y-axis. D3DXMATRIXA16 matWorld; // Set up the rotation matrix to generate 1 full rotation (2*PI radians) // every 1000 ms. To avoid the loss of precision inherent in very high // floating point numbers, the system time is modulated by the rotation // period before conversion to a radian angle. // UINT iTime = timeGetTime() % 1000; // FLOAT fAngle = iTime * ( 2.0f * D3DX_PI ) / 1000.0f; // D3DXMatrixRotationY( &matWorld, fAngle ); // g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); // Set up our view matrix. A view matrix can be defined given an eye point, // a point to lookat, and a direction for which way is up. Here, we set the // eye five units back along the z-axis and up three units, look at the // origin, and define "up" to be in the y-direction. D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f ); D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f ); D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f ); D3DXMATRIXA16 matView; D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec ); g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView ); // For the projection matrix, we set up a perspective transform (which // transforms geometry from 3D view space to 2D viewport space, with // a perspective divide making objects smaller in the distance). To build // a perpsective transform, we need the field of view (1/4 pi is common), // the aspect ratio, and the near and far clipping planes (which define at // what distances geometry should be no longer be rendered). D3DXMATRIXA16 matProj; D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f ); g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj ); } //----------------------------------------------------------------------------- // Name: Render() // Desc: Draws the scene //----------------------------------------------------------------------------- VOID Render() { // Clear the backbuffer to a black color g_pd3dDevice->Clear( 0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 0 ), 1.0f, 0 ); // Begin the scene if( SUCCEEDED( g_pd3dDevice->BeginScene() ) ) { // Setup the world, view, and projection Matrices SetupMatrices(); // Render the vertex buffer contents g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) ); g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX ); g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 1 ); // End the scene g_pd3dDevice->EndScene(); } // Present the backbuffer contents to the display g_pd3dDevice->Present(nullptr, nullptr, nullptr, nullptr); } //----------------------------------------------------------------------------- // Name: MsgProc() // Desc: The window's message handler //----------------------------------------------------------------------------- LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { case WM_DESTROY: Cleanup(); PostQuitMessage( 0 ); return 0; } return DefWindowProc( hWnd, msg, wParam, lParam ); } //----------------------------------------------------------------------------- // Name: WinMain() // Desc: The application's entry point //----------------------------------------------------------------------------- INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT ) { // Register the window class WNDCLASSEX wc = { sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, _T("D3D Tutorial"), nullptr }; RegisterClassEx( &wc ); // Connect to the server if it is running, to store screenshots SLNet::PacketizedTCP packetizedTCP; SLNet::SQLiteClientLoggerPlugin loggerPlugin; packetizedTCP.AttachPlugin(&loggerPlugin); packetizedTCP.Start(0,0); loggerPlugin.SetServerParameters(packetizedTCP.Connect("127.0.0.1", 38123, true), "d3dvideo.sqlite"); loggerPlugin.SetMemoryConstraint(8000000); DX9_BackbufferGrabber backbufferGrabber; // Create the application's window HWND hWnd = CreateWindow(_T("D3D Tutorial"), _T("D3D Tutorial 03: Matrices"), WS_OVERLAPPEDWINDOW, 100, 100, 512, 512, nullptr, nullptr, hInst, nullptr); DWORD timeSinceLastLog, timeSinceLastTick, lastLogTime=0; float lastFps = 0.f; // unnecessary assignment - added to workaround false-positive of C4701 timeSinceLastTick=0; // Initialize Direct3D if( SUCCEEDED( InitD3D( hWnd ) ) ) { // Create the scene geometry if( SUCCEEDED( InitGeometry() ) ) { // Show the window ShowWindow( hWnd, SW_SHOWDEFAULT ); UpdateWindow( hWnd ); // Start backbuffer grabber backbufferGrabber.InitBackbufferGrabber(g_pd3dDevice, 256, 256); // Enter the message loop MSG msg; ZeroMemory( &msg, sizeof( msg ) ); while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, nullptr, 0U, 0U, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else { Render(); timeSinceLastLog=timeGetTime()-lastLogTime; if (packetizedTCP.GetConnectionCount()>0 && timeSinceLastLog>30) { SLNet::RGBImageBlob blob; backbufferGrabber.LockBackbufferCopy(&blob); RakAssert(blob.data!=0); rakSqlLog("Screenshots", "screenshot", ( &blob )); static bool saveToDiskOnce=true; if (saveToDiskOnce) { blob.SaveToTGA("MatricesDemoFirstFrame.tga"); saveToDiskOnce=false; } backbufferGrabber.ReleaseBackbufferCopy(); } float fps; if (timeSinceLastTick!=0) { DWORD elapsedTime = timeGetTime()-timeSinceLastTick; if (elapsedTime==0) fps=lastFps; else fps = 1000.0f / (float) elapsedTime; } else { fps=0; } lastFps = fps; timeSinceLastTick=timeGetTime(); rakSqlLog("FPS", "FPS", ( fps )); loggerPlugin.IncrementAutoTickCount(); } } } } UnregisterClass(_T("D3D Tutorial"), wc.hInstance ); return 0; }