SDL DisplayFormat does rectangle - c++

Im new to SDL and C++ overall.
However when i do DisplayFormat on an image for faster blitting it makes it an rectangle.
SDL_Surface* tempImage = NULL;
// The image that will be used (optimized)
image = NULL;
image = IMG_Load( filename.c_str() );
if ( tempImage != NULL )
{
// Create optimization
image = SDL_DisplayFormat( tempImage ); // Makes the circle an rectangle
// Free the old image
SDL_FreeSurface( tempImage );
}
Why is that? If i dont do DisplayFormat, the circle remains an circle when blitted.

This is because your display format which you're converting your image to does not support transparent pixels. You must set your video mode to have 32 bits per pixel, like below:
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Surface *window = SDL_SetVideoMode(width, height, 32, flags);
// ...
You also need to change SDL_DisplayFormat to SDL_DisplayFormatAlpha.

Related

How to display a image on a user defined rectangle with SDL_surface?

Im working on a project with my friend and we have run into an issue with surfaces and windows in SDL.
Currently we are able to create a window and display a rectangle on that window and move it around. The next thing we want to do is take a image and display it on a rectangle and then move it around the screen.
We started with taking the SDL_window* and turning it into SDL_surface* though this would take the image and display it on the background of the window.
Is there a way to turn a rectangle we create into a surface and display the image on that rectangle?
I have also tried using textures and it distorts the image when I tried to move it and the whole image doesn’t move with the rectangle.
// this happens in the constructor
temp_image_sur = IMG_Load( image_location.c_str() );
if( temp_image_sur == NULL )
{
std::cout << "Image could not be loaded" <<std::endl;
exit(1);
}
// This is in the actual draw function.
display_surface = SDL_GetWindowSurface( display_window );
if(display_surface == NULL )
{
printf(" null im exiting here %s\n", SDL_GetError());
exit(1);
}
image_surface = SDL_ConvertSurface( temp_image_sur, display_surface->format, 0 );
image_size = { this->location.x, this->location.y, this->size.width, this->size.height };
SDL_BlitSurface( image_surface, &image_size, display_surface, &image_size );
This is what we did for our first attempt, and the image was displaying on the base window. I believe I understand why it is displaying on the base window, it is because we are using that window as the surface, though I'm confused how do I make a user defined rectangle the surface?
We did try using SDL_CreateRGBSurface, though nothing is being displayed on the screen when we do this either.
display_surface = SDL_CreateRGBSurface(0, this->size.width, this->size.height, 1, this->color.red, this->color.green, this->color.blue, this->color.alpha);
Thanks guys!
Please let me know if there is anymore information you need, this is my first time posting and I tried to put all the info that I could think of.
Create a texture from your image surface by using SDL_CreateTextureFromSurface:
SDL_Texture* image_surface = SDL_CreateTextureFromSurface(renderer, temp_image_sur);
(remember to free it with SDL_DestroyTexture)
then use SDL_RenderCopy to draw it:
SDL_RenderCopy(renderer, image_texture, nullptr, &image_rect);
where image_rect is a SDL_Rect and the destination rectangle you want to draw your image to, for example:
SDL_rect image_rect = {10, 10, 200, 200};
To move your image simply change image_rect.x and/or image_rect.y

Improving performance of Imshow with OpenGL

I have a raspberry pi running an opencv c++ application I developed. I'm doing some image manipulation of a cv::Mat from a camera, then I resize (if needed), create a border, then display it fullscreen with cv::imshow. Right now everything works, but performance is usually limited to 8 fps at 800x480 resolution.
What I would like to do is utilize opengl to increase perofrmance. I already have opencv compiled with opengl support and can open cv::namedWindow with the cv::WINDOW_OPENGL flag, but performance is actually worse. I believe the reason is because I am still using cv::imshow with a cv::Mat and not a ogl::buffer or other data type that takes advantage of the opengl support.
So the question I have is how can I convert my cv::Mat to an ogl:buffer, or other data type (ogl::Texture2D?), and can that step be combined with some of my others (specifically cv::Mat's copyTo() )? I'm thinking instead of copying my cv::Mat to a larger cv::Mat to create the border I could go directly to a ogl::buffer for the same effect. Is that possible?
Current code, let's assume 'image' is always a 640x480 cv::Mat*:
//Create initial cv::Mat's
cv::Mat imagetemp{ cv::Mat(480, 640, image->type(), cv::Scalar(0)) };
cv::Mat borderedimage{ cv::Mat(480, 800, image->type(), cv::Scalar(0)) };
//Create fullscreen opengl window
cv::namedWindow( "Output", cv::WINDOW_OPENGL );
cv::setWindowProperty( "Output", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN );
//Loop
while( true ) {
//Get latest image
displaymutex->lock();
imagetemp = *image;
displaymutex->unlock();
//Format
imagetemp.copyTo( borderedimage.rowRange(0, 480).colRange(80, 720) );
//Display
cv::imshow( "Output", borderedimage );
cv::waitKey( 1 );
}
OK, the following code works for converting a cv::Mat to a cv::ogl::buffer, and I also simplified it a bit by using copyMakeBorder(), however the result is only 1-2 fps!! Is this just not an application that can benefit from openGL? Any other suggestions for performance improvements with or without openGL utilization?
//Create temporary cv::Mat
cv::Mat imagetemp{ cv::Mat(480, 640, image->type(), cv::Scalar(0)) };
//Create fullscreen opengl window
cv::namedWindow( "Output", cv::WINDOW_OPENGL );
cv::setWindowProperty( "Output", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN );
//Loop
while( true ) {
//Get latest image
displaymutex->lock();
cv::copyMakeBorder( *image,
imagetemp,
0,
0,
80,
80,
cv::BORDER_CONSTANT,
cv::Scalar(0) );
displaymutex->unlock();
//Display
buffer.copyFrom(imagetemp, cv::ogl::Buffer::ARRAY_BUFFER, true);
cv::imshow( "Output", buffer );
cv::waitKey( 1 );
}
Thanks

SDL Image scale

I'm using the sdl library, but it dosent support scale / resize surface, so i downloaded the
SDL_image 1.2 & SDL_gfx Library. My function/code works, but the image appear in bad / low
quality.
Let say i got a image which is 100X100, if i scale down to 95X95 or scale up to 110X110 the
quality appear very low, but if i leave it at 100X100 which is the same size it appear in
good quality. Images most appear in good quality, if scaled down, but ... it dosent
my code is:
int drawImage(SDL_Surface* display, const char * filename, int x, int y, int xx, int yy , const double newwidth, const double newheight, int transparent = NULL)
{
SDL_Surface *image;
SDL_Surface *temp;
temp = IMG_Load(filename); if (temp == NULL) { printf("Unable to load image: %s\n", SDL_GetError()); return 1; }
image = SDL_DisplayFormat(temp); SDL_FreeSurface(temp);
// Zoom function uses doubles for rates of scaling, rather than
// exact size values. This is how we get around that:
double zoomx = newwidth / (float)image->w;
double zoomy = newheight / (float)image->h;
// This function assumes no smoothing, so that any colorkeys wont bleed.
SDL_Surface* sized = zoomSurface( image, zoomx, zoomy, SMOOTHING_OFF );
// If the original had an alpha color key, give it to the new one.
if( image->flags & SDL_SRCCOLORKEY )
{
// Acquire the original Key
Uint32 colorkey = image->format->colorkey;
// Set to the new image
SDL_SetColorKey( sized, SDL_SRCCOLORKEY, colorkey );
}
// The original picture is no longer needed.
SDL_FreeSurface( image );
// Set it instead to the new image.
image = sized;
SDL_Rect src, dest;
src.x = xx; src.y = yy; src.w = image->w; src.h = image->h; // size
dest.x = x; dest.y = y; dest.w = image->w; dest.h = image->h;
if(transparent == true )
{
//Set the color as transparent
SDL_SetColorKey(image,SDL_SRCCOLORKEY|SDL_RLEACCEL,SDL_MapRGB(image->format,0x0,0x0,0x0));
}
else {
}
SDL_BlitSurface(image, &src, display, &dest);
return true;
}
drawImage(display, "Image.png", 50, 100, NULL, NULL, 100, 100,true);
An image that is scaled without allowing smoothing is going to have artifacts. You might have better luck if you start with SVG and render it at the scale that you want. Here's an SVG -> SDL surface library.

SDL, change the cursor?

I'm using the SDL library, but what I'm trying to load a *.bmp file and display it as my new cursor, instead of the black and white cursor.
I think, that I most check the position of the mouse and draw the SDL_Surface at that position in a loop,
My code so far:
//Declare SDL_Surface pointers
SDL_Surface *cursor;
SDL_Surface *image;
SDL_ShowCursor( SDL_DISABLE ); //Standard cursor must be turned off
image = SDL_LoadBMP("mouse.bmp"); //Load my cursor
cursor = SDL_DisplayFormat(image); //Set
//Set the color as transparent
SDL_SetColorKey(cursor,SDL_SRCCOLORKEY|SDL_RLEACCEL,SDL_MapRGB(cursor->format,0x0,0x0,0x0));
Create and set a new SDL_Cursor should work.
SDL_Surface *surface = IMG_Load(filename);
SDL_Cursor *cursor = SDL_CreateColorCursor(surface);
SDL_SetCursor(cursor);

SDL loading my image messed up

I'm attemting to load an image that I exported from flash CS3 it's a very cute face but it loads very weird it loads on a blueish way this is the code for the two files:
//main.cpp
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include "test.hpp"
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_VIDEO);
// Activamos modo de video
screen = SDL_SetVideoMode(640,480,32,SDL_SWSURFACE | SDL_DOUBLEBUF);
image = IMG_Load("face.bmp");
dest.x = 200;
dest.y = 200;
//Main Loop
while(Abierto)
{
//We Draw
Draw();
//Events
while( SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT)
Abierto = false;
}
}
// We free the image
SDL_FreeSurface(image);
SDL_Quit();
return 0;
}
Now the other one the;
//test.hpp
DL_Surface *image = NULL, *screen = NULL;
SDL_Rect dest;
SDL_Event event;
bool Abierto = true;
float PlaneX = 300, PlaneY = 200;
float velX = 0.1, velY = 0.1;
void Draw()
{
Uint32 color;
// Black Background is created
color = SDL_MapRGB (screen -> format, 0, 0, 0);
SDL_FillRect (screen, NULL, color);
SDL_DisplayFormatAlpha(image);
SDL_BlitSurface(image, NULL, screen, &dest);
// Flip the working image buffer with the screen buffer
SDL_Flip (screen);
}
I need help with this please Im not that experienced on SDL stuff oh and if you want to take a closer look I uplaoded the project here.
Oh my bad I must add the image is 32 pixels with alpha according to flash exporting options
According to docs, SDL_DisplayFormatAlpha returns a new image and keeps the original intact.
So, try in the first part, when you load the image:
SDL_Surface *origImage = IMG_Load("face.bmp");
image = SDL_DisplayFormatAlpha(origImage);
SDL_FreeSurface(origImage)
As there is no need to call SDL_DisplayFormatAlpha each frame.
Then in the second part, just blit image, without calling SDL_DisplayFormatAlpha.
UPDATE
I've just checked your picture, and it looks like it is a weird bmp. I've seen that before: BMP format is such a mess that if you don't keep to the basics chances are that different programs will interpret the data differently.
In your case:
display face.bmp shows correctly.
gthumb face.bmp shows nothing.
eog face.bmp says "bogus header data".
I strongly recommend using PNG files for all your game cartoon-like pictures and JPG for all the photo-like ones.
So run
$ convert face.bmp face.png
And use the PNG file. I'll will work better and you will have a file 20% the size of the original.