DEADSOFTWARE

gl: implement texture filtering
[d2df-sdl.git] / src / game / renders / opengl / r_draw.pas
index 67bd23041275b237de894398f5960198e4691c30..4f28d505c7da6d1f8e01db2c2fe4dbe2fe2c7cd6 100644 (file)
@@ -22,6 +22,8 @@ interface
     r_textures
   ;
 
+  procedure r_Draw_SetFilter (img: TGLTexture; enable: Boolean);
+
   procedure r_Draw_Texture (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean);
   procedure r_Draw_TextureRepeat (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean);
   procedure r_Draw_TextureRepeatRotate (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean; rx, ry, angle: Integer);
@@ -33,22 +35,22 @@ interface
   procedure r_Draw_Rect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
   procedure r_Draw_FillRect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
   procedure r_Draw_InvertRect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
+  procedure r_Draw_Line (x0, y0, x1, y1: Integer; rr, gg, bb, aa: Byte);
 
   procedure r_Draw_Text (const text: AnsiString; x, y: Integer; r, g, b, a: Byte; f: TGLFont);
   procedure r_Draw_GetTextSize (const text: AnsiString; f: TGLFont; out w, h: Integer);
 
-  procedure r_Draw_Setup (w, h: Integer);
+  procedure r_Draw_Setup (sw, sh, gw, gh: Integer);
   procedure r_Draw_SetRect (l, t, r, b: Integer);
   procedure r_Draw_GetRect (out l, t, r, b: Integer);
 
+  procedure r_Draw_EnableTexture2D (enable: Boolean);
+  procedure r_Draw_SetColor (r, g, b, a: Byte);
+
 implementation
 
   uses
-    {$IFDEF USE_GLES1}
-      GLES11,
-    {$ELSE}
-      GL, GLEXT,
-    {$ENDIF}
+    {$I ../../../nogl/noGLuses.inc}
     SysUtils, Classes, Math,
     e_log, utils
   ;
@@ -62,22 +64,49 @@ implementation
   var
     sl, st, sr, sb: Integer;
     ScreenWidth, ScreenHeight: Integer;
+    GameWidth, GameHeight: Integer;
+
+    enableTexture2D: Boolean;
+    curR, curG, curB, curA: Byte;
 
-  procedure r_Draw_Setup (w, h: Integer);
+  procedure r_Draw_EnableTexture2D (enable: Boolean);
   begin
-    ASSERT(w >= 0);
-    ASSERT(h >= 0);
-    ScreenWidth := w;
-    ScreenHeight := h;
-    glScissor(0, 0, w, h);
-    glViewport(0, 0, w, h);
+    if enable <> enableTexture2D then
+    begin
+      if enable then glEnable(GL_TEXTURE_2D) else glDisable(GL_TEXTURE_2D);
+      enableTexture2D := enable;
+    end;
+  end;
+
+  procedure r_Draw_SetColor (r, g, b, a: Byte);
+  begin
+    if (r <> curR) or (g <> curG) or (b <> curB) or (curA <> a) then
+    begin
+      glColor4ub(r, g, b, a);
+      curR := r;
+      curG := g;
+      curB := b;
+      curA := a;
+    end;
+  end;
+
+  procedure r_Draw_Setup (sw, sh, gw, gh: Integer);
+  begin
+    ASSERT((sw >= 0) and (sh >= 0)); // screen/window size
+    ASSERT((gw >= 0) and (gh >= 0)); // virtual screen size
+    ScreenWidth := sw;
+    ScreenHeight := sh;
+    GameWidth := gw;
+    GameHeight := gh;
+    glScissor(0, 0, sw, sh);
+    glViewport(0, 0, sw, sh);
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity;
-    glOrtho(0, w, h, 0, 0, 1);
+    glOrtho(0, gw, gh, 0, 0, 1);
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity;
     glEnable(GL_SCISSOR_TEST);
-    r_Draw_SetRect(0, 0, w - 1, h - 1);
+    r_Draw_SetRect(0, 0, gw - 1, gh - 1);
   end;
 
   procedure DrawQuad (x, y, w, h: Integer);
@@ -90,16 +119,30 @@ implementation
     glEnd();
   end;
 
-  procedure DrawTile (tile: TGLAtlasNode; x, y, w, h: Integer; flip: Boolean; rr, gg, bb, aa: Byte; blend: Boolean);
+  procedure DrawTextureError (x, y, w, h: Integer);
+    var w2, h2: Integer;
+  begin
+    w2 := w div 2; h2 := h div 2;
+    r_Draw_FillRect(x,      y,      x + w2, y + h2, 255, 0,   255, 255);
+    r_Draw_FillRect(x + w2, y,      x + w,  y + h2, 255, 255, 255, 255);
+    r_Draw_FillRect(x + w2, y + h2, x + w,  y + h,  255, 0,   255, 255);
+    r_Draw_FillRect(x,      y + h2, x + w2, y + h,  255, 255, 255, 255);
+    if (w > 2) and (h > 2) then
+      r_Draw_Rect(x, y, x + w, y + h, 0, 255, 0, 255);
+  end;
+
+  procedure r_Draw_SetFilter (img: TGLTexture; enable: Boolean);
+  begin
+    ASSERT(img <> nil);
+    img.filter := enable;
+  end;
+
+  procedure DrawTile (tile: TGLAtlasNode; x, y, w, h: Integer; flip: Boolean; rr, gg, bb, aa: Byte; blend, filter: Boolean);
     var nw, nh, ax, bx, ay, by: GLfloat; l, t, r, b: Integer;
   begin
     if tile = nil then
     begin
-      glColor4ub(rr, gg, bb, aa);
-      if blend then glBlendFunc(GL_SRC_ALPHA, GL_ONE) else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-      glDisable(GL_TEXTURE_2D);
-      glEnable(GL_BLEND);
-      DrawQuad(x, y, w, h);
+      DrawTextureError(x, y, w, h);
     end
     else
     begin
@@ -110,10 +153,28 @@ implementation
       ay := (tile.t) / nw;
       by := (tile.b + 1) / nh;
       l := x; t := y; r := x + w; b := y + h;
-      glBindTexture(GL_TEXTURE_2D, tile.id);
-      glColor4ub(rr, gg, bb, aa);
+      r_Textures_GL_Bind(tile.id);
+      if filter <> tile.base.filter then
+      begin
+        if filter then
+        begin
+          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        end
+        else
+        begin
+          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        end;
+        tile.base.filter := filter;
+      end;
+      r_Draw_SetColor(rr, gg, bb, aa);
+      r_Draw_EnableTexture2D(true);
       if blend then glBlendFunc(GL_SRC_ALPHA, GL_ONE) else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-      glEnable(GL_TEXTURE_2D);
       glEnable(GL_BLEND);
       glBegin(GL_QUADS);
         glTexCoord2f(ax, ay); glVertex2i(r, t);
@@ -121,8 +182,6 @@ implementation
         glTexCoord2f(bx, by); glVertex2i(l, b);
         glTexCoord2f(ax, by); glVertex2i(r, b);
       glEnd();
-      glDisable(GL_TEXTURE_2D);
-      glBindTexture(GL_TEXTURE_2D, 0);
     end
   end;
 
@@ -134,10 +193,10 @@ implementation
     ay := 0 / nw;
     by := h / nh;
     l := x; t := y; r := x + w; b := y + h;
-    glBindTexture(GL_TEXTURE_2D, gltex);
-    glColor4ub(rr, gg, bb, aa);
+    r_Textures_GL_Bind(gltex);
+    r_Draw_SetColor(rr, gg, bb, aa);
+    r_Draw_EnableTexture2D(true);
     if blend then glBlendFunc(GL_SRC_ALPHA, GL_ONE) else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glEnable(GL_TEXTURE_2D);
     glEnable(GL_BLEND);
     glBegin(GL_QUADS);
       glTexCoord2f(ax, ay); glVertex2i(r, t);
@@ -145,8 +204,6 @@ implementation
       glTexCoord2f(bx, by); glVertex2i(l, b);
       glTexCoord2f(ax, by); glVertex2i(r, b);
     glEnd();
-    glDisable(GL_TEXTURE_2D);
-    glBindTexture(GL_TEXTURE_2D, 0);
   end;
 
   procedure r_Draw_Texture (img: TGLTexture; x, y, w, h: Integer; flip: Boolean; r, g, b, a: Byte; blend: Boolean);
@@ -155,7 +212,7 @@ implementation
     ASSERT(w >= 0);
     ASSERT(h >= 0);
     if img = nil then
-      DrawTile(nil, x, y, w, h, flip, NTR, NTB, NTG, NTA, blend)
+      DrawTextureError(x, y, w, h)
     else
     begin
       if flip then first := img.cols - 1 else first := 0;
@@ -170,7 +227,7 @@ implementation
         repeat
           n := img.GetTile(i, j);
           ASSERT(n <> nil);
-          DrawTile(n, 0, 0, n.width, n.height, flip, r, g, b, a, blend);
+          DrawTile(n, 0, 0, n.width, n.height, flip, r, g, b, a, blend, img.filter);
           glTranslatef(n.width, 0, 0);
           i := i + step;
         until i = last;
@@ -202,7 +259,7 @@ implementation
     ASSERT(w >= 0);
     ASSERT(h >= 0);
     if img = nil then
-      r_Draw_Texture(nil, x, y, w, h, flip, NTR, NTG, NTB, NTB, blend)
+      DrawTextureError(x, y, w, h)
     else if r_Draw_IsHWRepeatable(img) then
       DrawHWTexture(img.GetTile(0, 0).base.id, img.width, img.height, x, y, w, h, flip, r, g, b, a, blend)
     else
@@ -233,7 +290,7 @@ implementation
   begin
     ASSERT(anim.IsValid());
     if m = nil then
-      r_Draw_TextureRepeat(nil, x, y, w, h, flip, NTR, NTG, NTB, NTB, blend)
+      DrawTextureError(x, y, w, h)
     else
     begin
       g_Anim_GetFrameFromState(anim, backanim, frame);
@@ -261,85 +318,108 @@ implementation
       r_Draw_MultiTextureRepeat(m, anim, backanim, x, y, w, h, flip, r, g, b, a, blend);
   end;
 
