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.
- 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);
}
- 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;
}
}
- 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.