// Developed by Neil Kemp: http://neilkemp.us // Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php #ifndef BOOL #define BOOL int #define FALSE 0 #define TRUE 1 #endif // Globals IDirect3DSurface9* select_surface; IDirect3DSurface9* select_depth_surface; IDirect3DSurface9* select_memory_surface; // Create the select surface - Must be released on lost device and recreated on device reset BOOL create_select_surface(IDirect3DDevice9* device_pointer, const D3DPRESENT_PARAMETERS& d3dpp) { // Assertions _ASSERT(device_pointer != 0); // Create select render surface if(FAILED(device_pointer->CreateRenderTarget(d3dpp.BackBufferWidth, d3dpp.BackBufferHeight, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, TRUE, &select_surface, 0))) { MessageBox(_T("Failed to create D3D9 select surface."), _T("Unexpected Error"), MB_OK | MB_ICONEXCLAMATION); return FALSE; } // Create select depth surface if(FAILED(device_pointer->CreateDepthStencilSurface(d3dpp.BackBufferWidth, d3dpp.BackBufferHeight, D3DFMT_D16, D3DMULTISAMPLE_NONE, 0, TRUE, &select_depth_surface, 0))) { MessageBox(_T("Failed to create D3D9 select depth surface."), _T("Unexpected Error"), MB_OK | MB_ICONEXCLAMATION); return FALSE; } // Create select offscreen surface if(FAILED(device_pointer->CreateOffscreenPlainSurface(d3dpp.BackBufferWidth, d3dpp.BackBufferHeight, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &select_memory_surface, 0))) { MessageBox(_T("Failed to create D3D9 select memory surface."), _T("Unexpected Error"), MB_OK | MB_ICONEXCLAMATION); return FALSE; } return TRUE; } // Render the nodes to the select surface with index encoded colors BOOL render_select_surface(IDirect3DDevice9* device_pointer) { // Assertions _ASSERT(device_pointer != 0); _ASSERT(select_surface != 0); _ASSERT(select_depth_surface != 0); _ASSERT(select_memory_surface != 0); // Local data D3DMATERIAL9 material; D3DCOLOR saved_ambient; unsigned int count, i; int R, G, B; // Start rendering device_pointer->SetRenderTarget(0, select_surface); device_pointer->SetDepthStencilSurface(select_depth_surface); device_pointer->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(0, 0, 0, 255), 1.0f, 0); device_pointer->BeginScene(); // --------------------- // Save the current ambient color device_pointer->GetRenderState(D3DRS_AMBIENT, &saved_ambient); // !! IMPORTANT - for perfect color storage // Set texture operation to choose diffuse arg2 device_pointer->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2); // Set up a white material ZeroMemory(&material, sizeof(D3DMATERIAL9)); material.Diffuse.r = 1.0f; material.Diffuse.g = 1.0f; material.Diffuse.b = 1.0f; material.Diffuse.a = 1.0f; material.Ambient.r = 1.0f; material.Ambient.g = 1.0f; material.Ambient.b = 1.0f; material.Ambient.a = 1.0f; device_pointer->SetMaterial(&material); // Enable alpha test device_pointer->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x00000022); device_pointer->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER); device_pointer->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); // --------------------- // Initialize node RGB colors R = 0; G = 0; B = 1; // TODO You enter the number of nodes to render count = ?? for(i=0; iSetRenderState(D3DRS_AMBIENT, D3DCOLOR_RGBA(R, G, B, 255)); // TODO Set node texture with alpha device_pointer->SetTexture(0, node_texture); // TODO Render node i with fixed function lighting B++; } // --------------------- // Disable alpha test device_pointer->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); // Restore texture operation to modulate device_pointer->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); // Restore the ambient color device_pointer->SetRenderState(D3DRS_AMBIENT, saved_ambient); // --------------------- // End Direct3D scene device_pointer->EndScene(); // FOR TESTING // D3DXSaveSurfaceToFile(_T("C:\\select_surface.bmp"), D3DXIFF_BMP, select_surface, 0, 0); // Get color key surface data into memory if(FAILED(device_pointer->GetRenderTargetData(select_surface, select_memory_surface))) { return FALSE; } return TRUE; } // Select a node from the index encoded color select surface - index_out is -1 on no node selected BOOL select_node(IDirect3DDevice9* device_pointer, const CRect &d3d_window_client_rect, const CPoint& mouse_point, int& index_out) { // D3D Color Struct struct d3d_color_s { unsigned char B, G, R, A; }; // Assertions _ASSERT(device_pointer != 0); _ASSERT(select_memory_surface != 0); // Local data D3DLOCKED_RECT locked_rect; unsigned char* pixel_array; d3d_color_s pixel; // Set default index_out = -1; // Lock the memory surface if(FAILED(select_memory_surface->LockRect(&locked_rect, &d3d_window_client_rect, D3DLOCK_READONLY))) { return FALSE; } // Pointer to data is LR.pBits, each row is // LR.Pitch bytes apart (often it is the same as width*bpp, but // can be larger if driver uses padding) // Get the pixel pixel_array = static_cast(locked_rect.pBits); memcpy(&pixel, pixel_array + ((mouse_point.y * locked_rect.Pitch) + mouse_point.x * sizeof(d3d_color_s)), sizeof(d3d_color_s)); // Unlock the memory surface select_memory_surface->UnlockRect(); // If pixel is not black then we clicked a node if(pixel.R != 0 || pixel.G != 0 || pixel.B != 0) { // Get index index_out = ((pixel.R * 65536) + (pixel.G * 256) + pixel.B) - 1; } return TRUE; }