[Project] – Generating animated pixel patterns on Terminal (in C) –

-Cover by Yuri Samoilov / FLICKR-

Hi everyone !

Hope you’re doing well with your everyday projects ūüôā

Today i will share with you something I’ve code a month ago when I was practicing my memory manipulation in C language.

At the time, I’ve simply decided to try to display colored pixelized patterns thanks to special commands and matrix. As a big Demoscene fan, I’m really into computer generated graphics and I saw a cool occasion to “first try” it.

First, I need an 2-dimension Array (a matrix) to display colors and simulate pixels.

int **Init_blank_mx(void){
    int **temp_mx = (int**) malloc(yy*sizeof(int*));
    int i,j;

    for (i = 0; i < yy; ++i)
    {
        temp_mx[i] = (int*) malloc(xx*sizeof(int));
        for (j = 0; j < xx; ++j)
        {
            temp_mx[i][j] = 0;
        }
    }
    return temp_mx;
}

As you can see, this function return a (int**) after initializing all the lines*columns to 0.

This matrix is useless right now , but it’s a basis for more complex pattern.

Furthermore, using a malloc allow to loop this function without creating hundred of main variables.

Also, people teach me to have some programming habits, so after a “malloc” I always do a “free” and, between that, i need to display the matrix.

So the thread is basically : Creating a matrix > Display the matrix > Free the matrix.

Here the “display” and the “free” :

int **AffMat(int **Ma, int us){
    int u,v;
    for (u = 0; u < yy; ++u)
    {
        for (v = 0; v < xx; ++v)
        {
            printf("\e[4%dm..\e[0m",Ma[u][v]);
        }
        printf("\n");
    }
usleep(us);
return Ma;
}

void Free_mx(int **M, int ta){
    int i;
    for (i = 0; i < ta; ++i)
    {
        free(M[i]);
    }
    free(M);
}

