// Standard Windows header file.
#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>             // GLU library
#include <gl\glaux.h>
#include <math.h>    // Define for sine and cosine


#define GL_PI 3.14f

static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;


GLfloat x, z, temp;
GLfloat xTran = 4;
GLfloat zTran = 1;

 

HPALETTE hPalette = NULL;
static HINSTANCE hInstance;

// Forward declaration for the message handler.
LRESULT CALLBACK MyWndProc(HWND, UINT, WPARAM, LPARAM);
void Renderobject1(int h1,int bottom, int r2);
void Rendercube(void);
void Renderpolygon(void);
void RenderBall(void);
void RenderScene(void);
void RenderScene2(void);

BOOL APIENTRY AboutDlgProc (HWND hDlg, UINT message, UINT wParam, LONG lParam);

void SetupLight()
{
GLfloat ambientLight0[] = {0.0f,0.0f,0.5f};
GLfloat diffuseLight0[] = {0.0f,0.0f,1.0f};
GLfloat specularLight0[] = {0.0f,0.0f,1.0f};

GLfloat ambientLight1[] = {0.5f,0.0f,0.0f};
GLfloat diffuseLight1[] = {1.0f,0.0f,0.0f};
GLfloat specularLight1[] = {1.0f,0.0f,0.0f};

GLfloat ambientLight2[] = {0.0f,0.5f,0.0f};
GLfloat diffuseLight2[] = {0.0f,1.0f,0.0f};
GLfloat specularLight2[] = {0.0f,1.0f,0.0f};

GLfloat specref[] = {1.0f, 1.0f, 1.0f, 1.0f};


glEnable(GL_LIGHTING);
glShadeModel(GL_SMOOTH);

glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight0);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight0);
glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight0);
glEnable(GL_LIGHT0);

glLightfv(GL_LIGHT1, GL_AMBIENT, ambientLight1);
glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuseLight1);
glLightfv(GL_LIGHT1, GL_SPECULAR, specularLight1);
glEnable(GL_LIGHT1);

glLightfv(GL_LIGHT2, GL_AMBIENT, ambientLight2);
glLightfv(GL_LIGHT2, GL_DIFFUSE, diffuseLight2);
glLightfv(GL_LIGHT2, GL_SPECULAR, specularLight2);
glEnable(GL_LIGHT2);

glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glMaterialfv(GL_FRONT, GL_SPECULAR, specref);
glMateriali(GL_FRONT, GL_SHININESS, 128);
glMaterialf(GL_FRONT, GL_EMISSION, 100.0f);
}

void ChangeSize(GLsizei w, GLsizei h)
{
 GLfloat nRange = 300.0f;

 // Prevent a divide by zero
 if(h == 0)
  h = 1;

 // Set Viewport to window dimensions
    glViewport(0, 0, w, h);

 // Reset coordinate system
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();

 // Establish clipping volume (left, right, bottom, top, near, far)
    if (w <= h) 
  glOrtho(-nRange, nRange, -nRange*h/w, nRange*h/w,-nRange,nRange);
    else 
  glOrtho(-nRange*w/h, nRange*w/h,-nRange,nRange,-nRange,nRange);

 glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();
}

void SetupRC()
{
 glClearColor(0.0f, 1.0f, 0.8f, 1.0f );

 // Set color shading model to flat
 glShadeModel(GL_FLAT);

 // Clock wise wound polygons are front facing, this is reversed
 // because we are using triangle fans
 glFrontFace(GL_CW);
 SetupLight();
}


GLfloat Rot = 0.0f;

void RenderScene(void)
{ 
 
 GLfloat a = 150.0, b = 110.0;
 GLfloat light0pos[] = {a, 0.0f, b, 1.0f};
 a = 100 * (float)cos(150 * 3.14 / 180);
 b = -5 * (float)sin(150 * 3.14 / 180);
 GLfloat light1pos[] = {a, 0.0f, b, 1.0f};
 a = -15 * (float)cos(120 * 3.14 / 180);
 b = 100 * (float)sin(120 * 3.14/ 180);
 GLfloat light2pos[] = {a, 0.0f, b, 1.0f};

 glLightfv(GL_LIGHT0, GL_POSITION, light0pos); 
 glLightfv(GL_LIGHT1, GL_POSITION, light1pos);
 glLightfv(GL_LIGHT2, GL_POSITION, light2pos);


 glPushMatrix();

 //glEnable(GL_CULL_FACE);
 glShadeModel(GL_SMOOTH);
 glEnable(GL_DEPTH_TEST);
 //glPolygonMode(GL_BACK,GL_LINE);
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 

 glPushMatrix();
 GLfloat i=0,x=0,y=0;
 GLfloat z=0;
 int r=20;
 

 glPushMatrix();
 glRotatef(yRot,1.0f,5.0f,1.0f);
 glShadeModel(GL_SMOOTH);
 glTranslatef(200.0f,0.0f,0.0f);    
 glRotatef(30.0f,0.0f,0.0f,1.0f);


 glShadeModel(GL_SMOOTH);//비행기 돌리기


 glColor3f(0.5f,0.0f,0.5f);//1번 몸통
 glBegin(GL_TRIANGLE_STRIP);
 for(i=0.0f; i<=2.01f*GL_PI; i=i+0.01f)
 { 

  x=(float)(r*cos(i));
  y=(float)(r*sin(i));
  glVertex3f(x,y,-20);
  r=r-10;
  x=(float)(r*cos(i));
  y=(float)(r*sin(i));
  glVertex3f(x,y,-50);
  r=r+10;
 }
 glEnd();

 glColor3f(0.5f,0.0f,0.5f);//2번 몸통
 glBegin(GL_TRIANGLE_STRIP);
 for(i=0.0f; i<=2.01f*GL_PI; i=i+0.01f)
 { 

  x=(float)(r*cos(i));
  y=(float)(r*sin(i));
  glVertex3f(x,y,0);
  x=(float)(r*cos(i));
  y=(float)(r*sin(i));
  glVertex3f(x,y,-20);
 }
 glEnd();

 glColor3f(0.5f,0.0f,0.5f);//3번 몸통
 glBegin(GL_TRIANGLE_STRIP);
 for(i=0.0f; i<=2.01f*GL_PI; i=i+0.01f)
 { 

  x=(float)(r*cos(i));
  y=(float)(r*sin(i));
  glVertex3f(x,y,0);
  r=r-3;
  x=(float)(r*cos(i));
  y=(float)(r*sin(i));
  glVertex3f(x,y,45);
  r=r+3;
 }
 glEnd();

 glColor3f(0.5f,0.0f,0.5f);//4번 몸통
 glBegin(GL_TRIANGLE_STRIP);
 for(i=0.0f; i<=2.01f*GL_PI; i=i+0.01f)
 { 
  r=r-3;
  x=(float)(r*cos(i));
  y=(float)(r*sin(i));
  glVertex3f(x,y,45);
  r=r-10;
  x=(float)(r*cos(i));
  y=(float)(r*sin(i));
  glVertex3f(x,y,130);
  r=r+13;
 }
 glEnd();

 glColor3f(0.5f,0.0f,0.5f);//앞날개 위에 판
 glBegin(GL_TRIANGLE_STRIP);
  glVertex3f(100.0f,0.0f,0.0f);
  glVertex3f(-100.0f,0.0f,0.0f);
  glVertex3f(100.0f,0.0f,-20.0f);
  glVertex3f(-100.0f,0.0f,-20.0f);
 glEnd();
 glColor3f(0.5f,0.0f,0.5f);//앞날개 아래판
  glBegin(GL_TRIANGLE_STRIP);
  glVertex3f(100.0f,-5.0f,0.0f);
  glVertex3f(-100.0f,-5.0f,0.0f);
  glVertex3f(100.0f,-5.0f,-20.0f);
  glVertex3f(-100.0f,-5.0f,-20.0f);
 glEnd();
 glColor3f(0.5f,0.0f,0.5f);//앞날개 옆판
 glBegin(GL_TRIANGLE_STRIP);
  glVertex3f(0.0f,0.0f,0.0f);
  glVertex3f(0.0f,-5.0f,0.0f);
  glVertex3f(100.0f,0.0f,0.0f);
  glVertex3f(100.0f,-5.0f,0.0f);
  glVertex3f(100.0f,0.0f,-20.0f);
  glVertex3f(100.0f,-5.0f,-20.0f);
  glVertex3f(-100.0f,0.0f,-20.0f);
  glVertex3f(-100.0f,-5.0f,-20.0f);
  glVertex3f(-100.0f,0.0f,0.0f);
  glVertex3f(-100.0f,-5.0f,0.0f);
  glVertex3f(0.0f,0.0f,0.0f);
  glVertex3f(0.0f,-5.0f,0.0f);
 glEnd();


    glColor3f(0.5f,0.0f,0.5f);//뒷날개 위에 판
 glBegin(GL_TRIANGLE_STRIP);
  glVertex3f(0.0f,0.0f,90.0f);
  glVertex3f(30.0f,0.0f,115.0f);
  glVertex3f(-30.0f,0.0f,115.0f);
  glVertex3f(30.0f,0.0f,125.0f);
  glVertex3f(-30.0f,0.0f,125.0f);
 glEnd();
 glColor3f(0.5f,0.0f,0.5f);//뒷날개 아래판
  glBegin(GL_TRIANGLE_STRIP);
  glVertex3f(0.0f,-5.0f,90.0f);
  glVertex3f(30.0f,-5.0f,115.0f);
  glVertex3f(-30.0f,-5.0f,115.0f);
  glVertex3f(30.0f,-5.0f,125.0f);
  glVertex3f(-30.0f,-5.0f,125.0f);
 glEnd();
 
 glColor3f(0.5f,0.0f,0.5f);//뒷날개 옆판
 glBegin(GL_TRIANGLE_STRIP);
  glVertex3f(0.0f,0.0f,90.0f);
  glVertex3f(0.0f,-5.0f,90.0f);
  glVertex3f(30.0f,0.0f,115.0f);
  glVertex3f(30.0f,-5.0f,115.0f);
  glVertex3f(30.0f,0.0f,125.0f);
  glVertex3f(30.0f,-5.0f,125.0f);
  glVertex3f(-30.0f,0.0f,125.0f);
  glVertex3f(-30.0f,-5.0f,125.0f);
  glVertex3f(-30.0f,0.0f,115.0f);
  glVertex3f(-30.0f,-5.0f,115.0f);
  glVertex3f(0.0f,0.0f,90.0f);
  glVertex3f(0.0f,-5.0f,90.0f);
 glEnd();

 glColor3f(0.5f,0.0f,0.5f);
 glBegin(GL_TRIANGLE_STRIP);//꼬리부분 막는판
  for(i=0.0f; i<=2.01f*GL_PI; i=i+0.01f)
  { 
   glVertex3f(0,0,130);
   x=(float)(7*cos(i));
   y=(float)(7*sin(i));
   glVertex3f(x,y,130);
  }
 glEnd();
 
 
 glColor3f(0.5f,0.0f,0.5f); //앞에 동그란 뚜껑
 glPushMatrix();
 glTranslatef(0.0,0.0,-50);
 auxSolidSphere(10);
 glPopMatrix();

 glColor3f(0.0f,0.5f,1.0f); //조종석 
 glPushMatrix();
 glTranslatef(0.0,15.0,-10);
 auxSolidSphere(10);
 glPopMatrix();   
 glPushMatrix();
 glTranslatef(0.0,15.0,15);
 auxSolidSphere(10);
 glPopMatrix();
 
 
 glBegin(GL_TRIANGLE_STRIP);
 for(i=0.0f; i<=2.01f*GL_PI; i=i+0.01f)
 { 

  x=(float)(10*cos(i));
  y=(float)(10*sin(i));
  glVertex3f(x,y+15,-10);
  x=(float)(10*cos(i));
  y=(float)(10*sin(i));
  glVertex3f(x,y+15,15);
 }
 glEnd();
 
 glPopMatrix();
 glPopMatrix();
 glPopMatrix();

 glFlush();
}



 

 


