From ac204a11f7eb5d03e88188b06d004bb680902bfb Mon Sep 17 00:00:00 2001 From: nobytesgiven <80068279+nobytesgiven@users.noreply.github.com> Date: Tue, 11 May 2021 01:55:43 +0300 Subject: [PATCH] Redesigned billboards - added rotation/pro functions (#1759) * Redesigned billboards - added rotation/pro functions * updated parameters Co-authored-by: nobytesgiven --- src/models.c | 101 ++++++++++++++++++++++++++++++++++++++------------- src/raylib.h | 4 +- 2 files changed, 78 insertions(+), 27 deletions(-) diff --git a/src/models.c b/src/models.c index feaadf838..7a0ce8ad6 100644 --- a/src/models.c +++ b/src/models.c @@ -2802,15 +2802,28 @@ void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, { Rectangle source = { 0.0f, 0.0f, (float)texture.width, (float)texture.height }; - DrawBillboardRec(camera, texture, source, center, size, tint); + DrawBillboardRec(camera, texture, source, center, (Vector2){ size, size }, tint); } // Draw a billboard (part of a texture defined by a rectangle) -void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 center, float size, Color tint) +void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 center, Vector2 size, Color tint) { - // NOTE: Billboard size will maintain source rectangle aspect ratio, size will represent billboard width - Vector2 sizeRatio = { size, size*(float)source.height/source.width }; + DrawBillboardPro(camera, texture, source, center, size, Vector2Zero(), 0.0f, tint); +} +// Draw a billboard (part of a texture defined by a rectangle) +void DrawBillboardEx(Camera camera, Texture2D texture, Vector3 center, Vector2 origin, float rotation, Vector2 size, Color tint) +{ + Rectangle source = { 0.0f, 0.0f, (float)texture.width, (float)texture.height }; + + DrawBillboardPro(camera, texture, source, center, size, origin, rotation, tint); +} + +void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, 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.y, size.x*(float)source.height/source.width }; + Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); Vector3 right = { matView.m0, matView.m4, matView.m8 }; @@ -2818,24 +2831,60 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector // NOTE: Billboard locked on axis-Y Vector3 up = { 0.0f, 1.0f, 0.0f }; -/* - a-------b - | | - | * | - | | - d-------c -*/ - right = Vector3Scale(right, sizeRatio.x/2); - up = Vector3Scale(up, sizeRatio.y/2); - - Vector3 p1 = Vector3Add(right, up); - Vector3 p2 = Vector3Subtract(right, up); - - Vector3 a = Vector3Subtract(center, p2); - Vector3 b = Vector3Add(center, p1); - Vector3 c = Vector3Add(center, p2); - Vector3 d = Vector3Subtract(center, p1); + 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) + { + 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)); + } + + topLeft = Vector3Add(topLeft, position); // Translate points to the draw center (position) + topRight = Vector3Add(topRight, position); + bottomRight = Vector3Add(bottomRight, position); + bottomLeft = Vector3Add(bottomLeft, position); + rlCheckRenderBatchLimit(4); rlSetTexture(texture.id); @@ -2845,22 +2894,22 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector // Bottom-left corner for texture and quad rlTexCoord2f((float)source.x/texture.width, (float)source.y/texture.height); - rlVertex3f(a.x, a.y, a.z); + 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(d.x, d.y, d.z); + 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(c.x, c.y, c.z); + 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(b.x, b.y, b.z); + rlVertex3f(topRight.x, topRight.y, topRight.z); rlEnd(); - rlSetTexture(0); + rlSetTexture(0); } // Draw a bounding box with wires diff --git a/src/raylib.h b/src/raylib.h index 4caed9134..c525ad2ff 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1444,7 +1444,9 @@ RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint 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 center, float size, Color tint); // Draw a billboard texture -RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 center, float size, Color tint); // Draw a billboard texture defined by source +RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 center, Vector2 size, Color tint); // Draw a billboard texture defined by source +RLAPI void DrawBillboardEx(Camera camera, Texture2D texture, Vector3 center, Vector2 origin, float rotation, Vector2 size, Color tint); // Draw a billboard texture defined by rotation +RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source and rotation // Collision detection functions RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Detect collision between two spheres