From ad259150b3d5b8b81cb006023031d95ca0b40adf Mon Sep 17 00:00:00 2001
From: XProger <xproger@list.ru>
Date: Sun, 26 May 2019 02:27:19 +0300
Subject: [PATCH] fix 3DS build, fix autostereoscopy display support

---
 src/cache.h                            |  2 +-
 src/core.h                             |  6 ++-
 src/gapi/c3d.h                         | 23 +++--------
 src/gapi/gl.h                          | 12 +++++-
 src/inventory.h                        | 36 ++++++++++-------
 src/level.h                            | 10 ++++-
 src/mesh.h                             | 56 +++++++++++++-------------
 src/platform/3ds/compose.v.pica        | 41 +++++--------------
 src/platform/3ds/filter_upscale.v.pica | 18 +++++----
 src/platform/3ds/gui.v.pica            | 29 +++++--------
 src/shaders/gui.glsl                   | 10 ++---
 src/ui.h                               | 43 +++++++++-----------
 src/utils.h                            | 55 ++++++++++++++++++++-----
 13 files changed, 180 insertions(+), 161 deletions(-)

diff --git a/src/cache.h b/src/cache.h
index 131ec4a..ae80334 100644
--- a/src/cache.h
+++ b/src/cache.h
@@ -286,7 +286,7 @@ struct AmbientCache {
 
         mat4 mProj, mView;
         mView.identity();
-        mProj.identity();
+        mProj = GAPI::ortho(-1, +1, -1, +1, 0, 1);
         mProj.scale(vec3(1.0f / 32767.0f));
         Core::setViewProj(mView, mProj);
         game->setShader(Core::passFilter, Shader::FILTER_DOWNSAMPLE);
diff --git a/src/core.h b/src/core.h
index c9f72cd..daa87e2 100644
--- a/src/core.h
+++ b/src/core.h
@@ -122,7 +122,11 @@
 #include "utils.h"
 
 // muse be equal with base shader
-#define SHADOW_TEX_SIZE      2048
+#ifdef __OS_3DS
+    #define SHADOW_TEX_SIZE      512
+#else
+    #define SHADOW_TEX_SIZE      2048
+#endif
 
 extern void* osMutexInit     ();
 extern void  osMutexFree     (void *obj);
diff --git a/src/gapi/c3d.h b/src/gapi/c3d.h
index a7faed7..fc1d424 100644
--- a/src/gapi/c3d.h
+++ b/src/gapi/c3d.h
@@ -143,8 +143,7 @@ namespace GAPI {
             cbCount[uType] = count * 4;
 
             ASSERT(count == 1);
-            mat4 m = value.transpose();
-            memcpy(cbMem + bindings[uType], &m, sizeof(m));
+            memcpy(cbMem + bindings[uType], &value, sizeof(value));
         }
     };
 
