Target texture color modulation

Hi there!

I’ve been trying for some hours to get the SDL_SetTextureColorMod work on a target texture without success…
I’m trying to use it that way in order to use color filters easily, rather than setting up the texture color mod on all of the textures.

Does someone have any idea?

It’s hard to say without knowing more about your situation. A quick test shows that color modulation works on target textures. Can you explain or show us in more detail what your code does?

Here’s my little test that draws white rectangles to a target texture which will get a color from the color modulation when the target texture gets drawn to the default render target. You can use it as a reference but beware: there’s no error checking of any sort.

[details=tartexcolmod.c]

#include "SDL.h"

#define MAX_PARTICLES 512

typedef struct Particle {
	int active;
	float x, y;
	float vx, vy;
	float ax, ay;
} Particle;

static struct {
	SDL_Window * handle;
	int width, height;
	SDL_Renderer * renderer;
	SDL_Texture * texture;
	Uint32 particle_count;
	Particle particle[MAX_PARTICLES];
	Uint32 last_update;
} Window;

static Uint32 xstate = 905309021;
static float xorshift()
{
	xstate ^= xstate << 13;
	xstate ^= xstate >> 17;
	xstate ^= xstate << 5;
	return (float)xstate / 4294967295.f;
}

static void update_particles(Uint32 ms)
{
	int i;
	float sec = (float)ms / 1000.f;

	for (i = 0; i < MAX_PARTICLES; i++) {
		if (Window.particle[i].active) {
			Window.particle[i].vx += Window.particle[i].ax * sec;
			Window.particle[i].vy += Window.particle[i].ay * sec;
			Window.particle[i].vx *= Window.particle[i].y;
			Window.particle[i].vy *= 0.9f;
			Window.particle[i].x += Window.particle[i].vx * sec;
			Window.particle[i].y += Window.particle[i].vy * sec;
			if (Window.particle[i].y < -0.05f) {
				Window.particle[i].active = 0;
				Window.particle_count--;
			}
		}
	}

	for (i = 0; Window.particle_count < MAX_PARTICLES && i < MAX_PARTICLES; i++) {
		if (!Window.particle[i].active) {
			Window.particle[i].vx = 0;
			Window.particle[i].vy = 0;
			Window.particle[i].ax = (xorshift() - .5f) * 40.f;
			Window.particle[i].ay = -(10.f + xorshift() * 5.f);
			Window.particle[i].x = .5f + (xorshift() - .5f) * .02f;
			Window.particle[i].y = 0.95f + (xorshift() - .5f) * .02f;
			Window.particle[i].active = 1;
			Window.particle_count++;
			ms--;
		}
	}
}

static void create_tt()
{
	SDL_Texture * tt = SDL_CreateTexture(Window.renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, Window.width / 2, Window.height / 2);
	if (Window.texture != NULL) {
		SDL_DestroyTexture(Window.texture);
	}
	SDL_SetTextureBlendMode(tt, SDL_BLENDMODE_BLEND);
	Window.texture = tt;
}

static void draw_particles()
{
	int i;
	SDL_Rect dst_rect;

	SDL_SetRenderTarget(Window.renderer, Window.texture);

	SDL_SetRenderDrawColor(Window.renderer, 0, 0, 0, 0);
	SDL_RenderClear(Window.renderer);

	SDL_SetRenderDrawColor(Window.renderer, 255, 255, 255, 255);
	for (i = 0; i < MAX_PARTICLES; i++) {
		if (Window.particle[i].active) {
			dst_rect.x = (int)((Window.width / 2) * Window.particle[i].x) - 4;
			dst_rect.y = (int)((Window.height / 2) * Window.particle[i].y) - 4;
			dst_rect.w = 8;
			dst_rect.h = 8;
			SDL_RenderFillRect(Window.renderer, &dst_rect);
		}
	}

	SDL_SetRenderTarget(Window.renderer, NULL);
}

