schell / gelatin

A nice Haskell graphics API. There's always room for jello.
BSD 3-Clause "New" or "Revised" License
41 stars 4 forks source link

Flexibility with drawing primitives at runtime #34

Closed jxv closed 2 years ago

jxv commented 6 years ago

~Currently~ Previously, I used the sdl2-gfx package for drawing primitives. The primitives are currently placeholders until they're switched out for sprites. I want to transition into sprites to be easy, so I need to integrate gelatin first with primitives. I think adding or improving the API for primitives into gelatin should work similar to sdl2-gfx's API. Though, I'm open to alternatives.

These are the ones ~I'm currently using~ used. I think they're straightforward: smoothLine: https://hackage.haskell.org/package/sdl2-gfx-0.2/docs/SDL-Primitive.html#v:smoothLine fillRectangle: https://hackage.haskell.org/package/sdl2-gfx-0.2/docs/SDL-Primitive.html#v:fillRectangle smoothCircle: https://hackage.haskell.org/package/sdl2-gfx-0.2/docs/SDL-Primitive.html#v:smoothCircle fillCircle: https://hackage.haskell.org/package/sdl2-gfx-0.2/docs/SDL-Primitive.html#v:fillCircle fillPolygon: https://hackage.haskell.org/package/sdl2-gfx-0.2/docs/SDL-Primitive.html#v:fillPolygon

It's entirely possible that they'll require different shaders from the current simple2d one, as they'll need be more flexible at runtime. Issues

30 #28 would then be effected.

jxv commented 6 years ago

Even if it's temporary, it may be necessary to have another backend for only drawing primitives in this fashion. Of course, the gristle generated shaders would change that at some point.

jxv commented 6 years ago

By "flexibility," I mean positions and colors (non-gradient). Scaling and rotation is not used.

schell commented 6 years ago

I think we can write these primitives without altering the shaders or any of the compilation pipeline. The only departure from the sdl2-gfx versions would be that they return IO Renderer2, and in the case of shapes with colors, you would supply [multiplyV4 color] at render time.

jxv commented 6 years ago

Not quite. The aforementioned functions are called each frame. I guess I wasn't clear -- unless you mean to recreate another picture each frame. But doesn't that create a vertex object on each compile?

With my use case, the points between lines move around arbitrarily at runtime. I can imagine hacking together RenderTranform2 related functions likescale and rotate, but that seems overly difficult and would lose precision in thickness.

schell commented 6 years ago

If you'd like exactly these same signatures there will have to be some underlying layer or step that compiles to Renderer2, calls the rendering with the transformations you'd like and then releases the rendering. Doing it without releasing could be handled by supplying a rendering cache type as the first parameter. That's most likely what Renderer is in the sdl2-gfx calls.

schell commented 6 years ago

Would probably be better to have a special monadic context though, something like

type Pos = V2 Float
type Radius = Float
type Color = V4 Float
newtype RenderCache = RenderCache { unRenderCache :: Map Radius Renderer2 }

fillCircle :: (MonadIO m, MonadReader RenderCache m) => Pos -> Radius -> Color -> m ()
fillCircle pos rad color = do
  cache <- get
  r <- case M.lookup rad cache of
    Just r  -> return r 
    Nothing -> makeCircle rad
  snd r [moveV2 pos, multiplyV4 color]

Hand wavey.

jxv commented 6 years ago

I'm not sure how sdl2-gfx does it, but I'm willing to punt this. I'll just use two variations until I no longer need sdl2-gfx. My use case has gelatin integrated and can draw textures. And I don't think I'll need these primitives in a few months anyways. I rather have gelatin using gristle as a higher priority.