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.
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.
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
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With