// If necessary, creates a 3-3-2 palette for the device context listed.
HPALETTE GetOpenGLPalette(HDC hDC)
 {
 HPALETTE hRetPal = NULL; // Handle to palette to be created
 PIXELFORMATDESCRIPTOR pfd; // Pixel Format Descriptor
 LOGPALETTE *pPal;   // Pointer to memory for logical palette
 int nPixelFormat;   // Pixel format index
 int nColors;    // Number of entries in palette
 int i;      // Counting variable
 BYTE RedRange,GreenRange,BlueRange;
        // Range for each color entry (7,7,and 3)


 // Get the pixel format index and retrieve the pixel format description
 nPixelFormat = GetPixelFormat(hDC);
 DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

 // Does this pixel format require a palette?  If not, do not create a
 // palette and just return NULL
 if(!(pfd.dwFlags & PFD_NEED_PALETTE))
  return NULL;

 // Number of entries in palette.  8 bits yeilds 256 entries
 nColors = 1 << pfd.cColorBits; 

 // Allocate space for a logical palette structure plus all the palette entries
 pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +nColors*sizeof(PALETTEENTRY));

 // Fill in palette header 
 pPal->palVersion = 0x300;  // Windows 3.0
 pPal->palNumEntries = nColors; // table size

 // Build mask of all 1's.  This creates a number represented by having
 // the low order x bits set, where x = pfd.cRedBits, pfd.cGreenBits, and
 // pfd.cBlueBits.  
 RedRange = (1 << pfd.cRedBits) -1;
 GreenRange = (1 << pfd.cGreenBits) - 1;
 BlueRange = (1 << pfd.cBlueBits) -1;

 // Loop through all the palette entries
 for(i = 0; i < nColors; i++)
  {
  // Fill in the 8-bit equivalents for each component
  pPal->palPalEntry[i].peRed = (i >> pfd.cRedShift) & RedRange;
  pPal->palPalEntry[i].peRed = (unsigned char)(
   (double) pPal->palPalEntry[i].peRed * 255.0 / RedRange);

  pPal->palPalEntry[i].peGreen = (i >> pfd.cGreenShift) & GreenRange;
  pPal->palPalEntry[i].peGreen = (unsigned char)(
   (double)pPal->palPalEntry[i].peGreen * 255.0 / GreenRange);

  pPal->palPalEntry[i].peBlue = (i >> pfd.cBlueShift) & BlueRange;
  pPal->palPalEntry[i].peBlue = (unsigned char)(
   (double)pPal->palPalEntry[i].peBlue * 255.0 / BlueRange);

  pPal->palPalEntry[i].peFlags = (unsigned char) NULL;
  }
  

 // Create the palette
 hRetPal = CreatePalette(pPal);

 // Go ahead and select and realize the palette for this device context
 SelectPalette(hDC,hRetPal,FALSE);
 RealizePalette(hDC);

 // Free the memory used for the logical palette structure
 free(pPal);

 // Return the handle to the new palette
 return hRetPal;
 }


