Am I missing something obvious? iOS development

Hey Folks…

Trying to get started with SDL on iOS.

First test, modified rectangles.c to draw “concentric rectangles” on tap / click.

Is there some “double buffer” setting I don’t see?

Here’s what I get, drawing green, blue, cyan, magenta, yellow rectangles (I left out red, as will be obvious shortly):

Screen Recording 2022-02-11 at 9.04.49 AM

It looks like I end up with a black-cleared buffer and a red-cleared buffer, alternating with each call to SDL_RenderPresent(renderer);?

I also have an old copy of SDL — looks like the last commit was Oct 10, 2018 – which, with the same code, gives me what I expected:

Screen Recording 2022-02-11 at 9.03.30 AM

Same result on Simulator and Device.

Here’s the source code (based on the rectangles.c demo):

/*
 *
 * firstTest.c
 *
 *  based on rectangles.c
 *  written by Holmes Futrell
 *  use however you want
*/

#include "SDL.h"

void
fatalError(const char *string)
{
	printf("%s: %s\n", string, SDL_GetError());
	SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, string, SDL_GetError(), NULL);
	exit(1);
}

void
myDrawRect(SDL_Renderer *renderer, int x, int y, int *c)
{
	int renderW;
	int renderH;
	
	SDL_RenderGetLogicalSize(renderer, &renderW, &renderH);
	
	//	centered rect
	SDL_Rect rect;
	rect.x = x;
	rect.y = y;
	rect.w = renderW - x * 2;
	rect.h = renderH - y * 2;
	
	/*  Fill the rectangle in color */
	SDL_SetRenderDrawColor(renderer, c[0], c[1], c[2], 255);
	SDL_RenderFillRect(renderer, &rect);
	
	/* update screen */
	SDL_RenderPresent(renderer);
}

int
main(int argc, char *argv[])
{

    SDL_Window *window;
    SDL_Renderer *renderer;
    SDL_Event event;
    int windowW;
    int windowH;

	int done;

	// 5 colors
	int colors[5][3] = {
		{  0, 255,   0},	// green
		{  0,   0, 255},	// blue
		{  0, 255, 255},	// cyan
		{255,   0, 255},	// magenta
		{255, 255,   0}		// yellow
	};
	int c = 0;
	int x = 20, y = 20;
	
    /* initialize SDL */
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        fatalError("Could not initialize SDL");
    }

    /* create window and renderer */
    window = SDL_CreateWindow(NULL, 0, 0, 320, 480, SDL_WINDOW_ALLOW_HIGHDPI);
    if (window == 0) {
        fatalError("Could not initialize Window");
    }
    renderer = SDL_CreateRenderer(window, -1, 0);
    if (!renderer) {
        fatalError("Could not create renderer");
    }

    SDL_GetWindowSize(window, &windowW, &windowH);
    SDL_RenderSetLogicalSize(renderer, windowW, windowH);

    /* Fill screen with black */
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);

	// draw first rect
	myDrawRect(renderer, x, y, colors[c % 5]);
	x += 20;
	y += 20;
	c += 1;

	done = 0;
	while (!done) {
		while (SDL_PollEvent(&event) == 1) {
			switch (event.type) {
				case SDL_QUIT:
					done = 1;
					break;
				case SDL_MOUSEBUTTONDOWN:
					myDrawRect(renderer, x, y, colors[c % 5]);
					x += 20;
					y += 20;
					c += 1;
					break;
			}
		}
	}
		
    /* shutdown SDL */
    SDL_Quit();

    return 0;
}

I should also note… the same issue presents with all of the Demo app code (rectangles.c, happy.c, touch.c, fireworks.c, etc). They work fine with the Oct 2018 SDL code, not with the current.

SDL2 makes no guarantees about the state of the target (buffer) after a SDL_RenderPresent() so you should always call SDL_RenderClear() before drawing the next frame. The behavior might have changed between the two versions, but they are both legitimate. This is what the documentation says:

“The backbuffer should be considered invalidated after each present; do not assume that previous contents will exist between frames. You are strongly encouraged to call SDL_RenderClear() to initialize the backbuffer before starting each new frame’s drawing, even if you plan to overwrite every pixel”.

Hmmm… so, if I’ve drawn 50 various colored rectangles, and I want to draw a new rectangle…

I have to:

  • SDL_RenderClear()
  • re-draw the previous 50 rectangles
  • draw the new rectangle

and then SDL_RenderPresent() ?

You don’t have to, no. If you want to ‘build up’ your display in stages, you can use a ‘target texture’ (SDL_RENDERACCESS_TARGET). That will not be cleared or invalidated on a SDL_RenderPresent() so it will allow you to do exactly what you describe.

With that approach, instead of just calling SDL_RenderPresent() you need to do something like this:

	SDL_SetRenderTarget(renderer, NULL);
	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
	SDL_RenderClear(renderer);
	SDL_RenderCopy(renderer, target_texture, &srcrect, &dstrect);
	SDL_RenderPresent(renderer);
	SDL_SetRenderTarget(renderer, target_texture);

Ah… so, modifying the rectangle.c source was probably not the best one to get my feet wet with :frowning:

Thanks a bunch!