Compare commits
238 Commits
Author | SHA1 | Date | |
---|---|---|---|
bd762b559c | |||
e6b9950645 | |||
b4fd216bd2 | |||
0730ec7577 | |||
0e6f288a2f | |||
7f804d3d64 | |||
de44af5227 | |||
0f29cd7a14 | |||
a5a84a9b69 | |||
197b2763fc | |||
df00fa8113 | |||
e835ef1d90 | |||
ae75553ba1 | |||
2e576de9ca | |||
9e16317382 | |||
b5acb16378 | |||
38164a410d | |||
214c967df8 | |||
31654958f9 | |||
a31e44b99a | |||
54ea495207 | |||
eb789c0288 | |||
e9aead09cb | |||
e4a79e9fc8 | |||
e27eddfbd2 | |||
311a2f8328 | |||
df2ad5e899 | |||
07a6ba8aaf | |||
16d6561aba | |||
abe45e9976 | |||
c0999495e7 | |||
b9118750ae | |||
7f6453ca70 | |||
24a9d32531 | |||
ec4b510775 | |||
1484799b18 | |||
895f93f694 | |||
49defcf083 | |||
e78c47961e | |||
8c4fcf1359 | |||
2322318cac | |||
5f8175abaa | |||
ab4f5e6862 | |||
075fe0220e | |||
cf037b4769 | |||
97192606a6 | |||
e90984f638 | |||
366516c154 | |||
a6e0d182b0 | |||
3572b04c69 | |||
fd8752df8d | |||
f1dcd72e9f | |||
2aee4419e3 | |||
9f2545e6bb | |||
f3bd033b6d | |||
b15532345b | |||
15436b46e8 | |||
b01adf16de | |||
428c4d4ece | |||
172ff0a262 | |||
c6f3d0924e | |||
ac40284536 | |||
191e17eaf8 | |||
616668dac3 | |||
36e52167da | |||
3f85fe2fe7 | |||
447cc88e04 | |||
9c707b6d8f | |||
9b5493d1d9 | |||
8a65d97bf0 | |||
be93b842c1 | |||
7961c53145 | |||
d3bc92a674 | |||
4205241e86 | |||
c97636aef4 | |||
ee3355fe8e | |||
1e30400f80 | |||
3a64c77826 | |||
e19f0d370a | |||
6c192f3221 | |||
78645a7dba | |||
74363c5a43 | |||
0b10cf4bd7 | |||
3d84858755 | |||
fad5e45d2c | |||
05a3a9b962 | |||
85eee4a4c5 | |||
4c4798546e | |||
f768579377 | |||
e6eafd6fa8 | |||
1037bacc4b | |||
89a412690c | |||
af37fb1ee7 | |||
9f05a2bb16 | |||
48a944813c | |||
1d9a4748de | |||
36212b9ad9 | |||
bebadb9012 | |||
530e746daa | |||
ce481ec702 | |||
f1ea630dd0 | |||
ffc8264e9d | |||
ec625b7c49 | |||
f86286548e | |||
7751ce0a69 | |||
9bb95db68a | |||
0a8acf241c | |||
c388c7e6eb | |||
088df3d1ba | |||
09fae1c209 | |||
016dbb7472 | |||
6ec65c46aa | |||
0fa3d6e25f | |||
f898e658bb | |||
22fe7f23b1 | |||
b756510f21 | |||
b6ac371496 | |||
81b9480413 | |||
b9d9f62ae3 | |||
4b94454fb4 | |||
b86505bf2f | |||
df1c056c88 | |||
eb1b9d4521 | |||
d35ceb793e | |||
a61b92f362 | |||
51bbe1d961 | |||
e4d4dae3bf | |||
bd3c53754d | |||
a1162ac001 | |||
618a42acf8 | |||
3cd1b8a37b | |||
746951691a | |||
8eafb373f7 | |||
fec4232c79 | |||
85672fec2e | |||
d5ed586d70 | |||
d58a029285 | |||
6e039c8b7d | |||
05a42ba3a6 | |||
da2ccf0a78 | |||
3e647d86aa | |||
0e0cd5e705 | |||
8d32fcb7d4 | |||
4ea2af7ea5 | |||
3773fb4117 | |||
24028911e3 | |||
3fd68c3a31 | |||
1cf4b313e2 | |||
2e85dce1ee | |||
62d233aaab | |||
3cdb4fa456 | |||
7439df0ba1 | |||
ad42787543 | |||
91059da1a5 | |||
b420a51541 | |||
c07ab1b56a | |||
22a9555a99 | |||
25080d53e5 | |||
43448d9c89 | |||
e20077fbd0 | |||
2c677c45c7 | |||
3b339efeb2 | |||
8fc50f5ed3 | |||
dd5d251273 | |||
2fb63b6068 | |||
cd3d027df0 | |||
7adad71042 | |||
88c33ecc29 | |||
1f63e01cc6 | |||
bd26de0628 | |||
5a9639b423 | |||
b90d0c558d | |||
51f8e33eb4 | |||
80dd1e1065 | |||
5f6b261c9b | |||
681ac5f777 | |||
0d344e1f03 | |||
d2b43f31e3 | |||
d17a586738 | |||
710b9b68b1 | |||
29ba288ea0 | |||
addfa75eb0 | |||
882072cf30 | |||
7bd507d266 | |||
1ff104641a | |||
3b8d1ec207 | |||
e9e1fd2b3c | |||
6062d18cf9 | |||
05f0993616 | |||
6dd2b13220 | |||
5864c45fe3 | |||
4bc3642bdb | |||
a3f32381c4 | |||
67f17a644c | |||
e807d97089 | |||
23d156908d | |||
42d4b4be6a | |||
efc473df98 | |||
bbda899801 | |||
a17885f470 | |||
7de89e0da3 | |||
7c61822d26 | |||
ca027e1754 | |||
c5dacee3a7 | |||
d6f6afabb3 | |||
76a39ad224 | |||
aa7fc37b37 | |||
c13c2449bb | |||
c2cb727ac9 | |||
47fd8431c1 | |||
926f7bfcc5 | |||
f6414f2011 | |||
931a4c5b49 | |||
c32221fa20 | |||
a165954a69 | |||
ddf8b280e9 | |||
969b1e0563 | |||
6e15b71663 | |||
ef628a0a9d | |||
df5a06f119 | |||
e9b697698a | |||
5240013c90 | |||
1956703c42 | |||
f5dbb0a973 | |||
ade21a1ad5 | |||
868ba05a13 | |||
152878571e | |||
fa0aa5ace6 | |||
6267905a17 | |||
1509b8f634 | |||
2bc6346b48 | |||
9169b2911c | |||
a4b96445e8 | |||
6c11d7623e | |||
6d6ee4e1f1 | |||
f33eb89018 | |||
e9b0a61f48 | |||
e3001fb986 |
6
.gitignore
vendored
@ -1,7 +1,13 @@
|
||||
## Visual Studio files
|
||||
examples/Debug/*
|
||||
examples/Release/*
|
||||
examples/ipch/*
|
||||
examples/directx9_example/Debug/*
|
||||
examples/directx9_example/Release/*
|
||||
examples/directx9_example/ipch/*
|
||||
examples/directx11_example/Debug/*
|
||||
examples/directx11_example/Release/*
|
||||
examples/directx11_example/ipch/*
|
||||
examples/opengl_example/Debug/*
|
||||
examples/opengl_example/Release/*
|
||||
examples/opengl_example/ipch/*
|
||||
|
65
README.md
@ -1,9 +1,9 @@
|
||||
ImGui
|
||||
=====
|
||||
|
||||
ImGui is a bloat-free graphical user interface library for C++. It outputs vertex buffers that you can render in your 3D-pipeline enabled application. It is portable, renderer agnostic and carries minimal amount of dependencies (only 3 files are needed). It is based on an "immediate" graphical user interface paradigm which allows you to build simple user interfaces with ease.
|
||||
ImGui is a bloat-free graphical user interface library for C++. It outputs vertex buffers that you can render in your 3D-pipeline enabled application. It is portable, renderer agnostic and carries minimal amount of dependencies (only 3 files are needed). It is based on an "immediate" graphical user interface paradigm which allows you to build user interfaces with ease.
|
||||
|
||||
ImGui is designed to enable fast iteration and allow programmers to create "content creation" or "debug" tools (as opposed to tools for the average end-user). It favors simplicity and thus lacks certain features normally found in more high-level libraries, such as string localisation.
|
||||
ImGui is designed to enable fast iteration and allow programmers to create "content creation" or "debug" tools (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal, and thus lacks certain features normally found in more high-level libraries.
|
||||
|
||||
ImGui is particularly suited to integration in 3D applications, fullscreen applications, embedded applications, games, or any applications on consoles platforms where operating system features are non-standard.
|
||||
|
||||
@ -13,6 +13,8 @@ After ImGui is setup in your engine, you can use it like in this example:
|
||||
|
||||
ImGui outputs vertex buffers and simple command-lists that you can render in your application. Because it doesn't know or touch graphics state directly, you can call ImGui commands anywhere in your code (e.g. in the middle of a running algorithm, or in the middle of your own rendering process). Refer to the sample applications in the examples/ folder for instructions on how to integrate ImGui with your existing codebase.
|
||||
|
||||
ImGui allows you create elaborate tools as well as very short-lived ones. On the extreme side of short-liveness: using the Edit&Continue feature of compilers you can add a few widgets to tweaks variables while your application is running, and remove the code a minute later! ImGui is not just for tweaking values. You can use it to trace a running algorithm by just emitting text commands. You can use it along with your own reflection data to browse your dataset live. You can use it to expose the internals of a subsystem in your engine, to create a logger, an inspection tool, a profiler, a debugger, etc.
|
||||
|
||||
Gallery
|
||||
-------
|
||||
|
||||
@ -21,6 +23,10 @@ Gallery
|
||||

|
||||

|
||||
|
||||
UTF-8 is supported for text display and input. Here using M+ font to display Japanese:
|
||||
|
||||

|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
@ -30,15 +36,66 @@ The Immediate Mode GUI paradigm may at first appear unusual to some users. This
|
||||
- [Jari Komppa's tutorial on building an ImGui library](http://iki.fi/sol/imgui/).
|
||||
- [Casey Muratori's original video that popularized the concept](https://mollyrocket.com/861).
|
||||
|
||||
Frequently Asked Question
|
||||
-------------------------
|
||||
|
||||
<b>How do you use ImGui on a platform that may not have a mouse or keyboard?</b>
|
||||
|
||||
I recommend using [Synergy](http://synergy-project.org). With the uSynergy.c micro client running you can seamlessly use your PC input devices from a video game console or a tablet. ImGui was also designed to function with touch inputs if you increase the padding of widgets to compensate for the lack of precision of touch devices, but it is recommended you use a mouse to allow optimising for screen real-estate.
|
||||
|
||||
<b>I integrated ImGui in my engine and the text or lines are blurry..</b>
|
||||
|
||||
- Try adjusting ImGui::GetIO().PixelCenterOffset to 0.0f or 0.5f.
|
||||
- In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f).
|
||||
|
||||
<b>Can you create elaborate/serious tools with ImGui?</b>
|
||||
|
||||
Yes. I have written data browsers, debuggers, profilers and all sort of non-trivial tools with the library. There's no reason you cannot, and in my experience the simplicity of the API is very empowering. However note that ImGui is programmer centric and the immediate-mode GUI paradigm might requires a bit of adaptation before you can realize its full potential.
|
||||
|
||||
<b>Is ImGui fast?</b>
|
||||
|
||||
Down the fundation of its visual design, ImGui is engineered to be fairly performant both in term of CPU and GPU usage. Running elaborate code and creating elaborate UI will of course have a cost but ImGui aims to minimize it.
|
||||
|
||||
Mileage may vary but the following screenshot should give you an idea of the cost of running and rendering UI code (In the case of a trivial demo application like this one, your driver/os setup may be a bottleneck and cause higher variation or throttled framerate. Testing performance as part of a real application is recommended).
|
||||
|
||||

|
||||
|
||||
This is showing framerate on my 2011 iMac running Windows 7, OpenGL, AMD Radeon HD 6700M. ([click here for the full-size picture](/web/performance_01.png)).
|
||||
In contrast, librairies featuring higher-quality rendering and layouting techniques may have a higher resources footprint.
|
||||
|
||||
<b>Can you reskin the look of ImGui?</b>
|
||||
|
||||
Yes, you can alter the look of the interface to some degree: changing colors, sizes and padding, font. However, as ImGui is designed and optimised to create debug tools, the amount of skinning you can apply is limited. There is only so much you can stray away from the default look and feel of the interface. The example below uses modified settings to create a very compact UI with different colors:
|
||||
|
||||

|
||||
|
||||
<b>Why using C++ (as opposed to C)?</b>
|
||||
|
||||
ImGui takes advantage of a few C++ features for convenience but nothing in the realm of Boost-insanity/quagmire. In particular, function overloading and default parameters are used to make the API easier to use and code more terse. Doing so I believe the API is sitting on a sweet spot and giving up on those features would make the API more cumbersome. Other features such as namespace, constructors and templates (in the case of the ImVector<> class) are also relied on as a convenience but could be removed.
|
||||
|
||||
Shall someone wants to use ImGui from another language, it should be possible to wrap ImGui to be used from a raw C API in the future.
|
||||
|
||||
Support
|
||||
-------
|
||||
|
||||
<b>Can you develop features xxxx for ImGui?</b>
|
||||
|
||||
Please use GitHub 'Issues' facilities to suggest and discuss improvements. Your questions are often helpul to the community of users. If you represent an organization and would like specific non-trivial features to be implemented, I am available for hire to work on or with ImGui.
|
||||
|
||||
<b>Can I donate to support the development of ImGui?</b>
|
||||
|
||||
If you have the mean to help, I have setup a [**Patreon page**](http://www.patreon.com/imgui) to enable me to spend more time on the development of the library. One-off donations are also greatly appreciated. Thanks!
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
||||
Developed by [Omar Cornut](http://www.miracleworld.net). The library was developed with the support of [Media Molecule](http://www.mediamolecule.com) and first used internally on the game [Tearaway](http://tearaway.mediamolecule.com).
|
||||
|
||||
Embeds [proggy_clean](http://www.proggyfonts.net/) font by Tristan Grimmer (also MIT license).
|
||||
Embeds [proggy_clean](http://upperbounds.net) font by Tristan Grimmer (MIT license).
|
||||
Embeds [M+ fonts](http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/index-en.html) font by Coji Morishita (free software license).
|
||||
Embeds [stb_textedit.h](https://github.com/nothings/stb/) by Sean Barrett.
|
||||
|
||||
Inspiration, feedback, and testing: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Matt Willis. Thanks!
|
||||
Inspiration, feedback, and testing: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Anton Mikhailov, Matt Willis. Thanks!
|
||||
|
||||
License
|
||||
-------
|
||||
|
84
examples/directx11_example/directx11_example.vcxproj
Normal file
@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{9F316E83-5AE5-4939-A723-305A94F48005}</ProjectGuid>
|
||||
<RootNamespace>directx11_example</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>$(DXSDK_DIR)/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>d3d11.lib;d3dcompiler.lib;dxgi.lib;imm32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(DXSDK_DIR)/Lib/x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>$(DXSDK_DIR)/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>d3d11.lib;d3dcompiler.lib;dxgi.lib;imm32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(DXSDK_DIR)/Lib/x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\imconfig.h" />
|
||||
<ClInclude Include="..\..\imgui.h" />
|
||||
<ClInclude Include="..\..\stb_textedit.h" />
|
||||
<ClInclude Include="..\shared\stb_image.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\imgui.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\LICENSE" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
38
examples/directx11_example/directx11_example.vcxproj.filters
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="imgui">
|
||||
<UniqueIdentifier>{0587d7a3-f2ce-4d56-b84f-a0005d3bfce6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="sources">
|
||||
<UniqueIdentifier>{08e36723-ce4f-4cff-9662-c40801cf1acf}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\imconfig.h">
|
||||
<Filter>imgui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\imgui.h">
|
||||
<Filter>imgui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\stb_textedit.h">
|
||||
<Filter>imgui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\shared\stb_image.h">
|
||||
<Filter>sources</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\imgui.cpp">
|
||||
<Filter>imgui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>sources</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\LICENSE">
|
||||
<Filter>imgui</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
607
examples/directx11_example/main.cpp
Normal file
@ -0,0 +1,607 @@
|
||||
#include <windows.h>
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "../shared/stb_image.h" // for .png loading
|
||||
#include "../../imgui.h"
|
||||
|
||||
// DirectX 11
|
||||
#include <d3d11.h>
|
||||
#include <d3dcompiler.h>
|
||||
#define DIRECTINPUT_VERSION 0x0800
|
||||
#include <dinput.h>
|
||||
|
||||
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strdup
|
||||
|
||||
extern const char* vertexShader; // Implemented at the bottom
|
||||
extern const char* pixelShader;
|
||||
|
||||
static HWND hWnd;
|
||||
static ID3D11Device* g_pd3dDevice = NULL;
|
||||
static ID3D11DeviceContext* g_pd3dDeviceImmediateContext = NULL;
|
||||
static IDXGISwapChain* g_pSwapChain = NULL;
|
||||
static ID3D11Buffer* g_pVB = NULL;
|
||||
static ID3D11RenderTargetView* g_mainRenderTargetView;
|
||||
|
||||
static ID3D10Blob * g_pVertexShaderBlob = NULL;
|
||||
static ID3D11VertexShader* g_pVertexShader = NULL;
|
||||
static ID3D11InputLayout* g_pInputLayout = NULL;
|
||||
static ID3D11Buffer* g_pVertexConstantBuffer = NULL;
|
||||
|
||||
static ID3D10Blob * g_pPixelShaderBlob = NULL;
|
||||
static ID3D11PixelShader* g_pPixelShader = NULL;
|
||||
|
||||
static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
|
||||
static ID3D11SamplerState* g_pFontSampler = NULL;
|
||||
static ID3D11BlendState* g_blendState = NULL;
|
||||
|
||||
struct CUSTOMVERTEX
|
||||
{
|
||||
float pos[2];
|
||||
float uv[2];
|
||||
unsigned int col;
|
||||
};
|
||||
|
||||
struct VERTEX_CONSTANT_BUFFER
|
||||
{
|
||||
float mvp[4][4];
|
||||
};
|
||||
|
||||
// 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)
|
||||
// - try adjusting ImGui::GetIO().PixelCenterOffset to 0.5f or 0.375f
|
||||
static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
|
||||
{
|
||||
size_t total_vtx_count = 0;
|
||||
for (int n = 0; n < cmd_lists_count; n++)
|
||||
total_vtx_count += cmd_lists[n]->vtx_buffer.size();
|
||||
if (total_vtx_count == 0)
|
||||
return;
|
||||
|
||||
// Copy and convert all vertices into a single contiguous buffer
|
||||
D3D11_MAPPED_SUBRESOURCE mappedResource;
|
||||
if (g_pd3dDeviceImmediateContext->Map(g_pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource) != S_OK)
|
||||
return;
|
||||
CUSTOMVERTEX* vtx_dst = (CUSTOMVERTEX*)mappedResource.pData;
|
||||
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[0] = vtx_src->pos.x;
|
||||
vtx_dst->pos[1] = vtx_src->pos.y;
|
||||
vtx_dst->uv[0] = vtx_src->uv.x;
|
||||
vtx_dst->uv[1] = vtx_src->uv.y;
|
||||
vtx_dst->col = vtx_src->col;
|
||||
vtx_dst++;
|
||||
vtx_src++;
|
||||
}
|
||||
}
|
||||
g_pd3dDeviceImmediateContext->Unmap(g_pVB, 0);
|
||||
|
||||
// Setup orthographic projection matrix into our constant buffer
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE mappedResource;
|
||||
if (g_pd3dDeviceImmediateContext->Map(g_pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource) != S_OK)
|
||||
return;
|
||||
|
||||
VERTEX_CONSTANT_BUFFER* pConstantBuffer = (VERTEX_CONSTANT_BUFFER*)mappedResource.pData;
|
||||
const float L = 0.0f;
|
||||
const float R = ImGui::GetIO().DisplaySize.x;
|
||||
const float B = ImGui::GetIO().DisplaySize.y;
|
||||
const float T = 0.0f;
|
||||
const float mvp[4][4] =
|
||||
{
|
||||
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f},
|
||||
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f,},
|
||||
{ 0.0f, 0.0f, 0.5f, 0.0f },
|
||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
|
||||
};
|
||||
memcpy(&pConstantBuffer->mvp, mvp, sizeof(mvp));
|
||||
g_pd3dDeviceImmediateContext->Unmap(g_pVertexConstantBuffer, 0);
|
||||
}
|
||||
|
||||
// Setup viewport
|
||||
{
|
||||
D3D11_VIEWPORT vp;
|
||||
memset(&vp, 0, sizeof(D3D11_VIEWPORT));
|
||||
vp.Width = ImGui::GetIO().DisplaySize.x;
|
||||
vp.Height = ImGui::GetIO().DisplaySize.y;
|
||||
vp.MinDepth = 0.0f;
|
||||
vp.MaxDepth = 1.0f;
|
||||
vp.TopLeftX = 0;
|
||||
vp.TopLeftY = 0;
|
||||
g_pd3dDeviceImmediateContext->RSSetViewports(1, &vp);
|
||||
}
|
||||
|
||||
// Bind shader and vertex buffers
|
||||
unsigned int stride = sizeof(CUSTOMVERTEX);
|
||||
unsigned int offset = 0;
|
||||
g_pd3dDeviceImmediateContext->IASetInputLayout(g_pInputLayout);
|
||||
g_pd3dDeviceImmediateContext->IASetVertexBuffers(0, 1, &g_pVB, &stride, &offset);
|
||||
g_pd3dDeviceImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
g_pd3dDeviceImmediateContext->VSSetShader(g_pVertexShader, NULL, 0);
|
||||
g_pd3dDeviceImmediateContext->VSSetConstantBuffers(0, 1, &g_pVertexConstantBuffer);
|
||||
|
||||
g_pd3dDeviceImmediateContext->PSSetShader(g_pPixelShader, NULL, 0);
|
||||
g_pd3dDeviceImmediateContext->PSSetShaderResources(0, 1, &g_pFontTextureView);
|
||||
g_pd3dDeviceImmediateContext->PSSetSamplers(0, 1, &g_pFontSampler);
|
||||
|
||||
// Setup render state
|
||||
const float blendFactor[4] = { 0.f, 0.f, 0.f, 0.f };
|
||||
g_pd3dDeviceImmediateContext->OMSetBlendState(g_blendState, blendFactor, 0xffffffff);
|
||||
|
||||
// Render command lists
|
||||
int vtx_offset = 0;
|
||||
for (int n = 0; n < cmd_lists_count; n++)
|
||||
{
|
||||
// Render command list
|
||||
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];
|
||||
const D3D11_RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w };
|
||||
g_pd3dDeviceImmediateContext->RSSetScissorRects(1, &r);
|
||||
g_pd3dDeviceImmediateContext->Draw(pcmd->vtx_count, vtx_offset);
|
||||
vtx_offset += pcmd->vtx_count;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore modified state
|
||||
g_pd3dDeviceImmediateContext->IASetInputLayout(NULL);
|
||||
g_pd3dDeviceImmediateContext->PSSetShader(NULL, NULL, 0);
|
||||
g_pd3dDeviceImmediateContext->VSSetShader(NULL, NULL, 0);
|
||||
}
|
||||
|
||||
HRESULT InitDeviceD3D(HWND hWnd)
|
||||
{
|
||||
// Setup swap chain
|
||||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
{
|
||||
ZeroMemory(&sd, sizeof(sd));
|
||||
sd.BufferCount = 2;
|
||||
sd.BufferDesc.Width = (UINT)ImGui::GetIO().DisplaySize.x;
|
||||
sd.BufferDesc.Height = (UINT)ImGui::GetIO().DisplaySize.y;
|
||||
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;
|
||||
#ifdef _DEBUG
|
||||
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||
#endif
|
||||
D3D_FEATURE_LEVEL featureLevel;
|
||||
const D3D_FEATURE_LEVEL featureLevelArray[1] = { D3D_FEATURE_LEVEL_11_0, };
|
||||
if (D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags, featureLevelArray, 1, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceImmediateContext) != S_OK)
|
||||
return E_FAIL;
|
||||
|
||||
// Setup rasterizer
|
||||
{
|
||||
D3D11_RASTERIZER_DESC RSDesc;
|
||||
memset(&RSDesc, 0, sizeof(D3D11_RASTERIZER_DESC));
|
||||
RSDesc.FillMode = D3D11_FILL_SOLID;
|
||||
RSDesc.CullMode = D3D11_CULL_NONE;
|
||||
RSDesc.FrontCounterClockwise = FALSE;
|
||||
RSDesc.DepthBias = 0;
|
||||
RSDesc.SlopeScaledDepthBias = 0.0f;
|
||||
RSDesc.DepthBiasClamp = 0;
|
||||
RSDesc.DepthClipEnable = TRUE;
|
||||
RSDesc.ScissorEnable = TRUE;
|
||||
RSDesc.AntialiasedLineEnable = FALSE;
|
||||
RSDesc.MultisampleEnable = (sd.SampleDesc.Count > 1) ? TRUE : FALSE;
|
||||
|
||||
ID3D11RasterizerState* pRState = NULL;
|
||||
g_pd3dDevice->CreateRasterizerState(&RSDesc, &pRState);
|
||||
g_pd3dDeviceImmediateContext->RSSetState(pRState);
|
||||
pRState->Release();
|
||||
}
|
||||
|
||||
// Create the render target
|
||||
{
|
||||
ID3D11Texture2D* pBackBuffer;
|
||||
D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc;
|
||||
ZeroMemory(&render_target_view_desc, sizeof(render_target_view_desc));
|
||||
render_target_view_desc.Format = sd.BufferDesc.Format;
|
||||
render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||
g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
|
||||
g_pd3dDevice->CreateRenderTargetView(pBackBuffer, &render_target_view_desc, &g_mainRenderTargetView);
|
||||
g_pd3dDeviceImmediateContext->OMSetRenderTargets(1, &g_mainRenderTargetView, NULL);
|
||||
pBackBuffer->Release();
|
||||
}
|
||||
|
||||
// Create the vertex shader
|
||||
{
|
||||
D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &g_pVertexShaderBlob, NULL);
|
||||
if (g_pVertexShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||
return E_FAIL;
|
||||
if (g_pd3dDevice->CreateVertexShader((DWORD*)g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), NULL, &g_pVertexShader) != S_OK)
|
||||
return E_FAIL;
|
||||
|
||||
// Create the input layout
|
||||
D3D11_INPUT_ELEMENT_DESC localLayout[] = {
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, (size_t)(&((CUSTOMVERTEX*)0)->pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (size_t)(&((CUSTOMVERTEX*)0)->col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (size_t)(&((CUSTOMVERTEX*)0)->uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
|
||||
};
|
||||
|
||||
if (g_pd3dDevice->CreateInputLayout(localLayout, 3, g_pVertexShaderBlob->GetBufferPointer(), g_pVertexShaderBlob->GetBufferSize(), &g_pInputLayout) != S_OK)
|
||||
return E_FAIL;
|
||||
|
||||
// Create the constant buffer
|
||||
{
|
||||
D3D11_BUFFER_DESC cbDesc;
|
||||
cbDesc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER);
|
||||
cbDesc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
cbDesc.MiscFlags = 0;
|
||||
g_pd3dDevice->CreateBuffer(&cbDesc, NULL, &g_pVertexConstantBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the pixel shader
|
||||
{
|
||||
D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &g_pPixelShaderBlob, NULL);
|
||||
if (g_pPixelShaderBlob == NULL) // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
|
||||
return E_FAIL;
|
||||
if (g_pd3dDevice->CreatePixelShader((DWORD*)g_pPixelShaderBlob->GetBufferPointer(), g_pPixelShaderBlob->GetBufferSize(), NULL, &g_pPixelShader) != S_OK)
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Create the blending setup
|
||||
{
|
||||
D3D11_BLEND_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.AlphaToCoverageEnable = false;
|
||||
desc.RenderTarget[0].BlendEnable = true;
|
||||
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
||||
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
||||
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||
g_pd3dDevice->CreateBlendState(&desc, &g_blendState);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void CleanupDevice()
|
||||
{
|
||||
if (g_pd3dDeviceImmediateContext) g_pd3dDeviceImmediateContext->ClearState();
|
||||
|
||||
// InitImGui
|
||||
if (g_pFontSampler) g_pFontSampler->Release();
|
||||
if (g_pFontTextureView) g_pFontTextureView->Release();
|
||||
if (g_pVB) g_pVB->Release();
|
||||
|
||||
// InitDeviceD3D
|
||||
if (g_blendState) g_blendState->Release();
|
||||
if (g_pPixelShader) g_pPixelShader->Release();
|
||||
if (g_pPixelShaderBlob) g_pPixelShaderBlob->Release();
|
||||
if (g_pVertexConstantBuffer) g_pVertexConstantBuffer->Release();
|
||||
if (g_pInputLayout) g_pInputLayout->Release();
|
||||
if (g_pVertexShader) g_pVertexShader->Release();
|
||||
if (g_pVertexShaderBlob) g_pVertexShaderBlob->Release();
|
||||
if (g_mainRenderTargetView) g_mainRenderTargetView->Release();
|
||||
if (g_pSwapChain) g_pSwapChain->Release();
|
||||
if (g_pd3dDeviceImmediateContext) g_pd3dDeviceImmediateContext->Release();
|
||||
if (g_pd3dDevice) g_pd3dDevice->Release();
|
||||
}
|
||||
|
||||
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
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:
|
||||
// Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
|
||||
io.MousePos.x = (signed short)(lParam);
|
||||
io.MousePos.y = (signed short)(lParam >> 16);
|
||||
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;
|
||||
case WM_DESTROY:
|
||||
CleanupDevice();
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
}
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
void InitImGui()
|
||||
{
|
||||
RECT rect;
|
||||
GetClientRect(hWnd, &rect);
|
||||
int display_w = (int)(rect.right - rect.left);
|
||||
int display_h = (int)(rect.bottom - rect.top);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Display size, in pixels. For clamping windows positions.
|
||||
io.DeltaTime = 1.0f/60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our time step is variable)
|
||||
io.PixelCenterOffset = 0.0f; // Align Direct3D Texels
|
||||
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;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = VK_UP;
|
||||
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 = ImImpl_RenderDrawLists;
|
||||
|
||||
// Create the vertex buffer
|
||||
{
|
||||
D3D11_BUFFER_DESC bufferDesc;
|
||||
memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC));
|
||||
bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
bufferDesc.ByteWidth = 10000 * sizeof(CUSTOMVERTEX);
|
||||
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
bufferDesc.MiscFlags = 0;
|
||||
if (g_pd3dDevice->CreateBuffer(&bufferDesc, NULL, &g_pVB) < 0)
|
||||
{
|
||||
IM_ASSERT(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Load font texture
|
||||
// Default font (embedded in code)
|
||||
const void* png_data;
|
||||
unsigned int png_size;
|
||||
ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size);
|
||||
int tex_x, tex_y, tex_comp;
|
||||
void* tex_data = stbi_load_from_memory((const unsigned char*)png_data, (int)png_size, &tex_x, &tex_y, &tex_comp, 0);
|
||||
IM_ASSERT(tex_data != NULL);
|
||||
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.Width = tex_x;
|
||||
desc.Height = tex_y;
|
||||
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 = tex_data;
|
||||
subResource.SysMemPitch = tex_x * 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, &g_pFontTextureView);
|
||||
pTexture->Release();
|
||||
}
|
||||
|
||||
// Create texture sampler
|
||||
{
|
||||
D3D11_SAMPLER_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
desc.MipLODBias = 0.f;
|
||||
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
||||
desc.MinLOD = 0.f;
|
||||
desc.MaxLOD = 0.f;
|
||||
g_pd3dDevice->CreateSamplerState(&desc, &g_pFontSampler);
|
||||
}
|
||||
}
|
||||
|
||||
INT64 ticks_per_second = 0;
|
||||
INT64 last_time = 0;
|
||||
|
||||
void UpdateImGui()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Setup time step
|
||||
INT64 current_time;
|
||||
QueryPerformanceCounter((LARGE_INTEGER *)¤t_time);
|
||||
io.DeltaTime = (float)(current_time - last_time) / ticks_per_second;
|
||||
last_time = current_time;
|
||||
|
||||
// Setup inputs
|
||||
// (we already got mouse position, buttons, wheel from the window message callback)
|
||||
BYTE keystate[256];
|
||||
GetKeyboardState(keystate);
|
||||
for (int i = 0; i < 256; i++)
|
||||
io.KeysDown[i] = (keystate[i] & 0x80) != 0;
|
||||
io.KeyCtrl = (keystate[VK_CONTROL] & 0x80) != 0;
|
||||
io.KeyShift = (keystate[VK_SHIFT] & 0x80) != 0;
|
||||
// io.MousePos : filled by WM_MOUSEMOVE event
|
||||
// io.MouseDown : filled by WM_*BUTTON* events
|
||||
// io.MouseWheel : filled by WM_MOUSEWHEEL events
|
||||
|
||||
// Start the frame
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int)
|
||||
{
|
||||
// Register the window class
|
||||
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, "ImGui Example", NULL };
|
||||
RegisterClassEx(&wc);
|
||||
|
||||
// Create the application's window
|
||||
hWnd = CreateWindow("ImGui Example", "ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
|
||||
|
||||
if (!QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second))
|
||||
return 1;
|
||||
if (!QueryPerformanceCounter((LARGE_INTEGER *)&last_time))
|
||||
return 1;
|
||||
|
||||
// Initialize Direct3D
|
||||
if (InitDeviceD3D(hWnd) < 0)
|
||||
{
|
||||
CleanupDevice();
|
||||
UnregisterClass("ImGui Example", wc.hInstance);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Show the window
|
||||
ShowWindow(hWnd, SW_SHOWDEFAULT);
|
||||
UpdateWindow(hWnd);
|
||||
|
||||
InitImGui();
|
||||
|
||||
// Enter the message loop
|
||||
MSG msg;
|
||||
ZeroMemory(&msg, sizeof(msg));
|
||||
while (msg.message != WM_QUIT)
|
||||
{
|
||||
if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
continue;
|
||||
}
|
||||
|
||||
UpdateImGui();
|
||||
|
||||
static bool show_test_window = true;
|
||||
static bool show_another_window = false;
|
||||
|
||||
// 1. Show a simple window
|
||||
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
|
||||
{
|
||||
static float f;
|
||||
ImGui::Text("Hello, world!");
|
||||
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
|
||||
show_test_window ^= ImGui::Button("Test Window");
|
||||
show_another_window ^= ImGui::Button("Another Window");
|
||||
|
||||
// Calculate and show frame rate
|
||||
static float ms_per_frame[120] = { 0 };
|
||||
static int ms_per_frame_idx = 0;
|
||||
static float ms_per_frame_accum = 0.0f;
|
||||
ms_per_frame_accum -= ms_per_frame[ms_per_frame_idx];
|
||||
ms_per_frame[ms_per_frame_idx] = ImGui::GetIO().DeltaTime * 1000.0f;
|
||||
ms_per_frame_accum += ms_per_frame[ms_per_frame_idx];
|
||||
ms_per_frame_idx = (ms_per_frame_idx + 1) % 120;
|
||||
const float ms_per_frame_avg = ms_per_frame_accum / 120;
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ms_per_frame_avg, 1000.0f / ms_per_frame_avg);
|
||||
}
|
||||
|
||||
// 2. Show another simple window, this time using an explicit Begin/End pair
|
||||
if (show_another_window)
|
||||
{
|
||||
ImGui::Begin("Another Window", &show_another_window, ImVec2(200,100));
|
||||
ImGui::Text("Hello");
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowTestWindow()
|
||||
if (show_test_window)
|
||||
{
|
||||
ImGui::SetNewWindowDefaultPos(ImVec2(650, 20)); // Normally user code doesn't need/want to call it because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly!
|
||||
ImGui::ShowTestWindow(&show_test_window);
|
||||
}
|
||||
|
||||
// Rendering
|
||||
float clearColor[4] = { 204 / 255.f, 153 / 255.f, 153 / 255.f };
|
||||
g_pd3dDeviceImmediateContext->ClearRenderTargetView(g_mainRenderTargetView, clearColor);
|
||||
ImGui::Render();
|
||||
g_pSwapChain->Present(0, 0);
|
||||
}
|
||||
|
||||
ImGui::Shutdown();
|
||||
UnregisterClass("ImGui Example", wc.hInstance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char* vertexShader = "\
|
||||
cbuffer vertexBuffer : register(c0) \
|
||||
{\
|
||||
float4x4 ProjectionMatrix; \
|
||||
};\
|
||||
struct VS_INPUT\
|
||||
{\
|
||||
float2 pos : POSITION;\
|
||||
float4 col : COLOR0;\
|
||||
float2 uv : TEXCOORD0;\
|
||||
};\
|
||||
\
|
||||
struct PS_INPUT\
|
||||
{\
|
||||
float4 pos : SV_POSITION;\
|
||||
float4 col : COLOR0;\
|
||||
float2 uv : TEXCOORD0;\
|
||||
};\
|
||||
\
|
||||
PS_INPUT main(VS_INPUT input)\
|
||||
{\
|
||||
PS_INPUT output;\
|
||||
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
|
||||
output.col = input.col;\
|
||||
output.uv = input.uv;\
|
||||
return output;\
|
||||
}";
|
||||
|
||||
static const char* pixelShader = "\
|
||||
struct PS_INPUT\
|
||||
{\
|
||||
float4 pos : SV_POSITION;\
|
||||
float4 col : COLOR0;\
|
||||
float2 uv : TEXCOORD0;\
|
||||
};\
|
||||
sampler sampler0;\
|
||||
Texture2D texture0;\
|
||||
\
|
||||
float4 main(PS_INPUT input) : SV_Target\
|
||||
{\
|
||||
float4 out_col = texture0.Sample(sampler0, input.uv);\
|
||||
return input.col * out_col;\
|
||||
}";
|
@ -1,20 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "directx9_example", "directx9_example.vcxproj", "{4165A294-21F2-44CA-9B38-E3F935ABADF5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4165A294-21F2-44CA-9B38-E3F935ABADF5}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{4165A294-21F2-44CA-9B38-E3F935ABADF5}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{4165A294-21F2-44CA-9B38-E3F935ABADF5}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{4165A294-21F2-44CA-9B38-E3F935ABADF5}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -46,7 +46,7 @@
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(DXSDK_DIR)Lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>d3d9.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;winmm.lib;comctl32.lib;gdi32.lib;user32.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>d3d9.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;imm32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
</Link>
|
||||
@ -64,7 +64,7 @@
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>$(DXSDK_DIR)Lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>d3d9.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;winmm.lib;comctl32.lib;gdi32.lib;user32.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>d3d9.lib;d3dx9d.lib;dxerr.lib;dxguid.lib;imm32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
</Link>
|
||||
|
@ -1,105 +1,109 @@
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include "../../imgui.h"
|
||||
|
||||
// DirectX 9
|
||||
#include <d3dx9.h>
|
||||
#define DIRECTINPUT_VERSION 0x0800
|
||||
#include <dinput.h>
|
||||
#include "../../imgui.h"
|
||||
|
||||
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strdup
|
||||
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strdup
|
||||
|
||||
static HWND hWnd;
|
||||
static LPDIRECT3D9 g_pD3D = NULL; // Used to create the D3DDevice
|
||||
static HWND hWnd;
|
||||
static LPDIRECT3D9 g_pD3D = NULL; // Used to create the D3DDevice
|
||||
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Our rendering device
|
||||
static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer to hold vertices
|
||||
static LPDIRECT3DTEXTURE9 g_pTexture = NULL; // Our texture
|
||||
static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer to hold vertices
|
||||
static LPDIRECT3DTEXTURE9 g_pTexture = NULL; // Our texture
|
||||
struct CUSTOMVERTEX
|
||||
{
|
||||
D3DXVECTOR3 position;
|
||||
D3DCOLOR color;
|
||||
float tu, tv;
|
||||
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 structuer)
|
||||
// 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)
|
||||
// - try adjusting ImGui::GetIO().PixelCenterOffset to 0.5f or 0.375f
|
||||
static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
|
||||
{
|
||||
size_t total_vtx_count = 0;
|
||||
for (int n = 0; n < cmd_lists_count; n++)
|
||||
total_vtx_count += cmd_lists[n]->vtx_buffer.size();
|
||||
if (total_vtx_count == 0)
|
||||
return;
|
||||
size_t total_vtx_count = 0;
|
||||
for (int n = 0; n < cmd_lists_count; n++)
|
||||
total_vtx_count += cmd_lists[n]->vtx_buffer.size();
|
||||
if (total_vtx_count == 0)
|
||||
return;
|
||||
|
||||
// Copy and convert all vertices into a single contiguous buffer
|
||||
// Copy and convert all vertices into a single contiguous buffer
|
||||
CUSTOMVERTEX* vtx_dst;
|
||||
if (g_pVB->Lock(0, total_vtx_count, (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
|
||||
return;
|
||||
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->position.x = vtx_src->pos.x;
|
||||
vtx_dst->position.y = vtx_src->pos.y;
|
||||
vtx_dst->position.z = 0.0f;
|
||||
vtx_dst->color = (vtx_src->col & 0xFF00FF00) | ((vtx_src->col & 0xFF0000)>>16) | ((vtx_src->col & 0xFF) << 16); // RGBA --> ARGB for DirectX9
|
||||
vtx_dst->tu = vtx_src->uv.x;
|
||||
vtx_dst->tv = vtx_src->uv.y;
|
||||
vtx_dst++;
|
||||
vtx_src++;
|
||||
}
|
||||
}
|
||||
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++;
|
||||
}
|
||||
}
|
||||
g_pVB->Unlock();
|
||||
|
||||
g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );
|
||||
g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
|
||||
g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );
|
||||
g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
|
||||
|
||||
// Setup render state: alpha-blending, no face culling, no depth testing
|
||||
// Setup render state: alpha-blending, no face culling, no depth testing
|
||||
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->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 );
|
||||
|
||||
// Setup texture
|
||||
g_pd3dDevice->SetTexture( 0, g_pTexture );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, 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 );
|
||||
// Setup texture
|
||||
g_pd3dDevice->SetTexture( 0, g_pTexture );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
|
||||
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, 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 );
|
||||
|
||||
// Setup orthographic projection matrix
|
||||
D3DXMATRIXA16 mat;
|
||||
D3DXMatrixIdentity(&mat);
|
||||
g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat);
|
||||
g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat);
|
||||
D3DXMatrixOrthoOffCenterLH(&mat, 0.0f, ImGui::GetIO().DisplaySize.x, ImGui::GetIO().DisplaySize.y, 0.0f, -1.0f, +1.0f);
|
||||
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat);
|
||||
// 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;
|
||||
for (int n = 0; n < cmd_lists_count; n++)
|
||||
{
|
||||
// Render command list
|
||||
const ImDrawList* cmd_list = cmd_lists[n];
|
||||
const ImDrawCmd* pcmd_end = cmd_list->commands.end();
|
||||
for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++)
|
||||
{
|
||||
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->SetScissorRect(&r);
|
||||
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, vtx_offset, pcmd->vtx_count/3);
|
||||
vtx_offset += pcmd->vtx_count;
|
||||
}
|
||||
}
|
||||
// Render command lists
|
||||
int vtx_offset = 0;
|
||||
for (int n = 0; n < cmd_lists_count; n++)
|
||||
{
|
||||
// Render command list
|
||||
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];
|
||||
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->SetScissorRect(&r);
|
||||
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, vtx_offset, pcmd->vtx_count/3);
|
||||
vtx_offset += pcmd->vtx_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT InitD3D(HWND hWnd)
|
||||
HRESULT InitDeviceD3D(HWND hWnd)
|
||||
{
|
||||
if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
|
||||
return E_FAIL;
|
||||
@ -111,7 +115,7 @@ HRESULT InitD3D(HWND hWnd)
|
||||
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
|
||||
d3dpp.EnableAutoDepthStencil = TRUE;
|
||||
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
|
||||
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
||||
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
||||
|
||||
// Create the D3DDevice
|
||||
if (g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice) < 0)
|
||||
@ -120,163 +124,160 @@ HRESULT InitD3D(HWND hWnd)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void Cleanup()
|
||||
void CleanupDevice()
|
||||
{
|
||||
if (g_pTexture != NULL)
|
||||
g_pTexture->Release();
|
||||
// InitImGui
|
||||
if (g_pVB) g_pVB->Release();
|
||||
|
||||
if (g_pd3dDevice != NULL)
|
||||
g_pd3dDevice->Release();
|
||||
|
||||
if (g_pD3D != NULL)
|
||||
g_pD3D->Release();
|
||||
// InitDeviceD3D
|
||||
if (g_pTexture) g_pTexture->Release();
|
||||
if (g_pd3dDevice) g_pd3dDevice->Release();
|
||||
if (g_pD3D) g_pD3D->Release();
|
||||
}
|
||||
|
||||
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
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:
|
||||
// Mouse wheel: -1,0,+1
|
||||
io.MouseWheel = GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1 : -1;
|
||||
return true;
|
||||
case WM_MOUSEMOVE:
|
||||
// Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
|
||||
io.MousePos.x = (signed short)(lParam);
|
||||
io.MousePos.y = (signed short)(lParam >> 16);
|
||||
return true;
|
||||
case WM_CHAR:
|
||||
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
|
||||
if (wParam > 1 && wParam < 256)
|
||||
io.AddInputCharacter((char)wParam);
|
||||
return true;
|
||||
case WM_DESTROY:
|
||||
{
|
||||
Cleanup();
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
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:
|
||||
// Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
|
||||
io.MousePos.x = (signed short)(lParam);
|
||||
io.MousePos.y = (signed short)(lParam >> 16);
|
||||
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;
|
||||
case WM_DESTROY:
|
||||
CleanupDevice();
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
}
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
void InitImGui()
|
||||
{
|
||||
RECT rect;
|
||||
GetClientRect(hWnd, &rect);
|
||||
RECT rect;
|
||||
GetClientRect(hWnd, &rect);
|
||||
int display_w = (int)(rect.right - rect.left);
|
||||
int display_h = (int)(rect.bottom - rect.top);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); // Display size, in pixels. For clamping windows positions.
|
||||
io.DeltaTime = 1.0f/60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our timestep is variable)
|
||||
io.PixelCenterOffset = 0.0f; // Align Direct3D Texels
|
||||
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;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = VK_UP;
|
||||
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';
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Display size, in pixels. For clamping windows positions.
|
||||
io.DeltaTime = 1.0f/60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our time step is variable)
|
||||
io.PixelCenterOffset = 0.0f; // Align Direct3D Texels
|
||||
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;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = VK_UP;
|
||||
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 = ImImpl_RenderDrawLists;
|
||||
|
||||
// Create the vertex buffer
|
||||
if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
|
||||
{
|
||||
IM_ASSERT(0);
|
||||
return;
|
||||
}
|
||||
io.RenderDrawListsFn = ImImpl_RenderDrawLists;
|
||||
|
||||
// Create the vertex buffer
|
||||
if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
|
||||
{
|
||||
IM_ASSERT(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Load font texture
|
||||
const void* png_data;
|
||||
unsigned int png_size;
|
||||
ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size);
|
||||
if (D3DXCreateTextureFromFileInMemory(g_pd3dDevice, png_data, png_size, &g_pTexture) < 0)
|
||||
{
|
||||
IM_ASSERT(0);
|
||||
return;
|
||||
}
|
||||
// Load font texture
|
||||
const void* png_data;
|
||||
unsigned int png_size;
|
||||
ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size);
|
||||
if (D3DXCreateTextureFromFileInMemory(g_pd3dDevice, png_data, png_size, &g_pTexture) < 0)
|
||||
{
|
||||
IM_ASSERT(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
INT64 ticks_per_second = 0;
|
||||
INT64 time = 0;
|
||||
INT64 last_time = 0;
|
||||
|
||||
void UpdateImGui()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Setup timestep
|
||||
INT64 current_time;
|
||||
QueryPerformanceCounter((LARGE_INTEGER *)¤t_time);
|
||||
io.DeltaTime = (float)(current_time - time) / ticks_per_second;
|
||||
time = current_time;
|
||||
// Setup time step
|
||||
INT64 current_time;
|
||||
QueryPerformanceCounter((LARGE_INTEGER *)¤t_time);
|
||||
io.DeltaTime = (float)(current_time - last_time) / ticks_per_second;
|
||||
last_time = current_time;
|
||||
|
||||
// Setup inputs
|
||||
// (we already got mouse position, buttons, wheel from the window message callback)
|
||||
BYTE keystate[256];
|
||||
GetKeyboardState(keystate);
|
||||
for (int i = 0; i < 256; i++)
|
||||
io.KeysDown[i] = (keystate[i] & 0x80) != 0;
|
||||
io.KeyCtrl = (keystate[VK_CONTROL] & 0x80) != 0;
|
||||
io.KeyShift = (keystate[VK_SHIFT] & 0x80) != 0;
|
||||
// io.MousePos : filled by WM_MOUSEMOVE event
|
||||
// io.MouseDown : filled by WM_*BUTTON* events
|
||||
// io.MouseWheel : filled by WM_MOUSEWHEEL events
|
||||
// Setup inputs
|
||||
// (we already got mouse position, buttons, wheel from the window message callback)
|
||||
BYTE keystate[256];
|
||||
GetKeyboardState(keystate);
|
||||
for (int i = 0; i < 256; i++)
|
||||
io.KeysDown[i] = (keystate[i] & 0x80) != 0;
|
||||
io.KeyCtrl = (keystate[VK_CONTROL] & 0x80) != 0;
|
||||
io.KeyShift = (keystate[VK_SHIFT] & 0x80) != 0;
|
||||
// io.MousePos : filled by WM_MOUSEMOVE event
|
||||
// io.MouseDown : filled by WM_*BUTTON* events
|
||||
// io.MouseWheel : filled by WM_MOUSEWHEEL events
|
||||
|
||||
// Start the frame
|
||||
ImGui::NewFrame();
|
||||
// Start the frame
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int)
|
||||
{
|
||||
// Register the window class
|
||||
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, L"ImGui Example", NULL };
|
||||
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, L"ImGui Example", NULL };
|
||||
RegisterClassEx(&wc);
|
||||
|
||||
// Create the application's window
|
||||
hWnd = CreateWindow(L"ImGui Example", L"ImGui DirectX9 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL);
|
||||
|
||||
if (!QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second))
|
||||
return 1;
|
||||
if (!QueryPerformanceCounter((LARGE_INTEGER *)&time))
|
||||
return 1;
|
||||
if (!QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second))
|
||||
return 1;
|
||||
if (!QueryPerformanceCounter((LARGE_INTEGER *)&last_time))
|
||||
return 1;
|
||||
|
||||
// Initialize Direct3D
|
||||
if (InitD3D(hWnd) < 0)
|
||||
{
|
||||
if (g_pVB)
|
||||
g_pVB->Release();
|
||||
UnregisterClass(L"ImGui Example", wc.hInstance);
|
||||
return 1;
|
||||
}
|
||||
// Initialize Direct3D
|
||||
if (InitDeviceD3D(hWnd) < 0)
|
||||
{
|
||||
CleanupDevice();
|
||||
UnregisterClass(L"ImGui Example", wc.hInstance);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Show the window
|
||||
ShowWindow(hWnd, SW_SHOWDEFAULT);
|
||||
UpdateWindow(hWnd);
|
||||
// Show the window
|
||||
ShowWindow(hWnd, SW_SHOWDEFAULT);
|
||||
UpdateWindow(hWnd);
|
||||
|
||||
InitImGui();
|
||||
InitImGui();
|
||||
|
||||
// Enter the message loop
|
||||
MSG msg;
|
||||
@ -287,65 +288,64 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int)
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
UpdateImGui();
|
||||
|
||||
UpdateImGui();
|
||||
|
||||
// Create a simple window
|
||||
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
|
||||
static bool show_test_window = true;
|
||||
static bool show_another_window = false;
|
||||
static float f;
|
||||
ImGui::Text("Hello, world!");
|
||||
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
|
||||
show_test_window ^= ImGui::Button("Test Window");
|
||||
show_another_window ^= ImGui::Button("Another Window");
|
||||
static bool show_test_window = true;
|
||||
static bool show_another_window = false;
|
||||
|
||||
// Calculate and show framerate
|
||||
static float ms_per_frame[120] = { 0 };
|
||||
static int ms_per_frame_idx = 0;
|
||||
static float ms_per_frame_accum = 0.0f;
|
||||
ms_per_frame_accum -= ms_per_frame[ms_per_frame_idx];
|
||||
ms_per_frame[ms_per_frame_idx] = ImGui::GetIO().DeltaTime * 1000.0f;
|
||||
ms_per_frame_accum += ms_per_frame[ms_per_frame_idx];
|
||||
ms_per_frame_idx = (ms_per_frame_idx + 1) % 120;
|
||||
const float ms_per_frame_avg = ms_per_frame_accum / 120;
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ms_per_frame_avg, 1000.0f / ms_per_frame_avg);
|
||||
// 1. Show a simple window
|
||||
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
|
||||
{
|
||||
static float f;
|
||||
ImGui::Text("Hello, world!");
|
||||
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
|
||||
show_test_window ^= ImGui::Button("Test Window");
|
||||
show_another_window ^= ImGui::Button("Another Window");
|
||||
|
||||
// Show the ImGui test window
|
||||
// Most of user example code is in ImGui::ShowTestWindow()
|
||||
if (show_test_window)
|
||||
{
|
||||
ImGui::SetNewWindowDefaultPos(ImVec2(650, 20)); // Normally user code doesn't need/want to call it because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly!
|
||||
ImGui::ShowTestWindow(&show_test_window);
|
||||
}
|
||||
// Calculate and show frame rate
|
||||
static float ms_per_frame[120] = { 0 };
|
||||
static int ms_per_frame_idx = 0;
|
||||
static float ms_per_frame_accum = 0.0f;
|
||||
ms_per_frame_accum -= ms_per_frame[ms_per_frame_idx];
|
||||
ms_per_frame[ms_per_frame_idx] = ImGui::GetIO().DeltaTime * 1000.0f;
|
||||
ms_per_frame_accum += ms_per_frame[ms_per_frame_idx];
|
||||
ms_per_frame_idx = (ms_per_frame_idx + 1) % 120;
|
||||
const float ms_per_frame_avg = ms_per_frame_accum / 120;
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ms_per_frame_avg, 1000.0f / ms_per_frame_avg);
|
||||
}
|
||||
|
||||
// Show another simple window
|
||||
if (show_another_window)
|
||||
{
|
||||
ImGui::Begin("Another Window", &show_another_window, ImVec2(200,100));
|
||||
ImGui::Text("Hello");
|
||||
ImGui::End();
|
||||
}
|
||||
// 2. Show another simple window, this time using an explicit Begin/End pair
|
||||
if (show_another_window)
|
||||
{
|
||||
ImGui::Begin("Another Window", &show_another_window, ImVec2(200,100));
|
||||
ImGui::Text("Hello");
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// Rendering
|
||||
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, false);
|
||||
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(204, 153, 153), 1.0f, 0);
|
||||
if (g_pd3dDevice->BeginScene() >= 0)
|
||||
{
|
||||
ImGui::Render();
|
||||
g_pd3dDevice->EndScene();
|
||||
}
|
||||
g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
|
||||
}
|
||||
// 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowTestWindow()
|
||||
if (show_test_window)
|
||||
{
|
||||
ImGui::SetNewWindowDefaultPos(ImVec2(650, 20)); // Normally user code doesn't need/want to call it because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly!
|
||||
ImGui::ShowTestWindow(&show_test_window);
|
||||
}
|
||||
|
||||
ImGui::Shutdown();
|
||||
// Rendering
|
||||
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, false);
|
||||
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(204, 153, 153), 1.0f, 0);
|
||||
if (g_pd3dDevice->BeginScene() >= 0)
|
||||
{
|
||||
ImGui::Render();
|
||||
g_pd3dDevice->EndScene();
|
||||
}
|
||||
g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
if (g_pVB)
|
||||
g_pVB->Release();
|
||||
ImGui::Shutdown();
|
||||
|
||||
UnregisterClass(L"ImGui Example", wc.hInstance);
|
||||
return 0;
|
||||
|
32
examples/imgui_examples_msvc2010.sln
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opengl_example", "opengl_example\opengl_example.vcxproj", "{9CDA7840-B7A5-496D-A527-E95571496D18}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "directx9_example", "directx9_example\directx9_example.vcxproj", "{4165A294-21F2-44CA-9B38-E3F935ABADF5}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "directx11_example", "directx11_example\directx11_example.vcxproj", "{9F316E83-5AE5-4939-A723-305A94F48005}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{9CDA7840-B7A5-496D-A527-E95571496D18}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{9CDA7840-B7A5-496D-A527-E95571496D18}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{9CDA7840-B7A5-496D-A527-E95571496D18}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{9CDA7840-B7A5-496D-A527-E95571496D18}.Release|Win32.Build.0 = Release|Win32
|
||||
{4165A294-21F2-44CA-9B38-E3F935ABADF5}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{4165A294-21F2-44CA-9B38-E3F935ABADF5}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{4165A294-21F2-44CA-9B38-E3F935ABADF5}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{4165A294-21F2-44CA-9B38-E3F935ABADF5}.Release|Win32.Build.0 = Release|Win32
|
||||
{9F316E83-5AE5-4939-A723-305A94F48005}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{9F316E83-5AE5-4939-A723-305A94F48005}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{9F316E83-5AE5-4939-A723-305A94F48005}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{9F316E83-5AE5-4939-A723-305A94F48005}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
53
examples/opengl_example/Makefile
Normal file
@ -0,0 +1,53 @@
|
||||
#
|
||||
# Cross Platform Make file
|
||||
#
|
||||
# Compatible with Ubuntu 14.04.1 and Mac OS X
|
||||
#
|
||||
#
|
||||
# if you using Mac OS X:
|
||||
# You should install glew via homebrew
|
||||
# brew install glew
|
||||
# Also you'll need glfw
|
||||
# http://www.glfw.org
|
||||
#
|
||||
|
||||
CXX = g++
|
||||
|
||||
OBJS = main.o
|
||||
OBJS += ../../imgui.o
|
||||
|
||||
UNAME_S := $(shell uname -s)
|
||||
|
||||
|
||||
ifeq ($(UNAME_S), Linux) #LINUX
|
||||
ECHO_MESSAGE = "Linux"
|
||||
CXXFLAGS = -I../../ `pkg-config --cflags glfw3`
|
||||
LIBS = `pkg-config --static --libs glfw3` -lGLEW
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME_S), Darwin) #APPLE
|
||||
ECHO_MESSAGE = "Mac OS X"
|
||||
|
||||
LIBS = -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo
|
||||
LIBS += -L/usr/local/Cellar/glew/1.10.0/lib -L/usr/local/lib
|
||||
LIBS += -lglew -lglfw3
|
||||
|
||||
CXXFLAGS = -I/usr/local/Cellar/glew/1.10.0/include -I/usr/local/include
|
||||
CXXFLAGS += -I../../
|
||||
|
||||
# CXXFLAGS += -D__APPLE__
|
||||
|
||||
endif
|
||||
|
||||
.cpp.o:
|
||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
all:imgui_example
|
||||
@echo Build complete for $(ECHO_MESSAGE)
|
||||
|
||||
imgui_example:$(OBJS)
|
||||
$(CXX) -o imgui_example $(OBJS) $(CXXFLAGS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm $(OBJS)
|
||||
|
@ -1,18 +0,0 @@
|
||||
#
|
||||
# Quick and dirty makefile to build on Linux
|
||||
# tested on Ubuntu 14.04.1 32bit
|
||||
#
|
||||
|
||||
SRC = main.cpp ../../imgui.cpp
|
||||
|
||||
OBJ = $(SRC:.cpp=.o)
|
||||
|
||||
CXXFLAGS = -I../../ `pkg-config --cflags glfw3`
|
||||
|
||||
LIBS = `pkg-config --static --libs glfw3` -lGLEW
|
||||
|
||||
all: $(OBJ)
|
||||
$(CXX) $(OBJ) $(LIBS)
|
||||
|
||||
clean:
|
||||
$(RM) -f $(OBJ)
|
@ -1,18 +0,0 @@
|
||||
# This makefile currently only works for mac os
|
||||
# You should install via homebrew:
|
||||
# brew install glew
|
||||
# brew install glfw3
|
||||
#
|
||||
|
||||
CXXFLAGS=-framework OpenGL -framework Cocoa -framework IOKit
|
||||
CXXFLAGS+=-I/usr/local/Cellar/glew/1.10.0/include -I/usr/local/Cellar/glfw3/3.0.4/include
|
||||
CXXFLAGS+=-L/usr/local/Cellar/glew/1.10.0/lib -L/usr/local/Cellar/glfw3/3.0.4/lib
|
||||
CXXFLAGS+=-lglew -lglfw3
|
||||
CXXFLAGS+=-I../../
|
||||
CXXFLAGS+= -D__APPLE__
|
||||
|
||||
main: main.cpp ../../imgui.cpp
|
||||
$(CXX) $(CXXFLAGS) -o $@ $^
|
||||
|
||||
clean:
|
||||
rm main
|
@ -1,268 +1,314 @@
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "../shared/stb_image.h" // for .png loading
|
||||
#include "../../imgui.h"
|
||||
|
||||
// glew & glfw
|
||||
#define GLEW_STATIC
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h" // for .png loading
|
||||
#include "../../imgui.h"
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
|
||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||
#define GLFW_EXPOSE_NATIVE_WGL
|
||||
#include <GLFW/glfw3native.h>
|
||||
#endif
|
||||
|
||||
static GLFWwindow* window;
|
||||
static GLuint fontTex;
|
||||
static bool mousePressed[2] = { false, false };
|
||||
static ImVec2 mousePosScale(1.0f, 1.0f);
|
||||
|
||||
// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structuer)
|
||||
// We are using the fixed pipeline.
|
||||
// A faster way would be to collate all vertices from all cmd_lists into a single vertex buffer
|
||||
// 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)
|
||||
// - try adjusting ImGui::GetIO().PixelCenterOffset to 0.5f or 0.375f
|
||||
static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
|
||||
{
|
||||
if (cmd_lists_count == 0)
|
||||
return;
|
||||
if (cmd_lists_count == 0)
|
||||
return;
|
||||
|
||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers.
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
// We are using the OpenGL fixed pipeline to make the example code simpler to read!
|
||||
// A probable faster way to render would be to collate all vertices from all cmd_lists into a single vertex buffer.
|
||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers.
|
||||
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
// Setup texture
|
||||
glBindTexture(GL_TEXTURE_2D, fontTex);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
// Setup texture
|
||||
glBindTexture(GL_TEXTURE_2D, fontTex);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
// Setup orthographic projection matrix
|
||||
const float width = ImGui::GetIO().DisplaySize.x;
|
||||
const float height = ImGui::GetIO().DisplaySize.y;
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0.0f, width, height, 0.0f, -1.0f, +1.0f);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
// Setup orthographic projection matrix
|
||||
const float width = ImGui::GetIO().DisplaySize.x;
|
||||
const float height = ImGui::GetIO().DisplaySize.y;
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho(0.0f, width, height, 0.0f, -1.0f, +1.0f);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
// Render command lists
|
||||
for (int n = 0; n < cmd_lists_count; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = cmd_lists[n];
|
||||
const unsigned char* vtx_buffer = (const unsigned char*)cmd_list->vtx_buffer.begin();
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer));
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer+8));
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer+16));
|
||||
// Render command lists
|
||||
for (int n = 0; n < cmd_lists_count; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = cmd_lists[n];
|
||||
const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->vtx_buffer.front();
|
||||
glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + offsetof(ImDrawVert, pos)));
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + offsetof(ImDrawVert, uv)));
|
||||
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer + offsetof(ImDrawVert, col)));
|
||||
|
||||
int vtx_offset = 0;
|
||||
const ImDrawCmd* pcmd_end = cmd_list->commands.end();
|
||||
for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++)
|
||||
{
|
||||
glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y));
|
||||
glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count);
|
||||
vtx_offset += pcmd->vtx_count;
|
||||
}
|
||||
}
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
int vtx_offset = 0;
|
||||
for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i];
|
||||
glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y));
|
||||
glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count);
|
||||
vtx_offset += pcmd->vtx_count;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore modified state
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
// NB: ImGui already provide OS clipboard support for Windows so this isn't needed if you are using Windows only.
|
||||
static const char* ImImpl_GetClipboardTextFn()
|
||||
{
|
||||
return glfwGetClipboardString(window);
|
||||
return glfwGetClipboardString(window);
|
||||
}
|
||||
|
||||
static void ImImpl_SetClipboardTextFn(const char* text, const char* text_end)
|
||||
static void ImImpl_SetClipboardTextFn(const char* text)
|
||||
{
|
||||
if (!text_end)
|
||||
text_end = text + strlen(text);
|
||||
|
||||
if (*text_end == 0)
|
||||
{
|
||||
// Already got a zero-terminator at 'text_end', we don't need to add one
|
||||
glfwSetClipboardString(window, text);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add a zero-terminator because glfw function doesn't take a size
|
||||
char* buf = (char*)malloc(text_end - text + 1);
|
||||
memcpy(buf, text, text_end-text);
|
||||
buf[text_end-text] = '\0';
|
||||
glfwSetClipboardString(window, buf);
|
||||
free(buf);
|
||||
}
|
||||
glfwSetClipboardString(window, text);
|
||||
}
|
||||
|
||||
|
||||
// GLFW callbacks to get events
|
||||
static void glfw_error_callback(int error, const char* description)
|
||||
{
|
||||
fputs(description, stderr);
|
||||
fputs(description, stderr);
|
||||
}
|
||||
|
||||
static void glfw_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
|
||||
{
|
||||
if (action == GLFW_PRESS && button >= 0 && button < 2)
|
||||
mousePressed[button] = true;
|
||||
}
|
||||
|
||||
static void glfw_scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.MouseWheel = (yoffset != 0.0f) ? yoffset > 0.0f ? 1 : - 1 : 0; // Mouse wheel: -1,0,+1
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines.
|
||||
}
|
||||
|
||||
static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (action == GLFW_PRESS)
|
||||
io.KeysDown[key] = true;
|
||||
if (action == GLFW_RELEASE)
|
||||
io.KeysDown[key] = false;
|
||||
io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
|
||||
io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (action == GLFW_PRESS)
|
||||
io.KeysDown[key] = true;
|
||||
if (action == GLFW_RELEASE)
|
||||
io.KeysDown[key] = false;
|
||||
io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
|
||||
io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
|
||||
}
|
||||
|
||||
static void glfw_char_callback(GLFWwindow* window, unsigned int c)
|
||||
{
|
||||
if (c > 0 && c <= 255)
|
||||
ImGui::GetIO().AddInputCharacter((char)c);
|
||||
if (c > 0 && c < 0x10000)
|
||||
ImGui::GetIO().AddInputCharacter((unsigned short)c);
|
||||
}
|
||||
|
||||
// OpenGL code based on http://open.gl tutorials
|
||||
void InitGL()
|
||||
{
|
||||
glfwSetErrorCallback(glfw_error_callback);
|
||||
glfwSetErrorCallback(glfw_error_callback);
|
||||
|
||||
if (!glfwInit())
|
||||
exit(1);
|
||||
if (!glfwInit())
|
||||
exit(1);
|
||||
|
||||
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
|
||||
window = glfwCreateWindow(1280, 720, "ImGui OpenGL example", NULL, NULL);
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSetKeyCallback(window, glfw_key_callback);
|
||||
glfwSetScrollCallback(window, glfw_scroll_callback);
|
||||
glfwSetCharCallback(window, glfw_char_callback);
|
||||
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
|
||||
window = glfwCreateWindow(1280, 720, "ImGui OpenGL example", NULL, NULL);
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSetKeyCallback(window, glfw_key_callback);
|
||||
glfwSetMouseButtonCallback(window, glfw_mouse_button_callback);
|
||||
glfwSetScrollCallback(window, glfw_scroll_callback);
|
||||
glfwSetCharCallback(window, glfw_char_callback);
|
||||
|
||||
glewInit();
|
||||
glewInit();
|
||||
}
|
||||
|
||||
void InitImGui()
|
||||
{
|
||||
int w, h;
|
||||
glfwGetWindowSize(window, &w, &h);
|
||||
int w, h;
|
||||
int display_w, display_h;
|
||||
glfwGetWindowSize(window, &w, &h);
|
||||
glfwGetFramebufferSize(window, &display_w, &display_h);
|
||||
mousePosScale.x = (float)display_w / w; // Some screens e.g. Retina display have framebuffer size != from window size, and mouse inputs are given in window/screen coordinates.
|
||||
mousePosScale.y = (float)display_h / h;
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DisplaySize = ImVec2((float)w, (float)h); // Display size, in pixels. For clamping windows positions.
|
||||
io.DeltaTime = 1.0f/60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our timestep is variable)
|
||||
io.PixelCenterOffset = 0.5f; // Align OpenGL texels
|
||||
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array.
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
|
||||
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
|
||||
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
|
||||
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
|
||||
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
|
||||
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
|
||||
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
|
||||
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
|
||||
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
|
||||
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
|
||||
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
|
||||
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
|
||||
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DisplaySize = ImVec2((float)display_w, (float)display_h); // Display size, in pixels. For clamping windows positions.
|
||||
io.DeltaTime = 1.0f/60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our time step is variable)
|
||||
io.PixelCenterOffset = 0.0f; // Align OpenGL texels
|
||||
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array.
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
|
||||
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
|
||||
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
|
||||
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
|
||||
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
|
||||
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
|
||||
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
|
||||
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
|
||||
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
|
||||
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
|
||||
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
|
||||
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
|
||||
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
|
||||
|
||||
io.RenderDrawListsFn = ImImpl_RenderDrawLists;
|
||||
io.SetClipboardTextFn = ImImpl_SetClipboardTextFn;
|
||||
io.GetClipboardTextFn = ImImpl_GetClipboardTextFn;
|
||||
io.RenderDrawListsFn = ImImpl_RenderDrawLists;
|
||||
io.SetClipboardTextFn = ImImpl_SetClipboardTextFn;
|
||||
io.GetClipboardTextFn = ImImpl_GetClipboardTextFn;
|
||||
|
||||
// Load font texture
|
||||
glGenTextures(1, &fontTex);
|
||||
glBindTexture(GL_TEXTURE_2D, fontTex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
const void* png_data;
|
||||
unsigned int png_size;
|
||||
ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size);
|
||||
int tex_x, tex_y, tex_comp;
|
||||
void* tex_data = stbi_load_from_memory((const unsigned char*)png_data, (int)png_size, &tex_x, &tex_y, &tex_comp, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_x, tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_data);
|
||||
stbi_image_free(tex_data);
|
||||
// Load font texture
|
||||
glGenTextures(1, &fontTex);
|
||||
glBindTexture(GL_TEXTURE_2D, fontTex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
#if 1
|
||||
// Default font (embedded in code)
|
||||
const void* png_data;
|
||||
unsigned int png_size;
|
||||
ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size);
|
||||
int tex_x, tex_y, tex_comp;
|
||||
void* tex_data = stbi_load_from_memory((const unsigned char*)png_data, (int)png_size, &tex_x, &tex_y, &tex_comp, 0);
|
||||
IM_ASSERT(tex_data != NULL);
|
||||
#else
|
||||
// Custom font from filesystem
|
||||
io.Font = new ImFont();
|
||||
io.Font->LoadFromFile("../../extra_fonts/mplus-2m-medium_18.fnt");
|
||||
IM_ASSERT(io.Font->IsLoaded());
|
||||
|
||||
int tex_x, tex_y, tex_comp;
|
||||
void* tex_data = stbi_load("../../extra_fonts/mplus-2m-medium_18.png", &tex_x, &tex_y, &tex_comp, 0);
|
||||
IM_ASSERT(tex_data != NULL);
|
||||
|
||||
// Automatically find white pixel from the texture we just loaded
|
||||
// (io.Font->TexUvForWhite needs to contains UV coordinates pointing to a white pixel in order to render solid objects)
|
||||
for (int tex_data_off = 0; tex_data_off < tex_x*tex_y; tex_data_off++)
|
||||
if (((unsigned int*)tex_data)[tex_data_off] == 0xffffffff)
|
||||
{
|
||||
io.Font->TexUvForWhite = ImVec2((float)(tex_data_off % tex_x)/(tex_x), (float)(tex_data_off / tex_x)/(tex_y));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_x, tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_data);
|
||||
stbi_image_free(tex_data);
|
||||
}
|
||||
|
||||
void UpdateImGui()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Setup timestep
|
||||
static double time = 0.0f;
|
||||
const double current_time = glfwGetTime();
|
||||
io.DeltaTime = (float)(current_time - time);
|
||||
time = current_time;
|
||||
// Setup time step
|
||||
static double time = 0.0f;
|
||||
const double current_time = glfwGetTime();
|
||||
io.DeltaTime = (float)(current_time - time);
|
||||
time = current_time;
|
||||
|
||||
// Setup inputs
|
||||
// (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents())
|
||||
double mouse_x, mouse_y;
|
||||
glfwGetCursorPos(window, &mouse_x, &mouse_y);
|
||||
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
|
||||
io.MouseDown[0] = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) != 0;
|
||||
io.MouseDown[1] = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) != 0;
|
||||
// Setup inputs
|
||||
// (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents())
|
||||
double mouse_x, mouse_y;
|
||||
glfwGetCursorPos(window, &mouse_x, &mouse_y);
|
||||
io.MousePos = ImVec2((float)mouse_x * mousePosScale.x, (float)mouse_y * mousePosScale.y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
|
||||
io.MouseDown[0] = mousePressed[0] || glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||
io.MouseDown[1] = mousePressed[1] || glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) != 0;
|
||||
|
||||
// Start the frame
|
||||
ImGui::NewFrame();
|
||||
// Start the frame
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
// Application code
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
InitGL();
|
||||
InitImGui();
|
||||
InitGL();
|
||||
InitImGui();
|
||||
|
||||
while (!glfwWindowShouldClose(window))
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.MouseWheel = 0;
|
||||
glfwPollEvents();
|
||||
UpdateImGui();
|
||||
while (!glfwWindowShouldClose(window))
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
mousePressed[0] = mousePressed[1] = false;
|
||||
glfwPollEvents();
|
||||
UpdateImGui();
|
||||
|
||||
// Create a simple window
|
||||
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
|
||||
static bool show_test_window = true;
|
||||
static bool show_another_window = false;
|
||||
static float f;
|
||||
ImGui::Text("Hello, world!");
|
||||
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
|
||||
show_test_window ^= ImGui::Button("Test Window");
|
||||
show_another_window ^= ImGui::Button("Another Window");
|
||||
static bool show_test_window = true;
|
||||
static bool show_another_window = false;
|
||||
|
||||
// Calculate and show framerate
|
||||
static float ms_per_frame[120] = { 0 };
|
||||
static int ms_per_frame_idx = 0;
|
||||
static float ms_per_frame_accum = 0.0f;
|
||||
ms_per_frame_accum -= ms_per_frame[ms_per_frame_idx];
|
||||
ms_per_frame[ms_per_frame_idx] = ImGui::GetIO().DeltaTime * 1000.0f;
|
||||
ms_per_frame_accum += ms_per_frame[ms_per_frame_idx];
|
||||
ms_per_frame_idx = (ms_per_frame_idx + 1) % 120;
|
||||
const float ms_per_frame_avg = ms_per_frame_accum / 120;
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ms_per_frame_avg, 1000.0f / ms_per_frame_avg);
|
||||
// 1. Show a simple window
|
||||
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
|
||||
{
|
||||
static float f;
|
||||
ImGui::Text("Hello, world!");
|
||||
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
|
||||
show_test_window ^= ImGui::Button("Test Window");
|
||||
show_another_window ^= ImGui::Button("Another Window");
|
||||
|
||||
// Show the ImGui test window
|
||||
// Most of user example code is in ImGui::ShowTestWindow()
|
||||
if (show_test_window)
|
||||
{
|
||||
ImGui::SetNewWindowDefaultPos(ImVec2(650, 20)); // Normally user code doesn't need/want to call it because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly!
|
||||
ImGui::ShowTestWindow(&show_test_window);
|
||||
}
|
||||
// Calculate and show frame rate
|
||||
static float ms_per_frame[120] = { 0 };
|
||||
static int ms_per_frame_idx = 0;
|
||||
static float ms_per_frame_accum = 0.0f;
|
||||
ms_per_frame_accum -= ms_per_frame[ms_per_frame_idx];
|
||||
ms_per_frame[ms_per_frame_idx] = ImGui::GetIO().DeltaTime * 1000.0f;
|
||||
ms_per_frame_accum += ms_per_frame[ms_per_frame_idx];
|
||||
ms_per_frame_idx = (ms_per_frame_idx + 1) % 120;
|
||||
const float ms_per_frame_avg = ms_per_frame_accum / 120;
|
||||
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", ms_per_frame_avg, 1000.0f / ms_per_frame_avg);
|
||||
}
|
||||
|
||||
// Show another simple window
|
||||
if (show_another_window)
|
||||
{
|
||||
ImGui::Begin("Another Window", &show_another_window, ImVec2(200,100));
|
||||
ImGui::Text("Hello");
|
||||
ImGui::End();
|
||||
}
|
||||
// 2. Show another simple window, this time using an explicit Begin/End pair
|
||||
if (show_another_window)
|
||||
{
|
||||
ImGui::Begin("Another Window", &show_another_window, ImVec2(200,100));
|
||||
ImGui::Text("Hello");
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// Rendering
|
||||
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
|
||||
glClearColor(0.8f, 0.6f, 0.6f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui::Render();
|
||||
glfwSwapBuffers(window);
|
||||
}
|
||||
// 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowTestWindow()
|
||||
if (show_test_window)
|
||||
{
|
||||
ImGui::SetNewWindowDefaultPos(ImVec2(650, 20)); // Normally user code doesn't need/want to call this, because positions are saved in .ini file. Here we just want to make the demo initial state a bit more friendly!
|
||||
ImGui::ShowTestWindow(&show_test_window);
|
||||
}
|
||||
|
||||
ImGui::Shutdown();
|
||||
glfwTerminate();
|
||||
return 0;
|
||||
// Rendering
|
||||
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
|
||||
glClearColor(0.8f, 0.6f, 0.6f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui::Render();
|
||||
glfwSwapBuffers(window);
|
||||
}
|
||||
|
||||
ImGui::Shutdown();
|
||||
glfwTerminate();
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opengl_example", "opengl_example.vcxproj", "{9CDA7840-B7A5-496D-A527-E95571496D18}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{9CDA7840-B7A5-496D-A527-E95571496D18}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{9CDA7840-B7A5-496D-A527-E95571496D18}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{9CDA7840-B7A5-496D-A527-E95571496D18}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{9CDA7840-B7A5-496D-A527-E95571496D18}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -46,7 +46,7 @@
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)\glfw\lib-msvc100;$(SolutionDir)\glew\lib\Release\Win32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>opengl32.lib;glfw3.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>opengl32.lib;imm32.lib;glfw3.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SubSystem>NotSet</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@ -63,7 +63,7 @@
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)\glfw\lib-msvc100;$(SolutionDir)\glew\lib\Release\Win32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>opengl32.lib;glfw3.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>opengl32.lib;imm32.lib;glfw3.lib;glew32s.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<SubSystem>NotSet</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
@ -75,7 +75,7 @@
|
||||
<ClInclude Include="..\..\imconfig.h" />
|
||||
<ClInclude Include="..\..\imgui.h" />
|
||||
<ClInclude Include="..\..\stb_textedit.h" />
|
||||
<ClInclude Include="stb_image.h" />
|
||||
<ClInclude Include="..\shared\stb_image.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\LICENSE" />
|
||||
|
@ -18,9 +18,6 @@
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stb_image.h">
|
||||
<Filter>sources</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\imconfig.h">
|
||||
<Filter>imgui</Filter>
|
||||
</ClInclude>
|
||||
@ -30,6 +27,9 @@
|
||||
<ClInclude Include="..\..\stb_textedit.h">
|
||||
<Filter>imgui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\shared\stb_image.h">
|
||||
<Filter>sources</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\LICENSE">
|
||||
|
3
examples/shared/README.txt
Normal file
@ -0,0 +1,3 @@
|
||||
stb_image.h is used to load the PNG texture data by
|
||||
opengl_example
|
||||
directx11_example
|
@ -1,4 +1,4 @@
|
||||
/* stb_image - v1.43 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c
|
||||
/* stb_image - v1.46 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c
|
||||
when you control the images you're loading
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
avoid problematic images and only need the trivial interface
|
||||
|
||||
JPEG baseline (no JPEG progressive)
|
||||
PNG 8-bit-per-channel only
|
||||
PNG 1/2/4/8-bit-per-channel (16 bpc not supported)
|
||||
|
||||
TGA (not sure what subset, if a subset)
|
||||
BMP non-1bpp, non-RLE
|
||||
@ -28,11 +28,15 @@
|
||||
- overridable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD)
|
||||
|
||||
Latest revisions:
|
||||
1.xx (2014-09-26) 1/2/4-bit PNG support (both grayscale and paletted)
|
||||
1.46 (2014-08-26) fix broken tRNS chunk in non-paletted PNG
|
||||
1.45 (2014-08-16) workaround MSVC-ARM internal compiler error by wrapping malloc
|
||||
1.44 (2014-08-07) warnings
|
||||
1.43 (2014-07-15) fix MSVC-only bug in 1.42
|
||||
1.42 (2014-07-09) no _CRT_SECURE_NO_WARNINGS; error-path fixes; STBI_ASSERT
|
||||
1.41 (2014-06-25) fix search&replace that messed up comments/error messages
|
||||
1.40 (2014-06-22) gcc warning
|
||||
1.39 (2014-06-15) TGA optimization fix, multiple BMP fixes
|
||||
1.39 (2014-06-15) TGA optimization bugfix, multiple BMP fixes
|
||||
1.38 (2014-06-06) suppress MSVC run-time warnings, fix accidental rename of 'skip'
|
||||
1.37 (2014-06-04) remove duplicate typedef
|
||||
1.36 (2014-06-03) converted to header file, allow reading incorrect iphoned-images without iphone flag
|
||||
@ -60,17 +64,19 @@
|
||||
James "moose2000" Brown (iPhone PNG) David Woo
|
||||
Ben "Disch" Wenger (io callbacks) Roy Eltham
|
||||
Martin "SpartanJ" Golini Luke Graham
|
||||
Thomas Ruf
|
||||
Omar Cornut (1/2/4-bit png) Thomas Ruf
|
||||
John Bartholomew
|
||||
Optimizations & bugfixes Ken Hamada
|
||||
Fabian "ryg" Giesen Cort Stratton
|
||||
Arseny Kapoulkine Blazej Dariusz Roszkowski
|
||||
Thibault Reuille
|
||||
If your name should be here but Paul Du Bois
|
||||
isn't, let Sean know. Guillaume George
|
||||
Paul Du Bois
|
||||
Guillaume George
|
||||
Jerry Jansson
|
||||
Hayaki Saito
|
||||
Johan Duparc
|
||||
If your name should be here but Hayaki Saito
|
||||
isn't, let Sean know. Johan Duparc
|
||||
Ronny Chevalier
|
||||
Michal Cichon
|
||||
*/
|
||||
|
||||
#ifndef STBI_INCLUDE_STB_IMAGE_H
|
||||
@ -525,6 +531,11 @@ static int stbi__err(const char *str)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *stbi__malloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
// stbi__err - error
|
||||
// stbi__errpf - error returning pointer to float
|
||||
// stbi__errpuc - error returning pointer to unsigned char
|
||||
@ -577,11 +588,11 @@ static unsigned char *stbi_load_main(stbi__context *s, int *x, int *y, int *comp
|
||||
FILE *stbi__fopen(char const *filename, char const *mode)
|
||||
{
|
||||
FILE *f;
|
||||
#if _MSC_VER >= 1400
|
||||
if (0 != fopen_s(&f, filename, "rb"))
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
if (0 != fopen_s(&f, filename, mode))
|
||||
f=0;
|
||||
#else
|
||||
f = fopen(filename, "rb");
|
||||
f = fopen(filename, mode);
|
||||
#endif
|
||||
return f;
|
||||
}
|
||||
@ -756,7 +767,7 @@ static void stbi__refill_buffer(stbi__context *s)
|
||||
int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);
|
||||
if (n == 0) {
|
||||
// at end of file, treat same as if from memory, but need to handle case
|
||||
// where s->img_buffer isn't pointing to safe memory, stbi__err.g. 0-byte file
|
||||
// where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file
|
||||
s->read_from_callbacks = 0;
|
||||
s->img_buffer = s->buffer_start;
|
||||
s->img_buffer_end = s->buffer_start+1;
|
||||
@ -854,7 +865,7 @@ static stbi__uint32 stbi__get32le(stbi__context *s)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// generic converter from built-in img_n to req_comp
|
||||
// individual types do this automatically as much as possible (stbi__err.g. jpeg
|
||||
// individual types do this automatically as much as possible (e.g. jpeg
|
||||
// does all cases internally since it needs to colorspace convert anyway,
|
||||
// and it never has alpha, so very few cases ). png can automatically
|
||||
// interleave an alpha=255 channel, but falls back to this for other cases
|
||||
@ -875,7 +886,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
|
||||
if (req_comp == img_n) return data;
|
||||
STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
|
||||
|
||||
good = (unsigned char *) malloc(req_comp * x * y);
|
||||
good = (unsigned char *) stbi__malloc(req_comp * x * y);
|
||||
if (good == NULL) {
|
||||
free(data);
|
||||
return stbi__errpuc("outofmem", "Out of memory");
|
||||
@ -915,7 +926,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
|
||||
static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
|
||||
{
|
||||
int i,k,n;
|
||||
float *output = (float *) malloc(x * y * comp * sizeof(float));
|
||||
float *output = (float *) stbi__malloc(x * y * comp * sizeof(float));
|
||||
if (output == NULL) { free(data); return stbi__errpf("outofmem", "Out of memory"); }
|
||||
// compute number of non-alpha components
|
||||
if (comp & 1) n = comp; else n = comp-1;
|
||||
@ -933,7 +944,7 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
|
||||
static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp)
|
||||
{
|
||||
int i,k,n;
|
||||
stbi_uc *output = (stbi_uc *) malloc(x * y * comp);
|
||||
stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp);
|
||||
if (output == NULL) { free(data); return stbi__errpuc("outofmem", "Out of memory"); }
|
||||
// compute number of non-alpha components
|
||||
if (comp & 1) n = comp; else n = comp-1;
|
||||
@ -1601,16 +1612,16 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
|
||||
z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;
|
||||
|
||||
for (i=0; i < s->img_n; ++i) {
|
||||
// number of effective pixels (stbi__err.g. for non-interleaved MCU)
|
||||
// number of effective pixels (e.g. for non-interleaved MCU)
|
||||
z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;
|
||||
z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;
|
||||
// to simplify generation, we'll allocate enough memory to decode
|
||||
// the bogus oversized data from using interleaved MCUs and their
|
||||
// big blocks (stbi__err.g. a 16x16 iMCU on an image of width 33); we won't
|
||||
// big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
|
||||
// discard the extra data until colorspace conversion
|
||||
z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;
|
||||
z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;
|
||||
z->img_comp[i].raw_data = malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15);
|
||||
z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15);
|
||||
if (z->img_comp[i].raw_data == NULL) {
|
||||
for(--i; i >= 0; --i) {
|
||||
free(z->img_comp[i].raw_data);
|
||||
@ -1626,7 +1637,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// use comparisons since in some cases we handle more than one case (stbi__err.g. stbi__SOF)
|
||||
// use comparisons since in some cases we handle more than one case (e.g. stbi__SOF)
|
||||
#define stbi__DNL(x) ((x) == 0xdc)
|
||||
#define stbi__SOI(x) ((x) == 0xd8)
|
||||
#define stbi__EOI(x) ((x) == 0xd9)
|
||||
@ -1875,7 +1886,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
|
||||
|
||||
// allocate line buffer big enough for upsampling off the edges
|
||||
// with upsample factor of 4
|
||||
z->img_comp[k].linebuf = (stbi_uc *) malloc(z->s->img_x + 3);
|
||||
z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3);
|
||||
if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
|
||||
|
||||
r->hs = z->img_h_max / z->img_comp[k].h;
|
||||
@ -1893,7 +1904,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
|
||||
}
|
||||
|
||||
// can't error after this so, this is safe
|
||||
output = (stbi_uc *) malloc(n * z->s->img_x * z->s->img_y + 1);
|
||||
output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1);
|
||||
if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
|
||||
|
||||
// now go ahead and resample
|
||||
@ -2015,7 +2026,7 @@ stbi_inline static int stbi__bit_reverse(int v, int bits)
|
||||
{
|
||||
STBI_ASSERT(bits <= 16);
|
||||
// to bit reverse n bits, reverse 16 and shift
|
||||
// stbi__err.g. 11 bits, bit reverse and shift away 5
|
||||
// e.g. 11 bits, bit reverse and shift away 5
|
||||
return stbi__bitreverse16(v) >> (16-bits);
|
||||
}
|
||||
|
||||
@ -2338,7 +2349,7 @@ static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse
|
||||
STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)
|
||||
{
|
||||
stbi__zbuf a;
|
||||
char *p = (char *) malloc(initial_size);
|
||||
char *p = (char *) stbi__malloc(initial_size);
|
||||
if (p == NULL) return NULL;
|
||||
a.zbuffer = (stbi_uc *) buffer;
|
||||
a.zbuffer_end = (stbi_uc *) buffer + len;
|
||||
@ -2359,7 +2370,7 @@ STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)
|
||||
STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)
|
||||
{
|
||||
stbi__zbuf a;
|
||||
char *p = (char *) malloc(initial_size);
|
||||
char *p = (char *) stbi__malloc(initial_size);
|
||||
if (p == NULL) return NULL;
|
||||
a.zbuffer = (stbi_uc *) buffer;
|
||||
a.zbuffer_end = (stbi_uc *) buffer + len;
|
||||
@ -2386,7 +2397,7 @@ STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer
|
||||
STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)
|
||||
{
|
||||
stbi__zbuf a;
|
||||
char *p = (char *) malloc(16384);
|
||||
char *p = (char *) stbi__malloc(16384);
|
||||
if (p == NULL) return NULL;
|
||||
a.zbuffer = (stbi_uc *) buffer;
|
||||
a.zbuffer_end = (stbi_uc *) buffer+len;
|
||||
@ -2477,89 +2488,144 @@ static int stbi__paeth(int a, int b, int c)
|
||||
#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings
|
||||
|
||||
// create the png data from post-deflated data
|
||||
static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y)
|
||||
static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
|
||||
{
|
||||
stbi__context *s = a->s;
|
||||
stbi__uint32 i,j,stride = x*out_n;
|
||||
stbi__uint32 img_len;
|
||||
int k;
|
||||
int img_n = s->img_n; // copy it into a local for later
|
||||
stbi_uc* line8 = NULL; // point into raw when depth==8 else temporary local buffer
|
||||
|
||||
STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);
|
||||
a->out = (stbi_uc *) malloc(x * y * out_n);
|
||||
a->out = (stbi_uc *) stbi__malloc(x * y * out_n);
|
||||
if (!a->out) return stbi__err("outofmem", "Out of memory");
|
||||
|
||||
img_len = ((((img_n * x * depth) + 7) >> 3) + 1) * y;
|
||||
if (s->img_x == x && s->img_y == y) {
|
||||
if (raw_len != (img_n * x + 1) * y) return stbi__err("not enough pixels","Corrupt PNG");
|
||||
if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG");
|
||||
} else { // interlaced:
|
||||
if (raw_len < (img_n * x + 1) * y) return stbi__err("not enough pixels","Corrupt PNG");
|
||||
if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
|
||||
}
|
||||
|
||||
if (depth != 8) {
|
||||
line8 = (stbi_uc *) stbi__malloc((x+7) * out_n); // allocate buffer for one scanline
|
||||
if (!line8) return stbi__err("outofmem", "Out of memory");
|
||||
}
|
||||
|
||||
for (j=0; j < y; ++j) {
|
||||
stbi_uc *in;
|
||||
stbi_uc *cur = a->out + stride*j;
|
||||
stbi_uc *prior = cur - stride;
|
||||
int filter = *raw++;
|
||||
if (filter > 4) return stbi__err("invalid filter","Corrupt PNG");
|
||||
if (filter > 4) {
|
||||
if (depth != 8) free(line8);
|
||||
return stbi__err("invalid filter","Corrupt PNG");
|
||||
}
|
||||
|
||||
if (depth == 8) {
|
||||
in = raw;
|
||||
raw += x*img_n;
|
||||
}
|
||||
else {
|
||||
// unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit
|
||||
// png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop
|
||||
in = line8;
|
||||
stbi_uc* decode_out = line8;
|
||||
stbi_uc scale = (color == 0) ? 0xFF/((1<<depth)-1) : 1; // scale grayscale values to 0..255 range
|
||||
if (depth == 4) {
|
||||
for (k=x*img_n; k >= 1; k-=2, raw++) {
|
||||
*decode_out++ = scale * ((*raw >> 4) );
|
||||
*decode_out++ = scale * ((*raw ) & 0x0f);
|
||||
}
|
||||
} else if (depth == 2) {
|
||||
for (k=x*img_n; k >= 1; k-=4, raw++) {
|
||||
*decode_out++ = scale * ((*raw >> 6) );
|
||||
*decode_out++ = scale * ((*raw >> 4) & 0x03);
|
||||
*decode_out++ = scale * ((*raw >> 2) & 0x03);
|
||||
*decode_out++ = scale * ((*raw ) & 0x03);
|
||||
}
|
||||
} else if (depth == 1) {
|
||||
for (k=x*img_n; k >= 1; k-=8, raw++) {
|
||||
*decode_out++ = scale * ((*raw >> 7) );
|
||||
*decode_out++ = scale * ((*raw >> 6) & 0x01);
|
||||
*decode_out++ = scale * ((*raw >> 5) & 0x01);
|
||||
*decode_out++ = scale * ((*raw >> 4) & 0x01);
|
||||
*decode_out++ = scale * ((*raw >> 3) & 0x01);
|
||||
*decode_out++ = scale * ((*raw >> 2) & 0x01);
|
||||
*decode_out++ = scale * ((*raw >> 1) & 0x01);
|
||||
*decode_out++ = scale * ((*raw ) & 0x01);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if first row, use special filter that doesn't sample previous row
|
||||
if (j == 0) filter = first_row_filter[filter];
|
||||
|
||||
// handle first pixel explicitly
|
||||
for (k=0; k < img_n; ++k) {
|
||||
switch (filter) {
|
||||
case STBI__F_none : cur[k] = raw[k]; break;
|
||||
case STBI__F_sub : cur[k] = raw[k]; break;
|
||||
case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
|
||||
case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
|
||||
case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
|
||||
case STBI__F_avg_first : cur[k] = raw[k]; break;
|
||||
case STBI__F_paeth_first: cur[k] = raw[k]; break;
|
||||
case STBI__F_none : cur[k] = in[k]; break;
|
||||
case STBI__F_sub : cur[k] = in[k]; break;
|
||||
case STBI__F_up : cur[k] = STBI__BYTECAST(in[k] + prior[k]); break;
|
||||
case STBI__F_avg : cur[k] = STBI__BYTECAST(in[k] + (prior[k]>>1)); break;
|
||||
case STBI__F_paeth : cur[k] = STBI__BYTECAST(in[k] + stbi__paeth(0,prior[k],0)); break;
|
||||
case STBI__F_avg_first : cur[k] = in[k]; break;
|
||||
case STBI__F_paeth_first: cur[k] = in[k]; break;
|
||||
}
|
||||
}
|
||||
if (img_n != out_n) cur[img_n] = 255;
|
||||
raw += img_n;
|
||||
in += img_n;
|
||||
cur += out_n;
|
||||
prior += out_n;
|
||||
// this is a little gross, so that we don't switch per-pixel or per-component
|
||||
if (img_n == out_n) {
|
||||
#define CASE(f) \
|
||||
case f: \
|
||||
for (i=x-1; i >= 1; --i, raw+=img_n,cur+=img_n,prior+=img_n) \
|
||||
for (i=x-1; i >= 1; --i, in+=img_n,cur+=img_n,prior+=img_n) \
|
||||
for (k=0; k < img_n; ++k)
|
||||
switch (filter) {
|
||||
CASE(STBI__F_none) cur[k] = raw[k]; break;
|
||||
CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-img_n]); break;
|
||||
CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
|
||||
CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-img_n])>>1)); break;
|
||||
CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-img_n],prior[k],prior[k-img_n])); break;
|
||||
CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-img_n] >> 1)); break;
|
||||
CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-img_n],0,0)); break;
|
||||
CASE(STBI__F_none) cur[k] = in[k]; break;
|
||||
CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(in[k] + cur[k-img_n]); break;
|
||||
CASE(STBI__F_up) cur[k] = STBI__BYTECAST(in[k] + prior[k]); break;
|
||||
CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(in[k] + ((prior[k] + cur[k-img_n])>>1)); break;
|
||||
CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(in[k] + stbi__paeth(cur[k-img_n],prior[k],prior[k-img_n])); break;
|
||||
CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(in[k] + (cur[k-img_n] >> 1)); break;
|
||||
CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(in[k] + stbi__paeth(cur[k-img_n],0,0)); break;
|
||||
}
|
||||
#undef CASE
|
||||
} else {
|
||||
STBI_ASSERT(img_n+1 == out_n);
|
||||
#define CASE(f) \
|
||||
case f: \
|
||||
for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \
|
||||
for (i=x-1; i >= 1; --i, cur[img_n]=255,in+=img_n,cur+=out_n,prior+=out_n) \
|
||||
for (k=0; k < img_n; ++k)
|
||||
switch (filter) {
|
||||
CASE(STBI__F_none) cur[k] = raw[k]; break;
|
||||
CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-out_n]); break;
|
||||
CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
|
||||
CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-out_n])>>1)); break;
|
||||
CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break;
|
||||
CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-out_n] >> 1)); break;
|
||||
CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],0,0)); break;
|
||||
CASE(STBI__F_none) cur[k] = in[k]; break;
|
||||
CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(in[k] + cur[k-out_n]); break;
|
||||
CASE(STBI__F_up) cur[k] = STBI__BYTECAST(in[k] + prior[k]); break;
|
||||
CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(in[k] + ((prior[k] + cur[k-out_n])>>1)); break;
|
||||
CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(in[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break;
|
||||
CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(in[k] + (cur[k-out_n] >> 1)); break;
|
||||
CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(in[k] + stbi__paeth(cur[k-out_n],0,0)); break;
|
||||
}
|
||||
#undef CASE
|
||||
}
|
||||
}
|
||||
|
||||
if (depth != 8) free(line8);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int stbi__create_png_image(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, int interlaced)
|
||||
static int stbi__create_png_image(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, int depth, int color, int interlaced)
|
||||
{
|
||||
stbi_uc *final;
|
||||
int p;
|
||||
if (!interlaced)
|
||||
return stbi__create_png_image_raw(a, raw, raw_len, out_n, a->s->img_x, a->s->img_y);
|
||||
return stbi__create_png_image_raw(a, raw, raw_len, out_n, a->s->img_x, a->s->img_y, depth, color);
|
||||
|
||||
// de-interlacing
|
||||
final = (stbi_uc *) malloc(a->s->img_x * a->s->img_y * out_n);
|
||||
final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n);
|
||||
for (p=0; p < 7; ++p) {
|
||||
int xorig[] = { 0,4,0,2,0,1,0 };
|
||||
int yorig[] = { 0,0,4,0,2,0,1 };
|
||||
@ -2570,7 +2636,8 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_l
|
||||
x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];
|
||||
y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];
|
||||
if (x && y) {
|
||||
if (!stbi__create_png_image_raw(a, raw, raw_len, out_n, x, y)) {
|
||||
stbi__uint32 img_len = ((((out_n * x * depth) + 7) >> 3) + 1) * y;
|
||||
if (!stbi__create_png_image_raw(a, raw, raw_len, out_n, x, y, depth, color)) {
|
||||
free(final);
|
||||
return 0;
|
||||
}
|
||||
@ -2579,8 +2646,8 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_l
|
||||
memcpy(final + (j*yspc[p]+yorig[p])*a->s->img_x*out_n + (i*xspc[p]+xorig[p])*out_n,
|
||||
a->out + (j*x+i)*out_n, out_n);
|
||||
free(a->out);
|
||||
raw += (x*out_n+1)*y;
|
||||
raw_len -= (x*out_n+1)*y;
|
||||
raw += img_len;
|
||||
raw_len -= img_len;
|
||||
}
|
||||
}
|
||||
a->out = final;
|
||||
@ -2618,7 +2685,7 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int
|
||||
stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;
|
||||
stbi_uc *p, *temp_out, *orig = a->out;
|
||||
|
||||
p = (stbi_uc *) malloc(pixel_count * pal_img_n);
|
||||
p = (stbi_uc *) stbi__malloc(pixel_count * pal_img_n);
|
||||
if (p == NULL) return stbi__err("outofmem", "Out of memory");
|
||||
|
||||
// between here and free(out) below, exitting would leak
|
||||
@ -2710,7 +2777,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
|
||||
stbi_uc palette[1024], pal_img_n=0;
|
||||
stbi_uc has_trans=0, tc[3];
|
||||
stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;
|
||||
int first=1,k,interlace=0, is_iphone=0;
|
||||
int first=1,k,interlace=0, color=0, depth=0, is_iphone=0;
|
||||
stbi__context *s = z->s;
|
||||
|
||||
z->expanded = NULL;
|
||||
@ -2729,13 +2796,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
|
||||
stbi__skip(s, c.length);
|
||||
break;
|
||||
case PNG_TYPE('I','H','D','R'): {
|
||||
int depth,color,comp,filter;
|
||||
int comp,filter;
|
||||
if (!first) return stbi__err("multiple IHDR","Corrupt PNG");
|
||||
first = 0;
|
||||
if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG");
|
||||
s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
|
||||
s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
|
||||
depth = stbi__get8(s); if (depth != 8) return stbi__err("8bit only","PNG not supported: 8-bit only");
|
||||
depth = stbi__get8(s); if (depth != 1 && depth != 2 && depth != 4 && depth != 8) return stbi__err("1/2/4/8-bit only","PNG not supported: 1/2/4/8-bit only");
|
||||
color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG");
|
||||
if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG");
|
||||
comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG");
|
||||
@ -2819,7 +2886,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
|
||||
s->img_out_n = s->img_n+1;
|
||||
else
|
||||
s->img_out_n = s->img_n;
|
||||
if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, interlace)) return 0;
|
||||
if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, depth, color, interlace)) return 0;
|
||||
if (has_trans)
|
||||
if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;
|
||||
if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)
|
||||
@ -2872,7 +2939,7 @@ static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req
|
||||
}
|
||||
*x = p->s->img_x;
|
||||
*y = p->s->img_y;
|
||||
if (n) *n = p->s->img_n;
|
||||
if (n) *n = p->s->img_out_n;
|
||||
}
|
||||
free(p->out); p->out = NULL;
|
||||
free(p->expanded); p->expanded = NULL;
|
||||
@ -3074,7 +3141,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
|
||||
target = req_comp;
|
||||
else
|
||||
target = s->img_n; // if they want monochrome, we'll post-convert
|
||||
out = (stbi_uc *) malloc(target * s->img_x * s->img_y);
|
||||
out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y);
|
||||
if (!out) return stbi__errpuc("outofmem", "Out of memory");
|
||||
if (bpp < 16) {
|
||||
int z=0;
|
||||
@ -3303,7 +3370,7 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
|
||||
*y = tga_height;
|
||||
if (comp) *comp = tga_comp;
|
||||
|
||||
tga_data = (unsigned char*)malloc( tga_width * tga_height * tga_comp );
|
||||
tga_data = (unsigned char*)stbi__malloc( tga_width * tga_height * tga_comp );
|
||||
if (!tga_data) return stbi__errpuc("outofmem", "Out of memory");
|
||||
|
||||
// skip to the data's starting position (offset usually = 0)
|
||||
@ -3322,7 +3389,7 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
|
||||
// any data to skip? (offset usually = 0)
|
||||
stbi__skip(s, tga_palette_start );
|
||||
// load the palette
|
||||
tga_palette = (unsigned char*)malloc( tga_palette_len * tga_palette_bits / 8 );
|
||||
tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_palette_bits / 8 );
|
||||
if (!tga_palette) {
|
||||
free(tga_data);
|
||||
return stbi__errpuc("outofmem", "Out of memory");
|
||||
@ -3513,7 +3580,7 @@ static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int
|
||||
return stbi__errpuc("bad compression", "PSD has an unknown compression format");
|
||||
|
||||
// Create the destination image.
|
||||
out = (stbi_uc *) malloc(4 * w*h);
|
||||
out = (stbi_uc *) stbi__malloc(4 * w*h);
|
||||
if (!out) return stbi__errpuc("outofmem", "Out of memory");
|
||||
pixelCount = w*h;
|
||||
|
||||
@ -3798,7 +3865,7 @@ static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int re
|
||||
stbi__get16be(s); //skip `pad'
|
||||
|
||||
// intermediate buffer is RGBA
|
||||
result = (stbi_uc *) malloc(x*y*4);
|
||||
result = (stbi_uc *) stbi__malloc(x*y*4);
|
||||
memset(result, 0xff, x*y*4);
|
||||
|
||||
if (!stbi__pic_load_core(s,x,y,comp, result)) {
|
||||
@ -4049,14 +4116,14 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
|
||||
|
||||
if (g->out == 0) {
|
||||
if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header
|
||||
g->out = (stbi_uc *) malloc(4 * g->w * g->h);
|
||||
g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
|
||||
if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory");
|
||||
stbi__fill_gif_background(g);
|
||||
} else {
|
||||
// animated-gif-only path
|
||||
if (((g->eflags & 0x1C) >> 2) == 3) {
|
||||
old_out = g->out;
|
||||
g->out = (stbi_uc *) malloc(4 * g->w * g->h);
|
||||
g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
|
||||
if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory");
|
||||
memcpy(g->out, old_out, g->w*g->h*4);
|
||||
}
|
||||
@ -4279,7 +4346,7 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re
|
||||
if (req_comp == 0) req_comp = 3;
|
||||
|
||||
// Read data
|
||||
hdr_data = (float *) malloc(height * width * req_comp * sizeof(float));
|
||||
hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float));
|
||||
|
||||
// Load image data
|
||||
// image data is stored as some number of sca
|
||||
@ -4318,7 +4385,7 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re
|
||||
len <<= 8;
|
||||
len |= stbi__get8(s);
|
||||
if (len != width) { free(hdr_data); free(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); }
|
||||
if (scanline == NULL) scanline = (stbi_uc *) malloc(width * 4);
|
||||
if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4);
|
||||
|
||||
for (k = 0; k < 4; ++k) {
|
||||
i = 0;
|
||||
@ -4555,6 +4622,12 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
|
||||
|
||||
/*
|
||||
revision history:
|
||||
1.46 (2014-08-26)
|
||||
fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG
|
||||
1.45 (2014-08-16)
|
||||
fix MSVC-ARM internal compiler error by wrapping malloc
|
||||
1.44 (2014-08-07)
|
||||
various warning fixes from Ronny Chevalier
|
||||
1.43 (2014-07-15)
|
||||
fix MSVC-only compiler problem in code changed in 1.42
|
||||
1.42 (2014-07-09)
|
BIN
extra_fonts/ProggyClean.zip
Normal file
BIN
extra_fonts/ProggySmall.zip
Normal file
100
extra_fonts/README.txt
Normal file
@ -0,0 +1,100 @@
|
||||
|
||||
Extra fonts for ImGui.
|
||||
THOSE FONTS ARE OPTIONAL.
|
||||
|
||||
ImGui embeds a copy of 'proggy_clean' that you can use without any external files.
|
||||
Export your own font with bmfont (www.angelcode.com/products/bmfont).
|
||||
|
||||
bmfont reads fonts (.ttf, .fon, etc.) and output a .fnt file and a texture file, e.g:
|
||||
|
||||
proggy_clean.fon --> [bmfont] ---> proggy_clean_13.fnt
|
||||
proggy_clean_13.png
|
||||
|
||||
If you need a free font that supports chinese/japanese characters, you can use the M+ fonts.
|
||||
TTF and sources are availables at http://mplus-fonts.sourceforge.jp/mplus-outline-fonts.
|
||||
This directory include some of the M+ fonts converted by bmfont.
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
Configure bmfont:
|
||||
|
||||
- Export .fnt as Binary
|
||||
- Output .png, 32-bits (or whatever is suitable for your loader/renderer)
|
||||
- Tip: uncheck "Render from TrueType outline" and "Font Smoothing" for best result with non-anti-aliased type fonts.
|
||||
But you can experiment with other settings if you want anti-aliased fonts.
|
||||
- Tip: use pngout.exe (http://advsys.net/ken/utils.htm) to further reduce the file size of .png files
|
||||
All files in this folder have been optimised with pngout.exe
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
(A) Use font data embedded in ImGui
|
||||
|
||||
// Access embedded font data
|
||||
const void* fnt_data; // pointer to FNT data
|
||||
unsigned fnt_size; // size of FNT data
|
||||
const void* png_data; // pointer to PNG data
|
||||
unsigned int png_size; // size of PNG data
|
||||
ImGui::GetDefaultFontData(&fnt_data, &fnt_size, &png_data, &png_size);
|
||||
|
||||
1. Load the .FNT data from 'fnt_data' (NB: this is done for you by default if you don't do anything)
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.Font = new ImFont();
|
||||
io.Font->LoadFromMemory(fnt_data, fnt_size);
|
||||
|
||||
2. Load the .PNG data from 'png_data' into a texture
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
(B) Use fonts from external files
|
||||
|
||||
You need to set io.Font->TexUvForWhite to UV coordinates pointing to a white pixel in the texture.
|
||||
You can either locate a white pixel manually or use code at runtime to find or write one.
|
||||
The OpenGL example include sample code to find a white pixel given an uncompressed 32-bits texture:
|
||||
|
||||
// Automatically find white pixel from the texture we just loaded
|
||||
// (io.Font->TexUvForWhite needs to contains UV coordinates pointing to a white pixel in order to render solid objects)
|
||||
for (int tex_data_off = 0; tex_data_off < tex_x*tex_y; tex_data_off++)
|
||||
if (((unsigned int*)tex_data)[tex_data_off] == 0xffffffff)
|
||||
{
|
||||
io.Font->TexUvForWhite = ImVec2((float)(tex_data_off % tex_x)/(tex_x), (float)(tex_data_off / tex_x)/(tex_y));
|
||||
break;
|
||||
}
|
||||
|
||||
1. Load the .FNT data, e.g.
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// proggy_clean_13 [default]
|
||||
io.Font = new ImFont();
|
||||
io.Font->LoadFromFile("proggy_clean_13.fnt");
|
||||
IM_ASSERT(io.Font->IsLoaded());
|
||||
io.Font->TexUvForWhite = ImVec2(0.0f/256.0f,0.0f/128);
|
||||
io.Font->DisplayOffset = ImVec2(0.0f, +1.0f);
|
||||
|
||||
// proggy_small_12
|
||||
io.Font = new ImFont();
|
||||
io.Font->LoadFromFile("proggy_small_12.fnt");
|
||||
IM_ASSERT(io.Font->IsLoaded());
|
||||
io.Font->TexUvForWhite = ImVec2(84.0f/256.0f,20.0f/64);
|
||||
io.Font->DisplayOffset = ImVec2(0.0f, +2.0f);
|
||||
|
||||
// proggy_small_14
|
||||
io.Font = new ImFont();
|
||||
io.Font->LoadFromFile("proggy_small_14.fnt");
|
||||
IM_ASSERT(io.Font->IsLoaded());
|
||||
io.Font->TexUvForWhite = ImVec2(84.0f/256.0f,20.0f/64);
|
||||
io.Font->DisplayOffset = ImVec2(0.0f, +3.0f);
|
||||
|
||||
// courier_new_16
|
||||
io.Font->LoadFromFile("courier_new_16.fnt");
|
||||
io.Font->TexUvForWhite = ImVec2(1.0f/256.0f,4.0f/128);
|
||||
|
||||
// courier_new_18
|
||||
io.Font->LoadFromFile("courier_new_18.fnt");
|
||||
io.Font->TexUvForWhite = ImVec2(4.0f/256.0f,5.0f/256);
|
||||
|
||||
|
||||
2. Load the matching .PNG data into a texture
|
||||
|
||||
//-----------------------------------------------------------------------------
|
BIN
extra_fonts/courier_new_16.fnt
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
extra_fonts/courier_new_16.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
extra_fonts/courier_new_18.fnt
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
extra_fonts/courier_new_18.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
extra_fonts/mplus-2m-medium_18.fnt
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
extra_fonts/mplus-2m-medium_18.png
Normal file
After Width: | Height: | Size: 284 KiB |
BIN
extra_fonts/proggy_clean_13.fnt
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
extra_fonts/proggy_clean_13.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
extra_fonts/proggy_small_12.fnt
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
extra_fonts/proggy_small_12.png
Normal file
After Width: | Height: | Size: 949 B |
BIN
extra_fonts/proggy_small_14.fnt
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
extra_fonts/proggy_small_14.png
Normal file
After Width: | Height: | Size: 949 B |
35
imconfig.h
@ -1,41 +1,44 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// USER IMPLEMENTATION
|
||||
// This file contains compile-time options for ImGui.
|
||||
// Other options (memory allocation overrides, callbacks, etc.) can be set at runtime via the ImGuiIO structure - ImGui::GetIO().
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//---- Define your own ImVector<> type if you don't want to use the provided implementation defined in imgui.h
|
||||
//#include <vector>
|
||||
//#define ImVector std::vector
|
||||
//#define ImVector MyVector
|
||||
//#define ImVector std::vector
|
||||
//#define ImVector MyVector
|
||||
|
||||
//---- Define assertion handler. Defaults to calling assert().
|
||||
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||
|
||||
//---- Don't implement default clipboard handlers for Windows (so as not to link with OpenClipboard(), etc.)
|
||||
//---- Don't implement default clipboard handlers for Windows (so as not to link with OpenClipboard() and others Win32 functions)
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS
|
||||
|
||||
//---- If you are loading a custom font, ImGui expect to find a pure white pixel at (0,0)
|
||||
// Change it's UV coordinate here if you can't have a white pixel at (0,0)
|
||||
//#define IMGUI_FONT_TEX_UV_FOR_WHITE ImVec2(0.f/256.f,0.f/256.f)
|
||||
//---- Include imgui_user.inl at the end of imgui.cpp so you can include code that extends ImGui using its private data/functions.
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_INL
|
||||
|
||||
//---- Define implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4.
|
||||
/*
|
||||
#define IM_VEC2_CLASS_EXTRA \
|
||||
ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
|
||||
operator MyVec2() const { return MyVec2(x,y); }
|
||||
#define IM_VEC2_CLASS_EXTRA \
|
||||
ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
|
||||
operator MyVec2() const { return MyVec2(x,y); }
|
||||
|
||||
#define IM_VEC4_CLASS_EXTRA \
|
||||
ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \
|
||||
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||
#define IM_VEC4_CLASS_EXTRA \
|
||||
ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \
|
||||
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||
*/
|
||||
|
||||
//---- Freely implement extra functions within the ImGui:: namespace.
|
||||
//---- Declare helpers or widgets implemented in imgui_user.inl or elsewhere, so end-user doesn't need to include multiple files.
|
||||
//---- e.g. you can create variants of the ImGui::Value() helper for your low-level math types.
|
||||
/*
|
||||
namespace ImGui
|
||||
{
|
||||
void Value(const char* prefix, const MyVec2& v, const char* float_format = NULL);
|
||||
void Value(const char* prefix, const MyVec4& v, const char* float_format = NULL);
|
||||
};
|
||||
void Value(const char* prefix, const MyVec2& v, const char* float_format = NULL);
|
||||
void Value(const char* prefix, const MyVec4& v, const char* float_format = NULL);
|
||||
}
|
||||
*/
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// stb_textedit.h - v1.3 - public domain - Sean Barrett
|
||||
// stb_textedit.h - v1.4 - public domain - Sean Barrett
|
||||
// Development of this library was sponsored by RAD Game Tools
|
||||
//
|
||||
// This C header file implements the guts of a multi-line text-editing
|
||||
@ -30,8 +30,9 @@
|
||||
//
|
||||
// VERSION HISTORY
|
||||
//
|
||||
// 1.3 (2013-06-19) fix mouse clicking to round to nearest char boundary
|
||||
// 1.2 (2013-05-27) fix some RAD types that had crept into the new code
|
||||
// 1.4 (2014-08-17) fix signed/unsigned warnings
|
||||
// 1.3 (2014-06-19) fix mouse clicking to round to nearest char boundary
|
||||
// 1.2 (2014-05-27) fix some RAD types that had crept into the new code
|
||||
// 1.1 (2013-12-15) move-by-word (requires STB_TEXTEDIT_IS_SPACE )
|
||||
// 1.0 (2012-07-26) improve documentation, initial public release
|
||||
// 0.3 (2012-02-24) bugfixes, single-line mode; insert mode
|
||||
@ -41,7 +42,7 @@
|
||||
// ADDITIONAL CONTRIBUTORS
|
||||
//
|
||||
// Ulf Winklemann: move-by-word in 1.1
|
||||
// Scott Graham: mouse selectiom bugfix in 1.3
|
||||
// Scott Graham: mouse selection bugfix in 1.3
|
||||
//
|
||||
// USAGE
|
||||
//
|
||||
@ -445,7 +446,7 @@ static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state
|
||||
static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state);
|
||||
static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state);
|
||||
static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length);
|
||||
static void stb_text_makeundo_insert(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length);
|
||||
static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length);
|
||||
static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length);
|
||||
|
||||
typedef struct
|
||||
@ -649,7 +650,7 @@ static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state
|
||||
stb_textedit_delete_selection(str,state);
|
||||
// try to insert the characters
|
||||
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) {
|
||||
stb_text_makeundo_insert(str, state, state->cursor, len);
|
||||
stb_text_makeundo_insert(state, state->cursor, len);
|
||||
state->cursor += len;
|
||||
state->has_preferred_x = 0;
|
||||
return 1;
|
||||
@ -684,7 +685,7 @@ retry:
|
||||
} else {
|
||||
stb_textedit_delete_selection(str,state); // implicity clamps
|
||||
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
|
||||
stb_text_makeundo_insert(str, state, state->cursor, 1);
|
||||
stb_text_makeundo_insert(state, state->cursor, 1);
|
||||
++state->cursor;
|
||||
state->has_preferred_x = 0;
|
||||
}
|
||||
@ -1007,13 +1008,13 @@ static void stb_textedit_discard_undo(StbUndoState *state)
|
||||
int n = state->undo_rec[0].insert_length, i;
|
||||
// delete n characters from all other records
|
||||
state->undo_char_point = state->undo_char_point - (short) n; // vsnet05
|
||||
memmove(state->undo_char, state->undo_char + n, state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE));
|
||||
memmove(state->undo_char, state->undo_char + n, (size_t) ((size_t)state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE)));
|
||||
for (i=0; i < state->undo_point; ++i)
|
||||
if (state->undo_rec[i].char_storage >= 0)
|
||||
state->undo_rec[i].char_storage = state->undo_rec[i].char_storage - (short) n; // vsnet05 // @OPTIMIZE: get rid of char_storage and infer it
|
||||
}
|
||||
--state->undo_point;
|
||||
memmove(state->undo_rec, state->undo_rec+1, state->undo_point*sizeof(state->undo_rec[0]));
|
||||
memmove(state->undo_rec, state->undo_rec+1, (size_t) ((size_t)state->undo_point*sizeof(state->undo_rec[0])));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1031,13 +1032,13 @@ static void stb_textedit_discard_redo(StbUndoState *state)
|
||||
int n = state->undo_rec[k].insert_length, i;
|
||||
// delete n characters from all other records
|
||||
state->redo_char_point = state->redo_char_point + (short) n; // vsnet05
|
||||
memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE));
|
||||
memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE)));
|
||||
for (i=state->redo_point; i < k; ++i)
|
||||
if (state->undo_rec[i].char_storage >= 0)
|
||||
state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short) n; // vsnet05
|
||||
}
|
||||
++state->redo_point;
|
||||
memmove(state->undo_rec + state->redo_point-1, state->undo_rec + state->redo_point, (STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0]));
|
||||
memmove(state->undo_rec + state->redo_point-1, state->undo_rec + state->redo_point, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0])));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1203,7 +1204,7 @@ static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
s->redo_point++;
|
||||
}
|
||||
|
||||
static void stb_text_makeundo_insert(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length)
|
||||
static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length)
|
||||
{
|
||||
stb_text_createundo(&state->undostate, where, 0, length);
|
||||
}
|
||||
|
BIN
web/performance_01.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
web/performance_01_close_up.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
web/skinning_sample_01.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
web/utf8_sample_01.png
Normal file
After Width: | Height: | Size: 5.4 KiB |