So I've been looking around in my code for hours now and finally I think I found the issue with the code. An SFML method doesn't work or I am using it wrong.
I am trying to load a PNG file from my disk into the program so I can render it on screen.
But the picture is never even loaded into the program to begin with it seems. As when I check the debugger I see no actual info about the file I am trying to load in.
I'll show the entire Engine.cpp file first, and then explain step by step what happens.
My Engine.cpp looks like this:
#include "Engine.h"
#include <SFML\Graphics.hpp>
Engine::Engine()
{
}
Engine::~Engine()
{
}
bool Engine::Init()
{
LoadImages();
window = new sf::RenderWindow(sf::VideoMode(800,600,32), "RPG");
if(!window)
return false;
return true;
}
void Engine::LoadImages()
{
sf::Image sprite;
sprite.loadFromFile("C:/Users/Vipar/Pictures/sprite1.png");
imageManager.AddImage(sprite);
testTile = new Tile(imageManager.GetImage(0));
}
void Engine::RenderFrame()
{
window->clear();
testTile->Draw(0,0,window);
window->display();
}
void Engine::ProcessInput()
{
sf::Event evt;
//Loop through all window events
while(window->pollEvent(evt))
{
if(evt.type == sf::Event::Closed)
window->close();
}
}
void Engine::Update()
{
}
void Engine::MainLoop()
{
sf::Image sprite;
sprite.loadFromFile("C:/Users/Vipar/Pictures/sprite1.png");
imageManager.AddImage(sprite);
testTile = new Tile(imageManager.GetImage(0));
//Loop until our window is closed
while(window->isOpen())
{
ProcessInput();
Update();
RenderFrame();
testTile->Draw(0,0,window);
}
}
void Engine::Go()
{
if(!Init())
throw "Could not initialize Engine";
MainLoop();
}
I call this method:
void Engine::LoadImages()
{
sf::Image sprite;
sprite.loadFromFile("C:/Users/Vipar/Pictures/sprite1.png");
imageManager.AddImage(sprite);
testTile = new Tile(imageManager.GetImage(0));
}
It adds the Image to my ImageManager for later use if need be. This is done for a bit of efficiency. Then I apply the Image to my custom class called Tile. It looks like this:
#include "Tile.h"
#include <SFML\Graphics.hpp>
#include <iostream>
Tile::Tile(sf::Image& image)
{
sf::Texture tex;
tex.loadFromImage(image);
baseSprite.setTexture(tex,true);
}
Tile::~Tile()
{
}
void Tile::Draw(int x, int y, sf::RenderWindow* rw)
{
baseSprite.setPosition(x,y);
rw->draw(baseSprite);
}
void Tile::Destroy()
{
delete &baseSprite;
}
Then I draw the Tile on screen to test it out.
Why does this png file not even load into my program to begin with? If you need additional code, please let me know. I am a bit green on this SFML framework and C++ but I am good at Java and C#.
I only work with SFML.net (maybe you should use it?), and I don't like how you're doing things, but...
Throw some debug messages to make sure that all your appropriate
functions/code is getting run.
Clear with a different color and make sure it works.
Your naming is confusing and misleading.
Make sure you've checked the tutorial to see how they draw.
Related
I have a folder full of images, I need to save these images into the video while doing so I want to show the user the video being played from these images (frames). I can run two separate processes one for the saving and one for the showing but this is not what I am looking for, I want to do both in one step. If you know a solution please let me know.
My code uses C++ with OpenCV but feel free to share with me any code written with any language, or event a concept.
I use gStreamer, ffmpeg as well for the video generation, so I am not looking how to save a video or how to show the video I am looking for a process that can do both in one operation.
here's my quick brew using SFML. You have to link SFML and include the include folder. Simply set directory to your target folder, I use std::filesystem to add all files from that folder to a std::vector<std::string>.
#include <SFML/Graphics.hpp>
#include <vector>
#include <string>
#include <iostream>
#include <filesystem>
void add_frame_to_video(std::string path) {
//your encoding stuff ...
}
int main() {
auto dimension = sf::VideoMode(1280u, 720u);
sf::RenderWindow window;
window.create(dimension, "Video Rendering");
sf::Texture frame_texture;
std::vector<std::string> frame_paths;
std::string directory = "resources/";
for (auto i : std::filesystem::directory_iterator(directory)) {
frame_paths.push_back({ i.path().string() });
}
std::size_t frame_ctr = 0u;
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
}
if (frame_ctr >= frame_paths.size()) {
window.close();
return EXIT_FAILURE;
}
const auto& current_frame = frame_paths[frame_ctr];
add_frame_to_video(current_frame);
if (!frame_texture.loadFromFile(current_frame)) {
std::cout << "Error: couldn't load file \"" << current_frame << "\".\n";
window.close();
return EXIT_FAILURE;
}
sf::Sprite frame_sprite;
frame_sprite.setTexture(frame_texture);
++frame_ctr;
window.clear();
window.draw(frame_sprite);
window.display();
}
}
this will create a window that shows each picture per frame using sf::Texture to load and sf::Sprite to display the image. If no more frames are available, the window gets closed and the program terminates. If you want to add time between frames, you can set e.g. window.setFramerateLimit(10); to have 10 frames / second.
So I was trying out the SFML tutorial for playing a sound from a local file and came across a weird bug. Whenever I call the playSound function no sound is played and I get an error that I can't find the solution to:
[ALSOFT] (EE) Failed to set real-time priority for thread: Operation not permitted (1)
The strange thing is that if I do the same thing in the main function the sound is played. What is going on here? Here are the only files used in the project, the .wav is just a simple sound file:
main.cpp
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
void playSound() {
sf::SoundBuffer buffer;
if (!buffer.loadFromFile("1-retro-arcade-casino-notification.wav"))
return;
sf::Sound sound;
sound.setBuffer(buffer);
sound.play();
}
int main() {
sf::RenderWindow window(sf::VideoMode(800, 600), "Notification test");
sf::SoundBuffer buffer;
if (!buffer.loadFromFile("1-retro-arcade-casino-notification.wav"))
return -1;
sf::Sound sound;
sound.setBuffer(buffer);
sound.play();
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
if (event.type == sf::Event::TextEntered) {
char key = static_cast<char>(event.text.unicode);
if (key == 'p') {
playSound();
}
if (key == 'q') {
window.close();
}
}
}
}
return 0;
}
Makefile
all:
g++ -lsfml-audio -lsfml-graphics -lsfml-window -lsfml-system -o main main.cpp
The sound data is not stored directly in sf::Sound but instead in the sf::SoundBuffer. This class encapsulates the audio data, which is basically an array of 16-bit signed integers (called "audio samples").
Sounds (and music) are played in a separate thread. This means that you are free to do anything you want after calling
void play(), except destroying the sound or its data - which you are currently doing.
This is because you have declared your sf::SoundBuffer buffer; inside void playSound(), and subsequently, the sound data gets destroyed as it goes out of scope after returning from void playSound().
To fix your problem, don't declare sf::SoundBuffer in the function. You could just declare it outside the main function, or even pass it as a parameter to playSound().
See the relevant documentation for info.
I made this code that shows a timer and pauses when you press spacebar:
#include <SFML/Graphics.hpp>
#include <iostream>
using namespace sf;
using namespace std;
void events();
bool pause, exitPause;
char key;
double timeFrame, timeTot = 0;
Clock timer;
Text text;
Font font;
RenderWindow window(VideoMode(800, 600), "Window", Style::Close);
int main()
{
font.loadFromFile("C:/Windows/Fonts/arial.ttf");
text.setFont(font);
text.setCharacterSize(15);
window.setFramerateLimit(120);
while (window.isOpen())
{
for (Event event; window.pollEvent(event);) {
if (event.type == Event::Closed)
window.close();
if (event.type == Event::TextEntered) {
key = std::tolower(static_cast<char>(event.text.unicode));
if (key == ' ') {
pause = !pause;
if (!pause) {
timer.restart();
}
}
}
}
if (!pause) {
timeFrame = timer.restart().asSeconds();
timeTot += timeFrame;
text.setString(to_string(timeTot));
window.clear();
window.draw(text);
}
window.display();
}
}
If you test, you will see something curious. When pausing by pressing the spacebar, window.display alternates between the last and the current displayed number.
But if I put window.clear and window.draw together with window.display, the problem does not happen.
if (!pause) {
timeFrame = timer.restart().asSeconds();
timeTot += timeFrame;
text.setString(to_string(timeTot));
}
window.clear();
window.draw(text);
window.display();
I thought windows.display, alone, would only show the last buffer.
What is the problem?
The moment you pause you stop updating the draw buffers. SFML is always double-buffered, and in each iteration you always need to parse input, update whatever needs updating, redraw the "hidden" frame, and then flip the buffers. This is basically a "Game Loop" pattern.
In your code you always parse input, update the timer and pause state based on that, and you always flip the buffers (with window.display()). You only redraw the "hidden" frame buffer if the state is not paused, however.
So, you are seeing the expected output, and you found the correct solution.
As an aside, there are indeed several style issues in your code, including uninitialized variables, which is always dangerous in C++.
I got another problem with GTK. There is function programClose() which can be called by multiple ways:
// File->Quit
g_signal_connect(G_OBJECT(quit), "activate", G_CALLBACK(programClose), &data);
// User closed app by clicking red X mark on title bar
g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK(programClose), &data);
programClose() looks like that:
void programClose(GtkMenuItem *quit, fileData *data)
{
if(data->isSaved != true)
{
showSaveFileDialog(NULL, data);
}
}
And then in showSaveFileDialog():
void showSaveFileDialog(GtkMenuItem *saveFile, fileData *data)
{
cout << data->someBool; // ok
cout << data->someString; // crashes here
}
I tried making another function for closing app by clicking X, but that did not help:
void programClose(GtkWindow *window, fileData *data)
Any sugestions?
edit:
Lol, forgot to mention that everything is fine when user closes app by clicking file->quit, program crashes only when clicking the red X mark
Ok I fixed it myself. The problem was I forgot about callback functions signatures. So I created wrapper function for closing program by clicking red X:
void programCloseByX(GtkWindow *window, GdkEvent *event, fileData *data)
{
programClose(NULL, data);
}
I am making a game using SDL and my SoundHandler class is not working and I cannot figure out why. The file paths are definatly correct and I have SDL_Mixer set up properly as I have had sound work correctly before, I also get no errors or warnings the game runs fine there is just no music.
SoundHandler.h:
enum Sounds
{
BACKGROUND_MUSIC, STICK_COLLECT
};
class SoundHandler
{
public:
SoundHandler();
void PlaySound(Sounds sound);
private:
Mix_Music *backMusic;
Mix_Music *stickCollect;
};
SoundHandler.cpp:
SoundHandler::SoundHandler()
{
Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2, 4096);
this->backMusic = Mix_LoadMUS("Data//Music//Background.mp3");
this->stickCollect = Mix_LoadMUS("Data//Sounds//StickCollect.mp3");
Mix_VolumeMusic(128);
}
void SoundHandler::PlaySound(Sounds sound)
{
if(sound == BACKGROUND_MUSIC)
{
Mix_PlayMusic(this->backMusic, -1);
}
if(sound == STICK_COLLECT)
{
Mix_PlayMusic(this->stickCollect, 1);
}
}
Relevant Lines in main.cpp:
// Initialise Sound
SoundHandler soundHandler;
// Play Background Music
soundHandler.PlaySound(BACKGROUND_MUSIC);
// Play Sound
soundHandler.PlaySound(STICK_COLLECT);
I think that problem is in double slashes in file path, try to use single slash.
You will have long time of debugging without error checking.