From 7be3c917ca9bc2d759f0374f6f9a50633ec12ff4 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Sep 2019 18:10:17 +0200 Subject: [PATCH 1/9] Initial version --- Image-Loading-and-Displaying-Examples.md | 152 +++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 Image-Loading-and-Displaying-Examples.md diff --git a/Image-Loading-and-Displaying-Examples.md b/Image-Loading-and-Displaying-Examples.md new file mode 100644 index 0000000..5e6efea --- /dev/null +++ b/Image-Loading-and-Displaying-Examples.md @@ -0,0 +1,152 @@ +### TL;DR; + +Loading an image file into a GPU texture is outside of the scope of Dear ImGui and has more to do with your Graphics API. Because this is such a recurring issue for Dear ImGui users, we are providing a guide here. + +We will load this image: (Right-click to save as MyImage01.jpg, 20,123 bytes) + +![MyPhoto01](https://raw.githubusercontent.com/wiki/ocornut/imgui/tutorials/MyImage01.jpg) + +This is generally done in two steps: + +- Load image from the disk into a decompressed RGBA stored in RAM. You may use helper librairies such as [stb_image.h](https://github.com/nothings/stb/blob/master/stb_image.h) to do this. +- Load the decompressed RGBA image storage in RAM into a GPU texture. You'll want to use dedicated functions of your graphics API (e.g. OpenGL, DirectX11) to do this. + +Once you have an image in GPU texture memory, you can use functions such as `ImGui::Image()` to request Dear ImGui to create a draw command that your Dear ImGui rendering back-end will turn into a draw call. + +### About filenames + +**Please note that many new C/C++ users have issues their files _because the filename they provide is wrong_.** + +Two things to watch for: +- Make sure your IDE/debugger settings starts your executable from the right working directory. In Visual Studio you can change your working directory in project `Properties > General > Debugging > Working Directory`. People assume that their execution will start from the root folder of the project, where by default it oftens start from the folder where object or executable files are stored. +- In C/C++ and most programming languages if you want to use a backslash `\` within a string literal, you need to write it double backslash `\\`. So if you try to use `"C:\MyFiles\MyImage01.jpg"` when performing a quick test this will be incorrect. Use `"C:\\MyFiles\\MyImage01.jpg"` instead. + + +### Example for OpenGL users + +We will here use [stb_image.h](https://github.com/nothings/stb/blob/master/stb_image.h) to load image from disk. Grab stb_image.h and add at the top of one of your source file: + +``` +// Use stb_image.h to load a PNG from disk and turn it into raw RGBA pixel data: +#define STB_IMAGE_IMPLEMENTATION +#include +``` +You may then include `` from multiple sources, but only `#define STB_IMAGE_IMPLEMENTATION` in one of them. + +Then, let's load a file from disk: + +``` +int my_image_width = 0; +int my_image_height = 0; +unsigned char* my_image_data = stbi_load("MyImage01.jpg", &my_image_width, &my_image_height, NULL, 4); +IM_ASSERT(my_image_data != NULL); +``` + +In the snippet of code above, we added an assert (`IM_ASSERT(my_image_data != NULL)`) to check if the image file was loaded correctly. You may also use your Debugger and confirm that `my_image_data` is not null, and that `my_image_width` `my_image_width` are correct. + +Now, we'll be upload our pixels into an OpenGL texture: + +``` +// Create a OpenGL texture identifier +GLuint my_image_texture; +glGenTextures(1, &my_image_texture); +glBindTexture(GL_TEXTURE_2D, my_image_texture); + +// Setup filtering parameters for display +glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + +// Setup CPU->GPU upload parameters +glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + +// Upload pixels into texture +glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, my_image_width, my_image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data); +``` + +Now that we have an OpenGL texture, assuming our imgui rendering function (imgui_impl_xxx.cpp file) takes GLuint as ImTextureID, we can display it. Add in your main loop: + +``` +ImGui::Begin("Test"); +ImGui::Text("my_image_texture = %p", my_image_texture); +ImGui::Text("my_image_size = %d x %d", my_image_width, my_image_height); +ImGui::Image((void*)(intptr_t)my_image_texture, ImVec2(my_image_width, my_image_height)); +ImGui::End(); +``` + +![image](https://user-images.githubusercontent.com/8225057/65341917-d3d35100-dbd1-11e9-9f13-6d99a6f1a891.png) + +### Example for DirectX9 users + +### Example for DirectX11 users + +### Technical Explanation + +From the FAQ: "How can I display an image? What is ImTextureID, how does it works?" + +Short explanation: +- You may use functions such as `ImGui::Image()`, `ImGui::ImageButton()` or lower-level `ImDrawList::AddImage()` to emit draw calls that will use your own textures. +- Actual textures are identified in a way that is up to the user/engine. Those identifiers are stored and passed as a `ImTextureID` value (which is no other than a `void*`). +- Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason). You can read documentations or tutorials on your graphics API to understand how to upload textures. Onward in this document you'll find examples. + +Long explanation: +- Dear ImGui's job is to create "meshes", defined in a renderer-agnostic format made of draw commands and vertices. At the end of the frame those meshes (ImDrawList) will be displayed by your rendering function. They are made up of textured polygons and the code to render them is generally fairly short (a few dozen lines). In the examples/ folder we provide functions for popular graphics API (OpenGL, DirectX, etc.). +- Each rendering function decides on a data type to represent "textures". The concept of what is a "texture" is entirely tied to your underlying engine/graphics API. We carry the information to identify a "texture" in the ImTextureID type. ImTextureID is nothing more that a void*, aka 4/8 bytes worth of data: just enough to store 1 pointer or 1 integer of your choice. Dear ImGui doesn't know or understand what you are storing in ImTextureID, it merely pass ImTextureID values until they reach your rendering function. +- In the examples/ bindings, for each graphics API binding we decided on a type that is likely to be a good representation for specifying an image from the end-user perspective. This is what the _examples_ rendering functions are using: +``` +OpenGL: ImTextureID = GLuint (see ImGui_ImplOpenGL3_RenderDrawData() function in imgui_impl_opengl3.cpp) +DirectX9: ImTextureID = LPDIRECT3DTEXTURE9 (see ImGui_ImplDX9_RenderDrawData() function in imgui_impl_dx9.cpp) +DirectX11: ImTextureID = ID3D11ShaderResourceView* (see ImGui_ImplDX11_RenderDrawData() function in imgui_impl_dx11.cpp) +DirectX12: ImTextureID = D3D12_GPU_DESCRIPTOR_HANDLE (see ImGui_ImplDX12_RenderDrawData() function in imgui_impl_dx12.cpp) +``` +For example, in the OpenGL example binding we store raw OpenGL texture identifier (GLuint) inside ImTextureID. Whereas in the DirectX11 example binding we store a pointer to ID3D11ShaderResourceView inside ImTextureID, which is a higher-level structure tying together both the texture and information about its format and how to read it. +- If you have a custom engine built over e.g. OpenGL, instead of passing GLuint around you may decide to use a high-level data type to carry information about the texture as well as how to display it (shaders, etc.). The decision of what to use as ImTextureID can always be made better knowing how your codebase is designed. If your engine has high-level data types for "textures" and "material" then you may want to use them. If you are starting with OpenGL or DirectX or Vulkan and haven't built much of a rendering engine over them, keeping the default ImTextureID representation suggested by the example bindings is probably the best choice. (Advanced users may also decide to keep a low-level type in ImTextureID, and use ImDrawList callback and pass information to their renderer) +User code may do: +``` +// Cast our texture type to ImTextureID / void* +MyTexture* texture = g_CoffeeTableTexture; +ImGui::Image((void*)texture, ImVec2(texture->Width, texture->Height)); +``` +The renderer function called after ImGui::Render() will receive that same value that the user code passed: +``` +// Cast ImTextureID / void* stored in the draw command as our texture type +MyTexture* texture = (MyTexture*)pcmd->TextureId; +MyEngineBindTexture2D(texture); +``` +Once you understand this design you will understand that loading image files and turning them into displayable textures is not within the scope of Dear ImGui. This is by design and is actually a good thing, because it means your code has full control over your data types and how you display them. If you want to display an image file (e.g. PNG file) into the screen, please refer to documentation and tutorials for the graphics API you are using. + + Here's a simplified OpenGL example using stb_image.h: + + // Use stb_image.h to load a PNG from disk and turn it into raw RGBA pixel data: + #define STB_IMAGE_IMPLEMENTATION + #include + [...] + int my_image_width, my_image_height; + unsigned char* my_image_data = stbi_load("my_image.png", &my_image_width, &my_image_height, NULL, 4); + + // Turn the RGBA pixel data into an OpenGL texture: + GLuint my_opengl_texture; + glGenTextures(1, &my_opengl_texture); + glBindTexture(GL_TEXTURE_2D, my_opengl_texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data); + + // Now that we have an OpenGL texture, assuming our imgui rendering function (imgui_impl_xxx.cpp file) takes GLuint as ImTextureID, we can display it: + ImGui::Image((void*)(intptr_t)my_opengl_texture, ImVec2(my_image_width, my_image_height)); + + C/C++ tip: a void* is pointer-sized storage. You may safely store any pointer or integer into it by casting your value to ImTextureID / void*, and vice-versa. + Because both end-points (user code and rendering function) are under your control, you know exactly what is stored inside the ImTextureID / void*. + Examples: + + GLuint my_tex = XXX; + void* my_void_ptr; + my_void_ptr = (void*)(intptr_t)my_tex; // cast a GLuint into a void* (we don't take its address! we literally store the value inside the pointer) + my_tex = (GLuint)(intptr_t)my_void_ptr; // cast a void* into a GLuint + + ID3D11ShaderResourceView* my_dx11_srv = XXX; + void* my_void_ptr; + my_void_ptr = (void*)my_dx11_srv; // cast a ID3D11ShaderResourceView* into an opaque void* + my_dx11_srv = (ID3D11ShaderResourceView*)my_void_ptr; // cast a void* into a ID3D11ShaderResourceView* + + Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated. From 981c193041084f359b74ff646a29daa0920059ce Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Sep 2019 18:28:33 +0200 Subject: [PATCH 2/9] DirectX9 example --- Image-Loading-and-Displaying-Examples.md | 44 +++++++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/Image-Loading-and-Displaying-Examples.md b/Image-Loading-and-Displaying-Examples.md index 5e6efea..52e936d 100644 --- a/Image-Loading-and-Displaying-Examples.md +++ b/Image-Loading-and-Displaying-Examples.md @@ -1,3 +1,5 @@ +Examples: [OpenGL](#Example-for-OpenGL-users) - [DirectX9](#Example-for-DirectX9-users) - [DirectX11](#Example-for-DirectX11-users) + ### TL;DR; Loading an image file into a GPU texture is outside of the scope of Dear ImGui and has more to do with your Graphics API. Because this is such a recurring issue for Dear ImGui users, we are providing a guide here. @@ -34,7 +36,6 @@ We will here use [stb_image.h](https://github.com/nothings/stb/blob/master/stb_i You may then include `` from multiple sources, but only `#define STB_IMAGE_IMPLEMENTATION` in one of them. Then, let's load a file from disk: - ``` int my_image_width = 0; int my_image_height = 0; @@ -63,20 +64,53 @@ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, my_image_width, my_image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data); ``` -Now that we have an OpenGL texture, assuming our imgui rendering function (imgui_impl_xxx.cpp file) takes GLuint as ImTextureID, we can display it. Add in your main loop: +Now that we have an OpenGL texture and its dimension, we can add in our main loop: ``` ImGui::Begin("Test"); -ImGui::Text("my_image_texture = %p", my_image_texture); -ImGui::Text("my_image_size = %d x %d", my_image_width, my_image_height); +ImGui::Text("pointer = %p", my_image_texture); +ImGui::Text("size = %d x %d", my_image_width, my_image_height); ImGui::Image((void*)(intptr_t)my_image_texture, ImVec2(my_image_width, my_image_height)); ImGui::End(); ``` -![image](https://user-images.githubusercontent.com/8225057/65341917-d3d35100-dbd1-11e9-9f13-6d99a6f1a891.png) +![image](https://user-images.githubusercontent.com/8225057/65342485-26f9d380-dbd3-11e9-967e-b279b1ad8551.png) ### Example for DirectX9 users +Unlike the majority of modern graphics API, DirectX9 include helper functions to load image files from disk. We are going to use them here, instead of using `stb_image.h`. + +Add at the top of one of your source file: +``` +#include +#pragma comment(lib, "D3dx9") +``` + +Then, let's load a file from disk directly into a DirectX9 texture: +``` +// Load texture +PDIRECT3DTEXTURE9 my_image_texture; +HRESULT hr = D3DXCreateTextureFromFileA(g_pd3dDevice, "../../MyImage01.jpg", &my_image_texture); +IM_ASSERT(hr == S_OK); + +// Retrieve description of the texture surface so we can access its size +D3DSURFACE_DESC my_image_desc; +my_image_texture->GetLevelDesc(0, &my_image_desc); +int my_image_width = my_image_desc.Width; +int my_image_height = my_image_desc.Height; +``` + +Now that we have an DirectX9 texture and its dimensions, we can add in our main loop: +``` +ImGui::Begin("Test"); +ImGui::Text("pointer = %p", my_image_texture); +ImGui::Text("size = %d x %d", my_image_width, my_image_height); +ImGui::Image((void*)my_image_texture, ImVec2(my_image_width, my_image_height)); +ImGui::End(); +``` + +![image](https://user-images.githubusercontent.com/8225057/65342425-0467ba80-dbd3-11e9-833f-3feb5084e1da.png) + ### Example for DirectX11 users ### Technical Explanation From 3a31214e720965950f433cf6ca3e902d3aeec0ac Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Sep 2019 18:29:17 +0200 Subject: [PATCH 3/9] Cleanup --- Image-Loading-and-Displaying-Examples.md | 37 +----------------------- 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/Image-Loading-and-Displaying-Examples.md b/Image-Loading-and-Displaying-Examples.md index 52e936d..b3e3c5d 100644 --- a/Image-Loading-and-Displaying-Examples.md +++ b/Image-Loading-and-Displaying-Examples.md @@ -148,39 +148,4 @@ MyEngineBindTexture2D(texture); ``` Once you understand this design you will understand that loading image files and turning them into displayable textures is not within the scope of Dear ImGui. This is by design and is actually a good thing, because it means your code has full control over your data types and how you display them. If you want to display an image file (e.g. PNG file) into the screen, please refer to documentation and tutorials for the graphics API you are using. - Here's a simplified OpenGL example using stb_image.h: - - // Use stb_image.h to load a PNG from disk and turn it into raw RGBA pixel data: - #define STB_IMAGE_IMPLEMENTATION - #include - [...] - int my_image_width, my_image_height; - unsigned char* my_image_data = stbi_load("my_image.png", &my_image_width, &my_image_height, NULL, 4); - - // Turn the RGBA pixel data into an OpenGL texture: - GLuint my_opengl_texture; - glGenTextures(1, &my_opengl_texture); - glBindTexture(GL_TEXTURE_2D, my_opengl_texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data); - - // Now that we have an OpenGL texture, assuming our imgui rendering function (imgui_impl_xxx.cpp file) takes GLuint as ImTextureID, we can display it: - ImGui::Image((void*)(intptr_t)my_opengl_texture, ImVec2(my_image_width, my_image_height)); - - C/C++ tip: a void* is pointer-sized storage. You may safely store any pointer or integer into it by casting your value to ImTextureID / void*, and vice-versa. - Because both end-points (user code and rendering function) are under your control, you know exactly what is stored inside the ImTextureID / void*. - Examples: - - GLuint my_tex = XXX; - void* my_void_ptr; - my_void_ptr = (void*)(intptr_t)my_tex; // cast a GLuint into a void* (we don't take its address! we literally store the value inside the pointer) - my_tex = (GLuint)(intptr_t)my_void_ptr; // cast a void* into a GLuint - - ID3D11ShaderResourceView* my_dx11_srv = XXX; - void* my_void_ptr; - my_void_ptr = (void*)my_dx11_srv; // cast a ID3D11ShaderResourceView* into an opaque void* - my_dx11_srv = (ID3D11ShaderResourceView*)my_void_ptr; // cast a void* into a ID3D11ShaderResourceView* - - Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated. +Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated. \ No newline at end of file From d52d680800b64e0c427283a5dd1a44c1e583535d Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Sep 2019 18:29:52 +0200 Subject: [PATCH 4/9] Image-Loading-and-Displaying-Examples --- Home.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Home.md b/Home.md index 10a45cc..8661893 100644 --- a/Home.md +++ b/Home.md @@ -17,6 +17,7 @@ Feel free to edit and contribute! - [[Sponsors|Sponsors]] - [[Tips|Tips]] (for people working _with_ dear imgui) - [[Developer tips|Developer-Tips]] (for people working _on_ dear imgui) +- [[Image Loading and Displaying Examples|Image-Loading-and-Displaying-Examples]] - [[Loading Font Example|Loading-Font-Example]] (w/ Japanese font) ## Issues: Some Important Topics From 340fc137fb7233854c02b25f3d47640a54105726 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Sep 2019 18:39:31 +0200 Subject: [PATCH 5/9] DirectX11 example --- Image-Loading-and-Displaying-Examples.md | 83 +++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/Image-Loading-and-Displaying-Examples.md b/Image-Loading-and-Displaying-Examples.md index b3e3c5d..677bbe6 100644 --- a/Image-Loading-and-Displaying-Examples.md +++ b/Image-Loading-and-Displaying-Examples.md @@ -23,6 +23,7 @@ Two things to watch for: - Make sure your IDE/debugger settings starts your executable from the right working directory. In Visual Studio you can change your working directory in project `Properties > General > Debugging > Working Directory`. People assume that their execution will start from the root folder of the project, where by default it oftens start from the folder where object or executable files are stored. - In C/C++ and most programming languages if you want to use a backslash `\` within a string literal, you need to write it double backslash `\\`. So if you try to use `"C:\MyFiles\MyImage01.jpg"` when performing a quick test this will be incorrect. Use `"C:\\MyFiles\\MyImage01.jpg"` instead. +---- ### Example for OpenGL users @@ -76,6 +77,8 @@ ImGui::End(); ![image](https://user-images.githubusercontent.com/8225057/65342485-26f9d380-dbd3-11e9-967e-b279b1ad8551.png) +---- + ### Example for DirectX9 users Unlike the majority of modern graphics API, DirectX9 include helper functions to load image files from disk. We are going to use them here, instead of using `stb_image.h`. @@ -100,7 +103,7 @@ int my_image_width = my_image_desc.Width; int my_image_height = my_image_desc.Height; ``` -Now that we have an DirectX9 texture and its dimensions, we can add in our main loop: +Now that we have an DirectX9 texture and its dimensions, we can display it in our main loop: ``` ImGui::Begin("Test"); ImGui::Text("pointer = %p", my_image_texture); @@ -111,8 +114,86 @@ ImGui::End(); ![image](https://user-images.githubusercontent.com/8225057/65342425-0467ba80-dbd3-11e9-833f-3feb5084e1da.png) +---- + ### Example for DirectX11 users +``` +#define STB_IMAGE_IMPLEMENTATION +#include +``` +``` +// Simple helper function to load an image into a DX11 texture with common settings +bool LoadTextureFromFile(const char* filename, ID3D11ShaderResourceView** out_srv, int* out_width, int* out_height) +{ + // Load from disk into a raw RGBA buffer + int image_width = 0; + int image_height = 0; + unsigned char* image_data = stbi_load(filename, &image_width, &image_height, NULL, 4); + if (image_data == NULL) + { + IM_ASSERT(image_data != NULL); + return false; + } + + // Create texture + 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); + + // Create texture view + 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(); + + *out_width = image_width; + *out_height = image_height; + return true; +} +``` + +At initialization time, load our texture: +``` +int my_image_width = 0; +int my_image_height = 0; +ID3D11ShaderResourceView* my_texture = NULL; +bool ret = LoadTextureFromFile("../../MyImage01.jpg", &my_texture, &my_image_width, &my_image_height); +IM_ASSERT(ret); +``` + +Now that we have an DirectX9 texture and its dimensions, we can display it in our main loop: +``` +ImGui::Begin("DirectX11 Texture Test"); +ImGui::Text("pointer = %p", my_texture); +ImGui::Text("size = %d x %d", my_image_width, my_image_height); +ImGui::Image((void*)my_texture, ImVec2(my_image_width, my_image_height)); +ImGui::End(); +``` + +![image](https://user-images.githubusercontent.com/8225057/65343598-a38db180-dbd5-11e9-8776-80dfa4a7f3c6.png) + +---- + ### Technical Explanation From the FAQ: "How can I display an image? What is ImTextureID, how does it works?" From 5ed8e5763cba5bddf7d1ef17203f5ef654f6940c Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Sep 2019 18:45:33 +0200 Subject: [PATCH 6/9] Tweaks --- Image-Loading-and-Displaying-Examples.md | 48 ++++++++++++++---------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/Image-Loading-and-Displaying-Examples.md b/Image-Loading-and-Displaying-Examples.md index 677bbe6..3933f32 100644 --- a/Image-Loading-and-Displaying-Examples.md +++ b/Image-Loading-and-Displaying-Examples.md @@ -87,28 +87,41 @@ Add at the top of one of your source file: ``` #include #pragma comment(lib, "D3dx9") + +// Simple helper function to load an image into a DX9 texture with common settings +bool LoadTextureFromFile(const char* filename, PDIRECT3DTEXTURE9* out_texture, int* out_width, int* out_height) +{ + // Load texture from disk + PDIRECT3DTEXTURE9 texture; + HRESULT hr = D3DXCreateTextureFromFileA(g_pd3dDevice, filename, &texture); + if (hr != S_OK) + return false; + + // Retrieve description of the texture surface so we can access its size + D3DSURFACE_DESC my_image_desc; + texture->GetLevelDesc(0, &my_image_desc); + *out_texture = texture; + *out_width = (int)my_image_desc.Width; + *out_height = (int)my_image_desc.Height; + return true; +} ``` -Then, let's load a file from disk directly into a DirectX9 texture: +At initialization time, load our texture: ``` -// Load texture -PDIRECT3DTEXTURE9 my_image_texture; -HRESULT hr = D3DXCreateTextureFromFileA(g_pd3dDevice, "../../MyImage01.jpg", &my_image_texture); -IM_ASSERT(hr == S_OK); - -// Retrieve description of the texture surface so we can access its size -D3DSURFACE_DESC my_image_desc; -my_image_texture->GetLevelDesc(0, &my_image_desc); -int my_image_width = my_image_desc.Width; -int my_image_height = my_image_desc.Height; +int my_image_width = 0; +int my_image_height = 0; +PDIRECT3DTEXTURE9 my_texture = NULL; +bool ret = LoadTextureFromFile("../../MyImage01.jpg", &my_texture, &my_image_width, &my_image_height); +IM_ASSERT(ret); ``` Now that we have an DirectX9 texture and its dimensions, we can display it in our main loop: ``` -ImGui::Begin("Test"); -ImGui::Text("pointer = %p", my_image_texture); +ImGui::Begin("DirectX9 Texture Test"); +ImGui::Text("pointer = %p", my_texture); ImGui::Text("size = %d x %d", my_image_width, my_image_height); -ImGui::Image((void*)my_image_texture, ImVec2(my_image_width, my_image_height)); +ImGui::Image((void*)my_texture, ImVec2(my_image_width, my_image_height)); ImGui::End(); ``` @@ -118,11 +131,11 @@ ImGui::End(); ### Example for DirectX11 users +Add at the top of one of your source file: ``` #define STB_IMAGE_IMPLEMENTATION #include -``` -``` + // Simple helper function to load an image into a DX11 texture with common settings bool LoadTextureFromFile(const char* filename, ID3D11ShaderResourceView** out_srv, int* out_width, int* out_height) { @@ -131,10 +144,7 @@ bool LoadTextureFromFile(const char* filename, ID3D11ShaderResourceView** out_sr int image_height = 0; unsigned char* image_data = stbi_load(filename, &image_width, &image_height, NULL, 4); if (image_data == NULL) - { - IM_ASSERT(image_data != NULL); return false; - } // Create texture D3D11_TEXTURE2D_DESC desc; From 275708f90b124a93bf9bf4c12c01a3823996002d Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 20 Sep 2019 18:53:20 +0200 Subject: [PATCH 7/9] Tweaks --- Image-Loading-and-Displaying-Examples.md | 77 ++++++++++++++---------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/Image-Loading-and-Displaying-Examples.md b/Image-Loading-and-Displaying-Examples.md index 3933f32..61490cc 100644 --- a/Image-Loading-and-Displaying-Examples.md +++ b/Image-Loading-and-Displaying-Examples.md @@ -27,55 +27,66 @@ Two things to watch for: ### Example for OpenGL users -We will here use [stb_image.h](https://github.com/nothings/stb/blob/master/stb_image.h) to load image from disk. Grab stb_image.h and add at the top of one of your source file: +We will here use [stb_image.h](https://github.com/nothings/stb/blob/master/stb_image.h) to load images from disk. +Add at the top of one of your source file: ``` -// Use stb_image.h to load a PNG from disk and turn it into raw RGBA pixel data: #define STB_IMAGE_IMPLEMENTATION #include -``` -You may then include `` from multiple sources, but only `#define STB_IMAGE_IMPLEMENTATION` in one of them. -Then, let's load a file from disk: +// Simple helper function to load an image into a OpenGL texture with common settings +bool LoadTextureFromFile(const char* filename, GLuint* out_texture, int* out_width, int* out_height) +{ + // Load from file + int image_width = 0; + int image_height = 0; + unsigned char* image_data = stbi_load(filename, &image_width, &image_height, NULL, 4); + if (image_data == NULL) + return false; + + // Create a OpenGL texture identifier + GLuint image_texture; + glGenTextures(1, &image_texture); + glBindTexture(GL_TEXTURE_2D, image_texture); + + // Setup filtering parameters for display + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + // Upload pixels into texture + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data); + stbi_image_free(image_data); + + *out_texture = image_texture; + *out_width = image_width; + *out_height = image_height; + + return true; +} +``` + +At initialization time, load our texture: ``` int my_image_width = 0; int my_image_height = 0; -unsigned char* my_image_data = stbi_load("MyImage01.jpg", &my_image_width, &my_image_height, NULL, 4); -IM_ASSERT(my_image_data != NULL); +GLuint my_image_texture = 0; +bool ret = LoadTextureFromFile("../../MyImage01.jpg", &my_image_texture, &my_image_width, &my_image_height); +IM_ASSERT(ret); ``` -In the snippet of code above, we added an assert (`IM_ASSERT(my_image_data != NULL)`) to check if the image file was loaded correctly. You may also use your Debugger and confirm that `my_image_data` is not null, and that `my_image_width` `my_image_width` are correct. - -Now, we'll be upload our pixels into an OpenGL texture: +In the snippet of code above, we added an assert (`IM_ASSERT(ret)`) to check if the image file was loaded correctly. You may also use your Debugger and confirm that `my_image_texture` is not zeroand that `my_image_width` `my_image_width` are correct. +Now that we have an DirectX9 texture and its dimensions, we can display it in our main loop: ``` -// Create a OpenGL texture identifier -GLuint my_image_texture; -glGenTextures(1, &my_image_texture); -glBindTexture(GL_TEXTURE_2D, my_image_texture); - -// Setup filtering parameters for display -glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - -// Setup CPU->GPU upload parameters -glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - -// Upload pixels into texture -glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, my_image_width, my_image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data); -``` - -Now that we have an OpenGL texture and its dimension, we can add in our main loop: - -``` -ImGui::Begin("Test"); +ImGui::Begin("OpenGL Texture Text"); ImGui::Text("pointer = %p", my_image_texture); ImGui::Text("size = %d x %d", my_image_width, my_image_height); ImGui::Image((void*)(intptr_t)my_image_texture, ImVec2(my_image_width, my_image_height)); ImGui::End(); ``` -![image](https://user-images.githubusercontent.com/8225057/65342485-26f9d380-dbd3-11e9-967e-b279b1ad8551.png) +![image](https://user-images.githubusercontent.com/8225057/65344387-dfc21180-dbd7-11e9-9478-627403721435.png) ---- @@ -125,7 +136,7 @@ ImGui::Image((void*)my_texture, ImVec2(my_image_width, my_image_height)); ImGui::End(); ``` -![image](https://user-images.githubusercontent.com/8225057/65342425-0467ba80-dbd3-11e9-833f-3feb5084e1da.png) +![image](https://user-images.githubusercontent.com/8225057/65344041-dedcb000-dbd6-11e9-8a52-120673e8e85f.png) ---- @@ -178,6 +189,8 @@ bool LoadTextureFromFile(const char* filename, ID3D11ShaderResourceView** out_sr *out_width = image_width; *out_height = image_height; + stbi_image_free(image_data); + return true; } ``` From 6c44a263a503b0af9da3786f9ed30db6ee7835b3 Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 21 Sep 2019 13:55:13 +0200 Subject: [PATCH 8/9] imGuiZMO.quat --- Home.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Home.md b/Home.md index 8661893..7fe01f5 100644 --- a/Home.md +++ b/Home.md @@ -83,6 +83,7 @@ Feel free to edit and contribute! - Memory Editor: [https://github.com/ocornut/imgui_club/imgui_club/imgui_memory_editor/](https://github.com/ocornut/imgui_club/tree/master/imgui_memory_editor) - Markdown: https://github.com/juliettef/imgui_markdown - ImGuizmo (3d translation/rotation Gizmo) https://github.com/CedricGuillemet/ImGuizmo +- imGuiZMO.quat (3d translation/rotation Gizmo) https://github.com/BrutPitt/imGuIZMO.quat - Splitters: https://github.com/ocornut/imgui/issues/319 - Spinner + Loading Bar progress indicators: https://github.com/ocornut/imgui/issues/1901 - ImHotKey (Hotkey Editor): https://github.com/CedricGuillemet/ImHotKey From 2d369880180b664ee82aa56da12962c11f75abbd Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 21 Sep 2019 14:14:04 +0200 Subject: [PATCH 9/9] Tweaks --- Image-Loading-and-Displaying-Examples.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Image-Loading-and-Displaying-Examples.md b/Image-Loading-and-Displaying-Examples.md index 61490cc..266157c 100644 --- a/Image-Loading-and-Displaying-Examples.md +++ b/Image-Loading-and-Displaying-Examples.md @@ -11,7 +11,7 @@ We will load this image: (Right-click to save as MyImage01.jpg, 20,123 bytes) This is generally done in two steps: - Load image from the disk into a decompressed RGBA stored in RAM. You may use helper librairies such as [stb_image.h](https://github.com/nothings/stb/blob/master/stb_image.h) to do this. -- Load the decompressed RGBA image storage in RAM into a GPU texture. You'll want to use dedicated functions of your graphics API (e.g. OpenGL, DirectX11) to do this. +- Load the raw decompressed RGBA image in RAM into a GPU texture. You'll want to use dedicated functions of your graphics API (e.g. OpenGL, DirectX11) to do this. Once you have an image in GPU texture memory, you can use functions such as `ImGui::Image()` to request Dear ImGui to create a draw command that your Dear ImGui rendering back-end will turn into a draw call. @@ -21,7 +21,7 @@ Once you have an image in GPU texture memory, you can use functions such as `ImG Two things to watch for: - Make sure your IDE/debugger settings starts your executable from the right working directory. In Visual Studio you can change your working directory in project `Properties > General > Debugging > Working Directory`. People assume that their execution will start from the root folder of the project, where by default it oftens start from the folder where object or executable files are stored. -- In C/C++ and most programming languages if you want to use a backslash `\` within a string literal, you need to write it double backslash `\\`. So if you try to use `"C:\MyFiles\MyImage01.jpg"` when performing a quick test this will be incorrect. Use `"C:\\MyFiles\\MyImage01.jpg"` instead. +- In C/C++ and most programming languages if you want to use a backslash `\` within a string literal, you need to write it double backslash `\\`. So if you try to use `"C:\MyFiles\MyImage01.jpg"` when performing a quick test this will be incorrect. Use `"C:\\MyFiles\\MyImage01.jpg"` instead. In some situations, you may also use `/` path separator under Windows. ---- @@ -75,7 +75,7 @@ bool ret = LoadTextureFromFile("../../MyImage01.jpg", &my_image_texture, &my_ima IM_ASSERT(ret); ``` -In the snippet of code above, we added an assert (`IM_ASSERT(ret)`) to check if the image file was loaded correctly. You may also use your Debugger and confirm that `my_image_texture` is not zeroand that `my_image_width` `my_image_width` are correct. +In the snippet of code above, we added an assert `IM_ASSERT(ret)` to check if the image file was loaded correctly. You may also use your Debugger and confirm that `my_image_texture` is not zero and that `my_image_width` `my_image_width` are correct. Now that we have an DirectX9 texture and its dimensions, we can display it in our main loop: ``` @@ -252,4 +252,4 @@ MyEngineBindTexture2D(texture); ``` Once you understand this design you will understand that loading image files and turning them into displayable textures is not within the scope of Dear ImGui. This is by design and is actually a good thing, because it means your code has full control over your data types and how you display them. If you want to display an image file (e.g. PNG file) into the screen, please refer to documentation and tutorials for the graphics API you are using. -Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated. \ No newline at end of file +Finally, you may call `ImGui::ShowMetricsWindow()` to explore/visualize/understand how the ImDrawList are generated. \ No newline at end of file