program PostProcessing;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Windows,
  GL in 'OpenGL\GL.pas',
  GLu in 'OpenGL\GLu.pas',
  GLut in 'OpenGL\GLut.pas',
  GLext in 'OpenGL\GLext.pas',
  WGLext in 'OpenGL\WGLext.pas',
  GLtools in 'OpenGL\GLtools.pas',
  Math3D in 'Math3D\Math3D.pas',
  VertexArray in 'VertexArray\VertexArray.pas',
  CompiledVertexArray in 'VertexArray\CompiledVertexArray\CompiledVertexArray.pas',
  Images in 'Images\Images.pas',
  TGA in 'Images\TGA\TGA.pas',
  DXT in 'Images\DXT\DXT.pas',
  Textures in 'Textures\Textures.pas',
  Mipmaps in 'Textures\Mipmaps\Mipmaps.pas',
  TextureLODBias in 'Textures\TextureLODBias\TextureLODBias.pas',
  TextureCompression in 'Textures\TextureCompression\TextureCompression.pas',
  S3TC in 'Textures\TextureCompression\S3TC\S3TC.pas',
  AnisotropicFilter in 'Textures\AnisotropicFilter\AnisotropicFilter.pas',
  Texture3D in 'Textures\Texture3D\Texture3D.pas',
  TextureCubeMap in 'Textures\TextureCubeMap\TextureCubeMap.pas',
  TextureRectangle in 'Textures\TextureRectangle\TextureRectangle.pas',
  DepthTexture in 'Textures\DepthTexture\DepthTexture.pas',
  Occlusion in 'Culling\Occlusion\Occlusion.pas',
  ShaderObjects in 'Shaders\GLSL\ShaderObjects\ShaderObjects.pas',
  VertexShaderObject in 'Shaders\GLSL\ShaderObjects\VertexShaderObject\VertexShaderObject.pas',
  FragmentShaderObject in 'Shaders\GLSL\ShaderObjects\FragmentShaderObject\FragmentShaderObject.pas',
  ARBprograms in 'Shaders\ASMShaders\ARBprograms\ARBprograms.pas',
  ARBvertexProgram in 'Shaders\ASMShaders\ARBprograms\ARBvertexProgram\ARBvertexProgram.pas',
  ARBfragmentProgram in 'Shaders\ASMShaders\ARBprograms\ARBfragmentProgram\ARBfragmentProgram.pas',
  TextureCombiners in 'Shaders\TextureCombiners\TextureCombiners.pas',
  Scripts in 'Scripts\Scripts.pas',
  ATIfragmentShader in 'Shaders\ASMShaders\ATIfragmentShader\ATIfragmentShader.pas',
  RegisterCombiners in 'Shaders\RegisterCombiners\RegisterCombiners.pas',
  NV_parse in 'Shaders\NV_parse\NV_parse.pas',
  EnvMapBumpMap in 'Shaders\EnvMapBumpMap\EnvMapBumpMap.pas',
  OffsetTexture in 'Textures\OffsetTexture\OffsetTexture.pas',
  ScissorBox in 'Culling\ScissorBox\ScissorBox.pas',
  Models in 'Models\Models.pas',
  MDF in 'Models\MDF\MDF.pas',
  VertexArrayObject in 'VertexArray\VertexArrayObject\VertexArrayObject.pas',
  TruForm in 'VertexArray\TruForm\TruForm.pas',
  FragmentCombiners in 'Shaders\FragmentCombiners\FragmentCombiners.pas',
  Fonts in 'Fonts\Fonts.pas',
  VertexBufferObject in 'VertexArray\VertexBufferObject\VertexBufferObject.pas',
  Shaders in 'Shaders\Shaders.pas',
  FrameBuffers in 'FrameBuffers\FrameBuffers.pas',
  Camera in 'Camera\Camera.pas',
  FirstPersonCamera in 'Camera\FirstPersonCamera\FirstPersonCamera.pas',
  NewtonImport in 'Newton\NewtonImport.pas',
  PostProcessingPanel in 'PostProcessingPanel.pas' {PPPanel};

const
  OREN_NAYAR_SIGMA                  = 0.5;
  MINNAERT_M                        = 1.5;
  PHONG_N                           = 32;
  BLINN_PHONG_N                     = 64;
  SCHLICK_N                         = 32;
  WARD_ISO_SIGMA                    = 0.1;
  WARD_ANISO_SIGMAX                 = 0.5;
  WARD_ANISO_SIGMAY                 = 0.1;

var
  lx, ly: integer;
  rx, ry: single;
  width: integer = 600;
  height: integer = 600;
  i: integer;

  vs: array[1..5] of TVertexShaderObject;
  fs: array[1..5] of TFragmentShaderObject;
  po: array[1..5] of TProgramObject;
  name: array[1..5] of string = ('dof', 'downsample', 'gauss_h', 'gauss_v', 'bloom');
  tex: array[0..5] of TTexture2D;
  fbo: array[0..3] of TFrameBuffer;
  fbt: array[0..3] of TTexture2D;
  dt: TDepthTexture;
  img: TImage;

procedure display; cdecl;
begin
  fbo[0].Enable;

  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  gluPerspective(60, width/height, 0.1, 100);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;

  glTranslatef(0, 0, -2);
  glRotatef(rx, 1, 0, 0);
  glRotatef(ry, 0, 1, 0);
  glScalef(50, 50, 50);

  glEnable(GL_CULL_FACE);

  tex[4].Enable;

  glBegin(GL_QUADS);

    glNormal3f(0,0,-1);

    glTexCoord2f(1,0);
    glVertex3f(1,1,1);
    glTexCoord2f(1,1);
    glVertex3f(1,-1,1);
    glTexCoord2f(0,1);
    glVertex3f(-1,-1,1);
    glTexCoord2f(0,0);
    glVertex3f(-1,1,1);

  glEnd;

  tex[5].Enable;//

  glBegin(GL_QUADS);

    glNormal3f(0,0,1);

    glTexCoord2f(1,0);
    glVertex3f(-1,1,-1);
    glTexCoord2f(1,1);
    glVertex3f(-1,-1,-1);
    glTexCoord2f(0,1);
    glVertex3f(1,-1,-1);
    glTexCoord2f(0,0);
    glVertex3f(1,1,-1);

  glEnd;

  tex[0].Enable;//

  glBegin(GL_QUADS);

    glNormal3f(-1,0,0);

    glTexCoord2f(1,0);
    glVertex3f(1,1,-1);
    glTexCoord2f(1,1);
    glVertex3f(1,-1,-1);
    glTexCoord2f(0,1);
    glVertex3f(1,-1,1);
    glTexCoord2f(0,0);
    glVertex3f(1,1,1);

  glEnd;

  tex[1].Enable;//

  glBegin(GL_QUADS);

    glNormal3f(1,0,0);

    glTexCoord2f(1,0);
    glVertex3f(-1,1,1);
    glTexCoord2f(1,1);
    glVertex3f(-1,-1,1);
    glTexCoord2f(0,1);
    glVertex3f(-1,-1,-1);
    glTexCoord2f(0,0);
    glVertex3f(-1,1,-1);

  glEnd;

  tex[2].Enable;//

  glBegin(GL_QUADS);

    glNormal3f(0,-1,0);

    glTexCoord2f(0,0);
    glVertex3f(1,1,1);
    glTexCoord2f(1,0);
    glVertex3f(-1,1,1);
    glTexCoord2f(1,1);
    glVertex3f(-1,1,-1);
    glTexCoord2f(0,1);
    glVertex3f(1,1,-1);

  glEnd;

  tex[3].Enable;//

  glBegin(GL_QUADS);

    glNormal3f(0,1,0);

    glTexCoord2f(1,1);
    glVertex3f(1,-1,-1);
    glTexCoord2f(1,0);
    glVertex3f(-1,-1,-1);
    glTexCoord2f(0,0);
    glVertex3f(-1,-1,1);
    glTexCoord2f(0,1);
    glVertex3f(1,-1,1);

  glEnd;

  tex[3].Disable;

  glDisable(GL_CULL_FACE);

  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);

  glutSolidTeapot(0.01);

  glTranslatef(0, 0, 0.02);

  glutSolidTeapot(0.01);

  glTranslatef(0, 0, -0.04);

  glutSolidTeapot(0.01);

  glDisable(GL_LIGHTING);

  fbo[0].Disable;

  glDisable(GL_DEPTH_TEST);
  glDepthMask(GL_FALSE);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  glOrtho(0, 1, 0, 1, 1, 10);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;

  case PostProcessingPanel.PostProcessing of
    PP_NONE:
      begin
        fbt[0].Enable;

        glBegin(GL_QUADS);
          glTexCoord2f(0, 0);
          glVertex3f(0, 0, -2);
          glTexCoord2f(1, 0);
          glVertex3f(1, 0, -2);
          glTexCoord2f(1, 1);
          glVertex3f(1, 1, -2);
          glTexCoord2f(0, 1);
          glVertex3f(0, 1, -2);
        glEnd;
      end;
    PP_MOTION_BLUR:
      begin
        glEnable(GL_BLEND);
        glBlendFunc(GL_ONE_MINUS_CONSTANT_ALPHA, GL_CONSTANT_ALPHA);
        glBlendColor(0,0,0,0.8);

        fbt[0].Enable;

        glBegin(GL_QUADS);
          glTexCoord2f(0, 0);
          glVertex3f(0, 0, -2);
          glTexCoord2f(1, 0);
          glVertex3f(1, 0, -2);
          glTexCoord2f(1, 1);
          glVertex3f(1, 1, -2);
          glTexCoord2f(0, 1);
          glVertex3f(0, 1, -2);
        glEnd;

        glDisable(GL_BLEND);
      end;
    PP_DEPTH_OF_FIELD:
      begin
        po[1].Enable;
        po[1].GetUniformObject('colormap').Value1i := 0;
        po[1].GetUniformObject('depthmap').Value1i := 1;
        fbt[0].Enable;
        glActiveTexture(GL_TEXTURE1);
        dt.Enable;

        glBegin(GL_QUADS);
          glTexCoord2f(0, 0);
          glVertex3f(0, 0, -2);
          glTexCoord2f(1, 0);
          glVertex3f(1, 0, -2);
          glTexCoord2f(1, 1);
          glVertex3f(1, 1, -2);
          glTexCoord2f(0, 1);
          glVertex3f(0, 1, -2);
        glEnd;

        dt.Disable;
        glActiveTexture(GL_TEXTURE0);
        po[1].Disable;
      end;
    PP_BLOOM:
      begin
        // DOWNSAMPLE
        fbo[1].Enable;

        po[2].Enable;
        po[2].GetUniformObject('colormap').Value1i := 0;

        fbt[0].Enable;

        glBegin(GL_QUADS);
          glTexCoord2f(0, 0);
          glVertex3f(0, 0, -2);
          glTexCoord2f(1, 0);
          glVertex3f(1, 0, -2);
          glTexCoord2f(1, 1);
          glVertex3f(1, 1, -2);
          glTexCoord2f(0, 1);
          glVertex3f(0, 1, -2);
        glEnd;

        po[2].Disable;

        fbo[1].Disable;

        // GAUSSIAN BLUR (HORIZONTAL)
        fbo[2].Enable;

        po[3].Enable;
        po[3].GetUniformObject('colormap').Value1i := 0;

        fbt[1].Enable;

        glBegin(GL_QUADS);
          glTexCoord2f(0, 0);
          glVertex3f(0, 0, -2);
          glTexCoord2f(1, 0);
          glVertex3f(1, 0, -2);
          glTexCoord2f(1, 1);
          glVertex3f(1, 1, -2);
          glTexCoord2f(0, 1);
          glVertex3f(0, 1, -2);
        glEnd;

        po[3].Disable;

        fbo[2].Disable;

        // GAUSSIAN BLUR (VERTICAL)
        fbo[3].Enable;

        po[4].Enable;
        po[4].GetUniformObject('colormap').Value1i := 0;

        fbt[2].Enable;

        glBegin(GL_QUADS);
          glTexCoord2f(0, 0);
          glVertex3f(0, 0, -2);
          glTexCoord2f(1, 0);
          glVertex3f(1, 0, -2);
          glTexCoord2f(1, 1);
          glVertex3f(1, 1, -2);
          glTexCoord2f(0, 1);
          glVertex3f(0, 1, -2);
        glEnd;

        po[4].Disable;

        fbo[3].Disable;

        // BLOOM
        po[5].Enable;
        po[5].GetUniformObject('colormap').Value1i := 0;
        po[5].GetUniformObject('blurmap').Value1i := 1;

        fbt[0].Enable;
        glActiveTexture(GL_TEXTURE1);
        fbt[3].Enable;

        glBegin(GL_QUADS);
          glTexCoord2f(0, 0);
          glVertex3f(0, 0, -2);
          glTexCoord2f(1, 0);
          glVertex3f(1, 0, -2);
          glTexCoord2f(1, 1);
          glVertex3f(1, 1, -2);
          glTexCoord2f(0, 1);
          glVertex3f(0, 1, -2);
        glEnd;

        fbt[3].Disable;
        glActiveTexture(GL_TEXTURE0);
        po[5].Disable;
      end;
  end;

  glEnable(GL_DEPTH_TEST);
  glDepthMask(GL_TRUE);

  glutSwapBuffers;
  glutReportErrors;
end;

procedure reshape(w, h: Integer); cdecl;
begin
  width := w;
  height := h;
  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  gluPerspective(60, w/h, 0.1, 100);
  glMatrixMode(GL_MODELVIEW);
end;

procedure keyboard(key: byte; x, y: Integer); cdecl;
begin
  if key = 27 then halt;
end;

procedure special(key, x, y: Integer); cdecl;
begin
end;

procedure mouse(button, state, x, y: Integer); cdecl;
begin
  lx := x;
  ly := y;
end;

procedure motion(x, y: Integer); cdecl;
begin
  rx := rx + (y-ly)*0.5;
  ry := ry + (x-lx)*0.5;
  lx := x;
  ly := y;
end;

procedure passivemotion(x, y: Integer); cdecl;
begin
end;

procedure visibility(state: Integer); cdecl;
begin
end;

procedure idle; cdecl;
begin
end;

procedure timer(value: integer); cdecl;
begin
  glutTimerFunc(15, timer, 0);
  glutPostRedisplay;
end;

begin
  try
    rx := 30;
    ry := -30;

    writeln('***********************');
    writeln('  UTOFELDOLGOZAS DEMO  ');
    writeln('***********************');

    write('GLUT inicializalasa...................');

    glutInit;
    glutInitDisplayMode(GLUT_RGBA or GLUT_DOUBLE or GLUT_DEPTH);
    glutInitWindowSize(600, 600);
    glutCreateWindow('Post Processing Demo');

    Load_GL_VERSION_1_2;
    Load_GL_VERSION_1_3;
    Load_GL_VERSION_1_4;
    Load_GL_VERSION_1_5;
    Load_GL_VERSION_2_0;

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutSpecialFunc(special);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutPassiveMotionFunc(passivemotion);
    glutVisibilityFunc(visibility);
    glutIdleFunc(idle);
    glutTimerFunc(15, timer, 0);

    glEnable(GL_DEPTH_TEST);

    writeln('kesz');

    write('Konfiguracios panel inicializalasa....');

    PPPanel := TPPPanel.Create(nil);
    PPPanel.Show;

    writeln('kesz');

    write('Texturak betoltese....................');

    for i := 0 to 5 do
    begin
      img := LoadTGA('_textures\cubemap'+chr(ord('0')+i)+'.tga');
      tex[i] := TTexture2D.Create;
      GenerateMipmap(tex[i], GL_TRUE);
      tex[i].MagFilter := GL_LINEAR;
      tex[i].MinFilter := GL_LINEAR;
      tex[i].WrapModeS := GL_REPEAT;
      tex[i].WrapModeT := GL_REPEAT;
      tex[i].Image := img;
      img.Destroy;
    end;

    writeln('kesz');

    write('Frame bufferek inicializalasa.........');

    dt := TDepthTexture.Create;
    dt.MagFilter := GL_NEAREST;
    dt.MinFilter := GL_NEAREST;
    dt.WrapModeS := GL_CLAMP;
    dt.WrapModeT := GL_CLAMP;
    glCopyTexImage2D(dt.Target, 0, dt.InternalFormat, 0, 0, 512, 512, 0);
    for i := 0 to 3 do
    begin
      fbt[i] := TTexture2D.Create;
      fbt[i].MagFilter := GL_LINEAR;
      fbt[i].MinFilter := GL_LINEAR;
      fbt[i].WrapModeS := GL_CLAMP;
      fbt[i].WrapModeT := GL_CLAMP;
      if i = 0 then img := LoadTGA('_textures\512.tga')
               else img := LoadTGA('_textures\128.tga');
      fbt[i].Image := img;
      img.Destroy;
      fbo[i] := TFrameBuffer.Create;
      fbo[i].Attach(FBO_COLOR, fbt[i]);
      if i = 0 then      
        fbo[i].Attach(FBO_DEPTH, dt);
      fbo[i].Unbind;
    end;

    writeln('kesz');

    writeln('Shaderek inicializalasa...............');

    for i := 1 to 5 do
    begin
      write(uppercase(name[i]), ' :: beolvasas :: ');
      vs[i] := TVertexShaderObject.Create;
      fs[i] := TFragmentShaderObject.Create;
      po[i] := TProgramObject.Create;
      vs[i].Load('_shaders\'+name[i]+'.vsh');
      fs[i].Load('_shaders\'+name[i]+'.fsh');
      write('forditas :: ');
      vs[i].Compile;
      fs[i].Compile;
      write('szerkesztes :: ');
      po[i].Attach(vs[i]);
      po[i].Attach(fs[i]);
      po[i].Link;
      writeln('kesz');
    end;

    glutMainLoop;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.


