#include <GL/glut.h>
#include <GL/glu.h>
#include <GL/gl.h>
#include <math.h>
#include <unistd.h>

#include "init.h"
#include "globals.h"
#include "sizes.h"
#include "input.h"
#include "game.h"
#include "status.h"
#include "menu.h"
#include "netdata.h"
#include "network.h"
#include "star.h"
#include "texture.h"
#include "object.h"
#include "ship.h"


struct TransparencyQueue {
  int ObjectNumber;
  float zPosition;
  int Type;
};


struct Color White, Black, DarkRed, Red, Green, Blue, LightGray, Gray, DarkGray;
GLuint texture[6];
struct TransparencyQueue TransparenciesQueue[MAX_OBJECTS+MAX_PLAYERS];
int ReverseView;


void DrawTriangle(struct Point *point1, struct Point *point2,
                  struct Point *point3, struct Color *Point1Color,
                  struct Color *Point2Color, struct Color *Point3Color);
void CalcPoint(struct Point *point, struct Point *newpoint);
void CalcPointWithRotation(struct Point *point);
void CalcPointWithRotation(struct Point *point, struct Point *newpoint,
                           struct Point *Position, float RotationMatrix[3][3],
                           float Size);
void CalcPosition(struct Point *Position, struct Point *newPosition);
void DrawPoint(float xpos, float ypos, struct Color *PointColor);
void DrawPoint(struct Point *Position, struct Color *PointColor);
void DrawPoint(struct Point *Position, struct Color *PointColor, float Offset, int type);
void DrawCircle(int xpos, int ypos, struct Color *CircleColor,
                int numPoints, float Size, int offset);
void DrawCircle(Object *Obj, struct Color *CircleColor, float InternalTransparency,
                float ExternalTransparency, int numPoints, float Size);
void DrawExplosion(struct Point *Position, float Age, int Type);
void QueueTransparency(struct Point *Position, int objectnum, int Type);
void DrawObject(Object *Obj);
void DrawCrosshairs();
void InitMatrixMode();
void SetupGameMatrixMode();


void DrawTest()
{
  /*  glBegin(GL_TRIANGLES);
  glColor4f(1.0, 1.0, 1.0, 1.0);
  glVertex3f(-0.025, -0.03, -1.0);
  glVertex3f(0.0, 0.03, -1.0);
  glVertex3f(-0.018, -0.03, -1.0);

  glVertex3f(-0.018, -0.03, -1.0);
  glVertex3f(0.0, 0.03, -1.0);
  glVertex3f(0.0, 0.015, -1.0);

  glVertex3f(0.025, -0.03, -1.0);
  glVertex3f(0.0, 0.03, -1.0);
  glVertex3f(0.018, -0.03, -1.0);

  glVertex3f(0.018, -0.03, -1.0);
  glVertex3f(0.0, 0.03, -1.0);
  glVertex3f(0.0, 0.015, -1.0);

  glVertex3f(-0.009, -0.007, -1.0);
  glVertex3f(-0.009, 0.0, -1.0);
  glVertex3f(0.009, -0.007, -1.0);

  glVertex3f(0.009, 0.0, -1.0);
  glVertex3f(-0.009, 0.0, -1.0);
  glVertex3f(0.009, -0.007, -1.0);
  glEnd();*/
}


void DrawCrosshairs()
{
  struct Color CrossColor;

  CrossColor.red=0.0;
  CrossColor.green=0.0;
  CrossColor.blue=0.55;

  glColor4f(CrossColor.red, CrossColor.green, CrossColor.blue, 0.5);
  glBegin(GL_TRIANGLES);
  glVertex3f(0.0, 0.005, -0.1);
  glVertex3f(0.002, 0.01, -0.1);
  glVertex3f(-0.002, 0.01, -0.1);
  glVertex3f(0.0, -0.005, -0.1);
  glVertex3f(0.002, -0.01, -0.1);
  glVertex3f(-0.002, -0.01, -0.1);
  glVertex3f(0.005, 0.0, -0.1);
  glVertex3f(0.01, 0.002, -0.1);
  glVertex3f(0.01, -0.002, -0.1);
  glVertex3f(-0.005, 0.0, -0.1);
  glVertex3f(-0.01, 0.002, -0.1);
  glVertex3f(-0.01, -0.002, -0.1);
  glEnd();
}

void DrawCircle(int xpos, int ypos, struct Color *CircleColor,
                int numPoints, float Size, int offset)
{
  float xCenter, yCenter;
  float xpoint1, xpoint2, ypoint1, ypoint2;
  int i;
  float twoPI=2.0*3.14159265358;

  xCenter=xpos;
  yCenter=ypos;

  xCenter=(xCenter/ScreenWidth)*2.0-1.0;
  yCenter=(yCenter/ScreenHeight)*2.0-1.0;

  if (offset!=0) {
    glBegin(GL_LINES);
    glColor3f(CircleColor->red, CircleColor->green, CircleColor->blue);
    for (i=offset; i<numPoints; i+=8) {
      glVertex2f(xCenter+cos((twoPI/(float)numPoints)*(float)i)*Size,
                 yCenter+sin((twoPI/(float)numPoints)*(float)i)*Size);
      glVertex2f(xCenter+cos((twoPI/(float)numPoints)*(float)(i+2))*Size,
                 yCenter+sin((twoPI/(float)numPoints)*(float)(i+2))*Size);
    }
  } else {
    glBegin(GL_LINE_LOOP);
    for (i=0; i<numPoints; i++) {
      glVertex2f(xCenter+cos((twoPI/(float)numPoints)*(float)i)*Size,
                 yCenter+sin((twoPI/(float)numPoints)*(float)i)*Size);
    }
  }
  glEnd();
}


void DrawCircle(Object *Obj, struct Color *CircleColor, float InternalTransparency,
                float ExternalTransparency, int numPoints, float Size)
{
  float twoPI=2.0*3.14159265358;
  struct Point tempPoint;
  struct Point newPosition;
  float Distance;
  int i;

  tempPoint.x=0.0;
  tempPoint.y=0.0;
  tempPoint.z=0.0;

  CalcPosition(&Obj->Position, &newPosition);
  CalcPointWithRotation(&newPosition);
  Distance=sqrt(newPosition.x*newPosition.x+newPosition.y*newPosition.y+
                newPosition.z*newPosition.z);

  if (ReverseView) {
    newPosition.z*=-1.0;
  }

  if (Distance > Size) {
    newPosition.x-=Size*(newPosition.x/Distance);
    newPosition.y-=Size*(newPosition.y/Distance);
    newPosition.z-=Size*(newPosition.z/Distance);
  }

  glBegin(GL_TRIANGLES);
  for (i=0; i<numPoints; i++) {
    glColor4f(CircleColor->red, CircleColor->green, CircleColor->blue, InternalTransparency);
    glVertex3f(newPosition.x, newPosition.y, newPosition.z);
    glColor4f(CircleColor->red, CircleColor->green, CircleColor->blue, ExternalTransparency);
    glVertex3f(newPosition.x+cos((twoPI/(float)numPoints)*(float)i)*Size,
               newPosition.y+sin((twoPI/(float)numPoints)*(float)i)*Size,
               newPosition.z);
    glVertex3f(newPosition.x+cos((twoPI/(float)numPoints)*(float)(i+1))*Size,
               newPosition.y+sin((twoPI/(float)numPoints)*(float)(i+1))*Size,
               newPosition.z);
  }
  glEnd();
}


void InitTransparencyQueue()
{
  int i;

  for (i=0; i<MAX_OBJECTS+MAX_PLAYERS; i++) {
    TransparenciesQueue[i].ObjectNumber=-1;
  }
}


void QueueTransparency(struct Point *Position, int objectnum, int Type)
{
  int i, j;
  struct Point relPosition;

  CalcPoint(Position, &relPosition);
  if (ReverseView) {
    relPosition.z*=-1.0;
  }

  if (relPosition.z < 0.0) {
    for (i=0; i<MAX_OBJECTS+MAX_PLAYERS; i++) {
      if (TransparenciesQueue[i].ObjectNumber==-1) {
        TransparenciesQueue[i].ObjectNumber=objectnum;
        TransparenciesQueue[i].zPosition=relPosition.z;
        TransparenciesQueue[i].Type=Type;
        break;
      } else if (relPosition.z < TransparenciesQueue[i].zPosition) {
        for (j=MAX_OBJECTS-1; j>i; j--) {
          TransparenciesQueue[j].ObjectNumber=TransparenciesQueue[j-1].ObjectNumber;
          TransparenciesQueue[j].zPosition=TransparenciesQueue[j-1].zPosition;
          TransparenciesQueue[j].Type=TransparenciesQueue[j-1].Type;
        }
        TransparenciesQueue[i].ObjectNumber=objectnum;
        TransparenciesQueue[i].zPosition=relPosition.z;
        TransparenciesQueue[i].Type=Type;
        break;
      }
    }
  }
}


void DrawExplosion(struct Point *Position, float Age, int Type)
{
  struct Point relPosition;
  float Size;

  glEnable(GL_TEXTURE_2D);

  if (Type==EXPLOSION_TYPE) {
    Size=0.05*(1.0+2.0*Age);
  } else {
    Size=0.2*(0.25+2.0*Age);
  }

  if (Age < 1.0) {
      CalcPoint(Position, &relPosition);
      if (ReverseView) {
        relPosition.z*=-1.0;
      }

      glBindTexture(GL_TEXTURE_2D, texture[0]); 

      glColor4f(1.0, 1.0, 1.0, 1.0-Age);

      glBegin(GL_QUADS);
      glTexCoord2f(0, 1); glVertex3f(-Size+relPosition.x, Size+relPosition.y, relPosition.z);
      glTexCoord2f(0, 0); glVertex3f(-Size+relPosition.x, -Size+relPosition.y, relPosition.z);
      glTexCoord2f(1, 0); glVertex3f(Size+relPosition.x, -Size+relPosition.y, relPosition.z);
      glTexCoord2f(1, 1); glVertex3f(Size+relPosition.x, Size+relPosition.y, relPosition.z);
      glEnd();
  }

  glDisable(GL_TEXTURE_2D);
}


void DrawTransparencies()
{
  int i;
  struct Color ShieldColor;
  struct Color PowerupColor;
  struct Color NukeExplosionColor;

  ShieldColor.red=0.5;
  ShieldColor.green=0.4;
  ShieldColor.blue=1.0;

  PowerupColor.red=0.4;
  PowerupColor.green=0.6;
  PowerupColor.blue=0.0;

  NukeExplosionColor.red=0.6;
  NukeExplosionColor.green=0.0;
  NukeExplosionColor.blue=0.0;

  for (i=0; i<MAX_OBJECTS+MAX_PLAYERS; i++) {
    if (TransparenciesQueue[i].ObjectNumber!=-1) {
      if (TransparenciesQueue[i].Type==1) {
        DrawExplosion(&Objects[TransparenciesQueue[i].ObjectNumber]->Position, Objects[TransparenciesQueue[i].ObjectNumber]->Age, Objects[TransparenciesQueue[i].ObjectNumber]->Type);
      } else if (TransparenciesQueue[i].Type==2) {
        DrawCircle(Ships[TransparenciesQueue[i].ObjectNumber], &ShieldColor,
                   0.15, 0.5, 64, Ships[TransparenciesQueue[i].ObjectNumber]->Size);
      } else if (TransparenciesQueue[i].Type==3) {
        DrawCircle(Objects[TransparenciesQueue[i].ObjectNumber], &PowerupColor,
                   0.3, 0.5, 64, Objects[TransparenciesQueue[i].ObjectNumber]->Size);
      } else if (TransparenciesQueue[i].Type==4) {
        DrawCircle(Objects[TransparenciesQueue[i].ObjectNumber], &NukeExplosionColor,
                   0.5, 0.35, 256, Objects[TransparenciesQueue[i].ObjectNumber]->Size);
      }
    }
  }
}


// Function to draw a line on the screen
void DrawLine(int x1pos, int y1pos, int x2pos, int y2pos, struct Color *LineColor)
{
  float x1, y1, x2, y2;

  x1=x1pos;
  y1=y1pos;
  x2=x2pos;
  y2=y2pos;

  x1=(x1/ScreenWidth)*2.0-1.0;
  y1=(y1/ScreenHeight)*2.0-1.0;
  x2=(x2/ScreenWidth)*2.0-1.0;
  y2=(y2/ScreenHeight)*2.0-1.0;

  glBegin(GL_LINES);
  glColor3f(LineColor->red, LineColor->green, LineColor->blue);
  glVertex2f(x1, y1);
  glVertex2f(x2, y2);
  glEnd();
}


/*
  Function to draw a point on the screen
  glDrawPixels is used instead of glVertex2f, because the points were showing
  up in front of the blits
*/
void DrawPoint(int xpos, int ypos, struct Color *PointColor)
{
  float x, y;

  x=xpos;
  y=ypos;

  x=(x/ScreenWidth)*2.0-1.0;
  y=(y/ScreenHeight)*2.0-1.0;

  glBegin(GL_POINTS);
  glColor3f(PointColor->red, PointColor->green, PointColor->blue);
  glVertex2f(x, y);
  glEnd();
}


void DrawPoint(struct Point *Position, struct Color *PointColor)
{
  struct Point tempPosition;

  tempPosition.x=Ships[myShip]->CameraMatrix[0][0]*Position->x+Ships[myShip]->CameraMatrix[0][1]*Position->y+Ships[myShip]->CameraMatrix[0][2]*Position->z;
  tempPosition.y=Ships[myShip]->CameraMatrix[1][0]*Position->x+Ships[myShip]->CameraMatrix[1][1]*Position->y+Ships[myShip]->CameraMatrix[1][2]*Position->z;
  tempPosition.z=Ships[myShip]->CameraMatrix[2][0]*Position->x+Ships[myShip]->CameraMatrix[2][1]*Position->y+Ships[myShip]->CameraMatrix[2][2]*Position->z;

  if (ReverseView) {
    tempPosition.z*=-1.0;
  }

  if (tempPosition.z > 0.0) {
    return;
  }

  // Check if point is within radar
  if (tempPosition.x < 3.0 && tempPosition.x > -3.0 &&
      tempPosition.y < -3.0 && tempPosition.y > -7.0) {
    return;
  }

  glBegin(GL_POINTS);
  glColor3f(PointColor->red, PointColor->green, PointColor->blue);
  glVertex3f(tempPosition.x, tempPosition.y, tempPosition.z);
  glEnd();
}


