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.
I had some free time so I created a simple random walker. I don't think it's really random due to the randInt command but if there is a way to create a true random int please leave a comment.


** as you can see both images are exactly the same, and this because of the RandomInt Function (both images are different) **


Random Walker Code:

Main.c:

Code:
/* "Demo" Alvajoy123 "Random Walker v1.0" */

#include <tice.h>
#include <graphx.h>
#include <keypadc.h>

// Include walker file.
#include "walk.h"

int main(void)
{
   gfx_Begin();
   
   gfx_FillScreen(0);
   
   /* Set variables for walker */
   walk_init();
   
   /* Breaks when any key is clicked */
   while (!os_GetCSC()){
      
      /* Renders and Sets walker */
      walk_step();
      walk_render();
   }
   
   gfx_End();
   
    return 0;
}




Walk.c:

Code:
#include <tice.h>
#include <graphx.h>

// Include walker file.
#include "walk.h"

struct walker_t{
   int x;
   int y;
};

struct walker_t walker;

void walk_init(void)
{
   /* Sets Walker in the Center of the Screen */
   walker.x = LCD_WIDTH / 2;
   walker.y = LCD_HEIGHT / 2;
}

void walk_step(void)
{
   /* "Random" Int is chosen */
   int choice = randInt(0, 3);
   
   /* Turns out that if statements are faster than switches*/
   if (!choice){
      walker.x++;
   }else if (choice == 1){
      walker.x--;
   }else if (choice == 2){
      walker.y++;
   }else if (choice == 3){
      walker.y--;
   }
   
   /* Prevents x and y cord from going off screen */
   walker.x = walk_constrain(walker.x, 0, LCD_WIDTH - 1);
   walker.y = walk_constrain(walker.y, 0, LCD_HEIGHT - 1);
}

void walk_render(void)
{
   gfx_SetColor(randInt(1, 255));
   gfx_SetPixel(walker.x, walker.y);
}

int walk_constrain(int x, int a, int b)
{
   if (x < a){
      return a;
   }else if (x > b){
      return b;
   }else return x;
}



Walk.h:

Code:
#ifndef WALK_H
#define WALK_H

#include <tice.h>

/* Sets up walker */
void walk_init(void);

/* "step is also know as tick" manages the movement of the walker */
void walk_step(void);

/* Renders the walker */
void walk_render(void);

/* Constrains the given x with range from a to b */
int walk_constrain(int x, int a, int b);

#endif
You need to set the random seed, which you can do like:

Code:
srand(rtc_Time());


I ran into this issue when making HUE CE as well-without setting the seed you'll get the same "random" result each time.
epsilon5 wrote:
You need to set the random seed, which you can do like:

Code:
srand(rtc_Time());


I ran into this issue when making HUE CE as well-without setting the seed you'll get the same "random" result each time.


I implemented it at the start of main.c and it works!

Implemented:
I was recently testing different computer graphics on the CE calculator and stumbled upon boundary filling. I tried clearing the binary "/bin" and recompiling but that didn't work. Sad

Could you tell me what's wrong with my code? (there only one file "main.c")


Code:
/*
 *--------------------------------------
 * Program Name: Demo
 * Author: Alvajoy123
 * License: MIT
 * Description: Testing Boundary Filling
 *--------------------------------------
*/

#include <tice.h>
#include <graphx.h>
#include <keypadc.h>

static void BoundaryFill(uint24_t x, uint8_t y, uint8_t color_a, uint8_t color_b)
{
   uint8_t curr_check = gfx_GetPixel(x, y);
   
   if(curr_check != color_a && curr_check != color_b) {
      gfx_SetColor(color_b);
       gfx_SetPixel(x, y);

       BoundaryFill(x + 1, y, color_a, color_b);
       BoundaryFill(x - 1, y, color_a, color_b);
      
       BoundaryFill(x, y + 1, color_a, color_b);
       BoundaryFill(x, y - 1, color_a, color_b);
   }
}

int main(void)
{
   /* Initialize graphics drawing */
   gfx_Begin();
   gfx_FillScreen(255);
   
   /* Sets color to black and draws a mid point circle */
   gfx_SetColor(0);
   gfx_FillCircle(LCD_WIDTH/2, LCD_HEIGHT/2, 100);
   
   BoundaryFill(LCD_WIDTH/2, LCD_HEIGHT/2, 255, 7);
   
   /* Waits for a key */
    while (!os_GetCSC());
   
   /* End graphics drawing */
   gfx_End();
   
    return 0;
}
You are overflowing the stack.
  
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 UTC - 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