SDL_DisplayFormat works, but not SDL_DisplayFormatAlpha - c++

The following code is intended to display a green square on a black background. It executes, but the green square does not show up. However, if I change SDL_DisplayFormatAlpha to SDL_DisplayFormat the square is rendered correctly.
So what don't I understand? It seems to me that I am creating *surface with an alpha mask and I am using SDL_MapRGBA to map my green color, so it would be consistent to use SDL_DisplayFormatAlpha as well.
(I removed error-checking for clarity, but none of the SDL API calls fail in this example.)
#include <SDL.h>
int main(int argc, const char *argv[])
{
SDL_Init( SDL_INIT_EVERYTHING );
SDL_Surface *screen = SDL_SetVideoMode(
640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF
);
SDL_Surface *temp = SDL_CreateRGBSurface(
SDL_HWSURFACE, 100, 100, 32, 0, 0, 0,
( SDL_BYTEORDER == SDL_BIG_ENDIAN ? 0x000000ff : 0xff000000 )
);
SDL_Surface *surface = SDL_DisplayFormatAlpha( temp );
SDL_FreeSurface( temp );
SDL_FillRect(
surface, &surface->clip_rect, SDL_MapRGBA(
screen->format, 0x00, 0xff, 0x00, 0xff
)
);
SDL_Rect r;
r.x = 50;
r.y = 50;
SDL_BlitSurface( surface, NULL, screen, &r );
SDL_Flip( screen );
SDL_Delay( 1000 );
SDL_Quit();
return 0;
}

I was using the wrong format for SDL_MapRGBA. Should have been
SDL_FillRect(
surface, NULL, SDL_MapRGBA(
surface->format, 0xff, 0xff, 0x00, 0xff
)
);
(surface->format instead of screen->format.) I thought the two would be equivalent. And they are after calling SDL_DisplayFormat(), but not after calling SDL_DisplayFormatAlpha(). The screen surface doesn't have an alpha channel, so the format is different between the two.
(Cross-posted from gamedev.stackexchange.com)

Related

How do I render a box to the screen in C++ using SDL2?

I am trying to figure out the SDL2 library in C++, and can't seem to properly configure code to simply draw a rectangle to the screen. What should I do differently?
#include <SDL.h>
bool success = true; //success flag for functions, etc
int ScreenWidth = 640; //screen width and height for SDL window
int ScreenHeight = 480; //
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
SDL_Window* window = SDL_CreateWindow( "Game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, ScreenWidth, ScreenHeight, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawColor( renderer, 0xFF, 0xFF, 0xFF, 0xFF);
bool quit = false;
SDL_Event event;
while (!quit)
{
SDL_RenderClear(renderer);
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
quit = true;
}
SDL_Rect box;
box.w = 30;
box.h = 30;
box.x = 50;
box.y = 50;
SDL_SetRenderDrawColor(renderer, 0xFF,0x00,0x00,0xFF);
SDL_RenderFillRect(renderer, &box);
SDL_RenderPresent(renderer);
}
return 0; //because main is an int task
}
EDIT: This is the full file.
I expect it to draw a red rectangle on the screen, but the window is completely red (of the correct size, name, etc. that quits correctly).
You must call SDL_RenderPresent after all your rendering calls. In this case after SDL_RenderFillRect(...)
SDL_RenderClear is used at the beginning of a rendering loop to clear the buffer.
Example from SDL2's Wiki
SDL_SetRenderDrawColor() affects both SDL_RenderFillRect() and SDL_RenderClear().
After drawing the red square you need to re-set the color to white before the next SDL_RenderClear() call:
#include <SDL2/SDL.h>
int main( int argc, char** argv )
{
SDL_Init( SDL_INIT_EVERYTHING );
SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" );
SDL_Window* window = SDL_CreateWindow( "Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN );
SDL_Renderer* renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
bool running = true;
while( running )
{
SDL_Event ev;
while( SDL_PollEvent( &ev ) )
{
if( SDL_QUIT == ev.type )
{
running = false;
break;
}
}
SDL_SetRenderDrawColor( renderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( renderer );
SDL_Rect box;
box.w = 30;
box.h = 30;
box.x = 50;
box.y = 50;
SDL_SetRenderDrawColor( renderer, 0xFF, 0x00, 0x00, 0xFF );
SDL_RenderFillRect( renderer, &box );
SDL_RenderPresent( renderer );
}
return 0;
}
I figured it out!
I needed to put SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF); inside of the loop so it would reset the renderer to white each tick. I just had it set it back to white once at the beginning so SDL_RenderClear was filling the window with the current draw color (which was red). Thanks to TinfoilPancakes and genpfault for helping me!

How to render a rectangle SDL2 texture from a buffer of hex values?

I'm having some trouble understanding texture streaming and loading a 2D texture from an array of raw pixel data.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <SDL2/SDL.h>
#define WINDOW_W 640
#define WINDOW_H 320
int main(int argc, char *argv[])
{
if (SDL_Init(SDL_INIT_EVERYTHING))
exit(1);
/* Set up main window. */
SDL_Window *window = SDL_CreateWindow(
"Texture Streaming",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
WINDOW_W,
WINDOW_H,
SDL_WINDOW_SHOWN
);
if (window == NULL)
exit(2);
/* Set up renderer. */
SDL_Renderer *renderer = SDL_CreateRenderer(
window,
-1,
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
);
if (renderer == NULL)
exit(3);
SDL_Event ev;
int window_running = 1;
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, 64, 32);
Uint32 pixels[64 * 32];
for (int i = 0; i < (64 * 32); i++)
pixels[i] = 0xFF00FFFF;
for (int i = 0; i < 64; i++)
pixels[i] = 0xFF0000FF;
SDL_UpdateTexture(texture, NULL, pixels, 4);
while (window_running)
{
while (SDL_PollEvent(&ev) != 0)
{
if (ev.type == SDL_QUIT)
window_running = 0;
}
SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
Instead of my program drawing the first 64 pixels red and the rest magenta, it just spits out a random chunk of red and yellow pixels.
I'm having trouble understanding SDL_CreateTexture and SDL_UpdateTexture.
Your pitch in UpdateTexture is wrong. Pitch is byte length of a row, not single pixel. In your case pitch is 64*4.
Pixel format SDL_PIXELFORMAT_RGBA32 is alias to either SDL_PIXELFORMAT_RGBA8888 or SDL_PIXELFORMAT_ABGR8888 (latter in your case). Look at https://wiki.libsdl.org/SDL_PixelFormatEnum . So your 0xFF00FFFF is yellow (R=0xff, G=0xff, B=0, A=0xff).
Finally, if we're talking about texture streaming (i.e. updating every frame or otherwise very often), you should create streaming texture and use LockTexture/UnlockTexture. UpdateTexture is for static textures.

Confused on SDL_CreateRGBSurface() width and height parameters

So, after fooling around with the width and height numbers on the SDL_CreateRGBSurface() function, i am really confused on how they work. According to SDL Wiki the width and height refer to the width and height of the surface, however when I say SCREENWIDTH / 2, or SCREENHEIGHT / 2, it shows bigger than without the division. This is the code I was messing around with:
#include <iostream>
#include <SDL.h>
const int WIN_WIDTH = 640;
const int WIN_HEIGHT = 480;
int main(int argc, char **argv){
if (SDL_Init(SDL_INIT_EVERYTHING) != 0){
std::cerr << "SDL_Init failed: " << SDL_GetError() << "\n";
return 1;
}
SDL_Window *win = SDL_CreateWindow("Rendering to a texture!", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, WIN_WIDTH, WIN_HEIGHT, 0);
SDL_Renderer *renderer = SDL_CreateRenderer(win, -1,
SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
SDL_Surface* s;
SDL_Color c = { 155, 0, 0 };
SDL_Rect r = { 0, 0, 100, 100 };
s = SDL_CreateRGBSurface(0, WIN_WIDTH / 2, WIN_HEIGHT, 32, 0, 0, 0, 0);
SDL_FillRect(s, &r, SDL_MapRGB(s->format, c.r, c.g, c.b));
SDL_Texture* t;
t = SDL_CreateTextureFromSurface(renderer, s);
SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, t, NULL, NULL);
SDL_RenderPresent(renderer);
SDL_Delay(2000);
SDL_FreeSurface(s);
SDL_DestroyTexture(t);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
All I really want is a rect with a width of 100 and height of 100, but to have it appear correctly on the screen, the width and height must be specified to the width and height of the window. Why is that?
SDL_RenderCopy will stretch the source texture to fit into the destination renderer. So it will stretch your surface over the entire window. If you want to draw a 100x100 pixel rectangle, your SDL surface should be the same size as the window you're copying it to; that way no stretching will take place and the surface will be presented 1:1.

Transparent SDL_Surface without background

I'm working with SDL and OpenGL.
I'm using SDL ttf for create a surface with the text, then create a texture with that surface.
I'm trying to apply an alpha channel (opacity) to the text, I'm using this way:
SDL_Surface * fontsurf = TTF_RenderUTF8_Blended(font,buff_split.at(i).c_str(),color);
SDL_PixelFormat *format = fontsurf->format;
SDL_Surface* newSurface = SDL_CreateRGBSurface( SDL_SRCALPHA,
fontsurf->w, fontsurf->h, 32,
0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 );
Uint32 alpha = 0;
alpha = SDL_MapRGBA( newSurface->format, 0,0,0, color.unused);
SDL_Rect rect;
rect.x = 0;
rect.y = 0;
rect.h = fontsurf->h;
rect.w = fontsurf->w;
int ret = SDL_FillRect( newSurface, &rect, alpha);
SDL_SetAlpha(newSurface,SDL_SRCALPHA,SDL_ALPHA_TRANSPARENT);
ret = SDL_BlitSurface( fontsurf, 0, newSurface, 0 );
The opacity is applied correctly, but the SDL_MapRGBA creates a black background in the "newSurface".
How can I apply alpha/opacity to the text, without adding a background, only the text?
I think you are missing SDL_SetColorKey for newSurface.
Something like this:
SDL_SetColorKey( newSurface , SDL_SRCCOLORKEY, SDL_MapRGB( newSurface->format, 0, 0, 0) );
or even easier would be to skip filling newSurface with a black rectangle
remove this:
SDL_FillRect( newSurface, &rect, alpha);
Here is an example how I make a picture with transparent color:
testImage = IMG_Load( "trans.png" );
// This picture contains color 255,0,255 which will be set as transparent
SDL_SetColorKey( testImage , SDL_SRCCOLORKEY, SDL_MapRGB( screen->format, 255, 0, 255) );
// I set the color 255,0,255 as transparent for that surface
SDL_BlitSurface( testImage , NULL , screen , NULL );
// and I draw it on the main surface (screen)

Problems with SDL_SetColorKey

I'm trying to create a transparent sprite with SDL. I'm using SDL_SetColorKey on a bitmap with magenta (0xff00ff) background (it's 100% magenta, I checked it with the GIMP :)) The call to SDL_SetColorKey looks like this:
SDL_SetColorKey( bitmap, SDL_SRCCOLORKEY, SDL_MapRGB(bitmap->format, 255, 0, 255) );
The call to SDL_SetColorKey apparently returns 0, however there is no transparency. Can anyone tell me what I am missing here?
Here is the problematic code in case anyone wants to test it:
#include "SDL/SDL.h"
const int WINDOW_WIDTH = 640;
const int WINDOW_HEIGHT = 480;
const char* WINDOW_TITLE = "SDL Start";
int main(int argc, char **argv)
{
SDL_Init( SDL_INIT_VIDEO );
SDL_Surface* screen = SDL_SetVideoMode( WINDOW_WIDTH, WINDOW_HEIGHT, 0,
SDL_HWSURFACE | SDL_DOUBLEBUF );
SDL_WM_SetCaption( WINDOW_TITLE, 0 );
SDL_Surface* bitmap = SDL_LoadBMP("resources/ship.bmp");
if(SDL_SetColorKey( bitmap, SDL_SRCCOLORKEY, SDL_MapRGB(bitmap->format, 255, 0, 255) )) printf("aaaaa %s", SDL_GetError());
// Part of the screen we want to draw the sprite to
SDL_Rect destination;
destination.x = 100;
destination.y = 100;
destination.w = 65;
destination.h = 44;
SDL_Event event;
bool gameRunning = true;
while (gameRunning)
{
if (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
gameRunning = false;
}
}
SDL_BlitSurface(bitmap, NULL, screen, &destination);
SDL_Flip(screen);
}
SDL_FreeSurface(bitmap);
SDL_Quit();
return 0;
}
UPDATE:
In case anyone needs it, here is the bitmap: http://dl.dropbox.com/u/8936880/ship.bmp
The problem is with your image, i used one generated by me and it works out of the box with your code.
Your image is in 32 bits and it seems that SDL_SetColorKey doesn't like it, convert it to 24 bits and it should work.
You can convert it with Gimp when you save it to BMP from the advanced settings.
Try with this one converted to 24 bits.