How to not include texture in exe folder - c++

I'm doing some sfml project for school and teacher wants only the .exe program. I'm using Visual Studio 2017. In this project I'm using texture from .jpg file
sf::RenderWindow window(sf::VideoMode(640, 480, 32), "Kurs SFML ");
sf::Texture texture;
texture.loadFromFile("wood.jpg");
sf::Sprite pic;
pic.setTexture(texture);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
window.draw(pic);
window.display();
This file ( wood.jpg ) needs to be to in the same folder as project to show this texture otherwise it only shows black screen. When I checked the .exe program which is in another folder, it also needs this file to be in this folder or .exe shows black screen. But my teacher wants only .exe file without any folders. So is it possible to do something to not include this file( wood.jpg ) but show the texture in the .exe ?

Embed your texture in your executable.
One easy solution is to write a small tool that reads the file and writes out a C++ source file with a constexpr std::array containing the raw bytes. Then load your texture from that variable (SFML has functions to load a resource from memory) that you link into your executable.
Writing such a tool shouldn't be more than 10-20 lines of code.

For a SFML specific solution you can do this.
sf::Image tmp;
tmp.loadFromFile("super.jpeg");
std::ofstream file;
file.open("textarray.cpp");
size_t psize = tmp.getSize().x * tmp.getSize().y * 4;
auto ptr = tmp.getPixelsPtr();
file << "sf::Uint8 imageArray[] = {" << (int)ptr[0];
for (size_t i = 1; i<psize; ++i)
file << "," << (int)ptr[i];
file << "};";
file.close();
This will create a file name textarray.cpp containing something that looks like sf::Uint8 imageArray[] = {...};
Then you can load it in your program like this.
sf::Uint8 imageArray[] = {...};
sf::Image img;
img.create(80, 80, imageArray); // Replace 80, 80 with width and height of your image!!!
sf::Texture texture;
texture.loadFromImage(img);
sf::Sprite sprite;
sprite.setTexture(texture);
From here, just draw the sprite like normal.

Related

SFML Anti-Aliasing - lines look dotted and moving objects smear

Several months ago I made a Fourier Transform program using SFML 2.0. I used anti-aliasing level 8 and it looked perfectly fine. Just recently however (not quite sure when the problem began since I have not touched it in a while), it seems to have broken.
Whenever I draw a line it looks dotted and whenever something moves, it flashes between two states and it doesn't completely clear after calling window.clear(). It's not just that program however. Anytime I use any level of anti-aliasing greater than 0, even in SFML 2.5.1, the same problem occurs.
Here is the some sample code which does not work as it should on my computer:
#include <SFML/Graphics.hpp>
int main()
{
sf::Vertex line[2] =
{
sf::Vertex(sf::Vector2f(0, 0)),
sf::Vertex(sf::Vector2f(800, 0))
};
sf::ContextSettings settings;
settings.antialiasingLevel = 8.0;
sf::RenderWindow window(sf::VideoMode(800, 600), "Test", sf::Style::Close, settings);
window.setVerticalSyncEnabled(true);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
line[1].position.y += 1.0;
window.clear();
window.draw(line, 2, sf::Lines);
window.display();
}
return 0;
}
When the line finishes sweeping, it looks
like this
As this used to not be a problem, I don't think it's SFML's fault. I am using Windows 10 and my computer uses an integrated Intel UHD Graphics 620 graphics card, both of which have not changed since before the problem started happening. On a side note, I have not noticed any other programs on my computer break, only the ones I made.

Why the texture appears only in the first quadrant

What's wrong with this code using SFML?
In the code below, I have this image (1000x1000) and I want to show it in a window (500x500) using sf::RenderTexture.
However, only part of the image appears in the first quadrant:
#include <SFML/Graphics.hpp>
using namespace sf;
int main()
{
RenderWindow window({500, 500}, "SFML Views", Style::Close);
View camera;
camera.setSize(Vector2f(window.getSize()));
Texture background;
background.loadFromFile("numeros.png");
Sprite numeros (background);
RenderTexture texture;
texture.create(window.getSize().x, window.getSize().y);
Sprite content;
content.setTexture(texture.getTexture());
texture.draw(numeros);
texture.display();
while (window.isOpen())
{
for (Event event; window.pollEvent(event);)
if (event.type == Event::Closed)
window.close();
window.clear();
window.setView(camera);
window.draw(content);
window.display();
}
return EXIT_SUCCESS;
}
As far as I can understand, the code should generate the original image (1000x1000) automatically adjusted to 500x500.
Could anyone tell you what is wrong?
You're facing, in fact, two distinct problems:
First one:
As far as I can understand, the code should generate the original
image (1000x1000) automatically adjusted to 500x500.
This is not really true. SFML handles the sprites with the real size of the texture. If your image is 1000x1000, but you want representing it as 500x500, you should assign the texture to a sprite, as you do:
Sprite numeros(background);
and then scale this sprite to fit in a 500x500 window, this is:
numeros.setScale(0.5, 0.5);
With this change you should view the whole image, but...
Second one:
You're messing with the view of the window. If we check SFML documentation, we can see that sf::View expects:
A sf::FloatRect: this is, a coordinate (x,y) - in this case the top-left corner - and a size(width, height)
or
Two sf::Vector2f: one corresponding to the coordinates of the center and the other corresponding to the size of the view.
Assuming you want to use the second one, you're missing the first parameter, the center coordinates, but this is not really necessary. If you simply don't apply the view, the image should be shown in the whole window.
So you simply need to remove:
window.setView(camera);
The code I've tried:
int main()
{
RenderWindow window({ 500, 500 }, "SFML Views", Style::Close);
View camera;
camera.setSize(Vector2f(window.getSize()));
Texture background;
background.loadFromFile("numeros.png");
Sprite numeros(background);
numeros.setScale(0.5, 0.5); // <-- Add this
RenderTexture texture;
texture.create(window.getSize().x, window.getSize().y);
Sprite content;
content.setTexture(texture.getTexture());
texture.draw(numeros);
texture.display();
while (window.isOpen())
{
for (Event event; window.pollEvent(event);)
if (event.type == Event::Closed)
window.close();
window.clear();
//window.setView(camera); <-- Remove this
window.draw(content);
window.display();
}
return EXIT_SUCCESS;
}
And my result:
Just to add another option to #alseether 's excellent response, I realized that the whole issue consisted of that bad View initialization.
This way you can also set the size of the view = to the size of the background image (1000,1000) and finally set the center of the view to the windows's upper left corner.
As the view is larger than the window size (500,500) it will automatically be adjusted to this new size.
In short, the section to be changed would be:
View camera;
camera.setSize(Vector2f(background.getSize().x, background.getSize().y));
camera.setCenter(Vector2f(window.getSize()));

SFML Image.saveToFile access violation

So I am working on a program that generates images with shapes of random selected colors. and I want to save an image of the output so I can use shaders on the image like blurring, as well as have an output file for any purpose. Here is my main loop for the window.
while (window.isOpen())
{
Event event;
while (window.pollEvent(event))
{
if (event.type == Event::Closed)
window.close();
}
window.clear(Color::Black);
for (int i = 0; i < rectangles.size(); i++)
window.draw(rectangles[i]);
Texture outputTexture;
outputTexture.create(width, height);
outputTexture.update(window);
Image output;
output.create(width, height);
output = outputTexture.copyToImage();
output.saveToFile("output.png");
Sprite sprite;
sprite.setTexture(outputTexture);
window.clear();
window.draw(sprite);
window.display();
}
I have tested this with the sprite and the window draws the sprite correctly. However I am getting an error here
output.saveToFile("output.png");
Exception thrown at 0x00007FF8D1527190 (sfml-graphics-2.dll) in name.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.
I can't seem to figure out the issue, I really need to be able to save images to a file. Thanks all for help
I came across the same problem, the solution was to change "sfml-xxx.lib" to "sfml-xxx-d.lib" in "Additional Dependencies" property in Visual Studio.

Printing a 2d array in sfml from a text file

Im trying to print out a 2d array of characters that is from a text file, into a renderwindow using the window.draw() function. However, everything seems to work perfectly fine, except that when printing its skipping exactly one character.
For instance if i had a line of 15 chars, it will only print 8,but when i print it on the terminal it prints it perfectly fine, I simply dont know why its behaving like that, tried several things like changing the text file itself, or changing the size. Nothing seems to work for me. any ideas or help is very much appreciated.
here is the part of the code:
void Level::printgrid(int level)
{
sf::RenderWindow window(sf::VideoMode(800, 600), "Game On");
sf::Font MyFont;
if (!MyFont.loadFromFile("tnr.ttf"))
{
// Error...
}
ifstream my_file("nn.txt"); //text that i will be reading from
char number;
int i = 0; //to help loop
int j = 0;
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
else
{
window.clear();
while (i<row) // ive tried 2 for loops that didnt work cause
{ // it kept re-entering those loops
while (j<col)
{
my_file.get(grid[i][j]); //getting the chars one by one
cout << grid[i][j]; // printing them on terminal
//so i can check its correct
//changing to text that is drawable to print in window
sf::Text text(grid[i][j], MyFont, 30);
text.setPosition(0 + (30 * i), 0 + (30 * j));
// drawing it in window
window.draw(text);
window.display();
j++;
}
my_file.get(number);
cout << endl;
i++;
j = 0;
}
}
}
}
}
There are a few issues with your code, but the most apparent problem is the fact that you're always drawing only one character, then presenting the result (which will flip buffers).
Due to this you're basically alternating characters between the two buffers (since SFML is double buffering).
In addition, you're continually reading from your file, recreating the characters/text elements, etc. which is not very effective and should fail once you reach the end of the file.
For some actual game or program, you should work on optimizing the drawing (drawing 10 characters at once as one sf::Text is faster than drawing 10 individual sf::Text objects). I'll be ignoring this for simplicity for now.
The following is just a quick (untested) example to show you the basic idea.
// First I'd use some container to store our `sf::Text` objects
// This will just create all the objects
std::vector<sf::Text> chars(rows * cols);
// Now let's read the characters and add to our vector
for (std::size_t y = 0; y < rows; ++y) {
for (std::size_t x = 0; x < cols; ++x) {
// Just an alias to simplify the following lines
sf::Text &text = chars[y * cols + x];
// Now just set up everything
text.setFont(my_font);
text.setFillColor(sf::Color::White);
text.setCharacterSize(30);
text.setPosition(30 * x, 30 * y);
text.setString(my_file.get());
}
}
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
// Just your usual event handling
}
window.clear();
// Iterate over all elements and draw them
for (const auto &text : chars)
window.draw(text);
window.display();
}
If you're trying to create some kind of graphical console, you should put all characters into some sf::VertexArray or potentially render them using a shader.

SFML 2 drawing does not work when connected with OGRE

I am currently working on connecting OGRE and SFML.
SFML should be used for 2D drawing, network stuff and input.
OGRE is for the 3d Graphics.
Currently the whole thing is on Linux.
What works: Connecting OGRE and SFML. First I create a SFML Render Window, then I grab the handle of this window and give it to the OGRE Render WIndow while creating it. I can use the SFML Events now. Did not test the Network stuff, but I am sure this will work too.
What does not work: Drawing in the SFML window.
Case 1: SFML and OGRE are not connected. OGRE does not have the SFML window handle and has its own window. SFML still can't draw in its own window! The main loop executes a maximum of 3 times and then just stops. Nothing more happens. A few seconds later (about 20 or so) I get a Memory Access violation and the program ends.
Case 2: SFML and OGRE are connected. A similar thing happens: The main loop executes exectly 53 times, nothing gets drawn and then the program stops with the terminal message "aborted" (actually its "Abgebrochen", because it's in German)
The strange behaviour also happens, when I let SFML draw into a sf::RenderTexture instead of the sfml_window.
Here is my code:
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/System.hpp>
#include <iostream>
#include <OGRE/Ogre.h>
#include <vector>
#include <stdio.h>
int main(int argc, char * argv[])
{
if(argc == 1)
return -1;
// start with "1" and you get 1 window, start with "0" and you get two
bool together = atoi(argv[1]);
// create the SFML window
sf::RenderWindow sfml_window(sf::VideoMode(800, 600), "test");
sf::WindowHandle sfml_system_handle = sfml_window.getSystemHandle();
sfml_window.setVerticalSyncEnabled(true);
std::cout<<sfml_system_handle<<std::endl;
// init ogre
Ogre::Root * ogre_root = new Ogre::Root("", "", "");
std::vector<Ogre::String> plugins;
plugins.push_back("/usr/lib/x86_64-linux-gnu/OGRE-1.8.0/RenderSystem_GL");
for(auto p : plugins)
{
ogre_root->loadPlugin(p);
}
const Ogre::RenderSystemList& render_systems = ogre_root->getAvailableRenderers();
if(render_systems.size() == 0)
{
std::cerr<<"no rendersystem found"<<std::endl;
return -1;
}
Ogre::RenderSystem * render_system = render_systems[0];
ogre_root->setRenderSystem(render_system);
ogre_root->initialise( false, "", "");
// create the ogre window
Ogre::RenderWindow * ogre_window= NULL;
{
Ogre::NameValuePairList parameters;
parameters["FSAA"] = "0";
parameters["vsync"] = "true";
// if started with 1, connect the windows
if(together) parameters["externalWindowHandle"] = std::to_string(sfml_system_handle);
ogre_window = ogre_root->createRenderWindow("ogre window", 800, 600, false, &parameters);
}
// ogre stuff
Ogre::SceneManager * scene = ogre_root->createSceneManager(Ogre::ST_GENERIC, "Scene");
Ogre::SceneNode * root_node = scene->getRootSceneNode();
Ogre::Camera * cam = scene->createCamera("Cam");
Ogre::SceneNode * cam_node = root_node->createChildSceneNode("cam_node");
cam_node->attachObject(cam);
Ogre::Viewport * vp = ogre_window->addViewport(cam);
vp->setAutoUpdated(false);
vp->setBackgroundColour(Ogre::ColourValue(0, 1, 1));
ogre_window->setAutoUpdated(false);
ogre_root->clearEventTimes();
//sfml image loading
sf::Texture ring;
std::cout<<"ring loading: "<<ring.loadFromFile("ring.png")<<std::endl;
sf::Sprite sprite;
sprite.setTexture(ring);
// main loop
int counter = 0;
while(!ogre_window->isClosed() && sfml_window.isOpen())
{
std::cout<<counter<<std::endl;
counter++;
std::cout<<"a"<<std::endl;
// sfml events
sf::Event event;
while(sfml_window.pollEvent(event))
{
if(event.type == sf::Event::Closed)
{
sfml_window.close();
}
}
std::cout<<"b"<<std::endl;
std::cout<<"c"<<std::endl;
ogre_root->renderOneFrame();
std::cout<<"d"<<std::endl;
// here the strange behaviour happens
// if this line (draw) isn't present, everything works
sfml_window.pushGLStates();
sfml_window.draw(sprite);
sfml_window.popGLStates();
vp->update();
std::cout<<"e"<<std::endl;
sfml_window.display();
// only needs to be done for separated windows
// sfml display updates otherwise, both use double buffering
if(!together) ogre_window->update(true);
}
return 0;
}
Help would be really appreciated.
EDIT: I added the pushGLStates(); and popGLStates(); commands, forgot those earlier!
Not an answer really, but too long for a comment:
ogre_window = ogre_root->createRenderWindow("ogre window", 800, 600, false, &parameters);
Are you sure that it's okay to pass the address of an object you destroy the very next line here with &parameters?