Browse Source

Added new function `DrawTextureTiled()` (#1291)

* Implemented DrawTextureTiled()

* Example added
Vlad Adrian 5 năm trước cách đây
mục cha
commit
4d71e9b44f

BIN
examples/textures/resources/pat.png


+ 148 - 0
examples/textures/textures_draw_tiled.c

@@ -0,0 +1,148 @@
+/*******************************************************************************************
+*
+*   raylib [textures] example - Draw part of the texture tiled
+*
+*   This example has been created using raylib 3.0 (www.raylib.com)
+*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
+*
+*   Copyright (c) 2020 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+#include "raylib.h"
+
+#define SIZEOF(A) (sizeof(A)/sizeof(A[0]))
+#define OPT_WIDTH 220  // max width for the options container
+#define MARGIN_SIZE 8  // size for the margins
+#define COLOR_SIZE 16  // size of the color select buttons
+
+int main(int argc, char **argv)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    int screenWidth = 800;
+    int screenHeight = 450;
+    
+    SetConfigFlags(FLAG_WINDOW_RESIZABLE); // Make the window resizable
+    InitWindow(screenWidth, screenHeight, "raylib [textures] example - Draw part of a texture tiled");
+
+    // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
+    Texture ptex = LoadTexture("resources/pat.png");
+    SetTextureFilter(ptex, FILTER_TRILINEAR); // Makes the texture smoother when upscaled
+    
+    // Coordinates for all patterns inside the texture
+    const Rectangle patRec[] = { (Rectangle){3,3,66,66}, (Rectangle){75,3,100,100}, 
+            (Rectangle){3,75,66,66}, (Rectangle){7,156,50,50}, (Rectangle){85,106,90,45}, (Rectangle){75,154,100,60} };
+    
+    // Setup colors
+    const Color colors[] = { BLACK, MAROON, ORANGE, BLUE, PURPLE, BEIGE, LIME, RED, DARKGRAY, SKYBLUE};
+    enum {MAX_COLORS = SIZEOF(colors)};
+    Rectangle colorRec[MAX_COLORS] = { 0 };
+
+    // Calculate rectangle for each color
+    for(int i=0, x=0, y=0; i<MAX_COLORS; i++) {
+        colorRec[i].x =  2+MARGIN_SIZE + x;
+        colorRec[i].y =  22+256+MARGIN_SIZE + y;
+        colorRec[i].width = COLOR_SIZE*2;
+        colorRec[i].height = COLOR_SIZE;
+        if(i == MAX_COLORS/2 - 1) {
+            x = 0; y += COLOR_SIZE + MARGIN_SIZE;
+        } else x += COLOR_SIZE * 2 + MARGIN_SIZE; 
+        
+    }
+
+    int activePat = 0, activeCol = 0;
+    float scale = 1.0f, rotation = 0.0f;
+    
+    SetTargetFPS(60);
+    //---------------------------------------------------------------------------------------
+    
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        screenWidth = GetScreenWidth();
+        screenHeight = GetScreenHeight();
+        
+        // Handle mouse
+        if(IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
+            const Vector2 mouse = GetMousePosition();
+            
+            // Check which pattern was clicked and set it as the active pattern
+            for(int i=0; i<SIZEOF(patRec); ++i) {
+                if(CheckCollisionPointRec(mouse, (Rectangle){2+MARGIN_SIZE+patRec[i].x, 40+MARGIN_SIZE+patRec[i].y,patRec[i].width, patRec[i].height})) { 
+                    activePat = i; 
+                    break; 
+                }
+            }
+            
+            // Check to see which color was clicked and set it as the active color
+            for(int i=0; i<MAX_COLORS; ++i) {
+                if(CheckCollisionPointRec(mouse, colorRec[i])) {
+                    activeCol = i;
+                    break;
+                }
+            }
+        }
+        
+        // Handle keys
+        
+        // Change scale
+        if(IsKeyPressed(KEY_UP)) scale += 0.25f;
+        if(IsKeyPressed(KEY_DOWN)) scale -= 0.25f;
+        if(scale > 10.0f) scale = 10.0f;
+        else if( scale <= 0.0f) scale = 0.25f;
+        
+        // Change rotation
+        if(IsKeyPressed(KEY_LEFT)) rotation -= 25.0f;
+        if(IsKeyPressed(KEY_RIGHT)) rotation += 25.0f;
+        
+        // Reset
+        if(IsKeyPressed(KEY_SPACE)) { rotation = 0.0f; scale = 1.0f; }
+        //----------------------------------------------------------------------------------
+        
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+            ClearBackground(RAYWHITE);
+            
+            // Draw the tiled area
+            DrawTextureTiled(ptex, patRec[activePat], (Rectangle){OPT_WIDTH+MARGIN_SIZE, MARGIN_SIZE, screenWidth - OPT_WIDTH - 2*MARGIN_SIZE, screenHeight - 2*MARGIN_SIZE},
+                (Vector2){0.0f, 0.0f}, rotation, scale, colors[activeCol]);
+            
+            // Draw options
+            DrawRectangle(MARGIN_SIZE, MARGIN_SIZE, OPT_WIDTH - MARGIN_SIZE, screenHeight-2*MARGIN_SIZE, ColorAlpha(LIGHTGRAY, 0.5f));
+            
+            DrawText("Select Pattern", 2+MARGIN_SIZE, 30+MARGIN_SIZE, 10, BLACK);
+            DrawTexture(ptex, 2+MARGIN_SIZE, 40+MARGIN_SIZE, BLACK);
+            DrawRectangle(2+MARGIN_SIZE + patRec[activePat].x, 40+MARGIN_SIZE+patRec[activePat].y,patRec[activePat].width, patRec[activePat].height, ColorAlpha(DARKBLUE, 0.3f));
+            
+            DrawText("Select Color", 2+MARGIN_SIZE, 10+256+MARGIN_SIZE, 10, BLACK);
+            for(int i=0; i<MAX_COLORS; ++i) {
+                DrawRectangleRec(colorRec[i], colors[i]);
+                if(activeCol == i) DrawRectangleLinesEx(colorRec[i], 3.0f, ColorAlpha(WHITE, 0.5f));
+            }
+            
+            DrawText("Scale (UP/DOWN to change)", 2+MARGIN_SIZE, 80+256+MARGIN_SIZE, 10, BLACK);
+            DrawText(TextFormat("%.2fx", scale), 2+MARGIN_SIZE, 92+256+MARGIN_SIZE, 20, BLACK);
+            
+            DrawText("Rotation (LEFT/RIGHT to change)", 2+MARGIN_SIZE, 122+256+MARGIN_SIZE, 10, BLACK);
+            DrawText(TextFormat("%.0f degrees", rotation), 2+MARGIN_SIZE, 134+256+MARGIN_SIZE, 20, BLACK);
+            
+            DrawText("Press [SPACE] to reset",  2+MARGIN_SIZE, 164+256+MARGIN_SIZE, 10, DARKBLUE);
+            
+            // Draw FPS
+            DrawText(TextFormat("%i FPS", GetFPS()), 2+MARGIN_SIZE, 2+MARGIN_SIZE, 20, BLACK);
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+    
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadTexture(ptex);
+    CloseWindow();                // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+    
+	return 0;
+}
+

+ 1 - 0
src/raylib.h

@@ -1187,6 +1187,7 @@ RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint);
 RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint);  // Draw a Texture2D with extended parameters
 RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint);  // Draw a Texture2D with extended parameters
 RLAPI void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint);         // Draw a part of a texture defined by a rectangle
 RLAPI void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint);         // Draw a part of a texture defined by a rectangle
 RLAPI void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint);  // Draw texture quad with tiling and offset parameters
 RLAPI void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint);  // Draw texture quad with tiling and offset parameters
+RLAPI void DrawTextureTiled(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, float scale, Color tint);  // Draw part of a texture (defined by a rectangle) with rotation and scale tiled into destRec.
 RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint);       // Draw a part of a texture defined by a rectangle with 'pro' parameters
 RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint);       // Draw a part of a texture defined by a rectangle with 'pro' parameters
 RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle destRec, Vector2 origin, float rotation, Color tint);  // Draws a texture (or part of it) that stretches or shrinks nicely
 RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle destRec, Vector2 origin, float rotation, Color tint);  // Draws a texture (or part of it) that stretches or shrinks nicely
 
 

+ 74 - 0
src/textures.c

@@ -3005,6 +3005,80 @@ void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangl
     DrawTexturePro(texture, source, quad, origin, 0.0f, tint);
     DrawTexturePro(texture, source, quad, origin, 0.0f, tint);
 }
 }
 
 
+// Draw part of a texture (defined by a rectangle) with rotation and scale tiled into destRec.
+// NOTE: For tilling a whole texture DrawTextureQuad() is better
+void DrawTextureTiled(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, float scale, Color tint)
+{
+    if(texture.id <= 0 || scale <= 0.0f) return;  // Wanna see a infinite loop?!...just delete this line!
+    
+    int tileWidth = sourceRec.width*scale, tileHeight = sourceRec.height*scale;
+    if(destRec.width < tileWidth && destRec.height < tileHeight) 
+    {
+        // Can fit only one tile
+        DrawTexturePro(texture, (Rectangle){sourceRec.x, sourceRec.y, ((float)destRec.width/tileWidth)*sourceRec.width, ((float)destRec.height/tileHeight)*sourceRec.height}, 
+                    (Rectangle){destRec.x, destRec.y, destRec.width, destRec.height}, origin, rotation, tint);
+    }
+    else if(destRec.width <= tileWidth) 
+    {
+        // Tiled vertically (one column)
+        int dy = 0;
+        for(;dy+tileHeight < destRec.height; dy += tileHeight) {
+            DrawTexturePro(texture, (Rectangle){sourceRec.x, sourceRec.y, ((float)destRec.width/tileWidth)*sourceRec.width, sourceRec.height}, (Rectangle){destRec.x, destRec.y + dy, destRec.width, tileHeight}, origin, rotation, tint);
+        }
+        
+        // Fit last tile
+        if(dy < destRec.height) {
+            DrawTexturePro(texture, (Rectangle){sourceRec.x, sourceRec.y, ((float)destRec.width/tileWidth)*sourceRec.width, ((float)(destRec.height - dy)/tileHeight)*sourceRec.height}, 
+                        (Rectangle){destRec.x, destRec.y + dy, destRec.width, destRec.height - dy}, origin, rotation, tint);
+        }
+    } 
+    else if(destRec.height <= tileHeight) 
+    {
+        // Tiled horizontally (one row)
+        int dx = 0;
+        for(;dx+tileWidth < destRec.width; dx += tileWidth) {
+            DrawTexturePro(texture, (Rectangle){sourceRec.x, sourceRec.y, sourceRec.width, ((float)destRec.height/tileHeight)*sourceRec.height}, (Rectangle){destRec.x + dx, destRec.y, tileWidth, destRec.height}, origin, rotation, tint);
+        }
+        
+        // Fit last tile
+        if(dx < destRec.width) {
+            DrawTexturePro(texture, (Rectangle){sourceRec.x, sourceRec.y, ((float)(destRec.width - dx)/tileWidth)*sourceRec.width, ((float)destRec.height/tileHeight)*sourceRec.height}, 
+                        (Rectangle){destRec.x + dx, destRec.y, destRec.width - dx, destRec.height}, origin, rotation, tint);
+        }
+    }
+    else
+    {
+        // Tiled both horizontally and vertically (rows and columns)
+        int dx = 0;
+        for(;dx+tileWidth < destRec.width; dx += tileWidth) {
+            int dy = 0;
+            for(;dy+tileHeight < destRec.height; dy += tileHeight) {
+                DrawTexturePro(texture, sourceRec, (Rectangle){destRec.x + dx, destRec.y + dy, tileWidth, tileHeight}, origin, rotation, tint);
+            }
+            
+            if(dy < destRec.height) {
+                DrawTexturePro(texture, (Rectangle){sourceRec.x, sourceRec.y, sourceRec.width, ((float)(destRec.height - dy)/tileHeight)*sourceRec.height}, 
+                    (Rectangle){destRec.x + dx, destRec.y + dy, tileWidth, destRec.height - dy}, origin, rotation, tint);
+            }
+        }
+        
+        // Fit last column of tiles
+        if(dx < destRec.width) {
+            int dy = 0;
+            for(;dy+tileHeight < destRec.height; dy += tileHeight) {
+                DrawTexturePro(texture, (Rectangle){sourceRec.x, sourceRec.y, ((float)(destRec.width - dx)/tileWidth)*sourceRec.width, sourceRec.height}, 
+                        (Rectangle){destRec.x + dx, destRec.y + dy, destRec.width - dx, tileHeight}, origin, rotation, tint);
+            }
+            
+            // Draw final tile in the bottom right corner
+            if(dy < destRec.height) {
+                DrawTexturePro(texture, (Rectangle){sourceRec.x, sourceRec.y, ((float)(destRec.width - dx)/tileWidth)*sourceRec.width, ((float)(destRec.height - dy)/tileHeight)*sourceRec.height}, 
+                    (Rectangle){destRec.x + dx, destRec.y + dy, destRec.width - dx, destRec.height - dy}, origin, rotation, tint);
+            }
+        }
+    }
+}
+
 // Draw a part of a texture (defined by a rectangle) with 'pro' parameters
 // Draw a part of a texture (defined by a rectangle) with 'pro' parameters
 // NOTE: origin is relative to destination rectangle size
 // NOTE: origin is relative to destination rectangle size
 void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint)
 void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint)