DEADSOFTWARE

added optional framebuffer and resolution scaling
[d2df-sdl.git] / src / engine / e_graphics.pas
index b1d34101d44014c5ab06d3aa6b96dcfc32d94863..18f75c44ea3263119bd6bfbb429a614c05060e09 100644 (file)
@@ -2,8 +2,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation, version 3 of the License ONLY.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,7 +19,11 @@ interface
 
 uses
   {$INCLUDE ../nogl/noGLuses.inc}
-  SysUtils, Classes, Math, e_log, e_texture, SDL2, MAPDEF, ImagingTypes, Imaging, ImagingUtility;
+  {$IFDEF USE_SDL2}
+    SDL2,
+  {$ENDIF}
+  SysUtils, Classes, Math, e_log, e_texture,
+  MAPDEF, ImagingTypes, Imaging, ImagingUtility;
 
 type
   TMirrorType=(None, Horizontal, Vertical);
@@ -59,6 +62,8 @@ type
 procedure e_InitGL();
 procedure e_SetViewPort(X, Y, Width, Height: Word);
 procedure e_ResizeWindow(Width, Height: Integer);
+procedure e_ResizeFramebuffer(Width, Height: Integer);
+procedure e_BlitFramebuffer(WinWidth, WinHeight: Integer);
 
 procedure e_Draw(ID: DWORD; X, Y: Integer; Alpha: Byte; AlphaChannel: Boolean;
                  Blending: Boolean; Mirror: TMirrorType = TMirrorType.None);
@@ -129,8 +134,10 @@ procedure e_Clear(Mask: TGLbitfield; Red, Green, Blue: Single); overload;
 procedure e_Clear(); overload;
 procedure e_EndRender();
 
+{$IFDEF USE_SDL2}
 function e_GetGamma(win: PSDL_Window): Byte;
 procedure e_SetGamma(win: PSDL_Window;Gamma: Byte);
+{$ENDIF}
 
 procedure e_MakeScreenshot(st: TStream; Width, Height: Word);
 
@@ -146,6 +153,7 @@ var
   e_NoGraphics: Boolean = False;
   e_FastScreenshots: Boolean = true; // it's REALLY SLOW with `false`
   g_dbg_scale: Single = 1.0;
+  r_pixel_scale: Single = 1.0;
 
 
 implementation
@@ -191,6 +199,11 @@ var
   e_TextureFonts: array of TTextureFont = nil;
   e_CharFonts: array of TCharFont;
   //e_SavedTextures: array of TSavedTexture;
+  e_FBO: GLuint = 0;
+  e_RBO: GLuint = 0;
+  e_Frame: GLuint = 0;
+  e_FrameW: Integer = -1;
+  e_FrameH: Integer = -1;
 
 //function e_getTextGLId (ID: DWORD): GLuint; begin result := e_Textures[ID].tx.id; end;
 
@@ -366,6 +379,50 @@ begin
  if Height <> nil then Height^ := e_Textures[ID].tx.Height;
 end;
 
+procedure e_ResizeFramebuffer(Width, Height: Integer);
+begin
+  glBindTexture(GL_TEXTURE_2D, 0);
+  glBindRenderbuffer(GL_RENDERBUFFER, 0);
+  glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+  if e_Frame > 0 then
+  begin
+    glDeleteTextures(1, @e_Frame);
+    e_Frame := 0;
+  end;
+
+  if e_RBO > 0 then
+  begin
+    glDeleteRenderbuffers(1, @e_RBO);
+    e_RBO := 0;
+  end;
+
+  if e_FBO > 0 then
+  begin
+    glDeleteFramebuffers(1, @e_FBO);
+    e_FBO := 0;
+  end;
+
+  e_FrameW := Width;
+  e_FrameH := Height;
+
+  glGenFramebuffers(1, @e_FBO);
+
+  glGenTextures(1, @e_Frame);
+  glBindTexture(GL_TEXTURE_2D, e_Frame);
+  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, Width, Height, 0, GL_RGB, GL_UNSIGNED_BYTE, nil);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+  glGenRenderbuffers(1, @e_RBO);
+  glBindRenderbuffer(GL_RENDERBUFFER, e_RBO);
+  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, Width, Height);
+
+  glBindFramebuffer(GL_FRAMEBUFFER, e_FBO);
+  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, e_Frame, 0);
+  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, e_RBO);
+end;
+
 procedure e_ResizeWindow(Width, Height: Integer);
 begin
   if Height = 0 then
