28 Commits

Author SHA1 Message Date
0b87bd8519 Merge branch 'main' into sharedLib 2022-11-30 19:27:08 +03:00
48486ee8c2 Add setNextItemOpen (#161)
This change enables starting a new TreeNode open.
2022-11-28 15:56:27 +03:00
a2feb73fa5 Fix the glfw example build condition (#159)
The example needs the opengl2 flag.
2022-11-22 21:13:18 +02:00
051a17a1c5 Add plotLines (#158) 2022-11-20 17:57:15 +02:00
9dac0f9fbe Prepare 2.1.1 (#157) 2022-08-30 21:13:04 +00:00
dab5937eee Fix compilation on MacOS / GHC 8.10.7 (#156)
Fixes errors along the lines of:
dear-imgui  > [ 2 of 17] Compiling DearImGui.GLFW
dear-imgui  > error: unknown type name 'constexpr'

So the "-std=c++11" option is not being passed to the C++ compiler on
MacOS.
The issue seems related to https://github.com/haskell/cabal/issues/6421
2022-08-30 21:57:08 +03:00
03205f482e refactor sharedLib 2022-07-25 21:16:31 +03:00
12c7aafaf6 shared lib 2022-07-25 21:16:31 +03:00
7795b3d838 Prepare 2.1.0 (#153)
Breaking change in upstream.
2022-07-25 18:14:21 +00:00
3a5abb2037 Update to 1.88 (#152) 2022-07-25 17:58:22 +00:00
06eb052cc5 added flag_ImDrawIdx (#151)
Co-authored-by: Stefan Dresselhaus <stefan@dresselhaus.cloud>
2022-07-23 15:42:13 +03:00
cf87988336 Prepare 2.0.0 (#148) 2022-05-15 23:37:43 +03:00
3c1d381c14 Replace String arguments with Text (#138)
Shave a few allocations and pointer-chasing due to conversion.
2022-05-15 22:41:10 +03:00
04fe618871 Prepare 1.5.0 (#140) 2022-03-28 13:22:11 +00:00
08d4b423ad Fix GHC-9.2 build (#145) 2022-03-28 13:04:22 +00:00
7d4f3a8b93 Make value and read-only range types distinct (#143)
Fixes #142
2022-03-23 21:22:05 +03:00
bc590d97c5 Tweak tables and add an example (#139)
Previously: #135
2022-03-22 22:36:19 +03:00
e5969f6b35 implementation of ImGui Tables (#135) 2022-03-11 16:48:11 +03:00
f066d03017 added options to selectable (#137) 2022-03-10 15:17:42 +00:00
fc307a4d6e Add remaining popup wrappers (#136)
- BeginPopupContextItem
- BeginPopupContextWindow
- BeginPopupContextVoid

For #132
2022-03-10 11:34:13 +03:00
4517af8123 Add isPopupOpen and wrappers (#134) 2022-03-09 21:08:54 +03:00
b837d583a5 added openPopupOnItemClick (#133) 2022-02-25 17:28:53 +00:00
67e169dc35 Prepare 1.4.0 (#129) 2022-02-13 19:31:45 +03:00
ae3fdb8bc3 Add new GLFW callback from 1.87 (#128) 2022-02-13 16:12:15 +00:00
ccdff36774 Add wchar32 and disable-obsolete flags (#127) 2022-02-13 16:05:49 +00:00
af6ba9e989 Add image support for vulkan backend (#126) 2022-02-13 14:24:08 +00:00
dc11fad07f Update to 1.87 (#125) 2022-02-13 00:26:39 +03:00
265d143261 Prepare 1.3.1 (#123) 2022-01-31 10:56:12 +03:00
19 changed files with 1571 additions and 353 deletions

View File

@ -1,5 +1,38 @@
# Changelog for dear-imgui # Changelog for dear-imgui
## [2.1.1]
- Build flag fix for MacOS.
## [2.1.0]
- `imgui` updated to [1.88].
* Breaking: `ImGuiKeyModFlags` renamed to `ImGuiModFlags`.
## [2.0.0]
- `String` arguments replaced with `Text`.
* Upgrading to `text-2` recommended to reap the UTF-8 benefits.
## [1.5.0]
- Added table wrappers.
- Added popup wrappers.
- Added `selectableWith`/`SelectableOptions` to expose optional arguments.
- Fix GHC-9.2 compatibility.
## [1.4.0]
- `imgui` updated to [1.87].
- Added `DearImGui.Vulkan.vulkanAddTexture`.
- Added `DearImGui.GLFW.glfwCursorPosCallback`.
* Apps that don't install backend callbacks, *must* call it themselves.
- Added flags `use-wchar32` (default on) and `disable-obsolete` (default off).
## [1.3.1]
- `imgui` updated to [1.86].
## [1.3.0] ## [1.3.0]
- Added `DearImGui.FontAtlas` and related `DearImGui.Raw.Font.*` bits. - Added `DearImGui.FontAtlas` and related `DearImGui.Raw.Font.*` bits.
@ -7,7 +40,7 @@
## [1.2.2] ## [1.2.2]
- `imgui` updated to 1.85. - `imgui` updated to [1.85].
## [1.2.1] ## [1.2.1]
@ -29,7 +62,7 @@
## [1.1.0] ## [1.1.0]
- `imgui` updated to 1.84.2. - `imgui` updated to [1.84.2].
- Removed unused Window argument from SDL `newFrame` to match 1.84. - Removed unused Window argument from SDL `newFrame` to match 1.84.
- Added GLFW backend callbacks. - Added GLFW backend callbacks.
- Added more withXXX wrappers. - Added more withXXX wrappers.
@ -44,7 +77,7 @@
## [1.0.0] ## [1.0.0]
Initial Hackage release based on 1.83. Initial Hackage release based on [1.83].
[1.0.0]: https://github.com/haskell-game/dear-imgui.hs/tree/v1.0.0 [1.0.0]: https://github.com/haskell-game/dear-imgui.hs/tree/v1.0.0
[1.0.1]: https://github.com/haskell-game/dear-imgui.hs/tree/v1.0.1 [1.0.1]: https://github.com/haskell-game/dear-imgui.hs/tree/v1.0.1
@ -54,3 +87,15 @@ Initial Hackage release based on 1.83.
[1.2.1]: https://github.com/haskell-game/dear-imgui.hs/tree/v1.2.1 [1.2.1]: https://github.com/haskell-game/dear-imgui.hs/tree/v1.2.1
[1.2.2]: https://github.com/haskell-game/dear-imgui.hs/tree/v1.2.2 [1.2.2]: https://github.com/haskell-game/dear-imgui.hs/tree/v1.2.2
[1.3.0]: https://github.com/haskell-game/dear-imgui.hs/tree/v1.3.0 [1.3.0]: https://github.com/haskell-game/dear-imgui.hs/tree/v1.3.0
[1.3.1]: https://github.com/haskell-game/dear-imgui.hs/tree/v1.3.1
[1.4.0]: https://github.com/haskell-game/dear-imgui.hs/tree/v1.4.0
[1.5.0]: https://github.com/haskell-game/dear-imgui.hs/tree/v1.5.0
[2.0.0]: https://github.com/haskell-game/dear-imgui.hs/tree/v2.0.0
[2.1.0]: https://github.com/haskell-game/dear-imgui.hs/tree/v2.1.0
[2.1.1]: https://github.com/haskell-game/dear-imgui.hs/tree/v2.1.1
[1.87]: https://github.com/ocornut/imgui/releases/tag/v1.87
[1.86]: https://github.com/ocornut/imgui/releases/tag/v1.86
[1.85]: https://github.com/ocornut/imgui/releases/tag/v1.85
[1.84.2]: https://github.com/ocornut/imgui/releases/tag/v1.84.2
[1.83]: https://github.com/ocornut/imgui/releases/tag/v1.83

View File

@ -10,6 +10,7 @@ import Data.IORef
import qualified Data.Vector as Vector import qualified Data.Vector as Vector
import DearImGui import DearImGui
import DearImGui.OpenGL3 import DearImGui.OpenGL3
import DearImGui.Internal.Text (pack)
import DearImGui.SDL import DearImGui.SDL
import DearImGui.SDL.OpenGL import DearImGui.SDL.OpenGL
import Control.Exception import Control.Exception
@ -134,18 +135,18 @@ loop window checked color slider r pos size' selected tab1Ref tab2Ref = do
text "ListClipper" text "ListClipper"
withChildOpen "##fixed" (ImVec2 0 200) True ImGuiWindowFlags_None do withChildOpen "##fixed" (ImVec2 0 200) True ImGuiWindowFlags_None do
let lotsOfItems = Vector.generate 50 (mappend "Item " . show) let lotsOfItems = Vector.generate 50 (pack . mappend "Item " . show)
withListClipper Nothing lotsOfItems text withListClipper Nothing lotsOfItems text
text "ListClipper, Haskell-powered" text "ListClipper, Haskell-powered"
withChildOpen "##infinite" (ImVec2 0 200) True ImGuiWindowFlags_None do withChildOpen "##infinite" (ImVec2 0 200) True ImGuiWindowFlags_None do
let infiniteItems = map (mappend "Item " . show) [0 :: Int ..] let infiniteItems = map (pack . mappend "Item " . show) [0 :: Int ..]
withListClipper Nothing infiniteItems text withListClipper Nothing infiniteItems text
text "Ethereal ListClipper" text "Ethereal ListClipper"
withChildOpen "##ethereal" (ImVec2 0 200) True ImGuiWindowFlags_None do withChildOpen "##ethereal" (ImVec2 0 200) True ImGuiWindowFlags_None do
withListClipper Nothing (ClipRange (0 :: Int) 1000) $ withListClipper Nothing (ClipRange (0 :: Int) 1000) $
text . mappend "Item " . show text . pack . mappend "Item " . show
plotHistogram "A histogram" [ 10, 10, 20, 30, 90 ] plotHistogram "A histogram" [ 10, 10, 20, 30, 90 ]

View File

@ -1,7 +1,7 @@
cabal-version: 3.0 cabal-version: 3.0
name: dear-imgui name: dear-imgui
version: 1.3.0 version: 2.1.1
author: Oliver Charles author: Oliver Charles
maintainer: ollie@ocharles.org.uk, aenor.realm@gmail.com maintainer: ollie@ocharles.org.uk, aenor.realm@gmail.com
license: BSD-3-Clause license: BSD-3-Clause
@ -13,18 +13,17 @@ description:
Set package flags according to your needs. Set package flags according to your needs.
build-type: Simple build-type: Simple
extra-source-files:
README.md,
ChangeLog.md
extra-source-files: extra-source-files:
README.md,
ChangeLog.md,
imgui/*.h, imgui/*.h,
imgui/backends/*.h, imgui/backends/*.h,
imgui/backends/*.mm, imgui/backends/*.mm,
imgui/imconfig.h, imgui/imconfig.h,
imgui/LICENSE.txt imgui/LICENSE.txt
common build-flags common exe-flags
if flag(debug) if flag(debug)
if os(linux) if os(linux)
ghc-options: -Wall -g -rtsopts -dcore-lint -debug ghc-options: -Wall -g -rtsopts -dcore-lint -debug
@ -50,7 +49,6 @@ common build-flags
ghc-options: -Wall -O2 ghc-options: -Wall -O2
cc-options: -O2 cc-options: -O2
source-repository head source-repository head
type: git type: git
location: https://github.com/haskell-game/dear-imgui.hs location: https://github.com/haskell-game/dear-imgui.hs
@ -111,6 +109,33 @@ flag examples
manual: manual:
True True
flag disable-obsolete
description:
Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
default:
False
manual:
True
flag use-wchar32
description:
Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
default:
True
manual:
True
flag use-ImDrawIdx32
description:
Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
default:
True
manual:
True
common common common common
build-depends: build-depends:
base base
@ -122,20 +147,29 @@ library
import: common import: common
hs-source-dirs: hs-source-dirs:
src src
generator
exposed-modules: exposed-modules:
DearImGui DearImGui
DearImGui.FontAtlas DearImGui.FontAtlas
DearImGui.Internal.Text
DearImGui.Raw DearImGui.Raw
DearImGui.Raw.DrawList DearImGui.Raw.DrawList
DearImGui.Raw.Font DearImGui.Raw.Font
DearImGui.Raw.Font.Config DearImGui.Raw.Font.Config
DearImGui.Raw.Font.GlyphRanges DearImGui.Raw.Font.GlyphRanges
DearImGui.Raw.ListClipper
DearImGui.Raw.IO DearImGui.Raw.IO
DearImGui.Raw.ListClipper
other-modules: other-modules:
DearImGui.Context DearImGui.Context
DearImGui.Enums DearImGui.Enums
DearImGui.Structs DearImGui.Structs
DearImGui.Generator
DearImGui.Generator.Parser
DearImGui.Generator.Tokeniser
DearImGui.Generator.Types
ghc-options:
-static -dynamic-too
-- create both libHSdear-imgui... .a and .so
cxx-options: -std=c++11 cxx-options: -std=c++11
cxx-sources: cxx-sources:
imgui/imgui.cpp imgui/imgui.cpp
@ -143,19 +177,62 @@ library
imgui/imgui_draw.cpp imgui/imgui_draw.cpp
imgui/imgui_tables.cpp imgui/imgui_tables.cpp
imgui/imgui_widgets.cpp imgui/imgui_widgets.cpp
install-includes:
imgui.h
imgui_internal.h
imstb_rectpack.h
imstb_textedit.h
imstb_truetype.h
extra-libraries: extra-libraries:
stdc++ stdc++
include-dirs: include-dirs:
imgui imgui
build-depends: build-depends:
dear-imgui-generator managed
, containers
, managed
, inline-c
, inline-c-cpp , inline-c-cpp
, StateVar , StateVar
, unliftio , unliftio
, vector , vector
-- for the generator:
, template-haskell
>= 2.15 && < 2.19
, containers
^>= 0.6.2.1
, directory
>= 1.3 && < 1.4
, filepath
>= 1.4 && < 1.5
, inline-c
>= 0.9.0.0 && < 0.10
, megaparsec
>= 9.0 && < 9.3
, parser-combinators
>= 1.2.0 && < 1.4
, scientific
>= 0.3.6.2 && < 0.3.8
, text
>= 1.2.4 && < 2.1
, th-lift
>= 0.7 && < 0.9
, transformers
>= 0.5.6 && < 0.6
, unordered-containers
>= 0.2.11 && < 0.3
if os(darwin)
ghc-options:
-optcxx-std=c++11
if flag(disable-obsolete)
cxx-options: -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS
if flag(use-wchar32)
cxx-options: -DIMGUI_USE_WCHAR32
cpp-options: -DIMGUI_USE_WCHAR32
if flag(use-ImDrawIdx32)
cxx-options: "-DImDrawIdx=unsigned int"
cpp-options: "-DImDrawIdx=unsigned int"
if flag(opengl2) if flag(opengl2)
exposed-modules: exposed-modules:
@ -238,42 +315,8 @@ library
exposed-modules: exposed-modules:
DearImGui.GLFW.Vulkan DearImGui.GLFW.Vulkan
library dear-imgui-generator
import: common
hs-source-dirs: generator
exposed-modules:
DearImGui.Generator
, DearImGui.Generator.Parser
, DearImGui.Generator.Tokeniser
, DearImGui.Generator.Types
build-depends:
template-haskell
>= 2.15 && < 2.19
, containers
^>= 0.6.2.1
, directory
>= 1.3 && < 1.4
, filepath
>= 1.4 && < 1.5
, inline-c
>= 0.9.0.0 && < 0.10
, megaparsec
>= 9.0 && < 9.3
, parser-combinators
>= 1.2.0 && < 1.4
, scientific
>= 0.3.6.2 && < 0.3.8
, text
>= 1.2.4 && < 1.3
, th-lift
>= 0.7 && < 0.9
, transformers
>= 0.5.6 && < 0.6
, unordered-containers
>= 0.2.11 && < 0.3
executable test executable test
import: common, build-flags import: common, exe-flags
main-is: Main.hs main-is: Main.hs
default-language: Haskell2010 default-language: Haskell2010
if (!flag(examples) || !flag(sdl) || !flag(opengl2)) if (!flag(examples) || !flag(sdl) || !flag(opengl2))
@ -282,17 +325,17 @@ executable test
build-depends: base, sdl2, gl, dear-imgui, vector build-depends: base, sdl2, gl, dear-imgui, vector
executable glfw executable glfw
import: common, build-flags import: common, exe-flags
main-is: Main.hs main-is: Main.hs
hs-source-dirs: examples/glfw hs-source-dirs: examples/glfw
default-language: Haskell2010 default-language: Haskell2010
if (!flag(examples) || !flag(glfw) || !flag(opengl2)) if (!flag(examples) || !flag(glfw) || !flag(opengl2))
buildable: False buildable: False
else else
build-depends: base, GLFW-b, gl, dear-imgui, managed build-depends: base, GLFW-b, gl, dear-imgui, managed, text
executable readme executable readme
import: common, build-flags import: common, exe-flags
main-is: Readme.hs main-is: Readme.hs
hs-source-dirs: examples hs-source-dirs: examples
build-depends: sdl2, gl, dear-imgui, managed build-depends: sdl2, gl, dear-imgui, managed
@ -300,7 +343,7 @@ executable readme
buildable: False buildable: False
executable fonts executable fonts
import: common, build-flags import: common, exe-flags
main-is: Main.hs main-is: Main.hs
hs-source-dirs: examples/fonts hs-source-dirs: examples/fonts
build-depends: sdl2, gl, dear-imgui, managed build-depends: sdl2, gl, dear-imgui, managed
@ -308,7 +351,7 @@ executable fonts
buildable: False buildable: False
executable image executable image
import: common, build-flags import: common, exe-flags
main-is: Image.hs main-is: Image.hs
hs-source-dirs: examples/sdl hs-source-dirs: examples/sdl
build-depends: sdl2, gl, dear-imgui, managed, vector build-depends: sdl2, gl, dear-imgui, managed, vector
@ -316,7 +359,7 @@ executable image
buildable: False buildable: False
executable vulkan executable vulkan
import: common, build-flags import: common, exe-flags
main-is: Main.hs main-is: Main.hs
other-modules: Attachments, Backend, Input, Util other-modules: Attachments, Backend, Input, Util
hs-source-dirs: examples/vulkan hs-source-dirs: examples/vulkan
@ -350,3 +393,5 @@ executable vulkan
^>= 3.9 ^>= 3.9
, vulkan-utils , vulkan-utils
^>= 0.4.1 ^>= 0.4.1
, VulkanMemoryAllocator
, JuicyPixels

View File

@ -1,6 +1,7 @@
{-# language BlockArguments #-} {-# language BlockArguments #-}
{-# language LambdaCase #-} {-# language LambdaCase #-}
{-# language OverloadedStrings #-} {-# language OverloadedStrings #-}
{-# language RecordWildCards #-}
module Main ( main ) where module Main ( main ) where
@ -8,6 +9,12 @@ import Control.Exception
import Control.Monad import Control.Monad
import Control.Monad.IO.Class import Control.Monad.IO.Class
import Control.Monad.Managed import Control.Monad.Managed
import Data.Bits ((.|.))
import Data.IORef
import Data.List (sortBy)
import Data.Foldable (traverse_)
import Data.Text (Text, pack)
import DearImGui import DearImGui
import DearImGui.OpenGL2 import DearImGui.OpenGL2
import DearImGui.GLFW import DearImGui.GLFW
@ -40,14 +47,23 @@ main = do
-- Initialize ImGui's OpenGL backend -- Initialize ImGui's OpenGL backend
_ <- managed_ $ bracket_ openGL2Init openGL2Shutdown _ <- managed_ $ bracket_ openGL2Init openGL2Shutdown
liftIO $ mainLoop win tableRef <- liftIO $ newIORef
[ (1, "foo")
, (2, "bar")
, (3, "baz")
, (10, "spam")
, (11, "spam")
, (12, "spam")
]
liftIO $ mainLoop win tableRef
Nothing -> do Nothing -> do
error "GLFW createWindow failed" error "GLFW createWindow failed"
GLFW.terminate GLFW.terminate
mainLoop :: Window -> IO () mainLoop :: Window -> IORef [(Integer, Text)] -> IO ()
mainLoop win = do mainLoop win tableRef = do
-- Process the event loop -- Process the event loop
GLFW.pollEvents GLFW.pollEvents
close <- GLFW.windowShouldClose win close <- GLFW.windowShouldClose win
@ -64,12 +80,18 @@ mainLoop win = do
text "Hello, ImGui!" text "Hello, ImGui!"
-- Add a button widget, and call 'putStrLn' when it's clicked -- Add a button widget, and call 'putStrLn' when it's clicked
button "Clickety Click" >>= \case clicking <- button "Clickety Click"
False -> return () when clicking $
True -> putStrLn "Ow!" putStrLn "Ow!"
itemContextPopup do
text "pop!"
button "ok" >>= \clicked ->
when clicked $
closeCurrentPopup
-- Show the ImGui demo window newLine
showDemoWindow
mkTable tableRef
-- Render -- Render
glClear GL_COLOR_BUFFER_BIT glClear GL_COLOR_BUFFER_BIT
@ -79,4 +101,41 @@ mainLoop win = do
GLFW.swapBuffers win GLFW.swapBuffers win
mainLoop win mainLoop win tableRef
mkTable :: IORef [(Integer, Text)] -> IO ()
mkTable tableRef =
withTableOpen sortable "MyTable" 3 $ do
tableSetupColumn "Hello"
tableSetupColumnWith defTableColumnOptions "World"
withSortableTable \isDirty sortSpecs ->
when (isDirty && not (null sortSpecs)) do
-- XXX: do your sorting & cache it. Dont sort every frame.
putStrLn "So dirty!"
print sortSpecs
modifyIORef' tableRef . sortBy $
foldMap mkCompare sortSpecs
tableHeadersRow
readIORef tableRef >>=
traverse_ \(ix, title) -> do
tableNextRow
tableNextColumn $ text (pack $ show ix)
tableNextColumn $ text title
tableNextColumn $ void (button "")
where
mkCompare TableSortingSpecs{..} a b =
let
dir = if tableSortingReverse then flip else id
in
case tableSortingColumn of
0 -> dir compare (fst a) (fst b)
1 -> dir compare (snd a) (snd b)
_ -> EQ
sortable = defTableOptions
{ tableFlags =
ImGuiTableFlags_Sortable .|.
ImGuiTableFlags_SortMulti
}

View File

@ -190,9 +190,9 @@ initialiseVulkanContext instanceType appName ( VulkanRequirements { instanceRequ
device <- logDebug "Creating logical device" *> device <- logDebug "Creating logical device" *>
Vulkan.Utils.createDeviceFromRequirements swapchainDeviceRequirements [] physicalDevice deviceCreateInfo Vulkan.Utils.createDeviceFromRequirements swapchainDeviceRequirements [] physicalDevice deviceCreateInfo
queue <- Vulkan.getDeviceQueue device ( fromIntegral queueFamily ) 0 queue <- Vulkan.getDeviceQueue device ( fromIntegral queueFamily ) 0
pure ( VulkanContext { .. } ) pure ( VulkanContext { .. } )
vulkanInstanceInfo vulkanInstanceInfo
@ -206,7 +206,7 @@ vulkanInstanceInfo appName = do
let let
validationLayer :: Maybe ValidationLayerName validationLayer :: Maybe ValidationLayerName
validationLayer validationLayer
= coerce = coerce
. foldMap . foldMap
( ( Vulkan.layerName :: Vulkan.LayerProperties -> ByteString ) ( ( Vulkan.layerName :: Vulkan.LayerProperties -> ByteString )
>>> \case >>> \case
@ -374,11 +374,10 @@ chooseSwapchainFormat
case sortOn ( Down . score ) ( Boxed.Vector.toList surfaceFormats ) of case sortOn ( Down . score ) ( Boxed.Vector.toList surfaceFormats ) of
[] -> error "No formats found." [] -> error "No formats found."
( best : _ ) Vulkan.SurfaceFormatKHR{format=Vulkan.FORMAT_UNDEFINED} : _rest ->
| Vulkan.FORMAT_UNDEFINED <- ( Vulkan.format :: Vulkan.SurfaceFormatKHR -> Vulkan.Format ) best pure preferredFormat
-> pure preferredFormat best : _rest
| otherwise -> pure best
-> pure best
where where
match :: Eq a => a -> a -> Int match :: Eq a => a -> a -> Int
@ -406,20 +405,17 @@ createSwapchain physicalDevice device surface surfaceFormat imageUsage imageCoun
surfaceCapabilities <- Vulkan.getPhysicalDeviceSurfaceCapabilitiesKHR physicalDevice ( Vulkan.SurfaceKHR surface ) surfaceCapabilities <- Vulkan.getPhysicalDeviceSurfaceCapabilitiesKHR physicalDevice ( Vulkan.SurfaceKHR surface )
( _, presentModes ) <- Vulkan.getPhysicalDeviceSurfacePresentModesKHR physicalDevice ( Vulkan.SurfaceKHR surface ) ( _, presentModes ) <- Vulkan.getPhysicalDeviceSurfacePresentModesKHR physicalDevice ( Vulkan.SurfaceKHR surface )
let let
presentMode :: Vulkan.PresentModeKHR presentMode :: Vulkan.PresentModeKHR
presentMode presentMode
| Vulkan.PRESENT_MODE_MAILBOX_KHR `elem` presentModes | Vulkan.PRESENT_MODE_MAILBOX_KHR `elem` presentModes
= Vulkan.PRESENT_MODE_MAILBOX_KHR = Vulkan.PRESENT_MODE_MAILBOX_KHR
| otherwise | otherwise
= Vulkan.PRESENT_MODE_FIFO_KHR = Vulkan.PRESENT_MODE_FIFO_KHR
currentExtent :: Vulkan.Extent2D Vulkan.SurfaceCapabilitiesKHR{currentExtent, currentTransform} = surfaceCapabilities
currentExtent = ( Vulkan.currentExtent :: Vulkan.SurfaceCapabilitiesKHR -> Vulkan.Extent2D ) surfaceCapabilities Vulkan.SurfaceFormatKHR{format=fmt, colorSpace=csp} = surfaceFormat
currentTransform :: Vulkan.SurfaceTransformFlagBitsKHR
currentTransform = ( Vulkan.currentTransform :: Vulkan.SurfaceCapabilitiesKHR -> Vulkan.SurfaceTransformFlagBitsKHR ) surfaceCapabilities
swapchainCreateInfo :: Vulkan.SwapchainCreateInfoKHR '[] swapchainCreateInfo :: Vulkan.SwapchainCreateInfoKHR '[]
swapchainCreateInfo = swapchainCreateInfo =
@ -428,8 +424,8 @@ createSwapchain physicalDevice device surface surfaceFormat imageUsage imageCoun
, Vulkan.flags = Vulkan.zero , Vulkan.flags = Vulkan.zero
, Vulkan.surface = Vulkan.SurfaceKHR surface , Vulkan.surface = Vulkan.SurfaceKHR surface
, Vulkan.minImageCount = imageCount , Vulkan.minImageCount = imageCount
, Vulkan.imageFormat = ( Vulkan.format :: Vulkan.SurfaceFormatKHR -> Vulkan.Format ) surfaceFormat , Vulkan.imageFormat = fmt
, Vulkan.imageColorSpace = ( Vulkan.colorSpace :: Vulkan.SurfaceFormatKHR -> Vulkan.ColorSpaceKHR ) surfaceFormat , Vulkan.imageColorSpace = csp
, Vulkan.imageExtent = currentExtent , Vulkan.imageExtent = currentExtent
, Vulkan.imageArrayLayers = 1 , Vulkan.imageArrayLayers = 1
, Vulkan.imageUsage = imageUsage , Vulkan.imageUsage = imageUsage
@ -494,7 +490,7 @@ simpleRenderPass dev attachments = Vulkan.withRenderPass dev createInfo Nothing
{ Vulkan.next = () { Vulkan.next = ()
, Vulkan.flags = Vulkan.zero , Vulkan.flags = Vulkan.zero
, Vulkan.attachments = Boxed.Vector.fromList attachmentDescriptions , Vulkan.attachments = Boxed.Vector.fromList attachmentDescriptions
, Vulkan.subpasses = Boxed.Vector.singleton subpass , Vulkan.subpasses = Boxed.Vector.singleton subpass
, Vulkan.dependencies = Boxed.Vector.fromList [ dependency1, dependency2 ] , Vulkan.dependencies = Boxed.Vector.fromList [ dependency1, dependency2 ]
} }
@ -591,7 +587,7 @@ createFramebuffer
-> Vulkan.Extent2D -> Vulkan.Extent2D
-> f Vulkan.ImageView -> f Vulkan.ImageView
-> m ( ResourceT.ReleaseKey, Vulkan.Framebuffer ) -> m ( ResourceT.ReleaseKey, Vulkan.Framebuffer )
createFramebuffer dev renderPass extent attachments = Vulkan.withFramebuffer dev createInfo Nothing ResourceT.allocate createFramebuffer dev renderPass Vulkan.Extent2D{width, height} attachments = Vulkan.withFramebuffer dev createInfo Nothing ResourceT.allocate
where where
createInfo :: Vulkan.FramebufferCreateInfo '[] createInfo :: Vulkan.FramebufferCreateInfo '[]
createInfo = createInfo =
@ -600,8 +596,8 @@ createFramebuffer dev renderPass extent attachments = Vulkan.withFramebuffer dev
, Vulkan.flags = Vulkan.zero , Vulkan.flags = Vulkan.zero
, Vulkan.renderPass = renderPass , Vulkan.renderPass = renderPass
, Vulkan.attachments = Boxed.Vector.fromList . toList $ attachments , Vulkan.attachments = Boxed.Vector.fromList . toList $ attachments
, Vulkan.width = ( Vulkan.width :: Vulkan.Extent2D -> Word32 ) extent , Vulkan.width = width
, Vulkan.height = ( Vulkan.height :: Vulkan.Extent2D -> Word32 ) extent , Vulkan.height = height
, Vulkan.layers = 1 , Vulkan.layers = 1
} }

View File

@ -24,7 +24,9 @@ import Control.Arrow
import Control.Exception import Control.Exception
( throw ) ( throw )
import Control.Monad import Control.Monad
( unless, void ) ( unless, void, when )
import Data.Bits
( (.|.) )
import Data.Foldable import Data.Foldable
( traverse_ ) ( traverse_ )
import Data.String import Data.String
@ -62,11 +64,13 @@ import qualified Data.Vector as Boxed
( Vector ) ( Vector )
import qualified Data.Vector as Boxed.Vector import qualified Data.Vector as Boxed.Vector
( (!), head, singleton, unzip ) ( (!), head, singleton, unzip )
import qualified Data.Vector.Storable as Storable.Vector
-- vulkan -- vulkan
import qualified Vulkan import qualified Vulkan
import qualified Vulkan.Exception as Vulkan import qualified Vulkan.Exception as Vulkan
import qualified Vulkan.Zero as Vulkan import qualified Vulkan.Zero as Vulkan
import qualified VulkanMemoryAllocator as VMA
-- dear-imgui -- dear-imgui
import Attachments import Attachments
@ -76,6 +80,13 @@ import qualified DearImGui as ImGui
import qualified DearImGui.Vulkan as ImGui.Vulkan import qualified DearImGui.Vulkan as ImGui.Vulkan
import qualified DearImGui.SDL as ImGui.SDL import qualified DearImGui.SDL as ImGui.SDL
import qualified DearImGui.SDL.Vulkan as ImGui.SDL.Vulkan import qualified DearImGui.SDL.Vulkan as ImGui.SDL.Vulkan
import Util (vmaVulkanFunctions)
import Foreign (Ptr, castPtr, copyBytes, with, withForeignPtr, wordPtrToPtr)
import qualified DearImGui.Raw as ImGui.Raw
import UnliftIO (MonadUnliftIO)
import qualified Vulkan.CStruct.Extends as Vulkan
import qualified Codec.Picture as Picture
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -83,8 +94,8 @@ type Handler = LogMessage -> ResourceT IO ()
deriving via ( ReaderT Handler (ResourceT IO) ) deriving via ( ReaderT Handler (ResourceT IO) )
instance MonadResource ( LoggingT LogMessage (ResourceT IO) ) instance MonadResource ( LoggingT LogMessage (ResourceT IO) )
gui :: MonadIO m => m ImGui.DrawData gui :: MonadUnliftIO m => (ImGui.Raw.ImVec2, Ptr ()) -> m ImGui.DrawData
gui = do gui texture = do
-- Prepare frame -- Prepare frame
ImGui.Vulkan.vulkanNewFrame ImGui.Vulkan.vulkanNewFrame
ImGui.SDL.sdl2NewFrame ImGui.SDL.sdl2NewFrame
@ -92,6 +103,25 @@ gui = do
-- Run your windows -- Run your windows
ImGui.showDemoWindow ImGui.showDemoWindow
ImGui.withWindowOpen "Vulkan demo" do
clicked <- liftIO do
with (fst texture) \sizePtr ->
with (ImGui.Raw.ImVec2 0 0) \uv0Ptr ->
with (ImGui.Raw.ImVec2 1 1) \uv1Ptr ->
with (ImGui.Raw.ImVec4 1 1 1 1) \tintColPtr ->
with (ImGui.Raw.ImVec4 1 1 1 1) \bgColPtr ->
ImGui.Raw.imageButton
(snd texture)
sizePtr
uv0Ptr
uv1Ptr
(-1)
bgColPtr
tintColPtr
when clicked $
ImGui.text "clicky click!"
-- Process ImGui state into draw commands -- Process ImGui state into draw commands
ImGui.render ImGui.render
@ -171,9 +201,7 @@ app = do
surfaceCapabilities <- Vulkan.getPhysicalDeviceSurfaceCapabilitiesKHR physicalDevice ( Vulkan.SurfaceKHR surface ) surfaceCapabilities <- Vulkan.getPhysicalDeviceSurfaceCapabilitiesKHR physicalDevice ( Vulkan.SurfaceKHR surface )
let let
minImageCount, maxImageCount, imageCount :: Word32 Vulkan.SurfaceCapabilitiesKHR{minImageCount, maxImageCount} = surfaceCapabilities
minImageCount = ( Vulkan.minImageCount :: Vulkan.SurfaceCapabilitiesKHR -> Word32 ) surfaceCapabilities
maxImageCount = ( Vulkan.maxImageCount :: Vulkan.SurfaceCapabilitiesKHR -> Word32 ) surfaceCapabilities
imageCount imageCount
| maxImageCount == 0 = minImageCount + 1 | maxImageCount == 0 = minImageCount + 1
| otherwise = ( minImageCount + 1 ) `min` maxImageCount | otherwise = ( minImageCount + 1 ) `min` maxImageCount
@ -183,31 +211,30 @@ app = do
swapchainResources :: Maybe SwapchainResources -> m ( m (), SwapchainResources ) swapchainResources :: Maybe SwapchainResources -> m ( m (), SwapchainResources )
swapchainResources mbOldResources = do swapchainResources mbOldResources = do
( surfaceFormat, imGuiRenderPass ) <- case mbOldResources of ( colFmt, surfaceFormat, imGuiRenderPass ) <- case mbOldResources of
Nothing -> do Nothing -> do
logDebug "Choosing swapchain format & color space" logDebug "Choosing swapchain format & color space"
surfaceFormat <- chooseSwapchainFormat preferredFormat physicalDevice surface surfaceFormat <- chooseSwapchainFormat preferredFormat physicalDevice surface
let let Vulkan.SurfaceFormatKHR{format=colFmt} = surfaceFormat
colFmt :: Vulkan.Format
colFmt = ( Vulkan.format :: Vulkan.SurfaceFormatKHR -> Vulkan.Format ) surfaceFormat
logDebug "Creating Dear ImGui render pass" logDebug "Creating Dear ImGui render pass"
( _, imGuiRenderPass ) <- ( _, imGuiRenderPass ) <-
simpleRenderPass device simpleRenderPass device
( noAttachments ( noAttachments
{ colorAttachments = Boxed.Vector.singleton $ presentableColorAttachmentDescription colFmt } { colorAttachments = Boxed.Vector.singleton $ presentableColorAttachmentDescription colFmt }
) )
pure ( surfaceFormat, imGuiRenderPass ) pure ( colFmt, surfaceFormat, imGuiRenderPass )
Just oldResources -> pure ( surfaceFormat oldResources, imGuiRenderPass oldResources ) Just oldResources -> do
let surFmt = surfaceFormat oldResources
let let Vulkan.SurfaceFormatKHR{format=colFmt} = surFmt
colFmt :: Vulkan.Format pure ( colFmt, surFmt, imGuiRenderPass oldResources )
colFmt = ( Vulkan.format :: Vulkan.SurfaceFormatKHR -> Vulkan.Format ) surfaceFormat
logDebug "Creating swapchain" logDebug "Creating swapchain"
( swapchainKey, swapchain, swapchainExtent ) <- ( swapchainKey, swapchain, swapchainExtent ) <-
createSwapchain createSwapchain
physicalDevice device physicalDevice
surface surfaceFormat device
surface
surfaceFormat
surfaceUsage surfaceUsage
imageCount imageCount
( swapchain <$> mbOldResources ) ( swapchain <$> mbOldResources )
@ -275,6 +302,80 @@ app = do
logDebug "Allocating command buffers" logDebug "Allocating command buffers"
commandBuffers <- snd <$> allocatePrimaryCommandBuffers device commandPool imageCount commandBuffers <- snd <$> allocatePrimaryCommandBuffers device commandPool imageCount
logDebug "Allocating VMA"
(_key, vma) <- VMA.withAllocator
Vulkan.zero
{ VMA.instance' = Vulkan.instanceHandle instance'
, VMA.device = Vulkan.deviceHandle device
, VMA.physicalDevice = Vulkan.physicalDeviceHandle physicalDevice
, VMA.vulkanFunctions = Just $ vmaVulkanFunctions device instance'
}
ResourceT.allocate
logDebug "Loading image data"
picture <- liftIO (Picture.readImage "Example.png") >>= either error (pure . Picture.convertRGBA8)
logDebug "Allocating image"
let textureWidth = Picture.imageWidth picture
let textureHeight = Picture.imageHeight picture
(_key, (image, _imageAllocation, _imageAllocationInfo)) <- VMA.withImage
vma
( Vulkan.zero
{ Vulkan.imageType = Vulkan.IMAGE_TYPE_2D
, Vulkan.mipLevels = 1
, Vulkan.arrayLayers = 1
, Vulkan.format = Vulkan.FORMAT_R8G8B8A8_SRGB
, Vulkan.extent = Vulkan.Extent3D (fromIntegral textureWidth) (fromIntegral textureHeight) 1
, Vulkan.tiling = Vulkan.IMAGE_TILING_OPTIMAL
, Vulkan.initialLayout = Vulkan.IMAGE_LAYOUT_UNDEFINED
, Vulkan.usage = Vulkan.IMAGE_USAGE_SAMPLED_BIT .|. Vulkan.IMAGE_USAGE_TRANSFER_DST_BIT
, Vulkan.sharingMode = Vulkan.SHARING_MODE_EXCLUSIVE
, Vulkan.samples = Vulkan.SAMPLE_COUNT_1_BIT
}
)
( Vulkan.zero
{ VMA.flags = Vulkan.zero
, VMA.usage = VMA.MEMORY_USAGE_GPU_ONLY
, VMA.requiredFlags = Vulkan.MEMORY_PROPERTY_DEVICE_LOCAL_BIT
}
)
ResourceT.allocate
let (pictureF, pictureSize) = Storable.Vector.unsafeToForeignPtr0 (Picture.imageData picture)
let stageBufferCI = Vulkan.zero
{ Vulkan.size = fromIntegral pictureSize
, Vulkan.usage = Vulkan.BUFFER_USAGE_TRANSFER_SRC_BIT
, Vulkan.sharingMode = Vulkan.SHARING_MODE_EXCLUSIVE
}
let stageAllocationCI = Vulkan.zero
{ VMA.flags = VMA.ALLOCATION_CREATE_MAPPED_BIT
, VMA.usage = VMA.MEMORY_USAGE_CPU_TO_GPU
, VMA.requiredFlags = Vulkan.MEMORY_PROPERTY_HOST_VISIBLE_BIT
}
(stageKey, (stage, stageAllocation, stageAllocationInfo)) <- VMA.withBuffer
vma
stageBufferCI
stageAllocationCI
ResourceT.allocate
liftIO $ withForeignPtr pictureF \srcPtr ->
copyBytes (VMA.mappedData stageAllocationInfo) (castPtr srcPtr) pictureSize
VMA.flushAllocation vma stageAllocation 0 Vulkan.WHOLE_SIZE
logDebug "Allocating sampler"
(_key, sampler) <- Vulkan.withSampler device Vulkan.zero Nothing ResourceT.allocate
logDebug "Allocating image view"
(_key, imageView) <- createImageView
device
image
Vulkan.IMAGE_VIEW_TYPE_2D
Vulkan.FORMAT_R8G8B8A8_SRGB
Vulkan.IMAGE_ASPECT_COLOR_BIT
------------------------------------------- -------------------------------------------
-- Initialise Dear ImGui. -- Initialise Dear ImGui.
@ -308,23 +409,96 @@ app = do
logDebug "Creating fence" logDebug "Creating fence"
( fenceKey, fence ) <- createFence device ( fenceKey, fence ) <- createFence device
logDebug "Allocating one-shot command buffer" logDebug "Allocating one-shot command buffer"
( fontUploadCommandBufferKey, fontUploadCommandBuffer ) <- ( oneshotCommandBufferKey, oneshotCommandBuffer ) <-
second Boxed.Vector.head <$> second Boxed.Vector.head <$>
allocatePrimaryCommandBuffers device commandPool 1 allocatePrimaryCommandBuffers device commandPool 1
logDebug "Recording one-shot commands" logDebug "Recording one-shot commands"
beginCommandBuffer fontUploadCommandBuffer beginCommandBuffer oneshotCommandBuffer
_ <- ImGui.Vulkan.vulkanCreateFontsTexture fontUploadCommandBuffer _ <- ImGui.Vulkan.vulkanCreateFontsTexture oneshotCommandBuffer
endCommandBuffer fontUploadCommandBuffer
logDebug "Uploading texture"
let textureSubresource = Vulkan.ImageSubresourceRange
{ Vulkan.aspectMask = Vulkan.IMAGE_ASPECT_COLOR_BIT
, Vulkan.baseMipLevel = 0
, Vulkan.levelCount = 1
, Vulkan.baseArrayLayer = 0
, Vulkan.layerCount = 1
}
let uploadBarrier = Vulkan.zero
{ Vulkan.srcAccessMask = Vulkan.zero
, Vulkan.dstAccessMask = Vulkan.ACCESS_TRANSFER_WRITE_BIT
, Vulkan.oldLayout = Vulkan.IMAGE_LAYOUT_UNDEFINED
, Vulkan.newLayout = Vulkan.IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
, Vulkan.srcQueueFamilyIndex = Vulkan.QUEUE_FAMILY_IGNORED
, Vulkan.dstQueueFamilyIndex = Vulkan.QUEUE_FAMILY_IGNORED
, Vulkan.image = image
, Vulkan.subresourceRange = textureSubresource
} :: Vulkan.ImageMemoryBarrier '[]
Vulkan.cmdPipelineBarrier
oneshotCommandBuffer
Vulkan.PIPELINE_STAGE_TOP_OF_PIPE_BIT
Vulkan.PIPELINE_STAGE_TRANSFER_BIT
Vulkan.zero
mempty
mempty
(Boxed.Vector.singleton $ Vulkan.SomeStruct uploadBarrier)
Vulkan.cmdCopyBufferToImage oneshotCommandBuffer stage image Vulkan.IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL $
Boxed.Vector.singleton Vulkan.BufferImageCopy
{ Vulkan.bufferOffset = 0
, Vulkan.bufferRowLength = Vulkan.zero
, Vulkan.bufferImageHeight = Vulkan.zero
, Vulkan.imageSubresource = Vulkan.ImageSubresourceLayers
{ aspectMask = Vulkan.IMAGE_ASPECT_COLOR_BIT
, mipLevel = 0
, baseArrayLayer = 0
, layerCount = 1
}
, Vulkan.imageOffset = Vulkan.zero
, Vulkan.imageExtent = Vulkan.Extent3D
{ width = fromIntegral textureWidth
, height = fromIntegral textureHeight
, depth = 1
}
}
logDebug "Transitioning texture"
let transitionBarrier = Vulkan.zero
{ Vulkan.srcAccessMask = Vulkan.ACCESS_TRANSFER_WRITE_BIT
, Vulkan.dstAccessMask = Vulkan.ACCESS_SHADER_READ_BIT
, Vulkan.oldLayout = Vulkan.IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
, Vulkan.newLayout = Vulkan.IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
, Vulkan.srcQueueFamilyIndex = Vulkan.QUEUE_FAMILY_IGNORED
, Vulkan.dstQueueFamilyIndex = Vulkan.QUEUE_FAMILY_IGNORED
, Vulkan.image = image
, Vulkan.subresourceRange = textureSubresource
} :: Vulkan.ImageMemoryBarrier '[]
Vulkan.cmdPipelineBarrier
oneshotCommandBuffer
Vulkan.PIPELINE_STAGE_TRANSFER_BIT
Vulkan.PIPELINE_STAGE_FRAGMENT_SHADER_BIT
Vulkan.zero
mempty
mempty
(Boxed.Vector.singleton $ Vulkan.SomeStruct transitionBarrier)
endCommandBuffer oneshotCommandBuffer
logDebug "Submitting one-shot commands" logDebug "Submitting one-shot commands"
submitCommandBuffer queue fontUploadCommandBuffer [] [] ( Just fence ) submitCommandBuffer queue oneshotCommandBuffer [] [] ( Just fence )
waitForFences device ( WaitAll [ fence ] ) waitForFences device ( WaitAll [ fence ] )
logDebug "Finished uploading font objects" logDebug "Finished uploading font objects"
logDebug "Cleaning up one-shot commands" logDebug "Cleaning up one-shot commands"
ImGui.Vulkan.vulkanDestroyFontUploadObjects ImGui.Vulkan.vulkanDestroyFontUploadObjects
traverse_ ResourceT.release [ fenceKey, fontUploadCommandBufferKey ] traverse_ ResourceT.release [ fenceKey, oneshotCommandBufferKey, stageKey ]
logDebug "Adding imgui texture"
Vulkan.DescriptorSet ds <- ImGui.Vulkan.vulkanAddTexture sampler imageView Vulkan.IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
let textureSize = ImGui.Raw.ImVec2 (fromIntegral textureWidth) (fromIntegral textureHeight)
let texture = (textureSize, wordPtrToPtr $ fromIntegral ds)
let let
mainLoop :: AppState m -> m () mainLoop :: AppState m -> m ()
@ -364,7 +538,7 @@ app = do
beginCommandBuffer commandBuffer beginCommandBuffer commandBuffer
cmdBeginRenderPass commandBuffer imGuiRenderPass framebuffer clearValues swapchainExtent cmdBeginRenderPass commandBuffer imGuiRenderPass framebuffer clearValues swapchainExtent
drawData <- gui drawData <- gui texture
ImGui.Vulkan.vulkanRenderDrawData drawData commandBuffer Nothing ImGui.Vulkan.vulkanRenderDrawData drawData commandBuffer Nothing
cmdEndRenderPass commandBuffer cmdEndRenderPass commandBuffer

View File

@ -1,4 +1,7 @@
{-# LANGUAGE BlockArguments #-} {-# LANGUAGE BlockArguments #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
module Util where module Util where
@ -12,6 +15,10 @@ import Data.Functor.Identity
( Identity(..) ) ( Identity(..) )
import Data.Traversable import Data.Traversable
( for ) ( for )
#if MIN_VERSION_VulkanMemoryAllocator(0,8,0)
import Foreign
( castFunPtr )
#endif
-- transformers -- transformers
import Control.Monad.Trans.State.Strict import Control.Monad.Trans.State.Strict
@ -19,6 +26,16 @@ import Control.Monad.Trans.State.Strict
import Control.Monad.Trans.Writer.Strict import Control.Monad.Trans.Writer.Strict
( runWriter, tell ) ( runWriter, tell )
-- vulkan
import qualified Vulkan
#if MIN_VERSION_VulkanMemoryAllocator(0,8,0)
import qualified Vulkan.Dynamic as VkDynamic
#endif
import Vulkan.Zero (zero)
-- VulkanMemoryAllocator
import qualified VulkanMemoryAllocator as VMA
--------------------------------------------------------------- ---------------------------------------------------------------
iunzipWith iunzipWith
@ -38,3 +55,19 @@ ifor i0 upd ta f = (`evalState` i0) . getCompose $ result
where where
result :: Compose (State i) f (t b) result :: Compose (State i) f (t b)
result = for ta \ a -> ( coerce ( \ i -> ( f i a, upd i ) ) ) result = for ta \ a -> ( coerce ( \ i -> ( f i a, upd i ) ) )
vmaVulkanFunctions
:: Vulkan.Device
-> Vulkan.Instance
-> VMA.VulkanFunctions
#if MIN_VERSION_VulkanMemoryAllocator(0,8,0)
vmaVulkanFunctions Vulkan.Device{deviceCmds} Vulkan.Instance{instanceCmds} =
zero
{ VMA.vkGetInstanceProcAddr =
castFunPtr $ VkDynamic.pVkGetInstanceProcAddr instanceCmds
, VMA.vkGetDeviceProcAddr =
castFunPtr $ VkDynamic.pVkGetDeviceProcAddr deviceCmds
}
#else
vmaVulkanFunctions _device _instance = zero
#endif

View File

@ -24,6 +24,10 @@ import Data.Traversable
( for ) ( for )
import Foreign.Storable import Foreign.Storable
( Storable ) ( Storable )
#if MIN_VERSION_template_haskell(2,18,0)
import Data.Coerce
( coerce )
#endif
-- containers -- containers
import Data.Map.Strict import Data.Map.Strict
@ -171,7 +175,7 @@ declareEnumeration finiteEnumName countName ( Enumeration {..} ) = do
else else
\ nm args dir pat -> \ nm args dir pat ->
TH.patSynD_doc nm args dir pat TH.patSynD_doc nm args dir pat
( Just $ Text.unpack patDoc ) [] ( Just $ Text.unpack _patDoc ) []
) )
#else #else
TH.patSynD TH.patSynD

View File

@ -146,6 +146,8 @@ headers = do
_ <- skipManyTill anySingle ( namedSection "Viewports" ) _ <- skipManyTill anySingle ( namedSection "Viewports" )
_ <- skipManyTill anySingle ( namedSection "Platform Dependent Interfaces" ) -- XXX: since 1.87
_ <- skipManyTill anySingle ( namedSection "Obsolete functions and types" ) _ <- skipManyTill anySingle ( namedSection "Obsolete functions and types" )
let let
@ -254,13 +256,21 @@ patternNameAndValue enumName =
where where
count :: StateT EnumState m Integer count :: StateT EnumState m Integer
count = do count = do
_ <- single ( Identifier $ enumName <> "COUNT" ) let idName = enumName <> "COUNT"
_ <- single ( Identifier idName )
mbVal <- optional do mbVal <- optional do
_ <- reservedSymbol '=' _ <- reservedSymbol '='
integerExpression EnumState{enumValues} <- get
case mbVal of integerExpression enumValues
countVal <- case mbVal of
Nothing -> currEnumTag <$> get Nothing -> currEnumTag <$> get
Just ct -> pure ct Just ct -> pure ct
modify' ( \ st -> st { enumValues = HashMap.insert idName countVal ( enumValues st ) } )
pure countVal
value :: StateT EnumState m ( Text, Integer ) value :: StateT EnumState m ( Text, Integer )
value = do value = do
name <- identifier name <- identifier
@ -271,13 +281,16 @@ patternNameAndValue enumName =
patternRHS = patternRHS =
( do ( do
reservedSymbol '=' reservedSymbol '='
try integerExpression <|> try disjunction EnumState{enumValues} <- get
try disjunction <|> try (integerExpression enumValues)
) )
<|> ( currEnumTag <$> get ) <|> ( currEnumTag <$> get )
disjunction :: StateT EnumState m Integer disjunction :: StateT EnumState m Integer
disjunction = do disjunction = do
( summands :: [Text] ) <- identifier `sepBy1` symbol "|" initial <- identifier <* symbol "|"
( rest :: [Text] ) <- identifier `sepBy1` symbol "|"
let summands = initial : rest
valsMap <- enumValues <$> get valsMap <- enumValues <$> get
let let
res :: Either [ Text ] Integer res :: Either [ Text ] Integer
@ -327,34 +340,53 @@ symbol :: MonadParsec e [ Tok ] m => Text -> m ()
symbol s = token ( \ case { Symbolic s' | s == s' -> Just (); _ -> Nothing } ) mempty symbol s = token ( \ case { Symbolic s' | s == s' -> Just (); _ -> Nothing } ) mempty
<?> ( Text.unpack s <> " (symbol)" ) <?> ( Text.unpack s <> " (symbol)" )
integerExpression :: MonadParsec e [ Tok ] m => m Integer integerExpression :: MonadParsec e [ Tok ] m => HashMap Text Integer -> m Integer
integerExpression = try integerPower <|> integer integerExpression enums = try integerPower <|> try integerAdd <|> try integerSub <|> integer
integerPower :: MonadParsec e [ Tok ] m => m Integer
integerPower = do
a <- integer
_ <- symbol "<<"
i <- integer
pure ( a `shiftL` fromIntegral i )
integer :: forall e m. MonadParsec e [ Tok ] m => m Integer
integer =
option id mkSign <*>
token
( \ case {
Number i suff
| Just _ <- toBoundedInteger @Int64 i
, Right i' <- floatingOrInteger @Float @Integer i
, not ( Text.any ( (== 'f' ) . toLower ) suff )
-> Just i';
_ -> Nothing
}
)
mempty
<?> "integer"
where where
mkSign :: m ( Integer -> Integer ) integerPower :: MonadParsec e [ Tok ] m => m Integer
mkSign = ( symbol "+" $> id ) <|> ( symbol "-" $> negate ) integerPower = do
a <- integer
_ <- symbol "<<"
i <- integer
pure ( a `shiftL` fromIntegral i )
integerAdd :: MonadParsec e [ Tok ] m => m Integer
integerAdd = do
a <- integer
_ <- symbol "+"
i <- integer
pure ( a + i )
integerSub :: MonadParsec e [ Tok ] m => m Integer
integerSub = do
a <- integer
_ <- symbol "-"
i <- integer
pure ( a - i )
integer :: forall e m. MonadParsec e [ Tok ] m => m Integer
integer =
option id mkSign <*>
token
( \case
Number i suff
| Just _ <- toBoundedInteger @Int64 i
, Right i' <- floatingOrInteger @Float @Integer i
, not ( Text.any ( (== 'f' ) . toLower ) suff )
->
Just i'
Identifier name ->
HashMap.lookup name enums
_ ->
Nothing
)
mempty
<?> "integer"
where
mkSign :: m ( Integer -> Integer )
mkSign = ( symbol "+" $> id ) <|> ( symbol "-" $> negate )
section :: MonadParsec e [ Tok ] m => m [Text] section :: MonadParsec e [ Tok ] m => m [Text]
section = section =

2
imgui

Submodule imgui updated: 512c54bbc0...9aae45eb4a

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,7 @@ imguiContext = mempty
, ( TypeName "ImVec3", [t| ImVec3 |] ) , ( TypeName "ImVec3", [t| ImVec3 |] )
, ( TypeName "ImVec4", [t| ImVec4 |] ) , ( TypeName "ImVec4", [t| ImVec4 |] )
, ( TypeName "ImU32", [t| ImU32 |] ) , ( TypeName "ImU32", [t| ImU32 |] )
, ( TypeName "ImGuiID", [t| ImGuiID |] )
, ( TypeName "ImWchar", [t| ImWchar |] ) , ( TypeName "ImWchar", [t| ImWchar |] )
, ( TypeName "ImDrawList", [t| ImDrawList |] ) , ( TypeName "ImDrawList", [t| ImDrawList |] )
, ( TypeName "ImGuiContext", [t| ImGuiContext |] ) , ( TypeName "ImGuiContext", [t| ImGuiContext |] )
@ -41,5 +42,6 @@ imguiContext = mempty
, ( TypeName "ImFontConfig", [t| ImFontConfig |] ) , ( TypeName "ImFontConfig", [t| ImFontConfig |] )
, ( TypeName "ImFontGlyphRangesBuilder", [t| ImFontGlyphRangesBuilder |] ) , ( TypeName "ImFontGlyphRangesBuilder", [t| ImFontGlyphRangesBuilder |] )
, ( TypeName "ImGuiListClipper", [t| ImGuiListClipper |] ) , ( TypeName "ImGuiListClipper", [t| ImGuiListClipper |] )
, ( TypeName "ImGuiTableSortSpecs", [t| ImGuiTableSortSpecs |] )
] ]
} }

View File

@ -119,6 +119,8 @@ import DearImGui.Raw.Font.Config (FontConfig(..))
import qualified DearImGui.Raw.Font.Config as FontConfig import qualified DearImGui.Raw.Font.Config as FontConfig
import DearImGui.Raw.Font.GlyphRanges (GlyphRanges(..), GlyphRangesBuilder(..)) import DearImGui.Raw.Font.GlyphRanges (GlyphRanges(..), GlyphRangesBuilder(..))
import qualified DearImGui.Raw.Font.GlyphRanges as GlyphRanges import qualified DearImGui.Raw.Font.GlyphRanges as GlyphRanges
import DearImGui.Internal.Text (Text)
import qualified DearImGui.Internal.Text as Text
import DearImGui.Structs (ImVec2(..), ImWchar) import DearImGui.Structs (ImVec2(..), ImWchar)
@ -332,10 +334,10 @@ addChar char =
GlyphRanges.addChar builder char GlyphRanges.addChar builder char
-- | UTF-8 string -- | UTF-8 string
addText :: String -> RangesBuilderSetup addText :: Text -> RangesBuilderSetup
addText str = addText str =
RangesBuilderSetup \builder -> RangesBuilderSetup \builder ->
withCString str (GlyphRanges.addText builder) Text.withCString str (GlyphRanges.addText builder)
-- | Existing ranges (as is) -- | Existing ranges (as is)
addRangesRaw :: GlyphRanges -> RangesBuilderSetup addRangesRaw :: GlyphRanges -> RangesBuilderSetup

View File

@ -23,6 +23,7 @@ module DearImGui.GLFW (
-- $callbacks -- $callbacks
, glfwWindowFocusCallback , glfwWindowFocusCallback
, glfwCursorEnterCallback , glfwCursorEnterCallback
, glfwCursorPosCallback
, glfwMouseButtonCallback , glfwMouseButtonCallback
, glfwScrollCallback , glfwScrollCallback
, glfwKeyCallback , glfwKeyCallback
@ -108,6 +109,20 @@ glfwCursorEnterCallback window entered = liftIO do
where where
windowPtr = castPtr $ unWindow window windowPtr = castPtr $ unWindow window
glfwCursorPosCallback :: MonadIO m => Window -> CDouble -> CDouble -> m ()
glfwCursorPosCallback window x y = liftIO do
[C.exp| void {
ImGui_ImplGlfw_CursorPosCallback(
static_cast<GLFWwindow *>(
$(void * windowPtr)
),
$(double x),
$(double y)
);
} |]
where
windowPtr = castPtr $ unWindow window
glfwMouseButtonCallback :: MonadIO m => Window -> CInt -> CInt -> CInt -> m () glfwMouseButtonCallback :: MonadIO m => Window -> CInt -> CInt -> CInt -> m ()
glfwMouseButtonCallback window button action mods = liftIO do glfwMouseButtonCallback window button action mods = liftIO do
[C.exp| void { [C.exp| void {

View File

@ -0,0 +1,72 @@
{-# LANGUAGE CPP #-}
module DearImGui.Internal.Text
( withCString
, withCStringOrNull
, withCStringLen
, withCStringEnd
, peekCString
, Text
, pack
, unpack
) where
-- base
import Control.Monad.IO.Class (liftIO)
import Foreign (nullPtr, plusPtr)
import Foreign.C.String (CString)
import qualified GHC.Foreign as Foreign
import System.IO (utf8)
-- text
import Data.Text (Text, pack, unpack)
import Data.Text.Foreign (withCStringLen)
-- unliftio-core
import UnliftIO (MonadUnliftIO, UnliftIO(..), withUnliftIO)
#if MIN_VERSION_text(2,0,0)
import Data.Text.Foreign (lengthWord8, unsafeCopyToPtr)
import Data.Word (Word8)
import Foreign (castPtr, free, mallocBytes, pokeByteOff)
import UnliftIO.Exception (bracket)
withCString :: MonadUnliftIO m => Text -> (CString -> m a) -> m a
withCString t = bracket create destroy
where
size0 = lengthWord8 t + 1
create = liftIO $ do
ptr <- mallocBytes size0
unsafeCopyToPtr t (castPtr ptr)
pokeByteOff ptr size0 (0 :: Word8)
pure ptr
destroy ptr =
liftIO $ free ptr
#else
withCString :: MonadUnliftIO m => Text -> (CString -> m a) -> m a
withCString t action = do
withUnliftIO $ \(UnliftIO unlift) ->
liftIO $
Foreign.withCString utf8 (unpack t) $ \textPtr ->
unlift $ action textPtr
#endif
peekCString :: CString -> IO Text
peekCString = fmap pack . Foreign.peekCString utf8
withCStringOrNull :: Maybe Text -> (CString -> IO a) -> IO a
withCStringOrNull Nothing k = k nullPtr
withCStringOrNull (Just s) k = withCString s k
withCStringEnd :: MonadUnliftIO m => Text -> (CString -> CString -> m a) -> m a
withCStringEnd t action =
withUnliftIO $ \(UnliftIO unlift) ->
withCStringLen t $ \(textPtr, size) ->
unlift $ action textPtr (textPtr `plusPtr` size)

View File

@ -6,6 +6,7 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE ViewPatterns #-}
@ -157,10 +158,34 @@ module DearImGui.Raw
, colorPicker3 , colorPicker3
, colorButton , colorButton
-- * Tables
, beginTable
, endTable
, tableNextRow
, tableNextColumn
, tableSetColumnIndex
, tableSetupColumn
, tableSetupScrollFreeze
, tableHeadersRow
, tableHeader
, tableGetSortSpecs
, tableClearSortSpecsDirty
, tableGetColumnCount
, tableGetColumnIndex
, tableGetRowIndex
, tableGetColumnName
, tableGetColumnFlags
, tableSetColumnEnabled
, tableSetBgColor
-- * Trees -- * Trees
, treeNode , treeNode
, treePush , treePush
, treePop , treePop
, setNextItemOpen
-- ** Selectables -- ** Selectables
, selectable , selectable
@ -169,6 +194,7 @@ module DearImGui.Raw
, listBox , listBox
-- * Data Plotting -- * Data Plotting
, plotLines
, plotHistogram , plotHistogram
-- ** Menus -- ** Menus
@ -197,7 +223,12 @@ module DearImGui.Raw
, beginPopupModal , beginPopupModal
, endPopup , endPopup
, openPopup , openPopup
, openPopupOnItemClick
, closeCurrentPopup , closeCurrentPopup
, beginPopupContextItem
, beginPopupContextWindow
, beginPopupContextVoid
, isPopupOpen
-- * ID stack/scopes -- * ID stack/scopes
, pushIDInt , pushIDInt
@ -1063,6 +1094,128 @@ colorButton descPtr refPtr = liftIO do
(0 /=) <$> [C.exp| bool { ColorButton( $(char* descPtr), *$(ImVec4* refPtr) ) } |] (0 /=) <$> [C.exp| bool { ColorButton( $(char* descPtr), *$(ImVec4* refPtr) ) } |]
-- | Wraps @ImGui::BeginTable()@.
beginTable :: MonadIO m => CString -> CInt -> ImGuiTableFlags -> Ptr ImVec2 -> CFloat -> m Bool
beginTable labelPtr column flags outerSizePtr innerWidth = liftIO do
(0 /=) <$> [C.exp| bool { BeginTable($(char* labelPtr), $(int column), $(ImGuiTableFlags flags), *$(ImVec2* outerSizePtr), $(float innerWidth)) } |]
-- | Only call 'endTable' if 'beginTable' returns true!
--
-- Wraps @ImGui::EndTable()@.
endTable :: MonadIO m => m ()
endTable = liftIO do
[C.exp| void { EndTable() } |]
-- | Wraps @ImGui::TableNextRow()@.
-- append into the first cell of a new row.
tableNextRow :: MonadIO m => ImGuiTableRowFlags -> CFloat -> m ()
tableNextRow flags minRowHeight = liftIO do
[C.exp| void { TableNextRow($(ImGuiTableRowFlags flags), $(float minRowHeight)) } |]
-- | Wraps @ImGui::TableNextColumn()@.
-- append into the next column (or first column of next row if currently in
-- last column). Return true when column is visible.
tableNextColumn :: MonadIO m => m Bool
tableNextColumn = liftIO do
(0 /=) <$> [C.exp| bool { TableNextColumn() } |]
-- | Wraps @ImGui::TableSetColumnIndex()@.
-- append into the specified column. Return true when column is visible.
tableSetColumnIndex :: MonadIO m => CInt -> m Bool
tableSetColumnIndex column= liftIO do
(0 /=) <$> [C.exp| bool { TableSetColumnIndex($(int column)) } |]
-- | Wraps @ImGui::TableSetupColumn()@.
tableSetupColumn :: MonadIO m => CString -> ImGuiTableColumnFlags -> CFloat -> ImGuiID-> m ()
tableSetupColumn labelPtr flags initWidthOrWeight userId = liftIO do
[C.exp| void { TableSetupColumn($(char* labelPtr), $(ImGuiTableColumnFlags flags), $(float initWidthOrWeight), $(ImGuiID userId)) } |]
-- | Wraps @ImGui::TableSetupScrollFreeze()@.
tableSetupScrollFreeze :: MonadIO m => CInt -> CInt -> m ()
tableSetupScrollFreeze cols rows = liftIO do
[C.exp| void { TableSetupScrollFreeze($(int cols), $(int rows)) } |]
-- | Wraps @ImGui::TableHeadersRow()@.
-- submit all headers cells based on data provided to 'tableSetupColumn'
-- + submit context menu
tableHeadersRow :: MonadIO m => m ()
tableHeadersRow = liftIO do
[C.exp| void { TableHeadersRow() } |]
-- | Wraps @ImGui::TableHeader()@.
-- submit one header cell manually (rarely used)
tableHeader :: MonadIO m => CString -> m ()
tableHeader labelPtr = liftIO do
[C.exp| void { TableHeader($(char* labelPtr)) } |]
-- | Wraps @ImGui::TableGetSortSpecs()@.
-- Low-level-Function. Better use the wrapper that outomatically conform
-- to the things described below
--
-- Tables: Sorting
-- - Call TableGetSortSpecs() to retrieve latest sort specs for the table.
-- NULL when not sorting.
-- - When 'SpecsDirty == true' you should sort your data. It will be true when
-- sorting specs have changed since last call, or the first time. Make sure
-- to set 'SpecsDirty = false' after sorting, else you may wastefully sort
-- your data every frame!
-- - Lifetime: don't hold on this pointer over multiple frames or past any
-- subsequent call to BeginTable().
tableGetSortSpecs :: MonadIO m => m (Maybe (Ptr ImGuiTableSortSpecs))
tableGetSortSpecs = liftIO do
ptr <- [C.exp| ImGuiTableSortSpecs* { TableGetSortSpecs() } |]
if ptr == nullPtr then
return Nothing
else
return $ Just ptr
tableClearSortSpecsDirty :: MonadIO m => Ptr ImGuiTableSortSpecs -> m ()
tableClearSortSpecsDirty specsPtr = liftIO do
[C.block| void {
$(ImGuiTableSortSpecs* specsPtr)->SpecsDirty = false;
} |]
-- | Wraps @ImGui::TableGetColumnCount()@.
tableGetColumnCount :: MonadIO m => m CInt
tableGetColumnCount = liftIO do
[C.exp| int { TableGetColumnCount() } |]
-- | Wraps @ImGui::TableGetColumnIndex()@.
tableGetColumnIndex :: MonadIO m => m CInt
tableGetColumnIndex = liftIO do
[C.exp| int { TableGetColumnIndex() } |]
-- | Wraps @ImGui::TableGetRowIndex()@.
tableGetRowIndex :: MonadIO m => m CInt
tableGetRowIndex = liftIO do
[C.exp| int { TableGetRowIndex() } |]
-- | Wraps @ImGui::TableGetColumnName
-- 'Nothing' returns the current column name
tableGetColumnName :: MonadIO m => Maybe CInt -> m CString
tableGetColumnName Nothing = tableGetColumnName (Just (-1))
tableGetColumnName (Just column_n) = liftIO do
[C.exp| const char* { TableGetColumnName($(int column_n)) } |]
-- | Wraps @ImGui::TableGetRowIndex()@.
-- 'Nothing' returns the current column flags
tableGetColumnFlags :: MonadIO m => Maybe CInt -> m ImGuiTableColumnFlags
tableGetColumnFlags Nothing = tableGetColumnFlags (Just (-1))
tableGetColumnFlags (Just column_n) = liftIO do
[C.exp| ImGuiTableColumnFlags { TableGetColumnFlags($(int column_n)) } |]
-- | Wraps @ImGui::TableSetColumnEnabled()@.
tableSetColumnEnabled :: MonadIO m => CInt -> CBool -> m ()
tableSetColumnEnabled column_n v = liftIO do
[C.exp| void { TableSetColumnEnabled($(int column_n), $(bool v)) } |]
-- | Wraps @ImGui::TableSetBgColor()@.
-- 'Nothing' sets the current row/column color
tableSetBgColor :: MonadIO m => ImGuiTableBgTarget -> ImU32 -> Maybe CInt -> m ()
tableSetBgColor target color Nothing = tableSetBgColor target color (Just (-1))
tableSetBgColor target color (Just column_n) = liftIO do
[C.exp| void { TableSetBgColor($(ImGuiTableBgTarget target), $(ImU32 color), $(int column_n)) } |]
-- | Wraps @ImGui::TreeNode()@. -- | Wraps @ImGui::TreeNode()@.
treeNode :: (MonadIO m) => CString -> m Bool treeNode :: (MonadIO m) => CString -> m Bool
treeNode labelPtr = liftIO do treeNode labelPtr = liftIO do
@ -1081,10 +1234,22 @@ treePop = liftIO do
[C.exp| void { TreePop() } |] [C.exp| void { TreePop() } |]
-- | Wraps @ImGui::SetNextItemOpen()@.
setNextItemOpen :: (MonadIO m) => CBool -> m ()
setNextItemOpen is_open = liftIO do
[C.exp| void { SetNextItemOpen($(bool is_open)) } |]
-- -- | Wraps @ImGui::Selectable()@.
-- selectable :: (MonadIO m) => CString -> m Bool
-- selectable labelPtr = liftIO do
-- (0 /=) <$> [C.exp| bool { Selectable($(char* labelPtr)) } |]
-- | Wraps @ImGui::Selectable()@. -- | Wraps @ImGui::Selectable()@.
selectable :: (MonadIO m) => CString -> m Bool selectable :: (MonadIO m) => CString -> CBool -> ImGuiSelectableFlags -> Ptr ImVec2 -> m Bool
selectable labelPtr = liftIO do selectable labelPtr selected flags size = liftIO do
(0 /=) <$> [C.exp| bool { Selectable($(char* labelPtr)) } |] (0 /=) <$> [C.exp| bool { Selectable($(char* labelPtr), $(bool selected), $(ImGuiSelectableFlags flags), *$(ImVec2 *size)) } |]
-- | Wraps @ImGui::ListBox()@. -- | Wraps @ImGui::ListBox()@.
@ -1092,6 +1257,10 @@ listBox :: (MonadIO m) => CString -> Ptr CInt -> Ptr CString -> CInt -> m Bool
listBox labelPtr iPtr itemsPtr itemsLen = liftIO do listBox labelPtr iPtr itemsPtr itemsLen = liftIO do
(0 /=) <$> [C.exp| bool { ListBox($(char* labelPtr), $(int* iPtr), $(char** itemsPtr), $(int itemsLen)) }|] (0 /=) <$> [C.exp| bool { ListBox($(char* labelPtr), $(int* iPtr), $(char** itemsPtr), $(int itemsLen)) }|]
-- | Wraps @ImGui::PlotLines()@.
plotLines :: (MonadIO m) => CString -> Ptr CFloat -> CInt -> m ()
plotLines labelPtr valuesPtr valuesLen = liftIO do
[C.exp| void { PlotLines($(char* labelPtr), $(float* valuesPtr), $(int valuesLen)) } |]
-- | Wraps @ImGui::PlotHistogram()@. -- | Wraps @ImGui::PlotHistogram()@.
plotHistogram :: (MonadIO m) => CString -> Ptr CFloat -> CInt -> m () plotHistogram :: (MonadIO m) => CString -> Ptr CFloat -> CInt -> m ()
@ -1253,6 +1422,16 @@ openPopup popupIdPtr = liftIO do
[C.exp| void { OpenPopup($(char* popupIdPtr)) } |] [C.exp| void { OpenPopup($(char* popupIdPtr)) } |]
-- | Open popup when clicked on last item.
--
-- Note: actually triggers on the mouse _released_ event to be consistent with popup behaviors.
--
-- Wraps @ImGui::OpenPopupOnItemClick()@
openPopupOnItemClick :: (MonadIO m) => CString -> ImGuiPopupFlags-> m ()
openPopupOnItemClick popupIdPtr flags = liftIO do
[C.exp| void { OpenPopupOnItemClick($(char* popupIdPtr), $(ImGuiPopupFlags flags)) } |]
-- | Manually close the popup we have begin-ed into. -- | Manually close the popup we have begin-ed into.
-- --
-- Wraps @ImGui::ClosePopup()@ -- Wraps @ImGui::ClosePopup()@
@ -1260,6 +1439,36 @@ closeCurrentPopup :: (MonadIO m) => m ()
closeCurrentPopup = liftIO do closeCurrentPopup = liftIO do
[C.exp| void { CloseCurrentPopup() } |] [C.exp| void { CloseCurrentPopup() } |]
-- | Open+begin popup when clicked on last item.
--
-- Use str_id==NULL to associate the popup to previous item.
--
-- If you want to use that on a non-interactive item such as 'text' you need to pass in an explicit ID here.
beginPopupContextItem :: (MonadIO m) => CString -> ImGuiPopupFlags-> m Bool
beginPopupContextItem popupIdPtr flags = liftIO do
(0 /=) <$> [C.exp| bool { BeginPopupContextItem($(char* popupIdPtr), $(ImGuiPopupFlags flags)) } |]
-- | Open+begin popup when clicked on current window.
beginPopupContextWindow :: (MonadIO m) => CString -> ImGuiPopupFlags-> m Bool
beginPopupContextWindow popupIdPtr flags = liftIO do
(0 /=) <$> [C.exp| bool { BeginPopupContextWindow($(char* popupIdPtr), $(ImGuiPopupFlags flags)) } |]
-- | Open+begin popup when clicked in void (where there are no windows).
beginPopupContextVoid :: (MonadIO m) => CString -> ImGuiPopupFlags-> m Bool
beginPopupContextVoid popupIdPtr flags = liftIO do
(0 /=) <$> [C.exp| bool { BeginPopupContextVoid($(char* popupIdPtr), $(ImGuiPopupFlags flags)) } |]
-- | Query popup status
--
-- - return 'True' if the popup is open at the current 'beginPopup' level of the popup stack.
-- - with 'ImGuiPopupFlags_AnyPopupId': return 'True' if any popup is open at the current 'beginPopup' level of the popup stack.
-- - with 'ImGuiPopupFlags_AnyPopupId' | 'ImGuiPopupFlags_AnyPopupLevel': return 'True' if any popup is open.
--
-- Wraps @ImGui::IsPopupOpen()@
isPopupOpen :: (MonadIO m) => CString -> ImGuiPopupFlags-> m Bool
isPopupOpen popupIdPtr flags = liftIO do
(0 /=) <$> [C.exp| bool { IsPopupOpen($(char* popupIdPtr), $(ImGuiPopupFlags flags)) } |]
-- | Is the last item hovered? (and usable, aka not blocked by a popup, etc.). -- | Is the last item hovered? (and usable, aka not blocked by a popup, etc.).
-- --

View File

@ -1,13 +1,25 @@
{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE CPP #-}
module DearImGui.Structs where module DearImGui.Structs where
-- base -- base
import Data.Word import Data.Word
( Word32, Word16 ) ( Word32
#ifndef IMGUI_USE_WCHAR32
, Word16
#endif
)
import Foreign import Foreign
( Storable(..), castPtr, plusPtr ) ( Storable(..), castPtr, plusPtr, Ptr, Int16, nullPtr )
import Foreign.C
( CInt, CBool )
import DearImGui.Enums
import Data.Bits ((.&.))
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
data ImVec2 = ImVec2 { x, y :: {-# unpack #-} !Float } data ImVec2 = ImVec2 { x, y :: {-# unpack #-} !Float }
@ -92,9 +104,111 @@ data ImDrawList
-- | 'DearImGui.Raw.ListClipper.ListClipper' pointer tag. -- | 'DearImGui.Raw.ListClipper.ListClipper' pointer tag.
data ImGuiListClipper data ImGuiListClipper
-- | A unique ID used by widgets (typically the result of hashing a stack of string)
-- unsigned Integer (same as ImU32)
type ImGuiID = ImU32
-- | 32-bit unsigned integer (often used to store packed colors). -- | 32-bit unsigned integer (often used to store packed colors).
type ImU32 = Word32 type ImU32 = Word32
type ImS16 = Int16
-- | Single wide character (used mostly in glyph management) -- | Single wide character (used mostly in glyph management)
#ifdef IMGUI_USE_WCHAR32
type ImWchar = Word32
#else
type ImWchar = Word16 type ImWchar = Word16
-- FIXME: consider IMGUI_USE_WCHAR32 #endif
--------------------------------------------------------------------------------
-- | Sorting specifications for a table (often handling sort specs for a single column, occasionally more)
-- Obtained by calling TableGetSortSpecs().
-- When @SpecsDirty == true@ you can sort your data. It will be true with sorting specs have changed since last call, or the first time.
-- Make sure to set @SpecsDirty = false@ after sorting, else you may wastefully sort your data every frame!
data ImGuiTableSortSpecs = ImGuiTableSortSpecs
{ specs :: Ptr ImGuiTableColumnSortSpecs
, specsCount :: CInt
, specsDirty :: CBool
} deriving (Show, Eq)
instance Storable ImGuiTableSortSpecs where
sizeOf _ =
sizeOf (undefined :: Ptr ImGuiTableColumnSortSpecs) +
sizeOf (undefined :: CInt) +
sizeOf (undefined :: CBool)
alignment _ =
alignment nullPtr
poke ptr ImGuiTableSortSpecs{..} = do
let specsPtr = castPtr ptr
poke specsPtr specs
let specsCountPtr = castPtr $ specsPtr `plusPtr` sizeOf specs
poke specsCountPtr specsCount
let specsDirtyPtr = castPtr $ specsCountPtr `plusPtr` sizeOf specsCount
poke specsDirtyPtr specsDirty
peek ptr = do
let specsPtr = castPtr ptr
specs <- peek specsPtr
let specsCountPtr = castPtr $ specsPtr `plusPtr` sizeOf specs
specsCount <- peek specsCountPtr
let specsDirtyPtr = castPtr $ specsCountPtr `plusPtr` sizeOf specsCount
specsDirty <- peek specsDirtyPtr
pure ImGuiTableSortSpecs{..}
-- | Sorting specification for one column of a table
data ImGuiTableColumnSortSpecs = ImGuiTableColumnSortSpecs
{ columnUserID :: ImGuiID -- ^ User id of the column (if specified by a TableSetupColumn() call)
, columnIndex :: ImS16 -- ^ Index of the column
, sortOrder :: ImS16 -- ^ Index within parent ImGuiTableSortSpecs (always stored in order starting from 0, tables sorted on a single criteria will always have a 0 here)
, sortDirection :: ImGuiSortDirection -- ^ 'ImGuiSortDirection_Ascending' or 'ImGuiSortDirection_Descending'
} deriving (Show, Eq)
instance Storable ImGuiTableColumnSortSpecs where
sizeOf _ = 12
alignment _ = 4
poke ptr ImGuiTableColumnSortSpecs{..} = do
let columnUserIDPtr = castPtr ptr
poke columnUserIDPtr columnUserID
let columnIndexPtr = castPtr $ columnUserIDPtr `plusPtr` sizeOf columnUserID
poke columnIndexPtr columnIndex
let sortOrderPtr = castPtr $ columnIndexPtr `plusPtr` sizeOf columnIndex
poke sortOrderPtr sortOrder
let sortDirectionPtr = castPtr $ sortOrderPtr `plusPtr` sizeOf sortOrder
poke sortDirectionPtr sortDirection
peek ptr = do
let columnUserIDPtr = castPtr ptr
columnUserID <- peek columnUserIDPtr
let columnIndexPtr = castPtr $ columnUserIDPtr `plusPtr` sizeOf columnUserID
columnIndex <- peek columnIndexPtr
let sortOrderPtr = castPtr $ columnIndexPtr `plusPtr` sizeOf columnIndex
sortOrder <- peek sortOrderPtr
let sortDirectionPtr = castPtr $ sortOrderPtr `plusPtr` sizeOf sortOrder
sortDirection' <- peek sortDirectionPtr :: IO CInt
-- XXX: Specs struct uses trimmed field: @SortDirection : 8@
let sortDirection = case sortDirection' .&. 0xFF of
0 ->
ImGuiSortDirection_None
1 ->
ImGuiSortDirection_Ascending
2 ->
ImGuiSortDirection_Descending
_ ->
error $ "Unexpected value for ImGuiSortDirection: " <> show sortDirection
pure ImGuiTableColumnSortSpecs{..}

View File

@ -19,6 +19,8 @@ module DearImGui.Vulkan
, vulkanCreateFontsTexture , vulkanCreateFontsTexture
, vulkanDestroyFontUploadObjects , vulkanDestroyFontUploadObjects
, vulkanSetMinImageCount , vulkanSetMinImageCount
, vulkanAddTexture
) )
where where
@ -32,7 +34,7 @@ import Foreign.Marshal.Alloc
import Foreign.Ptr import Foreign.Ptr
( FunPtr, Ptr, freeHaskellFunPtr, nullPtr ) ( FunPtr, Ptr, freeHaskellFunPtr, nullPtr )
import Foreign.Storable import Foreign.Storable
( Storable(poke) ) ( poke )
-- inline-c -- inline-c
import qualified Language.C.Inline as C import qualified Language.C.Inline as C
@ -92,7 +94,7 @@ withVulkan initInfo renderPass action =
( \ ( _, initResult ) -> action initResult ) ( \ ( _, initResult ) -> action initResult )
-- | Wraps @ImGui_ImplVulkan_Init@. -- | Wraps @ImGui_ImplVulkan_Init@.
-- --
-- Use 'vulkanShutdown' to clean up on shutdown. -- Use 'vulkanShutdown' to clean up on shutdown.
-- Prefer using 'withVulkan' when possible, as it automatically handles cleanup. -- Prefer using 'withVulkan' when possible, as it automatically handles cleanup.
vulkanInit :: MonadIO m => InitInfo -> Vulkan.RenderPass -> m (FunPtr (Vulkan.Result -> IO ()), Bool) vulkanInit :: MonadIO m => InitInfo -> Vulkan.RenderPass -> m (FunPtr (Vulkan.Result -> IO ()), Bool)
@ -184,3 +186,16 @@ vulkanDestroyFontUploadObjects = liftIO do
vulkanSetMinImageCount :: MonadIO m => Word32 -> m () vulkanSetMinImageCount :: MonadIO m => Word32 -> m ()
vulkanSetMinImageCount minImageCount = liftIO do vulkanSetMinImageCount minImageCount = liftIO do
[C.exp| void { ImGui_ImplVulkan_SetMinImageCount($(uint32_t minImageCount)); } |] [C.exp| void { ImGui_ImplVulkan_SetMinImageCount($(uint32_t minImageCount)); } |]
-- | Wraps @ImGui_ImplVulkan_AddTexture@.
vulkanAddTexture :: MonadIO m => Vulkan.Sampler -> Vulkan.ImageView -> Vulkan.ImageLayout -> m Vulkan.DescriptorSet
vulkanAddTexture sampler imageView imageLayout = liftIO do
[C.block|
VkDescriptorSet {
return ImGui_ImplVulkan_AddTexture(
$(VkSampler sampler),
$(VkImageView imageView),
$(VkImageLayout imageLayout)
);
}
|]

View File

@ -31,6 +31,10 @@ vulkanTypesTable = Map.fromList
, ( C.TypeName "VkRenderPass" , [t| Vulkan.RenderPass |] ) , ( C.TypeName "VkRenderPass" , [t| Vulkan.RenderPass |] )
, ( C.TypeName "VkResult" , [t| Vulkan.Result |] ) , ( C.TypeName "VkResult" , [t| Vulkan.Result |] )
, ( C.TypeName "VkSampleCountFlagBits", [t| Vulkan.SampleCountFlagBits |] ) , ( C.TypeName "VkSampleCountFlagBits", [t| Vulkan.SampleCountFlagBits |] )
, ( C.TypeName "VkSampler" , [t| Vulkan.Sampler |] )
, ( C.TypeName "VkImageView" , [t| Vulkan.ImageView |] )
, ( C.TypeName "VkImageLayout" , [t| Vulkan.ImageLayout |] )
, ( C.TypeName "VkDescriptorSet" , [t| Vulkan.DescriptorSet |] )
] ]
vulkanCtx :: C.Context vulkanCtx :: C.Context