aboutsummaryrefslogtreecommitdiffstats
path: root/3rdparty/imgui/examples/example_win32_directx9/main.cpp
blob: 7e5b957ae12a8d40f8d96cc8618b5ba0755a375a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// dear imgui: standalone example application for DirectX 9
// If you are new to dear imgui, see examples/README.txt and documentation at the top of imgui.cpp.

#include "imgui.h"
#include "imgui_impl_dx9.h"
#include "imgui_impl_win32.h"
#include <d3d9.h>
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#include <tchar.h>

// Data
static LPDIRECT3DDEVICE9        g_pd3dDevice = NULL;
static D3DPRESENT_PARAMETERS    g_d3dpp;

extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
        return true;

    switch (msg)
    {
    case WM_SIZE:
        if (g_pd3dDevice != NULL && wParam != SIZE_MINIMIZED)
        {
            ImGui_ImplDX9_InvalidateDeviceObjects();
            g_d3dpp.BackBufferWidth  = LOWORD(lParam);
            g_d3dpp.BackBufferHeight = HIWORD(lParam);
            HRESULT hr = g_pd3dDevice->Reset(&g_d3dpp);
            if (hr == D3DERR_INVALIDCALL)
                IM_ASSERT(0);
            ImGui_ImplDX9_CreateDeviceObjects();
        }
        return 0;
    case WM_SYSCOMMAND:
        if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu
            return 0;
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}

