How to create an array of structs with arrays inside them

Hi, sorry if this seems like an odd question/request, but is there any kind soul out there able to show me an example of how you would make 3D array using structs that have arrays in them. I'll try to be as clear about the situation and what I am trying to do.

What do you want to achieve?

I want to be able to load a bitmap and store the pixel information. For each pixel at x and y location I want to store the red, green, and blue values in an array.

So why don't you just create a regular 3d array in c++?

I did, and all seemed well, until I discovered that the game engine I'm trying to use this in can't access cpp 3d arrays data from a critical feature I use in the game engine called 'blueprints' (Unreal Engine). Apparently they have to be 1d arrays

Wouldn't it be better to ask in those game engine specific forums?

I have, and I'm not getting much help at all, other than a suggestion on one forum to make structs with a 1D array in each of them, then make an array of those structs. I got no answers at all on the main forum they have.

Looking elsewhere I see these same suggestions, but the maximum they go to in the rare examples found are 2D with no obvious way to scale to 3D or more.

So the gist seems to be that I would need to make a struct containing 1d array for x, a struct with 1d array for Y, same again for red, green and blue values. Then make an array of these structs. Although I can see examples of how to create a struct with an array in, I simply can't get my head around how I write an array of those structs that makes them behave like a 3D array.


The original basic code is below to show what I am trying to convert.

Thanks in advance



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
      FILE*f;
    fopen_s(&f, "c:\\test\\test.bmp", "rb");
    if (f == NULL)
    throw "Argument Exception";
    unsigned char info[54];
    fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header
    // extract image height and width from header
    int width = *(int*)&info[18];
    int height = *(int*)&info[22];
    int rgb = 3;
    // this is where I create the new array based upon the width and height and max rgb value to store the x,y and rgb info.
    int ***rgbarr = new int**[width];
    for (int b = 0; b < width; ++b)
    {
    rgbarr[b] = new int*[height];
    for (int d = 0; d < height; ++d)
    rgbarr[b][d] = new int[3];
    }
So why don't you just create a regular 3d array in c++?

Perhaps I don't understand, so I'll ask a different question:
- Why do you need to make a 3D array?
- Why don't you just make a 1D array that has the values { R, G, B, R, G, B, R, G, B, ... }? and has a size of 3 * width * height? This is how many libraries/APIs expect data (e.g. OpenGL); it's the most portable format.

In a 1D array, you can convert an (x, y) position to an index as:
1
2
3
4
5
6
const int rgb = 3;
unsigned char* rgbarr = new unsigned char[rgb * width * height];
size_t index = rgb * width * y + rgb * x;
rgbarr[index];

delete[] rgbarr;

index is the red component
index + 1 is the green component
index + 2 is the blue component (assuming RGB ordering, I believe BMPs are sometimes BGR).

PS: sizeof(char) [or unsigned char] is always 1.
Last edited on
Hi Ganado, thanks for the suggestion. The reason I'm trying to use a 3d array is because I'll be querying the rgb values at given x, y coordinates and those x, y coordinates will also be used as x, y map coordinates for a 2d map I'll be implementing later based upon the x, y data. A 3d array just seemed easier for me to wrap my head around in terms of using the x,y coordinates. Would an array of structs be a bad idea? Looking at your code and trying to work out how I could go from a 1d to querying vales at given x, y with the x, y being removed from the equation. I understand I might be completely wrong as I am a noob, but I don't think a 1d array will work for me. I don't care about using the bmp as an image, I just want to translate it into map style coordinates and make decisions based upon the values at given x, y. Sorry for not adding more context originally, I realized now I wasn't very clear and hope this explains a bit better.
Last edited on
an array (prefer a vector) of structs is a great idea if you need a container for your (class/struct/etc). Its used all the time.

you can do anything in a 1d array that you can do in a N-d array. But we can go over that later if you want.

so let me ask very, very explicitly:
is your 'map' concept going to look like result = f(x,y);
if so, you only need 2d array. the data is the third dimension.
eg if x = 10 and y = 42, and z = 123 then.. data[10][42] = 123 for example...
its really 2-d (!!). X and Y are array indices and the data is Z here.

z could be a struct...
data[10][42].RED = 123, and .G and .B would have other values... etc.

Or am I missing something?
Last edited on
Well OK, if it's supposed to be a game map or something and not just image data, then I suppose you could abstract it a bit more with a 2D array. But if you were to use a 1D array, it would be something like this:

1
2
3
4
5
int f(int x, int y) // perhaps pass a component offset as a 3rd parameter
{
    size_t index = 3* width * y + 3* x;
    return rgbarr[index];
}


jonnin, I think Jclow was trying to do something like this:
arr[3][4][2], where it might mean y = 3, x = 4, component = 2 (e.g. B in RGB).
But I certainly think your suggestion of a 2D array of structs is better than a 3D array.

1
2
3
4
5
6
7
8
using byte = unsigned char;
struct color {
   byte red;
   byte green;
   byte blue;
};

color map[100][100] = {};
Last edited on
thanks Ganado and jonning for your help with this,

"arr[3][4][2], where it might mean y = 3, x = 4, component = 2 (e.g. B in RGB)."

That's exactly what I was trying to do but using 1d arrays within structs, because Unreal Engine Blueprints won't allow accessing 2d/3d arrays written in cpp from blueprints, only 1d.

jonning, what you said with "data[10][42].RED = 123, and .G and .B would have other values" sounds great because I didn't know you could do that with the struct on/in the array, though I still have the issue that it's a 2D array

"is your 'map' concept going to look like result = f(x,y);". If I'm understanding you right, then I think the answer is yes. Where a pixel exists at an x and y coordinate in the BMP file, go place a physical mesh at a relative x,y location in the world, what colour is the pixel? those RGB values are green so place a tree mesh at those coordinates. I think this is why Ganado, the colour struct you did along with jonning's example is the way forward, but converting x,y to a single index would mean I have no individual x and y to translate into world/map/grid location x,y in the game when it comes to telling the engine where to place a mesh, which makes me think I can't convert x,y to a single index..

Thank you both for your help, I'm certainly learning new things.
Last edited on
which makes me think I can't convert x,y to a single index..

Higher dimensions can be mapped to lower dimensions and vice versa as long as you have a uniform way of doing it.

Maybe this code helps demonstrate this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>

const int rgb = 3; // stride per pixel

void print_pixel(int x, int y, int width, int rgbarr[])
{
    size_t index = rgb * width * y + rgb * x;
    int r = rgbarr[index + 0];
    int g = rgbarr[index + 1];
    int b = rgbarr[index + 2];
    
    std::cout << "Pixel (" << x << ", " << y << ") [starting index " << index << "] value = "
              << "RGB(" << r << ", " << g << ", " << b << ")\n";
}

void print_x_y(size_t index, int width)
{
    int x = (index/rgb) % width;
    int y = (index/rgb) / width;
    std::cout << "Pixel (X, Y) at [index " << index << "] = (" << x << ", " << y << ")\n";
}


void assign_color_to_pixel(
    int rgbarr[], int x, int y, int r, int g, int b,
    int width) // necessary to pass in widt along with (x, y)
{
    size_t index = rgb * width * y + rgb * x;
    rgbarr[index + 0] = r;
    rgbarr[index + 1] = g;
    rgbarr[index + 2] = b;
}

int main()
{    
    const int width = 3;
    const int height = 2;
    const int size = rgb * width * height;
    int rgbarr[size]; // Dynamically allocate if size not known at compile-time
    
    for (int i = 0; i < size; i += rgb)
    {
        std::cout << i << "/" << size << std::endl;
        
        rgbarr[i+0] =     i+1     % 256; // RED
        rgbarr[i+1] = ((i+1) / 2) % 256; // BLUE
        rgbarr[i+2] = ((i+1) * 2) % 256; // GREEN
    }
    
    // INDEX & PIXEL VALUES GIVEN (X, Y) PAIR
    int x = 2; // 3rd column
    int y = 1; // 2nd row
    print_pixel(x, y, width, rgbarr);
    print_pixel(x-1, y-1, width, rgbarr);
    
    std::cout << '\n';
    
    // (X, Y) PAIR GIVEN INDEX
    print_x_y(rgb * 4,     width); // 5th pixel, red component
    print_x_y(rgb * 4 + 1, width); // 5th pixel, green component (same pixel)
    print_x_y(rgb * 5 + 2, width); // 6th pixel, blue component (different pixel)
    
    
    // example
    assign_color_to_pixel(
        rgbarr,       // array
        x, y,         // (X, Y) coordinate
        200, 100, 50, // (R G B) value
        width // necessary information
    );
}

0/18
3/18
6/18
9/18
12/18
15/18
Pixel (2, 1) [starting index 15] value = RGB(16, 8, 32)
Pixel (1, 0) [starting index 3] value = RGB(4, 2, 8)

Pixel (X, Y) at [index 12] = (1, 1)
Pixel (X, Y) at [index 13] = (1, 1)
Pixel (X, Y) at [index 17] = (2, 1)




image [width = 3, height = 2, format = (RGB, RGB, RGB, RGB, RGB, ...) ]
+-----------------------------------------------+
|                                               |
| +---+---+--+   +--+----+---+   +---+---+--+   |
| | 0 | 1 |2 |   |3 | 4  | 5 |   | 6 | 7 | 8|   |
| +---+---+--+   +--+----+---+   +---+---+--+   |
|                                               |
|                                               |
|  +--+---+--+   +---+----+--+   +---+---+---+  |
|  | 9|10 |11|   |12 | 13 |14|   |15 |16 |17 |  |
|  +--+---+--+   +---+----+--+   +---+---+---+  |
|                                               |
|                                               |
+-----------------------------------------------+

Last edited on
Thanks Ganado, that an awesome code example. I can't wait to have play with that code. :-)
Unreal Engine doesn't work the same way as opengl or any similar API, just look at a tutorial that does something like spinning a cube in UnrealEngine C++ and you will see that work is also being done outside of C++, and this includes the loading of the images. You shouldn't really be loading images from raw pixels, since that is what makes unreal engine easy to use.

Everything that everyone in this thread suggested is related to low level pixel manipulation, which you won't do very much in unreal engine, unless you are an expert and using the really low level UE API, which I doubt you want to go through the trouble for making a game.

But don't take my word for it, I don't know anything about UE, just like everyone else in this thread.

I feel like you aren't explaining what you want very well, and that you should take what you posted here, and post it in this thread you made at UE forums, because I guarantee you, not a single soul here knows anything about unreal engine, even stack overflow is better than this place, since it has a category just for UE.

https://forums.unrealengine.com/development-discussion/c-gameplay-programming/1576572-array-of-structs-with-arrays-in-them
I agree with poteto, despite our efforts I'm still not exactly sure what Jclow actually needs :)
Judging by the link poteto posted, it sounds like UE-specific code is needed, which I do not know about. But if you aren't looking for UE-specific code, then maybe try explaining what format a "1D array inside a struct" needs to look like.
I was hoping that, even though there is UE specific code involved ultimately in the end, I would be able to translate any C++ code/principles here into UE specific code, without confusing anyone on here by getting bogged down in anything UE specific. I only mentioned UE because I felt I needed to explain why I couldn't use 2D/3D arrays like the one in my example code because of the limits of the engine.

I looks like someone has given a specific UE code example on the link to my post on the unreal engine forums which will do what I need.

I am very grateful for the time you have taken to respond to my question and for the code examples because I want to learn cpp, not just UE4 specific code, so what has been posted here will be invaluable to me learning about how to use arrays.

Thanks, again, for your time and support. It is very much appreciated :)
Topic archived. No new replies allowed.