DEADSOFTWARE

gl: fix error messages
[d2df-sdl.git] / src / game / renders / opengl / r_textures.pas
index 97d572c5776b02fac7f16af63070b832cc4933c0..11dfdaeea189b39a6bc68ad41703e91254c270c6 100644 (file)
@@ -47,6 +47,7 @@ interface
     TGLAtlas = class (TAtlas)
       private
         mID: GLuint;
+        mFilter: Boolean;
 
       public
         constructor Create (ww, hh: Integer; id: GLuint);
@@ -56,6 +57,7 @@ interface
         function Alloc (ww, hh: Integer): TGLAtlasNode; overload;
 
         property id: GLuint read mID write mID default 0;
+        property filter: Boolean read mFilter write mFilter;
     end;
 
     TGLTexture = class
@@ -65,6 +67,7 @@ interface
         mCols: Integer;
         mTile: array of TGLAtlasNode;
         mHints: TGLHintsSet;
+        mFilter: Boolean;
 
       public
         destructor Destroy; override;
@@ -78,6 +81,7 @@ interface
         property cols: Integer read mCols;
         property lines: Integer read GetLines;
         property hints: TGLHintsSet read mHints;
+        property filter: Boolean read mFilter write mFilter;
     end;
 
     TGLMultiTexture = class
@@ -154,6 +158,40 @@ implementation
     atl, ratl: array of TGLAtlas;
     currentTexture2D: GLuint;
 
+  function r_Textures_GL_GetError (msg: AnsiString): Boolean;
+    var code: GLenum; s: AnsiString;
+  begin
+    code := glGetError();
+    if code <> GL_NO_ERROR then
+    begin
+      case code of
+        GL_INVALID_ENUM: s := 'GL_INVALID_ENUM';
+        GL_INVALID_VALUE: s := 'GL_INVALID_VALUE';
+        GL_INVALID_OPERATION: s := 'GL_INVALID_OPERATION';
+        GL_STACK_OVERFLOW: s := 'GL_STACK_OVERFLOW';
+        GL_STACK_UNDERFLOW: s := 'GL_STACK_UNDERFLOW';
+        GL_OUT_OF_MEMORY: s := 'GL_OUT_OF_MEMORY';
+        {$IFNDEF USE_GLES1}
+          GL_TABLE_TOO_LARGE: s := 'GL_TABLE_TOO_LARGE';
+        {$ENDIF}
+        otherwise s := '';
+      end;
+      if s <> '' then
+        e_LogWritefln('%s: %s', [msg, s])
+      else
+        e_LogWritefln('%s: error code %s', [msg, code]);
+    end;
+    result := code <> GL_NO_ERROR;
+  end;
+
+  procedure r_Textures_GL_ClearError;
+    var code: GLenum;
+  begin
+    repeat
+      code := glGetError();
+    until code = GL_NO_ERROR;
+  end;
+
   procedure r_Textures_GL_Bind (id: GLuint);
   begin
     if id <> currentTexture2D then
@@ -163,6 +201,19 @@ implementation
     end
   end;
 
+  function r_Textures_GL_BindAndCheck (id: GLuint): Boolean;
+  begin
+    result := true;
+    if id <> currentTexture2D then
+    begin
+      r_Textures_GL_ClearError;
+      glBindTexture(GL_TEXTURE_2D, id);
+      result := not r_Textures_GL_GetError('failed to bind texture');
+      if result = true then
+        currentTexture2D := id;
+    end
+  end;
+
   (* --------- TGLAtlasNode --------- *)
 
   constructor TGLAtlasNode.Create (base: TGLAtlas);
@@ -182,7 +233,7 @@ implementation
     result := self.base.id
   end;
 
-  procedure r_Textures_UpdateNode (n: TGLAtlasNode; data: Pointer; x, y, w, h: Integer);
+  function r_Textures_UpdateNode (n: TGLAtlasNode; data: Pointer; x, y, w, h: Integer): Boolean;
   begin
     ASSERT(n <> nil);
     // ASSERT(n.leaf);
@@ -193,9 +244,13 @@ implementation
     ASSERT(n.l + x + w - 1 <= n.r);
     ASSERT(n.t + y + h - 1 <= n.b);
     ASSERT(n.id > 0);
-    r_Textures_GL_Bind(n.id);
-    glTexSubImage2D(GL_TEXTURE_2D, 0, n.l + x, n.t + y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);
-    r_Textures_GL_Bind(0);
+    result := false;
+    if r_Textures_GL_BindAndCheck(n.id) then
+    begin
+      glTexSubImage2D(GL_TEXTURE_2D, 0, n.l + x, n.t + y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);
+      result := not r_Textures_GL_GetError('failed to update atlas node');
+      r_Textures_GL_Bind(0);
+    end;
   end;
 
   (* --------- TGLAtlas --------- *)
@@ -206,6 +261,7 @@ implementation
     ASSERT(hh > 0);
     inherited Create(ww, hh);
     self.mID := id;
+    self.mFilter := false;
   end;
 
   destructor TGLAtlas.Destroy;
@@ -223,29 +279,38 @@ implementation
     result := TGLAtlasNode(inherited Alloc(ww, hh));
   end;
 
