I have a simple program where I set the texture of a sprite and change its color, but it won't display. The window is entirely black. Is there something I did not do?
#include <SFML/Graphics.hpp>
int main()
{
sf::Texture texture;
sf::Sprite sprite;
texture.create(200, 200);
sprite.setTexture(texture);
sprite.setColor(sf::Color(209, 59, 59));
while (window.isOpen())
{
window.clear();
window.draw(sprite);
window.display();
}
return 0;
}
Setting a color to a sprite while its texture's pixels have no color will not work, because of how sf::Sprite::setColor() method works.
From SFML documentation:
void sf::Sprite::setColor ( const Color & color )
This color is modulated (multiplied) with the sprite's texture. It can be used to colorize the sprite, or change its global opacity. By default, the sprite's color is opaque white.
Multiplying any color against a transparent texture will not change anything in how the Sprite is rendered.
One solution would be to create an image of size 200,200 and setting the image to the desired color, using sf::Image::create (width, height, color) constructor, then loading the texture from that image.
Example code:
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(500,500), "TEST");
sf::Image image;
image.create(200,200,(sf::Color(209, 59, 59)));
sf::Texture texture;
texture.loadFromImage(image);
sf::Sprite sprite;
sprite.setTexture(texture);
while (window.isOpen())
{
window.clear();
window.draw(sprite);
window.display();
}
return 0;
}
Related
My main goal is to convert a bunch of pairs of numbers from a text file (numbers.txt) and assign each of these numbers as pixel coordinates. Then I need to print a pixel at each of those coordinates that will eventually form a picture of the United States composed of only single pixels.
Right now, what I'm doing is just trying to get any pixel of any color to print to the screen using SFML. Maybe if I can get that far I can somehow take the numbers stored in numbers.txt and convert them to coordinates with a pixel at each one.
Here's my code so far...
#include <iostream>
#include <fstream> // the fstream class
#include <SFML/Graphics.hpp>
#include <string> // will help to use strings
using namespace std;
int main()
{
string line;
int width, height;
fstream myFile;
myFile.open("resources/numbers.txt");
if (myFile)
{
cout << "This file is opened\n";
}
else
return EXIT_FAILURE;
cout << "Enter 2 integer values";
cin >> width >> height;
// Print a black window to the screen
sf::RenderWindow window(sf::VideoMode(width, height), "MAP");
sf::Texture texture;
sf::Sprite sprite;
sprite.setTexture(texture);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
switch (event.type)
{
case sf::Event::Closed:
window.close();
break;
}
}
window.clear();
//window.draw(sprite);
//*************DRAW THE SPRITE HERE****************
// create a new vertex
sf::Vertex vertex;
// set its position
vertex.position = sf::Vector2f(10.f, 50.f);
// set its color
vertex.color = sf::Color::Red;
// set its texture coordinates
vertex.texCoords = sf::Vector2f(100.f, 100.f);
sf::VertexArray pixel(sf::Points);
window.draw(pixel);
//display window
window.display();
}
return 0;
}
This does compile fine. But only displays a black screen to the user. I need to somehow get a pixel on that black screen. I am very new to SFML and C++ and looked up on the SFML mainpage about points and pixels but only got this far. Can any of you guys help? It's super appreciated!
All the best.
there are several approaches in SFML to draw a single pixel on the screen. The first one is what you are trying to do with sf::VertexArray.
In my opinion the simpler and more intuitive is approach with sf::RectangleShape where you can create rectangle with 1x1 size and this one I am going to present you.
Firstly, we can add helpful function which will create "pixel" at given position and color.
sf::RectangleShape addPixel(sf::Vector2f position, sf::Uint8 red, sf::Uint8 green, sf::Uint8 blue)
{
sf::RectangleShape pixel;
pixel.setSize({ 1.f, 1.f });
pixel.setFillColor({ red, green, blue });
pixel.setPosition(position);
return pixel;
}
That function will return sf::RectangleShape with the color created from RGBs values passed as arguments to that function.
But you have to store these pixels somewhere.
So let's create window, and some container to hold our pixels, e.g. std::vector<sf::RectangleShape>
and add to it some pixels:
sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window");
std::vector<sf::RectangleShape> pixels;
pixels.push_back(addPixel({ 100, 100 }, 255, 0, 0));
pixels.push_back(addPixel({ 101, 100 }, 255, 255, 0));
pixels.push_back(addPixel({ 102, 100 }, 0, 0, 0));
pixels.push_back(addPixel({ 103, 100 }, 255, 0, 255));
Finally you create main loop where you draw all pixels in each iteration.
while (window.isOpen())
{
window.clear();
for (const auto& pixel : pixels)
{
window.draw(pixel);
}
window.display();
}
Make sure you add more pixels before trying to display it. On high resolution screen single pixels could be invisible.
EDIT: You code also works but you forgot to add sf::Vertex to sf::VertexArray.
All you should do is:
sf::Vertex vertex1;
vertex1.position = sf::Vector2f(10.f, 50.f);
vertex1.color = sf::Color::Red;
sf::VertexArray pixel;
pixel.append(vertex1); // That's what you forgot.
window.draw(pixel);
As above, with this approach also add more sf::Vertex next to each other, otherwise you may not notice single pixel on the screen.
Hope it helps!
#include <iostream>
#include <SFML/Graphics.hpp>
int main()
{
int desktopwidth = sf::VideoMode::getDesktopMode().width;
int desktopheight = sf::VideoMode::getDesktopMode().height;
sf::ContextSettings settings;settings.antialiasingLevel = 8;
sf::RenderWindow window(sf::VideoMode(desktopwidth, desktopheight), "Texture Transforming!", sf::Style::Fullscreen, settings);
while (window.isOpen())
{
sf::Image image;
if (!(image.loadFromFile("texture.jpg")))
std::cout << "Cannot load image"; //Load Image
sf::Texture texture;
texture.loadFromImage(image); //Load Texture from image
sf::Sprite sprite;
sprite.setTexture(texture);
sprite.setTextureRect({ 0, 0, desktopwidth, desktopheight });
window.clear();
window.draw(sprite);
window.display();
}
return 0;
}
What I want to do is stretch the texture to the full size of the screen when the screen is bigger than the image. Using setTextureRect all I have achieved is stretching out the last pixel to the new size which isn't a great look for what i am trying to do, as image resize was removed, does anyone know of a work around to resize images or transform texture size/scales?
sf::Sprite::setTextureRect() defines the part of the texture that's visible as the sprite. It doesn't define the actual display size.
For this purpose you might want to use sf::Sprite::setScale(), which allows you to define a scaling ratio. For example, calling sprite.setScale(2, 2); will make the displayed sprite twice as wide/high.
If you want to downscale/upscale your whole scene, you might want looking into sf::View though.
New to game development with SFML and really like it.
So far I'm trying to render a circle on a sprite, but somehow I only get a quarter of the circle meaning that the window is taken as surface when drawing instead of sprite. If I make the sprie size as the window, I'll see the full circle..
Here's my code:
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
const char *glsl = R"(
#version 330 core
uniform vec2 u_resolution;
void main() {
vec2 pos = gl_FragCoord.xy / u_resolution;
float radius = 0.4;
float d = smoothstep(radius + 0.01, radius, distance(pos, vec2(0.5)));
gl_FragColor = vec4(d*0.0, d*0.5, d*1.0, 1.0);
}
)";
int main() {
sf::RenderWindow window(sf::VideoMode(800, 600), "GLSL", sf::Style::Default);
sf::Texture tex;
tex.create(800 / 2, 600 /2); // or tex.create(800, 600); for full window surface
sf::Sprite spr(tex);
sf::Shader shader;
shader.loadFromMemory(glsl, sf::Shader::Fragment);
shader.setUniform("u_resolution", sf::Vector2f(800, 600));
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) if(event.type == sf::Event::Closed) window.close();
window.clear(sf::Color(244,244,244));
window.draw(spr, &shader);
window.display();
}
}
Any help would be appreciate. What I'm looking to achieve is to render the full circle in the sprite range. Thanks!
You take a quarter of the screen because you do tex.create(800 / 2, 600 /2); and your window size is sf::RenderWindow window(sf::VideoMode(800, 600) ...);. So it devide by the width and the height. Create a texture with the same size that your window and I think you'll be good (tex.create(800, 600);).
Just started learning SFML (so please bear with me).
I have made a RenderWindow object, and I have a image I want to fit perfectly to that window.
By searching through the documentation, I found the sf::Sprite::SetScale function. Is this the right function to do it? But how do I set the scale of the sprite to the scale of the RenderWindow, when the RenderWindow object size is set in pixels? Do I have to get the scale of the RenderWindow, and then assign the background sprite to that scale or?
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <iostream>
int main()
{
sf::RenderWindow window(sf::VideoMode(600, 300), "Simple Game");
sf::Texture BackgroundTexture;
sf::Sprite background;
//background.setScale(0.2, 0.2); <--- how?
if(!BackgroundTexture.loadFromFile("media/background.png"))
{
return -1;
}
else
{
background.setTexture(BackgroundTexture);
}
while(window.isOpen())
{
sf::Event event;
while(window.pollEvent(event))
{
switch(event.type)
{
case sf::Event::Closed:
window.close();
}
}
window.clear();
window.draw(background);
window.display();
}
}
The scale factor you need is simply the ratio between the window size and the texture size. sf::Texture has a getSize function, as has sf::RenderWindow. Simply get the sizes of both, calculate the ratio and use it to set the scale of the sprite, like this:
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <iostream>
int main()
{
sf::RenderWindow window(sf::VideoMode(600, 300), "Simple Game");
sf::Texture BackgroundTexture;
sf::Sprite background;
sf::Vector2u TextureSize; //Added to store texture size.
sf::Vector2u WindowSize; //Added to store window size.
if(!BackgroundTexture.loadFromFile("background.png"))
{
return -1;
}
else
{
TextureSize = BackgroundTexture.getSize(); //Get size of texture.
WindowSize = window.getSize(); //Get size of window.
float ScaleX = (float) WindowSize.x / TextureSize.x;
float ScaleY = (float) WindowSize.y / TextureSize.y; //Calculate scale.
background.setTexture(BackgroundTexture);
background.setScale(ScaleX, ScaleY); //Set scale.
}
while(window.isOpen())
{
sf::Event event;
while(window.pollEvent(event))
{
switch(event.type)
{
case sf::Event::Closed:
window.close();
}
}
window.clear();
window.draw(background);
window.display();
}
}
I'm trying to draw a texture on a sf::vertexarray
if I call the below code (without the texture), I can display fine a rectangle with red border. When I add the texture, I see nothing.
What am I doing wrong?
sf::VertexArray v_array;
v_array.append(sf::Vertex(sf::Vector2f(1,1) , sf::Color::Red));
v_array.append(sf::Vertex(sf::Vector2f(60,1) , sf::Color::Red));
v_array.append(sf::Vertex(sf::Vector2f(60,10 ), sf::Color::Red));
v_array.append(sf::Vertex(sf::Vector2f(1,10), sf::Color::Red));
v_array.append(sf::Vertex(sf::Vector2f(1,1), sf::Color::Red ));
v_array.setPrimitiveType(sf::LinesStrip);
sf::Texture text;
text.loadFromFile("../ressources/tileset_base.png");
sf::RenderStates rend(&text);
sf::RenderWindow App(sf::VideoMode(800, 600, 32), "SFML Graphics");
// Start game loop
while (App.isOpen())
{
// Process events
sf::Event Event;
while (App.pollEvent(Event))
{
// Close window : exit
if (Event.type == sf::Event::Closed)
App.close();
}
App.clear();
App.draw(v_array/*, rend*/);
App.display();
}
You need to give some texture coordinate to your vertices. You can use one of the following two constructors:
Vertex (const Vector2f &thePosition, const Vector2f &theTexCoords)
Vertex (const Vector2f &thePosition, const Color &theColor, const Vector2f &theTexCoords)
See documentation here
Small tip: if you use only one render state (e.g. only the texture) you can use this shortcut:
App.draw(v_array, &text);