2024-02-28 04:07 PM
Hi,
after reviewing answers to following post
https://community.st.com/t5/stm32-mcus-touchgfx-and-gui/how-to-draw-pixel-line-or-rectangle/td-p/105737
and as a TouchGFX newby, I'm wondering: how one expects to do a following task by using TouchGFX's:
there are two images and some fading effect needs to be done: pseudo-random pixels from one hidden in-memory image A being moved to corresponding pixels of currently displayed image B, replacing them one by one, eventually making all pixels of image A equal to pixels of image B.
Does it need to be addressed in TouchFGX by creating single-pixel "Line" widget objects for each pixel? Seems like extremely inefficient... Are there any other options to do so?
Thanks
Solved! Go to Solution.
2024-03-04 06:53 AM
Hello @bear2023R ,
If your images take up a whole screen you can just use the block transition which does basically what you want but with bigger blocks than just a single pixel.
Another solution would be to use a dynamic bitmap and copy each pixel value individually (but it takes long to read from external ram).
The solution I went for is to set the second image visible on top of the first image and then invalidating each pixel individually. (It was taking too long so I added a RECTANGLESIZE define to invalidate multiple pixels at once.)
To be able to access each pixel and delete them once I already invalidated them I use a map that is declared globally :
std::map<int, int> pixels;
Then I initialize it :
void Screen1View::setupScreen()
{
for(int i = 0; i<WIDTH*HEIGHT/RECTANGLESIZE/RECTANGLESIZE; i++) pixels[i] = i;
pixelToInvalidate.height = RECTANGLESIZE;
pixelToInvalidate.width = RECTANGLESIZE;
}
Finally, I update one pixel (or one rectangle to be faster) each tick (60 ticks per second) in the handle tick event function :
void Screen1View::handleTickEvent()
{
//Set the image visible after the first frame
if(false == imageKitten.isVisible())
{
imageKitten.setVisible(true);
touchgfx_printf("\nImage set visible\nStarting transition");
if (HAL::USE_DOUBLE_BUFFERING) Application::getInstance()->copyInvalidatedAreasFromTFTToClientBuffer(); // Synchronize framebuffers if using double framebuffer
}
if(pixels.size() > 0) //Running transition
{
auto random_it = std::next(std::begin(pixels), rand()%pixels.size()); //Get random pixel from the ones available
pixelToInvalidate.x = (random_it->second)%(WIDTH/RECTANGLESIZE)*RECTANGLESIZE; //Translate pixel number to x position
pixelToInvalidate.y = (random_it->second)/(WIDTH/RECTANGLESIZE)*RECTANGLESIZE; //Translate pixel number to y position
imageKitten.invalidateRect(pixelToInvalidate); //Invalidate pixel
pixels.erase(random_it->first); //Remove invalidated pixel from list of pixels
touchgfx_printf("Remaining pixels : %05d\n", pixels.size());
}
else if(!transitionFinished)
{
touchgfx_printf("Transition finished.\n");
transitionFinished = true;
}
}
Note that if you want true random behavior you should set a seed.
Please find attached a working project running on the simulator (I also tested on a board).
If this post answers your question, make sure to set it as "Best answer" so I can close the ticket.
Regards,
2024-03-04 06:53 AM
Hello @bear2023R ,
If your images take up a whole screen you can just use the block transition which does basically what you want but with bigger blocks than just a single pixel.
Another solution would be to use a dynamic bitmap and copy each pixel value individually (but it takes long to read from external ram).
The solution I went for is to set the second image visible on top of the first image and then invalidating each pixel individually. (It was taking too long so I added a RECTANGLESIZE define to invalidate multiple pixels at once.)
To be able to access each pixel and delete them once I already invalidated them I use a map that is declared globally :
std::map<int, int> pixels;
Then I initialize it :
void Screen1View::setupScreen()
{
for(int i = 0; i<WIDTH*HEIGHT/RECTANGLESIZE/RECTANGLESIZE; i++) pixels[i] = i;
pixelToInvalidate.height = RECTANGLESIZE;
pixelToInvalidate.width = RECTANGLESIZE;
}
Finally, I update one pixel (or one rectangle to be faster) each tick (60 ticks per second) in the handle tick event function :
void Screen1View::handleTickEvent()
{
//Set the image visible after the first frame
if(false == imageKitten.isVisible())
{
imageKitten.setVisible(true);
touchgfx_printf("\nImage set visible\nStarting transition");
if (HAL::USE_DOUBLE_BUFFERING) Application::getInstance()->copyInvalidatedAreasFromTFTToClientBuffer(); // Synchronize framebuffers if using double framebuffer
}
if(pixels.size() > 0) //Running transition
{
auto random_it = std::next(std::begin(pixels), rand()%pixels.size()); //Get random pixel from the ones available
pixelToInvalidate.x = (random_it->second)%(WIDTH/RECTANGLESIZE)*RECTANGLESIZE; //Translate pixel number to x position
pixelToInvalidate.y = (random_it->second)/(WIDTH/RECTANGLESIZE)*RECTANGLESIZE; //Translate pixel number to y position
imageKitten.invalidateRect(pixelToInvalidate); //Invalidate pixel
pixels.erase(random_it->first); //Remove invalidated pixel from list of pixels
touchgfx_printf("Remaining pixels : %05d\n", pixels.size());
}
else if(!transitionFinished)
{
touchgfx_printf("Transition finished.\n");
transitionFinished = true;
}
}
Note that if you want true random behavior you should set a seed.
Please find attached a working project running on the simulator (I also tested on a board).
If this post answers your question, make sure to set it as "Best answer" so I can close the ticket.
Regards,
2024-03-14 07:56 AM
Hello @bear2023R ,
Was my answer helpful?
Were you able to solve your problem?
Regards,
2024-03-26 11:20 AM - edited 2024-03-26 11:21 AM
THanks Gaetan
sorry for late reply - was on vacation.
I'll try your solution yet it looks reasonable anyway, at first glance. Thanks!
2024-03-27 04:22 AM
Hello @bear2023R ,
No problem, hope you had good holidays.
I will keep this post open for a week or two. If you need more help within this timeline, comment the post, after that I will close it.
Regards,