zengine icon indicating copy to clipboard operation
zengine copied to clipboard

Sprites

Open define-private-public opened this issue 8 years ago • 22 comments

This is now a TODO list for me. The original comment is quoted at the bottom.

TODO:

  • [x] Write up a spec file and get it approved
  • [x] Port simple data structures and basic features over from Masala
  • [x] Write the loader
  • [ ] Create a SpriteBatch object for rendering. Give it some extra fun things like blending options and whatnot
  • [x] be able to display an animated sprite
  • [ ] ensure that origins and rotations are working.
  • [x] Write an simple example of the "Blau Geist"
  • [ ] Port the more complicated features of the Sprite from Masala
  • [ ] Write a more complex example. A character that walks, attacks, jumps
  • [ ] An example with multiple sprites.
  • [ ] copy constructors
  • [ ] fix the origin of the Blau Geist example to use (0, 0). Ensure that it's in the correct spots for both 2D and 3D mode.

Questions I've got:

  • [x] How to deal with sending timing updates?
  • [x] Where should we place the sprite's origin? And what about the coordinate system in general?

I'm interested in working on a Sprite object, so that this engine can have more 2D stuff than only the DrawTexture command.

I'm thinking about porting the Sprite object I made for my Masala engine a while back. There are a few tweaks and extra I'd like to add. How does this sound to you?

What are your opinions on the file format I designed? Example one, Example two.

I'd also like to get a Spline implementation working, but I'd rather get something simple working first. I saw that you had one in Frag. Did it go well?

define-private-public avatar Aug 12 '17 04:08 define-private-public

I think Raylib has quite a bit of sprite support we could probably port with minimal effort. I designed a texture packer for frag and a texture format which we could easily port over to this engine.

In regards to the spine implementation, yes it did go very well and I think we can also port it over here with some effort. I'll triage these shortly and get them in order that I think they can be addressed. I think this one is probably top in priority and then examples.

zacharycarter avatar Aug 12 '17 04:08 zacharycarter

AFAICT, Raylib supports spritefonts and rendering to textures; and that's it. When I meant sprite, I mean more complex lines like animation & sequences. That's what I made in Masala.

define-private-public avatar Aug 12 '17 04:08 define-private-public

Gotcha - I was under the impression raylib had more support than that. Sure we can borrow from your work on Masala then. Feel free to take this on and if you have any questions I can try to answer them.

As far as formats go, we should pick something easily parsable and preferably parsable by existing solutions so we don't have to invent our own.

For frag I used the https://nim-lang.org/docs/parsecfg.html module and my texture packer spit out textures in this format - https://github.com/fragworks/frag/blob/master/tools/texture_packer/tinydeflate/tilesheet.atlas

Even if we have to write our own parser, that's fine, but I think using popular formats might be a better option - your thoughts?

zacharycarter avatar Aug 12 '17 04:08 zacharycarter

I designed that format so it could be edited with a text editor. It's not the most optimal or space saving, but I think it did work pretty well for me.

As long as it's documented we should be fine for the short-term, but in the long term we should make some tools were people can do things such as select frames, order them into sequences, define origin points, pack them into one sheet, and save the file.

define-private-public avatar Aug 12 '17 04:08 define-private-public

I'm editing the original comment to use it as a TODO list.

define-private-public avatar Aug 14 '17 02:08 define-private-public

@zacharycarter I've got two questions that need answers for you:

  1. How are we going to deal with timing & updates? E.g. Many games engines have a float deltaTime parameter in their update() and draw() methods that are supposed to be passed down to everything that needs to be updated over a certain amount of time. I my case, this is sprite animation. How do you handle this right now with the 3D models? And what would be the best way for me to handle this with the Animated sprites?

  2. I'm making two objects right now Sprite and ZSprite. Sprite is the base class. In the future, SplineSprite will sub-object it. Does the design look good to you so far? https://github.com/define-private-public/zengine/blob/13.sprites_implementation/src/zengine/sprite.nim#L30

define-private-public avatar Aug 17 '17 01:08 define-private-public

  1. I tried to make the zengine footprint as small as possible and this means that it's up to the player to implement the game loop. For animations I think for now I'm just passing sdl.getTicks() to the method that needs time adjustments, see here - https://github.com/zacharycarter/zengine/blob/5330a20ae76eadcc3e7feeac2cc9e203611418e1/src/zengine/models.nim#L554

Ideally the drawModel proc would take in as a parameter, and I think it should be the same for whatever other draw methods we have that need timing. We can build samples with example game loops.

  1. Looks good to me so far 👍

zacharycarter avatar Aug 17 '17 23:08 zacharycarter

Doing sdl.getTicks() for that is kind of living on the dangerous side:

It's not synced with the current logic frame or render frame. Say if we call sdl.getTicks() at the begging of a draw, then 4 milliseconds later we call it again sdl.getTicks(). Those time dependent drawings will be out of sync. 4 milliseconds doesn't seem like a lot but it can be.

