SDL2 allows for viewports. Have a look at the following screenshot of a SDL2 game (Battle for Wesnoth).
This is a classical situation to use viewports. The game screen is clearly parted into three distinguished areas. The main screen is the large part left with the mountains and the castles. Then there is the minimap in the right-upper corner. And a statistics overview under the minimap. These areas and the corresponding viewports are highlightened in the following screenshot.
The advantage of viewports is that each of them behaves like an own window, so if you draw to the right outside of viewport 1 in the screenshot above, the texture will just be clipped and there is no overlap into viewport 2 oder 3.
Let’s have a look at the code.
program SDL2_Viewport;
uses SDL2;
const
Viewport1: TSDL_Rect = (x: 0; y: 0; w: 400; h: 500);
Viewport2: TSDL_Rect = (x: 400; y: 0; w: 100; h: 300);
Viewport3: TSDL_Rect = (x: 400; y: 300; w: 100; h: 200);
BlackDot: TSDL_Rect = (x: 10; y: 10; w: 3; h: 3);
var
sdlWindow1: PSDL_Window;
sdlRenderer: PSDL_Renderer;
begin
//initilization of video subsystem
if SDL_Init(SDL_INIT_VIDEO) < 0 then Halt;
SDL_CreateWindowAndRenderer(500, 500, SDL_WINDOW_SHOWN, @sdlWindow1, @sdlRenderer);
if (sdlWindow1 = nil) or (sdlRenderer = nil) then Halt;
// fill every viewport with background color and draw a black dot into it
SDL_RenderSetViewport(sdlRenderer, @Viewport1);
SDL_SetRenderDrawColor(sdlRenderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(sdlRenderer, nil);
SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(sdlRenderer, @BlackDot);
SDL_RenderSetViewport(sdlRenderer, @Viewport2);
SDL_SetRenderDrawColor(sdlRenderer, 255, 255, 0, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(sdlRenderer, nil);
SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(sdlRenderer, @BlackDot);
SDL_RenderSetViewport(sdlRenderer, @Viewport3);
SDL_SetRenderDrawColor(sdlRenderer, 0, 255, 0, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(sdlRenderer, nil);
SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(sdlRenderer, @BlackDot);
// render to window for 2 seconds
SDL_RenderPresent(sdlRenderer);
SDL_Delay(2000);
// clear memory
SDL_DestroyRenderer(sdlRenderer);
SDL_DestroyWindow (sdlWindow1);
//shutting down video subsystem
SDL_Quit;
end.
The result will look like this:
First we set up some SDL2 rectangles by
const
Viewport1: TSDL_Rect = (x: 0; y: 0; w: 400; h: 500);
Viewport2: TSDL_Rect = (x: 400; y: 0; w: 100; h: 300);
Viewport3: TSDL_Rect = (x: 400; y: 300; w: 100; h: 200);
BlackDot: TSDL_Rect = (x: 10; y: 10; w: 3; h: 3);
“Viewport1” represents the red viewport (left), “Viewport2” the yellow (upper-right) and “Viewport3” the green (lower-right) viewport in the result image.
Notice how we just prepare one “BlackDot” rectangle for a black dot of 3×3 px dimension at location (10/10).
After setting up SDL2, a renderer and a window as known, we start to set up the first (red, left) viewport.
// fill every viewport with background color and draw a black dot into it
SDL_RenderSetViewport(sdlRenderer, @Viewport1);
SDL_SetRenderDrawColor(sdlRenderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(sdlRenderer, nil);
SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(sdlRenderer, @BlackDot);
It is simple as that. Use the function SDL_RenderSetViewport(renderer, rectangle pointer) to set up a viewport. This function returns 0 on success or -1 on failure.
SDL_RenderSetViewport(renderer: PSDL_Renderer; const rect: PSDL_Rect)
After we set up the viewport, we set the draw color by SDL_SetRenderDrawColor(renderer, red, green, blue, alpha) to red (255/0/0/no transparency). Then we use SDL_RenderFillRect(renderer, rectangle pointer) to fill the whole viewport by not specifying a rectangle (nil). Both functions are known from a previous chapter.
Then the color is set to black and a tiny 3×3 rectangle is drawn at location (10/10).
This procedure is repeated for the other two viewports. Notice again, how we use the same rectangle for the black dot though and where it is shown in the result image. The black dot is always drawn at location (10/10) relative to the respective viewport’s location!
As general rule it applies:
The coordinates are always relative to the currently set viewport.
Well, the remaining parts of the code provides nothing new, just the rendering for 2 seconds and some clean up.
Let’s close with some helpful remarks.
No SDL_RenderClear for Viewports!
Do not use SDL_RenderClear(renderer). It will ignore the viewports and clear the whole window with the set drawing color.
Resetting the Viewport
The resetting is done simple by SDL_RenderSetViewport(renderer, nil) as one would expect.
Ukrainian translation avaliable here: https://lazarus-games.blogspot.com/p/11.html