@@ -394,6 +451,22 @@ begin
   glTexCoord2f(u, v); glVertex2i(x1, y0);
 end;
 
+procedure e_BlitFramebuffer(WinWidth, WinHeight: Integer);
+begin
+  if (e_FBO = 0) or (e_Frame = 0) then exit;
+  glDisable(GL_BLEND);
+  glEnable(GL_TEXTURE_2D);
+  glBindFramebuffer(GL_FRAMEBUFFER, 0);
+  glBindTexture(GL_TEXTURE_2D, e_Frame);
+  glColor4ub(255, 255, 255, 255);
+  e_SetViewPort(0, 0, WinWidth, WinHeight);
+  glBegin(GL_QUADS);
+  drawTxQuad(0, 0, WinWidth, WinHeight, e_FrameW, e_FrameH, 1, 1, TMirrorType.None);
+  glEnd();
+  glBindFramebuffer(GL_FRAMEBUFFER, e_FBO);
+  e_SetViewPort(0, 0, e_FrameW, e_FrameH);
+end;
+
 procedure e_Draw(ID: DWORD; X, Y: Integer; Alpha: Byte; AlphaChannel: Boolean;
                  Blending: Boolean; Mirror: TMirrorType = TMirrorType.None);
 begin
@@ -854,9 +927,6 @@ end;
 procedure e_DrawQuad(X1, Y1, X2, Y2: Integer; Red, Green, Blue: Byte; Alpha: Byte = 0);
 var
   nX1, nY1, nX2, nY2: Integer;
-{$IFDEF USE_NANOGL}
-  v: array [0..15] of GLfloat;
-{$ENDIF}
 begin
   if e_NoGraphics then Exit;
   // Only top-left/bottom-right quad
@@ -877,40 +947,13 @@ begin
   begin
     glEnable(GL_BLEND);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-  end else
+  end
+  else
     glDisable(GL_BLEND);
 
   glDisable(GL_TEXTURE_2D);
   glColor4ub(Red, Green, Blue, 255-Alpha);
   glLineWidth(1);
-{$IFDEF USE_NANOGL}
-  nX1 := X1; nY1 := Y1;
-  nX2 := X2; nY2 := Y1;
-  e_LineCorrection(nX1, nY1, nX2, nY2);
-  v[0] := nX1; v[1] := nY1; v[2] := nX2; v[3] := nY2;
-
-  nX1 := X2; nY1 := Y1;
-  nX2 := X2; nY2 := Y2;
-  e_LineCorrection(nX1, nY1, nX2, nY2);
-  v[4] := nX1; v[5] := nY1; v[6] := nX2; v[7] := nY2;
-
-  nX1 := X2; nY1 := Y2;
-  nX2 := X1; nY2 := Y2;
-  e_LineCorrection(nX1, nY1, nX2, nY2);
-  v[8] := nX1; v[9] := nY1; v[10] := nX2; v[11] := nY2;
-
-  nX1 := X1; nY1 := Y2;
-  nX2 := X1; nY2 := Y1;
-  e_LineCorrection(nX1, nY1, nX2, nY2);
-  v[12] := nX1; v[13] := nY1; v[14] := nX2; v[15] := nY2;
-
-  glVertexPointer(2, GL_FLOAT, 0, @v[0]);
-  glEnableClientState(GL_VERTEX_ARRAY);
-  glDisableClientState(GL_COLOR_ARRAY);
-  glDisableClientState(GL_NORMAL_ARRAY);
-  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-  glDrawArrays(GL_LINES, 0, 16);
-{$ELSE}
   glBegin(GL_LINES);
     nX1 := X1; nY1 := Y1;
     nX2 := X2; nY2 := Y1;
@@ -936,10 +979,7 @@ begin
     glVertex2i(nX1, nY1);
     glVertex2i(nX2, nY2);
   glEnd();
-{$ENDIF}
-
   glColor4ub(e_Colors.R, e_Colors.G, e_Colors.B, 255);
-
   glDisable(GL_BLEND);
 end;
 
@@ -1011,10 +1051,6 @@ end;
 
 
 procedure e_DrawLine(Width: Byte; X1, Y1, X2, Y2: Integer; Red, Green, Blue: Byte; Alpha: Byte = 0);
