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

Author Topic: Loading huge amount of images  (Read 8925 times)

0 Members and 1 Guest are viewing this topic.

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Loading huge amount of images
« on: May 05, 2015, 07:19:56 am »
I need to load a very high amount of 1000*1000 pixel images (40000*20000 pixel "world map") and would like to ask, if the image loading code can be written in a shorter way:

        sf::Image mapimage1;
        mapimage1.loadFromFile("mapimage1.png");
        sf::Texture maptexture1;
        maptexture1.loadFromImage(mapimage1);
        sf::Sprite mapsprite1(maptexture1);
        mapsprite1.setPosition(0, 0);

       ............

        sf::Image mapimage800;
        mapimage800.loadFromFile("mapimage800.png");
        sf::Texture maptexture800;
        maptexture800.loadFromImage(mapimage800);
        sf::Sprite mapsprite800(maptexture800);
        mapsprite1.setPosition(39000, 19000);

The images represent a "province map", where every province has a unique rgb color
and I need those images only to get the pixelcolor for finding out which province was clicked.
With this, there is another problem. For finding out, where the cursor is, I need 800 if conditions like the following one:

                        if(mapsprite1.getGlobalBounds().contains(coord_pos.x,coord_pos.y))
                        {
                                color = mapimage1.getPixel(coord_pos.x, coord_pos.y);
                        }

                        ..................

                        else if(mapsprite800.getGlobalBounds().contains(coord_pos.x,coord_pos.y))
                        {
                                color = mapimage800.getPixel(coord_pos.x, coord_pos.y);
                        }


Is there a way to make the code shorter, because that would be overkill needing many thousand lines of code only for those simple operations?
« Last Edit: May 05, 2015, 07:23:08 am by Bogdan »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11033
    • View Profile
    • development blog
    • Email
AW: Loading huge amount of images
« Reply #1 on: May 05, 2015, 07:29:47 am »
Use a std::vector.
Also if you only need some pixel information, why not store that in something else than 800 1000x1000 images?

Additionally you might run into memory issues at one point.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Loading huge amount of images
« Reply #2 on: May 05, 2015, 07:40:27 am »
How to get the pixel information in a different, not so ressource demanding way ? Checking if mouse is in "provincesprite" or "ConvexShape" is not possible, because the provinces have irregular and individual shapes/sizes, so collision detection is imprecise (only big rectangles possible) and I need pixel perfect checking if cursor is inside a province. How not running into memory issues?
« Last Edit: May 05, 2015, 07:47:49 am by Bogdan »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11033
    • View Profile
    • development blog
    • Email
AW: Loading huge amount of images
« Reply #3 on: May 05, 2015, 08:00:23 am »
Create your own format or use something like JSON to hold your geometry information.

Well if you load a 40000x20000 pixels you end up with about 2.98 GiB of data, that then needs to fit in your RAM and VRAM. So only load what's really needed.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Loading huge amount of images
« Reply #4 on: May 05, 2015, 10:07:25 am »
The images represent a "province map", where every province has a unique rgb color
And do you really need 32 bits to encode a province? How many provinces are there? If it's considerably less than 232, then use a smaller data type, e.g. std::vector<short>.

Another way to compress the data is to reduce the number of samples. If it's still accurate enough to aggregate 4 adjacent pixels as one (or 9, or whatever), then do that.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Loading huge amount of images
« Reply #5 on: May 05, 2015, 07:59:09 pm »
Right now I'm implementing simplified loading of images (example with a map consisting of two parts) and have encountered a small problem. Only the second sprite is visible. At the position of the first sprite, there is only a white rectangle. Something is wrong, althoungh the code seems ok?

        sf::Image ImageName;
        sf::Texture TextureName;
        sf::Sprite SpriteName;

        std::vector<std::tuple<sf::Image,sf::Texture,sf::Sprite,std::string>> Map;

        int x = 0;

        for(int i=0; i<2; i++)
        {
                std::stringstream stream;
                stream << "map" << i << ".png";
                std::string FileName = stream.str();

                Map.push_back(std::make_tuple(ImageName,TextureName,SpriteName,FileName));

                std::get<0>(Map[i]).loadFromFile(std::get<3>(Map[i]));
                std::get<1>(Map[i]).loadFromImage(std::get<0>(Map[i]));
                std::get<2>(Map[i]).setTexture(std::get<1>(Map[i]));
                std::get<2>(Map[i]).setPosition(x,0);
                x=x+500;
        }


//.......................................................................

        for (auto& it=Map.begin(); it!=Map.end(); ++it)
        {
                mMainWindow.draw(std::get<2>(*it));
        }

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Loading huge amount of images
« Reply #6 on: May 05, 2015, 08:17:25 pm »
Searching for "white rectangle/square" will give you tons of answers. It's such a popular mistake, there's a whole section on it in the tutorial. Maybe you should read it :)

And next time, please open a new thread if the problem is no longer related to the initial one.

By the way, you really don't want to use tuples like that... That code cluttered with std::get<MagicNumber> is far from readable, let alone maintainable.
« Last Edit: May 05, 2015, 08:19:33 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Loading huge amount of images
« Reply #7 on: May 05, 2015, 10:34:28 pm »
The problem is related to "loading a huge amount of images" :-)
I could't find anything on the net about it, but anyway there is a workaround:

Removing the following line from the for loop:
std::get<2>(Map[i]).setTexture(std::get<1>(Map[i]));

Creating another for loop outside of/after the first loop:
        for(int i=0; i<2; i++)
        {
        std::get<2>(Map[i]).setTexture(std::get<1>(Map[i]));
        }

Can anyone explain why it works this way but not if I put the .....setTexture inside the first loop? In the first case from above the texture information somehow gets overwritten/lost  and in the "workaround" everything is fine, although nothing really changed.

As for "managing" the huge amount of images I only use the sfml getPixel function for getting the rgb values so I don`t know where to use a smaller data type.
Reducing the number of samples sounds very interesting. Is there any tutorial for it?
« Last Edit: May 05, 2015, 10:39:58 pm by Bogdan »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Loading huge amount of images
« Reply #8 on: May 05, 2015, 10:55:41 pm »
I could't find anything on the net about it
I mentioned the tutorial, you didn't even need to search ::)
http://www.sfml-dev.org/tutorials/2.2/graphics-sprite.php#the-white-square-problem

There was a lot of effort put in the tutorials, yet so many people just don't read them, even after they're explicitly advised to do so...

As for "managing" the huge amount of images I only use the sfml getPixel function for getting the rgb values so I don`t know where to use a smaller data type.
Using sf::Image for that is wrong in the first place. You don't need 32 bit to encode a province, do you?

