Commit 58ba3e15 authored by Tristan de Cacqueray's avatar Tristan de Cacqueray Committed by sheaf
Browse files

[toy] Display two windows for both the map and julia view

parent 1c407df6
......@@ -380,7 +380,7 @@ bezier = runVulkan bezierInitialState do
inputEvents <- map SDL.Event.eventPayload <$> SDL.pollEvents
prevInput <- use _input
let newInput = foldl onSDLInput prevInput inputEvents
let newInput = foldl (onSDLInput window) prevInput inputEvents
let action = interpretInput 0.1 newInput
assign _input ( newInput { mouseRel = pure 0, keysPressed = [] } )
......
......@@ -387,7 +387,7 @@ fullPipeline = runVulkan initialState do
inputEvents <- map SDL.Event.eventPayload <$> SDL.pollEvents
prevInput <- use _input
let newInput = foldl onSDLInput prevInput inputEvents
let newInput = foldl (onSDLInput window) prevInput inputEvents
let action = interpretInput 0.1 newInput
assign _input ( newInput { mouseRel = pure 0, keysPressed = [] } )
......
......@@ -375,7 +375,7 @@ hopf = runVulkan initialState do
inputEvents <- map SDL.Event.eventPayload <$> SDL.pollEvents
prevInput <- use _input
let newInput = foldl onSDLInput prevInput inputEvents
let newInput = foldl (onSDLInput window) prevInput inputEvents
let action = interpretInput 0.1 newInput
assign _input ( newInput { mouseRel = pure 0, keysPressed = [] } )
......
......@@ -446,7 +446,7 @@ ising = runVulkan initialState do
prevInput <- use _input
timeNow <- SDL.time
let
newInput = foldl onSDLInput prevInput inputEvents
newInput = foldl (onSDLInput window) prevInput inputEvents
action = interpretInput 1 newInput
pos@(V2 px py) = mousePos newInput
temperature = max 1e-4 $ px / ( 0.3 * Ising.width )
......
......@@ -315,7 +315,7 @@ juliaSet = runVulkan initialState do
prevInput <- use _input
let
prevAction = interpretInput 1 prevInput
newInput = foldl onSDLInput prevInput inputEvents
newInput = foldl (onSDLInput window) prevInput inputEvents
action = interpretInput 1 newInput
pos <-
......
......@@ -337,7 +337,7 @@ kerr = runVulkan initialStateKerr do
inputEvents <- map SDL.Event.eventPayload <$> SDL.pollEvents
prevInput <- use _input
let newInput = foldl onSDLInput prevInput inputEvents
let newInput = foldl (onSDLInput window) prevInput inputEvents
let action = interpretInput 0.5 newInput
assign _input ( newInput { mouseRel = pure 0, keysPressed = [] } )
......
......@@ -309,7 +309,7 @@ logo = runVulkan initialStateLogo do
inputEvents <- map SDL.Event.eventPayload <$> SDL.pollEvents
prevInput <- use _input
let newInput = foldl onSDLInput prevInput inputEvents
let newInput = foldl (onSDLInput window) prevInput inputEvents
let action = interpretInput 1 newInput
angs = fmap getSum ( look action )
assign _input ( newInput { mouseRel = pure 0, keysPressed = [] } )
......
......@@ -820,7 +820,7 @@ rayTracing = runVulkan ( initialState, CameraIsLocked False ) do
prevCamLocked <- cameraIsLocked <$> use ( typed @CameraLock )
prevInput <- use ( typed @RenderState . _input )
let
newInput = foldl onSDLInput prevInput inputEvents
newInput = foldl (onSDLInput window) prevInput inputEvents
cameraIsLocked =
if SDL.ScancodeL `elem` ( keysPressed newInput )
then not prevCamLocked
......
......@@ -513,7 +513,7 @@ texture = runVulkan initialState do
inputEvents <- map SDL.Event.eventPayload <$> SDL.pollEvents
prevInput <- use _input
let newInput = foldl onSDLInput prevInput inputEvents
let newInput = foldl (onSDLInput window) prevInput inputEvents
let action = interpretInput 0.1 newInput
assign _input ( newInput { mouseRel = pure 0, keysPressed = [] } )
......
......@@ -58,9 +58,10 @@ import FIR.Examples.Paths
type InputData :: ControllerRef -> Type
type InputData ref =
Struct
'[ "mousePos" ':-> V 2 Float
'[ "map_mode" ':-> Word32
, "zoom" ':-> Float
, "origin" ':-> V 2 Float
, "seed" ':-> V 2 Float
, "scancodes" ':-> Array 512 Word32
, "imGuiData" ':-> ImGuiData ref
]
......@@ -70,18 +71,16 @@ type ImGuiData ref =
Struct
'[ "color" ':-> ControllerData ref Float
, "max_iter" ':-> ControllerData ref Float
, "map_mode" ':-> ControllerData ref Int32
]
initImGuiData :: ImGuiData InitValue
initImGuiData
= ( "Color", Slider, 0 )
:& ( "Iterations", Slider, 0 )
:& ( "Map Mode", Toggle, 0 )
:& End
initInputData :: InputData Value
initInputData = V2 0 0 :& 0 :& V2 0 0 :& Prelude.pure 0 :& controllerInitValues initImGuiData :& End
initInputData = 0 :& 0 :& V2 0 0 :& V2 0 0 :& Prelude.pure 0 :& controllerInitValues initImGuiData :& End
------------------------------------------------
-- pipeline input
......@@ -150,16 +149,14 @@ screenYF = Lit (fromIntegral screenY)
grad_freq :: Code Float
grad_freq = 0.6
seed :: Code (V 2 Float)
seed = Vec2 (-0.7477055835083013) (-2.692868835794263)
-- Params ends
fragment :: ShaderModule "main" FragmentShader FragmentDefs _
fragment = shader do
gl_FragCoord <- #gl_FragCoord
color <- use @(Name "ubo" :.: Name "imGuiData" :.: Name "color")
max_iter' <- use @(Name "ubo" :.: Name "imGuiData" :.: Name "max_iter")
map_mode' <- use @(Name "ubo" :.: Name "imGuiData" :.: Name "map_mode")
map_mode' <- use @(Name "ubo" :.: Name "map_mode")
seed <- use @(Name "ubo" :.: Name "seed")
range <- use @(Name "ubo" :.: Name "zoom")
origin <- use @(Name "ubo" :.: Name "origin")
......@@ -216,7 +213,7 @@ fragment = shader do
res = ml / fromIntegral max_iter
in res
let col = if map_mode && pixelCoord `nearBy` seed
let col = if map_mode && nearBy (range / 100) pixelCoord seed
then Lit seedColor
else gradient ((1 + 7 * color) * t) (Lit sunset)
......@@ -224,14 +221,11 @@ fragment = shader do
#out_colour .= col
nearBy :: Code (V 2 Float) -> Code (V 2 Float) -> Code Bool
nearBy (Vec2 x y) (Vec2 x' y') =
nearBy :: Code Float -> Code (V 2 Float) -> Code (V 2 Float) -> Code Bool
nearBy dist (Vec2 x y) (Vec2 x' y') =
if abs (x - x') < dist && abs (y - y') < dist
then Lit True
else Lit False
where
dist :: Code Float
dist = 0.01
mkRescaledComplex :: Code (V 2 Float) -> CodeComplex Float
mkRescaledComplex (Vec2 x y) =
......
......@@ -218,18 +218,10 @@ Interactive Julia set rendering, computed within a fragment shader.
[Application](examples/apps/FIR/Examples/Toy/Application.hs)[Shaders](examples/shaders/FIR/Examples/Toy/Shaders.hs)
</div>
Shader toy example using Dear ImGui to provide interactive sliders whose values are passed on to the shader.
Shader toy like example using Dear ImGui to provide interactive sliders whose values are passed on to the shader.
__Note:__ this requires a manual installation of the Haskell `dear-imgui` package,
because the `dear-imgui` package is not yet available on Hackage and contains an external submodule which
isn't fetched by `extra-src-repository` in `cabal`.
To allow `cabal` to use `Dear ImGui`, clone the [Dear ImGui](https://github.com/haskell-game/dear-imgui.hs)
repository manually and then add it to the `cabal.project.local` file in the `fir-examples` subdirectory:
```
packages: path/to/your/DearImGui/package
```
Use the mouse wheel and left button to adjust the position.
In the map mode, use the right button to adjust the seed (represented by a pink square).
<a name="offscreen"></a>
### Offscreen rendering
......
......@@ -13,6 +13,7 @@ module FIR.Examples.RenderState
, Action(..)
, Quit(Quit)
, Observer(..), initialObserver
, Observer2D(..), initialObserver2D, updateObserver2D
, RenderState(..), initialState
, _observer, _position, _angles, _input
, mainLoop
......@@ -100,6 +101,7 @@ _angles = lens angles ( \s v -> s { angles = v } )
_input :: Lens' RenderState Input
_input = lens input ( \s v -> s { input = v } )
----------------------------------------------------------------------------
newtype Quit = MkQuit Any
......@@ -133,6 +135,67 @@ data Observer = Observer
, frame :: Word32
} deriving Show
data Observer2D = Observer2D
{ zoom :: Float
, origin :: V 2 Float
, scroll :: Int
, mouseCoordPos :: V 2 Float
, mouseLeftDown :: Bool
, mouseLeftClicked :: Bool
, mouseRightDown :: Bool
, mouseRightClicked :: Bool
} deriving Show
initialObserver2D :: Observer2D
initialObserver2D =
let
zoom = 1
origin = V2 0 0
scroll = 0
mouseCoordPos = V2 0 0
mouseLeftDown = False
mouseLeftClicked = False
mouseRightDown = False
mouseRightClicked = False
in Observer2D {..}
updateObserver2D :: Observer2D -> V 2 Word32 -> Input -> Observer2D
updateObserver2D Observer2D {..} screen Input {..} =
let
scrolled = mouseWheel - scroll
newZoom =
if scrolled /= 0
then
let
offset = if scrolled < 0 then 0.1 else -0.1
in zoom + offset * zoom
else
zoom
newMouseCoordPos = pos2Coord screen origin zoom mousePos
newOrigin =
if newMouseLeftClicked
then mouseCoordPos
else origin
newScroll = mouseWheel
newMouseRightDown = SDL.ButtonRight `elem` mouseButtonsDown
newMouseLeftDown = SDL.ButtonLeft `elem` mouseButtonsDown
newMouseLeftClicked =
if newMouseLeftDown
-- Clicked is True only the first time the event is received
then Prelude.not mouseLeftDown
else False
newMouseRightClicked =
if newMouseRightDown
-- Clicked is True only the first time the event is received
then Prelude.not mouseRightDown
else False
in
Observer2D
newZoom newOrigin newScroll newMouseCoordPos
newMouseLeftDown newMouseLeftClicked newMouseRightDown newMouseRightClicked
nullInput :: Input
nullInput
......@@ -191,36 +254,44 @@ strafe multiplier
. foldMap (fmap Sum . strafeDir)
onSDLInput :: Input -> SDL.EventPayload -> Input
onSDLInput input SDL.QuitEvent
onSDLInput :: SDL.Window -> Input -> SDL.EventPayload -> Input
onSDLInput _ input SDL.QuitEvent
= input { quitEvent = Quit }
onSDLInput input (SDL.WindowClosedEvent _)
onSDLInput _ input (SDL.WindowClosedEvent _)
= input { quitEvent = Quit }
onSDLInput input (SDL.KeyboardEvent ev)
onSDLInput win input (SDL.KeyboardEvent ev)
| SDL.keyboardEventWindow ev /= Just win = input
| otherwise
= let keyCode = SDL.keysymScancode (SDL.keyboardEventKeysym ev)
in case SDL.keyboardEventKeyMotion ev of
SDL.Pressed -> input { keysDown = keyCode : filter (/= keyCode) (keysDown input)
, keysPressed = keyCode : filter (/= keyCode) (keysPressed input)
}
SDL.Released -> input { keysDown = filter (/= keyCode) (keysDown input) }
onSDLInput input (SDL.MouseButtonEvent ev)
onSDLInput win input (SDL.MouseButtonEvent ev)
| SDL.mouseButtonEventWindow ev /= Just win = input
| otherwise
= let button = SDL.mouseButtonEventButton ev
down = filter (/= button) (mouseButtonsDown input)
in case SDL.mouseButtonEventMotion ev of
SDL.Pressed -> input { mouseButtonsDown = button : down }
SDL.Released -> input { mouseButtonsDown = down }
onSDLInput input (SDL.MouseMotionEvent ev)
onSDLInput win input (SDL.MouseMotionEvent ev)
| SDL.mouseMotionEventWindow ev /= Just win = input
| otherwise
= input { mousePos = fmap Prelude.fromIntegral (V2 px py)
, mouseRel = fmap ((* 0.003) . Prelude.fromIntegral) (V2 rx ry)
}
where
SDL.P (SDL.V2 px py) = SDL.mouseMotionEventPos ev
SDL.V2 rx ry = SDL.mouseMotionEventRelMotion ev
onSDLInput input (SDL.MouseWheelEvent ev)
onSDLInput win input (SDL.MouseWheelEvent ev)
| SDL.mouseWheelEventWindow ev /= Just win = input
| otherwise
= input { mouseWheel = mouseWheel input + Prelude.fromIntegral wheelYOffset }
where
SDL.V2 _ wheelYOffset = SDL.mouseWheelEventPos ev
onSDLInput input _ = input
onSDLInput _ input _ = input
interpretInput :: Float -> Input -> Action
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment