SDL image render difficulties - c++

Hi there fellow Overflowers!
I have recently begun learning SDL. I chose simple directmedia layer as my external API to my C++ knowledge because I found it to offer the most visually enhanced mechanics for game dev. Consider this code below:
#include <iostream>
#include "SDL/SDL.h"
using std::cerr;
using std::endl;
int main(int argc, char* args[])
{
// Initialize the SDL
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
cerr << "SDL_Init() Failed: " << SDL_GetError() << endl;
exit(1);
}
// Set the video mode
SDL_Surface* display;
display = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
if (display == NULL)
{
cerr << "SDL_SetVideoMode() Failed: " << SDL_GetError() << endl;
exit(1);
}
// Set the title bar
SDL_WM_SetCaption("SDL Tutorial", "SDL Tutorial");
// Load the image
SDL_Surface* image;
image = SDL_LoadBMP("LAND.bmp");
if (image == NULL)
{
cerr << "SDL_LoadBMP() Failed: " << SDL_GetError() << endl;
exit(1);
}
// Main loop
SDL_Event event;
while(1)
{
// Check for messages
if (SDL_PollEvent(&event))
{
// Check for the quit message
if (event.type == SDL_QUIT)
{
// Quit the program
break;
}
}
// Game loop will go here...
// Apply the image to the display
if (SDL_BlitSurface(image, NULL, display, NULL) != 0)
{
cerr << "SDL_BlitSurface() Failed: " << SDL_GetError() << endl;
exit(1);
}
//Update the display
SDL_Flip(display);
}
// Tell the SDL to clean up and shut down
SDL_Quit();
return 0;
}
All I have done is just made a screen surface, Double buffered it, made another surface of an image, blit'ed the two together, and for some reason when I build the application, It closes instantly! The application build succeeds but then closes without a window opening! This is really frustrating.
I am using XCode5 and SDL 2.0.3 :)
Help is needed!
EDIT: Turns out in the error log, it says SDL_LoadBMP(): Failed to load LAND.bmp. The bmp is saved in the root directory, the same folder as the main.cpp folder? Why doesn't this work?

You should be able to test your code by using the absolute (full) path to the image. That will verify that the code is actually working.
To be able to use resources with an absolute path you should create a Build Phase to Copy Files. The Destination should be set to 'Product Directory'. You can leave Subpath blank or provide a directory to place the resource in (this will be useful when you get a lot of resources) eg textures. If you supply a Subpath then alter your code so it would be textures/LAND.bmp
You would also use the build phase for packaging the SDL2.framework and any others e.g. SDL2_image etc with your final application. This would allow users who don't have SDL on their machines to run the app. To do this create another build phase with the Detination set to 'Frameworks' and leave the Subpath empty. Then just add any frameworks you want to package with the app. One other setting you will want to make in Build Settings is to change 'Runpath Search Paths' (found under 'Linking') to be #executeable_path/../Frameworks so that the application knows where to find packaged frameworks
I have a tutorial on configuring SDL2 in Xcode along with a template to make it quick
http://zamma.co.uk/how-to-setup-sdl2-in-xcode-osx/

Related

How to create an OpenGL context on an NodeJS native addon on MacOS?

