i'm trying to create a manual color key with pixel manipulation in SDL2, but when i execute the program, the color key doesn't work, these pixels become white, but not transparent.
I tried to Lock the surface and set the surface blendmode, but doesn't work too.
Code:
// IO includes
#include <iostream>
// String includes
#include <string>
// SDL includes
#include <SDL.h>
#include <SDL_image.h>
// Screen constants
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
using namespace std;
// Window variables
SDL_Window *window = NULL;
SDL_Surface *windowSurface = NULL;
// Image surfaces
SDL_Surface *background = NULL;
SDL_Surface *image = NULL;
// Functions
bool initializeSDL();
SDL_Surface *loadSurfaceFromFile(string path);
void SetColorKey(SDL_Surface *surface, Uint32 color);
bool LoadFiles();
void FreeMemory();
// SDL_main
int main(int argc, char* argv[]){
// Try to initialize and load files
if(initializeSDL() == false){
FreeMemory();
return -1;
}
if(LoadFiles() == false){
FreeMemory();
return -1;
}
// Blit images
SDL_BlitSurface(background, NULL, windowSurface, NULL);
SDL_BlitSurface(image, NULL, windowSurface, new SDL_Rect(70, 277, image->w, image->h));
// Update screen
SDL_UpdateWindowSurface(window);
// Loop
SDL_Event ev;
while(true){
if(SDL_PollEvent(&ev) && ev.type == SDL_QUIT) break;
}
return 0;
}
bool initializeSDL(){
// Try to initialize the video
if( SDL_Init(SDL_INIT_VIDEO) < 0 ){
// Print error
cout << "Error to initialize the video: " << SDL_GetError() << endl;
return false;
}
// Try to create the window
window = SDL_CreateWindow("Surface", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if(window == NULL){
// Print error
cout << "Error to create the window: " << SDL_GetError() << endl;
return false;
}
// Try to initialize PNG format
int imgFlags = IMG_INIT_PNG;
if(! (IMG_Init(imgFlags) &imgFlags) ) return false;
// Get the window surface
windowSurface = SDL_GetWindowSurface(window);
// If everything is fine, return true
return true;
}
SDL_Surface* loadSurfaceFromFile(string path){
// Create a temporary surface
SDL_Surface *tmpSurface = NULL;
// Create an optimized surface
SDL_Surface *optimizedSurface = NULL;
// Try to load the tmpSurface
tmpSurface = IMG_Load(path.c_str());
if(tmpSurface == NULL){
// Print error
cout << "Error to load the image: " << SDL_GetError() << endl;
return NULL;
}
// Try to optimize the surface
optimizedSurface = SDL_ConvertSurface(tmpSurface, windowSurface->format, NULL);
SDL_FreeSurface(tmpSurface); // Free tmpSurface memory
delete tmpSurface; // Delete the tmpSurface
if(optimizedSurface == NULL){
// Print error
cout << "Error to optimize the image: " << SDL_GetError() << endl;
}
return optimizedSurface;
}
void SetColorKey(SDL_Surface *surface, Uint32 color){
Uint32 *pixels = (Uint32*)surface->pixels;
int pixelCount = (surface->pitch/4) * surface->h;
Uint32 transparent = SDL_MapRGBA(image->format, 255, 255, 255, 0);
for(int i=0;i<pixelCount;i++){
if(pixels[i] == color){
pixels[i] = transparent;
}
}
}
bool LoadFiles(){
// Try to load the background
background = loadSurfaceFromFile("background.bmp");
if(background == NULL) return false;
// Try to load the image
image = loadSurfaceFromFile("image.png");
if(image == NULL) return false;
// Set manual color key to image
SetColorKey(image, SDL_MapRGB(image->format, 0, 255, 255));
return true;
}
void FreeMemory(){
SDL_FreeSurface(background);
SDL_FreeSurface(image);
SDL_DestroyWindow(window);
IMG_Quit();
SDL_Quit();
}
Related
#include <cstdlib>
#include <stdlib.h>
#include <iostream>
#include <SDL2/SDL.h>
int main ( int argc, char** argv )
{
const int height = 700;
const int width = 800;
if (SDL_Init(SDL_INIT_EVERYTHING) < 0){
std::cout << "SDL Failed to initalize" << std::endl;
return 1;
}
SDL_Window *window = SDL_CreateWindow("Particle Fire Explosion", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_SHOWN);
if (window == NULL){
SDL_Quit();
return 1;
}
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, width, height);
if(renderer == NULL){
std::cout << "COULD NOT CREATE RENDERER" << std::endl;
SDL_DestroyTexture(texture);
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
if(texture == NULL){
std::cout << "COULD NOT CREATE TEXTURE" << std::endl;
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
Uint32 *buffer = new Uint32(width * height);
Uint32 *memsett = new Uint32(width * height * sizeof(Uint32));
memset(buffer, 0xFF, width*height*sizeof(Uint32));
SDL_UpdateTexture(texture, NULL, buffer, width*sizeof(Uint32));
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer,texture, NULL, NULL);
SDL_RenderPresent(renderer);
bool quit = false;
SDL_Event event;
while (quit == false){
while(SDL_PollEvent(&event)){
if(event.type == SDL_QUIT){
quit = true;
}
}
}
SDL_DestroyRenderer(renderer);
SDL_DestroyTexture(texture);
delete [] buffer;
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
this Is my code, Im trying to make an all white window in SDL an dim trying to use memset to so this but it is not working. The bug says: Segmentation fault core dumped. It goes away when I remove the memset function, so I know that the memory meaning that memset is using is using memory not free so how do I change this?
Uin32 *buffer = new Uint32(width * height) allocates a single Uint32 with the value width * height, not an array of width * height Uint32s. Your call to memset then writes beyond the end of that single Uin32 and off into unowned memory.
You want [] instead of ():
Uint32* buffer = new Uint32[width * height];
In the following code:
#include <iostream>
#include "SDL.h"
using namespace std;
int main(int argc, char** argv)
{
SDL_Surface* screenSurface = nullptr;
SDL_Surface* image = nullptr;
SDL_Window* window = nullptr;
const Uint8* keystate;
SDL_Rect offset;
offset.x = 100;
offset.y = 200;
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
cout << "Window initialization error: " << SDL_GetError();
}
else
{
window = SDL_CreateWindow("game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN);
bool isRunning = true;
SDL_Event ev;
//game loop
while (isRunning)
{
while (SDL_PollEvent(&ev) != 0)
{
if (ev.type == SDL_QUIT)
isRunning = false;
}
keystate = SDL_GetKeyboardState(NULL);
if (keystate[SDL_SCANCODE_W])
{
offset.y -= 1;
}
else if (keystate[SDL_SCANCODE_A])
{
offset.x -= 1;
}
else if (keystate[SDL_SCANCODE_S])
{
offset.y += 1;
}
else if (keystate[SDL_SCANCODE_D])
{
offset.x += 1;
}
screenSurface = SDL_GetWindowSurface(window);
image = SDL_LoadBMP("world.bmp");
SDL_BlitSurface(image, NULL, screenSurface, &offset);
SDL_UpdateWindowSurface(window);
cout << SDL_GetError() << endl;
}
}
SDL_FreeSurface(image);
SDL_DestroyWindow(window);
image = nullptr;
window = nullptr;
SDL_Quit();
return 0;
}
I get an error, saying: "SDL_UpperBlit: passed a NULL surface error." But the error did not occur until I went from using a switch statement in the while loop for SDL_PollEvent, to just using if statements using SDL_SCANCODE_ in the isRunning while loop. So the error does not occur instantly, but after a short while, like 10 seconds or so. So I am able to move around the world.bmp with WASD for a short while, then I get the error "SDL_UpperBlit: passed a NULL surface error.".
What's the solution for this?
image = SDL_LoadBMP("world.bmp");
This loads world.bmp from the disk, creates a brand new surface and stores the image inside. You never destroy this surface, and you don't check for errors either.
As you're running this once per frame, SDL quickly runs out of resources, SDL_LoadBMP returns NULL to signal it, and you pass that NULL to SDL_BlitSurface.
Only load your resources once, and take care of destroying them at the right time. C++ has smart pointers and RAII to do that for you.
I'm trying to organize my code a bit more, so I tried putting the SDL2 code used for displaying windows/images into a class. The window opens, the code runs successfully, and the image seems to be loading fine, -but the image will not appear when the code is arranged in a class like this. Why is this happening?
main.cpp:
#include <SDL.h>
#include "display.h"
SDL_Event event;
SDL_Surface* image = nullptr;
int main(int argc, char* args[])
{
if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
return false;
Display display;
display.loadImage("image.bmp");
bool quit = false;
while (!quit)
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
quit = true;
}
display.applySurface(0, 0, image, display.windowSurface);
display.update();
}
SDL_FreeSurface(image);
SDL_Quit();
return 0;
}
display.h:
#pragma once
#include <SDL.h>
#include <string>
#include <iostream>
class Display
{
public:
SDL_Window* window;
SDL_Surface* windowSurface;
Display();
SDL_Surface* loadImage(std::string fileName);
void applySurface(int x, int y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *clip = nullptr);
void update();
~Display();
private:
const int WINDOW_WIDTH = 612;
const int WINDOW_HEIGHT = 632;
const int SCREEN_BPP = 2;
};
display.cpp:
#pragma once
#include "display.h"
Display::Display()
{
window = SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
if (window == NULL)
std::cout << "Error: SDL_CreateWindow failed." << std::endl;
windowSurface = SDL_GetWindowSurface(window);
if (windowSurface == NULL)
std::cout << "Error: Window surface is null." << std::endl;
}
SDL_Surface* Display::loadImage(std::string fileName)
{
SDL_Surface* loadedImage = NULL;
SDL_Surface* optimizedImage = NULL;
loadedImage = SDL_LoadBMP(fileName.c_str());
if (loadedImage == NULL)
std::cout << "Loaded image = NULL" << std::endl;
if (loadedImage != NULL)
{
optimizedImage = SDL_ConvertSurface(loadedImage, windowSurface->format, 0);
SDL_FreeSurface(loadedImage);
if (optimizedImage == NULL)
std::cout << "Optimized image = NULL" << std::endl;
if (optimizedImage != NULL)
SDL_SetColorKey(optimizedImage, SDL_TRUE, SDL_MapRGB(optimizedImage->format, 255, 255, 255));
}
return optimizedImage;
}
void Display::applySurface(int x, int y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect *clip)
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
SDL_BlitSurface(source, clip, destination, &offset);
}
void Display::update()
{
if (SDL_UpdateWindowSurface(window) == -1)
std::cout << "Error: SDL_UpdateWindowSurface() failed." << std::endl;
}
Display::~Display()
{
SDL_FreeSurface(windowSurface);
windowSurface = NULL;
SDL_DestroyWindow(window);
window = NULL;
}
In your main.cpp your image is empty because you didn't use the return image :
image = display.loadImage("image.bmp");
I was watching this series = https://www.youtube.com/watch?v=2NVgHrOFneg
and for some reason for the guy in the video the code works but for me it compiles fine but doesn't load an image. I really don't know what to do.
#include "SDL.h"
#include <iostream>
#include "SDL_image.h"
SDL_Texture *LoadTexture(std::string filePath, SDL_Renderer *renderTarget) //texture optimization function
{
SDL_Texture *texture = nullptr;
SDL_Surface *surface = IMG_Load(filePath.c_str());
if (surface == NULL)
std::cout << "Error 1" << std::endl;
else
{
texture = SDL_CreateTextureFromSurface(renderTarget, surface);
if (texture == NULL)
std::cout << "Error 2" << std::endl;
}
SDL_FreeSurface(surface);
return texture;
}
int main(int, char *argv[])
{
const int FPS = 144;
int frameTime = 0;
SDL_Window *window = nullptr;
SDL_Texture *currentImage= nullptr;
SDL_Renderer *renderTarget = nullptr;
SDL_Rect playerRect;
int frameWidth, frameHeight;
int textureWidth, textureHeight;
SDL_Init(SDL_INIT_VIDEO );
int imgFlags = IMG_INIT_PNG | IMG_INIT_JPG;
if (!(IMG_Init(imgFlags) != imgFlags))
{
std::cout << "Error: " << IMG_GetError() << std::endl;
}
window = SDL_CreateWindow("SDL Pong", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1024, 720, SDL_WINDOW_SHOWN);
renderTarget = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
currentImage = LoadTexture("Untitled.jpg", renderTarget);
SDL_QueryTexture(currentImage, NULL, NULL, &textureWidth, &textureHeight);
SDL_SetRenderDrawColor(renderTarget, 0xFF, 0, 0, 0xFF);
frameWidth = textureWidth / 3;
frameHeight = textureHeight / 4;
playerRect.x = playerRect.y = 0;
playerRect.y = frameWidth;
playerRect.h = frameHeight;
bool isRunning = true; //game loop
SDL_Event ev;
while (isRunning)
{
while (SDL_PollEvent(&ev) != 0)
{
if (ev.type == SDL_QUIT)
isRunning = false;
}
frameTime++;
if (FPS / frameTime == 4)
{
frameTime = 0;
playerRect.x += frameWidth;
if (playerRect.x >= textureWidth)
playerRect.x =0;
}
SDL_RenderClear(renderTarget);
SDL_RenderCopy(renderTarget, currentImage, &playerRect, NULL);
SDL_RenderPresent(renderTarget);
}
SDL_DestroyWindow(window);
SDL_DestroyTexture(currentImage);
SDL_DestroyRenderer(renderTarget);
window = nullptr;
renderTarget = nullptr;
currentImage = nullptr;
SDL_Quit();
return 0;
}
This is the error message: http://imgur.com/LHMdt5F
IMG_Init returns bitfield of formats that was initialised. If resulting bitfield doesn't contain every format that was requested in flags, something gone wrong.
if (!(IMG_Init(imgFlags) != imgFlags)) checks if there is no error. Then you're trying to get error message, but there were no errors. Remove negation operator.
When you create the .exe and run it from an IDE it often stores the executable in a ../bin/.. directory. If Untitled.jpg is in the same directory as your source files, it will not find it.
SDL_GetBasePath(); will return the base path to your files. Check it out docs for it.
The string from SDL_GetBasePath() + "Untitled.jpg" will find and open the file.
So im trying to render an image. This code worked fine before I refactored into seperate classes but i cannot see the problem. The file path for the image also worked before the refactoring however i have not moved the image so it should still be in the same place.
The error i am getting is "Unable to create texture from surface. Error: Couldn't open Images/text.bmp" so im fairly certain its the line of code below that is messing up.
if (!(gTexture->LoadFromFile("Images/text.bmp")))
{
return false;
}
Here is the LoadFromFile function code
bool Texture2D::LoadFromFile(string path)
{
Free();
SDL_Texture* pTexture = NULL;
SDL_Surface* pSurface = IMG_Load(path.c_str());
if (pSurface != NULL)
{
//SDL_SetColorKey(pSurface, SDL_TRUE, SDL_MapRGB(pSurface->format, 0, 0xFF, 0xFF));
pTexture = SDL_CreateTextureFromSurface(mRenderer, pSurface);
if (pTexture == NULL)
{
cout << "Unable to create texture from surface. Error: " << SDL_GetError() << endl;
}
mWidth = pSurface->w;
mHeight = pSurface->h;
SDL_FreeSurface(pSurface);
}
else
{
cout << "Unable to create texture from surface. Error: " << IMG_GetError() << endl;
}
mTexture = pTexture;
return pTexture != NULL;
}
Below is the Source.cpp file:
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_mixer.h>
#include "Constants.h"
#include "Texture2D.h"
#include "Commons.h"
#include <iostream>
#include <string>
using namespace std;
//Globals
SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;
Texture2D* gTexture = NULL;
//prototypes
bool InitSDL();
void CloseSDL();
bool Update();
void Render();
int main(int argc, char* args[])
{
if(InitSDL())
{
bool quit = false;
while(!quit)
{
//gTexture->Render(Vector2D(), SDL_FLIP_NONE, 0);
Render();
quit = Update();
}
}
CloseSDL();
return 0;
}
bool InitSDL()
{
if(SDL_Init(SDL_INIT_VIDEO) < 0)
{
cout << "SDL did not initialise. Error: " << SDL_GetError();
return false;
}
else
{
//ITS ALL GOOD BRO
gWindow = SDL_CreateWindow("Games Engine Creation",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH,
SCREEN_HEIGHT,
SDL_WINDOW_SHOWN);
//DID IT GO?
if (gWindow == NULL)
{
//NUH UH
cout << "Window was not created. Error: " << SDL_GetError();
return false;
}
gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
if (gRenderer != NULL)
{
//INITIALISE THAT PNG BBY
int imageFlags = IMG_INIT_PNG;
if (!(IMG_Init(imageFlags) & imageFlags))
{
cout << "SDL_Image could not initialise. Error: " << IMG_GetError();
return false;
}
}
else
{
cout << "Renderer could not be initialised. Error: " << SDL_GetError();
return false;
}
gTexture = new Texture2D(gRenderer);
if (!(gTexture->LoadFromFile("Images/text.bmp")))
{
return false;
}
return true;
}
}
void CloseSDL()
{
SDL_DestroyWindow(gWindow);
gWindow = NULL;
delete gTexture;
gTexture = NULL;
SDL_DestroyRenderer(gRenderer);
gRenderer = NULL;
IMG_Quit();
SDL_Quit();
}
bool Update()
{
SDL_Event e;
SDL_PollEvent(&e);
switch(e.type)
{
case SDL_QUIT:
return true;
break;
case SDL_KEYUP:
switch(e.key.keysym.sym)
{
case SDLK_q:
return true;
break;
}
break;
case SDL_MOUSEBUTTONDOWN:
return true;
break;
}
return false;
}
void Render()
{
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(gRenderer);
gTexture->Render(Vector2D(), SDL_FLIP_NONE, 0);
//SDL_Rect renderLocation = { 0, 0, mWidth, mHeight };
//SDL_RenderCopyEx(mRenderer, mTexture, NULL, &renderLocation, 0, NULL, SDL_FLIP_NONE);
SDL_RenderPresent(gRenderer);
}
A simple way to start debugging is to place the image in the same folder with the executable and show the path as ./image.bmp to see if something is wrong with the path.