Cutting SDL_Rect object with another SDL_Rect

Hi everyone!
I am new to SDL and currently practicing drawing shapes using C++
My understanding is that each Rectangle is drawn sequentially in the buffer on top of previously drawn shapes.
So my question is - is there a way to “pre-process” a rectangle by cutting part of it with another rectangle (making the respective pixels transparent) and drawing the resulting shape into the buffer. The idea is to keep the previously drawn shapes in the background partially visible.

Should I go with using a surface or texture? What is the process of pre-processing (compositing) shapes?
An example code is much appreciated?

Thanks in advance.

The way I’d do it is figure out the overlap yourself, then draw the overlapping portion separately using whatever blend mode + alpha transparency is appropriate.

SDL has various functions to help you with stuff like checking if rectangles overlap etc. Look in SDL_Rect.h

Thanks for the reply @sjr
I’ve tried using blending modes but it does’t seem to work as expected.
I am looking for example code or more detailed explanation how to approach the problem.
Unfortunately I am not able to find anything in this form or online about it.

Can you provide an image example on how you want it to look when two rects collide/intersect?

Do you have something like this in mind?

ClippingExample

1 Like

There’s also SDL_SetTextureAlphaMod(), which you can use to set the overlapping texture to be more transparent, draw the overlapping region, then set it back to normal and draw the non-overlapping parts.

Hi @Daniel1985 ,
Thanks for the reply this is going in the right direction but let’s say there is something already drawn bellow the two rectangles so the green rectangle clipping the red one should look something like this:

example

On the image - the background is visible where the green (invisible) rectangle is positioned.

Having a bit of a hard time visualizing what you’re describing in your text.

Perhaps if you could explain what your end goal is and what the mechanic should do?

Hi @Daniel1985, I am just trying to draw a Rectangle with user defined thick border on top of other shapes.

Then I guess this is want you want to achieve:

ClippingExample

In the above gif, I’m rendering a filled red SDL_Rect that moves with the mouse. Then there’s 3 other filled SDL_Rect’s - the green, the blue and the orange.
I basically then do an intersection-check between the red rect and the other rects, and renders the intersection(s) on top of the red rect. A bit hacky but it works.
Note: this is kinda messy and kind of unnecessary work for what you want to do.

But if all you want to do is render a rect with a border on top of other rects, it would be easier to just have a texture of a given size, with a border and transparency inside the border.

Let me know if you want the code for doing what’s happening in the above gif or if you decide on using a border texture instead.

1 Like

For a thick-border rect, I usually just do something like one of the following:

void draw_thick_rect(SDL_Renderer *rend, SDL_Rect *outer, int border_thickness) 
{
    SDL_Rect drawrect = *outer;
    for (int i=0; i<border_thickness; i++) {
        SDL_RenderDrawRect(rend, &drawrect);
        drawrect.x++;
        drawrect.y++;
        drawrect.w -= 2;
        drawrect.h -= 2;
    }
}

void draw_thick_rect2(SDL_Renderer *rend, SDL_Rect *outer, int border_thickness) 
{
    SDL_Rect drawrect;

    /* top */
    drawrect = (SDL_Rect) {outer->x, outer->y, outer->w, border_thickness};
    SDL_RenderFillRect(rend, &drawrect);

    /* bottom */
    drawrect = (SDL_Rect) {outer->x, outer->y + outer->h - border_thickness, outer->w, border_thickness};
    SDL_RenderFillRect(rend, &drawrect);

    /* left */
    drawrect = (SDL_Rect) {outer->x, outer->y + border_thickness, border_thickness, outer->h - (2 * border_thickness)};
    SDL_RenderFillRect(rend, &drawrect);
    
    /* right */
    drawrect = (SDL_Rect) {outer->x + outer->w - border_thickness, outer->y + border_thickness, border_thickness, outer->h - (2 * border_thickness)};
    SDL_RenderFillRect(rend, &drawrect);
}

No need to mess around with textures, afaik.

Or just use SDL_RenderFillRect to draw the border.

One rect for the top, one rect for the bottom, one rect for the left and one rect for the right.

Like chvolow24 and Peter wrote above - instead of using a texture, just render 4 rects:

Yes this is exactly what I was trying to do.
If you are able to share the code that would be great.
I would love to try it.
I am curious why it toesn’t work on the image texture.

@chvolow24 , @Daniel1985
I was thinking about the same hack.
But got curious if SDL is capable of more complex compositing.
Like layer masks and grouping (as seen in Photoshop for example).

