cpu start

This commit is contained in:
moonpower
2026-03-15 12:33:32 +01:00
parent af86719c5a
commit 31c2e522f5
21 changed files with 3571 additions and 1 deletions
File diff suppressed because it is too large Load Diff
+81
View File
@@ -0,0 +1,81 @@
// dear imgui: CPU framebuffer renderer backend
// (supports caller-owned framebuffers/textures in generic packed pixel formats)
//
// Implemented features:
// [X] Renderer: User texture binding. Use 'ImGui_ImplCPU_Texture*' as texture identifier.
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices.
// [X] Renderer: Texture updates support for dynamic font atlas.
#pragma once
#ifndef IMGUI_DISABLE
#include "imgui.h"
struct ImGui_ImplCPU_PixelFormat;
typedef ImU32 (*ImGui_ImplCPU_MapColorFn)(const ImGui_ImplCPU_PixelFormat* format, unsigned char r, unsigned char g, unsigned char b, unsigned char a);
struct ImGui_ImplCPU_PixelFormat
{
int BitsPerPixel;
int BytesPerPixel;
ImU32 Rmask;
ImU32 Gmask;
ImU32 Bmask;
ImU32 Amask;
ImU8 Rshift;
ImU8 Gshift;
ImU8 Bshift;
ImU8 Ashift;
ImU8 Rloss;
ImU8 Gloss;
ImU8 Bloss;
ImU8 Aloss;
const ImU32* Palette; // Optional palette entries stored as IM_COL32(r, g, b, a).
int PaletteSize; // Number of palette entries, or 0 when Palette is unused.
ImGui_ImplCPU_MapColorFn MapColorFn; // Optional indexed/paletted mapping override. Return a raw packed pixel value.
};
enum ImGui_ImplCPU_BuiltinFormat
{
ImGui_ImplCPU_BuiltinFormat_RGBA8888 = 0,
ImGui_ImplCPU_BuiltinFormat_BGRA8888,
ImGui_ImplCPU_BuiltinFormat_ARGB8888,
ImGui_ImplCPU_BuiltinFormat_ABGR8888,
ImGui_ImplCPU_BuiltinFormat_RGB565,
ImGui_ImplCPU_BuiltinFormat_ARGB1555,
ImGui_ImplCPU_BuiltinFormat_RGBA4444,
ImGui_ImplCPU_BuiltinFormat_RGB888,
ImGui_ImplCPU_BuiltinFormat_BGR888,
ImGui_ImplCPU_BuiltinFormat_Alpha8,
ImGui_ImplCPU_BuiltinFormat_COUNT
};
struct ImGui_ImplCPU_Framebuffer
{
unsigned char* Pixels;
int Width;
int Height;
int Pitch;
const ImGui_ImplCPU_PixelFormat* Format; // Optional. Defaults to ImGui_ImplCPU_BuiltinFormat_RGBA8888.
};
struct ImGui_ImplCPU_Texture
{
const unsigned char* Pixels;
int Width;
int Height;
int Pitch;
const ImGui_ImplCPU_PixelFormat* Format; // Optional. Defaults to ImGui_ImplCPU_BuiltinFormat_RGBA8888.
};
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API const ImGui_ImplCPU_PixelFormat* ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat format);
IMGUI_IMPL_API bool ImGui_ImplCPU_Init();
IMGUI_IMPL_API void ImGui_ImplCPU_Shutdown();
IMGUI_IMPL_API void ImGui_ImplCPU_NewFrame();
IMGUI_IMPL_API void ImGui_ImplCPU_RenderDrawData(ImDrawData* draw_data, ImGui_ImplCPU_Framebuffer* framebuffer);
// (Advanced) Use e.g. if you need to precisely control the timing of texture updates
// by setting ImDrawData::Textures = nullptr to handle this manually.
IMGUI_IMPL_API void ImGui_ImplCPU_UpdateTexture(ImTextureData* tex);
#endif // #ifndef IMGUI_DISABLE
+2 -1
View File
@@ -84,6 +84,7 @@ List of Platforms Backends:
List of Renderer Backends: List of Renderer Backends:
imgui_impl_cpu.cpp ; Generic packed-pixel CPU framebuffer renderer (RGBA/BGRA/RGB565/indexed, etc. see example_sdl2_cpu, example_apple_cpu)
imgui_impl_dx9.cpp ; DirectX9 imgui_impl_dx9.cpp ; DirectX9
imgui_impl_dx10.cpp ; DirectX10 imgui_impl_dx10.cpp ; DirectX10
imgui_impl_dx11.cpp ; DirectX11 imgui_impl_dx11.cpp ; DirectX11
@@ -105,7 +106,7 @@ List of high-level Frameworks Backends (combining Platform + Renderer):
imgui_impl_null.cpp imgui_impl_null.cpp
Emscripten is also supported! Emscripten is also supported!
The SDL2+GL, SDL3+GL, SDL2+Surface, SDL3+Surface, GLFW+GL and GLFW+WebGPU examples are all ready to build and run with Emscripten. The SDL2+CPU, SDL2+GL, SDL3+GL, SDL2+Surface, SDL3+Surface, GLFW+GL and GLFW+WebGPU examples are all ready to build and run with Emscripten.
### Recommended Backends ### Recommended Backends
+11
View File
@@ -71,6 +71,11 @@ OSX + OpenGL2 example. <BR>
(NB: imgui_impl_osx.mm is currently not as feature complete as other platforms backends. (NB: imgui_impl_osx.mm is currently not as feature complete as other platforms backends.
You may prefer to use the GLFW Or SDL backends, which will also support Windows and Linux.) You may prefer to use the GLFW Or SDL backends, which will also support Windows and Linux.)
[example_apple_cpu/](https://github.com/ocornut/imgui/blob/master/examples/example_apple_cpu/) <BR>
OSX + CPU framebuffer example. <BR>
= main.mm + imgui_impl_osx.mm + imgui_impl_cpu.cpp <BR>
This is a native Cocoa example, renders to a native BGRA framebuffer, and does not use SDL.<BR>
[example_glfw_wgpu/](https://github.com/ocornut/imgui/blob/master/examples/example_glfw_wgpu/) <BR> [example_glfw_wgpu/](https://github.com/ocornut/imgui/blob/master/examples/example_glfw_wgpu/) <BR>
GLFW + WebGPU example. Supports Emscripten (web), Dawn (native), WGPU (native). <BR> GLFW + WebGPU example. Supports Emscripten (web), Dawn (native), WGPU (native). <BR>
= main.cpp + imgui_impl_glfw.cpp + imgui_impl_wgpu.cpp = main.cpp + imgui_impl_glfw.cpp + imgui_impl_wgpu.cpp
@@ -150,6 +155,12 @@ SDL2 (Win32, Mac, Linux, etc.) + SDL_Surface CPU renderer example.<BR>
= main.cpp + imgui_impl_sdl2.cpp + imgui_impl_sdlsurface2.cpp <BR> = main.cpp + imgui_impl_sdl2.cpp + imgui_impl_sdlsurface2.cpp <BR>
This supports building with Emscripten.<BR> This supports building with Emscripten.<BR>
[example_sdl2_cpu/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_cpu/) <BR>
SDL2 (Win32, Mac, Linux, etc.) + caller-owned packed-pixel CPU framebuffer renderer example.<BR>
= main.cpp + imgui_impl_sdl2.cpp + imgui_impl_cpu.cpp <BR>
This derives the CPU framebuffer format from the current SDL window surface.<BR>
This supports building with Emscripten.<BR>
[example_sdl2_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_vulkan/) <BR> [example_sdl2_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_vulkan/) <BR>
SDL2 (Win32, Mac, Linux, etc.) + Vulkan example. <BR> SDL2 (Win32, Mac, Linux, etc.) + Vulkan example. <BR>
= main.cpp + imgui_impl_sdl2.cpp + imgui_impl_vulkan.cpp <BR> = main.cpp + imgui_impl_sdl2.cpp + imgui_impl_vulkan.cpp <BR>
+23
View File
@@ -0,0 +1,23 @@
# Makefile for example_apple_cpu, for macOS only
CXX = clang++
EXE = example_apple_cpu
IMGUI_DIR = ../..
SOURCES = main.mm
SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_osx.mm $(IMGUI_DIR)/backends/imgui_impl_cpu.cpp
OPTFLAGS ?= -O2
CXXFLAGS = -std=c++11 -ObjC++ -fobjc-arc -g $(OPTFLAGS) -Wall -Wextra -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
FRAMEWORKS = -framework Cocoa -framework GameController
all: $(EXE)
@echo Build complete for Mac OS X
$(EXE): $(SOURCES)
$(CXX) $(CXXFLAGS) $(SOURCES) -o $(EXE) $(FRAMEWORKS)
run: all
./$(EXE)
clean:
rm -f $(EXE) *.o
+14
View File
@@ -0,0 +1,14 @@
# How to Build
## macOS
Use the provided `Makefile` or directly:
```sh
clang++ -std=c++11 -ObjC++ -fobjc-arc -I ../.. -I ../../backends \
main.mm ../../backends/imgui_impl_osx.mm ../../backends/imgui_impl_cpu.cpp ../../imgui*.cpp \
-framework Cocoa -framework GameController \
-o example_apple_cpu
```
This example uses Cocoa + `imgui_impl_osx` for windowing/input and `imgui_impl_cpu` for rendering.
It renders to a native BGRA CPU framebuffer and does not use SDL.
Binary file not shown.
+424
View File
@@ -0,0 +1,424 @@
// Dear ImGui: standalone macOS example using Cocoa + CPU framebuffer rendering.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
#import <Cocoa/Cocoa.h>
#include "imgui.h"
#include "imgui_impl_cpu.h"
#include "imgui_impl_osx.h"
#include <chrono>
#include <cmath>
#include <string.h>
struct ExampleTimingHistory
{
double Samples[120];
int Count;
int Offset;
ExampleTimingHistory() : Count(0), Offset(0) { memset(Samples, 0, sizeof(Samples)); }
void AddSample(double value_ms)
{
Samples[Offset] = value_ms;
Offset = (Offset + 1) % IM_ARRAYSIZE(Samples);
if (Count < IM_ARRAYSIZE(Samples))
Count++;
}
double GetAverageMs() const
{
if (Count == 0)
return 0.0;
double total = 0.0;
for (int i = 0; i < Count; i++)
total += Samples[i];
return total / (double)Count;
}
};
struct ExampleFramebuffer
{
ImVector<unsigned char> Storage;
ImGui_ImplCPU_Framebuffer CPU;
CGColorSpaceRef ColorSpace;
CGDataProviderRef DataProvider;
CGImageRef Image;
ExampleFramebuffer() : ColorSpace(nullptr), DataProvider(nullptr), Image(nullptr)
{
CPU.Pixels = nullptr;
CPU.Width = 0;
CPU.Height = 0;
CPU.Pitch = 0;
CPU.Format = nullptr;
}
};
static double ExampleGetTimeMs()
{
typedef std::chrono::steady_clock Clock;
return std::chrono::duration<double, std::milli>(Clock::now().time_since_epoch()).count();
}
static void DestroyFramebuffer(ExampleFramebuffer* framebuffer)
{
if (framebuffer->Image != nullptr)
{
CGImageRelease(framebuffer->Image);
framebuffer->Image = nullptr;
}
if (framebuffer->DataProvider != nullptr)
{
CGDataProviderRelease(framebuffer->DataProvider);
framebuffer->DataProvider = nullptr;
}
if (framebuffer->ColorSpace != nullptr)
{
CGColorSpaceRelease(framebuffer->ColorSpace);
framebuffer->ColorSpace = nullptr;
}
framebuffer->CPU.Pixels = nullptr;
framebuffer->CPU.Width = 0;
framebuffer->CPU.Height = 0;
framebuffer->CPU.Pitch = 0;
framebuffer->Storage.clear();
}
static ImU32 PackBGRA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
return ((ImU32)b << 24) | ((ImU32)g << 16) | ((ImU32)r << 8) | (ImU32)a;
#else
return (ImU32)b | ((ImU32)g << 8) | ((ImU32)r << 16) | ((ImU32)a << 24);
#endif
}
static bool RecreateFramebuffer(ExampleFramebuffer* framebuffer, int width, int height)
{
DestroyFramebuffer(framebuffer);
framebuffer->Storage.resize(width * height * 4);
framebuffer->CPU.Pixels = framebuffer->Storage.Data;
framebuffer->CPU.Width = width;
framebuffer->CPU.Height = height;
framebuffer->CPU.Pitch = width * 4;
framebuffer->CPU.Format = ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_BGRA8888);
if (framebuffer->CPU.Pixels == nullptr)
return false;
framebuffer->ColorSpace = CGColorSpaceCreateDeviceRGB();
if (framebuffer->ColorSpace == nullptr)
{
DestroyFramebuffer(framebuffer);
return false;
}
framebuffer->DataProvider = CGDataProviderCreateWithData(nullptr, framebuffer->CPU.Pixels, (size_t)framebuffer->CPU.Pitch * (size_t)framebuffer->CPU.Height, nullptr);
if (framebuffer->DataProvider == nullptr)
{
DestroyFramebuffer(framebuffer);
return false;
}
framebuffer->Image = CGImageCreate((size_t)framebuffer->CPU.Width, (size_t)framebuffer->CPU.Height, 8, 32, (size_t)framebuffer->CPU.Pitch, framebuffer->ColorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst, framebuffer->DataProvider, nullptr, false, kCGRenderingIntentDefault);
if (framebuffer->Image == nullptr)
{
DestroyFramebuffer(framebuffer);
return false;
}
return true;
}
static void ClearFramebuffer(ImGui_ImplCPU_Framebuffer* framebuffer, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
const ImU32 pixel = PackBGRA(r, g, b, a);
for (int y = 0; y < framebuffer->Height; y++)
{
ImU32* dst = (ImU32*)(void*)(framebuffer->Pixels + (size_t)y * (size_t)framebuffer->Pitch);
for (int x = 0; x < framebuffer->Width; x++)
dst[x] = pixel;
}
}
//-----------------------------------------------------------------------------------
// AppView
//-----------------------------------------------------------------------------------
@interface AppView : NSView
- (void)shutdownImGui;
@end
@implementation AppView
{
ExampleFramebuffer _framebuffer;
ExampleTimingHistory _rasterTimes;
ExampleTimingHistory _presentTimes;
BOOL _imguiInitialized;
BOOL _frameScheduled;
}
- (instancetype)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
return self;
}
- (BOOL)isFlipped
{
return YES;
}
- (void)viewDidMoveToWindow
{
[super viewDidMoveToWindow];
if (self.window != nil && !_imguiInitialized)
[self initializeImGui];
}
- (void)dealloc
{
[self shutdownImGui];
}
- (void)initializeImGui
{
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
ImGui::StyleColorsDark();
ImGui_ImplOSX_Init(self);
ImGui_ImplCPU_Init();
_imguiInitialized = YES;
[self scheduleNextFrameAfter:0.0];
}
- (void)shutdownImGui
{
if (!_imguiInitialized)
return;
DestroyFramebuffer(&_framebuffer);
ImGui_ImplCPU_Shutdown();
ImGui_ImplOSX_Shutdown();
ImGui::DestroyContext();
_imguiInitialized = NO;
}
// Queue the next draw on the main loop instead of pacing to display refresh.
- (void)scheduleNextFrameAfter:(double)delay_seconds
{
if (_frameScheduled)
return;
_frameScheduled = YES;
dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay_seconds * (double)NSEC_PER_SEC));
dispatch_after(when, dispatch_get_main_queue(), ^{
self->_frameScheduled = NO;
[self setNeedsDisplay:YES];
});
}
- (void)renderFrame
{
if (!_imguiInitialized)
return;
if (self.window == nil || [self.window isMiniaturized])
{
[self scheduleNextFrameAfter:0.01];
return;
}
const CGFloat scale = self.window.backingScaleFactor > 0.0 ? self.window.backingScaleFactor : 1.0;
const int logical_w = (int)llround(self.bounds.size.width);
const int logical_h = (int)llround(self.bounds.size.height);
const int framebuffer_w = (int)llround(self.bounds.size.width * scale);
const int framebuffer_h = (int)llround(self.bounds.size.height * scale);
if (framebuffer_w <= 0 || framebuffer_h <= 0)
{
[self scheduleNextFrameAfter:0.01];
return;
}
if (_framebuffer.CPU.Width != framebuffer_w || _framebuffer.CPU.Height != framebuffer_h)
if (!RecreateFramebuffer(&_framebuffer, framebuffer_w, framebuffer_h))
return;
// Start the Dear ImGui frame
ImGui_ImplCPU_NewFrame();
ImGui_ImplOSX_NewFrame(self);
ImGui::NewFrame();
// Our state
static bool show_demo_window = true;
static bool show_another_window = false;
static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
// 1. Show the big demo window
if (show_demo_window)
ImGui::ShowDemoWindow(&show_demo_window);
// 2. Show a simple window that we create ourselves.
{
static float f = 0.0f;
static int counter = 0;
ImGuiIO& io = ImGui::GetIO();
ImGui::Begin("Hello, world!");
ImGui::Text("This is some useful text.");
ImGui::Checkbox("Demo Window", &show_demo_window);
ImGui::Checkbox("Another Window", &show_another_window);
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
ImGui::ColorEdit3("clear color", (float*)&clear_color);
if (ImGui::Button("Button"))
counter++;
ImGui::SameLine();
ImGui::Text("counter = %d", counter);
ImGui::Text("Raster %.3f ms | Present %.3f ms", _rasterTimes.GetAverageMs(), _presentTimes.GetAverageMs());
ImGui::Text("Window %d x %d | Framebuffer %d x %d (scale %.2f)", logical_w, logical_h, framebuffer_w, framebuffer_h, scale);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End();
}
// 3. Show another simple window.
if (show_another_window)
{
ImGui::Begin("Another Window", &show_another_window);
ImGui::Text("Hello from another window!");
if (ImGui::Button("Close Me"))
show_another_window = false;
ImGui::End();
}
// Rendering
ImGui::Render();
const double raster_start_ms = ExampleGetTimeMs();
ClearFramebuffer(&_framebuffer.CPU,
(unsigned char)(clear_color.x * 255),
(unsigned char)(clear_color.y * 255),
(unsigned char)(clear_color.z * 255),
(unsigned char)(clear_color.w * 255));
ImGui_ImplCPU_RenderDrawData(ImGui::GetDrawData(), &_framebuffer.CPU);
_rasterTimes.AddSample(ExampleGetTimeMs() - raster_start_ms);
}
- (void)drawRect:(NSRect)dirtyRect
{
IM_UNUSED(dirtyRect);
[self renderFrame];
if (_framebuffer.Image != nullptr)
{
CGContextRef context = NSGraphicsContext.currentContext.CGContext;
// CGImage draws with a bottom-up raster convention here, while the CPU framebuffer is top-down.
const double present_start_ms = ExampleGetTimeMs();
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(0.0, 0.0, self.bounds.size.width, self.bounds.size.height), _framebuffer.Image);
CGContextRestoreGState(context);
_presentTimes.AddSample(ExampleGetTimeMs() - present_start_ms);
}
[self scheduleNextFrameAfter:0.0];
}
@end
//-----------------------------------------------------------------------------------
// AppDelegate
//-----------------------------------------------------------------------------------
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (nonatomic, readonly) NSWindow* window;
@property (nonatomic, readonly) AppView* view;
@end
@implementation AppDelegate
{
NSWindow* _window;
AppView* _view;
}
@synthesize window = _window;
@synthesize view = _view;
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)application
{
IM_UNUSED(application);
return YES;
}
- (void)setupMenu
{
NSMenu* main_menu_bar = [[NSMenu alloc] init];
NSMenu* app_menu = [[NSMenu alloc] initWithTitle:@"Dear ImGui macOS+CPU Example"];
NSMenuItem* menu_item = [app_menu addItemWithTitle:@"Quit Dear ImGui macOS+CPU Example" action:@selector(terminate:) keyEquivalent:@"q"];
[menu_item setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
menu_item = [[NSMenuItem alloc] init];
[menu_item setSubmenu:app_menu];
[main_menu_bar addItem:menu_item];
[NSApp setMainMenu:main_menu_bar];
}
- (void)applicationDidFinishLaunching:(NSNotification*)notification
{
IM_UNUSED(notification);
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[self setupMenu];
NSRect view_rect = NSMakeRect(100.0, 100.0, 1280.0, 720.0);
_window = [[NSWindow alloc] initWithContentRect:view_rect styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable | NSWindowStyleMaskClosable backing:NSBackingStoreBuffered defer:NO];
[_window setTitle:@"Dear ImGui macOS+CPU Example"];
[_window setAcceptsMouseMovedEvents:YES];
[_window setOpaque:YES];
_view = [[AppView alloc] initWithFrame:_window.contentView.bounds];
[_view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[_window setContentView:_view];
[_window makeKeyAndOrderFront:NSApp];
[NSApp activateIgnoringOtherApps:YES];
}
- (void)applicationWillTerminate:(NSNotification*)notification
{
IM_UNUSED(notification);
[_view shutdownImGui];
}
@end
int main(int argc, char** argv)
{
IM_UNUSED(argc);
IM_UNUSED(argv);
@autoreleasepool
{
NSApplication* application = [NSApplication sharedApplication];
AppDelegate* delegate = [AppDelegate new];
[application setDelegate:delegate];
[application run];
}
return 0;
}
+73
View File
@@ -0,0 +1,73 @@
#
# Cross Platform Makefile (example_sdl2_cpu)
# Compatible with MSYS2/MINGW, Linux and macOS
#
# You will need SDL2 (http://www.libsdl.org):
# Linux: apt-get install libsdl2-dev
# macOS: brew install sdl2
# MSYS2: pacman -S mingw-w64-i686-SDL2
#
EXE = example_sdl2_cpu
IMGUI_DIR = ../..
SOURCES = main.cpp
SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl2.cpp $(IMGUI_DIR)/backends/imgui_impl_cpu.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
SDL2_CONFIG ?= $(shell if command -v sdl2-config >/dev/null 2>&1; then command -v sdl2-config; elif [ -x /opt/homebrew/bin/sdl2-config ]; then echo /opt/homebrew/bin/sdl2-config; elif [ -x /usr/local/bin/sdl2-config ]; then echo /usr/local/bin/sdl2-config; else echo sdl2-config; fi)
CXXFLAGS = -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
OPTFLAGS ?= -O2
CXXFLAGS += -g $(OPTFLAGS) -Wall -Wformat
LIBS =
##---------------------------------------------------------------------
## BUILD FLAGS PER PLATFORM
##---------------------------------------------------------------------
ifeq ($(UNAME_S), Linux) #LINUX
ECHO_MESSAGE = "Linux"
LIBS += `$(SDL2_CONFIG) --libs`
CXXFLAGS += `$(SDL2_CONFIG) --cflags`
CFLAGS = $(CXXFLAGS)
endif
ifeq ($(UNAME_S), Darwin) #APPLE
ECHO_MESSAGE = "Mac OS X"
LIBS += `$(SDL2_CONFIG) --libs`
CXXFLAGS += `$(SDL2_CONFIG) --cflags`
CXXFLAGS += -I/usr/local/include -I/opt/local/include
CFLAGS = $(CXXFLAGS)
endif
ifeq ($(OS), Windows_NT)
ECHO_MESSAGE = "MinGW"
LIBS += -lgdi32 `pkg-config --static --libs sdl2`
CXXFLAGS += `pkg-config --cflags sdl2`
CFLAGS = $(CXXFLAGS)
endif
##---------------------------------------------------------------------
## BUILD RULES
##---------------------------------------------------------------------
%.o:%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
%.o:$(IMGUI_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
%.o:$(IMGUI_DIR)/backends/%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
all: $(EXE)
@echo Build complete for $(ECHO_MESSAGE)
$(EXE): $(OBJS)
$(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS)
clean:
rm -f $(EXE) $(OBJS)
@@ -0,0 +1,54 @@
CC = emcc
CXX = em++
WEB_DIR = web
EXE = $(WEB_DIR)/index.html
IMGUI_DIR = ../..
SOURCES = main.cpp
SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl2.cpp $(IMGUI_DIR)/backends/imgui_impl_cpu.cpp
OBJS = $(addprefix em_,$(addsuffix .o, $(basename $(notdir $(SOURCES)))))
CPPFLAGS =
LDFLAGS =
EMS =
EMS += -s USE_SDL=2
EMS += -s DISABLE_EXCEPTION_CATCHING=1
LDFLAGS += -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=0 -s ASSERTIONS=1
USE_FILE_SYSTEM ?= 0
ifeq ($(USE_FILE_SYSTEM), 0)
LDFLAGS += -s NO_FILESYSTEM=1
CPPFLAGS += -DIMGUI_DISABLE_FILE_FUNCTIONS
endif
ifeq ($(USE_FILE_SYSTEM), 1)
LDFLAGS += --no-heap-copy --preload-file ../../misc/fonts@/fonts
endif
CPPFLAGS += -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
CPPFLAGS += -Wall -Wformat -O2 $(EMS)
LDFLAGS += --shell-file ../libs/emscripten/shell_minimal.html
LDFLAGS += $(EMS)
em_%.o:%.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
em_%.o:$(IMGUI_DIR)/%.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
em_%.o:$(IMGUI_DIR)/backends/%.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
all: $(EXE)
@echo Build complete for $(EXE)
$(WEB_DIR):
mkdir $@
serve: all
python3 -m http.server -d $(WEB_DIR)
$(EXE): $(OBJS) $(WEB_DIR)
$(CXX) -o $@ $(OBJS) $(LDFLAGS)
clean:
rm -rf $(OBJS) $(WEB_DIR)
+47
View File
@@ -0,0 +1,47 @@
# How to Build
## Windows with Visual Studio's IDE
Use the provided project file (`example_sdl2_cpu.vcxproj`) or open `imgui_examples.sln`.
## Windows with Visual Studio's CLI
Use `build_win32.bat` or directly:
```
set SDL2_DIR=path_to_your_sdl2_folder
cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL2_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl2.cpp ..\..\backends\imgui_impl_cpu.cpp ..\..\imgui*.cpp /FeDebug/example_sdl2_cpu.exe /FoDebug/ /link /libpath:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib /subsystem:console
# ^^ include paths ^^ source files ^^ output exe ^^ output dir ^^ libraries
# or for 64-bit:
cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL2_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl2.cpp ..\..\backends\imgui_impl_cpu.cpp ..\..\imgui*.cpp /FeDebug/example_sdl2_cpu.exe /FoDebug/ /link /libpath:%SDL2_DIR%\lib\x64 SDL2.lib SDL2main.lib /subsystem:console
```
## Linux and similar Unixes
Use the provided `Makefile` or directly:
```
c++ `sdl2-config --cflags` -I .. -I ../.. -I ../../backends \
main.cpp ../../backends/imgui_impl_sdl2.cpp ../../backends/imgui_impl_cpu.cpp ../../imgui*.cpp \
`sdl2-config --libs`
```
## macOS
Use the provided `Makefile` or directly:
```
brew install sdl2
c++ `sdl2-config --cflags` -I .. -I ../.. -I ../../backends \
main.cpp ../../backends/imgui_impl_sdl2.cpp ../../backends/imgui_impl_cpu.cpp ../../imgui*.cpp \
`sdl2-config --libs`
```
## Emscripten
Use `Makefile.emscripten`:
```sh
source /path/to/emsdk/emsdk_env.sh
make -f Makefile.emscripten
```
This makes `web/index.html`, `web/index.js`, and `web/index.wasm`.
This example keeps Dear ImGui on the CPU and allocates its framebuffer in the active SDL window surface format, rather than forcing a fixed RGBA32 output format.
@@ -0,0 +1,8 @@
@REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler.
@set OUT_DIR=Debug
@set OUT_EXE=example_sdl2_cpu
@set INCLUDES=/I..\.. /I..\..\backends /I%SDL2_DIR%\include
@set SOURCES=main.cpp ..\..\backends\imgui_impl_sdl2.cpp ..\..\backends\imgui_impl_cpu.cpp ..\..\imgui*.cpp
@set LIBS=/LIBPATH:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib
mkdir %OUT_DIR%
cl /nologo /Zi /O2 /MD /utf-8 %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console
Binary file not shown.
@@ -0,0 +1,187 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.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="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{1E9DB182-9BF1-4C7D-8930-85ACAEAC2458}</ProjectGuid>
<RootNamespace>example_sdl2_cpu</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<ProjectName>example_sdl2_cpu</ProjectName>
</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>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</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 Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<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>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(ProjectDir)$(Configuration)\</OutDir>
<IntDir>$(ProjectDir)$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(ProjectDir)$(Configuration)\</OutDir>
<IntDir>$(ProjectDir)$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(ProjectDir)$(Configuration)\</OutDir>
<IntDir>$(ProjectDir)$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(ProjectDir)$(Configuration)\</OutDir>
<IntDir>$(ProjectDir)$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>%SDL2_DIR%\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>%SDL2_DIR%\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>%SDL2_DIR%\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>%SDL2_DIR%\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\imgui.cpp" />
<ClCompile Include="..\..\imgui_demo.cpp" />
<ClCompile Include="..\..\imgui_draw.cpp" />
<ClCompile Include="..\..\imgui_tables.cpp" />
<ClCompile Include="..\..\imgui_widgets.cpp" />
<ClCompile Include="..\..\backends\imgui_impl_sdl2.cpp" />
<ClCompile Include="..\..\backends\imgui_impl_cpu.cpp" />
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\imconfig.h" />
<ClInclude Include="..\..\imgui.h" />
<ClInclude Include="..\..\imgui_internal.h" />
<ClInclude Include="..\..\backends\imgui_impl_sdl2.h" />
<ClInclude Include="..\..\backends\imgui_impl_cpu.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\misc\debuggers\imgui.natstepfilter" />
<None Include="..\..\misc\debuggers\imgui.natvis" />
<None Include="..\README.txt" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="imgui">
<UniqueIdentifier>{20b90ce4-7fcb-4731-b9a0-075f875de82d}</UniqueIdentifier>
</Filter>
<Filter Include="sources">
<UniqueIdentifier>{f18ab499-84e1-499f-8eff-9754361e0e52}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\imgui.cpp">
<Filter>imgui</Filter>
</ClCompile>
<ClCompile Include="..\..\imgui_demo.cpp">
<Filter>imgui</Filter>
</ClCompile>
<ClCompile Include="..\..\imgui_draw.cpp">
<Filter>imgui</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<Filter>sources</Filter>
</ClCompile>
<ClCompile Include="..\..\imgui_tables.cpp">
<Filter>imgui</Filter>
</ClCompile>
<ClCompile Include="..\..\imgui_widgets.cpp">
<Filter>imgui</Filter>
</ClCompile>
<ClCompile Include="..\..\backends\imgui_impl_sdl2.cpp">
<Filter>sources</Filter>
</ClCompile>
<ClCompile Include="..\..\backends\imgui_impl_cpu.cpp">
<Filter>sources</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\imconfig.h">
<Filter>imgui</Filter>
</ClInclude>
<ClInclude Include="..\..\imgui.h">
<Filter>imgui</Filter>
</ClInclude>
<ClInclude Include="..\..\imgui_internal.h">
<Filter>imgui</Filter>
</ClInclude>
<ClInclude Include="..\..\backends\imgui_impl_cpu.h">
<Filter>sources</Filter>
</ClInclude>
<ClInclude Include="..\..\backends\imgui_impl_sdl2.h">
<Filter>sources</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\README.txt" />
<None Include="..\..\misc\debuggers\imgui.natvis">
<Filter>imgui</Filter>
</None>
<None Include="..\..\misc\debuggers\imgui.natstepfilter">
<Filter>imgui</Filter>
</None>
</ItemGroup>
</Project>
+321
View File
@@ -0,0 +1,321 @@
// main.cpp
// Example program using imgui_impl_cpu backend
#include "imgui.h"
#include "imgui_impl_cpu.h"
#include "imgui_impl_sdl2.h"
#include <SDL.h>
#include <chrono>
#include <stdio.h>
#include <string.h>
#ifdef __EMSCRIPTEN__
#include "../libs/emscripten/emscripten_mainloop_stub.h"
#endif
struct ExampleTimingHistory
{
double Samples[120];
int Count;
int Offset;
ExampleTimingHistory() : Count(0), Offset(0) { memset(Samples, 0, sizeof(Samples)); }
void AddSample(double value_ms)
{
Samples[Offset] = value_ms;
Offset = (Offset + 1) % IM_ARRAYSIZE(Samples);
if (Count < IM_ARRAYSIZE(Samples))
Count++;
}
double GetAverageMs() const
{
if (Count == 0)
return 0.0;
double total = 0.0;
for (int i = 0; i < Count; i++)
total += Samples[i];
return total / (double)Count;
}
};
struct ExampleFramebuffer
{
ImVector<unsigned char> Storage;
ImVector<ImU32> Palette;
ImGui_ImplCPU_PixelFormat Format;
ImGui_ImplCPU_Framebuffer CPU;
SDL_Surface* Surface;
Uint32 SDLFormat;
ExampleFramebuffer() { memset((void*)this, 0, sizeof(*this)); }
};
static double ExampleGetTimeMs()
{
typedef std::chrono::steady_clock Clock;
return std::chrono::duration<double, std::milli>(Clock::now().time_since_epoch()).count();
}
static void InitCPUFormatFromSDL(ImGui_ImplCPU_PixelFormat* out, ImVector<ImU32>* out_palette, const SDL_PixelFormat* format)
{
memset(out, 0, sizeof(*out));
out->BitsPerPixel = format->BitsPerPixel;
out->BytesPerPixel = format->BytesPerPixel;
out->Rmask = format->Rmask;
out->Gmask = format->Gmask;
out->Bmask = format->Bmask;
out->Amask = format->Amask;
out->Rshift = (ImU8)format->Rshift;
out->Gshift = (ImU8)format->Gshift;
out->Bshift = (ImU8)format->Bshift;
out->Ashift = (ImU8)format->Ashift;
out->Rloss = (ImU8)format->Rloss;
out->Gloss = (ImU8)format->Gloss;
out->Bloss = (ImU8)format->Bloss;
out->Aloss = (ImU8)format->Aloss;
out->Palette = nullptr;
out->PaletteSize = 0;
out->MapColorFn = nullptr;
out_palette->clear();
if (format->palette != nullptr && format->palette->colors != nullptr && format->palette->ncolors > 0)
{
out_palette->resize(format->palette->ncolors);
for (int i = 0; i < format->palette->ncolors; i++)
{
const SDL_Color& c = format->palette->colors[i];
(*out_palette)[i] = IM_COL32(c.r, c.g, c.b, c.a);
}
out->Palette = out_palette->Data;
out->PaletteSize = out_palette->Size;
}
}
static bool RecreateFramebuffer(ExampleFramebuffer* framebuffer, SDL_Surface* window_surface)
{
if (framebuffer->Surface != nullptr)
{
SDL_FreeSurface(framebuffer->Surface);
framebuffer->Surface = nullptr;
}
const int width = window_surface->w;
const int height = window_surface->h;
const int bytes_per_pixel = window_surface->format->BytesPerPixel;
if (width <= 0 || height <= 0 || bytes_per_pixel <= 0)
return false;
InitCPUFormatFromSDL(&framebuffer->Format, &framebuffer->Palette, window_surface->format);
framebuffer->Storage.resize(width * height * bytes_per_pixel);
framebuffer->CPU.Pixels = framebuffer->Storage.Data;
framebuffer->CPU.Width = width;
framebuffer->CPU.Height = height;
framebuffer->CPU.Pitch = width * bytes_per_pixel;
framebuffer->CPU.Format = &framebuffer->Format;
framebuffer->SDLFormat = window_surface->format->format;
framebuffer->Surface = SDL_CreateRGBSurfaceWithFormatFrom(framebuffer->CPU.Pixels, width, height, window_surface->format->BitsPerPixel, framebuffer->CPU.Pitch, window_surface->format->format);
return framebuffer->Surface != nullptr;
}
int main(int, char**)
{
// Setup SDL
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0)
{
printf("Error: %s\n", SDL_GetError());
return -1;
}
// From 2.0.18: Enable native IME.
#ifdef SDL_HINT_IME_SHOW_UI
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
#endif
// Create window
float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0);
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_SHOWN);
SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+CPU Example",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
(int)(1280 * main_scale), (int)(720 * main_scale), window_flags);
if (!window)
{
printf("Error creating window: %s\n", SDL_GetError());
return -1;
}
SDL_Surface* window_surface = SDL_GetWindowSurface(window);
if (!window_surface)
{
printf("Error getting window surface: %s\n", SDL_GetError());
return -1;
}
int win_w = window_surface->w;
int win_h = window_surface->h;
ExampleFramebuffer framebuffer;
if (!RecreateFramebuffer(&framebuffer, window_surface))
{
printf("Error creating framebuffer: %s\n", SDL_GetError());
return -1;
}
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
#ifdef __EMSCRIPTEN__
io.IniFilename = nullptr;
#endif
// Setup Dear ImGui style
ImGui::StyleColorsDark();
// Setup scaling
ImGuiStyle& style = ImGui::GetStyle();
style.ScaleAllSizes(main_scale); // Bake a fixed style scale.
style.FontScaleDpi = main_scale;
// Setup Platform/Renderer backends
ImGui_ImplSDL2_InitForOther(window);
ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode_AutoFirst, nullptr, 0);
ImGui_ImplCPU_Init();
// Our state
bool show_demo_window = true;
bool show_another_window = false;
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
ExampleTimingHistory raster_times;
ExampleTimingHistory present_times;
// Main loop
bool done = false;
#ifdef __EMSCRIPTEN__
EMSCRIPTEN_MAINLOOP_BEGIN
#else
while (!done)
#endif
{
// Poll and handle events (inputs, window resize, etc.)
SDL_Event event;
while (SDL_PollEvent(&event))
{
ImGui_ImplSDL2_ProcessEvent(&event);
if (event.type == SDL_QUIT)
done = true;
if (event.type == SDL_WINDOWEVENT)
{
if (event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
done = true;
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED || event.window.event == SDL_WINDOWEVENT_RESIZED)
{
// Recreate framebuffer at new size
window_surface = SDL_GetWindowSurface(window);
int new_w = window_surface->w;
int new_h = window_surface->h;
if (new_w != win_w || new_h != win_h || window_surface->format->format != framebuffer.SDLFormat)
{
if (!RecreateFramebuffer(&framebuffer, window_surface))
{
printf("Error creating framebuffer after resize: %s\n", SDL_GetError());
return -1;
}
win_w = new_w;
win_h = new_h;
}
}
}
}
// Skip rendering when minimized to avoid busy-looping
if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)
{
SDL_Delay(10);
continue;
}
// Start the Dear ImGui frame
ImGui_ImplCPU_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
int logical_w = 0;
int logical_h = 0;
SDL_GetWindowSize(window, &logical_w, &logical_h);
// 1. Show the big demo window
if (show_demo_window)
ImGui::ShowDemoWindow(&show_demo_window);
// 2. Show a simple window that we create ourselves. Mirror the SDL_Renderer example.
{
static float f = 0.0f;
static int counter = 0;
ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
ImGui::Text("This is some useful text."); // Display some text
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked
counter++;
ImGui::SameLine();
ImGui::Text("counter = %d", counter);
ImGui::Text("Raster %.3f ms | Present %.3f ms", raster_times.GetAverageMs(), present_times.GetAverageMs());
ImGui::Text("Window %d x %d | Framebuffer %d x %d", logical_w, logical_h, framebuffer.CPU.Width, framebuffer.CPU.Height);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End();
}
// 3. Show another simple window.
if (show_another_window)
{
ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
ImGui::Text("Hello from another window!");
if (ImGui::Button("Close Me"))
show_another_window = false;
ImGui::End();
}
// Rendering
ImGui::Render();
const double raster_start_ms = ExampleGetTimeMs();
SDL_FillRect(framebuffer.Surface, nullptr, SDL_MapRGBA(framebuffer.Surface->format,
(Uint8)(clear_color.x * 255),
(Uint8)(clear_color.y * 255),
(Uint8)(clear_color.z * 255),
(Uint8)(clear_color.w * 255)));
ImGui_ImplCPU_RenderDrawData(ImGui::GetDrawData(), &framebuffer.CPU);
raster_times.AddSample(ExampleGetTimeMs() - raster_start_ms);
const double present_start_ms = ExampleGetTimeMs();
SDL_BlitSurface(framebuffer.Surface, nullptr, window_surface, nullptr);
SDL_UpdateWindowSurface(window);
present_times.AddSample(ExampleGetTimeMs() - present_start_ms);
}
#ifdef __EMSCRIPTEN__
EMSCRIPTEN_MAINLOOP_END;
#endif
ImGui_ImplCPU_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
if (framebuffer.Surface != nullptr)
SDL_FreeSurface(framebuffer.Surface);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
+47
View File
@@ -5,11 +5,46 @@
#include "imgui_impl_sdl2.h" #include "imgui_impl_sdl2.h"
#include "imgui_impl_sdlsurface2.h" #include "imgui_impl_sdlsurface2.h"
#include <SDL.h> #include <SDL.h>
#include <chrono>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
#include "../libs/emscripten/emscripten_mainloop_stub.h" #include "../libs/emscripten/emscripten_mainloop_stub.h"
#endif #endif
struct ExampleTimingHistory
{
double Samples[120];
int Count;
int Offset;
ExampleTimingHistory() : Count(0), Offset(0) { memset(Samples, 0, sizeof(Samples)); }
void AddSample(double value_ms)
{
Samples[Offset] = value_ms;
Offset = (Offset + 1) % IM_ARRAYSIZE(Samples);
if (Count < IM_ARRAYSIZE(Samples))
Count++;
}
double GetAverageMs() const
{
if (Count == 0)
return 0.0;
double total = 0.0;
for (int i = 0; i < Count; i++)
total += Samples[i];
return total / (double)Count;
}
};
static double ExampleGetTimeMs()
{
typedef std::chrono::steady_clock Clock;
return std::chrono::duration<double, std::milli>(Clock::now().time_since_epoch()).count();
}
int main(int, char**) int main(int, char**)
{ {
// Setup SDL // Setup SDL
@@ -79,6 +114,8 @@ int main(int, char**)
bool show_demo_window = true; bool show_demo_window = true;
bool show_another_window = false; bool show_another_window = false;
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
ExampleTimingHistory raster_times;
ExampleTimingHistory present_times;
// Main loop // Main loop
bool done = false; bool done = false;
@@ -133,6 +170,10 @@ int main(int, char**)
ImGui_ImplSDL2_NewFrame(); ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
int logical_w = 0;
int logical_h = 0;
SDL_GetWindowSize(window, &logical_w, &logical_h);
// 1. Show the big demo window // 1. Show the big demo window
if (show_demo_window) if (show_demo_window)
ImGui::ShowDemoWindow(&show_demo_window); ImGui::ShowDemoWindow(&show_demo_window);
@@ -156,6 +197,8 @@ int main(int, char**)
ImGui::SameLine(); ImGui::SameLine();
ImGui::Text("counter = %d", counter); ImGui::Text("counter = %d", counter);
ImGui::Text("Raster %.3f ms | Present %.3f ms", raster_times.GetAverageMs(), present_times.GetAverageMs());
ImGui::Text("Window %d x %d | Framebuffer %d x %d", logical_w, logical_h, framebuffer->w, framebuffer->h);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End(); ImGui::End();
} }
@@ -173,6 +216,7 @@ int main(int, char**)
// Rendering // Rendering
ImGui::Render(); ImGui::Render();
const double raster_start_ms = ExampleGetTimeMs();
SDL_FillRect(framebuffer, nullptr, SDL_MapRGBA(framebuffer->format, SDL_FillRect(framebuffer, nullptr, SDL_MapRGBA(framebuffer->format,
(Uint8)(clear_color.x * 255), (Uint8)(clear_color.x * 255),
(Uint8)(clear_color.y * 255), (Uint8)(clear_color.y * 255),
@@ -180,9 +224,12 @@ int main(int, char**)
(Uint8)(clear_color.w * 255))); (Uint8)(clear_color.w * 255)));
ImGui_ImplSDLSurface2_RenderDrawData(ImGui::GetDrawData()); ImGui_ImplSDLSurface2_RenderDrawData(ImGui::GetDrawData());
raster_times.AddSample(ExampleGetTimeMs() - raster_start_ms);
const double present_start_ms = ExampleGetTimeMs();
SDL_BlitSurface(framebuffer, nullptr, window_surface, nullptr); SDL_BlitSurface(framebuffer, nullptr, window_surface, nullptr);
SDL_UpdateWindowSurface(window); SDL_UpdateWindowSurface(window);
present_times.AddSample(ExampleGetTimeMs() - present_start_ms);
} }
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
EMSCRIPTEN_MAINLOOP_END; EMSCRIPTEN_MAINLOOP_END;
+10
View File
@@ -31,6 +31,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl2_sdlrenderer2",
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl2_surface", "example_sdl2_surface\example_sdl2_surface.vcxproj", "{47525E56-7D05-474E-A455-64C5BBFFC029}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl2_surface", "example_sdl2_surface\example_sdl2_surface.vcxproj", "{47525E56-7D05-474E-A455-64C5BBFFC029}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl2_cpu", "example_sdl2_cpu\example_sdl2_cpu.vcxproj", "{1E9DB182-9BF1-4C7D-8930-85ACAEAC2458}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_opengl3", "example_sdl3_opengl3\example_sdl3_opengl3.vcxproj", "{84AAA301-84FE-428B-9E3E-817BC8123C0C}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_opengl3", "example_sdl3_opengl3\example_sdl3_opengl3.vcxproj", "{84AAA301-84FE-428B-9E3E-817BC8123C0C}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_sdlrenderer3", "example_sdl3_sdlrenderer3\example_sdl3_sdlrenderer3.vcxproj", "{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_sdlrenderer3", "example_sdl3_sdlrenderer3\example_sdl3_sdlrenderer3.vcxproj", "{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}"
@@ -167,6 +169,14 @@ Global
{47525E56-7D05-474E-A455-64C5BBFFC029}.Release|Win32.Build.0 = Release|Win32 {47525E56-7D05-474E-A455-64C5BBFFC029}.Release|Win32.Build.0 = Release|Win32
{47525E56-7D05-474E-A455-64C5BBFFC029}.Release|x64.ActiveCfg = Release|x64 {47525E56-7D05-474E-A455-64C5BBFFC029}.Release|x64.ActiveCfg = Release|x64
{47525E56-7D05-474E-A455-64C5BBFFC029}.Release|x64.Build.0 = Release|x64 {47525E56-7D05-474E-A455-64C5BBFFC029}.Release|x64.Build.0 = Release|x64
{1E9DB182-9BF1-4C7D-8930-85ACAEAC2458}.Debug|Win32.ActiveCfg = Debug|Win32
{1E9DB182-9BF1-4C7D-8930-85ACAEAC2458}.Debug|Win32.Build.0 = Debug|Win32
{1E9DB182-9BF1-4C7D-8930-85ACAEAC2458}.Debug|x64.ActiveCfg = Debug|x64
{1E9DB182-9BF1-4C7D-8930-85ACAEAC2458}.Debug|x64.Build.0 = Debug|x64
{1E9DB182-9BF1-4C7D-8930-85ACAEAC2458}.Release|Win32.ActiveCfg = Release|Win32
{1E9DB182-9BF1-4C7D-8930-85ACAEAC2458}.Release|Win32.Build.0 = Release|Win32
{1E9DB182-9BF1-4C7D-8930-85ACAEAC2458}.Release|x64.ActiveCfg = Release|x64
{1E9DB182-9BF1-4C7D-8930-85ACAEAC2458}.Release|x64.Build.0 = Release|x64
{84AAA301-84FE-428B-9E3E-817BC8123C0C}.Debug|Win32.ActiveCfg = Debug|Win32 {84AAA301-84FE-428B-9E3E-817BC8123C0C}.Debug|Win32.ActiveCfg = Debug|Win32
{84AAA301-84FE-428B-9E3E-817BC8123C0C}.Debug|Win32.Build.0 = Debug|Win32 {84AAA301-84FE-428B-9E3E-817BC8123C0C}.Debug|Win32.Build.0 = Debug|Win32
{84AAA301-84FE-428B-9E3E-817BC8123C0C}.Debug|x64.ActiveCfg = Debug|x64 {84AAA301-84FE-428B-9E3E-817BC8123C0C}.Debug|x64.ActiveCfg = Debug|x64
+1
View File
@@ -2,6 +2,7 @@
misc/cpp/ misc/cpp/
InputText() wrappers for C++ standard library (STL) type: std::string. InputText() wrappers for C++ standard library (STL) type: std::string.
This is also an example of how you may wrap your own similar types. This is also an example of how you may wrap your own similar types.
Includes imgui_cpu_validate.cpp, an offscreen validation utility for the imgui_impl_cpu backend.
misc/debuggers/ misc/debuggers/
Helper files for popular debuggers (Visual Studio, GDB, LLDB). Helper files for popular debuggers (Visual Studio, GDB, LLDB).
BIN
View File
Binary file not shown.
+385
View File
@@ -0,0 +1,385 @@
// dear imgui: imgui_impl_cpu format validation utility
// Build manually with imgui core sources + backends/imgui_impl_cpu.cpp.
#include "imgui.h"
#include "imgui_impl_cpu.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct ValidationBuffer
{
ImVector<unsigned char> Storage;
ImVector<ImU32> Palette;
ImGui_ImplCPU_PixelFormat Format;
ImGui_ImplCPU_Framebuffer Framebuffer;
ValidationBuffer() { memset((void*)this, 0, sizeof(*this)); }
};
static inline unsigned char Validation_ExpandBits(ImU32 value, int bits)
{
if (bits <= 0)
return 0;
if (bits >= 8)
return (unsigned char)value;
ImU32 max_value = (1u << bits) - 1u;
return (unsigned char)((value * 255u + (max_value >> 1)) / max_value);
}
static inline ImU32 Validation_CompressBits(unsigned char value, int bits)
{
if (bits <= 0)
return 0;
if (bits >= 8)
return value;
ImU32 max_value = (1u << bits) - 1u;
return (ImU32)((value * max_value + 127u) / 255u);
}
static inline void Validation_UnpackCanonicalRGBA(ImU32 pixel, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
{
*r = (unsigned char)((pixel >> IM_COL32_R_SHIFT) & 0xFF);
*g = (unsigned char)((pixel >> IM_COL32_G_SHIFT) & 0xFF);
*b = (unsigned char)((pixel >> IM_COL32_B_SHIFT) & 0xFF);
*a = (unsigned char)((pixel >> IM_COL32_A_SHIFT) & 0xFF);
}
static inline ImU32 Validation_ReadRawPixel(const ValidationBuffer& buffer, int x, int y)
{
const unsigned char* p = buffer.Framebuffer.Pixels + (size_t)y * (size_t)buffer.Framebuffer.Pitch + (size_t)x * (size_t)buffer.Format.BytesPerPixel;
switch (buffer.Format.BytesPerPixel)
{
case 1:
return *p;
case 2:
{
ImU16 pixel = 0;
memcpy(&pixel, p, sizeof(pixel));
return pixel;
}
case 3:
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
return (ImU32)((p[0] << 16) | (p[1] << 8) | p[2]);
#else
return (ImU32)(p[0] | (p[1] << 8) | (p[2] << 16));
#endif
case 4:
{
ImU32 pixel = 0;
memcpy(&pixel, p, sizeof(pixel));
return pixel;
}
default:
return 0;
}
}
static inline void Validation_WriteRawPixel(ValidationBuffer* buffer, int x, int y, ImU32 pixel)
{
unsigned char* p = buffer->Framebuffer.Pixels + (size_t)y * (size_t)buffer->Framebuffer.Pitch + (size_t)x * (size_t)buffer->Format.BytesPerPixel;
switch (buffer->Format.BytesPerPixel)
{
case 1:
*p = (unsigned char)pixel;
return;
case 2:
{
ImU16 v = (ImU16)pixel;
memcpy(p, &v, sizeof(v));
return;
}
case 3:
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
p[0] = (unsigned char)((pixel >> 16) & 0xFF);
p[1] = (unsigned char)((pixel >> 8) & 0xFF);
p[2] = (unsigned char)(pixel & 0xFF);
#else
p[0] = (unsigned char)(pixel & 0xFF);
p[1] = (unsigned char)((pixel >> 8) & 0xFF);
p[2] = (unsigned char)((pixel >> 16) & 0xFF);
#endif
return;
case 4:
memcpy(p, &pixel, sizeof(pixel));
return;
default:
return;
}
}
static ImU32 Validation_MapNearestPaletteColor(const ImGui_ImplCPU_PixelFormat* format, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
unsigned int best_distance = 0xFFFFFFFFu;
int best_index = 0;
for (int i = 0; i < format->PaletteSize; i++)
{
unsigned char pr, pg, pb, pa;
Validation_UnpackCanonicalRGBA(format->Palette[i], &pr, &pg, &pb, &pa);
int dr = (int)pr - (int)r;
int dg = (int)pg - (int)g;
int db = (int)pb - (int)b;
int da = (int)pa - (int)a;
unsigned int distance = (unsigned int)(dr * dr + dg * dg + db * db + da * da);
if (distance < best_distance)
{
best_distance = distance;
best_index = i;
if (distance == 0)
break;
}
}
return (ImU32)best_index;
}
static ImU32 Validation_PackPixel(const ValidationBuffer& buffer, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
if (buffer.Format.Palette != nullptr && buffer.Format.PaletteSize > 0)
{
if (buffer.Format.MapColorFn != nullptr)
return buffer.Format.MapColorFn(&buffer.Format, r, g, b, a);
return Validation_MapNearestPaletteColor(&buffer.Format, r, g, b, a);
}
ImU32 pixel = 0;
if (buffer.Format.Rmask != 0)
pixel |= (Validation_CompressBits(r, 8 - buffer.Format.Rloss) << buffer.Format.Rshift) & buffer.Format.Rmask;
if (buffer.Format.Gmask != 0)
pixel |= (Validation_CompressBits(g, 8 - buffer.Format.Gloss) << buffer.Format.Gshift) & buffer.Format.Gmask;
if (buffer.Format.Bmask != 0)
pixel |= (Validation_CompressBits(b, 8 - buffer.Format.Bloss) << buffer.Format.Bshift) & buffer.Format.Bmask;
if (buffer.Format.Amask != 0)
pixel |= (Validation_CompressBits(a, 8 - buffer.Format.Aloss) << buffer.Format.Ashift) & buffer.Format.Amask;
return pixel;
}
static void Validation_DecodePixel(const ValidationBuffer& buffer, int x, int y, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
{
ImU32 pixel = Validation_ReadRawPixel(buffer, x, y);
if (buffer.Format.Palette != nullptr && buffer.Format.PaletteSize > 0)
{
if (pixel >= (ImU32)buffer.Format.PaletteSize)
{
*r = *g = *b = *a = 0;
return;
}
Validation_UnpackCanonicalRGBA(buffer.Format.Palette[pixel], r, g, b, a);
return;
}
*r = (buffer.Format.Rmask != 0) ? Validation_ExpandBits((pixel & buffer.Format.Rmask) >> buffer.Format.Rshift, 8 - buffer.Format.Rloss) : 0;
*g = (buffer.Format.Gmask != 0) ? Validation_ExpandBits((pixel & buffer.Format.Gmask) >> buffer.Format.Gshift, 8 - buffer.Format.Gloss) : 0;
*b = (buffer.Format.Bmask != 0) ? Validation_ExpandBits((pixel & buffer.Format.Bmask) >> buffer.Format.Bshift, 8 - buffer.Format.Bloss) : 0;
*a = (buffer.Format.Amask != 0) ? Validation_ExpandBits((pixel & buffer.Format.Amask) >> buffer.Format.Ashift, 8 - buffer.Format.Aloss) : 255;
}
static bool Validation_InitBuffer(ValidationBuffer* buffer, int width, int height, const ImGui_ImplCPU_PixelFormat* format)
{
buffer->Format = *format;
buffer->Framebuffer.Width = width;
buffer->Framebuffer.Height = height;
buffer->Framebuffer.Pitch = width * buffer->Format.BytesPerPixel;
buffer->Storage.resize(height * buffer->Framebuffer.Pitch);
buffer->Framebuffer.Pixels = buffer->Storage.Data;
buffer->Framebuffer.Format = &buffer->Format;
return buffer->Framebuffer.Pixels != nullptr;
}
static bool Validation_InitIndexedBuffer(ValidationBuffer* buffer, int width, int height)
{
buffer->Palette.clear();
buffer->Palette.push_back(IM_COL32(114, 140, 153, 255));
buffer->Palette.push_back(IM_COL32(255, 0, 0, 255));
buffer->Palette.push_back(IM_COL32(0, 255, 0, 255));
buffer->Palette.push_back(IM_COL32(0, 0, 255, 255));
buffer->Palette.push_back(IM_COL32(255, 255, 255, 255));
buffer->Palette.push_back(IM_COL32(255, 255, 0, 255));
memset(&buffer->Format, 0, sizeof(buffer->Format));
buffer->Format.BitsPerPixel = 8;
buffer->Format.BytesPerPixel = 1;
buffer->Format.Palette = buffer->Palette.Data;
buffer->Format.PaletteSize = buffer->Palette.Size;
buffer->Format.MapColorFn = Validation_MapNearestPaletteColor;
return Validation_InitBuffer(buffer, width, height, &buffer->Format);
}
static void Validation_ClearBuffer(ValidationBuffer* buffer, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
ImU32 pixel = Validation_PackPixel(*buffer, r, g, b, a);
for (int y = 0; y < buffer->Framebuffer.Height; y++)
for (int x = 0; x < buffer->Framebuffer.Width; x++)
Validation_WriteRawPixel(buffer, x, y, pixel);
}
static bool Validation_CompareBuffers(const char* name, const ValidationBuffer& reference, const ValidationBuffer& candidate, int tolerance_rgb, int tolerance_alpha, bool ignore_alpha)
{
for (int y = 0; y < reference.Framebuffer.Height; y++)
for (int x = 0; x < reference.Framebuffer.Width; x++)
{
unsigned char rr, rg, rb, ra;
unsigned char cr, cg, cb, ca;
Validation_DecodePixel(reference, x, y, &rr, &rg, &rb, &ra);
Validation_DecodePixel(candidate, x, y, &cr, &cg, &cb, &ca);
if (abs((int)rr - (int)cr) > tolerance_rgb
|| abs((int)rg - (int)cg) > tolerance_rgb
|| abs((int)rb - (int)cb) > tolerance_rgb
|| (!ignore_alpha && abs((int)ra - (int)ca) > tolerance_alpha))
{
printf("Validation failed for %s at (%d, %d): ref=(%u,%u,%u,%u) got=(%u,%u,%u,%u)\n",
name, x, y, rr, rg, rb, ra, cr, cg, cb, ca);
return false;
}
}
return true;
}
static void Validation_FillBGRAImage(ImVector<unsigned char>* storage, ImGui_ImplCPU_Texture* texture)
{
const int width = 48;
const int height = 32;
storage->resize(width * height * 4);
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
{
unsigned char r = (unsigned char)(32 + x * 4);
unsigned char g = (unsigned char)(32 + y * 6);
unsigned char b = (unsigned char)(255 - x * 4);
int offset = (y * width + x) * 4;
(*storage)[offset + 0] = b;
(*storage)[offset + 1] = g;
(*storage)[offset + 2] = r;
(*storage)[offset + 3] = 255;
}
texture->Pixels = storage->Data;
texture->Width = width;
texture->Height = height;
texture->Pitch = width * 4;
texture->Format = ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_BGRA8888);
}
static void Validation_BuildMainScene(const ImGui_ImplCPU_Texture* image_texture)
{
ImDrawList* bg = ImGui::GetBackgroundDrawList();
bg->AddRectFilled(ImVec2(8.0f, 8.0f), ImVec2(40.0f, 40.0f), IM_COL32(255, 0, 0, 255));
bg->AddRectFilled(ImVec2(472.0f, 280.0f), ImVec2(504.0f, 312.0f), IM_COL32(0, 255, 0, 255));
ImGui::SetNextWindowPos(ImVec2(32.0f, 24.0f), ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(320.0f, 180.0f), ImGuiCond_Always);
ImGui::Begin("Validation", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
ImGui::Text("CPU format validation");
ImGui::Text("Top-left marker is red. Bottom-right is green.");
ImGui::ColorButton("##color", ImVec4(0.2f, 0.6f, 0.9f, 1.0f), 0, ImVec2(48.0f, 24.0f));
ImGui::SameLine();
ImGui::Image((ImTextureID)(intptr_t)image_texture, ImVec2((float)image_texture->Width, (float)image_texture->Height));
ImGui::ProgressBar(0.65f, ImVec2(240.0f, 0.0f));
ImGui::End();
}
static void Validation_BuildPaletteScene()
{
ImDrawList* bg = ImGui::GetBackgroundDrawList();
bg->AddRectFilled(ImVec2(8.0f, 8.0f), ImVec2(40.0f, 40.0f), IM_COL32(255, 0, 0, 255));
bg->AddRectFilled(ImVec2(472.0f, 280.0f), ImVec2(504.0f, 312.0f), IM_COL32(0, 255, 0, 255));
bg->AddRectFilled(ImVec2(160.0f, 32.0f), ImVec2(320.0f, 96.0f), IM_COL32(0, 0, 255, 255));
bg->AddRectFilled(ImVec2(56.0f, 232.0f), ImVec2(168.0f, 280.0f), IM_COL32(255, 255, 0, 255));
bg->AddRectFilled(ImVec2(360.0f, 64.0f), ImVec2(456.0f, 112.0f), IM_COL32(255, 255, 255, 255));
}
static bool Validation_RenderInto(ValidationBuffer* buffer, ImDrawData* draw_data)
{
Validation_ClearBuffer(buffer, 114, 140, 153, 255);
ImGui_ImplCPU_RenderDrawData(draw_data, &buffer->Framebuffer);
return true;
}
int main(int, char**)
{
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize = ImVec2(512.0f, 320.0f);
io.DeltaTime = 1.0f / 60.0f;
io.Fonts->TexDesiredFormat = ImTextureFormat_Alpha8;
ImGui::StyleColorsDark();
ImGui_ImplCPU_Init();
ImVector<unsigned char> image_storage;
ImGui_ImplCPU_Texture image_texture;
memset(&image_texture, 0, sizeof(image_texture));
Validation_FillBGRAImage(&image_storage, &image_texture);
ValidationBuffer reference;
Validation_InitBuffer(&reference, 512, 320, ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_RGBA8888));
const ImGui_ImplCPU_BuiltinFormat builtin_formats[] =
{
ImGui_ImplCPU_BuiltinFormat_RGBA8888,
ImGui_ImplCPU_BuiltinFormat_BGRA8888,
ImGui_ImplCPU_BuiltinFormat_ARGB8888,
ImGui_ImplCPU_BuiltinFormat_ABGR8888,
ImGui_ImplCPU_BuiltinFormat_RGB565,
ImGui_ImplCPU_BuiltinFormat_ARGB1555,
ImGui_ImplCPU_BuiltinFormat_RGBA4444,
ImGui_ImplCPU_BuiltinFormat_RGB888,
ImGui_ImplCPU_BuiltinFormat_BGR888
};
const char* builtin_names[] =
{
"RGBA8888",
"BGRA8888",
"ARGB8888",
"ABGR8888",
"RGB565",
"ARGB1555",
"RGBA4444",
"RGB888",
"BGR888"
};
const int builtin_tolerance[] =
{
0, 0, 0, 0, 8, 8, 17, 0, 0
};
const bool builtin_ignore_alpha[] =
{
false, false, false, false, true, false, false, true, true
};
ImGui_ImplCPU_NewFrame();
ImGui::NewFrame();
Validation_BuildMainScene(&image_texture);
ImGui::Render();
if (!Validation_RenderInto(&reference, ImGui::GetDrawData()))
return 1;
for (int i = 0; i < IM_ARRAYSIZE(builtin_formats); i++)
{
ValidationBuffer candidate;
Validation_InitBuffer(&candidate, 512, 320, ImGui_ImplCPU_GetBuiltinPixelFormat(builtin_formats[i]));
Validation_RenderInto(&candidate, ImGui::GetDrawData());
if (!Validation_CompareBuffers(builtin_names[i], reference, candidate, builtin_tolerance[i], builtin_tolerance[i], builtin_ignore_alpha[i]))
return 1;
}
ValidationBuffer palette_reference;
Validation_InitBuffer(&palette_reference, 512, 320, ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_RGBA8888));
ValidationBuffer palette_candidate;
Validation_InitIndexedBuffer(&palette_candidate, 512, 320);
ImGui_ImplCPU_NewFrame();
ImGui::NewFrame();
Validation_BuildPaletteScene();
ImGui::Render();
Validation_RenderInto(&palette_reference, ImGui::GetDrawData());
Validation_RenderInto(&palette_candidate, ImGui::GetDrawData());
if (!Validation_CompareBuffers("Indexed8", palette_reference, palette_candidate, 0, 0, false))
return 1;
ImGui_ImplCPU_Shutdown();
ImGui::DestroyContext();
printf("imgui_impl_cpu validation passed.\n");
return 0;
}