initial commit
This commit is contained in:
		
							
								
								
									
										43
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
# Prerequisites
 | 
			
		||||
*.d
 | 
			
		||||
 | 
			
		||||
# Compiled Object files
 | 
			
		||||
*.slo
 | 
			
		||||
*.lo
 | 
			
		||||
*.o
 | 
			
		||||
*.obj
 | 
			
		||||
 | 
			
		||||
# Precompiled Headers
 | 
			
		||||
*.gch
 | 
			
		||||
*.pch
 | 
			
		||||
 | 
			
		||||
# Compiled Dynamic libraries
 | 
			
		||||
*.so
 | 
			
		||||
*.dylib
 | 
			
		||||
*.dll
 | 
			
		||||
 | 
			
		||||
# Fortran module files
 | 
			
		||||
*.mod
 | 
			
		||||
*.smod
 | 
			
		||||
 | 
			
		||||
# Compiled Static libraries
 | 
			
		||||
*.lai
 | 
			
		||||
*.la
 | 
			
		||||
*.a
 | 
			
		||||
*.lib
 | 
			
		||||
 | 
			
		||||
# Executables
 | 
			
		||||
*.exe
 | 
			
		||||
*.out
 | 
			
		||||
*.app
 | 
			
		||||
 | 
			
		||||
*.DNG
 | 
			
		||||
*.dng
 | 
			
		||||
*.jpg
 | 
			
		||||
*.ARW
 | 
			
		||||
*.arw
 | 
			
		||||
example_*
 | 
			
		||||
tedit
 | 
			
		||||
asdf
 | 
			
		||||
 | 
			
		||||
.vscode/
 | 
			
		||||
							
								
								
									
										92
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
			
		||||
#
 | 
			
		||||
# Cross Platform Makefile
 | 
			
		||||
# Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X
 | 
			
		||||
#
 | 
			
		||||
# You will need SDL2 (http://www.libsdl.org):
 | 
			
		||||
# Linux:
 | 
			
		||||
#   apt-get install libsdl2-dev
 | 
			
		||||
# Mac OS X:
 | 
			
		||||
#   brew install sdl2
 | 
			
		||||
# MSYS2:
 | 
			
		||||
#   pacman -S mingw-w64-i686-SDL2
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
#CXX = g++
 | 
			
		||||
#CXX = clang++
 | 
			
		||||
 | 
			
		||||
EXE = tedit
 | 
			
		||||
IMGUI_DIR = ../..
 | 
			
		||||
SOURCES = main.cpp exif.cpp imgui_tex_inspect.cpp tex_inspect_opengl.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_opengl3.cpp
 | 
			
		||||
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
 | 
			
		||||
UNAME_S := $(shell uname -s)
 | 
			
		||||
LINUX_GL_LIBS = -lGLEW -lGL -ldl 
 | 
			
		||||
 | 
			
		||||
CXXFLAGS = -std=c++17 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
 | 
			
		||||
CXXFLAGS += -g -Wall -Wformat -O3
 | 
			
		||||
LIBS = -lraw -ljpeg -lpng -ltiff -lz -lm  -DIMGUI -DIMGUI_DEFINE_MATH_OPERATORS
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
##---------------------------------------------------------------------
 | 
			
		||||
## OPENGL ES
 | 
			
		||||
##---------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
## This assumes a GL ES library available in the system, e.g. libGLESv2.so
 | 
			
		||||
# CXXFLAGS += -DIMGUI_IMPL_OPENGL_ES2
 | 
			
		||||
# LINUX_GL_LIBS = -lGLESv2
 | 
			
		||||
## If you're on a Raspberry Pi and want to use the legacy drivers,
 | 
			
		||||
## use the following instead:
 | 
			
		||||
# LINUX_GL_LIBS = -L/opt/vc/lib -lbrcmGLESv2
 | 
			
		||||
 | 
			
		||||
##---------------------------------------------------------------------
 | 
			
		||||
## BUILD FLAGS PER PLATFORM
 | 
			
		||||
##---------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
ifeq ($(UNAME_S), Linux) #LINUX
 | 
			
		||||
	ECHO_MESSAGE = "Linux"
 | 
			
		||||
	LIBS += $(LINUX_GL_LIBS) -ldl `sdl2-config --libs`
 | 
			
		||||
 | 
			
		||||
	CXXFLAGS += `sdl2-config --cflags`
 | 
			
		||||
	CFLAGS = $(CXXFLAGS)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq ($(UNAME_S), Darwin) #APPLE
 | 
			
		||||
	ECHO_MESSAGE = "Mac OS X"
 | 
			
		||||
	LIBS += -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo `sdl2-config --libs`
 | 
			
		||||
	LIBS += -L/usr/local/lib -L/opt/local/lib
 | 
			
		||||
 | 
			
		||||
	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 -lopengl32 -limm32 `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)
 | 
			
		||||
							
								
								
									
										95
									
								
								Makefile.emscripten
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								Makefile.emscripten
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
			
		||||
#
 | 
			
		||||
# Makefile to use with SDL+emscripten
 | 
			
		||||
# See https://emscripten.org/docs/getting_started/downloads.html
 | 
			
		||||
# for installation instructions.
 | 
			
		||||
#
 | 
			
		||||
# This Makefile assumes you have loaded emscripten's environment.
 | 
			
		||||
# (On Windows, you may need to execute emsdk_env.bat or encmdprompt.bat ahead)
 | 
			
		||||
#
 | 
			
		||||
# Running `make -f Makefile.emscripten` will produce three files:
 | 
			
		||||
#  - web/index.html
 | 
			
		||||
#  - web/index.js
 | 
			
		||||
#  - web/index.wasm
 | 
			
		||||
#
 | 
			
		||||
# All three are needed to run the demo.
 | 
			
		||||
 | 
			
		||||
CC = emcc
 | 
			
		||||
CXX = em++
 | 
			
		||||
WEB_DIR = web
 | 
			
		||||
EXE = $(WEB_DIR)/index.html
 | 
			
		||||
IMGUI_DIR = ../..
 | 
			
		||||
SOURCES = main.cpp exif.cpp imgui_tex_inspect.cpp tex_inspect_opengl.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_opengl3.cpp
 | 
			
		||||
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
 | 
			
		||||
UNAME_S := $(shell uname -s)
 | 
			
		||||
CPPFLAGS =
 | 
			
		||||
LDFLAGS = -lraw -ljpeg -lpng -ltiff -lz -lm  -DIMGUI -DIMGUI_DEFINE_MATH_OPERATORS
 | 
			
		||||
EMS =
 | 
			
		||||
 | 
			
		||||
##---------------------------------------------------------------------
 | 
			
		||||
## EMSCRIPTEN OPTIONS
 | 
			
		||||
##---------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
# ("EMS" options gets added to both CPPFLAGS and LDFLAGS, whereas some options are for linker only)
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
# Build as single file (binary text encoded in .html file)
 | 
			
		||||
#LDFLAGS += -sSINGLE_FILE
 | 
			
		||||
 | 
			
		||||
# Uncomment next line to fix possible rendering bugs with Emscripten version older then 1.39.0 (https://github.com/ocornut/imgui/issues/2877)
 | 
			
		||||
#EMS += -s BINARYEN_TRAP_MODE=clamp
 | 
			
		||||
#EMS += -s SAFE_HEAP=1    ## Adds overhead
 | 
			
		||||
 | 
			
		||||
# Emscripten allows preloading a file or folder to be accessible at runtime.
 | 
			
		||||
# The Makefile for this example project suggests embedding the misc/fonts/ folder into our application, it will then be accessible as "/fonts"
 | 
			
		||||
# See documentation for more details: https://emscripten.org/docs/porting/files/packaging_files.html
 | 
			
		||||
# (Default value is 0. Set to 1 to enable file-system and include the misc/fonts/ folder as part of the build.)
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
##---------------------------------------------------------------------
 | 
			
		||||
## FINAL BUILD FLAGS
 | 
			
		||||
##---------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
CPPFLAGS += -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
 | 
			
		||||
#CPPFLAGS += -g
 | 
			
		||||
CPPFLAGS += -Wall -Wformat -Os $(EMS)
 | 
			
		||||
LDFLAGS += --shell-file ../libs/emscripten/shell_minimal.html
 | 
			
		||||
LDFLAGS += $(EMS)
 | 
			
		||||
 | 
			
		||||
##---------------------------------------------------------------------
 | 
			
		||||
## BUILD RULES
 | 
			
		||||
##---------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
%.o:%.cpp
 | 
			
		||||
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
 | 
			
		||||
 | 
			
		||||
%.o:$(IMGUI_DIR)/%.cpp
 | 
			
		||||
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
 | 
			
		||||
 | 
			
		||||
%.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)
 | 
			
		||||
							
								
								
									
										1759
									
								
								app_image.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1759
									
								
								app_image.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										918
									
								
								exif.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										918
									
								
								exif.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,918 @@
 | 
			
		||||
/**************************************************************************
 | 
			
		||||
  exif.cpp  -- A simple ISO C++ library to parse basic EXIF
 | 
			
		||||
               information from a JPEG file.
 | 
			
		||||
 | 
			
		||||
  Copyright (c) 2010-2015 Mayank Lahiri
 | 
			
		||||
  mlahiri@gmail.com
 | 
			
		||||
  All rights reserved (BSD License).
 | 
			
		||||
 | 
			
		||||
  See exif.h for version history.
 | 
			
		||||
 | 
			
		||||
  Redistribution and use in source and binary forms, with or without
 | 
			
		||||
  modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 | 
			
		||||
  -- Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
     this list of conditions and the following disclaimer.
 | 
			
		||||
  -- Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
     this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
     and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS
 | 
			
		||||
  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 | 
			
		||||
  NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 | 
			
		||||
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 | 
			
		||||
  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 | 
			
		||||
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
*/
 | 
			
		||||
#include "exif.h"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
using std::string;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
struct Rational {
 | 
			
		||||
  uint32_t numerator, denominator;
 | 
			
		||||
  operator double() const {
 | 
			
		||||
    if (denominator < 1e-20) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    return static_cast<double>(numerator) / static_cast<double>(denominator);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// IF Entry
 | 
			
		||||
class IFEntry {
 | 
			
		||||
 public:
 | 
			
		||||
  using byte_vector = std::vector<uint8_t>;
 | 
			
		||||
  using ascii_vector = std::string;
 | 
			
		||||
  using short_vector = std::vector<uint16_t>;
 | 
			
		||||
  using long_vector = std::vector<uint32_t>;
 | 
			
		||||
  using rational_vector = std::vector<Rational>;
 | 
			
		||||
 | 
			
		||||
  IFEntry()
 | 
			
		||||
      : tag_(0xFF), format_(0xFF), data_(0), length_(0), val_byte_(nullptr) {}
 | 
			
		||||
  IFEntry(const IFEntry &) = delete;
 | 
			
		||||
  IFEntry &operator=(const IFEntry &) = delete;
 | 
			
		||||
  IFEntry(IFEntry &&other)
 | 
			
		||||
      : tag_(other.tag_),
 | 
			
		||||
        format_(other.format_),
 | 
			
		||||
        data_(other.data_),
 | 
			
		||||
        length_(other.length_),
 | 
			
		||||
        val_byte_(other.val_byte_) {
 | 
			
		||||
    other.tag_ = 0xFF;
 | 
			
		||||
    other.format_ = 0xFF;
 | 
			
		||||
    other.data_ = 0;
 | 
			
		||||
    other.length_ = 0;
 | 
			
		||||
    other.val_byte_ = nullptr;
 | 
			
		||||
  }
 | 
			
		||||
  ~IFEntry() { delete_union(); }
 | 
			
		||||
  unsigned short tag() const { return tag_; }
 | 
			
		||||
  void tag(unsigned short tag) { tag_ = tag; }
 | 
			
		||||
  unsigned short format() const { return format_; }
 | 
			
		||||
  bool format(unsigned short format) {
 | 
			
		||||
    switch (format) {
 | 
			
		||||
      case 0x01:
 | 
			
		||||
      case 0x02:
 | 
			
		||||
      case 0x03:
 | 
			
		||||
      case 0x04:
 | 
			
		||||
      case 0x05:
 | 
			
		||||
      case 0x07:
 | 
			
		||||
      case 0x09:
 | 
			
		||||
      case 0x0a:
 | 
			
		||||
      case 0xff:
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    delete_union();
 | 
			
		||||
    format_ = format;
 | 
			
		||||
    new_union();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  unsigned data() const { return data_; }
 | 
			
		||||
  void data(unsigned data) { data_ = data; }
 | 
			
		||||
  unsigned length() const { return length_; }
 | 
			
		||||
  void length(unsigned length) { length_ = length; }
 | 
			
		||||
 | 
			
		||||
  // functions to access the data
 | 
			
		||||
  //
 | 
			
		||||
  // !! it's CALLER responsibility to check that format !!
 | 
			
		||||
  // !! is correct before accessing it's field          !!
 | 
			
		||||
  //
 | 
			
		||||
  // - getters are use here to allow future addition
 | 
			
		||||
  //   of checks if format is correct
 | 
			
		||||
  byte_vector &val_byte() { return *val_byte_; }
 | 
			
		||||
  ascii_vector &val_string() { return *val_string_; }
 | 
			
		||||
  short_vector &val_short() { return *val_short_; }
 | 
			
		||||
  long_vector &val_long() { return *val_long_; }
 | 
			
		||||
  rational_vector &val_rational() { return *val_rational_; }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  // Raw fields
 | 
			
		||||
  unsigned short tag_;
 | 
			
		||||
  unsigned short format_;
 | 
			
		||||
  unsigned data_;
 | 
			
		||||
  unsigned length_;
 | 
			
		||||
 | 
			
		||||
  // Parsed fields
 | 
			
		||||
  union {
 | 
			
		||||
    byte_vector *val_byte_;
 | 
			
		||||
    ascii_vector *val_string_;
 | 
			
		||||
    short_vector *val_short_;
 | 
			
		||||
    long_vector *val_long_;
 | 
			
		||||
    rational_vector *val_rational_;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  void delete_union() {
 | 
			
		||||
    switch (format_) {
 | 
			
		||||
      case 0x1:
 | 
			
		||||
        delete val_byte_;
 | 
			
		||||
        val_byte_ = nullptr;
 | 
			
		||||
        break;
 | 
			
		||||
      case 0x2:
 | 
			
		||||
        delete val_string_;
 | 
			
		||||
        val_string_ = nullptr;
 | 
			
		||||
        break;
 | 
			
		||||
      case 0x3:
 | 
			
		||||
        delete val_short_;
 | 
			
		||||
        val_short_ = nullptr;
 | 
			
		||||
        break;
 | 
			
		||||
      case 0x4:
 | 
			
		||||
        delete val_long_;
 | 
			
		||||
        val_long_ = nullptr;
 | 
			
		||||
        break;
 | 
			
		||||
      case 0x5:
 | 
			
		||||
        delete val_rational_;
 | 
			
		||||
        val_rational_ = nullptr;
 | 
			
		||||
        break;
 | 
			
		||||
      case 0xff:
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        // should not get here
 | 
			
		||||
        // should I throw an exception or ...?
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  void new_union() {
 | 
			
		||||
    switch (format_) {
 | 
			
		||||
      case 0x1:
 | 
			
		||||
        val_byte_ = new byte_vector();
 | 
			
		||||
        break;
 | 
			
		||||
      case 0x2:
 | 
			
		||||
        val_string_ = new ascii_vector();
 | 
			
		||||
        break;
 | 
			
		||||
      case 0x3:
 | 
			
		||||
        val_short_ = new short_vector();
 | 
			
		||||
        break;
 | 
			
		||||
      case 0x4:
 | 
			
		||||
        val_long_ = new long_vector();
 | 
			
		||||
        break;
 | 
			
		||||
      case 0x5:
 | 
			
		||||
        val_rational_ = new rational_vector();
 | 
			
		||||
        break;
 | 
			
		||||
      case 0xff:
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        // should not get here
 | 
			
		||||
        // should I throw an exception or ...?
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Helper functions
 | 
			
		||||
template <typename T, bool alignIntel>
 | 
			
		||||
T parse(const unsigned char *buf);
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
uint8_t parse<uint8_t, false>(const unsigned char *buf) {
 | 
			
		||||
  return *buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
uint8_t parse<uint8_t, true>(const unsigned char *buf) {
 | 
			
		||||
  return *buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
uint16_t parse<uint16_t, false>(const unsigned char *buf) {
 | 
			
		||||
  return (static_cast<uint16_t>(buf[0]) << 8) | buf[1];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
uint16_t parse<uint16_t, true>(const unsigned char *buf) {
 | 
			
		||||
  return (static_cast<uint16_t>(buf[1]) << 8) | buf[0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
uint32_t parse<uint32_t, false>(const unsigned char *buf) {
 | 
			
		||||
  return (static_cast<uint32_t>(buf[0]) << 24) |
 | 
			
		||||
         (static_cast<uint32_t>(buf[1]) << 16) |
 | 
			
		||||
         (static_cast<uint32_t>(buf[2]) << 8) | buf[3];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
uint32_t parse<uint32_t, true>(const unsigned char *buf) {
 | 
			
		||||
  return (static_cast<uint32_t>(buf[3]) << 24) |
 | 
			
		||||
         (static_cast<uint32_t>(buf[2]) << 16) |
 | 
			
		||||
         (static_cast<uint32_t>(buf[1]) << 8) | buf[0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
Rational parse<Rational, true>(const unsigned char *buf) {
 | 
			
		||||
  Rational r;
 | 
			
		||||
  r.numerator = parse<uint32_t, true>(buf);
 | 
			
		||||
  r.denominator = parse<uint32_t, true>(buf + 4);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
Rational parse<Rational, false>(const unsigned char *buf) {
 | 
			
		||||
  Rational r;
 | 
			
		||||
  r.numerator = parse<uint32_t, false>(buf);
 | 
			
		||||
  r.denominator = parse<uint32_t, false>(buf + 4);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Try to read entry.length() values for this entry.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns:
 | 
			
		||||
 *  true  - entry.length() values were read
 | 
			
		||||
 *  false - something went wrong, vec's content was not touched
 | 
			
		||||
 */
 | 
			
		||||
template <typename T, bool alignIntel, typename C>
 | 
			
		||||
bool extract_values(C &container, const unsigned char *buf, const unsigned base,
 | 
			
		||||
                    const unsigned len, const IFEntry &entry) {
 | 
			
		||||
  const unsigned char *data;
 | 
			
		||||
  uint32_t reversed_data;
 | 
			
		||||
  // if data fits into 4 bytes, they are stored directly in
 | 
			
		||||
  // the data field in IFEntry
 | 
			
		||||
  if (sizeof(T) * entry.length() <= 4) {
 | 
			
		||||
    if (alignIntel) {
 | 
			
		||||
      reversed_data = entry.data();
 | 
			
		||||
    } else {
 | 
			
		||||
      reversed_data = entry.data();
 | 
			
		||||
      // this reversing works, but is ugly
 | 
			
		||||
      unsigned char *rdata = reinterpret_cast<unsigned char *>(&reversed_data);
 | 
			
		||||
      unsigned char tmp;
 | 
			
		||||
      tmp = rdata[0];
 | 
			
		||||
      rdata[0] = rdata[3];
 | 
			
		||||
      rdata[3] = tmp;
 | 
			
		||||
      tmp = rdata[1];
 | 
			
		||||
      rdata[1] = rdata[2];
 | 
			
		||||
      rdata[2] = tmp;
 | 
			
		||||
    }
 | 
			
		||||
    data = reinterpret_cast<const unsigned char *>(&(reversed_data));
 | 
			
		||||
  } else {
 | 
			
		||||
    data = buf + base + entry.data();
 | 
			
		||||
    if (data + sizeof(T) * entry.length() > buf + len) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  container.resize(entry.length());
 | 
			
		||||
  for (size_t i = 0; i < entry.length(); ++i) {
 | 
			
		||||
    container[i] = parse<T, alignIntel>(data + sizeof(T) * i);
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <bool alignIntel>
 | 
			
		||||
void parseIFEntryHeader(const unsigned char *buf, unsigned short &tag,
 | 
			
		||||
                        unsigned short &format, unsigned &length,
 | 
			
		||||
                        unsigned &data) {
 | 
			
		||||
  // Each directory entry is composed of:
 | 
			
		||||
  // 2 bytes: tag number (data field)
 | 
			
		||||
  // 2 bytes: data format
 | 
			
		||||
  // 4 bytes: number of components
 | 
			
		||||
  // 4 bytes: data value or offset to data value
 | 
			
		||||
  tag = parse<uint16_t, alignIntel>(buf);
 | 
			
		||||
  format = parse<uint16_t, alignIntel>(buf + 2);
 | 
			
		||||
  length = parse<uint32_t, alignIntel>(buf + 4);
 | 
			
		||||
  data = parse<uint32_t, alignIntel>(buf + 8);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <bool alignIntel>
 | 
			
		||||
void parseIFEntryHeader(const unsigned char *buf, IFEntry &result) {
 | 
			
		||||
  unsigned short tag;
 | 
			
		||||
  unsigned short format;
 | 
			
		||||
  unsigned length;
 | 
			
		||||
  unsigned data;
 | 
			
		||||
 | 
			
		||||
  parseIFEntryHeader<alignIntel>(buf, tag, format, length, data);
 | 
			
		||||
 | 
			
		||||
  result.tag(tag);
 | 
			
		||||
  result.format(format);
 | 
			
		||||
  result.length(length);
 | 
			
		||||
  result.data(data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <bool alignIntel>
 | 
			
		||||
IFEntry parseIFEntry_temp(const unsigned char *buf, const unsigned offs,
 | 
			
		||||
                          const unsigned base, const unsigned len) {
 | 
			
		||||
  IFEntry result;
 | 
			
		||||
 | 
			
		||||
  // check if there even is enough data for IFEntry in the buffer
 | 
			
		||||
  if (buf + offs + 12 > buf + len) {
 | 
			
		||||
    result.tag(0xFF);
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  parseIFEntryHeader<alignIntel>(buf + offs, result);
 | 
			
		||||
 | 
			
		||||
  // Parse value in specified format
 | 
			
		||||
  switch (result.format()) {
 | 
			
		||||
    case 1:
 | 
			
		||||
      if (!extract_values<uint8_t, alignIntel>(result.val_byte(), buf, base,
 | 
			
		||||
                                               len, result)) {
 | 
			
		||||
        result.tag(0xFF);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case 2:
 | 
			
		||||
      // string is basically sequence of uint8_t (well, according to EXIF even
 | 
			
		||||
      // uint7_t, but
 | 
			
		||||
      // we don't have that), so just read it as bytes
 | 
			
		||||
      if (!extract_values<uint8_t, alignIntel>(result.val_string(), buf, base,
 | 
			
		||||
                                               len, result)) {
 | 
			
		||||
        result.tag(0xFF);
 | 
			
		||||
      }
 | 
			
		||||
      // and cut zero byte at the end, since we don't want that in the
 | 
			
		||||
      // std::string
 | 
			
		||||
      if (result.val_string()[result.val_string().length() - 1] == '\0') {
 | 
			
		||||
        result.val_string().resize(result.val_string().length() - 1);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case 3:
 | 
			
		||||
      if (!extract_values<uint16_t, alignIntel>(result.val_short(), buf, base,
 | 
			
		||||
                                                len, result)) {
 | 
			
		||||
        result.tag(0xFF);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case 4:
 | 
			
		||||
      if (!extract_values<uint32_t, alignIntel>(result.val_long(), buf, base,
 | 
			
		||||
                                                len, result)) {
 | 
			
		||||
        result.tag(0xFF);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case 5:
 | 
			
		||||
      if (!extract_values<Rational, alignIntel>(result.val_rational(), buf,
 | 
			
		||||
                                                base, len, result)) {
 | 
			
		||||
        result.tag(0xFF);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case 7:
 | 
			
		||||
    case 9:
 | 
			
		||||
    case 10:
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      result.tag(0xFF);
 | 
			
		||||
  }
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// helper functions for convinience
 | 
			
		||||
template <typename T>
 | 
			
		||||
T parse_value(const unsigned char *buf, bool alignIntel) {
 | 
			
		||||
  if (alignIntel) {
 | 
			
		||||
    return parse<T, true>(buf);
 | 
			
		||||
  } else {
 | 
			
		||||
    return parse<T, false>(buf);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void parseIFEntryHeader(const unsigned char *buf, bool alignIntel,
 | 
			
		||||
                        unsigned short &tag, unsigned short &format,
 | 
			
		||||
                        unsigned &length, unsigned &data) {
 | 
			
		||||
  if (alignIntel) {
 | 
			
		||||
    parseIFEntryHeader<true>(buf, tag, format, length, data);
 | 
			
		||||
  } else {
 | 
			
		||||
    parseIFEntryHeader<false>(buf, tag, format, length, data);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IFEntry parseIFEntry(const unsigned char *buf, const unsigned offs,
 | 
			
		||||
                     const bool alignIntel, const unsigned base,
 | 
			
		||||
                     const unsigned len) {
 | 
			
		||||
  if (alignIntel) {
 | 
			
		||||
    return parseIFEntry_temp<true>(buf, offs, base, len);
 | 
			
		||||
  } else {
 | 
			
		||||
    return parseIFEntry_temp<false>(buf, offs, base, len);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Locates the EXIF segment and parses it using parseFromEXIFSegment
 | 
			
		||||
//
 | 
			
		||||
int easyexif::EXIFInfo::parseFrom(const unsigned char *buf, unsigned len) {
 | 
			
		||||
  // Sanity check: all JPEG files start with 0xFFD8.
 | 
			
		||||
  if (!buf || len < 4) return PARSE_EXIF_ERROR_NO_JPEG;
 | 
			
		||||
  if (buf[0] != 0xFF || buf[1] != 0xD8) return PARSE_EXIF_ERROR_NO_JPEG;
 | 
			
		||||
 | 
			
		||||
  // Sanity check: some cameras pad the JPEG image with some bytes at the end.
 | 
			
		||||
  // Normally, we should be able to find the JPEG end marker 0xFFD9 at the end
 | 
			
		||||
  // of the image buffer, but not always. As long as there are some bytes
 | 
			
		||||
  // except 0xD9 at the end of the image buffer, keep decrementing len until
 | 
			
		||||
  // an 0xFFD9 is found. If JPEG end marker 0xFFD9 is not found,
 | 
			
		||||
  // then we can be reasonably sure that the buffer is not a JPEG.
 | 
			
		||||
  while (len > 2) {
 | 
			
		||||
    if (buf[len - 1] == 0xD9 && buf[len - 2] == 0xFF)
 | 
			
		||||
      break;
 | 
			
		||||
    len--;
 | 
			
		||||
  }
 | 
			
		||||
  if (len <= 2)
 | 
			
		||||
    return PARSE_EXIF_ERROR_NO_JPEG;
 | 
			
		||||
 | 
			
		||||
  clear();
 | 
			
		||||
 | 
			
		||||
  // Scan for EXIF header (bytes 0xFF 0xE1) and do a sanity check by
 | 
			
		||||
  // looking for bytes "Exif\0\0". The marker length data is in Motorola
 | 
			
		||||
  // byte order, which results in the 'false' parameter to parse16().
 | 
			
		||||
  // The marker has to contain at least the TIFF header, otherwise the
 | 
			
		||||
  // EXIF data is corrupt. So the minimum length specified here has to be:
 | 
			
		||||
  //   2 bytes: section size
 | 
			
		||||
  //   6 bytes: "Exif\0\0" string
 | 
			
		||||
  //   2 bytes: TIFF header (either "II" or "MM" string)
 | 
			
		||||
  //   2 bytes: TIFF magic (short 0x2a00 in Motorola byte order)
 | 
			
		||||
  //   4 bytes: Offset to first IFD
 | 
			
		||||
  // =========
 | 
			
		||||
  //  16 bytes
 | 
			
		||||
  unsigned offs = 0;  // current offset into buffer
 | 
			
		||||
  for (offs = 0; offs < len - 1; offs++)
 | 
			
		||||
    if (buf[offs] == 0xFF && buf[offs + 1] == 0xE1) break;
 | 
			
		||||
  if (offs + 4 > len) return PARSE_EXIF_ERROR_NO_EXIF;
 | 
			
		||||
  offs += 2;
 | 
			
		||||
  unsigned short section_length = parse_value<uint16_t>(buf + offs, false);
 | 
			
		||||
  if (offs + section_length > len || section_length < 16)
 | 
			
		||||
    return PARSE_EXIF_ERROR_CORRUPT;
 | 
			
		||||
  offs += 2;
 | 
			
		||||
 | 
			
		||||
  return parseFromEXIFSegment(buf + offs, len - offs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int easyexif::EXIFInfo::parseFrom(const string &data) {
 | 
			
		||||
  return parseFrom(
 | 
			
		||||
      reinterpret_cast<const unsigned char *>(data.data()), static_cast<unsigned>(data.length()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Main parsing function for an EXIF segment.
 | 
			
		||||
//
 | 
			
		||||
// PARAM: 'buf' start of the EXIF TIFF, which must be the bytes "Exif\0\0".
 | 
			
		||||
// PARAM: 'len' length of buffer
 | 
			
		||||
//
 | 
			
		||||
int easyexif::EXIFInfo::parseFromEXIFSegment(const unsigned char *buf,
 | 
			
		||||
                                             unsigned len) {
 | 
			
		||||
  bool alignIntel = true;  // byte alignment (defined in EXIF header)
 | 
			
		||||
  unsigned offs = 0;       // current offset into buffer
 | 
			
		||||
  if (!buf || len < 6) return PARSE_EXIF_ERROR_NO_EXIF;
 | 
			
		||||
 | 
			
		||||
  if (!std::equal(buf, buf + 6, "Exif\0\0")) return PARSE_EXIF_ERROR_NO_EXIF;
 | 
			
		||||
  offs += 6;
 | 
			
		||||
 | 
			
		||||
  // Now parsing the TIFF header. The first two bytes are either "II" or
 | 
			
		||||
  // "MM" for Intel or Motorola byte alignment. Sanity check by parsing
 | 
			
		||||
  // the unsigned short that follows, making sure it equals 0x2a. The
 | 
			
		||||
  // last 4 bytes are an offset into the first IFD, which are added to
 | 
			
		||||
  // the global offset counter. For this block, we expect the following
 | 
			
		||||
  // minimum size:
 | 
			
		||||
  //  2 bytes: 'II' or 'MM'
 | 
			
		||||
  //  2 bytes: 0x002a
 | 
			
		||||
  //  4 bytes: offset to first IDF
 | 
			
		||||
  // -----------------------------
 | 
			
		||||
  //  8 bytes
 | 
			
		||||
  if (offs + 8 > len) return PARSE_EXIF_ERROR_CORRUPT;
 | 
			
		||||
  unsigned tiff_header_start = offs;
 | 
			
		||||
  if (buf[offs] == 'I' && buf[offs + 1] == 'I')
 | 
			
		||||
    alignIntel = true;
 | 
			
		||||
  else {
 | 
			
		||||
    if (buf[offs] == 'M' && buf[offs + 1] == 'M')
 | 
			
		||||
      alignIntel = false;
 | 
			
		||||
    else
 | 
			
		||||
      return PARSE_EXIF_ERROR_UNKNOWN_BYTEALIGN;
 | 
			
		||||
  }
 | 
			
		||||
  this->ByteAlign = alignIntel;
 | 
			
		||||
  offs += 2;
 | 
			
		||||
  if (0x2a != parse_value<uint16_t>(buf + offs, alignIntel))
 | 
			
		||||
    return PARSE_EXIF_ERROR_CORRUPT;
 | 
			
		||||
  offs += 2;
 | 
			
		||||
  unsigned first_ifd_offset = parse_value<uint32_t>(buf + offs, alignIntel);
 | 
			
		||||
  offs += first_ifd_offset - 4;
 | 
			
		||||
  if (offs >= len) return PARSE_EXIF_ERROR_CORRUPT;
 | 
			
		||||
 | 
			
		||||
  // Now parsing the first Image File Directory (IFD0, for the main image).
 | 
			
		||||
  // An IFD consists of a variable number of 12-byte directory entries. The
 | 
			
		||||
  // first two bytes of the IFD section contain the number of directory
 | 
			
		||||
  // entries in the section. The last 4 bytes of the IFD contain an offset
 | 
			
		||||
  // to the next IFD, which means this IFD must contain exactly 6 + 12 * num
 | 
			
		||||
  // bytes of data.
 | 
			
		||||
  if (offs + 2 > len) return PARSE_EXIF_ERROR_CORRUPT;
 | 
			
		||||
  int num_entries = parse_value<uint16_t>(buf + offs, alignIntel);
 | 
			
		||||
  if (offs + 6 + 12 * num_entries > len) return PARSE_EXIF_ERROR_CORRUPT;
 | 
			
		||||
  offs += 2;
 | 
			
		||||
  unsigned exif_sub_ifd_offset = len;
 | 
			
		||||
  unsigned gps_sub_ifd_offset = len;
 | 
			
		||||
  while (--num_entries >= 0) {
 | 
			
		||||
    IFEntry result =
 | 
			
		||||
        parseIFEntry(buf, offs, alignIntel, tiff_header_start, len);
 | 
			
		||||
    offs += 12;
 | 
			
		||||
    switch (result.tag()) {
 | 
			
		||||
      case 0x102:
 | 
			
		||||
        // Bits per sample
 | 
			
		||||
        if (result.format() == 3 && result.val_short().size())
 | 
			
		||||
          this->BitsPerSample = result.val_short().front();
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      case 0x10E:
 | 
			
		||||
        // Image description
 | 
			
		||||
        if (result.format() == 2) this->ImageDescription = result.val_string();
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      case 0x10F:
 | 
			
		||||
        // Digicam make
 | 
			
		||||
        if (result.format() == 2) this->Make = result.val_string();
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      case 0x110:
 | 
			
		||||
        // Digicam model
 | 
			
		||||
        if (result.format() == 2) this->Model = result.val_string();
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      case 0x112:
 | 
			
		||||
        // Orientation of image
 | 
			
		||||
        if (result.format() == 3 && result.val_short().size())
 | 
			
		||||
          this->Orientation = result.val_short().front();
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      case 0x131:
 | 
			
		||||
        // Software used for image
 | 
			
		||||
        if (result.format() == 2) this->Software = result.val_string();
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      case 0x132:
 | 
			
		||||
        // EXIF/TIFF date/time of image modification
 | 
			
		||||
        if (result.format() == 2) this->DateTime = result.val_string();
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      case 0x8298:
 | 
			
		||||
        // Copyright information
 | 
			
		||||
        if (result.format() == 2) this->Copyright = result.val_string();
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      case 0x8825:
 | 
			
		||||
        // GPS IFS offset
 | 
			
		||||
        gps_sub_ifd_offset = tiff_header_start + result.data();
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      case 0x8769:
 | 
			
		||||
        // EXIF SubIFD offset
 | 
			
		||||
        exif_sub_ifd_offset = tiff_header_start + result.data();
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Jump to the EXIF SubIFD if it exists and parse all the information
 | 
			
		||||
  // there. Note that it's possible that the EXIF SubIFD doesn't exist.
 | 
			
		||||
  // The EXIF SubIFD contains most of the interesting information that a
 | 
			
		||||
  // typical user might want.
 | 
			
		||||
  if (exif_sub_ifd_offset + 4 <= len) {
 | 
			
		||||
    offs = exif_sub_ifd_offset;
 | 
			
		||||
    int num_sub_entries = parse_value<uint16_t>(buf + offs, alignIntel);
 | 
			
		||||
    if (offs + 6 + 12 * num_sub_entries > len) return PARSE_EXIF_ERROR_CORRUPT;
 | 
			
		||||
    offs += 2;
 | 
			
		||||
    while (--num_sub_entries >= 0) {
 | 
			
		||||
      IFEntry result =
 | 
			
		||||
          parseIFEntry(buf, offs, alignIntel, tiff_header_start, len);
 | 
			
		||||
      switch (result.tag()) {
 | 
			
		||||
        case 0x829a:
 | 
			
		||||
          // Exposure time in seconds
 | 
			
		||||
          if (result.format() == 5 && result.val_rational().size())
 | 
			
		||||
            this->ExposureTime = result.val_rational().front();
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0x829d:
 | 
			
		||||
          // FNumber
 | 
			
		||||
          if (result.format() == 5 && result.val_rational().size())
 | 
			
		||||
            this->FNumber = result.val_rational().front();
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
      case 0x8822:
 | 
			
		||||
        // Exposure Program
 | 
			
		||||
        if (result.format() == 3 && result.val_short().size())
 | 
			
		||||
          this->ExposureProgram = result.val_short().front();
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
        case 0x8827:
 | 
			
		||||
          // ISO Speed Rating
 | 
			
		||||
          if (result.format() == 3 && result.val_short().size())
 | 
			
		||||
            this->ISOSpeedRatings = result.val_short().front();
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0x9003:
 | 
			
		||||
          // Original date and time
 | 
			
		||||
          if (result.format() == 2)
 | 
			
		||||
            this->DateTimeOriginal = result.val_string();
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0x9004:
 | 
			
		||||
          // Digitization date and time
 | 
			
		||||
          if (result.format() == 2)
 | 
			
		||||
            this->DateTimeDigitized = result.val_string();
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0x9201:
 | 
			
		||||
          // Shutter speed value
 | 
			
		||||
          if (result.format() == 5 && result.val_rational().size())
 | 
			
		||||
            this->ShutterSpeedValue = result.val_rational().front();
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0x9204:
 | 
			
		||||
          // Exposure bias value
 | 
			
		||||
          if (result.format() == 5 && result.val_rational().size())
 | 
			
		||||
            this->ExposureBiasValue = result.val_rational().front();
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0x9206:
 | 
			
		||||
          // Subject distance
 | 
			
		||||
          if (result.format() == 5 && result.val_rational().size())
 | 
			
		||||
            this->SubjectDistance = result.val_rational().front();
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0x9209:
 | 
			
		||||
          // Flash used
 | 
			
		||||
          if (result.format() == 3 && result.val_short().size()) {
 | 
			
		||||
            uint16_t data = result.val_short().front();
 | 
			
		||||
            
 | 
			
		||||
            this->Flash = data & 1;
 | 
			
		||||
            this->FlashReturnedLight = (data & 6) >> 1;
 | 
			
		||||
            this->FlashMode = (data & 24) >> 3;
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0x920a:
 | 
			
		||||
          // Focal length
 | 
			
		||||
          if (result.format() == 5 && result.val_rational().size())
 | 
			
		||||
            this->FocalLength = result.val_rational().front();
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0x9207:
 | 
			
		||||
          // Metering mode
 | 
			
		||||
          if (result.format() == 3 && result.val_short().size())
 | 
			
		||||
            this->MeteringMode = result.val_short().front();
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0x9291:
 | 
			
		||||
          // Subsecond original time
 | 
			
		||||
          if (result.format() == 2)
 | 
			
		||||
            this->SubSecTimeOriginal = result.val_string();
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0xa002:
 | 
			
		||||
          // EXIF Image width
 | 
			
		||||
          if (result.format() == 4 && result.val_long().size())
 | 
			
		||||
            this->ImageWidth = result.val_long().front();
 | 
			
		||||
          if (result.format() == 3 && result.val_short().size())
 | 
			
		||||
            this->ImageWidth = result.val_short().front();
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0xa003:
 | 
			
		||||
          // EXIF Image height
 | 
			
		||||
          if (result.format() == 4 && result.val_long().size())
 | 
			
		||||
            this->ImageHeight = result.val_long().front();
 | 
			
		||||
          if (result.format() == 3 && result.val_short().size())
 | 
			
		||||
            this->ImageHeight = result.val_short().front();
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0xa20e:
 | 
			
		||||
          // EXIF Focal plane X-resolution
 | 
			
		||||
          if (result.format() == 5) {
 | 
			
		||||
            this->LensInfo.FocalPlaneXResolution = result.val_rational()[0];
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0xa20f:
 | 
			
		||||
          // EXIF Focal plane Y-resolution
 | 
			
		||||
          if (result.format() == 5) {
 | 
			
		||||
            this->LensInfo.FocalPlaneYResolution = result.val_rational()[0];
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0xa210:
 | 
			
		||||
            // EXIF Focal plane resolution unit
 | 
			
		||||
            if (result.format() == 3 && result.val_short().size()) {
 | 
			
		||||
                this->LensInfo.FocalPlaneResolutionUnit = result.val_short().front();
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case 0xa405:
 | 
			
		||||
          // Focal length in 35mm film
 | 
			
		||||
          if (result.format() == 3 && result.val_short().size())
 | 
			
		||||
            this->FocalLengthIn35mm = result.val_short().front();
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0xa432:
 | 
			
		||||
          // Focal length and FStop.
 | 
			
		||||
          if (result.format() == 5) {
 | 
			
		||||
            int sz = static_cast<unsigned>(result.val_rational().size());
 | 
			
		||||
            if (sz)
 | 
			
		||||
              this->LensInfo.FocalLengthMin = result.val_rational()[0];
 | 
			
		||||
            if (sz > 1)
 | 
			
		||||
              this->LensInfo.FocalLengthMax = result.val_rational()[1];
 | 
			
		||||
            if (sz > 2)
 | 
			
		||||
              this->LensInfo.FStopMin = result.val_rational()[2];
 | 
			
		||||
            if (sz > 3)
 | 
			
		||||
              this->LensInfo.FStopMax = result.val_rational()[3];
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0xa433:
 | 
			
		||||
          // Lens make.
 | 
			
		||||
          if (result.format() == 2) {
 | 
			
		||||
            this->LensInfo.Make = result.val_string();
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 0xa434:
 | 
			
		||||
          // Lens model.
 | 
			
		||||
          if (result.format() == 2) {
 | 
			
		||||
            this->LensInfo.Model = result.val_string();
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
      offs += 12;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Jump to the GPS SubIFD if it exists and parse all the information
 | 
			
		||||
  // there. Note that it's possible that the GPS SubIFD doesn't exist.
 | 
			
		||||
  if (gps_sub_ifd_offset + 4 <= len) {
 | 
			
		||||
    offs = gps_sub_ifd_offset;
 | 
			
		||||
    int num_sub_entries = parse_value<uint16_t>(buf + offs, alignIntel);
 | 
			
		||||
    if (offs + 6 + 12 * num_sub_entries > len) return PARSE_EXIF_ERROR_CORRUPT;
 | 
			
		||||
    offs += 2;
 | 
			
		||||
    while (--num_sub_entries >= 0) {
 | 
			
		||||
      unsigned short tag, format;
 | 
			
		||||
      unsigned length, data;
 | 
			
		||||
      parseIFEntryHeader(buf + offs, alignIntel, tag, format, length, data);
 | 
			
		||||
      switch (tag) {
 | 
			
		||||
        case 1:
 | 
			
		||||
          // GPS north or south
 | 
			
		||||
          this->GeoLocation.LatComponents.direction = *(buf + offs + 8);
 | 
			
		||||
          if (this->GeoLocation.LatComponents.direction == 0) {
 | 
			
		||||
            this->GeoLocation.LatComponents.direction = '?';
 | 
			
		||||
          }
 | 
			
		||||
          if ('S' == this->GeoLocation.LatComponents.direction) {
 | 
			
		||||
            this->GeoLocation.Latitude = -this->GeoLocation.Latitude;
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 2:
 | 
			
		||||
          // GPS latitude
 | 
			
		||||
          if ((format == 5 || format == 10) && length == 3) {
 | 
			
		||||
            this->GeoLocation.LatComponents.degrees = parse_value<Rational>(
 | 
			
		||||
                buf + data + tiff_header_start, alignIntel);
 | 
			
		||||
            this->GeoLocation.LatComponents.minutes = parse_value<Rational>(
 | 
			
		||||
                buf + data + tiff_header_start + 8, alignIntel);
 | 
			
		||||
            this->GeoLocation.LatComponents.seconds = parse_value<Rational>(
 | 
			
		||||
                buf + data + tiff_header_start + 16, alignIntel);
 | 
			
		||||
            this->GeoLocation.Latitude =
 | 
			
		||||
                this->GeoLocation.LatComponents.degrees +
 | 
			
		||||
                this->GeoLocation.LatComponents.minutes / 60 +
 | 
			
		||||
                this->GeoLocation.LatComponents.seconds / 3600;
 | 
			
		||||
            if ('S' == this->GeoLocation.LatComponents.direction) {
 | 
			
		||||
              this->GeoLocation.Latitude = -this->GeoLocation.Latitude;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 3:
 | 
			
		||||
          // GPS east or west
 | 
			
		||||
          this->GeoLocation.LonComponents.direction = *(buf + offs + 8);
 | 
			
		||||
          if (this->GeoLocation.LonComponents.direction == 0) {
 | 
			
		||||
            this->GeoLocation.LonComponents.direction = '?';
 | 
			
		||||
          }
 | 
			
		||||
          if ('W' == this->GeoLocation.LonComponents.direction) {
 | 
			
		||||
            this->GeoLocation.Longitude = -this->GeoLocation.Longitude;
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 4:
 | 
			
		||||
          // GPS longitude
 | 
			
		||||
          if ((format == 5 || format == 10) && length == 3) {
 | 
			
		||||
            this->GeoLocation.LonComponents.degrees = parse_value<Rational>(
 | 
			
		||||
                buf + data + tiff_header_start, alignIntel);
 | 
			
		||||
            this->GeoLocation.LonComponents.minutes = parse_value<Rational>(
 | 
			
		||||
                buf + data + tiff_header_start + 8, alignIntel);
 | 
			
		||||
            this->GeoLocation.LonComponents.seconds = parse_value<Rational>(
 | 
			
		||||
                buf + data + tiff_header_start + 16, alignIntel);
 | 
			
		||||
            this->GeoLocation.Longitude =
 | 
			
		||||
                this->GeoLocation.LonComponents.degrees +
 | 
			
		||||
                this->GeoLocation.LonComponents.minutes / 60 +
 | 
			
		||||
                this->GeoLocation.LonComponents.seconds / 3600;
 | 
			
		||||
            if ('W' == this->GeoLocation.LonComponents.direction)
 | 
			
		||||
              this->GeoLocation.Longitude = -this->GeoLocation.Longitude;
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 5:
 | 
			
		||||
          // GPS altitude reference (below or above sea level)
 | 
			
		||||
          this->GeoLocation.AltitudeRef = *(buf + offs + 8);
 | 
			
		||||
          if (1 == this->GeoLocation.AltitudeRef) {
 | 
			
		||||
            this->GeoLocation.Altitude = -this->GeoLocation.Altitude;
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 6:
 | 
			
		||||
          // GPS altitude
 | 
			
		||||
          if ((format == 5 || format == 10)) {
 | 
			
		||||
            this->GeoLocation.Altitude = parse_value<Rational>(
 | 
			
		||||
                buf + data + tiff_header_start, alignIntel);
 | 
			
		||||
            if (1 == this->GeoLocation.AltitudeRef) {
 | 
			
		||||
              this->GeoLocation.Altitude = -this->GeoLocation.Altitude;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
        case 11:
 | 
			
		||||
          // GPS degree of precision (DOP)
 | 
			
		||||
          if ((format == 5 || format == 10)) {
 | 
			
		||||
            this->GeoLocation.DOP = parse_value<Rational>(
 | 
			
		||||
                buf + data + tiff_header_start, alignIntel);
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
      offs += 12;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return PARSE_EXIF_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void easyexif::EXIFInfo::clear() {
 | 
			
		||||
  // Strings
 | 
			
		||||
  ImageDescription = "";
 | 
			
		||||
  Make = "";
 | 
			
		||||
  Model = "";
 | 
			
		||||
  Software = "";
 | 
			
		||||
  DateTime = "";
 | 
			
		||||
  DateTimeOriginal = "";
 | 
			
		||||
  DateTimeDigitized = "";
 | 
			
		||||
  SubSecTimeOriginal = "";
 | 
			
		||||
  Copyright = "";
 | 
			
		||||
 | 
			
		||||
  // Shorts / unsigned / double
 | 
			
		||||
  ByteAlign = 0;
 | 
			
		||||
  Orientation = 0;
 | 
			
		||||
 | 
			
		||||
  BitsPerSample = 0;
 | 
			
		||||
  ExposureTime = 0;
 | 
			
		||||
  FNumber = 0;
 | 
			
		||||
  ExposureProgram = 0;
 | 
			
		||||
  ISOSpeedRatings = 0;
 | 
			
		||||
  ShutterSpeedValue = 0;
 | 
			
		||||
  ExposureBiasValue = 0;
 | 
			
		||||
  SubjectDistance = 0;
 | 
			
		||||
  FocalLength = 0;
 | 
			
		||||
  FocalLengthIn35mm = 0;
 | 
			
		||||
  Flash = 0;
 | 
			
		||||
  FlashReturnedLight = 0;
 | 
			
		||||
  FlashMode = 0;
 | 
			
		||||
  MeteringMode = 0;
 | 
			
		||||
  ImageWidth = 0;
 | 
			
		||||
  ImageHeight = 0;
 | 
			
		||||
 | 
			
		||||
  // Geolocation
 | 
			
		||||
  GeoLocation.Latitude = 0;
 | 
			
		||||
  GeoLocation.Longitude = 0;
 | 
			
		||||
  GeoLocation.Altitude = 0;
 | 
			
		||||
  GeoLocation.AltitudeRef = 0;
 | 
			
		||||
  GeoLocation.DOP = 0;
 | 
			
		||||
  GeoLocation.LatComponents.degrees = 0;
 | 
			
		||||
  GeoLocation.LatComponents.minutes = 0;
 | 
			
		||||
  GeoLocation.LatComponents.seconds = 0;
 | 
			
		||||
  GeoLocation.LatComponents.direction = '?';
 | 
			
		||||
  GeoLocation.LonComponents.degrees = 0;
 | 
			
		||||
  GeoLocation.LonComponents.minutes = 0;
 | 
			
		||||
  GeoLocation.LonComponents.seconds = 0;
 | 
			
		||||
  GeoLocation.LonComponents.direction = '?';
 | 
			
		||||
 | 
			
		||||
  // LensInfo
 | 
			
		||||
  LensInfo.FocalLengthMax = 0;
 | 
			
		||||
  LensInfo.FocalLengthMin = 0;
 | 
			
		||||
  LensInfo.FStopMax = 0;
 | 
			
		||||
  LensInfo.FStopMin = 0;
 | 
			
		||||
  LensInfo.FocalPlaneYResolution = 0;
 | 
			
		||||
  LensInfo.FocalPlaneXResolution = 0;
 | 
			
		||||
  LensInfo.FocalPlaneResolutionUnit = 0;
 | 
			
		||||
  LensInfo.Make = "";
 | 
			
		||||
  LensInfo.Model = "";
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										168
									
								
								exif.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								exif.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
			
		||||
/**************************************************************************
 | 
			
		||||
  exif.h  -- A simple ISO C++ library to parse basic EXIF
 | 
			
		||||
             information from a JPEG file.
 | 
			
		||||
 | 
			
		||||
  Based on the description of the EXIF file format at:
 | 
			
		||||
  -- http://park2.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html
 | 
			
		||||
  -- http://www.media.mit.edu/pia/Research/deepview/exif.html
 | 
			
		||||
  -- http://www.exif.org/Exif2-2.PDF
 | 
			
		||||
 | 
			
		||||
  Copyright (c) 2010-2016 Mayank Lahiri
 | 
			
		||||
  mlahiri@gmail.com
 | 
			
		||||
  All rights reserved.
 | 
			
		||||
 | 
			
		||||
  Redistribution and use in source and binary forms, with or without
 | 
			
		||||
  modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 | 
			
		||||
  -- Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
     this list of conditions and the following disclaimer.
 | 
			
		||||
  -- Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
     this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
   and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS
 | 
			
		||||
   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 | 
			
		||||
   NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 | 
			
		||||
   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 | 
			
		||||
   OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 | 
			
		||||
   EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
*/
 | 
			
		||||
#ifndef __EXIF_H
 | 
			
		||||
#define __EXIF_H
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace easyexif {
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// Class responsible for storing and parsing EXIF information from a JPEG blob
 | 
			
		||||
//
 | 
			
		||||
class EXIFInfo {
 | 
			
		||||
 public:
 | 
			
		||||
  // Parsing function for an entire JPEG image buffer.
 | 
			
		||||
  //
 | 
			
		||||
  // PARAM 'data': A pointer to a JPEG image.
 | 
			
		||||
  // PARAM 'length': The length of the JPEG image.
 | 
			
		||||
  // RETURN:  PARSE_EXIF_SUCCESS (0) on succes with 'result' filled out
 | 
			
		||||
  //          error code otherwise, as defined by the PARSE_EXIF_ERROR_* macros
 | 
			
		||||
  int parseFrom(const unsigned char *data, unsigned length);
 | 
			
		||||
  int parseFrom(const std::string &data);
 | 
			
		||||
 | 
			
		||||
  // Parsing function for an EXIF segment. This is used internally by parseFrom()
 | 
			
		||||
  // but can be called for special cases where only the EXIF section is
 | 
			
		||||
  // available (i.e., a blob starting with the bytes "Exif\0\0").
 | 
			
		||||
  int parseFromEXIFSegment(const unsigned char *buf, unsigned len);
 | 
			
		||||
 | 
			
		||||
  // Set all data members to default values.
 | 
			
		||||
  void clear();
 | 
			
		||||
 | 
			
		||||
  // Data fields filled out by parseFrom()
 | 
			
		||||
  char ByteAlign;                   // 0 = Motorola byte alignment, 1 = Intel
 | 
			
		||||
  std::string ImageDescription;     // Image description
 | 
			
		||||
  std::string Make;                 // Camera manufacturer's name
 | 
			
		||||
  std::string Model;                // Camera model
 | 
			
		||||
  unsigned short Orientation;       // Image orientation, start of data corresponds to
 | 
			
		||||
                                    // 0: unspecified in EXIF data
 | 
			
		||||
                                    // 1: upper left of image
 | 
			
		||||
                                    // 3: lower right of image
 | 
			
		||||
                                    // 6: upper right of image
 | 
			
		||||
                                    // 8: lower left of image
 | 
			
		||||
                                    // 9: undefined
 | 
			
		||||
  unsigned short BitsPerSample;     // Number of bits per component
 | 
			
		||||
  std::string Software;             // Software used
 | 
			
		||||
  std::string DateTime;             // File change date and time
 | 
			
		||||
  std::string DateTimeOriginal;     // Original file date and time (may not exist)
 | 
			
		||||
  std::string DateTimeDigitized;    // Digitization date and time (may not exist)
 | 
			
		||||
  std::string SubSecTimeOriginal;   // Sub-second time that original picture was taken
 | 
			
		||||
  std::string Copyright;            // File copyright information
 | 
			
		||||
  double ExposureTime;              // Exposure time in seconds
 | 
			
		||||
  double FNumber;                   // F/stop
 | 
			
		||||
  unsigned short ExposureProgram;   // Exposure program
 | 
			
		||||
                                    // 0: Not defined
 | 
			
		||||
                                    // 1: Manual
 | 
			
		||||
                                    // 2: Normal program
 | 
			
		||||
                                    // 3: Aperture priority
 | 
			
		||||
                                    // 4: Shutter priority
 | 
			
		||||
                                    // 5: Creative program
 | 
			
		||||
                                    // 6: Action program
 | 
			
		||||
                                    // 7: Portrait mode
 | 
			
		||||
                                    // 8: Landscape mode
 | 
			
		||||
  unsigned short ISOSpeedRatings;   // ISO speed
 | 
			
		||||
  double ShutterSpeedValue;         // Shutter speed (reciprocal of exposure time)
 | 
			
		||||
  double ExposureBiasValue;         // Exposure bias value in EV
 | 
			
		||||
  double SubjectDistance;           // Distance to focus point in meters
 | 
			
		||||
  double FocalLength;               // Focal length of lens in millimeters
 | 
			
		||||
  unsigned short FocalLengthIn35mm; // Focal length in 35mm film
 | 
			
		||||
  char Flash;                       // 0 = no flash, 1 = flash used
 | 
			
		||||
  unsigned short FlashReturnedLight;// Flash returned light status
 | 
			
		||||
                                    // 0: No strobe return detection function
 | 
			
		||||
                                    // 1: Reserved
 | 
			
		||||
                                    // 2: Strobe return light not detected
 | 
			
		||||
                                    // 3: Strobe return light detected
 | 
			
		||||
  unsigned short FlashMode;         // Flash mode
 | 
			
		||||
                                    // 0: Unknown
 | 
			
		||||
                                    // 1: Compulsory flash firing
 | 
			
		||||
                                    // 2: Compulsory flash suppression
 | 
			
		||||
                                    // 3: Automatic mode
 | 
			
		||||
  unsigned short MeteringMode;      // Metering mode
 | 
			
		||||
                                    // 1: average
 | 
			
		||||
                                    // 2: center weighted average
 | 
			
		||||
                                    // 3: spot
 | 
			
		||||
                                    // 4: multi-spot
 | 
			
		||||
                                    // 5: multi-segment
 | 
			
		||||
  unsigned ImageWidth;              // Image width reported in EXIF data
 | 
			
		||||
  unsigned ImageHeight;             // Image height reported in EXIF data
 | 
			
		||||
  struct Geolocation_t {            // GPS information embedded in file
 | 
			
		||||
    double Latitude;                  // Image latitude expressed as decimal
 | 
			
		||||
    double Longitude;                 // Image longitude expressed as decimal
 | 
			
		||||
    double Altitude;                  // Altitude in meters, relative to sea level
 | 
			
		||||
    char AltitudeRef;                 // 0 = above sea level, -1 = below sea level
 | 
			
		||||
    double DOP;                       // GPS degree of precision (DOP)
 | 
			
		||||
    struct Coord_t {
 | 
			
		||||
      double degrees;
 | 
			
		||||
      double minutes;
 | 
			
		||||
      double seconds;
 | 
			
		||||
      char direction;
 | 
			
		||||
    } LatComponents, LonComponents;   // Latitude, Longitude expressed in deg/min/sec
 | 
			
		||||
  } GeoLocation;
 | 
			
		||||
  struct LensInfo_t {               // Lens information
 | 
			
		||||
    double FStopMin;                // Min aperture (f-stop)
 | 
			
		||||
    double FStopMax;                // Max aperture (f-stop)
 | 
			
		||||
    double FocalLengthMin;          // Min focal length (mm)
 | 
			
		||||
    double FocalLengthMax;          // Max focal length (mm)
 | 
			
		||||
    double FocalPlaneXResolution;   // Focal plane X-resolution
 | 
			
		||||
    double FocalPlaneYResolution;   // Focal plane Y-resolution
 | 
			
		||||
    unsigned short FocalPlaneResolutionUnit; // Focal plane resolution unit
 | 
			
		||||
                                             // 1: No absolute unit of measurement.
 | 
			
		||||
                                             // 2: Inch.
 | 
			
		||||
                                             // 3: Centimeter.
 | 
			
		||||
                                             // 4: Millimeter.
 | 
			
		||||
                                             // 5: Micrometer.
 | 
			
		||||
    std::string Make;               // Lens manufacturer
 | 
			
		||||
    std::string Model;              // Lens model
 | 
			
		||||
  } LensInfo;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  EXIFInfo() {
 | 
			
		||||
    clear();
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Parse was successful
 | 
			
		||||
#define PARSE_EXIF_SUCCESS                    0
 | 
			
		||||
// No JPEG markers found in buffer, possibly invalid JPEG file
 | 
			
		||||
#define PARSE_EXIF_ERROR_NO_JPEG              1982
 | 
			
		||||
// No EXIF header found in JPEG file.
 | 
			
		||||
#define PARSE_EXIF_ERROR_NO_EXIF              1983
 | 
			
		||||
// Byte alignment specified in EXIF file was unknown (not Motorola or Intel).
 | 
			
		||||
#define PARSE_EXIF_ERROR_UNKNOWN_BYTEALIGN    1984
 | 
			
		||||
// EXIF header was found, but data was corrupted.
 | 
			
		||||
#define PARSE_EXIF_ERROR_CORRUPT              1985
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										302
									
								
								imageviewer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								imageviewer.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,302 @@
 | 
			
		||||
#ifndef IMGUI_IMAGE_VIEWER_H
 | 
			
		||||
#define IMGUI_IMAGE_VIEWER_H
 | 
			
		||||
 | 
			
		||||
#include "app_image.h" // Needs the AppImage class definition
 | 
			
		||||
#include "imgui.h"
 | 
			
		||||
#define IMGUI_DEFINE_MATH_OPERATORS // Allows ImVec2 operators
 | 
			
		||||
#include "imgui_internal.h" // Need ImFloorSigned, ImClamp, ImMax, ImMin, ImAbs
 | 
			
		||||
#include <cmath>           // For pow, round, floor
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <algorithm>       // For std::max, std::min
 | 
			
		||||
 | 
			
		||||
#define IMGUI_DEFINE_MATH_OPERATORS // Allows ImVec2 operators
 | 
			
		||||
// --- Graphics API ---
 | 
			
		||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
 | 
			
		||||
#include <SDL_opengles2.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <SDL_opengl.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// --- User Instructions ---
 | 
			
		||||
// (Same as before: Include after dependencies, define IMPLEMENTATION once)
 | 
			
		||||
 | 
			
		||||
class ImGuiImageViewer {
 | 
			
		||||
public:
 | 
			
		||||
    ImGuiImageViewer();
 | 
			
		||||
    ~ImGuiImageViewer();
 | 
			
		||||
 | 
			
		||||
    ImGuiImageViewer(const ImGuiImageViewer&) = delete;
 | 
			
		||||
    ImGuiImageViewer& operator=(const ImGuiImageViewer&) = delete;
 | 
			
		||||
 | 
			
		||||
    bool LoadImage(const AppImage& appImage);
 | 
			
		||||
    void UnloadImage();
 | 
			
		||||
    // Renders within the available space, maintaining aspect ratio.
 | 
			
		||||
    void Render(const ImVec2& availableSize);
 | 
			
		||||
    void ResetView(); // Resets zoom to 100%, centers view
 | 
			
		||||
 | 
			
		||||
    // --- Getters ---
 | 
			
		||||
    float GetZoom() const { return m_zoom; }
 | 
			
		||||
    // Pan offset returns the center of the view in UV coordinates (0.0-1.0)
 | 
			
		||||
    ImVec2 GetPanOffsetUV() const { return m_panOffsetUV; }
 | 
			
		||||
    bool IsImageLoaded() const { return m_textureId != 0; }
 | 
			
		||||
    // Get the raw OpenGL texture ID for external use
 | 
			
		||||
    GLuint GetTextureId() const { return m_textureId; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    GLuint m_textureId = 0;
 | 
			
		||||
    int m_textureWidth = 0;
 | 
			
		||||
    int m_textureHeight = 0;
 | 
			
		||||
 | 
			
		||||
    float m_zoom = 1.0f; // Scale factor (1.0 = 100%)
 | 
			
		||||
    // Pan offset: Center of the view in UV coordinates (0.0 to 1.0)
 | 
			
		||||
    ImVec2 m_panOffsetUV = ImVec2(0.5f, 0.5f);
 | 
			
		||||
 | 
			
		||||
    // Interaction state
 | 
			
		||||
    bool m_isDragging = false;
 | 
			
		||||
    ImVec2 m_dragStartMousePos = ImVec2(0, 0);
 | 
			
		||||
    ImVec2 m_dragStartPanOffsetUV = ImVec2(0, 0);
 | 
			
		||||
 | 
			
		||||
    // Configuration
 | 
			
		||||
    const float m_minZoom = 0.01f; // 1%
 | 
			
		||||
    const float m_maxZoom = 50.0f; // 5000%
 | 
			
		||||
    const float m_zoomSpeed = 1.1f;
 | 
			
		||||
 | 
			
		||||
    // Clamps pan offset (UV) based on the container size and zoom.
 | 
			
		||||
    void ClampPanOffset(const ImVec2& containerSize);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// ============================================================================
 | 
			
		||||
// =================== IMPLEMENTATION SECTION =================================
 | 
			
		||||
// ============================================================================
 | 
			
		||||
#ifdef IMGUI_IMAGE_VIEWER_IMPLEMENTATION
 | 
			
		||||
 | 
			
		||||
// --- Helper namespace ---
 | 
			
		||||
namespace ImGuiImageViewerUtil {
 | 
			
		||||
    // Linear float [0,1+] -> sRGB approx [0,1]
 | 
			
		||||
    inline float linear_to_srgb_approx(float linearVal) {
 | 
			
		||||
        if (linearVal <= 0.0f) return 0.0f;
 | 
			
		||||
        linearVal = std::fmax(0.0f, std::fmin(1.0f, linearVal)); // Clamp for display
 | 
			
		||||
        if (linearVal <= 0.0031308f) { return linearVal * 12.92f; }
 | 
			
		||||
        else { return 1.055f * std::pow(linearVal, 1.0f / 2.4f) - 0.055f; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Round float to nearest integer
 | 
			
		||||
    inline float Round(float f) { return ImFloor(f + 0.5f); }
 | 
			
		||||
} // namespace ImGuiImageViewerUtil
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ImGuiImageViewer::ImGuiImageViewer() {}
 | 
			
		||||
ImGuiImageViewer::~ImGuiImageViewer() { UnloadImage(); }
 | 
			
		||||
 | 
			
		||||
void ImGuiImageViewer::UnloadImage() {
 | 
			
		||||
    if (m_textureId != 0) {
 | 
			
		||||
        glDeleteTextures(1, &m_textureId);
 | 
			
		||||
        m_textureId = 0;
 | 
			
		||||
        m_textureWidth = 0;
 | 
			
		||||
        m_textureHeight = 0;
 | 
			
		||||
        ResetView();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ImGuiImageViewer::LoadImage(const AppImage& appImage) {
 | 
			
		||||
    // --- Basic Error Checking ---
 | 
			
		||||
    if (appImage.isEmpty() || appImage.getWidth() == 0 || appImage.getHeight() == 0) {
 | 
			
		||||
        UnloadImage(); return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (!appImage.isLinear()) { /* Log warning */ }
 | 
			
		||||
    const int width = static_cast<int>(appImage.getWidth());
 | 
			
		||||
    const int height = static_cast<int>(appImage.getHeight());
 | 
			
		||||
    const int channels = static_cast<int>(appImage.getChannels());
 | 
			
		||||
    if (channels != 1 && channels != 3 && channels != 4) { UnloadImage(); return false; }
 | 
			
		||||
    const float* linearData = appImage.getData();
 | 
			
		||||
 | 
			
		||||
    // --- Prepare 8-bit sRGB data for OpenGL (RGBA format) ---
 | 
			
		||||
    GLenum internalFormat = GL_RGBA8; GLenum dataFormat = GL_RGBA; int outputChannels = 4;
 | 
			
		||||
    std::vector<unsigned char> textureData(static_cast<size_t>(width) * height * outputChannels);
 | 
			
		||||
    unsigned char* outPtr = textureData.data(); const float* inPtr = linearData;
 | 
			
		||||
    for (int y = 0; y < height; ++y) {
 | 
			
		||||
        for (int x = 0; x < width; ++x) {
 | 
			
		||||
            float r=0,g=0,b=0,a=1; if(channels==1){r=g=b=*inPtr++;} else if(channels==3){r=*inPtr++;g=*inPtr++;b=*inPtr++;} else{r=*inPtr++;g=*inPtr++;b=*inPtr++;a=*inPtr++;}
 | 
			
		||||
            float sr=ImGuiImageViewerUtil::linear_to_srgb_approx(r), sg=ImGuiImageViewerUtil::linear_to_srgb_approx(g), sb=ImGuiImageViewerUtil::linear_to_srgb_approx(b); a=std::fmax(0.f,std::fmin(1.f,a));
 | 
			
		||||
            *outPtr++=static_cast<unsigned char>(std::max(0, std::min(255, static_cast<int>(ImGuiImageViewerUtil::Round(sr*255.f)))));
 | 
			
		||||
            *outPtr++=static_cast<unsigned char>(std::max(0, std::min(255, static_cast<int>(ImGuiImageViewerUtil::Round(sg*255.f)))));
 | 
			
		||||
            *outPtr++=static_cast<unsigned char>(std::max(0, std::min(255, static_cast<int>(ImGuiImageViewerUtil::Round(sb*255.f)))));
 | 
			
		||||
            *outPtr++=static_cast<unsigned char>(std::max(0, std::min(255, static_cast<int>(ImGuiImageViewerUtil::Round(a*255.f)))));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // --- Upload to OpenGL Texture ---
 | 
			
		||||
    GLint lastTexture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastTexture);
 | 
			
		||||
    if (m_textureId == 0) { glGenTextures(1, &m_textureId); }
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, m_textureId);
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // No filtering
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // No filtering
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 | 
			
		||||
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
 | 
			
		||||
    glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, dataFormat, GL_UNSIGNED_BYTE, textureData.data());
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, lastTexture);
 | 
			
		||||
 | 
			
		||||
    m_textureWidth = width; m_textureHeight = height;
 | 
			
		||||
    ResetView(); // Reset view when loading a new image
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ImGuiImageViewer::ResetView() {
 | 
			
		||||
    m_zoom = 1.0f;
 | 
			
		||||
    m_panOffsetUV = ImVec2(0.5f, 0.5f); // Center view
 | 
			
		||||
    m_isDragging = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Clamp pan offset (UV coordinates)
 | 
			
		||||
void ImGuiImageViewer::ClampPanOffset(const ImVec2& containerSize) {
 | 
			
		||||
    if (m_textureWidth <= 0 || m_textureHeight <= 0 || m_zoom <= 0) return;
 | 
			
		||||
 | 
			
		||||
    // Size of the image content projected onto the screen at current zoom
 | 
			
		||||
    ImVec2 zoomedImageScreenSize = ImVec2(m_textureWidth * m_zoom, m_textureHeight * m_zoom);
 | 
			
		||||
 | 
			
		||||
    // Calculate the size of the visible area in UV coordinates
 | 
			
		||||
    ImVec2 viewSizeUV = containerSize / zoomedImageScreenSize; // If zoom=1, size=texSize, this is containerSize/texSize
 | 
			
		||||
    viewSizeUV.x = ImMin(viewSizeUV.x, 1.0f); // Cannot see more than 1.0 UV width
 | 
			
		||||
    viewSizeUV.y = ImMin(viewSizeUV.y, 1.0f); // Cannot see more than 1.0 UV height
 | 
			
		||||
 | 
			
		||||
    // Calculate min/max allowed pan values (center of view in UV space)
 | 
			
		||||
    ImVec2 minPanUV, maxPanUV;
 | 
			
		||||
 | 
			
		||||
    // If the zoomed image is smaller than the container, center it.
 | 
			
		||||
    // The pan offset (center of view) should be locked to 0.5 UV.
 | 
			
		||||
    if (zoomedImageScreenSize.x <= containerSize.x) {
 | 
			
		||||
        minPanUV.x = maxPanUV.x = 0.5f;
 | 
			
		||||
    } else {
 | 
			
		||||
        // Image is wider: Allow panning.
 | 
			
		||||
        // Min pan: Center of view is half the view-width (in UV) from the left edge (UV=0)
 | 
			
		||||
        minPanUV.x = viewSizeUV.x * 0.5f;
 | 
			
		||||
        // Max pan: Center of view is half the view-width (in UV) from the right edge (UV=1)
 | 
			
		||||
        maxPanUV.x = 1.0f - viewSizeUV.x * 0.5f;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (zoomedImageScreenSize.y <= containerSize.y) {
 | 
			
		||||
        // Image is shorter: Center it.
 | 
			
		||||
        minPanUV.y = maxPanUV.y = 0.5f;
 | 
			
		||||
    } else {
 | 
			
		||||
        // Image is taller: Allow panning.
 | 
			
		||||
        minPanUV.y = viewSizeUV.y * 0.5f;
 | 
			
		||||
        maxPanUV.y = 1.0f - viewSizeUV.y * 0.5f;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Apply clamping
 | 
			
		||||
    m_panOffsetUV.x = ImClamp(m_panOffsetUV.x, minPanUV.x, maxPanUV.x);
 | 
			
		||||
    m_panOffsetUV.y = ImClamp(m_panOffsetUV.y, minPanUV.y, maxPanUV.y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void ImGuiImageViewer::Render(const ImVec2& availableSize) {
 | 
			
		||||
    if (m_textureId == 0 || m_textureWidth <= 0 || m_textureHeight <= 0) {
 | 
			
		||||
        ImGui::Dummy(availableSize); return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ImGuiIO& io = ImGui::GetIO();
 | 
			
		||||
    ImGuiStyle& style = ImGui::GetStyle();
 | 
			
		||||
 | 
			
		||||
    // Begin a child window to establish a canvas with a background
 | 
			
		||||
    ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.1f, 0.1f, 0.1f, 1.0f)); // Dark background for contrast
 | 
			
		||||
    ImGui::BeginChild("ImageViewerCanvas", availableSize, false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDecoration);
 | 
			
		||||
 | 
			
		||||
    ImVec2 containerSize = ImGui::GetContentRegionAvail();
 | 
			
		||||
    if (containerSize.x < 1.0f) containerSize.x = 1.0f;
 | 
			
		||||
    if (containerSize.y < 1.0f) containerSize.y = 1.0f;
 | 
			
		||||
    ImVec2 containerTopLeftScreen = ImGui::GetCursorScreenPos();
 | 
			
		||||
 | 
			
		||||
    // Calculate aspect-correct display size and padding within the container
 | 
			
		||||
    float imageAspect = static_cast<float>(m_textureWidth) / static_cast<float>(m_textureHeight);
 | 
			
		||||
    float containerAspect = containerSize.x / containerSize.y;
 | 
			
		||||
    ImVec2 displaySize = containerSize; // Final screen size of the image content
 | 
			
		||||
    ImVec2 displayPadding = ImVec2(0, 0); // Padding for letter/pillarboxing
 | 
			
		||||
 | 
			
		||||
    if (containerAspect > imageAspect) { // Letterbox: Container wider than image
 | 
			
		||||
        displaySize.x = containerSize.y * imageAspect;
 | 
			
		||||
        displayPadding.x = (containerSize.x - displaySize.x) * 0.5f;
 | 
			
		||||
    } else { // Pillarbox: Container taller than image (or same aspect)
 | 
			
		||||
        displaySize.y = containerSize.x / imageAspect;
 | 
			
		||||
        displayPadding.y = (containerSize.y - displaySize.y) * 0.5f;
 | 
			
		||||
    }
 | 
			
		||||
    // Round padding to avoid pixel jitter
 | 
			
		||||
    displayPadding.x = ImFloor(displayPadding.x);
 | 
			
		||||
    displayPadding.y = ImFloor(displayPadding.y);
 | 
			
		||||
    displaySize = containerSize - displayPadding * 2.0f; // Recalculate based on rounded padding
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Screen position where the image content rendering starts
 | 
			
		||||
    ImVec2 displayTopLeftScreen = containerTopLeftScreen + displayPadding;
 | 
			
		||||
 | 
			
		||||
    // Invisible button covering the *entire container* for capturing inputs
 | 
			
		||||
    ImGui::SetCursorScreenPos(containerTopLeftScreen);
 | 
			
		||||
    ImGui::InvisibleButton("##canvas_interaction", containerSize);
 | 
			
		||||
    bool isHoveredOnCanvas = ImGui::IsItemHovered();
 | 
			
		||||
    bool isActiveOnCanvas = ImGui::IsItemActive();
 | 
			
		||||
 | 
			
		||||
    // Calculate mouse position relative to the *display area* top-left corner
 | 
			
		||||
    ImVec2 mousePosDisplay = io.MousePos - displayTopLeftScreen;
 | 
			
		||||
 | 
			
		||||
    // Check if the mouse is actually over the image content, not the padding
 | 
			
		||||
    bool isMouseInDisplayArea = (mousePosDisplay.x >= 0.0f && mousePosDisplay.x < displaySize.x &&
 | 
			
		||||
                                 mousePosDisplay.y >= 0.0f && mousePosDisplay.y < displaySize.y);
 | 
			
		||||
 | 
			
		||||
    // 1. Zooming (centered on mouse, only when hovering the image content)
 | 
			
		||||
    if (isHoveredOnCanvas && isMouseInDisplayArea && io.MouseWheel != 0.0f) {
 | 
			
		||||
        // Mouse position relative to display center, in screen pixels
 | 
			
		||||
        ImVec2 mouseRelCenter = mousePosDisplay - displaySize * 0.5f;
 | 
			
		||||
        // Convert mouse position to UV coordinates *before* zoom change
 | 
			
		||||
        ImVec2 mouseUV = m_panOffsetUV + mouseRelCenter / (ImVec2((float)m_textureWidth, (float)m_textureHeight) * m_zoom);
 | 
			
		||||
 | 
			
		||||
        float oldZoom = m_zoom;
 | 
			
		||||
        m_zoom *= std::pow(m_zoomSpeed, io.MouseWheel);
 | 
			
		||||
        m_zoom = ImClamp(m_zoom, m_minZoom, m_maxZoom); // Clamp zoom
 | 
			
		||||
 | 
			
		||||
        // Keep the same UV coordinate under the mouse cursor after zoom
 | 
			
		||||
        // NewPan = MouseUV - (MouseScreenPosRelCenter / NewZoomedImageScreenSize)
 | 
			
		||||
        m_panOffsetUV = mouseUV - mouseRelCenter / (ImVec2((float)m_textureWidth, (float)m_textureHeight) * m_zoom);
 | 
			
		||||
 | 
			
		||||
        ClampPanOffset(containerSize); // Re-clamp after zoom
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 2. Panning (allow dragging anywhere on the canvas)
 | 
			
		||||
    if (isActiveOnCanvas && ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
 | 
			
		||||
        if (!m_isDragging) {
 | 
			
		||||
            m_isDragging = true;
 | 
			
		||||
            m_dragStartMousePos = io.MousePos;
 | 
			
		||||
            m_dragStartPanOffsetUV = m_panOffsetUV;
 | 
			
		||||
        }
 | 
			
		||||
        ImVec2 mouseDelta = io.MousePos - m_dragStartMousePos;
 | 
			
		||||
        // Convert screen pixel delta to UV delta
 | 
			
		||||
        ImVec2 uvDelta = mouseDelta / (ImVec2((float)m_textureWidth, (float)m_textureHeight) * m_zoom);
 | 
			
		||||
 | 
			
		||||
        m_panOffsetUV = m_dragStartPanOffsetUV - uvDelta; // Subtract because dragging right moves content left (reduces UV offset)
 | 
			
		||||
 | 
			
		||||
        ClampPanOffset(containerSize); // Clamp during drag
 | 
			
		||||
 | 
			
		||||
    } else if (m_isDragging) {
 | 
			
		||||
        m_isDragging = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // --- UV Calculation ---
 | 
			
		||||
    // Calculate the size of the viewable rectangle in UV coordinates
 | 
			
		||||
    ImVec2 viewSizeUV = displaySize / (ImVec2((float)m_textureWidth, (float)m_textureHeight) * m_zoom);
 | 
			
		||||
    // Calculate top-left (uv0) and bottom-right (uv1) UV coordinates based on the centered pan offset
 | 
			
		||||
    ImVec2 uv0 = m_panOffsetUV - viewSizeUV * 0.5f;
 | 
			
		||||
    ImVec2 uv1 = m_panOffsetUV + viewSizeUV * 0.5f;
 | 
			
		||||
 | 
			
		||||
    // --- Draw the Image ---
 | 
			
		||||
    ImGui::SetCursorScreenPos(displayTopLeftScreen); // Position cursor for image drawing
 | 
			
		||||
    ImGui::Image((ImTextureID)(intptr_t)m_textureId, displaySize, uv0, uv1);
 | 
			
		||||
 | 
			
		||||
    ImGui::EndChild();
 | 
			
		||||
    ImGui::PopStyleColor(); // Pop ChildBg color
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // IMGUI_IMAGE_VIEWER_IMPLEMENTATION
 | 
			
		||||
 | 
			
		||||
#endif // IMGUI_IMAGE_VIEWER_H
 | 
			
		||||
							
								
								
									
										141
									
								
								imconfig.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								imconfig.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,141 @@
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
// DEAR IMGUI COMPILE-TIME OPTIONS
 | 
			
		||||
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
 | 
			
		||||
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
 | 
			
		||||
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
 | 
			
		||||
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
 | 
			
		||||
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
 | 
			
		||||
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
//---- Define assertion handler. Defaults to calling assert().
 | 
			
		||||
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
 | 
			
		||||
//#define IM_ASSERT(_EXPR)  MyAssert(_EXPR)
 | 
			
		||||
//#define IM_ASSERT(_EXPR)  ((void)(_EXPR))     // Disable asserts
 | 
			
		||||
 | 
			
		||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
 | 
			
		||||
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
 | 
			
		||||
// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
 | 
			
		||||
//   for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
 | 
			
		||||
//#define IMGUI_API __declspec(dllexport)                   // MSVC Windows: DLL export
 | 
			
		||||
//#define IMGUI_API __declspec(dllimport)                   // MSVC Windows: DLL import
 | 
			
		||||
//#define IMGUI_API __attribute__((visibility("default")))  // GCC/Clang: override visibility when set is hidden
 | 
			
		||||
 | 
			
		||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
 | 
			
		||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
 | 
			
		||||
 | 
			
		||||
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
 | 
			
		||||
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
 | 
			
		||||
//#define IMGUI_DISABLE                                     // Disable everything: all headers and source files will be empty.
 | 
			
		||||
//#define IMGUI_DISABLE_DEMO_WINDOWS                        // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
 | 
			
		||||
//#define IMGUI_DISABLE_DEBUG_TOOLS                         // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty.
 | 
			
		||||
 | 
			
		||||
//---- Don't implement some functions to reduce linkage requirements.
 | 
			
		||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS   // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
 | 
			
		||||
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS          // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
 | 
			
		||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS         // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
 | 
			
		||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS                     // [Win32] Won't use and link with any Win32 function (clipboard, IME).
 | 
			
		||||
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS      // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
 | 
			
		||||
//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS             // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")).
 | 
			
		||||
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS            // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
 | 
			
		||||
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS              // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
 | 
			
		||||
//#define IMGUI_DISABLE_FILE_FUNCTIONS                      // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
 | 
			
		||||
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS              // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
 | 
			
		||||
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS                  // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
 | 
			
		||||
//#define IMGUI_DISABLE_DEFAULT_FONT                        // Disable default embedded font (ProggyClean.ttf), remove ~9.5 KB from output binary. AddFontDefault() will assert.
 | 
			
		||||
//#define IMGUI_DISABLE_SSE                                 // Disable use of SSE intrinsics even if available
 | 
			
		||||
 | 
			
		||||
//---- Enable Test Engine / Automation features.
 | 
			
		||||
//#define IMGUI_ENABLE_TEST_ENGINE                          // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details.
 | 
			
		||||
 | 
			
		||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
 | 
			
		||||
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
 | 
			
		||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
 | 
			
		||||
//#define IMGUI_USER_H_FILENAME         "my_folder/my_imgui_user.h"
 | 
			
		||||
 | 
			
		||||
//---- Pack vertex colors as BGRA8 instead of RGBA8 (to avoid converting from one to another). Need dedicated backend support.
 | 
			
		||||
//#define IMGUI_USE_BGRA_PACKED_COLOR
 | 
			
		||||
 | 
			
		||||
//---- Use legacy CRC32-adler tables (used before 1.91.6), in order to preserve old .ini data that you cannot afford to invalidate.
 | 
			
		||||
//#define IMGUI_USE_LEGACY_CRC32_ADLER
 | 
			
		||||
 | 
			
		||||
//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
 | 
			
		||||
//#define IMGUI_USE_WCHAR32
 | 
			
		||||
 | 
			
		||||
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
 | 
			
		||||
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
 | 
			
		||||
//#define IMGUI_STB_TRUETYPE_FILENAME   "my_folder/stb_truetype.h"
 | 
			
		||||
//#define IMGUI_STB_RECT_PACK_FILENAME  "my_folder/stb_rect_pack.h"
 | 
			
		||||
//#define IMGUI_STB_SPRINTF_FILENAME    "my_folder/stb_sprintf.h"    // only used if IMGUI_USE_STB_SPRINTF is defined.
 | 
			
		||||
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
 | 
			
		||||
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
 | 
			
		||||
//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION                   // only disabled if IMGUI_USE_STB_SPRINTF is defined.
 | 
			
		||||
 | 
			
		||||
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
 | 
			
		||||
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
 | 
			
		||||
//#define IMGUI_USE_STB_SPRINTF
 | 
			
		||||
 | 
			
		||||
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
 | 
			
		||||
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
 | 
			
		||||
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
 | 
			
		||||
//#define IMGUI_ENABLE_FREETYPE
 | 
			
		||||
 | 
			
		||||
//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)
 | 
			
		||||
// Only works in combination with IMGUI_ENABLE_FREETYPE.
 | 
			
		||||
// - plutosvg is currently easier to install, as e.g. it is part of vcpkg. It will support more fonts and may load them faster. See misc/freetype/README for instructions.
 | 
			
		||||
// - Both require headers to be available in the include path + program to be linked with the library code (not provided).
 | 
			
		||||
// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
 | 
			
		||||
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
 | 
			
		||||
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
 | 
			
		||||
 | 
			
		||||
//---- Use stb_truetype to build and rasterize the font atlas (default)
 | 
			
		||||
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
 | 
			
		||||
//#define IMGUI_ENABLE_STB_TRUETYPE
 | 
			
		||||
 | 
			
		||||
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
 | 
			
		||||
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
 | 
			
		||||
/*
 | 
			
		||||
#define IM_VEC2_CLASS_EXTRA                                                     \
 | 
			
		||||
        constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {}                   \
 | 
			
		||||
        operator MyVec2() const { return MyVec2(x,y); }
 | 
			
		||||
 | 
			
		||||
#define IM_VEC4_CLASS_EXTRA                                                     \
 | 
			
		||||
        constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {}   \
 | 
			
		||||
        operator MyVec4() const { return MyVec4(x,y,z,w); }
 | 
			
		||||
*/
 | 
			
		||||
//---- ...Or use Dear ImGui's own very basic math operators.
 | 
			
		||||
//#define IMGUI_DEFINE_MATH_OPERATORS
 | 
			
		||||
 | 
			
		||||
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
 | 
			
		||||
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
 | 
			
		||||
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
 | 
			
		||||
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
 | 
			
		||||
//#define ImDrawIdx unsigned int
 | 
			
		||||
 | 
			
		||||
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
 | 
			
		||||
//struct ImDrawList;
 | 
			
		||||
//struct ImDrawCmd;
 | 
			
		||||
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
 | 
			
		||||
//#define ImDrawCallback MyImDrawCallback
 | 
			
		||||
 | 
			
		||||
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
 | 
			
		||||
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
 | 
			
		||||
//#define IM_DEBUG_BREAK  IM_ASSERT(0)
 | 
			
		||||
//#define IM_DEBUG_BREAK  __debugbreak()
 | 
			
		||||
 | 
			
		||||
//---- Debug Tools: Enable slower asserts
 | 
			
		||||
//#define IMGUI_DEBUG_PARANOID
 | 
			
		||||
 | 
			
		||||
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
 | 
			
		||||
/*
 | 
			
		||||
namespace ImGui
 | 
			
		||||
{
 | 
			
		||||
    void MyFunction(const char* name, MyMatrix44* mtx);
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
							
								
								
									
										1334
									
								
								imfilebrowser.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1334
									
								
								imfilebrowser.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										270
									
								
								imgui.ini
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										270
									
								
								imgui.ini
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,270 @@
 | 
			
		||||
[Window][Image Exif]
 | 
			
		||||
Pos=0,19
 | 
			
		||||
Size=501,2072
 | 
			
		||||
Collapsed=0
 | 
			
		||||
DockId=0x00000003,0
 | 
			
		||||
 | 
			
		||||
[Window][Edit Image]
 | 
			
		||||
Pos=3563,19
 | 
			
		||||
Size=277,2072
 | 
			
		||||
Collapsed=0
 | 
			
		||||
DockId=0x00000002,0
 | 
			
		||||
 | 
			
		||||
[Window][Image View]
 | 
			
		||||
Pos=503,19
 | 
			
		||||
Size=3058,2072
 | 
			
		||||
Collapsed=0
 | 
			
		||||
DockId=0x00000004,0
 | 
			
		||||
 | 
			
		||||
[Window][DockSpaceWindowHost]
 | 
			
		||||
Pos=0,19
 | 
			
		||||
Size=3840,2072
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Debug##Default]
 | 
			
		||||
Pos=60,60
 | 
			
		||||
Size=400,400
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_104234674021344]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_103820503331776]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Export Settings]
 | 
			
		||||
Pos=1779,983
 | 
			
		||||
Size=281,125
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_98063134548928]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Export Image As##filebrowser_98063134549408]
 | 
			
		||||
Pos=1570,820
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_105833422020672]
 | 
			
		||||
Pos=483,342
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Export Image As##filebrowser_105833422020192]
 | 
			
		||||
Pos=483,342
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_106326659371072]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Export Image As##filebrowser_106326659370592]
 | 
			
		||||
Pos=290,136
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_105277128065088]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_95064985587904]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_102890187944128]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_106831463805120]
 | 
			
		||||
Pos=290,137
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_107663186985152]
 | 
			
		||||
Pos=1570,820
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Export Image As##filebrowser_107663186984672]
 | 
			
		||||
Pos=1570,820
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_107790165545152]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_109207766827200]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_103700153057472]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_98304290763072]
 | 
			
		||||
Pos=1570,820
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_101853495222592]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_95128140845376]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_106527524852032]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_98089467183424]
 | 
			
		||||
Pos=1570,820
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Export Image As##filebrowser_98089467182944]
 | 
			
		||||
Pos=1570,820
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_104625190056256]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Export Image As##filebrowser_104625190055776]
 | 
			
		||||
Pos=1570,820
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_104822115266880]
 | 
			
		||||
Pos=419,435
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_94123613466944]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_95503940182336]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_101453941682496]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_95384985870656]
 | 
			
		||||
Pos=610,820
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_102433741902144]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_110281562521920]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_102264946090304]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_94907470143808]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_95449924194624]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_102446271447360]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_96827416379712]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_97775434105152]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_109659660910912]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_106451793555776]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_111077646164288]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_105124544713024]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_101628419936576]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_101417705099584]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_106953443598656]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Window][Open Image File##filebrowser_106456350257472]
 | 
			
		||||
Pos=290,135
 | 
			
		||||
Size=700,450
 | 
			
		||||
Collapsed=0
 | 
			
		||||
 | 
			
		||||
[Docking][Data]
 | 
			
		||||
DockSpace     ID=0xE098E157 Window=0x9E772337 Pos=0,19 Size=3840,2072 Split=X
 | 
			
		||||
  DockNode    ID=0x00000001 Parent=0xE098E157 SizeRef=1641,720 Split=X
 | 
			
		||||
    DockNode  ID=0x00000003 Parent=0x00000001 SizeRef=501,720 Selected=0x5593B2D4
 | 
			
		||||
    DockNode  ID=0x00000004 Parent=0x00000001 SizeRef=3058,720 CentralNode=1 Selected=0x9B39CB70
 | 
			
		||||
  DockNode    ID=0x00000002 Parent=0xE098E157 SizeRef=277,720 Selected=0x610DAB84
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10984
									
								
								imgui_demo.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10984
									
								
								imgui_demo.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4857
									
								
								imgui_draw.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4857
									
								
								imgui_draw.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1023
									
								
								imgui_impl_opengl3.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1023
									
								
								imgui_impl_opengl3.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										67
									
								
								imgui_impl_opengl3.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								imgui_impl_opengl3.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
 | 
			
		||||
// - Desktop GL: 2.x 3.x 4.x
 | 
			
		||||
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
 | 
			
		||||
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
 | 
			
		||||
 | 
			
		||||
// Implemented features:
 | 
			
		||||
//  [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
 | 
			
		||||
//  [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!]
 | 
			
		||||
//  [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
 | 
			
		||||
 | 
			
		||||
// About WebGL/ES:
 | 
			
		||||
// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
 | 
			
		||||
// - This is done automatically on iOS, Android and Emscripten targets.
 | 
			
		||||
// - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h.
 | 
			
		||||
 | 
			
		||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
 | 
			
		||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
 | 
			
		||||
// 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
 | 
			
		||||
 | 
			
		||||
// About GLSL version:
 | 
			
		||||
//  The 'glsl_version' initialization parameter should be nullptr (default) or a "#version XXX" string.
 | 
			
		||||
//  On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
 | 
			
		||||
//  Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "imgui.h"      // IMGUI_IMPL_API
 | 
			
		||||
#ifndef IMGUI_DISABLE
 | 
			
		||||
 | 
			
		||||
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr);
 | 
			
		||||
IMGUI_IMPL_API void     ImGui_ImplOpenGL3_Shutdown();
 | 
			
		||||
IMGUI_IMPL_API void     ImGui_ImplOpenGL3_NewFrame();
 | 
			
		||||
IMGUI_IMPL_API void     ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
 | 
			
		||||
 | 
			
		||||
// (Optional) Called by Init/NewFrame/Shutdown
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplOpenGL3_CreateFontsTexture();
 | 
			
		||||
IMGUI_IMPL_API void     ImGui_ImplOpenGL3_DestroyFontsTexture();
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplOpenGL3_CreateDeviceObjects();
 | 
			
		||||
IMGUI_IMPL_API void     ImGui_ImplOpenGL3_DestroyDeviceObjects();
 | 
			
		||||
 | 
			
		||||
// Configuration flags to add in your imconfig file:
 | 
			
		||||
//#define IMGUI_IMPL_OPENGL_ES2     // Enable ES 2 (Auto-detected on Emscripten)
 | 
			
		||||
//#define IMGUI_IMPL_OPENGL_ES3     // Enable ES 3 (Auto-detected on iOS/Android)
 | 
			
		||||
 | 
			
		||||
// You can explicitly select GLES2 or GLES3 API by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
 | 
			
		||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) \
 | 
			
		||||
 && !defined(IMGUI_IMPL_OPENGL_ES3)
 | 
			
		||||
 | 
			
		||||
// Try to detect GLES on matching platforms
 | 
			
		||||
#if defined(__APPLE__)
 | 
			
		||||
#include <TargetConditionals.h>
 | 
			
		||||
#endif
 | 
			
		||||
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
 | 
			
		||||
#define IMGUI_IMPL_OPENGL_ES3               // iOS, Android  -> GL ES 3, "#version 300 es"
 | 
			
		||||
#elif defined(__EMSCRIPTEN__) || defined(__amigaos4__)
 | 
			
		||||
#define IMGUI_IMPL_OPENGL_ES2               // Emscripten    -> GL ES 2, "#version 100"
 | 
			
		||||
#else
 | 
			
		||||
// Otherwise imgui_impl_opengl3_loader.h will be used.
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif // #ifndef IMGUI_DISABLE
 | 
			
		||||
							
								
								
									
										916
									
								
								imgui_impl_opengl3_loader.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										916
									
								
								imgui_impl_opengl3_loader.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,916 @@
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
// About imgui_impl_opengl3_loader.h:
 | 
			
		||||
//
 | 
			
		||||
// We embed our own OpenGL loader to not require user to provide their own or to have to use ours,
 | 
			
		||||
// which proved to be endless problems for users.
 | 
			
		||||
// Our loader is custom-generated, based on gl3w but automatically filtered to only include
 | 
			
		||||
// enums/functions that we use in our imgui_impl_opengl3.cpp source file in order to be small.
 | 
			
		||||
//
 | 
			
		||||
// YOU SHOULD NOT NEED TO INCLUDE/USE THIS DIRECTLY. THIS IS USED BY imgui_impl_opengl3.cpp ONLY.
 | 
			
		||||
// THE REST OF YOUR APP SHOULD USE A DIFFERENT GL LOADER: ANY GL LOADER OF YOUR CHOICE.
 | 
			
		||||
//
 | 
			
		||||
// IF YOU GET BUILD ERRORS IN THIS FILE (commonly macro redefinitions or function redefinitions):
 | 
			
		||||
// IT LIKELY MEANS THAT YOU ARE BUILDING 'imgui_impl_opengl3.cpp' OR INCLUDING 'imgui_impl_opengl3_loader.h'
 | 
			
		||||
// IN THE SAME COMPILATION UNIT AS ONE OF YOUR FILE WHICH IS USING A THIRD-PARTY OPENGL LOADER.
 | 
			
		||||
// (e.g. COULD HAPPEN IF YOU ARE DOING A UNITY/JUMBO BUILD, OR INCLUDING .CPP FILES FROM OTHERS)
 | 
			
		||||
// YOU SHOULD NOT BUILD BOTH IN THE SAME COMPILATION UNIT.
 | 
			
		||||
// BUT IF YOU REALLY WANT TO, you can '#define IMGUI_IMPL_OPENGL_LOADER_CUSTOM' and imgui_impl_opengl3.cpp
 | 
			
		||||
// WILL NOT BE USING OUR LOADER, AND INSTEAD EXPECT ANOTHER/YOUR LOADER TO BE AVAILABLE IN THE COMPILATION UNIT.
 | 
			
		||||
//
 | 
			
		||||
// Regenerate with:
 | 
			
		||||
//   python3 gl3w_gen.py --output ../imgui/backends/imgui_impl_opengl3_loader.h --ref ../imgui/backends/imgui_impl_opengl3.cpp ./extra_symbols.txt
 | 
			
		||||
//
 | 
			
		||||
// More info:
 | 
			
		||||
//   https://github.com/dearimgui/gl3w_stripped
 | 
			
		||||
//   https://github.com/ocornut/imgui/issues/4445
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This file was generated with gl3w_gen.py, part of imgl3w
 | 
			
		||||
 * (hosted at https://github.com/dearimgui/gl3w_stripped)
 | 
			
		||||
 *
 | 
			
		||||
 * This is free and unencumbered software released into the public domain.
 | 
			
		||||
 *
 | 
			
		||||
 * Anyone is free to copy, modify, publish, use, compile, sell, or
 | 
			
		||||
 * distribute this software, either in source code form or as a compiled
 | 
			
		||||
 * binary, for any purpose, commercial or non-commercial, and by any
 | 
			
		||||
 * means.
 | 
			
		||||
 *
 | 
			
		||||
 * In jurisdictions that recognize copyright laws, the author or authors
 | 
			
		||||
 * of this software dedicate any and all copyright interest in the
 | 
			
		||||
 * software to the public domain. We make this dedication for the benefit
 | 
			
		||||
 * of the public at large and to the detriment of our heirs and
 | 
			
		||||
 * successors. We intend this dedication to be an overt act of
 | 
			
		||||
 * relinquishment in perpetuity of all present and future rights to this
 | 
			
		||||
 * software under copyright law.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
			
		||||
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
			
		||||
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 | 
			
		||||
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | 
			
		||||
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | 
			
		||||
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | 
			
		||||
 * OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __gl3w_h_
 | 
			
		||||
#define __gl3w_h_
 | 
			
		||||
 | 
			
		||||
// Adapted from KHR/khrplatform.h to avoid including entire file.
 | 
			
		||||
#ifndef __khrplatform_h_
 | 
			
		||||
typedef          float         khronos_float_t;
 | 
			
		||||
typedef signed   char          khronos_int8_t;
 | 
			
		||||
typedef unsigned char          khronos_uint8_t;
 | 
			
		||||
typedef signed   short int     khronos_int16_t;
 | 
			
		||||
typedef unsigned short int     khronos_uint16_t;
 | 
			
		||||
#ifdef _WIN64
 | 
			
		||||
typedef signed   long long int khronos_intptr_t;
 | 
			
		||||
typedef signed   long long int khronos_ssize_t;
 | 
			
		||||
#else
 | 
			
		||||
typedef signed   long  int     khronos_intptr_t;
 | 
			
		||||
typedef signed   long  int     khronos_ssize_t;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) && !defined(__clang__)
 | 
			
		||||
typedef signed   __int64       khronos_int64_t;
 | 
			
		||||
typedef unsigned __int64       khronos_uint64_t;
 | 
			
		||||
#elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100)
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
typedef          int64_t       khronos_int64_t;
 | 
			
		||||
typedef          uint64_t      khronos_uint64_t;
 | 
			
		||||
#else
 | 
			
		||||
typedef signed   long long     khronos_int64_t;
 | 
			
		||||
typedef unsigned long long     khronos_uint64_t;
 | 
			
		||||
#endif
 | 
			
		||||
#endif  // __khrplatform_h_
 | 
			
		||||
 | 
			
		||||
#ifndef __gl_glcorearb_h_
 | 
			
		||||
#define __gl_glcorearb_h_ 1
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
/*
 | 
			
		||||
** Copyright 2013-2020 The Khronos Group Inc.
 | 
			
		||||
** SPDX-License-Identifier: MIT
 | 
			
		||||
**
 | 
			
		||||
** This header is generated from the Khronos OpenGL / OpenGL ES XML
 | 
			
		||||
** API Registry. The current version of the Registry, generator scripts
 | 
			
		||||
** used to make the header, and the header can be found at
 | 
			
		||||
**   https://github.com/KhronosGroup/OpenGL-Registry
 | 
			
		||||
*/
 | 
			
		||||
#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
 | 
			
		||||
#ifndef WIN32_LEAN_AND_MEAN
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN 1
 | 
			
		||||
#endif
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef APIENTRY
 | 
			
		||||
#define APIENTRY
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef APIENTRYP
 | 
			
		||||
#define APIENTRYP APIENTRY *
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef GLAPI
 | 
			
		||||
#define GLAPI extern
 | 
			
		||||
#endif
 | 
			
		||||
/* glcorearb.h is for use with OpenGL core profile implementations.
 | 
			
		||||
** It should should be placed in the same directory as gl.h and
 | 
			
		||||
** included as <GL/glcorearb.h>.
 | 
			
		||||
**
 | 
			
		||||
** glcorearb.h includes only APIs in the latest OpenGL core profile
 | 
			
		||||
** implementation together with APIs in newer ARB extensions which 
 | 
			
		||||
** can be supported by the core profile. It does not, and never will
 | 
			
		||||
** include functionality removed from the core profile, such as
 | 
			
		||||
** fixed-function vertex and fragment processing.
 | 
			
		||||
**
 | 
			
		||||
** Do not #include both <GL/glcorearb.h> and either of <GL/gl.h> or
 | 
			
		||||
** <GL/glext.h> in the same source file.
 | 
			
		||||
*/
 | 
			
		||||
/* Generated C header for:
 | 
			
		||||
 * API: gl
 | 
			
		||||
 * Profile: core
 | 
			
		||||
 * Versions considered: .*
 | 
			
		||||
 * Versions emitted: .*
 | 
			
		||||
 * Default extensions included: glcore
 | 
			
		||||
 * Additional extensions included: _nomatch_^
 | 
			
		||||
 * Extensions removed: _nomatch_^
 | 
			
		||||
 */
 | 
			
		||||
#ifndef GL_VERSION_1_0
 | 
			
		||||
typedef void GLvoid;
 | 
			
		||||
typedef unsigned int GLenum;
 | 
			
		||||
 | 
			
		||||
typedef khronos_float_t GLfloat;
 | 
			
		||||
typedef int GLint;
 | 
			
		||||
typedef int GLsizei;
 | 
			
		||||
typedef unsigned int GLbitfield;
 | 
			
		||||
typedef double GLdouble;
 | 
			
		||||
typedef unsigned int GLuint;
 | 
			
		||||
typedef unsigned char GLboolean;
 | 
			
		||||
typedef khronos_uint8_t GLubyte;
 | 
			
		||||
#define GL_COLOR_BUFFER_BIT               0x00004000
 | 
			
		||||
#define GL_FALSE                          0
 | 
			
		||||
#define GL_TRUE                           1
 | 
			
		||||
#define GL_TRIANGLES                      0x0004
 | 
			
		||||
#define GL_ONE                            1
 | 
			
		||||
#define GL_SRC_ALPHA                      0x0302
 | 
			
		||||
#define GL_ONE_MINUS_SRC_ALPHA            0x0303
 | 
			
		||||
#define GL_FRONT                          0x0404
 | 
			
		||||
#define GL_BACK                           0x0405
 | 
			
		||||
#define GL_FRONT_AND_BACK                 0x0408
 | 
			
		||||
#define GL_POLYGON_MODE                   0x0B40
 | 
			
		||||
#define GL_CULL_FACE                      0x0B44
 | 
			
		||||
#define GL_DEPTH_TEST                     0x0B71
 | 
			
		||||
#define GL_STENCIL_TEST                   0x0B90
 | 
			
		||||
#define GL_VIEWPORT                       0x0BA2
 | 
			
		||||
#define GL_BLEND                          0x0BE2
 | 
			
		||||
#define GL_SCISSOR_BOX                    0x0C10
 | 
			
		||||
#define GL_SCISSOR_TEST                   0x0C11
 | 
			
		||||
#define GL_UNPACK_ROW_LENGTH              0x0CF2
 | 
			
		||||
#define GL_PACK_ALIGNMENT                 0x0D05
 | 
			
		||||
#define GL_TEXTURE_2D                     0x0DE1
 | 
			
		||||
#define GL_UNSIGNED_BYTE                  0x1401
 | 
			
		||||
#define GL_UNSIGNED_SHORT                 0x1403
 | 
			
		||||
#define GL_UNSIGNED_INT                   0x1405
 | 
			
		||||
#define GL_FLOAT                          0x1406
 | 
			
		||||
#define GL_RGBA                           0x1908
 | 
			
		||||
#define GL_FILL                           0x1B02
 | 
			
		||||
#define GL_VENDOR                         0x1F00
 | 
			
		||||
#define GL_RENDERER                       0x1F01
 | 
			
		||||
#define GL_VERSION                        0x1F02
 | 
			
		||||
#define GL_EXTENSIONS                     0x1F03
 | 
			
		||||
#define GL_LINEAR                         0x2601
 | 
			
		||||
#define GL_TEXTURE_MAG_FILTER             0x2800
 | 
			
		||||
#define GL_TEXTURE_MIN_FILTER             0x2801
 | 
			
		||||
#define GL_TEXTURE_WRAP_S                 0x2802
 | 
			
		||||
#define GL_TEXTURE_WRAP_T                 0x2803
 | 
			
		||||
#define GL_REPEAT                         0x2901
 | 
			
		||||
typedef void (APIENTRYP PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode);
 | 
			
		||||
typedef void (APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
 | 
			
		||||
typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
 | 
			
		||||
typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
 | 
			
		||||
typedef void (APIENTRYP PFNGLCLEARPROC) (GLbitfield mask);
 | 
			
		||||
typedef void (APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
 | 
			
		||||
typedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap);
 | 
			
		||||
typedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap);
 | 
			
		||||
typedef void (APIENTRYP PFNGLFLUSHPROC) (void);
 | 
			
		||||
typedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param);
 | 
			
		||||
typedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
 | 
			
		||||
typedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data);
 | 
			
		||||
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGPROC) (GLenum name);
 | 
			
		||||
typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC) (GLenum cap);
 | 
			
		||||
typedef void (APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
 | 
			
		||||
#ifdef GL_GLEXT_PROTOTYPES
 | 
			
		||||
GLAPI void APIENTRY glPolygonMode (GLenum face, GLenum mode);
 | 
			
		||||
GLAPI void APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
 | 
			
		||||
GLAPI void APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
 | 
			
		||||
GLAPI void APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
 | 
			
		||||
GLAPI void APIENTRY glClear (GLbitfield mask);
 | 
			
		||||
GLAPI void APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
 | 
			
		||||
GLAPI void APIENTRY glDisable (GLenum cap);
 | 
			
		||||
GLAPI void APIENTRY glEnable (GLenum cap);
 | 
			
		||||
GLAPI void APIENTRY glFlush (void);
 | 
			
		||||
GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param);
 | 
			
		||||
GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
 | 
			
		||||
GLAPI GLenum APIENTRY glGetError (void);
 | 
			
		||||
GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *data);
 | 
			
		||||
GLAPI const GLubyte *APIENTRY glGetString (GLenum name);
 | 
			
		||||
GLAPI GLboolean APIENTRY glIsEnabled (GLenum cap);
 | 
			
		||||
GLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* GL_VERSION_1_0 */
 | 
			
		||||
#ifndef GL_VERSION_1_1
 | 
			
		||||
typedef khronos_float_t GLclampf;
 | 
			
		||||
typedef double GLclampd;
 | 
			
		||||
#define GL_TEXTURE_BINDING_2D             0x8069
 | 
			
		||||
typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices);
 | 
			
		||||
typedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
 | 
			
		||||
typedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
 | 
			
		||||
#ifdef GL_GLEXT_PROTOTYPES
 | 
			
		||||
GLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices);
 | 
			
		||||
GLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture);
 | 
			
		||||
GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures);
 | 
			
		||||
GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures);
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* GL_VERSION_1_1 */
 | 
			
		||||
#ifndef GL_VERSION_1_2
 | 
			
		||||
#define GL_CLAMP_TO_EDGE                  0x812F
 | 
			
		||||
#endif /* GL_VERSION_1_2 */
 | 
			
		||||
#ifndef GL_VERSION_1_3
 | 
			
		||||
#define GL_TEXTURE0                       0x84C0
 | 
			
		||||
#define GL_ACTIVE_TEXTURE                 0x84E0
 | 
			
		||||
typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
 | 
			
		||||
#ifdef GL_GLEXT_PROTOTYPES
 | 
			
		||||
GLAPI void APIENTRY glActiveTexture (GLenum texture);
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* GL_VERSION_1_3 */
 | 
			
		||||
#ifndef GL_VERSION_1_4
 | 
			
		||||
#define GL_BLEND_DST_RGB                  0x80C8
 | 
			
		||||
#define GL_BLEND_SRC_RGB                  0x80C9
 | 
			
		||||
#define GL_BLEND_DST_ALPHA                0x80CA
 | 
			
		||||
#define GL_BLEND_SRC_ALPHA                0x80CB
 | 
			
		||||
#define GL_FUNC_ADD                       0x8006
 | 
			
		||||
typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
 | 
			
		||||
typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);
 | 
			
		||||
#ifdef GL_GLEXT_PROTOTYPES
 | 
			
		||||
GLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
 | 
			
		||||
GLAPI void APIENTRY glBlendEquation (GLenum mode);
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* GL_VERSION_1_4 */
 | 
			
		||||
#ifndef GL_VERSION_1_5
 | 
			
		||||
typedef khronos_ssize_t GLsizeiptr;
 | 
			
		||||
typedef khronos_intptr_t GLintptr;
 | 
			
		||||
#define GL_ARRAY_BUFFER                   0x8892
 | 
			
		||||
#define GL_ELEMENT_ARRAY_BUFFER           0x8893
 | 
			
		||||
#define GL_ARRAY_BUFFER_BINDING           0x8894
 | 
			
		||||
#define GL_ELEMENT_ARRAY_BUFFER_BINDING   0x8895
 | 
			
		||||
#define GL_STREAM_DRAW                    0x88E0
 | 
			
		||||
typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
 | 
			
		||||
typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
 | 
			
		||||
typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
 | 
			
		||||
typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
 | 
			
		||||
#ifdef GL_GLEXT_PROTOTYPES
 | 
			
		||||
GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer);
 | 
			
		||||
GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);
 | 
			
		||||
GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
 | 
			
		||||
GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
 | 
			
		||||
GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* GL_VERSION_1_5 */
 | 
			
		||||
#ifndef GL_VERSION_2_0
 | 
			
		||||
typedef char GLchar;
 | 
			
		||||
typedef khronos_int16_t GLshort;
 | 
			
		||||
typedef khronos_int8_t GLbyte;
 | 
			
		||||
typedef khronos_uint16_t GLushort;
 | 
			
		||||
#define GL_BLEND_EQUATION_RGB             0x8009
 | 
			
		||||
#define GL_VERTEX_ATTRIB_ARRAY_ENABLED    0x8622
 | 
			
		||||
#define GL_VERTEX_ATTRIB_ARRAY_SIZE       0x8623
 | 
			
		||||
#define GL_VERTEX_ATTRIB_ARRAY_STRIDE     0x8624
 | 
			
		||||
#define GL_VERTEX_ATTRIB_ARRAY_TYPE       0x8625
 | 
			
		||||
#define GL_VERTEX_ATTRIB_ARRAY_POINTER    0x8645
 | 
			
		||||
#define GL_BLEND_EQUATION_ALPHA           0x883D
 | 
			
		||||
#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
 | 
			
		||||
#define GL_FRAGMENT_SHADER                0x8B30
 | 
			
		||||
#define GL_VERTEX_SHADER                  0x8B31
 | 
			
		||||
#define GL_COMPILE_STATUS                 0x8B81
 | 
			
		||||
#define GL_LINK_STATUS                    0x8B82
 | 
			
		||||
#define GL_INFO_LOG_LENGTH                0x8B84
 | 
			
		||||
#define GL_CURRENT_PROGRAM                0x8B8D
 | 
			
		||||
#define GL_UPPER_LEFT                     0x8CA2
 | 
			
		||||
typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
 | 
			
		||||
typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
 | 
			
		||||
typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
 | 
			
		||||
typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
 | 
			
		||||
typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
 | 
			
		||||
typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
 | 
			
		||||
typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
 | 
			
		||||
typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
 | 
			
		||||
typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
 | 
			
		||||
typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
 | 
			
		||||
typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
 | 
			
		||||
typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer);
 | 
			
		||||
typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program);
 | 
			
		||||
typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);
 | 
			
		||||
typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
 | 
			
		||||
typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);
 | 
			
		||||
typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
 | 
			
		||||
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
 | 
			
		||||
typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
 | 
			
		||||
#ifdef GL_GLEXT_PROTOTYPES
 | 
			
		||||
GLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
 | 
			
		||||
GLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader);
 | 
			
		||||
GLAPI void APIENTRY glCompileShader (GLuint shader);
 | 
			
		||||
GLAPI GLuint APIENTRY glCreateProgram (void);
 | 
			
		||||
GLAPI GLuint APIENTRY glCreateShader (GLenum type);
 | 
			
		||||
GLAPI void APIENTRY glDeleteProgram (GLuint program);
 | 
			
		||||
GLAPI void APIENTRY glDeleteShader (GLuint shader);
 | 
			
		||||
GLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader);
 | 
			
		||||
GLAPI void APIENTRY glDisableVertexAttribArray (GLuint index);
 | 
			
		||||
GLAPI void APIENTRY glEnableVertexAttribArray (GLuint index);
 | 
			
		||||
GLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name);
 | 
			
		||||
GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params);
 | 
			
		||||
GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
 | 
			
		||||
GLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params);
 | 
			
		||||
GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
 | 
			
		||||
GLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name);
 | 
			
		||||
GLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params);
 | 
			
		||||
GLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer);
 | 
			
		||||
GLAPI GLboolean APIENTRY glIsProgram (GLuint program);
 | 
			
		||||
GLAPI void APIENTRY glLinkProgram (GLuint program);
 | 
			
		||||
GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
 | 
			
		||||
GLAPI void APIENTRY glUseProgram (GLuint program);
 | 
			
		||||
GLAPI void APIENTRY glUniform1i (GLint location, GLint v0);
 | 
			
		||||
GLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
 | 
			
		||||
GLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* GL_VERSION_2_0 */
 | 
			
		||||
#ifndef GL_VERSION_2_1
 | 
			
		||||
#define GL_PIXEL_UNPACK_BUFFER            0x88EC
 | 
			
		||||
#define GL_PIXEL_UNPACK_BUFFER_BINDING    0x88EF
 | 
			
		||||
#endif /* GL_VERSION_2_1 */
 | 
			
		||||
#ifndef GL_VERSION_3_0
 | 
			
		||||
typedef khronos_uint16_t GLhalf;
 | 
			
		||||
#define GL_MAJOR_VERSION                  0x821B
 | 
			
		||||
#define GL_MINOR_VERSION                  0x821C
 | 
			
		||||
#define GL_NUM_EXTENSIONS                 0x821D
 | 
			
		||||
#define GL_FRAMEBUFFER_SRGB               0x8DB9
 | 
			
		||||
#define GL_VERTEX_ARRAY_BINDING           0x85B5
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data);
 | 
			
		||||
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index);
 | 
			
		||||
typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array);
 | 
			
		||||
typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
 | 
			
		||||
#ifdef GL_GLEXT_PROTOTYPES
 | 
			
		||||
GLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index);
 | 
			
		||||
GLAPI void APIENTRY glBindVertexArray (GLuint array);
 | 
			
		||||
GLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays);
 | 
			
		||||
GLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays);
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* GL_VERSION_3_0 */
 | 
			
		||||
#ifndef GL_VERSION_3_1
 | 
			
		||||
#define GL_VERSION_3_1 1
 | 
			
		||||
#define GL_PRIMITIVE_RESTART              0x8F9D
 | 
			
		||||
#endif /* GL_VERSION_3_1 */
 | 
			
		||||
#ifndef GL_VERSION_3_2
 | 
			
		||||
#define GL_VERSION_3_2 1
 | 
			
		||||
typedef struct __GLsync *GLsync;
 | 
			
		||||
typedef khronos_uint64_t GLuint64;
 | 
			
		||||
typedef khronos_int64_t GLint64;
 | 
			
		||||
#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
 | 
			
		||||
#define GL_CONTEXT_PROFILE_MASK           0x9126
 | 
			
		||||
typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data);
 | 
			
		||||
#ifdef GL_GLEXT_PROTOTYPES
 | 
			
		||||
GLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* GL_VERSION_3_2 */
 | 
			
		||||
#ifndef GL_VERSION_3_3
 | 
			
		||||
#define GL_VERSION_3_3 1
 | 
			
		||||
#define GL_SAMPLER_BINDING                0x8919
 | 
			
		||||
typedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);
 | 
			
		||||
#ifdef GL_GLEXT_PROTOTYPES
 | 
			
		||||
GLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler);
 | 
			
		||||
#endif
 | 
			
		||||
#endif /* GL_VERSION_3_3 */
 | 
			
		||||
#ifndef GL_VERSION_4_1
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data);
 | 
			
		||||
#endif /* GL_VERSION_4_1 */
 | 
			
		||||
#ifndef GL_VERSION_4_3
 | 
			
		||||
typedef void (APIENTRY  *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
 | 
			
		||||
#endif /* GL_VERSION_4_3 */
 | 
			
		||||
#ifndef GL_VERSION_4_5
 | 
			
		||||
#define GL_CLIP_ORIGIN                    0x935C
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint *param);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64 *param);
 | 
			
		||||
#endif /* GL_VERSION_4_5 */
 | 
			
		||||
#ifndef GL_ARB_bindless_texture
 | 
			
		||||
typedef khronos_uint64_t GLuint64EXT;
 | 
			
		||||
#endif /* GL_ARB_bindless_texture */
 | 
			
		||||
#ifndef GL_ARB_cl_event
 | 
			
		||||
struct _cl_context;
 | 
			
		||||
struct _cl_event;
 | 
			
		||||
#endif /* GL_ARB_cl_event */
 | 
			
		||||
#ifndef GL_ARB_clip_control
 | 
			
		||||
#define GL_ARB_clip_control 1
 | 
			
		||||
#endif /* GL_ARB_clip_control */
 | 
			
		||||
#ifndef GL_ARB_debug_output
 | 
			
		||||
typedef void (APIENTRY  *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
 | 
			
		||||
#endif /* GL_ARB_debug_output */
 | 
			
		||||
#ifndef GL_EXT_EGL_image_storage
 | 
			
		||||
typedef void *GLeglImageOES;
 | 
			
		||||
#endif /* GL_EXT_EGL_image_storage */
 | 
			
		||||
#ifndef GL_EXT_direct_state_access
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param);
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param);
 | 
			
		||||
#endif /* GL_EXT_direct_state_access */
 | 
			
		||||
#ifndef GL_NV_draw_vulkan_image
 | 
			
		||||
typedef void (APIENTRY  *GLVULKANPROCNV)(void);
 | 
			
		||||
#endif /* GL_NV_draw_vulkan_image */
 | 
			
		||||
#ifndef GL_NV_gpu_shader5
 | 
			
		||||
typedef khronos_int64_t GLint64EXT;
 | 
			
		||||
#endif /* GL_NV_gpu_shader5 */
 | 
			
		||||
#ifndef GL_NV_vertex_buffer_unified_memory
 | 
			
		||||
typedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result);
 | 
			
		||||
#endif /* GL_NV_vertex_buffer_unified_memory */
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef GL3W_API
 | 
			
		||||
#define GL3W_API
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __gl_h_
 | 
			
		||||
#define __gl_h_
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define GL3W_OK 0
 | 
			
		||||
#define GL3W_ERROR_INIT -1
 | 
			
		||||
#define GL3W_ERROR_LIBRARY_OPEN -2
 | 
			
		||||
#define GL3W_ERROR_OPENGL_VERSION -3
 | 
			
		||||
 | 
			
		||||
typedef void (*GL3WglProc)(void);
 | 
			
		||||
typedef GL3WglProc (*GL3WGetProcAddressProc)(const char *proc);
 | 
			
		||||
 | 
			
		||||
/* gl3w api */
 | 
			
		||||
GL3W_API int imgl3wInit(void);
 | 
			
		||||
GL3W_API int imgl3wInit2(GL3WGetProcAddressProc proc);
 | 
			
		||||
GL3W_API int imgl3wIsSupported(int major, int minor);
 | 
			
		||||
GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc);
 | 
			
		||||
 | 
			
		||||
/* gl3w internal state */
 | 
			
		||||
union ImGL3WProcs {
 | 
			
		||||
    GL3WglProc ptr[59];
 | 
			
		||||
    struct {
 | 
			
		||||
        PFNGLACTIVETEXTUREPROC            ActiveTexture;
 | 
			
		||||
        PFNGLATTACHSHADERPROC             AttachShader;
 | 
			
		||||
        PFNGLBINDBUFFERPROC               BindBuffer;
 | 
			
		||||
        PFNGLBINDSAMPLERPROC              BindSampler;
 | 
			
		||||
        PFNGLBINDTEXTUREPROC              BindTexture;
 | 
			
		||||
        PFNGLBINDVERTEXARRAYPROC          BindVertexArray;
 | 
			
		||||
        PFNGLBLENDEQUATIONPROC            BlendEquation;
 | 
			
		||||
        PFNGLBLENDEQUATIONSEPARATEPROC    BlendEquationSeparate;
 | 
			
		||||
        PFNGLBLENDFUNCSEPARATEPROC        BlendFuncSeparate;
 | 
			
		||||
        PFNGLBUFFERDATAPROC               BufferData;
 | 
			
		||||
        PFNGLBUFFERSUBDATAPROC            BufferSubData;
 | 
			
		||||
        PFNGLCLEARPROC                    Clear;
 | 
			
		||||
        PFNGLCLEARCOLORPROC               ClearColor;
 | 
			
		||||
        PFNGLCOMPILESHADERPROC            CompileShader;
 | 
			
		||||
        PFNGLCREATEPROGRAMPROC            CreateProgram;
 | 
			
		||||
        PFNGLCREATESHADERPROC             CreateShader;
 | 
			
		||||
        PFNGLDELETEBUFFERSPROC            DeleteBuffers;
 | 
			
		||||
        PFNGLDELETEPROGRAMPROC            DeleteProgram;
 | 
			
		||||
        PFNGLDELETESHADERPROC             DeleteShader;
 | 
			
		||||
        PFNGLDELETETEXTURESPROC           DeleteTextures;
 | 
			
		||||
        PFNGLDELETEVERTEXARRAYSPROC       DeleteVertexArrays;
 | 
			
		||||
        PFNGLDETACHSHADERPROC             DetachShader;
 | 
			
		||||
        PFNGLDISABLEPROC                  Disable;
 | 
			
		||||
        PFNGLDISABLEVERTEXATTRIBARRAYPROC DisableVertexAttribArray;
 | 
			
		||||
        PFNGLDRAWELEMENTSPROC             DrawElements;
 | 
			
		||||
        PFNGLDRAWELEMENTSBASEVERTEXPROC   DrawElementsBaseVertex;
 | 
			
		||||
        PFNGLENABLEPROC                   Enable;
 | 
			
		||||
        PFNGLENABLEVERTEXATTRIBARRAYPROC  EnableVertexAttribArray;
 | 
			
		||||
        PFNGLFLUSHPROC                    Flush;
 | 
			
		||||
        PFNGLGENBUFFERSPROC               GenBuffers;
 | 
			
		||||
        PFNGLGENTEXTURESPROC              GenTextures;
 | 
			
		||||
        PFNGLGENVERTEXARRAYSPROC          GenVertexArrays;
 | 
			
		||||
        PFNGLGETATTRIBLOCATIONPROC        GetAttribLocation;
 | 
			
		||||
        PFNGLGETERRORPROC                 GetError;
 | 
			
		||||
        PFNGLGETINTEGERVPROC              GetIntegerv;
 | 
			
		||||
        PFNGLGETPROGRAMINFOLOGPROC        GetProgramInfoLog;
 | 
			
		||||
        PFNGLGETPROGRAMIVPROC             GetProgramiv;
 | 
			
		||||
        PFNGLGETSHADERINFOLOGPROC         GetShaderInfoLog;
 | 
			
		||||
        PFNGLGETSHADERIVPROC              GetShaderiv;
 | 
			
		||||
        PFNGLGETSTRINGPROC                GetString;
 | 
			
		||||
        PFNGLGETSTRINGIPROC               GetStringi;
 | 
			
		||||
        PFNGLGETUNIFORMLOCATIONPROC       GetUniformLocation;
 | 
			
		||||
        PFNGLGETVERTEXATTRIBPOINTERVPROC  GetVertexAttribPointerv;
 | 
			
		||||
        PFNGLGETVERTEXATTRIBIVPROC        GetVertexAttribiv;
 | 
			
		||||
        PFNGLISENABLEDPROC                IsEnabled;
 | 
			
		||||
        PFNGLISPROGRAMPROC                IsProgram;
 | 
			
		||||
        PFNGLLINKPROGRAMPROC              LinkProgram;
 | 
			
		||||
        PFNGLPIXELSTOREIPROC              PixelStorei;
 | 
			
		||||
        PFNGLPOLYGONMODEPROC              PolygonMode;
 | 
			
		||||
        PFNGLREADPIXELSPROC               ReadPixels;
 | 
			
		||||
        PFNGLSCISSORPROC                  Scissor;
 | 
			
		||||
        PFNGLSHADERSOURCEPROC             ShaderSource;
 | 
			
		||||
        PFNGLTEXIMAGE2DPROC               TexImage2D;
 | 
			
		||||
        PFNGLTEXPARAMETERIPROC            TexParameteri;
 | 
			
		||||
        PFNGLUNIFORM1IPROC                Uniform1i;
 | 
			
		||||
        PFNGLUNIFORMMATRIX4FVPROC         UniformMatrix4fv;
 | 
			
		||||
        PFNGLUSEPROGRAMPROC               UseProgram;
 | 
			
		||||
        PFNGLVERTEXATTRIBPOINTERPROC      VertexAttribPointer;
 | 
			
		||||
        PFNGLVIEWPORTPROC                 Viewport;
 | 
			
		||||
    } gl;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
GL3W_API extern union ImGL3WProcs imgl3wProcs;
 | 
			
		||||
 | 
			
		||||
/* OpenGL functions */
 | 
			
		||||
#define glActiveTexture                   imgl3wProcs.gl.ActiveTexture
 | 
			
		||||
#define glAttachShader                    imgl3wProcs.gl.AttachShader
 | 
			
		||||
#define glBindBuffer                      imgl3wProcs.gl.BindBuffer
 | 
			
		||||
#define glBindSampler                     imgl3wProcs.gl.BindSampler
 | 
			
		||||
#define glBindTexture                     imgl3wProcs.gl.BindTexture
 | 
			
		||||
#define glBindVertexArray                 imgl3wProcs.gl.BindVertexArray
 | 
			
		||||
#define glBlendEquation                   imgl3wProcs.gl.BlendEquation
 | 
			
		||||
#define glBlendEquationSeparate           imgl3wProcs.gl.BlendEquationSeparate
 | 
			
		||||
#define glBlendFuncSeparate               imgl3wProcs.gl.BlendFuncSeparate
 | 
			
		||||
#define glBufferData                      imgl3wProcs.gl.BufferData
 | 
			
		||||
#define glBufferSubData                   imgl3wProcs.gl.BufferSubData
 | 
			
		||||
#define glClear                           imgl3wProcs.gl.Clear
 | 
			
		||||
#define glClearColor                      imgl3wProcs.gl.ClearColor
 | 
			
		||||
#define glCompileShader                   imgl3wProcs.gl.CompileShader
 | 
			
		||||
#define glCreateProgram                   imgl3wProcs.gl.CreateProgram
 | 
			
		||||
#define glCreateShader                    imgl3wProcs.gl.CreateShader
 | 
			
		||||
#define glDeleteBuffers                   imgl3wProcs.gl.DeleteBuffers
 | 
			
		||||
#define glDeleteProgram                   imgl3wProcs.gl.DeleteProgram
 | 
			
		||||
#define glDeleteShader                    imgl3wProcs.gl.DeleteShader
 | 
			
		||||
#define glDeleteTextures                  imgl3wProcs.gl.DeleteTextures
 | 
			
		||||
#define glDeleteVertexArrays              imgl3wProcs.gl.DeleteVertexArrays
 | 
			
		||||
#define glDetachShader                    imgl3wProcs.gl.DetachShader
 | 
			
		||||
#define glDisable                         imgl3wProcs.gl.Disable
 | 
			
		||||
#define glDisableVertexAttribArray        imgl3wProcs.gl.DisableVertexAttribArray
 | 
			
		||||
#define glDrawElements                    imgl3wProcs.gl.DrawElements
 | 
			
		||||
#define glDrawElementsBaseVertex          imgl3wProcs.gl.DrawElementsBaseVertex
 | 
			
		||||
#define glEnable                          imgl3wProcs.gl.Enable
 | 
			
		||||
#define glEnableVertexAttribArray         imgl3wProcs.gl.EnableVertexAttribArray
 | 
			
		||||
#define glFlush                           imgl3wProcs.gl.Flush
 | 
			
		||||
#define glGenBuffers                      imgl3wProcs.gl.GenBuffers
 | 
			
		||||
#define glGenTextures                     imgl3wProcs.gl.GenTextures
 | 
			
		||||
#define glGenVertexArrays                 imgl3wProcs.gl.GenVertexArrays
 | 
			
		||||
#define glGetAttribLocation               imgl3wProcs.gl.GetAttribLocation
 | 
			
		||||
#define glGetError                        imgl3wProcs.gl.GetError
 | 
			
		||||
#define glGetIntegerv                     imgl3wProcs.gl.GetIntegerv
 | 
			
		||||
#define glGetProgramInfoLog               imgl3wProcs.gl.GetProgramInfoLog
 | 
			
		||||
#define glGetProgramiv                    imgl3wProcs.gl.GetProgramiv
 | 
			
		||||
#define glGetShaderInfoLog                imgl3wProcs.gl.GetShaderInfoLog
 | 
			
		||||
#define glGetShaderiv                     imgl3wProcs.gl.GetShaderiv
 | 
			
		||||
#define glGetString                       imgl3wProcs.gl.GetString
 | 
			
		||||
#define glGetStringi                      imgl3wProcs.gl.GetStringi
 | 
			
		||||
#define glGetUniformLocation              imgl3wProcs.gl.GetUniformLocation
 | 
			
		||||
#define glGetVertexAttribPointerv         imgl3wProcs.gl.GetVertexAttribPointerv
 | 
			
		||||
#define glGetVertexAttribiv               imgl3wProcs.gl.GetVertexAttribiv
 | 
			
		||||
#define glIsEnabled                       imgl3wProcs.gl.IsEnabled
 | 
			
		||||
#define glIsProgram                       imgl3wProcs.gl.IsProgram
 | 
			
		||||
#define glLinkProgram                     imgl3wProcs.gl.LinkProgram
 | 
			
		||||
#define glPixelStorei                     imgl3wProcs.gl.PixelStorei
 | 
			
		||||
#define glPolygonMode                     imgl3wProcs.gl.PolygonMode
 | 
			
		||||
#define glReadPixels                      imgl3wProcs.gl.ReadPixels
 | 
			
		||||
#define glScissor                         imgl3wProcs.gl.Scissor
 | 
			
		||||
#define glShaderSource                    imgl3wProcs.gl.ShaderSource
 | 
			
		||||
#define glTexImage2D                      imgl3wProcs.gl.TexImage2D
 | 
			
		||||
#define glTexParameteri                   imgl3wProcs.gl.TexParameteri
 | 
			
		||||
#define glUniform1i                       imgl3wProcs.gl.Uniform1i
 | 
			
		||||
#define glUniformMatrix4fv                imgl3wProcs.gl.UniformMatrix4fv
 | 
			
		||||
#define glUseProgram                      imgl3wProcs.gl.UseProgram
 | 
			
		||||
#define glVertexAttribPointer             imgl3wProcs.gl.VertexAttribPointer
 | 
			
		||||
#define glViewport                        imgl3wProcs.gl.Viewport
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef IMGL3W_IMPL
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#define GL3W_ARRAY_SIZE(x)  (sizeof(x) / sizeof((x)[0]))
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32)
 | 
			
		||||
#ifndef WIN32_LEAN_AND_MEAN
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN 1
 | 
			
		||||
#endif
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
 | 
			
		||||
static HMODULE libgl;
 | 
			
		||||
typedef PROC(__stdcall* GL3WglGetProcAddr)(LPCSTR);
 | 
			
		||||
static GL3WglGetProcAddr wgl_get_proc_address;
 | 
			
		||||
 | 
			
		||||
static int open_libgl(void)
 | 
			
		||||
{
 | 
			
		||||
    libgl = LoadLibraryA("opengl32.dll");
 | 
			
		||||
    if (!libgl)
 | 
			
		||||
        return GL3W_ERROR_LIBRARY_OPEN;
 | 
			
		||||
    wgl_get_proc_address = (GL3WglGetProcAddr)GetProcAddress(libgl, "wglGetProcAddress");
 | 
			
		||||
    return GL3W_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void close_libgl(void) { FreeLibrary(libgl); }
 | 
			
		||||
static GL3WglProc get_proc(const char *proc)
 | 
			
		||||
{
 | 
			
		||||
    GL3WglProc res;
 | 
			
		||||
    res = (GL3WglProc)wgl_get_proc_address(proc);
 | 
			
		||||
    if (!res)
 | 
			
		||||
        res = (GL3WglProc)GetProcAddress(libgl, proc);
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
#elif defined(__APPLE__)
 | 
			
		||||
#include <dlfcn.h>
 | 
			
		||||
 | 
			
		||||
static void *libgl;
 | 
			
		||||
static int open_libgl(void)
 | 
			
		||||
{
 | 
			
		||||
    libgl = dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", RTLD_LAZY | RTLD_LOCAL);
 | 
			
		||||
    if (!libgl)
 | 
			
		||||
        return GL3W_ERROR_LIBRARY_OPEN;
 | 
			
		||||
    return GL3W_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void close_libgl(void) { dlclose(libgl); }
 | 
			
		||||
 | 
			
		||||
static GL3WglProc get_proc(const char *proc)
 | 
			
		||||
{
 | 
			
		||||
    GL3WglProc res;
 | 
			
		||||
    *(void **)(&res) = dlsym(libgl, proc);
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
#include <dlfcn.h>
 | 
			
		||||
 | 
			
		||||
static void* libgl;  // OpenGL library
 | 
			
		||||
static void* libglx;  // GLX library
 | 
			
		||||
static void* libegl;  // EGL library
 | 
			
		||||
static GL3WGetProcAddressProc gl_get_proc_address;
 | 
			
		||||
 | 
			
		||||
static void close_libgl(void)
 | 
			
		||||
{
 | 
			
		||||
    if (libgl) {
 | 
			
		||||
        dlclose(libgl);
 | 
			
		||||
        libgl = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (libegl) {
 | 
			
		||||
        dlclose(libegl);
 | 
			
		||||
        libegl = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (libglx) {
 | 
			
		||||
        dlclose(libglx);
 | 
			
		||||
        libglx = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int is_library_loaded(const char* name, void** lib)
 | 
			
		||||
{
 | 
			
		||||
    *lib = dlopen(name, RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
 | 
			
		||||
    return *lib != NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int open_libs(void)
 | 
			
		||||
{
 | 
			
		||||
    // On Linux we have two APIs to get process addresses: EGL and GLX.
 | 
			
		||||
    // EGL is supported under both X11 and Wayland, whereas GLX is X11-specific.
 | 
			
		||||
 | 
			
		||||
    libgl = NULL;
 | 
			
		||||
    libegl = NULL;
 | 
			
		||||
    libglx = NULL;
 | 
			
		||||
 | 
			
		||||
    // First check what's already loaded, the windowing library might have
 | 
			
		||||
    // already loaded either EGL or GLX and we want to use the same one.
 | 
			
		||||
 | 
			
		||||
    if (is_library_loaded("libEGL.so.1", &libegl) ||
 | 
			
		||||
        is_library_loaded("libGLX.so.0", &libglx)) {
 | 
			
		||||
        libgl = dlopen("libOpenGL.so.0", RTLD_LAZY | RTLD_LOCAL);
 | 
			
		||||
        if (libgl)
 | 
			
		||||
            return GL3W_OK;
 | 
			
		||||
        else
 | 
			
		||||
            close_libgl();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (is_library_loaded("libGL.so", &libgl))
 | 
			
		||||
        return GL3W_OK;
 | 
			
		||||
    if (is_library_loaded("libGL.so.1", &libgl))
 | 
			
		||||
        return GL3W_OK;
 | 
			
		||||
    if (is_library_loaded("libGL.so.3", &libgl))
 | 
			
		||||
        return GL3W_OK;
 | 
			
		||||
 | 
			
		||||
    // Neither is already loaded, so we have to load one.  Try EGL first
 | 
			
		||||
    // because it is supported under both X11 and Wayland.
 | 
			
		||||
 | 
			
		||||
    // Load OpenGL + EGL
 | 
			
		||||
    libgl = dlopen("libOpenGL.so.0", RTLD_LAZY | RTLD_LOCAL);
 | 
			
		||||
    libegl = dlopen("libEGL.so.1", RTLD_LAZY | RTLD_LOCAL);
 | 
			
		||||
    if (libgl && libegl)
 | 
			
		||||
        return GL3W_OK;
 | 
			
		||||
    else
 | 
			
		||||
        close_libgl();
 | 
			
		||||
 | 
			
		||||
    // Fall back to legacy libGL, which includes GLX
 | 
			
		||||
    // While most systems use libGL.so.1, NetBSD seems to use that libGL.so.3. See https://github.com/ocornut/imgui/issues/6983
 | 
			
		||||
    libgl = dlopen("libGL.so", RTLD_LAZY | RTLD_LOCAL);
 | 
			
		||||
    if (!libgl)
 | 
			
		||||
        libgl = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL);
 | 
			
		||||
    if (!libgl)
 | 
			
		||||
        libgl = dlopen("libGL.so.3", RTLD_LAZY | RTLD_LOCAL);
 | 
			
		||||
 | 
			
		||||
    if (libgl)
 | 
			
		||||
        return GL3W_OK;
 | 
			
		||||
 | 
			
		||||
    return GL3W_ERROR_LIBRARY_OPEN;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int open_libgl(void)
 | 
			
		||||
{
 | 
			
		||||
    int res = open_libs();
 | 
			
		||||
    if (res)
 | 
			
		||||
        return res;
 | 
			
		||||
 | 
			
		||||
    if (libegl)
 | 
			
		||||
        *(void**)(&gl_get_proc_address) = dlsym(libegl, "eglGetProcAddress");
 | 
			
		||||
    else if (libglx)
 | 
			
		||||
        *(void**)(&gl_get_proc_address) = dlsym(libglx, "glXGetProcAddressARB");
 | 
			
		||||
    else
 | 
			
		||||
        *(void**)(&gl_get_proc_address) = dlsym(libgl, "glXGetProcAddressARB");
 | 
			
		||||
 | 
			
		||||
    if (!gl_get_proc_address) {
 | 
			
		||||
        close_libgl();
 | 
			
		||||
        return GL3W_ERROR_LIBRARY_OPEN;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return GL3W_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static GL3WglProc get_proc(const char* proc)
 | 
			
		||||
{
 | 
			
		||||
    GL3WglProc res = NULL;
 | 
			
		||||
 | 
			
		||||
    // Before EGL version 1.5, eglGetProcAddress doesn't support querying core
 | 
			
		||||
    // functions and may return a dummy function if we try, so try to load the
 | 
			
		||||
    // function from the GL library directly first.
 | 
			
		||||
    if (libegl)
 | 
			
		||||
        *(void**)(&res) = dlsym(libgl, proc);
 | 
			
		||||
 | 
			
		||||
    if (!res)
 | 
			
		||||
        res = gl_get_proc_address(proc);
 | 
			
		||||
 | 
			
		||||
    if (!libegl && !res)
 | 
			
		||||
        *(void**)(&res) = dlsym(libgl, proc);
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static struct { int major, minor; } version;
 | 
			
		||||
 | 
			
		||||
static int parse_version(void)
 | 
			
		||||
{
 | 
			
		||||
    if (!glGetIntegerv)
 | 
			
		||||
        return GL3W_ERROR_INIT;
 | 
			
		||||
    glGetIntegerv(GL_MAJOR_VERSION, &version.major);
 | 
			
		||||
    glGetIntegerv(GL_MINOR_VERSION, &version.minor);
 | 
			
		||||
    if (version.major == 0 && version.minor == 0)
 | 
			
		||||
    {
 | 
			
		||||
        // Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
 | 
			
		||||
        if (const char* gl_version = (const char*)glGetString(GL_VERSION))
 | 
			
		||||
            sscanf(gl_version, "%d.%d", &version.major, &version.minor);
 | 
			
		||||
    }
 | 
			
		||||
    if (version.major < 2)
 | 
			
		||||
        return GL3W_ERROR_OPENGL_VERSION;
 | 
			
		||||
    return GL3W_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void load_procs(GL3WGetProcAddressProc proc);
 | 
			
		||||
 | 
			
		||||
int imgl3wInit(void)
 | 
			
		||||
{
 | 
			
		||||
    int res = open_libgl();
 | 
			
		||||
    if (res)
 | 
			
		||||
        return res;
 | 
			
		||||
    atexit(close_libgl);
 | 
			
		||||
    return imgl3wInit2(get_proc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int imgl3wInit2(GL3WGetProcAddressProc proc)
 | 
			
		||||
{
 | 
			
		||||
    load_procs(proc);
 | 
			
		||||
    return parse_version();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int imgl3wIsSupported(int major, int minor)
 | 
			
		||||
{
 | 
			
		||||
    if (major < 2)
 | 
			
		||||
        return 0;
 | 
			
		||||
    if (version.major == major)
 | 
			
		||||
        return version.minor >= minor;
 | 
			
		||||
    return version.major >= major;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GL3WglProc imgl3wGetProcAddress(const char *proc) { return get_proc(proc); }
 | 
			
		||||
 | 
			
		||||
static const char *proc_names[] = {
 | 
			
		||||
    "glActiveTexture",
 | 
			
		||||
    "glAttachShader",
 | 
			
		||||
    "glBindBuffer",
 | 
			
		||||
    "glBindSampler",
 | 
			
		||||
    "glBindTexture",
 | 
			
		||||
    "glBindVertexArray",
 | 
			
		||||
    "glBlendEquation",
 | 
			
		||||
    "glBlendEquationSeparate",
 | 
			
		||||
    "glBlendFuncSeparate",
 | 
			
		||||
    "glBufferData",
 | 
			
		||||
    "glBufferSubData",
 | 
			
		||||
    "glClear",
 | 
			
		||||
    "glClearColor",
 | 
			
		||||
    "glCompileShader",
 | 
			
		||||
    "glCreateProgram",
 | 
			
		||||
    "glCreateShader",
 | 
			
		||||
    "glDeleteBuffers",
 | 
			
		||||
    "glDeleteProgram",
 | 
			
		||||
    "glDeleteShader",
 | 
			
		||||
    "glDeleteTextures",
 | 
			
		||||
    "glDeleteVertexArrays",
 | 
			
		||||
    "glDetachShader",
 | 
			
		||||
    "glDisable",
 | 
			
		||||
    "glDisableVertexAttribArray",
 | 
			
		||||
    "glDrawElements",
 | 
			
		||||
    "glDrawElementsBaseVertex",
 | 
			
		||||
    "glEnable",
 | 
			
		||||
    "glEnableVertexAttribArray",
 | 
			
		||||
    "glFlush",
 | 
			
		||||
    "glGenBuffers",
 | 
			
		||||
    "glGenTextures",
 | 
			
		||||
    "glGenVertexArrays",
 | 
			
		||||
    "glGetAttribLocation",
 | 
			
		||||
    "glGetError",
 | 
			
		||||
    "glGetIntegerv",
 | 
			
		||||
    "glGetProgramInfoLog",
 | 
			
		||||
    "glGetProgramiv",
 | 
			
		||||
    "glGetShaderInfoLog",
 | 
			
		||||
    "glGetShaderiv",
 | 
			
		||||
    "glGetString",
 | 
			
		||||
    "glGetStringi",
 | 
			
		||||
    "glGetUniformLocation",
 | 
			
		||||
    "glGetVertexAttribPointerv",
 | 
			
		||||
    "glGetVertexAttribiv",
 | 
			
		||||
    "glIsEnabled",
 | 
			
		||||
    "glIsProgram",
 | 
			
		||||
    "glLinkProgram",
 | 
			
		||||
    "glPixelStorei",
 | 
			
		||||
    "glPolygonMode",
 | 
			
		||||
    "glReadPixels",
 | 
			
		||||
    "glScissor",
 | 
			
		||||
    "glShaderSource",
 | 
			
		||||
    "glTexImage2D",
 | 
			
		||||
    "glTexParameteri",
 | 
			
		||||
    "glUniform1i",
 | 
			
		||||
    "glUniformMatrix4fv",
 | 
			
		||||
    "glUseProgram",
 | 
			
		||||
    "glVertexAttribPointer",
 | 
			
		||||
    "glViewport",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
GL3W_API union ImGL3WProcs imgl3wProcs;
 | 
			
		||||
 | 
			
		||||
static void load_procs(GL3WGetProcAddressProc proc)
 | 
			
		||||
{
 | 
			
		||||
    size_t i;
 | 
			
		||||
    for (i = 0; i < GL3W_ARRAY_SIZE(proc_names); i++)
 | 
			
		||||
        imgl3wProcs.ptr[i] = proc(proc_names[i]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1232
									
								
								imgui_impl_sdl2.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1232
									
								
								imgui_impl_sdl2.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										50
									
								
								imgui_impl_sdl2.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								imgui_impl_sdl2.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
// dear imgui: Platform Backend for SDL2
 | 
			
		||||
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
 | 
			
		||||
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
 | 
			
		||||
 | 
			
		||||
// Implemented features:
 | 
			
		||||
//  [X] Platform: Clipboard support.
 | 
			
		||||
//  [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
 | 
			
		||||
//  [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
 | 
			
		||||
//  [X] Platform: Gamepad support.
 | 
			
		||||
//  [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
 | 
			
		||||
//  [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
 | 
			
		||||
//  [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
 | 
			
		||||
// Missing features or Issues:
 | 
			
		||||
//  [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows).
 | 
			
		||||
//  [ ] Platform: Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
 | 
			
		||||
 | 
			
		||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
 | 
			
		||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
 | 
			
		||||
// 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
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "imgui.h"      // IMGUI_IMPL_API
 | 
			
		||||
#ifndef IMGUI_DISABLE
 | 
			
		||||
 | 
			
		||||
struct SDL_Window;
 | 
			
		||||
struct SDL_Renderer;
 | 
			
		||||
struct _SDL_GameController;
 | 
			
		||||
typedef union SDL_Event SDL_Event;
 | 
			
		||||
 | 
			
		||||
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplSDL2_InitForVulkan(SDL_Window* window);
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplSDL2_InitForMetal(SDL_Window* window);
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer);
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplSDL2_InitForOther(SDL_Window* window);
 | 
			
		||||
IMGUI_IMPL_API void     ImGui_ImplSDL2_Shutdown();
 | 
			
		||||
IMGUI_IMPL_API void     ImGui_ImplSDL2_NewFrame();
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
 | 
			
		||||
 | 
			
		||||
// Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this.
 | 
			
		||||
// When using manual mode, caller is responsible for opening/closing gamepad.
 | 
			
		||||
enum ImGui_ImplSDL2_GamepadMode { ImGui_ImplSDL2_GamepadMode_AutoFirst, ImGui_ImplSDL2_GamepadMode_AutoAll, ImGui_ImplSDL2_GamepadMode_Manual };
 | 
			
		||||
IMGUI_IMPL_API void     ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array = nullptr, int manual_gamepads_count = -1);
 | 
			
		||||
 | 
			
		||||
#endif // #ifndef IMGUI_DISABLE
 | 
			
		||||
							
								
								
									
										1183
									
								
								imgui_impl_sdl3.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1183
									
								
								imgui_impl_sdl3.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										50
									
								
								imgui_impl_sdl3.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								imgui_impl_sdl3.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
// dear imgui: Platform Backend for SDL3
 | 
			
		||||
// This needs to be used along with a Renderer (e.g. SDL_GPU, DirectX11, OpenGL3, Vulkan..)
 | 
			
		||||
// (Info: SDL3 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
 | 
			
		||||
 | 
			
		||||
// Implemented features:
 | 
			
		||||
//  [X] Platform: Clipboard support.
 | 
			
		||||
//  [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
 | 
			
		||||
//  [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
 | 
			
		||||
//  [X] Platform: Gamepad support.
 | 
			
		||||
//  [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
 | 
			
		||||
//  [x] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable' -> the OS animation effect when window gets created/destroyed is problematic. SDL2 backend doesn't have issue.
 | 
			
		||||
// Missing features or Issues:
 | 
			
		||||
//  [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows).
 | 
			
		||||
//  [x] Platform: IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
 | 
			
		||||
 | 
			
		||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
 | 
			
		||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
 | 
			
		||||
// 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
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "imgui.h"      // IMGUI_IMPL_API
 | 
			
		||||
#ifndef IMGUI_DISABLE
 | 
			
		||||
 | 
			
		||||
struct SDL_Window;
 | 
			
		||||
struct SDL_Renderer;
 | 
			
		||||
struct SDL_Gamepad;
 | 
			
		||||
typedef union SDL_Event SDL_Event;
 | 
			
		||||
 | 
			
		||||
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplSDL3_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplSDL3_InitForVulkan(SDL_Window* window);
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplSDL3_InitForD3D(SDL_Window* window);
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplSDL3_InitForMetal(SDL_Window* window);
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer);
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplSDL3_InitForSDLGPU(SDL_Window* window);
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplSDL3_InitForOther(SDL_Window* window);
 | 
			
		||||
IMGUI_IMPL_API void     ImGui_ImplSDL3_Shutdown();
 | 
			
		||||
IMGUI_IMPL_API void     ImGui_ImplSDL3_NewFrame();
 | 
			
		||||
IMGUI_IMPL_API bool     ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event);
 | 
			
		||||
 | 
			
		||||
// Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this.
 | 
			
		||||
// When using manual mode, caller is responsible for opening/closing gamepad.
 | 
			
		||||
enum ImGui_ImplSDL3_GamepadMode { ImGui_ImplSDL3_GamepadMode_AutoFirst, ImGui_ImplSDL3_GamepadMode_AutoAll, ImGui_ImplSDL3_GamepadMode_Manual };
 | 
			
		||||
IMGUI_IMPL_API void     ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode mode, SDL_Gamepad** manual_gamepads_array = nullptr, int manual_gamepads_count = -1);
 | 
			
		||||
 | 
			
		||||
#endif // #ifndef IMGUI_DISABLE
 | 
			
		||||
							
								
								
									
										3941
									
								
								imgui_internal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3941
									
								
								imgui_internal.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4525
									
								
								imgui_tables.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4525
									
								
								imgui_tables.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1184
									
								
								imgui_tex_inspect.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1184
									
								
								imgui_tex_inspect.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										308
									
								
								imgui_tex_inspect.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										308
									
								
								imgui_tex_inspect.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,308 @@
 | 
			
		||||
// ImGuiTexInspect, a texture inspector widget for dear imgui
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "imgui.h"
 | 
			
		||||
 | 
			
		||||
namespace ImGuiTexInspect
 | 
			
		||||
{
 | 
			
		||||
struct Context;
 | 
			
		||||
struct Transform2D;
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] INIT & SHUTDOWN
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
void Init();
 | 
			
		||||
void Shutdown();
 | 
			
		||||
 | 
			
		||||
Context *CreateContext();
 | 
			
		||||
void DestroyContext(Context *);
 | 
			
		||||
void SetCurrentContext(Context *);
 | 
			
		||||
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] BASIC USAGE
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
enum InspectorAlphaMode
 | 
			
		||||
{
 | 
			
		||||
    InspectorAlphaMode_ImGui,      // Alpha is transparency so you see the ImGui panel background behind image
 | 
			
		||||
    InspectorAlphaMode_Black,      // Alpha is used to blend over a black background
 | 
			
		||||
    InspectorAlphaMode_White,      // Alpha is used to blend over a white background
 | 
			
		||||
    InspectorAlphaMode_CustomColor // Alpha is used to blend over a custom colour.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef ImU64 InspectorFlags;
 | 
			
		||||
enum InspectorFlags_
 | 
			
		||||
{
 | 
			
		||||
    InspectorFlags_ShowWrap             = 1 << 0,  // Draw beyong the [0,1] uv range. What you see will depend on API
 | 
			
		||||
    InspectorFlags_NoForceFilterNearest = 1 << 1,  // Normally we force nearest neighbour sampling when zoomed in. Set to disable this.
 | 
			
		||||
    InspectorFlags_NoGrid               = 1 << 2,  // By default a grid is shown at high zoom levels
 | 
			
		||||
    InspectorFlags_NoTooltip            = 1 << 3,  // Disable tooltip on hover
 | 
			
		||||
    InspectorFlags_FillHorizontal       = 1 << 4,  // Scale to fill available space horizontally
 | 
			
		||||
    InspectorFlags_FillVertical         = 1 << 5,  // Scale to fill available space vertically
 | 
			
		||||
    InspectorFlags_NoAutoReadTexture    = 1 << 6,  // By default texture data is read to CPU every frame for tooltip and annotations
 | 
			
		||||
    InspectorFlags_FlipX                = 1 << 7,  // Horizontally flip the way the texture is displayed
 | 
			
		||||
    InspectorFlags_FlipY                = 1 << 8,  // Vertically flip the way the texture is displayed
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Use one of these Size structs if you want to specify an exact size for the inspector panel. 
 | 
			
		||||
 * E.g.
 | 
			
		||||
 * BeginInspectorPanel("MyPanel", texture_1K, ImVec2(1024,1024), 0, SizeExcludingBorder(ImVec2(1024,1024)));
 | 
			
		||||
 *
 | 
			
		||||
 * However, most of the time the default size will be fine. E.g.
 | 
			
		||||
 *
 | 
			
		||||
 * BeginInspectorPanel("MyPanel", texture_1K, ImVec2(1024,1024));
 | 
			
		||||
 */
 | 
			
		||||
struct SizeIncludingBorder {ImVec2 Size; SizeIncludingBorder(ImVec2 size):Size(size){}};
 | 
			
		||||
struct SizeExcludingBorder {ImVec2 size; SizeExcludingBorder(ImVec2 size):size(size){}};
 | 
			
		||||
/* BeginInspectorPanel
 | 
			
		||||
 * Returns true if panel is drawn.  Note that flags will only be considered on the first call */
 | 
			
		||||
bool BeginInspectorPanel(const char *name, ImTextureID, ImVec2 textureSize, InspectorFlags flags = 0);
 | 
			
		||||
bool BeginInspectorPanel(const char *name, ImTextureID, ImVec2 textureSize, InspectorFlags flags, SizeIncludingBorder size);
 | 
			
		||||
bool BeginInspectorPanel(const char *name, ImTextureID, ImVec2 textureSize, InspectorFlags flags, SizeExcludingBorder size);
 | 
			
		||||
 | 
			
		||||
/* EndInspectorPanel 
 | 
			
		||||
 * Always call after BeginInspectorPanel and after you have drawn any required annotations*/
 | 
			
		||||
void EndInspectorPanel();
 | 
			
		||||
 | 
			
		||||
/* ReleaseInspectorData
 | 
			
		||||
 * ImGuiTexInspect keeps texture data cached in memory.  If you know you won't 
 | 
			
		||||
 * be displaying a particular panel for a while you can call this to release 
 | 
			
		||||
 * the memory. It won't be allocated again until next time you call 
 | 
			
		||||
 * BeginInspectorPanel.  If id is NULL then the current (most recent) inspector 
 | 
			
		||||
 * will be affected.  Unless you have a lot of different Inspector instances 
 | 
			
		||||
 * you can probably not worry about this. Call CurrentInspector_GetID to get 
 | 
			
		||||
 * the ID of an inspector. 
 | 
			
		||||
 */
 | 
			
		||||
void ReleaseInspectorData(ImGuiID id);
 | 
			
		||||
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] CURRENT INSPECTOR MANIPULATORS
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
/* All the functions starting with CurrentInspector_ can be used after calling 
 | 
			
		||||
 * BeginInspector until the end of the frame.  It is not necessary to call them 
 | 
			
		||||
 * before the matching EndInspectorPanel
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* CurrentInspector_SetColorMatrix
 | 
			
		||||
 * colorMatrix and colorOffset describe the transform which happens to the
 | 
			
		||||
 * color of each texel.
 | 
			
		||||
 * The calculation is finalColor = colorMatrix * originalColor + colorOffset.
 | 
			
		||||
 * Where finalColor, originalColor and colorOffset are column vectors with
 | 
			
		||||
 * components (r,g,b,a) and colorMatrix is a column-major matrix.
 | 
			
		||||
 */
 | 
			
		||||
void CurrentInspector_SetColorMatrix(const float (&colorMatrix)[16], const float (&colorOffset)[4]);
 | 
			
		||||
void CurrentInspector_ResetColorMatrix();
 | 
			
		||||
 | 
			
		||||
/* CurrentInspector_SetAlphaMode - see enum comments for details*/
 | 
			
		||||
void CurrentInspector_SetAlphaMode(InspectorAlphaMode);  
 | 
			
		||||
void CurrentInspector_SetFlags(InspectorFlags toSet, InspectorFlags toClear = 0);
 | 
			
		||||
inline void CurrentInspector_ClearFlags(InspectorFlags toClear) {CurrentInspector_SetFlags(0, toClear);}
 | 
			
		||||
void CurrentInspector_SetGridColor(ImU32 color);
 | 
			
		||||
void CurrentInspector_SetMaxAnnotations(int maxAnnotations);
 | 
			
		||||
 | 
			
		||||
/* CurrentInspector_InvalidateTextureCache
 | 
			
		||||
 * If using the InspectorFlags_NoAutoReadTexture flag then call this to 
 | 
			
		||||
 * indicate your texture has changed context.
 | 
			
		||||
 */
 | 
			
		||||
void CurrentInspector_InvalidateTextureCache();                 
 | 
			
		||||
 | 
			
		||||
/* CurrentInspector_SetCustomBackgroundColor
 | 
			
		||||
 * If using InspectorAlphaMode_CustomColor then this is the color that will be 
 | 
			
		||||
 * blended as the background where alpha is less than one.
 | 
			
		||||
 */
 | 
			
		||||
void CurrentInspector_SetCustomBackgroundColor(ImVec4 color);
 | 
			
		||||
void CurrentInspector_SetCustomBackgroundColor(ImU32 color);
 | 
			
		||||
 | 
			
		||||
/* CurrentInspector_GetID
 | 
			
		||||
 * Get the ID of the current inspector.  Currently only used for calling
 | 
			
		||||
 * ReleaseInspectorData. 
 | 
			
		||||
 */
 | 
			
		||||
ImGuiID CurrentInspector_GetID();
 | 
			
		||||
 | 
			
		||||
/* Some convenience functions for drawing ImGui controls for the current Inspector */
 | 
			
		||||
void DrawColorMatrixEditor();    // ColorMatrix editor.  See comments on ColorMatrix below.
 | 
			
		||||
void DrawGridEditor();           // Grid editor.  Enable/Disable grid. Set Grid Color.
 | 
			
		||||
void DrawColorChannelSelector(); // For toggling R,G,B channels
 | 
			
		||||
void DrawAlphaModeSelector();    // A combo box for selecting the alpha mode
 | 
			
		||||
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] CONTEXT-WIDE SETTINGS
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
/* SetZoomRate
 | 
			
		||||
 * factor should be greater than 1.  A value of 1.5 means one mouse wheel 
 | 
			
		||||
 * scroll will increase zoom level by 50%. The factor used for zooming out is 
 | 
			
		||||
 * 1/factor. */
 | 
			
		||||
void SetZoomRate(float factor); 
 | 
			
		||||
                                
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] ANNOTATION TOOLS
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
/* DrawAnnotationLine
 | 
			
		||||
 * Convenience function to add a line to draw list using texel coordinates. 
 | 
			
		||||
 */
 | 
			
		||||
void DrawAnnotationLine(ImDrawList *drawList, ImVec2 fromTexel, ImVec2 toTexel, Transform2D texelsToPixels, ImU32 color);
 | 
			
		||||
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] Annotation Classes
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
/* To draw annotations call DrawAnnotions in between BeginInspectorPanel and 
 | 
			
		||||
 * EndInspectorPanel.  Example usage:
 | 
			
		||||
 * DrawAnnotations(ValueText(ValueText::HexString));
 | 
			
		||||
 * 
 | 
			
		||||
 * To provide your own Annotation drawing class just define a class that 
 | 
			
		||||
 * implements the DrawAnnotation method.  See imgui_tex_inspect_demo.cpp
 | 
			
		||||
 * for an example.
 | 
			
		||||
 */
 | 
			
		||||
template <typename T>
 | 
			
		||||
void DrawAnnotations(T drawer, ImU64 maxAnnotatedTexels = 0);
 | 
			
		||||
 | 
			
		||||
/* ValueText
 | 
			
		||||
 * An annoation class that draws text inside each texel when zoom level is high enough for it to fit.
 | 
			
		||||
 * The text shows the value of the texel. E.g. "R:255, G: 128, B:0, A:255"
 | 
			
		||||
 */
 | 
			
		||||
class ValueText
 | 
			
		||||
{
 | 
			
		||||
  protected:
 | 
			
		||||
    int TextRowCount;
 | 
			
		||||
    int TextColumnCount;
 | 
			
		||||
    const char *TextFormatString;
 | 
			
		||||
    bool FormatAsFloats;
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    enum Format
 | 
			
		||||
    {
 | 
			
		||||
        HexString, // E.g.  #EF97B9FF
 | 
			
		||||
        BytesHex,  // E.g.  R:#EF G:#97 B:#B9 A:#FF  (split over 4 lines)
 | 
			
		||||
        BytesDec,  // E.g.  R:239 G: 151 B:185 A:255  (split over 4 lines)
 | 
			
		||||
        Floats     // E.g.  0.937 0.592 0.725 1.000 (split over 4 lines)
 | 
			
		||||
    };
 | 
			
		||||
    ValueText(Format format = HexString);
 | 
			
		||||
    void DrawAnnotation(ImDrawList *drawList, ImVec2 texel, Transform2D texelsToPixels, ImVec4 value);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Arrow 
 | 
			
		||||
 * An annotation class that draws an arrow inside each texel when zoom level is 
 | 
			
		||||
 * high enough. The direction and length of the arrow are determined by texel 
 | 
			
		||||
 * values.
 | 
			
		||||
 * The X and Y components of the arrow is determined by the VectorIndex_x, and 
 | 
			
		||||
 * VectorIndex_y channels of the texel value.  Examples:
 | 
			
		||||
 | 
			
		||||
 * VectorIndex_x = 0,  VectorIndex_y = 1  means  X component is red and Y component is green
 | 
			
		||||
 * VectorIndex_x = 1,  VectorIndex_y = 2  means  X component is green and Y component is blue
 | 
			
		||||
 * VectorIndex_x = 0,  VectorIndex_y = 3  means  X component is red and Y component is alpha
 | 
			
		||||
 *
 | 
			
		||||
 * ZeroPoint is the texel value which corresponds to a zero length vector. E.g. 
 | 
			
		||||
 * ZeroPoint = (0.5, 0.5) means (0.5, 0.5) will be drawn as a zero length arrow
 | 
			
		||||
 *
 | 
			
		||||
 * All public properties can be directly manipulated.  There are also presets that can be set
 | 
			
		||||
 * by calling UsePreset.
 | 
			
		||||
 | 
			
		||||
 */
 | 
			
		||||
class Arrow
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
    int VectorIndex_x;
 | 
			
		||||
    int VectorIndex_y;
 | 
			
		||||
    ImVec2 LineScale;
 | 
			
		||||
    ImVec2 ZeroPoint = {0, 0}; 
 | 
			
		||||
                              
 | 
			
		||||
    enum Preset
 | 
			
		||||
    {
 | 
			
		||||
        NormalMap,      // For normal maps. I.e. Arrow is in (R,G) channels.  128, 128 is zero point
 | 
			
		||||
        NormalizedFloat // Arrow in (R,G) channels. 0,0 is zero point, (1,0) will draw an arrow exactly to
 | 
			
		||||
                        // right edge of texture. (0,-1) will draw exactly to the bottom etc.
 | 
			
		||||
    };
 | 
			
		||||
    Arrow(int xVectorIndex = 0, int yVectorIndex = 1, ImVec2 lineScale = ImVec2(1, 1));
 | 
			
		||||
    Arrow &UsePreset(Preset);
 | 
			
		||||
    void DrawAnnotation(ImDrawList *drawList, ImVec2 texel, Transform2D texelsToPixels, ImVec4 value);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] INTERNAL
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
struct Transform2D
 | 
			
		||||
{
 | 
			
		||||
    ImVec2 Scale;
 | 
			
		||||
    ImVec2 Translate;
 | 
			
		||||
 | 
			
		||||
    /* Transform a vector by this transform.  Scale is applied first */
 | 
			
		||||
    ImVec2 operator*(const ImVec2 &rhs) const
 | 
			
		||||
    {
 | 
			
		||||
        return ImVec2(Scale.x * rhs.x + Translate.x, Scale.y * rhs.y + Translate.y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Return an inverse transform such that transform.Inverse() * transform * vector == vector*/
 | 
			
		||||
    Transform2D Inverse() const
 | 
			
		||||
    {
 | 
			
		||||
        ImVec2 inverseScale(1 / Scale.x, 1 / Scale.y);
 | 
			
		||||
        return {inverseScale, ImVec2(-inverseScale.x * Translate.x, -inverseScale.y * Translate.y)};
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct BufferDesc
 | 
			
		||||
{
 | 
			
		||||
    float         *Data_float     = nullptr; // Only one of these 
 | 
			
		||||
    ImU8          *Data_uint8_t   = nullptr; // two pointers should be non NULL
 | 
			
		||||
    size_t         BufferByteSize = 0; // Size of buffer pointed to by one of above pointers
 | 
			
		||||
    int            Stride         = 0; // Measured in size of data type, not bytes!
 | 
			
		||||
    int            LineStride     = 0; // Measured in size of data type, not bytes!
 | 
			
		||||
    int            StartX         = 0; // Texel coordinates of data start
 | 
			
		||||
    int            StartY         = 0;
 | 
			
		||||
    int            Width          = 0; // Size of block of texels which are in data
 | 
			
		||||
    int            Height         = 0;
 | 
			
		||||
 | 
			
		||||
    unsigned char  ChannelCount   = 0; // Number of color channels in data. E.g. 2 means just red and green
 | 
			
		||||
 | 
			
		||||
    /* These 4 values describe where each color is stored relative to the beginning of the texel in memory 
 | 
			
		||||
     * E.g. the float containing the red value would be at:
 | 
			
		||||
     * Data_float[texelIndex + bufferDesc.Red]
 | 
			
		||||
     */
 | 
			
		||||
    unsigned char  Red            = 0;
 | 
			
		||||
    unsigned char  Green          = 0;
 | 
			
		||||
    unsigned char  Blue           = 0;
 | 
			
		||||
    unsigned char  Alpha          = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* We use this struct for annotations rather than the Inspector struct so that
 | 
			
		||||
 * the whole Inspector struct doesn't have to be exposed in this header.
 | 
			
		||||
 */
 | 
			
		||||
struct AnnotationsDesc
 | 
			
		||||
{
 | 
			
		||||
    ImDrawList  *DrawList;
 | 
			
		||||
    ImVec2       TexelViewSize;  // How many texels are visible for annotating
 | 
			
		||||
    ImVec2       TexelTopLeft;   // Coordinated in texture space of top left visible texel
 | 
			
		||||
    BufferDesc   Buffer;         // Description of cache texel data
 | 
			
		||||
    Transform2D  TexelsToPixels; // Transform to go from texel space to screen pixel space
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] FORWARD DECLARATIONS FOR TEMPLATE IMPLEMENTATION - Do not call directly
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
ImVec4 GetTexel(const BufferDesc *bd, int x, int y);
 | 
			
		||||
bool GetAnnotationDesc(AnnotationsDesc *, ImU64 maxAnnotatedTexels);
 | 
			
		||||
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] TEMPLATE IMPLEMENTATION
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
template <typename T>
 | 
			
		||||
void DrawAnnotations(T drawer, ImU64 maxAnnotatedTexels)
 | 
			
		||||
{
 | 
			
		||||
    AnnotationsDesc ad;
 | 
			
		||||
    if (GetAnnotationDesc(&ad, maxAnnotatedTexels))
 | 
			
		||||
    {
 | 
			
		||||
        ImVec2 texelBottomRight = ImVec2(ad.TexelTopLeft.x + ad.TexelViewSize.x, ad.TexelTopLeft.y + ad.TexelViewSize.y);
 | 
			
		||||
        for (int ty = (int)ad.TexelTopLeft.y; ty < (int)texelBottomRight.y; ++ty)
 | 
			
		||||
        {
 | 
			
		||||
            for (int tx = (int)ad.TexelTopLeft.x; tx < (int)texelBottomRight.x; ++tx)
 | 
			
		||||
            {
 | 
			
		||||
                ImVec4 color = GetTexel(&ad.Buffer, tx, ty);
 | 
			
		||||
                ImVec2 center = {(float)tx + 0.5f, (float)ty + 0.5f};
 | 
			
		||||
                drawer.DrawAnnotation(ad.DrawList, center, ad.TexelsToPixels, color);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
} // namespace ImGuiTexInspect
 | 
			
		||||
							
								
								
									
										181
									
								
								imgui_tex_inspect_internal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								imgui_tex_inspect_internal.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,181 @@
 | 
			
		||||
// ImGuiTexInspect, a texture inspector widget for dear imgui
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "imgui.h"
 | 
			
		||||
#include "imgui_internal.h"
 | 
			
		||||
#include "imgui_tex_inspect.h"
 | 
			
		||||
 | 
			
		||||
namespace ImGuiTexInspect
 | 
			
		||||
{
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] UTILITIES
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// Returns true if a flag is set
 | 
			
		||||
template <typename TSet, typename TFlag>
 | 
			
		||||
static inline bool HasFlag(TSet set, TFlag flag)
 | 
			
		||||
{
 | 
			
		||||
    return (set & flag) == flag;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set flag or flags in set
 | 
			
		||||
template <typename TSet, typename TFlag>
 | 
			
		||||
static inline void SetFlag(TSet &set, TFlag flags)
 | 
			
		||||
{
 | 
			
		||||
    set = static_cast<TSet>(set | flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Clear flag or flags in set
 | 
			
		||||
template <typename TSet, typename TFlag>
 | 
			
		||||
static inline void ClearFlag(TSet &set, TFlag flag)
 | 
			
		||||
{
 | 
			
		||||
    set = static_cast<TSet>(set & ~flag);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Proper modulus operator, as opposed to remainder as calculated by %
 | 
			
		||||
template <typename T>
 | 
			
		||||
static inline T Modulus(T a, T b)
 | 
			
		||||
{
 | 
			
		||||
    return a - b * ImFloor(a / b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Defined in recent versions of imgui_internal.h.  Included here in case user is on older
 | 
			
		||||
// imgui version.
 | 
			
		||||
static inline float ImFloor(float f)
 | 
			
		||||
{
 | 
			
		||||
    return (float)((f >= 0 || (int)f == f) ? (int)f : (int)f - 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline float Round(float f)
 | 
			
		||||
{
 | 
			
		||||
    return ImFloor(f + 0.5f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline ImVec2 Abs(ImVec2 v)
 | 
			
		||||
{
 | 
			
		||||
    return ImVec2(ImAbs(v.x), ImAbs(v.y));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] STRUCTURES
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
struct ShaderOptions
 | 
			
		||||
{
 | 
			
		||||
    float  ColorTransform[16] = {};                    // See CurrentInspector_SetColorMatrix for details
 | 
			
		||||
    float  ColorOffset[4] = {};
 | 
			
		||||
 | 
			
		||||
    ImVec4 BackgroundColor                = {0,0,0,0}; // Color used for alpha blending
 | 
			
		||||
    float  PremultiplyAlpha               = 0;         // If 1 then color will be multiplied by alpha in shader, before blend stage 
 | 
			
		||||
    float  DisableFinalAlpha              = 0;         // If 1 then fragment shader will always output alpha = 1
 | 
			
		||||
 | 
			
		||||
    bool   ForceNearestSampling           = false;     // If true fragment shader will always sample from texel centers
 | 
			
		||||
 | 
			
		||||
    ImVec2 GridWidth                      = {0,0};     // Width in UV coords of grid line
 | 
			
		||||
    ImVec4 GridColor                      = {0,0,0,0};
 | 
			
		||||
 | 
			
		||||
    void   ResetColorTransform();
 | 
			
		||||
    ShaderOptions();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Inspector
 | 
			
		||||
{
 | 
			
		||||
    ImGuiID ID;
 | 
			
		||||
    bool Initialized = false;
 | 
			
		||||
 | 
			
		||||
    // Texture
 | 
			
		||||
    ImTextureID Texture = ImTextureID{};
 | 
			
		||||
    ImVec2 TextureSize = {0, 0};        // Size in texels of texture
 | 
			
		||||
    float PixelAspectRatio = 1;         // Values other than 1 not supported yet
 | 
			
		||||
 | 
			
		||||
    // View State
 | 
			
		||||
    bool IsDragging = false;            // Is user currently dragging to pan view
 | 
			
		||||
    ImVec2 PanPos = {0.5f, 0.5f};       // The UV value at the center of the current view
 | 
			
		||||
    ImVec2 Scale = {1, 1};              // 1 pixel is 1 texel
 | 
			
		||||
 | 
			
		||||
    ImVec2 PanelTopLeftPixel = {0, 0};  // Top left of view in ImGui pixel coordinates
 | 
			
		||||
    ImVec2 PanelSize = {0, 0};          // Size of area allocated to drawing the image in pixels.
 | 
			
		||||
 | 
			
		||||
    ImVec2 ViewTopLeftPixel = {0, 0};   // Position in ImGui pixel coordinates
 | 
			
		||||
    ImVec2 ViewSize = {0, 0};           // Rendered size of current image. This could be smaller than panel size if user has zoomed out.
 | 
			
		||||
    ImVec2 ViewSizeUV = {0, 0};         // Visible region of the texture in UV coordinates
 | 
			
		||||
 | 
			
		||||
    /* Conversion transforms to go back and forth between screen pixels  (what ImGui considers screen pixels) and texels*/
 | 
			
		||||
    Transform2D TexelsToPixels;
 | 
			
		||||
    Transform2D PixelsToTexels;
 | 
			
		||||
 | 
			
		||||
    // Cached pixel data
 | 
			
		||||
    bool HaveCurrentTexelData = false;
 | 
			
		||||
    BufferDesc Buffer;
 | 
			
		||||
 | 
			
		||||
    /* We don't actually access texel data through this pointer.  We just 
 | 
			
		||||
     * manage its lifetime. The backend might have asked us to allocated a 
 | 
			
		||||
     * buffer, or it might not.  The pointer we actually use to access texel 
 | 
			
		||||
     * data is in the Buffer object above (which depending on what the backend 
 | 
			
		||||
     * did might point to the same memory as this pointer)
 | 
			
		||||
     */
 | 
			
		||||
    ImU8 *DataBuffer = nullptr;  
 | 
			
		||||
    size_t DataBufferSize = 0;
 | 
			
		||||
 | 
			
		||||
    // Configuration
 | 
			
		||||
    InspectorFlags Flags = 0;
 | 
			
		||||
 | 
			
		||||
    // Background mode
 | 
			
		||||
    InspectorAlphaMode AlphaMode = InspectorAlphaMode_ImGui;
 | 
			
		||||
    ImVec4 CustomBackgroundColor = {0, 0, 0, 1};
 | 
			
		||||
 | 
			
		||||
    // Scaling limits
 | 
			
		||||
    ImVec2 ScaleMin = {0.02f, 0.02f};
 | 
			
		||||
    ImVec2 ScaleMax = {500, 500};
 | 
			
		||||
 | 
			
		||||
    // Grid
 | 
			
		||||
    float MinimumGridSize = 4; // Don't draw the grid if lines would be closer than MinimumGridSize pixels
 | 
			
		||||
 | 
			
		||||
    // Annotations
 | 
			
		||||
    ImU32 MaxAnnotatedTexels = 0;
 | 
			
		||||
 | 
			
		||||
    // Color transformation
 | 
			
		||||
    ShaderOptions ActiveShaderOptions;
 | 
			
		||||
    ShaderOptions CachedShaderOptions;
 | 
			
		||||
 | 
			
		||||
    ~Inspector();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] INTERNAL FUNCTIONS
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
Inspector *GetByKey(const Context *ctx, ImGuiID key);
 | 
			
		||||
Inspector *GetOrAddByKey(Context *ctx, ImGuiID key);
 | 
			
		||||
 | 
			
		||||
void SetPanPos(Inspector *inspector, ImVec2 pos);
 | 
			
		||||
void SetScale(Inspector *inspector, ImVec2 scale);
 | 
			
		||||
void SetScale(Inspector *inspector, float scaleY);
 | 
			
		||||
void RoundPanPos(Inspector *inspector);
 | 
			
		||||
 | 
			
		||||
ImU8 *GetBuffer(Inspector *inspector, size_t bytes);
 | 
			
		||||
 | 
			
		||||
/* GetTexelsToPixels 
 | 
			
		||||
 * Calculate a transform to convert from texel coordinates to screen pixel coordinates
 | 
			
		||||
 * */
 | 
			
		||||
Transform2D GetTexelsToPixels(ImVec2 screenTopLeft, ImVec2 screenViewSize, ImVec2 uvTopLeft, ImVec2 uvViewSize, ImVec2 textureSize);
 | 
			
		||||
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] IMGUI UTILS
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
/* TextVector
 | 
			
		||||
 * Draws a single-column ImGui table with one row for each provided string
 | 
			
		||||
 */
 | 
			
		||||
void TextVector(const char *title, const char *const *strings, int n);
 | 
			
		||||
 | 
			
		||||
/* PushDisabled & PopDisabled
 | 
			
		||||
 * Push and Pop and ImGui styles that disable and "grey out" ImGui elements
 | 
			
		||||
 * by making them non interactive and transparent*/
 | 
			
		||||
void PushDisabled();
 | 
			
		||||
void PopDisabled();
 | 
			
		||||
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] BACKEND FUNCTIONS
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
void BackEnd_SetShader(const ImDrawList *drawList, const ImDrawCmd *cmd, const Inspector *inspector);
 | 
			
		||||
bool BackEnd_GetData(Inspector *inspector, ImTextureID texture, int x, int y, int width, int height, BufferDesc *buffer);
 | 
			
		||||
 | 
			
		||||
} // namespace ImGuiTexInspect
 | 
			
		||||
							
								
								
									
										10577
									
								
								imgui_widgets.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10577
									
								
								imgui_widgets.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										627
									
								
								imstb_rectpack.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										627
									
								
								imstb_rectpack.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,627 @@
 | 
			
		||||
// [DEAR IMGUI]
 | 
			
		||||
// This is a slightly modified version of stb_rect_pack.h 1.01.
 | 
			
		||||
// Grep for [DEAR IMGUI] to find the changes.
 | 
			
		||||
// 
 | 
			
		||||
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
 | 
			
		||||
// Sean Barrett 2014
 | 
			
		||||
//
 | 
			
		||||
// Useful for e.g. packing rectangular textures into an atlas.
 | 
			
		||||
// Does not do rotation.
 | 
			
		||||
//
 | 
			
		||||
// Before #including,
 | 
			
		||||
//
 | 
			
		||||
//    #define STB_RECT_PACK_IMPLEMENTATION
 | 
			
		||||
//
 | 
			
		||||
// in the file that you want to have the implementation.
 | 
			
		||||
//
 | 
			
		||||
// Not necessarily the awesomest packing method, but better than
 | 
			
		||||
// the totally naive one in stb_truetype (which is primarily what
 | 
			
		||||
// this is meant to replace).
 | 
			
		||||
//
 | 
			
		||||
// Has only had a few tests run, may have issues.
 | 
			
		||||
//
 | 
			
		||||
// More docs to come.
 | 
			
		||||
//
 | 
			
		||||
// No memory allocations; uses qsort() and assert() from stdlib.
 | 
			
		||||
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
 | 
			
		||||
//
 | 
			
		||||
// This library currently uses the Skyline Bottom-Left algorithm.
 | 
			
		||||
//
 | 
			
		||||
// Please note: better rectangle packers are welcome! Please
 | 
			
		||||
// implement them to the same API, but with a different init
 | 
			
		||||
// function.
 | 
			
		||||
//
 | 
			
		||||
// Credits
 | 
			
		||||
//
 | 
			
		||||
//  Library
 | 
			
		||||
//    Sean Barrett
 | 
			
		||||
//  Minor features
 | 
			
		||||
//    Martins Mozeiko
 | 
			
		||||
//    github:IntellectualKitty
 | 
			
		||||
//
 | 
			
		||||
//  Bugfixes / warning fixes
 | 
			
		||||
//    Jeremy Jaussaud
 | 
			
		||||
//    Fabian Giesen
 | 
			
		||||
//
 | 
			
		||||
// Version history:
 | 
			
		||||
//
 | 
			
		||||
//     1.01  (2021-07-11)  always use large rect mode, expose STBRP__MAXVAL in public section
 | 
			
		||||
//     1.00  (2019-02-25)  avoid small space waste; gracefully fail too-wide rectangles
 | 
			
		||||
//     0.99  (2019-02-07)  warning fixes
 | 
			
		||||
//     0.11  (2017-03-03)  return packing success/fail result
 | 
			
		||||
//     0.10  (2016-10-25)  remove cast-away-const to avoid warnings
 | 
			
		||||
//     0.09  (2016-08-27)  fix compiler warnings
 | 
			
		||||
//     0.08  (2015-09-13)  really fix bug with empty rects (w=0 or h=0)
 | 
			
		||||
//     0.07  (2015-09-13)  fix bug with empty rects (w=0 or h=0)
 | 
			
		||||
//     0.06  (2015-04-15)  added STBRP_SORT to allow replacing qsort
 | 
			
		||||
//     0.05:  added STBRP_ASSERT to allow replacing assert
 | 
			
		||||
//     0.04:  fixed minor bug in STBRP_LARGE_RECTS support
 | 
			
		||||
//     0.01:  initial release
 | 
			
		||||
//
 | 
			
		||||
// LICENSE
 | 
			
		||||
//
 | 
			
		||||
//   See end of file for license information.
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//
 | 
			
		||||
//       INCLUDE SECTION
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#ifndef STB_INCLUDE_STB_RECT_PACK_H
 | 
			
		||||
#define STB_INCLUDE_STB_RECT_PACK_H
 | 
			
		||||
 | 
			
		||||
#define STB_RECT_PACK_VERSION  1
 | 
			
		||||
 | 
			
		||||
#ifdef STBRP_STATIC
 | 
			
		||||
#define STBRP_DEF static
 | 
			
		||||
#else
 | 
			
		||||
#define STBRP_DEF extern
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct stbrp_context stbrp_context;
 | 
			
		||||
typedef struct stbrp_node    stbrp_node;
 | 
			
		||||
typedef struct stbrp_rect    stbrp_rect;
 | 
			
		||||
 | 
			
		||||
typedef int            stbrp_coord;
 | 
			
		||||
 | 
			
		||||
#define STBRP__MAXVAL  0x7fffffff
 | 
			
		||||
// Mostly for internal use, but this is the maximum supported coordinate value.
 | 
			
		||||
 | 
			
		||||
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
 | 
			
		||||
// Assign packed locations to rectangles. The rectangles are of type
 | 
			
		||||
// 'stbrp_rect' defined below, stored in the array 'rects', and there
 | 
			
		||||
// are 'num_rects' many of them.
 | 
			
		||||
//
 | 
			
		||||
// Rectangles which are successfully packed have the 'was_packed' flag
 | 
			
		||||
// set to a non-zero value and 'x' and 'y' store the minimum location
 | 
			
		||||
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
 | 
			
		||||
// if you imagine y increasing downwards). Rectangles which do not fit
 | 
			
		||||
// have the 'was_packed' flag set to 0.
 | 
			
		||||
//
 | 
			
		||||
// You should not try to access the 'rects' array from another thread
 | 
			
		||||
// while this function is running, as the function temporarily reorders
 | 
			
		||||
// the array while it executes.
 | 
			
		||||
//
 | 
			
		||||
// To pack into another rectangle, you need to call stbrp_init_target
 | 
			
		||||
// again. To continue packing into the same rectangle, you can call
 | 
			
		||||
// this function again. Calling this multiple times with multiple rect
 | 
			
		||||
// arrays will probably produce worse packing results than calling it
 | 
			
		||||
// a single time with the full rectangle array, but the option is
 | 
			
		||||
// available.
 | 
			
		||||
//
 | 
			
		||||
// The function returns 1 if all of the rectangles were successfully
 | 
			
		||||
// packed and 0 otherwise.
 | 
			
		||||
 | 
			
		||||
struct stbrp_rect
 | 
			
		||||
{
 | 
			
		||||
   // reserved for your use:
 | 
			
		||||
   int            id;
 | 
			
		||||
 | 
			
		||||
   // input:
 | 
			
		||||
   stbrp_coord    w, h;
 | 
			
		||||
 | 
			
		||||
   // output:
 | 
			
		||||
   stbrp_coord    x, y;
 | 
			
		||||
   int            was_packed;  // non-zero if valid packing
 | 
			
		||||
 | 
			
		||||
}; // 16 bytes, nominally
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
 | 
			
		||||
// Initialize a rectangle packer to:
 | 
			
		||||
//    pack a rectangle that is 'width' by 'height' in dimensions
 | 
			
		||||
//    using temporary storage provided by the array 'nodes', which is 'num_nodes' long
 | 
			
		||||
//
 | 
			
		||||
// You must call this function every time you start packing into a new target.
 | 
			
		||||
//
 | 
			
		||||
// There is no "shutdown" function. The 'nodes' memory must stay valid for
 | 
			
		||||
// the following stbrp_pack_rects() call (or calls), but can be freed after
 | 
			
		||||
// the call (or calls) finish.
 | 
			
		||||
//
 | 
			
		||||
// Note: to guarantee best results, either:
 | 
			
		||||
//       1. make sure 'num_nodes' >= 'width'
 | 
			
		||||
//   or  2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
 | 
			
		||||
//
 | 
			
		||||
// If you don't do either of the above things, widths will be quantized to multiples
 | 
			
		||||
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
 | 
			
		||||
//
 | 
			
		||||
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
 | 
			
		||||
// may run out of temporary storage and be unable to pack some rectangles.
 | 
			
		||||
 | 
			
		||||
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
 | 
			
		||||
// Optionally call this function after init but before doing any packing to
 | 
			
		||||
// change the handling of the out-of-temp-memory scenario, described above.
 | 
			
		||||
// If you call init again, this will be reset to the default (false).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
 | 
			
		||||
// Optionally select which packing heuristic the library should use. Different
 | 
			
		||||
// heuristics will produce better/worse results for different data sets.
 | 
			
		||||
// If you call init again, this will be reset to the default.
 | 
			
		||||
 | 
			
		||||
enum
 | 
			
		||||
{
 | 
			
		||||
   STBRP_HEURISTIC_Skyline_default=0,
 | 
			
		||||
   STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
 | 
			
		||||
   STBRP_HEURISTIC_Skyline_BF_sortHeight
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//
 | 
			
		||||
// the details of the following structures don't matter to you, but they must
 | 
			
		||||
// be visible so you can handle the memory allocations for them
 | 
			
		||||
 | 
			
		||||
struct stbrp_node
 | 
			
		||||
{
 | 
			
		||||
   stbrp_coord  x,y;
 | 
			
		||||
   stbrp_node  *next;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct stbrp_context
 | 
			
		||||
{
 | 
			
		||||
   int width;
 | 
			
		||||
   int height;
 | 
			
		||||
   int align;
 | 
			
		||||
   int init_mode;
 | 
			
		||||
   int heuristic;
 | 
			
		||||
   int num_nodes;
 | 
			
		||||
   stbrp_node *active_head;
 | 
			
		||||
   stbrp_node *free_head;
 | 
			
		||||
   stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//
 | 
			
		||||
//     IMPLEMENTATION SECTION
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#ifdef STB_RECT_PACK_IMPLEMENTATION
 | 
			
		||||
#ifndef STBRP_SORT
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#define STBRP_SORT qsort
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef STBRP_ASSERT
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#define STBRP_ASSERT assert
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
#define STBRP__NOTUSED(v)  (void)(v)
 | 
			
		||||
#define STBRP__CDECL       __cdecl
 | 
			
		||||
#else
 | 
			
		||||
#define STBRP__NOTUSED(v)  (void)sizeof(v)
 | 
			
		||||
#define STBRP__CDECL
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
enum
 | 
			
		||||
{
 | 
			
		||||
   STBRP__INIT_skyline = 1
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
 | 
			
		||||
{
 | 
			
		||||
   switch (context->init_mode) {
 | 
			
		||||
      case STBRP__INIT_skyline:
 | 
			
		||||
         STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
 | 
			
		||||
         context->heuristic = heuristic;
 | 
			
		||||
         break;
 | 
			
		||||
      default:
 | 
			
		||||
         STBRP_ASSERT(0);
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
 | 
			
		||||
{
 | 
			
		||||
   if (allow_out_of_mem)
 | 
			
		||||
      // if it's ok to run out of memory, then don't bother aligning them;
 | 
			
		||||
      // this gives better packing, but may fail due to OOM (even though
 | 
			
		||||
      // the rectangles easily fit). @TODO a smarter approach would be to only
 | 
			
		||||
      // quantize once we've hit OOM, then we could get rid of this parameter.
 | 
			
		||||
      context->align = 1;
 | 
			
		||||
   else {
 | 
			
		||||
      // if it's not ok to run out of memory, then quantize the widths
 | 
			
		||||
      // so that num_nodes is always enough nodes.
 | 
			
		||||
      //
 | 
			
		||||
      // I.e. num_nodes * align >= width
 | 
			
		||||
      //                  align >= width / num_nodes
 | 
			
		||||
      //                  align = ceil(width/num_nodes)
 | 
			
		||||
 | 
			
		||||
      context->align = (context->width + context->num_nodes-1) / context->num_nodes;
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
 | 
			
		||||
{
 | 
			
		||||
   int i;
 | 
			
		||||
 | 
			
		||||
   for (i=0; i < num_nodes-1; ++i)
 | 
			
		||||
      nodes[i].next = &nodes[i+1];
 | 
			
		||||
   nodes[i].next = NULL;
 | 
			
		||||
   context->init_mode = STBRP__INIT_skyline;
 | 
			
		||||
   context->heuristic = STBRP_HEURISTIC_Skyline_default;
 | 
			
		||||
   context->free_head = &nodes[0];
 | 
			
		||||
   context->active_head = &context->extra[0];
 | 
			
		||||
   context->width = width;
 | 
			
		||||
   context->height = height;
 | 
			
		||||
   context->num_nodes = num_nodes;
 | 
			
		||||
   stbrp_setup_allow_out_of_mem(context, 0);
 | 
			
		||||
 | 
			
		||||
   // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
 | 
			
		||||
   context->extra[0].x = 0;
 | 
			
		||||
   context->extra[0].y = 0;
 | 
			
		||||
   context->extra[0].next = &context->extra[1];
 | 
			
		||||
   context->extra[1].x = (stbrp_coord) width;
 | 
			
		||||
   context->extra[1].y = (1<<30);
 | 
			
		||||
   context->extra[1].next = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// find minimum y position if it starts at x1
 | 
			
		||||
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
 | 
			
		||||
{
 | 
			
		||||
   stbrp_node *node = first;
 | 
			
		||||
   int x1 = x0 + width;
 | 
			
		||||
   int min_y, visited_width, waste_area;
 | 
			
		||||
 | 
			
		||||
   STBRP__NOTUSED(c);
 | 
			
		||||
 | 
			
		||||
   STBRP_ASSERT(first->x <= x0);
 | 
			
		||||
 | 
			
		||||
   #if 0
 | 
			
		||||
   // skip in case we're past the node
 | 
			
		||||
   while (node->next->x <= x0)
 | 
			
		||||
      ++node;
 | 
			
		||||
   #else
 | 
			
		||||
   STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
   STBRP_ASSERT(node->x <= x0);
 | 
			
		||||
 | 
			
		||||
   min_y = 0;
 | 
			
		||||
   waste_area = 0;
 | 
			
		||||
   visited_width = 0;
 | 
			
		||||
   while (node->x < x1) {
 | 
			
		||||
      if (node->y > min_y) {
 | 
			
		||||
         // raise min_y higher.
 | 
			
		||||
         // we've accounted for all waste up to min_y,
 | 
			
		||||
         // but we'll now add more waste for everything we've visted
 | 
			
		||||
         waste_area += visited_width * (node->y - min_y);
 | 
			
		||||
         min_y = node->y;
 | 
			
		||||
         // the first time through, visited_width might be reduced
 | 
			
		||||
         if (node->x < x0)
 | 
			
		||||
            visited_width += node->next->x - x0;
 | 
			
		||||
         else
 | 
			
		||||
            visited_width += node->next->x - node->x;
 | 
			
		||||
      } else {
 | 
			
		||||
         // add waste area
 | 
			
		||||
         int under_width = node->next->x - node->x;
 | 
			
		||||
         if (under_width + visited_width > width)
 | 
			
		||||
            under_width = width - visited_width;
 | 
			
		||||
         waste_area += under_width * (min_y - node->y);
 | 
			
		||||
         visited_width += under_width;
 | 
			
		||||
      }
 | 
			
		||||
      node = node->next;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   *pwaste = waste_area;
 | 
			
		||||
   return min_y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
   int x,y;
 | 
			
		||||
   stbrp_node **prev_link;
 | 
			
		||||
} stbrp__findresult;
 | 
			
		||||
 | 
			
		||||
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
 | 
			
		||||
{
 | 
			
		||||
   int best_waste = (1<<30), best_x, best_y = (1 << 30);
 | 
			
		||||
   stbrp__findresult fr;
 | 
			
		||||
   stbrp_node **prev, *node, *tail, **best = NULL;
 | 
			
		||||
 | 
			
		||||
   // align to multiple of c->align
 | 
			
		||||
   width = (width + c->align - 1);
 | 
			
		||||
   width -= width % c->align;
 | 
			
		||||
   STBRP_ASSERT(width % c->align == 0);
 | 
			
		||||
 | 
			
		||||
   // if it can't possibly fit, bail immediately
 | 
			
		||||
   if (width > c->width || height > c->height) {
 | 
			
		||||
      fr.prev_link = NULL;
 | 
			
		||||
      fr.x = fr.y = 0;
 | 
			
		||||
      return fr;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   node = c->active_head;
 | 
			
		||||
   prev = &c->active_head;
 | 
			
		||||
   while (node->x + width <= c->width) {
 | 
			
		||||
      int y,waste;
 | 
			
		||||
      y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
 | 
			
		||||
      if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
 | 
			
		||||
         // bottom left
 | 
			
		||||
         if (y < best_y) {
 | 
			
		||||
            best_y = y;
 | 
			
		||||
            best = prev;
 | 
			
		||||
         }
 | 
			
		||||
      } else {
 | 
			
		||||
         // best-fit
 | 
			
		||||
         if (y + height <= c->height) {
 | 
			
		||||
            // can only use it if it first vertically
 | 
			
		||||
            if (y < best_y || (y == best_y && waste < best_waste)) {
 | 
			
		||||
               best_y = y;
 | 
			
		||||
               best_waste = waste;
 | 
			
		||||
               best = prev;
 | 
			
		||||
            }
 | 
			
		||||
         }
 | 
			
		||||
      }
 | 
			
		||||
      prev = &node->next;
 | 
			
		||||
      node = node->next;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   best_x = (best == NULL) ? 0 : (*best)->x;
 | 
			
		||||
 | 
			
		||||
   // if doing best-fit (BF), we also have to try aligning right edge to each node position
 | 
			
		||||
   //
 | 
			
		||||
   // e.g, if fitting
 | 
			
		||||
   //
 | 
			
		||||
   //     ____________________
 | 
			
		||||
   //    |____________________|
 | 
			
		||||
   //
 | 
			
		||||
   //            into
 | 
			
		||||
   //
 | 
			
		||||
   //   |                         |
 | 
			
		||||
   //   |             ____________|
 | 
			
		||||
   //   |____________|
 | 
			
		||||
   //
 | 
			
		||||
   // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
 | 
			
		||||
   //
 | 
			
		||||
   // This makes BF take about 2x the time
 | 
			
		||||
 | 
			
		||||
   if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
 | 
			
		||||
      tail = c->active_head;
 | 
			
		||||
      node = c->active_head;
 | 
			
		||||
      prev = &c->active_head;
 | 
			
		||||
      // find first node that's admissible
 | 
			
		||||
      while (tail->x < width)
 | 
			
		||||
         tail = tail->next;
 | 
			
		||||
      while (tail) {
 | 
			
		||||
         int xpos = tail->x - width;
 | 
			
		||||
         int y,waste;
 | 
			
		||||
         STBRP_ASSERT(xpos >= 0);
 | 
			
		||||
         // find the left position that matches this
 | 
			
		||||
         while (node->next->x <= xpos) {
 | 
			
		||||
            prev = &node->next;
 | 
			
		||||
            node = node->next;
 | 
			
		||||
         }
 | 
			
		||||
         STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
 | 
			
		||||
         y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
 | 
			
		||||
         if (y + height <= c->height) {
 | 
			
		||||
            if (y <= best_y) {
 | 
			
		||||
               if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
 | 
			
		||||
                  best_x = xpos;
 | 
			
		||||
                  //STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
 | 
			
		||||
                  best_y = y;
 | 
			
		||||
                  best_waste = waste;
 | 
			
		||||
                  best = prev;
 | 
			
		||||
               }
 | 
			
		||||
            }
 | 
			
		||||
         }
 | 
			
		||||
         tail = tail->next;
 | 
			
		||||
      }
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   fr.prev_link = best;
 | 
			
		||||
   fr.x = best_x;
 | 
			
		||||
   fr.y = best_y;
 | 
			
		||||
   return fr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
 | 
			
		||||
{
 | 
			
		||||
   // find best position according to heuristic
 | 
			
		||||
   stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
 | 
			
		||||
   stbrp_node *node, *cur;
 | 
			
		||||
 | 
			
		||||
   // bail if:
 | 
			
		||||
   //    1. it failed
 | 
			
		||||
   //    2. the best node doesn't fit (we don't always check this)
 | 
			
		||||
   //    3. we're out of memory
 | 
			
		||||
   if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
 | 
			
		||||
      res.prev_link = NULL;
 | 
			
		||||
      return res;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   // on success, create new node
 | 
			
		||||
   node = context->free_head;
 | 
			
		||||
   node->x = (stbrp_coord) res.x;
 | 
			
		||||
   node->y = (stbrp_coord) (res.y + height);
 | 
			
		||||
 | 
			
		||||
   context->free_head = node->next;
 | 
			
		||||
 | 
			
		||||
   // insert the new node into the right starting point, and
 | 
			
		||||
   // let 'cur' point to the remaining nodes needing to be
 | 
			
		||||
   // stiched back in
 | 
			
		||||
 | 
			
		||||
   cur = *res.prev_link;
 | 
			
		||||
   if (cur->x < res.x) {
 | 
			
		||||
      // preserve the existing one, so start testing with the next one
 | 
			
		||||
      stbrp_node *next = cur->next;
 | 
			
		||||
      cur->next = node;
 | 
			
		||||
      cur = next;
 | 
			
		||||
   } else {
 | 
			
		||||
      *res.prev_link = node;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   // from here, traverse cur and free the nodes, until we get to one
 | 
			
		||||
   // that shouldn't be freed
 | 
			
		||||
   while (cur->next && cur->next->x <= res.x + width) {
 | 
			
		||||
      stbrp_node *next = cur->next;
 | 
			
		||||
      // move the current node to the free list
 | 
			
		||||
      cur->next = context->free_head;
 | 
			
		||||
      context->free_head = cur;
 | 
			
		||||
      cur = next;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   // stitch the list back in
 | 
			
		||||
   node->next = cur;
 | 
			
		||||
 | 
			
		||||
   if (cur->x < res.x + width)
 | 
			
		||||
      cur->x = (stbrp_coord) (res.x + width);
 | 
			
		||||
 | 
			
		||||
#ifdef _DEBUG
 | 
			
		||||
   cur = context->active_head;
 | 
			
		||||
   while (cur->x < context->width) {
 | 
			
		||||
      STBRP_ASSERT(cur->x < cur->next->x);
 | 
			
		||||
      cur = cur->next;
 | 
			
		||||
   }
 | 
			
		||||
   STBRP_ASSERT(cur->next == NULL);
 | 
			
		||||
 | 
			
		||||
   {
 | 
			
		||||
      int count=0;
 | 
			
		||||
      cur = context->active_head;
 | 
			
		||||
      while (cur) {
 | 
			
		||||
         cur = cur->next;
 | 
			
		||||
         ++count;
 | 
			
		||||
      }
 | 
			
		||||
      cur = context->free_head;
 | 
			
		||||
      while (cur) {
 | 
			
		||||
         cur = cur->next;
 | 
			
		||||
         ++count;
 | 
			
		||||
      }
 | 
			
		||||
      STBRP_ASSERT(count == context->num_nodes+2);
 | 
			
		||||
   }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
   return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
 | 
			
		||||
{
 | 
			
		||||
   const stbrp_rect *p = (const stbrp_rect *) a;
 | 
			
		||||
   const stbrp_rect *q = (const stbrp_rect *) b;
 | 
			
		||||
   if (p->h > q->h)
 | 
			
		||||
      return -1;
 | 
			
		||||
   if (p->h < q->h)
 | 
			
		||||
      return  1;
 | 
			
		||||
   return (p->w > q->w) ? -1 : (p->w < q->w);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
 | 
			
		||||
{
 | 
			
		||||
   const stbrp_rect *p = (const stbrp_rect *) a;
 | 
			
		||||
   const stbrp_rect *q = (const stbrp_rect *) b;
 | 
			
		||||
   return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
 | 
			
		||||
{
 | 
			
		||||
   int i, all_rects_packed = 1;
 | 
			
		||||
 | 
			
		||||
   // we use the 'was_packed' field internally to allow sorting/unsorting
 | 
			
		||||
   for (i=0; i < num_rects; ++i) {
 | 
			
		||||
      rects[i].was_packed = i;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   // sort according to heuristic
 | 
			
		||||
   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
 | 
			
		||||
 | 
			
		||||
   for (i=0; i < num_rects; ++i) {
 | 
			
		||||
      if (rects[i].w == 0 || rects[i].h == 0) {
 | 
			
		||||
         rects[i].x = rects[i].y = 0;  // empty rect needs no space
 | 
			
		||||
      } else {
 | 
			
		||||
         stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
 | 
			
		||||
         if (fr.prev_link) {
 | 
			
		||||
            rects[i].x = (stbrp_coord) fr.x;
 | 
			
		||||
            rects[i].y = (stbrp_coord) fr.y;
 | 
			
		||||
         } else {
 | 
			
		||||
            rects[i].x = rects[i].y = STBRP__MAXVAL;
 | 
			
		||||
         }
 | 
			
		||||
      }
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   // unsort
 | 
			
		||||
   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
 | 
			
		||||
 | 
			
		||||
   // set was_packed flags and all_rects_packed status
 | 
			
		||||
   for (i=0; i < num_rects; ++i) {
 | 
			
		||||
      rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
 | 
			
		||||
      if (!rects[i].was_packed)
 | 
			
		||||
         all_rects_packed = 0;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   // return the all_rects_packed status
 | 
			
		||||
   return all_rects_packed;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
------------------------------------------------------------------------------
 | 
			
		||||
This software is available under 2 licenses -- choose whichever you prefer.
 | 
			
		||||
------------------------------------------------------------------------------
 | 
			
		||||
ALTERNATIVE A - MIT License
 | 
			
		||||
Copyright (c) 2017 Sean Barrett
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
			
		||||
this software and associated documentation files (the "Software"), to deal in
 | 
			
		||||
the Software without restriction, including without limitation the rights to
 | 
			
		||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 | 
			
		||||
of the Software, and to permit persons to whom the Software is furnished to do
 | 
			
		||||
so, subject to the following conditions:
 | 
			
		||||
The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
copies or substantial portions of the Software.
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
SOFTWARE.
 | 
			
		||||
------------------------------------------------------------------------------
 | 
			
		||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
 | 
			
		||||
This is free and unencumbered software released into the public domain.
 | 
			
		||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
 | 
			
		||||
software, either in source code form or as a compiled binary, for any purpose,
 | 
			
		||||
commercial or non-commercial, and by any means.
 | 
			
		||||
In jurisdictions that recognize copyright laws, the author or authors of this
 | 
			
		||||
software dedicate any and all copyright interest in the software to the public
 | 
			
		||||
domain. We make this dedication for the benefit of the public at large and to
 | 
			
		||||
the detriment of our heirs and successors. We intend this dedication to be an
 | 
			
		||||
overt act of relinquishment in perpetuity of all present and future rights to
 | 
			
		||||
this software under copyright law.
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 | 
			
		||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 | 
			
		||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
------------------------------------------------------------------------------
 | 
			
		||||
*/
 | 
			
		||||
							
								
								
									
										1469
									
								
								imstb_textedit.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1469
									
								
								imstb_textedit.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										5085
									
								
								imstb_truetype.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5085
									
								
								imstb_truetype.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										58
									
								
								shaders/clarity.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								shaders/clarity.frag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
#version 330 core
 | 
			
		||||
 | 
			
		||||
float luminance(vec3 color) {
 | 
			
		||||
    return dot(color, vec3(0.2126, 0.7152, 0.0722));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
out vec4 FragColor;
 | 
			
		||||
in vec2 TexCoord;
 | 
			
		||||
 | 
			
		||||
uniform sampler2D InputTexture;
 | 
			
		||||
uniform float clarityValue; // -100 (blur) to 100 (sharpen)
 | 
			
		||||
 | 
			
		||||
// Simple Box Blur (approximates Gaussian for unsharp mask)
 | 
			
		||||
vec3 boxBlur(sampler2D tex, vec2 uv, vec2 texelSize, int radius) {
 | 
			
		||||
    vec3 blurred = vec3(0.0);
 | 
			
		||||
    float weightSum = 0.0;
 | 
			
		||||
    float r = float(radius);
 | 
			
		||||
 | 
			
		||||
    for (int x = -radius; x <= radius; ++x) {
 | 
			
		||||
        for (int y = -radius; y <= radius; ++y) {
 | 
			
		||||
            // Optional: Use Gaussian weights instead of box for better quality blur
 | 
			
		||||
            // float weight = exp(-(float(x*x + y*y)) / (2.0 * r*r));
 | 
			
		||||
            float weight = 1.0; // Box weight
 | 
			
		||||
            blurred += texture(tex, uv + vec2(x, y) * texelSize).rgb * weight;
 | 
			
		||||
            weightSum += weight;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return blurred / weightSum;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Apply Clarity using Unsharp Masking
 | 
			
		||||
vec3 applyClarity(vec3 originalColor, vec2 uv, float clarity) {
 | 
			
		||||
    if (abs(clarity) < 0.01) return originalColor; // No change
 | 
			
		||||
 | 
			
		||||
    vec2 texelSize = 1.0 / textureSize(InputTexture, 0);
 | 
			
		||||
    // Clarity targets mid-frequencies, use a moderate blur radius
 | 
			
		||||
    int blurRadius = 2; // Adjust radius for desired frequency range (1-3 typical)
 | 
			
		||||
 | 
			
		||||
    // 1. Create a blurred version (low-pass filter)
 | 
			
		||||
    vec3 blurredColor = boxBlur(InputTexture, uv, texelSize, blurRadius);
 | 
			
		||||
 | 
			
		||||
    // 2. Calculate the high-pass detail (Original - Blurred)
 | 
			
		||||
    vec3 highPassDetail = originalColor - blurredColor;
 | 
			
		||||
 | 
			
		||||
    // 3. Add the scaled detail back to the original
 | 
			
		||||
    // Map clarity -100..100 to a strength factor, e.g., 0..2
 | 
			
		||||
    float strength = clarity / 100.0; // Map to -1..1
 | 
			
		||||
 | 
			
		||||
    vec3 clarifiedColor = originalColor + highPassDetail * strength;
 | 
			
		||||
 | 
			
		||||
    return clarifiedColor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    vec4 color = texture(InputTexture, TexCoord);
 | 
			
		||||
    color.rgb = applyClarity(color.rgb, TexCoord, clarityValue);
 | 
			
		||||
    FragColor = vec4(max(color.rgb, vec3(0.0)), color.a);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								shaders/contrast.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								shaders/contrast.frag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
#version 330 core
 | 
			
		||||
out vec4 FragColor;
 | 
			
		||||
in vec2 TexCoord;
 | 
			
		||||
 | 
			
		||||
uniform sampler2D InputTexture;
 | 
			
		||||
uniform float contrastValue; // Expecting value e.g., -100 to 100
 | 
			
		||||
 | 
			
		||||
// Perceptually accurate contrast adjustment
 | 
			
		||||
vec3 applyContrast(vec3 color, float contrast) {
 | 
			
		||||
    float factor = pow(2.0, contrast / 50.0); // Exponential scaling for more natural feel
 | 
			
		||||
    
 | 
			
		||||
    // Use 0.18 as middle gray (photographic standard)
 | 
			
		||||
    const vec3 midPoint = vec3(0.18);
 | 
			
		||||
    
 | 
			
		||||
    // Apply contrast with proper pivot point
 | 
			
		||||
    return midPoint + factor * (color - midPoint);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    vec4 color = texture(InputTexture, TexCoord);
 | 
			
		||||
    color.rgb = applyContrast(color.rgb, contrastValue);
 | 
			
		||||
    
 | 
			
		||||
    // Clamp results to valid range
 | 
			
		||||
    FragColor = vec4(clamp(color.rgb, vec3(0.0), vec3(1.0)), color.a);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										198
									
								
								shaders/dehaze.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								shaders/dehaze.frag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,198 @@
 | 
			
		||||
#version 330 core
 | 
			
		||||
/*
 | 
			
		||||
 * Advanced Atmospheric Dehazing Shader
 | 
			
		||||
 * ------------------------------------
 | 
			
		||||
 * This shader simulates the behavior of Adobe Lightroom/Photoshop's Dehaze feature using:
 | 
			
		||||
 * 
 | 
			
		||||
 * 1. Dark Channel Prior (DCP) technique for estimating atmospheric light and transmission
 | 
			
		||||
 *    - In photography, haze appears as a low-contrast, brightened, desaturated overlay 
 | 
			
		||||
 *    - DCP assumes that haze-free regions have at least one RGB channel with very low intensity
 | 
			
		||||
 *    - By detecting regions where all RGB channels are high, we can identify hazy areas
 | 
			
		||||
 * 
 | 
			
		||||
 * 2. Multi-scale contrast enhancement with perceptual considerations
 | 
			
		||||
 *    - Detail recovery is based on local contrast improvement
 | 
			
		||||
 *    - Preserves color relationships similar to Lightroom by boosting both contrast and saturation
 | 
			
		||||
 * 
 | 
			
		||||
 * 3. Adaptive atmospheric light estimation
 | 
			
		||||
 *    - Uses a simplified version of sky/atmospheric light detection
 | 
			
		||||
 *    - Approximates the global atmospheric light color (typically grayish-blue)
 | 
			
		||||
 * 
 | 
			
		||||
 * 4. Tone-aware processing
 | 
			
		||||
 *    - Protects highlights from clipping, similar to Lightroom's implementation
 | 
			
		||||
 *    - Preserves natural shadows while improving visibility
 | 
			
		||||
 *
 | 
			
		||||
 * 5. Implements a non-linear response curve that matches the perceptual effect of Lightroom's
 | 
			
		||||
 *    dehaze slider within the -100 to +100 range
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
out vec4 FragColor;
 | 
			
		||||
in vec2 TexCoord;
 | 
			
		||||
 | 
			
		||||
uniform sampler2D InputTexture;
 | 
			
		||||
uniform float dehazeValue; // -100 to 100 (negative values add haze)
 | 
			
		||||
 | 
			
		||||
// Perceptual luminance weights (Rec. 709)
 | 
			
		||||
const vec3 luminanceWeight = vec3(0.2126, 0.7152, 0.0722);
 | 
			
		||||
 | 
			
		||||
float luminance(vec3 color) {
 | 
			
		||||
    return dot(color, luminanceWeight);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Improved box blur with edge-aware weighting
 | 
			
		||||
vec3 boxBlur(sampler2D tex, vec2 uv, vec2 texelSize, int radius) {
 | 
			
		||||
    vec3 blurred = vec3(0.0);
 | 
			
		||||
    float weightSum = 0.0;
 | 
			
		||||
    float r = float(radius);
 | 
			
		||||
    vec3 centerColor = texture(tex, uv).rgb;
 | 
			
		||||
    
 | 
			
		||||
    for (int x = -radius; x <= radius; ++x) {
 | 
			
		||||
        for (int y = -radius; y <= radius; ++y) {
 | 
			
		||||
            vec2 offset = vec2(x, y) * texelSize;
 | 
			
		||||
            vec3 sampleColor = texture(tex, uv + offset).rgb;
 | 
			
		||||
            
 | 
			
		||||
            // Edge-aware weight: lower weight for pixels that are very different
 | 
			
		||||
            float colorDist = distance(centerColor, sampleColor);
 | 
			
		||||
            float edgeWeight = exp(-colorDist * 10.0);
 | 
			
		||||
            
 | 
			
		||||
            // Spatial weight: Gaussian
 | 
			
		||||
            float spatialWeight = exp(-(float(x*x + y*y)) / (2.0 * r*r));
 | 
			
		||||
            
 | 
			
		||||
            float weight = spatialWeight * edgeWeight;
 | 
			
		||||
            blurred += sampleColor * weight;
 | 
			
		||||
            weightSum += weight;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return blurred / max(weightSum, 0.0001);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Calculates dark channel (minimum of RGB channels) for a local region
 | 
			
		||||
float getDarkChannel(sampler2D tex, vec2 uv, vec2 texelSize, int radius) {
 | 
			
		||||
    float darkChannel = 1.0;
 | 
			
		||||
    
 | 
			
		||||
    for (int x = -radius; x <= radius; ++x) {
 | 
			
		||||
        for (int y = -radius; y <= radius; ++y) {
 | 
			
		||||
            vec2 offset = vec2(x, y) * texelSize;
 | 
			
		||||
            vec3 sampleColor = texture(tex, uv + offset).rgb;
 | 
			
		||||
            float minChannel = min(min(sampleColor.r, sampleColor.g), sampleColor.b);
 | 
			
		||||
            darkChannel = min(darkChannel, minChannel);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return darkChannel;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Estimates atmospheric light (typically the brightest pixel in hazy regions)
 | 
			
		||||
vec3 estimateAtmosphericLight(sampler2D tex, vec2 uv, vec2 texelSize) {
 | 
			
		||||
    // Default slightly bluish-gray haze color, similar to most atmospheric conditions
 | 
			
		||||
    vec3 defaultAtmosphericLight = vec3(0.85, 0.9, 1.0);
 | 
			
		||||
    
 | 
			
		||||
    // Find brightest area in a larger region 
 | 
			
		||||
    vec3 brightest = vec3(0.0);
 | 
			
		||||
    float maxLum = 0.0;
 | 
			
		||||
    
 | 
			
		||||
    int searchRadius = 10;
 | 
			
		||||
    for (int x = -searchRadius; x <= searchRadius; x += 2) {
 | 
			
		||||
        for (int y = -searchRadius; y <= searchRadius; y += 2) {
 | 
			
		||||
            vec2 offset = vec2(x, y) * texelSize;
 | 
			
		||||
            vec3 sampleColor = texture(tex, uv + offset).rgb;
 | 
			
		||||
            float lum = luminance(sampleColor);
 | 
			
		||||
            
 | 
			
		||||
            if (lum > maxLum) {
 | 
			
		||||
                maxLum = lum;
 | 
			
		||||
                brightest = sampleColor;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Blend between default and detected atmospheric light
 | 
			
		||||
    return mix(defaultAtmosphericLight, brightest, 0.7);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Tone protection function to preserve highlights and shadows
 | 
			
		||||
vec3 protectTones(vec3 color, vec3 enhanced, float amount) {
 | 
			
		||||
    float lum = luminance(color);
 | 
			
		||||
    
 | 
			
		||||
    // Highlight and shadow protection factors
 | 
			
		||||
    float highlightProtection = 1.0 - smoothstep(0.75, 0.98, lum);
 | 
			
		||||
    float shadowProtection = smoothstep(0.0, 0.2, lum);
 | 
			
		||||
    
 | 
			
		||||
    float protection = mix(1.0, highlightProtection * shadowProtection, min(abs(amount) * 2.0, 1.0));
 | 
			
		||||
    
 | 
			
		||||
    return mix(color, enhanced, protection);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Apply advanced dehazing algorithm
 | 
			
		||||
vec3 applyDehaze(vec3 originalColor, vec2 uv, float dehaze) {
 | 
			
		||||
    // Convert dehaze from -100...100 to -1...1
 | 
			
		||||
    float amount = dehaze / 100.0;
 | 
			
		||||
    
 | 
			
		||||
    if (abs(amount) < 0.01) return originalColor;
 | 
			
		||||
    
 | 
			
		||||
    vec2 texelSize = 1.0 / textureSize(InputTexture, 0);
 | 
			
		||||
    
 | 
			
		||||
    // --- Atmospheric Scattering Model: I = J × t + A × (1-t) ---
 | 
			
		||||
    // I is the observed hazy image, J is the dehazed image, 
 | 
			
		||||
    // A is atmospheric light, t is transmission
 | 
			
		||||
    
 | 
			
		||||
    // Calculate dark channel (key to estimating haze)
 | 
			
		||||
    int darkChannelRadius = 3;
 | 
			
		||||
    float darkChannel = getDarkChannel(InputTexture, uv, texelSize, darkChannelRadius);
 | 
			
		||||
    
 | 
			
		||||
    // Estimate atmospheric light
 | 
			
		||||
    vec3 atmosphericLight = estimateAtmosphericLight(InputTexture, uv, texelSize);
 | 
			
		||||
    
 | 
			
		||||
    // Calculate transmission map using dark channel prior
 | 
			
		||||
    float omega = 0.95; // Preserves a small amount of haze for realism
 | 
			
		||||
    float transmission = 1.0 - omega * darkChannel;
 | 
			
		||||
    
 | 
			
		||||
    vec3 result;
 | 
			
		||||
    if (amount > 0.0) {
 | 
			
		||||
        // Remove haze (positive dehaze)
 | 
			
		||||
        float minTransmission = 0.1;
 | 
			
		||||
        float adjustedTransmission = max(transmission, minTransmission);
 | 
			
		||||
        adjustedTransmission = mix(1.0, adjustedTransmission, amount);
 | 
			
		||||
        
 | 
			
		||||
        // Apply dehaze formula: J = (I - A) / t + A
 | 
			
		||||
        result = (originalColor - atmosphericLight) / adjustedTransmission + atmosphericLight;
 | 
			
		||||
        
 | 
			
		||||
        // Additional local contrast enhancement
 | 
			
		||||
        vec3 localAverage = boxBlur(InputTexture, uv, texelSize, 3);
 | 
			
		||||
        vec3 localDetail = originalColor - localAverage;
 | 
			
		||||
        result = result + localDetail * (amount * 0.5);
 | 
			
		||||
        
 | 
			
		||||
        // Saturation boost (typical of dehaze)
 | 
			
		||||
        float satBoost = 1.0 + amount * 0.3;
 | 
			
		||||
        float resultLum = luminance(result);
 | 
			
		||||
        result = mix(vec3(resultLum), result, satBoost);
 | 
			
		||||
    } 
 | 
			
		||||
    else {
 | 
			
		||||
        // Add haze (negative dehaze)
 | 
			
		||||
        float hazeAmount = -amount;
 | 
			
		||||
        
 | 
			
		||||
        // Blend with atmospheric light
 | 
			
		||||
        result = mix(originalColor, atmosphericLight, hazeAmount * 0.5);
 | 
			
		||||
        
 | 
			
		||||
        // Reduce contrast to simulate haze
 | 
			
		||||
        vec3 localAverage = boxBlur(InputTexture, uv, texelSize, 5);
 | 
			
		||||
        result = mix(result, localAverage, hazeAmount * 0.3);
 | 
			
		||||
        
 | 
			
		||||
        // Reduce saturation
 | 
			
		||||
        float resultLum = luminance(result);
 | 
			
		||||
        result = mix(result, vec3(resultLum), hazeAmount * 0.4);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Protect highlights and shadows
 | 
			
		||||
    result = protectTones(originalColor, result, amount);
 | 
			
		||||
    
 | 
			
		||||
    // Non-linear response curve similar to Lightroom
 | 
			
		||||
    float blendFactor = 1.0 / (1.0 + exp(-abs(amount) * 3.0));
 | 
			
		||||
    result = mix(originalColor, result, blendFactor);
 | 
			
		||||
    
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    vec4 color = texture(InputTexture, TexCoord);
 | 
			
		||||
    color.rgb = applyDehaze(color.rgb, TexCoord, dehazeValue);
 | 
			
		||||
    FragColor = vec4(max(color.rgb, vec3(0.0)), color.a);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								shaders/exposure.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								shaders/exposure.frag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
#version 330 core
 | 
			
		||||
out vec4 FragColor;
 | 
			
		||||
in vec2 TexCoord;
 | 
			
		||||
 | 
			
		||||
uniform sampler2D InputTexture;
 | 
			
		||||
uniform float exposureValue; // Expecting value in stops, e.g., -5.0 to 5.0
 | 
			
		||||
 | 
			
		||||
// Calculate perceptual luminance
 | 
			
		||||
float luminance(vec3 color) {
 | 
			
		||||
    return dot(color, vec3(0.2126, 0.7152, 0.0722));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Apply exposure by adjusting luminance while preserving color relationships
 | 
			
		||||
vec3 applyExposure(vec3 color, float exposureStops) {
 | 
			
		||||
    // Get original luminance
 | 
			
		||||
    float lum = luminance(color);
 | 
			
		||||
    
 | 
			
		||||
    // Skip processing for very dark pixels to avoid division by zero
 | 
			
		||||
    if (lum < 0.0001) return color;
 | 
			
		||||
    
 | 
			
		||||
    // Calculate exposure factor
 | 
			
		||||
    float exposureFactor = pow(2.0, exposureStops);
 | 
			
		||||
    
 | 
			
		||||
    // Apply highlight compression when increasing exposure
 | 
			
		||||
    float newLum = lum * exposureFactor;
 | 
			
		||||
    if (exposureStops > 0.0 && newLum > 0.8) {
 | 
			
		||||
        // Soft highlight roll-off to prevent harsh clipping
 | 
			
		||||
        float excess = newLum - 0.8;
 | 
			
		||||
        newLum = 0.8 + 0.2 * (1.0 - exp(-excess * 5.0));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Scale RGB proportionally to maintain color relationships
 | 
			
		||||
    return color * (newLum / lum);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    vec4 color = texture(InputTexture, TexCoord);
 | 
			
		||||
    
 | 
			
		||||
    // Apply exposure adjustment
 | 
			
		||||
    color.rgb = applyExposure(color.rgb, exposureValue);
 | 
			
		||||
    
 | 
			
		||||
    // Ensure output is in valid range
 | 
			
		||||
    FragColor = vec4(clamp(color.rgb, vec3(0.0), vec3(1.0)), color.a);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								shaders/highlights_shadows.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								shaders/highlights_shadows.frag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
#version 330 core
 | 
			
		||||
 | 
			
		||||
out vec4 FragColor;
 | 
			
		||||
in vec2 TexCoord;
 | 
			
		||||
 | 
			
		||||
uniform sampler2D InputTexture;
 | 
			
		||||
uniform float highlightsValue; // -100 to 100
 | 
			
		||||
uniform float shadowsValue;    // -100 to 100
 | 
			
		||||
 | 
			
		||||
// More accurate perceptual luminance (Rec. 709)
 | 
			
		||||
float luminance(vec3 color) {
 | 
			
		||||
    return dot(color, vec3(0.2126, 0.7152, 0.0722));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Smoothstep with better performance than quintic
 | 
			
		||||
float smootherStep(float edge0, float edge1, float x) {
 | 
			
		||||
    float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
 | 
			
		||||
    return t * t * (3.0 - 2.0 * t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3 applyHighlightsShadows(vec3 color) {
 | 
			
		||||
    float lum = luminance(color);
 | 
			
		||||
    
 | 
			
		||||
    // Define threshold values similar to Lightroom
 | 
			
		||||
    float shadowThreshold = 0.3;
 | 
			
		||||
    float highlightThreshold = 0.7;
 | 
			
		||||
    
 | 
			
		||||
    // Calculate adjustment weights with smoother falloff
 | 
			
		||||
    float shadowWeight = 1.0 - smootherStep(0.0, shadowThreshold * 2.0, lum);
 | 
			
		||||
    float highlightWeight = smootherStep(highlightThreshold, 1.0, lum);
 | 
			
		||||
    
 | 
			
		||||
    // Calculate adaptive adjustment factors
 | 
			
		||||
    float shadowFactor = shadowsValue > 0.0 ? 
 | 
			
		||||
        mix(1.0, 1.0 + (shadowsValue / 100.0), shadowWeight) :
 | 
			
		||||
        mix(1.0, 1.0 + (shadowsValue / 150.0), shadowWeight);
 | 
			
		||||
        
 | 
			
		||||
    float highlightFactor = highlightsValue > 0.0 ?
 | 
			
		||||
        mix(1.0, 1.0 - (highlightsValue / 150.0), highlightWeight) :
 | 
			
		||||
        mix(1.0, 1.0 - (highlightsValue / 100.0), highlightWeight);
 | 
			
		||||
    
 | 
			
		||||
    // Apply adjustments while preserving colors
 | 
			
		||||
    vec3 adjusted = color * shadowFactor * highlightFactor;
 | 
			
		||||
    
 | 
			
		||||
    // Preserve some saturation characteristics like Lightroom
 | 
			
		||||
    float newLum = luminance(adjusted);
 | 
			
		||||
    float saturationFactor = 1.0;
 | 
			
		||||
    
 | 
			
		||||
    // Boost saturation slightly when lifting shadows (like Lightroom)
 | 
			
		||||
    // if (shadowsValue > 0.0 && lum < shadowThreshold) {
 | 
			
		||||
    //     saturationFactor = 1.0 + (shadowsValue / 300.0) * (1.0 - lum / shadowThreshold);
 | 
			
		||||
    // }
 | 
			
		||||
    
 | 
			
		||||
    // Reduce saturation slightly when recovering highlights (like Lightroom)
 | 
			
		||||
    if (highlightsValue > 0.0 && lum > highlightThreshold) {
 | 
			
		||||
        saturationFactor *= 1.0 - (highlightsValue / 400.0) * ((lum - highlightThreshold) / (1.0 - highlightThreshold));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Apply saturation adjustment while preserving luminance
 | 
			
		||||
    return mix(vec3(newLum), adjusted, saturationFactor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    vec4 color = texture(InputTexture, TexCoord);
 | 
			
		||||
    color.rgb = applyHighlightsShadows(color.rgb);
 | 
			
		||||
    FragColor = vec4(clamp(color.rgb, 0.0, 1.0), color.a);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								shaders/histogram.comp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								shaders/histogram.comp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
#version 430 core // Need SSBOs and atomic counters
 | 
			
		||||
 | 
			
		||||
// Input Texture (the processed image ready for display)
 | 
			
		||||
// Binding = 0 matches glBindImageTexture unit
 | 
			
		||||
// Use rgba8 format as we assume display texture is 8-bit sRGB (adjust if needed)
 | 
			
		||||
layout(binding = 0, rgba8) uniform readonly image2D InputTexture;
 | 
			
		||||
 | 
			
		||||
// Output Histogram Buffer (SSBO)
 | 
			
		||||
// Binding = 1 matches glBindBufferBase index
 | 
			
		||||
// Contains 256 bins for R, 256 for G, 256 for B sequentially (total 768 uints)
 | 
			
		||||
layout(std430, binding = 1) buffer HistogramBuffer {
 | 
			
		||||
    uint bins[]; // Use an unsized array
 | 
			
		||||
} histogram;
 | 
			
		||||
 | 
			
		||||
// Workgroup size (adjust based on GPU architecture for performance, 16x16 is often reasonable)
 | 
			
		||||
layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    // Get the global invocation ID (like pixel coordinates)
 | 
			
		||||
    ivec2 pixelCoord = ivec2(gl_GlobalInvocationID.xy);
 | 
			
		||||
    ivec2 textureSize = imageSize(InputTexture);
 | 
			
		||||
 | 
			
		||||
    // Boundary check: Don't process outside the image bounds
 | 
			
		||||
    if (pixelCoord.x >= textureSize.x || pixelCoord.y >= textureSize.y) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Load the pixel color (values are normalized float 0.0-1.0 from rgba8 image load)
 | 
			
		||||
    vec4 pixelColor = imageLoad(InputTexture, pixelCoord);
 | 
			
		||||
 | 
			
		||||
    // Calculate bin indices (0-255)
 | 
			
		||||
    // We clamp just in case, although imageLoad from rgba8 should be in range.
 | 
			
		||||
    uint rBin = uint(clamp(pixelColor.r, 0.0, 1.0) * 255.0);
 | 
			
		||||
    uint gBin = uint(clamp(pixelColor.g, 0.0, 1.0) * 255.0);
 | 
			
		||||
    uint bBin = uint(clamp(pixelColor.b, 0.0, 1.0) * 255.0);
 | 
			
		||||
 | 
			
		||||
    // Atomically increment the counters in the SSBO
 | 
			
		||||
    // Offset Green bins by 256, Blue bins by 512
 | 
			
		||||
    atomicAdd(histogram.bins[rBin],       1u);
 | 
			
		||||
    atomicAdd(histogram.bins[gBin + 256u], 1u);
 | 
			
		||||
    atomicAdd(histogram.bins[bBin + 512u], 1u);
 | 
			
		||||
 | 
			
		||||
    // Optional: Track Max Value (more complex, requires another SSBO or different strategy)
 | 
			
		||||
    // Example: atomicMax(histogram.maxBinValue, histogram.bins[rBin]); // Needs careful sync
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								shaders/linear_to_srgb.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								shaders/linear_to_srgb.frag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
#version 330 core
 | 
			
		||||
out vec4 FragColor;
 | 
			
		||||
in vec2 TexCoord;
 | 
			
		||||
uniform sampler2D InputTexture;
 | 
			
		||||
 | 
			
		||||
vec3 linearToSrgb(vec3 linearRGB) {
 | 
			
		||||
    linearRGB = max(linearRGB, vec3(0.0)); // Ensure non-negative input
 | 
			
		||||
    vec3 srgb = pow(linearRGB, vec3(1.0/2.4));
 | 
			
		||||
    srgb = mix(linearRGB * 12.92, srgb * 1.055 - 0.055, step(vec3(0.0031308), linearRGB));
 | 
			
		||||
    return clamp(srgb, 0.0, 1.0); // Clamp final output to display range
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    vec3 linearColor = texture(InputTexture, TexCoord).rgb;
 | 
			
		||||
    FragColor = vec4(linearToSrgb(linearColor), texture(InputTexture, TexCoord).a);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								shaders/passthrough.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								shaders/passthrough.frag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
#version 330 core
 | 
			
		||||
out vec4 FragColor;
 | 
			
		||||
in vec2 TexCoord;
 | 
			
		||||
 | 
			
		||||
uniform sampler2D InputTexture;
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    FragColor = texture(InputTexture, TexCoord);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								shaders/passthrough.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								shaders/passthrough.vert
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
#version 330 core
 | 
			
		||||
layout (location = 0) in vec2 aPos;
 | 
			
		||||
layout (location = 1) in vec2 aTexCoord;
 | 
			
		||||
 | 
			
		||||
out vec2 TexCoord;
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
 | 
			
		||||
    TexCoord = aTexCoord;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								shaders/saturation.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								shaders/saturation.frag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
#version 330 core
 | 
			
		||||
out vec4 FragColor;
 | 
			
		||||
in vec2 TexCoord;
 | 
			
		||||
 | 
			
		||||
uniform sampler2D InputTexture;
 | 
			
		||||
uniform float saturationValue; // -100 (grayscale) to 100 (double sat)
 | 
			
		||||
 | 
			
		||||
// Perceptual luminance weights (Rec. 709)
 | 
			
		||||
const vec3 luminanceWeight = vec3(0.2126, 0.7152, 0.0722);
 | 
			
		||||
 | 
			
		||||
vec3 applySaturation(vec3 color, float saturation) {
 | 
			
		||||
    // Get original luminance
 | 
			
		||||
    float lum = dot(color, luminanceWeight);
 | 
			
		||||
    
 | 
			
		||||
    // Skip processing for very dark or very bright pixels
 | 
			
		||||
    if (lum < 0.001 || lum > 0.999) return color;
 | 
			
		||||
    
 | 
			
		||||
    // Non-linear saturation response curve (more natural-looking)
 | 
			
		||||
    float factor;
 | 
			
		||||
    if (saturation >= 0.0) {
 | 
			
		||||
        // Positive saturation with highlight protection
 | 
			
		||||
        factor = 1.0 + (saturation / 100.0) * (1.0 - 0.3 * smoothstep(0.7, 1.0, lum));
 | 
			
		||||
    } else {
 | 
			
		||||
        // Negative saturation with shadow protection
 | 
			
		||||
        factor = 1.0 + (saturation / 100.0) * (1.0 - 0.1 * smoothstep(0.0, 0.2, lum));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Apply saturation while preserving luminance
 | 
			
		||||
    vec3 adjusted = mix(vec3(lum), color, factor);
 | 
			
		||||
    
 | 
			
		||||
    // Ensure we maintain original luminance exactly
 | 
			
		||||
    float newLum = dot(adjusted, luminanceWeight);
 | 
			
		||||
    return adjusted * (lum / max(newLum, 0.001));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    vec4 color = texture(InputTexture, TexCoord);
 | 
			
		||||
    
 | 
			
		||||
    // Apply saturation
 | 
			
		||||
    color.rgb = applySaturation(color.rgb, saturationValue);
 | 
			
		||||
    
 | 
			
		||||
    // Proper clamping to valid range
 | 
			
		||||
    FragColor = vec4(clamp(color.rgb, 0.0, 1.0), color.a);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								shaders/srgb_to_linear.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								shaders/srgb_to_linear.frag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
#version 330 core
 | 
			
		||||
out vec4 FragColor;
 | 
			
		||||
in vec2 TexCoord;
 | 
			
		||||
uniform sampler2D InputTexture;
 | 
			
		||||
 | 
			
		||||
vec3 linearToSrgb(vec3 linearRGB) {
 | 
			
		||||
    linearRGB = max(linearRGB, vec3(0.0)); // Ensure non-negative input
 | 
			
		||||
    vec3 srgb = pow(linearRGB, vec3(1.0/2.4));
 | 
			
		||||
    srgb = mix(linearRGB * 12.92, srgb * 1.055 - 0.055, step(vec3(0.0031308), linearRGB));
 | 
			
		||||
    return clamp(srgb, 0.0, 1.0); // Clamp final output to display range
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    vec3 linearColor = texture(InputTexture, TexCoord).rgb;
 | 
			
		||||
    FragColor = vec4(linearToSrgb(linearColor), texture(InputTexture, TexCoord).a);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										121
									
								
								shaders/texture.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								shaders/texture.frag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,121 @@
 | 
			
		||||
#version 330 core
 | 
			
		||||
/*
 | 
			
		||||
 * Advanced Texture Control Shader
 | 
			
		||||
 * -------------------------------
 | 
			
		||||
 * This shader emulates Adobe Lightroom/Photoshop's Texture slider by:
 | 
			
		||||
 * 
 | 
			
		||||
 * 1. Using frequency separation techniques to isolate medium-frequency details
 | 
			
		||||
 * 2. Employing multi-scale edge detection for more natural enhancement
 | 
			
		||||
 * 3. Adding tone-aware processing to protect highlights and shadows
 | 
			
		||||
 * 4. Implementing perceptual weighting to preserve color relationships
 | 
			
		||||
 * 5. Using non-linear response curves similar to Lightroom's implementation
 | 
			
		||||
 * 
 | 
			
		||||
 * Negative values: Smooth medium-frequency texture details (skin smoothing)
 | 
			
		||||
 * Positive values: Enhance medium-frequency texture details (fabric, hair, etc.)
 | 
			
		||||
 * 
 | 
			
		||||
 * Unlike Clarity (which affects larger contrast structures) or Sharpening (which 
 | 
			
		||||
 * affects fine details), Texture specifically targets medium-frequency details
 | 
			
		||||
 * that represent surface textures while avoiding edges.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
float luminance(vec3 color) {
 | 
			
		||||
    return dot(color, vec3(0.2126, 0.7152, 0.0722));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Improved blur function with Gaussian weights for better quality
 | 
			
		||||
vec3 gaussianBlur(sampler2D tex, vec2 uv, vec2 texelSize, float radius) {
 | 
			
		||||
    vec3 blurred = vec3(0.0);
 | 
			
		||||
    float weightSum = 0.0;
 | 
			
		||||
    float sigma = radius / 2.0;
 | 
			
		||||
    float sigma2 = 2.0 * sigma * sigma;
 | 
			
		||||
    int kernelSize = int(ceil(radius * 2.0));
 | 
			
		||||
    
 | 
			
		||||
    for (int x = -kernelSize; x <= kernelSize; ++x) {
 | 
			
		||||
        for (int y = -kernelSize; y <= kernelSize; ++y) {
 | 
			
		||||
            float dist2 = float(x*x + y*y);
 | 
			
		||||
            float weight = exp(-dist2 / sigma2);
 | 
			
		||||
            vec3 sample = texture(tex, uv + vec2(x, y) * texelSize).rgb;
 | 
			
		||||
            blurred += sample * weight;
 | 
			
		||||
            weightSum += weight;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return blurred / max(weightSum, 0.0001);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Edge-aware weight function to prevent halos
 | 
			
		||||
float edgeWeight(float lumaDiff, float threshold) {
 | 
			
		||||
    return 1.0 - smoothstep(0.0, threshold, abs(lumaDiff));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sigmoid function for smoother transitions
 | 
			
		||||
float sigmoid(float x, float strength) {
 | 
			
		||||
    return x * (1.0 + strength) / (1.0 + strength * abs(x));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
out vec4 FragColor;
 | 
			
		||||
in vec2 TexCoord;
 | 
			
		||||
 | 
			
		||||
uniform sampler2D InputTexture;
 | 
			
		||||
uniform float textureValue; // -100 (smooth) to 100 (enhance)
 | 
			
		||||
 | 
			
		||||
vec3 applyTexture(vec3 originalColor, vec2 uv, float textureAdj) {
 | 
			
		||||
    if (abs(textureAdj) < 0.01) return originalColor;
 | 
			
		||||
 | 
			
		||||
    vec2 texelSize = 1.0 / textureSize(InputTexture, 0);
 | 
			
		||||
    float origLuma = luminance(originalColor);
 | 
			
		||||
    
 | 
			
		||||
    // Multi-scale approach for medium frequency targeting
 | 
			
		||||
    // For texture, we want medium frequencies (not too small, not too large)
 | 
			
		||||
    float smallRadius = 2.0;   // For high frequency details
 | 
			
		||||
    float mediumRadius = 4.0;  // For medium frequency details (texture)
 | 
			
		||||
    float largeRadius = 8.0;   // For low frequency details
 | 
			
		||||
    
 | 
			
		||||
    vec3 smallBlur = gaussianBlur(InputTexture, uv, texelSize, smallRadius);
 | 
			
		||||
    vec3 mediumBlur = gaussianBlur(InputTexture, uv, texelSize, mediumRadius);
 | 
			
		||||
    vec3 largeBlur = gaussianBlur(InputTexture, uv, texelSize, largeRadius);
 | 
			
		||||
    
 | 
			
		||||
    // Extract medium frequencies (texture details)
 | 
			
		||||
    vec3 highFreq = smallBlur - mediumBlur;
 | 
			
		||||
    vec3 mediumFreq = mediumBlur - largeBlur;
 | 
			
		||||
    
 | 
			
		||||
    // Calculate local contrast for edge-aware processing
 | 
			
		||||
    float smallLuma = luminance(smallBlur);
 | 
			
		||||
    float mediumLuma = luminance(mediumBlur);
 | 
			
		||||
    float largeLuma = luminance(largeBlur);
 | 
			
		||||
    
 | 
			
		||||
    // Edge detection weights
 | 
			
		||||
    float edgeMask = edgeWeight(smallLuma - mediumLuma, 0.1);
 | 
			
		||||
    
 | 
			
		||||
    // Highlight & shadow protection
 | 
			
		||||
    float highlightProtect = 1.0 - smoothstep(0.75, 0.95, origLuma);
 | 
			
		||||
    float shadowProtect = smoothstep(0.05, 0.25, origLuma);
 | 
			
		||||
    float tonalWeight = highlightProtect * shadowProtect;
 | 
			
		||||
    
 | 
			
		||||
    // Map texture value to a perceptually balanced strength
 | 
			
		||||
    // Use non-linear mapping to match Lightroom's response curve
 | 
			
		||||
    float strength = sign(textureAdj) * pow(abs(textureAdj / 100.0), 0.8);
 | 
			
		||||
    
 | 
			
		||||
    // Apply different processing for positive vs negative values
 | 
			
		||||
    vec3 result = originalColor;
 | 
			
		||||
    if (strength > 0.0) {
 | 
			
		||||
        // Enhance texture (positive values)
 | 
			
		||||
        float enhanceFactor = strength * 1.5 * tonalWeight * edgeMask;
 | 
			
		||||
        result = originalColor + mediumFreq * enhanceFactor;
 | 
			
		||||
    } else {
 | 
			
		||||
        // Smooth texture (negative values)
 | 
			
		||||
        float smoothFactor = -strength * tonalWeight;
 | 
			
		||||
        result = mix(originalColor, mediumBlur, smoothFactor);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Apply sigmoid function for more natural transitions
 | 
			
		||||
    result = mix(originalColor, result, sigmoid(abs(strength), 0.5));
 | 
			
		||||
    
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    vec4 color = texture(InputTexture, TexCoord);
 | 
			
		||||
    color.rgb = applyTexture(color.rgb, TexCoord, textureValue);
 | 
			
		||||
    FragColor = vec4(max(color.rgb, vec3(0.0)), color.a);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										79
									
								
								shaders/vibrance.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								shaders/vibrance.frag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
#version 330 core
 | 
			
		||||
out vec4 FragColor;
 | 
			
		||||
in vec2 TexCoord;
 | 
			
		||||
 | 
			
		||||
uniform sampler2D InputTexture;
 | 
			
		||||
uniform float vibranceValue; // -100 to 100
 | 
			
		||||
 | 
			
		||||
const vec3 luminanceWeight = vec3(0.2126, 0.7152, 0.0722);
 | 
			
		||||
 | 
			
		||||
// Check if a color is potentially a skin tone (approximate)
 | 
			
		||||
float skinToneLikelihood(vec3 color) {
 | 
			
		||||
    // Simple skin tone detection - check if in common skin tone range
 | 
			
		||||
    // Based on normalized r/g ratio in RGB space
 | 
			
		||||
    float total = color.r + color.g + color.b;
 | 
			
		||||
    if (total < 0.001) return 0.0;
 | 
			
		||||
    
 | 
			
		||||
    vec3 normalized = color / total;
 | 
			
		||||
    
 | 
			
		||||
    // Detect skin tones based on red-green ratio and absolute red value
 | 
			
		||||
    bool redEnough = normalized.r > 0.35;
 | 
			
		||||
    bool redGreenRatio = normalized.r / normalized.g > 1.1 && normalized.r / normalized.g < 2.0;
 | 
			
		||||
    bool notTooBlue = normalized.b < 0.4;
 | 
			
		||||
    
 | 
			
		||||
    return (redEnough && redGreenRatio && notTooBlue) ? 1.0 - pow(normalized.b * 1.5, 2.0) : 0.0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3 applyVibrance(vec3 color, float vibrance) {
 | 
			
		||||
    float vibAmount = vibrance / 100.0; // Map to -1..1
 | 
			
		||||
    
 | 
			
		||||
    // Calculate better saturation
 | 
			
		||||
    float luma = dot(color, luminanceWeight);
 | 
			
		||||
    vec3 chroma = max(color - luma, 0.0);
 | 
			
		||||
    float sat = length(chroma) / (luma + 0.001);
 | 
			
		||||
    
 | 
			
		||||
    // Get skin tone protection factor
 | 
			
		||||
    float skinFactor = skinToneLikelihood(color);
 | 
			
		||||
    
 | 
			
		||||
    // Calculate adjustment strength based on current saturation
 | 
			
		||||
    // Less effect on already highly saturated colors
 | 
			
		||||
    float satWeight = 1.0 - smoothstep(0.2, 0.8, sat);
 | 
			
		||||
    
 | 
			
		||||
    // Apply less vibrance to skin tones
 | 
			
		||||
    float adjustmentFactor = satWeight * (1.0 - skinFactor * 0.7);
 | 
			
		||||
    
 | 
			
		||||
    // Create non-linear response curve for natural-looking adjustment
 | 
			
		||||
    float strength = vibAmount > 0.0 
 | 
			
		||||
        ? vibAmount * (1.0 - pow(sat, 2.0)) // Positive vibrance
 | 
			
		||||
        : vibAmount; // Negative vibrance (desaturation)
 | 
			
		||||
    
 | 
			
		||||
    // Fine-tune the saturation component-wise to preserve color relationships
 | 
			
		||||
    vec3 satColor = color;
 | 
			
		||||
    if (abs(vibAmount) > 0.001) {
 | 
			
		||||
        // Get distance from gray for each channel
 | 
			
		||||
        vec3 dist = color - luma;
 | 
			
		||||
        
 | 
			
		||||
        // Adjust distance based on vibrance
 | 
			
		||||
        dist *= (1.0 + strength * adjustmentFactor);
 | 
			
		||||
        
 | 
			
		||||
        // Rebuild color from luma + adjusted chroma
 | 
			
		||||
        satColor = luma + dist;
 | 
			
		||||
        
 | 
			
		||||
        // Preserve color ratios for extreme adjustments
 | 
			
		||||
        if (vibAmount > 0.5) {
 | 
			
		||||
            float maxComponent = max(satColor.r, max(satColor.g, satColor.b));
 | 
			
		||||
            if (maxComponent > 1.0) {
 | 
			
		||||
                float scale = min(1.0 / maxComponent, 2.0); // Limit scaling
 | 
			
		||||
                satColor = luma + (satColor - luma) * scale;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return satColor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    vec4 color = texture(InputTexture, TexCoord);
 | 
			
		||||
    color.rgb = applyVibrance(color.rgb, vibranceValue);
 | 
			
		||||
    FragColor = vec4(max(color.rgb, vec3(0.0)), color.a);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										158
									
								
								shaders/white_balance.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								shaders/white_balance.frag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,158 @@
 | 
			
		||||
#version 330 core
 | 
			
		||||
 | 
			
		||||
out vec4 FragColor;
 | 
			
		||||
in vec2 TexCoord;
 | 
			
		||||
 | 
			
		||||
uniform sampler2D InputTexture;
 | 
			
		||||
uniform float temperature; // Target Correlated Color Temperature (Kelvin, e.g., 1000-20000)
 | 
			
		||||
uniform float tint;        // Green-Magenta shift (-100 to +100)
 | 
			
		||||
 | 
			
		||||
// --- Constants ---
 | 
			
		||||
 | 
			
		||||
// sRGB Primaries to XYZ (D65)
 | 
			
		||||
const mat3 M_RGB_2_XYZ_D65 = mat3(
 | 
			
		||||
    0.4124564, 0.3575761, 0.1804375,
 | 
			
		||||
    0.2126729, 0.7151522, 0.0721750,
 | 
			
		||||
    0.0193339, 0.1191920, 0.9503041
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// XYZ (D65) to sRGB Primaries
 | 
			
		||||
const mat3 M_XYZ_2_RGB_D65 = mat3(
 | 
			
		||||
     3.2404542, -1.5371385, -0.4985314,
 | 
			
		||||
    -0.9692660,  1.8760108,  0.0415560,
 | 
			
		||||
     0.0556434, -0.2040259,  1.0572252
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// Standard Illuminant D65 XYZ (Normalized Y=1) - Our Target White
 | 
			
		||||
const vec3 WHITEPOINT_D65 = vec3(0.95047, 1.00000, 1.08883);
 | 
			
		||||
 | 
			
		||||
// Bradford CAT Matrices
 | 
			
		||||
const mat3 M_BRADFORD = mat3(
 | 
			
		||||
    0.8951,  0.2664, -0.1614,
 | 
			
		||||
   -0.7502,  1.7135,  0.0367,
 | 
			
		||||
    0.0389, -0.0685,  1.0296
 | 
			
		||||
);
 | 
			
		||||
const mat3 M_BRADFORD_INV = mat3(
 | 
			
		||||
    0.9869929, -0.1470543, 0.1599627,
 | 
			
		||||
    0.4323053,  0.5183603, 0.0492912,
 | 
			
		||||
   -0.0085287,  0.0400428, 0.9684867
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// --- Helper Functions ---
 | 
			
		||||
 | 
			
		||||
// Approximate Kelvin Temperature to XYZ Chromaticity (xy) -> XYZ coordinates
 | 
			
		||||
// Uses simplified polynomial fits for different temperature ranges.
 | 
			
		||||
// Note: More accurate methods often use look-up tables or spectral calculations.
 | 
			
		||||
vec3 kelvinToXYZ(float kelvin) {
 | 
			
		||||
    float temp = clamp(kelvin, 1000.0, 20000.0);
 | 
			
		||||
    float x, y;
 | 
			
		||||
 | 
			
		||||
    // Calculate xy chromaticity coordinates based on temperature
 | 
			
		||||
    // Formulas from: http://www.brucelindbloom.com/index.html?Eqn_T_to_xy.html (with slight adaptations)
 | 
			
		||||
    float t = temp;
 | 
			
		||||
    float t2 = t * t;
 | 
			
		||||
    float t3 = t2 * t;
 | 
			
		||||
 | 
			
		||||
    // Calculate x coordinate
 | 
			
		||||
    if (t >= 1000.0 && t <= 4000.0) {
 | 
			
		||||
        x = -0.2661239e9 / t3 - 0.2343589e6 / t2 + 0.8776956e3 / t + 0.179910;
 | 
			
		||||
    } else { // t > 4000.0 && t <= 25000.0
 | 
			
		||||
        x = -3.0258469e9 / t3 + 2.1070379e6 / t2 + 0.2226347e3 / t + 0.240390;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Calculate y coordinate based on x
 | 
			
		||||
    float x2 = x * x;
 | 
			
		||||
    float x3 = x2 * x;
 | 
			
		||||
    if (t >= 1000.0 && t <= 2222.0) {
 | 
			
		||||
         y = -1.1063814 * x3 - 1.34811020 * x2 + 2.18555832 * x - 0.18709;
 | 
			
		||||
    } else if (t > 2222.0 && t <= 4000.0) {
 | 
			
		||||
         y = -0.9549476 * x3 - 1.37418593 * x2 + 2.09137015 * x - 0.16748867;
 | 
			
		||||
    } else { // t > 4000.0 && t <= 25000.0
 | 
			
		||||
         y = 3.0817580 * x3 - 5.8733867 * x2 + 3.75112997 * x - 0.37001483;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Convert xyY (Y=1) to XYZ
 | 
			
		||||
    if (y < 1e-6) return vec3(0.0); // Avoid division by zero
 | 
			
		||||
    float Y = 1.0;
 | 
			
		||||
    float X = (x / y) * Y;
 | 
			
		||||
    float Z = ((1.0 - x - y) / y) * Y;
 | 
			
		||||
 | 
			
		||||
    return vec3(X, Y, Z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Apply Bradford Chromatic Adaptation Transform
 | 
			
		||||
vec3 adaptXYZ(vec3 xyzColor, vec3 sourceWhiteXYZ, vec3 destWhiteXYZ) {
 | 
			
		||||
    vec3 sourceCone = M_BRADFORD * sourceWhiteXYZ;
 | 
			
		||||
    vec3 destCone = M_BRADFORD * destWhiteXYZ;
 | 
			
		||||
 | 
			
		||||
    // Avoid division by zero if source cone response is zero
 | 
			
		||||
    // (shouldn't happen with typical white points but good practice)
 | 
			
		||||
    if (sourceCone.r < 1e-6 || sourceCone.g < 1e-6 || sourceCone.b < 1e-6) {
 | 
			
		||||
        return xyzColor; // Return original color if adaptation is impossible
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vec3 ratio = destCone / sourceCone;
 | 
			
		||||
 | 
			
		||||
    mat3 adaptationMatrix = M_BRADFORD_INV * mat3(ratio.x, 0, 0, 0, ratio.y, 0, 0, 0, ratio.z) * M_BRADFORD;
 | 
			
		||||
 | 
			
		||||
    return adaptationMatrix * xyzColor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// --- Main White Balance Function ---
 | 
			
		||||
vec3 applyWhiteBalance(vec3 linearSRGBColor, float tempK, float tintVal) {
 | 
			
		||||
 | 
			
		||||
    // 1. Convert input Linear sRGB (D65) to XYZ D65
 | 
			
		||||
    vec3 inputXYZ = M_RGB_2_XYZ_D65 * linearSRGBColor;
 | 
			
		||||
 | 
			
		||||
    // 2. Calculate the XYZ white point of the source illuminant (from Kelvin temp)
 | 
			
		||||
    // This is the white we want to adapt *FROM*
 | 
			
		||||
    vec3 sourceWhiteXYZ = kelvinToXYZ(tempK);
 | 
			
		||||
 | 
			
		||||
    // 3. Apply Bradford CAT to adapt from sourceWhiteXYZ to D65
 | 
			
		||||
    vec3 adaptedXYZ = adaptXYZ(inputXYZ, sourceWhiteXYZ, WHITEPOINT_D65);
 | 
			
		||||
 | 
			
		||||
    // 4. Convert adapted XYZ (now relative to D65) back to Linear sRGB
 | 
			
		||||
    vec3 adaptedLinearSRGB = M_XYZ_2_RGB_D65 * adaptedXYZ;
 | 
			
		||||
 | 
			
		||||
    // 5. Apply Tint adjustment (Post-CAT approximation)
 | 
			
		||||
    // This shifts color balance along a Green<->Magenta axis.
 | 
			
		||||
    // We scale RGB components slightly based on the tint value.
 | 
			
		||||
    // A common method is to affect Green opposite to Red/Blue.
 | 
			
		||||
    if (abs(tintVal) > 0.01) {
 | 
			
		||||
        // Map tint -100..100 to a scaling factor, e.g., -0.1..0.1
 | 
			
		||||
        float tintFactor = tintVal / 1000.0; // Smaller scale factor for subtle tint
 | 
			
		||||
 | 
			
		||||
        // Apply scaling: Increase G for negative tint, Decrease G for positive tint
 | 
			
		||||
        // Compensate R and B slightly in the opposite direction.
 | 
			
		||||
        // Coefficients below are heuristic and may need tuning for perceptual feel.
 | 
			
		||||
        float rScale = 1.0 + tintFactor * 0.5;
 | 
			
		||||
        float gScale = 1.0 - tintFactor * 1.0;
 | 
			
		||||
        float bScale = 1.0 + tintFactor * 0.5;
 | 
			
		||||
 | 
			
		||||
        vec3 tintScaleVec = vec3(rScale, gScale, bScale);
 | 
			
		||||
 | 
			
		||||
        // Optional: Normalize scale vector to preserve luminance (roughly)
 | 
			
		||||
        // Calculate luminance of the scale vector itself
 | 
			
		||||
        float scaleLum = dot(tintScaleVec, vec3(0.2126, 0.7152, 0.0722));
 | 
			
		||||
        if (scaleLum > 1e-5) {
 | 
			
		||||
           tintScaleVec /= scaleLum; // Normalize
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        adaptedLinearSRGB *= tintScaleVec;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return adaptedLinearSRGB;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    vec4 texColor = texture(InputTexture, TexCoord);
 | 
			
		||||
    vec3 linearInputColor = texColor.rgb; // Assuming input texture is already linear sRGB
 | 
			
		||||
 | 
			
		||||
    // Calculate white balanced color
 | 
			
		||||
    vec3 whiteBalancedColor = applyWhiteBalance(linearInputColor, temperature, tint);
 | 
			
		||||
 | 
			
		||||
    // Ensure output is non-negative
 | 
			
		||||
    whiteBalancedColor = max(whiteBalancedColor, vec3(0.0));
 | 
			
		||||
 | 
			
		||||
    FragColor = vec4(whiteBalancedColor, texColor.a);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								shaders/whites_blacks.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								shaders/whites_blacks.frag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
#version 330 core
 | 
			
		||||
out vec4 FragColor;
 | 
			
		||||
in vec2 TexCoord;
 | 
			
		||||
 | 
			
		||||
uniform sampler2D InputTexture;
 | 
			
		||||
uniform float whitesValue; // -100 (pull down) to 100 (push up)
 | 
			
		||||
uniform float blacksValue; // -100 (lift up) to 100 (push down)
 | 
			
		||||
 | 
			
		||||
const vec3 luminanceWeight = vec3(0.2126, 0.7152, 0.0722);
 | 
			
		||||
 | 
			
		||||
// Helper function to preserve color relationships when adjusting luminance
 | 
			
		||||
vec3 preserveColor(vec3 color, float newLum) {
 | 
			
		||||
    float oldLum = dot(color, luminanceWeight);
 | 
			
		||||
    return oldLum > 0.0 ? color * (newLum / oldLum) : vec3(newLum);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3 applyWhitesBlacks(vec3 color, float whites, float blacks) {
 | 
			
		||||
    float lum = dot(color, luminanceWeight);
 | 
			
		||||
    
 | 
			
		||||
    // Map slider values to more appropriate adjustment strengths
 | 
			
		||||
    float whitesStrength = whites / 100.0;
 | 
			
		||||
    float blacksStrength = blacks / 100.0;
 | 
			
		||||
    
 | 
			
		||||
    // Create better perceptual masks with wider, smoother influence
 | 
			
		||||
    // Whites affect primarily highlights but have some influence into midtones
 | 
			
		||||
    float whiteMask = smoothstep(0.25, 1.0, lum);
 | 
			
		||||
    whiteMask = pow(whiteMask, 2.0 - max(0.0, whitesStrength)); // Dynamic falloff
 | 
			
		||||
    
 | 
			
		||||
    // Blacks affect primarily shadows but have some influence into midtones
 | 
			
		||||
    float blackMask = 1.0 - smoothstep(0.0, 0.5, lum);
 | 
			
		||||
    blackMask = pow(blackMask, 2.0 - max(0.0, -blacksStrength)); // Dynamic falloff
 | 
			
		||||
    
 | 
			
		||||
    // Calculate adjustment curves with proper toe/shoulder response
 | 
			
		||||
    float whitesAdj = 1.0 + whitesStrength * whiteMask * (1.0 - pow(1.0 - whiteMask, 3.0));
 | 
			
		||||
    float blacksAdj = 1.0 - blacksStrength * blackMask * (1.0 - pow(1.0 - blackMask, 3.0));
 | 
			
		||||
    
 | 
			
		||||
    // Apply adjustments with color preservation
 | 
			
		||||
    float adjustedLum = lum * whitesAdj * blacksAdj;
 | 
			
		||||
    adjustedLum = clamp(adjustedLum, 0.0, 2.0); // Allow some headroom for highlights
 | 
			
		||||
    
 | 
			
		||||
    // Preserve color relationships by scaling RGB proportionally
 | 
			
		||||
    vec3 result = preserveColor(color, adjustedLum);
 | 
			
		||||
    
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
    vec4 color = texture(InputTexture, TexCoord);
 | 
			
		||||
    color.rgb = applyWhitesBlacks(color.rgb, whitesValue, blacksValue);
 | 
			
		||||
    FragColor = vec4(max(color.rgb, vec3(0.0)), color.a); // Ensure non-negative
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								shaderutils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								shaderutils.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
// shader_utils.h
 | 
			
		||||
#ifndef SHADER_UTILS_H
 | 
			
		||||
#define SHADER_UTILS_H
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
 | 
			
		||||
#include <SDL_opengles2.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <GL/glew.h>
 | 
			
		||||
#include <SDL_opengl.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
GLuint LoadShaderProgram(const std::string& vsSource, const std::string& fsSource);
 | 
			
		||||
GLuint LoadShaderProgramFromFiles(const std::string& vsPath, const std::string& fsPath);
 | 
			
		||||
 | 
			
		||||
#endif // SHADER_UTILS_H
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
// Function to compile a shader
 | 
			
		||||
GLuint CompileShader(GLenum type, const std::string& source) {
 | 
			
		||||
    GLuint shader = glCreateShader(type);
 | 
			
		||||
    const char* src = source.c_str();
 | 
			
		||||
    glShaderSource(shader, 1, &src, nullptr);
 | 
			
		||||
    glCompileShader(shader);
 | 
			
		||||
 | 
			
		||||
    GLint success;
 | 
			
		||||
    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
 | 
			
		||||
    if (!success) {
 | 
			
		||||
        GLint logLength;
 | 
			
		||||
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
 | 
			
		||||
        std::vector<char> log(logLength);
 | 
			
		||||
        glGetShaderInfoLog(shader, logLength, nullptr, log.data());
 | 
			
		||||
        std::cerr << "ERROR::SHADER::COMPILATION_FAILED\n" << (type == GL_VERTEX_SHADER ? "Vertex" : "Fragment") << "\n" << log.data() << std::endl;
 | 
			
		||||
        glDeleteShader(shader);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    return shader;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Function to link shaders into a program
 | 
			
		||||
GLuint LinkProgram(GLuint vertexShader, GLuint fragmentShader) {
 | 
			
		||||
    GLuint program = glCreateProgram();
 | 
			
		||||
    glAttachShader(program, vertexShader);
 | 
			
		||||
    glAttachShader(program, fragmentShader);
 | 
			
		||||
    glLinkProgram(program);
 | 
			
		||||
 | 
			
		||||
    GLint success;
 | 
			
		||||
    glGetProgramiv(program, GL_LINK_STATUS, &success);
 | 
			
		||||
    if (!success) {
 | 
			
		||||
        GLint logLength;
 | 
			
		||||
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
 | 
			
		||||
        std::vector<char> log(logLength);
 | 
			
		||||
        glGetProgramInfoLog(program, logLength, nullptr, log.data());
 | 
			
		||||
        std::cerr << "ERROR::PROGRAM::LINKING_FAILED\n" << log.data() << std::endl;
 | 
			
		||||
        glDeleteProgram(program);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    return program;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
GLuint LoadShaderProgram(const std::string& vsSource, const std::string& fsSource) {
 | 
			
		||||
    GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
 | 
			
		||||
    if (!vs) return 0;
 | 
			
		||||
    GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
 | 
			
		||||
    if (!fs) { glDeleteShader(vs); return 0; }
 | 
			
		||||
 | 
			
		||||
    GLuint program = LinkProgram(vs, fs);
 | 
			
		||||
 | 
			
		||||
    // Shaders can be deleted after linking
 | 
			
		||||
    glDeleteShader(vs);
 | 
			
		||||
    glDeleteShader(fs);
 | 
			
		||||
 | 
			
		||||
    return program;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
std::string ReadFile(const std::string& path) {
 | 
			
		||||
    std::ifstream file(path);
 | 
			
		||||
    if (!file) {
 | 
			
		||||
        std::cerr << "Error opening file: " << path << std::endl;
 | 
			
		||||
        return "";
 | 
			
		||||
    }
 | 
			
		||||
    std::stringstream buffer;
 | 
			
		||||
    buffer << file.rdbuf();
 | 
			
		||||
    return buffer.str();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GLuint LoadShaderProgramFromFiles(const std::string& vsPath, const std::string& fsPath) {
 | 
			
		||||
     std::string vsSource = ReadFile(vsPath);
 | 
			
		||||
     std::string fsSource = ReadFile(fsPath);
 | 
			
		||||
     if (vsSource.empty() || fsSource.empty()) {
 | 
			
		||||
         return 0;
 | 
			
		||||
     }
 | 
			
		||||
     return LoadShaderProgram(vsSource, fsSource);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										720
									
								
								tex_inspect_opengl.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										720
									
								
								tex_inspect_opengl.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,720 @@
 | 
			
		||||
// ImGuiTexInspect, a texture inspector widget for dear imgui
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
 | 
			
		||||
#define _CRT_SECURE_NO_WARNINGS
 | 
			
		||||
#endif
 | 
			
		||||
#if defined EMSCRIPTEN && defined IMGUI_TEX_INSPECT_FLOAT_READ_ENABLED
 | 
			
		||||
#warning "Float texture read back is disabled on Emscripten"
 | 
			
		||||
#undef IMGUI_TEX_INSPECT_FLOAT_READ_ENABLED
 | 
			
		||||
#endif
 | 
			
		||||
#include "imgui_tex_inspect_internal.h"
 | 
			
		||||
 | 
			
		||||
// ==========================================================================
 | 
			
		||||
// This file is largely based on:
 | 
			
		||||
// https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_opengl3.cpp
 | 
			
		||||
//
 | 
			
		||||
// In the following section the ImGui_ImplOpenGL3_Init function has been 
 | 
			
		||||
// changed to not rewrite global ImGui state.  It has also been wrapped in a 
 | 
			
		||||
// namespace to not clash with the main ImGui version.  Aside from that this 
 | 
			
		||||
// section is identical to the imgui original.
 | 
			
		||||
//
 | 
			
		||||
// It's reproduced here because none of this code is exposed in the ImGui API
 | 
			
		||||
// in a way that be reused (nor should it be).
 | 
			
		||||
//
 | 
			
		||||
// Search for "END COPIED" to find the end of the copied segment.
 | 
			
		||||
// ===========================================================================
 | 
			
		||||
 | 
			
		||||
// COPIED FROM imgui_impl_opengl3.cp  ////////////////////////////////////////
 | 
			
		||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
 | 
			
		||||
#define _CRT_SECURE_NO_WARNINGS
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "imgui.h"
 | 
			
		||||
#include "imgui_impl_opengl3.h"
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
 | 
			
		||||
#include <stddef.h>     // intptr_t
 | 
			
		||||
#else
 | 
			
		||||
#include <stdint.h>     // intptr_t
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// GL includes
 | 
			
		||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
 | 
			
		||||
#include <GLES2/gl2.h>
 | 
			
		||||
#elif defined(IMGUI_IMPL_OPENGL_ES3)
 | 
			
		||||
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
 | 
			
		||||
#include <OpenGLES/ES3/gl.h>    // Use GL ES 3
 | 
			
		||||
#else
 | 
			
		||||
#include <GLES3/gl3.h>          // Use GL ES 3
 | 
			
		||||
#endif
 | 
			
		||||
#else
 | 
			
		||||
// About Desktop OpenGL function loaders:
 | 
			
		||||
//  Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
 | 
			
		||||
//  Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
 | 
			
		||||
//  You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
 | 
			
		||||
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
 | 
			
		||||
#include <GL/gl3w.h>            // Needs to be initialized with gl3wInit() in user's code
 | 
			
		||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
 | 
			
		||||
#include <GL/glew.h>            // Needs to be initialized with glewInit() in user's code.
 | 
			
		||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
 | 
			
		||||
#include <glad/glad.h>          // Needs to be initialized with gladLoadGL() in user's code.
 | 
			
		||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
 | 
			
		||||
#include <glad/gl.h>            // Needs to be initialized with gladLoadGL(...) or gladLoaderLoadGL() in user's code.
 | 
			
		||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
 | 
			
		||||
#ifndef GLFW_INCLUDE_NONE
 | 
			
		||||
#define GLFW_INCLUDE_NONE       // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
 | 
			
		||||
#endif
 | 
			
		||||
#include <glbinding/Binding.h>  // Needs to be initialized with glbinding::Binding::initialize() in user's code.
 | 
			
		||||
#include <glbinding/gl/gl.h>
 | 
			
		||||
using namespace gl;
 | 
			
		||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
 | 
			
		||||
#ifndef GLFW_INCLUDE_NONE
 | 
			
		||||
#define GLFW_INCLUDE_NONE       // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
 | 
			
		||||
#endif
 | 
			
		||||
#include <glbinding/glbinding.h>// Needs to be initialized with glbinding::initialize() in user's code.
 | 
			
		||||
#include <glbinding/gl/gl.h>
 | 
			
		||||
using namespace gl;
 | 
			
		||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_EPOXY)
 | 
			
		||||
#include <epoxy/gl.h>
 | 
			
		||||
#else
 | 
			
		||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
 | 
			
		||||
#include <SDL_opengles2.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <SDL_opengl.h>
 | 
			
		||||
#include <SDL2/SDL_opengl.h>
 | 
			
		||||
#include <SDL2/SDL_opengles2.h>
 | 
			
		||||
#include <SDL2/SDL_opengles2_gl2.h>
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
 | 
			
		||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_2)
 | 
			
		||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Desktop GL 3.3+ has glBindSampler()
 | 
			
		||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_3)
 | 
			
		||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state
 | 
			
		||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1)
 | 
			
		||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace imgui_impl_opengl
 | 
			
		||||
{
 | 
			
		||||
// OpenGL Data
 | 
			
		||||
static GLuint       g_GlVersion = 0;                // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
 | 
			
		||||
static char         g_GlslVersionString[32] = "";   // Specified by user or detected based on compile time GL settings.
 | 
			
		||||
static GLuint       g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
 | 
			
		||||
static GLint        g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0;                                // Uniforms location
 | 
			
		||||
static GLuint       g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0; // Vertex attributes location
 | 
			
		||||
static GLint        g_UniformLocationForceNearestSampling = 0;
 | 
			
		||||
static GLint        g_UniformLocationGridWidth = 0;
 | 
			
		||||
 | 
			
		||||
// Functions
 | 
			
		||||
static bool    ImGui_ImplOpenGL3_Init(const char* glsl_version)
 | 
			
		||||
{
 | 
			
		||||
    // Query for GL version (e.g. 320 for GL 3.2)
 | 
			
		||||
#if !defined(IMGUI_IMPL_OPENGL_ES2)
 | 
			
		||||
    GLint major = 0;
 | 
			
		||||
    GLint minor = 0;
 | 
			
		||||
    glGetIntegerv(GL_MAJOR_VERSION, &major);
 | 
			
		||||
    glGetIntegerv(GL_MINOR_VERSION, &minor);
 | 
			
		||||
    if (major == 0 && minor == 0)
 | 
			
		||||
    {
 | 
			
		||||
        // Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
 | 
			
		||||
        const char* gl_version = (const char*)glGetString(GL_VERSION);
 | 
			
		||||
        sscanf(gl_version, "%d.%d", &major, &minor);
 | 
			
		||||
    }
 | 
			
		||||
    g_GlVersion = (GLuint)(major * 100 + minor * 10);
 | 
			
		||||
#else
 | 
			
		||||
    g_GlVersion = 200; // GLES 2
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Store GLSL version string so we can refer to it later in case we recreate shaders.
 | 
			
		||||
    // Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
 | 
			
		||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
 | 
			
		||||
    if (glsl_version == NULL)
 | 
			
		||||
        glsl_version = "#version 100";
 | 
			
		||||
#elif defined(IMGUI_IMPL_OPENGL_ES3)
 | 
			
		||||
    if (glsl_version == NULL)
 | 
			
		||||
        glsl_version = "#version 300 es";
 | 
			
		||||
#elif defined(__APPLE__)
 | 
			
		||||
    if (glsl_version == NULL)
 | 
			
		||||
        glsl_version = "#version 150";
 | 
			
		||||
#else
 | 
			
		||||
    if (glsl_version == NULL)
 | 
			
		||||
        glsl_version = "#version 130";
 | 
			
		||||
#endif
 | 
			
		||||
    IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));
 | 
			
		||||
    strcpy(g_GlslVersionString, glsl_version);
 | 
			
		||||
    strcat(g_GlslVersionString, "\n");
 | 
			
		||||
 | 
			
		||||
    // Debugging construct to make it easily visible in the IDE and debugger which GL loader has been selected.
 | 
			
		||||
    // The code actually never uses the 'gl_loader' variable! It is only here so you can read it!
 | 
			
		||||
    // If auto-detection fails or doesn't select the same GL loader file as used by your application,
 | 
			
		||||
    // you are likely to get a crash below.
 | 
			
		||||
    // You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
 | 
			
		||||
    const char* gl_loader = "Unknown";
 | 
			
		||||
    IM_UNUSED(gl_loader);
 | 
			
		||||
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
 | 
			
		||||
    gl_loader = "GL3W";
 | 
			
		||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
 | 
			
		||||
    gl_loader = "GLEW";
 | 
			
		||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
 | 
			
		||||
    gl_loader = "GLAD";
 | 
			
		||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
 | 
			
		||||
    gl_loader = "GLAD2";
 | 
			
		||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
 | 
			
		||||
    gl_loader = "glbinding2";
 | 
			
		||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
 | 
			
		||||
    gl_loader = "glbinding3";
 | 
			
		||||
#elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
 | 
			
		||||
    gl_loader = "custom";
 | 
			
		||||
#else
 | 
			
		||||
    gl_loader = "none";
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // Make an arbitrary GL call (we don't actually need the result)
 | 
			
		||||
    // IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.
 | 
			
		||||
    // Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.
 | 
			
		||||
    GLint current_texture;
 | 
			
		||||
    glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ===========================================================================
 | 
			
		||||
//  COPIED FROM A DIFFERENT PART OF imgui_impl_opengl3.cpp
 | 
			
		||||
// ===========================================================================
 | 
			
		||||
 | 
			
		||||
// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
 | 
			
		||||
static bool CheckShader(GLuint handle, const char* desc)
 | 
			
		||||
{
 | 
			
		||||
    GLint status = 0, log_length = 0;
 | 
			
		||||
    glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
 | 
			
		||||
    glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
 | 
			
		||||
    if ((GLboolean)status == GL_FALSE)
 | 
			
		||||
        fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
 | 
			
		||||
    if (log_length > 1)
 | 
			
		||||
    {
 | 
			
		||||
        ImVector<char> buf;
 | 
			
		||||
        buf.resize((int)(log_length + 1));
 | 
			
		||||
        glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
 | 
			
		||||
        fprintf(stderr, "%s\n", buf.begin());
 | 
			
		||||
    }
 | 
			
		||||
    return (GLboolean)status == GL_TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
 | 
			
		||||
static bool CheckProgram(GLuint handle, const char* desc)
 | 
			
		||||
{
 | 
			
		||||
    GLint status = 0, log_length = 0;
 | 
			
		||||
    glGetProgramiv(handle, GL_LINK_STATUS, &status);
 | 
			
		||||
    glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
 | 
			
		||||
    if ((GLboolean)status == GL_FALSE)
 | 
			
		||||
        fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString);
 | 
			
		||||
    if (log_length > 1)
 | 
			
		||||
    {
 | 
			
		||||
        ImVector<char> buf;
 | 
			
		||||
        buf.resize((int)(log_length + 1));
 | 
			
		||||
        glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());
 | 
			
		||||
        fprintf(stderr, "%s\n", buf.begin());
 | 
			
		||||
    }
 | 
			
		||||
    return (GLboolean)status == GL_TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height)
 | 
			
		||||
{
 | 
			
		||||
    // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
 | 
			
		||||
    glEnable(GL_BLEND);
 | 
			
		||||
    glBlendEquation(GL_FUNC_ADD);
 | 
			
		||||
    glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
 | 
			
		||||
    glDisable(GL_CULL_FACE);
 | 
			
		||||
    glDisable(GL_DEPTH_TEST);
 | 
			
		||||
    glDisable(GL_STENCIL_TEST);
 | 
			
		||||
    glEnable(GL_SCISSOR_TEST);
 | 
			
		||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
 | 
			
		||||
    if (g_GlVersion >= 310)
 | 
			
		||||
        glDisable(GL_PRIMITIVE_RESTART);
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef GL_POLYGON_MODE
 | 
			
		||||
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
 | 
			
		||||
#if defined(GL_CLIP_ORIGIN)
 | 
			
		||||
    bool clip_origin_lower_left = true;
 | 
			
		||||
    if (g_GlVersion >= 450)
 | 
			
		||||
    {
 | 
			
		||||
        GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin);
 | 
			
		||||
        if (current_clip_origin == GL_UPPER_LEFT)
 | 
			
		||||
            clip_origin_lower_left = false;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    // Setup viewport, orthographic projection matrix
 | 
			
		||||
    // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
 | 
			
		||||
    glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
 | 
			
		||||
    float L = draw_data->DisplayPos.x;
 | 
			
		||||
    float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
 | 
			
		||||
    float T = draw_data->DisplayPos.y;
 | 
			
		||||
    float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
 | 
			
		||||
#if defined(GL_CLIP_ORIGIN)
 | 
			
		||||
    if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
 | 
			
		||||
#endif
 | 
			
		||||
    const float ortho_projection[4][4] =
 | 
			
		||||
    {
 | 
			
		||||
        { 2.0f/(R-L),   0.0f,         0.0f,   0.0f },
 | 
			
		||||
        { 0.0f,         2.0f/(T-B),   0.0f,   0.0f },
 | 
			
		||||
        { 0.0f,         0.0f,        -1.0f,   0.0f },
 | 
			
		||||
        { (R+L)/(L-R),  (T+B)/(B-T),  0.0f,   1.0f },
 | 
			
		||||
    };
 | 
			
		||||
    glUseProgram(g_ShaderHandle);
 | 
			
		||||
    glUniform1i(g_AttribLocationTex, 0);
 | 
			
		||||
    glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
 | 
			
		||||
    // if (g_GlVersion >= 330)
 | 
			
		||||
    //     glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    glEnableVertexAttribArray(g_AttribLocationVtxPos);
 | 
			
		||||
    glEnableVertexAttribArray(g_AttribLocationVtxUV);
 | 
			
		||||
    //glEnableVertexAttribArray(g_AttribLocationVtxColor); //Our shader doesn't use vertex color
 | 
			
		||||
    glVertexAttribPointer(g_AttribLocationVtxPos,   2, GL_FLOAT,         GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
 | 
			
		||||
    glVertexAttribPointer(g_AttribLocationVtxUV,    2, GL_FLOAT,         GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
 | 
			
		||||
    //glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE,  sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ===========================================================================
 | 
			
		||||
//  END COPIED FROM imgui_impl_opengl3.cpp 
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
//  Note that a lot of the following code still orginated in 
 | 
			
		||||
//  imgui_impl_opengl3.cpp but there are more changes from here on.
 | 
			
		||||
// ===========================================================================
 | 
			
		||||
 | 
			
		||||
// New uniforms for ImGuiTexInspect fragment shader
 | 
			
		||||
static GLint g_UniformLocationTextureSize;
 | 
			
		||||
static GLint g_UniformLocationColorTransform;
 | 
			
		||||
static GLint g_UniformLocationColorOffset;
 | 
			
		||||
static GLint g_UniformLocationBackgroundColor;
 | 
			
		||||
static GLint g_UniformLocationPremultiplyAlpha;
 | 
			
		||||
static GLint g_UniformLocationDisableFinalAlpha;
 | 
			
		||||
static GLint g_UniformLocationGrid;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//  Vertex shaders are directly from imgui_impl_opengl3.cpp
 | 
			
		||||
const GLchar* vertex_shader_glsl_120 =
 | 
			
		||||
    "uniform mat4 ProjMtx;\n"
 | 
			
		||||
    "attribute vec2 Position;\n"
 | 
			
		||||
    "attribute vec2 UV;\n"
 | 
			
		||||
    "attribute vec4 Color;\n"
 | 
			
		||||
    "varying vec2 Frag_UV;\n"
 | 
			
		||||
    "varying vec4 Frag_Color;\n"
 | 
			
		||||
    "void main()\n"
 | 
			
		||||
    "{\n"
 | 
			
		||||
    "    Frag_UV = UV;\n"
 | 
			
		||||
    "    Frag_Color = Color;\n"
 | 
			
		||||
    "    gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
 | 
			
		||||
const GLchar* vertex_shader_glsl_130 =
 | 
			
		||||
    "uniform mat4 ProjMtx;\n"
 | 
			
		||||
    "in vec2 Position;\n"  
 | 
			
		||||
    "in vec2 UV;\n"
 | 
			
		||||
    "in vec4 Color;\n"
 | 
			
		||||
    "out vec2 Frag_UV;\n"
 | 
			
		||||
    "out vec4 Frag_Color;\n"
 | 
			
		||||
    "void main()\n"
 | 
			
		||||
    "{\n"
 | 
			
		||||
    "    Frag_UV = UV;\n"
 | 
			
		||||
    "    Frag_Color = Color;\n"
 | 
			
		||||
    "    gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
 | 
			
		||||
const GLchar* vertex_shader_glsl_300_es =
 | 
			
		||||
    "precision mediump float;\n"
 | 
			
		||||
    "layout (location = 0) in vec2 Position;\n"
 | 
			
		||||
    "layout (location = 1) in vec2 UV;\n"
 | 
			
		||||
    "layout (location = 2) in vec4 Color;\n"
 | 
			
		||||
    "uniform mat4 ProjMtx;\n"
 | 
			
		||||
    "out vec2 Frag_UV;\n"
 | 
			
		||||
    "out vec4 Frag_Color;\n"
 | 
			
		||||
    "void main()\n"
 | 
			
		||||
    "{\n"
 | 
			
		||||
    "    Frag_UV = UV;\n"
 | 
			
		||||
    "    Frag_Color = Color;\n"
 | 
			
		||||
    "    gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
 | 
			
		||||
const GLchar* vertex_shader_glsl_410_core =
 | 
			
		||||
    "layout (location = 0) in vec2 Position;\n"
 | 
			
		||||
    "layout (location = 1) in vec2 UV;\n"
 | 
			
		||||
    "layout (location = 2) in vec4 Color;\n"
 | 
			
		||||
    "uniform mat4 ProjMtx;\n"
 | 
			
		||||
    "out vec2 Frag_UV;\n"
 | 
			
		||||
    "out vec4 Frag_Color;\n"
 | 
			
		||||
    "void main()\n"
 | 
			
		||||
    "{\n"
 | 
			
		||||
    "    Frag_UV = UV;\n"
 | 
			
		||||
    "    Frag_Color = Color;\n"
 | 
			
		||||
    "    gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] IMGUI_TEX_INSPECT FRAGMENT SHADERS
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
const GLchar *fragment_shader_glsl_120 = "#ifdef GL_ES\n"
 | 
			
		||||
                                         "   precision mediump float;\n"
 | 
			
		||||
                                         "#endif\n"
 | 
			
		||||
                                         "uniform sampler2D Texture;\n"
 | 
			
		||||
                                         "uniform vec2 TextureSize;\n"
 | 
			
		||||
                                         "uniform mat4 ColorTransform;\n"
 | 
			
		||||
                                         "uniform vec4 ColorOffset;\n"
 | 
			
		||||
                                         "uniform vec3 BackgroundColor;\n"
 | 
			
		||||
                                         "uniform float PremultiplyAlpha;\n"
 | 
			
		||||
                                         "uniform float DisableFinalAlpha;\n"
 | 
			
		||||
                                         "uniform bool ForceNearestSampling;\n"
 | 
			
		||||
                                         "uniform vec4 Grid;\n"
 | 
			
		||||
                                         "uniform vec2 GridWidth;\n"
 | 
			
		||||
                                         "varying vec2 Frag_UV;\n"
 | 
			
		||||
                                         "void main()\n"
 | 
			
		||||
                                         "{\n"
 | 
			
		||||
                                         "    vec2 uv;\n"
 | 
			
		||||
                                         "    vec2 texel = Frag_UV * TextureSize;\n"
 | 
			
		||||
                                         "    if (ForceNearestSampling)\n"
 | 
			
		||||
                                         "        uv = (floor(texel) + vec2(0.5,0.5)) / TextureSize;\n"
 | 
			
		||||
                                         "    else\n"
 | 
			
		||||
                                         "        uv = Frag_UV;\n"
 | 
			
		||||
                                         "    vec2 texelEdge = step(mod(texel,vec2(1.0,1.0)),GridWidth);\n"
 | 
			
		||||
                                         "    float isGrid = max(texelEdge.x, texelEdge.y);\n"
 | 
			
		||||
                                         "    vec4 ct = ColorTransform * texture2D(Texture, uv) + ColorOffset;\n"
 | 
			
		||||
                                         "    ct.rgb = ct.rgb * mix(1.0, ct.a, PremultiplyAlpha);\n"
 | 
			
		||||
                                         "    ct.rgb += BackgroundColor * (1.0-ct.a);\n"
 | 
			
		||||
                                         "    ct.a = mix(ct.a, 1.0, DisableFinalAlpha);\n"
 | 
			
		||||
                                         "    ct = mix(ct, vec4(Grid.rgb,1), Grid.a * isGrid);\n"
 | 
			
		||||
                                         "    gl_FragColor = ct;\n"
 | 
			
		||||
                                         "}\n";
 | 
			
		||||
 | 
			
		||||
const GLchar *fragment_shader_glsl_130 = "uniform sampler2D Texture;\n"
 | 
			
		||||
                                         "uniform vec2 TextureSize;\n"
 | 
			
		||||
                                         "uniform mat4 ColorTransform;\n"
 | 
			
		||||
                                         "uniform vec4 ColorOffset;\n"
 | 
			
		||||
                                         "uniform vec3 BackgroundColor;\n"
 | 
			
		||||
                                         "uniform float PremultiplyAlpha;\n"
 | 
			
		||||
                                         "uniform float DisableFinalAlpha;\n"
 | 
			
		||||
                                         "uniform bool ForceNearestSampling;\n"
 | 
			
		||||
                                         "uniform vec4 Grid;\n"
 | 
			
		||||
                                         "uniform vec2 GridWidth;\n"
 | 
			
		||||
                                         "in vec2 Frag_UV;\n"
 | 
			
		||||
                                         "out vec4 Out_Color;\n"
 | 
			
		||||
                                         "void main()\n"
 | 
			
		||||
                                         "{\n"
 | 
			
		||||
                                         "    vec2 uv;\n"
 | 
			
		||||
                                         "    vec2 texel = Frag_UV * TextureSize;\n"
 | 
			
		||||
                                         "    if (ForceNearestSampling)\n"
 | 
			
		||||
                                         "        uv = (floor(texel) + vec2(0.5,0.5)) / TextureSize;\n"
 | 
			
		||||
                                         "    else\n"
 | 
			
		||||
                                         "        uv = Frag_UV;\n"
 | 
			
		||||
                                         "    vec2 texelEdge = step(mod(texel,vec2(1.0,1.0)),GridWidth);\n"
 | 
			
		||||
                                         "    float isGrid = max(texelEdge.x, texelEdge.y);\n"
 | 
			
		||||
                                         "    vec4 ct = ColorTransform * texture(Texture, uv) + ColorOffset;\n"
 | 
			
		||||
                                         "    ct.rgb = ct.rgb * mix(1.0, ct.a, PremultiplyAlpha);\n"
 | 
			
		||||
                                         "    ct.rgb += BackgroundColor * (1.0-ct.a);\n"
 | 
			
		||||
                                         "    ct.a = mix(ct.a, 1.0, DisableFinalAlpha);\n"
 | 
			
		||||
                                         "    ct = mix(ct, vec4(Grid.rgb,1), Grid.a * isGrid);\n"
 | 
			
		||||
                                         "    Out_Color = ct;\n"
 | 
			
		||||
                                         "}\n";
 | 
			
		||||
 | 
			
		||||
const GLchar *fragment_shader_glsl_300_es = "precision mediump float;\n"
 | 
			
		||||
                                            "uniform sampler2D Texture;\n"
 | 
			
		||||
                                            "uniform vec2 TextureSize;\n"
 | 
			
		||||
                                            "uniform mat4 ColorTransform;\n"
 | 
			
		||||
                                            "uniform vec4 ColorOffset;\n"
 | 
			
		||||
                                            "uniform vec3 BackgroundColor;\n"
 | 
			
		||||
                                            "uniform float PremultiplyAlpha;\n"
 | 
			
		||||
                                            "uniform float DisableFinalAlpha;\n"
 | 
			
		||||
                                            "uniform bool ForceNearestSampling;\n"
 | 
			
		||||
                                            "uniform vec4 Grid;\n"
 | 
			
		||||
                                            "uniform vec2 GridWidth;\n"
 | 
			
		||||
                                            "in vec2 Frag_UV;\n"
 | 
			
		||||
                                            "layout (location = 0) out vec4 Out_Color;\n"
 | 
			
		||||
                                            "void main()\n"
 | 
			
		||||
                                            "{\n"
 | 
			
		||||
                                            "    vec2 uv;\n"
 | 
			
		||||
                                            "    vec2 texel = Frag_UV * TextureSize;\n"
 | 
			
		||||
                                            "    if (ForceNearestSampling)\n"
 | 
			
		||||
                                            "        uv = (floor(texel) + vec2(0.5,0.5)) / TextureSize;\n"
 | 
			
		||||
                                            "    else\n"
 | 
			
		||||
                                            "        uv = Frag_UV;\n"
 | 
			
		||||
                                            "    vec2 texelEdge = step(mod(texel,vec2(1.0,1.0)),GridWidth);\n"
 | 
			
		||||
                                            "    float isGrid = max(texelEdge.x, texelEdge.y);\n"
 | 
			
		||||
                                            "    vec4 ct = ColorTransform * texture(Texture, uv) + ColorOffset;\n"
 | 
			
		||||
                                            "    ct.rgb = ct.rgb * mix(1.0, ct.a, PremultiplyAlpha);\n"
 | 
			
		||||
                                            "    ct.rgb += BackgroundColor * (1.0-ct.a);\n"
 | 
			
		||||
                                            "    ct.a = mix(ct.a, 1.0, DisableFinalAlpha);\n"
 | 
			
		||||
                                            "    ct = mix(ct, vec4(Grid.rgb,1), Grid.a * isGrid);\n"
 | 
			
		||||
                                            "    Out_Color = ct;\n"
 | 
			
		||||
                                            "}\n";
 | 
			
		||||
 | 
			
		||||
const GLchar *fragment_shader_glsl_410_core = "uniform sampler2D Texture;\n"
 | 
			
		||||
                                              "uniform vec2 TextureSize;\n"
 | 
			
		||||
                                              "uniform mat4 ColorTransform;\n"
 | 
			
		||||
                                              "uniform vec4 ColorOffset;\n"
 | 
			
		||||
                                              "uniform vec3 BackgroundColor;\n"
 | 
			
		||||
                                              "uniform float PremultiplyAlpha;\n"
 | 
			
		||||
                                              "uniform float DisableFinalAlpha;\n"
 | 
			
		||||
                                              "uniform bool ForceNearestSampling;\n"
 | 
			
		||||
                                              "uniform vec4 Grid;\n"
 | 
			
		||||
                                              "uniform vec2 GridWidth;\n"
 | 
			
		||||
                                              "in vec2 Frag_UV;\n"
 | 
			
		||||
                                              "layout (location = 0) out vec4 Out_Color;\n"
 | 
			
		||||
                                              "void main()\n"
 | 
			
		||||
                                              "{\n"
 | 
			
		||||
                                              "    vec2 uv;\n"
 | 
			
		||||
                                              "    vec2 texel = Frag_UV * TextureSize;\n"
 | 
			
		||||
                                              "    if (ForceNearestSampling)\n"
 | 
			
		||||
                                              "        uv = (floor(texel) + vec2(0.5,0.5)) / TextureSize;\n"
 | 
			
		||||
                                              "    else\n"
 | 
			
		||||
                                              "        uv = Frag_UV;\n"
 | 
			
		||||
                                              "    vec2 texelEdge = step(mod(texel,vec2(1.0,1.0)),GridWidth);\n"
 | 
			
		||||
                                              "    float isGrid = max(texelEdge.x, texelEdge.y);\n"
 | 
			
		||||
                                              "    vec4 ct = ColorTransform * texture(Texture, uv) + ColorOffset;\n"
 | 
			
		||||
                                              "    ct.rgb = ct.rgb * mix(1.0, ct.a, PremultiplyAlpha);\n"
 | 
			
		||||
                                              "    ct.rgb += BackgroundColor * (1.0-ct.a);\n"
 | 
			
		||||
                                              "    ct.a = mix(ct.a, 1.0, DisableFinalAlpha);\n"
 | 
			
		||||
                                              "    ct = mix(ct, vec4(Grid.rgb,1), Grid.a * isGrid);\n"
 | 
			
		||||
                                              "    Out_Color = ct;\n"
 | 
			
		||||
                                              "}\n";
 | 
			
		||||
 | 
			
		||||
/* BuildShader is from imgui_impl_opengl3.cpp.  Only change is to query the 
 | 
			
		||||
 * additional uniform locations for the new fragment shader*/
 | 
			
		||||
void BuildShader()
 | 
			
		||||
{
 | 
			
		||||
    // Shader selection code based on imgui_impl_opengl3.cpp
 | 
			
		||||
 | 
			
		||||
    // Parse GLSL version string
 | 
			
		||||
    int glsl_version = 130;
 | 
			
		||||
    sscanf(g_GlslVersionString, "#version %d", &glsl_version);
 | 
			
		||||
 | 
			
		||||
    // Select shaders matching our GLSL versions
 | 
			
		||||
    const GLchar *vertex_shader = NULL;
 | 
			
		||||
    const GLchar *fragment_shader = NULL;
 | 
			
		||||
    if (glsl_version < 130)
 | 
			
		||||
    {
 | 
			
		||||
        vertex_shader = vertex_shader_glsl_120;
 | 
			
		||||
        fragment_shader = fragment_shader_glsl_120;
 | 
			
		||||
    }
 | 
			
		||||
    else if (glsl_version >= 410)
 | 
			
		||||
    {
 | 
			
		||||
        vertex_shader = vertex_shader_glsl_410_core;
 | 
			
		||||
        fragment_shader = fragment_shader_glsl_410_core;
 | 
			
		||||
    }
 | 
			
		||||
    else if (glsl_version == 300)
 | 
			
		||||
    {
 | 
			
		||||
        vertex_shader = vertex_shader_glsl_300_es;
 | 
			
		||||
        fragment_shader = fragment_shader_glsl_300_es;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        vertex_shader = vertex_shader_glsl_130;
 | 
			
		||||
        fragment_shader = fragment_shader_glsl_130;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (fragment_shader == NULL)
 | 
			
		||||
    {
 | 
			
		||||
        fprintf(stderr, "ERROR: imgui_tex_inspect fragment shader for %s not implemented yet", g_GlslVersionString);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        // Create shaders
 | 
			
		||||
        const GLchar *vertex_shader_with_version[2] = {g_GlslVersionString, vertex_shader};
 | 
			
		||||
        g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
 | 
			
		||||
        glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL);
 | 
			
		||||
        glCompileShader(g_VertHandle);
 | 
			
		||||
        CheckShader(g_VertHandle, "vertex shader");
 | 
			
		||||
 | 
			
		||||
        const GLchar *fragment_shader_with_version[2] = {g_GlslVersionString, fragment_shader};
 | 
			
		||||
        g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
 | 
			
		||||
        glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL);
 | 
			
		||||
        glCompileShader(g_FragHandle);
 | 
			
		||||
        CheckShader(g_FragHandle, "fragment shader");
 | 
			
		||||
 | 
			
		||||
        g_ShaderHandle = glCreateProgram();
 | 
			
		||||
        glAttachShader(g_ShaderHandle, g_VertHandle);
 | 
			
		||||
        glAttachShader(g_ShaderHandle, g_FragHandle);
 | 
			
		||||
        glLinkProgram(g_ShaderHandle);
 | 
			
		||||
        CheckProgram(g_ShaderHandle, "shader program");
 | 
			
		||||
 | 
			
		||||
        g_AttribLocationTex      = glGetUniformLocation(g_ShaderHandle, "Texture");
 | 
			
		||||
        g_AttribLocationProjMtx  = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
 | 
			
		||||
        g_AttribLocationVtxPos   = (GLuint)glGetAttribLocation(g_ShaderHandle, "Position");
 | 
			
		||||
        g_AttribLocationVtxUV    = (GLuint)glGetAttribLocation(g_ShaderHandle, "UV");
 | 
			
		||||
 | 
			
		||||
        // Change from imgui_impl_opengl3.cpp  (Our shader doesn't use vertex color)
 | 
			
		||||
        //g_AttribLocationVtxColor = (GLuint)glGetAttribLocation(g_ShaderHandle, "Color");
 | 
			
		||||
 | 
			
		||||
        // New uniforms used by imgui_tex_inspect 
 | 
			
		||||
        g_UniformLocationTextureSize          = glGetUniformLocation(g_ShaderHandle, "TextureSize");
 | 
			
		||||
        g_UniformLocationColorTransform       = glGetUniformLocation(g_ShaderHandle, "ColorTransform");
 | 
			
		||||
        g_UniformLocationColorOffset          = glGetUniformLocation(g_ShaderHandle, "ColorOffset");
 | 
			
		||||
        g_UniformLocationBackgroundColor      = glGetUniformLocation(g_ShaderHandle, "BackgroundColor");
 | 
			
		||||
        g_UniformLocationPremultiplyAlpha     = glGetUniformLocation(g_ShaderHandle, "PremultiplyAlpha");
 | 
			
		||||
        g_UniformLocationDisableFinalAlpha    = glGetUniformLocation(g_ShaderHandle, "DisableFinalAlpha");
 | 
			
		||||
        g_UniformLocationGrid                 = glGetUniformLocation(g_ShaderHandle, "Grid");
 | 
			
		||||
        g_UniformLocationForceNearestSampling = glGetUniformLocation(g_ShaderHandle, "ForceNearestSampling");
 | 
			
		||||
        g_UniformLocationGridWidth            = glGetUniformLocation(g_ShaderHandle, "GridWidth");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace imgui_impl_opengl
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace ImGuiTexInspect
 | 
			
		||||
{
 | 
			
		||||
using namespace imgui_impl_opengl;
 | 
			
		||||
 | 
			
		||||
static GLuint readbackFramebuffer = 0;
 | 
			
		||||
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] Init and Shutdown
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
bool ImplOpenGL3_Init(const char *glsl_version)
 | 
			
		||||
{
 | 
			
		||||
    imgui_impl_opengl::ImGui_ImplOpenGL3_Init(glsl_version);
 | 
			
		||||
    BuildShader();
 | 
			
		||||
    glGenFramebuffers(1, &readbackFramebuffer);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
void ImplOpenGl3_Shutdown()
 | 
			
		||||
{
 | 
			
		||||
    // No need to call ImGui_ImplOpenGL3_Shutdown, it doesn't even
 | 
			
		||||
    // exist in the imgui_impl_opengl namespace.  Our version of
 | 
			
		||||
    // ImGui_ImplOpenGL3_Init doesn't affect OpenGL state.
 | 
			
		||||
 | 
			
		||||
    glDeleteShader(g_VertHandle);
 | 
			
		||||
    glDeleteShader(g_FragHandle);
 | 
			
		||||
    glDeleteProgram(g_ShaderHandle);
 | 
			
		||||
 | 
			
		||||
    g_VertHandle = 0;
 | 
			
		||||
    g_FragHandle = 0;
 | 
			
		||||
    g_ShaderHandle = 0;
 | 
			
		||||
 | 
			
		||||
    glDeleteFramebuffers(1, &readbackFramebuffer);
 | 
			
		||||
    readbackFramebuffer = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GiveNotInitializedWarning()
 | 
			
		||||
{
 | 
			
		||||
    static bool warningGiven = false;
 | 
			
		||||
    if (!warningGiven)
 | 
			
		||||
    {
 | 
			
		||||
        fprintf(stderr, "ERROR: ImGuiTexInspect backend not initialized\n");
 | 
			
		||||
        warningGiven = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
// [SECTION] BackEnd functions declared in imgui_tex_inspect_internal.h
 | 
			
		||||
//-------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
void BackEnd_SetShader(const ImDrawList *, const ImDrawCmd *, const Inspector *inspector)
 | 
			
		||||
{
 | 
			
		||||
    const ShaderOptions *texConversion = &inspector->CachedShaderOptions;
 | 
			
		||||
    if (g_ShaderHandle)
 | 
			
		||||
    {
 | 
			
		||||
        ImDrawData *draw_data = ImGui::GetDrawData();
 | 
			
		||||
        int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
 | 
			
		||||
        int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
 | 
			
		||||
 | 
			
		||||
        if (fb_width <= 0 || fb_height <= 0)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        // Setup normal ImGui GL state
 | 
			
		||||
        ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height);
 | 
			
		||||
 | 
			
		||||
        // Setup imgui_tex_inspect specific shader uniforms
 | 
			
		||||
        glUniformMatrix4fv(g_UniformLocationColorTransform, 1, GL_FALSE, texConversion->ColorTransform);
 | 
			
		||||
        glUniform2fv(g_UniformLocationTextureSize,          1, &inspector->TextureSize.x);
 | 
			
		||||
        glUniform4fv(g_UniformLocationColorOffset,          1, texConversion->ColorOffset);
 | 
			
		||||
        glUniform3fv(g_UniformLocationBackgroundColor,      1, &texConversion->BackgroundColor.x);
 | 
			
		||||
        glUniform1f(g_UniformLocationPremultiplyAlpha,         texConversion->PremultiplyAlpha);
 | 
			
		||||
        glUniform1f(g_UniformLocationDisableFinalAlpha,        texConversion->DisableFinalAlpha);
 | 
			
		||||
        glUniform1i(g_UniformLocationForceNearestSampling,     texConversion->ForceNearestSampling);
 | 
			
		||||
        glUniform2fv(g_UniformLocationGridWidth,            1, &texConversion->GridWidth.x);
 | 
			
		||||
        glUniform4fv(g_UniformLocationGrid,                 1, &texConversion->GridColor.x);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        GiveNotInitializedWarning();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
bool BackEnd_GetData(Inspector *inspector, ImTextureID texture, int /*x*/, int /*y*/, int /*width*/, int /*height*/, BufferDesc *bufferDesc)
 | 
			
		||||
{
 | 
			
		||||
    // Current simple implementation just gets data for whole texture
 | 
			
		||||
 | 
			
		||||
    if (readbackFramebuffer == 0)
 | 
			
		||||
    {
 | 
			
		||||
        GiveNotInitializedWarning();
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    const int numChannels = 4;
 | 
			
		||||
    glGetError(); // Discard any current error so that check at end of function is useful
 | 
			
		||||
    void * data;
 | 
			
		||||
    int texWidth     = (int)inspector->TextureSize.x;
 | 
			
		||||
    int texHeight    = (int)inspector->TextureSize.y;
 | 
			
		||||
    GLuint glTexture = (GLuint)(uintptr_t)texture; //Double cast to avoid warning
 | 
			
		||||
 | 
			
		||||
#ifdef IMGUI_TEX_INSPECT_FLOAT_READ_ENABLED
 | 
			
		||||
    size_t bufferSize      = sizeof(float) * texWidth * texHeight * numChannels;
 | 
			
		||||
    bufferDesc->Data_float = (float *)GetBuffer(inspector, bufferSize);
 | 
			
		||||
    GLuint type            = GL_FLOAT;
 | 
			
		||||
    data = (void *)bufferDesc->Data_float;
 | 
			
		||||
#else
 | 
			
		||||
    size_t bufferSize        = sizeof(uint8_t) * texWidth * texHeight * numChannels;
 | 
			
		||||
    bufferDesc->Data_uint8_t = (uint8_t *)GetBuffer(inspector, bufferSize);
 | 
			
		||||
    GLuint type              = GL_UNSIGNED_BYTE;
 | 
			
		||||
    data                     = (void *)bufferDesc->Data_uint8_t;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    if (data == NULL)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    bufferDesc->BufferByteSize = bufferSize;
 | 
			
		||||
    bufferDesc->Red            = 0; // Data is packed such that red channel is first
 | 
			
		||||
    bufferDesc->Green          = 1; // then green, then blue, the alpha. Hence, 0,1,2,3
 | 
			
		||||
    bufferDesc->Blue           = 2; // for these channel order values.
 | 
			
		||||
    bufferDesc->Alpha          = 3;
 | 
			
		||||
    bufferDesc->ChannelCount   = 4; // RGBA
 | 
			
		||||
    bufferDesc->LineStride     = (int)inspector->TextureSize.x * numChannels;
 | 
			
		||||
    bufferDesc->Stride         = 4; // No padding between each RGBA texel
 | 
			
		||||
    bufferDesc->StartX         = 0; // We queried the whole texture
 | 
			
		||||
    bufferDesc->StartY         = 0;
 | 
			
		||||
    bufferDesc->Width          = texWidth;
 | 
			
		||||
    bufferDesc->Height         = texHeight;
 | 
			
		||||
 | 
			
		||||
    // Save current frame buffer so we can restore it
 | 
			
		||||
    GLuint currentFramebuffer;
 | 
			
		||||
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *)¤tFramebuffer);
 | 
			
		||||
 | 
			
		||||
    // Read texture data
 | 
			
		||||
    glBindFramebuffer(GL_FRAMEBUFFER, readbackFramebuffer);
 | 
			
		||||
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glTexture, 0);
 | 
			
		||||
    glReadPixels(0, 0, texWidth, texHeight, GL_RGBA, type, data);
 | 
			
		||||
 | 
			
		||||
    // Restore previous framebuffer
 | 
			
		||||
    glBindFramebuffer(GL_FRAMEBUFFER, currentFramebuffer);
 | 
			
		||||
 | 
			
		||||
    return glGetError() == GL_NO_ERROR;
 | 
			
		||||
}
 | 
			
		||||
} // namespace ImGuiTexInspect
 | 
			
		||||
							
								
								
									
										9
									
								
								tex_inspect_opengl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tex_inspect_opengl.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
// ImGuiTexInspect, a texture inspector widget for dear imgui
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
namespace ImGuiTexInspect
 | 
			
		||||
{
 | 
			
		||||
bool ImplOpenGL3_Init(const char *glsl_version = NULL);
 | 
			
		||||
void ImplOpenGl3_Shutdown();
 | 
			
		||||
} // namespace ImGuiTexInspect
 | 
			
		||||
		Reference in New Issue
	
	Block a user