unit GLRender;

interface
  uses  windows, OpenGL, RoadGraphic, RoadSys;

type
    TGLFont  = class(TGraphicFont)
      ListBase  : cardinal;
      GMF       : array[0..255] of TGlyphMetricsFloat;
      procedure DrawText2D(X,Y : Single; Text : String);override;
      procedure DrawText3D(X,Y,Z : Single; Text : String);override;
      destructor Destroy;override;
    end;

    TGLRender   = class(TBaseRender)
      procedure DrawTriangles(VertexBuffer : pointer; NormalBuffer : pointer; TexBuffer : pointer; TrianglesCount : integer);override;
      procedure DrawQuads(VertexBuffer : pointer; NormalBuffer : pointer; TexBuffer : pointer; TrianglesCount : integer);override;
      function CreateFont(FontName : string; FontHeight : integer) : TGraphicFont;override;
      function CreateVectorFont(FontName : string; FontHeight : integer) : TGraphicFont;override;
      procedure InitRender(Handle : Cardinal; vDC  : HDC);override;
      procedure FreeRender;override;
      procedure SetRenderContext;override;
      procedure FreeRenderContext;override;
      procedure ClearBuffer;override;
      procedure SetPerspective;override;
      procedure ResetProjectionMatrix;override;
      procedure ResetModelViewMatrix;override;
      procedure LookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ: Single);override;
      procedure SwapBuffers;override;
      private
        GLCon : HGLRC;
    end;

  TTextureGL = class
    Width,
    Height : Integer;
    pBits : Pointer;
    destructor Destroy; override;
    procedure LoadFromBMP(const AFileName : String);
    procedure Enable;
    procedure Disable;
  end;

procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external opengl32;
procedure glGenTextures(n: GLsizei; var textures: GLuint); stdcall; external opengl32;

implementation
  uses  RoadGlobal;

procedure TGLRender.ClearBuffer;
begin
  inherited;
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
end;

function TGLRender.CreateFont(FontName: string;
  FontHeight: integer): TGraphicFont;
begin
  Result  :=  TGLFont.Create;
  with (Result as TGLFont) do
    begin
      Result.Font :=  TFont.Create(FontName,FontHeight);
      SelectObject(DC,Result.Font.Font);
      ListBase  :=  glGenLists(256);
      wglUseFontBitmaps(DC,0,256,ListBase);
    end;
end;

function TGLRender.CreateVectorFont(FontName: string;
  FontHeight: integer): TGraphicFont;
begin
  Result  :=  TGLFont.Create;
  with (Result as TGLFont) do
    begin
      Result.Font :=  TFont.Create(FontName,FontHeight);
      SelectObject(DC,Result.Font.Font);
      ListBase  :=  glGenLists(256);
      wglUseFontOutlines(DC,0,256,ListBase,0.0,0.2,WGL_FONT_POLYGONS,@GMF[0]);
    end;
end;

procedure TGLRender.DrawQuads(VertexBuffer, NormalBuffer,
  TexBuffer: pointer; TrianglesCount: integer);
var
  i : integer;
  j : integer;
begin
  inherited;
  glBegin(GL_QUADS);
    for i:=0  to  TrianglesCount-1 do
      begin
        glNormal3fv(pointer(integer(NormalBuffer)+3*i*SizeOf(Single)));
        glTexCoord2fv(pointer(integer(TexBuffer)+2*i*SizeOf(Single)));
        glVertex3fv(pointer(integer(VertexBuffer)+3*i*SizeOf(Single)));
      end;
  glEnd;

end;

procedure TGLRender.DrawTriangles(VertexBuffer : pointer; NormalBuffer : pointer; TexBuffer : pointer; TrianglesCount : integer);
var
  i : integer;
