Method for dividing an image into tiles
-
- Posts: 17
- Joined: Wed Dec 22, 2021 2:30 am
Method for dividing an image into tiles
Hi guys!
I have an image with 3840x2160 resolution from which I want to make sequencial square images of 20x20 and store them in an array of ITextures to use as texture maps on IMeshSceneNode's.
What's the best method to achieve this?
Thx in advance!
I have an image with 3840x2160 resolution from which I want to make sequencial square images of 20x20 and store them in an array of ITextures to use as texture maps on IMeshSceneNode's.
What's the best method to achieve this?
Thx in advance!
Re: Method for dividing an image into tiles
Can you describe a bit more what your target for this is? Because how to approach this depends somewhat on what exactly you try use it for.
The simplest case would be to call getTexture for the full image. Then call createImage (ITexture *texture, const core::position2d< s32 > &pos, const
core::dimension2d< u32 > &size) a few times to make tile images. Then addTexture for those tile-images (and then delete the IImages as you don't need them anymore). Which might already be enough for your case. But you end up having lots of tiny textures which depending on the use-case can lead to a speed problem (lots of textures-switches are expensive, but maybe it's still fast enough for your case).
Another solution can be to use the big image instead and modify the uv-coordinates in your mesh to access image parts. But that works mostly well if you have one (or few) meshes as it needs a mesh-copy for each mesh doing that.
Also if you then add stuff like scrolling/roation as well then this calculation can start to become rather complicated. Because once you need rotation you can no longer just change the uv-coordiantes but you have to calculate the vertex positions as well (aka create meshes on the fly). You can still rote the whole node though which might be enough (for example if it's about a 2d shooter).
But I guess that's basically the 3 options:
a) Create lots of tiny textures. Some risk of runtime-cost. (edit: Obviously you could also split them outside of Irrlicht before even loading)
b) Modify uv-coordinates. Might simply not be flexible enough. Some risk of texture-bleeding (so tiles should be multiples of 2 if you also need mipmaps)
c) Create vertices on the fly with correct uv's and positions. Which can be mathematically a bit tricky. Also still risk of texture-bleeding.
The simplest case would be to call getTexture for the full image. Then call createImage (ITexture *texture, const core::position2d< s32 > &pos, const
core::dimension2d< u32 > &size) a few times to make tile images. Then addTexture for those tile-images (and then delete the IImages as you don't need them anymore). Which might already be enough for your case. But you end up having lots of tiny textures which depending on the use-case can lead to a speed problem (lots of textures-switches are expensive, but maybe it's still fast enough for your case).
Another solution can be to use the big image instead and modify the uv-coordinates in your mesh to access image parts. But that works mostly well if you have one (or few) meshes as it needs a mesh-copy for each mesh doing that.
Also if you then add stuff like scrolling/roation as well then this calculation can start to become rather complicated. Because once you need rotation you can no longer just change the uv-coordiantes but you have to calculate the vertex positions as well (aka create meshes on the fly). You can still rote the whole node though which might be enough (for example if it's about a 2d shooter).
But I guess that's basically the 3 options:
a) Create lots of tiny textures. Some risk of runtime-cost. (edit: Obviously you could also split them outside of Irrlicht before even loading)
b) Modify uv-coordinates. Might simply not be flexible enough. Some risk of texture-bleeding (so tiles should be multiples of 2 if you also need mipmaps)
c) Create vertices on the fly with correct uv's and positions. Which can be mathematically a bit tricky. Also still risk of texture-bleeding.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
-
- Posts: 17
- Joined: Wed Dec 22, 2021 2:30 am
Re: Method for dividing an image into tiles
Thank you man!
Speed is not an issue as this is to make still rendered images.
I was using "m_pSourceImage->copyTo" method I took from some snippet here in this forum but I think I was over complicating things
I was making it like this:
void CGameCanvas::MakeImages()
{
int a = 0;
int step = IMAGE_WIDTH / NUMBER_X;
int max_x = IMAGE_WIDTH / step;
int max_y = IMAGE_HEIGHT / step;
const dimension2d<u32> dim(40, 40);
IImage* i = gm->getDriver()->createImage(m_pSourceTexture->getColorFormat(), dim);
ITexture* t = 0;
for (int x = 0; x < max_x; x++)
{
for (int y = 0; y < max_y; y++)
{
a++;
m_pSourceImage->copyTo(i, vector2di(x * step, y * step), recti(x * step, y * step, step, step));
m_aImages.push_back(i);
t = gm->getDriver()->addTexture("justaname.jpg", i);
m_aTextures.push_back(t);
}
}
}
I'm going to try as you mention it on first option. That might just be what I really need.
Speed is not an issue as this is to make still rendered images.
I was using "m_pSourceImage->copyTo" method I took from some snippet here in this forum but I think I was over complicating things
I was making it like this:
void CGameCanvas::MakeImages()
{
int a = 0;
int step = IMAGE_WIDTH / NUMBER_X;
int max_x = IMAGE_WIDTH / step;
int max_y = IMAGE_HEIGHT / step;
const dimension2d<u32> dim(40, 40);
IImage* i = gm->getDriver()->createImage(m_pSourceTexture->getColorFormat(), dim);
ITexture* t = 0;
for (int x = 0; x < max_x; x++)
{
for (int y = 0; y < max_y; y++)
{
a++;
m_pSourceImage->copyTo(i, vector2di(x * step, y * step), recti(x * step, y * step, step, step));
m_aImages.push_back(i);
t = gm->getDriver()->addTexture("justaname.jpg", i);
m_aTextures.push_back(t);
}
}
}
I'm going to try as you mention it on first option. That might just be what I really need.
Re: Method for dividing an image into tiles
Right, copyTo should also work. And is actually faster than calling createImage each time. I just forgot we have that as well. The loop is kinda the same.
Although I'm a bit confused in this code about the step thing and then using another value for dim. Because if step is not the same as dim then the target either only has part of what you copied (when step is larger) or it has uninitialed borders (when step is smaller).
Also recti seems to be calculated wrong. Author probably assumed the 4 values are (x,y,width, height) but the construction is instead (x1,y1,x2,y2). And the 'a' variable doesn't seem to be used at all - thought probably was meant to be added to filename to get a new one each time.
edit: Another bug in that code is the position value in copyTo should always be (0,0) (you want to copy to the left-top position of the target image). Otherwise it copies outside the target.
Although I'm a bit confused in this code about the step thing and then using another value for dim. Because if step is not the same as dim then the target either only has part of what you copied (when step is larger) or it has uninitialed borders (when step is smaller).
Also recti seems to be calculated wrong. Author probably assumed the 4 values are (x,y,width, height) but the construction is instead (x1,y1,x2,y2). And the 'a' variable doesn't seem to be used at all - thought probably was meant to be added to filename to get a new one each time.
edit: Another bug in that code is the position value in copyTo should always be (0,0) (you want to copy to the left-top position of the target image). Otherwise it copies outside the target.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
-
- Posts: 17
- Joined: Wed Dec 22, 2021 2:30 am
Re: Method for dividing an image into tiles
I've tried your method and it works perfectly. and yes the code was confusing because I omitted some stuff eheh
now:
void CGameCanvas::MakeImages()
{
int step = IMAGE_WIDTH / NUMBER_X;
int max_x = IMAGE_WIDTH / step;
int max_y = IMAGE_HEIGHT / step;
const dimension2d<u32> dim(step,step);
ITexture* t = 0;
for (int x = 0; x < max_x; x++)
{
for (int y = 0; y < max_y; y++)
{
IImage* i = gm->getDriver()->createImage(m_pSourceTexture, vector2di(x * step, y * step), dim);
t = gm->getDriver()->addTexture("justaname.jpg", i);
m_aTextures.push_back(t);
i->drop();
}
}
}
now I want to shuffle the array of ITextures m_aTextures...instead of opening a new thread maybe you could tell me here what could be the easiest way to do it??
Thanks in advance.
now:
void CGameCanvas::MakeImages()
{
int step = IMAGE_WIDTH / NUMBER_X;
int max_x = IMAGE_WIDTH / step;
int max_y = IMAGE_HEIGHT / step;
const dimension2d<u32> dim(step,step);
ITexture* t = 0;
for (int x = 0; x < max_x; x++)
{
for (int y = 0; y < max_y; y++)
{
IImage* i = gm->getDriver()->createImage(m_pSourceTexture, vector2di(x * step, y * step), dim);
t = gm->getDriver()->addTexture("justaname.jpg", i);
m_aTextures.push_back(t);
i->drop();
}
}
}
now I want to shuffle the array of ITextures m_aTextures...instead of opening a new thread maybe you could tell me here what could be the easiest way to do it??
Thanks in advance.
Re: Method for dividing an image into tiles
Big loop. Inside the loop swap 2 random textures in your array. The bigger the loop the more random the result ;-)
There's better algorithms I suppose...
One other option for example is using a second array. Then loop over first one and pull randomly one texture from it - aka place it in the second array and reset it to 0 in the first array. When you hit an empty spot while pulling (texture already reset to 0) then just loop until you find a non-zero one (be careful you have to wrap around the index).
Or instead of setting to 0 you can erase the element from the first array.
But better don't ask about simple problems like this one before you tried coding them yourself for a bit. Because thinking about those are just the way you learn coding. And you're not going to have much fun if someone else keeps telling you the result directly. And I'll just slow down your learning instead of really helping :-( So - no wories about asking - but always try to figure it out yourself first.
There's better algorithms I suppose...
One other option for example is using a second array. Then loop over first one and pull randomly one texture from it - aka place it in the second array and reset it to 0 in the first array. When you hit an empty spot while pulling (texture already reset to 0) then just loop until you find a non-zero one (be careful you have to wrap around the index).
Or instead of setting to 0 you can erase the element from the first array.
But better don't ask about simple problems like this one before you tried coding them yourself for a bit. Because thinking about those are just the way you learn coding. And you're not going to have much fun if someone else keeps telling you the result directly. And I'll just slow down your learning instead of really helping :-( So - no wories about asking - but always try to figure it out yourself first.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
-
- Posts: 17
- Joined: Wed Dec 22, 2021 2:30 am
Re: Method for dividing an image into tiles
top! yes I was thinking along those lines...been searching a bit...something like the fischer something method...but yes those two arrays i like! didnt tried yet..only in my head...and yes I also thought about pulling random and then delete...but I stuck there...I mean what if the random index number trys to pull a non-existant index??
well like you say better try in the laptop then I come here coz for sure I will ahah
well like you say better try in the laptop then I come here coz for sure I will ahah
Re: Method for dividing an image into tiles
You can easily limit random numbers by using modulo (if you don't know about it, it's the % operator and it gives you the rest left over after a division, or in other words it will wrap around back to 0 every time it reaches a given number. For example any integer % 10 will be between 0-9. Like 11%10 is 1, same as 21%10 or 1001%10).
So to stay inside the array you can do something like: myArray[rand() % myArray.size()];
So to stay inside the array you can do something like: myArray[rand() % myArray.size()];
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
-
- Posts: 17
- Joined: Wed Dec 22, 2021 2:30 am
Re: Method for dividing an image into tiles
bro you are the man!! thank you so much. yes i've crossed path a few times with the "%" but never quite understood it well.
-
- Posts: 17
- Joined: Wed Dec 22, 2021 2:30 am
Re: Method for dividing an image into tiles
ok I've tried something like this...which almost sure is NOT the right way to do it:
void CGameCanvas::SwapArrays()
{
for (int i = 0; i < NUMBER_INDEXES; i++)
{
int n = (int)RandInRange(0, NUMBER_INDEXES);
cout << i << " swap with " << n << endl;
do
{
m_aTexturesSwap.push_back(m_aTextures[n]);
m_aTextures[n] = 0;
}
while (m_aTextures[n] != 0);
}
cout << "size arrayswap:" << m_aTexturesSwap.size() << endl;
}
cout prints swaps and the correct swaparray size which should be equal to array and is 1296 (NUMBER_INDEXES)>>> (1920/40)*(1080/40) but when I render some nodes are without texture...
void CGameCanvas::SwapArrays()
{
for (int i = 0; i < NUMBER_INDEXES; i++)
{
int n = (int)RandInRange(0, NUMBER_INDEXES);
cout << i << " swap with " << n << endl;
do
{
m_aTexturesSwap.push_back(m_aTextures[n]);
m_aTextures[n] = 0;
}
while (m_aTextures[n] != 0);
}
cout << "size arrayswap:" << m_aTexturesSwap.size() << endl;
}
cout prints swaps and the correct swaparray size which should be equal to array and is 1296 (NUMBER_INDEXES)>>> (1920/40)*(1080/40) but when I render some nodes are without texture...
Re: Method for dividing an image into tiles
Yeah, that while loops does nothing (well the 'do' part at least ensures you run through it once). It will always be false after the code you run before, so never gonna loop.
And you don't actually do anything to prevent copying empty array elements.
So yeah - you have to think a bit more about what you are copying.
And totally unrelated to the bugs, but maybe call the function something like shuffle - it doesn't swap. Swap is when you exchange 2 elements without changing them. So like you got variable a and b. Then swap is something like:
Which results in a and b having swapped their content.
And lastly a hint for the forum - you can use a code flag in here to have your code look a bit more like code (what I did above).
And you don't actually do anything to prevent copying empty array elements.
So yeah - you have to think a bit more about what you are copying.
And totally unrelated to the bugs, but maybe call the function something like shuffle - it doesn't swap. Swap is when you exchange 2 elements without changing them. So like you got variable a and b. Then swap is something like:
Code: Select all
c=a; a=b; b=c;
And lastly a hint for the forum - you can use a code flag in here to have your code look a bit more like code (what I did above).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
-
- Posts: 17
- Joined: Wed Dec 22, 2021 2:30 am
Re: Method for dividing an image into tiles
thank you man. I just used the std::vector and random_shuffle and it seems to be fullfilling my needs for now. BUT I will try to finish this swap arrays method just for the sake of learning more
Re: Method for dividing an image into tiles
STL has a shuffle algorithm build in? Nice :-)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm