Browse Source

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

* Implemented DrawTextureTiled()

* Example added
Vlad Adrian 5 years ago
parent
commit
4d71e9b44f
4 changed files with 223 additions and 0 deletions
  1. BIN
      examples/textures/resources/pat.png
  2. 148 0
      examples/textures/textures_draw_tiled.c
  3. 1 0
      src/raylib.h
  4. 74 0
      src/textures.c

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 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 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 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);
 }
 
+// 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
 // NOTE: origin is relative to destination rectangle size
 void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint)