i want to display an image(.png) in a frame in SDL.But,somehow only the frame appears and image does not get loaded.i am reading the image details from an XML file.this is the sample code i am trying:
Class myclass{
mysurface2(io.loadAndSet(myftndata->getXmlStr("backfile"), true) ),
myfframe(new fframe(img2,
myftn->getXmlInt("backWidth"),
myftn->getXmlInt("backHeight"), 0, 0)),
myobjects()
{
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
throw string("SDL Error!!!: ");
}
atexit(SDL_Quit);
}
};
void myclass::drawImg() const {
SDL_FillRect( screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255) );
SDL_Rect dest = {0, 0, 0, 0};
SDL_BlitSurface( screen, NULL, screen, &dest );
}
void myclass::move()
{
while ( not done )
{
drawImg();
SDL_Flip(screen);
}
}
Please note: i have an entire framework,which i cannot give here.The above is my code that i am trying.
You are blitting the screen to the screen, which is a zero-operation. You should change the first screen in the blit function to the SDL_Surface* that represents your image.
Are you using a library (e.g. SDL_Image) for loading the .png file? Because SDL can only load .bmp files.
Related
I am trying to create a transparent surface, blit it bigger surface (size of my screen), then create a texture of it, copy to the renderer, and finaly render present.
I have seen many other forums saying I have to use SetBlendMode (for surface, texture, and renderer), ColorKey, SetSurfaceBlendMode. I tried them all but I can't seem to get it to work. I read that SDL_BlitScaled is not suitable for combining surfaces that have transparent pixels, but I am completely lost as to what I have to do instead.
What I noticed, when I use SDL_CreateRGBSurface (with an alpha value) to create a surface, the surface's PixelFormat is RGB888 instead of RGBA8888 (what I am expecting since I provide the alpha value). Using SDL_ConvertSurfaceFormat did not help.
Can somebody tell me what I am missing?
Complete code: removed, my appologies
Please note that I have removed the attempts to get transparency working
The renderer:
mRenderer = SDL_CreateRenderer(mWindow, -1, SDL_RENDERER_ACCELERATED);
My render loop:
void CApp::Render()
{
SDL_RenderClear(mRenderer);
mBackGround->Render(mRenderer);
mForeGround->Render(mRenderer);
SDL_RenderPresent(mRenderer);
}
The big surface I am blitting to:
mSurface = SDL_CreateRGBSurface(0, CApp::Window_W(), CApp::Window_H(), 32, 0, 0, 0, 0);
The code to get tiles from a spritesheet:
bool Map::GetTilesFromSpriteSheet(SDL_Surface *pSpriteSheet, int pTile_w, int pTile_h)
{
if(pSpriteSheet->w % pTile_w == 0 && pSpriteSheet->h % pTile_h == 0) {
SDL_Rect srcRect;
srcRect.w = pTile_w;
srcRect.h = pTile_h;
for(int y = 0; y < pSpriteSheet->h / pTile_h; y++) {
for(int x = 0; x < pSpriteSheet->w / pTile_w; x++) {
srcRect.x = x*pTile_w;
srcRect.y = y*pTile_h;
SDL_Surface* tempSurface = SDL_CreateRGBSurface(0, pTile_w, pTile_h, 32, 0, 0, 0, 0);
if(SDL_BlitSurface(pSpriteSheet, &srcRect, tempSurface, nullptr)==0) {
mTiles.push_back(tempSurface);
} else {
Log("Error extracting tile (%d,%d)(w,h): %s", x, y, SDL_GetError());
return false;
}
}
}
Log("Number of tiles: %d", static_cast<int>(mTiles.size()));
} else {
Log("Background spritesheet is incompatible with tile dimensions (%d,%d)(w,h).", pTile_w, pTile_h);
return false;
}
return true;
}
This is where I combine the tiles to create the big surface:
bool Map::GenerateMap(std::vector<std::vector<int>> &pMap, std::vector<SDL_Surface*> &pTiles, SDL_Surface* pDestination)
{
SDL_Rect rect;
rect.w = mDstTile_W;
rect.h = mDstTile_H;
SDL_Surface* transparent = SDL_CreateRGBSurface(0, mDstTile_W, mDstTile_H, 32, 0, 0, 0, 0);
for(int y = 0; y < static_cast<int>(pMap.size()); y++) {
for(int x = 0; x < static_cast<int>(pMap.at(static_cast<unsigned long>(y)).size()); x++) {
rect.x = x*mDstTile_W;
rect.y = y*mDstTile_H;
int index = static_cast<int>(pMap.at(static_cast<unsigned long>(y)).at(static_cast<unsigned long>(x)));
if(index < 0) {
if(SDL_BlitScaled(transparent, nullptr, pDestination, &rect) != 0) {
Log("Error blitting transparent surface to destination: %s", SDL_GetError());
}
} else if(SDL_BlitScaled(pTiles[static_cast<unsigned long>(index)],
nullptr, pDestination, &rect) != 0) {
Log("Error blitting surface to destination: %s", SDL_GetError());
return false;
}
}
}
SDL_FreeSurface(transparent);
return true;
}
And finaly, this is the code to render the big surface to the screen, first by creating a texture:
void ForeGround::Render(SDL_Renderer* pRenderer)
{
if(mTexture) SDL_DestroyTexture(mTexture);
mTexture = SDL_CreateTextureFromSurface(pRenderer, mSurface);
if(mTexture == nullptr) {
Log("Unable to create foreground texture: %s", SDL_GetError());
} else if (SDL_RenderCopy(pRenderer, mTexture, nullptr, nullptr)) {
Log("Unable to render foreground: %s", SDL_GetError());
}
}
As #keltar mentioned, I was not creating surfaces with an alpha value.
I had to change the SDL_CreateRGBSurface call. The code snippet below creates an empty, transparent surface where I can blit to if needed (for example, tiles from a spritesheet).
SDL_Surface* tempSurface = SDL_CreateRGBSurface(..., 32, 0xff, 0xff00, 0xff0000, 0xff000000);
The code snippet below creates a black, non-transparent surface.
SDL_Surface* tempSurface = SDL_CreateRGBSurface(..., 32, 0xff, 0xff00, 0xff0000, 0x00000000);
This was enough for me, I did not have to use SDL_SetRenderDrawBlendMode, SDL_SetSurfaceBlendMode, SDL_SetTextureBlendMode, or SDL_ConvertSurface. A quick look at the SDL wiki showed:
By default surfaces with an alpha mask are set up for blending as with
SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND)
Which explained why I did not have to call any of those functions. A big shout-out to keltar for his quick answer!
I am facing an issue with the SDL library and different resolution than 1920x1080.
I want to copy display an image of dimension 1080x608 at the center of a screen of resolution 1080x1920 (portrait).
I have only one plugged monitor screen.
I used the following command to switch screen from 1920x1080 to 1080x1920 :
xrandr --output DP-1 --mode 1920x1080 --rotate left --primary
I am using the following code to initialize the SDL renderer :
/**
* initialize everything so we are ready to display
*/
int SdlHandler::initialize(
unsigned int positionX,
unsigned int positionY,
unsigned int width,
unsigned int height,
bool showWindow,
std::string name) {
// Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl;
return -1;
}
// Size if the window
this->width = width;
this->height = height;
this->positionX = positionX;
this->positionY = positionY;
// Create the SDL window
// 0 and 0 are the position in X and Y
unsigned int flags = SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS;
if (showWindow) {
flags |= SDL_WINDOW_SHOWN;
} else {
flags |= SDL_WINDOW_HIDDEN;
}
this->window = SDL_CreateWindow(name.c_str(), this->positionX, this->positionY, this->width, this->height, flags);
// If there had been a problem, leave
if (!this->window) {
return -1;
}
// Create a new renderer
this->renderer = SDL_CreateRenderer(this->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
// If there is an error creating it, just leave
if (!this->renderer) {
return -1;
}
// Setup the best for the SDL render quality
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2");
return 0;
}
Then, i call the SDL_RenderCopy function to display the image. I pass it the created renderer created with theSDL_CreateRenderer on the above code :
// Create a window at 0,0 of dimension 1080x1920
this->initialize(0, 0, 1080, 1920, true, SDL_BASE_DISPLAY_WINDOW);
// Create the SDL Rectangle that will contain the image, at the center of the window
SDL_Rect *howToDraw = new SDL_Rect();
howToDraw->x = this->positionX + floor((this->width - this->imageWidth) / 2);
howToDraw->y = this->positionY + floor((this->height - this->imageHeight) / 2);
howToDraw->w = this->imageWidth;
howToDraw->h = this->imageHeight;
SDL_RenderCopy(this->renderer, this->texture, NULL, howToDraw);
But the axis seems to be at the wrong position, igot the following result :
EDIT AND SOLUTION
This was a bug related to Compton, the window manager, everything is working good without Compton ...
Since you are rotating your display using xrandr, we can consider this is a post processing step that will rotate everything after each framebuffer is rendered.
Because this post processing step takes a 1920x1080 image resolution as input, you should use the SDL at this resolution.
What if you change your code for:
// Create a window at 0,0 of dimension 1920x1080
this->initialize(0, 0, 1920, 1080, true, SDL_BASE_DISPLAY_WINDOW);
EDIT: I also understand that you want your image to start at the center of the window, but your are placing the middle of the image at the center of the window.
You should also try the following:
howToDraw->x = this->positionX + this->imageWidth / 2;
I am doing my code for a simple game using SDL library. I have 2 questions regarding this:
If I don't put a breakpoint and let the program runs by itself, the memory usage going high (like 20-30x compared to the beginning). However, if I stop the loop (main loop of the game) and click by myself, the memory usage stay same after around 100 clicks(?). Why?
So I decided to use instrument to analyze the reason why since I think in the loop I might adding new element without destroying it. And everytime I hit record in Instrument, the app goes on for 5 seconds and shutdowns with a crash report (The app runs perfectly, with the memory stuff, in xcode)
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 org.libsdl.SDL2 0x0000000100f5bea9 0x100ee9000 + 470697
1 Spike 10 0x0000000100ea40cc imageTexture::render() + 50 (imageTexture.cpp:37)
2 Spike 10 0x0000000100ea2b70 GUI::renderImage() + 40 (GUI.cpp:140)
3 Spike 10 0x0000000100ea30b2 GUI::run() + 1258 (GUI.cpp:172)
4 Spike 10 0x0000000100ea439e main + 36 (main.cpp:15)
5 libdyld.dylib 0x00007fff8c60f5ad start + 1
These are some codes that I think might related:
For number 3: //imageVector is just a vector contain all the imageVector pointer
SDL_RenderClear( gRenderer );
for (int i = 0; i < imageVector.size(); i++) {
imageVector[i]->render();
}
For number 2:
//set rendering space and render to screen
SDL_Rect temp = {x, y, width, height};
//render to the screen
SDL_RenderCopy(gRenderer, texture, NULL, &temp);
After a long try disable/enable code around to find what happen, I still have no idea what's wrong.
This is my current loop:
while (true) {
textVector[0]->setInput(system->output());
renderImage();
renderText();
SDL_RenderPresent( gRenderer );
}
Some code for it:
void textTexture::setInput(std::string newText) {
gText = newText;
}
void GUI::renderImage() {
SDL_RenderClear( gRenderer );
for (int i = 0; i < imageVector.size(); i++) {
imageVector[i]->render();
}
}
void GUI::renderText() {
for (int i = 0; i < textVector.size(); i++) {
textVector[i]->render();
}
}
void textTexture::render() {
//set rendering space and render to screen
SDL_Rect temp = {x, y, width, height};
//recreate the texture
createTextureFromRenderedText(gText);
//render to the screen
SDL_RenderCopy(gRenderer, texture, NULL, &temp);
}
void textTexture::createTextureFromRenderedText(std::string text) {
if (text != "") {
SDL_Surface* textSurface = TTF_RenderText_Blended_Wrapped(gFont, text.c_str(), textColor, 600);
if( textSurface == NULL )
{
printf( "Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError() );
}
else
{
//Create texture from surface pixels
texture = SDL_CreateTextureFromSurface( gRenderer, textSurface );
if( texture == NULL )
{
printf( "Unable to create texture from rendered text! SDL Error: %s\n", SDL_GetError() );
}
else
{
//Get image dimensions
width = textSurface->w;
height = textSurface->h;
}
//Get rid of old surface
SDL_FreeSurface( textSurface );
}
}
}
Find the problem. I copy the style of lazyfoo and try to implement in mine so when I render new textTexture, it actually create new texture without destroying it. By using SDL_DestroyTexture, everything works fine
Found the answer here:
https://stackoverflow.com/questions/24938695/memory-leak-sdl-while-using-sdl-createtexturefromsurface
My board game is using a matrix. I created a board using rectangles. gimprimir() takes the matrix and translates it creating different types of rectangles.
I need to insert an image on a part of the screen. This tutorial teaches how to put an image on screen, but not how to load it in a part of the screen. Whenever I try to modify it, I get a segmentation fault. I want to keep it simple. The image format is .bmp.
My code:
bool loadMedia();
void close();
SDL_Texture* loadTexture( std::string path );
SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;
const int SCREEN_WIDTH = 1200;
const int SCREEN_HEIGHT = 680;
int main(int argc, char* args[]){
nodo a;
if( !init() ){
cout << "Failed to initialize!\n" ;
}
else{
if(!loadMedia()){
cout << "Failed to load media!\n";
}
else{
bool quit = false; // flag ciclo principal
SDL_Event e; // variables manejo de eventos
SDL_Event t;
gimprimir(a);
}
}
}
Function gimprimir() prints a board using struct a:
struct nodo {
array<array<int,19>,19> tablero; // Estado tablero
array<int,2> p1,p2; // Posiciones
int d1,d2; // Distancias mínimas
int paredes1;
int paredes2;
} a;
gimprimir() uses empty and filled rectangles:
void gimprimir(nodo aa){
//Clear screen
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( gRenderer );
int i,j;
for (i=1; i<=17; i++){
if (i%2==1){
for (j=1; j<=17 ; j++){
if (j%2==1){
if (aa.p1[0]==i && aa.p1[1]==j){ // FICHA 1
SDL_Rect fillRect = {(50+SCREEN_WIDTH/11)+(SCREEN_WIDTH/11)*(j-1)/2+34, (SCREEN_HEIGHT/11)+(SCREEN_HEIGHT/11)*(i-1)/2+34, SCREEN_WIDTH/12, SCREEN_HEIGHT/12};
SDL_SetRenderDrawColor( gRenderer, 0xff, 0xcc, 0x66, 0xFF );
SDL_RenderFillRect( gRenderer, &fillRect );
}
else{
if (aa.p2[0]==i && aa.p2[1]==j){ // FICHA 2
SDL_Rect fillRect = {(50+SCREEN_WIDTH/11)+(SCREEN_WIDTH/11)*(j-1)/2+34, (SCREEN_HEIGHT/11)+(SCREEN_HEIGHT/11)*(i-1)/2+34, SCREEN_WIDTH/12, SCREEN_HEIGHT/12};
SDL_SetRenderDrawColor( gRenderer, 0x6E, 0x2C, 0x67, 0xFF );
SDL_RenderFillRect( gRenderer, &fillRect );
}
else{ // CASILLA VACÍA
SDL_Rect fillRect = {(50+SCREEN_WIDTH/11)+(SCREEN_WIDTH/11)*(j-1)/2+34, (SCREEN_HEIGHT/11)+(SCREEN_HEIGHT/11)*(i-1)/2+34, SCREEN_WIDTH/12, SCREEN_HEIGHT/12};
SDL_SetRenderDrawColor( gRenderer, 0x8B, 0x45, 0x13, 0xFF);
SDL_RenderFillRect( gRenderer, &fillRect );
}
}
}
}
}
}
SDL_RenderPresent( gRenderer );
}
loadMedia():
bool loadMedia()
{
//Loading success flag
bool success = true;
//Nothing to load
return success;
}
I want to have both on screen. To load the image to be left in a part of the screen forever and then update the rectangles generated with gimprimir().
SDL_BlitSurface is the SDL function used to blit (copy) from a surface to another, it takes two SDL_Rect arguments, srcrect for source and dstrect for destination.
SDL_BlitSurface isn't changed much from SDL1.2 to SDL2, so, old examples which use it should still work.
In the getting_an_image_on_the_screen example you propose a NULL pointer is used for both src and dst rect, a NULL rect mean copy the whole src surface into the destination at top, left = 0, 0 with a maximum size equal to the destination size (if the source is bigger should be cropped).
To blit a partial image just specify src and dst rect:
SDL_Rect srcrect = { 0, 0, 100, 100 };
SDL_Rect dstrect = { 50, 50, 100, 100 };
//Apply the image
SDL_BlitSurface( gHelloWorld, &srcrect, gScreenSurface, &dstrect );
In this case top, left = 0, 0 with width, height = 100, 100 from source surface (gHelloWorld) is blit to top, left = 50, 50 of dest surface (gScreenSurface).
how to load it with other types of objects
Sorry but is not clear to me what you mean by other types of objects
SDL_BlitSurface() will work, but since you're using SDL2 you're probably working mostly with SDL_Textures and not SDL_Surfaces. If this is the case the easiest way to copy one texture onto another texture or onto the screen is using SDL_RenderCopy() as keltar mentioned. The advantages of using SDL_Texture are explained here: http://wiki.libsdl.org/MigrationGuide#Video
As documented here, SDL_RenderCopy() takes four arguments: a pointer to the SDL_Renderer, a pointer to your source texture, a pointer to the source rectangle, and a pointer to the destination rectangle. By default the texture will be copied onto the screen but you can copy onto other textures by setting a target texture with SDL_SetRenderTarget().
Everything about source and destination rectangles carries over from SDL_BlitSurface.
i'm fairly new at programming with allegro, and i wanna change the background color of my programs from something more pleasant than black haha :) can some one help please?
and just for a reference of what im doing
#include <allegro.h>
BITMAP* buffer;
BITMAP* bmp;
int cursor_x = 20;
int cursor_y = 20;
int getMouseInfo(){
if(mouse_b & 1){
cursor_x = mouse_x;
cursor_y = mouse_y;
return 1;
}
return 0;
}
void updateScreen(){
show_mouse(NULL);
circlefill ( buffer, cursor_x, cursor_y, 60, makecol( 0, 255 , 0));
draw_sprite( screen, buffer, 0, 0);
}
int main(){
allegro_init();
install_mouse();
install_keyboard();
set_color_depth(16);
set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0);
rectfill (
buffer = create_bitmap( 640, 480);
show_mouse(screen);
while( !key[KEY_ESC])
{
int switcher=1;
while(getMouseInfo())
{
updateScreen();
if(getMouseInfo()==0) switcher=0;
}
if(switcher==0) show_mouse(screen);
}
return 0;
}
END_OF_MAIN();
To create backgroud bitmap try this:
/* Make a bitmap in RAM. */
BITMAP *bmp = create_bitmap(SCR_X, SCR_Y);
then try this to clear bmp to some different color:
/* Clear the screen to red. */
clear_to_color(bmp, makecol(255, 0, 0));
or this to load bitmap from file:
bmp = load_bitmap("image.pcx", palette);
Then you just need to blit this bitmap with your screen - like this:
/* Blit bmp on the screen. */
blit(bmp, screen, 0, 0, 0, 0, bmp->w, bmp->h);
Draw a screen-sized rectangle that is the color you want the background to be. Or just use clear_bitmap to clear the screen.
#include <iostream>
using namespace std;
int main()
{
cout<<" In the world were gamers play MINECRAFT, where they creating everithing they can emagine ...\n";
cin.get();
return 0;
}