cancel
Showing results for 
Search instead for 
Did you mean: 

what is the difference getAnimationStorage vs lockFrameBuffer, working with dynamic bitmaps

rBlr
Associate III

I'm looking for right way to draw simple shapes (like lines, circles, rectangles, Bezier curves, etc - just simple editor like oldschool Windows Paint) and studying how to implement this correctly.

I'm believe I should use some kind of canvas (Container or something else?) to draw my geometric objects. Looking at samples and documentations, I have found two methods for adding graphical points to canvas.

1. getAnimationStorage()

 

 

 

void MainView::setupRings()
{
    //draw a couple of random colorful rings in the pixel buffer
    int red = (int)random(0, 1000);
    int green = (int)random(0, 1000);
    int blue = (int)random(0, 1000);

    int rings = (int)random(0, 10) + 4;

    uint8_t* pixelBuffer = (uint8_t*)HAL::getInstance()->getAnimationStorage();
    uint32_t offset = 0;

    for (int y = 0; y < size; y++)
    {
        for (int x = 0; x < size; x++, offset += 4)
        {
            int dx = x - size / 2;
            int dy = y - size / 2;

            float dist = sqrtf((float)dx * dx + dy * dy);

            uint8_t alpha = 0;
            if (dist < size / 2)
            {
                alpha = (uint8_t)(cosf(dist / (size / 2) * rings * 2 * 3.14159f + 3.14159f) * 127 + 128);
            }

            // Due to endianness, ARGB8888 bytes are written backwards
            pixelBuffer[offset + 0] = (uint8_t)(sinf(dist * 2 * (rings + 10) / size + blue) * 127 + 128);
            pixelBuffer[offset + 1] = (uint8_t)(sinf(dist * 2 * (rings + 10) / size + green) * 127 + 128);
            pixelBuffer[offset + 2] = (uint8_t)(sinf(dist * 2 * (rings + 10) / size + red) * 127 + 128);
            pixelBuffer[offset + 3] = alpha;
        }
    }
}

 

 

 

 

one could look to full source code by creating Pixel Data Example in TouchGFX examples generator

 

2. lockFrameBuffer()

 

 

 

 

void QRCodeWidget::draw(const touchgfx::Rect& invalidatedArea) const
{
    if (!data)
    {
        return;
    }

    touchgfx::Rect absolute = getAbsoluteRect();

    uint16_t* framebuffer = touchgfx::HAL::getInstance()->lockFrameBuffer();

    for (int y = invalidatedArea.y; y < invalidatedArea.bottom(); y++)
    {
        for (int x = invalidatedArea.x; x < invalidatedArea.right(); x++)
        {
            framebuffer[absolute.x + x + (absolute.y + y) * touchgfx::HAL::FRAME_BUFFER_WIDTH] =
              data->at(x / scale, y / scale) ? 0x0000 : 0xffff;
        }
    }

    touchgfx::HAL::getInstance()->unlockFrameBuffer();
}

 

 

 

 

this is part from Custom Widget documentation.

In 1st case just used `getAnimationStorage` without any kind of `unlock` as in 2nd one.

So what is difference between them and what you could recommend to use in simple Painter-like application where user could add, modify, delete sample graphical objects (I use cross-cursor as pointer, user could move it to set location or input length, height, width, etc of shape).

Thank you! 

9 REPLIES 9
JTP1
Lead

Hello

Im not sure can I answer your question about those two methods, but I would also consider to use of Dynamic bitmaps.

Here is simple example how to use those:

https://community.st.com/t5/stm32-mcus-touchgfx-and-gui/asking-for-help-with-drawing-custom-image-from-data-that-is/td-p/635569

And the documentation:

https://support.touchgfx.com/docs/development/ui-development/touchgfx-engine-features/dynamic-bitmaps

Especially if you want to use also other widgets same time in some part of the screen, show some modal selection popups etc it would be much easier since dynamic bitmap is one of the widgets.

Br JTP

 

 

rBlr
Associate III

Interesting proposal, I will try

Should I multiply width, height and working with buffer multiplying everything by 3 in case I have 24 bit display?

Thank you

Hello

Basically yes, in the dynamic bitmap example the color depth is 16bit so so there multiplier is two when calculating size in bytes.

Note also to use 8 bit pointer when manipulating data in the memory. Just write then 3 bytes (rgb) for each pixel. And when using 8 bit pointer, remember to multiply with 3 when converting x and y coordinates to address offset.

Br JTP

rBlr
Associate III

I have tried, but since these all a bit difficult to understand for me, result is not I expect.

Modified code for try 24 bit

void screenView::setupScreen()
{
    screenViewBase::setupScreen();
    imgCursor.setPosition(cursorX, cursorY, cursorL, cursorL);

    bmpId = Bitmap::dynamicBitmapCreate(dynamicBitmapWidth, dynamicBitmapHeight, Bitmap::RGB888);

    // some random color pattern
    uint8_t *cache_ptr;
    uint32_t i;
    uint32_t color;
    color=0; // I'd like to iterate from 0x000000 black to 0xFFFFFF white

    cache_ptr=(uint8_t *)Bitmap::dynamicBitmapGetAddress(bmpId);
    for(i=0;i<dynamicBitmapWidth*dynamicBitmapHeight;i++)
    {

		*cache_ptr=color;
		cache_ptr++;
		*cache_ptr=color;
		cache_ptr++;
		*cache_ptr=color;
		cache_ptr++;

		color++;
   }

    image1.setBitmap(Bitmap(bmpId));
    image1.setXY(20, 20);
    image1.setWidth(dynamicBitmapWidth);
    image1.setHeight(dynamicBitmapHeight);
    image1.invalidate();
}

