Browse Source

Add DrawCapsule(Wires) (#2761)

* Add DrawCapsule & DrawCapsuleWires

* Add DrawCapsule & DrawCapsuleWires to example

Co-authored-by: Ian Band <[email protected]>
ianband 2 years ago
parent
commit
7e7939e

+ 3 - 0
examples/models/models_geometric_shapes.c

@@ -66,6 +66,9 @@ int main(void)
                 DrawCylinder((Vector3){1.0f, 0.0f, -4.0f}, 0.0f, 1.5f, 3.0f, 8, GOLD);
                 DrawCylinderWires((Vector3){1.0f, 0.0f, -4.0f}, 0.0f, 1.5f, 3.0f, 8, PINK);
 
+                DrawCapsule     ((Vector3){-3.0f, 1.5f, -4.0f}, (Vector3){-4.0f, -1.0f, -4.0f}, 1.2f, 8, 8, VIOLET);
+                DrawCapsuleWires((Vector3){-3.0f, 1.5f, -4.0f}, (Vector3){-4.0f, -1.0f, -4.0f}, 1.2f, 8, 8, PURPLE);
+
                 DrawGrid(10, 1.0f);        // Draw a grid
 
             EndMode3D();

BIN
examples/models/models_geometric_shapes.png


+ 2 - 0
src/raylib.h

@@ -1423,6 +1423,8 @@ RLAPI void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, f
 RLAPI void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder with base at startPos and top at endPos
 RLAPI void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires
 RLAPI void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder wires with base at startPos and top at endPos
+RLAPI void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color); // Draw a capsule with the center of its sphere caps at startPos and endPos
+RLAPI void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color); // Draw capsule wireframe with the center of its sphere caps at startPos and endPos
 RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color);                                      // Draw a plane XZ
 RLAPI void DrawRay(Ray ray, Color color);                                                                // Draw a ray line
 RLAPI void DrawGrid(int slices, float spacing);                                                          // Draw a grid (centered at (0, 0, 0))

+ 278 - 0
src/rmodels.c

@@ -817,6 +817,284 @@ void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, fl
     rlEnd();
 }
 
+// Draw a capsule with the center of its sphere caps at startPos and endPos
+void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color)
+{
+    if (slices < 3) slices = 3;
+
+    Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
+    
+    // draw a sphere if start and end points are the same
+    bool sphereCase = (direction.x == 0) && (direction.y == 0) && (direction.z == 0);
+    if (sphereCase) direction = (Vector3){0.0f, 1.0f, 0.0f};
+
+    // Construct a basis of the base and the caps:
+    Vector3 b0 = Vector3Normalize(direction);
+    Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction));
+    Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
+    Vector3 capCenter = endPos;
+
+    float baseSliceAngle = (2.0f*PI)/slices;
+    float baseRingAngle  = PI * 0.5 / rings; 
+
+    rlBegin(RL_TRIANGLES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        // render both caps
+        for (int c = 0; c < 2; c++)
+        {
+            for (int i = 0; i < rings; i++)
+            {
+                for (int j = 0; j < slices; j++) 
+                {
+
+                    // we build up the rings from capCenter in the direction of the 'direction' vector we computed earlier
+
+                    // as we iterate through the rings they must be placed higher above the center, the height we need is sin(angle(i))
+                    // as we iterate through the rings they must get smaller by the cos(angle(i))
+
+                    // compute the four vertices
+                    float ringSin1 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 0 ));
+                    float ringCos1 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 0 ));
+                    Vector3 w1 = (Vector3){ 
+                        capCenter.x + (sinf(baseRingAngle * ( i + 0 ))*b0.x + ringSin1*b1.x + ringCos1*b2.x) * radius,
+                        capCenter.y + (sinf(baseRingAngle * ( i + 0 ))*b0.y + ringSin1*b1.y + ringCos1*b2.y) * radius, 
+                        capCenter.z + (sinf(baseRingAngle * ( i + 0 ))*b0.z + ringSin1*b1.z + ringCos1*b2.z) * radius
+                    };
+                    float ringSin2 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 0 ));
+                    float ringCos2 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 0 ));
+                    Vector3 w2 = (Vector3){ 
+                        capCenter.x + (sinf(baseRingAngle * ( i + 0 ))*b0.x + ringSin2*b1.x + ringCos2*b2.x) * radius, 
+                        capCenter.y + (sinf(baseRingAngle * ( i + 0 ))*b0.y + ringSin2*b1.y + ringCos2*b2.y) * radius, 
+                        capCenter.z + (sinf(baseRingAngle * ( i + 0 ))*b0.z + ringSin2*b1.z + ringCos2*b2.z) * radius 
+                    };
+
+                    float ringSin3 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 1 ));
+                    float ringCos3 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 1 ));
+                    Vector3 w3 = (Vector3){ 
+                        capCenter.x + (sinf(baseRingAngle * ( i + 1 ))*b0.x + ringSin3*b1.x + ringCos3*b2.x) * radius, 
+                        capCenter.y + (sinf(baseRingAngle * ( i + 1 ))*b0.y + ringSin3*b1.y + ringCos3*b2.y) * radius, 
+                        capCenter.z + (sinf(baseRingAngle * ( i + 1 ))*b0.z + ringSin3*b1.z + ringCos3*b2.z) * radius 
+                    };
+                    float ringSin4 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 1 ));
+                    float ringCos4 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 1 ));
+                    Vector3 w4 = (Vector3){ 
+                        capCenter.x + (sinf(baseRingAngle * ( i + 1 ))*b0.x + ringSin4*b1.x + ringCos4*b2.x) * radius, 
+                        capCenter.y + (sinf(baseRingAngle * ( i + 1 ))*b0.y + ringSin4*b1.y + ringCos4*b2.y) * radius, 
+                        capCenter.z + (sinf(baseRingAngle * ( i + 1 ))*b0.z + ringSin4*b1.z + ringCos4*b2.z) * radius 
+                    };
+
+                    // make sure cap triangle normals are facing outwards
+                    if(c == 0)
+                    {
+                        rlVertex3f(w1.x, w1.y, w1.z);
+                        rlVertex3f(w2.x, w2.y, w2.z);
+                        rlVertex3f(w3.x, w3.y, w3.z);
+                        
+                        rlVertex3f(w2.x, w2.y, w2.z);   
+                        rlVertex3f(w4.x, w4.y, w4.z);  
+                        rlVertex3f(w3.x, w3.y, w3.z); 
+                    }
+                    else
+                    {
+                        rlVertex3f(w1.x, w1.y, w1.z);
+                        rlVertex3f(w3.x, w3.y, w3.z);
+                        rlVertex3f(w2.x, w2.y, w2.z);
+
+                        rlVertex3f(w2.x, w2.y, w2.z);  
+                        rlVertex3f(w3.x, w3.y, w3.z);  
+                        rlVertex3f(w4.x, w4.y, w4.z);     
+                    }
+                }
+            }
+            capCenter = startPos;
+            b0 = Vector3Scale(b0, -1.0f);
+        }
+        // render middle
+        if (!sphereCase)
+        {
+            for (int j = 0; j < slices; j++) 
+            {
+                // compute the four vertices
+                float ringSin1 = sinf(baseSliceAngle*(j + 0))*radius;
+                float ringCos1 = cosf(baseSliceAngle*(j + 0))*radius;
+                Vector3 w1 = { 
+                    startPos.x + ringSin1*b1.x + ringCos1*b2.x,
+                    startPos.y + ringSin1*b1.y + ringCos1*b2.y, 
+                    startPos.z + ringSin1*b1.z + ringCos1*b2.z 
+                };
+                float ringSin2 = sinf(baseSliceAngle*(j + 1))*radius;
+                float ringCos2 = cosf(baseSliceAngle*(j + 1))*radius;
+                Vector3 w2 = { 
+                    startPos.x + ringSin2*b1.x + ringCos2*b2.x, 
+                    startPos.y + ringSin2*b1.y + ringCos2*b2.y, 
+                    startPos.z + ringSin2*b1.z + ringCos2*b2.z 
+                };
+
+                float ringSin3 = sinf(baseSliceAngle*(j + 0))*radius;
+                float ringCos3 = cosf(baseSliceAngle*(j + 0))*radius;
+                Vector3 w3 = { 
+                    endPos.x + ringSin3*b1.x + ringCos3*b2.x, 
+                    endPos.y + ringSin3*b1.y + ringCos3*b2.y, 
+                    endPos.z + ringSin3*b1.z + ringCos3*b2.z 
+                };
+                float ringSin4 = sinf(baseSliceAngle*(j + 1))*radius;
+                float ringCos4 = cosf(baseSliceAngle*(j + 1))*radius;
+                Vector3 w4 = { 
+                    endPos.x + ringSin4*b1.x + ringCos4*b2.x, 
+                    endPos.y + ringSin4*b1.y + ringCos4*b2.y, 
+                    endPos.z + ringSin4*b1.z + ringCos4*b2.z 
+                };
+                                                                        //          w2 x.-----------x startPos
+                rlVertex3f(w1.x, w1.y, w1.z);                         // |           |\'.  T0    /
+                rlVertex3f(w2.x, w2.y, w2.z);                         // T1          | \ '.     /
+                rlVertex3f(w3.x, w3.y, w3.z);                         // |           |T \  '.  /
+                                                                        //             | 2 \ T 'x w1
+                rlVertex3f(w2.x, w2.y, w2.z);                         // |        w4 x.---\-1-|---x endPos
+                rlVertex3f(w4.x, w4.y, w4.z);                         // T2            '.  \  |T3/
+                rlVertex3f(w3.x, w3.y, w3.z);                         // |               '. \ | /
+                                                                        //                   '.\|/
+                                                                        //                   'x w3
+            }
+        }
+    rlEnd();
+}
+
+// Draw capsule wires with the center of its sphere caps at startPos and endPos
+void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color)
+{
+    if (slices < 3) slices = 3;
+
+    Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
+
+    // draw a sphere if start and end points are the same
+    bool sphereCase = (direction.x == 0) && (direction.y == 0) && (direction.z == 0);
+    if (sphereCase) direction = (Vector3){0.0f, 1.0f, 0.0f};
+
+    // Construct a basis of the base and the caps:
+    Vector3 b0 = Vector3Normalize(direction);
+    Vector3 b1 = Vector3Normalize(Vector3Perpendicular(direction));
+    Vector3 b2 = Vector3Normalize(Vector3CrossProduct(b1, direction));
+    Vector3 capCenter = endPos;
+
+    float baseSliceAngle = (2.0f*PI)/slices;
+    float baseRingAngle  = PI * 0.5 / rings; 
+
+    rlBegin(RL_LINES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+
+        // render both caps
+        for (int c = 0; c < 2; c++)
+        {
+            for (int i = 0; i < rings; i++)
+            {
+                for (int j = 0; j < slices; j++) 
+                {
+
+                    // we build up the rings from capCenter in the direction of the 'direction' vector we computed earlier
+
+                    // as we iterate through the rings they must be placed higher above the center, the height we need is sin(angle(i))
+                    // as we iterate through the rings they must get smaller by the cos(angle(i))
+
+                    // compute the four vertices
+                    float ringSin1 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 0 ));
+                    float ringCos1 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 0 ));
+                    Vector3 w1 = (Vector3){ 
+                        capCenter.x + (sinf(baseRingAngle * ( i + 0 ))*b0.x + ringSin1*b1.x + ringCos1*b2.x) * radius,
+                        capCenter.y + (sinf(baseRingAngle * ( i + 0 ))*b0.y + ringSin1*b1.y + ringCos1*b2.y) * radius, 
+                        capCenter.z + (sinf(baseRingAngle * ( i + 0 ))*b0.z + ringSin1*b1.z + ringCos1*b2.z) * radius
+                    };
+                    float ringSin2 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 0 ));
+                    float ringCos2 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 0 ));
+                    Vector3 w2 = (Vector3){ 
+                        capCenter.x + (sinf(baseRingAngle * ( i + 0 ))*b0.x + ringSin2*b1.x + ringCos2*b2.x) * radius, 
+                        capCenter.y + (sinf(baseRingAngle * ( i + 0 ))*b0.y + ringSin2*b1.y + ringCos2*b2.y) * radius, 
+                        capCenter.z + (sinf(baseRingAngle * ( i + 0 ))*b0.z + ringSin2*b1.z + ringCos2*b2.z) * radius 
+                    };
+
+                    float ringSin3 = sinf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 1 ));
+                    float ringCos3 = cosf(baseSliceAngle*(j + 0))*cosf(baseRingAngle * ( i + 1 ));
+                    Vector3 w3 = (Vector3){ 
+                        capCenter.x + (sinf(baseRingAngle * ( i + 1 ))*b0.x + ringSin3*b1.x + ringCos3*b2.x) * radius, 
+                        capCenter.y + (sinf(baseRingAngle * ( i + 1 ))*b0.y + ringSin3*b1.y + ringCos3*b2.y) * radius, 
+                        capCenter.z + (sinf(baseRingAngle * ( i + 1 ))*b0.z + ringSin3*b1.z + ringCos3*b2.z) * radius 
+                    };
+                    float ringSin4 = sinf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 1 ));
+                    float ringCos4 = cosf(baseSliceAngle*(j + 1))*cosf(baseRingAngle * ( i + 1 ));
+                    Vector3 w4 = (Vector3){ 
+                        capCenter.x + (sinf(baseRingAngle * ( i + 1 ))*b0.x + ringSin4*b1.x + ringCos4*b2.x) * radius, 
+                        capCenter.y + (sinf(baseRingAngle * ( i + 1 ))*b0.y + ringSin4*b1.y + ringCos4*b2.y) * radius, 
+                        capCenter.z + (sinf(baseRingAngle * ( i + 1 ))*b0.z + ringSin4*b1.z + ringCos4*b2.z) * radius 
+                    };
+
+                    rlVertex3f(w1.x, w1.y, w1.z);
+                    rlVertex3f(w2.x, w2.y, w2.z);
+
+                    rlVertex3f(w2.x, w2.y, w2.z);
+                    rlVertex3f(w3.x, w3.y, w3.z);
+
+                    rlVertex3f(w1.x, w1.y, w1.z);
+                    rlVertex3f(w3.x, w3.y, w3.z);
+                    
+                    rlVertex3f(w2.x, w2.y, w2.z);   
+                    rlVertex3f(w4.x, w4.y, w4.z); 
+
+                    rlVertex3f(w3.x, w3.y, w3.z);
+                    rlVertex3f(w4.x, w4.y, w4.z); 
+                }
+            }
+            capCenter = startPos;
+            b0 = Vector3Scale(b0, -1.0f);
+        }
+        // render middle
+        if (!sphereCase)
+        {
+            for (int j = 0; j < slices; j++) 
+            {
+                // compute the four vertices
+                float ringSin1 = sinf(baseSliceAngle*(j + 0))*radius;
+                float ringCos1 = cosf(baseSliceAngle*(j + 0))*radius;
+                Vector3 w1 = { 
+                    startPos.x + ringSin1*b1.x + ringCos1*b2.x,
+                    startPos.y + ringSin1*b1.y + ringCos1*b2.y, 
+                    startPos.z + ringSin1*b1.z + ringCos1*b2.z 
+                };
+                float ringSin2 = sinf(baseSliceAngle*(j + 1))*radius;
+                float ringCos2 = cosf(baseSliceAngle*(j + 1))*radius;
+                Vector3 w2 = { 
+                    startPos.x + ringSin2*b1.x + ringCos2*b2.x, 
+                    startPos.y + ringSin2*b1.y + ringCos2*b2.y, 
+                    startPos.z + ringSin2*b1.z + ringCos2*b2.z 
+                };
+
+                float ringSin3 = sinf(baseSliceAngle*(j + 0))*radius;
+                float ringCos3 = cosf(baseSliceAngle*(j + 0))*radius;
+                Vector3 w3 = { 
+                    endPos.x + ringSin3*b1.x + ringCos3*b2.x, 
+                    endPos.y + ringSin3*b1.y + ringCos3*b2.y, 
+                    endPos.z + ringSin3*b1.z + ringCos3*b2.z 
+                };
+                float ringSin4 = sinf(baseSliceAngle*(j + 1))*radius;
+                float ringCos4 = cosf(baseSliceAngle*(j + 1))*radius;
+                Vector3 w4 = { 
+                    endPos.x + ringSin4*b1.x + ringCos4*b2.x, 
+                    endPos.y + ringSin4*b1.y + ringCos4*b2.y, 
+                    endPos.z + ringSin4*b1.z + ringCos4*b2.z 
+                };
+
+                rlVertex3f(w1.x, w1.y, w1.z); 
+                rlVertex3f(w3.x, w3.y, w3.z);
+
+                rlVertex3f(w2.x, w2.y, w2.z); 
+                rlVertex3f(w4.x, w4.y, w4.z); 
+
+                rlVertex3f(w2.x, w2.y, w2.z); 
+                rlVertex3f(w3.x, w3.y, w3.z);
+            }
+        }
+    rlEnd();
+}
+
 // Draw a plane
 void DrawPlane(Vector3 centerPos, Vector2 size, Color color)
 {