I was reading some SDL2 tutorials and I noticed that you need to pass your window surface handle to any drawRect calls. Should I create a global surface handle or pass the handle by reference into draw functions?

Also for dealing with characters sprites, code structure-wise, which method would be more maintainable: each character object encapsulate its own set of sprites, or have a Sprites class hold all sprite information, and retrieve from there?

Edit: By Jon's advice, I'll probably look at generating one big texture sheet and reading off of that to reduce texturing binding overhead. As for the surface handle, I've created it as a private member variable in my Game class, and will pass it to any Draw calls that need it.

  • \$\begingroup\$ I, personally, would use static methods of the Sprite class so I wouldn't have to go hunting through a bunch of code files; even with a low object count. Each object can store a pointer to its' texture and use it without knowing when or how the texture was initialized. Routing the texture accesses through static Sprite methods would allow content to be demand-loaded the first time it's requested. \$\endgroup\$ – Jon Feb 27 '16 at 21:39
  • \$\begingroup\$ If all of your character objects are similar (textured squares), you can use instancing to draw the same 4 vertices over and over again swapping in a new location, dimensions, and texture coordinates for each set. That process can be optimized by atlasing, which allows you to bind a single mega-texture, once per frame, as opposed to binding individual textures through iteration. In that case, what does Sprite do now? All "character objects" share the same atlas so you might decide to embed the atlas/textures within CharacterObject and just delete Sprite. \$\endgroup\$ – Jon Feb 27 '16 at 22:01
  • \$\begingroup\$ I'm not sure I understand; so if I had a Player1 sprite sheet and an Enemy sprite sheet, I would combine them into one big sheet and use coordinates to find the sprites I need per frame? \$\endgroup\$ – Chara Feb 27 '16 at 22:15
  • \$\begingroup\$ Correct. Player1 is from (0, 0) to (width / 2 - 1, height). Enemy is from (width / 2, 0) to (width, height). Each of those areas may be further divided into sub-areas for animation frames, isometric views, etc. The critical point here is that you will have eliminated all of the overhead generated by repetitive iterating, binding, and drawing. Furthermore, the CPU now hands the GPU a long list of chores, tells it "do that", then continues through the remainder of your logic. The CPU and GPU operate asynchronously, neither waiting on the other. \$\endgroup\$ – Jon Feb 27 '16 at 22:55
  • \$\begingroup\$ You can also run your Update() method's deltaTime through a cyclical function like sin() to generate a never-ending back and forth between -1 and 1. You can translate/scale/round/mangle that range into any other desired range. A range of 0-8 would cycle through the same 9-frame animation every 1.0f seconds, forever. If all animations are identical, we can update all of them at once, by uploading a single new float value each frame. If AnimationLength is included PerInstance, the GPU can, then, dynamically calculate the correct UVs, with zero CPU interaction. \$\endgroup\$ – Jon Feb 27 '16 at 23:08

In general, the moderators close "best" or "better" questions because answers will be primarily opinions. Please revise your question, sooner than later.

No: Is it better to X or Y?
Everyone is right.

Yes: Given identical inputs, which is faster, X or Y?
One of the two is faster regardless of how anyone feels about it.

I have no experience with SDL2, however, this site contains a number of examples that make sense to me. It appears that you are free to maintain global pointers, if desired:

//The window we'll be rendering to
SDL_Window* gWindow = NULL;

//The surface contained by the window
SDL_Surface* gScreenSurface = NULL;

//The image we will load and show on the screen
SDL_Surface* gHelloWorld = NULL;

Both approaches to character sprites are likely to have advantages over the other in certain circumstances. You should always try to avoid iterating over large collections of CPU data, uploading and drawing it one object at a time. That being said, do things the easiest way possible. If circumstances require an atlas, you're going to use an atlas; otherwise, just keep it simple and iterate. If both ways are about equal, go with the one you know best.

As a beginner, give yourself some leeway and just focus on completely understanding topics and techniques, rather than trying to produce the "best" code possible. Otherwise, you'll get stuck in feature creep and/or continue solving problems you haven't even had yet. 60FPS is acceptable and attainable, even with disorganized and inefficient code.


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