#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
#pragma hdrstop
#define SGI_GL_H
#include <v_lib.h>

tripatch_p pat;

void init_colors(void)
{
  vec3_t c;
  int i,j;
  vec3_t r;
  vec_t R;
  vec3_t dis;
  vec_t dist;
  vec4_t rgba;
  /* calc center pt */
  vec2Copy(c,pat->base[0]);
  vec3Add(c,c,pat->base[1]);
  vec3Add(c,c,pat->base[2]);
  vec3Scale(c,c,.33333);
  /* calc radius */
  vec3Sub(r,pat->base[0],c);
  R=vec3Abs(r);
  /* calc colors */
  for(i=0;i<pat->numvert;i++)
  {
    vec3Sub(dis,pat->vlist[i],c);
    dist=vec3Abs(dis);
    /* при затенении заметить волнистость невозможно, а зеркальность
       портится совершенно ! */
    pat->vlist[i][2]=dist*dist/8; /*+.002*dist*dist/R/R*sin(4*M_2PI*dist/R);*/
  }
  patDefaultGeometry(pat,NULL);
  rgba[3]=0;
  for(i=0;i<pat->numvert;i++)
  {
    vec3Sub(dis,pat->vlist[i],c);
    dist=vec3Abs(dis);
    rgba[0]=.7+.2*sin(2*M_2PI*dist/R);
    rgba[1]=.7+.2*sin(4*M_2PI*dist/R);
    rgba[2]=.7+.2*cos(4*M_2PI*dist/R);
    rgbaByteFromFloat(pat->clist[i],rgba);
  }
}

vec_t al=50,bet;
vec3_t dist={0,-10,-20};
vec_t scale=20;
int w,h;
byte *tex;

int   toggles[10];
void  toggle(int i) { toggles[i]=!toggles[i]; }

void CALLBACK up_proc() {  al-=5.0; }
void CALLBACK down_proc() {  al+=5.0; }
void CALLBACK left_proc() {  bet-=5.0; }
void CALLBACK right_proc() {  bet+=5.0; }
void CALLBACK plus_proc() {  scale*=1.1; }
void CALLBACK minus_proc() {  scale/=1.1; }

void CALLBACK a_proc() {  dist[1]+=0.1; }
void CALLBACK z_proc() {  dist[1]-=0.1; }
void CALLBACK r_proc() {  dist[2]+=0.1; }
void CALLBACK f_proc() {  dist[2]-=0.1; }
void CALLBACK d_proc() {  dist[0]+=0.1; }
void CALLBACK g_proc() {  dist[0]-=0.1; }

void CALLBACK proc1() {  toggle(1); }
void CALLBACK proc2() {  toggle(2); }
void CALLBACK proc3() {  toggle(3); }
void CALLBACK proc4() {  toggle(4); }
void CALLBACK proc5() {  toggle(5); }
void CALLBACK proc6() {  toggle(6); }
void CALLBACK proc7() {  toggle(7); }
void CALLBACK proc8() {  toggle(8); }
void CALLBACK proc9() {  toggle(9); }
void CALLBACK proc0() {  toggle(0); }

void	V_GLOBAL
glvGetModelviewXForm(matrix3x4_t dest)
{
	int row;
	matrix4_t m;
#ifdef	DOUBLEVEC
	glGetDoublev(GL_MODELVIEW_MATRIX,(vec_t*)m);
#else
	glGetFloatv(GL_MODELVIEW_MATRIX,(vec_t*)m);
#endif
	for(row=0;row<3;row++)
	{
		dest[row][0]=m[0][row];
		dest[row][1]=m[1][row];
		dest[row][2]=m[2][row];
		dest[row][3]=m[3][row];
	}
}

void	V_GLOBAL
glvSetXForm(matrix3x4_t src,GLenum which)
{
	int row;
	matrix4_t m;
	for(row=0;row<3;row++)
	{
		m[row][0]=src[0][row];
		m[row][1]=src[1][row];
		m[row][2]=src[2][row];
		m[row][3]=src[3][row];
	}
#ifdef	DOUBLEVEC
	glLoadMatrixd((vec_t*)m);
#else
	glLoadMatrixf((vec_t*)m);
#endif
}

void texEnvUV(matrix3x4_t xform,vec3_t normal,vec2_t uv)
{
	vec3_t R;
	vec_t a, length;
	mat3x4VecMul(R,xform,normal);
	length = vec3Abs(R);
	if(length>FLOAT_ZERO_EPSILON) 
	{
		length = (vec_t)1.0 / length;
		vec3Scale(R,R,length);
	}
	else
		vec3Set(R,1,1,1);
	a = 2.0 * R[2];
	vec3Scale(R,R,a);
	R[2] -= 1.0;
	length = vec3Abs(R);
	if(length>FLOAT_ZERO_EPSILON) 
	{
		length=(vec_t)1.0/length;
		vec3Scale(R,R,length);
	}
	a=(vec_t)sqrt(1.0-R[1]*R[1]);
	uv[0] = (vec_t)atan2(R[0],-R[2])/M_2PI;
	if(uv[0] < 0.0)
		uv[0]+=1.0;
	uv[1]=1.0-(vec_t)atan2(a,R[1])/M_PI;
}

