
/*
 * texture.c
 *
 * FUNCTION:
 * texture mapping hack
 *
 * HISTORY:
 * Created by Linas Vepstas April 1994
 * Reaction-Diffusion added Dec 1996
 * Copyright (c) 1994, 1996, Linas Vepstas <linas@linas.org>
 */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "texture.h"

Texture * current_texture = 0x0;

Texture * planet_texture = 0x0;
Texture * check_texture = 0x0;
Texture * barberpole_texture = 0x0;
Texture * wild_tooth_texture = 0x0;
Texture * reaction_texture = 0x0;

void (*texanim)(int) = 0x0;
void (*reaction_texanim)(int) = 0x0;

/* ======================================================= */

#define TEXTURE_SIZE 256

static Texture * 
create_planet_texture (void) 
{
   int i, j;
   Texture * tex;
   unsigned char * pixmap;

   pixmap = (unsigned char *) malloc (TEXTURE_SIZE*TEXTURE_SIZE*3*sizeof (unsigned char));

   for (i=0; i< TEXTURE_SIZE; i++) {
      for (j=0; j< TEXTURE_SIZE; j++) {

         int mi = i - TEXTURE_SIZE/2;
         int mj = j - TEXTURE_SIZE/2;

         pixmap [3*TEXTURE_SIZE*i + 3*j] = 100*mi*mi + (40*mj*mj >> 8);
         pixmap [3*TEXTURE_SIZE*i + 3*j + 1] = (10*mi*mi + 4*mj*mj) ;
         pixmap [3*TEXTURE_SIZE*i + 3*j + 2] = (1000*mi*mi + 400*mj*mj) >> 16 ;

      }
   }

   tex = (Texture *) malloc (sizeof (Texture));
   tex -> size = TEXTURE_SIZE;
   tex -> pixmap = pixmap;

   return tex;
}

/* ======================================================= */

static Texture * 
create_check_texture (void) 
{
   int i, j;
   Texture * tex;
   unsigned char * pixmap;

   pixmap = (unsigned char *) malloc (TEXTURE_SIZE*TEXTURE_SIZE*3*sizeof (unsigned char));

   for (i=0; i< TEXTURE_SIZE; i++) {
      for (j=0; j< TEXTURE_SIZE; j++) {

         pixmap [3*TEXTURE_SIZE*i + 3*j] = 
		255 * ( (((i)/32) %2) == (((j)/32) %2));
         pixmap [3*TEXTURE_SIZE*i + 3*j + 1] = 
		255 * ( (((i)/32) %2) == (((j)/32) %2));
         pixmap [3*TEXTURE_SIZE*i + 3*j + 2] = 
		255 * ( (((i)/32) %2) == (((j)/32) %2));
      }
   }

   tex = (Texture *) malloc (sizeof (Texture));
   tex -> size = TEXTURE_SIZE;
   tex -> pixmap = pixmap;

   return tex;
}

/* ======================================================= */

static Texture * 
create_barberpole_texture (void) 
{
   int i, j;
   Texture * tex;
   unsigned char * pixmap;

   pixmap = (unsigned char *) malloc (TEXTURE_SIZE*TEXTURE_SIZE*3*sizeof (unsigned char));

   for (i=0; i< TEXTURE_SIZE; i++) {
      for (j=0; j< TEXTURE_SIZE; j++) {

         pixmap [3*TEXTURE_SIZE*i + 3*j] = 255 * (((i+j)/32) %2);
         pixmap [3*TEXTURE_SIZE*i + 3*j + 1] = 255 * (((i+j)/32) %2);
         pixmap [3*TEXTURE_SIZE*i + 3*j + 2] = 255 * (((i+j)/32) %2);

      }
   }

   tex = (Texture *) malloc (sizeof (Texture));
   tex -> size = TEXTURE_SIZE;
   tex -> pixmap = pixmap;

   return tex;
}

/* ======================================================= */

static Texture * 
create_wild_tooth_texture (void) 
{
   int i, j;
   Texture * tex;
   unsigned char * pixmap;

   pixmap = (unsigned char *) malloc (TEXTURE_SIZE*TEXTURE_SIZE*3*sizeof (unsigned char));

   for (i=0; i< TEXTURE_SIZE; i++) {
      for (j=0; j< TEXTURE_SIZE; j++) {

         pixmap [3*TEXTURE_SIZE*i + 3*j] = 
         255 * ( (((i+j)/32) %2) == (((i-j)/32) %2));
         pixmap [3*TEXTURE_SIZE*i + 3*j + 1] = 
         255 * ( (((i+j)/32) %2) == (((i-j)/32) %2));
         pixmap [3*TEXTURE_SIZE*i + 3*j + 2] = 
         255 * ( (((i+j)/32) %2) == (((i-j)/32) %2));

      }
   }

   tex = (Texture *) malloc (sizeof (Texture));
   tex -> size = TEXTURE_SIZE;
   tex -> pixmap = pixmap;

   return tex;
}

/* ======================================================= */
/* reaction-diffusion textures, witkin & kass, siggraph 1991 */
/* this is a quick and dirty, sloppy, non-cpu-efficient
 * non-parametric-corrected isotropic impelemtation. */

static float CPfield[TEXTURE_SIZE][TEXTURE_SIZE];
static float CMfield[TEXTURE_SIZE][TEXTURE_SIZE];
static float RPfield[TEXTURE_SIZE][TEXTURE_SIZE];
static float RMfield[TEXTURE_SIZE][TEXTURE_SIZE];
static float tmpfield[TEXTURE_SIZE][TEXTURE_SIZE];

int niter=0;

static Texture * 
create_reaction_texture (void)
{
   int i,j; 
   Texture * tex;
   unsigned char * pixmap;

   pixmap = (unsigned char *) 
              malloc (TEXTURE_SIZE*TEXTURE_SIZE*3* sizeof (unsigned char));

   for (i=0; i< TEXTURE_SIZE; i++) {
      for (j=0; j<TEXTURE_SIZE; j++) {
         CPfield[i][j] = ((float) ((i*j)%4096)) / 4096.0;
         CMfield[i][j] = ((float) ((i*i+j*j)%8192)) / 8192.0;
         RPfield[i][j] = 0.0;
         RMfield[i][j] = 0.0;
      }
   }

   for (i=0; i< TEXTURE_SIZE; i++) {
      for (j=0; j<TEXTURE_SIZE; j++) {
         pixmap [3*TEXTURE_SIZE*i+3*j] =  255.0 * CPfield[i][j];
         pixmap [3*TEXTURE_SIZE*i+3*j+1] = 127.0 * (CPfield[i][j]+CMfield[i][j]);
         pixmap [3*TEXTURE_SIZE*i+3*j+2] = 255.0 * CMfield[i][j];
      }
   }

   tex = (Texture *) malloc (sizeof (Texture));
   tex -> size = TEXTURE_SIZE;
   tex -> pixmap = pixmap;

   reaction_texture = tex;
   return tex;
}

static float delta_t = 0.1;
static float h = 1.0;
static float ap = 1.0;
static float am = 0.5;
static float b = 0.0;
static float r = 0.5;