Follow-up for this question.
I'm trying to create a NodeJS native addon that uses OpenGL.
I'm not able to use OpenGL functions because CGLGetCurrentContext() always returns NULL.
When trying to create a new context to draw into, CGLChoosePixelFormat always returns the error kCGLBadConnection invalid CoreGraphics connection.
What is bugging me out is that when I isolate the code that creates the OpenGL context into a standalone CPP project, it works! It just gives an error when I run it inside the NodeJS addon!
I created this NodeJS native addon project to exemplify my error: https://github.com/Psidium/node-opengl-context-error-example
This is the code that works when executed on a standalone project and errors out when running inside NodeJS:
//
// main.cpp
// test_cli
//
// Created by Borges, Gabriel on 4/3/20.
// Copyright © 2020 Psidium. All rights reserved.
//
#include <iostream>
#include <OpenGL/OpenGL.h>
int main(int argc, const char * argv[]) {
std::cout << "Context before creating it: " << CGLGetCurrentContext() << "\n";
CGLContextObj context;
CGLPixelFormatAttribute attributes[2] = {
kCGLPFAAccelerated, // no software rendering
(CGLPixelFormatAttribute) 0
};
CGLPixelFormatObj pix;
CGLError errorCode;
GLint num; // stores the number of possible pixel formats
errorCode = CGLChoosePixelFormat( attributes, &pix, &num );
if (errorCode > 0) {
std::cout << ": Error returned by choosePixelFormat: " << errorCode << "\n";
return 10;
}
errorCode = CGLCreateContext( pix, NULL, &context );
if (errorCode > 0) {
std::cout << ": Error returned by CGLCreateContext: " << errorCode << "\n";
return 10 ;
}
CGLDestroyPixelFormat( pix );
errorCode = CGLSetCurrentContext( context );
if (errorCode > 0) {
std::cout << "Error returned by CGLSetCurrentContext: " << errorCode << "\n";
return 10;
}
std::cout << "Context after being created is: " << CGLGetCurrentContext() << "\n";
return 0;
}
I already tried:
Using fork() to create a context in a subprocess (didn't work);
Changing the pixelformat attributes to something that will create my context (didn't work);
I have a hunch that it may have something to do with the fact that a Node native addon is a dynamically linked library, or maybe my OpenGL createContext function may not be executing on the main thread (but if this was the case, the fork() would have solved it, right?).
Accessing graphics hardware requires extra permissions - Windows and macOS (don't know for others) restrict creation of hardware-accelerated OpenGL context to interactive user session (I may be wrong with the terms here). From one of articles on the web:
In case the user is not logged in, the CGLChoosePixelFormat will return kCGLBadConnection
Interactive session is easier to feel than to understand; e.g. when you interactively login and launch application - it is interactive session; when process is started as service - it is non-interactive. How this is actually managed by system requires deeper reading. As far as I know, there is no easy way "escaping" non-interactive process flag.
NodeJS can be used as part of a web-server, so that I may expect that it can be exactly the problem - it is started as a service, by another non-interactive user or has other special conditions making it non-interactive. So maybe more details on how you use / start NodeJS itself might clarify why the code doesn't work. But I may expect that using OpenGL on server part might be not a good idea anyway (if this is a target); although it might be possible that software OpenGL implementation (without kCGLPFAAccelerated flag might work).
By the way, there are at least two OpenGL / WebGL extensions to NodeJS - have you tried their samples to see if they behave in the same or different way in your environment?
https://github.com/google/node-gles
https://github.com/mikeseven/node-webgl

Request image from X11 compositing WM in C or C++

I need to request and retrieve an image of a window from the X server or the WM (I believe the WM does the actual compositing). I need to be able to get an image of the window even if it is obscured by another window or located on another workspace (but still mapped). I need to use C or C++ and would like to use XCB or Xlib. I think I also have Gtk+ development tools installed but it's been a while since I used them.
I have tried using xcb_composite_name_window_pixmap() with no success (XCB errors).
I tried using the render extension to render the window to a picture which produced no errors, but I still needed to get the image loaded into my program's memory.
I tried to use xcb_get_image to get the picture which, IIRC, failed (bad resource I believe).
I tried to copy the picture to a pixmap and use xcb_get_image on that. I was able to download what appeared to be an image, but it looked more like random regions of the screen than the actual window.
In short, I'm just making guesses at this point.
I'm having a difficult time finding organized and complete documentation. The most recent publications I can find on X11, XCB, or Xlib is from 1994 (The O'Reilly book on Xlib and/or X11R6) which I doubt has much, if anything, valid on these extensions. Most of the man pages and online documentation has a lot of "TODO: explain this" and/or function descriptions like "deliver a request to the X server". Any help that anyone can provide will be of use to me.
I'm currently running compiz for my WM and emerald for window decorations and nothing else standard in terms of a "desktop environment". I'm working on some utility applications for a custom desktop that I plan to release when they are ready. I would like whatever I make to work with some other WMs but, if it requires special codepaths for each, I can add the others down the line.
EDIT: I originally had added a non-working example here, and then a stripped down working example, which has all been moved to an answer as suggested in the comments.
I now have a working example that I will post here:
#include <xcb/xcb.h>
#include <xcb/xproto.h>
#include <xcb/composite.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "usage: %s windowId\n", argv[0]);
return EXIT_FAILURE;
}
xcb_window_t req_win_id = strtoul(argv[1], NULL, 0);
xcb_connection_t *connection = xcb_connect(NULL, NULL);
xcb_generic_error_t *err = NULL, *err2 = NULL;
xcb_composite_query_version_cookie_t comp_ver_cookie = xcb_composite_query_version(connection, 0, 2);
xcb_composite_query_version_reply_t *comp_ver_reply = xcb_composite_query_version_reply(connection, comp_ver_cookie, &err);
if (comp_ver_reply)
{
if (comp_ver_reply->minor_version < 2) {
fprintf(stderr, "query composite failure: server returned v%d.%d\n", comp_ver_reply->major_version, comp_ver_reply->minor_version);
free(comp_ver_reply);
return EXIT_FAILURE;
}
free(comp_ver_reply);
}
else if (err)
{
fprintf(stderr, "xcb error: %d\n", err->error_code);
free(err);
return EXIT_FAILURE;
}
const xcb_setup_t *setup = xcb_get_setup(connection);
xcb_screen_iterator_t screen_iter = xcb_setup_roots_iterator(setup);
xcb_screen_t *screen = screen_iter.data;
// request redirection of window
xcb_composite_redirect_window(connection, req_win_id, XCB_COMPOSITE_REDIRECT_AUTOMATIC);
int win_h, win_w, win_d;
xcb_get_geometry_cookie_t gg_cookie = xcb_get_geometry(connection, req_win_id);
xcb_get_geometry_reply_t *gg_reply = xcb_get_geometry_reply(connection, gg_cookie, &err);
if (gg_reply) {
win_w = gg_reply->width;
win_h = gg_reply->height;
win_d = gg_reply->depth;
free(gg_reply);
} else {
if (err) {
fprintf(stderr, "get geometry: XCB error %d\n", err->error_code);
free(err);
}
return EXIT_FAILURE;
}
// create a pixmap
xcb_pixmap_t win_pixmap = xcb_generate_id(connection);
xcb_composite_name_window_pixmap(connection, req_win_id, win_pixmap);
// get the image
xcb_get_image_cookie_t gi_cookie = xcb_get_image(connection, XCB_IMAGE_FORMAT_Z_PIXMAP, win_pixmap, 0, 0, win_w, win_h, (uint32_t)(~0UL));
xcb_get_image_reply_t *gi_reply = xcb_get_image_reply(connection, gi_cookie, &err);
if (gi_reply) {
int data_len = xcb_get_image_data_length(gi_reply);
fprintf(stderr, "data_len = %d\n", data_len);
fprintf(stderr, "visual = %u\n", gi_reply->visual);
fprintf(stderr, "depth = %u\n", gi_reply->depth);
fprintf(stderr, "size = %dx%d\n", win_w, win_h);
uint8_t *data = xcb_get_image_data(gi_reply);
fwrite(data, data_len, 1, stdout);
free(gi_reply);
}
return EXIT_SUCCESS;
}
It was a case of overdoing it. I got the idea that I should use Xrender from somewhere and started pulling tons of data from that extension that I didn't really need. But the real problem I had was that the pixmap given to xcb_composite_name_window_pixmap should not be created first, but rather I just needed the new id for it. It turns out that it is really as simple as I expected it to be. All you need is the Window ID and the size, do some checks to make sure composite is there and a good version (>=0.2 in this case), and call xcb_composite_redirect_window, xcb_composite_name_window_pixmap (with a generated pixmap id), and xcb_get_image (+reply,data_len,data) in that order, and you have the image.

