// Dear ImGui: standalone example application for DirectX 11 // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. // Read online: https://github.com/ocornut/imgui/tree/master/docs #include "imgui.h" #include "imgui_impl_win32.h" #include "imgui_impl_dx11.h" #include #include #include "implot.h" #include #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" struct Pixel { int x; int y; float value; Pixel(int x, int y, float value) : x(x), y(y), value(value) {} }; static ID3D11Device* g_pd3dDevice = nullptr; static ID3D11DeviceContext* g_pd3dDeviceContext = nullptr; static IDXGISwapChain* g_pSwapChain = nullptr; static ID3D11RenderTargetView* g_mainRenderTargetView = nullptr; bool CreateDeviceD3D(HWND hWnd); void CleanupDeviceD3D(); void CreateRenderTarget(); void CleanupRenderTarget(); LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); unsigned char* ImageData(const char* filename, int &width, int &height, int &channels) { unsigned char* image_data = stbi_load(filename, &width, &height, &channels, 4); return image_data; } bool LoadTextureFromFile(unsigned char* image_data, int image_width, int image_height, ID3D11ShaderResourceView** out_srv) { D3D11_TEXTURE2D_DESC desc; ZeroMemory(&desc, sizeof(desc)); desc.Width = image_width; desc.Height = image_height; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.SampleDesc.Count = 1; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; desc.CPUAccessFlags = 0; ID3D11Texture2D *pTexture = NULL; D3D11_SUBRESOURCE_DATA subResource; subResource.pSysMem = image_data; subResource.SysMemPitch = desc.Width * 4; subResource.SysMemSlicePitch = 0; g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; ZeroMemory(&srvDesc, sizeof(srvDesc)); srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MipLevels = desc.MipLevels; srvDesc.Texture2D.MostDetailedMip = 0; g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, out_srv); pTexture->Release(); return true; } #undef max; #undef min; #include #include #include #include #include //void watershedSegmentation(unsigned char* image, int width, int height) { // const float INFINITY = std::numeric_limits::max(); // // int* labels = new int[width * height]; // for (int i = 0; i < width * height; ++i) { // labels[i] = -1; // } // // float* copy = new float[width * height]; // for (int i = 0; i < width * height; ++i) { // copy[i] = static_cast(image[i]); // } // // std::priority_queue, [](const Pixel& p1, const Pixel& p2) { // return p1.value < p2.value; // }> queue; // // for (int i = 0; i < width * height; ++i) { // queue.push(Pixel(i % width, i / width, copy[i])); // } // // while (!queue.empty()) { // Pixel pixel = queue.top(); // queue.pop(); // // int x = pixel.x; // int y = pixel.y; // int index = y * width + x; // // for (int i = -1; i <= 1; ++i) { // for (int j = -1; j <= 1; ++j) { // int nx = x + i; // int ny = y + j; // int nIndex = ny * width + nx; // // if (nx >= 0 && nx < width && ny >= 0 && ny < height && labels[nIndex] != -1) { // if (labels[index] == -1) { // labels[index] = labels[nIndex]; // } else if (labels[index] != labels[nIndex]) { // labels[index] = -2; // } // } // } // } // // if (labels[index] == -1) { // labels[index] = index; // // copy[index] = INFINITY; // // for (int i = -1; i <= 1; ++i) { // for (int j = -1; j <= 1; ++j) { // int nx = x + i; // int ny = y + j; // int nIndex = ny * width + nx; // // if (nx >= 0 && nx < width && ny >= 0 && ny < height && labels[nIndex] == -1) { // queue.push(Pixel(nx, ny, copy[nIndex])); // } // } // } // } // } // // for (int i = 0; i < width * height; ++i) { // if (labels[i] == -2) { // image[i] = static_cast(INFINITY); // } // } // // delete[] labels; // delete[] copy; //} // void dilation(unsigned char* image, int width, int height) { int structuringElement[3][3] = { {0, 255, 0}, {255, 255, 255}, {0, 255, 0} }; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { int maxPixelValue = 0; for (int j = -1; j <= 1; ++j) { for (int i = -1; i <= 1; ++i) { if (x + i >= 0 && x + i < width && y + j >= 0 && y + j < height) { int imagePixelValue = image[(y + j) * width + (x + i)]; int structuringElementValue = structuringElement[j + 1][i + 1]; int newPixelValue = imagePixelValue + structuringElementValue; if (newPixelValue > maxPixelValue) { maxPixelValue = newPixelValue; } } } } image[y * width + x] = static_cast(maxPixelValue > 255 ? 255 : maxPixelValue); } } } void erosion(unsigned char* image, int width, int height) { int structuringElement[3][3] = { {0, 255, 0}, {255, 255, 255}, {0, 255, 0} }; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { int minPixelValue = 255; for (int j = -1; j <= 1; ++j) { for (int i = -1; i <= 1; ++i) { if (x + i >= 0 && x + i < width && y + j >= 0 && y + j < height) { int imagePixelValue = image[(y + j) * width + (x + i)]; int structuringElementValue = structuringElement[j + 1][i + 1]; int newPixelValue = imagePixelValue - structuringElementValue; if (newPixelValue < minPixelValue) { minPixelValue = newPixelValue; } } } } image[y * width + x] = static_cast(minPixelValue < 0 ? 0 : minPixelValue); } } } void hitAndMiss(unsigned char* image, int width, int height) { int structuringElement1[3][3] = { {0, 0, 0}, {255, 255, 0}, {0, 255, 0} }; int structuringElement2[3][3] = { {255, 255, 255}, {0, 0, 255}, {0, 0, 0} }; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { bool match1 = true; bool match2 = true; for (int j = -1; j <= 1; ++j) { for (int i = -1; i <= 1; ++i) { if (x + i >= 0 && x + i < width && y + j >= 0 && y + j < height) { int imagePixelValue = image[(y + j) * width + (x + i)]; int structuringElement1Value = structuringElement1[j + 1][i + 1]; int structuringElement2Value = structuringElement2[j + 1][i + 1]; if (structuringElement1Value == 255 && imagePixelValue != 255) { match1 = false; } if (structuringElement2Value == 255 && imagePixelValue != 0) { match2 = false; } } } } image[y * width + x] = (match1 && match2) ? 255 : 0; } } } void thickening(unsigned char* image, int width, int height) { int structuringElement[3][3] = { {0, 255, 0}, {255, 255, 255}, {0, 255, 0} }; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { if (image[y * width + x] == 255) { for (int j = -1; j <= 1; ++j) { for (int i = -1; i <= 1; ++i) { if (x + i >= 0 && x + i < width && y + j >= 0 && y + j < height) { int structuringElementValue = structuringElement[j + 1][i + 1]; if (structuringElementValue == 255) { image[(y + j) * width + (x + i)] = 255; } } } } } } } } void thinning(unsigned char* image, int width, int height) { int structuringElement[3][3] = { {0, 255, 0}, {255, 255, 255}, {0, 255, 0} }; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { if (image[y * width + x] == 255) { bool match = true; for (int j = -1; j <= 1; ++j) { for (int i = -1; i <= 1; ++i) { if (x + i >= 0 && x + i < width && y + j >= 0 && y + j < height) { int imagePixelValue = image[(y + j) * width + (x + i)]; int structuringElementValue = structuringElement[j + 1][i + 1]; if (structuringElementValue == 255 && imagePixelValue != 255) { match = false; break; } } } if (!match) { break; } } image[y * width + x] = match ? 255 : 0; } } } } void rgbToHsl(float r, float g, float b, float &_h, float &_s, float &_l) { r /= 255.f; g /= 255.f; b /= 255.f; float max = std::max({r, g, b}); float min = std::min({r, g, b}); float h, s, l = (max + min) / 2.f; if(max - min < .001f) { h = s = 0.f; } else { float d = max - min; s = l > 0.5f ? d / (2.f - max - min) : d / (max + min); if (max - r < .001f) { h = (g - b) / d + (g < b ? 6.f : 0.f); } else if (max - g < .001f) { h = (b - r) / d + 2.f; } else if (max - b < .001f) { h = (r - g) / d + 4.f; } h /= 6; } _h = h; _s = s; _l = l; } void hslToRgb(float h, float s, float l, int &_r, int &_g, int &_b){ float r, g, b = 0.f; if(s < .001f) { r = g = b = l; } else { auto hue2rgb = [](float p, float q, float t) { if (t < 0) t += 1.f; if (t > 1) t -= 1.f; if (t < 1.f / 6.f) return p + (q - p) * 6.f * t; if (t < 1.f / 2.f) return q; if (t < 2.f / 3.f) return p + (q - p) * (2.f / 3.f - t) * 6.f; return p; }; float q = l < 0.5f ? l * (1.f + s) : l + s - l * s; float p = 2.f * l - q; r = hue2rgb(p, q, h + 1.f/3.f); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1.f/3.f); } _r = std::clamp(int(r * 255), 0, 255); _g = std::clamp(int(g * 255), 0, 255); _b = std::clamp(int(b * 255), 0, 255); } void InvertImageColors(unsigned char* imageData, int width, int height) { for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { int index = (y * width + x) * 4; imageData[index] = 255 - imageData[index]; imageData[index + 1] = 255 - imageData[index + 1]; imageData[index + 2] = 255 - imageData[index + 2]; } } } void Sepia(unsigned char* imageData, int width, int height) { for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { int index = (y * width + x) * 4; imageData[index] = int(std::min((imageData[index] * .393f) + (imageData[index + 1] * .769f) + (imageData[index + 2] * .189f), 255.f)); imageData[index + 1] = int(std::min((imageData[index] * .349f) + (imageData[index + 1] * .686f) + (imageData[index + 2] * .168f), 255.f)); imageData[index + 2] = int(std::min((imageData[index] * .272f) + (imageData[index + 1] * .534f) + (imageData[index + 2] * .131f), 255.f)); } } } void Saturation(unsigned char* imageData, int width, int height, float scale) { float h, s, l = 0.f; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { int index = (y * width + x) * 4; int r = imageData[index]; int b = imageData[index + 1]; int g = imageData[index + 2]; rgbToHsl(r, g, b, h, s, l); s *= scale; hslToRgb(h, s, l, r, g, b); imageData[index] = r; imageData[index + 1] = g; imageData[index + 2] = b; } } } void Light(unsigned char* imageData, int width, int height, float scale) { float h, s, l = 0.f; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { int index = (y * width + x) * 4; int r = imageData[index]; int b = imageData[index + 1]; int g = imageData[index + 2]; rgbToHsl(r, g, b, h, s, l); l *= scale; hslToRgb(h, s, l, r, g, b); imageData[index] = r; imageData[index + 1] = g; imageData[index + 2] = b; } } } std::array, 7> KernelFunction(float sigma) { const int kernel_size = 7; std::array, 7> kernel; float sum = 0.0f; for (int i = 0; i < kernel_size; i++) { for (int j = 0; j < kernel_size; j++) { int x = i - kernel_size / 2; int y = j - kernel_size / 2; kernel[i][j] = exp(-(x * x + y * y) / (2 * sigma * sigma)); sum += kernel[i][j]; } } for (int i = 0; i < kernel_size; i++) { for (int j = 0; j < kernel_size; j++) { kernel[i][j] /= sum; } } return kernel; } void GaussianKernel(unsigned char* imageData, int width, int height, int channels, int kernel_size, std::array, 7> kernel) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { for (int c = 0; c < channels; c++) { float sum = 0.0f; for (int i = 0; i < kernel_size; i++) { for (int j = 0; j < kernel_size; j++) { int px = x + i - kernel_size / 2; int py = y + j - kernel_size / 2; if (px < 0 || px >= width || py < 0 || py >= height) { continue; } sum += kernel[i][j] * imageData[(py * width + px) * channels + c]; } } imageData[(y * width + x) * channels + c] = (unsigned char)sum; } } } } unsigned char* greyScale(const unsigned char* image, unsigned char* grayscaleImage, int width, int height, int numChannels) { for (int i = 0; i < width * height; ++i) { unsigned char r = image[i * numChannels]; unsigned char g = image[i * numChannels + 1]; unsigned char b = image[i * numChannels + 2]; grayscaleImage[i] = static_cast(0.2989 * r + 0.587 * g + 0.114 * b); } return grayscaleImage; } void binaryTransform(unsigned char* grayscaleImage, unsigned char* binaryImage, int width, int height, int threshold) { for (int i = 0; i < width * height; ++i) { binaryImage[i] = (grayscaleImage[i] > threshold) ? 255 : 0; } } //void binaryTransform(const unsigned char* image, unsigned char* binaryImage, int threshold, int width, int height, int channels) //{ // for (int i = 0; i < width * height; i++) { // unsigned char brightness = 0.2126f * image[i * channels] + 0.7152f * image[i * channels + 1] + 0.0722f * image[i * channels + 2]; // // if (brightness < threshold) { // binaryImage[i] = 0; // } // else { // binaryImage[i] = 255; // } // } //} int calculateOtsuThreshold(const unsigned char* image, int width, int height) { int histogram[256] = {0}; for (int i = 0; i < width * height; ++i) { histogram[image[i]]++; } int totalPixels = width * height; float sum = 0.0; for (int i = 0; i < 256; ++i) { sum += i * histogram[i]; } float sumB = 0.0; int wB = 0; int wF = 0; float maxVariance = 0.0; int threshold = 0; for (int i = 0; i < 256; ++i) { wB += histogram[i]; if (wB == 0) continue; wF = totalPixels - wB; if (wF == 0) break; sumB += i * histogram[i]; float meanB = sumB / wB; float meanF = (sum - sumB) / wF; float betweenVariance = wB * wF * (meanB - meanF) * (meanB - meanF); if (betweenVariance > maxVariance) { maxVariance = betweenVariance; threshold = i; } } return threshold; } void hough_transform(const unsigned char* input_image, int width, int height, int threshold, unsigned char* hough_image, int channel) { int hough_width = 2 * (width + height); int hough_height = 180; int* hough_space = new int[hough_width * hough_height]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (input_image[(y * width + x)] > threshold) { for (int theta = 0; theta < hough_height; theta++) { double angle = theta * (3.14 / 180.0); int rho = static_cast((x * cos(angle)) + (y * sin(angle))); rho += (hough_width / 2); hough_space[(theta * hough_width) + rho]++; } } } } int max_value = 0; for (int i = 0; i < hough_width * hough_height; i++) { if (hough_space[i] > max_value) { max_value = hough_space[i]; } } hough_image = new unsigned char[hough_width * hough_height * channel]; for (int y = 0; y < hough_height; y++) { for (int x = 0; x < hough_width; x++) { int value = static_cast(255.0 * hough_space[(y * hough_width) + x] / max_value); hough_image[3 * (y * hough_width + x)] = value; hough_image[3 * (y * hough_width + x) + 1] = value; hough_image[3 * (y * hough_width + x) + 2] = value; } } delete[] hough_space; } int main(int, char**) { WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr }; ::RegisterClassExW(&wc); HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr); if (!CreateDeviceD3D(hwnd)) { CleanupDeviceD3D(); ::UnregisterClassW(wc.lpszClassName, wc.hInstance); return 1; } ::ShowWindow(hwnd, SW_SHOWDEFAULT); ::UpdateWindow(hwnd); IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImPlot::CreateContext(); //ImPlot::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; ImGui::StyleColorsDark(); ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); bool main_window = true; bool show_another_window = false; bool image_window = false; bool histogram = false; char image_location[MAX_PATH] = {}; ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); bool negative = false; bool sepia = false; bool saturation = false; bool blure = false; float scaleS = 0.f; bool light = false; float scaleL = 0.f; float sigma = 2.0f; bool binary = false; bool hough = false; bool thining = false; bool thick = false; bool hitmiss = false; bool erosi = false; bool dil = false; bool done = false; int* colorR = nullptr; int* colorG = nullptr; int* colorB = nullptr; static float sliderValue = 0.5f; float xMin = 0; float xMax = 256 * sliderValue; while (!done) { MSG msg; while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); if (msg.message == WM_QUIT) done = true; } if (done) break; ImGui_ImplDX11_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); if (main_window) { static float f = 0.0f; static int counter = 0; ImGui::Begin("App"); ImGui::InputText("Image location", image_location, sizeof(image_location), image_window ? ImGuiInputTextFlags_ReadOnly : 0); if (!image_window) { if (ImGui::Button("Load Image")) image_window = true; } else { if (ImGui::Button("Close Image")) image_window = false; if (colorR != NULL && colorB != NULL && colorG != NULL) { delete[] colorR; delete[] colorG; delete[] colorB; colorR = NULL; colorG = NULL; colorB = NULL; } } ImGui::End(); } if (image_window) { int my_image_width = 0; int my_image_height = 0; int my_image_channels = 0; unsigned char* image_data = ImageData(image_location, my_image_width, my_image_height, my_image_channels); unsigned char* grayscaleImage = new unsigned char[my_image_width * my_image_height * my_image_channels]; unsigned char* binaryImage = new unsigned char[my_image_width * my_image_height * my_image_channels]; unsigned char* hough_image = nullptr; if (colorR == NULL && colorB == NULL && colorG == NULL) { colorR = new int[256]; colorG = new int[256]; colorB = new int[256]; int place = 0; for (int i = 0; i < my_image_width * my_image_height * my_image_channels; i += my_image_channels) { colorR[image_data[i]]++; colorG[image_data[i + 1]]++; colorB[image_data[i + 2]]++; } } if (negative) { InvertImageColors(image_data, my_image_width, my_image_height); } if (sepia) { Sepia(image_data, my_image_width, my_image_height); } if (saturation) { Saturation(image_data, my_image_width, my_image_height, scaleS); } if (light) { Light(image_data, my_image_width, my_image_height, scaleL); } if (blure) { GaussianKernel(image_data, my_image_width, my_image_height, my_image_channels, 7, KernelFunction(sigma)); } if (binary) { binaryTransform(greyScale(image_data, grayscaleImage, my_image_width, my_image_height, my_image_channels), binaryImage, my_image_width, my_image_height, calculateOtsuThreshold(image_data, my_image_width, my_image_height)); } if (hough) { hough_transform(image_data, my_image_width, my_image_height, 125, hough_image, my_image_channels); } if (thining) { thinning(image_data, my_image_width, my_image_height); } if (thick) { thickening(image_data, my_image_width, my_image_height); } if (hitmiss) { hitAndMiss(image_data, my_image_width, my_image_height); } if (erosi) { erosion(image_data, my_image_width, my_image_height); } if (dil) { dilation(image_data, my_image_width, my_image_height); } if (histogram) { ImGui::Begin("Histogram"); float xMin = 0; float xMax = 256 * sliderValue; /*ImPlot::SetNextPlotLimitsX(xMin, xMax, ImGuiCond_Always);*/ if (ImPlot::BeginPlot("RGB Histogram")) { ImPlot::PlotHistogram("Red", colorR, 256); ImPlot::PlotHistogram("Green", colorG, 256); ImPlot::PlotHistogram("Blue", colorB, 256); ImPlot::EndPlot(); } ImGui::SliderFloat("X-axis Range", &sliderValue, 0.0f, 1.0f); ImGui::End(); } if (!image_data) { ImGui::Begin("Error"); ImGui::Text("Wrong path"); if (ImGui::Button("Ok")) image_window = false; ImGui::End(); } else { ID3D11ShaderResourceView* my_texture = NULL; if (binary == TRUE) { bool ret = LoadTextureFromFile(binaryImage, my_image_width, my_image_height, &my_texture); delete[] binaryImage; delete[] grayscaleImage; stbi_image_free(image_data); } else if (hough == TRUE) { bool ret = LoadTextureFromFile(hough_image, my_image_width, my_image_height, &my_texture); delete[] hough_image; stbi_image_free(image_data); } else { bool ret = LoadTextureFromFile(image_data, my_image_width, my_image_height, &my_texture); stbi_image_free(image_data); } ImGui::Begin("Image window"); ImGui::Image((void*)my_texture, ImVec2(my_image_width, my_image_height)); ImGui::End(); ImGui::Begin("Histograms"); ImGui::Checkbox("RGB", &histogram); ImGui::End(); ImGui::Begin("Operatory"); ImGui::Checkbox("Dylacja", &dil); ImGui::Checkbox("Erozja", &erosi); ImGui::Checkbox("Hit and Miss", &hitmiss); ImGui::Checkbox("Pogrubianie", &thick); ImGui::Checkbox("Thining", &thining); ImGui::End(); ImGui::Begin("Basic Filters"); ImGui::Checkbox("Negative", &negative); ImGui::Checkbox("Sepia", &sepia); ImGui::Checkbox("Saturation", &saturation); /*ImGui::SameLine();*/ ImGui::SliderFloat(" ", &scaleS, 0.f, 1.f); ImGui::Checkbox("Light", &light); /*ImGui::SameLine();*/ ImGui::SliderFloat(" ", &scaleL, 0.f, 1.f); ImGui::End(); ImGui::Begin("Filters"); ImGui::Checkbox("Blure", &blure); ImGui::SameLine(); ImGui::SliderFloat(" ", &sigma, 0.f, 10.f); ImGui::Checkbox("Binaryzacja", &binary); ImGui::Checkbox("Hough transform", &hough); ImGui::End(); } } ImGui::Render(); const float clear_color_with_alpha[4] = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w }; g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr); g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha); ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); g_pSwapChain->Present(1, 0); } ImGui_ImplDX11_Shutdown(); ImGui_ImplWin32_Shutdown(); ImPlot::DestroyContext(); ImGui::DestroyContext(); CleanupDeviceD3D(); ::DestroyWindow(hwnd); ::UnregisterClassW(wc.lpszClassName, wc.hInstance); return 0; } bool CreateDeviceD3D(HWND hWnd) { DXGI_SWAP_CHAIN_DESC sd; ZeroMemory(&sd, sizeof(sd)); sd.BufferCount = 2; sd.BufferDesc.Width = 0; sd.BufferDesc.Height = 0; sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.BufferDesc.RefreshRate.Numerator = 60; sd.BufferDesc.RefreshRate.Denominator = 1; sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.OutputWindow = hWnd; sd.SampleDesc.Count = 1; sd.SampleDesc.Quality = 0; sd.Windowed = TRUE; sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; UINT createDeviceFlags = 0; D3D_FEATURE_LEVEL featureLevel; const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, }; HRESULT res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); if (res == DXGI_ERROR_UNSUPPORTED) res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); if (res != S_OK) return false; CreateRenderTarget(); return true; } void CleanupDeviceD3D() { CleanupRenderTarget(); if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = nullptr; } if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = nullptr; } if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = nullptr; } } void CreateRenderTarget() { ID3D11Texture2D* pBackBuffer; g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_mainRenderTargetView); pBackBuffer->Release(); } void CleanupRenderTarget() { if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = nullptr; } } extern IMGUI_IMPL_API 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 != nullptr && wParam != SIZE_MINIMIZED) { CleanupRenderTarget(); g_pSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), DXGI_FORMAT_UNKNOWN, 0); CreateRenderTarget(); } return 0; case WM_SYSCOMMAND: if ((wParam & 0xfff0) == SC_KEYMENU) return 0; break; case WM_DESTROY: ::PostQuitMessage(0); return 0; } return ::DefWindowProcW(hWnd, msg, wParam, lParam); }