void DrawPoint(struct Point *Position, struct Color *PointColor, float Offset, int type)
{
  struct Point tempPosition;

  tempPosition.x=Ships[myShip]->CameraMatrix[0][0]*Position->x+Ships[myShip]->CameraMatrix[0][1]*Position->y+Ships[myShip]->CameraMatrix[0][2]*Position->z;
  tempPosition.y=Ships[myShip]->CameraMatrix[1][0]*Position->x+Ships[myShip]->CameraMatrix[1][1]*Position->y+Ships[myShip]->CameraMatrix[1][2]*Position->z;
  tempPosition.z=Ships[myShip]->CameraMatrix[2][0]*Position->x+Ships[myShip]->CameraMatrix[2][1]*Position->y+Ships[myShip]->CameraMatrix[2][2]*Position->z;

  if (type==0) {
    tempPosition.x+=Offset;
  } else if (type==1) {
    tempPosition.y+=Offset;
  } else {
    tempPosition.z+=Offset;
  }

  if (ReverseView) {
    tempPosition.z*=-1.0;
  }

  if (tempPosition.z > 0.0) {
    return;
  }

  // Check if point is within radar
  if (tempPosition.x < 3.0 && tempPosition.x > -3.0 &&
      tempPosition.y < -3.0 && tempPosition.y > -7.0) {
    return;
  }

  glBegin(GL_POINTS);
  glColor3f(PointColor->red, PointColor->green, PointColor->blue);
  glVertex3f(tempPosition.x, tempPosition.y, tempPosition.z);
  glEnd();
}


/*
  Function to draw text on the screen, it returns the x position after the text
  is drawn.
*/
int DrawText(int xpos, int ypos, char *text, struct Color *TextColor, int big=0)
{
  float x, y;
  float CharWidth;

  x=xpos;
  y=ypos;

  x=(x/ScreenWidth)*2.0-1.0;
  y=(y/ScreenHeight)*2.0-1.0;

  glColor3f(TextColor->red, TextColor->green, TextColor->blue);
  while (*text) {
    glRasterPos2f(x, y);
    if (big) {
#ifndef CYGWIN
      glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *text);
      CharWidth=glutBitmapWidth(GLUT_BITMAP_HELVETICA_18, *text);
#else
      glutBitmapCharacter((void *)8, *text);
      CharWidth=glutBitmapWidth((void *)8, *text);
#endif
    } else {
#ifndef CYGWIN
      glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, *text);
      CharWidth=glutBitmapWidth(GLUT_BITMAP_HELVETICA_10, *text);
#else
      glutBitmapCharacter((void *)6, *text);
      CharWidth=glutBitmapWidth((void *)6, *text);
#endif
    }
    x+=(CharWidth/ScreenWidth)*2.0;
    xpos+=(int)CharWidth;
    text++;
  }
  return(xpos);
}


// Function to draw a rectangle on the screen
void DrawRect(int x1pos, int y1pos, int x2pos, int y2pos,
              int x3pos, int y3pos, int x4pos, int y4pos,
              struct Color *LineColor)
{
  float x1, y1, x2, y2, x3, y3, x4, y4;

  x1=x1pos;
  y1=y1pos;
  x2=x2pos;
  y2=y2pos;
  x3=x3pos;
  y3=y3pos;
  x4=x4pos;
  y4=y4pos;

  x1=(x1/ScreenWidth)*2.0-1.0;
  y1=(y1/ScreenHeight)*2.0-1.0;
  x2=(x2/ScreenWidth)*2.0-1.0;
  y2=(y2/ScreenHeight)*2.0-1.0;
  x3=(x3/ScreenWidth)*2.0-1.0;
  y3=(y3/ScreenHeight)*2.0-1.0;
  x4=(x4/ScreenWidth)*2.0-1.0;
  y4=(y4/ScreenHeight)*2.0-1.0;

  glBegin(GL_QUADS);
  glColor3f(LineColor->red, LineColor->green, LineColor->blue);
  glVertex2f(x1, y1);
  glVertex2f(x2, y2);
  glVertex2f(x3, y3);
  glVertex2f(x4, y4);
  glEnd();
}


// Function to initialize the screen and setup keyboard callbacks
void InitScreen()
{
  GLenum type;
  char TextureFileName[1000];

  MainMenuItemHighlighted=0;
  ConfMenuItemHighlighted=15;
  ScoreMenuItemHighlighted=1;
  NewScreenWidth=ScreenWidth;
  NewScreenHeight=ScreenHeight;

  type = GLUT_DEPTH | GLUT_RGB | GLUT_DOUBLE;
  glutInitDisplayMode(type);
  glutInitWindowSize(ScreenWidth, ScreenHeight);
  glutCreateWindow("Avoid The Roid");
  glutIgnoreKeyRepeat(1);
  glutSpecialFunc(MainMenuSpecialKey);
  glutKeyboardFunc(MainMenuKey);
  glutIdleFunc(NULL);
  glutDisplayFunc(MainMenu);
  glClearColor(0, 0, 0, 0);
  glColor3f(1, 1, 1);
  glGenTextures(1, texture);
#ifdef WINDOWS
  sprintf(TextureFileName, "textures/explosion.rgb");
#else
  sprintf(TextureFileName, "%s/atr3d/textures/explosion.rgb", DATADIR);
#endif
  LoadTexture(TextureFileName);
  glEnable(GL_DEPTH_TEST);
}


void StartGame()
{
  glutMainLoop();
}


void ClearScreen()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glDisable(GL_LIGHT1);
}


void Setup3dMode()
{
  glClearColor(0.0, 0.0, 0.0, 0.0);
  glShadeModel(GL_SMOOTH);
  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  glLoadIdentity();
}



void UpdateScreen()
{
  glutSwapBuffers();
}


void InitColors()
{
  White.red=1.0;
  White.green=1.0;
  White.blue=1.0;

  Black.red=0.0;
  Black.green=0.0;
  Black.blue=0.0;

  Red.red=1.0;
  Red.green=0.0;
  Red.blue=0.0;

  DarkRed.red=0.7;
  DarkRed.green=0.0;
  DarkRed.blue=0.0;

  Green.red=0.0;
  Green.green=1.0;
  Green.blue=0.0;

  Blue.red=0.0;
  Blue.green=0.0;
  Blue.blue=1.0;

  LightGray.red=0.7;
  LightGray.green=0.7;
  LightGray.blue=0.7;

  Gray.red=0.45;
  Gray.green=0.45;
  Gray.blue=0.45;

  DarkGray.red=0.2;
  DarkGray.green=0.2;
  DarkGray.blue=0.2;
}


void DrawTriangle(struct Point *point1, struct Point *point2,
                  struct Point *point3, struct Color *Point1Color,
                  struct Color *Point2Color, struct Color *Point3Color)
{
  if (ReverseView) {
    point1->z*=-1.0;
    point2->z*=-1.0;
    point3->z*=-1.0;
  }

  glBegin(GL_TRIANGLES);
  glColor3f(Point1Color->red, Point1Color->green, Point1Color->blue);
  glVertex3f(point1->x, point1->y, point1->z);
  glColor3f(Point2Color->red, Point2Color->green, Point2Color->blue);
  glVertex3f(point2->x, point2->y, point2->z);
  glColor3f(Point3Color->red, Point3Color->green, Point3Color->blue);
  glVertex3f(point3->x, point3->y, point3->z);
  glEnd();
}


void CalcPosition(struct Point *Position, struct Point *newPosition)
{
  newPosition->x=Position->x-Ships[myShip]->Position.x;
  newPosition->y=Position->y-Ships[myShip]->Position.y;
  newPosition->z=Position->z-Ships[myShip]->Position.z;

  if (newPosition->x > WorldWidth) {
    newPosition->x-=WorldWidth*2.0;
  }
  if (newPosition->y > WorldWidth) {
    newPosition->y-=WorldWidth*2.0;
  }
  if (newPosition->z > WorldWidth) {
    newPosition->z-=WorldWidth*2.0;
  }
  if (newPosition->x < -WorldWidth) {
    newPosition->x+=WorldWidth*2.0;
  }
  if (newPosition->y < -WorldWidth) {
    newPosition->y+=WorldWidth*2.0;
  }
  if (newPosition->z < -WorldWidth) {
    newPosition->z+=WorldWidth*2.0;
  }
}