Since it also has to go through a whole call stack, (and fetch the location in memory), it can lead to slowdown as well. It would be better to call getTicks() once at the top of an update/draw loop, store it in a variable, and then use that elsewhere. As much as I don't like global state objects, it might be a good idea to make one of those here. E.g. we create a ZApp object, and it has a member that stores this value for us.

Also IIRC, getTicks() only has millisecond resolution. While that's okay (especially for drawing), I think some people might prefer something like microsecond resolution for logic updates. I did make the stopwatch package: https://gitlab.com/define-private-public/stopwatch and it has higher resolution. It can also be stopped and started, which might be useful (for some people).

This is starting to get out of the scope of the Sprite object, shall I make a new ticket for this?

define-private-public avatar Aug 18 '17 00:08 define-private-public

I agree we shouldn't use sdl.getTicks() probably the high performance counter sdl2 offers or your stopwatch package. I think sdl2's high performance counter will work for mobile too so that's something to consider.

If anything I'd rather have a timer module which does what you're describing for us. I'll make a new issue for this and we can discuss further there.

zacharycarter avatar Aug 18 '17 00:08 zacharycarter

Mind if I reserve 03 as the ZSprite example?

define-private-public avatar Aug 23 '17 01:08 define-private-public

Go for it.

Also feel free to put a PR in for stopwatch use, etc...

zacharycarter avatar Aug 23 '17 22:08 zacharycarter

Little bit of an update now. I got done with the basic ZSprite file format loader done (and it's now shoved into the ZSprite object.

I think SpriteBatch is where the OpenGL and shader stuff should live. Any thoughts on that? How do you currently init the 3D stuff for model rendering what whatnot?

define-private-public avatar Aug 31 '17 02:08 define-private-public

Right now there's a default shader that gets loaded at startup. You can also load models with specific shaders, although it might make more sense to allow you to pass in a shader on a particular draw call. I'm going to be away this weekend, but when I get back let's review what you have so far (please make a PR) and we can figure out how best to integrate your changes.

To answer your question - models are loaded in model.nim and then there are two functions in zgl that have to do with them - loadModel and drawModel. All the required shader setup etc is either handled by the setup of the default shader with the zgl module initializes, or is taken care of in the example file.

zacharycarter avatar Sep 01 '17 06:09 zacharycarter

Well, I do need to clarify that no rendering is happening at this moment. It's only loading and parsing. If you're still fine with merging that in for the moment I'll make the PR, but I'd really like to get something drawing on the screen first. I don't like saying "we have sprite, but we can't draw them at the moment."

define-private-public avatar Sep 01 '17 14:09 define-private-public

I added a new question: What should we consider the origin of the sprite to be? I'm not talking about the origin within the .zsprite file format, that's already done. I'm talking about when it comes to rendering.

I know that traditionally in 2D games we used a Cartesian graph that was flipped along the X axis, with (0, 0) being the top left of the screen, and (0, 0) being origin of the sprite (which was also in the top left). But we're working in 3D, and that's where our sprites live.

I'd like to propose that we should use a normal Cartesian graph, with (0, 0) being in the center of the screen. As for the sprite, the origin of the sprite should be the absolute center. This might get slightly tricky when we have to deal with an animated sprite who's frames are non all of the same dimension, but I think this is the best solution.

What are your thoughts?

EDIT: additional discussion here: https://github.com/zacharycarter/zengine/issues/33

define-private-public avatar Sep 02 '17 17:09 define-private-public

Actually, I think I'll send you a PR soon for what I have (minus some testing code).

define-private-public avatar Sep 02 '17 18:09 define-private-public

PR for what I've got so far is right here: https://github.com/zacharycarter/zengine/pull/32

define-private-public avatar Sep 02 '17 19:09 define-private-public

I also could use a proc in zgl to render a texture in a 3D space. So far, I only see how to draw a texture in 2D.

define-private-public avatar Sep 04 '17 17:09 define-private-public

Also, sprite transparency seems to not be working. If you check the sheet for BlauGest it should be transparent in the background. I think this is fixed by a call to glBlendFunc(). Which one should we be using? Or did we forgot the alpha channel in the shader? IIRC, some depth buffer stuff might also play a role in this, but I'm a little fuzzy on this. Sample pic included of what's happening now; some of the text is getting obstructed by the whole sprite frame:

bad-blending

define-private-public avatar Sep 04 '17 17:09 define-private-public

Are you fine with me using this sprite as one for a more complex example?

https://opengameart.org/content/platformer-animations

I'd like to doodle my own animation (like I did with the Blau Geist), but I'd rather get some more core stuff done first.

define-private-public avatar Sep 11 '17 02:09 define-private-public

I'm cool with that

zacharycarter avatar Sep 11 '17 03:09 zacharycarter

Good. Later on I might replace it with an original animation.

Something I do want to note, after I get done with this issue and #34, I'm going to duck out a little bit from zengine to finish up another project I've been juggling around for the past 3-4 months. I'll come back to focus more on zengine, but I've learned that I need to do one thing at a time. If I'm lucky I should only be gone for a month or less.

I'll still probably log issues and ideas. If any issues arise from the sprite module I'll come and fix them.

define-private-public avatar Sep 11 '17 03:09 define-private-public