1
\$\begingroup\$

I have some c++ game code that draws the game state on each game-loop cycle in "immediate mode". By that I mean that the game code does not add the sprites to be drawn to any sort of "scene graph" or other data structure. It just starts from a blank slate on each game loop cycle, and piles on the sprites from back to front. (I know you might wonder what API this c++ code is actually using. Well, it's written in Marmalade, which I'm moving away from. Marmalade provides an abstraction layer and the essence of this question is about replacing that abstraction layer.)

I am having trouble understanding what "immediate mode" really means in opengl es, and how it relates to the "fixed function" vs. "programmable" pipeline. Some things I read say, don't use the old immediate mode functions, use the modern shader-based programmable API instead." But at the same time, I believe glDrawArrays() is fine to use in opengl es 2.0, right? So that's an "immediate mode" function.

(I believe what's going on here is that "immediate mode" means different things at different levels. My understanding is that a library like cocosd2-x is "retained mode" in that you add sprites to a scene graph that's managed by the engine. But at the opengl level itself, I think "immediate mode" means something a bit different, namely whether you keep the vital drawing structures in CPU space until you draw them with a begin() end() sandwich, versus uploading them ahead of time to the GPU. So it that sense the GPU "retains" your data across calls. But still, you can draw a frame in "immediate" mode in the sense of piling on sprites one at a time using glDrawArrays() as many times as necessary.)

In the "hello world" example of cocos2d-x, we see

// add the sprite as a child to this layer
this->addChild(sprite, 0);

That is exactly what I don't want to have to do, because as I say, my code base is set up not thinking of the sprites as objects, but just as drawing a bunch of rectangles from texture sheets (atlases) stacked on top of each other. I don't want to think of adding sprites to some scene graph and "letting the engine take care of it." That may be a fine way of thinking in general, but it would involve a huge rewrite of my existing code.

On the other hand, I think I like the idea of cocos2d-x because it gives me a convenient way to develop a code base that I can develop on Windows and run on iPhone, Android, and elsewhere.

So what I'm trying to understand is: Can I use cocos2d-x in some "immediate mode" fashion?

Basically, in opengles 2.0, I am allowed to call glDrawArrays(), correct? And if I batch up my sprites in a reasonable way, I can limit the number of calls to glDrawArrays() in each frame. So I want to do that, and I'm fine writing that gl code myself. But I think even though perhaps this defeats some of the point of using cocos2d-x in the first place, there are still huge portability and not-reinventing-the-wheel advantages of using cocos2s-x vs writing things from scratch myself?

So can I use cocos2s-x in that "immediate mode" way, and still retain the write-once/run-everywhere benefits?

\$\endgroup\$
1
\$\begingroup\$

Cocos2d-x can draw in immediate mode, it's way easier to be done in 2.x but it's possible in 3.x as well. basically you have two ways of doing that:

  • The easiest route is to create your own class inherited from CCNode (or Node if you are using v3.x) and override it's void draw()(or for v3.x void draw(Renderer *renderer, const Mat4& transform, uint32_t flags);) function.
    This is how most of cocos2d classes are implemented themselves. For example that CCSprite you mentioned, does the same thing behind the hood.

  • A more complex method is to override 'void visit' (or for v3.x virtual void visit(Renderer *renderer, const Mat4& transform, uint32_t flags);) function. Normally this function does all this nodes transformations, then start rendering all it's children from the least zOrder to the highest. Also it calls it's draw function before it's first child with zOrder=0.

  • In case you are using cocos2d-x v3.x you should use CustomCommand.

So when should you override each of those functions? Think of it this way, is this class of yours going to integrate inside cocos2d code flow, or are going to break everything, and implement your own stuff all over? If it's the former, I suggest you go with overriding draw method, and if it's the later overriding visit is wiser.

If you want more exact information on how is each frame processed in cocos2d-x, take a look at Director::drawScene(), you'll basically find, in each frame, these are done in specified order:

  1. Compute delta_time
  2. Process input (aka. touch events, key events, ...)
  3. Update functions & actions
  4. call visit function on the running scene
  5. (in case of v3.x) do actual rendering stuff
\$\endgroup\$
  • \$\begingroup\$ Thank you very much for the detailed answer. A couple follow-ups: (a) Is there an advantage of using the Draw() vs. visit() vs. CustomCommand approach in terms of compatibility with future versions of cocos2d-x? (b) I may be tempted to use the Draw() override in case I want to use some of the traditional cocos functionality at some point. However, given that I don't necessarily care about the cocos functionality like animations or button handling or whatever, is there an advantage to using cocos2d-x at all vs. just writing stuff from scratch? Seems to me there is, just wanted to confirm. \$\endgroup\$ – M Katz Aug 12 '14 at 5:14
  • \$\begingroup\$ Sorry, one more follow-up: So it sounds like in theory my entire screen can be just a single "node" from the cocos2d-x point of view. If I already have a single function that draws the whole scene back to front, there is no advantage to treating it as multiple nodes in my cocos2d-x scene, right? Or perhaps I should have one node per sprite atlas or something like that? \$\endgroup\$ – M Katz Aug 12 '14 at 5:23
  • \$\begingroup\$ a) if you are going to use v3.x you should use custom command, either with draw or visit. and personally I prefer draw method since it almost needs no boilerplate code to make compatible with other stuff. b) porting to other systems is the biggest advantage. Also there are lots of other stuff that might help you in way (like textures, audio, debug helpers, ...) but you might take a look at SDL2 too (that's what I've migrated to for just one of my projects which required to run without GUI in some cases). c) As far as I know, there is absolutely no advantage of using scene graph in your case. \$\endgroup\$ – Ali1S232 Aug 12 '14 at 7:51

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.