1+ @file:Suppress(" UnstableApiUsage" , " INVISIBLE_MEMBER" , " INVISIBLE_REFERENCE" )
2+
13package org.polyfrost.oneconfig.api.ui.v1.internal
24
35import dev.deftu.omnicore.api.client.render.GlCapabilities
@@ -41,14 +43,36 @@ private const val MAX_BATCH = 1024
4143
4244private val EMPTY_ROW = floatArrayOf(0f , 0f , 0f , 0f )
4345private val NO_UV = floatArrayOf(- 1f , - 1f , 1f , 1f )
46+ private val IDENTITY = floatArrayOf(
47+ 1f , 0f , 0f ,
48+ 0f , 1f , 0f ,
49+ 0f , 0f , 1f
50+ )
51+
52+ private fun FloatArray.isIdentity (): Boolean {
53+ return this [0 ] == 1f && this [1 ] == 0f && this [2 ] == 0f &&
54+ this [3 ] == 0f && this [4 ] == 1f && this [5 ] == 0f &&
55+ this [6 ] == 0f && this [7 ] == 0f && this [8 ] == 1f
56+ }
57+
58+ @kotlin.internal.InlineOnly
59+ private inline fun FloatArray.set (other : FloatArray ) {
60+ System .arraycopy(other, 0 , this , 0 , 9 )
61+ }
62+
63+ @kotlin.internal.InlineOnly
64+ private inline fun FloatArray.setThenClear (other : FloatArray ) {
65+ System .arraycopy(other, 0 , this , 0 , 9 )
66+ System .arraycopy(IDENTITY , 0 , other, 0 , 9 )
67+ }
4468
45- @Suppress(" UnstableApiUsage" , " INVISIBLE_MEMBER" , " INVISIBLE_REFERENCE" )
4669class GLRendererImpl (private val nsvg : NanoSvgApi , private val stb : StbApi ) : Renderer, RendererExt {
4770
4871 private val buffer = BufferUtils .createFloatBuffer(MAX_BATCH * STRIDE )
4972 private val scissorStack = IntArray (MAX_UI_DEPTH * 4 )
50- private val transformStack = ArrayList < FloatArray > (MAX_UI_DEPTH )
73+ private val transformStack = Array (MAX_UI_DEPTH ) { FloatArray ( 9 ) }
5174 private val fonts = HashMap <Font , FontAtlas >()
75+ private val init get() = program != 0
5276
5377 // lateinit
5478 private var mipmapMode = 0
@@ -75,6 +99,7 @@ class GLRendererImpl(private val nsvg: NanoSvgApi, private val stb: StbApi) : Re
7599 // Current batch state
76100 private var count = 0
77101 private var curTex = 0
102+ private var transformDepth = 0
78103 private var curScissor = 0
79104 private var transform = floatArrayOf(
80105 1f , 0f , 0f ,
@@ -86,7 +111,6 @@ class GLRendererImpl(private val nsvg: NanoSvgApi, private val stb: StbApi) : Re
86111 private var pixelRatio = 1f
87112 private var alphaCap = 1f
88113 private var popFlushNeeded = false
89- private val init get() = program != 0
90114
91115 private var slotX = 0
92116 private var slotY = 0
@@ -128,14 +152,19 @@ class GLRendererImpl(private val nsvg: NanoSvgApi, private val stb: StbApi) : Re
128152 float rRight = mix(r.z, r.y, py); // bottom-right / top-right
129153 float radius = mix(rLeft, rRight, px);
130154
131- vec2 d = abs(p) - b + vec2(radius);
132- vec2 dClamped = max(d, vec2(0.0));
133- return length(dClamped) - radius + min(max(d.x, d.y), 0.0);
155+ vec2 q = abs(p) - (b - vec2(radius));
156+ return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - radius;
134157 }
135158
136159 float hollowRoundedBoxSDF(vec2 p, vec2 b, vec4 r, float thickness) {
137- float dist = roundedBoxSDF(p, b, r);
138- return abs(dist) - thickness * 0.5;
160+ float outer = roundedBoxSDF(p, b + vec2(0.2), r);
161+ float inner = roundedBoxSDF(p, b - vec2(thickness), max(r - vec4(thickness), 0.0));
162+ return max(outer, -inner);
163+ }
164+
165+ float roundBoxSDF(vec2 p, vec2 halfSize, float radius) {
166+ vec2 q = abs(p) - (halfSize - vec2(radius));
167+ return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - radius;
139168 }
140169
141170 void main() {
@@ -152,20 +181,19 @@ class GLRendererImpl(private val nsvg: NanoSvgApi, private val stb: StbApi) : Re
152181 col = (vThickness == -1.0) ? vec4(col.rgb, col.a * texColor.r) : col * texColor;
153182 }
154183 else if (vThickness == -2.0) { // linear gradient, vUV as start and vUV2 as end
155- vec2 dir = normalize( vUV2 - vUV) ;
156- float t = dot((p + halfSize) - vUV, dir) / length(vUV2 - vUV );
157- t = clamp(t , 0.0, 1.0);
184+ vec2 dir = vUV2 - vUV;
185+ float len = length(dir );
186+ float t = clamp(dot((p + halfSize) - vUV, dir / len) / len , 0.0, 1.0);
158187 col = mix(vColor0, vColor1, t);
159188 }
160189 else if (vThickness == -3.0) { // radial gradient, vUV as center and vUV2.x as radius
161190 float dist = length(p + halfSize - vUV);
162- float t = (dist - vUV2.x) / (vUV2.y - vUV2.x);
163- t = clamp(t, 0.0, 1.0);
191+ float t = clamp((dist - vUV2.x) / (vUV2.y - vUV2.x), 0.0, 1.0);
164192 col = mix(vColor0, vColor1, t);
165193 }
166194 else if (vThickness == -4.0) { // box gradient, vUV.x as radius and vUV.y as feather
167- float dist = roundedBoxSDF (p, halfSize - vec2(vUV.x), vec4( vUV.x) );
168- float t = clamp(dist / vUV.y, 0.0, 1.0);
195+ float dist = roundBoxSDF (p, halfSize, vUV.x);
196+ float t = clamp(( dist + vUV.y * 0.5) / vUV.y, 0.0, 1.0);
169197 col = mix(vColor0, vColor1, t);
170198 }
171199
@@ -380,7 +408,8 @@ class GLRendererImpl(private val nsvg: NanoSvgApi, private val stb: StbApi) : Re
380408 alphaCap = 1f
381409 count = 0
382410 buffer.clear()
383- loadIdentity()
411+ transform.set(IDENTITY )
412+ transformDepth = 0
384413 val prevProg = glGetInteger(GL_CURRENT_PROGRAM )
385414 glUseProgram(program)
386415 glUniform2f(uWindow, width, height)
@@ -596,7 +625,7 @@ class GLRendererImpl(private val nsvg: NanoSvgApi, private val stb: StbApi) : Re
596625 if (count >= MAX_BATCH ) {
597626 flush()
598627 }
599- val glyph = fAtlas.get(c) ? : continue
628+ val glyph = fAtlas.get(c)
600629 buffer.put(penX + glyph.xOff * scaleFactor).put(penY + glyph.yOff * scaleFactor)
601630 .put(glyph.width * scaleFactor).put(glyph.height * scaleFactor)
602631 buffer.put(EMPTY_ROW ) // zero radii
@@ -697,15 +726,17 @@ class GLRendererImpl(private val nsvg: NanoSvgApi, private val stb: StbApi) : Re
697726
698727 override fun push () {
699728 if (transform.isIdentity()) return
700- transformStack.add (transform.copyOf() )
729+ transformStack[transformDepth ++ ].set (transform)
701730 }
702731
703732 override fun pop () {
704733 if (transform.isIdentity()) return
705734 flush()
706- if (transformStack.isEmpty()) {
707- loadIdentity()
708- } else transform = transformStack.removeLast()
735+ if (transformDepth == 0 ) {
736+ transform.set(IDENTITY )
737+ } else {
738+ transform.setThenClear(transformStack[-- transformDepth])
739+ }
709740 popFlushNeeded = true
710741 }
711742
@@ -763,20 +794,6 @@ class GLRendererImpl(private val nsvg: NanoSvgApi, private val stb: StbApi) : Re
763794 popFlushNeeded = true
764795 }
765796
766- private fun FloatArray.isIdentity (): Boolean {
767- return this [0 ] == 1f && this [1 ] == 0f && this [2 ] == 0f &&
768- this [3 ] == 0f && this [4 ] == 1f && this [5 ] == 0f &&
769- this [6 ] == 0f && this [7 ] == 0f && this [8 ] == 1f
770- }
771-
772- private fun loadIdentity () {
773- val transform = transform
774- transform[0 ] = 1f ; transform[1 ] = 0f ; transform[2 ] = 0f
775- transform[3 ] = 0f ; transform[4 ] = 1f ; transform[5 ] = 0f
776- transform[6 ] = 0f ; transform[7 ] = 0f ; transform[8 ] = 1f
777- this .transform = transform
778- }
779-
780797 override fun initImage (image : PolyImage , size : Vec2 ) {
781798 if (image.initialized) return
782799 val w = IntArray (1 )
@@ -800,27 +817,26 @@ class GLRendererImpl(private val nsvg: NanoSvgApi, private val stb: StbApi) : Re
800817 h[0 ] / ATLAS_SIZE .toFloat()
801818 )
802819
803- synchronized(this ) {
804- val prevActive = glGetInteger(GL_ACTIVE_TEXTURE )
805- val prevTex = glGetInteger(GL_TEXTURE_BINDING_2D )
806- glActiveTexture(GL_TEXTURE0 )
807- glBindTexture(GL_TEXTURE_2D , atlas)
808- glPixelStorei(GL_UNPACK_ALIGNMENT , 1 )
809- glPixelStorei(GL_UNPACK_ROW_LENGTH , 0 )
810- glPixelStorei(GL_UNPACK_SKIP_PIXELS , 0 )
811- glPixelStorei(GL_UNPACK_SKIP_ROWS , 0 )
812- glTexSubImage2D(GL_TEXTURE_2D , 0 , slotX, slotY, w[0 ], h[0 ], GL_RGBA , GL_UNSIGNED_BYTE , d)
813- when (mipmapMode) {
814- 1 -> org.lwjgl.opengl.GL30 .glGenerateMipmap(GL_TEXTURE_2D )
815- 2 -> org.lwjgl.opengl.EXTFramebufferObject .glGenerateMipmapEXT(GL_TEXTURE_2D )
816- }
817- glBindTexture(GL_TEXTURE_2D , prevTex)
818- glActiveTexture(prevActive)
820+ val prevActive = glGetInteger(GL_ACTIVE_TEXTURE )
821+ val prevTex = glGetInteger(GL_TEXTURE_BINDING_2D )
822+ glActiveTexture(GL_TEXTURE0 )
823+ glBindTexture(GL_TEXTURE_2D , atlas)
824+ glPixelStorei(GL_UNPACK_ALIGNMENT , 1 )
825+ glPixelStorei(GL_UNPACK_ROW_LENGTH , 0 )
826+ glPixelStorei(GL_UNPACK_SKIP_PIXELS , 0 )
827+ glPixelStorei(GL_UNPACK_SKIP_ROWS , 0 )
828+ glTexSubImage2D(GL_TEXTURE_2D , 0 , slotX, slotY, w[0 ], h[0 ], GL_RGBA , GL_UNSIGNED_BYTE , d)
829+ when (mipmapMode) {
830+ 1 -> org.lwjgl.opengl.GL30 .glGenerateMipmap(GL_TEXTURE_2D )
831+ 2 -> org.lwjgl.opengl.EXTFramebufferObject .glGenerateMipmapEXT(GL_TEXTURE_2D )
819832 }
833+ glBindTexture(GL_TEXTURE_2D , prevTex)
834+ glActiveTexture(prevActive)
835+
820836 if (image.type == PolyImage .Type .Raster ) stb.image_free(d)
821837
822- slotX + = w[0 ]
823- if (h[0 ] > atlasRowHeight) atlasRowHeight = h[0 ]
838+ slotX + = w[0 ] + 1
839+ if (h[0 ] + 1 > atlasRowHeight) atlasRowHeight = h[0 ] + 1
824840 image.reportInit()
825841 }
826842
@@ -882,7 +898,6 @@ class GLRendererImpl(private val nsvg: NanoSvgApi, private val stb: StbApi) : Re
882898 if (quadVbo != 0 ) glDeleteBuffers(quadVbo)
883899 if (instancedVbo != 0 ) glDeleteBuffers(instancedVbo)
884900 if (atlas != 0 ) glDeleteTextures(atlas)
885- transformStack.clear()
886901 fonts.clear()
887902 buffer.clear()
888903 }
@@ -985,44 +1000,43 @@ class GLRendererImpl(private val nsvg: NanoSvgApi, private val stb: StbApi) : Re
9851000 stb.free(packed)
9861001 stb.free(range)
9871002
988- synchronized(this @GLRendererImpl) {
989- val prevActive = glGetInteger(GL_ACTIVE_TEXTURE )
990- val prevTex = glGetInteger(GL_TEXTURE_BINDING_2D )
991- glActiveTexture(GL_TEXTURE0 )
992- glBindTexture(GL_TEXTURE_2D , atlas)
993- glPixelStorei(GL_UNPACK_ALIGNMENT , 1 )
994- glPixelStorei(GL_UNPACK_ROW_LENGTH , 0 )
995- glPixelStorei(GL_UNPACK_SKIP_PIXELS , 0 )
996- glPixelStorei(GL_UNPACK_SKIP_ROWS , 0 )
997- // can't write to the alpha channel in GL3 core! lol haha
998- glTexSubImage2D(
999- GL_TEXTURE_2D ,
1000- 0 ,
1001- sx,
1002- sy,
1003- FONT_MAX_BITMAP_W ,
1004- FONT_MAX_BITMAP_H ,
1005- GL_RED ,
1006- GL_UNSIGNED_BYTE ,
1007- bitMap
1008- )
1009- when (mipmapMode) {
1010- 1 -> org.lwjgl.opengl.GL30 .glGenerateMipmap(GL_TEXTURE_2D )
1011- 2 -> org.lwjgl.opengl.EXTFramebufferObject .glGenerateMipmapEXT(GL_TEXTURE_2D )
1012- }
1013- glBindTexture(GL_TEXTURE_2D , prevTex)
1014- glActiveTexture(prevActive)
1003+ val prevActive = glGetInteger(GL_ACTIVE_TEXTURE )
1004+ val prevTex = glGetInteger(GL_TEXTURE_BINDING_2D )
1005+ glActiveTexture(GL_TEXTURE0 )
1006+ glBindTexture(GL_TEXTURE_2D , atlas)
1007+ glPixelStorei(GL_UNPACK_ALIGNMENT , 1 )
1008+ glPixelStorei(GL_UNPACK_ROW_LENGTH , 0 )
1009+ glPixelStorei(GL_UNPACK_SKIP_PIXELS , 0 )
1010+ glPixelStorei(GL_UNPACK_SKIP_ROWS , 0 )
1011+ // can't write to the alpha channel in GL3 core! lol haha
1012+ glTexSubImage2D(
1013+ GL_TEXTURE_2D ,
1014+ 0 ,
1015+ sx,
1016+ sy,
1017+ FONT_MAX_BITMAP_W ,
1018+ FONT_MAX_BITMAP_H ,
1019+ GL_RED ,
1020+ GL_UNSIGNED_BYTE ,
1021+ bitMap
1022+ )
1023+ when (mipmapMode) {
1024+ 1 -> org.lwjgl.opengl.GL30 .glGenerateMipmap(GL_TEXTURE_2D )
1025+ 2 -> org.lwjgl.opengl.EXTFramebufferObject .glGenerateMipmapEXT(GL_TEXTURE_2D )
10151026 }
1016- slotX + = totalSizeX
1017- atlasRowHeight = maxOf(atlasRowHeight, totalSizeY)
1027+ glBindTexture(GL_TEXTURE_2D , prevTex)
1028+ glActiveTexture(prevActive)
1029+
1030+ slotX + = totalSizeX + 1
1031+ atlasRowHeight = maxOf(atlasRowHeight, totalSizeY + 1 )
10181032 }
10191033
10201034 fun measure (text : String , fontSize : Float ): Vec2 {
10211035 var width = 0f
10221036// var height = 0f
10231037 val scaleFactor = fontSize / this .renderedSize
10241038 for (c in text) {
1025- val g = get(c) ? : continue
1039+ val g = get(c)
10261040 width + = g.xAdvance * scaleFactor
10271041// height = maxOf(height, g.height + g.offsetY)
10281042 }
@@ -1031,7 +1045,7 @@ class GLRendererImpl(private val nsvg: NanoSvgApi, private val stb: StbApi) : Re
10311045
10321046 @Suppress(" DEPRECATION" )
10331047 @kotlin.internal.InlineOnly
1034- inline fun get (char : Char ) = if (char.toInt() in 32 .. 32 + 95 ) glyphs[(char.toInt() - 32 )] else null
1048+ inline fun get (char : Char ) = if (char.toInt() in 32 .. 32 + 95 ) glyphs[(char.toInt() - 32 )] else glyphs[ ' ? ' .toInt()]
10351049 }
10361050
10371051 @kotlin.internal.InlineOnly
0 commit comments