SDL_BlitSurface() return -1 ... Why? - c++

The SDL documentation say that SDL_BlitSurface() returns -1 when it is not successful, but i can not find why it would fail.
Here is my source code:
main.cpp
#include <iostream>
#include <string>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include "window.cpp"
#include "player.cpp"
int init();
void quit();
int main(int argc,char *args[])
{
if (init() == -1)
{
std::cerr << "Error:init()" << std::endl;
return -1;
}
window main_window("Juego","img/bg.png",800,600,32);
player player1(500,500,0,0,5,5,"img/square.png");
while (!main_window.close)
{
main_window.handle_events();
if ( main_window.draw_background() != true)
{
std::cerr << "ERROR->main_window.draw_background()" << std::endl;
main_window.close = true;
}
player1.update(main_window.screen);
SDL_Flip(main_window.screen);
SDL_Delay(60/1000);
}
quit();
return 0;
}
int init()
{
if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
{
std::cerr << "Error while initialising SDL" << std::endl;
return -1;
}
return 0;
}
void quit()
{
SDL_Quit();
}
window.cpp
class window
{
private:
void load_image(std::string source,SDL_Surface *destination);
SDL_Surface *window_bg;
SDL_Event event_queue;
SDL_Rect window_rect;
public:
window(std::string SCREEN_TITLE,std::string SCREEN_BG,int sw,int sh,int sbpp);
void handle_events();
bool draw_background();
SDL_Surface *screen;
bool close;
};
window::window(std::string SCREEN_TITLE,std::string SCREEN_BG,int sw,int sh,int sbpp)
{
window_bg = NULL;
screen = NULL;
close = false;
window_rect.x = 0;
window_rect.y = 0;
window_rect.w = sw;
window_rect.h = sh;
screen = SDL_SetVideoMode(sw,sh,sbpp,SDL_SWSURFACE);
std::cout << "Screen created." << std::endl;
SDL_WM_SetCaption(SCREEN_TITLE.c_str(),NULL);
std::cout << "Window title: " << SCREEN_TITLE << std::endl;
load_image(SCREEN_BG,window_bg);
}
void window::handle_events()
{
while (SDL_PollEvent(&event_queue))
{
if (event_queue.type == SDL_QUIT)
{
close = true;
}
}
}
void window::load_image(std::string source,SDL_Surface *destination)
{
SDL_Surface *tmp_img = IMG_Load(source.c_str());
if (tmp_img != NULL)
{
if ((destination = SDL_DisplayFormat(tmp_img)) == NULL)
{
std::cerr << "ERROR->SDL_DisplayFormat()" << std::endl;
}
std::cout << source << " Loaded." << std::endl;
SDL_FreeSurface(tmp_img);
}
else
{
std::cerr << "Could not load: " << source << std::endl;
}
}
bool window::draw_background()
{
int error_check = SDL_BlitSurface(window_bg,&window_rect,screen,NULL);
if (error_check != 0)
{
std::cerr << "SDL_BlitSurface() == " << error_check << std::endl;
return false;
}
return true;
}
The error is in window.cpp (i think):
bool window::draw_background()
{
int error_check = SDL_BlitSurface(window_bg,NULL,screen,NULL);
if (error_check != 0)
{
std::cerr << "SDL_BlitSurface() == " << error_check << std::endl;
return false;
}
return true;
}
The output of my program is:
Screen created.
Window title: Juego
img/bg.png Loaded.
img/square.png Loaded
SDL_BlitSurface() == -1
ERROR->main_window.draw_background()

load_image(SCREEN_BG,window_bg); in the window constructor loads into a temporary SDL_Surface and never populates the destination, which I assume is an output parameter. Then when draw_background() uses window_bg, it's still NULL.

Anything could be the cause of this (I could not be arsed to look through your code, see http://sscce.org/), you can debug what's wrong by printing out SDL_GetError() on an error return value.

Related

Why do EnumDomains/NextDomain loop forever?

The following simple code can be directly run in Visual Studio C++ console project.
It will loop forever because the NextDomain will always return the same IUnknown *
According to Microsoft, it should return NULL if the enumeration reaches end. See https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/icorruntimehost-nextdomain-method
However, the NULL is never reached. It seems that it never return the NextDomain but keep returning the same domain.
Is there anything wrong? Thanks.
#include <iostream>
#include <Windows.h>
#include <metahost.h>
#include <mscoree.h>
#pragma comment(lib, "mscoree.lib")
int main()
{
ICLRMetaHost* clrMetaHost = NULL;
ICLRRuntimeInfo* clrRuntimeInfo = NULL;
ICorRuntimeHost* clrCorRuntimeHost = NULL;
do {
if (FAILED(CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&clrMetaHost))))
{
std::cout << "failed 1" << std::endl;
break;
}
if (FAILED(clrMetaHost->GetRuntime(L"v2.0.50727", IID_PPV_ARGS(&clrRuntimeInfo))))
{
if (FAILED(clrMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&clrRuntimeInfo))))
{
std::cout << "failed 2" << std::endl;
break;
}
}
if (FAILED(clrRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_PPV_ARGS(&clrCorRuntimeHost))))
{
std::cout << "failed 3" << std::endl;
break;
}
if (FAILED(clrCorRuntimeHost->Start()))
{
std::cout << "failed 4" << std::endl;
break;
}
HDOMAINENUM hDomainEnum = nullptr;
if (FAILED(clrCorRuntimeHost->EnumDomains(&hDomainEnum))) {
std::cout << "failed 5" << std::endl;
break;
}
IUnknown* domain;
while (SUCCEEDED(clrCorRuntimeHost->NextDomain(hDomainEnum, &domain))
&& domain != NULL) {
std::cout << "why loop forever here?" << std::endl;
domain->Release();
}
if (FAILED(clrCorRuntimeHost->CloseEnum(hDomainEnum))) {
std::cout << "failed 6" << std::endl;
}
break;
} while (0);
if (clrCorRuntimeHost != NULL) clrCorRuntimeHost->Release();
if (clrRuntimeInfo != NULL) clrRuntimeInfo->Release();
if (clrMetaHost != NULL) clrMetaHost->Release();
return 0;
}
Return code from most enumerators is S_OK to continue and S_FALSE when it did not succeed. S_FALSE is not a fail code.
while (S_OK == clrCorRuntimeHost->NextDomain(hDomainEnum, &domain))
&& domain != NULL) {
std::cout << "why loop forever here?" << std::endl;
domain->Release();
}

sdl_net udp server setup

I've looked at tutorials and many other places on how to do this however I'm still having trouble getting this to work. Interestingly enough I did find a tutorial (which is where I derived this code from) on how to setup a UDP chat program which was wonderful for a basic example.
However just as soon as I do non local testing (I switch the IP for the server the client is supposed to connect to from localhost to my real IP), the packet ends up not being received. I can't help but feel that I've setup the server portion of this code wrong.
So here's what I have so far.
Network.h //the UDP networking code.
#pragma once
#include "include/SDL2/SDL_net.h"
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
/*******************************************************************************************
Some things to note about the UDPConnection class.
Init this on both the client and/or server's excutable. No extra work required. Unless your
planning on tracking the activity and data between multiple clients (eg: for multiplayer).
At which point you just memorize and communicate between different ip's manually.
HINT: look at packet->ip;
*******************************************************************************************/
class UDPConnection
{
bool quit;
UDPsocket ourSocket;
IPaddress serverIP;
public:
UDPpacket *packet;
UDPConnection()
{
quit = false;
}
~UDPConnection()
{
SDLNet_FreePacket(packet);
SDLNet_Quit();
}
bool Init(const std::string &ip, int32_t remotePort, int32_t localPort)
{
std::cout << "Connecting to \n\tIP : " << ip << "\n\tPort : " << remotePort << std::endl;
std::cout << "Local port : " << localPort << "\n\n";
// Initialize SDL_net
if (!InitSDL_Net())
return false;
if (!OpenPort(localPort))
return false;
if (!SetIPAndPort(ip, remotePort))
return false;
if (!CreatePacket(65536))
return false;
/* bind server address to channel 0 */
if (SDLNet_UDP_Bind(ourSocket, 0, &serverIP) == -1)
{
printf("SDLNet_UDP_Bind: %s\n", SDLNet_GetError());
return false;
}
return true;
}
bool InitServer(int32_t remotePort, int32_t localPort) {
std::cout << "connecting to port" << remotePort << std::endl;
std::cout << "Local port : " << localPort << "\n\n";
// Initialize SDL_net
if (!InitSDL_Net())
return false;
if (!OpenPort(localPort))
return false;
if (!SetPort(remotePort))
return false;
if (!CreatePacket(65536))
return false;
SDLNet_UDP_Unbind(ourSocket, 0);
return true;
}
bool InitSDL_Net()
{
std::cout << "Initializing SDL_net...\n";
if (SDLNet_Init() == -1)
{
std::cout << "\tSDLNet_Init failed : " << SDLNet_GetError() << std::endl;
return false;
}
std::cout << "\tSuccess!\n\n";
return true;
}
bool CreatePacket(int32_t packetSize)
{
std::cout << "Creating packet with size " << packetSize << "...\n";
// Allocate memory for the packet
packet = SDLNet_AllocPacket(packetSize);
if (packet == nullptr)
{
std::cout << "\tSDLNet_AllocPacket failed : " << SDLNet_GetError() << std::endl;
return false;
}
// Set the destination host and port
// We got these from calling SetIPAndPort()
packet->address.host = serverIP.host;
packet->address.port = serverIP.port;
std::cout << "\tSuccess!\n\n";
return true;
}
bool OpenPort(int32_t port)
{
std::cout << "Opening port " << port << "...\n";
// Sets our sovket with our local port
ourSocket = SDLNet_UDP_Open(port);
if (ourSocket == nullptr)
{
std::cout << "\tSDLNet_UDP_Open failed : " << SDLNet_GetError() << std::endl;
return false;
}
std::cout << "\tSuccess!\n\n";
return true;
}
bool SetIPAndPort(const std::string &ip, uint16_t port)
{
std::cout << "Setting IP ( " << ip << " ) " << "and port ( " << port << " )\n";
// Set IP and port number with correct endianess
if (SDLNet_ResolveHost(&serverIP, ip.c_str(), port) == -1)
{
std::cout << "\tSDLNet_ResolveHost failed : " << SDLNet_GetError() << std::endl;
return false;
}
std::cout << "\tSuccess!\n\n";
return true;
}
bool SetPort(uint16_t port)
{
std::cout << "Setting up port ( " << port << " )\n";
// Set IP and port number with correct endianess
//IS THE ISSUE HERE?
if (SDLNet_ResolveHost(&serverIP, NULL, port) == -1)
{
std::cout << "\tSDLNet_ResolveHost failed : " << SDLNet_GetError() << std::endl;
return false;
}
std::cout << "\tSuccess!\n\n";
return true;
}
// Send data.
bool Send(const std::string &str)
{
// Set the data
// UDPPacket::data is an Uint8, which is similar to char*
// This means we can't set it directly.
//
// std::stringstreams let us add any data to it using << ( like std::cout )
// We can extract any data from a std::stringstream using >> ( like std::cin )
//
//str
memcpy(packet->data, str.c_str(), str.length());
packet->len = str.length();
// Send
// SDLNet_UDP_Send returns number of packets sent. 0 means error
//packet->channel = -1;
if (SDLNet_UDP_Send(ourSocket, -1, packet) == 0)
{
std::cout << "\tSDLNet_UDP_Send failed : " << SDLNet_GetError() << "\n"
<< "==========================================================================================================\n";
//msg.resize(0);
return false;
}
std::cout << "sent to: " << packet->address.host << "\n";
std::cout << "length is: " << packet->len << "\n";
}
inline UDPpacket* recievedData(){
// Check to see if there is a packet wauting for us...
if (SDLNet_UDP_Recv(ourSocket, packet))
{
/*for (int i = packet->len; i < 512; i++) {
//may only be needed for local testing.
packet->data[i] = 0;
}*/
//std::cout << "\tData received : " << packet->data << "\n";
return packet;
}return NULL;
}
inline bool WasQuit()
{
return quit;
}
};
clientSend.cpp //our client's exe.
#include "Network.h"
#include "Graphics.h"
#include <cstdlib>
UDPConnection *udpConnection;
using namespace std;
#define DISPLAY_STRING_ROWS 20
char displayString[DISPLAY_STRING_ROWS][256];
int main(int argc, char **argv){
setup(120, 120, 600, 400); //Inits SDL.
std::string IP = "72.49.67.66";
int32_t remotePort = 333;
int32_t localPort = 222;
udpConnection = new UDPConnection();
udpConnection->Init(IP, remotePort, localPort);
UDPpacket *packet;
for (int i = 0; i < DISPLAY_STRING_ROWS; i++) {
for (int j = 0; j < 256; j++) {
displayString[i][j] = 0;
}
}
while (!udpConnection->WasQuit()){
clear();
packet = udpConnection->recievedData();
#define PACKET_LEN packet->len
#define PACKET_DATA packet->data
static int currentRow = 0;
if (packet != NULL) {
for (int i = 0; i < PACKET_LEN; i++) {
displayString[currentRow][i] = udpConnection->packet->data[i];
}
displayString[currentRow][PACKET_LEN] = 0;
if (currentRow >= DISPLAY_STRING_ROWS) {
currentRow = 0;
}
else {
currentRow++;
}
}
for (int i = 0; i < currentRow; i++) {
if (displayString[i][0] != 0) {
text(displayString[i], 20, 20, PACKET_LEN * 16, 16, 0, 0, 0);
}
}
render();
std::string send;
getline(cin, send);
udpConnection->Send(send);
}
endGame();
}
void displayText() {
}
server.cpp //the server's exe.
#include "Network.h"
#include "Graphics.h"
#include <cstdlib>
//Right now i'm just assuming that the ip is givin every time it's sent to client/server.
UDPConnection *udpConnection;
using namespace std;
int main(int argc, char* args[]) {
//std::string IP = "0.0.0.0"; //Not necessary.
int32_t remotePort = 222;
int32_t localPort = 333;
udpConnection = new UDPConnection();
udpConnection->InitServer(remotePort, localPort);
UDPpacket *packet;
setup(120, 120, 600, 400); //Inits SDL.
char c[10][80000];
int cCount = 0;
int cLength[10];
bool running = true; //Is our game loop running?
while (running) { //--GAME LOOP!--//
clear(); //Clears garbage form SDL.
packet = udpConnection->recievedData();
#define PACKET_LEN packet->len
//#define PACKET_DATA packet->data
if (packet != NULL) {
cout << "we got a message" << endl;
packet->data[PACKET_LEN] = 0;
for (int i = 0; i <= PACKET_LEN; i++) {
c[cCount][i] = packet->data[i];
}
//*c[cCount] = udpConnection->packet->data;
cLength[cCount] = PACKET_LEN;
if (cCount == 9) {
cCount = 0;
}else{
cCount++;
}
}
for (int i = 0; i < cCount; i++) {
text(c[i], 20, i*16, cLength[i] * 16, 16, 0, 0, 0);
}
render(); //Causes SDL to draw what we made to our window.
}
endGame(); //Necessary to properly shutdown SDL.
}
I'd hope I won't have to include the graphic.c and graphics.h files however if this is necessary just ask and I'll post the whole project up on a repo for anyone to reference. I'm hoping however the answer is something really easy that I just kept glancing over.
Here's the link to the tutorial I got the code from. http://headerphile.com/sdl2/sdl2-part-12-multiplayer/
The goal is to have a udp server that's able to receive packets from anyone. The problem is that it simply won't receive over the internet even with the router's ports open.
(Posted on behalf of the OP)
This is pretty much resolved. the problem wasn't the code it was the modem my isp gave me. Turns it's possible and recommended to buy your own modem (facepalm).

TTF_RenderText_Solid() Crashing Game and Visual Studio [c++][sdl ttf]

Stack Trace :
So, I'm trying to create a 2D game and right now I'm trying to display and move a image, however when I Debug the game/run it, visual studio and the game freezes and can't quit, not even when using the task manager to kill it.
The only way to unfreeze it is by logging off or restarting the pc which forces both of them to close.
I also get some weird error :
Unhandled exception at 0x71002A95 (SDL2_ttf.dll) in SDLGame.exe: 0xC0000005: Access violation reading location 0x00000000.
I have no idea what it means and how to fix it, but I'm guessing it has something to do with my code that I need to change.
Here's my code :
#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
// Macros
#define pause system("PAUSE"); // Works on windows only, removed in alpha / beta versions.
// Pre "init" of functions
void QuitGame();
int InitGame();
void processInput();
void InitRects();
// Variables
int FramesPassed = 0;
int FramesPerSecond = 0; // Not used yet
SDL_Renderer* renderer = nullptr;
SDL_Window* window = nullptr;
SDL_Event evnt;
SDL_Rect sprite1_Rect;
SDL_Rect FPS_Text_Rect;
TTF_Font* Sans = TTF_OpenFont("Fonts/Aaargh.ttf", 40);
SDL_Color Color_White = { 255, 255, 255 };
SDL_Surface* FPS_Text_Surface = nullptr;
SDL_Texture* FPS_Text = nullptr;
SDL_Texture* testImg = nullptr;
static bool isRunning = true;
int SDL_main(int argc, char* argv[])
{
InitGame();
InitRects();
std::cout << "Displaying text on screen using SDL TTF doesn't work" << std::endl;
std::cout << "This happens when the TTF Surface is being rendered on screen" << std::endl;
std::cout << "check line : 123 and 124." << std::endl;
while (isRunning)
{
FramesPassed++;
processInput();
SDL_RenderClear(renderer); // Clears the last/current frame?
// Render testImage on screen. (needs to be between render present and clear.)
SDL_RenderCopy(renderer, testImg, NULL, &sprite1_Rect);
SDL_RenderCopy(renderer, FPS_Text, NULL, &FPS_Text_Rect);
SDL_RenderPresent(renderer); // Pretty much draws everything again.
}
return 0;
QuitGame();
}
int InitGame()
{
std::cout << "Game Initializing..." << std::endl;
std::cout << "TTF SDL Initializing..." << std::endl;
if (TTF_Init() < 0)
{
std::cout << "SDL TTF Failed To Initialize : " << TTF_GetError() << std::endl;
pause
QuitGame();
}
else
{
std::cout << "SDL TTF Initialized Successfully" << std::endl;
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
std::cout << "SDL Initialization Failed : " << SDL_GetError() << std::endl;
pause
QuitGame();
}
else
{
std::cout << "SDL Initializing" << std::endl;
window = SDL_CreateWindow("Game Title", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1024, 720, SDL_WINDOW_SHOWN);
if (window == NULL)
{
std::cout << "Window Creation Failed : " << SDL_GetError() << std::endl;
pause
QuitGame();
}
else
{
std::cout << "SDL Initialized Successfully" << std::endl;
std::cout << "Renderer Initializing..." << std::endl;
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (renderer == NULL)
{
std::cout << "Renderer Creation Failed : " << SDL_GetError() << std::endl;
pause
QuitGame();
}
else
{
std::cout << "Renderer Initialized Successfully" << std::endl;
// This line (under) crashes game, and crashes visual studio...
FPS_Text_Surface = TTF_RenderText_Solid(Sans, "Frames Passed : " + FramesPassed, Color_White);
testImg = IMG_LoadTexture(renderer, "images/test.bmp");
FPS_Text = SDL_CreateTextureFromSurface(renderer, FPS_Text_Surface);
}
}
}
}
std::cout << "Game Has Successfully Initialized!" << std::endl;
return 0;
}
void InitRects()
{
sprite1_Rect.h = 32;
sprite1_Rect.w = 32;
sprite1_Rect.x = 10;
sprite1_Rect.y = 10;
FPS_Text_Rect.h = 100;
FPS_Text_Rect.w = 50;
FPS_Text_Rect.x = 2;
FPS_Text_Rect.y = 2;
}
void processInput()
{
if (SDL_PollEvent(&evnt)) {
switch (evnt.type) {
case SDL_QUIT:
QuitGame();
break;
case SDL_KEYDOWN:
switch (evnt.key.keysym.sym) {
case SDLK_a:
sprite1_Rect.x -= 1;
break;
case SDLK_d:
sprite1_Rect.x += 1;
break;
case SDLK_w:
sprite1_Rect.y-= 1;
break;
case SDLK_s:
sprite1_Rect.y += 1;
break;
}
break;
}
}
}
void QuitGame()
{
isRunning = false;
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
The problem is that you have the font as a global variable and load it straight away!
You need to call TTF_Init() first and load the font after!
By using a global vairable your loading it before initializing SDL_TTF, and this way TTF_OpenFont() will return a nullptr and if you try to read a nullptr gives an Access violation reading location 0x00000000 error!
Just call TTF_OpenFont() in a function and after TTF_Init() and it will work!
Just a tip you should check that Sans isn't a nullptr before using it!

SDL blit surface: Segmentation fault

Every time I run this program I got a this error:
Segmentation fault
testing.cpp
#include <iostream>
#include <cstdint>
#include <SDL.h>
#include <SDL_image.h>
#include "Surface.h"
#include "Point2D.h"
int main() {
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
std::cerr << "Can not init SDL" << std::endl;
return -1;
}
SDL_Surface *scr = SDL_SetVideoMode(800, 600, 0, SDL_HWSURFACE | SDL_DOUBLEBUF);
if ( scr == NULL ) {
std::cerr << "Can not open window" << std::endl;
return -1;
}
SDL_WM_SetCaption("Test Surface class", NULL);
Surface screen;
Surface image;
screen.set(SDL_GetVideoSurface());
if (image.load("./data/images/logo.png") == false) {
std::cerr << "Can not open file" << std::endl;
return -1;
}
bool run = true;
uint32_t sticks = SDL_GetTicks();
while(run) {
if (screen.draw(image, Rectangle(0, 0, image.getWidth(), image.getHeight()), Point2D(0, 0)) == false) {
std::cerr << "Can not draw to window" << std::endl;
return -1;
}
if ((SDL_GetTicks() - sticks)/1000 > 5) {
std::cerr << "End of time" << std::endl;
run = false;
}
SDL_Flip(screen.sdlSurface());
}
std::cerr << "Done" << std::endl;
SDL_Quit();
return 0;
}
There is the source code of class Surface
#include "Surface.h"
#include "Color.h"
Surface::Surface() {
this->surface = NULL;
}
Surface::~Surface() {
SDL_FreeSurface(this->surface);
this->surface = NULL;
}
bool Surface::draw(Surface source, Rectangle source_area, Point2D position) {
SDL_Rect sr = source_area.sdlRect();
SDL_Rect tr = {position.getX(), position.getY(), 0, 0};
std::cout << sr.x << "," << sr.y << "," << sr.w << "," << sr.h << std::endl;
std::cout << tr.x << "," << tr.y << "," << tr.w << "," << tr.h << std::endl;
std::cout << source.sdlSurface() << std::endl;
std::cout << this->surface << std::endl;
// TR and SR are currently unused. Just for case of testing
if (SDL_BlitSurface(source.sdlSurface(), NULL, this->surface, NULL) != 0) {
return false;
}
return true;
}
bool Surface::fill(Color color, Rectangle area) {
SDL_Rect tr = area.sdlRect();
std::cout << tr.x << "," << tr.y << "," << tr.w << "," << tr.h << std::endl;
std::cout << (int)color.sdlColor() << std::endl;
if ( SDL_FillRect(this->surface, &tr, color.sdlColor()) != 0) {
return false;
}
return true;
}
Rectangle Surface::getSize() {
return Rectangle(0, 0, this->getWidth(), this->getHeight());
}
bool Surface::load(std::string file) {
SDL_Surface *src = IMG_Load(file.c_str());
if (src == NULL) {
std::cout << "cyh" << std::endl;
std::cout << IMG_GetError() << std::endl;
return false;
}
this->surface = SDL_DisplayFormatAlpha(src);
if (this->surface == NULL) {
std::cout << "cyh1" << std::endl;
std::cout << SDL_GetError() << std::endl;
return false;
}
SDL_FreeSurface(src);
src = NULL;
return true;
}
void Surface::set(SDL_Surface *surface) {
this->surface = surface;
}
void Surface::set(Surface surface) {
this->surface = surface.sdlSurface();
}
The problem is probably in the draw function. If I change this line:
if (SDL_BlitSurface(source.sdlSurface(), NULL, this->surface, NULL) != 0) {
to:
if (SDL_BlitSurface(IMG_Load("./data/images/logo.png"), NULL, this->surface, NULL) != 0) {
everything seems to be ok. Could you give me a suggestion where should be the problem?
You're violating The Rule of 3.
You need to define a copy constructor and a copy assignment operator for this to work properly.
When you're passing the Surface in to the draw method, you're making a copy of it. Since you're managing a resource inside the Surface class (the SDL_Surface*), you'll have multiple instances of the class pointing at the same surface, so when the destructors are called, you'd be freeing the same SDL_Surface* more than once.
Edit: I would recommend passing your arguments by const reference. You don't need to make copies of the Surface objects when you want to draw them.
This:
bool Surface::draw(Surface source, Rectangle source_area, Point2D position);
Would become this:
bool Surface::draw(const Surface &source, const Rectangle &source_area, const Point2D &position);
And this can be applied to your other functions too.

Berkeley DB, concurrent queues

I'm trying to implement a concurrent persistent queue using Berkeley DB. As a starter I tried to make two process which both appends to the DB:
#include <unistd.h>
#include <sstream>
#include <db_cxx.h>
class Queue : public DbEnv
{
public:
Queue ( ) :
DbEnv(0),
db(0)
{
set_flags(DB_CDB_ALLDB, 1);
open("/tmp/db", DB_INIT_LOCK |
DB_INIT_LOG |
DB_INIT_TXN |
DB_INIT_MPOOL |
DB_RECOVER |
DB_CREATE |
DB_THREAD,
0);
db = new Db(this, 0);
db->set_flags(DB_RENUMBER);
db->open(NULL, "db", NULL, DB_RECNO, DB_CREATE | DB_AUTO_COMMIT | DB_THREAD, 0);
}
virtual ~Queue ()
{
db->close(0);
delete db;
close(0);
}
protected:
Db * db;
};
class Enqueue : public Queue
{
public:
Enqueue ( ) : Queue() { }
virtual ~Enqueue () { }
bool push(const std::string& s)
{
int res;
DbTxn * txn;
try {
txn_begin(NULL, &txn, DB_TXN_SYNC | DB_TXN_WAIT );
db_recno_t k0[4]; // not sure how mutch data is needs???
k0[0] = 0;
Dbt val((void*)s.c_str(), s.length());
Dbt key((void*)&k0, sizeof(k0[0]));
key.set_ulen(sizeof(k0));
key.set_flags(DB_DBT_USERMEM);
res = db->put(txn, &key, &val, DB_APPEND);
if( res == 0 ) {
txn->commit(0);
return true;
} else {
std::cerr << "push failed: " << res << std::endl;
txn->abort();
return false;
}
} catch( DbException e) {
std::cerr << "DB What()" << e.what() << std::endl;
txn->abort();
return false;
} catch( std::exception e) {
std::cerr << "What()" << e.what() << std::endl;
txn->abort();
return false;
} catch(...) {
std::cerr << "Unknown error" << std::endl;
txn->abort();
return false;
}
}
};
using namespace std;
int main(int argc, const char *argv[])
{
fork();
Enqueue e;
stringstream ss;
for(int i = 0; i < 10; i++){
ss.str("");
ss << "asdf" << i;
cout << ss.str() << endl;
if( ! e.push(ss.str()) )
break;
}
return 0;
}
Compiling it:
g++ test.cxx -I/usr/include/db4.8 -ldb_cxx-4.8
Create the db-dir
mkdir /tmp/db
And when I run it I get all kind of errors (segmentations fault, allocation error, and some times it actually works)
I'm sure that I have missed some locking, but I just do not know how to do it. So, any hints and/or suggestions to fix this are most welcome.
Just for the record, here is the solution I have settled on after much googleing and trial'n'error.
The application is a call home process, where the producer is adding data, and consumer tries to send it home. If the consumer fails to send it home, it must try again. The database must not block for producer while the consumer is trying to sink data.
The code has a file lock, and will only allow one consumer process.
Here are the code:
#include <db_cxx.h>
#include <sstream>
#include <fstream>
#include <vector>
#include <boost/interprocess/sync/file_lock.hpp>
class Queue : public DbEnv
{
public:
Queue ( bool sync ) :
DbEnv(0),
db(0)
{
set_flags(DB_CDB_ALLDB, 1);
if( sync )
set_flags(DB_TXN_NOSYNC, 0);
else
set_flags(DB_TXN_NOSYNC, 1);
open("/tmp/db", DB_INIT_LOCK |
DB_INIT_LOG | DB_INIT_TXN | DB_INIT_MPOOL |
DB_REGISTER | DB_RECOVER | DB_CREATE | DB_THREAD,
0);
db = new Db(this, 0);
db->set_flags(DB_RENUMBER);
db->open(NULL, "db", NULL, DB_RECNO, DB_CREATE | DB_AUTO_COMMIT | DB_THREAD, 0);
}
virtual ~Queue ()
{
db->close(0);
delete db;
close(0);
}
protected:
Db * db;
};
struct Transaction
{
Transaction() : t(0) { }
bool init(DbEnv * dbenv ){
try {
dbenv->txn_begin(NULL, &t, 0);
} catch( DbException e) {
std::cerr << "DB What()" << e.what() << std::endl;
return false;
} catch( std::exception e) {
std::cerr << "What()" << e.what() << std::endl;
return false;
} catch(...) {
std::cerr << "Unknown error" << std::endl;
return false;
}
return true;
}
~Transaction(){ if( t!=0) t->abort(); }
void abort() { t->abort(); t = 0; }
void commit() { t->commit(0); t = 0; }
DbTxn * t;
};
struct Cursor
{
Cursor() : c(0) { }
bool init( Db * db, DbTxn * t) {
try {
db->cursor(t, &c, 0);
} catch( DbException e) {
std::cerr << "DB What()" << e.what() << std::endl;
return false;
} catch( std::exception e) {
std::cerr << "What()" << e.what() << std::endl;
return false;
} catch(...) {
std::cerr << "Unknown error" << std::endl;
return false;
}
return true;
}
~Cursor(){ if( c!=0) c->close(); }
void close(){ c->close(); c = 0; }
Dbc * c;
};
class Enqueue : public Queue
{
public:
Enqueue ( bool sync ) : Queue(sync) { }
virtual ~Enqueue () { }
bool push(const std::string& s)
{
int res;
Transaction transaction;
if( ! transaction.init(this) )
return false;
try {
db_recno_t k0[4]; // not sure how mutch data is needs???
k0[0] = 0;
Dbt val((void*)s.c_str(), s.length());
Dbt key((void*)&k0, sizeof(k0[0]));
key.set_ulen(sizeof(k0));
key.set_flags(DB_DBT_USERMEM);
res = db->put(transaction.t, &key, &val, DB_APPEND);
if( res == 0 ) {
transaction.commit();
return true;
} else {
std::cerr << "push failed: " << res << std::endl;
return false;
}
} catch( DbException e) {
std::cerr << "DB What()" << e.what() << std::endl;
return false;
} catch( std::exception e) {
std::cerr << "What()" << e.what() << std::endl;
return false;
} catch(...) {
std::cerr << "Unknown error" << std::endl;
return false;
}
}
};
const char * create_file(const char * f ){
std::ofstream _f;
_f.open(f, std::ios::out);
_f.close();
return f;
}
class Dequeue : public Queue
{
public:
Dequeue ( bool sync ) :
Queue(sync),
lock(create_file("/tmp/db-test-pop.lock")),
number_of_records_(0)
{
std::cout << "Trying to get exclusize access to database" << std::endl;
lock.lock();
}
virtual ~Dequeue ()
{
}
bool pop(size_t number_of_records, std::vector<std::string>& records)
{
if( number_of_records_ != 0 ) // TODO, warning
abort();
Cursor cursor;
records.clear();
if( number_of_records_ != 0 )
abort(); // TODO, warning
// Get a cursor
try {
db->cursor(0, &cursor.c, 0);
} catch( DbException e) {
std::cerr << "DB What()" << e.what() << std::endl;
abort();
return false;
}
// Read and delete
try {
Dbt val;
db_recno_t k0 = 0;
Dbt key((void*)&k0, sizeof(k0));
for( size_t i = 0; i < number_of_records; i ++ ) {
int get_res = cursor.c->get(&key, &val, DB_NEXT);
if( get_res == 0 )
records.push_back(std::string((char *)val.get_data(), val.get_size()));
else
break;
}
number_of_records_ = records.size();
if( number_of_records_ == 0 ) {
abort();
return false;
} else {
return true;
}
} catch( DbException e) {
std::cerr << "DB read/delete What() " << e.what() << std::endl;
abort();
return false;
} catch( std::exception e) {
std::cerr << "DB read/delete What() " << e.what() << std::endl;
abort();
return false;
}
}
bool commit()
{
if( number_of_records_ == 0 )
return true;
Transaction transaction;
Cursor cursor;
if( ! transaction.init(this) )
return false;
if( ! cursor.init(db, transaction.t) )
return false;
// Read and delete
try {
Dbt val;
db_recno_t k0 = 0;
Dbt key((void*)&k0, sizeof(k0));
for( size_t i = 0; i < number_of_records_; i ++ ) {
int get_res = cursor.c->get(&key, &val, DB_NEXT);
if( get_res == 0 )
cursor.c->del(0);
else
break; // this is bad!
}
number_of_records_ = 0;
cursor.close();
transaction.commit();
return true;
} catch( DbException e) {
std::cerr << "DB read/delete What() " << e.what() << std::endl;
return false;
} catch( std::exception e) {
std::cerr << "DB read/delete What() " << e.what() << std::endl;
return false;
}
}
void abort()
{
number_of_records_ = 0;
}
private:
boost::interprocess::file_lock lock;
size_t number_of_records_;
sigset_t orig_mask;
};
Please let me know if you see any errors, or if know about an easier way to do this.