mirror of
https://github.com/Drezil/imgui.git
synced 2025-07-17 02:03:13 +02:00
Compare commits
25 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 |
11
README.md
11
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.
|
||||
|
||||
@ -23,6 +23,10 @@ Gallery
|
||||

|
||||

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

|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
@ -63,7 +67,8 @@ 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://upperbounds.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).
|
||||
|
||||
Inspiration, feedback, and testing: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Anton Mikhailov, Matt Willis. Thanks!
|
||||
|
||||
|
@ -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;winmm.lib;comctl32.lib;gdi32.lib;imm32.lib;user32.lib</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;winmm.lib;comctl32.lib;gdi32.lib;imm32.lib;user32.lib</AdditionalDependencies>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
</Link>
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <windows.h>
|
||||
#include <imm.h>
|
||||
#include <mmsystem.h>
|
||||
#include <d3dx9.h>
|
||||
#define DIRECTINPUT_VERSION 0x0800
|
||||
@ -163,8 +164,8 @@ LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
return true;
|
||||
case WM_CHAR:
|
||||
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
|
||||
if (wParam > 1 && wParam < 256)
|
||||
io.AddInputCharacter((char)wParam);
|
||||
if (wParam > 0 && wParam < 0x10000)
|
||||
io.AddInputCharacter((unsigned short)wParam);
|
||||
return true;
|
||||
case WM_DESTROY:
|
||||
{
|
||||
@ -176,6 +177,19 @@ LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
// Notify OS Input Method Editor of text input position (e.g. when using Japanese/Chinese inputs, otherwise this isn't needed)
|
||||
static void ImImpl_ImeSetInputScreenPosFn(int x, int y)
|
||||
{
|
||||
if (HIMC himc = ImmGetContext(hWnd))
|
||||
{
|
||||
COMPOSITIONFORM cf;
|
||||
cf.ptCurrentPos.x = x;
|
||||
cf.ptCurrentPos.y = y;
|
||||
cf.dwStyle = CFS_FORCE_POSITION;
|
||||
ImmSetCompositionWindow(himc, &cf);
|
||||
}
|
||||
}
|
||||
|
||||
void InitImGui()
|
||||
{
|
||||
RECT rect;
|
||||
@ -204,6 +218,7 @@ void InitImGui()
|
||||
io.KeyMap[ImGuiKey_Z] = 'Z';
|
||||
|
||||
io.RenderDrawListsFn = ImImpl_RenderDrawLists;
|
||||
io.ImeSetInputScreenPosFn = ImImpl_ImeSetInputScreenPosFn;
|
||||
|
||||
// Create the vertex buffer
|
||||
if (g_pd3dDevice->CreateVertexBuffer(10000 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
|
||||
|
53
examples/opengl_example/Makefile
Normal file
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 -framework CoreVideo
|
||||
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,11 +1,20 @@
|
||||
#define GLEW_STATIC
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
|
||||
#include <Windows.h>
|
||||
#include <Imm.h>
|
||||
#endif
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h" // for .png loading
|
||||
#include "../../imgui.h"
|
||||
|
||||
// glew & glfw
|
||||
#define GLEW_STATIC
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.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;
|
||||
@ -70,32 +79,32 @@ static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_c
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Notify OS Input Method Editor of text input position (e.g. when using Japanese/Chinese inputs, otherwise this isn't needed)
|
||||
static void ImImpl_ImeSetInputScreenPosFn(int x, int y)
|
||||
{
|
||||
HWND hwnd = glfwGetWin32Window(window);
|
||||
if (HIMC himc = ImmGetContext(hwnd))
|
||||
{
|
||||
COMPOSITIONFORM cf;
|
||||
cf.ptCurrentPos.x = x;
|
||||
cf.ptCurrentPos.y = y;
|
||||
cf.dwStyle = CFS_FORCE_POSITION;
|
||||
ImmSetCompositionWindow(himc, &cf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// GLFW callbacks to get events
|
||||
static void glfw_error_callback(int error, const char* description)
|
||||
@ -122,8 +131,8 @@ static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int act
|
||||
|
||||
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
|
||||
@ -178,17 +187,44 @@ void InitImGui()
|
||||
io.RenderDrawListsFn = ImImpl_RenderDrawLists;
|
||||
io.SetClipboardTextFn = ImImpl_SetClipboardTextFn;
|
||||
io.GetClipboardTextFn = ImImpl_GetClipboardTextFn;
|
||||
#ifdef _MSC_VER
|
||||
io.ImeSetInputScreenPosFn = ImImpl_ImeSetInputScreenPosFn;
|
||||
#endif
|
||||
|
||||
// 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 ImBitmapFont();
|
||||
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.FontTexUvForWhite 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.FontTexUvForWhite = 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);
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -10,12 +10,22 @@ bmfont reads fonts (.ttf, .fon, etc.) and output a .fnt file and a texture file,
|
||||
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
|
||||
|
||||
@ -34,28 +44,45 @@ Configure bmfont:
|
||||
|
||||
2. Load the .PNG data from 'png_data' into a texture
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
(B) Use fonts from external files
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
You need to set io.FontTexUvForWhite 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.FontTexUvForWhite 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.FontTexUvForWhite = 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 ImBitmapFont();
|
||||
io.Font->LoadFromFile("proggy_clean_13.fnt");
|
||||
IM_ASSERT(io.Font->IsLoaded());
|
||||
io.FontTexUvForWhite = ImVec2(0.0f/256.0f,0.0f/128);
|
||||
io.FontYOffset = +1;
|
||||
|
||||
// proggy_small_12
|
||||
io.Font = new ImBitmapFont();
|
||||
io.Font->LoadFromFile("proggy_small_12.fnt");
|
||||
IM_ASSERT(io.Font->IsLoaded());
|
||||
io.FontTexUvForWhite = ImVec2(84.0f/256.0f,20.0f/64);
|
||||
io.FontYOffset = +2;
|
||||
|
||||
// proggy_small_14
|
||||
io.Font = new ImBitmapFont();
|
||||
io.Font->LoadFromFile("proggy_small_14.fnt");
|
||||
IM_ASSERT(io.Font->IsLoaded());
|
||||
io.FontTexUvForWhite = ImVec2(84.0f/256.0f,20.0f/64);
|
||||
io.FontYOffset = +3;
|
||||
|
||||
@ -67,5 +94,7 @@ Configure bmfont:
|
||||
io.Font->LoadFromFile("courier_new_18.fnt");
|
||||
io.FontTexUvForWhite = ImVec2(4.0f/256.0f,5.0f/256);
|
||||
|
||||
|
||||
2. Load the matching .PNG data into a texture
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
BIN
extra_fonts/mplus-2m-medium_18.fnt
Normal file
BIN
extra_fonts/mplus-2m-medium_18.fnt
Normal file
Binary file not shown.
After Width: | Height: | Size: 117 KiB |
BIN
extra_fonts/mplus-2m-medium_18.png
Normal file
BIN
extra_fonts/mplus-2m-medium_18.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 284 KiB |
432
imgui.cpp
432
imgui.cpp
@ -1,4 +1,4 @@
|
||||
// ImGui library v1.12
|
||||
// ImGui library v1.13
|
||||
// See ImGui::ShowTestWindow() for sample code.
|
||||
// Read 'Programmer guide' below for notes on how to setup ImGui in your codebase.
|
||||
// Get latest version at https://github.com/ocornut/imgui
|
||||
@ -22,7 +22,6 @@
|
||||
Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes:
|
||||
- doesn't look fancy, doesn't animate
|
||||
- limited layout features, intricate layouts are typically crafted in code
|
||||
- assume ASCII text, using strlen() and [] operators, etc
|
||||
- occasionally use statically sized buffers for string manipulations - won't crash, but some long text may be clipped
|
||||
|
||||
END-USER GUIDE
|
||||
@ -139,6 +138,7 @@
|
||||
API BREAKING CHANGES
|
||||
====================
|
||||
|
||||
- 2014/09/25 (1.13) removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
|
||||
- 2014/09/24 (1.12) renamed SetFontScale() to SetWindowFontScale()
|
||||
- 2014/09/24 (1.12) moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
|
||||
- 2014/08/30 (1.09) removed IO.FontHeight (now computed automatically)
|
||||
@ -246,7 +246,7 @@ static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs);
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static const char* GetClipboardTextFn_DefaultImpl();
|
||||
static void SetClipboardTextFn_DefaultImpl(const char* text, const char* text_end);
|
||||
static void SetClipboardTextFn_DefaultImpl(const char* text);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// User facing structures
|
||||
@ -319,28 +319,30 @@ ImGuiIO::ImGuiIO()
|
||||
FontTexUvForWhite = ImVec2(0.0f,0.0f);
|
||||
FontBaseScale = 1.0f;
|
||||
FontAllowUserScaling = false;
|
||||
FontFallbackGlyph = (ImWchar)'?';
|
||||
PixelCenterOffset = 0.0f;
|
||||
MousePos = ImVec2(-1,-1);
|
||||
MousePosPrev = ImVec2(-1,-1);
|
||||
MouseDoubleClickTime = 0.30f;
|
||||
MouseDoubleClickMaxDist = 6.0f;
|
||||
|
||||
// Memory management functions, default to posix
|
||||
// User functions
|
||||
RenderDrawListsFn = NULL;
|
||||
MemAllocFn = malloc;
|
||||
MemReallocFn = realloc;
|
||||
MemFreeFn = free;
|
||||
|
||||
// Platform dependant default implementations
|
||||
GetClipboardTextFn = GetClipboardTextFn_DefaultImpl;
|
||||
GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependant default implementations
|
||||
SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
|
||||
ImeSetInputScreenPosFn = NULL;
|
||||
}
|
||||
|
||||
// Pass in translated ASCII characters for text input.
|
||||
// - with glfw you can get those from the callback set in glfwSetCharCallback()
|
||||
// - on Windows you can get those using ToAscii+keyboard state, or via the VM_CHAR message
|
||||
void ImGuiIO::AddInputCharacter(char c)
|
||||
static size_t ImStrlenW(const ImWchar* str);
|
||||
void ImGuiIO::AddInputCharacter(ImWchar c)
|
||||
{
|
||||
const size_t n = strlen(InputCharacters);
|
||||
const size_t n = ImStrlenW(InputCharacters);
|
||||
if (n < sizeof(InputCharacters) / sizeof(InputCharacters[0]))
|
||||
{
|
||||
InputCharacters[n] = c;
|
||||
@ -390,6 +392,11 @@ static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t)
|
||||
static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); }
|
||||
static inline float ImLength(const ImVec2& lhs) { return sqrt(lhs.x*lhs.x + lhs.y*lhs.y); }
|
||||
|
||||
static int ImTextCharToUtf8(char* buf, size_t buf_size, unsigned int in_char); // return output UTF-8 bytes count
|
||||
static int ImTextStrToUtf8(char* buf, size_t buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count
|
||||
static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // return input UTF-8 bytes count
|
||||
static int ImTextStrFromUtf8(ImWchar* buf, size_t buf_size, const char* in_text, const char* in_text_end); // return input UTF-8 bytes count
|
||||
|
||||
static int ImStricmp(const char* str1, const char* str2)
|
||||
{
|
||||
int d;
|
||||
@ -405,6 +412,14 @@ static char* ImStrdup(const char *str)
|
||||
return buff;
|
||||
}
|
||||
|
||||
static size_t ImStrlenW(const ImWchar* str)
|
||||
{
|
||||
size_t n = 0;
|
||||
while (*str++)
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
static const char* ImStristr(const char* haystack, const char* needle, const char* needle_end)
|
||||
{
|
||||
if (!needle_end)
|
||||
@ -606,19 +621,20 @@ struct ImGuiDrawContext
|
||||
|
||||
struct ImGuiTextEditState;
|
||||
#define STB_TEXTEDIT_STRING ImGuiTextEditState
|
||||
#define STB_TEXTEDIT_CHARTYPE char
|
||||
#define STB_TEXTEDIT_CHARTYPE ImWchar
|
||||
#include "stb_textedit.h"
|
||||
|
||||
// State of the currently focused/edited text input box
|
||||
struct ImGuiTextEditState
|
||||
{
|
||||
char Text[1024]; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so own buffer.
|
||||
char InitialText[1024]; // backup of end-user buffer at focusing time, to ESC key can do a revert. Also used for arithmetic operations (but could use a pre-parsed float there).
|
||||
ImWchar Text[1024]; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer.
|
||||
char InitialText[1024*3+1]; // backup of end-user buffer at the time of focus (in UTF-8, unconverted)
|
||||
size_t BufSize; // end-user buffer size, <= 1024 (or increase above)
|
||||
float Width; // widget width
|
||||
float ScrollX;
|
||||
STB_TexteditState StbState;
|
||||
float CursorAnim;
|
||||
ImVec2 LastCursorPos;
|
||||
bool SelectedAllMouseLock;
|
||||
ImFont Font;
|
||||
float FontSize;
|
||||
@ -628,14 +644,15 @@ struct ImGuiTextEditState
|
||||
void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking
|
||||
bool CursorIsVisible() const { return CursorAnim <= 0.0f || fmodf(CursorAnim, 1.20f) <= 0.80f; } // Blinking
|
||||
bool HasSelection() const { return StbState.select_start != StbState.select_end; }
|
||||
void SelectAll() { StbState.select_start = 0; StbState.select_end = (int)strlen(Text); StbState.cursor = StbState.select_end; StbState.has_preferred_x = false; }
|
||||
void SelectAll() { StbState.select_start = 0; StbState.select_end = (int)ImStrlenW(Text); StbState.cursor = StbState.select_end; StbState.has_preferred_x = false; }
|
||||
|
||||
void OnKeyboardPressed(int key);
|
||||
void UpdateScrollOffset();
|
||||
ImVec2 CalcDisplayOffsetFromCharIdx(int i) const;
|
||||
|
||||
// Static functions because they are used to render non-focused instances of a text input box
|
||||
static const char* GetTextPointerClipped(ImFont font, float font_size, const char* text, float width, ImVec2* out_text_size = NULL);
|
||||
static const char* GetTextPointerClippedA(ImFont font, float font_size, const char* text, float width, ImVec2* out_text_size = NULL);
|
||||
static const ImWchar* GetTextPointerClippedW(ImFont font, float font_size, const ImWchar* text, float width, ImVec2* out_text_size = NULL);
|
||||
static void RenderTextScrolledClipped(ImFont font, float font_size, const char* text, ImVec2 pos_base, float width, float scroll_x);
|
||||
};
|
||||
|
||||
@ -1705,7 +1722,7 @@ ImVec2 CalcTextSize(const char* text, const char* text_end, const bool hide_text
|
||||
else
|
||||
text_display_end = text_end;
|
||||
|
||||
const ImVec2 size = window->Font()->CalcTextSize(window->FontSize(), 0, text, text_display_end, NULL);
|
||||
const ImVec2 size = window->Font()->CalcTextSizeA(window->FontSize(), 0, text, text_display_end, NULL);
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -2373,7 +2390,7 @@ void End()
|
||||
{
|
||||
g.LogClipboard->append("\n");
|
||||
if (g.IO.SetClipboardTextFn)
|
||||
g.IO.SetClipboardTextFn(g.LogClipboard->begin(), g.LogClipboard->end());
|
||||
g.IO.SetClipboardTextFn(g.LogClipboard->begin());
|
||||
g.LogClipboard->clear();
|
||||
}
|
||||
}
|
||||
@ -3795,15 +3812,15 @@ bool RadioButton(const char* label, int* v, int v_button)
|
||||
}; // namespace ImGui
|
||||
|
||||
// Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, ASCII, fixed-width font)
|
||||
int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return (int)strlen(obj->Text); }
|
||||
char STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return (char)obj->Text[idx]; }
|
||||
float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { (void)line_start_idx; return obj->Font->CalcTextSize(obj->FontSize, 0, &obj->Text[char_idx], &obj->Text[char_idx]+1, NULL).x; }
|
||||
char STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x10000 ? 0 : (char)key; }
|
||||
char STB_TEXTEDIT_NEWLINE = '\n';
|
||||
int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return (int)ImStrlenW(obj->Text); }
|
||||
ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return obj->Text[idx]; }
|
||||
float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { (void)line_start_idx; return obj->Font->CalcTextSizeW(obj->FontSize, 0, &obj->Text[char_idx], &obj->Text[char_idx]+1, NULL).x; }
|
||||
int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x10000 ? 0 : key; }
|
||||
ImWchar STB_TEXTEDIT_NEWLINE = '\n';
|
||||
void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int line_start_idx)
|
||||
{
|
||||
const char* text_remaining = NULL;
|
||||
const ImVec2 size = obj->Font->CalcTextSize(obj->FontSize, FLT_MAX, obj->Text + line_start_idx, NULL, &text_remaining);
|
||||
const ImWchar* text_remaining = NULL;
|
||||
const ImVec2 size = obj->Font->CalcTextSizeW(obj->FontSize, FLT_MAX, obj->Text + line_start_idx, NULL, &text_remaining);
|
||||
r->x0 = 0.0f;
|
||||
r->x1 = size.x;
|
||||
r->baseline_y_delta = size.y;
|
||||
@ -3812,22 +3829,22 @@ void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int
|
||||
r->num_chars = (int)(text_remaining - (obj->Text + line_start_idx));
|
||||
}
|
||||
|
||||
static bool is_white(char c) { return c==0 || c==' ' || c=='\t' || c=='\r' || c=='\n'; }
|
||||
static bool is_separator(char c) { return c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; }
|
||||
static bool is_white(unsigned int c) { return c==0 || c==' ' || c=='\t' || c=='\r' || c=='\n'; }
|
||||
static bool is_separator(unsigned int c) { return c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; }
|
||||
|
||||
#define STB_TEXTEDIT_IS_SPACE(c) (is_white(c) || is_separator(c))
|
||||
void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int idx, int n) { char* dst = obj->Text+idx; const char* src = obj->Text+idx+n; while (char c = *src++) *dst++ = c; *dst = '\0'; }
|
||||
#define STB_TEXTEDIT_IS_SPACE(c) (is_white((unsigned int)c) || is_separator((unsigned int)c))
|
||||
void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int idx, int n) { ImWchar* dst = obj->Text+idx; const ImWchar* src = obj->Text+idx+n; while (ImWchar c = *src++) *dst++ = c; *dst = '\0'; }
|
||||
|
||||
bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int idx, const char* new_text, int new_text_len)
|
||||
bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int idx, const ImWchar* new_text, int new_text_len)
|
||||
{
|
||||
char* buf_end = obj->Text + obj->BufSize;
|
||||
const size_t text_len = strlen(obj->Text);
|
||||
ImWchar* buf_end = obj->Text + obj->BufSize;
|
||||
const size_t text_len = ImStrlenW(obj->Text);
|
||||
|
||||
if (new_text_len > buf_end - (obj->Text + text_len + 1))
|
||||
return false;
|
||||
|
||||
memmove(obj->Text + (size_t)idx + new_text_len, obj->Text + (size_t)idx, text_len - (size_t)idx);
|
||||
memcpy(obj->Text + (size_t)idx, new_text, (size_t)new_text_len);
|
||||
memmove(obj->Text + (size_t)idx + new_text_len, obj->Text + (size_t)idx, (text_len - (size_t)idx) * sizeof(ImWchar));
|
||||
memcpy(obj->Text + (size_t)idx, new_text, (size_t)new_text_len * sizeof(ImWchar));
|
||||
obj->Text[text_len + (size_t)new_text_len] = 0;
|
||||
|
||||
return true;
|
||||
@ -3865,7 +3882,7 @@ void ImGuiTextEditState::UpdateScrollOffset()
|
||||
{
|
||||
// Scroll in chunks of quarter width
|
||||
const float scroll_x_increment = Width * 0.25f;
|
||||
const float cursor_offset_x = Font->CalcTextSize(FontSize, 0, Text, Text+StbState.cursor, NULL).x;
|
||||
const float cursor_offset_x = Font->CalcTextSizeW(FontSize, 0, Text, Text+StbState.cursor, NULL).x;
|
||||
if (ScrollX > cursor_offset_x)
|
||||
ScrollX = ImMax(0.0f, cursor_offset_x - scroll_x_increment);
|
||||
else if (ScrollX < cursor_offset_x - Width)
|
||||
@ -3874,22 +3891,35 @@ void ImGuiTextEditState::UpdateScrollOffset()
|
||||
|
||||
ImVec2 ImGuiTextEditState::CalcDisplayOffsetFromCharIdx(int i) const
|
||||
{
|
||||
const char* text_start = GetTextPointerClipped(Font, FontSize, Text, ScrollX, NULL);
|
||||
const char* text_end = (Text+i >= text_start) ? Text+i : text_start; // Clip if requested character is outside of display
|
||||
const ImWchar* text_start = GetTextPointerClippedW(Font, FontSize, Text, ScrollX, NULL);
|
||||
const ImWchar* text_end = (Text+i >= text_start) ? Text+i : text_start; // Clip if requested character is outside of display
|
||||
IM_ASSERT(text_end >= text_start);
|
||||
|
||||
const ImVec2 offset = Font->CalcTextSize(FontSize, Width, text_start, text_end, NULL);
|
||||
const ImVec2 offset = Font->CalcTextSizeW(FontSize, Width, text_start, text_end, NULL);
|
||||
return offset;
|
||||
}
|
||||
|
||||
// [Static]
|
||||
const char* ImGuiTextEditState::GetTextPointerClipped(ImFont font, float font_size, const char* text, float width, ImVec2* out_text_size)
|
||||
const char* ImGuiTextEditState::GetTextPointerClippedA(ImFont font, float font_size, const char* text, float width, ImVec2* out_text_size)
|
||||
{
|
||||
if (width <= 0.0f)
|
||||
return text;
|
||||
|
||||
const char* text_clipped_end = NULL;
|
||||
const ImVec2 text_size = font->CalcTextSize(font_size, width, text, NULL, &text_clipped_end);
|
||||
const ImVec2 text_size = font->CalcTextSizeA(font_size, width, text, NULL, &text_clipped_end);
|
||||
if (out_text_size)
|
||||
*out_text_size = text_size;
|
||||
return text_clipped_end;
|
||||
}
|
||||
|
||||
// [Static]
|
||||
const ImWchar* ImGuiTextEditState::GetTextPointerClippedW(ImFont font, float font_size, const ImWchar* text, float width, ImVec2* out_text_size)
|
||||
{
|
||||
if (width <= 0.0f)
|
||||
return text;
|
||||
|
||||
const ImWchar* text_clipped_end = NULL;
|
||||
const ImVec2 text_size = font->CalcTextSizeW(font_size, width, text, NULL, &text_clipped_end);
|
||||
if (out_text_size)
|
||||
*out_text_size = text_size;
|
||||
return text_clipped_end;
|
||||
@ -3900,8 +3930,8 @@ void ImGuiTextEditState::RenderTextScrolledClipped(ImFont font, float font_size,
|
||||
{
|
||||
// NB- We start drawing at character boundary
|
||||
ImVec2 text_size;
|
||||
const char* text_start = GetTextPointerClipped(font, font_size, buf, scroll_x, NULL);
|
||||
const char* text_end = GetTextPointerClipped(font, font_size, text_start, width, &text_size);
|
||||
const char* text_start = GetTextPointerClippedA(font, font_size, buf, scroll_x, NULL);
|
||||
const char* text_end = GetTextPointerClippedA(font, font_size, text_start, width, &text_size);
|
||||
|
||||
// Draw a little clip symbol if we've got text on either left or right of the box
|
||||
const char symbol_c = '~';
|
||||
@ -4028,12 +4058,14 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag
|
||||
if (g.ActiveId != id)
|
||||
{
|
||||
// Start edition
|
||||
strcpy(edit_state.Text, buf);
|
||||
strcpy(edit_state.InitialText, buf);
|
||||
// Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar)
|
||||
ImFormatString(edit_state.InitialText, IM_ARRAYSIZE(edit_state.InitialText), "%s", buf);
|
||||
ImTextStrFromUtf8(edit_state.Text, IM_ARRAYSIZE(edit_state.Text), buf, NULL);
|
||||
edit_state.ScrollX = 0.0f;
|
||||
edit_state.Width = w;
|
||||
stb_textedit_initialize_state(&edit_state.StbState, true);
|
||||
edit_state.CursorAnimReset();
|
||||
edit_state.LastCursorPos = ImVec2(-1.f,-1.f);
|
||||
|
||||
if (tab_focus_requested || is_ctrl_down)
|
||||
select_all = true;
|
||||
@ -4052,6 +4084,7 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag
|
||||
bool value_changed = false;
|
||||
bool cancel_edit = false;
|
||||
bool enter_pressed = false;
|
||||
static char text_tmp_utf8[IM_ARRAYSIZE(edit_state.InitialText)];
|
||||
if (g.ActiveId == id)
|
||||
{
|
||||
// Edit in progress
|
||||
@ -4096,55 +4129,62 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag
|
||||
else if (is_ctrl_down && IsKeyPressedMap(ImGuiKey_Z)) edit_state.OnKeyboardPressed(STB_TEXTEDIT_K_UNDO); // I don't want to use shortcuts but we should probably have an Input-catch stack
|
||||
else if (is_ctrl_down && IsKeyPressedMap(ImGuiKey_Y)) edit_state.OnKeyboardPressed(STB_TEXTEDIT_K_REDO);
|
||||
else if (is_ctrl_down && IsKeyPressedMap(ImGuiKey_A)) edit_state.SelectAll();
|
||||
else if (is_ctrl_down && IsKeyPressedMap(ImGuiKey_X))
|
||||
else if (is_ctrl_down && (IsKeyPressedMap(ImGuiKey_X) || IsKeyPressedMap(ImGuiKey_C)))
|
||||
{
|
||||
if (!edit_state.HasSelection())
|
||||
// Cut, Copy
|
||||
const bool cut = IsKeyPressedMap(ImGuiKey_X);
|
||||
if (cut && !edit_state.HasSelection())
|
||||
edit_state.SelectAll();
|
||||
|
||||
const int ib = ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end);
|
||||
const int ie = ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end);
|
||||
if (g.IO.SetClipboardTextFn)
|
||||
g.IO.SetClipboardTextFn(edit_state.Text+ib, edit_state.Text+ie);
|
||||
stb_textedit_cut(&edit_state, &edit_state.StbState);
|
||||
}
|
||||
else if (is_ctrl_down && IsKeyPressedMap(ImGuiKey_C))
|
||||
{
|
||||
const int ib = edit_state.HasSelection() ? ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end) : 0;
|
||||
const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : (int)strlen(edit_state.Text);
|
||||
if (g.IO.SetClipboardTextFn)
|
||||
g.IO.SetClipboardTextFn(edit_state.Text+ib, edit_state.Text+ie);
|
||||
const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : (int)ImStrlenW(edit_state.Text);
|
||||
ImTextStrToUtf8(text_tmp_utf8, IM_ARRAYSIZE(text_tmp_utf8), edit_state.Text+ib, edit_state.Text+ie);
|
||||
g.IO.SetClipboardTextFn(text_tmp_utf8);
|
||||
}
|
||||
|
||||
if (cut)
|
||||
stb_textedit_cut(&edit_state, &edit_state.StbState);
|
||||
}
|
||||
else if (is_ctrl_down && IsKeyPressedMap(ImGuiKey_V))
|
||||
{
|
||||
// Paste
|
||||
if (g.IO.GetClipboardTextFn)
|
||||
{
|
||||
if (const char* clipboard = g.IO.GetClipboardTextFn())
|
||||
{
|
||||
// Remove new-line from pasted buffer
|
||||
size_t clipboard_len = strlen(clipboard);
|
||||
char* clipboard_filtered = (char*)ImGui::MemAlloc(clipboard_len+1);
|
||||
ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len+1) * sizeof(ImWchar));
|
||||
int clipboard_filtered_len = 0;
|
||||
for (int i = 0; clipboard[i]; i++)
|
||||
for (const char* s = clipboard; *s; )
|
||||
{
|
||||
const char c = clipboard[i];
|
||||
unsigned int c;
|
||||
const int bytes_count = ImTextCharFromUtf8(&c, s, NULL);
|
||||
if (bytes_count <= 0)
|
||||
break;
|
||||
s += bytes_count;
|
||||
if (c == '\n' || c == '\r')
|
||||
continue;
|
||||
clipboard_filtered[clipboard_filtered_len++] = clipboard[i];
|
||||
clipboard_filtered[clipboard_filtered_len++] = c;
|
||||
}
|
||||
clipboard_filtered[clipboard_filtered_len] = 0;
|
||||
stb_textedit_paste(&edit_state, &edit_state.StbState, clipboard_filtered, clipboard_filtered_len);
|
||||
ImGui::MemFree(clipboard_filtered);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (g.IO.InputCharacters[0])
|
||||
{
|
||||
// Text input
|
||||
for (int n = 0; n < IM_ARRAYSIZE(g.IO.InputCharacters) && g.IO.InputCharacters[n]; n++)
|
||||
{
|
||||
const char c = g.IO.InputCharacters[n];
|
||||
const ImWchar c = g.IO.InputCharacters[n];
|
||||
if (c)
|
||||
{
|
||||
// Filter
|
||||
if (!isprint(c) && c != ' ')
|
||||
if (c < 256 && !isprint((char)(c & 0xFF)) && c != ' ')
|
||||
continue;
|
||||
if (flags & ImGuiInputTextFlags_CharsDecimal)
|
||||
if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/'))
|
||||
@ -4171,9 +4211,13 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag
|
||||
else
|
||||
{
|
||||
// Apply new value immediately - copy modified buffer back
|
||||
if (strcmp(edit_state.Text, buf) != 0)
|
||||
// Note that as soon as we can focus into the input box, the in-widget value gets priority over any underlying modification of the input buffer
|
||||
// FIXME: We actually always render 'buf' in RenderTextScrolledClipped
|
||||
// FIXME-OPT: CPU waste to do this everytime the widget is active, should mark dirty state from the textedit callbacks
|
||||
ImTextStrToUtf8(text_tmp_utf8, IM_ARRAYSIZE(text_tmp_utf8), edit_state.Text, NULL);
|
||||
if (strcmp(text_tmp_utf8, buf) != 0)
|
||||
{
|
||||
ImFormatString(buf, buf_size, "%s", edit_state.Text);
|
||||
ImFormatString(buf, buf_size, "%s", text_tmp_utf8);
|
||||
value_changed = true;
|
||||
}
|
||||
}
|
||||
@ -4202,12 +4246,17 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag
|
||||
|
||||
if (g.ActiveId == id)
|
||||
{
|
||||
const ImVec2 cursor_pos = frame_bb.Min + style.FramePadding + edit_state.CalcDisplayOffsetFromCharIdx(edit_state.StbState.cursor);
|
||||
|
||||
// Draw blinking cursor
|
||||
if (g.InputTextState.CursorIsVisible())
|
||||
{
|
||||
const ImVec2 cursor_pos = frame_bb.Min + style.FramePadding + edit_state.CalcDisplayOffsetFromCharIdx(edit_state.StbState.cursor);
|
||||
window->DrawList->AddRect(cursor_pos - font_off_up + ImVec2(0,2), cursor_pos + font_off_dn - ImVec2(0,3), window->Color(ImGuiCol_Text));
|
||||
}
|
||||
|
||||
// Notify OS of text input position
|
||||
if (io.ImeSetInputScreenPosFn && ImLength(edit_state.LastCursorPos - cursor_pos) > 0.01f)
|
||||
io.ImeSetInputScreenPosFn((int)cursor_pos.x - 1, (int)(cursor_pos.y - window->FontSize())); // -1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.
|
||||
|
||||
edit_state.LastCursorPos = cursor_pos;
|
||||
}
|
||||
|
||||
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
|
||||
@ -5386,7 +5435,140 @@ const ImBitmapFont::FntGlyph* ImBitmapFont::FindGlyph(unsigned short c) const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ImVec2 ImBitmapFont::CalcTextSize(float size, float max_width, const char* text_begin, const char* text_end, const char** remaining) const
|
||||
// Convert UTF-8 to 32-bits character, process single character input.
|
||||
// Based on stb_from_utf8() from github.com/nothings/stb/
|
||||
static int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
|
||||
{
|
||||
if (*in_text != 0)
|
||||
{
|
||||
unsigned int c = -1;
|
||||
const unsigned char* str = (const unsigned char*)in_text;
|
||||
if (!(*str & 0x80))
|
||||
{
|
||||
c = (unsigned int)(*str++);
|
||||
*out_char = c;
|
||||
return 1;
|
||||
}
|
||||
if ((*str & 0xe0) == 0xc0)
|
||||
{
|
||||
if (in_text_end && in_text_end - (const char*)str < 2) return -1;
|
||||
if (*str < 0xc2) return -1;
|
||||
c = (*str++ & 0x1f) << 6;
|
||||
if ((*str & 0xc0) != 0x80) return -1;
|
||||
c += (*str++ & 0x3f);
|
||||
*out_char = c;
|
||||
return 2;
|
||||
}
|
||||
if ((*str & 0xf0) == 0xe0)
|
||||
{
|
||||
if (in_text_end && in_text_end - (const char*)str < 3) return -1;
|
||||
if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return -1;
|
||||
if (*str == 0xed && str[1] > 0x9f) return -1; // str[1] < 0x80 is checked below
|
||||
c = (*str++ & 0x0f) << 12;
|
||||
if ((*str & 0xc0) != 0x80) return -1;
|
||||
c += (*str++ & 0x3f) << 6;
|
||||
if ((*str & 0xc0) != 0x80) return -1;
|
||||
c += (*str++ & 0x3f);
|
||||
*out_char = c;
|
||||
return 3;
|
||||
}
|
||||
if ((*str & 0xf8) == 0xf0)
|
||||
{
|
||||
if (in_text_end && in_text_end - (const char*)str < 4) return -1;
|
||||
if (*str > 0xf4) return -1;
|
||||
if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return -1;
|
||||
if (*str == 0xf4 && str[1] > 0x8f) return -1; // str[1] < 0x80 is checked below
|
||||
c = (*str++ & 0x07) << 18;
|
||||
if ((*str & 0xc0) != 0x80) return -1;
|
||||
c += (*str++ & 0x3f) << 12;
|
||||
if ((*str & 0xc0) != 0x80) return -1;
|
||||
c += (*str++ & 0x3f) << 6;
|
||||
if ((*str & 0xc0) != 0x80) return -1;
|
||||
c += (*str++ & 0x3f);
|
||||
// utf-8 encodings of values used in surrogate pairs are invalid
|
||||
if ((c & 0xFFFFF800) == 0xD800) return -1;
|
||||
*out_char = c;
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
*out_char = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ImTextStrFromUtf8(ImWchar* buf, size_t buf_size, const char* in_text, const char* in_text_end)
|
||||
{
|
||||
ImWchar* buf_out = buf;
|
||||
ImWchar* buf_end = buf + buf_size;
|
||||
while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
|
||||
{
|
||||
unsigned int c;
|
||||
in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
|
||||
if (c < 0x10000) // FIXME: Losing characters that don't fit in 2 bytes
|
||||
*buf_out++ = (ImWchar)c;
|
||||
}
|
||||
*buf_out = 0;
|
||||
return buf_out - buf;
|
||||
}
|
||||
|
||||
// Based on stb_to_utf8() from github.com/nothings/stb/
|
||||
static int ImTextCharToUtf8(char* buf, size_t buf_size, unsigned int c)
|
||||
{
|
||||
if (c)
|
||||
{
|
||||
int i = 0;
|
||||
int n = (size_t)buf_size;
|
||||
if (c < 0x80)
|
||||
{
|
||||
if (i+1 > n) return 0;
|
||||
buf[i++] = (char)c;
|
||||
return 1;
|
||||
}
|
||||
else if (c < 0x800)
|
||||
{
|
||||
if (i+2 > n) return 0;
|
||||
buf[i++] = 0xc0 + (c >> 6);
|
||||
buf[i++] = 0x80 + (c & 0x3f);
|
||||
return 2;
|
||||
}
|
||||
else if (c >= 0xdc00 && c < 0xe000)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (c >= 0xd800 && c < 0xdc00)
|
||||
{
|
||||
if (i+4 > n) return 0;
|
||||
buf[i++] = 0xf0 + (c >> 18);
|
||||
buf[i++] = 0x80 + ((c >> 12) & 0x3f);
|
||||
buf[i++] = 0x80 + ((c >> 6) & 0x3f);
|
||||
buf[i++] = 0x80 + ((c ) & 0x3f);
|
||||
return 4;
|
||||
}
|
||||
//else if (c < 0x10000)
|
||||
{
|
||||
if (i+3 > n) return 0;
|
||||
buf[i++] = 0xe0 + (c >> 12);
|
||||
buf[i++] = 0x80 + ((c>> 6) & 0x3f);
|
||||
buf[i++] = 0x80 + ((c ) & 0x3f);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ImTextStrToUtf8(char* buf, size_t buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
|
||||
{
|
||||
char* buf_out = buf;
|
||||
const char* buf_end = buf + buf_size;
|
||||
while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
|
||||
{
|
||||
buf_out += ImTextCharToUtf8(buf_out, buf_end-buf_out-1, (unsigned int)*in_text);
|
||||
in_text++;
|
||||
}
|
||||
*buf_out = 0;
|
||||
return buf_out - buf;
|
||||
}
|
||||
|
||||
ImVec2 ImBitmapFont::CalcTextSizeA(float size, float max_width, const char* text_begin, const char* text_end, const char** remaining) const
|
||||
{
|
||||
if (max_width == 0.0f)
|
||||
max_width = FLT_MAX;
|
||||
@ -5395,6 +5577,7 @@ ImVec2 ImBitmapFont::CalcTextSize(float size, float max_width, const char* text_
|
||||
|
||||
const float scale = size / (float)Info->FontSize;
|
||||
const float line_height = (float)Info->FontSize * scale;
|
||||
const FntGlyph* fallback_glyph = FindGlyph(GImGui.IO.FontFallbackGlyph);
|
||||
|
||||
ImVec2 text_size = ImVec2(0,0);
|
||||
float line_width = 0.0f;
|
||||
@ -5402,7 +5585,10 @@ ImVec2 ImBitmapFont::CalcTextSize(float size, float max_width, const char* text_
|
||||
const char* s = text_begin;
|
||||
while (s < text_end)
|
||||
{
|
||||
const char c = *s;
|
||||
unsigned int c;
|
||||
const int bytes_count = ImTextCharFromUtf8(&c, s, text_end);
|
||||
s += bytes_count > 0 ? bytes_count : 1; // Handle decoding failure by skipping to next byte
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
if (text_size.x < line_width)
|
||||
@ -5410,22 +5596,87 @@ ImVec2 ImBitmapFont::CalcTextSize(float size, float max_width, const char* text_
|
||||
text_size.y += line_height;
|
||||
line_width = 0;
|
||||
}
|
||||
else if (const FntGlyph* glyph = FindGlyph((unsigned short)c))
|
||||
else if (c == '\t')
|
||||
{
|
||||
// FIXME: Better TAB handling needed.
|
||||
if (const FntGlyph* glyph = FindGlyph((unsigned short)' '))
|
||||
line_width += (glyph->XAdvance + Info->SpacingHoriz) * 4 * scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
const FntGlyph* glyph = FindGlyph((unsigned short)c);
|
||||
if (!glyph)
|
||||
glyph = fallback_glyph;
|
||||
if (glyph)
|
||||
{
|
||||
const float char_width = (glyph->XAdvance + Info->SpacingHoriz) * scale;
|
||||
//const float char_extend = (glyph->XOffset + glyph->Width * scale);
|
||||
|
||||
if (line_width + char_width >= max_width)
|
||||
break;
|
||||
line_width += char_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (line_width > 0 || text_size.y == 0.0f)
|
||||
{
|
||||
if (text_size.x < line_width)
|
||||
text_size.x = line_width;
|
||||
text_size.y += line_height;
|
||||
}
|
||||
|
||||
if (remaining)
|
||||
*remaining = s;
|
||||
|
||||
return text_size;
|
||||
}
|
||||
|
||||
ImVec2 ImBitmapFont::CalcTextSizeW(float size, float max_width, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining) const
|
||||
{
|
||||
if (max_width == 0.0f)
|
||||
max_width = FLT_MAX;
|
||||
if (!text_end)
|
||||
text_end = text_begin + ImStrlenW(text_begin);
|
||||
|
||||
const float scale = size / (float)Info->FontSize;
|
||||
const float line_height = (float)Info->FontSize * scale;
|
||||
const FntGlyph* fallback_glyph = FindGlyph(GImGui.IO.FontFallbackGlyph);
|
||||
|
||||
ImVec2 text_size = ImVec2(0,0);
|
||||
float line_width = 0.0f;
|
||||
|
||||
const ImWchar* s = text_begin;
|
||||
while (s < text_end)
|
||||
{
|
||||
const unsigned int c = (unsigned int)(*s++);
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
if (text_size.x < line_width)
|
||||
text_size.x = line_width;
|
||||
text_size.y += line_height;
|
||||
line_width = 0;
|
||||
}
|
||||
else if (c == '\t')
|
||||
{
|
||||
// FIXME: Better TAB handling needed.
|
||||
if (const FntGlyph* glyph = FindGlyph((unsigned short)' '))
|
||||
line_width += (glyph->XAdvance + Info->SpacingHoriz) * 4 * scale;
|
||||
}
|
||||
|
||||
s += 1;
|
||||
else
|
||||
{
|
||||
const FntGlyph* glyph = FindGlyph((unsigned short)c);
|
||||
if (!glyph)
|
||||
glyph = fallback_glyph;
|
||||
if (glyph)
|
||||
{
|
||||
const float char_width = (glyph->XAdvance + Info->SpacingHoriz) * scale;
|
||||
//const float char_extend = (glyph->XOffset + glyph->Width * scale);
|
||||
if (line_width + char_width >= max_width)
|
||||
break;
|
||||
line_width += char_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (line_width > 0 || text_size.y == 0.0f)
|
||||
@ -5451,6 +5702,7 @@ void ImBitmapFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& c
|
||||
const float tex_scale_x = 1.0f / (float)Common->ScaleW;
|
||||
const float tex_scale_y = 1.0f / (float)(Common->ScaleH);
|
||||
const float outline = (float)Info->Outline;
|
||||
const FntGlyph* fallback_glyph = FindGlyph(GImGui.IO.FontFallbackGlyph);
|
||||
|
||||
// Align to be pixel perfect
|
||||
pos.x = (float)(int)pos.x;
|
||||
@ -5460,9 +5712,14 @@ void ImBitmapFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& c
|
||||
|
||||
float x = pos.x;
|
||||
float y = pos.y;
|
||||
for (const char* s = text_begin; s < text_end; s++)
|
||||
for (const char* s = text_begin; s < text_end; )
|
||||
{
|
||||
const char c = *s;
|
||||
unsigned int c;
|
||||
const int bytes_count = ImTextCharFromUtf8(&c, s, text_end);
|
||||
s += bytes_count > 0 ? bytes_count : 1; // Handle decoding failure by skipping to next byte
|
||||
if (c >= 0x10000)
|
||||
continue;
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
x = pos.x;
|
||||
@ -5470,7 +5727,10 @@ void ImBitmapFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& c
|
||||
continue;
|
||||
}
|
||||
|
||||
if (const FntGlyph* glyph = FindGlyph((unsigned short)c))
|
||||
const FntGlyph* glyph = FindGlyph((unsigned short)c);
|
||||
if (!glyph)
|
||||
glyph = fallback_glyph;
|
||||
if (glyph)
|
||||
{
|
||||
const float char_width = (glyph->XAdvance + Info->SpacingHoriz) * scale;
|
||||
//const float char_extend = (glyph->XOffset + glyph->Width * scale);
|
||||
@ -5562,12 +5822,11 @@ static const char* GetClipboardTextFn_DefaultImpl()
|
||||
}
|
||||
|
||||
// Win32 API clipboard implementation
|
||||
static void SetClipboardTextFn_DefaultImpl(const char* text, const char* text_end)
|
||||
static void SetClipboardTextFn_DefaultImpl(const char* text)
|
||||
{
|
||||
if (!OpenClipboard(NULL))
|
||||
return;
|
||||
if (!text_end)
|
||||
text_end = text + strlen(text);
|
||||
const char* text_end = text + strlen(text);
|
||||
const int buf_length = (int)(text_end - text) + 1;
|
||||
HGLOBAL buf_handle = GlobalAlloc(GMEM_MOVEABLE, buf_length * sizeof(char));
|
||||
if (buf_handle == NULL)
|
||||
@ -5590,15 +5849,14 @@ static const char* GetClipboardTextFn_DefaultImpl()
|
||||
}
|
||||
|
||||
// Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
|
||||
static void SetClipboardTextFn_DefaultImpl(const char* text, const char* text_end)
|
||||
static void SetClipboardTextFn_DefaultImpl(const char* text)
|
||||
{
|
||||
if (GImGui.PrivateClipboard)
|
||||
{
|
||||
ImGui::MemFree(GImGui.PrivateClipboard);
|
||||
GImGui.PrivateClipboard = NULL;
|
||||
}
|
||||
if (!text_end)
|
||||
text_end = text + strlen(text);
|
||||
const char* text_end = text + strlen(text);
|
||||
GImGui.PrivateClipboard = (char*)ImGui::MemAlloc((size_t)(text_end - text) + 1);
|
||||
memcpy(GImGui.PrivateClipboard, text, (size_t)(text_end - text));
|
||||
GImGui.PrivateClipboard[(size_t)(text_end - text)] = 0;
|
||||
@ -5798,6 +6056,22 @@ void ShowTestWindow(bool* open)
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("UTF-8 Text"))
|
||||
{
|
||||
// UTF-8 test (need a suitable font, try extra_fonts/mplus* files for example)
|
||||
// Most compiler appears to support UTF-8 in source code (with Visual Studio you need to save your file as 'UTF-8 without signature')
|
||||
// However for the sake for maximum portability here we are *not* including raw UTF-8 character in this source file, instead we encode the string with with hexadecimal constants.
|
||||
// In your own application please be reasonable and use UTF-8 in the source or get the data from external files. :)
|
||||
//const char* utf8_string = "\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93\x20\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; // Japanese text for "Kakikukeo" (Hiragana) followed by "Nihongo" (kanji)
|
||||
ImGui::Text("(CJK text will only appears if the font supports it. Please check in\nthe extra_fonts/ folder if you intend to use non-ASCII characters.\nNote that characters values are preserved even if the font cannot be\ndisplayed, so you can safely copy & paste garbled characters.)");
|
||||
ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)");
|
||||
ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
|
||||
static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
|
||||
ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf));
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
|
||||
static int e = 0;
|
||||
ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
|
||||
ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
|
||||
|
48
imgui.h
48
imgui.h
@ -1,4 +1,4 @@
|
||||
// ImGui library v1.12
|
||||
// ImGui library v1.13
|
||||
// See .cpp file for commentary.
|
||||
// See ImGui::ShowTestWindow() for sample code.
|
||||
// Read 'Programmer guide' in .cpp for notes on how to setup ImGui in your codebase.
|
||||
@ -17,6 +17,7 @@ struct ImGuiWindow;
|
||||
#include "imconfig.h"
|
||||
#include <float.h> // FLT_MAX
|
||||
#include <stdarg.h> // va_list
|
||||
#include <stddef.h> // ptrdiff_t
|
||||
#include <stdlib.h> // NULL, malloc
|
||||
|
||||
#ifndef IM_ASSERT
|
||||
@ -25,6 +26,7 @@ struct ImGuiWindow;
|
||||
#endif
|
||||
|
||||
typedef unsigned int ImU32;
|
||||
typedef unsigned short ImWchar;
|
||||
typedef ImU32 ImGuiID;
|
||||
typedef int ImGuiCol; // enum ImGuiCol_
|
||||
typedef int ImGuiKey; // enum ImGuiKey_
|
||||
@ -400,7 +402,10 @@ struct ImGuiStyle
|
||||
// Read 'Programmer guide' section in .cpp file for general usage.
|
||||
struct ImGuiIO
|
||||
{
|
||||
//------------------------------------------------------------------
|
||||
// Settings (fill once) // Default value:
|
||||
//------------------------------------------------------------------
|
||||
|
||||
ImVec2 DisplaySize; // <unset> // Display size, in pixels. For clamping windows positions.
|
||||
float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds.
|
||||
float IniSavingRate; // = 5.0f // Maximum time between saving .ini file, in seconds. Set to a negative value to disable .ini saving.
|
||||
@ -414,42 +419,56 @@ struct ImGuiIO
|
||||
ImVec2 FontTexUvForWhite; // = (0.0f,0.0f) // Font texture must have a white pixel at this UV coordinate. Adjust if you are using custom texture.
|
||||
float FontBaseScale; // = 1.0f // Base font scale, multiplied by the per-window font scale which you can adjust with SetFontScale()
|
||||
bool FontAllowUserScaling; // = false // Set to allow scaling text with CTRL+Wheel.
|
||||
ImWchar FontFallbackGlyph; // = '?' // Replacement glyph is one isn't found.
|
||||
float PixelCenterOffset; // = 0.0f // Try to set to 0.5f or 0.375f if rendering is blurry
|
||||
|
||||
// Settings - Rendering function (REQUIRED)
|
||||
//------------------------------------------------------------------
|
||||
// User Functions
|
||||
//------------------------------------------------------------------
|
||||
|
||||
// REQUIRED: rendering function.
|
||||
// See example code if you are unsure of how to implement this.
|
||||
void (*RenderDrawListsFn)(ImDrawList** const draw_lists, int count);
|
||||
|
||||
// Settings - Clipboard Support
|
||||
// Override to provide your clipboard handlers.
|
||||
// On Windows architecture, defaults to use the native Win32 clipboard, otherwise default to use a ImGui private clipboard.
|
||||
// NB- for SetClipboardTextFn, the string is *NOT* zero-terminated at 'text_end'
|
||||
// Optional: access OS clipboard (default to use native Win32 clipboard on Windows, otherwise use a ImGui private clipboard)
|
||||
// Override to access OS clipboard on other architectures.
|
||||
const char* (*GetClipboardTextFn)();
|
||||
void (*SetClipboardTextFn)(const char* text, const char* text_end);
|
||||
void (*SetClipboardTextFn)(const char* text);
|
||||
|
||||
// Settings - Memory allocation
|
||||
// Default to posix malloc/realloc/free functions.
|
||||
// Optional: override memory allocations (default to posix malloc/realloc/free)
|
||||
void* (*MemAllocFn)(size_t sz);
|
||||
void* (*MemReallocFn)(void* ptr, size_t sz);
|
||||
void (*MemFreeFn)(void* ptr);
|
||||
|
||||
// Optional: notify OS Input Method Editor of text input position (e.g. when using Japanese/Chinese inputs, otherwise this isn't needed)
|
||||
void (*ImeSetInputScreenPosFn)(int x, int y);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Input - Fill before calling NewFrame()
|
||||
//------------------------------------------------------------------
|
||||
|
||||
ImVec2 MousePos; // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
|
||||
bool MouseDown[5]; // Mouse buttons. ImGui itself only uses button 0 (left button) but you can use others as storage for convenience.
|
||||
int MouseWheel; // Mouse wheel: -1,0,+1
|
||||
bool KeyCtrl; // Keyboard modifier pressed: Control
|
||||
bool KeyShift; // Keyboard modifier pressed: Shift
|
||||
bool KeysDown[512]; // Keyboard keys that are pressed (in whatever order user naturally has access to keyboard data)
|
||||
char InputCharacters[16]; // List of characters input (translated by user from keypress+keyboard state). Fill using AddInputCharacter() helper.
|
||||
ImWchar InputCharacters[16]; // List of characters input (translated by user from keypress+keyboard state). Fill using AddInputCharacter() helper.
|
||||
|
||||
// Function
|
||||
void AddInputCharacter(ImWchar); // Helper to add a new character into InputCharacters[]
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Output - Retrieve after calling NewFrame(), you can use them to discard inputs or hide them from the rest of your application
|
||||
//------------------------------------------------------------------
|
||||
|
||||
bool WantCaptureMouse; // Mouse is hovering a window or widget is active (= ImGui will use your mouse input)
|
||||
bool WantCaptureKeyboard; // Widget is active (= ImGui will use your keyboard input)
|
||||
|
||||
// Function
|
||||
void AddInputCharacter(char c); // Helper to add a new character into InputCharacters[]
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// [Internal] ImGui will maintain those fields for you
|
||||
//------------------------------------------------------------------
|
||||
|
||||
ImVec2 MousePosPrev;
|
||||
ImVec2 MouseDelta;
|
||||
bool MouseClicked[5];
|
||||
@ -670,6 +689,7 @@ struct ImBitmapFont
|
||||
float GetFontSize() const { return (float)Info->FontSize; }
|
||||
bool IsLoaded() const { return Info != NULL && Common != NULL && Glyphs != NULL; }
|
||||
|
||||
ImVec2 CalcTextSize(float size, float max_width, const char* text_begin, const char* text_end, const char** remaining = NULL) const;
|
||||
ImVec2 CalcTextSizeA(float size, float max_width, const char* text_begin, const char* text_end, const char** remaining = NULL) const; // utf8
|
||||
ImVec2 CalcTextSizeW(float size, float max_width, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL) const; // wchar
|
||||
void RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, ImDrawVert*& out_vertices) const;
|
||||
};
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 7.1 KiB |
BIN
web/utf8_sample_01.png
Normal file
BIN
web/utf8_sample_01.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
Reference in New Issue
Block a user