vec4_t v[256];
int nv;

static GLvoid CALLBACK  drawScene(GLvoid)
{
  int i;
  int *t;
  matrix3x4_t xf;

  if(!pat) return;
  
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  
  glPushMatrix();
  
  if(toggles[3])
    glEnable(GL_COLOR_MATERIAL);
  else
  {
    glDisable(GL_COLOR_MATERIAL);
  }
    
  if(toggles[1])
  {

    nv=0;
    
    // not working ...
    /*
    glLightfv(GL_LIGHT0,GL_DIFFUSE,vec4Set(v[nv++],   1,    1,    1,    1     ));
    glLightfv(GL_LIGHT0,GL_SPECULAR,vec4Set(v[nv++],  1,    1,    1,    1     ));
    glLightfv(GL_LIGHT0,GL_POSITION,vec4Set(v[nv++],  0,    0,    0,    1     ));
    */
    glEnable(GL_LIGHT0);

    /*
    glLightfv(GL_LIGHT1,GL_DIFFUSE,vec4Set(v[nv++],   1,    0,    0,  0   ));
    glLightfv(GL_LIGHT1,GL_SPECULAR,vec4Set(v[nv++],  1,    1,    1,    0   ));
    glLightfv(GL_LIGHT1,GL_POSITION,vec4Set(v[nv++],  5,    0,    0,  1   ));
    glEnable(GL_LIGHT1);
    glLightfv(GL_LIGHT2,GL_DIFFUSE,vec4Set(v[nv++],   0,    0,    1,  0   ));
    glLightfv(GL_LIGHT2,GL_SPECULAR,vec4Set(v[nv++],  1,    1,    1,    0   ));
    glLightfv(GL_LIGHT2,GL_POSITION,vec4Set(v[nv++],  -5,   0,    0,  1   ));
    glEnable(GL_LIGHT2);
    */
    glEnable(GL_LIGHTING);
    /*
    glMaterialfv(GL_FRONT,GL_DIFFUSE,vec4Set(v[nv++],   .6,   .8,   .6, 0 ));
    glMaterialfv(GL_FRONT,GL_SPECULAR,vec4Set(v[nv++],  1,    .5,   .5,  0 ));
    glMaterialfv(GL_FRONT,GL_SHININESS,vec4Set(v[nv++], 30,   0,    0,  0 ));
    glMaterialfv(GL_FRONT,GL_EMISSION,vec4Set(v[nv++],  .3,   .3,   .3,  0 ));
    glMaterialfv(GL_BACK, GL_DIFFUSE,vec4Set(v[nv++],   .4,   .1,   .4, 0 ));
    glMaterialfv(GL_BACK, GL_SPECULAR,vec4Set(v[nv++],  0,    1,    0,  0 ));
    glMaterialfv(GL_BACK, GL_SHININESS,vec4Set(v[nv++], 10,   0,    0,  0 ));
    glMaterialfv(GL_BACK, GL_EMISSION,vec4Set(v[nv++],  .4,   .4,   .4,  0 ));
    */

  }
  else
  {
    glDisable(GL_LIGHTING);
  }
  
  glTranslatef(dist[0],dist[1],dist[2]);
  glScalef(scale,scale,scale);
  glRotatef(al,1,0,0);
  glRotatef(bet,0,0,1);
  
  if(toggles[4] && tex) 
  {
  	/*
    {
    	int i;
    	char c;
    	c=rand() % 256;
    	for(i=0;i<128;i++)
    	{
    		tex[3*i]=c;
    		tex[3*i+1]=255-c;
    		tex[3*i+2]=c;
    	}
    }
    */
    glTexImage2D(GL_TEXTURE_2D,0,4,w,h,0,GL_RGBA,GL_UNSIGNED_BYTE,tex);

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    /*
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
    */

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
    if(toggles[5])
      glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
    else
      if(toggles[6])
        glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_BLEND);
      else
        glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
    glEnable(GL_TEXTURE_2D);
  }
  else
    glDisable(GL_TEXTURE_2D);
  
  glvGetModelviewXForm(xf);
  
  glBegin(GL_TRIANGLES);
    if(toggles[2])
    {
      if(toggles[7])
      {
        vec2_t uv;
        for(i=0;i<pat->numtri;i++)
        {
          t=pat->tlist[i];
          glColor4ubv(pat->clist[t[0]]);
          glNormal3fv(pat->nlist[t[0]]);
          texEnvUV(xf,pat->nlist[t[0]],uv);
          glTexCoord2fv(uv);
          glVertex3fv(pat->vlist[t[0]]);
          glColor4ubv(pat->clist[t[1]]);
          glNormal3fv(pat->nlist[t[1]]);
          texEnvUV(xf,pat->nlist[t[1]],uv);
          glTexCoord2fv(uv);
          glVertex3fv(pat->vlist[t[1]]);
          glColor4ubv(pat->clist[t[2]]);
          glNormal3fv(pat->nlist[t[2]]);
          texEnvUV(xf,pat->nlist[t[2]],uv);
          glTexCoord2fv(uv);
          glVertex3fv(pat->vlist[t[2]]);
        }
      }
      else
      {
        for(i=0;i<pat->numtri;i++)
        {
          t=pat->tlist[i];
          glColor4ubv(pat->clist[t[0]]);
          glNormal3fv(pat->nlist[t[0]]);
          glTexCoord2fv(pat->uvlist[t[0]]);
          glVertex3fv(pat->vlist[t[0]]);
          glColor4ubv(pat->clist[t[1]]);
          glNormal3fv(pat->nlist[t[1]]);
          glTexCoord2fv(pat->uvlist[t[1]]);
          glVertex3fv(pat->vlist[t[1]]);
          glColor4ubv(pat->clist[t[2]]);
          glNormal3fv(pat->nlist[t[2]]);
          glTexCoord2fv(pat->uvlist[t[2]]);
          glVertex3fv(pat->vlist[t[2]]);
        }
      }
    }
    else
    {
      if(toggles[7])
      {
        vec2_t uv;
        for(i=0;i<pat->numtri;i++)
        {
          t=pat->tlist[i];
          texEnvUV(xf,pat->fnlist[i],uv);
          glTexCoord2fv(uv);
          glColor4ubv(pat->clist[t[0]]);
          glVertex3fv(pat->vlist[t[0]]);
          glColor4ubv(pat->clist[t[1]]);
          glVertex3fv(pat->vlist[t[1]]);
          glColor4ubv(pat->clist[t[2]]);
          glVertex3fv(pat->vlist[t[2]]);
        }
      }
      else
        for(i=0;i<pat->numtri;i++)
        {
          t=pat->tlist[i];
          glNormal3fv(pat->fnlist[i]);
          glColor4ubv(pat->clist[t[0]]);
          glTexCoord2fv(pat->uvlist[t[0]]);
          glVertex3fv(pat->vlist[t[0]]);
          glColor4ubv(pat->clist[t[1]]);
          glTexCoord2fv(pat->uvlist[t[1]]);
          glVertex3fv(pat->vlist[t[1]]);
          glColor4ubv(pat->clist[t[2]]);
          glTexCoord2fv(pat->uvlist[t[2]]);
          glVertex3fv(pat->vlist[t[2]]);
        }
    }
  glEnd();

  glPopMatrix();
  auxSwapBuffers();
}

