commit 07d2b8270ca1c0c1f09d4456772b8ef47996e688
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Wed Dec 3 02:36:31 2025 +0100

    move all android.graphics stuff to the 'platform' package.

diff --git a/src/main/java/org/distorted/library/main/DistortedScreen.kt b/src/main/java/org/distorted/library/main/DistortedScreen.kt
index f7d665f..a247dd9 100644
--- a/src/main/java/org/distorted/library/main/DistortedScreen.kt
+++ b/src/main/java/org/distorted/library/main/DistortedScreen.kt
@@ -19,13 +19,11 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 package org.distorted.library.main
 
-import android.graphics.Bitmap
-import android.graphics.Canvas
-import android.graphics.Paint
 import org.distorted.library.platform.GLES
 import org.distorted.library.effect.MatrixEffectMove
 import org.distorted.library.effect.MatrixEffectScale
 import org.distorted.library.mesh.MeshQuad
+import org.distorted.library.platform.NativeBitmap
 import org.distorted.library.type.Static3D
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -42,14 +40,12 @@ class DistortedScreen : DistortedFramebuffer(DistortedLibrary.WAIT_FOR_FBO_QUEUE
     private var debugMesh: MeshQuad? = null
     private var debugTexture: DistortedTexture? = null
     private var debugEffects: DistortedEffects? = null
-    private var debugCanvas: Canvas? = null
-    private var debugBitmap: Bitmap? = null
-    private var mPaint: Paint? = null
     private var debugString: String? = null
     private var lastTime: Long = 0
     private var durations: LongArray? = null
     private var currDuration = 0
     private var frameNumber = 0
+    private var debugBitmap: NativeBitmap? = null
 
     ///// END DEBUGGING //////////////////////////
     private var mQueueSize: Int
@@ -143,29 +139,16 @@ class DistortedScreen : DistortedFramebuffer(DistortedLibrary.WAIT_FOR_FBO_QUEUE
                     }
                 }
 
-                debugBitmap = Bitmap.createBitmap(mDebugWidth, mDebugHeight, Bitmap.Config.ARGB_8888)
+                debugBitmap = NativeBitmap(mDebugWidth, mDebugHeight, 0.7f)
                 debugMesh = MeshQuad()
                 debugTexture = DistortedTexture()
-                debugTexture!!.setTexture(debugBitmap!!)
-                debugCanvas = Canvas(debugBitmap!!)
                 debugEffects = DistortedEffects()
                 debugEffects!!.apply(MatrixEffectScale(Static3D(mDebugWidth.toFloat(), mDebugHeight.toFloat(), 1f)))
                 debugEffects!!.apply(mMoveEffect)
-
-                mPaint = Paint()
-                mPaint!!.isAntiAlias = true
-                mPaint!!.textAlign = Paint.Align.CENTER
-                mPaint!!.textSize = 0.7f*mDebugHeight
             }
-
-            mPaint!!.color = mDebugBackColor
-            debugCanvas!!.drawRect(0f, 0f, mDebugWidth.toFloat(), mDebugHeight.toFloat(), mPaint!!)
-            mPaint!!.color = mDebugTextColor
-            debugCanvas!!.drawText(debugString!!, 0.5f*mDebugWidth, 0.75f*mDebugHeight, mPaint!!)
-            debugTexture!!.setTexture(debugBitmap!!)
-
+            debugBitmap!!.drawDebug(mDebugBackColor,mDebugTextColor,debugString!!)
+            debugTexture!!.setTexture( debugBitmap!! )
             mMoveVector.set((-w+mDebugWidth)*0.5f+mDebugGap, (h-mDebugHeight)*0.5f-mDebugGap, 0f)
-
             lastTime = time
         }
 
diff --git a/src/main/java/org/distorted/library/main/DistortedTexture.kt b/src/main/java/org/distorted/library/main/DistortedTexture.kt
index 9460709..e024441 100644
--- a/src/main/java/org/distorted/library/main/DistortedTexture.kt
+++ b/src/main/java/org/distorted/library/main/DistortedTexture.kt
@@ -20,12 +20,7 @@
 package org.distorted.library.main
 
 import org.distorted.library.platform.GLES
-
-import android.graphics.Bitmap
-import android.graphics.Canvas
-import android.graphics.Matrix
-import android.graphics.Paint
-import android.opengl.GLUtils
+import org.distorted.library.platform.NativeBitmap
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -36,47 +31,38 @@ import android.opengl.GLUtils
 class DistortedTexture
 constructor(type: Int = TYPE_USER) : InternalSurface(NOT_CREATED_YET, 1, 1, type, STORAGE_PRIVATE)
 {
-    private var mBmp: Bitmap? = null
+    private var mBmp: NativeBitmap? = null
     private var mBitmapInverted = false
 
-    companion object
-    {
-        ///////////////////////////////////////////////////////////////////////////////////////////////////
-        // We have to vertically flip all the bitmaps passed here via setTexture().
-        //
-        // Reason: textures read from files are the only objects in OpenGL which have their origins at the
-        // upper-left corner. Everywhere else the origin is in the lower-left corner. Thus we have to flip.
-        // The alternative solution, namely inverting the y-coordinate of the TexCoord does not really work-
-        // i.e. it works only in case of rendering directly to the screen, but if we render to an FBO and
-        // then take the FBO and render to screen, (DistortedNode does so!) things get inverted as textures
-        // created from FBO have their origins in the lower-left...
-        private fun flipBitmap(src: Bitmap): Bitmap
-        {
-            val matrix = Matrix()
-            matrix.preScale(1.0f, -1.0f)
-
-            return Bitmap.createBitmap(src, 0, 0, src.width, src.height, matrix, true)
-        }
-    }
-
     ///////////////////////////////////////////////////////////////////////////////////////////////////
     // must be called from a thread holding OpenGL Context
     override fun create()
     {
-        if (mBmp!=null)
+        if( mBmp!=null )
         {
-            if (mColorCreated==NOT_CREATED_YET)
+            if( mColorCreated==NOT_CREATED_YET )
             {
                 mColorCreated = CREATED
                 GLES.glGenTextures(1, mColorH, 0)
             }
 
+            ///////////////////////////////////////////////////////////////////////////////////////////////////
+            // We have to vertically flip all the bitmaps passed here via setTexture().
+            //
+            // Reason: textures read from files are the only objects in OpenGL which have their origins at the
+            // upper-left corner. Everywhere else the origin is in the lower-left corner. Thus we have to flip.
+            // The alternative solution, namely inverting the y-coordinate of the TexCoord does not really work-
+            // i.e. it works only in case of rendering directly to the screen, but if we render to an FBO and
+            // then take the FBO and render to screen, (DistortedNode does so!) things get inverted as textures
+            // created from FBO have their origins in the lower-left...
+            if( !mBitmapInverted ) mBmp!!.flip()
+
             GLES.glBindTexture(GLES.GL_TEXTURE_2D, mColorH!![0])
             GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_MIN_FILTER, GLES.GL_LINEAR)
             GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_MAG_FILTER, GLES.GL_LINEAR)
             GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_WRAP_S, GLES.GL_CLAMP_TO_EDGE)
             GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_WRAP_T, GLES.GL_CLAMP_TO_EDGE)
-            GLUtils.texImage2D(GLES.GL_TEXTURE_2D, 0, if (mBitmapInverted) mBmp else flipBitmap(mBmp!!), 0)
+            GLES.texImage2D(GLES.GL_TEXTURE_2D, 0, mBmp, 0)
             GLES.glBindTexture(GLES.GL_TEXTURE_2D, 0)
 
             mBmp = null
