SDL2/psp semi transparent png


#1

I’ve been trying to get semi transparent textures drawn using SDL2 + SDL2 Image on the psp using custom firmware 661 PRO-C.

http://sphere.sf.net/flik/files/sdl2-render-image.zip

  • That link shows an EBOOT.PBP file and source code of the SDL2 library running on the psp, loading a bmp, jpg and png image and drawing it to the screen.

Trouble is I can’t get the png drawn to the screen with the alpha channel in the image.

I’ve got three methods of drawing the png.

  1. render_png_simple - draws a background rect (using SDL_RenderFillRect) and then draws the png with SDL_RenderCopy & SDL_RenderPresent.
    But this doesn’t honour the alpha channel so I just get the png image as if it was opaque.
Summary

void render_png_simple(SDL_Renderer* renderer,
SDL_Surface* image_png,
SDL_Texture* texture_png)
{
int png_width = image_png->w;
int png_height = image_png->h;

SDL_SetRenderDrawColor( renderer, 0, 0, 0, SDL_ALPHA_OPAQUE );
SDL_RenderClear( renderer );

// render background as red
if (1)
{
	SDL_SetRenderDrawColor( renderer, 255, 0, 0, SDL_ALPHA_OPAQUE );
	SDL_Rect r;
	r.x = 0;
	r.y = 0;
	r.w = SCREEN_WIDTH;
	r.h = SCREEN_HEIGHT;
	SDL_RenderFillRect( renderer, &r );
}

// the png image has an alpha channel
SDL_BlendMode blend_mode = SDL_BLENDMODE_NONE;
SDL_GetTextureBlendMode(texture_png, &blend_mode);

// confirm the texture is in blend mode
if (blend_mode == SDL_BLENDMODE_BLEND)
{
	SDL_Rect r;
	r.x = 0;
	r.y = 0;
	r.w = png_width;
	r.h = png_height;
	SDL_RenderCopy(renderer, texture_png, NULL, &r);
}

// Render the rect to the screen
SDL_RenderPresent(renderer);

}

  1. render_png_alpha_surface - draws a background rect to a surface then copies the surface to a texture (using SDL_UpdateTexture) and then draws the texture to the screen using SDL_RenderCopy & SDL_RenderPresent.
Summary

void render_png_alpha_surface(
SDL_Renderer* renderer,
SDL_Window* window,
SDL_Surface* image_png,
SDL_Texture* texture_png)
{
const Uint32 pixel_format = SDL_GetWindowPixelFormat(window);
SDL_Surface *screen_image = SDL_CreateRGBSurfaceWithFormat(0, SCREEN_WIDTH, SCREEN_HEIGHT, 32, pixel_format);

if (screen_image == NULL)
{
	SDL_Log("Unable to initialize screen image: %s\n", SDL_GetError());
}
else
{
	SDL_Texture* screen_texture = SDL_CreateTexture(renderer, pixel_format, SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT);
	if (screen_texture == NULL)
	{
		SDL_Log("Unable to initialize screen texture: %s\n", SDL_GetError());
	}
	else
	{

		int png_width = image_png->w;
		int png_height = image_png->h;

		// render background as red
		if (1)
		{
			SDL_Rect r;
			r.x = 0;
			r.y = 0;
			r.w = SCREEN_WIDTH;
			r.h = SCREEN_HEIGHT;
			SDL_FillRect( screen_image, &r, SDL_MapRGB(screen_image->format, 255, 0, 0) );
		}

		SDL_Rect r;
		r.x = 0;
		r.y = 0;
		r.w = png_width;
		r.h = png_height;

		// the png has an alpha channel
		SDL_SetSurfaceBlendMode(screen_image, SDL_BLENDMODE_BLEND);
		SDL_BlitSurface(image_png, NULL, screen_image, &r);

		SDL_SetRenderDrawColor( renderer, 0, 0, 0, SDL_ALPHA_OPAQUE );
		SDL_RenderClear( renderer );

		// now draw from the image to the render/screen
		if (SDL_UpdateTexture(screen_texture, NULL, screen_image->pixels, screen_image->pitch) < 0)
		{
			SDL_Log("SDL_UpdateTexture() failed: %s\n", SDL_GetError());
		}

		SDL_RenderCopy(renderer, screen_texture, NULL, NULL);

		// Render the rect to the screen
		SDL_RenderPresent(renderer);

		if (screen_texture != NULL)
		{
			SDL_DestroyTexture(screen_texture);
			screen_texture = NULL;
		}
	}
}

if (screen_image != NULL)
{
	SDL_FreeSurface(screen_image);
	screen_image = NULL;
}

}

  1. render_png_alpha_render - draws the background rect and png to the screen via a render target…
    Which doesn’t work presumably because SDL_SetRenderTarget is a newer api than when the psp code was written.
Summary

void render_png_alpha_render(
SDL_Renderer* renderer,
SDL_Window* window,
SDL_Surface* image_png,
SDL_Texture* texture_png)
{
const Uint32 pixel_format = SDL_GetWindowPixelFormat(window);
if (pixel_format == SDL_PIXELFORMAT_UNKNOWN)
{
SDL_Log(“Unknown pixel format.\n”);
}
else
{
SDL_Texture* screen_texture = SDL_CreateTexture(renderer, pixel_format, SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT);
if (screen_texture == NULL)
{
SDL_Log(“Unable to initialize screen texture: %s\n”, SDL_GetError());
}
else
{
int png_width = image_png->w;
int png_height = image_png->h;

		// render to screen texture
		SDL_SetRenderTarget(renderer, screen_texture);

		// render background as green
		if (1)
		{
			SDL_Rect r;
			r.x = 0;
			r.y = 0;
			r.w = SCREEN_WIDTH;
			r.h = SCREEN_HEIGHT;
			SDL_SetRenderDrawColor( renderer, 0, 255, 0, SDL_ALPHA_OPAQUE );
			SDL_RenderFillRect(renderer, &r );
		}

		SDL_Rect r;
		r.x = 0;
		r.y = 0;
		r.w = png_width;
		r.h = png_height;

		// the png has an alpha channel
		SDL_RenderCopy(renderer, texture_png, NULL, &r);

		// restore render target and draw screen
		SDL_SetRenderTarget(renderer, NULL);

		// Now render the texture target to our screen
		SDL_RenderClear(renderer);
		SDL_RenderCopy(renderer, screen_texture, NULL, NULL);
		SDL_RenderPresent(renderer);

		if (screen_texture != NULL)
		{
			SDL_DestroyTexture(screen_texture);
			screen_texture = NULL;
		}
	}
}

}

I’ve modified my copy src\render\psp\SDL_render_psp.c so that it has clipping (SDL_RenderSetClipRect) and so that the scale mode is calculated when the texture is created and so that hopefuly SDL_SetTextureAlphaMod and SDL_SetTextureColorMod work.

So can someone help me figure out how to draw a semi transparent png on the psp? I know the texture I’ve loaded has the correct alpha values because it draws properly via render_png_alpha_surface but I can’t get render_png_simple or render_png_alpha_render to work.

Edit:
http://sphere.sourceforge.net/flik/files/SDL_render_psp.c
Is the modified version of SDL_render_psp.c that I’m using - which has support for SDL_RenderSetClipRect and SDL_SetTextureAlphaMod/SDL_SetTextureColorMod.

Thanks.