Browse Source

Merge branch 'master' of https://github.com/raysan5/raylib

Ray 4 tháng trước cách đây
mục cha
commit
a51d334440

+ 1 - 0
build.zig

@@ -256,6 +256,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
                     raylib.root_module.linkSystemLibrary("GLESv2", .{});
                     raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES2", "");
                 }
+                raylib.root_module.linkSystemLibrary("EGL", .{});
 
                 setDesktopPlatform(raylib, .android);
             } else {

+ 3 - 3
parser/output/raylib_api.json

@@ -3139,7 +3139,7 @@
           "name": "fileName"
         },
         {
-          "type": "char *",
+          "type": "const char *",
           "name": "text"
         }
       ]
@@ -4409,7 +4409,7 @@
           "name": "fileName"
         },
         {
-          "type": "char *",
+          "type": "const char *",
           "name": "text"
         }
       ]
@@ -4707,7 +4707,7 @@
       "returnType": "unsigned char *",
       "params": [
         {
-          "type": "const unsigned char *",
+          "type": "const char *",
           "name": "data"
         },
         {

+ 3 - 3
parser/output/raylib_api.lua

@@ -3108,7 +3108,7 @@ return {
       returnType = "bool",
       params = {
         {type = "const char *", name = "fileName"},
-        {type = "char *", name = "text"}
+        {type = "const char *", name = "text"}
       }
     },
     {
@@ -4006,7 +4006,7 @@ return {
       returnType = "bool",
       params = {
         {type = "const char *", name = "fileName"},
-        {type = "char *", name = "text"}
+        {type = "const char *", name = "text"}
       }
     },
     {
@@ -4211,7 +4211,7 @@ return {
       description = "Decode Base64 string data, memory must be MemFree()",
       returnType = "unsigned char *",
       params = {
-        {type = "const unsigned char *", name = "data"},
+        {type = "const char *", name = "data"},
         {type = "int *", name = "outputSize"}
       }
     },

+ 3 - 3
parser/output/raylib_api.txt

@@ -985,7 +985,7 @@ Callback 005: SaveFileTextCallback() (2 input parameters)
   Return type: bool
   Description: FileIO: Save text data
   Param[1]: fileName (type: const char *)
-  Param[2]: text (type: char *)
+  Param[2]: text (type: const char *)
 Callback 006: AudioCallback() (2 input parameters)
   Name: AudioCallback
   Return type: void
@@ -1656,7 +1656,7 @@ Function 123: SaveFileText() (2 input parameters)
   Return type: bool
   Description: Save text data to file (write), string must be '\0' terminated, returns true on success
   Param[1]: fileName (type: const char *)
-  Param[2]: text (type: char *)
+  Param[2]: text (type: const char *)
 Function 124: FileExists() (1 input parameters)
   Name: FileExists
   Return type: bool
@@ -1795,7 +1795,7 @@ Function 149: DecodeDataBase64() (2 input parameters)
   Name: DecodeDataBase64
   Return type: unsigned char *
   Description: Decode Base64 string data, memory must be MemFree()
-  Param[1]: data (type: const unsigned char *)
+  Param[1]: data (type: const char *)
   Param[2]: outputSize (type: int *)
 Function 150: ComputeCRC32() (2 input parameters)
   Name: ComputeCRC32

+ 3 - 3
parser/output/raylib_api.xml

@@ -672,7 +672,7 @@
         </Callback>
         <Callback name="SaveFileTextCallback" retType="bool" paramCount="2" desc="FileIO: Save text data">
             <Param type="const char *" name="fileName" desc="" />
-            <Param type="char *" name="text" desc="" />
+            <Param type="const char *" name="text" desc="" />
         </Callback>
         <Callback name="AudioCallback" retType="void" paramCount="2" desc="">
             <Param type="void *" name="bufferData" desc="" />
@@ -1046,7 +1046,7 @@
         </Function>
         <Function name="SaveFileText" retType="bool" paramCount="2" desc="Save text data to file (write), string must be '\0' terminated, returns true on success">
             <Param type="const char *" name="fileName" desc="" />
-            <Param type="char *" name="text" desc="" />
+            <Param type="const char *" name="text" desc="" />
         </Function>
         <Function name="FileExists" retType="bool" paramCount="1" desc="Check if file exists">
             <Param type="const char *" name="fileName" desc="" />
@@ -1129,7 +1129,7 @@
             <Param type="int *" name="outputSize" desc="" />
         </Function>
         <Function name="DecodeDataBase64" retType="unsigned char *" paramCount="2" desc="Decode Base64 string data, memory must be MemFree()">
-            <Param type="const unsigned char *" name="data" desc="" />
+            <Param type="const char *" name="data" desc="" />
             <Param type="int *" name="outputSize" desc="" />
         </Function>
         <Function name="ComputeCRC32" retType="unsigned int" paramCount="2" desc="Compute CRC32 hash code">

+ 1 - 1
src/raylib.h

@@ -954,7 +954,7 @@ typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args);
 typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize);    // FileIO: Load binary data
 typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, int dataSize);   // FileIO: Save binary data
 typedef char *(*LoadFileTextCallback)(const char *fileName);            // FileIO: Load text data
-typedef bool (*SaveFileTextCallback)(const char *fileName, char *text); // FileIO: Save text data
+typedef bool (*SaveFileTextCallback)(const char *fileName, const char *text); // FileIO: Save text data
 
 //------------------------------------------------------------------------------------
 // Global Variables Definition

+ 96 - 41
src/rmodels.c

@@ -3608,16 +3608,16 @@ BoundingBox GetMeshBoundingBox(Mesh mesh)
 }
 
 // Compute mesh tangents
