Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I am trying to draw a Checkerboard pattern on a LCD using a GUI library called emWin. I have actually managed to draw it using the following code. But having this many loops in the program body for a single task, that too in the internal flash of the microcontroller is not a good idea.
For those who have not worked with emWin, I will try and explain a few things before we go for the actual logic.

  • GUI_REST is a structure which id define source files of emWin and I am blind to it.
  • Rect, Rect2, Rect3.. and so on until Rect10 are objects.
  • Elements of the Rect array are {x0,y0,x1,y1}, where x0,y0 are starting locations of the rectangle in the X-Y plane and x1, y1 are end locations of the Rectangle in the X-Y plane.

So, Rect={0,0,79,79} is a rectangle starts at top left of the LCD and is up to (79,79), so it's a square basically.
The function GUI_setBkColor(int color); sets the color of the background.
The function GUI_setColor(int color); sets the color of the foreground.
GUI_WHITE and DM_CHECKERBOARD_COLOR are two color values, #defineed GUI_FillRectEx(&Rect); will draw the Rectangle.

The code below works fine but I want to make it smarter.

GUI_RECT Rect = {0, 0, 79, 79};  
GUI_RECT Rect2 = {80, 0, 159, 79};  
GUI_RECT Rect3 = {160, 0, 239, 79};  
GUI_RECT Rect4 = {240, 0, 319, 79};  
GUI_RECT Rect5 = {320, 0, 399, 79};  
GUI_RECT Rect6 = {400, 0, 479, 79};  
GUI_RECT Rect7 = {480, 0, 559, 79};  
GUI_RECT Rect8 = {560, 0, 639, 79};    
GUI_RECT Rect9 = {640, 0, 719, 79};  
GUI_RECT Rect10 = {720, 0, 799, 79};  

    WM_SelectWindow(Win_DM_Main);
    GUI_SetBkColor(GUI_BLACK);
    GUI_Clear();

    for(i = 0; i < 6; i++)
    {
        if(i%2 == 0)
            GUI_SetColor(GUI_WHITE);
        else
            GUI_SetColor(DM_CHECKERBOARD_COLOR);

        GUI_FillRectEx(&Rect);

        Rect.y0 += 80;
        Rect.y1 += 80;
    }

    for(i = 0; i < 6; i++)
    {
        if(i%2 == 0)
            GUI_SetColor(DM_CHECKERBOARD_COLOR);    
        else
            GUI_SetColor(GUI_WHITE);

        GUI_FillRectEx(&Rect2);

        Rect2.y0 += 80;
        Rect2.y1 += 80;
    }

    for(i = 0; i < 6; i++)
    {
        if(i%2 == 0)
            GUI_SetColor(GUI_WHITE);
        else
            GUI_SetColor(DM_CHECKERBOARD_COLOR);

        GUI_FillRectEx(&Rect3);

        Rect3.y0 += 80;
        Rect3.y1 += 80;
    }

    for(i = 0; i < 6; i++)
    {
        if(i%2 == 0)
            GUI_SetColor(DM_CHECKERBOARD_COLOR);    
        else
            GUI_SetColor(GUI_WHITE);

        GUI_FillRectEx(&Rect4);

        Rect4.y0 += 80;
        Rect4.y1 += 80;
    }

    for(i = 0; i < 6; i++)
    {
        if(i%2 == 0)
            GUI_SetColor(GUI_WHITE);
        else
            GUI_SetColor(DM_CHECKERBOARD_COLOR);

        GUI_FillRectEx(&Rect5);

        Rect5.y0 += 80;
        Rect5.y1 += 80;
    }

    for(i = 0; i < 6; i++)
    {
        if(i%2 == 0)
            GUI_SetColor(DM_CHECKERBOARD_COLOR);    
        else
            GUI_SetColor(GUI_WHITE);

        GUI_FillRectEx(&Rect6);

        Rect6.y0 += 80;
        Rect6.y1 += 80;
    }

    for(i = 0; i < 6; i++)
    {
        if(i%2 == 0)
            GUI_SetColor(GUI_WHITE);
        else
            GUI_SetColor(DM_CHECKERBOARD_COLOR);

        GUI_FillRectEx(&Rect7);

        Rect7.y0 += 80;
        Rect7.y1 += 80;
    }

    for(i = 0; i < 6; i++)
    {
        if(i%2 == 0)
            GUI_SetColor(DM_CHECKERBOARD_COLOR);    
        else
            GUI_SetColor(GUI_WHITE);

        GUI_FillRectEx(&Rect8);

        Rect8.y0 += 80;
        Rect8.y1 += 80;
    }

    for(i = 0; i < 6; i++)
    {
        if(i%2 == 0)
            GUI_SetColor(GUI_WHITE);
        else
            GUI_SetColor(DM_CHECKERBOARD_COLOR);

        GUI_FillRectEx(&Rect9);

        Rect9.y0 += 80;
        Rect9.y1 += 80;
    }

    for(i = 0; i < 6; i++)
    {
        if(i%2 == 0)
            GUI_SetColor(DM_CHECKERBOARD_COLOR);    
        else
            GUI_SetColor(GUI_WHITE);

        GUI_FillRectEx(&Rect10);

        Rect10.y0 += 80;
        Rect10.y1 += 80;
    }
