/*
   CMSC 427 - Term Project Candidate
   ---------------------------------

   Beth Weinstein - bweinste@wam.umd.edu
   Ben Stewart - stewartb@wam.umd.edu
   Nawfel Tricha - Topaz@endorproductions.com

   Minimal OpenGL project using Microsoft Visual C++.
   This project is a premilinary candidate for the term 
   project required by CMSC 427.

   ABSTRACT:
      In this project, we will develop several fast 
      rendering and collision routines which would 
      require C/C++ speed and accuracy and then 
      implement a VisualJ++ interface.

   MODULE:
      Main Digital Signal Processing module.
*/

#include "global.h"
#include <mmsystem.h>
#include <math.h>

//Local Defines:

extern skin_t chrome_skin;
extern skin_t r_chrome_skin;

#define  DSP_SPECTRUM_TRESHHOLD  192
#define  DSP_SPECTRUM_BAR_WIDTH  7.0f

/*
   NT:
   Return scalar of the current DSP input:   
*/
float DSPGetBass(struct winampVisModule *this_mod, int format)
{
   static float dsp_output = 1;
   register unsigned char spec_low_bass;
   register unsigned char spec_low_mid_bass;
   edict_t *ent = &g_edicts[0];

   switch (format)
      {
      case DSP_SPECTRUM_KICK:
         spec_low_bass = this_mod->spectrumData[0][0];
         spec_low_mid_bass = this_mod->spectrumData[0][1];

         if (spec_low_bass + spec_low_mid_bass > DSP_SPECTRUM_TRESHHOLD)
            {
            float inter_scale = (float) (spec_low_bass + spec_low_mid_bass) / 255;
            if (dsp_output < inter_scale)
               dsp_output = inter_scale;
            else
               dsp.tick++;
            }
         if (dsp_output > .2f)
            dsp_output -= 0.1f;
         dsp.kick = dsp_output;
         break;
      case DSP_SPECTRUM_VOLUME:
         {
         int total = 0;
         int last = 0, x;
         for (x = 1; x < 16; x ++)
		      {
			   total += abs(last - this_mod->waveformData[0][x]);
			   last = this_mod->waveformData[0][x];
		      }
         total >>= 4;
		   if (total > 127) total = 127;
         dsp_output = (float)total / 127.0f;
         break;
         }
      default:
         dsp_output = 0;
      }

   // Call entity specific DSP functions:
   for (; ent < &g_edicts[eng.num_edicts]; ent++) 
      if (ent->taken && ent->listen)
         ent->listen(ent, this_mod);

   // Call entity specific DSP functions:
   for (ent = &g_tedicts[0]; ent < &g_tedicts[eng.num_tedicts]; ent++) 
      if (ent->taken && ent->listen)
         ent->listen(ent, this_mod);

   return dsp_output;
}

/*
   NT:
   Render a rectangle of (value) height:
*/
inline void DSPRenderSpectrumBar(float value)
{
   glBegin(GL_TRIANGLE_STRIP);
   glVertex3f (0, 0, 0);
   glVertex3f (DSP_SPECTRUM_BAR_WIDTH, 0, 0);
   glVertex3f (0, 4 + value * 30, 0);
   glVertex3f (DSP_SPECTRUM_BAR_WIDTH, 4 + value * 30, 0);
   glEnd();
}


/*
   NT:
   Render a spectrum at (origin):
*/
void DSPRenderSpectrum(vec3_t origin, struct winampVisModule *this_mod)
{
   float spec_data;
   register float env_x, env_y;
   env_x = cam.origin[0] / 430.0f;
   env_y = -cam.origin[2] / 430.0f;
   int i = 0;
   glEnable(GL_DEPTH_TEST);   
   glDepthMask(false);
   glColor4f(1, 0, 0, .4f);
   glPushMatrix();

   glLoadIdentity();
   glRotatef(-cam.angle[PITCH], 1, 0, 0);
   glRotatef(-cam.angle[YAW], 0, 1, 0);
   glRotatef(-cam.angle[ROLL], 0, 0, 1);
   glTranslatef(-cam.origin[0], -cam.origin[1], -cam.origin[2]);

   glScalef(.4f, .4f, .4f);
   glTranslatef(-35, 33, -398.1);
   //glTranslatef(origin[0], origin[1], origin[2]);


   glDisable(GL_TEXTURE_2D);
   glPushMatrix();
   for (i = 0; i < 10; i++)
      {
      spec_data = (float) this_mod->spectrumData[0][i]/192.0f;
      glColor4f(spec_data, 1 - spec_data, 0, .7f);
      DSPRenderSpectrumBar(spec_data);
      glTranslatef(DSP_SPECTRUM_BAR_WIDTH, 0, 0);
      }
   glEnable(GL_TEXTURE_2D);
   glPopMatrix();

   // NT: Render Reflective glass:
   glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);

   glBindTexture (GL_TEXTURE_2D, r_chrome_skin.index); 
   last_texture = -1;
   glColor4f(1, 1, 1, .38f);
   glBegin(GL_TRIANGLE_STRIP);
      glTexCoord2f(0 + env_x, .10 + env_y);
      glVertex3f (-6, -3, .5f);
      glTexCoord2f(.10 + env_x, .10 + env_y);      
      glVertex3f (DSP_SPECTRUM_BAR_WIDTH * 10 + 6, -3, .5f);
      glTexCoord2f(0 + env_x, 0 + env_y);
      glVertex3f (-6, 58, .5f);
      glTexCoord2f(.10 + env_x, 0 + env_y);
      glVertex3f (DSP_SPECTRUM_BAR_WIDTH * 10 + 6, 58, .5f); 
   glEnd();
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   glDepthMask(true);
   glDisable(GL_DEPTH_TEST);
   glPopMatrix();
}

/*
   NT:
   Render a wave at (origin):
*/
void DSPRenderFrequency(vec3_t origin, struct winampVisModule *this_mod)
{
   float spec_data, x = 0;
   int i = 0; 
   register int nCh = this_mod->nCh;
   glDisable(GL_TEXTURE_2D);
   glColor3f(0, 1, 0);
   glPushMatrix();
   glTranslatef(origin[0], origin[1], origin[2]);
   glBegin(GL_LINE_STRIP);
   for (i = 0; i < 200; i++)
      {
      spec_data = ((int) this_mod->waveformData[0][i*2]^128) / 1024.0f;
      glVertex3f(x, spec_data, 0);
      x += .012f;
      }
   glEnd();
   glPopMatrix();
   glEnable(GL_TEXTURE_2D);
}