static void 
iterate_reaction_texture (int reset)
{
   int i,j, im1, ip1, jm1, jp1; 
   int iter;
   unsigned char * pixmap;
   float tmp;
   float cpmax, cpmin, cmmax, cmmin, cps, cms;
   float cpr, cmr;

   niter ++;
   printf ("diffusion-reaction iteration %d \n", niter);

   cpmax = -1.0e50;
   cpmin = +1.0e50;

   cmmax = -1.0e50;
   cmmin = +1.0e50;

   if (reset) {
      niter = 0;
      for (i=0; i< TEXTURE_SIZE; i++) {
         for (j=0; j<TEXTURE_SIZE; j++) {
            CPfield[i][j] = ((float) ((i*j)%4096)) / 4096.0;
            CMfield[i][j] = ((float) ((i*i+j*j)%8192)) / 8192.0;
            RPfield[i][j] = 0.0;
            RMfield[i][j] = 0.0;
         }
      }
   } else {

      for (iter=0; iter<1; iter ++) {

         /* reaction-diffusion */
         for (i=0; i< TEXTURE_SIZE; i++) {
            im1 = (i+TEXTURE_SIZE-1)%TEXTURE_SIZE;
            ip1 = (i+1)%TEXTURE_SIZE;
            for (j=0; j<TEXTURE_SIZE; j++) {
               jm1 = (j+TEXTURE_SIZE-1)%TEXTURE_SIZE;
               jp1 = (j+1)%TEXTURE_SIZE;

               tmp = CPfield[im1][j];
               tmp += CPfield[ip1][j];
               tmp += CPfield[i][jm1];
               tmp += CPfield[i][jp1];
               tmp -= 4.0 * CPfield[i][j];
               tmp *= ap*ap / (h*h);
               tmp -= b* CPfield[i][j];
               tmp += RPfield[i][j];
               tmpfield[i][j] = tmp;
            }
         }
         for (i=0; i< TEXTURE_SIZE; i++) {
            for (j=0; j<TEXTURE_SIZE; j++) {
               CPfield[i][j] += delta_t * tmpfield[i][j];
               if (cpmax < CPfield[i][j]) cpmax = CPfield[i][j];
               if (cpmin > CPfield[i][j]) cpmin = CPfield[i][j];
            }
         }
      
         for (i=0; i< TEXTURE_SIZE; i++) {
            im1 = (i+TEXTURE_SIZE-1)%TEXTURE_SIZE;
            ip1 = (i+1)%TEXTURE_SIZE;
            for (j=0; j<TEXTURE_SIZE; j++) {
               jm1 = (j+TEXTURE_SIZE-1)%TEXTURE_SIZE;
               jp1 = (j+1)%TEXTURE_SIZE;

               tmp = CMfield[im1][j];
               tmp += CMfield[ip1][j];
               tmp += CMfield[i][jm1];
               tmp += CMfield[i][jp1];
               tmp -= 4.0 * CMfield[i][j];
               tmp *= am*am / (h*h);
               tmp -= b* CMfield[i][j];
               tmp += RMfield[i][j];
               tmpfield[i][j] = tmp;
            }
         }
         for (i=0; i< TEXTURE_SIZE; i++) {
            for (j=0; j<TEXTURE_SIZE; j++) {
               CMfield[i][j] += delta_t * tmpfield[i][j];
               if (cmmax < CMfield[i][j]) cmmax = CMfield[i][j];
               if (cmmin > CMfield[i][j]) cmmin = CMfield[i][j];
            }
         }
      
         for (i=0; i< TEXTURE_SIZE; i++) {
            for (j=0; j<TEXTURE_SIZE; j++) {
               if ( CPfield[i][j] > CMfield[i][j]) {
                  RPfield[i][j] = r;
                  RMfield[i][j] = r;
               } else {
                  RPfield[i][j] = 0.0;
                  RMfield[i][j] = 0.0;
               }
            }
         }
      }
   }


   pixmap = reaction_texture -> pixmap;
   cps = 1.0 / (cpmax-cpmin);
   cms = 1.0 / (cmmax-cmmin);
   for (i=0; i< TEXTURE_SIZE; i++) {
      for (j=0; j<TEXTURE_SIZE; j++) {
         cpr = cps * (CPfield[i][j]-cpmin);
         cmr = cms * (CMfield[i][j]-cmmin);
         cpr = CPfield[i][j];
         cmr = CMfield[i][j];
         pixmap [3*TEXTURE_SIZE*i+3*j] = 255.0 * cpr;
         pixmap [3*TEXTURE_SIZE*i+3*j+1] = 70.0 * (cpr+cmr);
         pixmap [3*TEXTURE_SIZE*i+3*j+2] = 130.0 * cmr;
      }
   }
}

/* ======================================================= */

void setup_textures (void) {

   planet_texture = create_planet_texture ();
   check_texture = create_check_texture ();
   barberpole_texture = create_barberpole_texture ();
   wild_tooth_texture = create_wild_tooth_texture ();
   reaction_texture = create_reaction_texture ();

   reaction_texanim = iterate_reaction_texture;

   current_texture = wild_tooth_texture;
   current_texture = check_texture;
}


/* ================== END OF FILE ========================= */
