Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] How to render changeable picture efficiently enough? #283

Open
Lev135 opened this issue May 18, 2023 · 3 comments
Open

[Question] How to render changeable picture efficiently enough? #283

Lev135 opened this issue May 18, 2023 · 3 comments
Labels
question Further information is requested

Comments

@Lev135
Copy link

Lev135 commented May 18, 2023

I want to show square grid with about 100x100 colored cells. The state of the grid (i. e. the colors of the cells) shouldn't change frequently. However, the simplest solution, which I've tried: to create a widget and draw the grid in render function works very poorly, since rerendering is called too often. Is there any way to make it better?

makeGrid :: ()
  => (Int, Int)
  -> Widget s e
makeGrid (w, h)
  = createSingle () def {
      singleGetSizeReq = getSizeReq
    , singleRender = render
    }
  where
    cellSize = 10
    coord n = fromIntegral n * cellSize

    getSizeReq _wenv _node = (fixedSize $ coord w, fixedSize $ coord h)

    render _wenv node renderer = do
      let vp = node ^. L.info . L.viewport
          origin = Point (vp ^. L.x) (vp ^. L.y)
      drawInTranslation renderer origin do
        for_ [0 .. w - 1] \i -> do
          for_ [0 .. h - 1] \j -> do
            let rect = Rect (coord i) (coord j) (coord 1) (coord 1)
                s = Just $ BorderSide 0.1 gray
                bd = Border s s s s
            drawRectBorder renderer rect bd Nothing
@Deltaspace0
Copy link
Contributor

Deltaspace0 commented May 19, 2023

@Lev135 Hi! In color picker widget there is a pattern with alternating colors to indicate transparency which is implemented using imageMem widget:

patternImage :: WidgetEvent e => Int -> Int -> Color -> Color -> WidgetNode s e
patternImage steps blockW col1 col2 = newImg where
row1 = encodeRow steps blockW col1 col2
row2 = encodeRow steps blockW col2 col1
builder = mconcat (replicate steps (row1 <> row2))
imgData = BL.toStrict $ toLazyByteString builder
imgLen = fromIntegral (steps * blockW)
imgSize = Size imgLen imgLen
imgConfig = [fitFill, imageRepeatX, imageRepeatY]
newImg = imageMem_ "colorPickerAlphaBg" imgData imgSize imgConfig

Perhaps you can use imageMem to render your square grid.

@fjvallarino
Copy link
Owner

Hi @Lev135!

The main problem is you're drawing quite a few items using a helper function that is not particularly efficient. This function is used to render widget borders in several scenarios, and because of that it's too general; I added a note for myself to review it for the most basic case.

Based on what I see from the code, is the objective only drawing a grid, or are you planning on drawing squares in the viewport?

If you are only going to draw the borders, the simplest/most efficient solution is just drawing ten lines horizontally and ten lines vertically.

If you need to draw individual blocks and want them to have their own borders (be it because there are spaces between blocks or the border colors are different), you could try using Renderer's renderRect, which is a lower level version of drawRect and drawBorderRect. In this case you'll have to call the begin/end functions manually:

beginPath renderer
setFillColor renderer rectColor
renderRect renderer rectBounds
fill renderer

Alternatively, if you only want to draw borders, you can call:

setStrokeColor renderer color
setStrokeWidth renderer width

@fjvallarino fjvallarino added the question Further information is requested label May 19, 2023
@Lev135
Copy link
Author

Lev135 commented May 21, 2023

In my case I have colored cells, so solution with drawing lines doesn't work. ReplacingdrawRect with renderRect doesn't seems to have a notable effect. For @Deltaspace0 suggestion to use imageMem: I can't see any drawing primitives for such images... Maybe I've missed something. To be honest, I haven't quite figured out how it works and how it should solve my problem: render function will use a ready picture? For ColorPicker there should be no efficiency difficulies at all (untill we haven't several thousands of them).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants