Rectangles: Texture Positioning and Scaling in SDL3


Screens, images, texture and sprites are rectangular, so this shape has a special importance to SDL3 and graphics programming in particular.

Rectangles: TSDL_FRect, PSDL_FRect and PPSDL_FRect

  PPSDL_FRect = ^PSDL_FRect;
  PSDL_FRect = ^TSDL_FRect;
  TSDL_FRect = record
    x: cfloat;
    y: cfloat;
    w: cfloat;
    h: cfloat;
  end;

TSDL_FRect describes a rectangle by four float point values (indicated by the F prefix). The variables x and y correspond to the x/y coordinates of the left upper corner of the rectangle, related to the origin 0/0 which is the left upper corner of, e.g. a texture, window,… The variable w is the width and h the height of the rectangle.

Often functions require an argument of PSDL_FRect type. This is the pointer counterpart to TSDL_FRect. And for convenience there is a double pointer PPSDL_FRect available, which in some cases may be needed.

Using Rectangles for Positioning and Scaling

The following code demonstrates the basic principle how to position and scale a texture simply by using rectangles in SDL3. It assumes you have the fpsdl.bmp image file available from the previous chapter about rendering a bitmap file. (If not, copy it from there.)

program SDL3_Rectangles;

uses SDL3;

var
  sdlWindow1: PSDL_Window;
  sdlRenderer: PSDL_Renderer;
  sdlSurface1: PSDL_Surface;
  sdlTexture1: PSDL_Texture;
  sdlRectangle: TSDL_FRect;

begin

  // initilization of video subsystem
  if not SDL_Init(SDL_INIT_VIDEO) then
    Halt;

  // create window and renderer
  if not SDL_CreateWindowAndRenderer('SDL3 Rectangles', 500, 500, 0, @sdlWindow1, @sdlRenderer) then
    Halt;

  // create surface from file
  sdlSurface1 := SDL_LoadBMP('fpsdl.bmp');
  if sdlSurface1 = nil then
    Halt;

  // create texture from surface
  sdlTexture1 := SDL_CreateTextureFromSurface(sdlRenderer, sdlSurface1);
  if sdlTexture1 = nil then
    Halt;

  // set scaling mode
  SDL_SetTextureScaleMode(sdlTexture1, SDL_SCALEMODE_NEAREST);

  // prepare rectangle enclosing word "SDL" in fpsdl.bmp
  sdlRectangle.x := 17;
  sdlRectangle.y := 104;
  sdlRectangle.w := 73;
  sdlRectangle.h := 36;

  // render "SDL"-part from the texture to the whole window
  SDL_RenderTexture(sdlRenderer, sdlTexture1, @sdlRectangle, nil);
  // render the whole texture into the rectangle dimensions
  SDL_RenderTexture(sdlRenderer, sdlTexture1, nil, @sdlRectangle);

  // render to window for 2 seconds
  SDL_RenderPresent(sdlRenderer);
  SDL_Delay(2000);

  // clear memory
  SDL_DestroyTexture(sdlTexture1);
  SDL_DestroySurface(sdlSurface1);
  SDL_DestroyRenderer(sdlRenderer);
  SDL_DestroyWindow (sdlWindow1);

  // quitting SDL3
  SDL_Quit;

end.

We will get this as a result.

Creative Commons License This image by https://www.freepascal-meets-sdl.net is licensed under a Creative Commons Attribution 4.0 International License.
The result of the example program (500×500 px window). A part of the full image is stretched in the background while the full image is also squeezed into a small area.

For comparison, the original 200×200 px image (fpsdl.bmp) looks like this:

Original image (200×200 px) with a marked area which represents the used rectangle dimensions.

The dotted black part marks the rectangle we used in the code.

Let’s dissect the code.

var
  sdlWindow1: PSDL_Window;
  sdlRenderer: PSDL_Renderer;
  sdlSurface1: PSDL_Surface;
  sdlTexture1: PSDL_Texture;
  sdlRectangle: TSDL_FRect;

In the var clause we declare the known variables for window, renderer, surface and a texture. Also we have a new variable of TSDL_FRect type.

  // prepare rectangle enclosing word "SDL" in fpsdl.bmp
  sdlRectangle.x := 17;
  sdlRectangle.y := 104;
  sdlRectangle.w := 73;
  sdlRectangle.h := 36;

After initializing SDL3 and setting up the window, renderer and texture as known, the rectangle is getting some values. It just encloses the word “SDL” in the original image (see above, black dots). 

Scaling in SDL3

Scaling Mode

Right before creating the surface and texture, there is this line in code.

  // set scaling mode
  SDL_SetTextureScaleMode(sdlTexture1, SDL_SCALEMODE_NEAREST); 

The SDL_SetTextureScaleMode(texture, scale mode) function sets the render mode. Possible values are

  1. SDL_SCALEMODE_NEAREST
    • nearest pixel sampling
  2. SDL_SCALEMODE_LINEAR
    •  linear filtering

The difference can be seen in the following image.

Positioning and Scaling SDL3 Textures by using Rectangles

  // render "SDL"-part from the texture to the whole window
  SDL_RenderTexture(sdlRenderer, sdlTexture1, @sdlRectangle, nil);
  // render the whole texture into the rectangle dimensions
  SDL_RenderTexture(sdlRenderer, sdlTexture1, nil, @sdlRectangle);

At this point happens the magic that leads to the resulting image. By the way, since the SDL_RenderTexture function requires the rectangle arguments to be of PSDL_Rect, we use the @-operator (pointer operator) here.

  // render "SDL"-part from the texture to the whole window
  SDL_RenderTexture(sdlRenderer, sdlTexture1, @sdlRectangle, nil);

This means, copy the area described by “sdlRectangle” from the source (“sdlTexture1” here) to the whole area (because of the nil value) of the destination, hence the whole window.

Since the window has a width and height of 500 px each, whereas the source rectangle has just a width of 73 px and a height of 36 px, SDL3 automatically scales the image to fit into the larger dimensions of the window.

A Texture Atlas (Spritesheet)

Instead of creating individual textures for every sprite in a game, often one texture atlas is used. A texture atlas is a large texture which contains all textures for the game. When composing a game scene, you just render all the needed textures from the texture atlas by using corresponding rectangles as just seen above. This method is fast and convenient.

Let’s get back to the code.

  // render the whole texture into the rectangle dimensions
  SDL_RenderTexture(sdlRenderer, sdlTexture1, nil, @sdlRectangle);

This means, copy the whole source texture (because of nil value) to the area described by “sdlRectangle”. The source is the 200×200 px “Free Pascal meets SDL” texture, which is squeezed to the 73×36 px rectangle at (x/y)-position (17/104). This is just what you see in the resulting image (above) where the whole image is squeezed into this tiny area.

Movement of Textures (Sprites)

Although not covered directly by this code example, you get the picture how to achieve the impression of movement of textures (sprites). Every game loop cycle you adjust the (x/y) coordinates of the rectangle for the destination to bring the texture about to move.

Clean up

After rendering the two textures as seen above, the program is delayed for 2 seconds, then cleans all objects from memory and quits SDL3. Nothing new here, though.

Previous Chapter | Next Chapter

[Title image created with https://flatai.org; public domain]

Leave a Reply

Your email address will not be published. Required fields are marked *