I have attached the complete code for my little test application.

The reason why nothing happens when the mouse rect is in the lower right corner is because that is just a background texture being rendered behind everything else, in the size of the window.
I don’t do any intersection-check between the mouse rect and that.

For simplicity and to reduce the code amount, I’ve removed the code for the background texture.

If you run the code, you should see a window with a black background, 3 colored rects and a red rect that follows the mouse pointer.
Press the up/down key on the keyboard to increase/decrease the border size on the red rect.

Code
#include <stdio.h>
#include <string>

#include <SDL.h>

#define WINDOW_WIDTH	(800)
#define WINDOW_HEIGHT	(600)

SDL_Window* pWindow = nullptr;
SDL_Renderer* pRenderer = nullptr;

SDL_Rect Rects[3]	= {0};
SDL_Rect RectMouse	= {0, 0, 0, 0};

SDL_Color RectColors[3] =
{
	{25, 255, 90, 255},
	{25, 150, 255, 255},
	{255, 100, 25, 255},
};

double OldTime = 0.0;
double NewTime = 0.0;
double DeltaTime = 0.0;

float Border = 50.0f;

bool Running = true;

bool InitSDL()
{
	if(SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		printf("Error: SDL could not initialize! %s\n", SDL_GetError());
		return false;
	}

	pWindow = SDL_CreateWindow("SDL clipping", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
	if(!pWindow)
	{
		printf("Error: SDL window could not be created! %s\n", SDL_GetError());
		return false;
	}

	pRenderer = SDL_CreateRenderer(pWindow, -1, SDL_RENDERER_ACCELERATED);
	if(!pRenderer)
	{
		printf("Error: SDL renderer could not be created! %s\n", SDL_GetError());
		return false;
	}

	SDL_SetRenderDrawColor(pRenderer, 0, 0, 0, 255);
	SDL_SetRenderDrawBlendMode(pRenderer, SDL_BLENDMODE_BLEND);

	SDL_RenderClear(pRenderer);
	SDL_RenderPresent(pRenderer);

	return true;
}

void DeinitSDL()
{
	SDL_DestroyRenderer(pRenderer);
	SDL_DestroyWindow(pWindow);

	SDL_Quit();
}

void InitAssets()
{
	Rects[0] = {0,					0,					WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2};
	Rects[1] = {WINDOW_WIDTH / 2,	0,					WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2};
	Rects[2] = {0,					WINDOW_HEIGHT / 2,	WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2};

	RectMouse = {0, 0, 350, 250};
}

void HandleEvents()
{
	SDL_Event Event = {0};
	while(SDL_PollEvent(&Event))
	{
		switch(Event.type)
		{
			case SDL_QUIT:
			{
				Running = false;

				break;
			}

			default:
				break;
		}
	}
}

void Update()
{
	NewTime = (double)SDL_GetTicks();
	DeltaTime = (NewTime - OldTime) * 0.001;
	OldTime = NewTime;

	int32_t MouseX = 0;
	int32_t MouseY = 0;
	SDL_GetMouseState(&MouseX, &MouseY);

	// The mouse rect follows the mouse pointer
	RectMouse.x = MouseX - (RectMouse.w / 2);
	RectMouse.y = MouseY - (RectMouse.h / 2);

	// Hold the up/down key on the keyboard to increase/decrease the border size (clamped between 'Lowest' and 'Highest')

	const Uint8* pKeyboardState = SDL_GetKeyboardState(nullptr);
	const float Speed = 64.0f;
	const float Lowest = 5.0f;
	const float Highest = 50.0f;

	if (pKeyboardState[SDL_SCANCODE_UP])
	{
		Border += Speed * (float)DeltaTime;

		if(Border > Highest)
			Border = Highest;
	}

	else if (pKeyboardState[SDL_SCANCODE_DOWN])
	{
		Border -= Speed * (float)DeltaTime;

		if(Border < Lowest)
			Border = Lowest;
	}
}

void Render()
{
	SDL_SetRenderDrawColor(pRenderer, 0, 0, 0, 255);
	SDL_RenderClear(pRenderer);

	//////////////////////////////////////////////////////////////////////////

	// First render the three colored rects that the mouse rect should check intersection against
	for (uint32_t i = 0; i < 3; ++i)
	{
		SDL_SetRenderDrawColor(pRenderer, RectColors[i].r, RectColors[i].g, RectColors[i].b, RectColors[i].a);
		SDL_RenderFillRect(pRenderer, &Rects[i]);
	}

	// Render the mouse rect
	SDL_SetRenderDrawColor(pRenderer, 200, 0, 0, 255);
	SDL_RenderFillRect(pRenderer, &RectMouse);

	for (uint32_t i = 0; i < 3; ++i)
	{
		const SDL_Point BorderSize			= {(int32_t)Border, (int32_t)Border};
		const SDL_Rect	IntersectingRect	= {RectMouse.x + BorderSize.x, RectMouse.y + BorderSize.y, RectMouse.w - (BorderSize.x * 2), RectMouse.h - (BorderSize.y * 2)};
		SDL_Rect		Intersection		= {0, 0, 0, 0};

		// Do intersection test between the mouse rect (minus the border size, see 'IntersectionRect' above) and the colored rects
		if(SDL_IntersectRect(&Rects[i], &IntersectingRect, &Intersection) == SDL_TRUE)
		{
			// If an intersection occurs, the intersection part is rendered on top of the mouse rect, in the same color as the rect that the mouse rect is intersecting with
			SDL_SetRenderDrawColor(pRenderer, RectColors[i].r, RectColors[i].g, RectColors[i].b, RectColors[i].a);
			SDL_RenderFillRect(pRenderer, &Intersection);
		}
	}

	//////////////////////////////////////////////////////////////////////////

	SDL_RenderPresent(pRenderer);
}

int main(int argc, char** argv)
{
	if(!InitSDL() )
		return -1;

	InitAssets();

	while(Running)
	{
		HandleEvents();
		Update();
		Render();
	}

	DeinitSDL();

	return 0;
}

Hi @Daniel1985
I am sorry for the delay. Thank you so much for the code. It’s a pleasure to look at it.
I’ve played around with it and managed to make it work with a texture too.
It probably needs more attention to be generalized. Here is the new code (I am using SDL2_Image library, note the include statements, but it should work with BMP image).

I’ll be happy if you have time to look at it and let me know your opinion.

#include <stdio.h>
#include <string>
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
using namespace std;

#define WINDOW_WIDTH	(800)
#define WINDOW_HEIGHT	(600)

SDL_Window* pWindow = nullptr;
SDL_Renderer* pRenderer = nullptr;

SDL_Rect Rects[4]	= {0};

//the 4th rect will hold the image
SDL_Surface* tempSurface = IMG_Load("assets/image.png");
SDL_Texture* tex = NULL;

SDL_Rect srcRect = {306, 102, WINDOW_WIDTH/2, WINDOW_HEIGHT/2};

SDL_Rect RectMouse	= {0, 0, 0, 0};

SDL_Color RectColors[3] =
{
	{25, 255, 90, 255},
	{25, 150, 255, 255},
	{255, 100, 25, 255},
};

double OldTime = 0.0;
double NewTime = 0.0;
double DeltaTime = 0.0;

float Border = 50.0f;

bool Running = true;

bool InitSDL()
{
	if(SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		printf("Error: SDL could not initialize! %s\n", SDL_GetError());
		return false;
	}

	pWindow = SDL_CreateWindow("SDL clipping", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
	if(!pWindow)
	{
		printf("Error: SDL window could not be created! %s\n", SDL_GetError());
		return false;
	}

	pRenderer = SDL_CreateRenderer(pWindow, -1, SDL_RENDERER_ACCELERATED);
	if(!pRenderer)
	{
		printf("Error: SDL renderer could not be created! %s\n", SDL_GetError());
		return false;
	}

	tex = SDL_CreateTextureFromSurface(pRenderer, tempSurface);

	if(tex == NULL){
		cout << "No texture loaded\n";
	}
	if (tempSurface == NULL){
		cout << "No surface created\n";
	}
	SDL_FreeSurface(tempSurface); //can't be outside of a function? ***************

	SDL_SetRenderDrawColor(pRenderer, 0, 0, 0, 255);
	SDL_SetRenderDrawBlendMode(pRenderer, SDL_BLENDMODE_BLEND);

	SDL_RenderClear(pRenderer);
	SDL_RenderPresent(pRenderer);

	return true;
}

void DeinitSDL()
{
	SDL_DestroyRenderer(pRenderer);
	SDL_DestroyWindow(pWindow);

	SDL_Quit();
}

void InitAssets()
{
	Rects[0] = {0,					0,					WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2};
	Rects[1] = {WINDOW_WIDTH / 2,	0,					WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2};
	Rects[2] = {0,					WINDOW_HEIGHT / 2,	WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2};
	Rects[3] = {WINDOW_WIDTH / 2,	WINDOW_HEIGHT / 2,	WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2}; //image

	RectMouse = {0, 0, 350, 250};
}

void HandleEvents()
{
	SDL_Event Event = {0};
	while(SDL_PollEvent(&Event))
	{
		switch(Event.type)
		{
			case SDL_QUIT:
			{
				Running = false;

				break;
			}

			default:
				break;
		}
	}
}

void Update()
{
	NewTime = (double)SDL_GetTicks();
	DeltaTime = (NewTime - OldTime) * 0.001;
	OldTime = NewTime;

	int32_t MouseX = 0;
	int32_t MouseY = 0;
	SDL_GetMouseState(&MouseX, &MouseY);

	// The mouse rect follows the mouse pointer
	RectMouse.x = MouseX - (RectMouse.w / 2);
	RectMouse.y = MouseY - (RectMouse.h / 2);

	// Hold the up/down key on the keyboard to increase/decrease the border size (clamped between 'Lowest' and 'Highest')

	const Uint8* pKeyboardState = SDL_GetKeyboardState(nullptr);
	const float Speed = 64.0f;
	const float Lowest = 5.0f;
	const float Highest = 50.0f;

	if (pKeyboardState[SDL_SCANCODE_UP])
	{
		Border += Speed * (float)DeltaTime;

		if(Border > Highest)
			Border = Highest;
	}

	else if (pKeyboardState[SDL_SCANCODE_DOWN])
	{
		Border -= Speed * (float)DeltaTime;

		if(Border < Lowest)
			Border = Lowest;
	}
}

void Render()
{
	SDL_SetRenderDrawColor(pRenderer, 0, 0, 0, 255);
	SDL_RenderClear(pRenderer);

	//////////////////////////////////////////////////////////////////////////

	// First render the three colored rects that the mouse rect should check intersection against
	for (uint32_t i = 0; i < 3; ++i)
	{
		SDL_SetRenderDrawColor(pRenderer, RectColors[i].r, RectColors[i].g, RectColors[i].b, RectColors[i].a);
		SDL_RenderFillRect(pRenderer, &Rects[i]);
	}
	//
	
	SDL_RenderCopy(pRenderer, tex, &srcRect, &Rects[3]);
	

	// Render the mouse rect
	SDL_SetRenderDrawColor(pRenderer, 200, 0, 0, 255);
	SDL_RenderFillRect(pRenderer, &RectMouse);

	for (uint32_t i = 0; i < 4; ++i)
	{
		const SDL_Point BorderSize			= {(int32_t)Border, (int32_t)Border};
		const SDL_Rect	IntersectingRect	= {RectMouse.x + BorderSize.x, RectMouse.y + BorderSize.y, RectMouse.w - (BorderSize.x * 2), RectMouse.h - (BorderSize.y * 2)};
		SDL_Rect		Intersection		= {0, 0, 0, 0};

		// Do intersection test between the mouse rect (minus the border size, see 'IntersectionRect' above) and the colored rects
		if(SDL_IntersectRect(&Rects[i], &IntersectingRect, &Intersection) == SDL_TRUE)
		{
			// If an intersection occurs, the intersection part is rendered on top of the mouse rect, in the same color as the rect that the mouse rect is intersecting with
			SDL_SetRenderDrawColor(pRenderer, RectColors[i].r, RectColors[i].g, RectColors[i].b, RectColors[i].a);
			//SDL_SetRenderDrawColor(pRenderer, 89, 12, 126, 255); // renders aditional rectangles with color of the intersected ones
			SDL_RenderFillRect(pRenderer, &Intersection);
			if (i == 3){
				SDL_Rect crop = {srcRect.x - (WINDOW_WIDTH/2 - Intersection.x), srcRect.y - (WINDOW_HEIGHT/2 - Intersection.y), Intersection.w, Intersection.h};
				SDL_RenderCopy(pRenderer, tex,	&crop, &Intersection);
			}
		}
	}

	//////////////////////////////////////////////////////////////////////////

	SDL_RenderPresent(pRenderer);
}

int main(int argc, char** argv)
{
	if(!InitSDL() )
		return -1;

	InitAssets();

	while(Running)
	{
		HandleEvents();
		Update();
		Render();
	}

	DeinitSDL();

	return 0;
}

It looks okey. There’s just some things that I personally would change/fix:

  1. You don’t initialize/deinitialize the SDL_Image library. I guess it loads dynamically when an SDL_Image-specific function is called, like IMG_Load for example.
    I like to control when libraries and objects are initialized and deinitialized so a call to IMG_Init and IMG_Quit should be made in the InitSDL/DeinitSDL function, along with SDL.
  2. I see textures as assets, so you should create the SDL_Texture in the InitAssets function instead of the InitSDL function.
  3. You don’t destroy the created texture. For every object created with a call to SDL_Create*, there should be a corresponding call to SDL_Destroy* to destroy the object. In this case you should call SDL_DestroyTexture to destroy the created texture. Since there is now an asset that needs to be destroyed, you should add a DeinitAssets function and destroy needed assets in that.
  4. I don’t like the “using namespace std”. You should stop using that and just use “std::” where it’s needed.
  5. Use the c++ nullptr keyword instead of NULL.
Fixed code
#include <iostream>
#include <stdio.h>
#include <string>

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

#define WINDOW_WIDTH	(800)
#define WINDOW_HEIGHT	(600)

SDL_Window* pWindow		= nullptr;
SDL_Renderer* pRenderer = nullptr;

SDL_Texture* pTexture = nullptr;

SDL_Rect Rects[4]	= {0};
SDL_Rect MouseRect	= {0, 0, 0, 0};
SDL_Rect SrcRect	= {0, 0, 0, 0};

SDL_Color RectColors[4] =
{
	{ 25, 255,	90, 255},
	{ 25, 150, 255, 255},
	{255, 100,	25, 255},
	{255, 255, 255, 255},
};

double OldTime		= 0.0;
double NewTime		= 0.0;
double DeltaTime	= 0.0;

float Border = 50.0f;

bool Running = true;

bool InitLibraries()
{
	if(SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		printf("Error: SDL could not initialize! %s\n", SDL_GetError());
		return false;
	}

	if(IMG_Init(IMG_InitFlags::IMG_INIT_PNG) != IMG_InitFlags::IMG_INIT_PNG)
	{
		printf("Error: SDL_Image could not initialize! %s\n", IMG_GetError());
		return false;
	}

	// Add other library initialization here, like SDL_TTF for example


	return true;
}

void DeinitLibraries()
{
	// Add other library deinitialization here, like SDL_TTF for example


	IMG_Quit();
	SDL_Quit();
}

bool CreateWindowAndRenderer()
{
	pWindow = SDL_CreateWindow("SDL clipping", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
	if(!pWindow)
	{
		printf("Error: SDL window could not be created! %s\n", SDL_GetError());
		return false;
	}

	pRenderer = SDL_CreateRenderer(pWindow, -1, SDL_RENDERER_ACCELERATED);
	if(!pRenderer)
	{
		printf("Error: SDL renderer could not be created! %s\n", SDL_GetError());
		return false;
	}

	SDL_SetRenderDrawColor(pRenderer, 0, 0, 0, 255);
	SDL_SetRenderDrawBlendMode(pRenderer, SDL_BLENDMODE_BLEND);

	SDL_RenderClear(pRenderer);
	SDL_RenderPresent(pRenderer);

	return true;
}

void DestroyWindowAndRenderer()
{
	SDL_DestroyRenderer(pRenderer);
	SDL_DestroyWindow(pWindow);
}

bool CreateAssets()
{
	pTexture = IMG_LoadTexture(pRenderer, "assets/image.png");
	if(!pTexture)
	{
		printf("Error: failed to create texture! %s\n", IMG_GetError());
		return false;
	}

	// Create textures, fonts and other objects here


	Rects[0] = {0,					0,					WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2};
	Rects[1] = {WINDOW_WIDTH / 2,	0,					WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2};
	Rects[2] = {0,					WINDOW_HEIGHT / 2,	WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2};
	Rects[3] = {WINDOW_WIDTH / 2,	WINDOW_HEIGHT / 2,	WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2};

	MouseRect = {0, 0, 350, 250};

	SrcRect = {306, 102, WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2};

	return true;
}

void DestroyAssets()
{
	// Destroy textures, fonts and other objects here


	SDL_DestroyTexture(pTexture);
	pTexture = nullptr;
}

void HandleEvents()
{
	SDL_Event Event = {0};
	while(SDL_PollEvent(&Event))
	{
		switch(Event.type)
		{
			case SDL_QUIT:
			{
				Running = false;
				break;
			}

			default:
				break;
		}
	}
}

void Update()
{
	NewTime		= (double)SDL_GetTicks();
	DeltaTime	= (NewTime - OldTime) * 0.001;
	OldTime		= NewTime;

	int32_t MouseX = 0;
	int32_t MouseY = 0;
	SDL_GetMouseState(&MouseX, &MouseY);

	// The mouse rect follows the mouse pointer
	MouseRect.x = MouseX - (MouseRect.w / 2);
	MouseRect.y = MouseY - (MouseRect.h / 2);

	// Hold the up/down key on the keyboard to increase/decrease the border size (clamped between 'Lowest' and 'Highest')

	const Uint8*	pKeyboardState	= SDL_GetKeyboardState(nullptr);
	const float		Speed			= 64.0f;
	const float		Lowest			= 5.0f;
	const float		Highest			= 50.0f;

	if(pKeyboardState[SDL_SCANCODE_UP])
	{
		Border += Speed * (float)DeltaTime;

		if(Border > Highest)
			Border = Highest;
	}

	else if(pKeyboardState[SDL_SCANCODE_DOWN])
	{
		Border -= Speed * (float)DeltaTime;

		if(Border < Lowest)
			Border = Lowest;
	}
}

void Render()
{
	SDL_SetRenderDrawColor(pRenderer, 0, 0, 0, 255);
	SDL_RenderClear(pRenderer);

	//////////////////////////////////////////////////////////////////////////

	// First render the three colored rects that the mouse rect should check intersection against
	for(uint32_t i = 0; i < 3; ++i)
	{
		SDL_SetRenderDrawColor(pRenderer, RectColors[i].r, RectColors[i].g, RectColors[i].b, RectColors[i].a);
		SDL_RenderFillRect(pRenderer, &Rects[i]);
	}

	SDL_SetTextureColorMod(pTexture, 255, 255, 255);
	SDL_RenderCopy(pRenderer, pTexture, nullptr, &Rects[3]);

	// Render the mouse rect
	SDL_SetRenderDrawColor(pRenderer, 200, 0, 0, 255);
	SDL_RenderFillRect(pRenderer, &MouseRect);

	for(uint32_t i = 0; i < 4; ++i)
	{
		const SDL_Point BorderSize			= {(int32_t)Border, (int32_t)Border};
		const SDL_Rect	IntersectingRect	= {MouseRect.x + BorderSize.x, MouseRect.y + BorderSize.y, MouseRect.w - (BorderSize.x * 2), MouseRect.h - (BorderSize.y * 2)};
		SDL_Rect		Intersection		= {0, 0, 0, 0};

		// Do intersection test between the mouse rect (minus the border size, see 'IntersectionRect' above) and the colored rects
		if(SDL_IntersectRect(&Rects[i], &IntersectingRect, &Intersection) == SDL_TRUE)
		{
			// If an intersection occurs, the intersection part is rendered on top of the mouse rect, in the same color as the rect that the mouse rect is intersecting with
			SDL_SetRenderDrawColor(pRenderer, RectColors[i].r, RectColors[i].g, RectColors[i].b, RectColors[i].a);
			SDL_RenderFillRect(pRenderer, &Intersection);

			if(i == 3)
			{
				const SDL_Rect Crop = {SrcRect.x - ((WINDOW_WIDTH / 2) - Intersection.x), SrcRect.y - ((WINDOW_HEIGHT / 2) - Intersection.y), Intersection.w, Intersection.h};

				SDL_RenderCopy(pRenderer, pTexture, &Crop, &Intersection);
			}
		}
	}

	// Render other game objects/assets here


	//////////////////////////////////////////////////////////////////////////

	SDL_RenderPresent(pRenderer);
}

int main(int argc, char** argv)
{
	if(!InitLibraries() || !CreateWindowAndRenderer() || !CreateAssets())
		return -1;

	while(Running)
	{
		HandleEvents();
		Update();
		Render();
	}

	DestroyAssets();
	DestroyWindowAndRenderer();
	DeinitLibraries();

	return 0;
}
  • The window- and renderer creation/destruction has been moved into it’s own functions.
  • The InitSDL and DeinitSDL functions are renamed to InitLibraries and DeinitLibraries, since they’re now initializing/deinitializing multiple libraries, and not just SDL.
  • The texture is created by using SDL_Image’s function IMG_LoadTexture instead of IMG_Load, so no temporary SDL_Surface needs to be created.

It works great! I just had to replace the nullptr with SrcRect in the line:

SDL_RenderCopy(pRenderer, pTexture, nullptr, &Rects[3]);

to avoid image distortion.

Thank you for all your suggestions. Your help and coding advises are much aperciated.