-{$IFDEF USE_NANOGL}
-  var
-    v: array [0..3] of GLfloat;
-{$ENDIF}
 begin
   if e_NoGraphics then Exit;
   // Pixel-perfect lines
@@ -1031,22 +1067,10 @@ begin
   glDisable(GL_TEXTURE_2D);
   glColor4ub(Red, Green, Blue, 255-Alpha);
   glLineWidth(Width);
-
-{$IFDEF USE_NANOGL}
-  v[0] := X1; v[1] := Y1; v[2] := X2; v[3] := Y2;
-  glVertexPointer(2, GL_FLOAT, 0, @v[0]);
-  glEnableClientState(GL_VERTEX_ARRAY);
-  glDisableClientState(GL_COLOR_ARRAY);
-  glDisableClientState(GL_NORMAL_ARRAY);
-  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-  glDrawArrays(GL_LINES, 0, 4);
-{$ELSE}
   glBegin(GL_LINES);
     glVertex2i(X1, Y1);
     glVertex2i(X2, Y2);
   glEnd();
-{$ENDIF}
-
   glColor4ub(e_Colors.R, e_Colors.G, e_Colors.B, 255);
 
   glDisable(GL_BLEND);
@@ -1114,6 +1138,7 @@ begin
   glPopMatrix();
 end;
 
+{$IFDEF USE_SDL2}
 function e_GetGamma(win: PSDL_Window): Byte;
 var
   ramp: array [0..256*3-1] of Word;
@@ -1176,6 +1201,7 @@ begin
 
  SDL_SetWindowGammaRamp(win, @ramp[0], @ramp[256], @ramp[512]);
 end;
+{$ENDIF}
 
 function e_CharFont_Create(sp: ShortInt=0): DWORD;
 var
@@ -1497,8 +1523,10 @@ end;
 procedure e_TextureFontBuild(Tex: DWORD; var FontID: DWORD; XCount, YCount: Word;
                              Space: ShortInt=0);
 var
+{$IFDEF NOGL_LISTS}
   loop1 : GLuint;
   cx, cy : real;
+{$ENDIF}
   i, id: DWORD;
 begin
  if e_NoGraphics then Exit;
@@ -1522,7 +1550,7 @@ begin
 
  with e_TextureFonts[id] do
  begin
-{$IF not DEFINED(USE_NANOGL) and not DEFINED(USE_NOGL)}
+{$IFDEF NOGL_LISTS}
   Base := glGenLists(XCount*YCount);
 {$ENDIF}
   TextureID := e_Textures[Tex].tx.id;
@@ -1534,7 +1562,7 @@ begin
   SPC := Space;
  end;
 
-{$IF not DEFINED(USE_NANOGL) and not DEFINED(USE_NOGL)}
+{$IFDEF NOGL_LISTS}
  glBindTexture(GL_TEXTURE_2D, e_Textures[Tex].tx.id);
  for loop1 := 0 to XCount*YCount-1 do
  begin
@@ -1566,13 +1594,13 @@ end;
 procedure e_TextureFontKill(FontID: DWORD);
 begin
   if e_NoGraphics then Exit;
-{$IF not DEFINED(USE_NANOGL) and not DEFINED(USE_NOGL)}
+{$IFDEF NOGL_LISTS}
   glDeleteLists(e_TextureFonts[FontID].Base, 256);
 {$ENDIF}
   e_TextureFonts[FontID].Base := 0;
 end;
 
-{$IF DEFINED(USE_NANOGL) or DEFINED(USE_NOGL)}
+{$IFNDEF NOGL_LISTS}
 procedure e_TextureFontDrawChar(ch: Char; FontID: DWORD);
   var
     index: Integer;
@@ -1626,11 +1654,11 @@ begin
   glBindTexture(GL_TEXTURE_2D, e_TextureFonts[FontID].TextureID);
   glEnable(GL_TEXTURE_2D);
   glTranslatef(x, y, 0);
-{$IF DEFINED(USE_NANOGL) or DEFINED(USE_NOGL)}
-  e_TextureFontDrawString(Text, FontID);
-{$ELSE}
+{$IFDEF NOGL_LISTS}
   glListBase(DWORD(Integer(e_TextureFonts[FontID].Base)-32));
   glCallLists(Length(Text), GL_UNSIGNED_BYTE, PChar(Text));
