Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: I am encountering the "White Sprite Problem", but I think the texture is alive  (Read 1321 times)

0 Members and 1 Guest are viewing this topic.

Pseudonymous

  • Newbie
  • *
  • Posts: 4
    • View Profile
This is an entire, minimal, runnable example, stripped from anything that wasn't related to the problem. It's not idiomatic C++ and there are style problems, but for now I'm interested in understanding why this does not work.

The sprite seems to draw as a white square, even though I *think* I'm properly keeping the texture alive.

In my draw function I clear everything in magenta. If I don't move the sprite, only a small white square on the top left is drawn. This confirms that the sprite, of the right size, is drawn; but it's just white instead of the correct image.

#define SFML_STATIC

#include <stdint.h>
typedef uint64_t u64;

#define TILE_SIZE 32

#define WIDTH  640
#define HEIGHT 640

#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>

struct State {
    sf::Texture dirt_texture;
    sf::Sprite dirt_sprite;

    sf::RenderWindow* window;
};

void update(State state) {
}

void draw(State state) {
    state.window->clear(sf::Color::Magenta);

    for (u64 x = 0; x < 64; x++) {
        for (u64 y = 0; y < 64; y++) {
            state.dirt_sprite.setPosition(x * TILE_SIZE, y * TILE_SIZE);
            state.window->draw(state.dirt_sprite);
        }
    }

    state.window->display();
}

State new_state(sf::RenderWindow* window) {
    State state;
    state.window = window;
   
   
    if (!state.dirt_texture.loadFromFile("art/dirt.png")) {
        printf("Error loading dirt!!!!\n");
    }

    state.dirt_sprite.setTexture(state.dirt_texture);

    return state;
}

int main() {
    sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT), "My window");
    State state = new_state(&window);

    while (window.isOpen()) {
        sf::Event event;

        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                window.close();
            }
        }

        update(state);
        draw(state);
    }

    return 0;
}
 

I do get this warning in the console output:

An internal OpenGL call failed in Texture.cpp(98).
Expression:
   glFlush()
Error description:
   GL_INVALID_OPERATION
   The specified operation is not allowed in the current state.

Pseudonymous

  • Newbie
  • *
  • Posts: 4
    • View Profile
Moreover, changing the texture to a pointer and creating it with new works (but I'm pretty sure this is even worse C++):

#define SFML_STATIC

#include <stdint.h>
typedef uint64_t u64;

#define TILE_SIZE 32

#define WIDTH  640
#define HEIGHT 640

#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>

struct State {
    sf::Texture* dirt_texture;
    sf::Sprite dirt_sprite;

    sf::RenderWindow* window;
};

void update(State state) {
}

void draw(State state) {
    state.window->clear(sf::Color::Magenta);

    for (u64 x = 0; x < 64; x++) {
        for (u64 y = 0; y < 64; y++) {
            state.dirt_sprite.setPosition(x * TILE_SIZE, y * TILE_SIZE);
            state.window->draw(state.dirt_sprite);
        }
    }

    state.window->display();
}

State new_state(sf::RenderWindow* window) {
    State state;
    state.window = window;
   
    state.dirt_texture = new sf::Texture();
    if (!state.dirt_texture->loadFromFile("art/dirt.png")) {
        printf("Error loading dirt!!!!\n");
    }

    state.dirt_sprite.setTexture(*state.dirt_texture);

    return state;
}

int main() {
    sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT), "My window");
    State state = new_state(&window);

    while (window.isOpen()) {
        sf::Event event;

        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                window.close();
            }
        }

        update(state);
        draw(state);
    }

    return 0;
}
 

This suggests that my misunderstanding is coming from C++ and not from SFML. What's the problem of the first version?

Pseudonymous

  • Newbie
  • *
  • Posts: 4
    • View Profile
This is a triple post, but I think it's the cleanest way to post it...

I think the problem with the first piece of code is that when I return the game from new_game(), game (along with its members) gets copied, and the texture getting copied causes the white sprite problem.


Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
It seems you are passing "State" by value, which means they get copied. The texture is inside a state so the texture is also getting passed by value.
You are assigning the texture to a sprite inside a function but then both get copied (to another state). The pointer to texture that the sprite holds will still point to the original address (the texture inside the other state, which may even have been destroyed).
When you use pointers, the texture doesn't get copied around each time, only its address, which doesn't change.

You could also pass the state itself by either pointer or reference. This could solve the problem as well.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Pseudonymous

  • Newbie
  • *
  • Posts: 4
    • View Profile
Thanks for the detailed explanation. Everything's clear now.

PS: could you post again, so I can see if your post count really is in hex? You're at 9 in the least significant digit :P