2015-03-09 21:03:46 +08:00
// ImGui Win32 + DirectX9 binding
// https://github.com/ocornut/imgui
# include <imgui.h>
# include "imgui_impl_dx9.h"
// DirectX
# include <d3dx9.h>
# define DIRECTINPUT_VERSION 0x0800
# include <dinput.h>
// Data
2015-03-09 22:13:29 +08:00
static HWND g_hWnd = 0 ;
2015-03-09 21:03:46 +08:00
static INT64 g_Time = 0 ;
static INT64 g_TicksPerSecond = 0 ;
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL ;
static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL ;
2015-04-10 04:05:35 +08:00
static LPDIRECT3DINDEXBUFFER9 g_pIB = NULL ;
static int VERTEX_BUFFER_SIZE = 30000 ; // TODO: Make buffers smaller and grow dynamically as needed.
static int INDEX_BUFFER_SIZE = 30000 ; // TODO: Make buffers smaller and grow dynamically as needed.
2015-03-09 21:03:46 +08:00
struct CUSTOMVERTEX
{
D3DXVECTOR3 pos ;
D3DCOLOR col ;
D3DXVECTOR2 uv ;
} ;
# define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
// If text or lines are blurry when integrating ImGui in your engine:
// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
static void ImGui_ImplDX9_RenderDrawLists ( ImDrawList * * const cmd_lists , int cmd_lists_count )
{
size_t total_vtx_count = 0 ;
2015-04-10 04:05:35 +08:00
size_t total_idx_count = 0 ;
2015-03-09 21:03:46 +08:00
for ( int n = 0 ; n < cmd_lists_count ; n + + )
2015-04-10 04:05:35 +08:00
{
2015-03-09 21:03:46 +08:00
total_vtx_count + = cmd_lists [ n ] - > vtx_buffer . size ( ) ;
2015-04-10 04:05:35 +08:00
total_idx_count + = cmd_lists [ n ] - > idx_buffer . size ( ) ;
}
2015-03-09 21:03:46 +08:00
if ( total_vtx_count = = 0 )
return ;
// Copy and convert all vertices into a single contiguous buffer
CUSTOMVERTEX * vtx_dst ;
2015-04-10 04:05:35 +08:00
ImDrawIdx * idx_dst ;
2015-03-09 21:03:46 +08:00
if ( g_pVB - > Lock ( 0 , ( UINT ) total_vtx_count , ( void * * ) & vtx_dst , D3DLOCK_DISCARD ) < 0 )
return ;
2015-04-10 04:05:35 +08:00
if ( g_pIB - > Lock ( 0 , ( UINT ) total_idx_count , ( void * * ) & idx_dst , D3DLOCK_DISCARD ) < 0 )
return ;
2015-03-09 21:03:46 +08:00
for ( int n = 0 ; n < cmd_lists_count ; n + + )
{
const ImDrawList * cmd_list = cmd_lists [ n ] ;
const ImDrawVert * vtx_src = & cmd_list - > vtx_buffer [ 0 ] ;
for ( size_t i = 0 ; i < cmd_list - > vtx_buffer . size ( ) ; i + + )
{
vtx_dst - > pos . x = vtx_src - > pos . x ;
vtx_dst - > pos . y = vtx_src - > pos . y ;
vtx_dst - > pos . z = 0.0f ;
vtx_dst - > col = ( vtx_src - > col & 0xFF00FF00 ) | ( ( vtx_src - > col & 0xFF0000 ) > > 16 ) | ( ( vtx_src - > col & 0xFF ) < < 16 ) ; // RGBA --> ARGB for DirectX9
vtx_dst - > uv . x = vtx_src - > uv . x ;
vtx_dst - > uv . y = vtx_src - > uv . y ;
vtx_dst + + ;
vtx_src + + ;
}
2015-04-10 04:05:35 +08:00
memcpy ( idx_dst , & cmd_list - > idx_buffer [ 0 ] , cmd_list - > idx_buffer . size ( ) * sizeof ( ImDrawIdx ) ) ;
idx_dst + = cmd_list - > idx_buffer . size ( ) ;
2015-03-09 21:03:46 +08:00
}
g_pVB - > Unlock ( ) ;
2015-04-10 04:05:35 +08:00
g_pIB - > Unlock ( ) ;
2015-03-09 21:03:46 +08:00
g_pd3dDevice - > SetStreamSource ( 0 , g_pVB , 0 , sizeof ( CUSTOMVERTEX ) ) ;
2015-04-10 04:05:35 +08:00
g_pd3dDevice - > SetIndices ( g_pIB ) ;
2015-03-09 21:03:46 +08:00
g_pd3dDevice - > SetFVF ( D3DFVF_CUSTOMVERTEX ) ;
2015-04-07 19:56:52 +08:00
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing
g_pd3dDevice - > SetPixelShader ( NULL ) ;
g_pd3dDevice - > SetVertexShader ( NULL ) ;
2015-03-09 21:03:46 +08:00
g_pd3dDevice - > SetRenderState ( D3DRS_CULLMODE , D3DCULL_NONE ) ;
g_pd3dDevice - > SetRenderState ( D3DRS_LIGHTING , false ) ;
g_pd3dDevice - > SetRenderState ( D3DRS_ZENABLE , false ) ;
g_pd3dDevice - > SetRenderState ( D3DRS_ALPHABLENDENABLE , true ) ;
g_pd3dDevice - > SetRenderState ( D3DRS_BLENDOP , D3DBLENDOP_ADD ) ;
g_pd3dDevice - > SetRenderState ( D3DRS_ALPHATESTENABLE , false ) ;
g_pd3dDevice - > SetRenderState ( D3DRS_SRCBLEND , D3DBLEND_SRCALPHA ) ;
g_pd3dDevice - > SetRenderState ( D3DRS_DESTBLEND , D3DBLEND_INVSRCALPHA ) ;
g_pd3dDevice - > SetRenderState ( D3DRS_SCISSORTESTENABLE , true ) ;
g_pd3dDevice - > SetTextureStageState ( 0 , D3DTSS_COLOROP , D3DTOP_SELECTARG1 ) ;
g_pd3dDevice - > SetTextureStageState ( 0 , D3DTSS_COLORARG1 , D3DTA_DIFFUSE ) ;
g_pd3dDevice - > SetTextureStageState ( 0 , D3DTSS_ALPHAOP , D3DTOP_MODULATE ) ;
g_pd3dDevice - > SetTextureStageState ( 0 , D3DTSS_ALPHAARG1 , D3DTA_TEXTURE ) ;
g_pd3dDevice - > SetTextureStageState ( 0 , D3DTSS_ALPHAARG2 , D3DTA_DIFFUSE ) ;
g_pd3dDevice - > SetSamplerState ( 0 , D3DSAMP_MINFILTER , D3DTEXF_LINEAR ) ;
g_pd3dDevice - > SetSamplerState ( 0 , D3DSAMP_MAGFILTER , D3DTEXF_LINEAR ) ;
// Setup orthographic projection matrix
D3DXMATRIXA16 mat ;
D3DXMatrixIdentity ( & mat ) ;
g_pd3dDevice - > SetTransform ( D3DTS_WORLD , & mat ) ;
g_pd3dDevice - > SetTransform ( D3DTS_VIEW , & mat ) ;
D3DXMatrixOrthoOffCenterLH ( & mat , 0.5f , ImGui : : GetIO ( ) . DisplaySize . x + 0.5f , ImGui : : GetIO ( ) . DisplaySize . y + 0.5f , 0.5f , - 1.0f , + 1.0f ) ;
g_pd3dDevice - > SetTransform ( D3DTS_PROJECTION , & mat ) ;
// Render command lists
int vtx_offset = 0 ;
2015-04-10 04:05:35 +08:00
int idx_offset = 0 ;
2015-03-09 21:03:46 +08:00
for ( int n = 0 ; n < cmd_lists_count ; n + + )
{
const ImDrawList * cmd_list = cmd_lists [ n ] ;
for ( size_t cmd_i = 0 ; cmd_i < cmd_list - > commands . size ( ) ; cmd_i + + )
{
const ImDrawCmd * pcmd = & cmd_list - > commands [ cmd_i ] ;
2015-03-09 23:26:58 +08:00
if ( pcmd - > user_callback )
{
pcmd - > user_callback ( cmd_list , pcmd ) ;
}
else
{
const RECT r = { ( LONG ) pcmd - > clip_rect . x , ( LONG ) pcmd - > clip_rect . y , ( LONG ) pcmd - > clip_rect . z , ( LONG ) pcmd - > clip_rect . w } ;
g_pd3dDevice - > SetTexture ( 0 , ( LPDIRECT3DTEXTURE9 ) pcmd - > texture_id ) ;
g_pd3dDevice - > SetScissorRect ( & r ) ;
2015-06-30 05:46:18 +08:00
g_pd3dDevice - > DrawIndexedPrimitive ( D3DPT_TRIANGLELIST , vtx_offset , 0 , ( UINT ) cmd_list - > vtx_buffer . size ( ) , idx_offset , pcmd - > idx_count / 3 ) ;
2015-03-09 23:26:58 +08:00
}
2015-04-10 04:05:35 +08:00
idx_offset + = pcmd - > idx_count ;
2015-03-09 21:03:46 +08:00
}
2015-06-30 05:46:18 +08:00
vtx_offset + = ( int ) cmd_list - > vtx_buffer . size ( ) ;
2015-03-09 21:03:46 +08:00
}
}
2015-03-14 18:32:29 +08:00
LRESULT ImGui_ImplDX9_WndProcHandler ( HWND , UINT msg , WPARAM wParam , LPARAM lParam )
2015-03-09 21:03:46 +08:00
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
switch ( msg )
{
case WM_LBUTTONDOWN :
io . MouseDown [ 0 ] = true ;
return true ;
case WM_LBUTTONUP :
io . MouseDown [ 0 ] = false ;
return true ;
case WM_RBUTTONDOWN :
io . MouseDown [ 1 ] = true ;
return true ;
case WM_RBUTTONUP :
io . MouseDown [ 1 ] = false ;
return true ;
case WM_MOUSEWHEEL :
io . MouseWheel + = GET_WHEEL_DELTA_WPARAM ( wParam ) > 0 ? + 1.0f : - 1.0f ;
return true ;
case WM_MOUSEMOVE :
io . MousePos . x = ( signed short ) ( lParam ) ;
io . MousePos . y = ( signed short ) ( lParam > > 16 ) ;
return true ;
case WM_KEYDOWN :
2015-03-14 18:49:26 +08:00
if ( wParam < 256 )
2015-03-09 21:03:46 +08:00
io . KeysDown [ wParam ] = 1 ;
return true ;
case WM_KEYUP :
2015-03-14 18:49:26 +08:00
if ( wParam < 256 )
2015-03-09 21:03:46 +08:00
io . KeysDown [ wParam ] = 0 ;
return true ;
case WM_CHAR :
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
if ( wParam > 0 & & wParam < 0x10000 )
io . AddInputCharacter ( ( unsigned short ) wParam ) ;
return true ;
}
return 0 ;
}
2015-03-09 21:05:18 +08:00
bool ImGui_ImplDX9_Init ( void * hwnd , IDirect3DDevice9 * device )
2015-03-09 21:03:46 +08:00
{
2015-03-09 22:13:29 +08:00
g_hWnd = ( HWND ) hwnd ;
2015-03-09 21:03:46 +08:00
g_pd3dDevice = device ;
2015-03-09 22:13:29 +08:00
2015-03-09 21:03:46 +08:00
if ( ! QueryPerformanceFrequency ( ( LARGE_INTEGER * ) & g_TicksPerSecond ) )
return false ;
if ( ! QueryPerformanceCounter ( ( LARGE_INTEGER * ) & g_Time ) )
return false ;
ImGuiIO & io = ImGui : : GetIO ( ) ;
io . KeyMap [ ImGuiKey_Tab ] = VK_TAB ; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime.
io . KeyMap [ ImGuiKey_LeftArrow ] = VK_LEFT ;
io . KeyMap [ ImGuiKey_RightArrow ] = VK_RIGHT ;
io . KeyMap [ ImGuiKey_UpArrow ] = VK_UP ;
2015-04-24 15:18:56 +08:00
io . KeyMap [ ImGuiKey_DownArrow ] = VK_DOWN ;
2015-03-09 21:03:46 +08:00
io . KeyMap [ ImGuiKey_Home ] = VK_HOME ;
io . KeyMap [ ImGuiKey_End ] = VK_END ;
io . KeyMap [ ImGuiKey_Delete ] = VK_DELETE ;
io . KeyMap [ ImGuiKey_Backspace ] = VK_BACK ;
io . KeyMap [ ImGuiKey_Enter ] = VK_RETURN ;
io . KeyMap [ ImGuiKey_Escape ] = VK_ESCAPE ;
io . KeyMap [ ImGuiKey_A ] = ' A ' ;
io . KeyMap [ ImGuiKey_C ] = ' C ' ;
io . KeyMap [ ImGuiKey_V ] = ' V ' ;
io . KeyMap [ ImGuiKey_X ] = ' X ' ;
io . KeyMap [ ImGuiKey_Y ] = ' Y ' ;
io . KeyMap [ ImGuiKey_Z ] = ' Z ' ;
io . RenderDrawListsFn = ImGui_ImplDX9_RenderDrawLists ;
2015-03-09 22:13:29 +08:00
io . ImeWindowHandle = g_hWnd ;
2015-03-09 21:03:46 +08:00
return true ;
}
2015-03-09 22:55:46 +08:00
void ImGui_ImplDX9_Shutdown ( )
{
ImGui_ImplDX9_InvalidateDeviceObjects ( ) ;
ImGui : : Shutdown ( ) ;
g_pd3dDevice = NULL ;
g_hWnd = 0 ;
}
static void ImGui_ImplDX9_CreateFontsTexture ( )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
// Build
unsigned char * pixels ;
int width , height , bytes_per_pixel ;
io . Fonts - > GetTexDataAsAlpha8 ( & pixels , & width , & height , & bytes_per_pixel ) ;
// Create DX9 texture
LPDIRECT3DTEXTURE9 pTexture = NULL ;
if ( D3DXCreateTexture ( g_pd3dDevice , width , height , 1 , D3DUSAGE_DYNAMIC , D3DFMT_A8 , D3DPOOL_DEFAULT , & pTexture ) < 0 )
{
IM_ASSERT ( 0 ) ;
return ;
}
D3DLOCKED_RECT tex_locked_rect ;
if ( pTexture - > LockRect ( 0 , & tex_locked_rect , NULL , 0 ) ! = D3D_OK )
{
IM_ASSERT ( 0 ) ;
return ;
}
for ( int y = 0 ; y < height ; y + + )
memcpy ( ( unsigned char * ) tex_locked_rect . pBits + tex_locked_rect . Pitch * y , pixels + ( width * bytes_per_pixel ) * y , ( width * bytes_per_pixel ) ) ;
pTexture - > UnlockRect ( 0 ) ;
// Store our identifier
io . Fonts - > TexID = ( void * ) pTexture ;
2015-05-12 22:16:12 +08:00
// Cleanup (don't clear the input data if you want to append new fonts later)
io . Fonts - > ClearInputData ( ) ;
io . Fonts - > ClearTexData ( ) ;
2015-03-09 22:55:46 +08:00
}
bool ImGui_ImplDX9_CreateDeviceObjects ( )
{
if ( ! g_pd3dDevice )
return false ;
2015-03-16 18:02:10 +08:00
if ( g_pd3dDevice - > CreateVertexBuffer ( VERTEX_BUFFER_SIZE * sizeof ( CUSTOMVERTEX ) , D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY , D3DFVF_CUSTOMVERTEX , D3DPOOL_DEFAULT , & g_pVB , NULL ) < 0 )
2015-03-09 22:55:46 +08:00
return false ;
2015-04-10 04:05:35 +08:00
if ( g_pd3dDevice - > CreateIndexBuffer ( INDEX_BUFFER_SIZE * sizeof ( ImDrawIdx ) , D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY , D3DFMT_INDEX16 , D3DPOOL_DEFAULT , & g_pIB , NULL ) < 0 )
return false ;
2015-03-09 22:55:46 +08:00
ImGui_ImplDX9_CreateFontsTexture ( ) ;
return true ;
}
2015-03-09 22:13:29 +08:00
void ImGui_ImplDX9_InvalidateDeviceObjects ( )
2015-03-09 21:03:46 +08:00
{
2015-03-09 22:13:29 +08:00
if ( ! g_pd3dDevice )
return ;
2015-03-09 21:03:46 +08:00
if ( g_pVB )
{
g_pVB - > Release ( ) ;
g_pVB = NULL ;
}
2015-04-10 04:05:35 +08:00
if ( g_pIB )
{
g_pIB - > Release ( ) ;
g_pIB = NULL ;
}
2015-03-09 21:03:46 +08:00
if ( LPDIRECT3DTEXTURE9 tex = ( LPDIRECT3DTEXTURE9 ) ImGui : : GetIO ( ) . Fonts - > TexID )
{
tex - > Release ( ) ;
ImGui : : GetIO ( ) . Fonts - > TexID = 0 ;
}
2015-03-09 22:13:29 +08:00
}
2015-03-09 21:03:46 +08:00
void ImGui_ImplDX9_NewFrame ( )
{
2015-03-09 22:55:46 +08:00
if ( ! g_pVB )
ImGui_ImplDX9_CreateDeviceObjects ( ) ;
2015-03-09 21:03:46 +08:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2015-03-09 22:13:29 +08:00
// Setup display size (every frame to accommodate for window resizing)
RECT rect ;
GetClientRect ( g_hWnd , & rect ) ;
io . DisplaySize = ImVec2 ( ( float ) ( rect . right - rect . left ) , ( float ) ( rect . bottom - rect . top ) ) ;
2015-03-09 21:03:46 +08:00
// Setup time step
INT64 current_time ;
QueryPerformanceCounter ( ( LARGE_INTEGER * ) & current_time ) ;
io . DeltaTime = ( float ) ( current_time - g_Time ) / g_TicksPerSecond ;
g_Time = current_time ;
// Read keyboard modifiers inputs
io . KeyCtrl = ( GetKeyState ( VK_CONTROL ) & 0x8000 ) ! = 0 ;
io . KeyShift = ( GetKeyState ( VK_SHIFT ) & 0x8000 ) ! = 0 ;
2015-03-13 17:49:38 +08:00
io . KeyAlt = ( GetKeyState ( VK_MENU ) & 0x8000 ) ! = 0 ;
2015-03-09 21:03:46 +08:00
// io.KeysDown : filled by WM_KEYDOWN/WM_KEYUP events
// io.MousePos : filled by WM_MOUSEMOVE events
// io.MouseDown : filled by WM_*BUTTON* events
// io.MouseWheel : filled by WM_MOUSEWHEEL events
2015-05-01 17:25:15 +08:00
// Hide OS mouse cursor if ImGui is drawing it
SetCursor ( io . MouseDrawCursor ? NULL : LoadCursor ( NULL , IDC_ARROW ) ) ;
2015-03-09 21:03:46 +08:00
// Start the frame
ImGui : : NewFrame ( ) ;
}