+{$ELSE}
+  e_TextureFontDrawString(Text, FontID);
 {$ENDIF}
   glDisable(GL_TEXTURE_2D);
   glPopMatrix;
@@ -1648,10 +1676,10 @@ begin
   begin
    glColor4ub(0, 0, 0, 128);
    glTranslatef(X+1, Y+1, 0);
-{$IF DEFINED(USE_NANOGL) or DEFINED(USE_NOGL)}
-   e_TextureFontDrawChar(Ch, FontID);
-{$ELSE}
+{$IFDEF NOGL_LISTS}
    glCallLists(1, GL_UNSIGNED_BYTE, @Ch);
+{$ELSE}
+   e_TextureFontDrawChar(Ch, FontID);
 {$ENDIF}
    glPopMatrix;
    glPushMatrix;
@@ -1659,10 +1687,10 @@ begin
 
   glColor4ub(e_Colors.R, e_Colors.G, e_Colors.B, 255);
   glTranslatef(X, Y, 0);
-{$IF DEFINED(USE_NANOGL) or DEFINED(USE_NOGL)}
-  e_TextureFontDrawChar(Ch, FontID);
-{$ELSE}
+{$IFDEF NOGL_LISTS}
   glCallLists(1, GL_UNSIGNED_BYTE, @Ch);
+{$ELSE}
+  e_TextureFontDrawChar(Ch, FontID);
 {$ENDIF}
 
   glPopMatrix;
@@ -1714,7 +1742,7 @@ begin
     glBindTexture(GL_TEXTURE_2D, e_TextureFonts[FontID].TextureID);
     glEnable(GL_TEXTURE_2D);
 
-{$IF not DEFINED(USE_NANOGL) and not DEFINED(USE_NOGL)}
+{$IFDEF NOGL_LISTS}
     glListBase(DWORD(Integer(e_TextureFonts[FontID].Base)-32));
 {$ENDIF}
 
@@ -1797,7 +1825,7 @@ begin
   glBindTexture(GL_TEXTURE_2D, e_TextureFonts[FontID].TextureID);
   glEnable(GL_TEXTURE_2D);
 
-{$IF not DEFINED(USE_NANOGL) and not DEFINED(USE_NOGL)}
+{$IFDEF NOGL_LISTS}
   glListBase(DWORD(Integer(e_TextureFonts[FontID].Base)-32));
 {$ENDIF}
 
@@ -1809,10 +1837,10 @@ begin
    glColor4ub(0, 0, 0, 128);
    glTranslatef(x+1, y+1, 0);
    glScalef(Scale, Scale, 0);
-{$IF DEFINED(USE_NANOGL) or DEFINED(USE_NOGL)}
-   e_TextureFontDrawString(Text, FontID);
-{$ELSE}
+{$IFDEF NOGL_LISTS}
    glCallLists(Length(Text), GL_UNSIGNED_BYTE, PChar(Text));
+{$ELSE}
+   e_TextureFontDrawString(Text, FontID);
 {$ENDIF}
    glPopMatrix;
    glPushMatrix;
@@ -1821,10 +1849,10 @@ begin
   glColor4ub(Red, Green, Blue, 255);
   glTranslatef(x, y, 0);
   glScalef(Scale, Scale, 0);
-{$IF DEFINED(USE_NANOGL) or DEFINED(USE_NOGL)}
-  e_TextureFontDrawString(Text, FontID);
-{$ELSE}
+{$IFDEF NOGL_LISTS}
   glCallLists(Length(Text), GL_UNSIGNED_BYTE, PChar(Text));
+{$ELSE}
+  e_TextureFontDrawString(Text, FontID);
 {$ENDIF}
 
   glDisable(GL_TEXTURE_2D);
@@ -1854,7 +1882,7 @@ begin
  for i := 0 to High(e_TextureFonts) do
   if e_TextureFonts[i].Base <> 0 then
   begin
-{$IF not DEFINED(USE_NANOGL) and not DEFINED(USE_NOGL)}  
+{$IFDEF NOGL_LISTS}
    glDeleteLists(e_TextureFonts[i].Base, 256);
 {$ENDIF}
    e_TextureFonts[i].Base := 0;