@@ -477,26 +476,14 @@ namespace GAPI {
     
     mat4 ortho(float l, float r, float b, float t, float znear, float zfar) {
         mat4 m;
-        Mtx_OrthoTilt((C3D_Mtx*)&m, l, r, b, t, znear, zfar, false);
-
-        mat4 res;
-        res.e00 = m.e30; res.e10 = m.e31; res.e20 = m.e32; res.e30 = m.e33;
-        res.e01 = m.e20; res.e11 = m.e21; res.e21 = m.e22; res.e31 = m.e23;
-        res.e02 = m.e10; res.e12 = m.e11; res.e22 = m.e12; res.e32 = m.e13;
-        res.e03 = m.e00; res.e13 = m.e01; res.e23 = m.e02; res.e33 = m.e03;
-        return res;
+        m.ortho(mat4::PROJ_NEG_ZERO, l, r, b, t, znear, zfar, true);
+        return m;
     }
 
     mat4 perspective(float fov, float aspect, float znear, float zfar, float eye) {
         mat4 m;
-        Mtx_PerspTilt((C3D_Mtx*)&m, fov * DEG2RAD, aspect, znear, zfar, false);
-
-        mat4 res;
-        res.e00 = m.e30; res.e10 = m.e31; res.e20 = m.e32; res.e30 = m.e33;
-        res.e01 = m.e20; res.e11 = m.e21; res.e21 = m.e22; res.e31 = m.e23;
-        res.e02 = m.e10; res.e12 = m.e11; res.e22 = m.e12; res.e32 = m.e13;
-        res.e03 = m.e00; res.e13 = m.e01; res.e23 = m.e02; res.e33 = m.e03;
-        return res;
+        m.perspective(mat4::PROJ_NEG_ZERO, fov, aspect, znear, zfar, eye, true);
+        return m;
     }
 
     bool beginFrame() {
diff --git a/src/gapi/gl.h b/src/gapi/gl.h
index 729297f..2a78fcd 100644
--- a/src/gapi/gl.h
+++ b/src/gapi/gl.h
@@ -430,6 +430,7 @@ namespace GAPI {
     typedef ::Vertex Vertex;
 
     int cullMode, blendMode;
+    bool depthWrite;
 
     char GLSL_HEADER_VERT[512];
     char GLSL_HEADER_FRAG[512];
@@ -1454,7 +1455,15 @@ namespace GAPI {
 
     void clear(bool color, bool depth) {
         uint32 mask = (color ? GL_COLOR_BUFFER_BIT : 0) | (depth ? GL_DEPTH_BUFFER_BIT : 0);
-        if (mask) glClear(mask);
+        if (mask) {
+            if (depth && !depthWrite) {
+                glDepthMask(GL_TRUE);
+                glClear(mask);
+                glDepthMask(GL_FALSE);
+            } else {
+                glClear(mask);
+            }
+        }
     }
 
     void setClearColor(const vec4 &color) {
@@ -1474,6 +1483,7 @@ namespace GAPI {
     }
 
     void setDepthWrite(bool enable) {
+        depthWrite = enable;
         glDepthMask(enable ? GL_TRUE : GL_FALSE);
     }
 
diff --git a/src/inventory.h b/src/inventory.h
index 98fc448..153f03f 100644
--- a/src/inventory.h
+++ b/src/inventory.h
@@ -1401,6 +1401,10 @@ struct Inventory {
             return;
         #endif
 
+        #ifdef _OS_3DS
+            return;
+        #endif
+
         game->renderGame(false, true);
 
         Core::setDepthTest(false);
@@ -1417,7 +1421,7 @@ struct Inventory {
 
         mat4 mProj, mView;
         mView.identity();
-        mProj.identity();
+        mProj = GAPI::ortho(-1, +1, -1, +1, 0, 1);
         mProj.scale(vec3(1.0f / 32767.0f));
         Core::setViewProj(mView, mProj);
 
@@ -1716,20 +1720,20 @@ struct Inventory {
         Index  indices[10 * 3] = { 0,1,2, 0,2,3, 8,9,5, 8,5,4, 9,10,6, 9,6,5, 10,11,7, 10,7,6, 11,8,4, 11,4,7 };
         Vertex vertices[4 * 3];
 
-        vertices[ 0].coord = short4(-size.x,  size.y, 0, 0);
-        vertices[ 1].coord = short4( size.x,  size.y, 0, 0);
-        vertices[ 2].coord = short4( size.x, -size.y, 0, 0);
-        vertices[ 3].coord = short4(-size.x, -size.y, 0, 0);
+        vertices[ 0].coord = short4(-size.x,  size.y, 0, 1);
+        vertices[ 1].coord = short4( size.x,  size.y, 0, 1);
+        vertices[ 2].coord = short4( size.x, -size.y, 0, 1);
+        vertices[ 3].coord = short4(-size.x, -size.y, 0, 1);
 
         vertices[ 4].coord = vertices[0].coord;
         vertices[ 5].coord = vertices[1].coord;
         vertices[ 6].coord = vertices[2].coord;
         vertices[ 7].coord = vertices[3].coord;
 
-        vertices[ 8].coord = short4(-o_frame,  o_frame, 0, 0);
-        vertices[ 9].coord = short4( o_frame,  o_frame, 0, 0);
-        vertices[10].coord = short4( o_frame, -o_frame, 0, 0);
-        vertices[11].coord = short4(-o_frame, -o_frame, 0, 0);
+        vertices[ 8].coord = short4(-o_frame,  o_frame, 0, 1);
+        vertices[ 9].coord = short4( o_frame,  o_frame, 0, 1);
+        vertices[10].coord = short4( o_frame, -o_frame, 0, 1);
+        vertices[11].coord = short4(-o_frame, -o_frame, 0, 1);
 
         vertices[ 0].light =
         vertices[ 1].light =
@@ -1770,7 +1774,7 @@ struct Inventory {
 
         mat4 mProj, mView;
         mView.identity();
-        mProj.identity();
+        mProj = GAPI::ortho(-1, +1, -1, +1, 0, 1);
         mProj.scale(vec3(1.0f / max(size.x, size.y)));
         mProj.translate(vec3(eye, 0.0f, 0.0f));
         Core::setViewProj(mView, mProj);
@@ -1783,10 +1787,10 @@ struct Inventory {
     void renderGameBG(int view) {
         Index  indices[6] = { 0, 1, 2, 0, 2, 3 };
         Vertex vertices[4];
-        vertices[0].coord = short4(-32767,  32767, 0, 0);
-        vertices[1].coord = short4( 32767,  32767, 0, 0);
-        vertices[2].coord = short4( 32767, -32767, 0, 0);
-        vertices[3].coord = short4(-32767, -32767, 0, 0);
+        vertices[0].coord = short4(-32767,  32767, 0, 1);
+        vertices[1].coord = short4( 32767,  32767, 0, 1);
+        vertices[2].coord = short4( 32767, -32767, 0, 1);
+        vertices[3].coord = short4(-32767, -32767, 0, 1);
         vertices[0].light =
         vertices[1].light =
         vertices[2].light =
@@ -1821,7 +1825,7 @@ struct Inventory {
 
         mat4 mProj, mView;
         mView.identity();
-        mProj.identity();
+        mProj = GAPI::ortho(-1, +1, -1, +1, 0, 1);
         mProj.scale(vec3(1.0f / 32767.0f));
         Core::setViewProj(mView, mProj);
 
@@ -1837,6 +1841,7 @@ struct Inventory {
             return;
 
         Core::setDepthTest(false);
+        Core::setDepthWrite(false);
 
         uint8 alpha;
         if (!isActive() && titleTimer > 0.0f && titleTimer < 1.0f)
@@ -1863,6 +1868,7 @@ struct Inventory {
 
         Core::setBlendMode(bmPremult);
         Core::setDepthTest(true);
+        Core::setDepthWrite(true);
     }
 
     void setupCamera(float aspect, bool ui = false) {
diff --git a/src/level.h b/src/level.h
index ff75eed..bbc819b 100644
--- a/src/level.h
+++ b/src/level.h
@@ -3000,7 +3000,7 @@ struct Level : IGame {
         int texIndex = eye <= 0 ? 0 : 1;
 
         #ifdef _OS_3DS
-            Core::eye *= osGet3DSliderState() / 3.0f;
+            Core::eye *= osGet3DSliderState();
 
             GAPI::curTarget = GAPI::defTarget[texIndex];
 
@@ -3081,9 +3081,12 @@ struct Level : IGame {
         if (Core::settings.detail.stereo == Core::Settings::STEREO_ANAGLYPH && !invBG) {
             mat4 mProj, mView;
             mView.identity();
-            mProj.identity();
+            mProj = GAPI::ortho(-1, +1, -1, +1, 0, 1);
             mProj.scale(vec3(1.0f / 32767.0f));
             Core::setViewProj(mView, mProj);
+\
+            Core::setDepthTest(false);
+            Core::setDepthWrite(false);
 
             Core::setTarget(NULL, NULL, RT_STORE_COLOR);
             setShader(Core::passFilter, Shader::FILTER_ANAGLYPH, false, false);
@@ -3091,6 +3094,9 @@ struct Level : IGame {
             Core::eyeTex[1]->bind(sNormal);
             Core::setDepthTest(false);
             mesh->renderQuad();
+
+            Core::setDepthTest(true);
+            Core::setDepthWrite(true);
         }
     }
 
diff --git a/src/mesh.h b/src/mesh.h
index 5eabba5..9ecad6f 100644
--- a/src/mesh.h
+++ b/src/mesh.h
@@ -1208,17 +1208,17 @@ struct MeshBuilder {
     #ifndef MERGE_SPRITES
         if (!expand) {
             vec3 pos = vec3(float(x), float(y), float(z));
-            quad[0].coord = coordTransform(pos, vec3( float(sprite.l), float(-sprite.t), 0 ));
-            quad[1].coord = coordTransform(pos, vec3( float(sprite.r), float(-sprite.t), 0 ));
-            quad[2].coord = coordTransform(pos, vec3( float(sprite.r), float(-sprite.b), 0 ));
-            quad[3].coord = coordTransform(pos, vec3( float(sprite.l), float(-sprite.b), 0 ));
+            quad[0].coord = coordTransform(pos, vec3( float(sprite.l), float(-sprite.t), 1 ));
+            quad[1].coord = coordTransform(pos, vec3( float(sprite.r), float(-sprite.t), 1 ));
+            quad[2].coord = coordTransform(pos, vec3( float(sprite.r), float(-sprite.b), 1 ));
+            quad[3].coord = coordTransform(pos, vec3( float(sprite.l), float(-sprite.b), 1 ));
         } else
     #endif
         {
-            quad[0].coord = short4( x0, y0, z, 0 );
-            quad[1].coord = short4( x1, y0, z, 0 );
-            quad[2].coord = short4( x1, y1, z, 0 );
-            quad[3].coord = short4( x0, y1, z, 0 );
+            quad[0].coord = short4( x0, y0, z, 1 );
+            quad[1].coord = short4( x1, y0, z, 1 );
+            quad[2].coord = short4( x1, y1, z, 1 );
+            quad[3].coord = short4( x0, y1, z, 1 );
         }
 
         quad[0].normal = quad[1].normal = quad[2].normal = quad[3].normal = short4( 0, 0, 0, 0 );
@@ -1250,10 +1250,10 @@ struct MeshBuilder {
         int16 maxX = int16(size.x) + minX;
         int16 maxY = int16(size.y) + minY;
 
-        vertices[vCount + 0].coord = short4( minX, minY, 0, 0 );
-        vertices[vCount + 1].coord = short4( maxX, minY, 0, 0 );
-        vertices[vCount + 2].coord = short4( maxX, maxY, 0, 0 );
-        vertices[vCount + 3].coord = short4( minX, maxY, 0, 0 );
+        vertices[vCount + 0].coord = short4( minX, minY, 0, 1 );
+        vertices[vCount + 1].coord = short4( maxX, minY, 0, 1 );
+        vertices[vCount + 2].coord = short4( maxX, maxY, 0, 1 );
+        vertices[vCount + 3].coord = short4( minX, maxY, 0, 1 );
 
         for (int i = 0; i < 4; i++) {
             Vertex &v = vertices[vCount + i];
@@ -1286,15 +1286,15 @@ struct MeshBuilder {
         int16 maxX = int16(size.x) + minX;
         int16 maxY = int16(size.y) + minY;
 
-        vertices[vCount + 0].coord = short4( minX, minY, 0, 0 );
-        vertices[vCount + 1].coord = short4( maxX, minY, 0, 0 );
-        vertices[vCount + 2].coord = short4( maxX, int16(minY + 1), 0, 0 );
-        vertices[vCount + 3].coord = short4( minX, int16(minY + 1), 0, 0 );
+        vertices[vCount + 0].coord = short4( minX, minY, 0, 1 );
+        vertices[vCount + 1].coord = short4( maxX, minY, 0, 1 );
+        vertices[vCount + 2].coord = short4( maxX, int16(minY + 1), 0, 1 );
+        vertices[vCount + 3].coord = short4( minX, int16(minY + 1), 0, 1 );
 
-        vertices[vCount + 4].coord = short4( minX, minY, 0, 0 );
-        vertices[vCount + 5].coord = short4( int16(minX + 1), minY, 0, 0 );
-        vertices[vCount + 6].coord = short4( int16(minX + 1), maxY, 0, 0 );
-        vertices[vCount + 7].coord = short4( minX, maxY, 0, 0 );
+        vertices[vCount + 4].coord = short4( minX, minY, 0, 1 );
+        vertices[vCount + 5].coord = short4( int16(minX + 1), minY, 0, 1 );
+        vertices[vCount + 6].coord = short4( int16(minX + 1), maxY, 0, 1 );
+        vertices[vCount + 7].coord = short4( minX, maxY, 0, 1 );
 
         for (int i = 0; i < 8; i++) {
             Vertex &v = vertices[vCount + i];
@@ -1306,15 +1306,15 @@ struct MeshBuilder {
         addQuad(indices, iCount, vCount, 0, vertices, NULL, false, false); vCount += 4;
         addQuad(indices, iCount, vCount, 0, vertices, NULL, false, false); vCount += 4;
 
-        vertices[vCount + 0].coord = short4( minX, int16(maxY - 1), 0, 0 );
-        vertices[vCount + 1].coord = short4( maxX, int16(maxY - 1), 0, 0 );
-        vertices[vCount + 2].coord = short4( maxX, maxY, 0, 0 );
-        vertices[vCount + 3].coord = short4( minX, maxY, 0, 0 );
+        vertices[vCount + 0].coord = short4( minX, int16(maxY - 1), 0, 1 );
+        vertices[vCount + 1].coord = short4( maxX, int16(maxY - 1), 0, 1 );
+        vertices[vCount + 2].coord = short4( maxX, maxY, 0, 1 );
+        vertices[vCount + 3].coord = short4( minX, maxY, 0, 1 );
 
-        vertices[vCount + 4].coord = short4( int16(maxX - 1), minY, 0, 0 );
-        vertices[vCount + 5].coord = short4( maxX, minY, 0, 0 );
-        vertices[vCount + 6].coord = short4( maxX, maxY, 0, 0 );
-        vertices[vCount + 7].coord = short4( int16(maxX - 1), maxY, 0, 0 );
+        vertices[vCount + 4].coord = short4( int16(maxX - 1), minY, 0, 1 );
+        vertices[vCount + 5].coord = short4( maxX, minY, 0, 1 );
+        vertices[vCount + 6].coord = short4( maxX, maxY, 0, 1 );
+        vertices[vCount + 7].coord = short4( int16(maxX - 1), maxY, 0, 1 );
 
         for (int i = 0; i < 8; i++) {
             Vertex &v = vertices[vCount + i];
diff --git a/src/platform/3ds/compose.v.pica b/src/platform/3ds/compose.v.pica
index 41a2d3d..a4a157c 100644
--- a/src/platform/3ds/compose.v.pica
+++ b/src/platform/3ds/compose.v.pica
@@ -20,19 +20,8 @@
 
 .proc main
 ; mulQuat
-    ;mul r0.xyz, uBasis[0], aCoord.zxy
-    ;mad r0.xyz, aCoord, uBasis[0].zxy, -r0
-    ;mad r0.xyz, aCoord.yzx, uBasis[0].w, r0
-    ;mul r1.xyz, uBasis[0].zxy, r0
-    ;mad r0.xyz, r0.yzx, uBasis[0].yzx, -r1
-    ;mad r0.xyz, r0, const0.x, aCoord
-    ;add r0.xyz, uBasis[1], r0
-    ;mov r0.w, uBasis[1].w
-    
     mul r0.x, const0.xxxx, aCoord.wwww
-    
-    ;frc r0.x, v0.w
-    ;add r0.x, -r0.x, v0.w
+
     mova a0.x, r0.x
     mul r0.xyz, uBasis[a0.x], aCoord.zxyw
     mad r0.xyz, aCoord, uBasis[a0.x].zxyw, -r0
@@ -44,24 +33,16 @@
     mov r0.w, uBasis[a0.x + 1].w
 
 ; uViewProj * coord
-    dp4 vPosition.x, uViewProj[0], r0
-    dp4 vPosition.y, uViewProj[1], r0
-    dp4 vPosition.z, uViewProj[2], r0
-    dp4 vPosition.w, uViewProj[3], r0
-    
-    mul r2, const1.xxxx, aTexCoord.xyzw
-    mov vTexCoord, r2
-    
-    mov r3, aColor
-    mul r3, const1.yyyy, r3.xyzw
-    
-    mov r4, aLight
-    mul r4, const1.yyyy, r4.xyzw
-        
+    mul r1, uViewProj[0], r0.xxxx
+    mad r1, r0.yyyy, uViewProj[1], r1
+    mad r1, r0.zzzz, uViewProj[2], r1
+    mad vPosition, r0.wwww, uViewProj[3], r1
+
+    mul vTexCoord, const1.xxxx, aTexCoord.xyzw
+
+    mul r3, const1.yyyy, aColor
+    mul r4, const1.yyyy, aLight
     mul vColor, r3, r4
-    ;mov vColor, r3
-    ;mov vColor.xyz, r2.xyz
-    ;mov vColor.w, const0.yyyy
-    
+
     end
 .end
diff --git a/src/platform/3ds/filter_upscale.v.pica b/src/platform/3ds/filter_upscale.v.pica
index d8e05e7..be68a1f 100644
--- a/src/platform/3ds/filter_upscale.v.pica
+++ b/src/platform/3ds/filter_upscale.v.pica
@@ -1,5 +1,8 @@
 ; constants
-.constf const0(1.0, 3.05185094e-005, 0.00392156886, -0.5)
+.constf const0(3.05185094e-005, 0.00392156886, 0.0, 0.0)
+
+; uniforms
+.fvec uViewProj[4]
 
 ; in
 .alias aCoord    v0
@@ -12,13 +15,14 @@
 .out vColor    color
 
 .proc main
-    mul r0.xyzw, const0.yyyy, aCoord.yxzw
-    mov r0.w, const0.xxxx
-    mov r0.y, -r0.y
-    mov vPosition, r0
+; uViewProj * coord
+    mov r0, uViewProj[3]
+    mad r1, aCoord.xxxx, uViewProj[0], r0
+    mad r1, aCoord.yyyy, uViewProj[1], r1
+    mad vPosition, aCoord.zzzz, uViewProj[2], r1
 
-    mul vTexCoord, const0.yyyy, aTexCoord
-    mul vColor, const0.zzzz, aLight
+    mul vTexCoord, const0.xxxx, aTexCoord
+    mul vColor, const0.yyyy, aLight
 
     end
 .end
diff --git a/src/platform/3ds/gui.v.pica b/src/platform/3ds/gui.v.pica
index 3a68fe7..409a127 100644
--- a/src/platform/3ds/gui.v.pica
+++ b/src/platform/3ds/gui.v.pica
@@ -1,6 +1,5 @@
 ; constants
-.constf const0(2.0, 1.0, 0.5, 0.25)
-.constf const1(3.05185094e-005, 0.00392156886, 0.00784313725, 0.0)
+.constf const0(3.05185094e-005, 0.00392156886, 1.0, 0.0)
 
 ; uniforms
 .fvec uViewProj[4]
@@ -8,9 +7,7 @@
 
 ; in
 .alias aCoord    v0
-.alias aNormal   v1
 .alias aTexCoord v2
-.alias aColor    v3
 .alias aLight    v4
 
 ; out
@@ -19,21 +16,15 @@
 .out vColor    color
 
 .proc main
-    mov r0.xyz, aCoord
-    mov r0.w, const0.yyyy
-
 ; uViewProj * coord
-    dp4 vPosition.x, uViewProj[0], r0
-    dp4 vPosition.y, uViewProj[1], r0
-    dp4 vPosition.z, uViewProj[2], r0
-    dp4 vPosition.w, uViewProj[3], r0
-    
-    mul r2, const1.xxxx, aTexCoord.xyzw
-    mov vTexCoord, r2
-    
-    mov r3, aLight
-    mul r3, const1.yyyy, r3.xyzw
-    mul vColor, uMaterial, r3
-    
+    mov r0, uViewProj[3]
+    mad r1, aCoord.xxxx, uViewProj[0], r0
+    mad r1, aCoord.yyyy, uViewProj[1], r1
+    mad vPosition, aCoord.zzzz, uViewProj[2], r1
+
+    mul vTexCoord, const0.xxxx, aTexCoord
+    mul r2, const0.yyyy, aLight
+    mul vColor, uMaterial, r2
+
     end
 .end
diff --git a/src/shaders/gui.glsl b/src/shaders/gui.glsl
index c800a0f..54ef398 100644
--- a/src/shaders/gui.glsl
+++ b/src/shaders/gui.glsl
@@ -11,15 +11,15 @@ varying vec4 vColor;
 	attribute vec4 aLight;
 
 	void main() {
-		vTexCoord	= aTexCoord.xy;
-		vColor		= aLight * uMaterial;
-		gl_Position = uViewProj * vec4(aCoord.xyz, 1.0);
+		vTexCoord   = aTexCoord.xy;
+		vColor      = aLight * uMaterial;
+		gl_Position = uViewProj * aCoord;
 	}
 #else
-	uniform sampler2D	sDiffuse;
+	uniform sampler2D sDiffuse;
 
 	void main() {
 		fragColor = texture2D(sDiffuse, vTexCoord) * vColor;
 	}
 #endif
-)===="
\ No newline at end of file
+)===="
diff --git a/src/ui.h b/src/ui.h
index 3d565ee..060a282 100644
--- a/src/ui.h
+++ b/src/ui.h
@@ -105,8 +105,14 @@ namespace UI {
     void patchGlyphs(TR::Level &level) {
         UI::advGlyphsStart = level.spriteTexturesCount;
 
-        TR::TextureInfo ruSprites[RU_GLYPH_COUNT];
-        for (int i = 0; i < COUNT(ruSprites); i++) {
+    // init new sprites array with additional sprites
+        TR::TextureInfo *newSprites = new TR::TextureInfo[level.spriteTexturesCount + RU_GLYPH_COUNT + JA_GLYPH_COUNT + GR_GLYPH_COUNT];
+
+    // copy original sprites
+        memcpy(newSprites, level.spriteTextures, sizeof(TR::TextureInfo) * level.spriteTexturesCount);
+    // append russian glyphs
+        TR::TextureInfo *ruSprites = newSprites + level.spriteTexturesCount;
+        for (int i = 0; i < RU_GLYPH_COUNT; i++) {
             int idx = 110 + i; // mapped index
             int w = char_width[idx];
             int h = upperCase(idx) ? 13 : 9;
@@ -119,34 +125,21 @@ namespace UI {
 
             ruSprites[i] = TR::TextureInfo(TR::TEX_TYPE_SPRITE, 0, -h + o, w, o, (i % 16) * 16, (i / 16) * 16 + (16 - h), w, h);
         }
-
-        TR::TextureInfo jaSprites[JA_GLYPH_COUNT];
-        for (int i = 0; i < COUNT(jaSprites); i++) {
+    // append japanese glyphs
+        TR::TextureInfo *jaSprites = newSprites + level.spriteTexturesCount + RU_GLYPH_COUNT;
+        for (int i = 0; i < JA_GLYPH_COUNT; i++) {
             jaSprites[i] = TR::TextureInfo(TR::TEX_TYPE_SPRITE, 0, -16, 16, 0, (i % 16) * 16, ((i % 256) / 16) * 16, 16, 16);
         }
-
-        TR::TextureInfo grSprites[GR_GLYPH_COUNT];
-        for (int i = 0; i < COUNT(grSprites); i++) {
+    // append greek glyphs
+        TR::TextureInfo *grSprites = newSprites + level.spriteTexturesCount + RU_GLYPH_COUNT + JA_GLYPH_COUNT;
+        for (int i = 0; i < GR_GLYPH_COUNT; i++) {
             grSprites[i] = TR::TextureInfo(TR::TEX_TYPE_SPRITE, 0, -16 + GR_GLYPH_BASE - 1, GR_GLYPH_WIDTH[i], 0 + GR_GLYPH_BASE - 1, (i % 16) * 16, ((i % 256) / 16) * 16, GR_GLYPH_WIDTH[i], 16);
         }
 
-    // init new sprites array with additional sprites
-        TR::TextureInfo *newSprites = new TR::TextureInfo[level.spriteTexturesCount + COUNT(ruSprites) + COUNT(jaSprites) + COUNT(grSprites)];
-    // copy original sprites
-        memcpy(newSprites, level.spriteTextures, sizeof(TR::TextureInfo) * level.spriteTexturesCount);
-    // append russian glyphs
-        memcpy(newSprites + level.spriteTexturesCount, ruSprites, sizeof(TR::TextureInfo) * COUNT(ruSprites));
-        level.spriteTexturesCount += COUNT(ruSprites);
-    // append japanese glyphs
-        memcpy(newSprites + level.spriteTexturesCount, jaSprites, sizeof(TR::TextureInfo) * COUNT(jaSprites));
-        level.spriteTexturesCount += COUNT(jaSprites);
-    // append greek glyphs
-        memcpy(newSprites + level.spriteTexturesCount, grSprites, sizeof(TR::TextureInfo) * COUNT(grSprites));
-        level.spriteTexturesCount += COUNT(grSprites);
+        level.spriteTexturesCount += RU_GLYPH_COUNT + JA_GLYPH_COUNT + GR_GLYPH_COUNT;
 
         delete[] level.spriteTextures;
-        level.spriteTextures = newSprites;
-        TR::gSpriteTextures      = level.spriteTextures;
+        TR::gSpriteTextures      = level.spriteTextures = newSprites;
         TR::gSpriteTexturesCount = level.spriteTexturesCount;
     }
 
@@ -276,6 +269,7 @@ namespace UI {
         ensureLanguage(Core::settings.audio.language);
 
         Core::setDepthTest(false);
+        Core::setDepthWrite(false);
         Core::setBlendMode(bmPremult);
         Core::setCullMode(cmNone);
         game->setupBinding();
@@ -298,6 +292,7 @@ namespace UI {
         Core::setCullMode(cmFront);
         Core::setBlendMode(bmNone);
         Core::setDepthTest(true);
+        Core::setDepthWrite(true);
     }
 
     enum ShadeType {
@@ -802,6 +797,7 @@ namespace UI {
         Basis joints[MAX_SPHERES];
 
         Core::setDepthTest(true);
+        Core::setDepthWrite(true);
 
         for (int i = 0; i < pickups.length; i++) {
             const PickupItem &item = pickups[i];
@@ -836,6 +832,7 @@ namespace UI {
         }
 
         Core::setDepthTest(false);
+        Core::setDepthWrite(false);
 
         Core::setViewProj(mView, Core::mProj);
         game->setShader(Core::passGUI, Shader::DEFAULT);
diff --git a/src/utils.h b/src/utils.h
index 38d6b77..712062e 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -615,6 +615,7 @@ struct mat4 {
 
     enum ProjRange {
         PROJ_NEG_POS,
+        PROJ_NEG_ZERO,
         PROJ_ZERO_POS,
     };
 
@@ -646,30 +647,49 @@ struct mat4 {
         e33 = 1.0f;
     }
 
-    void ortho(ProjRange range, float l, float r, float b, float t, float znear, float zfar) {
+    void ortho(ProjRange range, float l, float r, float b, float t, float znear, float zfar, bool rotate90 = false) {
         identity();
 
-        e00 = 2.0f / (r - l);
-        e11 = 2.0f / (t - b);
-        e22 = 2.0f / (znear - zfar);
+        if (rotate90) {
+            e00 = e11 = 0.0f;
+            e01 = 2.0f / (r - l);
+            e10 = 2.0f / (b - t);
+        } else {
+            e00 = 2.0f / (r - l);
+            e11 = 2.0f / (t - b);
+        }
+
         e03 = (l + r) / (l - r);
         e13 = (t + b) / (b - t);
 
         switch (range) {
             case PROJ_NEG_POS :
-                e23 = (zfar + znear) / (znear - zfar);
+                e22 = 2.0f / (znear - zfar);
+                e23 = (znear + zfar) / (znear - zfar);
+                break;
+            case PROJ_NEG_ZERO :
+                e22 = 1.0f / (znear - zfar);
+                e23 = (znear + zfar) / (znear - zfar) * 0.5f - 0.5f;
                 break;
             case PROJ_ZERO_POS :
+                e22 = 2.0f / (znear - zfar);
                 e23 = znear / (znear - zfar);
                 break;
         }
     }
 
-    void frustum(ProjRange range, float l, float r, float b, float t, float znear, float zfar) {
+    void frustum(ProjRange range, float l, float r, float b, float t, float znear, float zfar, bool rotate90 = false) {
         identity();
 
-        e00 = 2.0f * znear / (r - l);
-        e11 = 2.0f * znear / (t - b);
+        if (rotate90) {
+            e00 = e11 = 0.0f;
+            e01 = 2.0f * znear / (r - l);
+            e10 = 2.0f * znear / (b - t);
+        } else {
+            e00 = 2.0f * znear / (r - l);
+            e11 = 2.0f * znear / (t - b);
+        }
+
         e02 = (r + l) / (r - l);
         e12 = (t + b) / (t - b);
         e32 = -1.0f;
@@ -680,6 +700,10 @@ struct mat4 {
                 e22 = (znear + zfar) / (znear - zfar);
                 e23 = 2.0f * zfar * znear / (znear - zfar);
                 break;
+            case PROJ_NEG_ZERO :
+                e22 = znear / (znear - zfar);
+                e23 = zfar * znear / (znear - zfar);
+                break;
             case PROJ_ZERO_POS :
                 e22 = zfar / (znear - zfar);
                 e23 = znear * e22;
@@ -687,18 +711,27 @@ struct mat4 {
         }
     }
 
-    void perspective(ProjRange range, float fov, float aspect, float znear, float zfar, float eye = 0.0f) {
+    void perspective(ProjRange range, float fov, float aspect, float znear, float zfar, float eye = 0.0f, bool rotate90 = false) {
         float y = tanf(fov * 0.5f * DEG2RAD) * znear;
         float x = y;
 
+        float eyeX, eyeY;
+        if (rotate90) {
+            eyeX = 0.0f;
+            eyeY = -eye;
+            aspect = 1.0f / aspect;
+        } else {
+            eyeX = eye;
+            eyeY = 0.0f;
+        }
+
         if (aspect >= 1.0f) {
             x = y * aspect;
         } else {
-            x = y;
             y /= aspect;
         }
 
-        frustum(range, -x - eye, x - eye, -y, y, znear, zfar);
+        frustum(range, -x - eyeX, x - eyeX, -y - eyeY, y - eyeY, znear, zfar, rotate90);
     }
 
     mat4(const vec3 &from, const vec3 &at, const vec3 &up) {