// Select the pixel format for a given device context
void SetDCPixelFormat(HDC hDC)
 {
 int nPixelFormat;

 static PIXELFORMATDESCRIPTOR pfd = {
  sizeof(PIXELFORMATDESCRIPTOR), // Size of this structure
  1,        // Version of this structure 
  PFD_DRAW_TO_WINDOW |   // Draw to Window (not to bitmap)
  PFD_SUPPORT_OPENGL |   // Support OpenGL calls in window
  PFD_DOUBLEBUFFER,    // Double buffered mode
  PFD_TYPE_RGBA,     // RGBA Color mode
  24,        // Want 8 bit color 
  0,0,0,0,0,0,     // Not used to select mode
  0,0,       // Not used to select mode
  0,0,0,0,0,      // Not used to select mode
  32,        // Size of depth buffer
  0,        // Not used to select mode
  0,        // Not used to select mode
  PFD_MAIN_PLANE,     // Draw in main plane
  0,        // Not used to select mode
  0,0,0 };      // Not used to select mode

 // Choose a pixel format that best matches that described in pfd
 nPixelFormat = ChoosePixelFormat(hDC, &pfd);

 // Set the pixel format for the device context
 SetPixelFormat(hDC, nPixelFormat, &pfd);
 }

// WinMain: required for all Windows applications.
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, 
       LPSTR lpszCmdLine, int nCmdShow)
{

 char szApplicationName[] = "비행기";
 HWND hwnd;
 MSG msg;
 WNDCLASS wc;

 hInstance = hInst;

 // Window class data structure

 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;   // style: causes repaint when resizing
 wc.lpfnWndProc = (WNDPROC) MyWndProc;   // the window procedure
 wc.cbClsExtra = 0;       // number of extra bytes following the class structure
 wc.cbWndExtra = 0;       // number of extra bytes following the window instance
 wc.hInstance = hInstance;      // this instance that the window procedure is within
 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // the class icon
 wc.hCursor = LoadCursor(NULL, IDC_ARROW);  // the class cursor
 wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);// backgrounds brush
 wc.lpszMenuName = NULL;
 wc.lpszClassName = szApplicationName;   // the app name

 // Register the window.
 RegisterClass(&wc);

 // Now create the window.
 hwnd = CreateWindow(
  szApplicationName,  // registered class name
  szApplicationName,  // window name
  WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,  // window style
  CW_USEDEFAULT,   // x position of window
  CW_USEDEFAULT,   // y position of window
  800,   // width of window
     800,   // height of window
  NULL,
//  HWND_DESKTOP,   // handle to parent window 
  NULL,     // handle to menu identifier
  hInstance,    // handle to application instance 
  NULL      // pointer to window-creation data
 ); 

 // Display the window.
 ShowWindow(hwnd, nCmdShow);
 UpdateWindow(hwnd);

 // Pump messages until a quit message is received.
 while(GetMessage(&msg, NULL, 0,0))
 {
  TranslateMessage(&msg); // translates virtual-key messages into character messages
  DispatchMessage(&msg); // dispatches a message to the window procedure
 }


 return msg.wParam;
}

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 static HGLRC hRC;  // Permenant Rendering context
 static HDC hDC;   // Private GDI Device context

 switch (message)
 {
  // This function is called by Windows to handle messages for this application.
  case WM_CREATE:
   // Store the device context
   hDC = GetDC(hWnd);  

   // Select the pixel format
   SetDCPixelFormat(hDC);  

   // Create the rendering context and make it current
   hRC = wglCreateContext(hDC);
   wglMakeCurrent(hDC, hRC);
   SetupRC();
   // Create the palette
   hPalette = GetOpenGLPalette(hDC);

   //Create a timer that fires every millisecond
   SetTimer(hWnd,101,1,NULL);  //프로펠러 돌리기 타이머
   break;

  // Window is being destroyed, cleanup
  case WM_DESTROY:
   // Kill the timer that we created
   KillTimer(hWnd,101);

   // Deselect the current rendering context and delete it
   wglMakeCurrent(hDC,NULL);
   wglDeleteContext(hRC);

   // Delete the palette
   if(hPalette != NULL)
    DeleteObject(hPalette);

   // Tell the application to terminate after the window
   // is gone.
   PostQuitMessage(0);
   break;

  // Window is resized.
  case WM_SIZE:
   // Call our function which modifies the clipping
   // volume and viewport
   ChangeSize(LOWORD(lParam), HIWORD(lParam));
   break;

  // The painting function.  This message sent by Windows 
  // whenever the screen needs updating.
  case WM_PAINT:
   {
   // Call OpenGL drawing code
    
   RenderScene();

   // Call function to swap the buffers
   SwapBuffers(hDC);

   // Validate the newly painted client area
   ValidateRect(hWnd,NULL);
   }
   break;


  // Windows is telling the application that it may modify
  // the system palette.  This message in essance asks the 
  // application for a new palette.
  case WM_QUERYNEWPALETTE:
   // If the palette was created.
   if(hPalette)
    {
    int nRet;

    // Selects the palette into the current device context
    SelectPalette(hDC, hPalette, FALSE);

    // Map entries from the currently selected palette to
    // the system palette.  The return value is the number 
    // of palette entries modified.
    nRet = RealizePalette(hDC);

    // Repaint, forces remap of palette in current window
    InvalidateRect(hWnd,NULL,FALSE);

    return nRet;
    }
   break;


  // This window may set the palette, even though it is not the 
  // currently active window.
  case WM_PALETTECHANGED:
   // Don't do anything if the palette does not exist, or if
   // this is the window that changed the palette.
   if((hPalette != NULL) && ((HWND)wParam != hWnd))
    {
    // Select the palette into the device context
    SelectPalette(hDC,hPalette,FALSE);

    // Map entries to system palette
    RealizePalette(hDC);
    
    // Remap the current colors to the newly realized palette
    UpdateColors(hDC);
    return 0;
    }
   break;

  case WM_TIMER:  //프로펠러 돌리기 위한 Rot값 증가 
    Rot += 2.0f;
    yRot += 1.5f;
    //xRot += 0.5f;
    InvalidateRect(hWnd,NULL,FALSE);
   break;


  case WM_KEYDOWN:
   {
    if(wParam == VK_UP)
     xRot-= 3.0f;
    if(wParam == VK_DOWN)
     xRot+= 3.0f;
    if(wParam == VK_LEFT)
     yRot-= 3.0f;
    if(wParam == VK_RIGHT)
     yRot+= 3.0f;
    if(xRot > 356.0f)
     xRot = 0.0f;
    if(xRot < -1.0f)
     xRot = 355.0f;
    if(yRot > 356.0f)
     yRot = 0.0f;
    if(yRot < -1.0f)
     yRot = 355.0f; 
   InvalidateRect(hWnd,NULL,FALSE);
   }
   break;

        default:   // Passes it on if unproccessed
            return (DefWindowProc(hWnd, message, wParam, lParam));

        }

    return (0L);
 }

 