As you can see, the “AffMat” function have some special feature :

  • The “usleep” allow to control the time between “frames” displayed on the terminal
  • The return of the matrix variable allow to directly launch a “free” after display
  • The ” printf(“\e[4%dm..\e[0m”,Ma[u][v]); ” allow to display a color for each value contained by the matrix. If it contain only “0” (like ‘init_blank_mx ‘), the pattern will be monochromatic.

Now that I’ve choose this type of thread I need to create more patterns (a blank one is not really fun).

One of the best (for me) function is the SINUS. Because if you put into your matrix-values the return of a “sinus equation” you could shift and modify the result by many parameters (phase, frequency, numeric shift, amplitude etc..).

Then the SINUS equation mainly display vertical stripes, you could transform it in diagonals stripes, waves, etc…

Example of SINUS use :

int **Init_sin_mx(float la, float de){
    int **temps_mx = (int**) malloc(yy*sizeof(int*));
    int is,js;

    for (is = 0; is < yy; ++is)
    {
        temps_mx[is] = (int*) malloc(xx*sizeof(int));
        for (js = 0; js < xx; ++js)
        {
            temps_mx[is][js] = sin((js/la)+is/de)+0.5*la;
        }
    }

    return temps_mx;
}

Same method than for “BLANK” => Mallocs > Values > return Matrix

The “la” variable is for Width and the “de” is for the Shift

It displays this :

Untitled
– the “dots” are for measurements – Blue is 0 , Red is 1 – SINUS with shift

Now, I have a method to display , temporize and create funny pattern with matrix.

One more step : If I want to display 300 frame with slight variations I need to create a “master” function who will call patterns, make their initial variables change for a chosen number of loops.

After coding 4 pattern types, this is the function I’ve coded :

void loops (int iter, char cmd, float stepf1, float stepf2, float stepf3, float stepf4, int stepus, float f1, float f2,float f3, float f4, int uus) {
    int l;
    for(l=0;l<iter;l++){
        if(cmd == 'b'){
            Free_mx(AffMat(Init_blank_mx(),uus),yy);
            uus = uus + stepus;
        }
        if(cmd == 's'){
            Free_mx(AffMat(Init_sin_mx(f1,f2),uus),yy);
            f1 = f1 + stepf1;
            f2 = f2 + stepf2;
            uus = uus + stepus;
        }
        if(cmd == 'h'){
            Free_mx(AffMat(Init_Hray_mx(f1),uus),yy);
            f1 = f1 + stepf1;
            uus = uus + stepus;
        }
        if(cmd == 'w'){
            Free_mx(AffMat(Init_wave_mx(f1,f2,f3,f4),uus),yy);
            f1 = f1 + stepf1;
            f2 = f2 + stepf2;
            f3 = f3 + stepf3;
            f4 = f4 + stepf4;
            uus = uus + stepus;
        }
        printf("\e[2J\e[1;1H");
    }
}

Many thing to observe :

  • the function takes 12 parameters :
    • “Iter” for the iteration number
    • “Cmd” for the pattern selection
    • the “Steps” variables are for the amount of change of each variables at each loop
    • the “F” variables are for the initial value of each variables
    • Note : “Stepus” and “us” are the steps of time between frames and the initial time.
  • Not all the function parameters are used for each pattern.
    • For example the sinus pattern only uses two variables + two steps variables (without considering time “us”)
  • It’s interesting to see that the thread Create Matrix > Display it > Free it, is resumed in one line (for example): ” Free_mx(AffMat(Init_Hray_mx(f1),uus),yy); “

 

  • ” printf(“\e[2J\e[1;1H”); ” cleans the terminal.

And with all the block put together , you have a tool for displaying animated patterns on terminal !

The Animation (BAD quality with lag):

https://asciinema.org/a/acd1ca6k1d3sbouklrhdofbap

The full code to launch (Better , tried on Linux):

/* Code by Ozellius  */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <unistd.h>

#define xx 32
#define yy 32

int **Init_blank_mx(void);
int **Init_sin_mx(float la, float de);
int **Init_Hray_mx(float decc);
int **Init_wave_mx(float amp, float frq, float phz, int deca);
void Free_mx(int **M, int ta);
int **AffMat(int **Ma, int us);
void loops(int iter, char cmd, float stepf1, float stepf2, float stepf3, float stepf4, int stepus, float f1, float f2,float f3, float f4, int uus);

int **Init_wave_mx(float amp, float frq, float phz, int deca){
    int **temps_mw = Init_blank_mx();
    int iw,sft;
    sft = (yy/deca) + amp;

    while((sft<yy)&&(sft>0)){
        for(iw=0;iw<xx;iw++){
            if(((int)(sft+amp*sin(frq*iw+phz)))>yy&&((int)(sft+amp*sin(frq*iw+phz)))<0){}
            else{temps_mw[(int)(sft+amp*sin(frq*iw+phz))][iw]++;}
        }
        sft = sft + deca;
    }

    return temps_mw;
}

void loops(int iter, char cmd, float stepf1, float stepf2, float stepf3, float stepf4, int stepus, float f1, float f2,float f3, float f4, int uus){
    int l;
    for(l=0;l<iter;l++){
        if(cmd == 'b'){
            Free_mx(AffMat(Init_blank_mx(),uus),yy);
            uus = uus + stepus;
        }
        if(cmd == 's'){
            Free_mx(AffMat(Init_sin_mx(f1,f2),uus),yy);
            f1 = f1 + stepf1;
            f2 = f2 + stepf2;
            uus = uus + stepus;
        }
        if(cmd == 'h'){
            Free_mx(AffMat(Init_Hray_mx(f1),uus),yy);
            f1 = f1 + stepf1;
            uus = uus + stepus;
        }
        if(cmd == 'w'){
            Free_mx(AffMat(Init_wave_mx(f1,f2,f3,f4),uus),yy);
            f1 = f1 + stepf1;
            f2 = f2 + stepf2;
            f3 = f3 + stepf3;
            f4 = f4 + stepf4;
            uus = uus + stepus;
        }
        printf("\e[2J\e[1;1H");
    }
}

int **AffMat(int **Ma, int us){
    int u,v;
    for (u = 0; u < yy; ++u)
    {
        for (v = 0; v < xx; ++v)
        {
            printf("\e[4%dm  \e[0m",Ma[u][v]);
        }
        printf("\n");
    }
usleep(us);
return Ma;
}

void Free_mx(int **M, int ta){
    int i;

    for (i = 0; i < ta; ++i)
    {
        free(M[i]);
    }

    free(M);
}

int **Init_sin_mx(float la, float de){
    int **temps_mx = (int**) malloc(yy*sizeof(int*));
    int is,js;

    for (is = 0; is < yy; ++is)
    {
        temps_mx[is] = (int*) malloc(xx*sizeof(int));
        for (js = 0; js < xx; ++js)
        {
            temps_mx[is][js] = sin((js/la)+is/de)+0.5*la;
        }
    }

    return temps_mx;
}

int **Init_Hray_mx(float decc){
    int **temphr_mx = (int**) malloc(yy*sizeof(int*));
    int ihr,jhr;

    for (ihr = 0; ihr < yy; ++ihr)
    {
        temphr_mx[ihr] = (int*) malloc(xx*sizeof(int));
        for (jhr = 0; jhr < xx; ++jhr)
        {
            temphr_mx[ihr][jhr] = sin(ihr/decc+decc)+0.5;
        }
    }

    return temphr_mx;
}

int **Init_blank_mx(void){
    int **temp_mx = (int**) malloc(yy*sizeof(int*));
    int i,j;

    for (i = 0; i < yy; ++i)
    {
        temp_mx[i] = (int*) malloc(xx*sizeof(int));
        for (j = 0; j < xx; ++j)
        {
            temp_mx[i][j] = 0;
        }
    }

    return temp_mx;
}

int main(void){

    int nl;
    int t;
    t = 100000;

    for(nl=0;nl<1;nl++){
        /*(frames, mode, iteration factor 1, if2, if3, if4, iteration time, factor1, f2, f3, f4, time base)*/
        loops(8, 's', 0.2, 0.2, 0, 0, 0, 1, 1, 0, 0,t);
        loops(8, 's', -0.2, -0.2, 0, 0, 0, 2.6, 2.6, 0, 0, t);
        loops(8, 's', 0.2, -0.2, 0, 0, 0, 1, -1, 0, 0, t);
        loops(8, 's', -0.2, 0.2, 0, 0, 0, 2.6, -2.6, 0, 0, t);
        loops(8, 's', 0.1, 0.1, 0, 0, 0, 1, -1, 0, 0, t);
        loops(8, 's', -0.1, -0.1, 0, 0, 0, 1.8, -0.2, 0, 0, t);
        loops(10, 'h', 0.1, 0, 0, 0, 0, 1, 0, 0, 0, t);
        loops(10, 'h', -0.1, 0, 0, 0, 0, 2, 0, 0, 0, t);
        loops(8, 'w', 0.1, 0.1, 0.1, 0, 0, 1, 1, 1, 11, t);
        loops(8, 'w',-0.1, -0.1, -0.1, 0, 0, 1.8, 1.8, 1.8, 11, t);
    }
    return 0;
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s