2021-09-12 10:35:03 +00:00
|
|
|
{-# language BlockArguments #-}
|
|
|
|
{-# language LambdaCase #-}
|
|
|
|
{-# language OverloadedStrings #-}
|
|
|
|
|
2021-09-12 11:56:43 +00:00
|
|
|
{- | Drawing an DearImGui image using OpenGL textures.
|
|
|
|
|
|
|
|
https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
|
|
|
|
-}
|
|
|
|
|
2021-09-12 10:35:03 +00:00
|
|
|
module Main ( main ) where
|
|
|
|
|
|
|
|
import Control.Exception
|
2021-09-12 11:56:43 +00:00
|
|
|
import Control.Monad.IO.Class (MonadIO(..))
|
|
|
|
import Control.Monad.Managed (managed, managed_, runManaged)
|
2021-09-12 10:35:03 +00:00
|
|
|
import DearImGui
|
|
|
|
import qualified DearImGui.Raw as Raw
|
|
|
|
import DearImGui.OpenGL3
|
|
|
|
import DearImGui.SDL
|
|
|
|
import DearImGui.SDL.OpenGL
|
|
|
|
import Graphics.GL
|
|
|
|
import qualified SDL as SDL
|
|
|
|
|
|
|
|
-- For the texture creation
|
|
|
|
import Foreign
|
|
|
|
import qualified Data.Vector.Storable as VS
|
|
|
|
|
2021-09-12 11:56:43 +00:00
|
|
|
data Texture = Texture
|
|
|
|
{ textureID :: GLuint
|
|
|
|
, textureWidth :: GLsizei
|
|
|
|
, textureHeight :: GLsizei
|
|
|
|
}
|
2021-09-12 10:35:03 +00:00
|
|
|
|
2021-09-12 11:56:43 +00:00
|
|
|
textureSize :: Texture -> ImVec2
|
|
|
|
textureSize texture =
|
|
|
|
ImVec2
|
|
|
|
(fromIntegral $ textureWidth texture)
|
|
|
|
(fromIntegral $ textureHeight texture)
|
|
|
|
|
|
|
|
-- | Create a texture pointer in GL memory.
|
2021-09-12 10:35:03 +00:00
|
|
|
create2DTexture :: Int -> Int -> IO Texture
|
2021-09-12 11:56:43 +00:00
|
|
|
create2DTexture width height =
|
|
|
|
alloca \ptr -> do
|
2021-09-12 10:35:03 +00:00
|
|
|
glGenTextures 1 ptr
|
|
|
|
tID <- peek ptr
|
2021-09-12 11:56:43 +00:00
|
|
|
return Texture
|
|
|
|
{ textureID = tID
|
|
|
|
, textureWidth = fromIntegral width
|
|
|
|
, textureHeight = fromIntegral height
|
|
|
|
}
|
|
|
|
|
|
|
|
bindTexture :: Texture -> Ptr GLubyte -> IO ()
|
|
|
|
bindTexture texture dataPtr = do
|
2021-09-12 10:35:03 +00:00
|
|
|
glEnable GL_TEXTURE_2D
|
2021-09-12 11:56:43 +00:00
|
|
|
glBindTexture GL_TEXTURE_2D (textureID texture)
|
|
|
|
|
2021-09-12 10:35:03 +00:00
|
|
|
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER GL_LINEAR
|
|
|
|
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER GL_LINEAR
|
|
|
|
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S GL_REPEAT
|
|
|
|
glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T GL_REPEAT
|
|
|
|
|
2021-09-12 11:56:43 +00:00
|
|
|
glTexImage2D
|
|
|
|
GL_TEXTURE_2D
|
|
|
|
0
|
|
|
|
GL_RGB
|
|
|
|
(textureWidth texture)
|
|
|
|
(textureHeight texture)
|
|
|
|
0
|
|
|
|
GL_RGB
|
|
|
|
GL_UNSIGNED_BYTE
|
|
|
|
(castPtr dataPtr)
|
|
|
|
|
|
|
|
fill :: Integral size => size -> size -> VS.Vector GLubyte
|
|
|
|
fill width height =
|
|
|
|
VS.generate
|
|
|
|
(3 * fromIntegral width * fromIntegral height)
|
|
|
|
(\i ->
|
|
|
|
case i `mod` 3 of
|
|
|
|
0 -> 0x00
|
|
|
|
1 -> 0x7F
|
|
|
|
2 -> 0xFF
|
|
|
|
_ -> error "assert: 3-byte pitch"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
main :: IO ()
|
|
|
|
main = do
|
2021-09-12 10:35:03 +00:00
|
|
|
-- Initialize SDL
|
|
|
|
SDL.initializeAll
|
|
|
|
|
|
|
|
runManaged do
|
|
|
|
-- Create a window using SDL. As we're using OpenGL, we need to enable OpenGL too.
|
2021-09-12 11:56:43 +00:00
|
|
|
window <- do
|
2021-09-12 10:35:03 +00:00
|
|
|
let title = "Hello, Dear ImGui!"
|
|
|
|
let config = SDL.defaultWindow { SDL.windowGraphicsContext = SDL.OpenGLContext SDL.defaultOpenGL, SDL.windowResizable = True }
|
|
|
|
managed $ bracket (SDL.createWindow title config) SDL.destroyWindow
|
|
|
|
|
|
|
|
-- Create an OpenGL context
|
2021-09-12 11:56:43 +00:00
|
|
|
glContext <- managed $ bracket (SDL.glCreateContext window) SDL.glDeleteContext
|
2021-09-12 10:35:03 +00:00
|
|
|
|
|
|
|
-- Create an ImGui context
|
2021-09-12 11:56:43 +00:00
|
|
|
_dearContext <- managed $ bracket createContext destroyContext
|
2021-09-12 10:35:03 +00:00
|
|
|
|
|
|
|
-- Initialize ImGui's SDL2 backend
|
2021-09-12 11:56:43 +00:00
|
|
|
managed_ $ bracket_ (sdl2InitForOpenGL window glContext) sdl2Shutdown
|
2021-09-12 10:35:03 +00:00
|
|
|
|
|
|
|
-- Initialize ImGui's OpenGL backend
|
2021-09-12 11:56:43 +00:00
|
|
|
managed_ $ bracket_ openGL3Init do
|
2021-09-12 10:35:03 +00:00
|
|
|
putStrLn "ImguiOpenGL shut down"
|
2021-09-12 11:56:43 +00:00
|
|
|
openGL3Shutdown
|
|
|
|
|
|
|
|
liftIO do
|
|
|
|
let width = 320
|
|
|
|
height = 240
|
|
|
|
texture <- create2DTexture width height
|
|
|
|
VS.unsafeWith (fill width height) $
|
|
|
|
bindTexture texture
|
2021-09-12 10:35:03 +00:00
|
|
|
err <- glGetError
|
2021-09-12 11:56:43 +00:00
|
|
|
putStrLn $ "Error-code: " ++ show err
|
2021-09-12 10:35:03 +00:00
|
|
|
|
2021-09-12 11:56:43 +00:00
|
|
|
mainLoop window texture
|
2021-09-12 10:35:03 +00:00
|
|
|
|
2021-09-12 11:56:43 +00:00
|
|
|
mainLoop :: SDL.Window -> Texture -> IO ()
|
|
|
|
mainLoop window texture = unlessQuit do
|
2021-09-12 10:35:03 +00:00
|
|
|
-- Tell ImGui we're starting a new frame
|
|
|
|
openGL3NewFrame
|
|
|
|
sdl2NewFrame
|
|
|
|
newFrame
|
|
|
|
|
|
|
|
-- Build the GUI
|
2021-09-12 11:56:43 +00:00
|
|
|
withWindowOpen "Image example" $ runManaged do
|
|
|
|
-- Drawing images require some backend-specific code.
|
|
|
|
-- Meanwhile, we have to deal with raw binding.
|
|
|
|
let openGLtextureID = intPtrToPtr $ fromIntegral $ textureID texture
|
|
|
|
sizePtr <- managed $ Foreign.with (textureSize texture)
|
|
|
|
uv0Ptr <- managed $ Foreign.with (ImVec2 0 0)
|
|
|
|
uv1Ptr <- managed $ Foreign.with (ImVec2 1 1)
|
|
|
|
tintColPtr <- managed $ Foreign.with (ImVec4 1 1 1 1)
|
|
|
|
borderColPtr <- managed $ Foreign.with (ImVec4 0 1 0 0)
|
|
|
|
Raw.image openGLtextureID sizePtr uv0Ptr uv1Ptr tintColPtr borderColPtr
|
2021-09-12 10:35:03 +00:00
|
|
|
|
|
|
|
-- Render
|
|
|
|
glClear GL_COLOR_BUFFER_BIT
|
|
|
|
|
2021-09-12 11:56:43 +00:00
|
|
|
DearImGui.render
|
|
|
|
DearImGui.getDrawData >>= openGL3RenderDrawData
|
2021-09-12 10:35:03 +00:00
|
|
|
|
2021-09-12 11:56:43 +00:00
|
|
|
SDL.glSwapWindow window
|
2021-09-12 10:35:03 +00:00
|
|
|
|
2021-09-12 11:56:43 +00:00
|
|
|
mainLoop window texture
|
2021-09-12 10:35:03 +00:00
|
|
|
|
|
|
|
where
|
2021-09-12 11:56:43 +00:00
|
|
|
unlessQuit action = do
|
|
|
|
shouldQuit <- checkEvents
|
|
|
|
if shouldQuit then pure () else action
|
|
|
|
|
|
|
|
checkEvents = do
|
|
|
|
pollEventWithImGui >>= \case
|
|
|
|
Nothing ->
|
|
|
|
return False
|
|
|
|
Just event ->
|
|
|
|
(isQuit event ||) <$> checkEvents
|
|
|
|
|
|
|
|
isQuit event =
|
|
|
|
SDL.eventPayload event == SDL.QuitEvent
|