Skip to content


Connecting Yampa with LambdaCube-Engine

LambdaCube TileRacer Jochen Leopold

Abstract

In this post I present a minimal LambdaCube-Engine program which connects a 3D rendering engine to Yampa FRP. The code is an adaption of the lambdacube-basic.hs example delivered with lambdacube-examples. Some changes to Yampa were necessary to allow MonadIO transformations in order to connect with LambdaCube. The goal is to get quickstarted with Yampa and LambdaCube, so the code was intentionally kept simple. Full source code is available at bottom of post.

LambdaCube Examples

First we’re going to setup LamdaCube, run the lambdacube-basic example and see how it does work. Note that the latest version (0.2.4) of LamdaCube is available at GoogleCode (instead of Hackage (0.2.3)).

# cabal unpack lambdacube-engine # old version
svn checkout http://lambdacube.googlecode.com/svn/trunk/ lambdacube # new version
cd lambdacube/lambdacube-examples
dist/build/lambdacube-basic/lambdacube-basic
# ls lambdacube-examples.cabal
# ls src/lambdacube-basic.hs
# ls media/

It should show 1 frame of a bluesky scene. However it stops immediately because of an issue in Elerea FRP with the following message (bug report): thread blocked indefinitely in an MVar operation

This is unfortunate, however we’re going to integrate Yampa anyway. The important parts of the example are outlined here:

lambdacube-basic.hs (outlined)

import FRP.Elerea.Param
...

main = do
    openWindow
    ...
    runLCM renderSystem [Stb.loadImage] $ do
    ...
    addScene [ node "Root" "Obj" ...]
    ...
    addRenderWindow "MainWindow" 640 480 ...
    ...
    sc <- liftIO $ start $ scene ...        
    driveNetwork sc (readInput ...)

scene :: RenderSystem r vb ib q t p lp
      => ...
      -> SignalGen FloatType (Signal (LCM (World r vb ib q t p lp) e ()))
scene = do
        ...
        return $ drawGLScene <$> ...

drawGLScene :: RenderSystem r vb ib q t2 p lp
            => ...
            -> FloatType
            -> LCM   (World r vb ib q t2 p lp) e ()
drawGLScene ... time = do
    updateTransforms $ ...
    updateTargetSize "MainWindow" w h
    renderWorld (realToFrac time) "MainWindow"

What happens here is that a LCM world (LambdaCubeMonad) is created and several changes are made by “shoving” through the World via runLCM. Finally Elerea’s driveNetwork starts an infinite loop to make repeated renderWorld calls within the LCM context. So all we have to do is replace Elerea’s driveNetwork with Yampa’s reactimate and “shove” the LCM into reactimate. Unfortunately the types don’t match: (IO vs LCM). Also note how an external renderWorld is called within an LCM context. What’s going on? Let’s look up the definition! Because there are no public docs available we’ll generate them ourselves:

cd lambdacube/lambdacube-engine
cabal haddock
firefox dist/doc/html/lambdacube-engine/index.html
data LCM w e a

Instances
Monad (LCM w e)
Functor (LCM w e)
Applicative (LCM w e)
MonadIO (LCM w e)

What’s interesting here is that LCM instances MonadIO and provides a free type variable a. Thus LCM has an IO context and can be extended with other Monad contexts and types. All we have to do therefore is to make Yampa’s reactimate less strict and do some Monad lifting.

cabal install transformers

cabal unpack Yampa
cd Yampa-0.9.3/src/FRP

Yampa.hs

reactimate :: IO a
           -> (Bool -> IO (DTime, Maybe a))
           -> (Bool -> b -> IO Bool)
           -> SF a b
           -> IO ()

Change to:

import Control.Monad.IO.Class (MonadIO)
...

reactimate :: MonadIO m
           => m a
           -> (Bool -> m (DTime, Maybe a))
           -> (Bool -> b -> m Bool)
           -> SF a b
           -> m ()

Now we can call reactimate within runLCM and use Yampa as usual. Copy the lambdacube-basic.hs file and extend lambdacube-examples.cabal with the new executable.

YampaCube.hs (outlined)

type ObjInput  = (Int, Int)      -- mouse-position
type ObjOutput = (String, Proj4) -- object name, transformation

main :: IO ()
main = do
    mediaPath <- getDataFileName "media"
    renderSystem <- mkGLRenderSystem
    runLCM renderSystem [Stb.loadImage] (reactimate (initput title mediaPath) input output (process objs))
    closeWindow

initput :: RenderSystem r vb ib q t p lp
      => Bool
      -> LCM     (World r vb ib q t p lp) e (DTime, Maybe (Bool, ObjInput))
initput _ = do
    ...
    liftIO $ openWindow ...
    ...
    addScene [ node "Root" "Obj" ...]
    ...

output :: RenderSystem r vb ib q t p lp
       => Bool -> [ObjOutput]
       -> LCM   (World r vb ib q t p lp) e Bool

cam :: SF ObjInput ObjOutput
cam = proc _ -> do
    t <- localTime -< ()
    returnA -< ("Cam", translation (Vec3 0 0 (realToFrac t)))
cd lambdacube/lambdacube-examples
cabal configure
cabal build
dist/build/YampaCube/YampaCube

Download full source code: YampaCube.hs

Viola! What you should see is a small box with the bluesky texture and the camera slowly moving away from it.

Tagged with , , , .


4 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Jameson says

    I can’t seem to download the source… broken link?

  2. Gerold Meisinger says

    fixed

  3. Jameson says

    Nice, thankyou.

  4. cube world cracked says

    Downloading Dice planet typically charges money. I will give you Dice Entire world total edition which you can down load
    below for cost-free. Sure you will be ready to perform Cube
    Globe in a handful of minutes listed here for free of charge, all you have to do is obtain Dice Entire
    world with the website link supplied here. We provided Dice Globe
    crack so after you set up Cube Globe Alpha, you can enjoy it immediately.
    Cube Planet is a 3D action RPG kind game that is produced/designed by Wollay and his wife.
    Dice Entire world was started out in June 2011 and now, the Alpha variation is out previously.



Some HTML is OK

or, reply to this post via trackback.