2011-03-13 14 views
1

有一個這樣的例子。我怎麼能用gtk和haskell做2d雙緩衝。我想將原語渲染到屏幕外的緩衝區並翻轉。這段代碼只渲染一個像素/矩形。我想使用雙緩衝方法添加移動。Haskell GTK,雙緩衝與原語

import Graphics.UI.Gtk 
import Graphics.UI.Gtk.Gdk.GC 
import Graphics.UI.Gtk hiding (Color, Point, Object) 

defaultFgColor :: Color 
defaultFgColor = Color 65535 65535 65535 

defaultBgColor :: Color 
defaultBgColor = Color 0 0 0 

renderScene d ev = do 
    dw  <- widgetGetDrawWindow d 
    (w, h) <- widgetGetSize d 
    gc  <- gcNew dw 
    let fg = Color (round (65535 * 205)) 
        (round (65535 * 0)) 
        (round (65535 * 0)) 
    gcSetValues gc $ newGCValues { foreground = fg } 
    drawPoint dw gc (120, 120) 
    drawPoint dw gc (22, 22) 
    drawRectangle dw gc True 20 20 20 20 
    return True 

main :: IO() 
main = do 
    initGUI 
    window <- windowNew 
    drawing <- drawingAreaNew 
    windowSetTitle window "Cells" 
    containerAdd window drawing 
    let bg = Color (round (65535 * 205)) 
        (round (65535 * 205)) 
        (round (65535 * 255)) 
    widgetModifyBg drawing StateNormal bg 
    onExpose drawing (renderScene drawing) 

    onDestroy window mainQuit 
    windowSetDefaultSize window 800 600 
    windowSetPosition window WinPosCenter 
    widgetShowAll window 
    mainGUI 
+0

你能告訴我,什麼不適合你嗎? – fuz 2011-03-13 15:34:46

+0

該代碼只渲染一個像素。我想使用雙緩衝方法添加移動。 – 2011-03-14 17:31:27

回答

2

這是我使用的是開羅畫繪圖區域,避免 閃爍的東西。嘗試將此代碼添加到您的renderScene功能:

-- Get the draw window (dw) and its size (w,h) 
    -- ... 

    regio <- regionRectangle $ Rectangle 0 0 w h 
    drawWindowBeginPaintRegion dw regio 

    -- Put paiting code here 
    -- .. 

    drawWindowEndPaint dw 

你的最終代碼看起來是這樣的:

import Graphics.UI.Gtk 
import Graphics.UI.Gtk.Gdk.GC 
import Graphics.UI.Gtk hiding (Color, Point, Object) 
import Data.IORef 

defaultFgColor :: Color 
defaultFgColor = Color 65535 65535 65535 

defaultBgColor :: Color 
defaultBgColor = Color 0 0 0 

renderScene pref d _ev = renderScene' pref d 

renderScene' :: IORef Int -> DrawingArea -> IO Bool 
renderScene' pref d = do 
    dw  <- widgetGetDrawWindow d 
    (w, h) <- widgetGetSize d 
    regio <- regionRectangle $ Rectangle 0 0 w h 

    pos <- readIORef pref 
    -- Go around, CCW, in a circle of size 20, centered at (100,100) 
    let x = 100 + round (20 * sin (fromIntegral pos * pi * 2/360)) 
     y = 100 + round (20 * cos (fromIntegral pos * pi * 2/360)) 
     pos' = (pos + 1) `mod` 360 
    writeIORef pref pos' 

    drawWindowBeginPaintRegion dw regio 
    gc  <- gcNew dw 
    let fg = Color (round (65535 * 205)) 
        (round (65535 * 0)) 
        (round (65535 * 0)) 
    gcSetValues gc $ newGCValues { foreground = fg } 
    drawPoint dw gc (120, 120) 
    drawPoint dw gc (22, 22) 
    drawRectangle dw gc True x y 20 20 
    -- Paint an extra rectangle 
    drawRectangle dw gc True 200 200 200 200 
    drawWindowEndPaint dw 
    return True 

main :: IO() 
main = do 
    initGUI 
    window <- windowNew 
    drawing <- drawingAreaNew 
    windowSetTitle window "Cells" 
    containerAdd window drawing 
    let bg = Color (round (65535 * 205)) 
        (round (65535 * 205)) 
        (round (65535 * 255)) 
    widgetModifyBg drawing StateNormal bg 

    pref <- newIORef 0 

    onExpose drawing (renderScene pref drawing) 
    timeoutAdd (renderScene' pref drawing) 10 

    onDestroy window mainQuit 
    windowSetDefaultSize window 800 600 
    windowSetPosition window WinPosCenter 
    widgetShowAll window 
    mainGUI 
+0

看起來很有趣。你有沒有更多的代碼。我看不到交換。 – 2011-03-15 14:03:24

+1

交換髮生在drawWindowEndPaint。根據文檔,它「表示最近調用drawWindowBeginPaintRegion創建的後備存儲應該被複制到屏幕上並被刪除」。 – 2011-03-15 15:11:40

+0

我用你可以使用的代碼修改了我原來的評論。它畫一個方形的圓圈,另一個只是躺在那裏。如果您不使用paintRegions並清除背景(例如繪製白色矩形),則會看到閃爍。這樣,當你調用drawWindowEndPaint時,所有東西都被繪製了。 – 2011-03-15 15:54:42

0

這可能是一個想法,看看ThreadScope。滾動在那裏實現,非常接近雙緩衝。這裏是什麼,我認爲他們做一個簡化版本:

prev_surface <- readIORef prevView 
win <- widgetGetDrawWindow timelineDrawingArea 
renderWithDrawable win $ do 

    -- Create new surface based on the old one 
    new_surface <- liftIO $ createSimilarSurface [...] 
    renderWith new_surface $ do 
    setSourceSurface prev_surface off 0 
    Cairo.rectangle [...] 
    Cairo.fill 
    [... render newly exposed stuff ...] 
    surfaceFinish new_surface 

    -- Save back new view 
    liftIO $ writeIORef prevView new_surface 

    -- Paint new view 
    setSourceSurface new_surface 0 0 
    setOperator OperatorSource 
    paint 

實際的代碼可以在Timeline/Render.hs找到。不知道這是否是最好的方法,但它在實踐中似乎運作良好。我希望這有幫助。