-  procedure r_Draw_Filter (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
+  procedure r_Draw_Rect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
   begin
-    ASSERT(r >= l);
-    ASSERT(b >= t);
-    glEnable(GL_BLEND);
-    glBlendFunc(GL_ZERO, GL_SRC_COLOR);
-    glDisable(GL_TEXTURE_2D);
-    glColor4ub(rr, gg, bb, aa);
-    glBegin(GL_QUADS);
-      glVertex2i(l, t);
-      glVertex2i(r, t);
-      glVertex2i(r, b);
-      glVertex2i(l, b);
-    glEnd;
+    ASSERT(l <= r);
+    ASSERT(t <= b);
+    if (l < r) and (t < b) then
+    begin
+      glEnable(GL_BLEND);
+      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+      r_Draw_EnableTexture2D(false);
+      r_Draw_SetColor(rr, gg, bb, aa);
+      glBegin(GL_QUADS);
+        (* top *)
+        glVertex2i(l, t);
+        glVertex2i(r, t);
+        glVertex2i(r, t+1);
+        glVertex2i(l, t+1);
+        (* bottom *)
+        glVertex2i(l, b-1);
+        glVertex2i(r, b-1);
+        glVertex2i(r, b);
+        glVertex2i(l, b);
+        (* left *)
+        glVertex2i(l,   t+1);
+        glVertex2i(l+1, t+1);
+        glVertex2i(l+1, b-1);
+        glVertex2i(l,   b-1);
+        (* right *)
+        glVertex2i(r-1, t+1);
+        glVertex2i(r,   t+1);
+        glVertex2i(r,   b-1);
+        glVertex2i(r-1, b-1);
+      glEnd;
+    end;
   end;
 
-  procedure r_Draw_Rect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
+  procedure r_Draw_FillRect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
   begin
-    ASSERT(r >= l);
-    ASSERT(b >= t);
-    glEnable(GL_BLEND);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glDisable(GL_TEXTURE_2D);
-    glColor4ub(rr, gg, bb, aa);
-    glBegin(GL_LINE_LOOP);
-{
-      glVertex2i(l, t);
-      glVertex2i(r, t);
-      glVertex2i(r, b);
-      glVertex2i(l, b);
-}
-      glVertex2f(l + 0.5, t + 0.5);
-      glVertex2f(r - 0.5, t + 0.5);
-      glVertex2f(r - 0.5, b - 0.5);
-      glVertex2f(l + 0.5, b - 0.5);
-    glEnd;
+    ASSERT(l <= r);
+    ASSERT(t <= b);
+    if (l < r) and (t < b) then
+    begin
+      glEnable(GL_BLEND);
+      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+      r_Draw_EnableTexture2D(false);
+      r_Draw_SetColor(rr, gg, bb, aa);
+      glBegin(GL_QUADS);
+        glVertex2i(l, t);
+        glVertex2i(r, t);
+        glVertex2i(r, b);
+        glVertex2i(l, b);
+      glEnd;
+    end;
   end;
 
-  procedure r_Draw_FillRect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
+  procedure r_Draw_Filter (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
   begin
-    ASSERT(r >= l);
-    ASSERT(b >= t);
-    glEnable(GL_BLEND);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glDisable(GL_TEXTURE_2D);
-    glColor4ub(rr, gg, bb, aa);
-    glBegin(GL_QUADS);
-{
-      glVertex2i(l, t);
-      glVertex2i(r, t);
-      glVertex2i(r, b);
-      glVertex2i(l, b);
-}
-{
-      glVertex2f(l + 0.5, t + 0.5);
-      glVertex2f(r - 0.5, t + 0.5);
-      glVertex2f(r - 0.5, b - 0.5);
-      glVertex2f(l + 0.5, b - 0.5);
-}
-      glVertex2f(l + 0, t + 0);
-      glVertex2f(r + 0.75, t + 0);
-      glVertex2f(r + 0.75, b + 0.75);
-      glVertex2f(l + 0, b + 0.75);
-    glEnd;
+    ASSERT(l <= r);
+    ASSERT(t <= b);
+    if (l < r) and (t < b) then
+    begin
+      glEnable(GL_BLEND);
+      glBlendFunc(GL_ZERO, GL_SRC_COLOR);
+      r_Draw_EnableTexture2D(false);
+      r_Draw_SetColor(rr, gg, bb, aa);
+      glBegin(GL_QUADS);
+        glVertex2i(l, t);
+        glVertex2i(r, t);
+        glVertex2i(r, b);
+        glVertex2i(l, b);
+      glEnd;
+    end;
   end;
 
   procedure r_Draw_InvertRect (l, t, r, b: Integer; rr, gg, bb, aa: Byte);
   begin
-    ASSERT(r >= l);
-    ASSERT(b >= t);
+    ASSERT(l <= r);
+    ASSERT(t <= b);
+    if (l < r) and (t < b) then
+    begin
+      glEnable(GL_BLEND);
+      glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
+      r_Draw_EnableTexture2D(false);
+      r_Draw_SetColor(rr, gg, bb, aa);
+      glBegin(GL_QUADS);
+        glVertex2i(l, t);
+        glVertex2i(r, t);
+        glVertex2i(r, b);
+        glVertex2i(l, b);
+      glEnd;
+    end;
+  end;
+
+  procedure r_Draw_Line (x0, y0, x1, y1: Integer; rr, gg, bb, aa: Byte);
+  begin
     glEnable(GL_BLEND);
-    glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
-    glDisable(GL_TEXTURE_2D);
-    glColor4ub(rr, gg, bb, aa);
-    glBegin(GL_QUADS);
-      glVertex2i(l, t);
-      glVertex2i(r, t);
-      glVertex2i(r, b);
-      glVertex2i(l, b);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    r_Draw_EnableTexture2D(false);
+    r_Draw_SetColor(rr, gg, bb, aa);
+    glLineWidth(1);
+    glBegin(GL_LINES);
+      glVertex2i(x0, y0);
+      glVertex2i(x1, y1);
     glEnd;
   end;
 
@@ -373,13 +453,15 @@ implementation
   end;
 
   procedure r_Draw_SetRect (l, t, r, b: Integer);
-    var w, h: Integer;
+    var x, y, w, h: Integer;
   begin
     ASSERT(l <= r);
     ASSERT(t <= b);
-    w := r - l + 1;
-    h := b - t + 1;
-    glScissor(l, ScreenHeight - h - t, w, h);
+    x := l * ScreenWidth div GameWidth;
+    y := t * ScreenHeight div GameHeight;
+    w := (r - l + 1) * ScreenWidth div GameWidth;
+    h := (b - t + 1) * ScreenHeight div GameHeight;
+    glScissor(x, ScreenHeight - h - y, w, h);
     sl := l; st := t; sr := r; sb := b;
   end;