begin
  inherited;
  glBegin(GL_TRIANGLES);
    for i:=0  to  TrianglesCount-1 do
      begin
        glNormal3fv(pointer(integer(NormalBuffer)+3*i*SizeOf(Single)));
        glTexCoord2fv(pointer(integer(TexBuffer)+2*i*SizeOf(Single)));
        glVertex3fv(pointer(integer(VertexBuffer)+3*i*SizeOf(Single)));
      end;
  glEnd;
end;

procedure TGLRender.FreeRender;
begin
  inherited;
  FreeRenderContext;
  wglDeleteContext(GLCon);
end;

procedure TGLRender.FreeRenderContext;
begin
  inherited;
  wglMakeCurrent(0,0);
end;

procedure TGLRender.InitRender(Handle: Cardinal; vDC: HDC);
var
  pfd : TPixelFormatDescriptor;
  ipf : integer;
begin
  inherited;
  DC  :=  vDC;
  ZeroMemory(@pfd,SizeOf(pfd));
  with pfd do
    begin
      nSize     :=  SizeOf(ipf);
      nVersion  :=  1;
      dwFlags   :=  PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;;
      iPixelType  :=  PFD_TYPE_RGBA;
      cColorBits  :=  24;
      iLayerType  :=  PFD_MAIN_PLANE;
      cDepthBits  :=  32;
    end;
  ipf :=  ChoosePixelFormat(DC,@pfd);
  SetPixelFormat(DC,ipf,@pfd);
  GLCon :=  wglCreateContext(DC);
  wglMakeCurrent(DC,GLCon);
end;

procedure TGLRender.LookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ: Single);
begin
  inherited;
  gluLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
end;


procedure TGLRender.ResetModelViewMatrix;
begin
  inherited;
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;
end;

procedure TGLRender.ResetProjectionMatrix;
begin
  inherited;
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
end;

procedure TGLRender.SetPerspective;
begin
  inherited;
  gluPerspective(45,Application.Window.Width/Application.Window.Height,0.1,100);
end;

procedure TGLRender.SetRenderContext;
begin
  inherited;
  wglMakeCurrent(DC,GLCon);
end;

procedure TGLRender.SwapBuffers;
begin
  inherited;
  windows.SwapBuffers(DC);
end;


Destructor TTextureGL.Destroy;
begin
  if Assigned(pBits) then FreeMem(pBits);
  Inherited Destroy;
end;

procedure TTextureGl.LoadFromBMP( const AFileName : String);
var
  B : TBitmap;
begin
  B := TBitmap.Create;
  B.LoadFromFile(AFileName);
  Width := B.Width;
  Height := B.Height;
  GetMem(pBits,Width*Height*3);
  CopyMemory(pBits,B.bits,Width*Height*3);
  B.Free;
end;

procedure TTextureGL.Enable;
begin
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

  glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,Width,Height,0,GL_RGB,GL_UNSIGNED_BYTE,pBits);

  glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
  glEnable(GL_TEXTURE_2D);
end;

procedure TTextureGL.Disable;
begin
  glDisable(GL_TEXTURE_2D);
end;

{ TGLFont }

destructor TGLFont.Destroy;
begin
  glDeleteLists(ListBase,256);
  inherited;
end;

procedure TGLFont.DrawText2D(X, Y: Single; Text: String);
var
  Raster:array[1..4] of Single;
begin
  inherited;
  glGetError;
  glPushAttrib(GL_LIST_BIT);
    glRasterPos2f(X,Y);
    glListBase(ListBase);
    glCallLists(Length(Text),GL_UNSIGNED_BYTE,@Text[1]);
  glPopAttrib;
end;

procedure TGLFont.DrawText3D(X, Y, Z: Single; Text: String);
begin
  inherited;
  glPushAttrib(GL_LIST_BIT);
    glRasterPos3f(X,Y,Z);
    glListBase(ListBase);
    glCallLists(Length(Text),GL_UNSIGNED_BYTE,@Text[1]);
  glPopAttrib;
end;

end.