static GLvoid CALLBACK Resize(GLsizei width,GLsizei height)
{
  GLfloat aspect;
  glViewport(0,0,width,height );
  aspect = (GLfloat)width/height;
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glFrustum(-aspect,aspect,1,-1,1,100);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_FASTEST);
}    

#define t_name	"../media/mist.jpg"

void main()
{
  vec3_t a={-.867,-.5,0};
  vec3_t b={.867,-.5,0};
  vec3_t c={0,1,0};
  
  /*
  vec2_t mins={-1,-1};
  vec2_t maxs={1,1};
  */
  
  /* pat=patCreateRectangular(mins,maxs,3,2); */
  pat=patCreateTriangular(a,b,c,40,1);
  init_colors();
  logStartConsoleLog();
  logUpperLevel(LOG_TRACE);
  
  tex=jpgLoad(t_name,&w,&h);
  
  if(!tex)
  {
  		printf("can't open '%s'\n",t_name);
  		return;
  }
  auxInitPosition(0,0,640,480);
  auxInitDisplayMode(AUX_RGB|AUX_DEPTH|AUX_DOUBLE);
  auxInitWindow("Test");
  SetClassLong(GetActiveWindow(),GCL_HBRBACKGROUND,0);
  auxReshapeFunc(Resize);

  auxKeyFunc(AUX_UP,up_proc);
  auxKeyFunc(AUX_DOWN,down_proc);
  auxKeyFunc(AUX_LEFT,left_proc);
  auxKeyFunc(AUX_RIGHT,right_proc);
  auxKeyFunc(AUX_e,plus_proc);
  auxKeyFunc(AUX_t,minus_proc);
  auxKeyFunc(AUX_a,a_proc);
  auxKeyFunc(AUX_z,z_proc);
  auxKeyFunc(AUX_r,r_proc);
  auxKeyFunc(AUX_f,f_proc);
  auxKeyFunc(AUX_d,d_proc);
  auxKeyFunc(AUX_g,g_proc);
  auxKeyFunc(AUX_0,proc0);
  auxKeyFunc(AUX_1,proc1);
  auxKeyFunc(AUX_2,proc2);
  auxKeyFunc(AUX_3,proc3);
  auxKeyFunc(AUX_4,proc4);
  auxKeyFunc(AUX_5,proc5);
  auxKeyFunc(AUX_6,proc6);
  auxKeyFunc(AUX_7,proc7);
  auxKeyFunc(AUX_8,proc8);
  auxKeyFunc(AUX_9,proc9);
  
  glClearColor(0.0,0.5,0.5,0.0);
  glClearDepth(1);
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LESS);
  
  Resize(640,480);
  auxMainLoop(drawScene);

  patFree(pat);
  
  libvFree(tex);
}
