@@ -57,7 +57,7 @@ BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 0
|
||||
ColumnLimit: 90
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
QualifierAlignment: Leave
|
||||
CompactNamespaces: false
|
||||
|
||||
186
.vims
Normal file
186
.vims
Normal file
@@ -0,0 +1,186 @@
|
||||
let SessionLoad = 1
|
||||
let s:so_save = &g:so | let s:siso_save = &g:siso | setg so=0 siso=0 | setl so=-1 siso=-1
|
||||
let v:this_session=expand("<sfile>:p")
|
||||
silent only
|
||||
silent tabonly
|
||||
cd ~/dprog/active/inferno-hart
|
||||
if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == ''
|
||||
let s:wipebuf = bufnr('%')
|
||||
endif
|
||||
let s:shortmess_save = &shortmess
|
||||
if &shortmess =~ 'A'
|
||||
set shortmess=aoOA
|
||||
else
|
||||
set shortmess=aoO
|
||||
endif
|
||||
badd +693 src/graphics/vulkan_tutorial.cpp
|
||||
badd +316 src/inferno.cpp
|
||||
badd +45 src/scene/mesh.hpp
|
||||
badd +75 src/scene/mesh.cpp
|
||||
badd +33 src/graphics/pipeline.cpp
|
||||
badd +40 src/graphics/vkrenderer.cpp
|
||||
badd +14 src/graphics/pipeline.hpp
|
||||
badd +1 src/graphics/device.cpp
|
||||
badd +20 src/graphics/device.hpp
|
||||
badd +54 src/graphics/renderpass.cpp
|
||||
badd +20 src/graphics/renderpass.hpp
|
||||
badd +13 src/graphics/swapchain.hpp
|
||||
badd +56 src/inferno.hpp
|
||||
badd +1 src/main.cpp
|
||||
badd +1 ~/dprog/active/inferno-hart/src/graphics/descriptor.cpp
|
||||
badd +53 src/graphics/vkrenderer.hpp
|
||||
badd +42 src/renderer/renderer.hpp
|
||||
badd +28 src/scene/scene.cpp
|
||||
badd +173 src/graphics/buffer.cpp
|
||||
badd +5 res/shaders/vulkan_test.vert
|
||||
badd +46 src/graphics/buffer.hpp
|
||||
badd +3 src/renderer/renderer.cpp
|
||||
badd +279 src/graphics/swapchain.cpp
|
||||
badd +22 res/shaders/basic.vert
|
||||
badd +181 src/graphics/shader.cpp
|
||||
badd +51 src/graphics/shader.hpp
|
||||
badd +2 src/scene/scene.hpp
|
||||
badd +240 src/scene/camera.cpp
|
||||
badd +59 libhart/scene/camera.hpp
|
||||
badd +30 src/graphics.hpp
|
||||
badd +43 src/gui/gui.hpp
|
||||
badd +130 src/window.cpp
|
||||
badd +111 src/thirdparty/imgui/imgui_impl_vulkan.cpp
|
||||
badd +66 ~/dprog/active/inferno-hart/src/thirdparty/imgui/imgui_impl_vulkan.h
|
||||
badd +38 src/preview_renderer/renderer.hpp
|
||||
badd +59 src/preview_renderer/renderer.cpp
|
||||
argglobal
|
||||
%argdel
|
||||
edit src/inferno.cpp
|
||||
let s:save_splitbelow = &splitbelow
|
||||
let s:save_splitright = &splitright
|
||||
set splitbelow splitright
|
||||
wincmd _ | wincmd |
|
||||
vsplit
|
||||
wincmd _ | wincmd |
|
||||
vsplit
|
||||
2wincmd h
|
||||
wincmd w
|
||||
wincmd w
|
||||
wincmd _ | wincmd |
|
||||
split
|
||||
1wincmd k
|
||||
wincmd w
|
||||
let &splitbelow = s:save_splitbelow
|
||||
let &splitright = s:save_splitright
|
||||
wincmd t
|
||||
let s:save_winminheight = &winminheight
|
||||
let s:save_winminwidth = &winminwidth
|
||||
set winminheight=0
|
||||
set winheight=1
|
||||
set winminwidth=0
|
||||
set winwidth=1
|
||||
wincmd =
|
||||
argglobal
|
||||
balt src/preview_renderer/renderer.hpp
|
||||
setlocal fdm=manual
|
||||
setlocal fde=0
|
||||
setlocal fmr={{{,}}}
|
||||
setlocal fdi=#
|
||||
setlocal fdl=0
|
||||
setlocal fml=1
|
||||
setlocal fdn=20
|
||||
setlocal fen
|
||||
silent! normal! zE
|
||||
let &fdl = &fdl
|
||||
let s:l = 317 - ((60 * winheight(0) + 43) / 86)
|
||||
if s:l < 1 | let s:l = 1 | endif
|
||||
keepjumps exe s:l
|
||||
normal! zt
|
||||
keepjumps 317
|
||||
normal! 050|
|
||||
wincmd w
|
||||
argglobal
|
||||
if bufexists(fnamemodify("src/preview_renderer/renderer.cpp", ":p")) | buffer src/preview_renderer/renderer.cpp | else | edit src/preview_renderer/renderer.cpp | endif
|
||||
if &buftype ==# 'terminal'
|
||||
silent file src/preview_renderer/renderer.cpp
|
||||
endif
|
||||
balt src/graphics/vkrenderer.cpp
|
||||
setlocal fdm=manual
|
||||
setlocal fde=0
|
||||
setlocal fmr={{{,}}}
|
||||
setlocal fdi=#
|
||||
setlocal fdl=0
|
||||
setlocal fml=1
|
||||
setlocal fdn=20
|
||||
setlocal fen
|
||||
silent! normal! zE
|
||||
let &fdl = &fdl
|
||||
let s:l = 59 - ((56 * winheight(0) + 43) / 86)
|
||||
if s:l < 1 | let s:l = 1 | endif
|
||||
keepjumps exe s:l
|
||||
normal! zt
|
||||
keepjumps 59
|
||||
normal! 015|
|
||||
wincmd w
|
||||
argglobal
|
||||
if bufexists(fnamemodify("src/graphics/vkrenderer.hpp", ":p")) | buffer src/graphics/vkrenderer.hpp | else | edit src/graphics/vkrenderer.hpp | endif
|
||||
if &buftype ==# 'terminal'
|
||||
silent file src/graphics/vkrenderer.hpp
|
||||
endif
|
||||
balt src/graphics/vkrenderer.cpp
|
||||
setlocal fdm=manual
|
||||
setlocal fde=0
|
||||
setlocal fmr={{{,}}}
|
||||
setlocal fdi=#
|
||||
setlocal fdl=0
|
||||
setlocal fml=1
|
||||
setlocal fdn=20
|
||||
setlocal fen
|
||||
silent! normal! zE
|
||||
let &fdl = &fdl
|
||||
let s:l = 10 - ((4 * winheight(0) + 24) / 49)
|
||||
if s:l < 1 | let s:l = 1 | endif
|
||||
keepjumps exe s:l
|
||||
normal! zt
|
||||
keepjumps 10
|
||||
normal! 0
|
||||
wincmd w
|
||||
argglobal
|
||||
if bufexists(fnamemodify("src/preview_renderer/renderer.hpp", ":p")) | buffer src/preview_renderer/renderer.hpp | else | edit src/preview_renderer/renderer.hpp | endif
|
||||
if &buftype ==# 'terminal'
|
||||
silent file src/preview_renderer/renderer.hpp
|
||||
endif
|
||||
balt src/graphics/pipeline.hpp
|
||||
setlocal fdm=manual
|
||||
setlocal fde=0
|
||||
setlocal fmr={{{,}}}
|
||||
setlocal fdi=#
|
||||
setlocal fdl=0
|
||||
setlocal fml=1
|
||||
setlocal fdn=20
|
||||
setlocal fen
|
||||
silent! normal! zE
|
||||
let &fdl = &fdl
|
||||
let s:l = 1 - ((0 * winheight(0) + 18) / 36)
|
||||
if s:l < 1 | let s:l = 1 | endif
|
||||
keepjumps exe s:l
|
||||
normal! zt
|
||||
keepjumps 1
|
||||
normal! 08|
|
||||
wincmd w
|
||||
wincmd =
|
||||
tabnext 1
|
||||
if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0 && getbufvar(s:wipebuf, '&buftype') isnot# 'terminal'
|
||||
silent exe 'bwipe ' . s:wipebuf
|
||||
endif
|
||||
unlet! s:wipebuf
|
||||
set winheight=1 winwidth=20
|
||||
let &shortmess = s:shortmess_save
|
||||
let &winminheight = s:save_winminheight
|
||||
let &winminwidth = s:save_winminwidth
|
||||
let s:sx = expand("<sfile>:p:r")."x.vim"
|
||||
if filereadable(s:sx)
|
||||
exe "source " . fnameescape(s:sx)
|
||||
endif
|
||||
let &g:so = s:so_save | let &g:siso = s:siso_save
|
||||
set hlsearch
|
||||
nohlsearch
|
||||
doautoall SessionLoadPost
|
||||
unlet SessionLoad
|
||||
" vim: set ft=vim :
|
||||
77
.vscode/settings.json
vendored
77
.vscode/settings.json
vendored
@@ -1,77 +0,0 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"string": "cpp",
|
||||
"vector": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"cctype": "cpp",
|
||||
"chrono": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"codecvt": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"forward_list": "cpp",
|
||||
"list": "cpp",
|
||||
"map": "cpp",
|
||||
"set": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"fstream": "cpp",
|
||||
"future": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"numbers": "cpp",
|
||||
"ostream": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"thread": "cpp",
|
||||
"cfenv": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeindex": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"valarray": "cpp",
|
||||
"variant": "cpp",
|
||||
"complex": "cpp",
|
||||
"hash_map": "cpp",
|
||||
"filesystem": "cpp"
|
||||
},
|
||||
"cmake.configureOnOpen": false
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(inferno)
|
||||
|
||||
file(GLOB_RECURSE SRC "src/*.cpp" "src/*.c")
|
||||
file(GLOB SRC "src/*.cpp" "src/graphics/*.cpp" "src/preview_renderer/*.cpp" "src/scene/*.cpp" "src/thirdparty/imgui/*.cpp" "src/preview_renderer/*.cpp")
|
||||
|
||||
add_executable(inferno ${SRC})
|
||||
target_include_directories(inferno PRIVATE "libhart/")
|
||||
target_include_directories(inferno PRIVATE "libhart/thirdparty")
|
||||
target_include_directories(inferno PRIVATE "libhart/")
|
||||
target_include_directories(inferno PRIVATE "src/")
|
||||
target_include_directories(inferno PRIVATE "src/thirdparty")
|
||||
|
||||
@@ -35,23 +35,49 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Compile shaders first..
|
||||
file(GLOB SHADERS "res/shaders/*.vert" "res/shaders/*.frag")
|
||||
foreach(SHADER ${SHADERS})
|
||||
get_filename_component(FILENAME ${SHADER} ABSOLUTE)
|
||||
set(SPIRV "${FILENAME}.spv")
|
||||
add_custom_command(
|
||||
OUTPUT ${SPIRV}
|
||||
COMMAND glslc ${SHADER} -o ${SPIRV}
|
||||
DEPENDS ${SHADER}
|
||||
)
|
||||
list(APPEND SPIRV_BINARY_FILES ${SPIRV})
|
||||
endforeach(SHADER)
|
||||
|
||||
add_custom_target(
|
||||
shaders
|
||||
DEPENDS ${SPIRV_BINARY_FILES}
|
||||
)
|
||||
|
||||
add_dependencies(inferno shaders)
|
||||
|
||||
# Copy resources
|
||||
#invole install_res.sh on compile with make
|
||||
add_custom_command(TARGET shaders POST_BUILD
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/install_res.sh
|
||||
COMMENT "Copying resources"
|
||||
)
|
||||
|
||||
# "Universal" libraries
|
||||
set(THREADS_PREFER_PTHREAD_FLAD ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
set(OpenGL_GL_PREFERENCE GLVND)
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
find_package(OpenMP REQUIRED)
|
||||
|
||||
find_package(Vulkan REQUIRED)
|
||||
|
||||
# Libraries
|
||||
if (WIN32)
|
||||
# cmake .. "-DCMAKE_TOOLCHAIN_FILE=C:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake"
|
||||
find_package(glfw3 CONFIG REQUIRED)
|
||||
target_link_libraries(inferno PUBLIC glfw)
|
||||
|
||||
# OpenGL
|
||||
target_link_libraries(inferno PRIVATE OpenGL::GL)
|
||||
target_link_libraries(inferno PRIVATE Vulkan::Vulkan)
|
||||
else()
|
||||
find_package(PkgConfig)
|
||||
|
||||
@@ -67,7 +93,8 @@ else()
|
||||
|
||||
target_link_libraries(inferno PRIVATE
|
||||
${GLFW3_LIBRARIES}
|
||||
OpenGL::GL
|
||||
Vulkan::Vulkan
|
||||
libvulkan.so
|
||||
OpenMP::OpenMP_CXX
|
||||
)
|
||||
endif()
|
||||
|
||||
1
DAP Breakpoints
Normal file
1
DAP Breakpoints
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
37
imgui.ini
37
imgui.ini
@@ -1,37 +0,0 @@
|
||||
[Window][Preview]
|
||||
Pos=8,34
|
||||
Size=499,677
|
||||
Collapsed=0
|
||||
DockId=0x00000001,0
|
||||
|
||||
[Window][Render]
|
||||
Pos=509,34
|
||||
Size=763,677
|
||||
Collapsed=0
|
||||
DockId=0x00000002,0
|
||||
|
||||
[Window][main]
|
||||
Pos=0,0
|
||||
Size=1280,720
|
||||
Collapsed=0
|
||||
|
||||
[Window][Debug##Default]
|
||||
Pos=60,60
|
||||
Size=400,400
|
||||
Collapsed=0
|
||||
|
||||
[Window][Inferno HART]
|
||||
Pos=60,60
|
||||
Size=338,222
|
||||
Collapsed=0
|
||||
|
||||
[Window][Dear ImGui Demo]
|
||||
Pos=650,20
|
||||
Size=550,680
|
||||
Collapsed=0
|
||||
|
||||
[Docking][Data]
|
||||
DockSpace ID=0x9498A894 Window=0xBF28CD64 Pos=8,34 Size=1264,677 Split=X
|
||||
DockNode ID=0x00000001 Parent=0x9498A894 SizeRef=499,1000 Selected=0x382916D5
|
||||
DockNode ID=0x00000002 Parent=0x9498A894 SizeRef=499,1000 CentralNode=1 Selected=0x81AED595
|
||||
|
||||
1
install_res.sh
Executable file
1
install_res.sh
Executable file
@@ -0,0 +1 @@
|
||||
rsync -a --progress res/ build/res/
|
||||
@@ -1,7 +1,4 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
@@ -19,9 +16,9 @@
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"text": "-enable-pretty-printing"
|
||||
}
|
||||
],
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -2,18 +2,18 @@
|
||||
|
||||
// easy include for graphics shit
|
||||
|
||||
// Include OpenGL
|
||||
extern "C"
|
||||
{
|
||||
#include <glad/glad.h>
|
||||
}
|
||||
|
||||
// Include GLFW
|
||||
// Include GLFW and ImGUI
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
// glm
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/intersect.hpp>
|
||||
#include <glm/gtx/component_wise.hpp>
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/imgui_internal.h"
|
||||
#include "imgui/imgui_impl_vulkan.h"
|
||||
#include "imgui/imgui_impl_glfw.h"
|
||||
|
||||
// glm
|
||||
#define GLM_FORCE_SWIZZLE
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
|
||||
|
||||
@@ -55,8 +55,8 @@ glm::ivec2 camera_raster_get_viewport(Camera* camera);
|
||||
void camera_ray_set_viewport(Camera* camera, glm::ivec2 viewport);
|
||||
glm::ivec2 camera_ray_get_viewport(Camera* camera);
|
||||
|
||||
void camera_move(Camera* camera, uint8_t movement_delta);
|
||||
void camera_mouse_move(Camera* camera, glm::vec2 mouse_delta);
|
||||
void camera_move(Camera* camera, uint8_t movement_delta, float delta_time);
|
||||
void camera_mouse_move(Camera* camera, glm::vec2 mouse_delta, float delta_time);
|
||||
|
||||
void camera_set_position(Camera* camera, glm::vec3 position);
|
||||
void camera_set_euler_look(Camera* camera, float roll,
|
||||
|
||||
3617
libhart/thirdparty/glad/glad.h
vendored
3617
libhart/thirdparty/glad/glad.h
vendored
File diff suppressed because it is too large
Load Diff
282
libhart/thirdparty/glad/khrplatform.h
vendored
282
libhart/thirdparty/glad/khrplatform.h
vendored
@@ -1,282 +0,0 @@
|
||||
#ifndef __khrplatform_h_
|
||||
#define __khrplatform_h_
|
||||
|
||||
/*
|
||||
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are 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 Materials.
|
||||
**
|
||||
** THE MATERIALS ARE 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
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
/* Khronos platform-specific types and definitions.
|
||||
*
|
||||
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||
* The last semantic modification to khrplatform.h was at commit ID:
|
||||
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||
*
|
||||
* Adopters may modify this file to suit their platform. Adopters are
|
||||
* encouraged to submit platform specific modifications to the Khronos
|
||||
* group so that they can be included in future versions of this file.
|
||||
* Please submit changes by filing pull requests or issues on
|
||||
* the EGL Registry repository linked above.
|
||||
*
|
||||
*
|
||||
* See the Implementer's Guidelines for information about where this file
|
||||
* should be located on your system and for more details of its use:
|
||||
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||
*
|
||||
* This file should be included as
|
||||
* #include <KHR/khrplatform.h>
|
||||
* by Khronos client API header files that use its types and defines.
|
||||
*
|
||||
* The types in khrplatform.h should only be used to define API-specific types.
|
||||
*
|
||||
* Types defined in khrplatform.h:
|
||||
* khronos_int8_t signed 8 bit
|
||||
* khronos_uint8_t unsigned 8 bit
|
||||
* khronos_int16_t signed 16 bit
|
||||
* khronos_uint16_t unsigned 16 bit
|
||||
* khronos_int32_t signed 32 bit
|
||||
* khronos_uint32_t unsigned 32 bit
|
||||
* khronos_int64_t signed 64 bit
|
||||
* khronos_uint64_t unsigned 64 bit
|
||||
* khronos_intptr_t signed same number of bits as a pointer
|
||||
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||
* khronos_ssize_t signed size
|
||||
* khronos_usize_t unsigned size
|
||||
* khronos_float_t signed 32 bit floating point
|
||||
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||
* nanoseconds
|
||||
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||
* only be used as a base type when a client API's boolean type is
|
||||
* an enum. Client APIs which use an integer or other type for
|
||||
* booleans cannot use this as the base type for their boolean.
|
||||
*
|
||||
* Tokens defined in khrplatform.h:
|
||||
*
|
||||
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||
*
|
||||
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||
*
|
||||
* Calling convention macros defined in this file:
|
||||
* KHRONOS_APICALL
|
||||
* KHRONOS_APIENTRY
|
||||
* KHRONOS_APIATTRIBUTES
|
||||
*
|
||||
* These may be used in function prototypes as:
|
||||
*
|
||||
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||
* int arg1,
|
||||
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APICALL
|
||||
*-------------------------------------------------------------------------
|
||||
* This precedes the return type of the function in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
# define KHRONOS_APICALL __declspec(dllimport)
|
||||
#elif defined (__SYMBIAN32__)
|
||||
# define KHRONOS_APICALL IMPORT_C
|
||||
#elif defined(__ANDROID__)
|
||||
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||
#else
|
||||
# define KHRONOS_APICALL
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIENTRY
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the return type of the function and precedes the function
|
||||
* name in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
|
||||
/* Win32 but not WinCE */
|
||||
# define KHRONOS_APIENTRY __stdcall
|
||||
#else
|
||||
# define KHRONOS_APIENTRY
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIATTRIBUTES
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the closing parenthesis of the function prototype arguments.
|
||||
*/
|
||||
#if defined (__ARMCC_2__)
|
||||
#define KHRONOS_APIATTRIBUTES __softfp
|
||||
#else
|
||||
#define KHRONOS_APIATTRIBUTES
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* basic type definitions
|
||||
*-----------------------------------------------------------------------*/
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||
|
||||
|
||||
/*
|
||||
* Using <stdint.h>
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__VMS ) || defined(__sgi)
|
||||
|
||||
/*
|
||||
* Using <inttypes.h>
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
|
||||
/*
|
||||
* Win32
|
||||
*/
|
||||
typedef __int32 khronos_int32_t;
|
||||
typedef unsigned __int32 khronos_uint32_t;
|
||||
typedef __int64 khronos_int64_t;
|
||||
typedef unsigned __int64 khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__sun__) || defined(__digital__)
|
||||
|
||||
/*
|
||||
* Sun or Digital
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#if defined(__arch64__) || defined(_LP64)
|
||||
typedef long int khronos_int64_t;
|
||||
typedef unsigned long int khronos_uint64_t;
|
||||
#else
|
||||
typedef long long int khronos_int64_t;
|
||||
typedef unsigned long long int khronos_uint64_t;
|
||||
#endif /* __arch64__ */
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif 0
|
||||
|
||||
/*
|
||||
* Hypothetical platform with no float or int64 support
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#define KHRONOS_SUPPORT_INT64 0
|
||||
#define KHRONOS_SUPPORT_FLOAT 0
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Generic fallback
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Types that are (so far) the same on all platforms
|
||||
*/
|
||||
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;
|
||||
|
||||
/*
|
||||
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||
* to be the only LLP64 architecture in current use.
|
||||
*/
|
||||
#ifdef _WIN64
|
||||
typedef signed long long int khronos_intptr_t;
|
||||
typedef unsigned long long int khronos_uintptr_t;
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
typedef unsigned long long int khronos_usize_t;
|
||||
#else
|
||||
typedef signed long int khronos_intptr_t;
|
||||
typedef unsigned long int khronos_uintptr_t;
|
||||
typedef signed long int khronos_ssize_t;
|
||||
typedef unsigned long int khronos_usize_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_FLOAT
|
||||
/*
|
||||
* Float type
|
||||
*/
|
||||
typedef float khronos_float_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_INT64
|
||||
/* Time types
|
||||
*
|
||||
* These types can be used to represent a time interval in nanoseconds or
|
||||
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||
* time the system booted). The Unadjusted System Time is an unsigned
|
||||
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||
* may be either signed or unsigned.
|
||||
*/
|
||||
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dummy value used to pad enum types to 32 bits.
|
||||
*/
|
||||
#ifndef KHRONOS_MAX_ENUM
|
||||
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enumerated boolean type
|
||||
*
|
||||
* Values other than zero should be considered to be true. Therefore
|
||||
* comparisons should not be made against KHRONOS_TRUE.
|
||||
*/
|
||||
typedef enum {
|
||||
KHRONOS_FALSE = 0,
|
||||
KHRONOS_TRUE = 1,
|
||||
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||
} khronos_boolean_enum_t;
|
||||
|
||||
#endif /* __khrplatform_h_ */
|
||||
@@ -1,41 +1,20 @@
|
||||
#type vertex
|
||||
#version 450 core
|
||||
|
||||
layout (location = 0) in vec3 position;
|
||||
layout (location = 1) in vec3 normal;
|
||||
layout (location = 2) in vec2 uv;
|
||||
|
||||
uniform mat4 model;
|
||||
uniform mat4 view;
|
||||
uniform mat4 proj;
|
||||
|
||||
out vec3 vNormal;
|
||||
out vec3 vFragPos;
|
||||
|
||||
void main() {
|
||||
vFragPos = vec3(model * vec4(position, 1.0));
|
||||
vNormal = normal;
|
||||
gl_Position = proj * view * model * vec4(position, 1.0);
|
||||
}
|
||||
|
||||
#type fragment
|
||||
#version 450 core
|
||||
layout (location = 0) in vec3 vNormal;
|
||||
layout (location = 1) in vec3 vFragPos;
|
||||
|
||||
layout(location = 0) out vec4 outColour;
|
||||
|
||||
in vec3 vNormal;
|
||||
in vec3 vFragPos;
|
||||
|
||||
vec3 lightColour = {1.0, 1.0, 1.0};
|
||||
vec3 lightPos = {12.0, 2.0, 4.0};
|
||||
vec3 lightPos = {12.0, 2.0, 4.0};
|
||||
vec3 objectColour = {1.0, 0.74, 0.21};
|
||||
|
||||
void main() {
|
||||
// ambient
|
||||
float ambientStrength = 0.1;
|
||||
vec3 ambient = ambientStrength * lightColour;
|
||||
|
||||
// diffuse
|
||||
|
||||
// diffuse
|
||||
vec3 norm = normalize(vNormal);
|
||||
vec3 lightDir = normalize(lightPos - vFragPos);
|
||||
float diff = max(dot(norm, lightDir), 0.0);
|
||||
BIN
res/shaders/basic.frag.spv
Normal file
BIN
res/shaders/basic.frag.spv
Normal file
Binary file not shown.
22
res/shaders/basic.vert
Normal file
22
res/shaders/basic.vert
Normal file
@@ -0,0 +1,22 @@
|
||||
#version 450 core
|
||||
|
||||
layout (location = 0) in vec3 position;
|
||||
layout (location = 1) in vec3 normal;
|
||||
|
||||
layout (binding = 0) uniform SceneUniformBufferObject {
|
||||
mat4 proj;
|
||||
mat4 view;
|
||||
mat4 unused0;
|
||||
mat4 unused1;
|
||||
} ubo;
|
||||
|
||||
// mat4 model;
|
||||
|
||||
layout (location = 0) out vec3 vNormal;
|
||||
layout (location = 1) out vec3 vFragPos;
|
||||
|
||||
void main() {
|
||||
vFragPos = vec3(vec4(position, 1.0));
|
||||
vNormal = normal;
|
||||
gl_Position = ubo.proj * ubo.view * vec4(position, 1.0);
|
||||
}
|
||||
BIN
res/shaders/basic.vert.spv
Normal file
BIN
res/shaders/basic.vert.spv
Normal file
Binary file not shown.
11
res/shaders/lines_debug.frag
Normal file
11
res/shaders/lines_debug.frag
Normal file
@@ -0,0 +1,11 @@
|
||||
#version 450 core
|
||||
|
||||
layout (location = 0) in vec3 vFragPos;
|
||||
|
||||
layout(location = 0) out vec4 outColour;
|
||||
|
||||
void main()
|
||||
{
|
||||
outColour = vec4(1., 0., 0., 1.0);
|
||||
}
|
||||
|
||||
BIN
res/shaders/lines_debug.frag.spv
Normal file
BIN
res/shaders/lines_debug.frag.spv
Normal file
Binary file not shown.
19
res/shaders/lines_debug.vert
Normal file
19
res/shaders/lines_debug.vert
Normal file
@@ -0,0 +1,19 @@
|
||||
#version 450 core
|
||||
|
||||
layout (location = 0) in vec3 position;
|
||||
|
||||
layout (binding = 0) uniform SceneUniformBufferObject {
|
||||
mat4 proj;
|
||||
mat4 view;
|
||||
mat4 unused0;
|
||||
mat4 unused1;
|
||||
} ubo;
|
||||
|
||||
// mat4 model;
|
||||
|
||||
layout (location = 1) out vec3 vFragPos;
|
||||
|
||||
void main() {
|
||||
vFragPos = vec3(vec4(position, 1.0));
|
||||
gl_Position = ubo.proj * ubo.view * vec4(position, 1.0);
|
||||
}
|
||||
BIN
res/shaders/lines_debug.vert.spv
Normal file
BIN
res/shaders/lines_debug.vert.spv
Normal file
Binary file not shown.
11
res/shaders/unused/lines_debug.frag
Normal file
11
res/shaders/unused/lines_debug.frag
Normal file
@@ -0,0 +1,11 @@
|
||||
#version 450 core
|
||||
|
||||
in vec4 vFragPos;
|
||||
|
||||
layout(location = 0) out vec4 outColour;
|
||||
|
||||
void main()
|
||||
{
|
||||
outColour = vec4(vFragPos.xyz, 1.0);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#type vertex
|
||||
#version 450 core
|
||||
|
||||
layout(location = 0) in vec4 position;
|
||||
@@ -14,16 +13,3 @@ void main()
|
||||
vFragPos = model * position;
|
||||
gl_Position = proj * view * model * position;
|
||||
}
|
||||
|
||||
#type fragment
|
||||
#version 450 core
|
||||
|
||||
in vec4 vFragPos;
|
||||
|
||||
layout(location = 0) out vec4 outColour;
|
||||
|
||||
void main()
|
||||
{
|
||||
outColour = vec4(vFragPos.xyz, 1.0);
|
||||
}
|
||||
|
||||
9
res/shaders/vulkan_test.frag
Normal file
9
res/shaders/vulkan_test.frag
Normal file
@@ -0,0 +1,9 @@
|
||||
#version 450 core
|
||||
|
||||
layout(location = 0) in vec3 fFragColour;
|
||||
|
||||
layout(location = 0) out vec4 outColour;
|
||||
|
||||
void main() {
|
||||
outColour = vec4(fFragColour, 1.0);
|
||||
}
|
||||
BIN
res/shaders/vulkan_test.frag.spv
Normal file
BIN
res/shaders/vulkan_test.frag.spv
Normal file
Binary file not shown.
13
res/shaders/vulkan_test.vert
Normal file
13
res/shaders/vulkan_test.vert
Normal file
@@ -0,0 +1,13 @@
|
||||
#version 450 core
|
||||
|
||||
layout(location = 0) in vec3 vPosition;
|
||||
layout(location = 1) in vec3 vColor;
|
||||
|
||||
layout(location = 0) out vec3 fFragColour;
|
||||
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(vPosition, 1.0);
|
||||
fFragColour = vColor;
|
||||
}
|
||||
|
||||
BIN
res/shaders/vulkan_test.vert.spv
Normal file
BIN
res/shaders/vulkan_test.vert.spv
Normal file
Binary file not shown.
@@ -1,21 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
// easy include for graphics shit
|
||||
|
||||
// Include OpenGL
|
||||
extern "C"
|
||||
{
|
||||
#include <glad/glad.h>
|
||||
}
|
||||
#define FRAMES_IN_FLIGHT 3
|
||||
#define SHADER_STAGES 2
|
||||
|
||||
// Include GLFW and ImGUI
|
||||
#ifdef _WIN32
|
||||
#define VK_USE_PLATFORM_WIN32_KHR
|
||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#define VK_USE_PLATFORM_XLIB_KHR
|
||||
#define GLFW_EXPOSE_NATIVE_X11
|
||||
#include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <vulkan/vulkan_xlib.h>
|
||||
#include <GLFW/glfw3native.h>
|
||||
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/imgui_internal.h"
|
||||
#include "imgui/imgui_impl_opengl3.h"
|
||||
#include "imgui/imgui_impl_glfw.h"
|
||||
#include "imgui/imgui_impl_vulkan.h"
|
||||
#include "imgui/imgui_internal.h"
|
||||
|
||||
// glm
|
||||
#define GLM_FORCE_RADIANS
|
||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||
#define GLM_FORCE_SWIZZLE
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
@@ -23,7 +35,7 @@ extern "C"
|
||||
#include <vector>
|
||||
namespace inferno {
|
||||
namespace graphics::rays {
|
||||
class Ray;
|
||||
class Ray;
|
||||
}
|
||||
using RayField = std::vector<graphics::rays::Ray*>;
|
||||
}
|
||||
|
||||
203
src/graphics/buffer.cpp
Normal file
203
src/graphics/buffer.cpp
Normal file
@@ -0,0 +1,203 @@
|
||||
#include "buffer.hpp"
|
||||
|
||||
#include "device.hpp"
|
||||
|
||||
#include "scene/mesh.hpp"
|
||||
|
||||
#include "yolo/yolo.hpp"
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
GenBuffer* generic_buffer_create(GraphicsDevice* device, uint32_t count,
|
||||
VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties)
|
||||
{
|
||||
GenBuffer* buffer = new GenBuffer;
|
||||
|
||||
buffer->Device = device;
|
||||
buffer->Count = count;
|
||||
buffer->Size = size;
|
||||
|
||||
VkBufferCreateInfo bufferInfo = {};
|
||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
bufferInfo.size = size;
|
||||
bufferInfo.usage = usage;
|
||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
if (vkCreateBuffer(device->VulkanDevice, &bufferInfo, nullptr, &buffer->Handle)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to create vertex buffer!");
|
||||
}
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
vkGetBufferMemoryRequirements(device->VulkanDevice, buffer->Handle, &memRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo = {};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = memRequirements.size;
|
||||
allocInfo.memoryTypeIndex
|
||||
= device_find_memory_type(device, memRequirements.memoryTypeBits, properties);
|
||||
|
||||
if (vkAllocateMemory(device->VulkanDevice, &allocInfo, nullptr, &buffer->DeviceData)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to allocate vertex buffer memory!");
|
||||
}
|
||||
|
||||
vkBindBufferMemory(device->VulkanDevice, buffer->Handle, buffer->DeviceData, 0);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void generic_buffer_cleanup(GenBuffer* buffer)
|
||||
{
|
||||
vkDestroyBuffer(buffer->Device->VulkanDevice, buffer->Handle, nullptr);
|
||||
vkFreeMemory(buffer->Device->VulkanDevice, buffer->DeviceData, nullptr);
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
void buffer_copy(Buffer* buffer, GraphicsDevice* device)
|
||||
{
|
||||
VkCommandBufferAllocateInfo allocInfo = {};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
// shit this needs command pool access
|
||||
allocInfo.commandPool = device->VulkanCommandPool;
|
||||
allocInfo.commandBufferCount = 1;
|
||||
|
||||
VkCommandBuffer commandBuffer;
|
||||
vkAllocateCommandBuffers(device->VulkanDevice, &allocInfo, &commandBuffer);
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo = {};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
|
||||
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
||||
|
||||
VkBufferCopy copyRegion = {};
|
||||
copyRegion.srcOffset = 0;
|
||||
copyRegion.dstOffset = 0;
|
||||
copyRegion.size = buffer->StagingBuffer->Size;
|
||||
|
||||
vkCmdCopyBuffer(commandBuffer, buffer->StagingBuffer->Handle,
|
||||
buffer->GenericBuffer->Handle, 1, ©Region);
|
||||
vkEndCommandBuffer(commandBuffer);
|
||||
|
||||
VkSubmitInfo submitInfo = {};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &commandBuffer;
|
||||
|
||||
vkQueueSubmit(device->VulkanGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
|
||||
vkQueueWaitIdle(device->VulkanGraphicsQueue);
|
||||
|
||||
vkFreeCommandBuffers(
|
||||
device->VulkanDevice, device->VulkanCommandPool, 1, &commandBuffer);
|
||||
}
|
||||
|
||||
Buffer* vertex_buffer_create(GraphicsDevice* device, void* data, uint32_t size, bool bind)
|
||||
{
|
||||
VkDeviceSize bufferSize = size * sizeof(scene::Vert);
|
||||
Buffer* buffer = new Buffer;
|
||||
buffer->StagingBuffer = generic_buffer_create(device, size, bufferSize,
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
yolo::debug("Staging buffer size: {}", bufferSize);
|
||||
buffer->NullableClientData = data;
|
||||
|
||||
void* mData;
|
||||
vkMapMemory(device->VulkanDevice, buffer->StagingBuffer->DeviceData, 0, bufferSize, 0,
|
||||
&mData);
|
||||
memcpy(mData, data, bufferSize);
|
||||
vkUnmapMemory(device->VulkanDevice, buffer->StagingBuffer->DeviceData);
|
||||
|
||||
buffer->GenericBuffer = generic_buffer_create(device, size, bufferSize,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
buffer_copy(buffer, device);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void vertex_buffer_cleanup(Buffer* buffer)
|
||||
{
|
||||
generic_buffer_cleanup(buffer->GenericBuffer);
|
||||
generic_buffer_cleanup(buffer->StagingBuffer);
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
void vertex_buffer_update(Buffer* buffer, void* data, uint32_t size)
|
||||
{
|
||||
VkDeviceSize bufferSize = size * sizeof(scene::Vert);
|
||||
|
||||
if (buffer->StagingBuffer->Size < bufferSize) {
|
||||
generic_buffer_cleanup(buffer->StagingBuffer);
|
||||
generic_buffer_cleanup(buffer->GenericBuffer);
|
||||
|
||||
buffer->StagingBuffer = generic_buffer_create(buffer->GenericBuffer->Device, size,
|
||||
bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
buffer->GenericBuffer
|
||||
= generic_buffer_create(buffer->GenericBuffer->Device, size, bufferSize,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
}
|
||||
|
||||
void* mData;
|
||||
vkMapMemory(buffer->GenericBuffer->Device->VulkanDevice,
|
||||
buffer->StagingBuffer->DeviceData, 0, bufferSize, 0, &mData);
|
||||
memcpy(mData, data, bufferSize);
|
||||
vkUnmapMemory(
|
||||
buffer->GenericBuffer->Device->VulkanDevice, buffer->StagingBuffer->DeviceData);
|
||||
|
||||
buffer_copy(buffer, buffer->GenericBuffer->Device);
|
||||
}
|
||||
|
||||
void vertex_buffer_bind(Buffer* buffer, VkCommandBuffer commandBuffer)
|
||||
{
|
||||
VkBuffer vertexBuffers[] = { buffer->GenericBuffer->Handle };
|
||||
VkDeviceSize offsets[] = { 0 };
|
||||
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
|
||||
}
|
||||
|
||||
Buffer* index_buffer_create(GraphicsDevice* device, void* data, uint32_t size, bool bind)
|
||||
{
|
||||
VkDeviceSize bufferSize = size * sizeof(scene::Index);
|
||||
Buffer* buffer = new Buffer;
|
||||
buffer->StagingBuffer = generic_buffer_create(device, size, bufferSize,
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
buffer->NullableClientData = data;
|
||||
|
||||
void* mData;
|
||||
vkMapMemory(device->VulkanDevice, buffer->StagingBuffer->DeviceData, 0, bufferSize, 0,
|
||||
&mData);
|
||||
memcpy(mData, data, bufferSize);
|
||||
vkUnmapMemory(device->VulkanDevice, buffer->StagingBuffer->DeviceData);
|
||||
|
||||
buffer->GenericBuffer = generic_buffer_create(device, size, bufferSize,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
buffer_copy(buffer, device);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void index_buffer_cleanup(Buffer* buffer)
|
||||
{
|
||||
generic_buffer_cleanup(buffer->GenericBuffer);
|
||||
generic_buffer_cleanup(buffer->StagingBuffer);
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
void index_buffer_bind(Buffer* buffer, VkCommandBuffer commandBuffer)
|
||||
{
|
||||
vkCmdBindIndexBuffer(
|
||||
commandBuffer, buffer->GenericBuffer->Handle, 0, VK_INDEX_TYPE_UINT32);
|
||||
}
|
||||
|
||||
}
|
||||
74
src/graphics/buffer.hpp
Normal file
74
src/graphics/buffer.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics.hpp"
|
||||
|
||||
#include "device.hpp"
|
||||
|
||||
namespace inferno::scene {
|
||||
struct Vert;
|
||||
}
|
||||
|
||||
namespace inferno::graphics {
|
||||
struct GraphicsDevice;
|
||||
|
||||
typedef struct GenBuffer {
|
||||
GraphicsDevice* Device;
|
||||
|
||||
VkBuffer Handle;
|
||||
VkDeviceMemory DeviceData;
|
||||
|
||||
void* MappedData;
|
||||
|
||||
uint32_t Count;
|
||||
VkDeviceSize Size;
|
||||
} GenBuffer;
|
||||
|
||||
// NOTE: Staging Buffer and Buffer are literally the exact same thing
|
||||
// It's all about the semantics of on-device memory transfer
|
||||
// TODO: Does the size of the staging buffer matter?
|
||||
typedef struct Buffer {
|
||||
GenBuffer* GenericBuffer;
|
||||
GenBuffer* StagingBuffer;
|
||||
void* NullableClientData;
|
||||
} Buffer;
|
||||
|
||||
GenBuffer* generic_buffer_create(GraphicsDevice* device, uint32_t count,
|
||||
VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties);
|
||||
void generic_buffer_cleanup(GenBuffer* buffer);
|
||||
|
||||
void buffer_copy(Buffer* buffer, GraphicsDevice* device);
|
||||
|
||||
Buffer* vertex_buffer_create(
|
||||
GraphicsDevice* device, void* data, uint32_t size, bool bind = false);
|
||||
void vertex_buffer_cleanup(Buffer* buffer);
|
||||
void vertex_buffer_update(Buffer* buffer, void* data, uint32_t size);
|
||||
void vertex_buffer_bind(Buffer* buffer, VkCommandBuffer commandBuffer);
|
||||
|
||||
Buffer* index_buffer_create(
|
||||
GraphicsDevice* device, void* data, uint32_t size, bool bind = false);
|
||||
void index_buffer_cleanup(Buffer* buffer);
|
||||
void index_buffer_update(Buffer* buffer, void* data, uint32_t size);
|
||||
void index_buffer_bind(Buffer* buffer, VkCommandBuffer commandBuffer);
|
||||
|
||||
// We *do* want universally mapped memory to act as a "uniform buffer"
|
||||
template <typename T>
|
||||
GenBuffer* uniform_buffer_create(GraphicsDevice* device, bool bind = false)
|
||||
{
|
||||
GenBuffer* buffer
|
||||
= generic_buffer_create(device, 0, sizeof(T), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
vkMapMemory(device->VulkanDevice, buffer->DeviceData, 0, buffer->Size, 0,
|
||||
&buffer->MappedData);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline void uniform_buffer_cleanup(GenBuffer* buffer) { generic_buffer_cleanup(buffer); }
|
||||
|
||||
template <typename T> void uniform_buffer_update(GenBuffer* buffer, T* data)
|
||||
{
|
||||
memcpy(buffer->MappedData, (void*)data, sizeof(T));
|
||||
}
|
||||
|
||||
}
|
||||
426
src/graphics/device.cpp
Normal file
426
src/graphics/device.cpp
Normal file
@@ -0,0 +1,426 @@
|
||||
#include "device.hpp"
|
||||
|
||||
#include "graphics.hpp"
|
||||
#include "window.hpp"
|
||||
|
||||
#include "yolo/yolo.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData)
|
||||
{
|
||||
yolo::warn("[VULKAN] {}", pCallbackData->pMessage);
|
||||
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
VkResult createDebugUtilsMessengerEXT(VkInstance instance,
|
||||
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger)
|
||||
{
|
||||
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
|
||||
instance, "vkCreateDebugUtilsMessengerEXT");
|
||||
if (func != nullptr) {
|
||||
return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
|
||||
} else {
|
||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
}
|
||||
}
|
||||
|
||||
void destroyDebugUtilsMessengerEXT(VkInstance instance,
|
||||
VkDebugUtilsMessengerEXT debugMessenger, const VkAllocationCallbacks* pAllocator)
|
||||
{
|
||||
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
|
||||
instance, "vkDestroyDebugUtilsMessengerEXT");
|
||||
if (func != nullptr) {
|
||||
func(instance, debugMessenger, pAllocator);
|
||||
}
|
||||
}
|
||||
|
||||
void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo)
|
||||
{
|
||||
createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT
|
||||
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
|
||||
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||
createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
|
||||
| VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
|
||||
| VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||
createInfo.pfnUserCallback = debugCallback;
|
||||
}
|
||||
|
||||
#ifdef VALIDATION_LAYERS_ENABLED
|
||||
bool checkValidationLayerSupport()
|
||||
{
|
||||
uint32_t layerCount;
|
||||
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
|
||||
|
||||
std::vector<VkLayerProperties> availableLayers(layerCount);
|
||||
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
|
||||
|
||||
for (const char* layerName : VALIDATION_LAYERS) {
|
||||
bool layerFound = false;
|
||||
|
||||
for (const auto& layerProperties : availableLayers) {
|
||||
if (strcmp(layerName, layerProperties.layerName) == 0) {
|
||||
layerFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!layerFound) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::vector<const char*> getRequiredExtensions()
|
||||
{
|
||||
uint32_t glfwExtensionCount = 0;
|
||||
const char** glfwExtensions;
|
||||
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
|
||||
|
||||
std::vector<const char*> extensions(
|
||||
glfwExtensions, glfwExtensions + glfwExtensionCount);
|
||||
|
||||
#ifdef VALIDATION_LAYERS_ENABLED
|
||||
yolo::info("Validation layers enabled");
|
||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
#endif
|
||||
|
||||
yolo::info("Requested instance extensions:");
|
||||
for (const auto& extension : extensions) {
|
||||
yolo::info("\t{}", extension);
|
||||
}
|
||||
|
||||
return extensions;
|
||||
}
|
||||
|
||||
QueueFamilyIndices device_get_queue_families(GraphicsDevice* g, VkPhysicalDevice device)
|
||||
{
|
||||
QueueFamilyIndices indices;
|
||||
uint32_t queueFamilyCount = 0;
|
||||
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
|
||||
|
||||
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(
|
||||
device, &queueFamilyCount, queueFamilies.data());
|
||||
|
||||
uint32_t queueFamIndex = 0;
|
||||
|
||||
for (const auto& queueFamily : queueFamilies) {
|
||||
if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||
indices.graphicsFamily = queueFamIndex;
|
||||
}
|
||||
|
||||
VkBool32 presentSupport = false;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(
|
||||
device, queueFamIndex, g->VulkanSurface, &presentSupport);
|
||||
|
||||
if (presentSupport) {
|
||||
indices.presentFamily = queueFamIndex;
|
||||
}
|
||||
|
||||
if (indices.isComplete()) {
|
||||
break;
|
||||
}
|
||||
|
||||
queueFamIndex++;
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
|
||||
bool device_evaluate_extensions(
|
||||
VkPhysicalDevice device, std::vector<const char*> extensions)
|
||||
{
|
||||
uint32_t extensionCount;
|
||||
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
|
||||
|
||||
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
|
||||
vkEnumerateDeviceExtensionProperties(
|
||||
device, nullptr, &extensionCount, availableExtensions.data());
|
||||
|
||||
std::set<std::string> requiredExtensions(extensions.begin(), extensions.end());
|
||||
|
||||
for (const auto& extension : availableExtensions) {
|
||||
requiredExtensions.erase(extension.extensionName);
|
||||
}
|
||||
|
||||
return requiredExtensions.empty();
|
||||
}
|
||||
|
||||
bool device_evaluate(GraphicsDevice* g, VkPhysicalDevice device)
|
||||
{
|
||||
int score = 0;
|
||||
|
||||
VkPhysicalDeviceProperties deviceProperties;
|
||||
vkGetPhysicalDeviceProperties(device, &deviceProperties);
|
||||
|
||||
VkPhysicalDeviceFeatures deviceFeatures;
|
||||
vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
|
||||
|
||||
yolo::info("Found device {}", deviceProperties.deviceName);
|
||||
// Discrete GPUs have a significant performance advantage
|
||||
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
|
||||
yolo::info("Device {} is a discrete GPU", deviceProperties.deviceName);
|
||||
score += 1000;
|
||||
}
|
||||
|
||||
// does the device support the extensions we need?
|
||||
if (!device_evaluate_extensions(device, DEVICE_EXTENSIONS)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Maximum possible size of textures affects graphics quality
|
||||
score += deviceProperties.limits.maxImageDimension2D;
|
||||
|
||||
// Ensure that the device can process the graphics commands that we need
|
||||
QueueFamilyIndices indices = device_get_queue_families(g, device);
|
||||
if (!indices.isComplete())
|
||||
return 0;
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
GraphicsDevice* device_create()
|
||||
{
|
||||
GraphicsDevice* device = new GraphicsDevice();
|
||||
device_create_vulkan_instance(device);
|
||||
device_vulkan_debugger(device);
|
||||
window_init_device(device, &device_resize_callback);
|
||||
device->SurfaceSize = window_get_size();
|
||||
device_create_vulkan_physical_device(device);
|
||||
device_create_vulkan_logical_device(device);
|
||||
device_create_command_pool(device);
|
||||
return device;
|
||||
}
|
||||
|
||||
void device_cleanup(GraphicsDevice* device)
|
||||
{
|
||||
vkDestroyDevice(device->VulkanDevice, nullptr);
|
||||
|
||||
#ifdef VALIDATION_LAYERS_ENABLED
|
||||
destroyDebugUtilsMessengerEXT(
|
||||
device->VulkanInstance, device->VulkanDebugMessenger, nullptr);
|
||||
#endif
|
||||
vkDestroySurfaceKHR(device->VulkanInstance, device->VulkanSurface, nullptr);
|
||||
vkDestroyInstance(device->VulkanInstance, nullptr);
|
||||
}
|
||||
|
||||
void device_create_vulkan_instance(GraphicsDevice* device)
|
||||
{
|
||||
|
||||
#ifdef VALIDATION_LAYERS_ENABLED
|
||||
if (!checkValidationLayerSupport()) {
|
||||
yolo::error("validation layers requested, but not available!");
|
||||
}
|
||||
#endif
|
||||
|
||||
VkApplicationInfo appInfo {};
|
||||
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
appInfo.pApplicationName = "Inferno HART";
|
||||
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
appInfo.pEngineName = "No Engine";
|
||||
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
appInfo.apiVersion = VK_API_VERSION_1_3;
|
||||
|
||||
VkInstanceCreateInfo createInfo {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
createInfo.pApplicationInfo = &appInfo;
|
||||
|
||||
auto extensions = getRequiredExtensions();
|
||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||
createInfo.ppEnabledExtensionNames = extensions.data();
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
|
||||
#ifdef VALIDATION_LAYERS_ENABLED
|
||||
createInfo.enabledLayerCount = static_cast<uint32_t>(VALIDATION_LAYERS.size());
|
||||
createInfo.ppEnabledLayerNames = VALIDATION_LAYERS.data();
|
||||
|
||||
populateDebugMessengerCreateInfo(debugCreateInfo);
|
||||
createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugCreateInfo;
|
||||
#else
|
||||
createInfo.enabledLayerCount = 0;
|
||||
|
||||
createInfo.pNext = nullptr;
|
||||
#endif
|
||||
|
||||
if (vkCreateInstance(&createInfo, nullptr, &device->VulkanInstance) != VK_SUCCESS) {
|
||||
yolo::error("failed to create instance!");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void device_vulkan_debugger(GraphicsDevice* device)
|
||||
{
|
||||
#ifndef VALIDATION_LAYERS_ENABLED
|
||||
yolo::warn("Validation layers disabled");
|
||||
return;
|
||||
#endif
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT createInfo;
|
||||
populateDebugMessengerCreateInfo(createInfo);
|
||||
|
||||
if (createDebugUtilsMessengerEXT(
|
||||
device->VulkanInstance, &createInfo, nullptr, &device->VulkanDebugMessenger)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to set up debug messenger!");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void device_create_vulkan_physical_device(GraphicsDevice* device)
|
||||
{
|
||||
uint32_t deviceCount = 0;
|
||||
vkEnumeratePhysicalDevices(device->VulkanInstance, &deviceCount, nullptr);
|
||||
|
||||
if (deviceCount == 0) {
|
||||
yolo::error("failed to find GPUs with Vulkan support!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::vector<VkPhysicalDevice> devices(deviceCount);
|
||||
vkEnumeratePhysicalDevices(device->VulkanInstance, &deviceCount, devices.data());
|
||||
|
||||
// std::multimap is sorted list of key-value pairs. Sorted by key.
|
||||
std::multimap<int, VkPhysicalDevice> candidates;
|
||||
|
||||
for (const auto& device_candidate : devices) {
|
||||
int score = device_evaluate(device, device_candidate);
|
||||
candidates.insert(std::make_pair(score, device_candidate));
|
||||
}
|
||||
|
||||
// as candidates is a sorted list, the last value will always be the biggest score
|
||||
// (first element)
|
||||
if (candidates.rbegin()->first > 0) {
|
||||
VkPhysicalDeviceProperties deviceProperties;
|
||||
vkGetPhysicalDeviceProperties(candidates.rbegin()->second, &deviceProperties);
|
||||
yolo::info("Using device: {}", deviceProperties.deviceName);
|
||||
|
||||
// established the device with the best score, or the only one in the system.
|
||||
device->VulkanPhysicalDevice = candidates.rbegin()->second;
|
||||
} else {
|
||||
yolo::error("failed to find a suitable GPU!");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void device_create_vulkan_logical_device(GraphicsDevice* device)
|
||||
{
|
||||
QueueFamilyIndices indices
|
||||
= device_get_queue_families(device, device->VulkanPhysicalDevice);
|
||||
|
||||
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
||||
std::set<uint32_t> uniqueQueueFamilies
|
||||
= { indices.graphicsFamily.value(), indices.presentFamily.value() };
|
||||
|
||||
float queuePriority = 1.0f;
|
||||
for (uint32_t queueFamily : uniqueQueueFamilies) {
|
||||
VkDeviceQueueCreateInfo queueCreateInfo {};
|
||||
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queueCreateInfo.queueFamilyIndex = queueFamily;
|
||||
queueCreateInfo.pQueuePriorities = &queuePriority;
|
||||
queueCreateInfo.queueCount = 1;
|
||||
queueCreateInfos.push_back(queueCreateInfo);
|
||||
}
|
||||
|
||||
VkPhysicalDeviceFeatures deviceFeatures {};
|
||||
|
||||
VkDeviceCreateInfo createInfo {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
|
||||
createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
|
||||
createInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||
|
||||
createInfo.pEnabledFeatures = &deviceFeatures;
|
||||
|
||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(DEVICE_EXTENSIONS.size());
|
||||
createInfo.ppEnabledExtensionNames = DEVICE_EXTENSIONS.data();
|
||||
yolo::info("Requested device extensions:");
|
||||
for (const auto& extension : DEVICE_EXTENSIONS) {
|
||||
yolo::info("\t{}", extension);
|
||||
}
|
||||
|
||||
VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamicCreateInfo {};
|
||||
dynamicCreateInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR;
|
||||
dynamicCreateInfo.dynamicRendering = VK_TRUE;
|
||||
createInfo.pNext = &dynamicCreateInfo;
|
||||
|
||||
#ifdef VALIDATION_LAYERS_ENABLED
|
||||
createInfo.enabledLayerCount = static_cast<uint32_t>(VALIDATION_LAYERS.size());
|
||||
createInfo.ppEnabledLayerNames = VALIDATION_LAYERS.data();
|
||||
#endif
|
||||
#ifndef VALIDATION_LAYERS_ENABLED
|
||||
createInfo.enabledLayerCount = 0;
|
||||
#endif
|
||||
|
||||
|
||||
if (vkCreateDevice(
|
||||
device->VulkanPhysicalDevice, &createInfo, nullptr, &device->VulkanDevice)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to create logical device!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
vkGetDeviceQueue(device->VulkanDevice, indices.graphicsFamily.value(), 0,
|
||||
&device->VulkanGraphicsQueue);
|
||||
vkGetDeviceQueue(device->VulkanDevice, indices.presentFamily.value(), 0,
|
||||
&device->VulkanPresentQueue);
|
||||
}
|
||||
|
||||
void device_create_command_pool(GraphicsDevice* device)
|
||||
{
|
||||
QueueFamilyIndices queueFamilyIndices
|
||||
= device_get_queue_families(device, device->VulkanPhysicalDevice);
|
||||
|
||||
VkCommandPoolCreateInfo poolInfo = {};
|
||||
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();
|
||||
poolInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT
|
||||
| VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
|
||||
if (vkCreateCommandPool(
|
||||
device->VulkanDevice, &poolInfo, nullptr, &device->VulkanCommandPool)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to create command pool!");
|
||||
}
|
||||
}
|
||||
|
||||
void device_resize_callback(GLFWwindow* window, int width, int height)
|
||||
{
|
||||
auto device = (GraphicsDevice*)glfwGetWindowUserPointer(window);
|
||||
device->Resized = true;
|
||||
device->SurfaceSize = glm::ivec2(width, height);
|
||||
yolo::info("Window resized to {}x{}", width, height);
|
||||
}
|
||||
|
||||
uint32_t device_find_memory_type(
|
||||
GraphicsDevice* g, uint32_t typeFilter, VkMemoryPropertyFlags properties)
|
||||
{
|
||||
VkPhysicalDeviceMemoryProperties memProperties;
|
||||
vkGetPhysicalDeviceMemoryProperties(g->VulkanPhysicalDevice, &memProperties);
|
||||
|
||||
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
|
||||
if ((typeFilter & (1 << i))
|
||||
&& (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
yolo::error("Failed to find suitable memory type!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
60
src/graphics/device.hpp
Normal file
60
src/graphics/device.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics.hpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
#define VALIDATION_LAYERS_ENABLED 1
|
||||
#ifdef VALIDATION_LAYERS_ENABLED
|
||||
const std::vector<const char*> VALIDATION_LAYERS = {
|
||||
"VK_LAYER_KHRONOS_validation",
|
||||
};
|
||||
#endif
|
||||
|
||||
const std::vector<const char*> DEVICE_EXTENSIONS = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
typedef struct GraphicsDevice {
|
||||
VkInstance VulkanInstance;
|
||||
VkDebugUtilsMessengerEXT VulkanDebugMessenger;
|
||||
VkPhysicalDevice VulkanPhysicalDevice;
|
||||
VkDevice VulkanDevice;
|
||||
VkSurfaceKHR VulkanSurface;
|
||||
VkQueue VulkanGraphicsQueue;
|
||||
VkQueue VulkanPresentQueue;
|
||||
VkCommandPool VulkanCommandPool;
|
||||
|
||||
glm::ivec2 SurfaceSize;
|
||||
bool Resized = false;
|
||||
} GraphicsDevice;
|
||||
|
||||
struct QueueFamilyIndices {
|
||||
std::optional<uint32_t> graphicsFamily;
|
||||
std::optional<uint32_t> presentFamily;
|
||||
|
||||
bool isComplete()
|
||||
{
|
||||
return graphicsFamily.has_value() && presentFamily.has_value();
|
||||
}
|
||||
};
|
||||
|
||||
// MUST ONLY BE CALLED AFTER GLFW INIT
|
||||
GraphicsDevice* device_create();
|
||||
void device_cleanup(GraphicsDevice* device);
|
||||
|
||||
void device_create_vulkan_instance(GraphicsDevice* device);
|
||||
void device_vulkan_debugger(GraphicsDevice* device);
|
||||
void device_create_vulkan_physical_device(GraphicsDevice* device);
|
||||
void device_create_vulkan_logical_device(GraphicsDevice* device);
|
||||
void device_create_command_pool(GraphicsDevice* device);
|
||||
|
||||
void device_resize_callback(GLFWwindow* device, int width, int height);
|
||||
|
||||
QueueFamilyIndices device_get_queue_families(GraphicsDevice* g, VkPhysicalDevice device);
|
||||
uint32_t device_find_memory_type(GraphicsDevice* g, uint32_t typeFilter, VkMemoryPropertyFlags properties);
|
||||
|
||||
}
|
||||
101
src/graphics/image.cpp
Normal file
101
src/graphics/image.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
#include "graphics/image.hpp"
|
||||
|
||||
#include "device.hpp"
|
||||
|
||||
#include "yolo/yolo.hpp"
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
void create_image(GraphicsDevice* device, uint32_t width, uint32_t height,
|
||||
VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory)
|
||||
{
|
||||
VkImageCreateInfo imageInfo {};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.extent.width = width;
|
||||
imageInfo.extent.height = height;
|
||||
imageInfo.extent.depth = 1;
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.arrayLayers = 1;
|
||||
imageInfo.format = format;
|
||||
imageInfo.tiling = tiling;
|
||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageInfo.usage = usage;
|
||||
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
if (vkCreateImage(device->VulkanDevice, &imageInfo, nullptr, &image) != VK_SUCCESS) {
|
||||
yolo::error("failed to create image!");
|
||||
}
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
vkGetImageMemoryRequirements(device->VulkanDevice, image, &memRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo {};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = memRequirements.size;
|
||||
allocInfo.memoryTypeIndex
|
||||
= device_find_memory_type(device, memRequirements.memoryTypeBits, properties);
|
||||
|
||||
if (vkAllocateMemory(device->VulkanDevice, &allocInfo, nullptr, &imageMemory)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to allocate image memory!");
|
||||
}
|
||||
|
||||
vkBindImageMemory(device->VulkanDevice, image, imageMemory, 0);
|
||||
}
|
||||
|
||||
VkImageView create_image_view(GraphicsDevice* device, VkImage image, VkFormat format,
|
||||
VkImageAspectFlags aspectFlags)
|
||||
{
|
||||
VkImageViewCreateInfo viewInfo {};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = image;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = format;
|
||||
viewInfo.subresourceRange.aspectMask = aspectFlags;
|
||||
viewInfo.subresourceRange.baseMipLevel = 0;
|
||||
viewInfo.subresourceRange.levelCount = 1;
|
||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
viewInfo.subresourceRange.layerCount = 1;
|
||||
|
||||
VkImageView imageView;
|
||||
if (vkCreateImageView(device->VulkanDevice, &viewInfo, nullptr, &imageView)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to create texture image view!");
|
||||
}
|
||||
|
||||
return imageView;
|
||||
}
|
||||
|
||||
VkFormat find_format(GraphicsDevice* device, const std::vector<VkFormat>& candidates,
|
||||
VkImageTiling tiling, VkFormatFeatureFlags features)
|
||||
{
|
||||
for (VkFormat format : candidates) {
|
||||
VkFormatProperties props;
|
||||
vkGetPhysicalDeviceFormatProperties(device->VulkanPhysicalDevice, format, &props);
|
||||
|
||||
if (tiling == VK_IMAGE_TILING_LINEAR
|
||||
&& (props.linearTilingFeatures & features) == features) {
|
||||
return format;
|
||||
} else if (tiling == VK_IMAGE_TILING_OPTIMAL
|
||||
&& (props.optimalTilingFeatures & features) == features) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error("failed to find supported format!");
|
||||
}
|
||||
|
||||
VkFormat find_depth_format(GraphicsDevice* device)
|
||||
{
|
||||
return VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||
return find_format(device,
|
||||
{ VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT },
|
||||
VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
20
src/graphics/image.hpp
Normal file
20
src/graphics/image.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics.hpp"
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
struct GraphicsDevice;
|
||||
|
||||
void create_image(GraphicsDevice* device, uint32_t width, uint32_t height,
|
||||
VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory);
|
||||
|
||||
VkImageView create_image_view(GraphicsDevice* device, VkImage image, VkFormat format,
|
||||
VkImageAspectFlags aspectFlags);
|
||||
|
||||
VkFormat find_format(GraphicsDevice* device, const std::vector<VkFormat>& candidates,
|
||||
VkImageTiling tiling, VkFormatFeatureFlags features);
|
||||
VkFormat find_depth_format(GraphicsDevice* device);
|
||||
|
||||
}
|
||||
207
src/graphics/pipeline.cpp
Normal file
207
src/graphics/pipeline.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
#include "pipeline.hpp"
|
||||
|
||||
#include "device.hpp"
|
||||
#include "shader.hpp"
|
||||
#include "swapchain.hpp"
|
||||
|
||||
#include "scene/mesh.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
#include "yolo/yolo.hpp"
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
Pipeline* pipeline_create(GraphicsDevice* device, SwapChain* swap, Shader* shader,
|
||||
uint32_t descriptorSetLayoutCount, VkDescriptorSetLayout* layouts, PipelineType type)
|
||||
{
|
||||
Pipeline* pipeline = new Pipeline();
|
||||
|
||||
pipeline->Device = device;
|
||||
pipeline->Swap = swap;
|
||||
pipeline->RelaventShader = shader;
|
||||
pipeline->Type = type;
|
||||
|
||||
pipeline->DescriptorSetLayoutCount = descriptorSetLayoutCount;
|
||||
pipeline->DescriptorSetLayouts = layouts;
|
||||
|
||||
auto bindingDescription
|
||||
= new VkVertexInputBindingDescription(scene::get_vert_binding_description());
|
||||
auto attributeDescriptions = new std::array<VkVertexInputAttributeDescription, 2>(
|
||||
scene::get_vert_attribute_descriptions());
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertexInputInfo {};
|
||||
vertexInputInfo.pNext = nullptr;
|
||||
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
vertexInputInfo.vertexBindingDescriptionCount = 1;
|
||||
vertexInputInfo.vertexAttributeDescriptionCount
|
||||
= static_cast<uint32_t>(attributeDescriptions->size());
|
||||
vertexInputInfo.pVertexBindingDescriptions = bindingDescription;
|
||||
vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions->data();
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssembly {};
|
||||
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
inputAssembly.primitiveRestartEnable = VK_FALSE;
|
||||
if (type == PIPELINE_TYPE_GRAPHICS_LINE) {
|
||||
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
|
||||
}
|
||||
|
||||
VkPipelineViewportStateCreateInfo viewportState {};
|
||||
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
viewportState.viewportCount = 1;
|
||||
viewportState.scissorCount = 1;
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rasterizer {};
|
||||
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
rasterizer.depthClampEnable = VK_FALSE; // NOTE: This is for shadow mapping
|
||||
rasterizer.rasterizerDiscardEnable = VK_FALSE;
|
||||
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rasterizer.lineWidth = 1.3f;
|
||||
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||
// rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||||
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||
rasterizer.depthBiasEnable = VK_FALSE;
|
||||
if (type == PIPELINE_TYPE_GRAPHICS_LINE) {
|
||||
rasterizer.polygonMode = VK_POLYGON_MODE_LINE;
|
||||
rasterizer.cullMode = VK_CULL_MODE_NONE;
|
||||
}
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo multisampling {};
|
||||
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
multisampling.sampleShadingEnable = VK_FALSE;
|
||||
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
VkPipelineColorBlendAttachmentState colorBlendAttachment {};
|
||||
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT
|
||||
| VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
// Alpha blending
|
||||
colorBlendAttachment.blendEnable = VK_TRUE;
|
||||
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||
colorBlendAttachment.dstColorBlendFactor
|
||||
= VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo colorBlending {};
|
||||
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
colorBlending.logicOpEnable = VK_FALSE;
|
||||
colorBlending.logicOp = VK_LOGIC_OP_COPY; // Optional
|
||||
colorBlending.attachmentCount = 1;
|
||||
colorBlending.pAttachments = &colorBlendAttachment;
|
||||
colorBlending.blendConstants[0] = 0.0f; // Optional
|
||||
colorBlending.blendConstants[1] = 0.0f; // Optional
|
||||
colorBlending.blendConstants[2] = 0.0f; // Optional
|
||||
colorBlending.blendConstants[3] = 0.0f; // pipeline->Optional
|
||||
|
||||
VkPipelineDepthStencilStateCreateInfo depthState {};
|
||||
depthState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||
depthState.depthTestEnable = VK_TRUE;
|
||||
depthState.depthWriteEnable = VK_TRUE;
|
||||
depthState.depthCompareOp = VK_COMPARE_OP_LESS;
|
||||
depthState.depthBoundsTestEnable = VK_TRUE;
|
||||
depthState.minDepthBounds = 0.0f;
|
||||
depthState.maxDepthBounds = 1.0f;
|
||||
depthState.stencilTestEnable = VK_FALSE;
|
||||
depthState.front = {};
|
||||
depthState.back = {};
|
||||
|
||||
VkPipelineDynamicStateCreateInfo dynamicStatesCreateInfo {};
|
||||
std::vector<VkDynamicState> dynamicStates
|
||||
= { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
|
||||
dynamicStatesCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||
dynamicStatesCreateInfo.dynamicStateCount
|
||||
= static_cast<uint32_t>(dynamicStates.size());
|
||||
dynamicStatesCreateInfo.pDynamicStates = dynamicStates.data();
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo {};
|
||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipelineLayoutInfo.setLayoutCount = descriptorSetLayoutCount;
|
||||
pipelineLayoutInfo.pSetLayouts = layouts;
|
||||
pipelineLayoutInfo.pushConstantRangeCount = 0; // Optional
|
||||
|
||||
if (vkCreatePipelineLayout(
|
||||
device->VulkanDevice, &pipelineLayoutInfo, nullptr, &pipeline->Layout)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to create pipeline layout!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VkPipelineRenderingCreateInfo renderingPipelineInfo = {};
|
||||
renderingPipelineInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR;
|
||||
renderingPipelineInfo.colorAttachmentCount = 1;
|
||||
renderingPipelineInfo.pColorAttachmentFormats = &swap->ImageFormat;
|
||||
renderingPipelineInfo.depthAttachmentFormat = find_depth_format(device);
|
||||
renderingPipelineInfo.pNext = nullptr;
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipelineInfo.stageCount = SHADER_STAGES;
|
||||
pipelineInfo.pStages = shader->ShaderStages;
|
||||
pipelineInfo.pNext = &renderingPipelineInfo;
|
||||
|
||||
pipelineInfo.pVertexInputState = &vertexInputInfo;
|
||||
pipelineInfo.pInputAssemblyState = &inputAssembly;
|
||||
pipelineInfo.pViewportState = &viewportState;
|
||||
pipelineInfo.pRasterizationState = &rasterizer;
|
||||
pipelineInfo.pMultisampleState = &multisampling;
|
||||
pipelineInfo.pColorBlendState = &colorBlending;
|
||||
pipelineInfo.pDynamicState = &dynamicStatesCreateInfo;
|
||||
pipelineInfo.pDepthStencilState = &depthState;
|
||||
pipelineInfo.pTessellationState = VK_NULL_HANDLE; // Optional
|
||||
pipelineInfo.layout = pipeline->Layout;
|
||||
pipelineInfo.subpass = 0;
|
||||
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; // Optional
|
||||
|
||||
yolo::debug("All Binding Description: {} stride: {}",
|
||||
vertexInputInfo.pVertexBindingDescriptions->binding,
|
||||
vertexInputInfo.pVertexBindingDescriptions->stride);
|
||||
yolo::debug("All Attribute Description0: {} location: {} format: {} offset: {}",
|
||||
vertexInputInfo.pVertexAttributeDescriptions[0].binding,
|
||||
vertexInputInfo.pVertexAttributeDescriptions[0].location,
|
||||
vertexInputInfo.pVertexAttributeDescriptions[0].format,
|
||||
vertexInputInfo.pVertexAttributeDescriptions[0].offset);
|
||||
yolo::debug("All Attribute Description1: {} location: {} format: {} offset: {}",
|
||||
vertexInputInfo.pVertexAttributeDescriptions[1].binding,
|
||||
vertexInputInfo.pVertexAttributeDescriptions[1].location,
|
||||
vertexInputInfo.pVertexAttributeDescriptions[1].format,
|
||||
vertexInputInfo.pVertexAttributeDescriptions[1].offset);
|
||||
|
||||
if (vkCreateGraphicsPipelines(device->VulkanDevice, VK_NULL_HANDLE, 1, &pipelineInfo,
|
||||
nullptr, &pipeline->GraphicsPipeline)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to create graphics pipeline!");
|
||||
}
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
void pipeline_cleanup(Pipeline* pipeline)
|
||||
{
|
||||
vkDestroyPipeline(
|
||||
pipeline->Device->VulkanDevice, pipeline->GraphicsPipeline, nullptr);
|
||||
vkDestroyPipelineLayout(pipeline->Device->VulkanDevice, pipeline->Layout, nullptr);
|
||||
delete pipeline;
|
||||
}
|
||||
|
||||
void pipeline_recreate(Pipeline* pipeline)
|
||||
{
|
||||
vkDeviceWaitIdle(pipeline->Device->VulkanDevice);
|
||||
GraphicsDevice* device = pipeline->Device;
|
||||
SwapChain* swap = pipeline->Swap;
|
||||
|
||||
swapchain_recreate(swap);
|
||||
|
||||
Shader* shader = pipeline->RelaventShader;
|
||||
uint32_t descriptorSetLayoutCount = descriptorSetLayoutCount;
|
||||
VkDescriptorSetLayout* layouts = pipeline->DescriptorSetLayouts;
|
||||
PipelineType type = pipeline->Type;
|
||||
|
||||
pipeline_cleanup(pipeline);
|
||||
pipeline = pipeline_create(device, swap, shader, descriptorSetLayoutCount, layouts, type);
|
||||
}
|
||||
|
||||
} // namespace inferno::graphics
|
||||
39
src/graphics/pipeline.hpp
Normal file
39
src/graphics/pipeline.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics.hpp"
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
struct GraphicsDevice;
|
||||
struct RenderPass;
|
||||
struct SwapChain;
|
||||
struct Shader;
|
||||
|
||||
typedef enum PipelineType {
|
||||
PIPELINE_TYPE_GRAPHICS,
|
||||
PIPELINE_TYPE_GRAPHICS_LINE,
|
||||
PIPELINE_TYPE_COMPUTE,
|
||||
PIPELINE_TYPE_RAYTRACING
|
||||
} PipelineType;
|
||||
|
||||
typedef struct Pipeline {
|
||||
GraphicsDevice* Device;
|
||||
SwapChain* Swap;
|
||||
Shader* RelaventShader;
|
||||
|
||||
uint32_t DescriptorSetLayoutCount;
|
||||
VkDescriptorSetLayout* DescriptorSetLayouts;
|
||||
|
||||
VkPipeline GraphicsPipeline;
|
||||
VkPipelineLayout Layout;
|
||||
|
||||
PipelineType Type;
|
||||
} Pipeline;
|
||||
|
||||
Pipeline* pipeline_create(GraphicsDevice* device, SwapChain* swap, Shader* shader,
|
||||
uint32_t descriptorSetLayoutCount, VkDescriptorSetLayout* layouts, PipelineType type);
|
||||
void pipeline_cleanup(Pipeline* pipeline);
|
||||
|
||||
void pipeline_recreate(Pipeline* pipeline);
|
||||
|
||||
}
|
||||
114
src/graphics/rendertarget.cpp
Normal file
114
src/graphics/rendertarget.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
#include "rendertarget.hpp"
|
||||
|
||||
#include "device.hpp"
|
||||
#include "graphics.hpp"
|
||||
#include "image.hpp"
|
||||
|
||||
#include "yolo/yolo.hpp"
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
RenderTarget* rendertarget_create(
|
||||
GraphicsDevice* device, VkExtent2D extent, VkFormat format, bool depth)
|
||||
{
|
||||
RenderTarget* target = new RenderTarget();
|
||||
target->Device = device;
|
||||
target->Format = format;
|
||||
target->Extent = extent;
|
||||
|
||||
VkSamplerCreateInfo samplerInfo {};
|
||||
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
samplerInfo.magFilter = VK_FILTER_LINEAR;
|
||||
samplerInfo.minFilter = VK_FILTER_LINEAR;
|
||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
samplerInfo.anisotropyEnable = VK_FALSE;
|
||||
samplerInfo.maxAnisotropy = 1.0f;
|
||||
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
||||
samplerInfo.unnormalizedCoordinates = VK_FALSE;
|
||||
samplerInfo.compareEnable = VK_FALSE;
|
||||
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
samplerInfo.mipLodBias = 0.0f;
|
||||
samplerInfo.minLod = 0.0f;
|
||||
samplerInfo.maxLod = 0.0f;
|
||||
|
||||
if (vkCreateSampler(device->VulkanDevice, &samplerInfo, nullptr, &target->Sampler)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to create texture sampler!");
|
||||
}
|
||||
|
||||
create_image(device, extent.width, extent.height, format, VK_IMAGE_TILING_OPTIMAL,
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, target->Image, target->Memory);
|
||||
|
||||
|
||||
target->ImageView
|
||||
= create_image_view(device, target->Image, format, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
|
||||
target->DescriptorSet = ImGui_ImplVulkan_AddTexture(
|
||||
target->Sampler, target->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
if (depth) {
|
||||
rendertarget_create_depth(target);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
void rendertarget_cleanup(RenderTarget* target)
|
||||
{
|
||||
vkDestroyImageView(target->Device->VulkanDevice, target->ImageView, nullptr);
|
||||
vkDestroyImage(target->Device->VulkanDevice, target->Image, nullptr);
|
||||
vkFreeMemory(target->Device->VulkanDevice, target->Memory, nullptr);
|
||||
|
||||
rendertarget_destroy_depth(target);
|
||||
|
||||
delete target;
|
||||
}
|
||||
|
||||
void rendertarget_create_depth(RenderTarget* target)
|
||||
{
|
||||
VkFormat depthFormat = find_depth_format(target->Device);
|
||||
|
||||
target->TargetDepth = new DepthAttachment();
|
||||
target->TargetDepth->Format = depthFormat;
|
||||
|
||||
create_image(target->Device, target->Extent.width, target->Extent.height, depthFormat,
|
||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, target->TargetDepth->Image,
|
||||
target->TargetDepth->Memory);
|
||||
|
||||
target->TargetDepth->ImageView = create_image_view(target->Device, target->TargetDepth->Image,
|
||||
depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
}
|
||||
|
||||
void rendertarget_destroy_depth(RenderTarget* target)
|
||||
{
|
||||
if (target->TargetDepth != nullptr) {
|
||||
vkDestroyImageView(
|
||||
target->Device->VulkanDevice, target->TargetDepth->ImageView, nullptr);
|
||||
vkDestroyImage(target->Device->VulkanDevice, target->TargetDepth->Image, nullptr);
|
||||
vkFreeMemory(target->Device->VulkanDevice, target->TargetDepth->Memory, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void rendertarget_recreate(RenderTarget* target, VkExtent2D extent, VkFormat format)
|
||||
{
|
||||
vkDeviceWaitIdle(target->Device->VulkanDevice);
|
||||
|
||||
bool doDepth = target->TargetDepth != nullptr;
|
||||
|
||||
rendertarget_cleanup(target);
|
||||
|
||||
target->Extent = extent;
|
||||
target->Format = format;
|
||||
|
||||
rendertarget_create(target->Device, extent, format, doDepth);
|
||||
|
||||
// if (doDepth)
|
||||
// rendertarget_create_depth(target);
|
||||
}
|
||||
|
||||
}
|
||||
48
src/graphics/rendertarget.hpp
Normal file
48
src/graphics/rendertarget.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics.hpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
struct GraphicsDevice;
|
||||
|
||||
// TODO: Should probably be "ImageAttachment" and then the
|
||||
// target will abstract which sort of attachment it is
|
||||
typedef struct DepthAttachment {
|
||||
VkImage Image;
|
||||
VkDeviceMemory Memory;
|
||||
VkImageView ImageView;
|
||||
VkFormat Format;
|
||||
} DepthAttachment;
|
||||
|
||||
// TODO: What about the present mode?
|
||||
typedef struct RenderTarget {
|
||||
VkImage Image;
|
||||
VkDeviceMemory Memory;
|
||||
VkImageView ImageView;
|
||||
|
||||
VkFormat Format;
|
||||
VkExtent2D Extent;
|
||||
|
||||
DepthAttachment* TargetDepth = nullptr;
|
||||
|
||||
// NOTE: This is for the ImGui renderer.. it needs a descriptor set of a sampler of an
|
||||
// image
|
||||
VkSampler Sampler;
|
||||
VkDescriptorSet DescriptorSet;
|
||||
|
||||
GraphicsDevice* Device;
|
||||
} RenderTarget;
|
||||
|
||||
RenderTarget* rendertarget_create(
|
||||
GraphicsDevice* device, VkExtent2D extent, VkFormat format, bool depth);
|
||||
void rendertarget_cleanup(RenderTarget* target);
|
||||
|
||||
void rendertarget_create_depth(RenderTarget* target);
|
||||
void rendertarget_destroy_depth(RenderTarget* target);
|
||||
|
||||
void rendertarget_recreate(RenderTarget* target, VkExtent2D extent, VkFormat format);
|
||||
|
||||
}
|
||||
223
src/graphics/shader.cpp
Normal file
223
src/graphics/shader.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
#include "shader.hpp"
|
||||
|
||||
#include "buffer.hpp"
|
||||
#include "device.hpp"
|
||||
#include "pipeline.hpp"
|
||||
#include "swapchain.hpp"
|
||||
|
||||
#include "scene/scene.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "yolo/yolo.hpp"
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
std::string textFromFile(const std::filesystem::path& path)
|
||||
{
|
||||
std::ifstream input(path);
|
||||
return std::string(
|
||||
(std::istreambuf_iterator<char>(input)), std::istreambuf_iterator<char>());
|
||||
}
|
||||
|
||||
Shader* shader_create(
|
||||
GraphicsDevice* device, SwapChain* swapchain, ShaderProgramType type)
|
||||
{
|
||||
Shader* shader = new Shader;
|
||||
shader->Device = device;
|
||||
shader->GraphicsSwapchain = swapchain;
|
||||
shader->Type = type;
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
void shader_cleanup(Shader* shader)
|
||||
{
|
||||
uniform_buffer_cleanup(shader->GlobalUniformBuffer);
|
||||
pipeline_cleanup(shader->GraphicsPipeline);
|
||||
vkDestroyDescriptorPool(
|
||||
shader->Device->VulkanDevice, shader->DescriptorPool, nullptr);
|
||||
vkDestroyDescriptorSetLayout(
|
||||
shader->Device->VulkanDevice, shader->DescriptorLayout, nullptr);
|
||||
vkDestroyShaderModule(shader->Device->VulkanDevice, shader->VertexShader, nullptr);
|
||||
vkDestroyShaderModule(shader->Device->VulkanDevice, shader->FragmentShader, nullptr);
|
||||
delete shader;
|
||||
}
|
||||
|
||||
void shader_load(Shader* shader, std::filesystem::path path)
|
||||
{
|
||||
std::string shaderPath = path.string();
|
||||
std::string vertexShaderPath = shaderPath + ".vert.spv";
|
||||
std::string fragmentShaderPath = shaderPath + ".frag.spv";
|
||||
assert(std::filesystem::exists(vertexShaderPath));
|
||||
assert(std::filesystem::exists(fragmentShaderPath));
|
||||
|
||||
std::string vertexLoadedShaderCode = textFromFile(vertexShaderPath);
|
||||
VkShaderModuleCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
createInfo.codeSize = vertexLoadedShaderCode.size();
|
||||
createInfo.pCode = (uint32_t*)(vertexLoadedShaderCode.data());
|
||||
|
||||
if (vkCreateShaderModule(
|
||||
shader->Device->VulkanDevice, &createInfo, nullptr, &shader->VertexShader)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to create shader module");
|
||||
}
|
||||
|
||||
memset(&shader->ShaderStages, 0,
|
||||
SHADER_STAGES * sizeof(VkPipelineShaderStageCreateInfo));
|
||||
|
||||
shader->ShaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
shader->ShaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
shader->ShaderStages[0].module = shader->VertexShader;
|
||||
shader->ShaderStages[0].pName = "main";
|
||||
shader->ShaderStages[0].pSpecializationInfo = nullptr; // Optional
|
||||
shader->ShaderStages[0].flags = 0; // Optional
|
||||
shader->ShaderStages[0].pNext = nullptr; // Optional
|
||||
|
||||
std::string fragmentLoadedShaderCode = textFromFile(fragmentShaderPath);
|
||||
VkShaderModuleCreateInfo createInfo2 = {};
|
||||
createInfo2.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
createInfo2.codeSize = fragmentLoadedShaderCode.size();
|
||||
createInfo2.pCode = (uint32_t*)(fragmentLoadedShaderCode.data());
|
||||
|
||||
if (vkCreateShaderModule(
|
||||
shader->Device->VulkanDevice, &createInfo2, nullptr, &shader->FragmentShader)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to create shader module");
|
||||
}
|
||||
|
||||
shader->ShaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
shader->ShaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
shader->ShaderStages[1].module = shader->FragmentShader;
|
||||
shader->ShaderStages[1].pName = "main";
|
||||
shader->ShaderStages[0].pSpecializationInfo = nullptr; // Optional
|
||||
shader->ShaderStages[0].flags = 0; // Optional
|
||||
shader->ShaderStages[0].pNext = nullptr; // Optional
|
||||
}
|
||||
|
||||
void shader_update_state(Shader* shader, VkCommandBuffer commandBuffer,
|
||||
scene::GlobalUniformObject object, uint32_t frameIndex)
|
||||
{
|
||||
VkDescriptorSet descriptorSet = shader->Descriptors[frameIndex];
|
||||
|
||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
shader->GraphicsPipeline->Layout, 0, 1, &descriptorSet, 0, nullptr);
|
||||
|
||||
uniform_buffer_update(shader->GlobalUniformBuffer, &object);
|
||||
|
||||
VkDescriptorBufferInfo bufferInfo {};
|
||||
bufferInfo.buffer = shader->GlobalUniformBuffer->Handle;
|
||||
bufferInfo.offset = 0;
|
||||
bufferInfo.range = sizeof(scene::GlobalUniformObject);
|
||||
|
||||
VkWriteDescriptorSet descriptorWrite {};
|
||||
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptorWrite.dstSet = descriptorSet;
|
||||
descriptorWrite.dstBinding = 0;
|
||||
descriptorWrite.dstArrayElement = 0;
|
||||
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
descriptorWrite.descriptorCount = 1;
|
||||
descriptorWrite.pBufferInfo = &bufferInfo;
|
||||
|
||||
vkUpdateDescriptorSets(shader->Device->VulkanDevice, 1, &descriptorWrite, 0, nullptr);
|
||||
}
|
||||
|
||||
// build the desriptor set layout and pipeline layout
|
||||
void shader_build(Shader* shader)
|
||||
{
|
||||
VkDescriptorSetLayoutBinding uboLayoutBinding {};
|
||||
uboLayoutBinding.binding = 0;
|
||||
uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
uboLayoutBinding.descriptorCount = 1;
|
||||
uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
uboLayoutBinding.pImmutableSamplers = nullptr; // Optional
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo layoutInfo {};
|
||||
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
layoutInfo.bindingCount = 1;
|
||||
layoutInfo.pBindings = &uboLayoutBinding;
|
||||
|
||||
if (vkCreateDescriptorSetLayout(
|
||||
shader->Device->VulkanDevice, &layoutInfo, nullptr, &shader->DescriptorLayout)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to create descriptor set layout!");
|
||||
}
|
||||
|
||||
VkDescriptorPoolSize poolSize {};
|
||||
poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
poolSize.descriptorCount = static_cast<uint32_t>(FRAMES_IN_FLIGHT);
|
||||
|
||||
VkDescriptorPoolCreateInfo poolInfo {};
|
||||
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
poolInfo.poolSizeCount = 1;
|
||||
poolInfo.pPoolSizes = &poolSize;
|
||||
poolInfo.maxSets = static_cast<uint32_t>(FRAMES_IN_FLIGHT);
|
||||
|
||||
if (vkCreateDescriptorPool(
|
||||
shader->Device->VulkanDevice, &poolInfo, nullptr, &shader->DescriptorPool)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to create descriptor pool!");
|
||||
}
|
||||
|
||||
std::vector<VkDescriptorSetLayout> layouts(
|
||||
FRAMES_IN_FLIGHT, shader->DescriptorLayout);
|
||||
VkDescriptorSetAllocateInfo allocInfo {};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
allocInfo.descriptorPool = shader->DescriptorPool;
|
||||
allocInfo.descriptorSetCount = static_cast<uint32_t>(FRAMES_IN_FLIGHT);
|
||||
allocInfo.pSetLayouts = layouts.data();
|
||||
|
||||
if (vkAllocateDescriptorSets(
|
||||
shader->Device->VulkanDevice, &allocInfo, shader->Descriptors)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to allocate descriptor sets!");
|
||||
}
|
||||
|
||||
PipelineType pipelineType = PIPELINE_TYPE_GRAPHICS;
|
||||
switch (shader->Type) {
|
||||
case SHADER_PROGRAM_TYPE_GRAPHICS:
|
||||
pipelineType = PIPELINE_TYPE_GRAPHICS;
|
||||
break;
|
||||
case SHADER_PROGRAM_TYPE_GRAPHICS_LINE:
|
||||
pipelineType = PIPELINE_TYPE_GRAPHICS_LINE;
|
||||
break;
|
||||
default:
|
||||
yolo::error("Shader type not supported");
|
||||
break;
|
||||
}
|
||||
|
||||
shader->GraphicsPipeline = pipeline_create(shader->Device, shader->GraphicsSwapchain,
|
||||
shader, layouts.size(), layouts.data(), pipelineType);
|
||||
shader->GlobalUniformBuffer
|
||||
= uniform_buffer_create<scene::GlobalUniformObject>(shader->Device, true);
|
||||
}
|
||||
|
||||
void shader_use(Shader* shader, VkCommandBuffer commandBuffer, VkRect2D renderArea)
|
||||
{
|
||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
shader->GraphicsPipeline->GraphicsPipeline);
|
||||
|
||||
VkViewport viewport {};
|
||||
viewport.x = 0.0f;
|
||||
// viewport.y = static_cast<float>(renderArea.extent.height);
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = static_cast<float>(renderArea.extent.width);
|
||||
viewport.height = static_cast<float>(renderArea.extent.height);
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||
|
||||
VkRect2D scissor {};
|
||||
scissor.offset = { 0, 0 };
|
||||
scissor.extent = renderArea.extent;
|
||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||
}
|
||||
|
||||
void shader_unuse(Shader* shader, VkCommandBuffer commandBuffer)
|
||||
{
|
||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, VK_NULL_HANDLE);
|
||||
}
|
||||
|
||||
}
|
||||
73
src/graphics/shader.hpp
Normal file
73
src/graphics/shader.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#include "../graphics.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace inferno::scene {
|
||||
struct GlobalUniformObject;
|
||||
}
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
struct GraphicsDevice;
|
||||
struct SwapChain;
|
||||
struct Pipeline;
|
||||
struct GenBuffer;
|
||||
|
||||
typedef enum ShaderProgramType {
|
||||
SHADER_PROGRAM_TYPE_GRAPHICS,
|
||||
SHADER_PROGRAM_TYPE_GRAPHICS_LINE,
|
||||
SHADER_PROGRAM_TYPE_COMPUTE,
|
||||
SHADER_PROGRAM_TYPE_RAYTRACING
|
||||
} ShaderProgramType;
|
||||
|
||||
typedef struct ShaderPushConst {
|
||||
union {
|
||||
glm::mat4 mat[2]; // 64 bytes each
|
||||
float data[16];
|
||||
};
|
||||
} ShaderPushConstants;
|
||||
|
||||
// TODO: Make general
|
||||
typedef struct Shader {
|
||||
GraphicsDevice* Device;
|
||||
|
||||
ShaderProgramType Type;
|
||||
|
||||
SwapChain* GraphicsSwapchain;
|
||||
Pipeline* GraphicsPipeline;
|
||||
|
||||
VkDescriptorPool DescriptorPool;
|
||||
VkDescriptorSet Descriptors[FRAMES_IN_FLIGHT];
|
||||
VkDescriptorSetLayout DescriptorLayout;
|
||||
|
||||
GenBuffer* GlobalUniformBuffer;
|
||||
|
||||
VkShaderModule VertexShader;
|
||||
VkShaderModule FragmentShader;
|
||||
VkPipelineShaderStageCreateInfo ShaderStages[SHADER_STAGES];
|
||||
VkPipelineVertexInputStateCreateInfo VertexInputInfo;
|
||||
} Shader;
|
||||
|
||||
Shader* shader_create(
|
||||
GraphicsDevice* device, SwapChain* swapchain, ShaderProgramType type);
|
||||
void shader_cleanup(Shader* shader);
|
||||
|
||||
void shader_load(Shader* shader, std::filesystem::path path);
|
||||
|
||||
void shader_update_state(Shader* shader, VkCommandBuffer commandBuffer,
|
||||
scene::GlobalUniformObject object, uint32_t frameIndex);
|
||||
void shader_push_const(glm::mat4 mat);
|
||||
|
||||
// actually creates the pipeline
|
||||
void shader_build(Shader* shader);
|
||||
|
||||
void shader_use(Shader* shader, VkCommandBuffer commandBuffer, VkRect2D renderArea);
|
||||
void shader_unuse(Shader* shader, VkCommandBuffer commandBuffer);
|
||||
|
||||
}
|
||||
208
src/graphics/swapchain.cpp
Normal file
208
src/graphics/swapchain.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
#include "swapchain.hpp"
|
||||
|
||||
#include "graphics.hpp"
|
||||
|
||||
#include "device.hpp"
|
||||
#include "image.hpp"
|
||||
|
||||
#include "yolo/yolo.hpp"
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
struct SwapChainSupportDetails {
|
||||
VkSurfaceCapabilitiesKHR Capabilities;
|
||||
std::vector<VkSurfaceFormatKHR> Formats;
|
||||
std::vector<VkPresentModeKHR> PresentModes;
|
||||
};
|
||||
|
||||
SwapChainSupportDetails device_get_swapchain_support(
|
||||
GraphicsDevice* g, VkPhysicalDevice device)
|
||||
{
|
||||
SwapChainSupportDetails details;
|
||||
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
|
||||
device, g->VulkanSurface, &details.Capabilities);
|
||||
|
||||
uint32_t formatCount;
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(device, g->VulkanSurface, &formatCount, nullptr);
|
||||
|
||||
if (formatCount != 0) {
|
||||
details.Formats.resize(formatCount);
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(
|
||||
device, g->VulkanSurface, &formatCount, details.Formats.data());
|
||||
}
|
||||
|
||||
uint32_t presentModeCount;
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(
|
||||
device, g->VulkanSurface, &presentModeCount, nullptr);
|
||||
|
||||
if (presentModeCount != 0) {
|
||||
details.PresentModes.resize(presentModeCount);
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(
|
||||
device, g->VulkanSurface, &presentModeCount, details.PresentModes.data());
|
||||
}
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
VkSurfaceFormatKHR device_choose_swap_surface_format(
|
||||
const std::vector<VkSurfaceFormatKHR>& availableFormats)
|
||||
{
|
||||
for (const auto& availableFormat : availableFormats) {
|
||||
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB
|
||||
&& availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
||||
return availableFormat;
|
||||
}
|
||||
}
|
||||
|
||||
return availableFormats[0];
|
||||
}
|
||||
|
||||
VkPresentModeKHR device_choose_swap_present_mode(
|
||||
const std::vector<VkPresentModeKHR>& availablePresentModes)
|
||||
{
|
||||
for (const auto& availablePresentMode : availablePresentModes) {
|
||||
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
|
||||
return availablePresentMode;
|
||||
}
|
||||
}
|
||||
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
}
|
||||
|
||||
VkExtent2D device_choose_swap_extent(
|
||||
const VkSurfaceCapabilitiesKHR& capabilities, int width, int height)
|
||||
{
|
||||
if (capabilities.currentExtent.width != UINT32_MAX) {
|
||||
yolo::info("Surface size: {}x{}", capabilities.currentExtent.width,
|
||||
capabilities.currentExtent.height);
|
||||
return capabilities.currentExtent;
|
||||
} else {
|
||||
VkExtent2D actualExtent = { (uint32_t)width, (uint32_t)height };
|
||||
yolo::info("Surface size: {}x{}", width, height);
|
||||
|
||||
actualExtent.width = std::max(capabilities.minImageExtent.width,
|
||||
std::min(capabilities.maxImageExtent.width, actualExtent.width));
|
||||
|
||||
actualExtent.height = std::max(capabilities.minImageExtent.height,
|
||||
std::min(capabilities.maxImageExtent.height, actualExtent.height));
|
||||
|
||||
return actualExtent;
|
||||
}
|
||||
}
|
||||
|
||||
SwapChain* swapchain_create(GraphicsDevice* device, glm::ivec2 surface_size)
|
||||
{
|
||||
SwapChain* swapchain = new SwapChain();
|
||||
|
||||
SwapChainSupportDetails swapChainSupport
|
||||
= device_get_swapchain_support(device, device->VulkanPhysicalDevice);
|
||||
|
||||
VkSurfaceFormatKHR surfaceFormat
|
||||
= device_choose_swap_surface_format(swapChainSupport.Formats);
|
||||
VkPresentModeKHR presentMode
|
||||
= device_choose_swap_present_mode(swapChainSupport.PresentModes);
|
||||
yolo::debug("Surface format: {}", surfaceFormat.format);
|
||||
VkExtent2D extent = device_choose_swap_extent(
|
||||
swapChainSupport.Capabilities, surface_size.x, surface_size.y);
|
||||
swapchain->Extent = extent;
|
||||
uint32_t imageCount = swapChainSupport.Capabilities.minImageCount + 1;
|
||||
|
||||
if (swapChainSupport.Capabilities.maxImageCount > 0
|
||||
&& imageCount > swapChainSupport.Capabilities.maxImageCount) {
|
||||
imageCount = swapChainSupport.Capabilities.maxImageCount;
|
||||
}
|
||||
|
||||
VkSwapchainCreateInfoKHR createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
createInfo.surface = device->VulkanSurface;
|
||||
createInfo.minImageCount = imageCount;
|
||||
|
||||
createInfo.imageFormat = surfaceFormat.format;
|
||||
createInfo.imageColorSpace = surfaceFormat.colorSpace;
|
||||
createInfo.imageExtent = extent;
|
||||
createInfo.imageArrayLayers = 1;
|
||||
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
QueueFamilyIndices indices
|
||||
= device_get_queue_families(device, device->VulkanPhysicalDevice);
|
||||
uint32_t queueFamilyIndices[]
|
||||
= { indices.graphicsFamily.value(), indices.presentFamily.value() };
|
||||
|
||||
if (indices.graphicsFamily != indices.presentFamily) {
|
||||
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||
createInfo.queueFamilyIndexCount = 2;
|
||||
createInfo.pQueueFamilyIndices = queueFamilyIndices;
|
||||
} else {
|
||||
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
createInfo.queueFamilyIndexCount = 0; // Optional
|
||||
createInfo.pQueueFamilyIndices = nullptr; // Optional
|
||||
}
|
||||
|
||||
createInfo.preTransform = swapChainSupport.Capabilities.currentTransform;
|
||||
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
createInfo.presentMode = presentMode;
|
||||
createInfo.clipped = VK_TRUE;
|
||||
createInfo.oldSwapchain = VK_NULL_HANDLE;
|
||||
|
||||
if (vkCreateSwapchainKHR(
|
||||
device->VulkanDevice, &createInfo, nullptr, &swapchain->Handle)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to create swap chain!");
|
||||
exit(1);
|
||||
}
|
||||
yolo::info("Swap chain created");
|
||||
|
||||
vkGetSwapchainImagesKHR(
|
||||
device->VulkanDevice, swapchain->Handle, &imageCount, nullptr);
|
||||
swapchain->Images.resize(imageCount);
|
||||
vkGetSwapchainImagesKHR(
|
||||
device->VulkanDevice, swapchain->Handle, &imageCount, swapchain->Images.data());
|
||||
|
||||
swapchain->ImageFormat = surfaceFormat.format;
|
||||
swapchain->Device = device;
|
||||
|
||||
swapchain_image_view_create(swapchain);
|
||||
|
||||
return swapchain;
|
||||
}
|
||||
|
||||
void swapchain_cleanup(SwapChain* swapchain)
|
||||
{
|
||||
for (auto imageView : swapchain->ImageViews) {
|
||||
vkDestroyImageView(swapchain->Device->VulkanDevice, imageView, nullptr);
|
||||
}
|
||||
vkDestroySwapchainKHR(swapchain->Device->VulkanDevice, swapchain->Handle, nullptr);
|
||||
delete swapchain;
|
||||
}
|
||||
|
||||
void swapchain_image_view_create(SwapChain* swapchain)
|
||||
{
|
||||
swapchain->ImageViews.resize(swapchain->Images.size());
|
||||
|
||||
for (size_t i = 0; i < swapchain->Images.size(); i++) {
|
||||
swapchain->ImageViews[i] = create_image_view(swapchain->Device,
|
||||
swapchain->Images[i], swapchain->ImageFormat, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
}
|
||||
|
||||
VkFormat depthFormat = find_depth_format(swapchain->Device);
|
||||
swapchain->DepthFormat = depthFormat;
|
||||
|
||||
create_image(swapchain->Device, swapchain->Extent.width, swapchain->Extent.height,
|
||||
depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, swapchain->depthImage,
|
||||
swapchain->depthImageMemory);
|
||||
swapchain->DepthImageView = create_image_view(
|
||||
swapchain->Device, swapchain->depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
}
|
||||
|
||||
void swapchain_recreate(SwapChain* swapchain)
|
||||
{
|
||||
vkDeviceWaitIdle(swapchain->Device->VulkanDevice);
|
||||
GraphicsDevice* device = swapchain->Device;
|
||||
|
||||
swapchain_cleanup(swapchain);
|
||||
swapchain = swapchain_create(device, device->SurfaceSize);
|
||||
}
|
||||
|
||||
}
|
||||
37
src/graphics/swapchain.hpp
Normal file
37
src/graphics/swapchain.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics.hpp"
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
struct GraphicsDevice;
|
||||
|
||||
struct RenderPass;
|
||||
|
||||
typedef struct SwapChain {
|
||||
VkSwapchainKHR Handle;
|
||||
VkFormat ImageFormat;
|
||||
VkFormat DepthFormat;
|
||||
VkExtent2D Extent;
|
||||
|
||||
std::vector<VkImage> Images;
|
||||
std::vector<VkImageView> ImageViews;
|
||||
|
||||
VkImage depthImage;
|
||||
VkDeviceMemory depthImageMemory;
|
||||
VkImageView DepthImageView;
|
||||
|
||||
GraphicsDevice* Device;
|
||||
} SwapChain;
|
||||
|
||||
SwapChain* swapchain_create(GraphicsDevice* device, glm::ivec2 surface_size);
|
||||
void swapchain_cleanup(SwapChain* swapchain);
|
||||
|
||||
void swapchain_image_view_create(SwapChain* swapchain);
|
||||
void swapchain_framebuffers_create(SwapChain* swapchain);
|
||||
|
||||
void swapchain_recreate(SwapChain* swapchain);
|
||||
|
||||
VkFormat find_depth_format(GraphicsDevice* device);
|
||||
|
||||
}
|
||||
399
src/graphics/vkrenderer.cpp
Normal file
399
src/graphics/vkrenderer.cpp
Normal file
@@ -0,0 +1,399 @@
|
||||
#include "vkrenderer.hpp"
|
||||
|
||||
#include "device.hpp"
|
||||
#include "graphics.hpp"
|
||||
#include "pipeline.hpp"
|
||||
#include "rendertarget.hpp"
|
||||
#include "swapchain.hpp"
|
||||
|
||||
#include "gui/gui.hpp"
|
||||
|
||||
#include "yolo/yolo.hpp"
|
||||
#include <functional>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
VulkanRenderer* renderer_create(GraphicsDevice* device)
|
||||
{
|
||||
auto renderer = new VulkanRenderer();
|
||||
renderer->Device = device;
|
||||
renderer->Swap = swapchain_create(device, device->SurfaceSize);
|
||||
|
||||
renderer->InFlight.resize(FRAMES_IN_FLIGHT);
|
||||
|
||||
// Creating the synchronization objects
|
||||
VkSemaphoreCreateInfo semaphoreInfo = {};
|
||||
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
|
||||
VkFenceCreateInfo fenceInfo = {};
|
||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; // Start in signaled state
|
||||
|
||||
for (size_t i = 0; i < FRAMES_IN_FLIGHT; i++) {
|
||||
renderer->InFlight[i] = FrameInFlight {};
|
||||
// Create the Uniform Buffer here
|
||||
|
||||
if (vkCreateSemaphore(device->VulkanDevice, &semaphoreInfo, nullptr,
|
||||
&renderer->InFlight[i].ImageAvailable)
|
||||
!= VK_SUCCESS
|
||||
|| vkCreateSemaphore(device->VulkanDevice, &semaphoreInfo, nullptr,
|
||||
&renderer->InFlight[i].RenderFinished)
|
||||
!= VK_SUCCESS
|
||||
|| vkCreateFence(device->VulkanDevice, &fenceInfo, nullptr,
|
||||
&renderer->InFlight[i].Fence)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to create synchronization objects for a frame!");
|
||||
}
|
||||
}
|
||||
|
||||
renderer->CurrentFrameIndex = 0;
|
||||
renderer->CurrentFrame = &renderer->InFlight[0];
|
||||
|
||||
return renderer;
|
||||
}
|
||||
|
||||
void renderer_configure_gui(VulkanRenderer* renderer) { gui::imgui_init(renderer); }
|
||||
|
||||
void renderer_cleanup(VulkanRenderer* renderer)
|
||||
{
|
||||
vkDestroyCommandPool(
|
||||
renderer->Device->VulkanDevice, renderer->Device->VulkanCommandPool, nullptr);
|
||||
for (size_t i = 0; i < FRAMES_IN_FLIGHT; i++) {
|
||||
vkDestroySemaphore(renderer->Device->VulkanDevice,
|
||||
renderer->InFlight[i].ImageAvailable, nullptr);
|
||||
vkDestroySemaphore(renderer->Device->VulkanDevice,
|
||||
renderer->InFlight[i].RenderFinished, nullptr);
|
||||
vkDestroyFence(
|
||||
renderer->Device->VulkanDevice, renderer->InFlight[i].Fence, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void renderer_configure_command_buffer(VulkanRenderer* renderer)
|
||||
{
|
||||
renderer->CommandBuffersInFlight.resize(FRAMES_IN_FLIGHT);
|
||||
VkCommandBufferAllocateInfo allocInfo {};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocInfo.commandPool = renderer->Device->VulkanCommandPool;
|
||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
allocInfo.commandBufferCount = (uint32_t)FRAMES_IN_FLIGHT;
|
||||
|
||||
if (vkAllocateCommandBuffers(renderer->Device->VulkanDevice, &allocInfo,
|
||||
&renderer->CommandBuffersInFlight[0])
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to allocate command buffers!");
|
||||
}
|
||||
|
||||
yolo::debug("Command buffer created");
|
||||
}
|
||||
|
||||
void renderer_record_command_buffer(VulkanRenderer* renderer, uint32_t imageIndex)
|
||||
{
|
||||
VkCommandBufferBeginInfo beginInfo {};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
beginInfo.flags = 0; // Optional
|
||||
beginInfo.pInheritanceInfo = nullptr; // Optional
|
||||
|
||||
if (vkBeginCommandBuffer(
|
||||
renderer->CommandBuffersInFlight[renderer->CurrentFrameIndex], &beginInfo)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to begin recording command buffer!");
|
||||
}
|
||||
|
||||
renderer->CommandBufferInFlight
|
||||
= &renderer->CommandBuffersInFlight[renderer->CurrentFrameIndex];
|
||||
}
|
||||
|
||||
void renderer_submit_oneoff(VulkanRenderer* renderer,
|
||||
std::function<void(VulkanRenderer*, VkCommandBuffer*)> callback, bool post)
|
||||
{
|
||||
if (post) {
|
||||
renderer->SubmitQueueOneOffPostFrame.push_back(callback);
|
||||
} else {
|
||||
renderer->SubmitQueueOneOffPreFrame.push_back(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void renderer_submit_repeat(VulkanRenderer* renderer,
|
||||
std::function<void(VulkanRenderer*, VkCommandBuffer*)> callback, bool post)
|
||||
{
|
||||
if (post) {
|
||||
renderer->SubmitQueuePostFrame.push_back(callback);
|
||||
} else {
|
||||
renderer->SubmitQueuePreFrame.push_back(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void work_queue(VulkanRenderer* renderer,
|
||||
std::vector<std::function<void(VulkanRenderer*, VkCommandBuffer*)>>* queue,
|
||||
bool clear)
|
||||
{
|
||||
for (auto& callback : *queue) {
|
||||
callback(renderer, renderer->CommandBufferInFlight);
|
||||
}
|
||||
if (clear) {
|
||||
queue->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void renderer_submit_now(VulkanRenderer* renderer,
|
||||
std::function<void(VulkanRenderer*, VkCommandBuffer*)> callback)
|
||||
{
|
||||
VkCommandBufferAllocateInfo allocInfo {};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
allocInfo.commandPool = renderer->Device->VulkanCommandPool;
|
||||
allocInfo.commandBufferCount = 1;
|
||||
|
||||
VkCommandBuffer commandBuffer;
|
||||
vkAllocateCommandBuffers(renderer->Device->VulkanDevice, &allocInfo, &commandBuffer);
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo {};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
|
||||
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
||||
|
||||
callback(renderer, &commandBuffer);
|
||||
|
||||
vkEndCommandBuffer(commandBuffer);
|
||||
VkSubmitInfo submitInfo {};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &commandBuffer;
|
||||
|
||||
vkQueueSubmit(renderer->Device->VulkanGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
|
||||
vkQueueWaitIdle(renderer->Device->VulkanGraphicsQueue);
|
||||
|
||||
vkFreeCommandBuffers(renderer->Device->VulkanDevice,
|
||||
renderer->Device->VulkanCommandPool, 1, &commandBuffer);
|
||||
}
|
||||
|
||||
bool renderer_begin_frame(VulkanRenderer* renderer)
|
||||
{
|
||||
vkWaitForFences(renderer->Device->VulkanDevice, 1, &renderer->CurrentFrame->Fence,
|
||||
VK_TRUE, UINT64_MAX);
|
||||
|
||||
auto swapStatus = vkAcquireNextImageKHR(renderer->Device->VulkanDevice,
|
||||
renderer->Swap->Handle, UINT64_MAX, renderer->CurrentFrame->ImageAvailable,
|
||||
VK_NULL_HANDLE, &renderer->ImageIndex);
|
||||
|
||||
if (swapStatus == VK_ERROR_OUT_OF_DATE_KHR || renderer->Device->Resized) {
|
||||
yolo::info("Swapchain out of date");
|
||||
swapchain_recreate(renderer->Swap);
|
||||
return false;
|
||||
} else if (swapStatus != VK_SUCCESS) {
|
||||
yolo::error("failed to acquire swap chain image!");
|
||||
}
|
||||
|
||||
vkResetFences(renderer->Device->VulkanDevice, 1, &renderer->CurrentFrame->Fence);
|
||||
vkResetCommandBuffer(
|
||||
renderer->CommandBuffersInFlight[renderer->CurrentFrameIndex], 0);
|
||||
renderer_record_command_buffer(renderer, renderer->ImageIndex);
|
||||
|
||||
work_queue(renderer, &renderer->SubmitQueueOneOffPreFrame, true);
|
||||
work_queue(renderer, &renderer->SubmitQueuePreFrame, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void renderer_begin_pass(
|
||||
VulkanRenderer* renderer, RenderTarget* target, VkRect2D renderArea, bool clear)
|
||||
{
|
||||
VkImageMemoryBarrier imageMemoryBarrier {};
|
||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
imageMemoryBarrier.image = target->Image;
|
||||
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
|
||||
imageMemoryBarrier.subresourceRange.layerCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
|
||||
imageMemoryBarrier.subresourceRange.levelCount = 1;
|
||||
if (!clear) {
|
||||
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
vkCmdPipelineBarrier(renderer->CommandBuffersInFlight[renderer->CurrentFrameIndex],
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
||||
|
||||
VkClearValue clearColor = { { { 0.0f, 0.0f, 0.0f, 1.0f } } };
|
||||
VkRenderingAttachmentInfo attachmentInfo {};
|
||||
attachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
|
||||
attachmentInfo.imageView = target->ImageView;
|
||||
attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR;
|
||||
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachmentInfo.clearValue = clearColor;
|
||||
if (!clear) {
|
||||
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
}
|
||||
|
||||
VkRenderingAttachmentInfo depthAttachmentInfo;
|
||||
if (target->TargetDepth != nullptr) {
|
||||
depthAttachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
|
||||
depthAttachmentInfo.imageView = target->TargetDepth->ImageView;
|
||||
depthAttachmentInfo.imageLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR;
|
||||
depthAttachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
depthAttachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
depthAttachmentInfo.clearValue.depthStencil = { 1.0f, 0 };
|
||||
depthAttachmentInfo.resolveMode = VK_RESOLVE_MODE_NONE;
|
||||
depthAttachmentInfo.resolveImageView = VK_NULL_HANDLE;
|
||||
depthAttachmentInfo.resolveImageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
depthAttachmentInfo.pNext = VK_NULL_HANDLE;
|
||||
if (!clear) {
|
||||
depthAttachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
}
|
||||
}
|
||||
|
||||
VkRenderingInfo renderingInfo {};
|
||||
renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR;
|
||||
renderingInfo.renderArea = renderArea;
|
||||
renderingInfo.layerCount = 1;
|
||||
renderingInfo.colorAttachmentCount = 1;
|
||||
renderingInfo.pColorAttachments = &attachmentInfo;
|
||||
if (target->TargetDepth != nullptr)
|
||||
renderingInfo.pDepthAttachment = &depthAttachmentInfo;
|
||||
|
||||
vkCmdBeginRendering(
|
||||
renderer->CommandBuffersInFlight[renderer->CurrentFrameIndex], &renderingInfo);
|
||||
}
|
||||
|
||||
void renderer_begin_pass(VulkanRenderer* renderer, VkRect2D renderArea)
|
||||
{
|
||||
VkImageMemoryBarrier imageMemoryBarrier {};
|
||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
imageMemoryBarrier.image = renderer->Swap->Images[renderer->ImageIndex];
|
||||
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
|
||||
imageMemoryBarrier.subresourceRange.layerCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
|
||||
imageMemoryBarrier.subresourceRange.levelCount = 1;
|
||||
|
||||
vkCmdPipelineBarrier(renderer->CommandBuffersInFlight[renderer->CurrentFrameIndex],
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
||||
|
||||
VkClearValue clearColor = { { { 0.0f, 0.0f, 0.0f, 1.0f } } };
|
||||
VkRenderingAttachmentInfo attachmentInfo {};
|
||||
attachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
|
||||
attachmentInfo.imageView = renderer->Swap->ImageViews[renderer->ImageIndex];
|
||||
attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR;
|
||||
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachmentInfo.clearValue = clearColor;
|
||||
|
||||
VkRenderingAttachmentInfo depthAttachmentInfo;
|
||||
depthAttachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
|
||||
depthAttachmentInfo.imageView = renderer->Swap->DepthImageView;
|
||||
depthAttachmentInfo.imageLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR;
|
||||
depthAttachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
depthAttachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
depthAttachmentInfo.clearValue.depthStencil = { 1.0f, 0 };
|
||||
depthAttachmentInfo.resolveMode = VK_RESOLVE_MODE_NONE;
|
||||
depthAttachmentInfo.resolveImageView = VK_NULL_HANDLE;
|
||||
depthAttachmentInfo.resolveImageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
depthAttachmentInfo.pNext = VK_NULL_HANDLE;
|
||||
|
||||
VkRenderingInfo renderingInfo {};
|
||||
renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR;
|
||||
renderingInfo.renderArea = renderArea;
|
||||
renderingInfo.layerCount = 1;
|
||||
renderingInfo.colorAttachmentCount = 1;
|
||||
renderingInfo.pColorAttachments = &attachmentInfo;
|
||||
renderingInfo.pDepthAttachment = &depthAttachmentInfo;
|
||||
|
||||
vkCmdBeginRendering(
|
||||
renderer->CommandBuffersInFlight[renderer->CurrentFrameIndex], &renderingInfo);
|
||||
}
|
||||
|
||||
void renderer_end_pass(VulkanRenderer* renderer)
|
||||
{
|
||||
vkCmdEndRendering(*renderer->CommandBufferInFlight);
|
||||
VkImageMemoryBarrier imageMemoryBarrier {};
|
||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
imageMemoryBarrier.image = renderer->Swap->Images[renderer->ImageIndex];
|
||||
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
|
||||
imageMemoryBarrier.subresourceRange.layerCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
|
||||
imageMemoryBarrier.subresourceRange.levelCount = 1;
|
||||
|
||||
vkCmdPipelineBarrier(renderer->CommandBuffersInFlight[renderer->CurrentFrameIndex],
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1,
|
||||
&imageMemoryBarrier);
|
||||
}
|
||||
|
||||
bool renderer_draw_frame(VulkanRenderer* renderer)
|
||||
{
|
||||
work_queue(renderer, &renderer->SubmitQueueOneOffPostFrame, true);
|
||||
work_queue(renderer, &renderer->SubmitQueuePostFrame, false);
|
||||
|
||||
if (vkEndCommandBuffer(renderer->CommandBuffersInFlight[renderer->CurrentFrameIndex])
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to record command buffer!");
|
||||
}
|
||||
|
||||
VkSubmitInfo submitInfo = {};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
|
||||
VkSemaphore waitSemaphores[] = { renderer->CurrentFrame->ImageAvailable };
|
||||
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
|
||||
submitInfo.waitSemaphoreCount = 1;
|
||||
submitInfo.pWaitSemaphores = waitSemaphores;
|
||||
submitInfo.pWaitDstStageMask
|
||||
= waitStages; // TODO: This is a bit of a hack, we should be waiting for the
|
||||
// renderpass to finish, not the color attachment stage
|
||||
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers
|
||||
= &renderer->CommandBuffersInFlight[renderer->CurrentFrameIndex];
|
||||
|
||||
VkSemaphore signalSemaphores[] = { renderer->CurrentFrame->RenderFinished };
|
||||
submitInfo.signalSemaphoreCount = 1;
|
||||
submitInfo.pSignalSemaphores = signalSemaphores;
|
||||
|
||||
if (vkQueueSubmit(renderer->Device->VulkanGraphicsQueue, 1, &submitInfo,
|
||||
renderer->CurrentFrame->Fence)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to submit draw command buffer!");
|
||||
}
|
||||
|
||||
VkPresentInfoKHR presentInfo = {};
|
||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
presentInfo.waitSemaphoreCount = 1;
|
||||
presentInfo.pWaitSemaphores = signalSemaphores;
|
||||
|
||||
VkSwapchainKHR swapChains[] = { renderer->Swap->Handle };
|
||||
presentInfo.swapchainCount = 1;
|
||||
presentInfo.pSwapchains = swapChains;
|
||||
|
||||
presentInfo.pImageIndices = &renderer->ImageIndex;
|
||||
|
||||
auto swapStatus
|
||||
= vkQueuePresentKHR(renderer->Device->VulkanPresentQueue, &presentInfo);
|
||||
|
||||
if (swapStatus == VK_ERROR_OUT_OF_DATE_KHR || swapStatus == VK_SUBOPTIMAL_KHR
|
||||
|| renderer->Device->Resized) {
|
||||
yolo::info("Swapchain out of date");
|
||||
swapchain_recreate(renderer->Swap);
|
||||
} else if (swapStatus != VK_SUCCESS) {
|
||||
yolo::error("failed to present swap chain image!");
|
||||
}
|
||||
|
||||
renderer->CurrentFrameIndex = (renderer->CurrentFrameIndex + 1) % FRAMES_IN_FLIGHT;
|
||||
renderer->CurrentFrame = &renderer->InFlight[renderer->CurrentFrameIndex];
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
79
src/graphics/vkrenderer.hpp
Normal file
79
src/graphics/vkrenderer.hpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
struct GraphicsDevice;
|
||||
struct Pipeline;
|
||||
struct SwapChain;
|
||||
struct RenderTarget;
|
||||
struct GenBuffer;
|
||||
struct Shader;
|
||||
|
||||
// TODO: Make the inflight frames work better
|
||||
typedef struct FrameInFlight {
|
||||
VkSemaphore ImageAvailable;
|
||||
VkSemaphore RenderFinished;
|
||||
VkFence Fence;
|
||||
|
||||
// Global Uniform Buffer
|
||||
// TODO: We also need push constants
|
||||
GenBuffer* UniformBuffer;
|
||||
} FrameInFlight;
|
||||
|
||||
typedef struct VulkanRenderer {
|
||||
GraphicsDevice* Device;
|
||||
SwapChain* Swap;
|
||||
|
||||
// TODO: This is really fucking annoying, how can we
|
||||
// not do this? CommandBuffers need to be *sequential*
|
||||
// in client memory
|
||||
std::vector<VkCommandBuffer> CommandBuffersInFlight;
|
||||
VkCommandBuffer* CommandBufferInFlight;
|
||||
|
||||
std::vector<FrameInFlight> InFlight;
|
||||
FrameInFlight* CurrentFrame;
|
||||
|
||||
uint32_t CurrentFrameIndex;
|
||||
uint32_t ImageIndex;
|
||||
|
||||
std::vector<std::function<void(VulkanRenderer*, VkCommandBuffer*)>>
|
||||
SubmitQueueOneOffPreFrame;
|
||||
std::vector<std::function<void(VulkanRenderer*, VkCommandBuffer*)>>
|
||||
SubmitQueueOneOffPostFrame;
|
||||
std::vector<std::function<void(VulkanRenderer*, VkCommandBuffer*)>>
|
||||
SubmitQueuePreFrame;
|
||||
std::vector<std::function<void(VulkanRenderer*, VkCommandBuffer*)>>
|
||||
SubmitQueuePostFrame;
|
||||
} VulkanRenderer;
|
||||
|
||||
VulkanRenderer* renderer_create(GraphicsDevice* device);
|
||||
void renderer_cleanup(VulkanRenderer* renderer);
|
||||
|
||||
void renderer_configure_gui(VulkanRenderer* renderer);
|
||||
void renderer_configure_command_buffer(VulkanRenderer* renderer);
|
||||
|
||||
void renderer_submit_oneoff(VulkanRenderer* renderer,
|
||||
std::function<void(VulkanRenderer*, VkCommandBuffer*)> callback, bool post = false);
|
||||
void renderer_submit_repeat(VulkanRenderer* renderer,
|
||||
std::function<void(VulkanRenderer*, VkCommandBuffer*)> callback, bool post = false);
|
||||
void renderer_submit_now(VulkanRenderer* renderer,
|
||||
std::function<void(VulkanRenderer*, VkCommandBuffer*)> callback);
|
||||
|
||||
bool renderer_begin_frame(VulkanRenderer* renderer);
|
||||
|
||||
void renderer_begin_pass(VulkanRenderer* renderer, RenderTarget* target,
|
||||
VkRect2D renderArea, bool clear = true);
|
||||
|
||||
// this is for rendering to the swapchain / present image
|
||||
void renderer_begin_pass(VulkanRenderer* renderer, VkRect2D renderArea);
|
||||
void renderer_end_pass(VulkanRenderer* renderer);
|
||||
|
||||
bool renderer_draw_frame(VulkanRenderer* renderer);
|
||||
|
||||
}
|
||||
110
src/gui/gui.hpp
Normal file
110
src/gui/gui.hpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics.hpp"
|
||||
#include "imgui/imgui.h"
|
||||
#include "style.hpp"
|
||||
|
||||
#include "graphics/device.hpp"
|
||||
#include "graphics/swapchain.hpp"
|
||||
#include "graphics/vkrenderer.hpp"
|
||||
|
||||
#include "window.hpp"
|
||||
|
||||
#include "yolo/yolo.hpp"
|
||||
|
||||
namespace inferno::gui {
|
||||
|
||||
#define WINDOW_FLAGS \
|
||||
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse \
|
||||
| ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove \
|
||||
| ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus \
|
||||
| ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoBackground \
|
||||
| ImGuiWindowFlags_NoDecoration | ImGuiMouseCursor_Arrow
|
||||
|
||||
inline void imgui_init(graphics::VulkanRenderer* renderer)
|
||||
{
|
||||
graphics::GraphicsDevice* device = renderer->Device;
|
||||
VkDescriptorPoolSize pool_sizes[] = { { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 },
|
||||
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 },
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 },
|
||||
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 },
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 },
|
||||
{ VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 },
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 },
|
||||
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 },
|
||||
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 },
|
||||
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 },
|
||||
{ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 } };
|
||||
|
||||
VkDescriptorPoolCreateInfo pool_info = {};
|
||||
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
|
||||
pool_info.maxSets = 1000;
|
||||
pool_info.poolSizeCount = std::size(pool_sizes);
|
||||
pool_info.pPoolSizes = pool_sizes;
|
||||
|
||||
VkDescriptorPool imguiPool;
|
||||
vkCreateDescriptorPool(device->VulkanDevice, &pool_info, nullptr, &imguiPool);
|
||||
|
||||
// this initializes the core structures of imgui
|
||||
ImGui::CreateContext();
|
||||
|
||||
auto& io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||
|
||||
ImGui_ImplGlfw_InitForVulkan(graphics::window_get_glfw_window(), true);
|
||||
|
||||
// this initializes imgui for Vulkan
|
||||
ImGui_ImplVulkan_InitInfo init_info = {};
|
||||
init_info.Instance = device->VulkanInstance;
|
||||
init_info.PhysicalDevice = device->VulkanPhysicalDevice;
|
||||
init_info.Device = device->VulkanDevice;
|
||||
init_info.Queue = device->VulkanGraphicsQueue;
|
||||
init_info.DescriptorPool = imguiPool;
|
||||
init_info.MinImageCount = 3;
|
||||
init_info.ImageCount = 3;
|
||||
init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
init_info.UseDynamicRendering = true;
|
||||
init_info.ColorAttachmentFormat = renderer->Swap->ImageFormat;
|
||||
ImGui_ImplVulkan_Init(&init_info, VK_NULL_HANDLE);
|
||||
|
||||
SetupImGuiStyle2();
|
||||
|
||||
yolo::info("Initialized ImGUI");
|
||||
}
|
||||
|
||||
inline void imgui_new_frame()
|
||||
{
|
||||
ImGui_ImplVulkan_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
ImGui::Begin("main", nullptr, WINDOW_FLAGS);
|
||||
|
||||
ImGui::SetWindowPos({ 0, 0 });
|
||||
ImGui::SetWindowSize(
|
||||
{ graphics::window_get_size().x, graphics::window_get_size().y });
|
||||
|
||||
ImGuiID dockspace_id = ImGui::GetID("main");
|
||||
static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_PassthruCentralNode;
|
||||
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
|
||||
}
|
||||
|
||||
inline void imgui_render_frame(VkCommandBuffer command_buffer)
|
||||
{
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Render();
|
||||
ImDrawData* draw_data = ImGui::GetDrawData();
|
||||
ImGui_ImplVulkan_RenderDrawData(draw_data, command_buffer);
|
||||
}
|
||||
|
||||
inline void imgui_shutdown()
|
||||
{
|
||||
ImGui_ImplVulkan_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <graphics.hpp>
|
||||
|
||||
namespace inferno {
|
||||
namespace inferno::gui {
|
||||
|
||||
inline void SetupImGuiStyle2()
|
||||
{
|
||||
|
||||
208
src/inferno.cpp
208
src/inferno.cpp
@@ -1,25 +1,32 @@
|
||||
#include "inferno.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <graphics.hpp>
|
||||
#include <version.hpp>
|
||||
// #include "gui/layout.hpp"
|
||||
#include "imgui/imgui.h"
|
||||
#include "renderer/renderer.hpp"
|
||||
#include "scene/scene.hpp"
|
||||
|
||||
#include "graphics/rendertarget.hpp"
|
||||
#include "gui/gui.hpp"
|
||||
// #include "renderer/renderer.hpp"
|
||||
// #include "scene/scene.hpp"
|
||||
#include "graphics/buffer.hpp"
|
||||
#include "graphics/device.hpp"
|
||||
#include "graphics/pipeline.hpp"
|
||||
#include "graphics/shader.hpp"
|
||||
#include "graphics/swapchain.hpp"
|
||||
#include "graphics/vkrenderer.hpp"
|
||||
#include "preview_renderer/debug.hpp"
|
||||
#include "window.hpp"
|
||||
|
||||
#include "preview_renderer/debug.hpp"
|
||||
#include "preview_renderer/renderer.hpp"
|
||||
#include "preview_renderer/shader.hpp"
|
||||
// #include "preview_renderer/debug.hpp"
|
||||
// #include "preview_renderer/renderer.hpp"
|
||||
#include "scene/camera.hpp"
|
||||
#include "scene/material.hpp"
|
||||
// #include "scene/material.hpp"
|
||||
#include "scene/mesh.hpp"
|
||||
#include "scene/scene.hpp"
|
||||
|
||||
#include <yolo/yolo.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
|
||||
namespace inferno {
|
||||
@@ -33,16 +40,15 @@ InfernoTimer* inferno_timer_create()
|
||||
return timer;
|
||||
}
|
||||
|
||||
void inferno_timer_cleanup(InfernoTimer* timer)
|
||||
{
|
||||
delete timer;
|
||||
}
|
||||
void inferno_timer_cleanup(InfernoTimer* timer) { delete timer; }
|
||||
|
||||
void inferno_timer_rolling_average(InfernoTimer* timer, int count)
|
||||
{
|
||||
if (timer->Times.size() > count)
|
||||
timer->Times.erase(timer->Times.begin());
|
||||
timer->RollingAverage = std::accumulate(timer->Times.begin(), timer->Times.end(), std::chrono::duration<double>(0.0)) / count;
|
||||
timer->RollingAverage = std::accumulate(timer->Times.begin(), timer->Times.end(),
|
||||
std::chrono::duration<double>(0.0))
|
||||
/ count;
|
||||
}
|
||||
|
||||
void inferno_timer_start(InfernoTimer* timer)
|
||||
@@ -55,7 +61,7 @@ void inferno_timer_end(InfernoTimer* timer)
|
||||
timer->EndTime = std::chrono::high_resolution_clock::now();
|
||||
timer->Time = timer->EndTime - timer->StartTime;
|
||||
timer->Times.push_back(timer->Time);
|
||||
inferno_timer_rolling_average(timer, 100);
|
||||
inferno_timer_rolling_average(timer, 1000);
|
||||
}
|
||||
|
||||
void inferno_timer_print(InfernoTimer* timer, bool time)
|
||||
@@ -88,35 +94,51 @@ InfernoApp* inferno_create()
|
||||
graphics::camera_set_position(app->Scene->Camera, { 0.0f, 1.0f, 3.1f });
|
||||
|
||||
// Create window
|
||||
graphics::window_create("Inferno v" INFERNO_VERSION, 1280, 720);
|
||||
graphics::window_create("Inferno v" INFERNO_VERSION, 1920, 1080);
|
||||
app->Device = graphics::device_create();
|
||||
app->Renderer = graphics::renderer_create(app->Device);
|
||||
|
||||
// setup the scene
|
||||
scene::Material* basicMaterial = new scene::Material("basic");
|
||||
graphics::Shader* basicShader = graphics::shader_create();
|
||||
graphics::shader_load(basicShader, "res/shaders/basic.glsl");
|
||||
graphics::shader_link(basicShader);
|
||||
basicMaterial->setGlShader(basicShader);
|
||||
graphics::renderer_configure_gui(app->Renderer);
|
||||
graphics::renderer_configure_command_buffer(app->Renderer);
|
||||
|
||||
scene::Mesh* mesh = new scene::Mesh;
|
||||
mesh->loadOBJ("res/cornell.obj");
|
||||
mesh->ready();
|
||||
mesh->setMaterial(basicMaterial);
|
||||
app->PreviewRenderer = graphics::preview_create(app->Renderer);
|
||||
graphics::debug_do_depth_test(false);
|
||||
|
||||
graphics::renderer_submit_repeat(
|
||||
app->Renderer,
|
||||
[](graphics::VulkanRenderer* renderer, VkCommandBuffer* commandBuffer) {
|
||||
gui::imgui_new_frame();
|
||||
},
|
||||
false);
|
||||
graphics::renderer_submit_repeat(
|
||||
app->Renderer,
|
||||
[&](graphics::VulkanRenderer* renderer, VkCommandBuffer* commandBuffer) {
|
||||
graphics::renderer_begin_pass(renderer,
|
||||
{ 0, 0, (uint32_t)graphics::window_get_size().x,
|
||||
(uint32_t)graphics::window_get_size().y });
|
||||
gui::imgui_render_frame(*commandBuffer);
|
||||
graphics::renderer_end_pass(renderer);
|
||||
},
|
||||
true);
|
||||
|
||||
scene::Mesh* mesh = scene::mesh_create(app->Device);
|
||||
scene::mesh_load_obj(mesh, "res/cornell-box.obj");
|
||||
scene::mesh_ready(mesh);
|
||||
scene::SceneObject* object = scene::scene_object_create();
|
||||
scene::scene_object_add_mesh(object, mesh);
|
||||
scene::scene_add_object(app->Scene, object);
|
||||
|
||||
// scene::Mesh* box = new scene::Mesh;
|
||||
// box->loadOBJ("res/cornell.obj");
|
||||
// box->ready();
|
||||
// box->setMaterial(basicMaterial);
|
||||
// scene::SceneObject* box_object = scene::scene_object_create();
|
||||
// scene::scene_object_add_mesh(box_object, box);
|
||||
// scene::scene_add_object(app->Scene, box_object);
|
||||
scene::Mesh* lucy = scene::mesh_create(app->Device);
|
||||
scene::mesh_load_obj(lucy, "res/lucy.obj");
|
||||
scene::mesh_ready(lucy);
|
||||
scene::SceneObject* lucyObject = scene::scene_object_create();
|
||||
scene::scene_object_add_mesh(lucyObject, lucy);
|
||||
scene::scene_add_object(app->Scene, lucyObject);
|
||||
|
||||
app->PreviewRenderer = graphics::preview_create();
|
||||
graphics::preview_set_viewport(app->PreviewRenderer, app->Scene->Camera);
|
||||
app->RayRenderer = graphics::rayr_create(app->Scene);
|
||||
graphics::rayr_set_viewport(app->RayRenderer, app->Scene->Camera);
|
||||
// app->PreviewRenderer = graphics::preview_create();
|
||||
// graphics::preview_set_viewport(app->PreviewRenderer, app->Scene->Camera);
|
||||
// app->RayRenderer = graphics::rayr_create(app->Scene);
|
||||
// graphics::rayr_set_viewport(app->RayRenderer, app->Scene->Camera);
|
||||
|
||||
return app;
|
||||
}
|
||||
@@ -142,13 +164,13 @@ static void inferno_gui_help_marker(const char* desc)
|
||||
void inferno_preset_gui(InfernoApp* app)
|
||||
{
|
||||
ImGuiID dockspace_id = ImGui::GetID("main");
|
||||
|
||||
ImGui::DockBuilderRemoveNode(dockspace_id); // Clear out existing layout
|
||||
ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_DockSpace); // Add empty node
|
||||
ImGui::DockBuilderSetNodeSize(dockspace_id, { 1000, 1000 });
|
||||
ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_DockSpace); // Add empty
|
||||
// node ImGui::DockBuilderSetNodeSize(dockspace_id, { 1000, 1000 });
|
||||
|
||||
ImGuiID dock_main_id = dockspace_id;
|
||||
ImGuiID dock_left = ImGui::DockBuilderSplitNode(dock_main_id, ImGuiDir_Left, 0.5f, NULL, &dock_main_id);
|
||||
ImGuiID dock_left = ImGui::DockBuilderSplitNode(
|
||||
dock_main_id, ImGuiDir_Left, 0.5f, NULL, &dock_main_id);
|
||||
ImGui::DockBuilderDockWindow("Preview", dock_left);
|
||||
ImGui::DockBuilderDockWindow("Render", dock_main_id);
|
||||
ImGui::DockBuilderFinish(dockspace_id);
|
||||
@@ -165,13 +187,16 @@ void inferno_move_input(InfernoApp* app, std::chrono::duration<double> deltaTime
|
||||
// pan only get on hold
|
||||
static glm::dvec2 lastMousePos;
|
||||
static int firstClick = 0;
|
||||
if (glfwGetMouseButton(graphics::window_get_glfw_window(), GLFW_MOUSE_BUTTON_1) == GLFW_PRESS) {
|
||||
if (glfwGetMouseButton(graphics::window_get_glfw_window(), GLFW_MOUSE_BUTTON_1)
|
||||
== GLFW_PRESS) {
|
||||
firstClick++;
|
||||
if (firstClick == 1) {
|
||||
glfwGetCursorPos(graphics::window_get_glfw_window(), &lastMousePos.x, &lastMousePos.y);
|
||||
glfwGetCursorPos(
|
||||
graphics::window_get_glfw_window(), &lastMousePos.x, &lastMousePos.y);
|
||||
}
|
||||
glm::dvec2 tempMousePos = { 0.0f, 0.0f };
|
||||
glfwGetCursorPos(graphics::window_get_glfw_window(), &tempMousePos.x, &tempMousePos.y);
|
||||
glfwGetCursorPos(
|
||||
graphics::window_get_glfw_window(), &tempMousePos.x, &tempMousePos.y);
|
||||
app->Input->MouseDelta = lastMousePos - tempMousePos;
|
||||
lastMousePos = tempMousePos;
|
||||
} else {
|
||||
@@ -203,57 +228,40 @@ void inferno_stop_move_input(InfernoApp* app)
|
||||
|
||||
bool inferno_pre(InfernoApp* app)
|
||||
{
|
||||
inferno_timer_start(app->MainTimer);
|
||||
|
||||
app->FrameCount++;
|
||||
if (app->FrameCount % 100 == 0) {
|
||||
yolo::info("Average FPS: {}", 1.0 / inferno_timer_get_time(app->MainTimer).count());
|
||||
yolo::info(
|
||||
"Average FPS: {}", 1.0 / inferno_timer_get_time(app->MainTimer).count());
|
||||
inferno_timer_print(app->MainTimer, false);
|
||||
}
|
||||
|
||||
if (!graphics::window_new_frame())
|
||||
if (!graphics::renderer_begin_frame(app->Renderer))
|
||||
return false;
|
||||
|
||||
// set the main window to the dockspace and then on the first launch set the preset
|
||||
ImGuiID dockspace_id = ImGui::GetID("main");
|
||||
static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_PassthruCentralNode;
|
||||
if (ImGui::DockBuilderGetNode(dockspace_id) == NULL) {
|
||||
inferno_preset_gui(app);
|
||||
}
|
||||
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void inferno_end(InfernoApp* app)
|
||||
{
|
||||
// clang-format off
|
||||
GLenum err;
|
||||
while((err = glGetError()) != GL_NO_ERROR) {
|
||||
std::string error;
|
||||
switch (err) {
|
||||
case GL_INVALID_ENUM: error = "INVALID_ENUM"; break;
|
||||
case GL_INVALID_VALUE: error = "INVALID_VALUE"; break;
|
||||
case GL_INVALID_OPERATION: error = "INVALID_OPERATION"; break;
|
||||
case GL_STACK_OVERFLOW: error = "STACK_OVERFLOW"; break;
|
||||
case GL_STACK_UNDERFLOW: error = "STACK_UNDERFLOW"; break;
|
||||
case GL_OUT_OF_MEMORY: error = "OUT_OF_MEMORY"; break;
|
||||
case GL_INVALID_FRAMEBUFFER_OPERATION: error = "INVALID_FRAMEBUFFER_OPERATION"; break;
|
||||
default: error = std::to_string((uint32_t)err); break;
|
||||
}
|
||||
yolo::error("[GL]: {} {}", err, error);
|
||||
}
|
||||
graphics::renderer_draw_frame(app->Renderer);
|
||||
graphics::window_render();
|
||||
inferno_timer_end(app->MainTimer);
|
||||
}
|
||||
|
||||
int inferno_run(InfernoApp* app)
|
||||
{
|
||||
while (true) {
|
||||
inferno_timer_start(app->MainTimer);
|
||||
while (graphics::window_new_frame()) {
|
||||
if (!inferno_pre(app))
|
||||
break;
|
||||
continue;
|
||||
|
||||
if (glm::length(app->Input->MouseDelta) > 0.0f)
|
||||
graphics::camera_mouse_move(app->Scene->Camera, app->Input->MouseDelta);
|
||||
graphics::camera_mouse_move(app->Scene->Camera, app->Input->MouseDelta,
|
||||
inferno_timer_get_time(app->MainTimer).count());
|
||||
if (app->Input->MovementDelta != 0b00000000)
|
||||
graphics::camera_move(app->Scene->Camera, app->Input->MovementDelta);
|
||||
graphics::camera_move(app->Scene->Camera, app->Input->MovementDelta,
|
||||
inferno_timer_get_time(app->MainTimer).count());
|
||||
|
||||
// Menu Bar
|
||||
static bool showPreview = true;
|
||||
@@ -279,8 +287,7 @@ int inferno_run(InfernoApp* app)
|
||||
|
||||
if (showRenderSettings && ImGui::Begin("Inferno HART")) {
|
||||
if (ImGui::TreeNode("Camera")) {
|
||||
graphics::Camera* camera = scene::scene_get_camera(app->Scene);
|
||||
graphics::camera_draw_ui(camera);
|
||||
graphics::camera_draw_ui(scene::scene_get_camera(app->Scene));
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode("Preview Render")) {
|
||||
@@ -293,43 +300,51 @@ int inferno_run(InfernoApp* app)
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode("RayTraced Render")) {
|
||||
graphics::rayr_draw_ui(app->RayRenderer);
|
||||
// graphics::rayr_draw_ui(app->RayRenderer);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (showPreview && ImGui::Begin("Preview", nullptr, ImGuiWindowFlags_NoScrollbar)) {
|
||||
if (showPreview
|
||||
&& ImGui::Begin("Preview", nullptr, ImGuiWindowFlags_NoScrollbar)) {
|
||||
if (ImGui::IsWindowHovered()) {
|
||||
inferno_move_input(app, inferno_timer_get_time(app->MainTimer));
|
||||
} else {
|
||||
inferno_stop_move_input(app);
|
||||
}
|
||||
|
||||
graphics::camera_raster_set_viewport(scene::scene_get_camera(app->Scene),
|
||||
{ ImGui::GetWindowSize().x, ImGui::GetWindowSize().y });
|
||||
graphics::preview_set_viewport(app->PreviewRenderer, app->Scene->Camera);
|
||||
static ImVec2 lastViewport = { 0, 0 };
|
||||
ImVec2 currentViewport = ImGui::GetWindowSize();
|
||||
if (lastViewport.x != currentViewport.x
|
||||
|| lastViewport.y != currentViewport.y) {
|
||||
graphics::camera_raster_set_viewport(scene::scene_get_camera(app->Scene),
|
||||
{ ImGui::GetWindowSize().x, ImGui::GetWindowSize().y });
|
||||
// if imgui has changed the viewport, we need to recreate the rendertarget
|
||||
graphics::preview_set_viewport(app->PreviewRenderer, app->Scene->Camera);
|
||||
}
|
||||
lastViewport = currentViewport;
|
||||
|
||||
graphics::preview_draw(app->PreviewRenderer, app->Scene);
|
||||
graphics::debug_draw_to_target(app->Scene);
|
||||
graphics::debug_draw_line({ 0, 0, 0 }, { 1, 1, 0 }, { 1, 1, 0 });
|
||||
graphics::debug_draw_to_preview(app->Scene);
|
||||
|
||||
ImTextureID texture = (ImTextureID)graphics::preview_get_rendered_texture(app->PreviewRenderer);
|
||||
ImGui::Image(
|
||||
texture,
|
||||
{ ImGui::GetWindowSize().x, ImGui::GetWindowSize().y },
|
||||
ImTextureID texture
|
||||
= (ImTextureID)graphics::preview_get_target(app->PreviewRenderer)
|
||||
->DescriptorSet;
|
||||
ImGui::Image(texture, { ImGui::GetWindowSize().x, ImGui::GetWindowSize().y },
|
||||
ImVec2(0, 1), ImVec2(1, 0));
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
if (ImGui::Begin("Render")) {
|
||||
graphics::rayr_draw(app->RayRenderer);
|
||||
// graphics::rayr_draw(app->RayRenderer);
|
||||
|
||||
ImTextureID texture = (ImTextureID)graphics::rayr_get_rendered_texture(app->RayRenderer);
|
||||
ImGui::Image(
|
||||
texture,
|
||||
{ ImGui::GetWindowSize().x, ImGui::GetWindowSize().y },
|
||||
ImVec2(0, 1), ImVec2(1, 0));
|
||||
// ImTextureID texture
|
||||
// = (ImTextureID)graphics::rayr_get_rendered_texture(app->RayRenderer);
|
||||
// ImGui::Image(texture, { ImGui::GetWindowSize().x, ImGui::GetWindowSize().y
|
||||
// },
|
||||
// ImVec2(0, 1), ImVec2(1, 0));
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
@@ -337,11 +352,8 @@ int inferno_run(InfernoApp* app)
|
||||
ImGui::ShowDemoWindow();
|
||||
}
|
||||
|
||||
graphics::window_render();
|
||||
inferno_end(app);
|
||||
inferno_timer_end(app->MainTimer);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics.hpp"
|
||||
#include "graphics/device.hpp"
|
||||
#include "scene/mesh.hpp"
|
||||
#include "scene/scene.hpp"
|
||||
#include "scene/camera.hpp"
|
||||
#include "renderer/renderer.hpp"
|
||||
// #include "scene/camera.hpp"
|
||||
#include "preview_renderer/renderer.hpp"
|
||||
#include "renderer/renderer.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -12,10 +14,16 @@ namespace inferno {
|
||||
|
||||
namespace graphics {
|
||||
struct Camera;
|
||||
struct GraphicsDevice;
|
||||
struct VulkanRenderer;
|
||||
struct RenderTarget;
|
||||
struct Buffer;
|
||||
struct Shader;
|
||||
}
|
||||
|
||||
namespace scene {
|
||||
struct Scene;
|
||||
struct Vert;
|
||||
}
|
||||
|
||||
typedef struct InfernoTimer {
|
||||
@@ -40,13 +48,17 @@ std::chrono::duration<double> inferno_timer_get_time(InfernoTimer* timer);
|
||||
std::chrono::duration<double> inferno_timer_get_average(InfernoTimer* timer);
|
||||
|
||||
typedef struct InfernoInput {
|
||||
glm::vec2 MouseDelta = {0.0f, 0.0f};
|
||||
glm::vec2 MouseDelta = { 0.0f, 0.0f };
|
||||
uint8_t MovementDelta = 0;
|
||||
} InfernoInput;
|
||||
|
||||
typedef struct InfernoApp {
|
||||
InfernoInput* Input;
|
||||
scene::Scene* Scene;
|
||||
|
||||
graphics::GraphicsDevice* Device;
|
||||
graphics::VulkanRenderer* Renderer;
|
||||
|
||||
graphics::PreviewRenderer* PreviewRenderer;
|
||||
graphics::RayRenderer* RayRenderer;
|
||||
|
||||
@@ -62,6 +74,7 @@ void inferno_stop_move_input(InfernoApp* app);
|
||||
|
||||
bool inferno_pre(InfernoApp* app);
|
||||
void inferno_end(InfernoApp* app);
|
||||
|
||||
int inferno_run(InfernoApp* app);
|
||||
|
||||
} // namespace inferno
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
#include "debug.hpp"
|
||||
|
||||
#include "graphics/buffer.hpp"
|
||||
#include "graphics/rendertarget.hpp"
|
||||
#include "graphics/shader.hpp"
|
||||
#include "graphics/vkrenderer.hpp"
|
||||
|
||||
#include "preview_renderer/renderer.hpp"
|
||||
#include "preview_renderer/shader.hpp"
|
||||
|
||||
#include "scene/camera.hpp"
|
||||
#include "scene/mesh.hpp"
|
||||
#include "scene/scene.hpp"
|
||||
|
||||
#include <graphics.hpp>
|
||||
@@ -25,42 +31,35 @@ struct DebugTextBillboard {
|
||||
struct _DebugInternal {
|
||||
std::mutex DebugMutex;
|
||||
|
||||
GLuint VAO;
|
||||
GLuint VBO;
|
||||
Buffer* LineBuffer = nullptr;
|
||||
Shader* LineShader;
|
||||
};
|
||||
|
||||
static DebugDrawer* DebugDrawerInstance = nullptr;
|
||||
|
||||
void debug_init()
|
||||
void debug_init(PreviewRenderer* renderer)
|
||||
{
|
||||
DebugDrawerInstance = new DebugDrawer;
|
||||
|
||||
DebugDrawerInstance->Renderer = renderer;
|
||||
DebugDrawerInstance->LineElements = std::vector<DebugLine>();
|
||||
DebugDrawerInstance->BillboardElements = std::vector<DebugTextBillboard>();
|
||||
// DebugDrawerInstance->BillboardElements = std::vector<DebugTextBillboard>();
|
||||
|
||||
DebugDrawerInstance->_Internal = new _DebugInternal;
|
||||
DebugDrawerInstance->_Internal->LineShader = shader_create();
|
||||
shader_load(DebugDrawerInstance->_Internal->LineShader, "res/shaders/lines_debug.glsl");
|
||||
shader_link(DebugDrawerInstance->_Internal->LineShader);
|
||||
|
||||
glGenVertexArrays(1, &DebugDrawerInstance->_Internal->VAO);
|
||||
glBindVertexArray(DebugDrawerInstance->_Internal->VAO);
|
||||
|
||||
glGenBuffers(1, &DebugDrawerInstance->_Internal->VBO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, DebugDrawerInstance->_Internal->VBO);
|
||||
DebugDrawerInstance->_Internal->LineShader = shader_create(renderer->Renderer->Device,
|
||||
renderer->Renderer->Swap, SHADER_PROGRAM_TYPE_GRAPHICS_LINE);
|
||||
graphics::shader_load(
|
||||
DebugDrawerInstance->_Internal->LineShader, "res/shaders/lines_debug");
|
||||
graphics::shader_build(DebugDrawerInstance->_Internal->LineShader);
|
||||
|
||||
yolo::debug("DebugDrawer initialized");
|
||||
}
|
||||
|
||||
void debug_cleanup()
|
||||
{
|
||||
delete DebugDrawerInstance;
|
||||
}
|
||||
void debug_cleanup() { delete DebugDrawerInstance; }
|
||||
|
||||
void debug_attach_renderer(PreviewRenderer* renderer)
|
||||
void debug_do_depth_test(bool doDepthTest)
|
||||
{
|
||||
DebugDrawerInstance->Renderer = renderer;
|
||||
DebugDrawerInstance->DoDepthTest = doDepthTest;
|
||||
}
|
||||
|
||||
void debug_draw_line(glm::vec3 start, glm::vec3 end, glm::vec3 color)
|
||||
@@ -69,85 +68,63 @@ void debug_draw_line(glm::vec3 start, glm::vec3 end, glm::vec3 color)
|
||||
DebugDrawerInstance->LineElements.push_back({ start, end, color });
|
||||
}
|
||||
|
||||
void debug_draw_text_billboard(glm::vec3 position, glm::vec3 color, std::string text)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(DebugDrawerInstance->_Internal->DebugMutex);
|
||||
DebugDrawerInstance->BillboardElements.push_back({ position, color, text });
|
||||
}
|
||||
void debug_draw_ui() { ImGui::Checkbox("Show Overlay", &DebugDrawerInstance->DoShow); }
|
||||
|
||||
void debug_draw_ui()
|
||||
{
|
||||
ImGui::Checkbox("Show Overlay", &DebugDrawerInstance->DoShow);
|
||||
}
|
||||
|
||||
void debug_draw_to_target(scene::Scene* scene)
|
||||
void debug_draw_to_preview(scene::Scene* scene)
|
||||
{
|
||||
if (!DebugDrawerInstance->DoShow)
|
||||
return;
|
||||
|
||||
auto renderer = DebugDrawerInstance->Renderer;
|
||||
uint32_t bufferSize
|
||||
= DebugDrawerInstance->LineElements.size() * sizeof(DebugLine) * 2;
|
||||
scene::DebugLineVert* bufferData = new scene::DebugLineVert[bufferSize];
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, renderer->RenderTarget);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, DebugDrawerInstance->_Internal->VBO);
|
||||
glBindVertexArray(DebugDrawerInstance->_Internal->VAO);
|
||||
|
||||
GLuint vertex_position_arr_size = DebugDrawerInstance->LineElements.size() * 2 * 3;
|
||||
GLfloat vertex_position_arr[vertex_position_arr_size];
|
||||
for (int i = 0; i < DebugDrawerInstance->LineElements.size(); i++) {
|
||||
auto line = DebugDrawerInstance->LineElements[i];
|
||||
vertex_position_arr[i * 6 + 0] = line.Start.x;
|
||||
vertex_position_arr[i * 6 + 1] = line.Start.y;
|
||||
vertex_position_arr[i * 6 + 2] = line.Start.z;
|
||||
vertex_position_arr[i * 6 + 3] = line.End.x;
|
||||
vertex_position_arr[i * 6 + 4] = line.End.y;
|
||||
vertex_position_arr[i * 6 + 5] = line.End.z;
|
||||
bufferData[i * 2] = { DebugDrawerInstance->LineElements[i].Start,
|
||||
DebugDrawerInstance->LineElements[i].Color };
|
||||
bufferData[i * 2 + 1] = { DebugDrawerInstance->LineElements[i].End,
|
||||
DebugDrawerInstance->LineElements[i].Color };
|
||||
}
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, vertex_position_arr_size * sizeof(GLfloat), vertex_position_arr, GL_STATIC_DRAW);
|
||||
if (bufferSize > 0 && DebugDrawerInstance->_Internal->LineBuffer == nullptr) {
|
||||
DebugDrawerInstance->_Internal->LineBuffer = vertex_buffer_create(
|
||||
DebugDrawerInstance->Renderer->Renderer->Device, bufferData, bufferSize);
|
||||
}
|
||||
|
||||
Shader* shader = DebugDrawerInstance->_Internal->LineShader;
|
||||
shader_use(shader);
|
||||
auto backend = DebugDrawerInstance->Renderer->Renderer;
|
||||
VkCommandBuffer commandBuffer = *backend->CommandBufferInFlight;
|
||||
|
||||
GLint posAttrib = glGetAttribLocation(graphics::shader_get_program(shader), "position");
|
||||
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
glEnableVertexAttribArray(posAttrib);
|
||||
graphics::renderer_begin_pass(backend,
|
||||
DebugDrawerInstance->Renderer->PreviewRenderTarget,
|
||||
DebugDrawerInstance->Renderer->Viewport, false);
|
||||
|
||||
auto viewMatrix = graphics::camera_get_view(scene::scene_get_camera(scene));
|
||||
auto projMatrix = graphics::camera_get_projection(scene::scene_get_camera(scene));
|
||||
graphics::shader_use(DebugDrawerInstance->_Internal->LineShader, commandBuffer,
|
||||
DebugDrawerInstance->Renderer->Viewport);
|
||||
|
||||
GLint uniTrans = glGetUniformLocation(graphics::shader_get_program(shader), "model");
|
||||
glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(glm::mat4(1.0f)));
|
||||
scene::GlobalUniformObject GlobalUniformObject {
|
||||
.Projection = graphics::camera_get_projection(scene->Camera),
|
||||
.View = graphics::camera_get_view(scene->Camera),
|
||||
};
|
||||
|
||||
GLint uniView = glGetUniformLocation(graphics::shader_get_program(shader), "view");
|
||||
glUniformMatrix4fv(uniView, 1, GL_FALSE, glm::value_ptr(viewMatrix));
|
||||
graphics::shader_update_state(DebugDrawerInstance->_Internal->LineShader,
|
||||
commandBuffer, GlobalUniformObject, backend->CurrentFrameIndex);
|
||||
|
||||
GLint uniProj = glGetUniformLocation(graphics::shader_get_program(shader), "proj");
|
||||
glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(projMatrix));
|
||||
graphics::vertex_buffer_bind(
|
||||
DebugDrawerInstance->_Internal->LineBuffer, commandBuffer);
|
||||
|
||||
glDrawArrays(GL_LINES, 0, vertex_position_arr_size);
|
||||
if (DebugDrawerInstance->DoDepthTest)
|
||||
vkCmdSetDepthTestEnable(commandBuffer, VK_TRUE);
|
||||
else
|
||||
vkCmdSetDepthTestEnable(commandBuffer, VK_FALSE);
|
||||
|
||||
vkCmdDraw(commandBuffer, DebugDrawerInstance->LineElements.size() * 2, 1, 0, 0);
|
||||
|
||||
vkCmdSetDepthTestEnable(commandBuffer, VK_TRUE);
|
||||
|
||||
graphics::renderer_end_pass(backend);
|
||||
|
||||
DebugDrawerInstance->LineElements.clear();
|
||||
|
||||
// glEnable(GL_TEXTURE_2D);
|
||||
// glEnable(GL_BLEND);
|
||||
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
//
|
||||
// for (auto& billboard : DebugDrawerInstance->BillboardElements) {
|
||||
// glColor3f(billboard.Color.x, billboard.Color.y, billboard.Color.z);
|
||||
// glRasterPos3f(billboard.Position.x, billboard.Position.y, billboard.Position.z);
|
||||
//
|
||||
// for (auto& c : billboard.Text) {
|
||||
// glutBitmapCharacter(GL_BITMAP, c);
|
||||
// }
|
||||
// }
|
||||
|
||||
DebugDrawerInstance->BillboardElements.clear();
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
delete[] bufferData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,24 +21,25 @@ struct DebugTextBillboard;
|
||||
struct _DebugInternal;
|
||||
|
||||
struct DebugDrawer {
|
||||
PreviewRenderer* Renderer = nullptr;
|
||||
_DebugInternal* _Internal = nullptr;
|
||||
|
||||
bool DoShow = true;
|
||||
PreviewRenderer* Renderer = nullptr;
|
||||
bool DoDepthTest = true;
|
||||
|
||||
std::vector<DebugLine> LineElements;
|
||||
std::vector<DebugTextBillboard> BillboardElements;
|
||||
// std::vector<DebugTextBillboard> BillboardElements;
|
||||
};
|
||||
|
||||
void debug_init();
|
||||
void debug_init(PreviewRenderer* renderer);
|
||||
void debug_cleanup();
|
||||
|
||||
void debug_attach_renderer(PreviewRenderer* renderer);
|
||||
|
||||
void debug_do_depth_test(bool doDepthTest);
|
||||
void debug_draw_line(glm::vec3 start, glm::vec3 end, glm::vec3 color);
|
||||
void debug_draw_text_billboard(glm::vec3 position, glm::vec3 color, std::string text);
|
||||
// void debug_draw_text_billboard(glm::vec3 position, glm::vec3 color, std::string text);
|
||||
|
||||
void debug_draw_ui();
|
||||
|
||||
void debug_draw_to_target(scene::Scene* scene);
|
||||
void debug_draw_to_preview(scene::Scene* scene);
|
||||
|
||||
}
|
||||
|
||||
@@ -3,14 +3,20 @@
|
||||
#include <graphics.hpp>
|
||||
|
||||
#include "preview_renderer/debug.hpp"
|
||||
|
||||
#include "graphics/buffer.hpp"
|
||||
#include "graphics/rendertarget.hpp"
|
||||
#include "graphics/shader.hpp"
|
||||
#include "graphics/vkrenderer.hpp"
|
||||
|
||||
#include "scene/mesh.hpp"
|
||||
#include "scene/object.hpp"
|
||||
#include "shader.hpp"
|
||||
#include "scene/scene.hpp"
|
||||
|
||||
#include <yolo/yolo.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <scene/camera.hpp>
|
||||
#include <scene/material.hpp>
|
||||
#include <scene/mesh.hpp>
|
||||
#include <scene/object.hpp>
|
||||
#include <scene/scene.hpp>
|
||||
@@ -19,132 +25,79 @@
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
PreviewRenderer* preview_create()
|
||||
PreviewRenderer* preview_create(VulkanRenderer* vkrenderer)
|
||||
{
|
||||
PreviewRenderer* renderer = new PreviewRenderer;
|
||||
renderer->Renderer = vkrenderer;
|
||||
|
||||
glGenFramebuffers(1, &renderer->RenderTarget);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, renderer->RenderTarget);
|
||||
renderer->DrawShader = graphics::shader_create(
|
||||
vkrenderer->Device, vkrenderer->Swap, SHADER_PROGRAM_TYPE_GRAPHICS);
|
||||
|
||||
glGenTextures(1, &renderer->RenderTargetTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, renderer->RenderTargetTexture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||
graphics::shader_load(renderer->DrawShader, "res/shaders/basic");
|
||||
graphics::shader_build(renderer->DrawShader);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glGenTextures(1, &renderer->RenderTargetDepthTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, renderer->RenderTargetDepthTexture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 800, 600, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
// Attach the texture to the framebuffer.
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, renderer->RenderTargetDepthTexture, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderer->RenderTargetTexture, 0);
|
||||
|
||||
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
renderer->PreviewRenderTarget = graphics::rendertarget_create(
|
||||
renderer->Renderer->Device, { 1920, 1080 }, VK_FORMAT_R8G8B8A8_UNORM, true);
|
||||
|
||||
// bind preview renderer to debugdraw
|
||||
debug_init();
|
||||
debug_attach_renderer(renderer);
|
||||
debug_init(renderer);
|
||||
|
||||
return renderer;
|
||||
}
|
||||
|
||||
void preview_cleanup(PreviewRenderer* renderer)
|
||||
{
|
||||
}
|
||||
void preview_cleanup(PreviewRenderer* renderer) { }
|
||||
|
||||
void preview_draw_ui(PreviewRenderer* renderer)
|
||||
{
|
||||
}
|
||||
void preview_draw_ui(PreviewRenderer* renderer) { }
|
||||
|
||||
void preview_set_viewport(PreviewRenderer* renderer, Camera* camera)
|
||||
{
|
||||
auto viewport = camera_raster_get_viewport(camera);
|
||||
renderer->Viewport = viewport;
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, renderer->RenderTarget);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, renderer->RenderTargetTexture);
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGB,
|
||||
renderer->Viewport.x,
|
||||
renderer->Viewport.y,
|
||||
0,
|
||||
GL_RGB,
|
||||
GL_UNSIGNED_BYTE,
|
||||
NULL);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, renderer->RenderTargetDepthTexture);
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_DEPTH24_STENCIL8,
|
||||
renderer->Viewport.x,
|
||||
renderer->Viewport.y,
|
||||
0,
|
||||
GL_DEPTH_COMPONENT,
|
||||
GL_FLOAT,
|
||||
NULL);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
renderer->Viewport.offset.x = 0;
|
||||
renderer->Viewport.offset.y = 0;
|
||||
renderer->Viewport.extent.width = viewport.x;
|
||||
renderer->Viewport.extent.height = viewport.y;
|
||||
renderer->HasViewportChanged = true;
|
||||
}
|
||||
|
||||
GLuint preview_get_rendered_texture(PreviewRenderer* renderer)
|
||||
RenderTarget* preview_get_target(PreviewRenderer* renderer)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, renderer->RenderTarget);
|
||||
return renderer->RenderTargetTexture;
|
||||
return renderer->PreviewRenderTarget;
|
||||
}
|
||||
|
||||
void preview_draw(PreviewRenderer* renderer, scene::Scene* scene)
|
||||
{
|
||||
// clear
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, renderer->RenderTarget);
|
||||
glClearColor(0.1, 0.1, 0.1, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
VkCommandBuffer commandBuffer = *renderer->Renderer->CommandBufferInFlight;
|
||||
// if changed
|
||||
if (renderer->HasViewportChanged) {
|
||||
graphics::rendertarget_recreate(renderer->PreviewRenderTarget,
|
||||
renderer->Viewport.extent, VK_FORMAT_R8G8B8A8_UNORM);
|
||||
}
|
||||
|
||||
// draw
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, renderer->RenderTarget);
|
||||
glViewport(0,
|
||||
0,
|
||||
renderer->Viewport.x,
|
||||
renderer->Viewport.y);
|
||||
graphics::renderer_begin_pass(
|
||||
renderer->Renderer, renderer->PreviewRenderTarget, renderer->Viewport);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
graphics::shader_use(renderer->DrawShader, commandBuffer, renderer->Viewport);
|
||||
|
||||
scene::GlobalUniformObject globalUniformObject {
|
||||
.Projection = graphics::camera_get_projection(scene->Camera),
|
||||
.View = graphics::camera_get_view(scene->Camera),
|
||||
};
|
||||
|
||||
graphics::shader_update_state(renderer->DrawShader, commandBuffer,
|
||||
globalUniformObject, renderer->Renderer->CurrentFrameIndex);
|
||||
|
||||
for (scene::SceneObject* o : scene::scene_get_renderables(scene)) {
|
||||
for (scene::Mesh* m : scene::scene_object_get_meshs(o)) {
|
||||
graphics::Shader* shader = m->getMaterial()->getGlShader();
|
||||
graphics::shader_use(shader);
|
||||
|
||||
auto viewMatrix = graphics::camera_get_view(scene::scene_get_camera(scene));
|
||||
auto projMatrix = graphics::camera_get_projection(scene::scene_get_camera(scene));
|
||||
graphics::vertex_buffer_bind(m->VertexBuffer, commandBuffer);
|
||||
graphics::index_buffer_bind(m->IndexBuffer, commandBuffer);
|
||||
|
||||
GLint uniTrans = glGetUniformLocation(graphics::shader_get_program(shader), "model");
|
||||
glUniformMatrix4fv(uniTrans, 1, GL_FALSE, glm::value_ptr(glm::mat4(1.0f)));
|
||||
|
||||
GLint uniView = glGetUniformLocation(graphics::shader_get_program(shader), "view");
|
||||
glUniformMatrix4fv(uniView, 1, GL_FALSE, glm::value_ptr(viewMatrix));
|
||||
|
||||
GLint uniProj = glGetUniformLocation(graphics::shader_get_program(shader), "proj");
|
||||
glUniformMatrix4fv(uniProj, 1, GL_FALSE, glm::value_ptr(projMatrix));
|
||||
|
||||
glBindVertexArray(m->getVAO());
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->getEBO());
|
||||
|
||||
glDrawElements(GL_TRIANGLES, m->getIndexCount() * sizeof(uint32_t), GL_UNSIGNED_INT, 0);
|
||||
vkCmdDrawIndexed(
|
||||
commandBuffer, m->IndexBuffer->GenericBuffer->Count, 1, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
graphics::renderer_end_pass(renderer->Renderer);
|
||||
renderer->HasViewportChanged = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,19 +10,25 @@ struct Scene;
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
struct VulkanRenderer;
|
||||
struct Viewport;
|
||||
struct Camera;
|
||||
struct DebugDraw;
|
||||
struct RenderTarget;
|
||||
struct Shader;
|
||||
|
||||
typedef struct PreviewRenderer {
|
||||
glm::ivec2 Viewport;
|
||||
VulkanRenderer* Renderer;
|
||||
|
||||
GLuint RenderTarget = 0;
|
||||
GLuint RenderTargetTexture = 0;
|
||||
GLuint RenderTargetDepthTexture = 0;
|
||||
RenderTarget* PreviewRenderTarget;
|
||||
|
||||
Shader* DrawShader;
|
||||
|
||||
VkRect2D Viewport;
|
||||
bool HasViewportChanged = false;
|
||||
} PreviewRenderer;
|
||||
|
||||
PreviewRenderer* preview_create();
|
||||
PreviewRenderer* preview_create(VulkanRenderer* renderer);
|
||||
void preview_cleanup(PreviewRenderer* renderer);
|
||||
|
||||
void preview_draw_debug_ui(PreviewRenderer* renderer);
|
||||
@@ -30,7 +36,7 @@ void preview_draw_debug_ui(PreviewRenderer* renderer);
|
||||
void preview_draw_ui(PreviewRenderer* renderer);
|
||||
void preview_set_viewport(PreviewRenderer* renderer, Camera* camera);
|
||||
|
||||
GLuint preview_get_rendered_texture(PreviewRenderer* renderer);
|
||||
RenderTarget* preview_get_target(PreviewRenderer* renderer);
|
||||
|
||||
void preview_draw(PreviewRenderer* renderer, scene::Scene* scene);
|
||||
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
#include "shader.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
static std::unordered_map<GLuint, int> shader2Index = {
|
||||
{ GL_VERTEX_SHADER, 0 },
|
||||
{ GL_GEOMETRY_SHADER, 1 },
|
||||
{ GL_FRAGMENT_SHADER, 2 }
|
||||
};
|
||||
|
||||
inline std::string trim(std::string& str)
|
||||
{
|
||||
str.erase(str.find_last_not_of(' ') + 1); // suffixing spaces
|
||||
str.erase(0, str.find_first_not_of(' ')); // prefixing spaces
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string textFromFile(const std::filesystem::path& path)
|
||||
{
|
||||
std::ifstream input(path);
|
||||
return std::string((std::istreambuf_iterator<char>(input)),
|
||||
std::istreambuf_iterator<char>());
|
||||
}
|
||||
|
||||
std::vector<const ShaderPreprocessorDefinition*> getKeys(Shader* shader, std::string key)
|
||||
{
|
||||
std::vector<const ShaderPreprocessorDefinition*> ret;
|
||||
for (const auto& p : shader->PreprocessorDefinitions)
|
||||
if (p.key == key)
|
||||
ret.push_back(&p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool checkShader(GLuint uid)
|
||||
{
|
||||
GLint isCompiled = 0;
|
||||
glGetShaderiv(uid, GL_COMPILE_STATUS, &isCompiled);
|
||||
if (isCompiled == GL_FALSE) {
|
||||
GLint maxLength = 0;
|
||||
glGetShaderiv(uid, GL_INFO_LOG_LENGTH, &maxLength);
|
||||
|
||||
std::vector<GLchar> errorLog(maxLength);
|
||||
glGetShaderInfoLog(uid, maxLength, &maxLength, &errorLog[0]);
|
||||
|
||||
for (int i = 0; i < errorLog.size(); i++) {
|
||||
std::cout << errorLog[i];
|
||||
}
|
||||
|
||||
glDeleteShader(uid);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Shader* shader_create()
|
||||
{
|
||||
Shader* shader = new Shader;
|
||||
|
||||
shader->Program = 0;
|
||||
shader->Shaders[0] = GL_NONE;
|
||||
shader->Shaders[1] = GL_NONE;
|
||||
shader->Shaders[2] = GL_NONE;
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
void shader_cleanup(Shader* shader)
|
||||
{
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (shader->Shaders[i] == GL_NONE)
|
||||
continue;
|
||||
glDeleteShader(shader->Shaders[i]);
|
||||
}
|
||||
|
||||
glDeleteProgram(shader->Program);
|
||||
}
|
||||
|
||||
void shader_load(Shader* shader, std::filesystem::path path)
|
||||
{
|
||||
|
||||
assert(std::filesystem::exists(path));
|
||||
|
||||
std::string loadedShaderSource = textFromFile(path);
|
||||
|
||||
for (int i = 0; i < loadedShaderSource.length(); i++) {
|
||||
const char& c = loadedShaderSource[i];
|
||||
if (c == '#') {
|
||||
ShaderPreprocessorDefinition def = { .start = i };
|
||||
int j;
|
||||
for (j = ++i; loadedShaderSource[j] != ' '; j++) {
|
||||
def.key += loadedShaderSource[j];
|
||||
}
|
||||
for (j++; loadedShaderSource[j] != '\n'; j++) {
|
||||
def.def += loadedShaderSource[j];
|
||||
}
|
||||
def.end = j;
|
||||
i = j; // advance i
|
||||
def.def = trim(def.def);
|
||||
def.key = trim(def.key);
|
||||
shader->PreprocessorDefinitions.push_back(def);
|
||||
}
|
||||
}
|
||||
|
||||
// now we have all of the key/value definitions
|
||||
// we can extract the relavent ones, for example
|
||||
// "type"
|
||||
std::vector<const ShaderPreprocessorDefinition*> types = getKeys(shader, "type");
|
||||
int i = 0;
|
||||
for (const ShaderPreprocessorDefinition* type : types) {
|
||||
GLuint glType = GL_NONE;
|
||||
if (type->def == "vertex")
|
||||
glType = GL_VERTEX_SHADER;
|
||||
if (type->def == "geometry")
|
||||
glType = GL_GEOMETRY_SHADER;
|
||||
if (type->def == "fragment")
|
||||
glType = GL_FRAGMENT_SHADER;
|
||||
|
||||
assert(glType != GL_NONE);
|
||||
|
||||
shader->Shaders[shader2Index[glType]] = glCreateShader(glType);
|
||||
|
||||
const char* source = loadedShaderSource.c_str() + type->end;
|
||||
int end = types.size() - 1 == i ? types.size() : types[i + 1]->start;
|
||||
int length = end - type->end;
|
||||
|
||||
glShaderSource(shader->Shaders[shader2Index[glType]], 1, &source, &length);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void shader_link(Shader* shader)
|
||||
{
|
||||
shader->Program = glCreateProgram();
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (shader->Shaders[i] == GL_NONE)
|
||||
continue;
|
||||
|
||||
glCompileShader(shader->Shaders[i]);
|
||||
if (!checkShader(shader->Shaders[i]))
|
||||
continue;
|
||||
|
||||
glAttachShader(shader->Program, shader->Shaders[i]);
|
||||
}
|
||||
|
||||
glLinkProgram(shader->Program);
|
||||
}
|
||||
|
||||
GLuint shader_get_program(Shader* shader)
|
||||
{
|
||||
return shader->Program;
|
||||
}
|
||||
|
||||
void shader_add_attribute(Shader* shader, const std::string& attribute)
|
||||
{
|
||||
shader->Attributes[attribute] = glGetAttribLocation(shader->Program, attribute.c_str());
|
||||
}
|
||||
|
||||
void shader_add_uniform(Shader* shader, const std::string& uniform)
|
||||
{
|
||||
shader->Uniforms[uniform] = glGetUniformLocation(shader->Program, uniform.c_str());
|
||||
}
|
||||
|
||||
GLuint shader_get_attribute(Shader* shader, const std::string& attribute)
|
||||
{
|
||||
return shader->Attributes[attribute];
|
||||
}
|
||||
|
||||
GLuint shader_get_uniform(Shader* shader, const std::string& uniform)
|
||||
{
|
||||
return shader->Uniforms[uniform];
|
||||
}
|
||||
|
||||
void shader_use(Shader* shader)
|
||||
{
|
||||
glUseProgram(shader->Program);
|
||||
}
|
||||
|
||||
void shader_unuse(Shader* shader)
|
||||
{
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../graphics.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
typedef struct ShaderPreprocessorDefinition {
|
||||
int start, end;
|
||||
std::string key;
|
||||
std::string def;
|
||||
} shaderpreprocessordefinition;
|
||||
|
||||
typedef struct Shader {
|
||||
GLuint Shaders[3];
|
||||
GLuint Program;
|
||||
std::unordered_map<std::string, GLuint> Attributes;
|
||||
std::unordered_map<std::string, GLuint> Uniforms;
|
||||
std::vector<ShaderPreprocessorDefinition> PreprocessorDefinitions;
|
||||
} Shader;
|
||||
|
||||
Shader* shader_create();
|
||||
void shader_cleanup(Shader* shader);
|
||||
|
||||
void shader_load(Shader* shader, std::filesystem::path path);
|
||||
void shader_link(Shader* shader);
|
||||
|
||||
GLuint shader_get_program(Shader* shader);
|
||||
|
||||
// TODO: Implement shader_reload
|
||||
void shader_add_attribute(Shader* shader, const std::string& attribute);
|
||||
void shader_add_uniform(Shader* shader, const std::string& uniform);
|
||||
GLuint shader_get_attribute(Shader* shader, const std::string& attribute);
|
||||
GLuint shader_get_uniform(Shader* shader, const std::string& uniform);
|
||||
|
||||
void shader_use(Shader* shader);
|
||||
void shader_unuse(Shader* shader);
|
||||
|
||||
}
|
||||
@@ -177,7 +177,7 @@ glm::ivec2 camera_ray_get_viewport(Camera* camera)
|
||||
return camera->Views.Ray;
|
||||
}
|
||||
|
||||
void camera_move(Camera* camera, uint8_t movement_delta)
|
||||
void camera_move(Camera* camera, uint8_t movement_delta, float delta_time)
|
||||
{
|
||||
if (movement_delta == 0)
|
||||
return;
|
||||
@@ -223,16 +223,17 @@ void camera_move(Camera* camera, uint8_t movement_delta)
|
||||
|
||||
// forward vector must be negative to look forward.
|
||||
// read :http://in2gpu.com/2015/05/17/view-matrix/
|
||||
camera->Position += delta * camera->Speed;
|
||||
camera->Position += delta * camera->Speed * (delta_time * 100);
|
||||
|
||||
// update the view matrix
|
||||
camera_update(camera);
|
||||
}
|
||||
|
||||
void camera_mouse_move(Camera* camera, glm::vec2 mouse_delta)
|
||||
void camera_mouse_move(Camera* camera, glm::vec2 mouse_delta, float delta_time)
|
||||
{
|
||||
if (glm::length(mouse_delta) == 0)
|
||||
return;
|
||||
|
||||
// note that yaw and pitch must be converted to radians.
|
||||
// this is done in update() by glm::rotate
|
||||
camera->Yaw += camera->MouseSensitivity * (mouse_delta.x / 100);
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
#include "material.hpp"
|
||||
|
||||
#include "preview_renderer/shader.hpp"
|
||||
|
||||
namespace inferno::scene {
|
||||
|
||||
Material::Material(std::string name)
|
||||
: mName(name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Material::~Material()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Material::setGlShader(graphics::Shader* shader)
|
||||
{
|
||||
mGlShader = shader;
|
||||
}
|
||||
|
||||
graphics::Shader* Material::getGlShader()
|
||||
{
|
||||
return mGlShader;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <hart_graphics.hpp>
|
||||
|
||||
namespace inferno::graphics {
|
||||
class Shader;
|
||||
};
|
||||
|
||||
namespace inferno::scene {
|
||||
|
||||
class HitInfo;
|
||||
|
||||
class Material {
|
||||
public:
|
||||
Material(std::string name);
|
||||
~Material();
|
||||
|
||||
std::string getName();
|
||||
void setGlShader(graphics::Shader* shader);
|
||||
graphics::Shader* getGlShader();
|
||||
|
||||
glm::vec3 sample(HitInfo* hit);
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
graphics::Shader* mGlShader;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,120 +1,114 @@
|
||||
#include "mesh.hpp"
|
||||
|
||||
#include <yolo/yolo.hpp>
|
||||
|
||||
#include <scene/objloader.hpp>
|
||||
|
||||
#include "graphics/buffer.hpp"
|
||||
#include "graphics/device.hpp"
|
||||
|
||||
#include <yolo/yolo.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace inferno::scene {
|
||||
|
||||
Mesh::Mesh()
|
||||
VkVertexInputBindingDescription get_vert_binding_description()
|
||||
{
|
||||
VkVertexInputBindingDescription bindingDescription = {};
|
||||
bindingDescription.binding = 0;
|
||||
bindingDescription.stride = sizeof(Vert);
|
||||
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
|
||||
return bindingDescription;
|
||||
}
|
||||
|
||||
Mesh::~Mesh()
|
||||
std::array<VkVertexInputAttributeDescription, 2> get_vert_attribute_descriptions()
|
||||
{
|
||||
delete mObjLoader;
|
||||
std::array<VkVertexInputAttributeDescription, 2> attributeDescriptions = {};
|
||||
|
||||
// Position
|
||||
attributeDescriptions[0].binding = 0;
|
||||
attributeDescriptions[0].location = 0;
|
||||
attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||
attributeDescriptions[0].offset = offsetof(Vert, Position);
|
||||
|
||||
// Normal
|
||||
attributeDescriptions[1].binding = 0;
|
||||
attributeDescriptions[1].location = 1;
|
||||
attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||
attributeDescriptions[1].offset = offsetof(Vert, Normal);
|
||||
|
||||
return attributeDescriptions;
|
||||
}
|
||||
|
||||
void Mesh::loadOBJ(std::filesystem::path file)
|
||||
Mesh* mesh_create(graphics::GraphicsDevice* device)
|
||||
{
|
||||
mObjLoader = new ObjLoader();
|
||||
mObjLoader->load(file);
|
||||
Mesh* mesh = new Mesh();
|
||||
mesh->Device = device;
|
||||
|
||||
int vertCount = mObjLoader->getVertCount();
|
||||
for (int i = 0; i < vertCount * 3; i += 3)
|
||||
{
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void mesh_cleanup(Mesh* mesh)
|
||||
{
|
||||
delete mesh->MeshObjLoader;
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
void mesh_load_obj(Mesh* mesh, std::filesystem::path file)
|
||||
{
|
||||
mesh->MeshObjLoader = new ObjLoader();
|
||||
mesh->MeshObjLoader->load(file);
|
||||
|
||||
int vertCount = mesh->MeshObjLoader->getVertCount();
|
||||
for (int i = 0; i < vertCount * 3; i += 3) {
|
||||
Vert vert;
|
||||
vert.Position = {
|
||||
mObjLoader->getPositions()[i],
|
||||
mObjLoader->getPositions()[i+1],
|
||||
mObjLoader->getPositions()[i+2],
|
||||
mesh->MeshObjLoader->getPositions()[i],
|
||||
mesh->MeshObjLoader->getPositions()[i + 1],
|
||||
mesh->MeshObjLoader->getPositions()[i + 2],
|
||||
};
|
||||
vert.Normal = {
|
||||
mObjLoader->getNormals()[i],
|
||||
mObjLoader->getNormals()[i+1],
|
||||
mObjLoader->getNormals()[i+2],
|
||||
mesh->MeshObjLoader->getNormals()[i],
|
||||
mesh->MeshObjLoader->getNormals()[i + 1],
|
||||
mesh->MeshObjLoader->getNormals()[i + 2],
|
||||
};
|
||||
|
||||
mVerticies.push_back(vert);
|
||||
mesh->Verticies.push_back(vert);
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::ready()
|
||||
void mesh_ready(Mesh* mesh)
|
||||
{
|
||||
// TODO: ready check
|
||||
glGenVertexArrays(1, &mVAO);
|
||||
glGenBuffers(1, &mVBO);
|
||||
glGenBuffers(1, &mEBO);
|
||||
void* data = mesh->Verticies.data();
|
||||
void* indexData = (void*)mesh->MeshObjLoader->getFaces();
|
||||
|
||||
glBindVertexArray(mVAO);
|
||||
// load data into vertex buffers
|
||||
uint32_t size = mesh->Verticies.size();
|
||||
// yolo::debug("Mesh size: {}", size);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, mVerticies.size() * sizeof(Vert), &mVerticies[0], GL_STATIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mEBO);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mObjLoader->getIndexCount() * sizeof(uint32_t), &mObjLoader->getFaces()[0], GL_STATIC_DRAW);
|
||||
|
||||
// set the vertex attribute pointers
|
||||
// vertex Positions
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vert), (void*)0);
|
||||
// vertex normals
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vert), (void*)offsetof(Vert, Normal));
|
||||
// vertex UV
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vert), (void*)offsetof(Vert, UV));
|
||||
|
||||
glBindVertexArray(0);
|
||||
mesh->VertexBuffer = graphics::vertex_buffer_create(mesh->Device, data, size);
|
||||
mesh->IndexBuffer = graphics::index_buffer_create(
|
||||
mesh->Device, indexData, mesh->MeshObjLoader->getIndexCount());
|
||||
|
||||
yolo::debug("Mesh for preview ready...");
|
||||
}
|
||||
|
||||
int Mesh::getVerticies(const float** v, const float** n)
|
||||
uint32_t mesh_get_verticies(Mesh* mesh, const float** v, const float** n)
|
||||
{
|
||||
*v = &mObjLoader->getPositions()[0];
|
||||
*n = &mObjLoader->getNormals()[0];
|
||||
return mObjLoader->getVertCount();
|
||||
*v = &mesh->MeshObjLoader->getPositions()[0];
|
||||
*n = &mesh->MeshObjLoader->getNormals()[0];
|
||||
return mesh->MeshObjLoader->getVertCount();
|
||||
}
|
||||
|
||||
int Mesh::getIndicies(const uint32_t** i)
|
||||
uint32_t mesh_get_indicies(Mesh* mesh, const uint32_t** i)
|
||||
{
|
||||
*i = &mObjLoader->getFaces()[0];
|
||||
return mObjLoader->getIndexCount();
|
||||
*i = &mesh->MeshObjLoader->getFaces()[0];
|
||||
return mesh->MeshObjLoader->getIndexCount();
|
||||
}
|
||||
|
||||
int Mesh::getIndexCount()
|
||||
{
|
||||
return mObjLoader->getIndexCount();
|
||||
}
|
||||
uint32_t mesh_get_index_count(Mesh* mesh) { return mesh->MeshObjLoader->getIndexCount(); }
|
||||
|
||||
void Mesh::setMaterial(Material* mat)
|
||||
{
|
||||
mMaterial = mat;
|
||||
}
|
||||
void mesh_set_model_matrix(Mesh* mesh, glm::mat4 model) { mesh->ModelMatrix = model; }
|
||||
|
||||
Material* Mesh::getMaterial()
|
||||
{
|
||||
return mMaterial;
|
||||
}
|
||||
|
||||
GLuint Mesh::getVAO()
|
||||
{
|
||||
return mVAO;
|
||||
}
|
||||
|
||||
GLuint Mesh::getVBO()
|
||||
{
|
||||
return mVBO;
|
||||
}
|
||||
|
||||
GLuint Mesh::getEBO()
|
||||
{
|
||||
return mEBO;
|
||||
}
|
||||
glm::mat4 mesh_get_model_matrix(Mesh* mesh) { return mesh->ModelMatrix; }
|
||||
|
||||
}
|
||||
|
||||
@@ -1,56 +1,61 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
|
||||
#include <hart_graphics.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
namespace inferno::graphics {
|
||||
struct GraphicsDevice;
|
||||
struct Buffer;
|
||||
}
|
||||
|
||||
namespace inferno::scene {
|
||||
|
||||
class ObjLoader;
|
||||
class Material;
|
||||
|
||||
// TODO: This should be procedural like everything else
|
||||
struct Vert
|
||||
{
|
||||
struct Vert {
|
||||
glm::vec3 Position;
|
||||
glm::vec3 Normal;
|
||||
glm::vec2 UV;
|
||||
};
|
||||
|
||||
class Mesh
|
||||
{
|
||||
public:
|
||||
Mesh();
|
||||
~Mesh();
|
||||
|
||||
void loadOBJ(std::filesystem::path file);
|
||||
void ready();
|
||||
|
||||
int getVerticies(const float** v, const float** n);
|
||||
int getIndicies(const uint32_t** i);
|
||||
|
||||
int getIndexCount();
|
||||
|
||||
void setMaterial(Material* mat);
|
||||
Material* getMaterial();
|
||||
|
||||
// Raster
|
||||
public:
|
||||
GLuint getVAO();
|
||||
GLuint getVBO();
|
||||
GLuint getEBO();
|
||||
|
||||
private:
|
||||
GLuint mVAO;
|
||||
GLuint mVBO;
|
||||
GLuint mEBO;
|
||||
glm::mat4 mModel;
|
||||
|
||||
private:
|
||||
ObjLoader* mObjLoader;
|
||||
Material* mMaterial;
|
||||
|
||||
std::vector<Vert> mVerticies;
|
||||
struct DebugLineVert {
|
||||
glm::vec3 Position;
|
||||
glm::vec3 Color;
|
||||
};
|
||||
|
||||
using Index = uint32_t;
|
||||
|
||||
// NOTE: Out of coincidence, this is the same for both vert and debug line vert
|
||||
// TODO: Make this a template // somehow
|
||||
VkVertexInputBindingDescription get_vert_binding_description();
|
||||
std::array<VkVertexInputAttributeDescription, 2> get_vert_attribute_descriptions();
|
||||
|
||||
typedef struct Mesh {
|
||||
graphics::GraphicsDevice* Device;
|
||||
|
||||
glm::mat4 ModelMatrix;
|
||||
|
||||
ObjLoader* MeshObjLoader;
|
||||
std::vector<Vert> Verticies;
|
||||
|
||||
graphics::Buffer* VertexBuffer;
|
||||
graphics::Buffer* IndexBuffer;
|
||||
} Mesh;
|
||||
|
||||
Mesh* mesh_create(graphics::GraphicsDevice* device);
|
||||
void mesh_cleanup(Mesh* mesh);
|
||||
|
||||
void mesh_load_obj(Mesh* mesh, std::filesystem::path file);
|
||||
void mesh_ready(Mesh* mesh);
|
||||
|
||||
uint32_t mesh_get_verticies(Mesh* mesh, const float** v, const float** n);
|
||||
uint32_t mesh_get_indicies(Mesh* mesh, const uint32_t** i);
|
||||
uint32_t mesh_get_index_count(Mesh* mesh);
|
||||
|
||||
void mesh_set_model_matrix(Mesh* mesh, glm::mat4 model);
|
||||
glm::mat4 mesh_get_model_matrix(Mesh* mesh);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "hart_graphics.hpp"
|
||||
|
||||
#include "scene/object.hpp"
|
||||
|
||||
#include <memory>
|
||||
@@ -14,6 +16,13 @@ namespace inferno::scene {
|
||||
class SceneObject;
|
||||
class Mesh;
|
||||
|
||||
typedef struct GlobalUniformObject {
|
||||
glm::mat4 Projection;
|
||||
glm::mat4 View;
|
||||
glm::mat4 _padding0; // Fuck you nvidia!
|
||||
glm::mat4 _padding1;
|
||||
} GlobalUniformObject;
|
||||
|
||||
typedef struct Scene {
|
||||
std::vector<SceneObject*> Objects;
|
||||
graphics::Camera* Camera;
|
||||
|
||||
1838
src/thirdparty/glad/glad.c
vendored
1838
src/thirdparty/glad/glad.c
vendored
File diff suppressed because it is too large
Load Diff
34
src/thirdparty/imgui/imconfig.h
vendored
34
src/thirdparty/imgui/imconfig.h
vendored
@@ -1,5 +1,5 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -9,7 +9,7 @@
|
||||
// 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 files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||
// 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
|
||||
@@ -26,21 +26,21 @@
|
||||
//#define IMGUI_API __declspec( dllexport )
|
||||
//#define IMGUI_API __declspec( dllimport )
|
||||
|
||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
|
||||
//---- 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
|
||||
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
|
||||
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by 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 ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88).
|
||||
//#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_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_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.
|
||||
@@ -62,9 +62,10 @@
|
||||
// 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 enabled
|
||||
//#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.
|
||||
@@ -75,6 +76,12 @@
|
||||
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||
//#define IMGUI_ENABLE_FREETYPE
|
||||
|
||||
//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT)
|
||||
// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided).
|
||||
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
||||
// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||
//#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
|
||||
@@ -90,6 +97,8 @@
|
||||
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).
|
||||
@@ -103,23 +112,18 @@
|
||||
//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
|
||||
//---- 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: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(),
|
||||
// (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.)
|
||||
// This adds a small runtime cost which is why it is not enabled by default.
|
||||
//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
|
||||
|
||||
//---- Debug Tools: Enable slower asserts
|
||||
//#define IMGUI_DEBUG_PARANOID
|
||||
|
||||
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
|
||||
//---- 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, const MyMatrix44& v);
|
||||
void MyFunction(const char* name, MyMatrix44* mtx);
|
||||
}
|
||||
*/
|
||||
|
||||
7047
src/thirdparty/imgui/imgui.cpp
vendored
7047
src/thirdparty/imgui/imgui.cpp
vendored
File diff suppressed because it is too large
Load Diff
695
src/thirdparty/imgui/imgui.h
vendored
695
src/thirdparty/imgui/imgui.h
vendored
File diff suppressed because it is too large
Load Diff
1376
src/thirdparty/imgui/imgui_demo.cpp
vendored
1376
src/thirdparty/imgui/imgui_demo.cpp
vendored
File diff suppressed because it is too large
Load Diff
401
src/thirdparty/imgui/imgui_draw.cpp
vendored
401
src/thirdparty/imgui/imgui_draw.cpp
vendored
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.89 WIP
|
||||
// dear imgui, v1.90.1 WIP
|
||||
// (drawing and font code)
|
||||
|
||||
/*
|
||||
@@ -26,13 +26,12 @@ Index of this file:
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "imgui.h"
|
||||
#ifndef IMGUI_DISABLE
|
||||
|
||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#endif
|
||||
|
||||
#include "imgui.h"
|
||||
#ifndef IMGUI_DISABLE
|
||||
#include "imgui_internal.h"
|
||||
#ifdef IMGUI_ENABLE_FREETYPE
|
||||
#include "misc/freetype/imgui_freetype.h"
|
||||
@@ -64,6 +63,7 @@ Index of this file:
|
||||
#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier
|
||||
#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
|
||||
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
|
||||
#pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
|
||||
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
|
||||
@@ -135,7 +135,7 @@ namespace IMGUI_STB_NAMESPACE
|
||||
#define STBTT_sqrt(x) ImSqrt(x)
|
||||
#define STBTT_pow(x,y) ImPow(x,y)
|
||||
#define STBTT_fabs(x) ImFabs(x)
|
||||
#define STBTT_ifloor(x) ((int)ImFloorSigned(x))
|
||||
#define STBTT_ifloor(x) ((int)ImFloor(x))
|
||||
#define STBTT_iceil(x) ((int)ImCeil(x))
|
||||
#define STBTT_STATIC
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
@@ -392,9 +392,9 @@ void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error)
|
||||
void ImDrawList::_ResetForNewFrame()
|
||||
{
|
||||
// Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory.
|
||||
IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0);
|
||||
IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4));
|
||||
IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID));
|
||||
IM_STATIC_ASSERT(offsetof(ImDrawCmd, ClipRect) == 0);
|
||||
IM_STATIC_ASSERT(offsetof(ImDrawCmd, TextureId) == sizeof(ImVec4));
|
||||
IM_STATIC_ASSERT(offsetof(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID));
|
||||
if (_Splitter._Count > 1)
|
||||
_Splitter.Merge(this);
|
||||
|
||||
@@ -455,11 +455,13 @@ void ImDrawList::AddDrawCmd()
|
||||
// Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL
|
||||
void ImDrawList::_PopUnusedDrawCmd()
|
||||
{
|
||||
if (CmdBuffer.Size == 0)
|
||||
return;
|
||||
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
||||
if (curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL)
|
||||
while (CmdBuffer.Size > 0)
|
||||
{
|
||||
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
|
||||
if (curr_cmd->ElemCount != 0 || curr_cmd->UserCallback != NULL)
|
||||
return;// break;
|
||||
CmdBuffer.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
|
||||
@@ -479,7 +481,7 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
|
||||
}
|
||||
|
||||
// Compare ClipRect, TextureId and VtxOffset with a single memcmp()
|
||||
#define ImDrawCmd_HeaderSize (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int))
|
||||
#define ImDrawCmd_HeaderSize (offsetof(ImDrawCmd, VtxOffset) + sizeof(unsigned int))
|
||||
#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset
|
||||
#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset
|
||||
#define ImDrawCmd_AreSequentialIdxOffset(CMD_0, CMD_1) (CMD_0->IdxOffset + CMD_0->ElemCount == CMD_1->IdxOffset)
|
||||
@@ -565,7 +567,7 @@ int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const
|
||||
{
|
||||
// Automatic segment count
|
||||
const int radius_idx = (int)(radius + 0.999999f); // ceil to never reduce accuracy
|
||||
if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts))
|
||||
if (radius_idx >= 0 && radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts))
|
||||
return _Data->CircleSegmentCounts[radius_idx]; // Use cached value
|
||||
else
|
||||
return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError);
|
||||
@@ -712,7 +714,7 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c
|
||||
// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.
|
||||
void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, ImDrawFlags flags, float thickness)
|
||||
{
|
||||
if (points_count < 2)
|
||||
if (points_count < 2 || (col & IM_COL32_A_MASK) == 0)
|
||||
return;
|
||||
|
||||
const bool closed = (flags & ImDrawFlags_Closed) != 0;
|
||||
@@ -970,7 +972,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
|
||||
// - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing.
|
||||
void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
|
||||
{
|
||||
if (points_count < 3)
|
||||
if (points_count < 3 || (col & IM_COL32_A_MASK) == 0)
|
||||
return;
|
||||
|
||||
const ImVec2 uv = _Data->TexUvWhitePixel;
|
||||
@@ -1195,8 +1197,8 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa
|
||||
const float a_min_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_min / (IM_PI * 2.0f);
|
||||
const float a_max_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_max / (IM_PI * 2.0f);
|
||||
|
||||
const int a_min_sample = a_is_reverse ? (int)ImFloorSigned(a_min_sample_f) : (int)ImCeil(a_min_sample_f);
|
||||
const int a_max_sample = a_is_reverse ? (int)ImCeil(a_max_sample_f) : (int)ImFloorSigned(a_max_sample_f);
|
||||
const int a_min_sample = a_is_reverse ? (int)ImFloor(a_min_sample_f) : (int)ImCeil(a_min_sample_f);
|
||||
const int a_max_sample = a_is_reverse ? (int)ImCeil(a_max_sample_f) : (int)ImFloor(a_max_sample_f);
|
||||
const int a_mid_samples = a_is_reverse ? ImMax(a_min_sample - a_max_sample, 0) : ImMax(a_max_sample - a_min_sample, 0);
|
||||
|
||||
const float a_min_segment_angle = a_min_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
|
||||
@@ -1221,6 +1223,27 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa
|
||||
}
|
||||
}
|
||||
|
||||
void ImDrawList::PathEllipticalArcTo(const ImVec2& center, float radius_x, float radius_y, float rot, float a_min, float a_max, int num_segments)
|
||||
{
|
||||
if (num_segments <= 0)
|
||||
num_segments = _CalcCircleAutoSegmentCount(ImMax(radius_x, radius_y)); // A bit pessimistic, maybe there's a better computation to do here.
|
||||
|
||||
_Path.reserve(_Path.Size + (num_segments + 1));
|
||||
|
||||
const float cos_rot = ImCos(rot);
|
||||
const float sin_rot = ImSin(rot);
|
||||
for (int i = 0; i <= num_segments; i++)
|
||||
{
|
||||
const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
|
||||
ImVec2 point(ImCos(a) * radius_x, ImSin(a) * radius_y);
|
||||
const float rel_x = (point.x * cos_rot) - (point.y * sin_rot);
|
||||
const float rel_y = (point.x * sin_rot) + (point.y * cos_rot);
|
||||
point.x = rel_x + center.x;
|
||||
point.y = rel_y + center.y;
|
||||
_Path.push_back(point);
|
||||
}
|
||||
}
|
||||
|
||||
ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t)
|
||||
{
|
||||
float u = 1.0f - t;
|
||||
@@ -1316,33 +1339,22 @@ void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3,
|
||||
}
|
||||
}
|
||||
|
||||
IM_STATIC_ASSERT(ImDrawFlags_RoundCornersTopLeft == (1 << 4));
|
||||
static inline ImDrawFlags FixRectCornerFlags(ImDrawFlags flags)
|
||||
{
|
||||
/*
|
||||
IM_STATIC_ASSERT(ImDrawFlags_RoundCornersTopLeft == (1 << 4));
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
// Obsoleted in 1.82 (from February 2021)
|
||||
// Legacy Support for hard coded ~0 (used to be a suggested equivalent to ImDrawCornerFlags_All)
|
||||
// ~0 --> ImDrawFlags_RoundCornersAll or 0
|
||||
if (flags == ~0)
|
||||
return ImDrawFlags_RoundCornersAll;
|
||||
|
||||
// Legacy Support for hard coded 0x01 to 0x0F (matching 15 out of 16 old flags combinations)
|
||||
// 0x01 --> ImDrawFlags_RoundCornersTopLeft (VALUE 0x01 OVERLAPS ImDrawFlags_Closed but ImDrawFlags_Closed is never valid in this path!)
|
||||
// 0x02 --> ImDrawFlags_RoundCornersTopRight
|
||||
// 0x03 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight
|
||||
// 0x04 --> ImDrawFlags_RoundCornersBotLeft
|
||||
// 0x05 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBotLeft
|
||||
// ...
|
||||
// 0x0F --> ImDrawFlags_RoundCornersAll or 0
|
||||
// (See all values in ImDrawCornerFlags_)
|
||||
if (flags >= 0x01 && flags <= 0x0F)
|
||||
return (flags << 4);
|
||||
|
||||
// Obsoleted in 1.82 (from February 2021). This code was stripped/simplified and mostly commented in 1.90 (from September 2023)
|
||||
// - Legacy Support for hard coded ~0 (used to be a suggested equivalent to ImDrawCornerFlags_All)
|
||||
if (flags == ~0) { return ImDrawFlags_RoundCornersAll; }
|
||||
// - Legacy Support for hard coded 0x01 to 0x0F (matching 15 out of 16 old flags combinations). Read details in older version of this code.
|
||||
if (flags >= 0x01 && flags <= 0x0F) { return (flags << 4); }
|
||||
// We cannot support hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundCornersNone or use 'float rounding = 0.0f'
|
||||
#endif
|
||||
|
||||
// If this triggers, please update your code replacing hardcoded values with new ImDrawFlags_RoundCorners* values.
|
||||
// Note that ImDrawFlags_Closed (== 0x01) is an invalid flag for AddRect(), AddRectFilled(), PathRect() etc...
|
||||
*/
|
||||
// If this assert triggers, please update your code replacing hardcoded values with new ImDrawFlags_RoundCorners* values.
|
||||
// Note that ImDrawFlags_Closed (== 0x01) is an invalid flag for AddRect(), AddRectFilled(), PathRect() etc. anyway.
|
||||
// See details in 1.82 Changelog as well as 2021/03/12 and 2023/09/08 entries in "API BREAKING CHANGES" section.
|
||||
IM_ASSERT((flags & 0x0F) == 0 && "Misuse of legacy hardcoded ImDrawCornerFlags values!");
|
||||
|
||||
if ((flags & ImDrawFlags_RoundCornersMask_) == 0)
|
||||
@@ -1353,10 +1365,12 @@ static inline ImDrawFlags FixRectCornerFlags(ImDrawFlags flags)
|
||||
|
||||
void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawFlags flags)
|
||||
{
|
||||
flags = FixRectCornerFlags(flags);
|
||||
rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f ) - 1.0f);
|
||||
rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f ) - 1.0f);
|
||||
|
||||
if (rounding >= 0.5f)
|
||||
{
|
||||
flags = FixRectCornerFlags(flags);
|
||||
rounding = ImMin(rounding, ImFabs(b.x - a.x) * (((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f) - 1.0f);
|
||||
rounding = ImMin(rounding, ImFabs(b.y - a.y) * (((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f) - 1.0f);
|
||||
}
|
||||
if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
|
||||
{
|
||||
PathLineTo(a);
|
||||
@@ -1549,6 +1563,35 @@ void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, in
|
||||
PathFillConvex(col);
|
||||
}
|
||||
|
||||
// Ellipse
|
||||
void ImDrawList::AddEllipse(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot, int num_segments, float thickness)
|
||||
{
|
||||
if ((col & IM_COL32_A_MASK) == 0)
|
||||
return;
|
||||
|
||||
if (num_segments <= 0)
|
||||
num_segments = _CalcCircleAutoSegmentCount(ImMax(radius_x, radius_y)); // A bit pessimistic, maybe there's a better computation to do here.
|
||||
|
||||
// Because we are filling a closed shape we remove 1 from the count of segments/points
|
||||
const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
|
||||
PathEllipticalArcTo(center, radius_x, radius_y, rot, 0.0f, a_max, num_segments - 1);
|
||||
PathStroke(col, true, thickness);
|
||||
}
|
||||
|
||||
void ImDrawList::AddEllipseFilled(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot, int num_segments)
|
||||
{
|
||||
if ((col & IM_COL32_A_MASK) == 0)
|
||||
return;
|
||||
|
||||
if (num_segments <= 0)
|
||||
num_segments = _CalcCircleAutoSegmentCount(ImMax(radius_x, radius_y)); // A bit pessimistic, maybe there's a better computation to do here.
|
||||
|
||||
// Because we are filling a closed shape we remove 1 from the count of segments/points
|
||||
const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
|
||||
PathEllipticalArcTo(center, radius_x, radius_y, rot, 0.0f, a_max, num_segments - 1);
|
||||
PathFillConvex(col);
|
||||
}
|
||||
|
||||
// Cubic Bezier takes 4 controls points
|
||||
void ImDrawList::AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments)
|
||||
{
|
||||
@@ -1813,6 +1856,63 @@ void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx)
|
||||
// [SECTION] ImDrawData
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void ImDrawData::Clear()
|
||||
{
|
||||
Valid = false;
|
||||
CmdListsCount = TotalIdxCount = TotalVtxCount = 0;
|
||||
CmdLists.resize(0); // The ImDrawList are NOT owned by ImDrawData but e.g. by ImGuiContext, so we don't clear them.
|
||||
DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.0f, 0.0f);
|
||||
OwnerViewport = NULL;
|
||||
}
|
||||
|
||||
// Important: 'out_list' is generally going to be draw_data->CmdLists, but may be another temporary list
|
||||
// as long at it is expected that the result will be later merged into draw_data->CmdLists[].
|
||||
void ImGui::AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector<ImDrawList*>* out_list, ImDrawList* draw_list)
|
||||
{
|
||||
if (draw_list->CmdBuffer.Size == 0)
|
||||
return;
|
||||
if (draw_list->CmdBuffer.Size == 1 && draw_list->CmdBuffer[0].ElemCount == 0 && draw_list->CmdBuffer[0].UserCallback == NULL)
|
||||
return;
|
||||
|
||||
// Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
|
||||
// May trigger for you if you are using PrimXXX functions incorrectly.
|
||||
IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
|
||||
IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
|
||||
if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset))
|
||||
IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
|
||||
|
||||
// Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
|
||||
// If this assert triggers because you are drawing lots of stuff manually:
|
||||
// - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds.
|
||||
// Be mindful that the lower-level ImDrawList API doesn't filter vertices. Use the Metrics/Debugger window to inspect draw list contents.
|
||||
// - If you want large meshes with more than 64K vertices, you can either:
|
||||
// (A) Handle the ImDrawCmd::VtxOffset value in your renderer backend, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'.
|
||||
// Most example backends already support this from 1.71. Pre-1.71 backends won't.
|
||||
// Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them.
|
||||
// (B) Or handle 32-bit indices in your renderer backend, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h.
|
||||
// Most example backends already support this. For example, the OpenGL example code detect index size at compile-time:
|
||||
// glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
|
||||
// Your own engine or render API may use different parameters or function calls to specify index sizes.
|
||||
// 2 and 4 bytes indices are generally supported by most graphics API.
|
||||
// - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching
|
||||
// the 64K limit to split your draw commands in multiple draw lists.
|
||||
if (sizeof(ImDrawIdx) == 2)
|
||||
IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
|
||||
|
||||
// Add to output list + records state in ImDrawData
|
||||
out_list->push_back(draw_list);
|
||||
draw_data->CmdListsCount++;
|
||||
draw_data->TotalVtxCount += draw_list->VtxBuffer.Size;
|
||||
draw_data->TotalIdxCount += draw_list->IdxBuffer.Size;
|
||||
}
|
||||
|
||||
void ImDrawData::AddDrawList(ImDrawList* draw_list)
|
||||
{
|
||||
IM_ASSERT(CmdLists.Size == CmdListsCount);
|
||||
draw_list->_PopUnusedDrawCmd();
|
||||
ImGui::AddDrawListToDrawDataEx(this, &CmdLists, draw_list);
|
||||
}
|
||||
|
||||
// For backward compatibility: convert all buffers from indexed to de-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering!
|
||||
void ImDrawData::DeIndexAllBuffers()
|
||||
{
|
||||
@@ -1837,15 +1937,9 @@ void ImDrawData::DeIndexAllBuffers()
|
||||
// or if there is a difference between your window resolution and framebuffer resolution.
|
||||
void ImDrawData::ScaleClipRects(const ImVec2& fb_scale)
|
||||
{
|
||||
for (int i = 0; i < CmdListsCount; i++)
|
||||
{
|
||||
ImDrawList* cmd_list = CmdLists[i];
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
cmd->ClipRect = ImVec4(cmd->ClipRect.x * fb_scale.x, cmd->ClipRect.y * fb_scale.y, cmd->ClipRect.z * fb_scale.x, cmd->ClipRect.w * fb_scale.y);
|
||||
}
|
||||
}
|
||||
for (ImDrawList* draw_list : CmdLists)
|
||||
for (ImDrawCmd& cmd : draw_list->CmdBuffer)
|
||||
cmd.ClipRect = ImVec4(cmd.ClipRect.x * fb_scale.x, cmd.ClipRect.y * fb_scale.y, cmd.ClipRect.z * fb_scale.x, cmd.ClipRect.w * fb_scale.y);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -1901,6 +1995,14 @@ void ImGui::ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int ve
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui::ShadeVertsTransformPos(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& pivot_in, float cos_a, float sin_a, const ImVec2& pivot_out)
|
||||
{
|
||||
ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;
|
||||
ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;
|
||||
for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
|
||||
vertex->pos = ImRotate(vertex->pos- pivot_in, cos_a, sin_a) + pivot_out;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] ImFontConfig
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -1909,10 +2011,11 @@ ImFontConfig::ImFontConfig()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
FontDataOwnedByAtlas = true;
|
||||
OversampleH = 3; // FIXME: 2 may be a better default?
|
||||
OversampleH = 2;
|
||||
OversampleV = 1;
|
||||
GlyphMaxAdvanceX = FLT_MAX;
|
||||
RasterizerMultiply = 1.0f;
|
||||
RasterizerDensity = 1.0f;
|
||||
EllipsisChar = (ImWchar)-1;
|
||||
}
|
||||
|
||||
@@ -1986,19 +2089,19 @@ ImFontAtlas::~ImFontAtlas()
|
||||
void ImFontAtlas::ClearInputData()
|
||||
{
|
||||
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
|
||||
for (int i = 0; i < ConfigData.Size; i++)
|
||||
if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas)
|
||||
for (ImFontConfig& font_cfg : ConfigData)
|
||||
if (font_cfg.FontData && font_cfg.FontDataOwnedByAtlas)
|
||||
{
|
||||
IM_FREE(ConfigData[i].FontData);
|
||||
ConfigData[i].FontData = NULL;
|
||||
IM_FREE(font_cfg.FontData);
|
||||
font_cfg.FontData = NULL;
|
||||
}
|
||||
|
||||
// When clearing this we lose access to the font name and other information used to build the font.
|
||||
for (int i = 0; i < Fonts.Size; i++)
|
||||
if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size)
|
||||
for (ImFont* font : Fonts)
|
||||
if (font->ConfigData >= ConfigData.Data && font->ConfigData < ConfigData.Data + ConfigData.Size)
|
||||
{
|
||||
Fonts[i]->ConfigData = NULL;
|
||||
Fonts[i]->ConfigDataCount = 0;
|
||||
font->ConfigData = NULL;
|
||||
font->ConfigDataCount = 0;
|
||||
}
|
||||
ConfigData.clear();
|
||||
CustomRects.clear();
|
||||
@@ -2095,6 +2198,8 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
|
||||
if (new_font_cfg.DstFont->EllipsisChar == (ImWchar)-1)
|
||||
new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar;
|
||||
|
||||
ImFontAtlasUpdateConfigDataPointers(this);
|
||||
|
||||
// Invalidate texture
|
||||
TexReady = false;
|
||||
ClearTexData();
|
||||
@@ -2131,7 +2236,7 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
|
||||
if (font_cfg.Name[0] == '\0')
|
||||
ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels);
|
||||
font_cfg.EllipsisChar = (ImWchar)0x0085;
|
||||
font_cfg.GlyphOffset.y = 1.0f * IM_FLOOR(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units
|
||||
font_cfg.GlyphOffset.y = 1.0f * IM_TRUNC(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units
|
||||
|
||||
const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
|
||||
const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault();
|
||||
@@ -2161,13 +2266,14 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels,
|
||||
}
|
||||
|
||||
// NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build().
|
||||
ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
|
||||
ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
|
||||
{
|
||||
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
|
||||
ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
|
||||
IM_ASSERT(font_cfg.FontData == NULL);
|
||||
font_cfg.FontData = ttf_data;
|
||||
font_cfg.FontDataSize = ttf_size;
|
||||
IM_ASSERT(font_data_size > 100 && "Incorrect value for font_data_size!"); // Heuristic to prevent accidentally passing a wrong value to font_data_size.
|
||||
font_cfg.FontData = font_data;
|
||||
font_cfg.FontDataSize = font_data_size;
|
||||
font_cfg.SizePixels = size_pixels > 0.0f ? size_pixels : font_cfg.SizePixels;
|
||||
if (glyph_ranges)
|
||||
font_cfg.GlyphRanges = glyph_ranges;
|
||||
@@ -2382,13 +2488,21 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
|
||||
IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found.");
|
||||
if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
|
||||
{
|
||||
IM_ASSERT(0 && "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Measure highest codepoints
|
||||
ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
||||
src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
|
||||
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
||||
{
|
||||
// Check for valid range. This may also help detect *some* dangling pointers, because a common
|
||||
// user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent.
|
||||
IM_ASSERT(src_range[0] <= src_range[1]);
|
||||
src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
|
||||
}
|
||||
dst_tmp.SrcCount++;
|
||||
dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
|
||||
}
|
||||
@@ -2459,7 +2573,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
|
||||
// Convert our ranges in the format stb_truetype wants
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
src_tmp.PackRange.font_size = cfg.SizePixels;
|
||||
src_tmp.PackRange.font_size = cfg.SizePixels * cfg.RasterizerDensity;
|
||||
src_tmp.PackRange.first_unicode_codepoint_in_range = 0;
|
||||
src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data;
|
||||
src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size;
|
||||
@@ -2468,7 +2582,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV;
|
||||
|
||||
// Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects)
|
||||
const float scale = (cfg.SizePixels > 0) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels);
|
||||
const float scale = (cfg.SizePixels > 0.0f) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels * cfg.RasterizerDensity) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels * cfg.RasterizerDensity);
|
||||
const int padding = atlas->TexGlyphPadding;
|
||||
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
|
||||
{
|
||||
@@ -2553,13 +2667,10 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
// 9. Setup ImFont and glyphs for runtime
|
||||
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
||||
{
|
||||
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
||||
if (src_tmp.GlyphsCount == 0)
|
||||
continue;
|
||||
|
||||
// When merging fonts with MergeMode=true:
|
||||
// - We can have multiple input fonts writing into a same destination font.
|
||||
// - dst_font->ConfigData is != from cfg which is our source configuration.
|
||||
ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
||||
ImFontConfig& cfg = atlas->ConfigData[src_i];
|
||||
ImFont* dst_font = cfg.DstFont;
|
||||
|
||||
@@ -2567,12 +2678,14 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
int unscaled_ascent, unscaled_descent, unscaled_line_gap;
|
||||
stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
|
||||
|
||||
const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1));
|
||||
const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1));
|
||||
const float ascent = ImTrunc(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1));
|
||||
const float descent = ImTrunc(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1));
|
||||
ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
|
||||
const float font_off_x = cfg.GlyphOffset.x;
|
||||
const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
|
||||
|
||||
const float inv_rasterization_scale = 1.0f / cfg.RasterizerDensity;
|
||||
|
||||
for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
||||
{
|
||||
// Register glyph
|
||||
@@ -2581,7 +2694,11 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
||||
stbtt_aligned_quad q;
|
||||
float unused_x = 0.0f, unused_y = 0.0f;
|
||||
stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &unused_x, &unused_y, &q, 0);
|
||||
dst_font->AddGlyph(&cfg, (ImWchar)codepoint, q.x0 + font_off_x, q.y0 + font_off_y, q.x1 + font_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, pc.xadvance);
|
||||
float x0 = q.x0 * inv_rasterization_scale + font_off_x;
|
||||
float y0 = q.y0 * inv_rasterization_scale + font_off_y;
|
||||
float x1 = q.x1 * inv_rasterization_scale + font_off_x;
|
||||
float y1 = q.y1 * inv_rasterization_scale + font_off_y;
|
||||
dst_font->AddGlyph(&cfg, (ImWchar)codepoint, x0, y0, x1, y1, q.s0, q.t0, q.s1, q.t1, pc.xadvance * inv_rasterization_scale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2601,19 +2718,31 @@ const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype()
|
||||
|
||||
#endif // IMGUI_ENABLE_STB_TRUETYPE
|
||||
|
||||
void ImFontAtlasUpdateConfigDataPointers(ImFontAtlas* atlas)
|
||||
{
|
||||
for (ImFontConfig& font_cfg : atlas->ConfigData)
|
||||
{
|
||||
ImFont* font = font_cfg.DstFont;
|
||||
if (!font_cfg.MergeMode)
|
||||
{
|
||||
font->ConfigData = &font_cfg;
|
||||
font->ConfigDataCount = 0;
|
||||
}
|
||||
font->ConfigDataCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent)
|
||||
{
|
||||
if (!font_config->MergeMode)
|
||||
{
|
||||
font->ClearOutputData();
|
||||
font->FontSize = font_config->SizePixels;
|
||||
font->ConfigData = font_config;
|
||||
font->ConfigDataCount = 0;
|
||||
IM_ASSERT(font->ConfigData == font_config);
|
||||
font->ContainerAtlas = atlas;
|
||||
font->Ascent = ascent;
|
||||
font->Descent = descent;
|
||||
}
|
||||
font->ConfigDataCount++;
|
||||
}
|
||||
|
||||
void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque)
|
||||
@@ -2623,6 +2752,9 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opa
|
||||
|
||||
ImVector<ImFontAtlasCustomRect>& user_rects = atlas->CustomRects;
|
||||
IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.
|
||||
#ifdef __GNUC__
|
||||
if (user_rects.Size < 1) { __builtin_unreachable(); } // Workaround for GCC bug if IM_ASSERT() is defined to conditionally throw (see #5343)
|
||||
#endif
|
||||
|
||||
ImVector<stbrp_rect> pack_rects;
|
||||
pack_rects.resize(user_rects.Size);
|
||||
@@ -2757,6 +2889,13 @@ static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas)
|
||||
// Note: this is called / shared by both the stb_truetype and the FreeType builder
|
||||
void ImFontAtlasBuildInit(ImFontAtlas* atlas)
|
||||
{
|
||||
// Round font size
|
||||
// - We started rounding in 1.90 WIP (18991) as our layout system currently doesn't support non-rounded font size well yet.
|
||||
// - Note that using io.FontGlobalScale or SetWindowFontScale(), with are legacy-ish, partially supported features, can still lead to unrounded sizes.
|
||||
// - We may support it better later and remove this rounding.
|
||||
for (ImFontConfig& cfg : atlas->ConfigData)
|
||||
cfg.SizePixels = ImTrunc(cfg.SizePixels);
|
||||
|
||||
// Register texture region for mouse cursors or standard white pixels
|
||||
if (atlas->PackIdMouseCursors < 0)
|
||||
{
|
||||
@@ -2798,9 +2937,9 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
|
||||
}
|
||||
|
||||
// Build all fonts lookup tables
|
||||
for (int i = 0; i < atlas->Fonts.Size; i++)
|
||||
if (atlas->Fonts[i]->DirtyLookupTables)
|
||||
atlas->Fonts[i]->BuildLookupTable();
|
||||
for (ImFont* font : atlas->Fonts)
|
||||
if (font->DirtyLookupTables)
|
||||
font->BuildLookupTable();
|
||||
|
||||
atlas->TexReady = true;
|
||||
}
|
||||
@@ -2943,19 +3082,19 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
|
||||
// 2999 ideograms code points for Japanese
|
||||
// - 2136 Joyo (meaning "for regular use" or "for common use") Kanji code points
|
||||
// - 863 Jinmeiyo (meaning "for personal name") Kanji code points
|
||||
// - Sourced from the character information database of the Information-technology Promotion Agency, Japan
|
||||
// - https://mojikiban.ipa.go.jp/mji/
|
||||
// - Available under the terms of the Creative Commons Attribution-ShareAlike 2.1 Japan (CC BY-SA 2.1 JP).
|
||||
// - https://creativecommons.org/licenses/by-sa/2.1/jp/deed.en
|
||||
// - https://creativecommons.org/licenses/by-sa/2.1/jp/legalcode
|
||||
// - You can generate this code by the script at:
|
||||
// - https://github.com/vaiorabbit/everyday_use_kanji
|
||||
// - Sourced from official information provided by the government agencies of Japan:
|
||||
// - List of Joyo Kanji by the Agency for Cultural Affairs
|
||||
// - https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kijun/naikaku/kanji/
|
||||
// - List of Jinmeiyo Kanji by the Ministry of Justice
|
||||
// - http://www.moj.go.jp/MINJI/minji86.html
|
||||
// - Available under the terms of the Creative Commons Attribution 4.0 International (CC BY 4.0).
|
||||
// - https://creativecommons.org/licenses/by/4.0/legalcode
|
||||
// - You can generate this code by the script at:
|
||||
// - https://github.com/vaiorabbit/everyday_use_kanji
|
||||
// - References:
|
||||
// - List of Joyo Kanji
|
||||
// - (Official list by the Agency for Cultural Affairs) https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kakuki/14/tosin02/index.html
|
||||
// - (Wikipedia) https://en.wikipedia.org/wiki/List_of_j%C5%8Dy%C5%8D_kanji
|
||||
// - List of Jinmeiyo Kanji
|
||||
// - (Official list by the Ministry of Justice) http://www.moj.go.jp/MINJI/minji86.html
|
||||
// - (Wikipedia) https://en.wikipedia.org/wiki/Jinmeiy%C5%8D_kanji
|
||||
// - Missing 1 Joyo Kanji: U+20B9F (Kun'yomi: Shikaru, On'yomi: Shitsu,shichi), see https://github.com/ocornut/imgui/pull/3627 for details.
|
||||
// You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
|
||||
@@ -3118,7 +3257,8 @@ ImFont::ImFont()
|
||||
FallbackAdvanceX = 0.0f;
|
||||
FallbackChar = (ImWchar)-1;
|
||||
EllipsisChar = (ImWchar)-1;
|
||||
DotChar = (ImWchar)-1;
|
||||
EllipsisWidth = EllipsisCharStep = 0.0f;
|
||||
EllipsisCharCount = 0;
|
||||
FallbackGlyph = NULL;
|
||||
ContainerAtlas = NULL;
|
||||
ConfigData = NULL;
|
||||
@@ -3164,6 +3304,7 @@ void ImFont::BuildLookupTable()
|
||||
max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint);
|
||||
|
||||
// Build lookup table
|
||||
IM_ASSERT(Glyphs.Size > 0 && "Font has not loaded glyph!");
|
||||
IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved
|
||||
IndexAdvanceX.clear();
|
||||
IndexLookup.clear();
|
||||
@@ -3199,17 +3340,7 @@ void ImFont::BuildLookupTable()
|
||||
SetGlyphVisible((ImWchar)' ', false);
|
||||
SetGlyphVisible((ImWchar)'\t', false);
|
||||
|
||||
// Ellipsis character is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
|
||||
// However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
|
||||
// FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots.
|
||||
const ImWchar ellipsis_chars[] = { (ImWchar)0x2026, (ImWchar)0x0085 };
|
||||
const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E };
|
||||
if (EllipsisChar == (ImWchar)-1)
|
||||
EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars));
|
||||
if (DotChar == (ImWchar)-1)
|
||||
DotChar = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars));
|
||||
|
||||
// Setup fallback character
|
||||
// Setup Fallback character
|
||||
const ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' };
|
||||
FallbackGlyph = FindGlyphNoFallback(FallbackChar);
|
||||
if (FallbackGlyph == NULL)
|
||||
@@ -3222,11 +3353,32 @@ void ImFont::BuildLookupTable()
|
||||
FallbackChar = (ImWchar)FallbackGlyph->Codepoint;
|
||||
}
|
||||
}
|
||||
|
||||
FallbackAdvanceX = FallbackGlyph->AdvanceX;
|
||||
for (int i = 0; i < max_codepoint + 1; i++)
|
||||
if (IndexAdvanceX[i] < 0.0f)
|
||||
IndexAdvanceX[i] = FallbackAdvanceX;
|
||||
|
||||
// Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
|
||||
// However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
|
||||
// FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots.
|
||||
const ImWchar ellipsis_chars[] = { (ImWchar)0x2026, (ImWchar)0x0085 };
|
||||
const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E };
|
||||
if (EllipsisChar == (ImWchar)-1)
|
||||
EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars));
|
||||
const ImWchar dot_char = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars));
|
||||
if (EllipsisChar != (ImWchar)-1)
|
||||
{
|
||||
EllipsisCharCount = 1;
|
||||
EllipsisWidth = EllipsisCharStep = FindGlyph(EllipsisChar)->X1;
|
||||
}
|
||||
else if (dot_char != (ImWchar)-1)
|
||||
{
|
||||
const ImFontGlyph* glyph = FindGlyph(dot_char);
|
||||
EllipsisChar = dot_char;
|
||||
EllipsisCharCount = 3;
|
||||
EllipsisCharStep = (glyph->X1 - glyph->X0) + 1.0f;
|
||||
EllipsisWidth = EllipsisCharStep * 3.0f - 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// API is designed this way to avoid exposing the 4K page size
|
||||
@@ -3269,7 +3421,7 @@ void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, floa
|
||||
advance_x = ImClamp(advance_x, cfg->GlyphMinAdvanceX, cfg->GlyphMaxAdvanceX);
|
||||
if (advance_x != advance_x_original)
|
||||
{
|
||||
float char_off_x = cfg->PixelSnapH ? ImFloor((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f;
|
||||
float char_off_x = cfg->PixelSnapH ? ImTrunc((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f;
|
||||
x0 += char_off_x;
|
||||
x1 += char_off_x;
|
||||
}
|
||||
@@ -3375,6 +3527,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
|
||||
bool inside_word = true;
|
||||
|
||||
const char* s = text;
|
||||
IM_ASSERT(text_end != NULL);
|
||||
while (s < text_end)
|
||||
{
|
||||
unsigned int c = (unsigned int)*s;
|
||||
@@ -3383,8 +3536,6 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
|
||||
next_s = s + 1;
|
||||
else
|
||||
next_s = s + ImTextCharFromUtf8(&c, s, text_end);
|
||||
if (c == 0)
|
||||
break;
|
||||
|
||||
if (c < 32)
|
||||
{
|
||||
@@ -3490,15 +3641,9 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
|
||||
const char* prev_s = s;
|
||||
unsigned int c = (unsigned int)*s;
|
||||
if (c < 0x80)
|
||||
{
|
||||
s += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
s += ImTextCharFromUtf8(&c, s, text_end);
|
||||
if (c == 0) // Malformed UTF-8?
|
||||
break;
|
||||
}
|
||||
|
||||
if (c < 32)
|
||||
{
|
||||
@@ -3544,8 +3689,8 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, Im
|
||||
if (glyph->Colored)
|
||||
col |= ~IM_COL32_A_MASK;
|
||||
float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f;
|
||||
float x = IM_FLOOR(pos.x);
|
||||
float y = IM_FLOOR(pos.y);
|
||||
float x = IM_TRUNC(pos.x);
|
||||
float y = IM_TRUNC(pos.y);
|
||||
draw_list->PrimReserve(6, 4);
|
||||
draw_list->PrimRectUV(ImVec2(x + glyph->X0 * scale, y + glyph->Y0 * scale), ImVec2(x + glyph->X1 * scale, y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col);
|
||||
}
|
||||
@@ -3557,8 +3702,8 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
|
||||
text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
|
||||
|
||||
// Align to be pixel perfect
|
||||
float x = IM_FLOOR(pos.x);
|
||||
float y = IM_FLOOR(pos.y);
|
||||
float x = IM_TRUNC(pos.x);
|
||||
float y = IM_TRUNC(pos.y);
|
||||
if (y > clip_rect.w)
|
||||
return;
|
||||
|
||||
@@ -3578,7 +3723,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
|
||||
// FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPositionA().
|
||||
// If the specs for CalcWordWrapPositionA() were reworked to optionally return on \n we could combine both.
|
||||
// However it is still better than nothing performing the fast-forward!
|
||||
s = CalcWordWrapPositionA(scale, s, line_end, wrap_width);
|
||||
s = CalcWordWrapPositionA(scale, s, line_end ? line_end : text_end, wrap_width);
|
||||
s = CalcWordWrapNextLineStartA(s, text_end);
|
||||
}
|
||||
else
|
||||
@@ -3610,10 +3755,9 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
|
||||
const int idx_count_max = (int)(text_end - s) * 6;
|
||||
const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;
|
||||
draw_list->PrimReserve(idx_count_max, vtx_count_max);
|
||||
|
||||
ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
|
||||
ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
|
||||
unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx;
|
||||
ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
|
||||
ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
|
||||
unsigned int vtx_index = draw_list->_VtxCurrentIdx;
|
||||
|
||||
const ImU32 col_untinted = col | ~IM_COL32_A_MASK;
|
||||
const char* word_wrap_eol = NULL;
|
||||
@@ -3639,15 +3783,9 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
|
||||
// Decode and advance source
|
||||
unsigned int c = (unsigned int)*s;
|
||||
if (c < 0x80)
|
||||
{
|
||||
s += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
s += ImTextCharFromUtf8(&c, s, text_end);
|
||||
if (c == 0) // Malformed UTF-8?
|
||||
break;
|
||||
}
|
||||
|
||||
if (c < 32)
|
||||
{
|
||||
@@ -3718,14 +3856,14 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
|
||||
|
||||
// We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:
|
||||
{
|
||||
idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2);
|
||||
idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3);
|
||||
vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = glyph_col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1;
|
||||
vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = glyph_col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1;
|
||||
vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = glyph_col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2;
|
||||
vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = glyph_col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2;
|
||||
idx_write[0] = (ImDrawIdx)(vtx_index); idx_write[1] = (ImDrawIdx)(vtx_index + 1); idx_write[2] = (ImDrawIdx)(vtx_index + 2);
|
||||
idx_write[3] = (ImDrawIdx)(vtx_index); idx_write[4] = (ImDrawIdx)(vtx_index + 2); idx_write[5] = (ImDrawIdx)(vtx_index + 3);
|
||||
vtx_write += 4;
|
||||
vtx_current_idx += 4;
|
||||
vtx_index += 4;
|
||||
idx_write += 6;
|
||||
}
|
||||
}
|
||||
@@ -3739,7 +3877,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
|
||||
draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);
|
||||
draw_list->_VtxWritePtr = vtx_write;
|
||||
draw_list->_IdxWritePtr = idx_write;
|
||||
draw_list->_VtxCurrentIdx = vtx_current_idx;
|
||||
draw_list->_VtxCurrentIdx = vtx_index;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -3792,6 +3930,7 @@ void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir d
|
||||
|
||||
void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col)
|
||||
{
|
||||
// FIXME-OPT: This should be baked in font.
|
||||
draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8);
|
||||
}
|
||||
|
||||
|
||||
336
src/thirdparty/imgui/imgui_impl_glfw.cpp
vendored
336
src/thirdparty/imgui/imgui_impl_glfw.cpp
vendored
@@ -1,10 +1,11 @@
|
||||
// dear imgui: Platform Backend for GLFW
|
||||
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
|
||||
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||
// (Requires: GLFW 3.1+. Prefer GLFW 3.3+ for full feature support.)
|
||||
// (Requires: GLFW 3.1+. Prefer GLFW 3.3+ or GLFW 3.4+ for full feature support.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only).
|
||||
// [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 GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
|
||||
@@ -15,15 +16,29 @@
|
||||
|
||||
// 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.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
// 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
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys.
|
||||
// 2023-07-18: Inputs: Revert ignoring mouse data on GLFW_CURSOR_DISABLED as it can be used differently. User may set ImGuiConfigFLags_NoMouse if desired. (#5625, #6609)
|
||||
// 2023-06-12: Accept glfwGetTime() not returning a monotonically increasing value. This seems to happens on some Windows setup when peripherals disconnect, and is likely to also happen on browser + Emscripten. (#6491)
|
||||
// 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen/ImGuiMouseSource_Pen on Windows ONLY, using a custom WndProc hook. (#2702)
|
||||
// 2023-03-16: Inputs: Fixed key modifiers handling on secondary viewports (docking branch). Broken on 2023/01/04. (#6248, #6034)
|
||||
// 2023-03-14: Emscripten: Avoid using glfwGetError() and glfwGetGamepadState() which are not correctly implemented in Emscripten emulation. (#6240)
|
||||
// 2023-02-03: Emscripten: Registering custom low-level mouse wheel handler to get more accurate scrolling impulses on Emscripten. (#4019, #6096)
|
||||
// 2023-01-18: Handle unsupported glfwGetVideoMode() call on e.g. Emscripten.
|
||||
// 2023-01-04: Inputs: Fixed mods state on Linux when using Alt-GR text input (e.g. German keyboard layout), could lead to broken text input. Revert a 2022/01/17 change were we resumed using mods provided by GLFW, turns out they were faulty.
|
||||
// 2022-11-22: Perform a dummy glfwGetError() read to cancel missing names with glfwGetKeyName(). (#5908)
|
||||
// 2022-10-18: Perform a dummy glfwGetError() read to cancel missing mouse cursors errors. Using GLFW_VERSION_COMBINED directly. (#5785)
|
||||
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
|
||||
// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
|
||||
// 2022-09-01: Inputs: Honor GLFW_CURSOR_DISABLED by not setting mouse position.
|
||||
// 2022-09-01: Inputs: Honor GLFW_CURSOR_DISABLED by not setting mouse position *EDIT* Reverted 2023-07-18.
|
||||
// 2022-04-30: Inputs: Fixed ImGui_ImplGlfw_TranslateUntranslatedKey() for lower case letters on OSX.
|
||||
// 2022-03-23: Inputs: Fixed a regression in 1.87 which resulted in keyboard modifiers events being reported incorrectly on Linux/X11.
|
||||
// 2022-02-07: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing callbacks after initializing backend.
|
||||
@@ -60,6 +75,7 @@
|
||||
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
|
||||
|
||||
#include "imgui.h"
|
||||
#ifndef IMGUI_DISABLE
|
||||
#include "imgui_impl_glfw.h"
|
||||
|
||||
// Clang warnings with -Weverything
|
||||
@@ -82,27 +98,39 @@
|
||||
#include <GLFW/glfw3native.h> // for glfwGetCocoaWindow()
|
||||
#endif
|
||||
|
||||
#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING
|
||||
#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED
|
||||
#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity
|
||||
#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale
|
||||
#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface
|
||||
#define GLFW_HAS_FOCUS_WINDOW (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwFocusWindow
|
||||
#define GLFW_HAS_FOCUS_ON_SHOW (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_FOCUS_ON_SHOW
|
||||
#define GLFW_HAS_MONITOR_WORK_AREA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorWorkarea
|
||||
#define GLFW_HAS_OSX_WINDOW_POS_FIX (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION * 10 >= 3310) // 3.3.1+ Fixed: Resizing window repositions it on MacOS #1553
|
||||
#ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
|
||||
#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
|
||||
#else
|
||||
#define GLFW_HAS_NEW_CURSORS (0)
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
#endif
|
||||
#ifdef GLFW_MOUSE_PASSTHROUGH // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2020-07-17 (passthrough)
|
||||
#define GLFW_HAS_MOUSE_PASSTHROUGH (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_MOUSE_PASSTHROUGH
|
||||
|
||||
// We gather version tests as define in order to easily see which features are version-dependent.
|
||||
#define GLFW_VERSION_COMBINED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION)
|
||||
#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_COMBINED >= 3200) // 3.2+ GLFW_FLOATING
|
||||
#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_COMBINED >= 3300) // 3.3+ GLFW_HOVERED
|
||||
#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwSetWindowOpacity
|
||||
#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetMonitorContentScale
|
||||
#if defined(__EMSCRIPTEN__) || defined(__SWITCH__) // no Vulkan support in GLFW for Emscripten or homebrew Nintendo Switch
|
||||
#define GLFW_HAS_VULKAN (0)
|
||||
#else
|
||||
#define GLFW_HAS_MOUSE_PASSTHROUGH (0)
|
||||
#define GLFW_HAS_VULKAN (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwCreateWindowSurface
|
||||
#endif
|
||||
#define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetGamepadState() new api
|
||||
#define GLFW_HAS_GET_KEY_NAME (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwGetKeyName()
|
||||
#define GLFW_HAS_FOCUS_WINDOW (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwFocusWindow
|
||||
#define GLFW_HAS_FOCUS_ON_SHOW (GLFW_VERSION_COMBINED >= 3300) // 3.3+ GLFW_FOCUS_ON_SHOW
|
||||
#define GLFW_HAS_MONITOR_WORK_AREA (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetMonitorWorkarea
|
||||
#define GLFW_HAS_OSX_WINDOW_POS_FIX (GLFW_VERSION_COMBINED >= 3301) // 3.3.1+ Fixed: Resizing window repositions it on MacOS #1553
|
||||
#ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
|
||||
#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_COMBINED >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
|
||||
#else
|
||||
#define GLFW_HAS_NEW_CURSORS (0)
|
||||
#endif
|
||||
#ifdef GLFW_MOUSE_PASSTHROUGH // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2020-07-17 (passthrough)
|
||||
#define GLFW_HAS_MOUSE_PASSTHROUGH (GLFW_VERSION_COMBINED >= 3400) // 3.4+ GLFW_MOUSE_PASSTHROUGH
|
||||
#else
|
||||
#define GLFW_HAS_MOUSE_PASSTHROUGH (0)
|
||||
#endif
|
||||
#define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetGamepadState() new api
|
||||
#define GLFW_HAS_GETKEYNAME (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwGetKeyName()
|
||||
#define GLFW_HAS_GETERROR (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetError()
|
||||
|
||||
// GLFW data
|
||||
enum GlfwClientApi
|
||||
@@ -122,10 +150,8 @@ struct ImGui_ImplGlfw_Data
|
||||
ImVec2 LastValidMousePos;
|
||||
GLFWwindow* KeyOwnerWindows[GLFW_KEY_LAST];
|
||||
bool InstalledCallbacks;
|
||||
bool CallbacksChainForAllWindows;
|
||||
bool WantUpdateMonitors;
|
||||
#ifdef _WIN32
|
||||
WNDPROC GlfwWndProc;
|
||||
#endif
|
||||
|
||||
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
|
||||
GLFWwindowfocusfun PrevUserCallbackWindowFocus;
|
||||
@@ -136,6 +162,9 @@ struct ImGui_ImplGlfw_Data
|
||||
GLFWkeyfun PrevUserCallbackKey;
|
||||
GLFWcharfun PrevUserCallbackChar;
|
||||
GLFWmonitorfun PrevUserCallbackMonitor;
|
||||
#ifdef _WIN32
|
||||
WNDPROC PrevWndProc;
|
||||
#endif
|
||||
|
||||
ImGui_ImplGlfw_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
@@ -277,39 +306,46 @@ static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key)
|
||||
case GLFW_KEY_F10: return ImGuiKey_F10;
|
||||
case GLFW_KEY_F11: return ImGuiKey_F11;
|
||||
case GLFW_KEY_F12: return ImGuiKey_F12;
|
||||
case GLFW_KEY_F13: return ImGuiKey_F13;
|
||||
case GLFW_KEY_F14: return ImGuiKey_F14;
|
||||
case GLFW_KEY_F15: return ImGuiKey_F15;
|
||||
case GLFW_KEY_F16: return ImGuiKey_F16;
|
||||
case GLFW_KEY_F17: return ImGuiKey_F17;
|
||||
case GLFW_KEY_F18: return ImGuiKey_F18;
|
||||
case GLFW_KEY_F19: return ImGuiKey_F19;
|
||||
case GLFW_KEY_F20: return ImGuiKey_F20;
|
||||
case GLFW_KEY_F21: return ImGuiKey_F21;
|
||||
case GLFW_KEY_F22: return ImGuiKey_F22;
|
||||
case GLFW_KEY_F23: return ImGuiKey_F23;
|
||||
case GLFW_KEY_F24: return ImGuiKey_F24;
|
||||
default: return ImGuiKey_None;
|
||||
}
|
||||
}
|
||||
|
||||
static int ImGui_ImplGlfw_KeyToModifier(int key)
|
||||
{
|
||||
if (key == GLFW_KEY_LEFT_CONTROL || key == GLFW_KEY_RIGHT_CONTROL)
|
||||
return GLFW_MOD_CONTROL;
|
||||
if (key == GLFW_KEY_LEFT_SHIFT || key == GLFW_KEY_RIGHT_SHIFT)
|
||||
return GLFW_MOD_SHIFT;
|
||||
if (key == GLFW_KEY_LEFT_ALT || key == GLFW_KEY_RIGHT_ALT)
|
||||
return GLFW_MOD_ALT;
|
||||
if (key == GLFW_KEY_LEFT_SUPER || key == GLFW_KEY_RIGHT_SUPER)
|
||||
return GLFW_MOD_SUPER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateKeyModifiers(int mods)
|
||||
// X11 does not include current pressed/released modifier key in 'mods' flags submitted by GLFW
|
||||
// See https://github.com/ocornut/imgui/issues/6034 and https://github.com/glfw/glfw/issues/1630
|
||||
static void ImGui_ImplGlfw_UpdateKeyModifiers(GLFWwindow* window)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.AddKeyEvent(ImGuiMod_Ctrl, (mods & GLFW_MOD_CONTROL) != 0);
|
||||
io.AddKeyEvent(ImGuiMod_Shift, (mods & GLFW_MOD_SHIFT) != 0);
|
||||
io.AddKeyEvent(ImGuiMod_Alt, (mods & GLFW_MOD_ALT) != 0);
|
||||
io.AddKeyEvent(ImGuiMod_Super, (mods & GLFW_MOD_SUPER) != 0);
|
||||
io.AddKeyEvent(ImGuiMod_Ctrl, (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS));
|
||||
io.AddKeyEvent(ImGuiMod_Shift, (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS));
|
||||
io.AddKeyEvent(ImGuiMod_Alt, (glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS));
|
||||
io.AddKeyEvent(ImGuiMod_Super, (glfwGetKey(window, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS));
|
||||
}
|
||||
|
||||
static bool ImGui_ImplGlfw_ShouldChainCallback(GLFWwindow* window)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
return bd->CallbacksChainForAllWindows ? true : (window == bd->Window);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackMousebutton != nullptr && window == bd->Window)
|
||||
if (bd->PrevUserCallbackMousebutton != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
|
||||
bd->PrevUserCallbackMousebutton(window, button, action, mods);
|
||||
|
||||
ImGui_ImplGlfw_UpdateKeyModifiers(mods);
|
||||
ImGui_ImplGlfw_UpdateKeyModifiers(window);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (button >= 0 && button < ImGuiMouseButton_COUNT)
|
||||
@@ -319,16 +355,21 @@ void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int acti
|
||||
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackScroll != nullptr && window == bd->Window)
|
||||
if (bd->PrevUserCallbackScroll != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
|
||||
bd->PrevUserCallbackScroll(window, xoffset, yoffset);
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
// Ignore GLFW events: will be processed in ImGui_ImplEmscripten_WheelCallback().
|
||||
return;
|
||||
#endif
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.AddMouseWheelEvent((float)xoffset, (float)yoffset);
|
||||
}
|
||||
|
||||
static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
|
||||
{
|
||||
#if GLFW_HAS_GET_KEY_NAME && !defined(__EMSCRIPTEN__)
|
||||
#if GLFW_HAS_GETKEYNAME && !defined(__EMSCRIPTEN__)
|
||||
// GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult.
|
||||
// (It had reasons to do so: namely GLFW is/was more likely to be used for WASD-type game controls rather than lettered shortcuts, but IHMO the 3.1 change could have been done differently)
|
||||
// See https://github.com/glfw/glfw/issues/1502 for details.
|
||||
@@ -336,7 +377,12 @@ static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
|
||||
// This won't cover edge cases but this is at least going to cover common cases.
|
||||
if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_EQUAL)
|
||||
return key;
|
||||
GLFWerrorfun prev_error_callback = glfwSetErrorCallback(nullptr);
|
||||
const char* key_name = glfwGetKeyName(key, scancode);
|
||||
glfwSetErrorCallback(prev_error_callback);
|
||||
#if GLFW_HAS_GETERROR && !defined(__EMSCRIPTEN__) // Eat errors (see #5908)
|
||||
(void)glfwGetError(nullptr);
|
||||
#endif
|
||||
if (key_name && key_name[0] != 0 && key_name[1] == 0)
|
||||
{
|
||||
const char char_names[] = "`-=[]\\,;\'./";
|
||||
@@ -357,16 +403,13 @@ static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
|
||||
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackKey != nullptr && window == bd->Window)
|
||||
if (bd->PrevUserCallbackKey != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
|
||||
bd->PrevUserCallbackKey(window, keycode, scancode, action, mods);
|
||||
|
||||
if (action != GLFW_PRESS && action != GLFW_RELEASE)
|
||||
return;
|
||||
|
||||
// Workaround: X11 does not include current pressed/released modifier key in 'mods' flags. https://github.com/glfw/glfw/issues/1630
|
||||
if (int keycode_to_mod = ImGui_ImplGlfw_KeyToModifier(keycode))
|
||||
mods = (action == GLFW_PRESS) ? (mods | keycode_to_mod) : (mods & ~keycode_to_mod);
|
||||
ImGui_ImplGlfw_UpdateKeyModifiers(mods);
|
||||
ImGui_ImplGlfw_UpdateKeyModifiers(window);
|
||||
|
||||
if (keycode >= 0 && keycode < IM_ARRAYSIZE(bd->KeyOwnerWindows))
|
||||
bd->KeyOwnerWindows[keycode] = (action == GLFW_PRESS) ? window : nullptr;
|
||||
@@ -382,7 +425,7 @@ void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, i
|
||||
void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackWindowFocus != nullptr && window == bd->Window)
|
||||
if (bd->PrevUserCallbackWindowFocus != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
|
||||
bd->PrevUserCallbackWindowFocus(window, focused);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
@@ -392,10 +435,8 @@ void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
|
||||
void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackCursorPos != nullptr && window == bd->Window)
|
||||
if (bd->PrevUserCallbackCursorPos != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
|
||||
bd->PrevUserCallbackCursorPos(window, x, y);
|
||||
if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
|
||||
return;
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
@@ -414,10 +455,8 @@ void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y)
|
||||
void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackCursorEnter != nullptr && window == bd->Window)
|
||||
if (bd->PrevUserCallbackCursorEnter != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
|
||||
bd->PrevUserCallbackCursorEnter(window, entered);
|
||||
if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
|
||||
return;
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (entered)
|
||||
@@ -436,7 +475,7 @@ void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
|
||||
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (bd->PrevUserCallbackChar != nullptr && window == bd->Window)
|
||||
if (bd->PrevUserCallbackChar != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window))
|
||||
bd->PrevUserCallbackChar(window, c);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
@@ -449,6 +488,28 @@ void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
|
||||
bd->WantUpdateMonitors = true;
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
static EM_BOOL ImGui_ImplEmscripten_WheelCallback(int, const EmscriptenWheelEvent* ev, void*)
|
||||
{
|
||||
// Mimic Emscripten_HandleWheel() in SDL.
|
||||
// Corresponding equivalent in GLFW JS emulation layer has incorrect quantizing preventing small values. See #6096
|
||||
float multiplier = 0.0f;
|
||||
if (ev->deltaMode == DOM_DELTA_PIXEL) { multiplier = 1.0f / 100.0f; } // 100 pixels make up a step.
|
||||
else if (ev->deltaMode == DOM_DELTA_LINE) { multiplier = 1.0f / 3.0f; } // 3 lines make up a step.
|
||||
else if (ev->deltaMode == DOM_DELTA_PAGE) { multiplier = 80.0f; } // A page makes up 80 steps.
|
||||
float wheel_x = ev->deltaX * -multiplier;
|
||||
float wheel_y = ev->deltaY * -multiplier;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.AddMouseWheelEvent(wheel_x, wheel_y);
|
||||
//IMGUI_DEBUG_LOG("[Emsc] mode %d dx: %.2f, dy: %.2f, dz: %.2f --> feed %.2f %.2f\n", (int)ev->deltaMode, ev->deltaX, ev->deltaY, ev->deltaZ, wheel_x, wheel_y);
|
||||
return EM_TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
#endif
|
||||
|
||||
void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
@@ -491,10 +552,21 @@ void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window)
|
||||
bd->PrevUserCallbackMonitor = nullptr;
|
||||
}
|
||||
|
||||
// Set to 'true' to enable chaining installed callbacks for all windows (including secondary viewports created by backends or by user.
|
||||
// This is 'false' by default meaning we only chain callbacks for the main viewport.
|
||||
// We cannot set this to 'true' by default because user callbacks code may be not testing the 'window' parameter of their callback.
|
||||
// If you set this to 'true' your user callback code will need to make sure you are testing the 'window' parameter.
|
||||
void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
bd->CallbacksChainForAllWindows = chain_for_all_windows;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
|
||||
//printf("GLFW_VERSION: %d.%d.%d (%d)", GLFW_VERSION_MAJOR, GLFW_VERSION_MINOR, GLFW_VERSION_REVISION, GLFW_VERSION_COMBINED);
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)();
|
||||
@@ -502,7 +574,9 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
|
||||
io.BackendPlatformName = "imgui_impl_glfw";
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
#ifndef __EMSCRIPTEN__
|
||||
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
|
||||
#endif
|
||||
#if GLFW_HAS_MOUSE_PASSTHROUGH || (GLFW_HAS_WINDOW_HOVERED && defined(_WIN32))
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional)
|
||||
#endif
|
||||
@@ -537,26 +611,44 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
|
||||
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
#endif
|
||||
glfwSetErrorCallback(prev_error_callback);
|
||||
#if GLFW_HAS_GETERROR && !defined(__EMSCRIPTEN__) // Eat errors (see #5908)
|
||||
(void)glfwGetError(nullptr);
|
||||
#endif
|
||||
|
||||
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
|
||||
if (install_callbacks)
|
||||
ImGui_ImplGlfw_InstallCallbacks(window);
|
||||
// Register Emscripten Wheel callback to workaround issue in Emscripten GLFW Emulation (#6096)
|
||||
// We intentionally do not check 'if (install_callbacks)' here, as some users may set it to false and call GLFW callback themselves.
|
||||
// FIXME: May break chaining in case user registered their own Emscripten callback?
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_set_wheel_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, false, ImGui_ImplEmscripten_WheelCallback);
|
||||
#endif
|
||||
|
||||
// Update monitors the first time (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784)
|
||||
ImGui_ImplGlfw_UpdateMonitors();
|
||||
glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
|
||||
|
||||
// Our mouse update function expect PlatformHandle to be filled for the main viewport
|
||||
// Set platform dependent data in viewport
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
main_viewport->PlatformHandle = (void*)bd->Window;
|
||||
#ifdef _WIN32
|
||||
main_viewport->PlatformHandleRaw = glfwGetWin32Window(bd->Window);
|
||||
#elif defined(__APPLE__)
|
||||
main_viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(bd->Window);
|
||||
#else
|
||||
IM_UNUSED(main_viewport);
|
||||
#endif
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
ImGui_ImplGlfw_InitPlatformInterface();
|
||||
|
||||
// Windows: register a WndProc hook so we can intercept some messages.
|
||||
#ifdef _WIN32
|
||||
bd->PrevWndProc = (WNDPROC)::GetWindowLongPtr((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC);
|
||||
IM_ASSERT(bd->PrevWndProc != nullptr);
|
||||
::SetWindowLongPtr((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc);
|
||||
#endif
|
||||
|
||||
bd->ClientApi = client_api;
|
||||
return true;
|
||||
}
|
||||
@@ -586,12 +678,23 @@ void ImGui_ImplGlfw_Shutdown()
|
||||
|
||||
if (bd->InstalledCallbacks)
|
||||
ImGui_ImplGlfw_RestoreCallbacks(bd->Window);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_set_wheel_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, false, nullptr);
|
||||
#endif
|
||||
|
||||
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||
glfwDestroyCursor(bd->MouseCursors[cursor_n]);
|
||||
|
||||
// Windows: restore our WndProc hook
|
||||
#ifdef _WIN32
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
::SetWindowLongPtr((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)bd->PrevWndProc);
|
||||
bd->PrevWndProc = nullptr;
|
||||
#endif
|
||||
|
||||
io.BackendPlatformName = nullptr;
|
||||
io.BackendPlatformUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport);
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
@@ -601,11 +704,6 @@ static void ImGui_ImplGlfw_UpdateMouseData()
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
|
||||
if (glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
|
||||
{
|
||||
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
|
||||
return;
|
||||
}
|
||||
|
||||
ImGuiID mouse_viewport_id = 0;
|
||||
const ImVec2 mouse_pos_prev = io.MousePos;
|
||||
@@ -707,7 +805,7 @@ static void ImGui_ImplGlfw_UpdateGamepads()
|
||||
return;
|
||||
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||
#if GLFW_HAS_GAMEPAD_API
|
||||
#if GLFW_HAS_GAMEPAD_API && !defined(__EMSCRIPTEN__)
|
||||
GLFWgamepadstate gamepad;
|
||||
if (!glfwGetGamepadState(GLFW_JOYSTICK_1, &gamepad))
|
||||
return;
|
||||
@@ -755,8 +853,13 @@ static void ImGui_ImplGlfw_UpdateMonitors()
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
bd->WantUpdateMonitors = false;
|
||||
|
||||
int monitors_count = 0;
|
||||
GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count);
|
||||
if (monitors_count == 0) // Preserve existing monitor list if there are none. Happens on macOS sleeping (#5683)
|
||||
return;
|
||||
|
||||
platform_io.Monitors.resize(0);
|
||||
for (int n = 0; n < monitors_count; n++)
|
||||
{
|
||||
@@ -764,6 +867,8 @@ static void ImGui_ImplGlfw_UpdateMonitors()
|
||||
int x, y;
|
||||
glfwGetMonitorPos(glfw_monitors[n], &x, &y);
|
||||
const GLFWvidmode* vid_mode = glfwGetVideoMode(glfw_monitors[n]);
|
||||
if (vid_mode == nullptr)
|
||||
continue; // Failed to get Video mode (e.g. Emscripten does not support this function)
|
||||
monitor.MainPos = monitor.WorkPos = ImVec2((float)x, (float)y);
|
||||
monitor.MainSize = monitor.WorkSize = ImVec2((float)vid_mode->width, (float)vid_mode->height);
|
||||
#if GLFW_HAS_MONITOR_WORK_AREA
|
||||
@@ -781,9 +886,9 @@ static void ImGui_ImplGlfw_UpdateMonitors()
|
||||
glfwGetMonitorContentScale(glfw_monitors[n], &x_scale, &y_scale);
|
||||
monitor.DpiScale = x_scale;
|
||||
#endif
|
||||
monitor.PlatformHandle = (void*)glfw_monitors[n]; // [...] GLFW doc states: "guaranteed to be valid only until the monitor configuration changes"
|
||||
platform_io.Monitors.push_back(monitor);
|
||||
}
|
||||
bd->WantUpdateMonitors = false;
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_NewFrame()
|
||||
@@ -804,7 +909,10 @@ void ImGui_ImplGlfw_NewFrame()
|
||||
ImGui_ImplGlfw_UpdateMonitors();
|
||||
|
||||
// Setup time step
|
||||
// (Accept glfwGetTime() not returning a monotonically increasing value. Seems to happens on disconnecting peripherals and probably on VMs and Emscripten, see #6491, #6189, #6114, #3644)
|
||||
double current_time = glfwGetTime();
|
||||
if (current_time <= bd->Time)
|
||||
current_time = bd->Time + 0.00001f;
|
||||
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
|
||||
bd->Time = current_time;
|
||||
|
||||
@@ -821,15 +929,18 @@ void ImGui_ImplGlfw_NewFrame()
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Helper structure we store in the void* RenderUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
struct ImGui_ImplGlfw_ViewportData
|
||||
{
|
||||
GLFWwindow* Window;
|
||||
bool WindowOwned;
|
||||
int IgnoreWindowPosEventFrame;
|
||||
int IgnoreWindowSizeEventFrame;
|
||||
#ifdef _WIN32
|
||||
WNDPROC PrevWndProc;
|
||||
#endif
|
||||
|
||||
ImGui_ImplGlfw_ViewportData() { Window = nullptr; WindowOwned = false; IgnoreWindowSizeEventFrame = IgnoreWindowPosEventFrame = -1; }
|
||||
ImGui_ImplGlfw_ViewportData() { memset(this, 0, sizeof(*this)); IgnoreWindowSizeEventFrame = IgnoreWindowPosEventFrame = -1; }
|
||||
~ImGui_ImplGlfw_ViewportData() { IM_ASSERT(Window == nullptr); }
|
||||
};
|
||||
|
||||
@@ -947,26 +1058,6 @@ static void ImGui_ImplGlfw_DestroyWindow(ImGuiViewport* viewport)
|
||||
viewport->PlatformUserData = viewport->PlatformHandle = nullptr;
|
||||
}
|
||||
|
||||
// We have submitted https://github.com/glfw/glfw/pull/1568 to allow GLFW to support "transparent inputs".
|
||||
// In the meanwhile we implement custom per-platform workarounds here (FIXME-VIEWPORT: Implement same work-around for Linux/OSX!)
|
||||
#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)
|
||||
static LRESULT CALLBACK WndProcNoInputs(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (msg == WM_NCHITTEST)
|
||||
{
|
||||
// Let mouse pass-through the window. This will allow the backend to call io.AddMouseViewportEvent() properly (which is OPTIONAL).
|
||||
// The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
|
||||
// If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in
|
||||
// your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
|
||||
ImGuiViewport* viewport = (ImGuiViewport*)::GetPropA(hWnd, "IMGUI_VIEWPORT");
|
||||
if (viewport->Flags & ImGuiViewportFlags_NoInputs)
|
||||
return HTTRANSPARENT;
|
||||
}
|
||||
return ::CallWindowProc(bd->GlfwWndProc, hWnd, msg, wParam, lParam);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ImGui_ImplGlfw_ShowWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
@@ -984,11 +1075,9 @@ static void ImGui_ImplGlfw_ShowWindow(ImGuiViewport* viewport)
|
||||
|
||||
// GLFW hack: install hook for WM_NCHITTEST message handler
|
||||
#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
::SetPropA(hwnd, "IMGUI_VIEWPORT", viewport);
|
||||
if (bd->GlfwWndProc == nullptr)
|
||||
bd->GlfwWndProc = (WNDPROC)::GetWindowLongPtr(hwnd, GWLP_WNDPROC);
|
||||
::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)WndProcNoInputs);
|
||||
vd->PrevWndProc = (WNDPROC)::GetWindowLongPtr(hwnd, GWLP_WNDPROC);
|
||||
::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc);
|
||||
#endif
|
||||
|
||||
#if !GLFW_HAS_FOCUS_ON_SHOW
|
||||
@@ -1173,6 +1262,63 @@ static void ImGui_ImplGlfw_ShutdownPlatformInterface()
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// WndProc hook (declared here because we will need access to ImGui_ImplGlfw_ViewportData)
|
||||
#ifdef _WIN32
|
||||
static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo()
|
||||
{
|
||||
LPARAM extra_info = ::GetMessageExtraInfo();
|
||||
if ((extra_info & 0xFFFFFF80) == 0xFF515700)
|
||||
return ImGuiMouseSource_Pen;
|
||||
if ((extra_info & 0xFFFFFF80) == 0xFF515780)
|
||||
return ImGuiMouseSource_TouchScreen;
|
||||
return ImGuiMouseSource_Mouse;
|
||||
}
|
||||
static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
WNDPROC prev_wndproc = bd->PrevWndProc;
|
||||
ImGuiViewport* viewport = (ImGuiViewport*)::GetPropA(hWnd, "IMGUI_VIEWPORT");
|
||||
if (viewport != NULL)
|
||||
if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData)
|
||||
prev_wndproc = vd->PrevWndProc;
|
||||
|
||||
switch (msg)
|
||||
{
|
||||
// GLFW doesn't allow to distinguish Mouse vs TouchScreen vs Pen.
|
||||
// Add support for Win32 (based on imgui_impl_win32), because we rely on _TouchScreen info to trickle inputs differently.
|
||||
case WM_MOUSEMOVE: case WM_NCMOUSEMOVE:
|
||||
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_LBUTTONUP:
|
||||
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: case WM_RBUTTONUP:
|
||||
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: case WM_MBUTTONUP:
|
||||
case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: case WM_XBUTTONUP:
|
||||
ImGui::GetIO().AddMouseSourceEvent(GetMouseSourceFromMessageExtraInfo());
|
||||
break;
|
||||
|
||||
// We have submitted https://github.com/glfw/glfw/pull/1568 to allow GLFW to support "transparent inputs".
|
||||
// In the meanwhile we implement custom per-platform workarounds here (FIXME-VIEWPORT: Implement same work-around for Linux/OSX!)
|
||||
#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED
|
||||
case WM_NCHITTEST:
|
||||
{
|
||||
// Let mouse pass-through the window. This will allow the backend to call io.AddMouseViewportEvent() properly (which is OPTIONAL).
|
||||
// The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
|
||||
// If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in
|
||||
// your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
|
||||
if (viewport && (viewport->Flags & ImGuiViewportFlags_NoInputs))
|
||||
return HTTRANSPARENT;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return ::CallWindowProc(prev_wndproc, hWnd, msg, wParam, lParam);
|
||||
}
|
||||
#endif // #ifdef _WIN32
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
|
||||
19
src/thirdparty/imgui/imgui_impl_glfw.h
vendored
19
src/thirdparty/imgui/imgui_impl_glfw.h
vendored
@@ -5,6 +5,7 @@
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only).
|
||||
// [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 GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
||||
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
|
||||
@@ -15,11 +16,15 @@
|
||||
|
||||
// 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.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
// 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 GLFWwindow;
|
||||
struct GLFWmonitor;
|
||||
@@ -30,13 +35,17 @@ IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool ins
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
|
||||
|
||||
// GLFW callbacks (installer)
|
||||
// GLFW callbacks install
|
||||
// - When calling Init with 'install_callbacks=true': ImGui_ImplGlfw_InstallCallbacks() is called. GLFW callbacks will be installed for you. They will chain-call user's previously installed callbacks, if any.
|
||||
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call individual function yourself from your own GLFW callbacks.
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window);
|
||||
|
||||
// GLFW callbacks (individual callbacks to call if you didn't install callbacks)
|
||||
// GFLW callbacks options:
|
||||
// - Set 'chain_for_all_windows=true' to enable chaining callbacks for all windows (including secondary viewports created by backends or by user)
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows);
|
||||
|
||||
// GLFW callbacks (individual callbacks to call yourself if you didn't install callbacks)
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87
|
||||
@@ -45,3 +54,5 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event);
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
|
||||
921
src/thirdparty/imgui/imgui_impl_opengl3.cpp
vendored
921
src/thirdparty/imgui/imgui_impl_opengl3.cpp
vendored
@@ -1,921 +0,0 @@
|
||||
// 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: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// [x] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
|
||||
|
||||
// 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.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
|
||||
// 2022-09-27: OpenGL: Added ability to '#define IMGUI_IMPL_OPENGL_DEBUG'.
|
||||
// 2022-05-23: OpenGL: Reworking 2021-12-15 "Using buffer orphaning" so it only happens on Intel GPU, seems to cause problems otherwise. (#4468, #4825, #4832, #5127).
|
||||
// 2022-05-13: OpenGL: Fix state corruption on OpenGL ES 2.0 due to not preserving GL_ELEMENT_ARRAY_BUFFER_BINDING and vertex attribute states.
|
||||
// 2021-12-15: OpenGL: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports with some Intel HD drivers.
|
||||
// 2021-08-23: OpenGL: Fixed ES 3.0 shader ("#version 300 es") use normal precision floats to avoid wobbly rendering at HD resolutions.
|
||||
// 2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader.
|
||||
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||
// 2021-06-25: OpenGL: Use OES_vertex_array extension on Emscripten + backup/restore current state.
|
||||
// 2021-06-21: OpenGL: Destroy individual vertex/fragment shader objects right after they are linked into the main shader.
|
||||
// 2021-05-24: OpenGL: Access GL_CLIP_ORIGIN when "GL_ARB_clip_control" extension is detected, inside of just OpenGL 4.5 version.
|
||||
// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||
// 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater.
|
||||
// 2021-02-18: OpenGL: Change blending equation to preserve alpha in output buffer.
|
||||
// 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state.
|
||||
// 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state.
|
||||
// 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x)
|
||||
// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader.
|
||||
// 2020-07-10: OpenGL: Added support for glad2 OpenGL loader.
|
||||
// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX.
|
||||
// 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix.
|
||||
// 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset.
|
||||
// 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader.
|
||||
// 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader.
|
||||
// 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.
|
||||
// 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.
|
||||
// 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.
|
||||
// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.
|
||||
// 2019-03-15: OpenGL: Added a GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.
|
||||
// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).
|
||||
// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
|
||||
// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
|
||||
// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
|
||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||
// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.
|
||||
// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
|
||||
// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
|
||||
// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
|
||||
// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.
|
||||
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||
// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.
|
||||
// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a nullptr pointer.
|
||||
// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150".
|
||||
// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.
|
||||
// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.
|
||||
// 2017-05-01: OpenGL: Fixed save and restore of current blend func state.
|
||||
// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.
|
||||
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
|
||||
// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)
|
||||
|
||||
//----------------------------------------
|
||||
// OpenGL GLSL GLSL
|
||||
// version version string
|
||||
//----------------------------------------
|
||||
// 2.0 110 "#version 110"
|
||||
// 2.1 120 "#version 120"
|
||||
// 3.0 130 "#version 130"
|
||||
// 3.1 140 "#version 140"
|
||||
// 3.2 150 "#version 150"
|
||||
// 3.3 330 "#version 330 core"
|
||||
// 4.0 400 "#version 400 core"
|
||||
// 4.1 410 "#version 410 core"
|
||||
// 4.2 420 "#version 410 core"
|
||||
// 4.3 430 "#version 430 core"
|
||||
// ES 2.0 100 "#version 100" = WebGL 1.0
|
||||
// ES 3.0 300 "#version 300 es" = WebGL 2.0
|
||||
//----------------------------------------
|
||||
|
||||
#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
|
||||
#if defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
// Clang warnings with -Weverything
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#endif
|
||||
|
||||
// GL includes
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
|
||||
#include <OpenGLES/ES2/gl.h> // Use GL ES 2
|
||||
#else
|
||||
#include <GLES2/gl2.h> // Use GL ES 2
|
||||
#endif
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
#ifndef GL_GLEXT_PROTOTYPES
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#endif
|
||||
#include <GLES2/gl2ext.h>
|
||||
#endif
|
||||
#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
|
||||
#elif !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||
// 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 using our own minimal custom loader based on gl3w.
|
||||
// In the rest of your app/engine, you can use another loader of your choice (gl3w, glew, glad, glbinding, glext, glLoadGen, etc.).
|
||||
// If you happen to be developing a new feature for this backend (imgui_impl_opengl3.cpp):
|
||||
// - You may need to regenerate imgui_impl_opengl3_loader.h to add new symbols. See https://github.com/dearimgui/gl3w_stripped
|
||||
// - You can temporarily use an unstripped version. See https://github.com/dearimgui/gl3w_stripped/releases
|
||||
// Changes to this backend using new APIs should be accompanied by a regenerated stripped loader version.
|
||||
#define IMGL3W_IMPL
|
||||
#include "imgui_impl_opengl3_loader.h"
|
||||
#endif
|
||||
|
||||
// Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension
|
||||
#ifndef IMGUI_IMPL_OPENGL_ES2
|
||||
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
#define glBindVertexArray glBindVertexArrayOES
|
||||
#define glGenVertexArrays glGenVertexArraysOES
|
||||
#define glDeleteVertexArrays glDeleteVertexArraysOES
|
||||
#define GL_VERTEX_ARRAY_BINDING GL_VERTEX_ARRAY_BINDING_OES
|
||||
#endif
|
||||
|
||||
// Desktop GL 2.0+ has glPolygonMode() which GL ES and WebGL don't have.
|
||||
#ifdef GL_POLYGON_MODE
|
||||
#define IMGUI_IMPL_HAS_POLYGON_MODE
|
||||
#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
|
||||
|
||||
// Desktop GL use extension detection
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
#define IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
|
||||
#endif
|
||||
|
||||
// [Debugging]
|
||||
//#define IMGUI_IMPL_OPENGL_DEBUG
|
||||
#ifdef IMGUI_IMPL_OPENGL_DEBUG
|
||||
#include <stdio.h>
|
||||
#define GL_CALL(_CALL) do { _CALL; GLenum gl_err = glGetError(); if (gl_err != 0) fprintf(stderr, "GL error 0x%x returned from '%s'.\n", gl_err, #_CALL); } while (0) // Call with error check
|
||||
#else
|
||||
#define GL_CALL(_CALL) _CALL // Call without error check
|
||||
#endif
|
||||
|
||||
// OpenGL Data
|
||||
struct ImGui_ImplOpenGL3_Data
|
||||
{
|
||||
GLuint GlVersion; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
|
||||
char GlslVersionString[32]; // Specified by user or detected based on compile time GL settings.
|
||||
GLuint FontTexture;
|
||||
GLuint ShaderHandle;
|
||||
GLint AttribLocationTex; // Uniforms location
|
||||
GLint AttribLocationProjMtx;
|
||||
GLuint AttribLocationVtxPos; // Vertex attributes location
|
||||
GLuint AttribLocationVtxUV;
|
||||
GLuint AttribLocationVtxColor;
|
||||
unsigned int VboHandle, ElementsHandle;
|
||||
GLsizeiptr VertexBufferSize;
|
||||
GLsizeiptr IndexBufferSize;
|
||||
bool HasClipOrigin;
|
||||
bool UseBufferSubData;
|
||||
|
||||
ImGui_ImplOpenGL3_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||
static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData()
|
||||
{
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplOpenGL3_InitPlatformInterface();
|
||||
static void ImGui_ImplOpenGL3_ShutdownPlatformInterface();
|
||||
|
||||
// OpenGL vertex attribute state (for ES 1.0 and ES 2.0 only)
|
||||
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
struct ImGui_ImplOpenGL3_VtxAttribState
|
||||
{
|
||||
GLint Enabled, Size, Type, Normalized, Stride;
|
||||
GLvoid* Ptr;
|
||||
|
||||
void GetState(GLint index)
|
||||
{
|
||||
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &Enabled);
|
||||
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_SIZE, &Size);
|
||||
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_TYPE, &Type);
|
||||
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &Normalized);
|
||||
glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &Stride);
|
||||
glGetVertexAttribPointerv(index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &Ptr);
|
||||
}
|
||||
void SetState(GLint index)
|
||||
{
|
||||
glVertexAttribPointer(index, Size, Type, (GLboolean)Normalized, Stride, Ptr);
|
||||
if (Enabled) glEnableVertexAttribArray(index); else glDisableVertexAttribArray(index);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||
|
||||
// Initialize our loader
|
||||
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
|
||||
if (imgl3wInit() != 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to initialize OpenGL loader!\n");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Setup backend capabilities flags
|
||||
ImGui_ImplOpenGL3_Data* bd = IM_NEW(ImGui_ImplOpenGL3_Data)();
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_opengl3";
|
||||
|
||||
// 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);
|
||||
}
|
||||
bd->GlVersion = (GLuint)(major * 100 + minor * 10);
|
||||
|
||||
// Query vendor to enable glBufferSubData kludge
|
||||
#ifdef _WIN32
|
||||
if (const char* vendor = (const char*)glGetString(GL_VENDOR))
|
||||
if (strncmp(vendor, "Intel", 5) == 0)
|
||||
bd->UseBufferSubData = true;
|
||||
#endif
|
||||
#else
|
||||
bd->GlVersion = 200; // GLES 2
|
||||
#endif
|
||||
|
||||
#ifdef IMGUI_IMPL_OPENGL_DEBUG
|
||||
printf("GL_MAJOR_VERSION = %d\nGL_MINOR_VERSION = %d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", major, minor, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG]
|
||||
#endif
|
||||
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
if (bd->GlVersion >= 320)
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
#endif
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
// 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 nullptr if unsure.
|
||||
if (glsl_version == nullptr)
|
||||
{
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
glsl_version = "#version 100";
|
||||
#elif defined(IMGUI_IMPL_OPENGL_ES3)
|
||||
glsl_version = "#version 300 es";
|
||||
#elif defined(__APPLE__)
|
||||
glsl_version = "#version 150";
|
||||
#else
|
||||
glsl_version = "#version 130";
|
||||
#endif
|
||||
}
|
||||
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(bd->GlslVersionString));
|
||||
strcpy(bd->GlslVersionString, glsl_version);
|
||||
strcat(bd->GlslVersionString, "\n");
|
||||
|
||||
// Make an arbitrary GL call (we don't actually need the result)
|
||||
// IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know!
|
||||
GLint current_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||
|
||||
// Detect extensions we support
|
||||
bd->HasClipOrigin = (bd->GlVersion >= 450);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
|
||||
GLint num_extensions = 0;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
|
||||
for (GLint i = 0; i < num_extensions; i++)
|
||||
{
|
||||
const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
||||
if (extension != nullptr && strcmp(extension, "GL_ARB_clip_control") == 0)
|
||||
bd->HasClipOrigin = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
ImGui_ImplOpenGL3_InitPlatformInterface();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_Shutdown()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplOpenGL3_ShutdownPlatformInterface();
|
||||
ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_NewFrame()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplOpenGL3_Init()?");
|
||||
|
||||
if (!bd->ShaderHandle)
|
||||
ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// 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 (bd->GlVersion >= 310)
|
||||
glDisable(GL_PRIMITIVE_RESTART);
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_HAS_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 (bd->HasClipOrigin)
|
||||
{
|
||||
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.
|
||||
GL_CALL(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(bd->ShaderHandle);
|
||||
glUniform1i(bd->AttribLocationTex, 0);
|
||||
glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
if (bd->GlVersion >= 330)
|
||||
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
|
||||
#endif
|
||||
|
||||
(void)vertex_array_object;
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glBindVertexArray(vertex_array_object);
|
||||
#endif
|
||||
|
||||
// Bind vertex/index buffers and setup attributes for ImDrawVert
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, bd->VboHandle));
|
||||
GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bd->ElementsHandle));
|
||||
GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxPos));
|
||||
GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxUV));
|
||||
GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxColor));
|
||||
GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos)));
|
||||
GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv)));
|
||||
GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col)));
|
||||
}
|
||||
|
||||
// OpenGL3 Render function.
|
||||
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
|
||||
// This is in order to be able to run within an OpenGL engine that doesn't do so.
|
||||
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
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;
|
||||
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// Backup GL state
|
||||
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
|
||||
GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
GLuint last_sampler; if (bd->GlVersion >= 330) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; }
|
||||
#endif
|
||||
GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
|
||||
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
// This is part of VAO on OpenGL 3.0+ and OpenGL ES 3.0+.
|
||||
GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer);
|
||||
ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_pos; last_vtx_attrib_state_pos.GetState(bd->AttribLocationVtxPos);
|
||||
ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_uv; last_vtx_attrib_state_uv.GetState(bd->AttribLocationVtxUV);
|
||||
ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_color; last_vtx_attrib_state_color.GetState(bd->AttribLocationVtxColor);
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
|
||||
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
|
||||
#endif
|
||||
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
|
||||
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
|
||||
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
|
||||
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
|
||||
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
|
||||
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
|
||||
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
|
||||
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
|
||||
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
|
||||
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
|
||||
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
|
||||
GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
|
||||
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
GLboolean last_enable_primitive_restart = (bd->GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
|
||||
#endif
|
||||
|
||||
// Setup desired GL state
|
||||
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
|
||||
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
|
||||
GLuint vertex_array_object = 0;
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
GL_CALL(glGenVertexArrays(1, &vertex_array_object));
|
||||
#endif
|
||||
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||
|
||||
// Will project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
|
||||
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
|
||||
|
||||
// Render command lists
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
|
||||
// Upload vertex/index buffers
|
||||
// - On Intel windows drivers we got reports that regular glBufferData() led to accumulating leaks when using multi-viewports, so we started using orphaning + glBufferSubData(). (See https://github.com/ocornut/imgui/issues/4468)
|
||||
// - On NVIDIA drivers we got reports that using orphaning + glBufferSubData() led to glitches when using multi-viewports.
|
||||
// - OpenGL drivers are in a very sorry state in 2022, for now we are switching code path based on vendors.
|
||||
const GLsizeiptr vtx_buffer_size = (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert);
|
||||
const GLsizeiptr idx_buffer_size = (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx);
|
||||
if (bd->UseBufferSubData)
|
||||
{
|
||||
if (bd->VertexBufferSize < vtx_buffer_size)
|
||||
{
|
||||
bd->VertexBufferSize = vtx_buffer_size;
|
||||
GL_CALL(glBufferData(GL_ARRAY_BUFFER, bd->VertexBufferSize, nullptr, GL_STREAM_DRAW));
|
||||
}
|
||||
if (bd->IndexBufferSize < idx_buffer_size)
|
||||
{
|
||||
bd->IndexBufferSize = idx_buffer_size;
|
||||
GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, bd->IndexBufferSize, nullptr, GL_STREAM_DRAW));
|
||||
}
|
||||
GL_CALL(glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data));
|
||||
GL_CALL(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data));
|
||||
}
|
||||
else
|
||||
{
|
||||
GL_CALL(glBufferData(GL_ARRAY_BUFFER, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW));
|
||||
GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW));
|
||||
}
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback != nullptr)
|
||||
{
|
||||
// User callback, registered via ImDrawList::AddCallback()
|
||||
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
|
||||
else
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Project scissor/clipping rectangles into framebuffer space
|
||||
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
||||
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
||||
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||
continue;
|
||||
|
||||
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
|
||||
GL_CALL(glScissor((int)clip_min.x, (int)((float)fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y)));
|
||||
|
||||
// Bind texture, Draw
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()));
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
|
||||
if (bd->GlVersion >= 320)
|
||||
GL_CALL(glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset));
|
||||
else
|
||||
#endif
|
||||
GL_CALL(glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy the temporary VAO
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
GL_CALL(glDeleteVertexArrays(1, &vertex_array_object));
|
||||
#endif
|
||||
|
||||
// Restore modified GL state
|
||||
glUseProgram(last_program);
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
|
||||
if (bd->GlVersion >= 330)
|
||||
glBindSampler(0, last_sampler);
|
||||
#endif
|
||||
glActiveTexture(last_active_texture);
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glBindVertexArray(last_vertex_array_object);
|
||||
#endif
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer);
|
||||
last_vtx_attrib_state_pos.SetState(bd->AttribLocationVtxPos);
|
||||
last_vtx_attrib_state_uv.SetState(bd->AttribLocationVtxUV);
|
||||
last_vtx_attrib_state_color.SetState(bd->AttribLocationVtxColor);
|
||||
#endif
|
||||
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
|
||||
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
|
||||
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
|
||||
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
|
||||
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
|
||||
if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST);
|
||||
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
|
||||
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
|
||||
if (bd->GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
|
||||
#endif
|
||||
|
||||
#ifdef IMGUI_IMPL_HAS_POLYGON_MODE
|
||||
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
|
||||
#endif
|
||||
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
|
||||
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
|
||||
(void)bd; // Not all compilation paths use this
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// Build texture atlas
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||
|
||||
// Upload texture to graphics system
|
||||
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||
GLint last_texture;
|
||||
GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture));
|
||||
GL_CALL(glGenTextures(1, &bd->FontTexture));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, bd->FontTexture));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
|
||||
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
|
||||
#endif
|
||||
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
||||
|
||||
// Restore state
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, last_texture));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
if (bd->FontTexture)
|
||||
{
|
||||
glDeleteTextures(1, &bd->FontTexture);
|
||||
io.Fonts->SetTexID(0);
|
||||
bd->FontTexture = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
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! With GLSL: %s\n", desc, bd->GlslVersionString);
|
||||
if (log_length > 1)
|
||||
{
|
||||
ImVector<char> buf;
|
||||
buf.resize((int)(log_length + 1));
|
||||
glGetShaderInfoLog(handle, log_length, nullptr, (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)
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
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, bd->GlslVersionString);
|
||||
if (log_length > 1)
|
||||
{
|
||||
ImVector<char> buf;
|
||||
buf.resize((int)(log_length + 1));
|
||||
glGetProgramInfoLog(handle, log_length, nullptr, (GLchar*)buf.begin());
|
||||
fprintf(stderr, "%s\n", buf.begin());
|
||||
}
|
||||
return (GLboolean)status == GL_TRUE;
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
|
||||
// Backup GL state
|
||||
GLint last_texture, last_array_buffer;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
GLint last_vertex_array;
|
||||
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||
#endif
|
||||
|
||||
// Parse GLSL version string
|
||||
int glsl_version = 130;
|
||||
sscanf(bd->GlslVersionString, "#version %d", &glsl_version);
|
||||
|
||||
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 highp 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";
|
||||
|
||||
const GLchar* fragment_shader_glsl_120 =
|
||||
"#ifdef GL_ES\n"
|
||||
" precision mediump float;\n"
|
||||
"#endif\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"varying vec2 Frag_UV;\n"
|
||||
"varying vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_130 =
|
||||
"uniform sampler2D Texture;\n"
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_300_es =
|
||||
"precision mediump float;\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"layout (location = 0) out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader_glsl_410_core =
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"layout (location = 0) out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
// Select shaders matching our GLSL versions
|
||||
const GLchar* vertex_shader = nullptr;
|
||||
const GLchar* fragment_shader = nullptr;
|
||||
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;
|
||||
}
|
||||
|
||||
// Create shaders
|
||||
const GLchar* vertex_shader_with_version[2] = { bd->GlslVersionString, vertex_shader };
|
||||
GLuint vert_handle = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vert_handle, 2, vertex_shader_with_version, nullptr);
|
||||
glCompileShader(vert_handle);
|
||||
CheckShader(vert_handle, "vertex shader");
|
||||
|
||||
const GLchar* fragment_shader_with_version[2] = { bd->GlslVersionString, fragment_shader };
|
||||
GLuint frag_handle = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(frag_handle, 2, fragment_shader_with_version, nullptr);
|
||||
glCompileShader(frag_handle);
|
||||
CheckShader(frag_handle, "fragment shader");
|
||||
|
||||
// Link
|
||||
bd->ShaderHandle = glCreateProgram();
|
||||
glAttachShader(bd->ShaderHandle, vert_handle);
|
||||
glAttachShader(bd->ShaderHandle, frag_handle);
|
||||
glLinkProgram(bd->ShaderHandle);
|
||||
CheckProgram(bd->ShaderHandle, "shader program");
|
||||
|
||||
glDetachShader(bd->ShaderHandle, vert_handle);
|
||||
glDetachShader(bd->ShaderHandle, frag_handle);
|
||||
glDeleteShader(vert_handle);
|
||||
glDeleteShader(frag_handle);
|
||||
|
||||
bd->AttribLocationTex = glGetUniformLocation(bd->ShaderHandle, "Texture");
|
||||
bd->AttribLocationProjMtx = glGetUniformLocation(bd->ShaderHandle, "ProjMtx");
|
||||
bd->AttribLocationVtxPos = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Position");
|
||||
bd->AttribLocationVtxUV = (GLuint)glGetAttribLocation(bd->ShaderHandle, "UV");
|
||||
bd->AttribLocationVtxColor = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Color");
|
||||
|
||||
// Create buffers
|
||||
glGenBuffers(1, &bd->VboHandle);
|
||||
glGenBuffers(1, &bd->ElementsHandle);
|
||||
|
||||
ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||
|
||||
// Restore modified GL state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
glBindVertexArray(last_vertex_array);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
if (bd->VboHandle) { glDeleteBuffers(1, &bd->VboHandle); bd->VboHandle = 0; }
|
||||
if (bd->ElementsHandle) { glDeleteBuffers(1, &bd->ElementsHandle); bd->ElementsHandle = 0; }
|
||||
if (bd->ShaderHandle) { glDeleteProgram(bd->ShaderHandle); bd->ShaderHandle = 0; }
|
||||
ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
static void ImGui_ImplOpenGL3_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||
{
|
||||
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
ImGui_ImplOpenGL3_RenderDrawData(viewport->DrawData);
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_InitPlatformInterface()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplOpenGL3_RenderWindow;
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_ShutdownPlatformInterface()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
56
src/thirdparty/imgui/imgui_impl_opengl3.h
vendored
56
src/thirdparty/imgui/imgui_impl_opengl3.h
vendored
@@ -1,56 +0,0 @@
|
||||
// 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: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// [x] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
|
||||
|
||||
// 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.
|
||||
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
|
||||
// Read online: https://github.com/ocornut/imgui/tree/master/docs
|
||||
|
||||
// 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
|
||||
|
||||
// Backend API
|
||||
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();
|
||||
|
||||
// Specific OpenGL ES versions
|
||||
//#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten
|
||||
//#define IMGUI_IMPL_OPENGL_ES3 // 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
|
||||
794
src/thirdparty/imgui/imgui_impl_opengl3_loader.h
vendored
794
src/thirdparty/imgui/imgui_impl_opengl3_loader.h
vendored
@@ -1,794 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 INCUDING '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:
|
||||
// python 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_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
|
||||
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_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 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 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_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;
|
||||
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 GL3WProcs {
|
||||
GL3WglProc ptr[58];
|
||||
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;
|
||||
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 GL3WProcs 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 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 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;
|
||||
static GL3WglProc (*glx_get_proc_address)(const GLubyte *);
|
||||
|
||||
static int open_libgl(void)
|
||||
{
|
||||
libgl = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libgl)
|
||||
return GL3W_ERROR_LIBRARY_OPEN;
|
||||
*(void **)(&glx_get_proc_address) = dlsym(libgl, "glXGetProcAddressARB");
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void close_libgl(void) { dlclose(libgl); }
|
||||
|
||||
static GL3WglProc get_proc(const char *proc)
|
||||
{
|
||||
GL3WglProc res;
|
||||
res = glx_get_proc_address((const GLubyte *)proc);
|
||||
if (!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 < 3)
|
||||
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 < 3)
|
||||
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",
|
||||
"glLinkProgram",
|
||||
"glPixelStorei",
|
||||
"glPolygonMode",
|
||||
"glReadPixels",
|
||||
"glScissor",
|
||||
"glShaderSource",
|
||||
"glTexImage2D",
|
||||
"glTexParameteri",
|
||||
"glUniform1i",
|
||||
"glUniformMatrix4fv",
|
||||
"glUseProgram",
|
||||
"glVertexAttribPointer",
|
||||
"glViewport",
|
||||
};
|
||||
|
||||
GL3W_API union GL3WProcs imgl3wProcs;
|
||||
|
||||
static void load_procs(GL3WGetProcAddressProc proc)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAY_SIZE(proc_names); i++)
|
||||
imgl3wProcs.ptr[i] = proc(proc_names[i]);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
1883
src/thirdparty/imgui/imgui_impl_vulkan.cpp
vendored
Normal file
1883
src/thirdparty/imgui/imgui_impl_vulkan.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
170
src/thirdparty/imgui/imgui_impl_vulkan.h
vendored
Normal file
170
src/thirdparty/imgui/imgui_impl_vulkan.h
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
// dear imgui: Renderer Backend for Vulkan
|
||||
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [x] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions.
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
|
||||
// [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
|
||||
|
||||
// Important: on 32-bit systems, user texture binding is only supported if your imconfig file has '#define ImTextureID ImU64'.
|
||||
// See imgui_impl_vulkan.cpp file for details.
|
||||
|
||||
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
|
||||
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
|
||||
|
||||
// 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
|
||||
|
||||
// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.
|
||||
// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.
|
||||
// You will use those if you want to use this rendering backend in your engine/app.
|
||||
// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by
|
||||
// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.
|
||||
// Read comments in imgui_impl_vulkan.h.
|
||||
|
||||
#pragma once
|
||||
#ifndef IMGUI_DISABLE
|
||||
#include "imgui.h" // IMGUI_IMPL_API
|
||||
|
||||
// [Configuration] in order to use a custom Vulkan function loader:
|
||||
// (1) You'll need to disable default Vulkan function prototypes.
|
||||
// We provide a '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' convenience configuration flag.
|
||||
// In order to make sure this is visible from the imgui_impl_vulkan.cpp compilation unit:
|
||||
// - Add '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' in your imconfig.h file
|
||||
// - Or as a compilation flag in your build system
|
||||
// - Or uncomment here (not recommended because you'd be modifying imgui sources!)
|
||||
// - Do not simply add it in a .cpp file!
|
||||
// (2) Call ImGui_ImplVulkan_LoadFunctions() before ImGui_ImplVulkan_Init() with your custom function.
|
||||
// If you have no idea what this is, leave it alone!
|
||||
//#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES
|
||||
|
||||
// Vulkan includes
|
||||
#if defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES) && !defined(VK_NO_PROTOTYPES)
|
||||
#define VK_NO_PROTOTYPES
|
||||
#endif
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
// Initialization data, for ImGui_ImplVulkan_Init()
|
||||
// [Please zero-clear before use!]
|
||||
struct ImGui_ImplVulkan_InitInfo
|
||||
{
|
||||
VkInstance Instance;
|
||||
VkPhysicalDevice PhysicalDevice;
|
||||
VkDevice Device;
|
||||
uint32_t QueueFamily;
|
||||
VkQueue Queue;
|
||||
VkPipelineCache PipelineCache;
|
||||
VkDescriptorPool DescriptorPool;
|
||||
uint32_t Subpass;
|
||||
uint32_t MinImageCount; // >= 2
|
||||
uint32_t ImageCount; // >= MinImageCount
|
||||
VkSampleCountFlagBits MSAASamples; // >= VK_SAMPLE_COUNT_1_BIT (0 -> default to VK_SAMPLE_COUNT_1_BIT)
|
||||
|
||||
// Dynamic Rendering (Optional)
|
||||
bool UseDynamicRendering; // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3.
|
||||
VkFormat ColorAttachmentFormat; // Required for dynamic rendering
|
||||
|
||||
// Allocation, Debugging
|
||||
const VkAllocationCallbacks* Allocator;
|
||||
void (*CheckVkResultFn)(VkResult err);
|
||||
};
|
||||
|
||||
// Called by user code
|
||||
IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass);
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE);
|
||||
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture();
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontsTexture();
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
|
||||
|
||||
// Register a texture (VkDescriptorSet == ImTextureID)
|
||||
// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem
|
||||
// Please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions.
|
||||
IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout);
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set);
|
||||
|
||||
// Optional: load Vulkan functions with a custom function loader
|
||||
// This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES
|
||||
IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = nullptr);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Internal / Miscellaneous Vulkan Helpers
|
||||
// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
|
||||
//-------------------------------------------------------------------------
|
||||
// You probably do NOT need to use or care about those functions.
|
||||
// Those functions only exist because:
|
||||
// 1) they facilitate the readability and maintenance of the multiple main.cpp examples files.
|
||||
// 2) the multi-viewport / platform window implementation needs them internally.
|
||||
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
|
||||
// but it is too much code to duplicate everywhere so we exceptionally expose them.
|
||||
//
|
||||
// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
|
||||
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
|
||||
// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
struct ImGui_ImplVulkanH_Frame;
|
||||
struct ImGui_ImplVulkanH_Window;
|
||||
|
||||
// Helpers
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wnd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wnd, const VkAllocationCallbacks* allocator);
|
||||
IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
|
||||
IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
|
||||
IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
|
||||
|
||||
// Helper structure to hold the data needed by one rendering frame
|
||||
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
|
||||
// [Please zero-clear before use!]
|
||||
struct ImGui_ImplVulkanH_Frame
|
||||
{
|
||||
VkCommandPool CommandPool;
|
||||
VkCommandBuffer CommandBuffer;
|
||||
VkFence Fence;
|
||||
VkImage Backbuffer;
|
||||
VkImageView BackbufferView;
|
||||
VkFramebuffer Framebuffer;
|
||||
};
|
||||
|
||||
struct ImGui_ImplVulkanH_FrameSemaphores
|
||||
{
|
||||
VkSemaphore ImageAcquiredSemaphore;
|
||||
VkSemaphore RenderCompleteSemaphore;
|
||||
};
|
||||
|
||||
// Helper structure to hold the data needed by one rendering context into one OS window
|
||||
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
|
||||
struct ImGui_ImplVulkanH_Window
|
||||
{
|
||||
int Width;
|
||||
int Height;
|
||||
VkSwapchainKHR Swapchain;
|
||||
VkSurfaceKHR Surface;
|
||||
VkSurfaceFormatKHR SurfaceFormat;
|
||||
VkPresentModeKHR PresentMode;
|
||||
VkRenderPass RenderPass;
|
||||
VkPipeline Pipeline; // The window pipeline may uses a different VkRenderPass than the one passed in ImGui_ImplVulkan_InitInfo
|
||||
bool UseDynamicRendering;
|
||||
bool ClearEnable;
|
||||
VkClearValue ClearValue;
|
||||
uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
|
||||
uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
|
||||
uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
|
||||
ImGui_ImplVulkanH_Frame* Frames;
|
||||
ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
|
||||
|
||||
ImGui_ImplVulkanH_Window()
|
||||
{
|
||||
memset((void*)this, 0, sizeof(*this));
|
||||
PresentMode = (VkPresentModeKHR)~0; // Ensure we get an error if user doesn't set this.
|
||||
ClearEnable = true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
1062
src/thirdparty/imgui/imgui_internal.h
vendored
1062
src/thirdparty/imgui/imgui_internal.h
vendored
File diff suppressed because it is too large
Load Diff
732
src/thirdparty/imgui/imgui_tables.cpp
vendored
732
src/thirdparty/imgui/imgui_tables.cpp
vendored
File diff suppressed because it is too large
Load Diff
1500
src/thirdparty/imgui/imgui_widgets.cpp
vendored
1500
src/thirdparty/imgui/imgui_widgets.cpp
vendored
File diff suppressed because it is too large
Load Diff
182
src/thirdparty/imgui/imstb_textedit.h
vendored
182
src/thirdparty/imgui/imstb_textedit.h
vendored
@@ -2,7 +2,9 @@
|
||||
// This is a slightly modified version of stb_textedit.h 1.14.
|
||||
// Those changes would need to be pushed into nothings/stb:
|
||||
// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
|
||||
// - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000 + #6783)
|
||||
// Grep for [DEAR IMGUI] to find the changes.
|
||||
// - Also renamed macros used or defined outside of IMSTB_TEXTEDIT_IMPLEMENTATION block from STB_TEXTEDIT_* to IMSTB_TEXTEDIT_*
|
||||
|
||||
// stb_textedit.h - v1.14 - public domain - Sean Barrett
|
||||
// Development of this library was sponsored by RAD Game Tools
|
||||
@@ -29,7 +31,7 @@
|
||||
// DEPENDENCIES
|
||||
//
|
||||
// Uses the C runtime function 'memmove', which you can override
|
||||
// by defining STB_TEXTEDIT_memmove before the implementation.
|
||||
// by defining IMSTB_TEXTEDIT_memmove before the implementation.
|
||||
// Uses no other functions. Performs no runtime allocations.
|
||||
//
|
||||
//
|
||||
@@ -273,8 +275,8 @@
|
||||
////
|
||||
////
|
||||
|
||||
#ifndef INCLUDE_STB_TEXTEDIT_H
|
||||
#define INCLUDE_STB_TEXTEDIT_H
|
||||
#ifndef INCLUDE_IMSTB_TEXTEDIT_H
|
||||
#define INCLUDE_IMSTB_TEXTEDIT_H
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@@ -285,33 +287,33 @@
|
||||
// and undo state.
|
||||
//
|
||||
|
||||
#ifndef STB_TEXTEDIT_UNDOSTATECOUNT
|
||||
#define STB_TEXTEDIT_UNDOSTATECOUNT 99
|
||||
#ifndef IMSTB_TEXTEDIT_UNDOSTATECOUNT
|
||||
#define IMSTB_TEXTEDIT_UNDOSTATECOUNT 99
|
||||
#endif
|
||||
#ifndef STB_TEXTEDIT_UNDOCHARCOUNT
|
||||
#define STB_TEXTEDIT_UNDOCHARCOUNT 999
|
||||
#ifndef IMSTB_TEXTEDIT_UNDOCHARCOUNT
|
||||
#define IMSTB_TEXTEDIT_UNDOCHARCOUNT 999
|
||||
#endif
|
||||
#ifndef STB_TEXTEDIT_CHARTYPE
|
||||
#define STB_TEXTEDIT_CHARTYPE int
|
||||
#ifndef IMSTB_TEXTEDIT_CHARTYPE
|
||||
#define IMSTB_TEXTEDIT_CHARTYPE int
|
||||
#endif
|
||||
#ifndef STB_TEXTEDIT_POSITIONTYPE
|
||||
#define STB_TEXTEDIT_POSITIONTYPE int
|
||||
#ifndef IMSTB_TEXTEDIT_POSITIONTYPE
|
||||
#define IMSTB_TEXTEDIT_POSITIONTYPE int
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// private data
|
||||
STB_TEXTEDIT_POSITIONTYPE where;
|
||||
STB_TEXTEDIT_POSITIONTYPE insert_length;
|
||||
STB_TEXTEDIT_POSITIONTYPE delete_length;
|
||||
IMSTB_TEXTEDIT_POSITIONTYPE where;
|
||||
IMSTB_TEXTEDIT_POSITIONTYPE insert_length;
|
||||
IMSTB_TEXTEDIT_POSITIONTYPE delete_length;
|
||||
int char_storage;
|
||||
} StbUndoRecord;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// private data
|
||||
StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT];
|
||||
STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT];
|
||||
StbUndoRecord undo_rec [IMSTB_TEXTEDIT_UNDOSTATECOUNT];
|
||||
IMSTB_TEXTEDIT_CHARTYPE undo_char[IMSTB_TEXTEDIT_UNDOCHARCOUNT];
|
||||
short undo_point, redo_point;
|
||||
int undo_char_point, redo_char_point;
|
||||
} StbUndoState;
|
||||
@@ -370,7 +372,7 @@ typedef struct
|
||||
float ymin,ymax; // height of row above and below baseline
|
||||
int num_chars;
|
||||
} StbTexteditRow;
|
||||
#endif //INCLUDE_STB_TEXTEDIT_H
|
||||
#endif //INCLUDE_IMSTB_TEXTEDIT_H
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
@@ -383,11 +385,11 @@ typedef struct
|
||||
|
||||
// implementation isn't include-guarded, since it might have indirectly
|
||||
// included just the "header" portion
|
||||
#ifdef STB_TEXTEDIT_IMPLEMENTATION
|
||||
#ifdef IMSTB_TEXTEDIT_IMPLEMENTATION
|
||||
|
||||
#ifndef STB_TEXTEDIT_memmove
|
||||
#ifndef IMSTB_TEXTEDIT_memmove
|
||||
#include <string.h>
|
||||
#define STB_TEXTEDIT_memmove memmove
|
||||
#define IMSTB_TEXTEDIT_memmove memmove
|
||||
#endif
|
||||
|
||||
|
||||
@@ -397,7 +399,7 @@ typedef struct
|
||||
//
|
||||
|
||||
// traverse the layout to locate the nearest character to a display position
|
||||
static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
|
||||
static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
|
||||
{
|
||||
StbTexteditRow r;
|
||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||
@@ -457,7 +459,7 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
|
||||
}
|
||||
|
||||
// API click: on mouse down, move the cursor to the clicked location, and reset the selection
|
||||
static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
||||
static void stb_textedit_click(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
||||
{
|
||||
// In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
|
||||
// goes off the top or bottom of the text
|
||||
@@ -475,7 +477,7 @@ static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *stat
|
||||
}
|
||||
|
||||
// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location
|
||||
static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
||||
static void stb_textedit_drag(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
||||
{
|
||||
int p = 0;
|
||||
|
||||
@@ -501,11 +503,11 @@ static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state
|
||||
//
|
||||
|
||||
// forward declarations
|
||||
static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state);
|
||||
static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state);
|
||||
static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length);
|
||||
static void stb_text_undo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state);
|
||||
static void stb_text_redo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state);
|
||||
static void stb_text_makeundo_delete(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length);
|
||||
static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length);
|
||||
static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length);
|
||||
static void stb_text_makeundo_replace(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -517,36 +519,21 @@ typedef struct
|
||||
|
||||
// find the x/y location of a character, and remember info about the previous row in
|
||||
// case we get a move-up event (for page up, we'll have to rescan)
|
||||
static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str, int n, int single_line)
|
||||
static void stb_textedit_find_charpos(StbFindState *find, IMSTB_TEXTEDIT_STRING *str, int n, int single_line)
|
||||
{
|
||||
StbTexteditRow r;
|
||||
int prev_start = 0;
|
||||
int z = STB_TEXTEDIT_STRINGLEN(str);
|
||||
int i=0, first;
|
||||
|
||||
if (n == z) {
|
||||
// if it's at the end, then find the last line -- simpler than trying to
|
||||
// explicitly handle this case in the regular code
|
||||
if (single_line) {
|
||||
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
|
||||
find->y = 0;
|
||||
find->first_char = 0;
|
||||
find->length = z;
|
||||
find->height = r.ymax - r.ymin;
|
||||
find->x = r.x1;
|
||||
} else {
|
||||
find->y = 0;
|
||||
find->x = 0;
|
||||
find->height = 1;
|
||||
while (i < z) {
|
||||
STB_TEXTEDIT_LAYOUTROW(&r, str, i);
|
||||
prev_start = i;
|
||||
i += r.num_chars;
|
||||
}
|
||||
find->first_char = i;
|
||||
find->length = 0;
|
||||
find->prev_first = prev_start;
|
||||
}
|
||||
if (n == z && single_line) {
|
||||
// special case if it's at the end (may not be needed?)
|
||||
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
|
||||
find->y = 0;
|
||||
find->first_char = 0;
|
||||
find->length = z;
|
||||
find->height = r.ymax - r.ymin;
|
||||
find->x = r.x1;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -557,9 +544,16 @@ static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *s
|
||||
STB_TEXTEDIT_LAYOUTROW(&r, str, i);
|
||||
if (n < i + r.num_chars)
|
||||
break;
|
||||
if (i + r.num_chars == z && z > 0 && STB_TEXTEDIT_GETCHAR(str, z - 1) != STB_TEXTEDIT_NEWLINE) // [DEAR IMGUI] special handling for last line
|
||||
break; // [DEAR IMGUI]
|
||||
prev_start = i;
|
||||
i += r.num_chars;
|
||||
find->y += r.baseline_y_delta;
|
||||
if (i == z) // [DEAR IMGUI]
|
||||
{
|
||||
r.num_chars = 0; // [DEAR IMGUI]
|
||||
break; // [DEAR IMGUI]
|
||||
}
|
||||
}
|
||||
|
||||
find->first_char = first = i;
|
||||
@@ -576,7 +570,7 @@ static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *s
|
||||
#define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end)
|
||||
|
||||
// make the selection/cursor state valid if client altered the string
|
||||
static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
static void stb_textedit_clamp(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
{
|
||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||
if (STB_TEXT_HAS_SELECTION(state)) {
|
||||
@@ -590,7 +584,7 @@ static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *stat
|
||||
}
|
||||
|
||||
// delete characters while updating undo
|
||||
static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len)
|
||||
static void stb_textedit_delete(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len)
|
||||
{
|
||||
stb_text_makeundo_delete(str, state, where, len);
|
||||
STB_TEXTEDIT_DELETECHARS(str, where, len);
|
||||
@@ -598,7 +592,7 @@ static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *sta
|
||||
}
|
||||
|
||||
// delete the section
|
||||
static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
static void stb_textedit_delete_selection(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
{
|
||||
stb_textedit_clamp(str, state);
|
||||
if (STB_TEXT_HAS_SELECTION(state)) {
|
||||
@@ -635,7 +629,7 @@ static void stb_textedit_move_to_first(STB_TexteditState *state)
|
||||
}
|
||||
|
||||
// move cursor to last character of selection
|
||||
static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
static void stb_textedit_move_to_last(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
{
|
||||
if (STB_TEXT_HAS_SELECTION(state)) {
|
||||
stb_textedit_sortselection(state);
|
||||
@@ -647,13 +641,13 @@ static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditStat
|
||||
}
|
||||
|
||||
#ifdef STB_TEXTEDIT_IS_SPACE
|
||||
static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx )
|
||||
static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx )
|
||||
{
|
||||
return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1;
|
||||
}
|
||||
|
||||
#ifndef STB_TEXTEDIT_MOVEWORDLEFT
|
||||
static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c )
|
||||
static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c )
|
||||
{
|
||||
--c; // always move at least one character
|
||||
while( c >= 0 && !is_word_boundary( str, c ) )
|
||||
@@ -668,7 +662,7 @@ static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c )
|
||||
#endif
|
||||
|
||||
#ifndef STB_TEXTEDIT_MOVEWORDRIGHT
|
||||
static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c )
|
||||
static int stb_textedit_move_to_word_next( IMSTB_TEXTEDIT_STRING *str, int c )
|
||||
{
|
||||
const int len = STB_TEXTEDIT_STRINGLEN(str);
|
||||
++c; // always move at least one character
|
||||
@@ -695,7 +689,7 @@ static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state)
|
||||
}
|
||||
|
||||
// API cut: delete selection
|
||||
static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
static int stb_textedit_cut(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
{
|
||||
if (STB_TEXT_HAS_SELECTION(state)) {
|
||||
stb_textedit_delete_selection(str,state); // implicitly clamps
|
||||
@@ -706,7 +700,7 @@ static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
}
|
||||
|
||||
// API paste: replace existing selection with passed-in text
|
||||
static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
|
||||
static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, IMSTB_TEXTEDIT_CHARTYPE *text, int len)
|
||||
{
|
||||
// if there's a selection, the paste should delete it
|
||||
stb_textedit_clamp(str, state);
|
||||
@@ -727,14 +721,14 @@ static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditSta
|
||||
#endif
|
||||
|
||||
// API key: process a keyboard input
|
||||
static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
|
||||
static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
|
||||
{
|
||||
retry:
|
||||
switch (key) {
|
||||
default: {
|
||||
int c = STB_TEXTEDIT_KEYTOTEXT(key);
|
||||
if (c > 0) {
|
||||
STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c;
|
||||
IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE) c;
|
||||
|
||||
// can't add newline in single-line mode
|
||||
if (c == '\n' && state->single_line)
|
||||
@@ -899,8 +893,8 @@ retry:
|
||||
x = row.x0;
|
||||
for (i=0; i < row.num_chars; ++i) {
|
||||
float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
|
||||
#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
|
||||
if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
|
||||
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
||||
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
||||
break;
|
||||
#endif
|
||||
x += dx;
|
||||
@@ -961,8 +955,8 @@ retry:
|
||||
x = row.x0;
|
||||
for (i=0; i < row.num_chars; ++i) {
|
||||
float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
|
||||
#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
|
||||
if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
|
||||
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
||||
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
||||
break;
|
||||
#endif
|
||||
x += dx;
|
||||
@@ -1119,8 +1113,8 @@ retry:
|
||||
|
||||
static void stb_textedit_flush_redo(StbUndoState *state)
|
||||
{
|
||||
state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
|
||||
state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
|
||||
state->redo_point = IMSTB_TEXTEDIT_UNDOSTATECOUNT;
|
||||
state->redo_char_point = IMSTB_TEXTEDIT_UNDOCHARCOUNT;
|
||||
}
|
||||
|
||||
// discard the oldest entry in the undo list
|
||||
@@ -1132,13 +1126,13 @@ static void stb_textedit_discard_undo(StbUndoState *state)
|
||||
int n = state->undo_rec[0].insert_length, i;
|
||||
// delete n characters from all other records
|
||||
state->undo_char_point -= n;
|
||||
STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE)));
|
||||
IMSTB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(IMSTB_TEXTEDIT_CHARTYPE)));
|
||||
for (i=0; i < state->undo_point; ++i)
|
||||
if (state->undo_rec[i].char_storage >= 0)
|
||||
state->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it
|
||||
}
|
||||
--state->undo_point;
|
||||
STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0])));
|
||||
IMSTB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0])));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1148,7 +1142,7 @@ static void stb_textedit_discard_undo(StbUndoState *state)
|
||||
// fill up even though the undo buffer didn't
|
||||
static void stb_textedit_discard_redo(StbUndoState *state)
|
||||
{
|
||||
int k = STB_TEXTEDIT_UNDOSTATECOUNT-1;
|
||||
int k = IMSTB_TEXTEDIT_UNDOSTATECOUNT-1;
|
||||
|
||||
if (state->redo_point <= k) {
|
||||
// if the k'th undo state has characters, clean those up
|
||||
@@ -1156,7 +1150,7 @@ static void stb_textedit_discard_redo(StbUndoState *state)
|
||||
int n = state->undo_rec[k].insert_length, i;
|
||||
// move the remaining redo character data to the end of the buffer
|
||||
state->redo_char_point += n;
|
||||
STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE)));
|
||||
IMSTB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((IMSTB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(IMSTB_TEXTEDIT_CHARTYPE)));
|
||||
// adjust the position of all the other records to account for above memmove
|
||||
for (i=state->redo_point; i < k; ++i)
|
||||
if (state->undo_rec[i].char_storage >= 0)
|
||||
@@ -1164,12 +1158,12 @@ static void stb_textedit_discard_redo(StbUndoState *state)
|
||||
}
|
||||
// now move all the redo records towards the end of the buffer; the first one is at 'redo_point'
|
||||
// [DEAR IMGUI]
|
||||
size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0]));
|
||||
size_t move_size = (size_t)((IMSTB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0]));
|
||||
const char* buf_begin = (char*)state->undo_rec; (void)buf_begin;
|
||||
const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end;
|
||||
IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin);
|
||||
IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end);
|
||||
STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size);
|
||||
IMSTB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size);
|
||||
|
||||
// now move redo_point to point to the new one
|
||||
++state->redo_point;
|
||||
@@ -1183,32 +1177,32 @@ static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numch
|
||||
|
||||
// if we have no free records, we have to make room, by sliding the
|
||||
// existing records down
|
||||
if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
|
||||
if (state->undo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
|
||||
stb_textedit_discard_undo(state);
|
||||
|
||||
// if the characters to store won't possibly fit in the buffer, we can't undo
|
||||
if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) {
|
||||
if (numchars > IMSTB_TEXTEDIT_UNDOCHARCOUNT) {
|
||||
state->undo_point = 0;
|
||||
state->undo_char_point = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// if we don't have enough free characters in the buffer, we have to make room
|
||||
while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT)
|
||||
while (state->undo_char_point + numchars > IMSTB_TEXTEDIT_UNDOCHARCOUNT)
|
||||
stb_textedit_discard_undo(state);
|
||||
|
||||
return &state->undo_rec[state->undo_point++];
|
||||
}
|
||||
|
||||
static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len)
|
||||
static IMSTB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len)
|
||||
{
|
||||
StbUndoRecord *r = stb_text_create_undo_record(state, insert_len);
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
|
||||
r->where = pos;
|
||||
r->insert_length = (STB_TEXTEDIT_POSITIONTYPE) insert_len;
|
||||
r->delete_length = (STB_TEXTEDIT_POSITIONTYPE) delete_len;
|
||||
r->insert_length = (IMSTB_TEXTEDIT_POSITIONTYPE) insert_len;
|
||||
r->delete_length = (IMSTB_TEXTEDIT_POSITIONTYPE) delete_len;
|
||||
|
||||
if (insert_len == 0) {
|
||||
r->char_storage = -1;
|
||||
@@ -1220,7 +1214,7 @@ static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos,
|
||||
}
|
||||
}
|
||||
|
||||
static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
static void stb_text_undo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
{
|
||||
StbUndoState *s = &state->undostate;
|
||||
StbUndoRecord u, *r;
|
||||
@@ -1247,7 +1241,7 @@ static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
// characters stored for *undoing* don't leave room for redo
|
||||
// if the last is true, we have to bail
|
||||
|
||||
if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) {
|
||||
if (s->undo_char_point + u.delete_length >= IMSTB_TEXTEDIT_UNDOCHARCOUNT) {
|
||||
// the undo records take up too much character space; there's no space to store the redo characters
|
||||
r->insert_length = 0;
|
||||
} else {
|
||||
@@ -1256,7 +1250,7 @@ static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
// there's definitely room to store the characters eventually
|
||||
while (s->undo_char_point + u.delete_length > s->redo_char_point) {
|
||||
// should never happen:
|
||||
if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
|
||||
if (s->redo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
|
||||
return;
|
||||
// there's currently not enough room, so discard a redo record
|
||||
stb_textedit_discard_redo(s);
|
||||
@@ -1288,11 +1282,11 @@ static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
s->redo_point--;
|
||||
}
|
||||
|
||||
static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
static void stb_text_redo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
{
|
||||
StbUndoState *s = &state->undostate;
|
||||
StbUndoRecord *u, r;
|
||||
if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
|
||||
if (s->redo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
|
||||
return;
|
||||
|
||||
// we need to do two things: apply the redo record, and create an undo record
|
||||
@@ -1344,20 +1338,20 @@ static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int le
|
||||
stb_text_createundo(&state->undostate, where, 0, length);
|
||||
}
|
||||
|
||||
static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length)
|
||||
static void stb_text_makeundo_delete(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length)
|
||||
{
|
||||
int i;
|
||||
STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0);
|
||||
IMSTB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0);
|
||||
if (p) {
|
||||
for (i=0; i < length; ++i)
|
||||
p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
|
||||
}
|
||||
}
|
||||
|
||||
static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length)
|
||||
static void stb_text_makeundo_replace(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length)
|
||||
{
|
||||
int i;
|
||||
STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length);
|
||||
IMSTB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length);
|
||||
if (p) {
|
||||
for (i=0; i < old_length; ++i)
|
||||
p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
|
||||
@@ -1369,8 +1363,8 @@ static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_lin
|
||||
{
|
||||
state->undostate.undo_point = 0;
|
||||
state->undostate.undo_char_point = 0;
|
||||
state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
|
||||
state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
|
||||
state->undostate.redo_point = IMSTB_TEXTEDIT_UNDOSTATECOUNT;
|
||||
state->undostate.redo_char_point = IMSTB_TEXTEDIT_UNDOCHARCOUNT;
|
||||
state->select_end = state->select_start = 0;
|
||||
state->cursor = 0;
|
||||
state->has_preferred_x = 0;
|
||||
@@ -1393,16 +1387,16 @@ static void stb_textedit_initialize_state(STB_TexteditState *state, int is_singl
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
|
||||
static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len)
|
||||
static int stb_textedit_paste(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, IMSTB_TEXTEDIT_CHARTYPE const *ctext, int len)
|
||||
{
|
||||
return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len);
|
||||
return stb_textedit_paste_internal(str, state, (IMSTB_TEXTEDIT_CHARTYPE *) ctext, len);
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif//STB_TEXTEDIT_IMPLEMENTATION
|
||||
#endif//IMSTB_TEXTEDIT_IMPLEMENTATION
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
2
src/thirdparty/imgui/imstb_truetype.h
vendored
2
src/thirdparty/imgui/imstb_truetype.h
vendored
@@ -2008,7 +2008,7 @@ static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int gly
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
if (fdselector == -1) stbtt__new_buf(NULL, 0);
|
||||
if (fdselector == -1) return stbtt__new_buf(NULL, 0); // [DEAR IMGUI] fixed, see #6007 and nothings/stb#1422
|
||||
return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector));
|
||||
}
|
||||
|
||||
|
||||
6
src/thirdparty/imgui/vulkan/generate_spv.sh
vendored
Normal file
6
src/thirdparty/imgui/vulkan/generate_spv.sh
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
## -V: create SPIR-V binary
|
||||
## -x: save binary output as text-based 32-bit hexadecimal numbers
|
||||
## -o: output file
|
||||
glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag
|
||||
glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert
|
||||
14
src/thirdparty/imgui/vulkan/glsl_shader.frag
vendored
Normal file
14
src/thirdparty/imgui/vulkan/glsl_shader.frag
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
#version 450 core
|
||||
layout(location = 0) out vec4 fColor;
|
||||
|
||||
layout(set=0, binding=0) uniform sampler2D sTexture;
|
||||
|
||||
layout(location = 0) in struct {
|
||||
vec4 Color;
|
||||
vec2 UV;
|
||||
} In;
|
||||
|
||||
void main()
|
||||
{
|
||||
fColor = In.Color * texture(sTexture, In.UV.st);
|
||||
}
|
||||
25
src/thirdparty/imgui/vulkan/glsl_shader.vert
vendored
Normal file
25
src/thirdparty/imgui/vulkan/glsl_shader.vert
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
#version 450 core
|
||||
layout(location = 0) in vec2 aPos;
|
||||
layout(location = 1) in vec2 aUV;
|
||||
layout(location = 2) in vec4 aColor;
|
||||
|
||||
layout(push_constant) uniform uPushConstant {
|
||||
vec2 uScale;
|
||||
vec2 uTranslate;
|
||||
} pc;
|
||||
|
||||
out gl_PerVertex {
|
||||
vec4 gl_Position;
|
||||
};
|
||||
|
||||
layout(location = 0) out struct {
|
||||
vec4 Color;
|
||||
vec2 UV;
|
||||
} Out;
|
||||
|
||||
void main()
|
||||
{
|
||||
Out.Color = aColor;
|
||||
Out.UV = aUV;
|
||||
gl_Position = vec4(aPos * pc.uScale + pc.uTranslate, 0, 1);
|
||||
}
|
||||
151
src/window.cpp
151
src/window.cpp
@@ -1,18 +1,27 @@
|
||||
|
||||
#include "window.hpp"
|
||||
|
||||
#include "graphics/device.hpp"
|
||||
#include "gui/style.hpp"
|
||||
|
||||
#include <graphics.hpp>
|
||||
#include <version.hpp>
|
||||
|
||||
#include "yolo/yolo.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
static GLFWwindow* Window;
|
||||
static WINDOW_MODE WinMode = WINDOW_MODE::WIN_MODE_DEFAULT;
|
||||
static KeyCallback UserKeyCallback = nullptr;
|
||||
static int Width, Height;
|
||||
static const char* GlslVersion;
|
||||
static GLFWwindow* Window;
|
||||
|
||||
void glfwKeyCallback(GLFWwindow* window, int key, int scancode,
|
||||
int action, int mods)
|
||||
void glfwKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
if (UserKeyCallback != nullptr) {
|
||||
UserKeyCallback(key, scancode, action, mods);
|
||||
@@ -24,79 +33,14 @@ void glfwErrorCallback(int error, const char* description)
|
||||
yolo::error("[GLFW {}] {}", error, description);
|
||||
}
|
||||
|
||||
void setupGLFW(std::string title)
|
||||
void setupWindow(std::string title)
|
||||
{
|
||||
glfwSetErrorCallback(glfwErrorCallback);
|
||||
if (!glfwInit())
|
||||
throw std::runtime_error("Failed to initialize GLFW");
|
||||
glfwInit();
|
||||
|
||||
// Decide GL+GLSL versions
|
||||
#if defined(IMGUI_IMPL_OPENGL_ES2)
|
||||
// GL ES 2.0 + GLSL 100
|
||||
GlslVersion = "#version 100";
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
|
||||
#elif defined(__APPLE__)
|
||||
// GL 3.2 + GLSL 150
|
||||
GlslVersion = "#version 150";
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
|
||||
#else
|
||||
// GL 4.5 + GLSL 450
|
||||
GlslVersion = "#version 450";
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only
|
||||
#endif
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
||||
|
||||
// Create window with graphics context
|
||||
Window = glfwCreateWindow(1280, 720, title.c_str(), NULL, NULL);
|
||||
if (Window == NULL)
|
||||
throw std::runtime_error("Could not create window");
|
||||
glfwMakeContextCurrent(Window);
|
||||
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
|
||||
glfwSwapInterval(1); // Enable vsync
|
||||
yolo::info("GLFW {} initialized", glfwGetVersionString());
|
||||
yolo::info("OpenGL {} initialized", glGetString(GL_VERSION));
|
||||
yolo::info("GLSL {} initialized", glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
yolo::info("INFERNO HART Running on ", glGetString(GL_RENDERER));
|
||||
}
|
||||
|
||||
void setupImGui()
|
||||
{
|
||||
// Setup Dear ImGui context
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
|
||||
// Setup Dear ImGui style
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
(void)io;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleFonts; // FIXME: THIS CURRENTLY DOESN'T
|
||||
// WORK AS EXPECTED. DON'T USE IN
|
||||
// USER APP!
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleViewports; // FIXME:
|
||||
// io.ConfigDockingWithShift
|
||||
// = true;
|
||||
|
||||
// Setup Platform/Renderer backends
|
||||
ImGui_ImplGlfw_InitForOpenGL(Window, true);
|
||||
ImGui_ImplOpenGL3_Init(GlslVersion);
|
||||
|
||||
inferno::SetupImGuiStyle2();
|
||||
}
|
||||
|
||||
void shutdownImGui()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
Window = glfwCreateWindow(Width, Height, title.c_str(), nullptr, nullptr);
|
||||
}
|
||||
|
||||
void shutdownGLFW()
|
||||
@@ -109,21 +53,26 @@ void window_create(std::string title, int width, int height)
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
setupGLFW(title);
|
||||
setupWindow(title);
|
||||
glfwSetKeyCallback(Window, glfwKeyCallback);
|
||||
setupImGui();
|
||||
}
|
||||
|
||||
void window_cleanup()
|
||||
void window_init_device(GraphicsDevice* device, GLFWframebuffersizefun resizeCallback)
|
||||
{
|
||||
shutdownImGui();
|
||||
shutdownGLFW();
|
||||
if (glfwCreateWindowSurface(
|
||||
device->VulkanInstance, Window, nullptr, &device->VulkanSurface)
|
||||
!= VK_SUCCESS) {
|
||||
yolo::error("failed to create window surface!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
glfwSetWindowUserPointer(Window, device);
|
||||
glfwSetFramebufferSizeCallback(Window, (GLFWframebuffersizefun)resizeCallback);
|
||||
}
|
||||
|
||||
void window_set_title(std::string title)
|
||||
{
|
||||
glfwSetWindowTitle(Window, title.c_str());
|
||||
}
|
||||
void window_cleanup() { shutdownGLFW(); }
|
||||
|
||||
void window_set_title(std::string title) { glfwSetWindowTitle(Window, title.c_str()); }
|
||||
|
||||
void window_set_size(int w, int h)
|
||||
{
|
||||
@@ -143,9 +92,9 @@ GLFWwindow* window_get_glfw_window() { return Window; }
|
||||
void window_set_mode(WINDOW_MODE mode)
|
||||
{
|
||||
WinMode = mode;
|
||||
if (mode == WINDOW_MODE::WIN_MODE_FPS) {
|
||||
glfwSetInputMode(Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
}
|
||||
// if (mode == WINDOW_MODE::WIN_MODE_FPS) {
|
||||
// glfwSetInputMode(Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
// }
|
||||
}
|
||||
|
||||
void window_set_key_callback(KeyCallback callback) { UserKeyCallback = callback; }
|
||||
@@ -155,39 +104,23 @@ KeyCallback window_get_key_callback() { return UserKeyCallback; }
|
||||
bool window_new_frame()
|
||||
{
|
||||
glfwPollEvents();
|
||||
if (WinMode == WIN_MODE_FPS) {
|
||||
glfwSetInputMode(Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
glfwSetCursorPos(Window, (double)Width / 2, (double)Height / 2);
|
||||
}
|
||||
// if (WinMode == WIN_MODE_FPS) {
|
||||
// glfwSetInputMode(Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
// glfwSetCursorPos(Window, (double)Width / 2, (double)Height / 2);
|
||||
// }
|
||||
if (glfwWindowShouldClose(Window)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
glfwSetInputMode(Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
glfwGetWindowSize(Window, &Width, &Height);
|
||||
|
||||
glClearColor(0.1, 0.1, 0.1, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
ImGui::Begin("main", nullptr, WINDOW_FLAGS);
|
||||
ImGui::SetWindowPos(ImVec2(0, 0));
|
||||
ImGui::SetWindowSize(ImVec2(Width, Height));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void window_render()
|
||||
{
|
||||
ImGui::End();
|
||||
ImGui::Render();
|
||||
auto io = ImGui::GetIO();
|
||||
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
glfwSwapBuffers(Window);
|
||||
ImGui::UpdatePlatformWindows();
|
||||
// ImGui::UpdatePlatformWindows();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "graphics.hpp"
|
||||
|
||||
#define WINDOW_FLAGS ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoCollapse
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace inferno::graphics {
|
||||
|
||||
struct GraphicsDevice;
|
||||
|
||||
typedef void (*KeyCallback)(int key, int scan, int action, int mod);
|
||||
typedef void (*MouseCallback)(double x, double y);
|
||||
|
||||
@@ -19,6 +20,8 @@ enum WINDOW_MODE {
|
||||
void window_create(std::string title, int width, int height);
|
||||
void window_cleanup();
|
||||
|
||||
void window_init_device(GraphicsDevice* device, GLFWframebuffersizefun resizeCallback);
|
||||
|
||||
void window_set_title(std::string title);
|
||||
|
||||
void window_set_size(int w, int h);
|
||||
|
||||
31
vk_layer_settings.txt
Normal file
31
vk_layer_settings.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
# The main, heavy-duty validation checks. This may be valuable early in the
|
||||
# development cycle to reduce validation output while correcting
|
||||
# parameter/object usage errors.
|
||||
khronos_validation.validate_core = true
|
||||
|
||||
# Enable synchronization validation during command buffers recording. This
|
||||
# feature reports resource access conflicts due to missing or incorrect
|
||||
# synchronization operations between actions (Draw, Copy, Dispatch, Blit)
|
||||
# reading or writing the same regions of memory.
|
||||
khronos_validation.validate_sync = true
|
||||
|
||||
# Thread checks. In order to not degrade performance, it might be best to run
|
||||
# your program with thread-checking disabled most of the time, enabling it
|
||||
# occasionally for a quick sanity check or when debugging difficult application
|
||||
# behaviors.
|
||||
khronos_validation.thread_safety = true
|
||||
|
||||
# Specifies what action is to be taken when a layer reports information
|
||||
khronos_validation.debug_action = VK_DBG_LAYER_ACTION_LOG_MSG
|
||||
|
||||
# Comma-delineated list of options specifying the types of messages to be reported
|
||||
khronos_validation.report_flags = debug,error,perf,info,warn
|
||||
|
||||
# Enable limiting of duplicate messages.
|
||||
khronos_validation.enable_message_limit = true
|
||||
|
||||
# Maximum number of times any single validation message should be reported.
|
||||
khronos_validation.duplicate_message_limit = 3
|
||||
|
||||
khronos_validation.printf_to_stdout = true
|
||||
khronos_validation.printf_verbose = true
|
||||
Reference in New Issue
Block a user