Update C sources

This commit is contained in:
Milan Nikolic 2022-10-23 14:21:08 +02:00
parent a460a0fc06
commit 1b0affeed0
No known key found for this signature in database
GPG key ID: 9229D0EAA3AA4E75
96 changed files with 26693 additions and 11843 deletions

View file

@ -163,11 +163,6 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, unsigned int
// Draw a line in 3D world space
void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color)
{
// WARNING: Be careful with internal buffer vertex alignment
// when using RL_LINES or RL_TRIANGLES, data is aligned to fit
// lines-triangles-quads in the same indexed buffers!!!
rlCheckRenderBatchLimit(8);
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex3f(startPos.x, startPos.y, startPos.z);
@ -178,8 +173,6 @@ void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color)
// Draw a point in 3D space, actually a small line
void DrawPoint3D(Vector3 position, Color color)
{
rlCheckRenderBatchLimit(8);
rlPushMatrix();
rlTranslatef(position.x, position.y, position.z);
rlBegin(RL_LINES);
@ -193,8 +186,6 @@ void DrawPoint3D(Vector3 position, Color color)
// Draw a circle in 3D world space
void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color)
{
rlCheckRenderBatchLimit(2*36);
rlPushMatrix();
rlTranslatef(center.x, center.y, center.z);
rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
@ -214,8 +205,6 @@ void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rota
// Draw a color-filled triangle (vertex in counter-clockwise order!)
void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color)
{
rlCheckRenderBatchLimit(8);
rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex3f(v1.x, v1.y, v1.z);
@ -227,30 +216,27 @@ void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color)
// Draw a triangle strip defined by points
void DrawTriangleStrip3D(Vector3 *points, int pointCount, Color color)
{
if (pointCount >= 3)
{
rlCheckRenderBatchLimit(3*(pointCount - 2));
if (pointCount < 3) return;
rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 2; i < pointCount; i++)
for (int i = 2; i < pointCount; i++)
{
if ((i%2) == 0)
{
if ((i%2) == 0)
{
rlVertex3f(points[i].x, points[i].y, points[i].z);
rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z);
rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z);
}
else
{
rlVertex3f(points[i].x, points[i].y, points[i].z);
rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z);
rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z);
}
rlVertex3f(points[i].x, points[i].y, points[i].z);
rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z);
rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z);
}
rlEnd();
}
else
{
rlVertex3f(points[i].x, points[i].y, points[i].z);
rlVertex3f(points[i - 1].x, points[i - 1].y, points[i - 1].z);
rlVertex3f(points[i - 2].x, points[i - 2].y, points[i - 2].z);
}
}
rlEnd();
}
// Draw cube
@ -261,8 +247,6 @@ void DrawCube(Vector3 position, float width, float height, float length, Color c
float y = 0.0f;
float z = 0.0f;
rlCheckRenderBatchLimit(36);
rlPushMatrix();
// NOTE: Transformation is applied in inverse order (scale -> rotate -> translate)
rlTranslatef(position.x, position.y, position.z);
@ -342,65 +326,67 @@ void DrawCubeWires(Vector3 position, float width, float height, float length, Co
float y = 0.0f;
float z = 0.0f;
rlCheckRenderBatchLimit(36);
rlPushMatrix();
rlTranslatef(position.x, position.y, position.z);
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
// Front face -----------------------------------------------------
// Front face
//------------------------------------------------------------------
// Bottom line
rlVertex3f(x-width/2, y-height/2, z+length/2); // Bottom left
rlVertex3f(x+width/2, y-height/2, z+length/2); // Bottom right
rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom left
rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom right
// Left line
rlVertex3f(x+width/2, y-height/2, z+length/2); // Bottom right
rlVertex3f(x+width/2, y+height/2, z+length/2); // Top right
rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom right
rlVertex3f(x + width/2, y + height/2, z + length/2); // Top right
// Top line
rlVertex3f(x+width/2, y+height/2, z+length/2); // Top right
rlVertex3f(x-width/2, y+height/2, z+length/2); // Top left
rlVertex3f(x + width/2, y + height/2, z + length/2); // Top right
rlVertex3f(x - width/2, y + height/2, z + length/2); // Top left
// Right line
rlVertex3f(x-width/2, y+height/2, z+length/2); // Top left
rlVertex3f(x-width/2, y-height/2, z+length/2); // Bottom left
rlVertex3f(x - width/2, y + height/2, z + length/2); // Top left
rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom left
// Back face ------------------------------------------------------
// Back face
//------------------------------------------------------------------
// Bottom line
rlVertex3f(x-width/2, y-height/2, z-length/2); // Bottom left
rlVertex3f(x+width/2, y-height/2, z-length/2); // Bottom right
rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom left
rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom right
// Left line
rlVertex3f(x+width/2, y-height/2, z-length/2); // Bottom right
rlVertex3f(x+width/2, y+height/2, z-length/2); // Top right
rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom right
rlVertex3f(x + width/2, y + height/2, z - length/2); // Top right
// Top line
rlVertex3f(x+width/2, y+height/2, z-length/2); // Top right
rlVertex3f(x-width/2, y+height/2, z-length/2); // Top left
rlVertex3f(x + width/2, y + height/2, z - length/2); // Top right
rlVertex3f(x - width/2, y + height/2, z - length/2); // Top left
// Right line
rlVertex3f(x-width/2, y+height/2, z-length/2); // Top left
rlVertex3f(x-width/2, y-height/2, z-length/2); // Bottom left
rlVertex3f(x - width/2, y + height/2, z - length/2); // Top left
rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom left
// Top face -------------------------------------------------------
// Top face
//------------------------------------------------------------------
// Left line
rlVertex3f(x-width/2, y+height/2, z+length/2); // Top left front
rlVertex3f(x-width/2, y+height/2, z-length/2); // Top left back
rlVertex3f(x - width/2, y + height/2, z + length/2); // Top left front
rlVertex3f(x - width/2, y + height/2, z - length/2); // Top left back
// Right line
rlVertex3f(x+width/2, y+height/2, z+length/2); // Top right front
rlVertex3f(x+width/2, y+height/2, z-length/2); // Top right back
rlVertex3f(x + width/2, y + height/2, z + length/2); // Top right front
rlVertex3f(x + width/2, y + height/2, z - length/2); // Top right back
// Bottom face ---------------------------------------------------
// Bottom face
//------------------------------------------------------------------
// Left line
rlVertex3f(x-width/2, y-height/2, z+length/2); // Top left front
rlVertex3f(x-width/2, y-height/2, z-length/2); // Top left back
rlVertex3f(x - width/2, y - height/2, z + length/2); // Top left front
rlVertex3f(x - width/2, y - height/2, z - length/2); // Top left back
// Right line
rlVertex3f(x+width/2, y-height/2, z+length/2); // Top right front
rlVertex3f(x+width/2, y-height/2, z-length/2); // Top right back
rlVertex3f(x + width/2, y - height/2, z + length/2); // Top right front
rlVertex3f(x + width/2, y - height/2, z - length/2); // Top right back
rlEnd();
rlPopMatrix();
}
@ -419,8 +405,6 @@ void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float hei
float y = position.y;
float z = position.z;
rlCheckRenderBatchLimit(36);
rlSetTexture(texture.id);
//rlPushMatrix();
@ -432,37 +416,37 @@ void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float hei
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
// Front Face
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left Of The Texture and Quad
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right Of The Texture and Quad
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Right Of The Texture and Quad
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left Of The Texture and Quad
// Back Face
rlNormal3f(0.0f, 0.0f, - 1.0f); // Normal Pointing Away From Viewer
rlNormal3f(0.0f, 0.0f, - 1.0f); // Normal Pointing Away From Viewer
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right Of The Texture and Quad
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Right Of The Texture and Quad
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Left Of The Texture and Quad
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Left Of The Texture and Quad
// Top Face
rlNormal3f(0.0f, 1.0f, 0.0f); // Normal Pointing Up
rlNormal3f(0.0f, 1.0f, 0.0f); // Normal Pointing Up
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left Of The Texture and Quad
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - width/2, y + height/2, z + length/2); // Bottom Left Of The Texture and Quad
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right Of The Texture and Quad
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right Of The Texture and Quad
// Bottom Face
rlNormal3f(0.0f, - 1.0f, 0.0f); // Normal Pointing Down
rlNormal3f(0.0f, - 1.0f, 0.0f); // Normal Pointing Down
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Right Of The Texture and Quad
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + width/2, y - height/2, z - length/2); // Top Left Of The Texture and Quad
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left Of The Texture and Quad
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Right Of The Texture and Quad
// Right face
rlNormal3f(1.0f, 0.0f, 0.0f); // Normal Pointing Right
rlNormal3f(1.0f, 0.0f, 0.0f); // Normal Pointing Right
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right Of The Texture and Quad
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right Of The Texture and Quad
rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left Of The Texture and Quad
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left Of The Texture and Quad
// Left Face
rlNormal3f( - 1.0f, 0.0f, 0.0f); // Normal Pointing Left
rlNormal3f( - 1.0f, 0.0f, 0.0f); // Normal Pointing Left
rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Left Of The Texture and Quad
rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Right Of The Texture and Quad
rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Right Of The Texture and Quad
@ -482,8 +466,6 @@ void DrawCubeTextureRec(Texture2D texture, Rectangle source, Vector3 position, f
float texWidth = (float)texture.width;
float texHeight = (float)texture.height;
rlCheckRenderBatchLimit(36);
rlSetTexture(texture.id);
rlBegin(RL_QUADS);
@ -569,9 +551,6 @@ void DrawSphere(Vector3 centerPos, float radius, Color color)
// Draw sphere with extended parameters
void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color)
{
int numVertex = (rings + 2)*slices*6;
rlCheckRenderBatchLimit(numVertex);
rlPushMatrix();
// NOTE: Transformation is applied in inverse order (scale -> translate)
rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
@ -612,9 +591,6 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
// Draw sphere wires
void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color)
{
int numVertex = (rings + 2)*slices*6;
rlCheckRenderBatchLimit(numVertex);
rlPushMatrix();
// NOTE: Transformation is applied in inverse order (scale -> translate)
rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
@ -659,9 +635,6 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
{
if (sides < 3) sides = 3;
int numVertex = sides*6;
rlCheckRenderBatchLimit(numVertex);
rlPushMatrix();
rlTranslatef(position.x, position.y, position.z);
@ -718,9 +691,6 @@ void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float e
{
if (sides < 3) sides = 3;
int numVertex = sides*6;
rlCheckRenderBatchLimit(numVertex);
Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
if ((direction.x == 0) && (direction.y == 0) && (direction.z == 0)) return;
@ -777,9 +747,6 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl
{
if (sides < 3) sides = 3;
int numVertex = sides*8;
rlCheckRenderBatchLimit(numVertex);
rlPushMatrix();
rlTranslatef(position.x, position.y, position.z);
@ -811,9 +778,6 @@ void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, fl
{
if (sides < 3) sides = 3;
int numVertex = sides*6;
rlCheckRenderBatchLimit(numVertex);
Vector3 direction = { endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z };
if ((direction.x == 0) && (direction.y == 0) && (direction.z == 0))return;
@ -853,12 +817,287 @@ 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)
{
rlCheckRenderBatchLimit(4);
// NOTE: Plane is always created on XZ ground
rlPushMatrix();
rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
@ -895,8 +1134,6 @@ void DrawGrid(int slices, float spacing)
{
int halfSlices = slices/2;
rlCheckRenderBatchLimit((slices + 2)*4);
rlBegin(RL_LINES);
for (int i = -halfSlices; i <= halfSlices; i++)
{
@ -2671,7 +2908,7 @@ Mesh GenMeshKnot(float radius, float size, int radSeg, int sides)
// NOTE: Vertex data is uploaded to GPU
Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
{
#define GRAY_VALUE(c) ((c.r+c.g+c.b)/3.0f)
#define GRAY_VALUE(c) ((float)(c.r + c.g + c.b)/3.0f)
Mesh mesh = { 0 };
@ -2681,7 +2918,7 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
Color *pixels = LoadImageColors(heightmap);
// NOTE: One vertex per pixel
mesh.triangleCount = (mapX-1)*(mapZ-1)*2; // One quad every four pixels
mesh.triangleCount = (mapX - 1)*(mapZ - 1)*2; // One quad every four pixels
mesh.vertexCount = mesh.triangleCount*3;
@ -2694,7 +2931,7 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
int tcCounter = 0; // Used to count texcoords float by float
int nCounter = 0; // Used to count normals float by float
Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ };
Vector3 scaleFactor = { size.x/(mapX - 1), size.y/255.0f, size.z/(mapZ - 1) };
Vector3 vA = { 0 };
Vector3 vB = { 0 };
@ -2721,7 +2958,7 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
mesh.vertices[vCounter + 7] = GRAY_VALUE(pixels[(x + 1) + z*mapX])*scaleFactor.y;
mesh.vertices[vCounter + 8] = (float)z*scaleFactor.z;
// another triangle - 3 vertex
// Another triangle - 3 vertex
mesh.vertices[vCounter + 9] = mesh.vertices[vCounter + 6];
mesh.vertices[vCounter + 10] = mesh.vertices[vCounter + 7];
mesh.vertices[vCounter + 11] = mesh.vertices[vCounter + 8];
@ -3421,8 +3658,6 @@ void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector
bottomRight = Vector3Add(bottomRight, position);
bottomLeft = Vector3Add(bottomLeft, position);
rlCheckRenderBatchLimit(8);
rlSetTexture(texture.id);
rlBegin(RL_QUADS);
@ -4302,6 +4537,7 @@ static Model LoadIQM(const char *fileName)
RL_FREE(blendi);
RL_FREE(blendw);
RL_FREE(ijoint);
RL_FREE(color);
return model;
}
@ -5263,18 +5499,28 @@ static Model LoadM3D(const char *fileName)
}
// Add skin (vertex / bone weight pairs)
if (m3d->numbone && m3d->numskin) {
for (n = 0; n < 3; n++) {
if (m3d->numbone && m3d->numskin)
{
for (n = 0; n < 3; n++)
{
int skinid = m3d->vertex[m3d->face[i].vertex[n]].skinid;
// check if there's a skin for this mesh, should be, just failsafe
// Check if there is a skin for this mesh, should be, just failsafe
if (skinid != M3D_UNDEF && skinid < m3d->numskin)
{
for (j = 0; j < 4; j++)
{
model.meshes[k].boneIds[l * 12 + n * 4 + j] = m3d->skin[skinid].boneid[j];
model.meshes[k].boneWeights[l * 12 + n * 4 + j] = m3d->skin[skinid].weight[j];
model.meshes[k].boneIds[l*12 + n*4 + j] = m3d->skin[skinid].boneid[j];
model.meshes[k].boneWeights[l*12 + n*4 + j] = m3d->skin[skinid].weight[j];
}
}
else
{
// raylib does not handle boneless meshes with skeletal animations, so
// we put all vertices without a bone into a special "no bone" bone
model.meshes[k].boneIds[l * 12 + n * 4] = m3d->numbone;
model.meshes[k].boneWeights[l * 12 + n * 4] = 1.0f;
}
}
}
}
@ -5351,18 +5597,19 @@ static Model LoadM3D(const char *fileName)
}
// Load bones
if(m3d->numbone)
if (m3d->numbone)
{
model.boneCount = m3d->numbone;
model.bones = RL_MALLOC(m3d->numbone*sizeof(BoneInfo));
model.bindPose = RL_MALLOC(m3d->numbone*sizeof(Transform));
model.boneCount = m3d->numbone + 1;
model.bones = RL_CALLOC(model.boneCount, sizeof(BoneInfo));
model.bindPose = RL_CALLOC(model.boneCount, sizeof(Transform));
for (i = 0; i < m3d->numbone; i++)
{
model.bones[i].parent = m3d->bone[i].parent;
strncpy(model.bones[i].name, m3d->bone[i].name, sizeof(model.bones[i].name));
model.bindPose[i].translation.x = m3d->vertex[m3d->bone[i].pos].x;
model.bindPose[i].translation.y = m3d->vertex[m3d->bone[i].pos].y;
model.bindPose[i].translation.z = m3d->vertex[m3d->bone[i].pos].z;
model.bindPose[i].translation.x = m3d->vertex[m3d->bone[i].pos].x*m3d->scale;
model.bindPose[i].translation.y = m3d->vertex[m3d->bone[i].pos].y*m3d->scale;
model.bindPose[i].translation.z = m3d->vertex[m3d->bone[i].pos].z*m3d->scale;
model.bindPose[i].rotation.x = m3d->vertex[m3d->bone[i].ori].x;
model.bindPose[i].rotation.y = m3d->vertex[m3d->bone[i].ori].y;
model.bindPose[i].rotation.z = m3d->vertex[m3d->bone[i].ori].z;
@ -5370,7 +5617,28 @@ static Model LoadM3D(const char *fileName)
// TODO: if the orientation quaternion not normalized, then that's encoding scaling
model.bindPose[i].rotation = QuaternionNormalize(model.bindPose[i].rotation);
model.bindPose[i].scale.x = model.bindPose[i].scale.y = model.bindPose[i].scale.z = 1.0f;
// Child bones are stored in parent bone relative space, convert that into model space
if (model.bones[i].parent >= 0)
{
model.bindPose[i].rotation = QuaternionMultiply(model.bindPose[model.bones[i].parent].rotation, model.bindPose[i].rotation);
model.bindPose[i].translation = Vector3RotateByQuaternion(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].rotation);
model.bindPose[i].translation = Vector3Add(model.bindPose[i].translation, model.bindPose[model.bones[i].parent].translation);
model.bindPose[i].scale = Vector3Multiply(model.bindPose[i].scale, model.bindPose[model.bones[i].parent].scale);
}
}
// Add a special "no bone" bone
model.bones[i].parent = -1;
strcpy(model.bones[i].name, "NO BONE");
model.bindPose[i].translation.x = 0.0f;
model.bindPose[i].translation.y = 0.0f;
model.bindPose[i].translation.z = 0.0f;
model.bindPose[i].rotation.x = 0.0f;
model.bindPose[i].rotation.y = 0.0f;
model.bindPose[i].rotation.z = 0.0f;
model.bindPose[i].rotation.w = 1.0f;
model.bindPose[i].scale.x = model.bindPose[i].scale.y = model.bindPose[i].scale.z = 1.0f;
}
// Load bone-pose default mesh into animation vertices. These will be updated when UpdateModelAnimation gets
@ -5430,8 +5698,8 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, unsigned int
for (unsigned int a = 0; a < m3d->numaction; a++)
{
animations[a].frameCount = m3d->action[a].durationmsec / M3D_ANIMDELAY;
animations[a].boneCount = m3d->numbone;
animations[a].bones = RL_MALLOC(m3d->numbone*sizeof(BoneInfo));
animations[a].boneCount = m3d->numbone + 1;
animations[a].bones = RL_MALLOC((m3d->numbone + 1)*sizeof(BoneInfo));
animations[a].framePoses = RL_MALLOC(animations[a].frameCount*sizeof(Transform *));
// strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name));
TRACELOG(LOG_INFO, "MODEL: [%s] animation #%i: %i msec, %i frames", fileName, a, m3d->action[a].durationmsec, animations[a].frameCount);
@ -5442,27 +5710,50 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, unsigned int
strncpy(animations[a].bones[i].name, m3d->bone[i].name, sizeof(animations[a].bones[i].name));
}
// A special, never transformed "no bone" bone, used for boneless vertices
animations[a].bones[i].parent = -1;
strcpy(animations[a].bones[i].name, "NO BONE");
// M3D stores frames at arbitrary intervals with sparse skeletons. We need full skeletons at
// regular intervals, so let the M3D SDK do the heavy lifting and calculate interpolated bones
for (i = 0; i < animations[a].frameCount; i++)
{
animations[a].framePoses[i] = RL_MALLOC(m3d->numbone*sizeof(Transform));
animations[a].framePoses[i] = RL_MALLOC((m3d->numbone + 1)*sizeof(Transform));
m3db_t *pose = m3d_pose(m3d, a, i * M3D_ANIMDELAY);
if (pose != NULL)
{
for (j = 0; j < m3d->numbone; j++)
{
animations[a].framePoses[i][j].translation.x = m3d->vertex[pose[j].pos].x;
animations[a].framePoses[i][j].translation.y = m3d->vertex[pose[j].pos].y;
animations[a].framePoses[i][j].translation.z = m3d->vertex[pose[j].pos].z;
animations[a].framePoses[i][j].translation.x = m3d->vertex[pose[j].pos].x*m3d->scale;
animations[a].framePoses[i][j].translation.y = m3d->vertex[pose[j].pos].y*m3d->scale;
animations[a].framePoses[i][j].translation.z = m3d->vertex[pose[j].pos].z*m3d->scale;
animations[a].framePoses[i][j].rotation.x = m3d->vertex[pose[j].ori].x;
animations[a].framePoses[i][j].rotation.y = m3d->vertex[pose[j].ori].y;
animations[a].framePoses[i][j].rotation.z = m3d->vertex[pose[j].ori].z;
animations[a].framePoses[i][j].rotation.w = m3d->vertex[pose[j].ori].w;
animations[a].framePoses[i][j].rotation = QuaternionNormalize(animations[a].framePoses[i][j].rotation);
animations[a].framePoses[i][j].scale.x = animations[a].framePoses[i][j].scale.y = animations[a].framePoses[i][j].scale.z = 1.0f;
// Child bones are stored in parent bone relative space, convert that into model space
if (animations[a].bones[j].parent >= 0)
{
animations[a].framePoses[i][j].rotation = QuaternionMultiply(animations[a].framePoses[i][animations[a].bones[j].parent].rotation, animations[a].framePoses[i][j].rotation);
animations[a].framePoses[i][j].translation = Vector3RotateByQuaternion(animations[a].framePoses[i][j].translation, animations[a].framePoses[i][animations[a].bones[j].parent].rotation);
animations[a].framePoses[i][j].translation = Vector3Add(animations[a].framePoses[i][j].translation, animations[a].framePoses[i][animations[a].bones[j].parent].translation);
animations[a].framePoses[i][j].scale = Vector3Multiply(animations[a].framePoses[i][j].scale, animations[a].framePoses[i][animations[a].bones[j].parent].scale);
}
}
// Default transform for the "no bone" bone
animations[a].framePoses[i][j].translation.x = 0.0f;
animations[a].framePoses[i][j].translation.y = 0.0f;
animations[a].framePoses[i][j].translation.z = 0.0f;
animations[a].framePoses[i][j].rotation.x = 0.0f;
animations[a].framePoses[i][j].rotation.y = 0.0f;
animations[a].framePoses[i][j].rotation.z = 0.0f;
animations[a].framePoses[i][j].rotation.w = 1.0f;
animations[a].framePoses[i][j].scale.x = animations[a].framePoses[i][j].scale.y = animations[a].framePoses[i][j].scale.z = 1.0f;
RL_FREE(pose);
}
}