FEZTouch / FillRectangle Problem

Hello,

I think I just found a small problem with the FillRectangle() method provided with FEZ_Components_FEZTouch.cs.

In the code, after you’ve looped though writing full buffers of data, the following code is present:

                int pixelsLeft = pixelCount % bufferPixels;
                if (pixelsLeft > 0)
                {
                    // first half
                    pp.Write(buffer, 0, pixelsLeft);
                    // second half
                    pp.Write(buffer, 0, pixelsLeft);
                }

I’ve run into a problem when pixelsLeft is odd. The ‘first half’ write works correctly, but writes an extra byte. Then the ‘second half’ write gets messed up (off by one, because of the earlier leftover byte). So, the rectangle gets a strange color for the last bytes.

Unless I’m missing something, a simple fix seems to be to replace the two writes with a single write, like this:

               int pixelsLeft = pixelCount % bufferPixels;
                if (pixelsLeft > 0)
                {
                    pp.Write(buffer, 0, (pixelsLeft * 2));
                }

It seems to work like I would expect. But let me know if that doesn’t make sense.

Thanks,
Paul

What changes are you making on the original code?
I think pixelsLeft will always be 0 by default.
Also, why would it be odd? pixelCount is width*height so it is never odd
Where would the extra byte come from?

I haven’t made any changes to the original code.

pixelsLeft will be whatever is left over that wasn’t sent as part of a full buffer (1024 bytes).

If pixelCount is width*height, pixelCount can be odd any time the product is odd (17x17 for example):

This code shows the problem:


// Color drawing canvas using touch events
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;

namespace FEZ_Touch_Example
{
    public class Program
    {
        static FEZ_Components.FEZTouch lcd;

        public static void Main()
        {
            // This is for FEZ Panda II
            FEZ_Components.FEZTouch.LCDConfiguration lcdConfig = new FEZ_Components.FEZTouch.LCDConfiguration(
                FEZ_Pin.Digital.Di28,
                FEZ_Pin.Digital.Di20,
                FEZ_Pin.Digital.Di22,
                FEZ_Pin.Digital.Di23,
                new FEZ_Pin.Digital[8] { FEZ_Pin.Digital.Di51, FEZ_Pin.Digital.Di50, FEZ_Pin.Digital.Di49, FEZ_Pin.Digital.Di48, FEZ_Pin.Digital.Di47, FEZ_Pin.Digital.Di46, FEZ_Pin.Digital.Di45, FEZ_Pin.Digital.Di44 },
                FEZ_Pin.Digital.Di24,
                FEZ_Pin.Digital.Di26

                );

            FEZ_Components.FEZTouch.TouchConfiguration touchConfig = new FEZ_Components.FEZTouch.TouchConfiguration(
                SPI.SPI_module.SPI2, FEZ_Pin.Digital.Di25, FEZ_Pin.Digital.Di34
                );

            lcd = new FEZ_Components.FEZTouch(lcdConfig, touchConfig);

            lcd.FillRectangle(0, 0, FEZ_Components.FEZTouch.ScreenWidth, FEZ_Components.FEZTouch.ScreenHeight, FEZ_Components.FEZTouch.Color.Black);

            lcd.FillRectangle(1, 2, 17, 17, FEZ_Components.FEZTouch.Color.Green);

            Thread.Sleep(Timeout.Infinite);
        }

    }
}

Mike,

I’ve seen this too; I actually changed the code for Spiral with code similar to Peddy’s.

Yes, thank you for reporting this issue. I was thinking about filling the entire screen for some reason. The code will be updated asap.

Can we also add dynamic touch calibration as well? :slight_smile: super mike!

@ Mike

Can you also add the circular functions?
I have attached code added in the driver FEZ_Components_FEZTouch.cs.


            public void SetPixelInt(int x, int y)
            {
                SetDrawingWindow(x, y, 1, 1);
                SetRegister(REGISTER_WRITE_GRAM);
                pp.Write(buffer, 0, 2); 
            }

            public void Circle(int xp, int yp, int radius, Color col)
            {
                xp += radius;
                yp += radius;
                if ((xp - radius) < 0 || (yp - radius) < 0 || (xp + radius) > ScreenWidth || (yp + radius) > ScreenHeight)
                    throw new ArgumentException();

                int x = 0;
                int y = radius;
                int p = -radius;

                lcdCS.Write(false);
                buffer[0] = (byte)((int)col >> 8);
                buffer[1] = (byte)(col);

                while (x <= y)
                {
                    SetPixelInt(xp + x, yp + y);
                    SetPixelInt(xp - x, yp + y);
                    SetPixelInt(xp - x, yp - y);
                    SetPixelInt(xp + x, yp - y);
                    SetPixelInt(xp + y, yp + x);
                    SetPixelInt(xp - y, yp + x);
                    SetPixelInt(xp - y, yp - x);
                    SetPixelInt(xp + y, yp - x);
                    if ((p += x++ + x) >= 0)
                    {
                        p -= --y + y;
                    }
                }
                lcdCS.Write(true);
            }

            public void FillCircle(int xp, int yp, int radius, Color col)
            {
                xp += radius;
                yp += radius;
                if ((xp - radius) < 0 || (yp - radius) < 0 || (xp + radius) > ScreenWidth || (yp + radius) > ScreenHeight)
                    throw new ArgumentException();

                int x = 0;
                int y = radius;
                int p = -radius;
                int i;

                lcdCS.Write(false);
                buffer[0] = (byte)((int)col >> 8);
                buffer[1] = (byte)(col);

                while (x <= y)
                {
                    for (i = xp - x; i <= xp + x; i++) { SetPixelInt(i, yp + y); }
                    for (i = xp - x; i <= xp + x; i++) { SetPixelInt(i, yp - y); }
                    for (i = xp - y; i <= xp + y; i++) { SetPixelInt(i, yp + x); }
                    for (i = xp - y; i <= xp + y; i++) { SetPixelInt(i, yp - x); }
                    if ((p += x++ + x) >= 0)
                    {
                        p -= --y + y;
                    }
                }
                lcdCS.Write(true);
            }

The code works well, but need to be adjusted for better speed.

Thanks Hinnie. We will look into it. I am not sure far we can optimize the code. It might have to be done in RLP to make this fast.

I say this would be a whole a lot faster in RLP.

Has anyone looked into how much faster some of the drawing methods in the FEZTouch class would run using RLP?

I have it on my list of things to look into, but would hate to start if anyone is close to posting their own solution (lots of other things on my to-do list!)

What are you looking for to improve? FillRectangle and other basic drawing methods are fast enough now I think…

The FillCircle function is slow

The basic drawing methods aren’t bad if you don’t do too many of them, or too often. However, if you want to create more dynamic/complex displays, improved drawing speed would be very useful. I noticed that many of the controls I created in the FEZTouch UI Controls library [url]http://code.tinyclr.com/project/328/fez-touch-ui-controls/[/url] were sluggish, or in some cases, unusable. You can see examples in the video I attached to the submission.

I don’t know how much improvement you’d see if the methods could be implemented using RLP, which is why I was curious about it.

FillCircle can be done w/ FillRects :wink: That’s how Spiral does it.

@ Peddy none as far as I’ve seen. I originally wrote all the methods in RLP but found their Managed counterparts to be faster because of the invoke overhead. Only exception is Alpha-blended stuff.

@ Skewworks - Can you give more explanation of what you mean by the “invoke overhead”? At what level did you try to use RLP? For example, did you try writing the entire FillRectangle() functionality in RLP? Or did you use RLP for the “lower level” methods (WriteRegister(), for example)?

It seems like there would only be a single invoke if the entire FillRectangle() was implemented in RLP. Or maybe I’m not understanding how it all works. ???

I did the entire method in RLP basically duplicated the Managed code in RLP. I posted the exact results in another thread somewhere.

Yes I was thinking about using FillRectangles. So I am not sure how soon this can be added it to the official driver because we have to try several things.

The driver is well optimized. The bulk part is in ParallelPort which is done natively. It writes many pixels at once (with one invoke).
It should be faster in RLP but I think it would be just small improvements…
On the other hand, FillCircle with writing each pixel separately, means hundreds of invokes from C#. Almost all the time is spent in C# so it will be very slow.