What the result looks like ? It should be complete mess since the color is overflowing all the time.

If you put something like

If((i%dynamicBitmapHeight)==0)color++;

Instead of increment color with every pixel, you should get colored lines.(start from black, shades of grey).

Br JTP

rBlr
Associate III

As I mentioned in comment, I'd like to obtain some thing like RGB-color picker, from 0x000000 to 0xFFFFFF HTML colors.

Screenshot 2024-02-20 141133.png

so I need to increment by 1 for get next RGB color for each following pixel.

Is I'm right understand that for each position when increment pointer by 1 and 2, I should write same color as without increment? or for each increment I should set different part of color: R, G for increment 1 and B for increment 2?

Is this way is correct (same color for each increment for single pixel at display)? or I should split color to R, G, B for each pixel?

    for(i=0;i<dynamicBitmapWidth*dynamicBitmapHeight;i++)
    {
		*cache_ptr=color;
		cache_ptr++;
		*cache_ptr=color;
		cache_ptr++;
		*cache_ptr=color;
		cache_ptr++;
		color++;
   }

 

Hello

To get this kind of color scale, it needs much more complicated code. This is the way how color components should vary.

JTP1_0-1708448621627.png

This is probably the slowest and dummiest impementation of this color slide, but as an example:

void Screen1View::setupScreen()
{
	uint8_t widthPer6,colStep,phase=0;
	uint8_t *cache_ptr;
	uint32_t i;
	int16_t red=0,green=0,blue=0;
		
    Screen1ViewBase::setupScreen();
	
	// REMOVE const from dynamicBitmapWidth at view.hpp !!
	// color slide works best when 256/(width/6) is integer, so use 96,192,384 as dynamicBitmapWidth !!
	
	// make dynamicBitmapWidth divisible with 6
	dynamicBitmapWidth-=(dynamicBitmapWidth%6);
	
	// to avoid div-by-zero later
	if(dynamicBitmapWidth>=6)
	{
		bmpId = Bitmap::dynamicBitmapCreate(dynamicBitmapWidth, dynamicBitmapHeight, Bitmap::RGB888);
    
		// divide line to 6 areas 
		widthPer6=(dynamicBitmapWidth/6);
		
		// calculate color step
		colStep=(256/widthPer6);
		
		// init pointer to bitmap	
		cache_ptr=(uint8_t *)Bitmap::dynamicBitmapGetAddress(bmpId);
		
		for(i=0;i<(dynamicBitmapWidth*dynamicBitmapHeight);i++)
		{
			// check color stepping boundaries when not in the first pixel
			if(i>0)
			{
				if((i%dynamicBitmapWidth)==0)phase=0;
				else if((i%widthPer6)==0)phase++;
				
			}
			
			// make increments/decrements
			switch(phase)
			{
				case 0:
					red=0xff;
					blue=0;
					green+=colStep;
					if(green>0xff)green=0xff;
				break;
					
				case 1:
					red-=colStep;
					if(red<0)red=0;
					blue=0;
					green=0xff;
				break;
				
				case 2:
					red=0;
					blue+=colStep;
					if(blue>0xff)blue=0xff;
					green=0xff;
				break;
				
				case 3:
					red=0;
					blue=0xff;
					green-=colStep;
					if(green<0)green=0;
				break;

				case 4:
					red+=colStep;
					if(red>0xff)red=0xff;
					blue=0xff;
					green=0;
				break;
				
				case 5:
					red+=0xff;
					blue-=colStep;
					if(blue<0)blue=0;
					green=0;
				break;
			}
			
			// finally draw the pixel
			*cache_ptr=blue;
			cache_ptr++;
			*cache_ptr=green;
			cache_ptr++;
			*cache_ptr=red;
			cache_ptr++;
		}
 	
		//Make Image widget show the dynamic bitmap
		image1.setBitmap(Bitmap(bmpId));

		//Position image and add to View
		image1.setXY(20, 20);
	}
}

This is how it looks then in simulator (width is 384 pixel)

JTP1_1-1708449163121.png

Maybe you can develop yourself the vertical slide 😉

Br JTP

rBlr
Associate III

Wow! Thank you very much!

And I understand right by looking to your code, it is need to split RGB to 3 parts for each 3 positions , by setting blue at 1st, green at 2nd and finally red ad last position?

// finally draw the pixel
*cache_ptr=blue;
cache_ptr++;
*cache_ptr=green;
cache_ptr++;
*cache_ptr=red;
cache_ptr++;

 

GaetanGodart
ST Employee

This conversation have continued on this thread : https://community.st.com/t5/stm32-mcus-touchgfx-and-gui/how-to-drawing-geometric-shapes-on-dynamic-bitmap-suggestions/m-p/646940#M36543

Gaetan Godart
Software engineer at ST (TouchGFX)