SDL_Mixer when play again, starts from random place for a while then from the beginning

Hi I'm trying to trigger multiple music playing here, here are some code.
Mix_Music *mix_list[MUSIC_COUNT] ;
//init music with SDL
int result = 0;
int flags = MIX_INIT_MP3;
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
printf("Failed to init SDL\n");
exit(1);
}
if (flags != (result = Mix_Init(flags))) {
printf("Could not initialize mixer (result: %d).\n", result);
printf("Mix_Init: %s\n", Mix_GetError());
exit(1);
}
//load music
Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 640);
for (int i = 0 ; i < musiclist.size() ; ++i){
mix_list[i] = Mix_LoadMUS(musiclist[i].c_str());
}
Then in a loop,
for (; ;){
//trigger from here, some code detect if there's a new music need to be played
//play sound here
if (!Mix_PlayingMusic()){
//if not playing just start fresh play
std::cout << "Start Play " << musiclist[markerIds[0]] << std::endl ;
Mix_FadeInMusic(mix_list[markerIds[0]],1,1000) ;
}
else{
//only if change to next music
if (lastDetected != markerIds[0]){
std::cout << "Fading out current" << std::endl ;
//first need to fade out current
while(!Mix_FadeOutMusic(2000) && Mix_PlayingMusic()) {
// wait for any fades to complete
SDL_Delay(100);
}
Mix_HaltMusic() ;
//then start the one
//problem happens here
//there will always be several seconds it plays from the middle somewhere, then plays from the beginning.
Mix_FadeInMusic(mix_list[markerIds[0]],1,4000) ;
}
}
}
My problem is listed in the code, the issue is when play the music that was played before, no matter Mix_FadeInMusic () or the Mix_PlayMusic() always plays the music from random place first for several seconds, then from the beginning. But all I need, is just smooth play through.
OS: Ubuntu 16.04
SDL:2.0.4
Mixer:2.0.1
I figured this myself, it is actually the mp3 issue. The SDL library bundled with Ubuntu 16.04 has little issue on playing some mp3 files. So after I convert file to OGG and use int flags = MIX_INIT_OGG; the problem just gone.

AntTweakBar doesn't register SFML mouse events

I'm trying to add GUI for easier level editing in our game engine. We're using SFML for all the basic stuff (window management, input events etc). I've chosen AntTweakBar because it is a well known library with a few examples around. I was following the tutorial at AntTweakBar's website
I was able to draw a simple bar with those example codes. However, mouse events received by SFML are not registered by AntTweakBar's TwEventSDL()function. Here is an example code for Input:
sf::Event event;
while (_pWindow->pollEvent(event))
{
// Check if the event should be handled by AntTweakBar
int handled = TwEventSFML(&event, 2, 3); // for SFML version 2.3
if (!handled){
switch (event.type)
{
case sf::Event::MouseButtonPressed: // To check whether SFML received mouse button events properly
if (event.mouseButton.button == sf::Mouse::Button::Left){
std::cout << "Left button pressed" << std::endl;
std::cout << "x: " << event.mouseButton.x << std::endl;
std::cout << "y: " << event.mouseButton.y << std::endl;
}
}
}
else{ //To check whether TwEventSFML received events
std::cout << "FINALLY!" << std::endl;
}
When I press buttons, I can see "FINALLY!" showing up. I can also see that my mouse clicks are received by SFML. However, when I click on an AntTweakBar element (be it a button or help section) it doesn't register it. (Also, I can't see "FINALLY!" when I use the mouse).
Any help or ideas will be appreciated.
Anttweakbar hasnt been updated in 3 years, last SFML integration was for SFML 1.6
What version of SFML are you using ?
If not 1.6 then you have to create your own input handler for it.

OpenCV VideoCapture returns an empty frame only in first call to glutDisplayFunc callback

I have been trying to work with OpenCV and freeglut.
The program involves capturing an image from a WebCam, processing the image with OpenCV, and drawing 3D objects with OpenGL according to the processed image.
It works perfectly fine when I only use OpenCV routines.
The problem arises when the main loop becomes controlled by GLUT. When I try to grab a frame from within a callback I registered with glutDisplayFunc() the image returned is empty.
Strangely, however, when I grab a frame from a callback I registered with glutIdleFunc() it successfully returns a frame.
And after doodling around I figured out that somehow a frame cannot be captured in the first call of display() and works after the second call.
Currently my code is querying a frame inside the idle() function.
Regarding such background I have several questions.
Why does this happen? Is it because the program stalls inside display() before VideoCapture gains full access to the webcam? Or is this purely a hardware problem?
Is this safe? I'm perfectly fine about grabbing a frame from within idle(), but is this method safe to use?
If not so, is there a workaround? If this approach is not safe may somebody please notify me with another way of dealing with this issue?
The program is built on OS X Version 10.9.1 and libraries being use are
OpenCV 2.4.7.0
freeglut 2.0.1
Here is the simplified version of my code:
#include <opencv2/opencv.hpp>
#include <GL/freeglut.h>
#include <iostream>
cv::VideoCapture capture;
cv::Mat render;
void display()
{
std::cerr << "Grabbing frame in display()" << std::endl;
capture >> render; // This does not work on first call
if(render.empty()) {
std::cerr << "Error: Grabbing empty frame in display()" << std::endl;
}
}
void idle()
{
std::cerr << "Grabbing frame in idle()" << std::endl;
capture >> render; // This always works
if(render.empty()) {
std::cerr << "Error: Grabbing empty frame in idle()" << std::endl;
}
glutPostRedisplay();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA);
glutInitWindowSize(640, 480);
int debug_window = glutCreateWindow("Debug");
glutDisplayFunc(display);
glutIdleFunc(idle);
capture.open(0);
if(!capture.isOpened()) {
std::cerr << "Error: Failed to open camera" << std::endl;
exit(1);
}
glutMainLoop();
return 0;
}
known problem.
some sloppy webcam drivers return an empty 1st frame, warmup or something.
just try to capture 1 frame, before you go into the idle loop