static void draw_texture(Uint32 now)
{
	SDL_Rect dst_rect;

	SDL_SetRenderDrawColor(Window.renderer, 0, 0, 0, 255);
	SDL_RenderClear(Window.renderer);

	dst_rect.x = 0;
	dst_rect.y = 0;
	dst_rect.w = Window.width / 2;
	dst_rect.h = Window.height / 2;

	SDL_SetRenderDrawColor(Window.renderer, 200, 0, 0, 255);
	SDL_RenderFillRect(Window.renderer, &dst_rect);

	SDL_SetTextureColorMod(Window.texture, 0, 255, 255);
	SDL_RenderCopy(Window.renderer, Window.texture, NULL, &dst_rect);


	dst_rect.x = Window.width / 2;
	dst_rect.y = 0;

	SDL_SetRenderDrawColor(Window.renderer, 0, 200, 0, 255);
	SDL_RenderFillRect(Window.renderer, &dst_rect);

	SDL_SetTextureColorMod(Window.texture, 255, 0, 255);
	SDL_RenderCopy(Window.renderer, Window.texture, NULL, &dst_rect);


	dst_rect.x = 0;
	dst_rect.y = Window.height / 2;

	SDL_SetRenderDrawColor(Window.renderer, 0, 0, 200, 255);
	SDL_RenderFillRect(Window.renderer, &dst_rect);

	SDL_SetTextureColorMod(Window.texture, 255, 255, 0);
	SDL_RenderCopy(Window.renderer, Window.texture, NULL, &dst_rect);


	dst_rect.x = Window.width / 2;
	dst_rect.y = Window.height / 2;

	SDL_SetRenderDrawColor(Window.renderer, 255, 255, 255, 255);
	SDL_RenderFillRect(Window.renderer, &dst_rect);

	SDL_SetTextureColorMod(Window.texture, now / 14 % 256, now / 15 % 256, now / 16 % 256);
	SDL_RenderCopy(Window.renderer, Window.texture, NULL, &dst_rect);

	SDL_RenderPresent(Window.renderer);
}

static int loop()
{
	SDL_Event e;
	Uint32 now;

	while (SDL_PollEvent(&e)) {
		if (e.type == SDL_QUIT) {
			return 0;
		} else if (e.type == SDL_KEYUP) {
			Uint32 sym = e.key.keysym.sym;
			if (sym == SDLK_ESCAPE) {
				return 0;
			} else if (sym == SDLK_f) {
				if (SDL_GetWindowFlags(Window.handle) & SDL_WINDOW_FULLSCREEN) {
					SDL_SetWindowFullscreen(Window.handle, SDL_FALSE);
				} else {
					SDL_SetWindowFullscreen(Window.handle, SDL_WINDOW_FULLSCREEN_DESKTOP);
				}
			}
		} else if (e.type == SDL_WINDOWEVENT) {
			if (e.window.event == SDL_WINDOWEVENT_RESIZED || e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
				SDL_GetWindowSize(Window.handle, &Window.width, &Window.height);
				create_tt();
			}
		}
	}

	now = SDL_GetTicks();
	update_particles(now - Window.last_update);
	Window.last_update = now;

	draw_particles();
	draw_texture(now);

	return 1;
}

int main(int argc, char * argv[])
{
	int i;
	char title[256] = {0};
	SDL_RendererInfo info;

	Window.texture = NULL;
	Window.last_update = SDL_GetTicks();
	Window.particle_count = 0;
	for (i = 0; i < MAX_PARTICLES; i++) {
		Window.particle[i].active = 0;
	}

	SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
	Window.handle = SDL_CreateWindow("Loading...",
		SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 500, SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL);
	Window.renderer = SDL_CreateRenderer(Window.handle, -1, 0);

	SDL_GetRendererInfo(Window.renderer, &info);
	SDL_strlcat(title, info.name, sizeof(title));
	SDL_Log("Renderer %s started.", info.name);
	if (!(info.flags & SDL_RENDERER_TARGETTEXTURE)) {
		SDL_Log(" Renderer has no target texture support!");
		SDL_strlcat(title, " (no target textures!)", sizeof(title));
	}
	SDL_strlcat(title, ": Target Texture Color Mod", sizeof(title));
	SDL_SetWindowTitle(Window.handle, title);

	SDL_GetWindowSize(Window.handle, &Window.width, &Window.height);
	create_tt();

	SDL_SetRenderDrawBlendMode(Window.renderer, SDL_BLENDMODE_BLEND);
	SDL_SetRenderDrawColor(Window.renderer, 0, 0, 0, 0);
	SDL_RenderClear(Window.renderer);
	SDL_RenderPresent(Window.renderer);

	while (loop()) {
		SDL_Delay(3);
	}

	SDL_DestroyTexture(Window.texture);
	SDL_DestroyRenderer(Window.renderer);
	SDL_DestroyWindow(Window.handle);
	SDL_Quit();

	return 0;
}

```[/details]

(I'm new to discourse. Hope it can handle the code dump. Preview shows some indentation missing.)

Preview shows some indentation missing

(fwiw, I didn’t know the magic incantation that syntax highlights code before I read this, so that’s awesome. :slight_smile:)

If you indent something by at least 4 spaces, Discourse will treat it as preformatted, so go ahead and edit your post, highlight the code and click this guy in the editor toolbar to do that for you:

Thank you for your help! :slight_smile:
I’ve looked more deeply in my code and I found out that one of the functions was changing the renderer, that’s why the color mod wasn’t correctly working.