@@ -120,10 +106,10 @@ constructor(type: Int = TYPE_USER) : InternalSurface(NOT_CREATED_YET, 1, 1, type
      * @param bmp The android.graphics.Bitmap object to apply effects to and display.
      * @return true if successful, false if texture too large.
      */
-    fun setTexture(bmp: Bitmap): Boolean
+    fun setTexture(bmp: NativeBitmap): Boolean
     {
-        val width = bmp.width
-        val height = bmp.height
+        val width  = bmp.getW()
+        val height = bmp.getH()
         val max = DistortedLibrary.maxTextureSize
 
         if( width>max || height>max )
@@ -151,10 +137,10 @@ constructor(type: Int = TYPE_USER) : InternalSurface(NOT_CREATED_YET, 1, 1, type
      * @param bmp The (vertically flipped!) android.graphics.Bitmap object to apply effects to and display.
      * @return true if successful, false if texture too large.
      */
-    fun setTextureAlreadyInverted(bmp: Bitmap): Boolean
+    fun setTextureAlreadyInverted(bmp: NativeBitmap): Boolean
     {
-        val width = bmp.width
-        val height = bmp.height
+        val width  = bmp.getW()
+        val height = bmp.getH()
         val max = DistortedLibrary.maxTextureSize
 
         if( width>max || height>max )
@@ -179,14 +165,8 @@ constructor(type: Int = TYPE_USER) : InternalSurface(NOT_CREATED_YET, 1, 1, type
      */
     fun setColorARGB(argb: Int)
     {
-        val paint = Paint()
-        paint.color = argb
-        paint.style = Paint.Style.FILL
-
-        mBmp = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
-        val canvas = Canvas(mBmp!!)
-        canvas.drawRect(0f, 0f, 1f, 1f, paint)
-
+        mBmp = mBmp ?: NativeBitmap()
+        mBmp!!.createARGB(1,1, argb)
         markForCreation()
     }
 }
diff --git a/src/main/java/org/distorted/library/platform/GLES.kt b/src/main/java/org/distorted/library/platform/GLES.kt
index cf408f4..d2a782a 100644
--- a/src/main/java/org/distorted/library/platform/GLES.kt
+++ b/src/main/java/org/distorted/library/platform/GLES.kt
@@ -21,6 +21,7 @@
 package org.distorted.library.platform
 
 import android.opengl.GLES31
+import android.opengl.GLUtils
 
 import java.nio.Buffer
 import java.nio.ByteBuffer
@@ -327,29 +328,36 @@ object GLES
 
    fun glGetIntegerv(pname: Int, params: IntArray, offset: Int)         = GLES31.glGetIntegerv(pname, params, offset)
    fun glCullFace(mode: Int)                                            = GLES31.glCullFace(mode)
-   fun glUseProgram(p0: Int)                                            = GLES31.glUseProgram(p0)
-   fun glEnableVertexAttribArray(p0: Int)                               = GLES31.glEnableVertexAttribArray(p0)
-   fun glDisableVertexAttribArray(p0: Int)                              = GLES31.glDisableVertexAttribArray(p0)
-   fun glDeleteProgram(p0: Int)                                         = GLES31.glDeleteProgram(p0)
-   fun glLinkProgram(p0: Int)                                           = GLES31.glLinkProgram(p0)
-   fun glShaderSource(p0: Int, p1: String)                              = GLES31.glShaderSource(p0, p1)
-   fun glCompileShader(p0: Int)                                         = GLES31.glCompileShader(p0)
-   fun glDeleteShader(p0: Int)                                          = GLES31.glDeleteShader(p0)
+   fun glUseProgram(program: Int)                                       = GLES31.glUseProgram(program)
+   fun glEnableVertexAttribArray(index: Int)                            = GLES31.glEnableVertexAttribArray(index)
+   fun glDisableVertexAttribArray(index: Int)                           = GLES31.glDisableVertexAttribArray(index)
+   fun glDeleteProgram(program: Int)                                    = GLES31.glDeleteProgram(program)
+   fun glLinkProgram(program: Int)                                      = GLES31.glLinkProgram(program)
+   fun glShaderSource(shader: Int, string: String)                      = GLES31.glShaderSource(shader, string)
+   fun glCompileShader(shader: Int)                                     = GLES31.glCompileShader(shader)
+   fun glDeleteShader(shader: Int)                                      = GLES31.glDeleteShader(shader)
    fun glGetShaderiv(p0: Int, p1: Int, p2: IntArray, p3: Int)           = GLES31.glGetShaderiv(p0, p1, p2, p3)
    fun glAttachShader(p0: Int, p1: Int)                                 = GLES31.glAttachShader(p0, p1)
    fun glGetProgramiv(p0: Int, p1: Int, p2: IntArray, p3: Int)          = GLES31.glGetProgramiv(p0, p1, p2, p3)
    fun glBindAttribLocation(p0: Int, p1: Int, p2: String)               = GLES31.glBindAttribLocation(p0, p1, p2)
    fun glTransformFeedbackVaryings(p0: Int, p1: Array<String>, p2: Int) = GLES31.glTransformFeedbackVaryings(p0, p1, p2)
-   fun glStencilFunc(p0: Int, p1: Int, p2: Int)                         = GLES31.glStencilFunc(p0, 1, p2)
-   fun glStencilOp(p0: Int, p1: Int, p2: Int)                           = GLES31.glStencilOp(p0, p1, p2)
-   fun glScissor(p0: Int, p1: Int, p2: Int, p3: Int)                    = GLES31.glScissor(p0, p1, p2, p3)
-   fun glBlendFunc(p0: Int, p1: Int)                                    = GLES31.glBlendFunc(p0, p1)
-   fun glDepthFunc(p0: Int)                                             = GLES31.glDepthFunc(p0)
+   fun glStencilFunc(func: Int, ref: Int, mask: Int)                    = GLES31.glStencilFunc(func, ref, mask)
+   fun glStencilOp(fail: Int, zfail: Int, zpass: Int)                   = GLES31.glStencilOp(fail, zfail, zpass)
+   fun glScissor(x: Int, y: Int, width: Int, height: Int)               = GLES31.glScissor(x, y, width, height)
+   fun glBlendFunc(sfactor: Int, dfactor: Int)                          = GLES31.glBlendFunc(sfactor, dfactor)
+   fun glDepthFunc(func: Int)                                           = GLES31.glDepthFunc(func)
+   fun glGetString(name: Int) : String                                  = GLES31.glGetString(name)
+   fun glCreateShader(type: Int): Int                                   = GLES31.glCreateShader(type)
+   fun glGetProgramInfoLog(program: Int): String                        = GLES31.glGetProgramInfoLog(program)
+   fun glGetShaderInfoLog(shader: Int): String                          = GLES31.glGetShaderInfoLog(shader)
+   fun glGetAttribLocation(program: Int, name: String): Int             = GLES31.glGetAttribLocation(program,name)
+   fun glCreateProgram(): Int                                           = GLES31.glCreateProgram()
 
-   fun glGetString(p0: Int) : String                 { return GLES31.glGetString(p0) }
-   fun glCreateShader(p0: Int): Int                  { return GLES31.glCreateShader(p0) }
-   fun glGetProgramInfoLog(p0: Int): String          { return GLES31.glGetProgramInfoLog(p0) }
-   fun glGetShaderInfoLog(p0: Int): String           { return GLES31.glGetShaderInfoLog(p0) }
-   fun glGetAttribLocation(p0: Int, p1: String): Int { return GLES31.glGetAttribLocation(p0,p1) }
-   fun glCreateProgram(): Int                        { return GLES31.glCreateProgram() }
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// GLUtils
+
+   fun texImage2D(target: Int, level: Int, bmp: NativeBitmap?, border: Int)
+   {
+       GLUtils.texImage2D(target, level, bmp!!.bitmap, border)
+   }
 }
\ No newline at end of file
diff --git a/src/main/java/org/distorted/library/platform/NativeBitmap.kt b/src/main/java/org/distorted/library/platform/NativeBitmap.kt
new file mode 100644
index 0000000..ac597a2
--- /dev/null
+++ b/src/main/java/org/distorted/library/platform/NativeBitmap.kt
@@ -0,0 +1,92 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2025 Leszek Koltunski  leszek@koltunski.pl                                          //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// This library is free software; you can redistribute it and/or                                 //
+// modify it under the terms of the GNU Lesser General Public                                    //
+// License as published by the Free Software Foundation; either                                  //
+// version 2.1 of the License, or (at your option) any later version.                            //
+//                                                                                               //
+// This library is distributed in the hope that it will be useful,                               //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                             //
+// Lesser General Public License for more details.                                               //
+//                                                                                               //
+// You should have received a copy of the GNU Lesser General Public                              //
+// License along with this library; if not, write to the Free Software                           //
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.platform
+
+import android.graphics.Matrix
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Paint
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 1. NativeBitmap b = NativeBitmap()
+//    b.createARGB(w,h,argb)
+//
+// 2. NativeBitmap b = NativeBitmap(w,h,0.7f)
+//    b.createDebug(backColor, textColor, text)
+//
+// 3. NativeBitmap b = NativeBitmap(bmp: Bitmap)
+
+class NativeBitmap()
+{
+    var bitmap: Bitmap? = null
+    var paint: Paint?   = null
+    var canvas: Canvas? = null
+
+    constructor(w: Int, h: Int, r: Float): this()
+    {
+        bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
+        canvas = Canvas(bitmap!!)
+        paint  = Paint()
+        paint!!.isAntiAlias = true
+        paint!!.textAlign = Paint.Align.CENTER
+        paint!!.textSize = r*h
+    }
+
+    constructor(bmp: Bitmap) : this()
+    {
+        bitmap = bmp
+    }
+
+    fun getW(): Int = if( bitmap==null ) 0 else bitmap!!.width
+    fun getH(): Int = if( bitmap==null ) 0 else bitmap!!.height
+
+    fun flip()
+    {
+        if( bitmap!=null )
+        {
+            val bmp = bitmap!!
+            val matrix = Matrix()
+            matrix.preScale(1.0f, -1.0f)
+            bitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.width, bmp.height, matrix, true)
+            if( canvas!=null ) canvas = Canvas(bitmap!!)
+        }
+    }
+
+    fun createARGB(w: Int, h: Int, argb: Int)
+    {
+        paint = paint ?: Paint()
+        paint!!.color = argb
+        paint!!.style = Paint.Style.FILL
+        bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
+        canvas = Canvas(bitmap!!)
+        canvas!!.drawRect(0f, 0f, w.toFloat(), h.toFloat(), paint!!)
+    }
+
+    fun drawDebug(backColor: Int, textColor: Int, text: String)
+    {
+        val width = bitmap!!.width
+        val height = bitmap!!.height
+        paint!!.color = backColor
+        canvas!!.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint!!)
+        paint!!.color = textColor
+        canvas!!.drawText(text, 0.5f*width, 0.75f*height, paint!!)
+    }
+}
\ No newline at end of file