void CalcPoint(struct Point *point, struct Point *newpoint)
{
  struct Point tmpPoint;

  CalcPosition(point, &tmpPoint);

  newpoint->x=Ships[myShip]->CameraMatrix[0][0]*tmpPoint.x+Ships[myShip]->CameraMatrix[0][1]*tmpPoint.y+Ships[myShip]->CameraMatrix[0][2]*tmpPoint.z;
  newpoint->y=Ships[myShip]->CameraMatrix[1][0]*tmpPoint.x+Ships[myShip]->CameraMatrix[1][1]*tmpPoint.y+Ships[myShip]->CameraMatrix[1][2]*tmpPoint.z;
  newpoint->z=Ships[myShip]->CameraMatrix[2][0]*tmpPoint.x+Ships[myShip]->CameraMatrix[2][1]*tmpPoint.y+Ships[myShip]->CameraMatrix[2][2]*tmpPoint.z;
}


void CalcPointWithRotation(struct Point *point, struct Point *newpoint,
                           struct Point *Position, float RotationMatrix[3][3],
                           float Size)
{
  struct Point tmpPoint;

  tmpPoint.x=RotationMatrix[0][0]*point->x+RotationMatrix[0][1]*point->y+RotationMatrix[0][2]*point->z;
  tmpPoint.y=RotationMatrix[1][0]*point->x+RotationMatrix[1][1]*point->y+RotationMatrix[1][2]*point->z;
  tmpPoint.z=RotationMatrix[2][0]*point->x+RotationMatrix[2][1]*point->y+RotationMatrix[2][2]*point->z;

  tmpPoint.x*=Size;
  tmpPoint.y*=Size;
  tmpPoint.z*=Size;

  tmpPoint.x+=Position->x;
  tmpPoint.y+=Position->y;
  tmpPoint.z+=Position->z;

  newpoint->x=Ships[myShip]->CameraMatrix[0][0]*tmpPoint.x+Ships[myShip]->CameraMatrix[0][1]*tmpPoint.y+Ships[myShip]->CameraMatrix[0][2]*tmpPoint.z;
  newpoint->y=Ships[myShip]->CameraMatrix[1][0]*tmpPoint.x+Ships[myShip]->CameraMatrix[1][1]*tmpPoint.y+Ships[myShip]->CameraMatrix[1][2]*tmpPoint.z;
  newpoint->z=Ships[myShip]->CameraMatrix[2][0]*tmpPoint.x+Ships[myShip]->CameraMatrix[2][1]*tmpPoint.y+Ships[myShip]->CameraMatrix[2][2]*tmpPoint.z;
}


void CalcPointWithRotation(struct Point *point)
{
  struct Point tmpPoint;

  tmpPoint.x=point->x;
  tmpPoint.y=point->y;
  tmpPoint.z=point->z;

  point->x=Ships[myShip]->CameraMatrix[0][0]*tmpPoint.x+Ships[myShip]->CameraMatrix[0][1]*tmpPoint.y+Ships[myShip]->CameraMatrix[0][2]*tmpPoint.z;
  point->y=Ships[myShip]->CameraMatrix[1][0]*tmpPoint.x+Ships[myShip]->CameraMatrix[1][1]*tmpPoint.y+Ships[myShip]->CameraMatrix[1][2]*tmpPoint.z;
  point->z=Ships[myShip]->CameraMatrix[2][0]*tmpPoint.x+Ships[myShip]->CameraMatrix[2][1]*tmpPoint.y+Ships[myShip]->CameraMatrix[2][2]*tmpPoint.z;
}


void CalcRotation(struct Point *point, struct Point *newpoint,
                  float RotationMatrix[3][3])
{
  newpoint->x=RotationMatrix[0][0]*point->x+RotationMatrix[0][1]*point->y+RotationMatrix[0][2]*point->z;
  newpoint->y=RotationMatrix[1][0]*point->x+RotationMatrix[1][1]*point->y+RotationMatrix[1][2]*point->z;
  newpoint->z=RotationMatrix[2][0]*point->x+RotationMatrix[2][1]*point->y+RotationMatrix[2][2]*point->z;
}


void DrawPowerup(Object *Obj)
{
  struct Triangle *tempModel;
  struct Point newPosition;
  struct Point testPosition;
  struct Point tempPoints[3];
  int i, j;

  CalcPosition(&Obj->Position, &newPosition);

  // Check if object is behind the player, if so don't draw
  memcpy(&testPosition, &newPosition, sizeof(struct Point));
  CalcPointWithRotation(&testPosition);

  if (ReverseView) {
    testPosition.z*=-1.0;
  }

  if (testPosition.z > 0.0) {
    return;
  }

  if (ReverseView) {
    testPosition.z*=-1.0;
  }

  for (i=0; i<Obj->ObjModel->NumSides; i++) {
    for (j=0; j<3; j++) {
      tempPoints[j].x=testPosition.x+Obj->ObjModel->Sides[i].Vertices[j]->x*Obj->Size;
      tempPoints[j].y=testPosition.y+Obj->ObjModel->Sides[i].Vertices[j]->y*Obj->Size;
      tempPoints[j].z=testPosition.z+Obj->ObjModel->Sides[i].Vertices[j]->z*Obj->Size;
    }

    DrawTriangle(&tempPoints[0], &tempPoints[1], &tempPoints[2],
                 Obj->ObjModel->Sides[i].VertexColors[0],
                 Obj->ObjModel->Sides[i].VertexColors[1],
                 Obj->ObjModel->Sides[i].VertexColors[2]);
  }
}


void DrawObject(Object *Obj)
{
  struct Triangle *tempModel;
  struct Point newPosition;
  struct Point testPosition;
  struct Point tempPoints[3];
  int i, j;

  CalcPosition(&Obj->Position, &newPosition);

  // Check if object is behind the player, if so don't draw
  memcpy(&testPosition, &newPosition, sizeof(struct Point));
  CalcPointWithRotation(&testPosition);
  if (ReverseView) {
    testPosition.z*=-1.0;
  }

  if (testPosition.z > 0.0) {
    return;
  }

  for (i=0; i<Obj->ObjModel->NumSides; i++) {
    for (j=0; j<3; j++) {
      CalcPointWithRotation(Obj->ObjModel->Sides[i].Vertices[j],
                            &tempPoints[j], &newPosition,
                            Obj->RotationMatrix, Obj->Size);
    }

    DrawTriangle(&tempPoints[0], &tempPoints[1], &tempPoints[2],
                 Obj->ObjModel->Sides[i].VertexColors[0],
                 Obj->ObjModel->Sides[i].VertexColors[1],
                 Obj->ObjModel->Sides[i].VertexColors[2]);
  }
}


void LoadTexture(char *fn)
{
  int texwid, texht;
  int texcomps;
  unsigned *teximage;

  teximage = read_texture(fn, &texwid, &texht, &texcomps);
  if (!teximage) {
    printf("Sorry, can't read texture file...");
    exit(0);
  }
  glBindTexture(GL_TEXTURE_2D, texture[0]);
  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  glTexImage2D(GL_TEXTURE_2D, 0, 3, texwid, texht, 0, GL_RGBA, GL_UNSIGNED_BYTE, teximage);
  gluBuild2DMipmaps(GL_TEXTURE_2D, 3, texwid, texht, GL_RGBA, GL_UNSIGNED_BYTE, teximage);

  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); 

  free(teximage);
} 


void EnableTransparency()
{
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);
}


void DisableTransparency()
{
  glDisable(GL_BLEND);
}


void InitMatrixMode()
{
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
}


void SetupGameMatrixMode()
{
  float Ratio;

  Ratio=(float)ScreenWidth/(float)ScreenHeight;
  gluPerspective(60.0, Ratio, 0.1, 20.0);
  glMatrixMode(GL_MODELVIEW);
}
