Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing std::vector with a repeating pattern

I'm working with OpenGL at the moment, creating a 'texture cache' which handles loading images and buffering them with OpenGL. In the event an image file can't be loaded it needs to fall back to a default texture which I've hard-coded in the constructor.

What I basically need to do is create a texture of a uniform colour. This is not too difficult, it's just an array of size Pixels * Colour Channels.

I am currently using a std::vector to hold the initial data before I upload it OpenGL. The problem I'm having is that I can't find any information on the best way to initialize a vector with a repeating pattern.

The first way that occurred to me was to use a loop.

std::vector<unsigned char> blue_texture;
for (int iii = 0; iii < width * height; iii++)
{
    blue_texture.push_back(0);
    blue_texture.push_back(0);
    blue_texture.push_back(255);
    blue_texture.push_back(255);
}

However, this seems inefficient since the vector will have to resize itself numerous times. Even if I reserve space first and perform the loop it's still not efficient since the contents will be zeroed before the loop which means two writes for each unsigned char.

Currently I'm using the following method:

struct colour {unsigned char r; unsigned char g; unsigned char b; unsigned char a;};
colour blue = {0, 0, 255, 255};
std::vector<colour> texture((width * height), blue);

I then extract the data using:

reinterpret_cast<unsigned char*>(texture.data());

Is there a better way than this? I'm new to C/C++ and I'll be honest, casting pointers scares me.

like image 547
Fibbs Avatar asked Dec 24 '22 17:12

Fibbs


2 Answers

Your loop solution is the right way to go in my opinion. To make it efficient by removing repeated realloc calls, use blue_texture.reserve(width * height * 4)

The reserve call will increase the allocation, aka capacity to that size without zero-filling it. (Note that the operating system may still zero it, if it pulls the memory from mmap for example.) It does not change the size of the vector, so push_back and friends still work the same way.

like image 173
Zan Lynx Avatar answered Jan 08 '23 11:01

Zan Lynx


You can use reserve to pre-allocate the vector; this will avoid the reallocations. You can also define a small sequence (probably a C style vector:

char const init[] = { 0, 0, 255, 255 };

and loop inserting that into the end of the vector:

for ( int i = 0; i < pixelCount; ++ i ) {
    v.insert( v.end(), std::begin( init ), std::end( init ) );
}

this is only marginally more efficient than using the four push_back in the loop, but is more succinct, and perhaps makes it clearer what you're doing, albeit only marginally: the big advantage might be being able to give a name to the initialization sequence (eg something like defaultBackground).

like image 30
James Kanze Avatar answered Jan 08 '23 11:01

James Kanze