int main(int, char**)
{
    // Create application window
    WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("ImGui Example"), NULL };
    RegisterClassEx(&wc);
    HWND hwnd = CreateWindow(_T("ImGui Example"), _T("Dear ImGui DirectX9 Example"), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);

    // Initialize Direct3D
    LPDIRECT3D9 pD3D;
    if ((pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
    {
        UnregisterClass(_T("ImGui Example"), wc.hInstance);
        return 0;
    }
    ZeroMemory(&g_d3dpp, sizeof(g_d3dpp));
    g_d3dpp.Windowed = TRUE;
    g_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    g_d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
    g_d3dpp.EnableAutoDepthStencil = TRUE;
    g_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
    g_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; // Present with vsync
    //g_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Present without vsync, maximum unthrottled framerate

    // Create the D3DDevice
    if (pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_d3dpp, &g_pd3dDevice) < 0)
    {
        pD3D->Release();
        UnregisterClass(_T("ImGui Example"), wc.hInstance);
        return 0;
    }

    // Setup Dear ImGui binding
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO(); (void)io;
    //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;  // Enable Keyboard Controls
    ImGui_ImplWin32_Init(hwnd);
    ImGui_ImplDX9_Init(g_pd3dDevice);

    // Setup style
    ImGui::StyleColorsDark();
    //ImGui::StyleColorsClassic();

    // Load Fonts
    // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. 
    // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. 
    // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
    // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
    // - Read 'misc/fonts/README.txt' for more instructions and details.
    // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
    //io.Fonts->AddFontDefault();
    //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
    //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
    //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
    //io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f);
    //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
    //IM_ASSERT(font != NULL);

    bool show_demo_window = true;
    bool show_another_window = false;
    ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);

    // Main loop
    MSG msg;
    ZeroMemory(&msg, sizeof(msg));
    ShowWindow(hwnd, SW_SHOWDEFAULT);
    UpdateWindow(hwnd);
    while (msg.message != WM_QUIT)
    {
        // Poll and handle messages (inputs, window resize, etc.)
        // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
        // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
        // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
        // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
        if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            continue;
        }

        // Start the Dear ImGui frame
        ImGui_ImplDX9_NewFrame();
        ImGui_ImplWin32_NewFrame();
        ImGui::NewFrame();

        // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
        if (show_demo_window)
            ImGui::ShowDemoWindow(&show_demo_window);

        // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window.
        {
            static float f = 0.0f;
            static int counter = 0;

            ImGui::Begin("Hello, world!");                          // Create a window called "Hello, world!" and append into it.

            ImGui::Text("This is some useful text.");               // Display some text (you can use a format strings too)
            ImGui::Checkbox("Demo Window", &show_demo_window);      // Edit bools storing our window open/close state
            ImGui::Checkbox("Another Window", &show_another_window);

            ImGui::SliderFloat("float", &f, 0.0f, 1.0f);            // Edit 1 float using a slider from 0.0f to 1.0f    
            ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color

            if (ImGui::Button("Button"))                            // Buttons return true when clicked (most widgets return true when edited/activated)
                counter++;
            ImGui::SameLine();
            ImGui::Text("counter = %d", counter);

            ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
            ImGui::End();
        }

        // 3. Show another simple window.
        if (show_another_window)
        {
            ImGui::Begin("Another Window", &show_another_window);   // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
            ImGui::Text("Hello from another window!");
            if (ImGui::Button("Close Me"))
                show_another_window = false;
            ImGui::End();
        }

        // Rendering
        ImGui::EndFrame();
        g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false);
        g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
        g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, false);
        D3DCOLOR clear_col_dx = D3DCOLOR_RGBA((int)(clear_color.x*255.0f), (int)(clear_color.y*255.0f), (int)(clear_color.z*255.0f), (int)(clear_color.w*255.0f));
        g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, clear_col_dx, 1.0f, 0);
        if (g_pd3dDevice->BeginScene() >= 0)
        {
            ImGui::Render();
            ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
            g_pd3dDevice->EndScene();
        }
        HRESULT result = g_pd3dDevice->Present(NULL, NULL, NULL, NULL);

        // Handle loss of D3D9 device
        if (result == D3DERR_DEVICELOST && g_pd3dDevice->TestCooperativeLevel() == D3DERR_DEVICENOTRESET)
        {
            ImGui_ImplDX9_InvalidateDeviceObjects();
            g_pd3dDevice->Reset(&g_d3dpp);
            ImGui_ImplDX9_CreateDeviceObjects();
        }
    }

    ImGui_ImplDX9_Shutdown();
    ImGui_ImplWin32_Shutdown();
    ImGui::DestroyContext();

    if (g_pd3dDevice) g_pd3dDevice->Release();
    if (pD3D) pD3D->Release();
    DestroyWindow(hwnd);
    UnregisterClass(_T("ImGui Example"), wc.hInstance);

    return 0;
}
> 0x00); break; case _ADJUST: rgblight_setrgb (0x7A, 0x00, 0xFF); break; default: // for any other layers, or the default layer rgblight_setrgb (0x00, 0xFF, 0xFF); break; } return state; } ``` ### `layer_state_set_*` 函数文档 * 键盘/修订: `uint32_t layer_state_set_kb(uint32_t state)` * 布局: `uint32_t layer_state_set_user(uint32_t state)``状态`是活动层的bitmask, 详见[布局概述](keymap.md#布局的层状态) # 掉电保存配置 (EEPROM) 这会让你的配置长期的保存在键盘中。这些配置保存在你主控的EEPROM里,掉电不会消失。 设置可以用`eeconfig_read_kb`和`eeconfig_read_user`读取,可以用`eeconfig_update_kb`和`eeconfig_update_user`写入。这对于您希望能够切换的功能很有用(比如切换RGB层指示。此外,你可以用`eeconfig_init_kb`和`eeconfig_init_user`来设置EEPROM默认值。 最复杂的部分可能是,有很多方法可以通过EEPROM存储和访问数据,并且并没有用哪种方法是“政治正确”的。你每个功能只有一个双字(四字节)空间。 记住EEPROM是有写入寿命的。尽管写入寿命很高,但是并不是只有设置写道EEPROM中。如果你写入频繁,你的MCU寿命将会变短。 * 如果您不理解这个例子,那么您可能希望避免使用这个特性,因为它相当复杂。 ### 示例实现 本例讲解了如何添加设置,并且读写。本里使用了用户布局。这是一个复杂的函数,有很多事情要做。实际上,它使用了很多上述函数来工作! 在你的keymap.c文件中,将以下代码添加至顶部: ```c typedef union { uint32_t raw; struct { bool rgb_layer_change :1; }; } user_config_t; user_config_t user_config; ``` 以上代码建立了一个结构体,该结构体可以存储设置并可用于写入EEPROM。如此这般将无需定义变量,因为在结构体中已然定义。要记住`bool` (布尔)值使用1位, `uint8_t`使用8位, `uint16_t`使用16位。你可以混合搭配使用,但是顺序记错可能会招致麻烦,因为那会改变写入写出的值。 `layer_state_set_*`函数中使用了`rgb_layer_change`,使用了`keyboard_post_init_user`和`process_record_user`来配置一切。 首先要使用`keyboard_post_init_user,你要加入`eeconfig_read_user()`来填充你刚刚创建的结构体。然后您可以立即使用这个结构来控制您的布局中的功能。就像这样: ```c void keyboard_post_init_user(void) { // 调用布局级别的矩阵初始化 // 从EEPROM读用户配置 user_config.raw = eeconfig_read_user(); // 如使能,设置默认层 if (user_config.rgb_layer_change) { rgblight_enable_noeeprom(); rgblight_sethsv_noeeprom_cyan(); rgblight_mode_noeeprom(1); } } ``` 以上函数会在读EEPROM配置后立即使用该设置来设置默认层RGB颜色。"raw"的值是从你上面基于"union"创建的结构体中转换来的。 ```c uint32_t layer_state_set_user(uint32_t state) { switch (biton32(state)) { case _RAISE: if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_magenta(); rgblight_mode_noeeprom(1); } break; case _LOWER: if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_red(); rgblight_mode_noeeprom(1); } break; case _PLOVER: if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_green(); rgblight_mode_noeeprom(1); } break; case _ADJUST: if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_white(); rgblight_mode_noeeprom(1); } break; default: // 针对其他层或默认层 if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_cyan(); rgblight_mode_noeeprom(1); } break; } return state; } ``` 这样仅在值使能时会改变RGB背光灯。现在配置这个值, 为`process_record_user`创建一个新键码叫做`RGB_LYR`。我们要确保,如果使用正常的RGB代码,使用上面的示例将其关闭,请将其设置为: ```c bool process_record_user(uint16_t keycode, keyrecord_t *record) { switch (keycode) { case FOO: if (record->event.pressed) { // 按下时做点什么 } else { // 释放时做点什么 } return false; // 跳过此键的进一步处理 case KC_ENTER: // 在按下回车时播放音符 if (record->event.pressed) { PLAY_SONG(tone_qwerty); } return true; // 让QMK产生回车按下/释放事件 case RGB_LYR: // 本句让underglow作为层指示,或正常使用。 if (record->event.pressed) { user_config.rgb_layer_change ^= 1; // 切换状态 eeconfig_update_user(user_config.raw); // 向EEPROM写入新状态 if (user_config.rgb_layer_change) { // 如果层状态被使能 layer_state_set(layer_state); // 那么立刻更新层颜色 } } return false; case RGB_MODE_FORWARD ... RGB_MODE_GRADIENT: // 对于所有的RGB代码 (see quantum_keycodes.h, L400 可以参考) if (record->event.pressed) { //本句失能层指示,假设你改变了这个…你要把它禁用 if (user_config.rgb_layer_change) { // 仅当使能时 user_config.rgb_layer_change = false; // 失能,然后 eeconfig_update_user(user_config.raw); // 向EEPROM写入设置 } } return true; break; default: return true; // 按其他键正常 } } ``` 最后你要加入`eeconfig_init_user`函数,所以当EEPROM重置时,可以指定默认值, 甚至自定义操作。想强制重置EEPROM,请用`EEP_RST`键码或[Bootmagic](feature_bootmagic.md)函数。比如,如果要在默认情况下设置RGB层指示,并保存默认值 ```c void eeconfig_init_user(void) { // EEPROM正被重置 user_config.raw = 0; user_config.rgb_layer_change = true; // 我们想要默认使能 eeconfig_update_user(user_config.raw); // 向EEPROM写入默认值 // use the non noeeprom versions, 还要向EEPROM写入这些值 rgblight_enable(); // 默认使能RGB rgblight_sethsv_cyan(); // 默认设置青色 rgblight_mode(1); // 默认设置长亮 } ``` 然后就完事了。RGB层指示会在你想让它工作时工作。这个设置会一直保存,即便你拔下键盘。如果你使用其他RGB代码,层指示将失能,现在它可以做你所想了。 ### 'EECONFIG' 函数文档 * 键盘/修订: `void eeconfig_init_kb(void)`, `uint32_t eeconfig_read_kb(void)``void eeconfig_update_kb(uint32_t val)` * 布局: `void eeconfig_init_user(void)`, `uint32_t eeconfig_read_user(void)``void eeconfig_update_user(uint32_t val)` `val` 是你想写入EEPROM的值,`eeconfig_read_*`函数会从EEPROM返回一个32位(双字)的值。 # 自定义击键-长按临界值(TAPPING_TERM) 默认情况下,击键-长按临界值是全球统一的,并且不能通过键进行配置。对于大多数用户来说这很好。但是在有些情况下,对于`LT`键来说按键延时对双功能键的提升更大,可能是因为有些键比其他的键更容易按住。为了不给每个都自定义键码,本功能可以为每个键定义`TAPPING_TERM`。 想使能这个功能的话, 要先在`config.h`加上`#define TAPPING_TERM_PER_KEY`。 ## `get_tapping_term`示例实现 想要修改基于键码的`TAPPING TERM`,你要向`keymap.c`文件添加如下代码: ```c uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { switch (keycode) { case SFT_T(KC_SPC): return TAPPING_TERM + 1250; case LT(1, KC_GRV): return 130; default: return TAPPING_TERM; } } ``` ### `get_tapping_term` 函数文档 不像这篇的其他功能,这个不需要quantum或者键盘级别的函数,只要用户级函数即可。