Reducing the number of samples sounds very interesting. Is there any tutorial for it?
No idea, but it's simple. Just don't store every pixel, but every second or third. Then you automatically have only 1/4 or 1/9 of the data.
« Last Edit: May 05, 2015, 10:57:23 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Loading huge amount of images
« Reply #9 on: May 05, 2015, 11:23:32 pm »
To my defence I have to say, that I often read the tutorials and with "net" I mean, that I`ve looked in the tutorials as well and even read that linked part :-)       But the problem here seems to be different or isn't it?

You're right, that I don't need 32 bit for encoding provinces, because I will only have some thousands of them or even less. But I need the rgb color values, at least red and blue. Sfml getPixel is the only function I know. Thats the reason why I need those sf::Images at all. Array experiments would fail anyway with using several billion pixels :-)

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Loading huge amount of images
« Reply #10 on: May 05, 2015, 11:38:52 pm »
But the problem here seems to be different or isn't it?
No -- the problem is that the pointer to the texture becomes invalid, because std::vector relocates its elements when it grows. It's not a good idea to store sprite and texture together anyway.

You're right, that I don't need 32 bit for encoding provinces, because I will only have some thousands of them or even less. But I need the rgb color values, at least red and blue.
Why? If you draw the province in red and blue, you can still do that at runtime, without holding textures of all possible provinces that you don't see at the moment.

Sfml getPixel is the only function I know. Thats the reason why I need those sf::Images at all.
Maybe you get to know some other functions then :P

Array experiments would fail anyway with using several billion pixels :-)
What do you think sf::Image is, if not an array of pixels? And yes, your problem is that you want to keep several billion pixels, although you actually need considerably less data.

You have to think of a good representation of your provinces in memory. And how that looks exactly depends on your game. But what I know for sure is that sf::Image is not appropriate for the use case you describe.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Loading huge amount of images
« Reply #11 on: May 06, 2015, 09:34:50 am »
Some time ago I tried to work with ConvexShapes. As they only have a very imprecise collision detection with the consequence, that it is not possible to use them as province representation, I went on to using images.
The images are only used to get the color and aren't to be manipulated in any way. Every province on the image has a unique rgb representation as seen in the attachment "provinces.png". In the final version this image map won't be even drawn on the screen, because it will not be visible anyway, due to the fact that I intend on using a second  layer of many white single sprites for every province (see attachment province1 for province 1). The only purpose of the second "sprite layer" is to represent the "owner colors", so you see to whom the provinces belongs. The sprites will change their color, when conquered. The function used here is "setColor". The sprite layer is not usable for collision detection, because of the same problem like with ConvexShapes. By the way the used pngs have only a size of some kilobytes, even the bigger "slices". It is not excluded that the sprites later get nicer textures as they aren't used for detection/identification purposes of any kind anyway. They are only for the "eye."

I simply cannot imagine how to do that differently. How to do that without loading the image layer, while still being able to detect, which province was clicked. What do you mean by drawing province at runtime. Drawing the image or filling it with color like I do with the sprites. Please point me in the right direction, so I can find the right solution.
« Last Edit: May 06, 2015, 09:42:12 am by Bogdan »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Loading huge amount of images
« Reply #12 on: May 06, 2015, 10:53:37 am »
Some time ago I tried to work with ConvexShapes. As they only have a very imprecise collision detection with the consequence, that it is not possible to use them as province representation, I went on to using images.
Wrong premise: convex shapes are not meant to be used as geometries in collision detection. They're graphical shapes for rendering. When you need something exact, use polygons from Boost.Geometry. They take up nearly no memory, and come with very precise geometry algorithms, e.g. to check whether a point is inside.

In the final version this image map won't be even drawn on the screen, because it will not be visible anyway
Another reason why you should not use SFML's classes to store the colors. Why don't you store integers and map them to colors, instead of storing colors themselves? E.g. 0 is red, 1 is blue and so on. Unless you have more than 256 province colors, one byte is already enough.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Bogdan

  • Jr. Member
  • **
  • Posts: 93
    • View Profile
Re: Loading huge amount of images
« Reply #13 on: May 06, 2015, 08:14:23 pm »
Do you mean something like this?

#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
#include <array>

int main()
{
    sf::RenderWindow mMainWindow(sf::VideoMode(1000,600), "Map", sf::Style::Close);
        sf::View view(sf::Vector2f(0, 0), sf::Vector2f(1000, 600));
        mMainWindow.setFramerateLimit(60);
        mMainWindow.setKeyRepeatEnabled(false);
        view.zoom(0.1f);

        int itcolorpos = 0;
        int itpos = 0;

        const std::string ProvinceArray[] = {"Province1", "Province2", "Province3"};   
        const std::vector<std::string> ProvinceVector(ProvinceArray,ProvinceArray+sizeof(ProvinceArray)/sizeof(std::string));

        const sf::Vector3i ProvinceColorsArray[] = {sf::Vector3i(255,0,255), sf::Vector3i(0,255,255),sf::Vector3i(0,0,255)};
        const std::vector<sf::Vector3i> ProvinceColorsVector(ProvinceColorsArray,ProvinceColorsArray+sizeof(ProvinceColorsArray)/sizeof(sf::Vector3i));

        std::array<std::array<unsigned short, 8>, 10> Map =        {{{0, 0, 0, 0, 0, 0, 0, 0},
                                                                                                                         {0, 0, 0, 0, 0, 0, 0, 0},
                                                                                                                         {0, 0, 1, 2, 2, 2, 1, 1},
                                                                                                                         {0, 0, 1, 2, 2, 2, 1, 1},
                                                                                                                         {0, 0, 1, 1, 1, 1, 1, 1},
                                                                                                                         {0, 0, 1, 1, 1, 1, 1, 1},
                                                                                                                         {0, 0, 1, 1, 1, 1, 1, 1},
                                                                                                                         {0, 0, 1, 1, 1, 2, 2, 2},
                                                                                                                         {0, 0, 1, 1, 1, 2, 2, 2},
                                                                                                                         {0, 0, 1, 1, 1, 2, 2, 2}}};

        sf::VertexArray MapDraw(sf::Points);
       
        for(int y = 0; y < 8; y++)
        {
            for(int x = 0; x < 10; x++)
                {
                        for (auto& it=ProvinceColorsVector.begin(); it!=ProvinceColorsVector.end(); ++it)      
                        {
                                itcolorpos = it - ProvinceColorsVector.begin();
                                if(Map[x][y]==itcolorpos)
                                {
                                        MapDraw.append(sf::Vertex(sf::Vector2f(y, x), sf::Color(ProvinceColorsVector[itcolorpos].x, ProvinceColorsVector[itcolorpos].y, ProvinceColorsVector[itcolorpos].z)));
                                }
                        }
                }
        }

    while (mMainWindow.isOpen())
    {
        sf::Event event;
                sf::Vector2i mousePos;
                bool leftclicked = false;

        while (mMainWindow.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::Closed:
                mMainWindow.close();
                break;
                        case sf::Event::MouseButtonPressed:
                if (event.mouseButton.button == sf::Mouse::Left)
                                {
                                        leftclicked = true;
                                        mousePos = sf::Vector2i(event.mouseButton.x, event.mouseButton.y);
                                        break;
                                }
            }
                }

                sf::Vector2i pixel_pos = sf::Mouse::getPosition(mMainWindow);
                sf::Vector2f coord_pos = mMainWindow.mapPixelToCoords(pixel_pos);
                int abspos_x = coord_pos.x;
                int abspos_y = coord_pos.y;

                if(leftclicked)
                {
                        if(abspos_x<=7 && abspos_x>=0 && abspos_y<=9 && abspos_y>=0)
                        {
                                for (auto& it=ProvinceVector.begin(); it!=ProvinceVector.end(); ++it)
                                {
                                        itpos = it - ProvinceVector.begin();
                                        if(Map[abspos_y][abspos_x]==itpos)
                                        {
                                                std::cout << ProvinceVector[itpos] << std::endl;
                                                break;
                                        }
                                }
                        }
                }
        mMainWindow.clear();
                mMainWindow.setView(view);
                mMainWindow.draw(MapDraw);
        mMainWindow.display();
    }
    return 0;
}

Drawing here is only for demonstration purposes, but not necessary for functioning. Map is zoomed in for being able to see the pixels better. I could use 2d Vectors instead of 3d for the Color and set the third color to 0 (only relevant when drawing), but I definitely need more than 256 provinces.

But there are still big problems, so for example I have to fill in the information manually and that would take 100 years :-)
And the second problem is that an array can only hold some millions of pixels/numbers, but not hundreds of millions.
Even the VertexArray didn't work when I tried to fill it with some (2.4) billions of pixels, so the RAM/32 bit?/compiler limit problem still persists.

« Last Edit: May 06, 2015, 08:21:49 pm by Bogdan »

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Loading huge amount of images
« Reply #14 on: May 06, 2015, 08:19:53 pm »
One thing I'm wondering when reading this thread is; regardless of how big your world is and regardless of what datastructure you use to represent it; why do you have to keep it all in memory at once?
Couldn't you divide your world into "zones" and only keep the players current "zone" and the ones adjacent to it, in memory. Then load and unload "zones" depending on how the player moves around in the world?
« Last Edit: May 06, 2015, 08:22:20 pm by Jesper Juhl »

 

anything