[rmodels] Consistent DrawBillboardPro
with DrawTexturePro
(#4132)
* [rmodels] Re-implement `DrawBillboardPro` * [rmodels] Add comments to `DrawBillboardPro` * [rmodels] Make `DrawBillboardPro` consistent with `DrawTexturePro` * Update raylib_api.* by CI --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
b61303244c
commit
6dd2a0e645
@ -44,10 +44,12 @@ int main(void)
|
||||
// NOTE: Billboard locked on axis-Y
|
||||
Vector3 billUp = { 0.0f, 1.0f, 0.0f };
|
||||
|
||||
// Set the height of the rotating billboard to 1.0 with the aspect ratio fixed
|
||||
Vector2 size = { source.width / source.height, 1.0f };
|
||||
|
||||
// Rotate around origin
|
||||
// Here we choose to rotate around the image center
|
||||
// NOTE: (-1, 1) is the range where origin.x, origin.y is inside the texture
|
||||
Vector2 rotateOrigin = { 0.0f };
|
||||
Vector2 origin = Vector2Scale(size, 0.5f);
|
||||
|
||||
// Distance is needed for the correct billboard draw order
|
||||
// Larger distance (further away from the camera) should be drawn prior to smaller distance.
|
||||
@ -84,11 +86,11 @@ int main(void)
|
||||
if (distanceStatic > distanceRotating)
|
||||
{
|
||||
DrawBillboard(camera, bill, billPositionStatic, 2.0f, WHITE);
|
||||
DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, (Vector2) {1.0f, 1.0f}, rotateOrigin, rotation, WHITE);
|
||||
DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, size, origin, rotation, WHITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, (Vector2) {1.0f, 1.0f}, rotateOrigin, rotation, WHITE);
|
||||
DrawBillboardPro(camera, bill, source, billPositionRotating, billUp, size, origin, rotation, WHITE);
|
||||
DrawBillboard(camera, bill, billPositionStatic, 2.0f, WHITE);
|
||||
}
|
||||
|
||||
@ -108,4 +110,4 @@ int main(void)
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -10400,7 +10400,7 @@
|
||||
},
|
||||
{
|
||||
"type": "float",
|
||||
"name": "size"
|
||||
"name": "scale"
|
||||
},
|
||||
{
|
||||
"type": "Color",
|
||||
|
@ -7230,7 +7230,7 @@ return {
|
||||
{type = "Camera", name = "camera"},
|
||||
{type = "Texture2D", name = "texture"},
|
||||
{type = "Vector3", name = "position"},
|
||||
{type = "float", name = "size"},
|
||||
{type = "float", name = "scale"},
|
||||
{type = "Color", name = "tint"}
|
||||
}
|
||||
},
|
||||
|
@ -3968,7 +3968,7 @@ Function 466: DrawBillboard() (5 input parameters)
|
||||
Param[1]: camera (type: Camera)
|
||||
Param[2]: texture (type: Texture2D)
|
||||
Param[3]: position (type: Vector3)
|
||||
Param[4]: size (type: float)
|
||||
Param[4]: scale (type: float)
|
||||
Param[5]: tint (type: Color)
|
||||
Function 467: DrawBillboardRec() (6 input parameters)
|
||||
Name: DrawBillboardRec
|
||||
|
@ -2645,7 +2645,7 @@
|
||||
<Param type="Camera" name="camera" desc="" />
|
||||
<Param type="Texture2D" name="texture" desc="" />
|
||||
<Param type="Vector3" name="position" desc="" />
|
||||
<Param type="float" name="size" desc="" />
|
||||
<Param type="float" name="scale" desc="" />
|
||||
<Param type="Color" name="tint" desc="" />
|
||||
</Function>
|
||||
<Function name="DrawBillboardRec" retType="void" paramCount="6" desc="Draw a billboard texture defined by source">
|
||||
|
@ -1546,7 +1546,7 @@ RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, floa
|
||||
RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set)
|
||||
RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters
|
||||
RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires)
|
||||
RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float size, Color tint); // Draw a billboard texture
|
||||
RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a billboard texture
|
||||
RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source
|
||||
RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source and rotation
|
||||
|
||||
|
152
src/rmodels.c
152
src/rmodels.c
@ -3638,11 +3638,11 @@ void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float
|
||||
}
|
||||
|
||||
// Draw a billboard
|
||||
void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float size, Color tint)
|
||||
void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint)
|
||||
{
|
||||
Rectangle source = { 0.0f, 0.0f, (float)texture.width, (float)texture.height };
|
||||
|
||||
DrawBillboardRec(camera, texture, source, position, (Vector2){ size, size }, tint);
|
||||
DrawBillboardRec(camera, texture, source, position, (Vector2) { scale*fabsf((float)source.width/source.height), scale }, tint);
|
||||
}
|
||||
|
||||
// Draw a billboard (part of a texture defined by a rectangle)
|
||||
@ -3651,116 +3651,82 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector
|
||||
// NOTE: Billboard locked on axis-Y
|
||||
Vector3 up = { 0.0f, 1.0f, 0.0f };
|
||||
|
||||
DrawBillboardPro(camera, texture, source, position, up, size, Vector2Zero(), 0.0f, tint);
|
||||
DrawBillboardPro(camera, texture, source, position, up, size, Vector2Scale(size, 0.5), 0.0f, tint);
|
||||
}
|
||||
|
||||
// Draw a billboard with additional parameters
|
||||
// NOTE: Size defines the destination rectangle size, stretching the source texture as required
|
||||
void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint)
|
||||
{
|
||||
// NOTE: Billboard size will maintain source rectangle aspect ratio, size will represent billboard width
|
||||
Vector2 sizeRatio = { size.x*fabsf((float)source.width/source.height), size.y };
|
||||
|
||||
// Compute the up vector and the right vector
|
||||
Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
|
||||
|
||||
Vector3 right = { matView.m0, matView.m4, matView.m8 };
|
||||
//Vector3 up = { matView.m1, matView.m5, matView.m9 };
|
||||
right = Vector3Scale(right, size.x);
|
||||
up = Vector3Scale(up, size.y);
|
||||
|
||||
Vector3 rightScaled = Vector3Scale(right, sizeRatio.x/2);
|
||||
Vector3 upScaled = Vector3Scale(up, sizeRatio.y/2);
|
||||
|
||||
Vector3 p1 = Vector3Add(rightScaled, upScaled);
|
||||
Vector3 p2 = Vector3Subtract(rightScaled, upScaled);
|
||||
|
||||
Vector3 topLeft = Vector3Scale(p2, -1);
|
||||
Vector3 topRight = p1;
|
||||
Vector3 bottomRight = p2;
|
||||
Vector3 bottomLeft = Vector3Scale(p1, -1);
|
||||
|
||||
if (rotation != 0.0f)
|
||||
// Flip the content of the billboard while maintaining the counterclockwise edge rendering order
|
||||
if (size.x < 0.0f)
|
||||
{
|
||||
float sinRotation = sinf(rotation*DEG2RAD);
|
||||
float cosRotation = cosf(rotation*DEG2RAD);
|
||||
|
||||
// NOTE: (-1, 1) is the range where origin.x, origin.y is inside the texture
|
||||
float rotateAboutX = sizeRatio.x*origin.x/2;
|
||||
float rotateAboutY = sizeRatio.y*origin.y/2;
|
||||
|
||||
float xtvalue, ytvalue;
|
||||
float rotatedX, rotatedY;
|
||||
|
||||
xtvalue = Vector3DotProduct(right, topLeft) - rotateAboutX; // Project points to x and y coordinates on the billboard plane
|
||||
ytvalue = Vector3DotProduct(up, topLeft) - rotateAboutY;
|
||||
rotatedX = xtvalue*cosRotation - ytvalue*sinRotation + rotateAboutX; // Rotate about the point origin
|
||||
rotatedY = xtvalue*sinRotation + ytvalue*cosRotation + rotateAboutY;
|
||||
topLeft = Vector3Add(Vector3Scale(up, rotatedY), Vector3Scale(right, rotatedX)); // Translate back to cartesian coordinates
|
||||
|
||||
xtvalue = Vector3DotProduct(right, topRight) - rotateAboutX;
|
||||
ytvalue = Vector3DotProduct(up, topRight) - rotateAboutY;
|
||||
rotatedX = xtvalue*cosRotation - ytvalue*sinRotation + rotateAboutX;
|
||||
rotatedY = xtvalue*sinRotation + ytvalue*cosRotation + rotateAboutY;
|
||||
topRight = Vector3Add(Vector3Scale(up, rotatedY), Vector3Scale(right, rotatedX));
|
||||
|
||||
xtvalue = Vector3DotProduct(right, bottomRight) - rotateAboutX;
|
||||
ytvalue = Vector3DotProduct(up, bottomRight) - rotateAboutY;
|
||||
rotatedX = xtvalue*cosRotation - ytvalue*sinRotation + rotateAboutX;
|
||||
rotatedY = xtvalue*sinRotation + ytvalue*cosRotation + rotateAboutY;
|
||||
bottomRight = Vector3Add(Vector3Scale(up, rotatedY), Vector3Scale(right, rotatedX));
|
||||
|
||||
xtvalue = Vector3DotProduct(right, bottomLeft)-rotateAboutX;
|
||||
ytvalue = Vector3DotProduct(up, bottomLeft)-rotateAboutY;
|
||||
rotatedX = xtvalue*cosRotation - ytvalue*sinRotation + rotateAboutX;
|
||||
rotatedY = xtvalue*sinRotation + ytvalue*cosRotation + rotateAboutY;
|
||||
bottomLeft = Vector3Add(Vector3Scale(up, rotatedY), Vector3Scale(right, rotatedX));
|
||||
source.x += size.x;
|
||||
source.width *= -1.0;
|
||||
right = Vector3Negate(right);
|
||||
origin.x *= -1.0f;
|
||||
}
|
||||
if (size.y < 0.0f)
|
||||
{
|
||||
source.y += size.y;
|
||||
source.height *= -1.0;
|
||||
up = Vector3Negate(up);
|
||||
origin.y *= -1.0f;
|
||||
}
|
||||
|
||||
// Translate points to the draw center (position)
|
||||
topLeft = Vector3Add(topLeft, position);
|
||||
topRight = Vector3Add(topRight, position);
|
||||
bottomRight = Vector3Add(bottomRight, position);
|
||||
bottomLeft = Vector3Add(bottomLeft, position);
|
||||
// Draw the texture region described by source on the following rectangle in 3D space:
|
||||
//
|
||||
// size.x <--.
|
||||
// 3 ^---------------------------+ 2 \ rotation
|
||||
// | | /
|
||||
// | |
|
||||
// | origin.x position |
|
||||
// up |.............. | size.y
|
||||
// | . |
|
||||
// | . origin.y |
|
||||
// | . |
|
||||
// 0 +---------------------------> 1
|
||||
// right
|
||||
Vector3 forward;
|
||||
if (rotation != 0.0) forward = Vector3CrossProduct(right, up);
|
||||
|
||||
Vector3 origin3D = Vector3Add(Vector3Scale(Vector3Normalize(right), origin.x), Vector3Scale(Vector3Normalize(up), origin.y));
|
||||
|
||||
Vector3 points[4];
|
||||
points[0] = Vector3Zero();
|
||||
points[1] = right;
|
||||
points[2] = Vector3Add(up, right);
|
||||
points[3] = up;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
points[i] = Vector3Subtract(points[i], origin3D);
|
||||
if (rotation != 0.0) points[i] = Vector3RotateByAxisAngle(points[i], forward, rotation * DEG2RAD);
|
||||
points[i] = Vector3Add(points[i], position);
|
||||
}
|
||||
|
||||
Vector2 texcoords[4];
|
||||
texcoords[0] = (Vector2) { (float)source.x/texture.width, (float)(source.y + source.height)/texture.height };
|
||||
texcoords[1] = (Vector2) { (float)(source.x + source.width)/texture.width, (float)(source.y + source.height)/texture.height };
|
||||
texcoords[2] = (Vector2) { (float)(source.x + source.width)/texture.width, (float)source.y/texture.height };
|
||||
texcoords[3] = (Vector2) { (float)source.x/texture.width, (float)source.y/texture.height };
|
||||
|
||||
rlSetTexture(texture.id);
|
||||
|
||||
rlBegin(RL_QUADS);
|
||||
|
||||
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
|
||||
|
||||
if (sizeRatio.x*sizeRatio.y >= 0.0f)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
// Bottom-left corner for texture and quad
|
||||
rlTexCoord2f((float)source.x/texture.width, (float)source.y/texture.height);
|
||||
rlVertex3f(topLeft.x, topLeft.y, topLeft.z);
|
||||
|
||||
// Top-left corner for texture and quad
|
||||
rlTexCoord2f((float)source.x/texture.width, (float)(source.y + source.height)/texture.height);
|
||||
rlVertex3f(bottomLeft.x, bottomLeft.y, bottomLeft.z);
|
||||
|
||||
// Top-right corner for texture and quad
|
||||
rlTexCoord2f((float)(source.x + source.width)/texture.width, (float)(source.y + source.height)/texture.height);
|
||||
rlVertex3f(bottomRight.x, bottomRight.y, bottomRight.z);
|
||||
|
||||
// Bottom-right corner for texture and quad
|
||||
rlTexCoord2f((float)(source.x + source.width)/texture.width, (float)source.y/texture.height);
|
||||
rlVertex3f(topRight.x, topRight.y, topRight.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reverse vertex order if the size has only one negative dimension
|
||||
rlTexCoord2f((float)(source.x + source.width)/texture.width, (float)source.y/texture.height);
|
||||
rlVertex3f(topRight.x, topRight.y, topRight.z);
|
||||
|
||||
rlTexCoord2f((float)(source.x + source.width)/texture.width, (float)(source.y + source.height)/texture.height);
|
||||
rlVertex3f(bottomRight.x, bottomRight.y, bottomRight.z);
|
||||
|
||||
rlTexCoord2f((float)source.x/texture.width, (float)(source.y + source.height)/texture.height);
|
||||
rlVertex3f(bottomLeft.x, bottomLeft.y, bottomLeft.z);
|
||||
|
||||
rlTexCoord2f((float)source.x/texture.width, (float)source.y/texture.height);
|
||||
rlVertex3f(topLeft.x, topLeft.y, topLeft.z);
|
||||
rlTexCoord2f(texcoords[i].x, texcoords[i].y);
|
||||
rlVertex3f(points[i].x, points[i].y, points[i].z);
|
||||
}
|
||||
|
||||
rlEnd();
|
||||
|
||||
rlSetTexture(0);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user