share|improve this question

migrated from programmers.stackexchange.com Jun 28 at 12:16

4 Answers

C-style pseudo-code:

char cellSize = 50;
int cellX,cellY;
Color cellColor;

for ( char row = 0 ; row < 8 ; row++ )
{
  for ( char col = 0 ; col < 8 ; col++ )
  {
    cellX = col*cellSize
    cellY = row*cellSize;
    cellColor = (row+col)%2 ? COLOR_WHITE : COLOR_BLACK;
    drawRect(cellX,cellY,cellSize,cellSize,cellColor);
  }
}

I believe the algorithm of drawing a checkerboard is that trivial. Draw cell by cell moving from left to right and from bottom to top and choose color basing on whether the sum of row and col is even or odd.

share|improve this answer
Totally agree with with what you said regarding drawing the checkerboard, but here this function GUI_FillRectEx is a library function call, and that I can not change, and I have no other alternative like writing my own function to draw like the one drawRect(cellX,cellY,cellSize,cellSize,cellSize,cellColor); you suggested – WedaPashi Jun 28 at 11:24
I have no other alternative like writing my own function to draw like the one In fact it is a very good practice. You should split your code in functions doing exactly one thing. So extracting the functionality of drawing a rectangle from the function drawing the checker-board is what you should do. – Kolyunya Jun 28 at 11:31
Ok Let me try. Thanks :) – WedaPashi Jun 28 at 11:36
1  
This checkering algorithm is guaranteed to only work in the horizontal case. The checkering pattern will not continue vertically unless there are an odd number of horizontal squares. A better approach to set <cellColor> based on whether the sum of <row> and <col> is even or odd. – Sparky Jun 28 at 12:26
@Sparky true, thank you for a correction. Updated the answer. – Kolyunya Jun 28 at 12:55

It's unlikely that your app's performance concerns are due to the excessive looping. They are all small loops and should rip through pretty quickly, even on an embedded controller. I suspect your expensive call is the GUI_FillRectEx() calls.

That said, there are techniques to clean up your code and make it more maintainable.

  • Look for the duplicated logic.

Notice how you have the same loop structure + code for each of those blocks?

for(i = 0; i < 6; i++)
{
    if(i%2 == 0)
        GUI_SetColor(DM_CHECKERBOARD_COLOR);    
    else
        GUI_SetColor(GUI_WHITE);

While the cost isn't necessarily great in this case, you are repeating it for each of your rectangles.

  • Look for the actions that don't need to occur.

    1. In this case, do you really need to paint both the white and black squares? Could you "cheat" by using a black canvas and only paint the white squares? That would cut your FillRectEx() calls in half.

    2. Do you really need to declare 10 Rect's and increment coordinates on each loop? How about declaring a fixed array ahead of time and pre-populate / hard code all the coordinates?

share|improve this answer
Sir, totally agree with you. The same thing occurred to me as well of drawing alternate white squares on a black background, but the requirements are like, I should have a background color other than the two colors used to draw the checkerboard. – WedaPashi Jun 28 at 11:28
@ GlenH7: I will try and spend some time coding to see if I can manage that with two Rects, each for single color. – WedaPashi Jun 28 at 11:29
@wedapashi having two rectangles will simplify the code but will require more calculations in order to complete the task. You need to decide on which path you want to follow. If execution time is critical, minimize calculations. – GlenH7 Jun 28 at 13:45

Pseudo-code:

GUI_RECT Rect = new int[10][4];
for (int groi = 0; groi < 10; groi++)
{
  Rect[groi] = {groi*80, 0, (groi+1)*80 - 1, 79};
}

WM_SelectWindow(Win_DM_Main);
GUI_SetBkColor(GUI_BLACK);
GUI_Clear();

for(int groi = 0; groi < 10; groi++)
{
  for(i = 0; i < 6; i++)
  {
    if(i%2 == 0)
        GUI_SetColor(GUI_WHITE);
    else
        GUI_SetColor(DM_CHECKERBOARD_COLOR);

    GUI_FillRectEx(&Rect[groi]);

    Rect[groi].y0 += 80;
    Rect[groi].y1 += 80;
  }
}
share|improve this answer
up vote 0 down vote accepted

Got it to work with a single Rect array.

GUI_RECT Rect = {0,0,79,79};  
int i=0,j=0,color_toggle=0;  

for(i = 0 ; i < 10 ; i++)  
{  
   for(j = 0; j < 6 ; j++)  
   {  
      if(color_toggle == 0)  
        GUI_SetColor(GUI_WHITE);  
      else  
        GUI_SetColor(DM_CHECKERBOARD_COLOR);  

      GUI_FillRectEx(&Rect);  
      Rect.y0 += 80;  
      Rect.y1 += 80;  
      color_toggle ^= 1;  
   }  
   Rect.x0 += 80;  
   Rect.x1 += 80;  
   Rect.y0 = 0;
   Rect.y1 = 80;  
   color_toggle ^= 1;    
}  
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.