Last active
March 23, 2021 13:22
-
-
Save chrisdill/7c174db8d82859db471b140f43fc510c to your computer and use it in GitHub Desktop.
DrawTexturePro and DrawRectanglePro optimizations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Updated with bug fixes etc | |
// Draw a part of a texture (defined by a rectangle) with 'pro' parameters | |
// NOTE: origin is relative to destination rectangle size | |
void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint) | |
{ | |
// Check if texture is valid | |
if (texture.id > 0) | |
{ | |
float width = (float)texture.width; | |
float height = (float)texture.height; | |
bool flipX = false; | |
if (source.width < 0) { flipX = true; source.width *= -1; } | |
if (source.height < 0) source.y -= source.height; | |
Vector2 topLeft = { 0 }; | |
Vector2 topRight = { 0 }; | |
Vector2 bottomLeft = { 0 }; | |
Vector2 bottomRight = { 0 }; | |
// Only calculate rotation if needed | |
if (rotation == 0.0f) | |
{ | |
float x = dest.x - origin.x; | |
float y = dest.y - origin.y; | |
topLeft = (Vector2){ x, y }; | |
topRight = (Vector2){ x + dest.width, y }; | |
bottomLeft = (Vector2){ x, y + dest.height }; | |
bottomRight = (Vector2){ x + dest.width, y + dest.height }; | |
} | |
else | |
{ | |
float sinRotation = sinf(rotation*DEG2RAD); | |
float cosRotation = cosf(rotation*DEG2RAD); | |
float x = dest.x; | |
float y = dest.y; | |
float dx = -origin.x; | |
float dy = -origin.y; | |
topLeft.x = x + dx*cosRotation - dy*sinRotation; | |
topLeft.y = y + dx*sinRotation + dy*cosRotation; | |
topRight.x = x + (dx + dest.width)*cosRotation - dy*sinRotation; | |
topRight.y = y + (dx + dest.width)*sinRotation + dy*cosRotation; | |
bottomLeft.x = x + dx*cosRotation - (dy + dest.height)*sinRotation; | |
bottomLeft.y = y + dx*sinRotation + (dy + dest.height)*cosRotation; | |
bottomRight.x = x + (dx + dest.width)*cosRotation - (dy + dest.height)*sinRotation; | |
bottomRight.y = y + (dx + dest.width)*sinRotation + (dy + dest.height)*cosRotation; | |
} | |
rlEnableTexture(texture.id); | |
rlBegin(RL_QUADS); | |
rlColor4ub(tint.r, tint.g, tint.b, tint.a); | |
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer | |
// Top-left corner for texture and quad | |
if (flipX) rlTexCoord2f((source.x + source.width)/width, source.y/height); | |
else rlTexCoord2f(source.x/width, source.y/height); | |
rlVertex2f(topLeft.x, topLeft.y); | |
// Bottom-left corner for texture and quad | |
if (flipX) rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height); | |
else rlTexCoord2f(source.x/width, (source.y + source.height)/height); | |
rlVertex2f(bottomLeft.x, bottomLeft.y); | |
// Bottom-right corner for texture and quad | |
if (flipX) rlTexCoord2f(source.x/width, (source.y + source.height)/height); | |
else rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height); | |
rlVertex2f(bottomRight.x, bottomRight.y); | |
// Top-right corner for texture and quad | |
if (flipX) rlTexCoord2f(source.x/width, source.y/height); | |
else rlTexCoord2f((source.x + source.width)/width, source.y/height); | |
rlVertex2f(topRight.x, topRight.y); | |
rlEnd(); | |
rlDisableTexture(); | |
// NOTE: Vertex position can be transformed using matrices | |
// but the process is way more costly than just calculating | |
// the vertex positions manually, like done above. | |
// I leave here the old implementation for educational pourposes, | |
// just in case someone wants to do some performance test | |
/* | |
rlEnableTexture(texture.id); | |
rlPushMatrix(); | |
rlTranslatef(dest.x, dest.y, 0.0f); | |
if (rotation != 0.0f) rlRotatef(rotation, 0.0f, 0.0f, 1.0f); | |
rlTranslatef(-origin.x, -origin.y, 0.0f); | |
rlBegin(RL_QUADS); | |
rlColor4ub(tint.r, tint.g, tint.b, tint.a); | |
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer | |
// Bottom-left corner for texture and quad | |
if (flipX) rlTexCoord2f((source.x + source.width)/width, source.y/height); | |
else rlTexCoord2f(source.x/width, source.y/height); | |
rlVertex2f(0.0f, 0.0f); | |
// Bottom-right corner for texture and quad | |
if (flipX) rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height); | |
else rlTexCoord2f(source.x/width, (source.y + source.height)/height); | |
rlVertex2f(0.0f, dest.height); | |
// Top-right corner for texture and quad | |
if (flipX) rlTexCoord2f(source.x/width, (source.y + source.height)/height); | |
else rlTexCoord2f((source.x + source.width)/width, (source.y + source.height)/height); | |
rlVertex2f(dest.width, dest.height); | |
// Top-left corner for texture and quad | |
if (flipX) rlTexCoord2f(source.x/width, source.y/height); | |
else rlTexCoord2f((source.x + source.width)/width, source.y/height); | |
rlVertex2f(dest.width, 0.0f); | |
rlEnd(); | |
rlPopMatrix(); | |
rlDisableTexture(); | |
*/ | |
} | |
} | |
// Draw a color-filled rectangle with pro parameters | |
void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color) | |
{ | |
rlCheckRenderBatchLimit(4); | |
Vector2 topLeft = { 0 }; | |
Vector2 topRight = { 0 }; | |
Vector2 bottomLeft = { 0 }; | |
Vector2 bottomRight = { 0 }; | |
// Only calculate rotation if needed | |
if (rotation == 0.0f) | |
{ | |
float x = rec.x - origin.x; | |
float y = rec.y - origin.y; | |
topLeft = (Vector2){ x, y }; | |
topRight = (Vector2){ x + rec.width, y }; | |
bottomLeft = (Vector2){ x, y + rec.height }; | |
bottomRight = (Vector2){ x + rec.width, y + rec.height }; | |
} | |
else | |
{ | |
float sinRotation = sinf(rotation*DEG2RAD); | |
float cosRotation = cosf(rotation*DEG2RAD); | |
float x = rec.x; | |
float y = rec.y; | |
float dx = -origin.x; | |
float dy = -origin.y; | |
topLeft.x = x + dx*cosRotation - dy*sinRotation; | |
topLeft.y = y + dx*sinRotation + dy*cosRotation; | |
topRight.x = x + (dx + rec.width)*cosRotation - dy*sinRotation; | |
topRight.y = y + (dx + rec.width)*sinRotation + dy*cosRotation; | |
bottomLeft.x = x + dx*cosRotation - (dy + rec.height)*sinRotation; | |
bottomLeft.y = y + dx*sinRotation + (dy + rec.height)*cosRotation; | |
bottomRight.x = x + (dx + rec.width)*cosRotation - (dy + rec.height)*sinRotation; | |
bottomRight.y = y + (dx + rec.width)*sinRotation + (dy + rec.height)*cosRotation; | |
} | |
rlEnableTexture(rlGetShapesTexture().id); | |
rlBegin(RL_QUADS); | |
rlNormal3f(0.0f, 0.0f, 1.0f); | |
rlColor4ub(color.r, color.g, color.b, color.a); | |
rlTexCoord2f(rlGetShapesTextureRec().x/rlGetShapesTexture().width, rlGetShapesTextureRec().y/rlGetShapesTexture().height); | |
rlVertex2f(topLeft.x, topLeft.y); | |
rlTexCoord2f(rlGetShapesTextureRec().x/rlGetShapesTexture().width, (rlGetShapesTextureRec().y + rlGetShapesTextureRec().height)/rlGetShapesTexture().height); | |
rlVertex2f(bottomLeft.x, bottomLeft.y); | |
rlTexCoord2f((rlGetShapesTextureRec().x + rlGetShapesTextureRec().width)/rlGetShapesTexture().width, (rlGetShapesTextureRec().y + rlGetShapesTextureRec().height)/rlGetShapesTexture().height); | |
rlVertex2f(bottomRight.x, bottomRight.y); | |
rlTexCoord2f((rlGetShapesTextureRec().x + rlGetShapesTextureRec().width)/rlGetShapesTexture().width, rlGetShapesTextureRec().y/rlGetShapesTexture().height); | |
rlVertex2f(topRight.x, topRight.y); | |
rlEnd(); | |
rlDisableTexture(); | |
} |
Amazing!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Comparing the performance of textures_bunnymark between Raylib and Monogame.
Raylib can handle around 30k bunnies at 60fps whereas Monogame can go much higher.
I found that raylib used matrices for translation and rotation whereas Monogame calculates it into vertex data and only calculates the rotation if needed. Applied to raylib, these changes allows it to handle around 70k bunnies at 60fps!