-// NOTE: To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates
-// Implementation based on: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html
 void GenMeshTangents(Mesh *mesh)
 {
-    if ((mesh->vertices == NULL) || (mesh->texcoords == NULL))
+    // Check if input mesh data is useful
+    if ((mesh == NULL) || (mesh->vertices == NULL) || (mesh->texcoords == NULL) || (mesh->normals == NULL))
     {
-        TRACELOG(LOG_WARNING, "MESH: Tangents generation requires texcoord vertex attribute data");
+        TRACELOG(LOG_WARNING, "MESH: Tangents generation requires vertices, texcoords and normals vertex attribute data");
         return;
     }
 
+    // Allocate or reallocate tangents data
     if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
     else
     {
@@ -3625,26 +3625,51 @@ void GenMeshTangents(Mesh *mesh)
         mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
     }
 
-    Vector3 *tan1 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
-    Vector3 *tan2 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
+    // Allocate temporary arrays for tangents calculation
+    Vector3 *tan1 = (Vector3 *)RL_CALLOC(mesh->vertexCount, sizeof(Vector3));
+    Vector3 *tan2 = (Vector3 *)RL_CALLOC(mesh->vertexCount, sizeof(Vector3));
 
-    if (mesh->vertexCount % 3 != 0)
+    if (tan1 == NULL || tan2 == NULL)
     {
-        TRACELOG(LOG_WARNING, "MESH: vertexCount expected to be a multiple of 3. Expect uninitialized values.");
+        TRACELOG(LOG_WARNING, "MESH: Failed to allocate temporary memory for tangent calculation");
+        if (tan1) RL_FREE(tan1);
+        if (tan2) RL_FREE(tan2);
+        return;
     }
 
-    for (int i = 0; i <= mesh->vertexCount - 3; i += 3)
+    // Process all triangles of the mesh
+    // 'triangleCount' must be always valid
+    for (int t = 0; t < mesh->triangleCount; t++)
     {
-        // Get triangle vertices
-        Vector3 v1 = { mesh->vertices[(i + 0)*3 + 0], mesh->vertices[(i + 0)*3 + 1], mesh->vertices[(i + 0)*3 + 2] };
-        Vector3 v2 = { mesh->vertices[(i + 1)*3 + 0], mesh->vertices[(i + 1)*3 + 1], mesh->vertices[(i + 1)*3 + 2] };
-        Vector3 v3 = { mesh->vertices[(i + 2)*3 + 0], mesh->vertices[(i + 2)*3 + 1], mesh->vertices[(i + 2)*3 + 2] };
+        // Get triangle vertex indices
+        int i0, i1, i2;
+
+        if (mesh->indices != NULL)
+        {
+            // Use indices if available
+            i0 = mesh->indices[t*3 + 0];
+            i1 = mesh->indices[t*3 + 1];
+            i2 = mesh->indices[t*3 + 2];
+        }
+        else
+        {
+            // Sequential access for non-indexed mesh
+            i0 = t*3 + 0;
+            i1 = t*3 + 1;
+            i2 = t*3 + 2;
+        }
+
+        // Get triangle vertices position
+        Vector3 v1 = { mesh->vertices[i0*3 + 0], mesh->vertices[i0*3 + 1], mesh->vertices[i0*3 + 2] };
+        Vector3 v2 = { mesh->vertices[i1*3 + 0], mesh->vertices[i1*3 + 1], mesh->vertices[i1*3 + 2] };
+        Vector3 v3 = { mesh->vertices[i2*3 + 0], mesh->vertices[i2*3 + 1], mesh->vertices[i2*3 + 2] };
 
         // Get triangle texcoords
-        Vector2 uv1 = { mesh->texcoords[(i + 0)*2 + 0], mesh->texcoords[(i + 0)*2 + 1] };
-        Vector2 uv2 = { mesh->texcoords[(i + 1)*2 + 0], mesh->texcoords[(i + 1)*2 + 1] };
-        Vector2 uv3 = { mesh->texcoords[(i + 2)*2 + 0], mesh->texcoords[(i + 2)*2 + 1] };
+        Vector2 uv1 = { mesh->texcoords[i0*2 + 0], mesh->texcoords[i0*2 + 1] };
+        Vector2 uv2 = { mesh->texcoords[i1*2 + 0], mesh->texcoords[i1*2 + 1] };
+        Vector2 uv3 = { mesh->texcoords[i2*2 + 0], mesh->texcoords[i2*2 + 1] };
 
+        // Calculate triangle edges
         float x1 = v2.x - v1.x;
         float y1 = v2.y - v1.y;
         float z1 = v2.z - v1.z;
@@ -3652,65 +3677,95 @@ void GenMeshTangents(Mesh *mesh)
         float y2 = v3.y - v1.y;
         float z2 = v3.z - v1.z;
 
+        // Calculate texture coordinate differences
         float s1 = uv2.x - uv1.x;
         float t1 = uv2.y - uv1.y;
         float s2 = uv3.x - uv1.x;
         float t2 = uv3.y - uv1.y;
 
+        // Calculate denominator and check for degenerate UV
         float div = s1*t2 - s2*t1;
-        float r = (div == 0.0f)? 0.0f : 1.0f/div;
+        float r = (fabsf(div) < 0.0001f)? 0.0f : 1.0f/div;
 
+        // Calculate tangent and bitangent directions
         Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r };
         Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r };
 
-        tan1[i + 0] = sdir;
-        tan1[i + 1] = sdir;
-        tan1[i + 2] = sdir;
+        // Accumulate tangents and bitangents for each vertex of the triangle
+        tan1[i0] = Vector3Add(tan1[i0], sdir);
+        tan1[i1] = Vector3Add(tan1[i1], sdir);
+        tan1[i2] = Vector3Add(tan1[i2], sdir);
 
-        tan2[i + 0] = tdir;
-        tan2[i + 1] = tdir;
-        tan2[i + 2] = tdir;
+        tan2[i0] = Vector3Add(tan2[i0], tdir);
+        tan2[i1] = Vector3Add(tan2[i1], tdir);
+        tan2[i2] = Vector3Add(tan2[i2], tdir);
     }
 
-    // Compute tangents considering normals
+    // Calculate final tangents for each vertex
     for (int i = 0; i < mesh->vertexCount; i++)
     {
         Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
         Vector3 tangent = tan1[i];
 
-        // TODO: Review, not sure if tangent computation is right, just used reference proposed maths...
-#if defined(COMPUTE_TANGENTS_METHOD_01)
-        Vector3 tmp = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
-        tmp = Vector3Normalize(tmp);
-        mesh->tangents[i*4 + 0] = tmp.x;
-        mesh->tangents[i*4 + 1] = tmp.y;
-        mesh->tangents[i*4 + 2] = tmp.z;
-        mesh->tangents[i*4 + 3] = 1.0f;
-#else
-        Vector3OrthoNormalize(&normal, &tangent);
-        mesh->tangents[i*4 + 0] = tangent.x;
-        mesh->tangents[i*4 + 1] = tangent.y;
-        mesh->tangents[i*4 + 2] = tangent.z;
-        mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f)? -1.0f : 1.0f;
-#endif
+        // Handle zero tangent (can happen with degenerate UVs)
+        if (Vector3Length(tangent) < 0.0001f)
+        {
+            // Create a tangent perpendicular to the normal
+            if (fabsf(normal.z) > 0.707f) tangent = (Vector3){ 1.0f, 0.0f, 0.0f };
+            else tangent = Vector3Normalize((Vector3){ -normal.y, normal.x, 0.0f });
+                
+            mesh->tangents[i*4 + 0] = tangent.x;
+            mesh->tangents[i*4 + 1] = tangent.y;
+            mesh->tangents[i*4 + 2] = tangent.z;
+            mesh->tangents[i*4 + 3] = 1.0f;
+            continue;
+        }
+
+        // Gram-Schmidt orthogonalization to make tangent orthogonal to normal
+        // T_prime = T - N * dot(N, T)
+        Vector3 orthogonalized = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
+        
+        // Handle cases where orthogonalized vector is too small
+        if (Vector3Length(orthogonalized) < 0.0001f)
+        {
+            // Create a tangent perpendicular to the normal
+            if (fabsf(normal.z) > 0.707f) orthogonalized = (Vector3){ 1.0f, 0.0f, 0.0f };
+            else orthogonalized = Vector3Normalize((Vector3){ -normal.y, normal.x, 0.0f });
+        }
+        else
+        {
+            // Normalize the orthogonalized tangent
+            orthogonalized = Vector3Normalize(orthogonalized);
+        }
+
+        // Store the calculated tangent
+        mesh->tangents[i*4 + 0] = orthogonalized.x;
+        mesh->tangents[i*4 + 1] = orthogonalized.y;
+        mesh->tangents[i*4 + 2] = orthogonalized.z;
+        
+        // Calculate the handedness (w component)
+        mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, orthogonalized), tan2[i]) < 0.0f)? -1.0f : 1.0f;
     }
 
+    // Free temporary arrays
     RL_FREE(tan1);
     RL_FREE(tan2);
 
+    // Update vertex buffers if available
     if (mesh->vboId != NULL)
     {
         if (mesh->vboId[SHADER_LOC_VERTEX_TANGENT] != 0)
         {
-            // Update existing vertex buffer
+            // Update existing tangent vertex buffer
             rlUpdateVertexBuffer(mesh->vboId[SHADER_LOC_VERTEX_TANGENT], mesh->tangents, mesh->vertexCount*4*sizeof(float), 0);
         }
         else
         {
-            // Load a new tangent attributes buffer
+            // Create new tangent vertex buffer
             mesh->vboId[SHADER_LOC_VERTEX_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), false);
         }
 
+        // Set up vertex attributes for shader
         rlEnableVertexArray(mesh->vaoId);
         rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0);
         rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);