-  function r_Textures_AllocHWTexture (w, h: Integer): GLuint;
-    var id: GLuint;
+  procedure r_Textures_AllocHWTexture (w, h: Integer; out id: GLuint; out ok: Boolean);
   begin
+    id := 0; ok := false;
+    r_Textures_GL_ClearError;
     glGenTextures(1, @id);
-    if id <> 0 then
-    begin
-      r_Textures_GL_Bind(id);
-      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);
-      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
-      r_Textures_GL_Bind(0);
+    if not r_Textures_GL_GetError('failed to allocate texture id') then
+    begin
+      if r_Textures_GL_BindAndCheck(id) then
+      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);
+        r_Textures_GL_ClearError;
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
+        ok := not r_Textures_GL_GetError('failed to allocate hardware texture');
+        r_Textures_GL_Bind(0);
+      end;
+      if ok = false then
+      begin
+        glDeleteTextures(1, @id);
+        id := 0;
+      end;
     end;
-    result := id
   end;
 
   function r_Textures_AllocAtlas (): TGLAtlas;
-    var i: Integer; id: GLuint;
+    var i: Integer; id: GLuint; ok: Boolean;
   begin
     result := nil;
-    id := r_Textures_AllocHWTexture(maxTileSize, maxTileSize);
-    if id <> 0 then
+    r_Textures_AllocHWTexture(maxTileSize, maxTileSize, id, ok);
+    if ok then
     begin
       i := Length(atl);
       SetLength(atl, i + 1);
@@ -255,11 +320,11 @@ implementation
   end;
 
   function r_Textures_AllocRepeatAtlas (w, h: Integer): TGLAtlas;
-    var i: Integer; id: GLuint;
+    var i: Integer; id: GLuint; ok: Boolean;
   begin
     result := nil;
-    id := r_Textures_AllocHWTexture(w, h);
-    if id <> 0 then
+    r_Textures_AllocHWTexture(w, h, id, ok);
+    if ok then
     begin
       i := Length(ratl);
       SetLength(ratl, i + 1);
@@ -378,6 +443,7 @@ implementation
       t.mCols := cols;
       // t.mLines := lines;
       t.mHints := hints;
+      t.mFilter := false;
       SetLength(t.mTile, cols * lines);
       for y := 0 to lines - 1 do
       begin
@@ -465,7 +531,8 @@ implementation
     begin
       // auto, max possible reccomended by driver
       glGetIntegerv(GL_MAX_TEXTURE_SIZE, @size);
-      if size < 1 then size := 64;
+      size := size div 2; (* hack: on some devices max size may produce invalid texture *)
+      if size < 64 then size := 64; (* at least 64x64 are guarantied by specification *)
     end
     else
     begin
@@ -482,7 +549,7 @@ implementation
   begin
     currentTexture2D := 0;
     maxTileSize := r_Textures_GetMaxHardwareSize();
-    e_LogWritefln('TEXTURE SIZE: %s', [maxTileSize]);
+    e_LogWritefln('Texture Tile Size: %s', [maxTileSize]);
   end;
 
   procedure r_Textures_Finalize;
@@ -536,9 +603,9 @@ implementation
   end;
 
   function r_Textures_LoadFromImage (var img: TImageData; hints: TGLHintsSet): TGLTexture; // !!!
-    var t: TGLTexture; n: TGLAtlasNode; c: TDynImageDataArray; cw, ch, i, j: LongInt;
+    var t: TGLTexture; n: TGLAtlasNode; c: TDynImageDataArray; cw, ch, i, j: LongInt; ok: Boolean;
   begin
-    result := nil;
+    t := nil; ok := false;
     if r_Textures_ValidRepeatTexture(img.width, img.height, hints) then
     begin
       t := r_Textures_Alloc(img.width, img.height, hints - [TGLHints.txNoRepeat]);
@@ -546,8 +613,7 @@ implementation
       begin
         n := t.GetTile(0, 0);
         ASSERT(n <> nil);
-        r_Textures_UpdateNode(n, img.bits, 0, 0, n.width, n.height);
-        result := t
+        ok := r_Textures_UpdateNode(n, img.bits, 0, 0, n.width, n.height);
       end
     end
     else if SplitImage(img, c, maxTileSize, maxTileSize, cw, ch, False) then
@@ -555,6 +621,7 @@ implementation
       t := r_Textures_Alloc(img.width, img.height, hints + [TGLHints.txNoRepeat]);
       if t <> nil then
       begin
+        ok := true;
         ASSERT(cw = t.cols);
         ASSERT(ch = t.lines);
         for j := 0 to ch - 1 do
@@ -563,13 +630,15 @@ implementation
           begin
             n := t.GetTile(i, j);
             if n <> nil then
-              r_Textures_UpdateNode(n, c[j * cw + i].bits, 0, 0, n.width, n.height)
+              ok := ok and r_Textures_UpdateNode(n, c[j * cw + i].bits, 0, 0, n.width, n.height)
           end
         end;
-        result := t
       end;
       FreeImagesInArray(c);
     end;
+    if ok = false then
+      r_Common_FreeAndNil(t);
+    result := t
   end;
 
   function r_Textures_LoadFromMemory (data: Pointer; size: LongInt; hints: TGLHintsSet): TGLTexture;