From b0c9dac996f4f10d7e5203d2041e1db0ba0f7127 Mon Sep 17 00:00:00 2001 From: coco24 <1281299809@qq.com> Date: Sat, 6 Jul 2024 17:25:13 +0800 Subject: [PATCH] [rmodels] Re-implement `DrawBillboardPro` using `DrawTexturePro3D` --- src/rmodels.c | 129 ++++++++++++-------------------------------------- 1 file changed, 29 insertions(+), 100 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 0ca10191782b..77eea37290f6 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -3659,7 +3659,7 @@ void DrawTexturePro3D(Texture2D texture, Rectangle source, Rectangle3D dest, Vec Vector3 forward; if (rotation != 0.0) forward = Vector3CrossProduct(dest.right, dest.up); - Vector3 origin3D = Vector3Add(Vector3Scale(Vector3Normalize(dest.up), origin.y), Vector3Scale(Vector3Normalize(dest.right), origin.x)); + Vector3 origin3D = Vector3Add(Vector3Scale(Vector3Normalize(dest.right), origin.x), Vector3Scale(Vector3Normalize(dest.up), origin.y)); Vector3 points[4]; points[0] = Vector3Zero(); @@ -3694,114 +3694,43 @@ void DrawTexturePro3D(Texture2D texture, Rectangle source, Rectangle3D dest, Vec rlSetTexture(0); } -// 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) +static Rectangle3D BillboardRectangle3D(Camera camera, Vector3 position, Vector2 size) { - // 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 }; - Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); + Vector3 up = { matView.m1, matView.m5, matView.m9 }; Vector3 right = { matView.m0, matView.m4, matView.m8 }; - //Vector3 up = { matView.m1, matView.m5, matView.m9 }; - - Vector3 rightScaled = Vector3Scale(right, sizeRatio.x/2); - Vector3 upScaled = Vector3Scale(up, sizeRatio.y/2); - Vector3 p1 = Vector3Add(rightScaled, upScaled); - Vector3 p2 = Vector3Subtract(rightScaled, upScaled); + return (Rectangle3D) { position, Vector3Scale(up, size.y), Vector3Scale(right, size.x) }; +} - Vector3 topLeft = Vector3Scale(p2, -1); - Vector3 topRight = p1; - Vector3 bottomRight = p2; - Vector3 bottomLeft = Vector3Scale(p1, -1); +static Rectangle RectangleScale(Rectangle rectangle, Vector2 scale) +{ + rectangle.position = Vector2Add(rectangle.position, Vector2Scale(Vector2Multiply(rectangle.size, Vector2Subtract(Vector2One(), scale)), 0.5f)); + rectangle.size = Vector2Multiply(rectangle.size, scale); + return rectangle; +} - if (rotation != 0.0f) +// 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 }; + Rectangle3D dest = BillboardRectangle3D(camera, position, sizeRatio); + dest.up = Vector3Scale(up, sizeRatio.y); + 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)); + dest.right = Vector3Negate(dest.right); + source = RectangleScale(source, (Vector2) { -1.0f, 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); - - rlSetTexture(texture.id); - - rlBegin(RL_QUADS); - rlColor4ub(tint.r, tint.g, tint.b, tint.a); - - if (sizeRatio.x*sizeRatio.y >= 0.0f) - { - // 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); - } - - rlEnd(); - - rlSetTexture(0); + if (size.y < 0.0f) + { + dest.up = Vector3Negate(dest.up); + source = RectangleScale(source, (Vector2) { 1.0f, -1.0f }); + } + Vector2 originUnnormalized = Vector2Multiply(Vector2Scale(Vector2Add(origin, Vector2One()), 0.5f), (Vector2) { fabsf(sizeRatio.x), fabsf(sizeRatio.y) }); + DrawTexturePro3D(texture, source, dest, originUnnormalized, rotation, tint); } // Draw a bounding box with wires