Hello Everyone, I will be using this thread for my "endeavor" as I explore the possibilities with C Basically making / test functions that may or not be useful and at the same time I will be learning more about C Razz (feel free to join).

I will start with gradients, I have been research for past few days attempting to learn in how gradients are done in other languages (such as JavaScript, python, rust, etc.) I happened to have stubbled upon stack overflow thread with an example in python using pygame.

So, I attempted to port it onto the CE, this is what I got:




Code:
void main(void)
{
   gfx_Begin();
   gfx_FillScreen(0);
   gradientRectangle(1, 1, 10, 10);
   delay(3000);
   gfx_End();
    return;
}

void gradientRectangle(int x, int y, int w, int h)
{
        uint8_t start_color[3] = {0,0,0};
   uint8_t end_color[3] = {255,130,0};
   uint8_t rm, gm, bm; //red, green, blue medium
   
   rm = (start_color[0] + end_color[0]) * w;
   gm = (start_color[1] + end_color[1]) * w;
   bm = (start_color[2] + end_color[2]) * w;
   
   for (int i = 0; i < w + 1; i++){
      gfx_palette[i+1] = gfx_RGBTo1555(start_color[0] + rm*i, start_color[1] + gm*i, start_color[2] + bm*i);
      gfx_SetColor(i+1);
      gfx_VertLine(x + i, y, h);
   }
   return;
}


"The code is very limited and could be approved upon"

I attempted to increase the size of the rectangle and was met with an error:




Code:
void main(void)
{
   gfx_Begin();
   gfx_FillScreen(0);
   gradientRectangle(1, 1, 50, 50);
   delay(3000);
   gfx_End();
    return;
}

void gradientRectangle(int x, int y, int w, int h)
{
   uint8_t start_color[3] = {0,0,0};
   uint8_t end_color[3] = {255,130,0};
   uint8_t rm, gm, bm; //red, green, blue medium
   
   rm = (end_color[0] - start_color[0]) * w;
   gm = (end_color[1] - start_color[1]) * w;
   bm = (end_color[2] - start_color[2]) * w;
   
   for (int i = 0; i < w + 1; i++){
      gfx_palette[i+1] = gfx_RGBTo1555(start_color[0] + rm*i, start_color[1] + gm*i, start_color[2] + bm*i);
      gfx_SetColor(i+1);
      gfx_VertLine(x + i, y, h);
   }
   return;
}


How could I fix it and how could you improve upon the code?
Thank you, commandz.
Quote:
3:45:04 AM [#] [#] [commandz] so maybe see if that works
3:44:53 AM [#] [#] [commandz] I think the issue is that you're multiplying by w instead of dividing





Code:
void gradientRectangle(int x, int y, int w, int h)
{
   uint8_t start_color[3] = {0,0,0};
   uint8_t end_color[3] = {255,130,0};
   uint8_t rm, gm, bm; //red, green, blue (medium or minimum IDK)
   
   rm = (end_color[0] - start_color[0]) / w;
   gm = (end_color[1] - start_color[1]) / w;
   bm = (end_color[2] - start_color[2]) / w;
   
   for (int i = 0; i < w + 1; i++){
      gfx_palette[i+1] = gfx_RGBTo1555(start_color[0] + rm*i, start_color[1] + gm*i, start_color[2] + bm*i);
      gfx_SetColor(i+1);
      gfx_VertLine(x + i, y, h);
   }
   return;
}


More Examples:
In the post that you linked, rm/gm/bm are being multiplied by 1/height. So, you'll want to divide by w instead of multiplying by it. However, as PT_ mentioned in SAX, this is prone to rounding errors - if (end_color[0] - start_color[0]) / w isn't an integer, the final palette value might be very far off due to rounding errors. This also means that any gradients wider than a certain width would just be a flat image, since the average difference between two palette values is less than 1.
To get around this, you'll have to use some other method of interpolating. Something similar to Bresenham's line algorithm might work well here, although an easy but slow way to do it would be to reorder the multiplication by i to occur before the division by w, e.g.

Code:
void main(void)
{
   gfx_Begin();
   gfx_FillScreen(0);
   gradientRectangle(1, 1, 50, 50);
   delay(3000);
   gfx_End();
    return;
}

void gradientRectangle(int x, int y, int w, int h)
{
   uint8_t start_color[3] = {0,0,0};
   uint8_t end_color[3] = {255,130,0};
   
   for (int i = 0; i < w + 1; i++){
      uint8_t rm, gm, bm;
   
      rm = (end_color[0] - start_color[0]) * i / w;
      gm = (end_color[1] - start_color[1]) * i / w;
      bm = (end_color[2] - start_color[2]) * i / w;
      gfx_palette[i+1] = gfx_RGBTo1555(start_color[0] + rm, start_color[1] + gm, start_color[2] + bm);
      gfx_SetColor(i+1);
      gfx_VertLine(x + i, y, h);
   }
   return;
}

This will be significantly slower, however, as three divisions occur for every loop iteration, as opposed to just three divisions total with the old code.
commandblockguy wrote:
This will be significantly slower, however, as three divisions occur for every loop iteration, as opposed to just three divisions total with the old code.


I believe there could be other ways to implement this in a different manner, you stated that the function could not run when faced with a bigger width ... Instead of "significantly" reducing speed. I would rather enlarge rectangle to maximum width (when there is no error) and create a sprite of the rectangle, then scaling it to the desired width and height, if it's possible.

commandblockguy wrote:
Something similar to Bresenham's line algorithm might work well here


I'll will attempt implement this if possible but I think the sprite implementation version should work for now.
Alright so, I attempted to simplify the gradient routine more palette safe by adding a palette
limiter/reducer for large rectangles (320 at max), but I ran into a few issues:




Note: "code was written very quickly I optimize later <_<"


Code:
void main(void)
{
   gfx_Begin();
   gfx_FillScreen(0);
   gradientRectangle(0, 0, 320, 240);
   delay(3000);
   gfx_End();
    return;
}

void gradientRectangle(int x, int y, int w, int h)
{
   uint8_t start_color[3] = {255, 0, 0};
   uint8_t end_color[3] = {255, 255, 255};
   uint8_t rm, gm, bm; //red, green, blue
   // gfx_sprite_t* rectangle = NULL;
   int add_when; // when to add new color to palette (palette saver)
   int width;
   
   if (w > 255) { // limit
      width = 255;
      if (w / 2 < 255) add_when = 2;
   } else {
      add_when = 1;
      width = w;
   }
   
   rm = (end_color[0] - start_color[0]) / width;
   gm = (end_color[1] - start_color[1]) / width;
   bm = (end_color[2] - start_color[2]) / width;
   
   for (int i = 0; i < w + 1; i++) {
      
      if (i%add_when == 0 && i != 0) {
         gfx_palette[i/add_when] = gfx_RGBTo1555(start_color[0] + rm*i, start_color[1] + gm*i, start_color[2] + bm*i);
         gfx_SetColor(i/add_when);
      } else if (i == 0) {
         gfx_palette[i+1] = gfx_RGBTo1555(start_color[0] + rm*i, start_color[1] + gm*i, start_color[2] + bm*i);
         gfx_SetColor(i+1);
      }
      
      gfx_VertLine(x + i, y, h);
      
   }
   
   return;
}


I added a variable add_when which basically adds the needed color the palette and sets color then Vertline color when i has no remainder when it's divided by add_when. In the test above add_when equaled to 2, meaning it should add a new every 2 lines. After a while the pattern begins to repeat Why is this?

Maybe its this line Confused :

Code:
gfx_palette[i/add_when] = gfx_RGBTo1555(start_color[0] + rm*i, start_color[1] + gm*i, start_color[2] + bm*i);
It's probably because start_color[0] + rm*i is overflowing. rm is calculated for a width of width pixels, but is being multiplied by a value in the range of 1 to w. You could fix this by either dividing by w instead of width, or multiplying by i/add_when instead of i.

However, I personally would just get rid of add_when entirely, and just check if the color calculated is the same as the color before it, and if so, reuse it.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are GMT - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement