Quellcode durchsuchen

LibGL+LibSoftGPU: Implement normalization of normals

* LibGL now supports the `GL_NORMALIZE` capability
* LibSoftGPU transforms and normalizes the vertices' normals

Normals are heavily used in texture coordinate generation, to be
implemented in a future commit.
Jelle Raaijmakers vor 3 Jahren
Ursprung
Commit
3a5f69b6f3

+ 22 - 1
Userland/Libraries/LibGL/SoftwareGLContext.cpp

@@ -280,7 +280,16 @@ void SoftwareGLContext::gl_end()
         VERIFY_NOT_REACHED();
     }
 
-    m_rasterizer.draw_primitives(primitive_type, m_projection_matrix * m_model_view_matrix, m_texture_matrix, m_vertex_list, enabled_texture_units);
+    // Set up normals transform by taking the upper left 3x3 elements from the model view matrix
+    // See section 2.11.3 of the OpenGL 1.5 spec
+    auto const& mv_elements = m_model_view_matrix.elements();
+    auto normal_transform = FloatMatrix3x3(
+        mv_elements[0][0], mv_elements[0][1], mv_elements[0][2],
+        mv_elements[1][0], mv_elements[1][1], mv_elements[1][2],
+        mv_elements[2][0], mv_elements[2][1], mv_elements[2][2]);
+    normal_transform = normal_transform.inverse();
+
+    m_rasterizer.draw_primitives(primitive_type, m_projection_matrix * m_model_view_matrix, normal_transform, m_texture_matrix, m_vertex_list, enabled_texture_units);
 
     m_vertex_list.clear_with_capacity();
 }
@@ -619,6 +628,11 @@ void SoftwareGLContext::gl_enable(GLenum capability)
     case GL_LIGHTING:
         m_lighting_enabled = true;
         break;
+    case GL_NORMALIZE:
+        m_normalize = true;
+        rasterizer_options.normalization_enabled = true;
+        update_rasterizer_options = true;
+        break;
     case GL_SCISSOR_TEST:
         rasterizer_options.scissor_enabled = true;
         update_rasterizer_options = true;
@@ -690,6 +704,11 @@ void SoftwareGLContext::gl_disable(GLenum capability)
     case GL_LIGHTING:
         m_lighting_enabled = false;
         break;
+    case GL_NORMALIZE:
+        m_normalize = false;
+        rasterizer_options.normalization_enabled = false;
+        update_rasterizer_options = true;
+        break;
     case GL_SCISSOR_TEST:
         rasterizer_options.scissor_enabled = false;
         update_rasterizer_options = true;
@@ -742,6 +761,8 @@ GLboolean SoftwareGLContext::gl_is_enabled(GLenum capability)
         return rasterizer_options.fog_enabled;
     case GL_LIGHTING:
         return m_lighting_enabled;
+    case GL_NORMALIZE:
+        return m_normalize;
     case GL_SCISSOR_TEST:
         return rasterizer_options.scissor_enabled;
     case GL_STENCIL_TEST:

+ 1 - 0
Userland/Libraries/LibGL/SoftwareGLContext.h

@@ -206,6 +206,7 @@ private:
     GLclampf m_alpha_test_ref_value = 0;
 
     bool m_dither_enabled { true };
+    bool m_normalize { false };
 
     // Stencil configuration
     bool m_stencil_test_enabled { false };

+ 12 - 2
Userland/Libraries/LibSoftGPU/Device.cpp

@@ -524,7 +524,8 @@ DeviceInfo Device::info() const
     };
 }
 
-void Device::draw_primitives(PrimitiveType primitive_type, FloatMatrix4x4 const& transform, FloatMatrix4x4 const& texture_matrix, Vector<Vertex> const& vertices, Vector<size_t> const& enabled_texture_units)
+void Device::draw_primitives(PrimitiveType primitive_type, FloatMatrix4x4 const& transform, FloatMatrix3x3 const& normal_transform,
+    FloatMatrix4x4 const& texture_transform, Vector<Vertex> const& vertices, Vector<size_t> const& enabled_texture_units)
 {
     // At this point, the user has effectively specified that they are done with defining the geometry
     // of what they want to draw. We now need to do a few things (https://www.khronos.org/opengl/wiki/Rendering_Pipeline_Overview):
@@ -675,8 +676,17 @@ void Device::draw_primitives(PrimitiveType primitive_type, FloatMatrix4x4 const&
                 continue;
         }
 
-        if (area > 0) {
+        if (area > 0)
             swap(triangle.vertices[0], triangle.vertices[1]);
+
+        // Transform normals
+        triangle.vertices[0].normal = normal_transform * triangle.vertices[0].normal;
+        triangle.vertices[1].normal = normal_transform * triangle.vertices[1].normal;
+        triangle.vertices[2].normal = normal_transform * triangle.vertices[2].normal;
+        if (m_options.normalization_enabled) {
+            triangle.vertices[0].normal.normalize();
+            triangle.vertices[1].normal.normalize();
+            triangle.vertices[2].normal.normalize();
         }
 
         submit_triangle(triangle, enabled_texture_units);

+ 3 - 1
Userland/Libraries/LibSoftGPU/Device.h

@@ -10,6 +10,7 @@
 #include <AK/NonnullRefPtr.h>
 #include <AK/OwnPtr.h>
 #include <LibGfx/Bitmap.h>
+#include <LibGfx/Matrix3x3.h>
 #include <LibGfx/Matrix4x4.h>
 #include <LibGfx/Rect.h>
 #include <LibGfx/Vector4.h>
@@ -47,6 +48,7 @@ struct RasterizerOptions {
     float fog_start { 0.0f };
     float fog_end { 1.0f };
     bool scissor_enabled { false };
+    bool normalization_enabled { false };
     Gfx::IntRect scissor_box;
     bool enable_color_write { true };
     float depth_offset_factor { 0 };
@@ -65,7 +67,7 @@ public:
 
     DeviceInfo info() const;
 
-    void draw_primitives(PrimitiveType, FloatMatrix4x4 const& transform, FloatMatrix4x4 const& texture_matrix, Vector<Vertex> const& vertices, Vector<size_t> const& enabled_texture_units);
+    void draw_primitives(PrimitiveType, FloatMatrix4x4 const& transform, FloatMatrix3x3 const& normal_transform, FloatMatrix4x4 const& texture_transform, Vector<Vertex> const& vertices, Vector<size_t> const& enabled_texture_units);
     void resize(const Gfx::IntSize& min_size);
     void clear_color(const FloatVector4&);
     void clear_depth(float);