textures_tiled_drawing.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*******************************************************************************************
  2. *
  3. * raylib [textures] example - tiled drawing
  4. *
  5. * Example complexity rating: [★★★☆] 3/4
  6. *
  7. * Example originally created with raylib 3.0, last time updated with raylib 4.2
  8. *
  9. * Example contributed by Vlad Adrian (@demizdor) and reviewed by Ramon Santamaria (@raysan5)
  10. *
  11. * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
  12. * BSD-like license that allows static linking with closed source software
  13. *
  14. * Copyright (c) 2020-2025 Vlad Adrian (@demizdor) and Ramon Santamaria (@raysan5)
  15. *
  16. ********************************************************************************************/
  17. #include "raylib.h"
  18. #define SIZEOF(A) (sizeof(A)/sizeof(A[0]))
  19. #define OPT_WIDTH 220 // Max width for the options container
  20. #define MARGIN_SIZE 8 // Size for the margins
  21. #define COLOR_SIZE 16 // Size of the color select buttons
  22. // Draw part of a texture (defined by a rectangle) with rotation and scale tiled into dest
  23. void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, float scale, Color tint);
  24. //------------------------------------------------------------------------------------
  25. // Program main entry point
  26. //------------------------------------------------------------------------------------
  27. int main(void)
  28. {
  29. // Initialization
  30. //--------------------------------------------------------------------------------------
  31. const int screenWidth = 800;
  32. const int screenHeight = 450;
  33. SetConfigFlags(FLAG_WINDOW_RESIZABLE); // Make the window resizable
  34. InitWindow(screenWidth, screenHeight, "raylib [textures] example - tiled drawing");
  35. // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
  36. Texture texPattern = LoadTexture("resources/patterns.png");
  37. SetTextureFilter(texPattern, TEXTURE_FILTER_BILINEAR); // Makes the texture smoother when upscaled
  38. // Coordinates for all patterns inside the texture
  39. const Rectangle recPattern[] = {
  40. (Rectangle){ 3, 3, 66, 66 },
  41. (Rectangle){ 75, 3, 100, 100 },
  42. (Rectangle){ 3, 75, 66, 66 },
  43. (Rectangle){ 7, 156, 50, 50 },
  44. (Rectangle){ 85, 106, 90, 45 },
  45. (Rectangle){ 75, 154, 100, 60}
  46. };
  47. // Setup colors
  48. const Color colors[] = { BLACK, MAROON, ORANGE, BLUE, PURPLE, BEIGE, LIME, RED, DARKGRAY, SKYBLUE };
  49. enum { MAX_COLORS = SIZEOF(colors) };
  50. Rectangle colorRec[MAX_COLORS] = { 0 };
  51. // Calculate rectangle for each color
  52. for (int i = 0, x = 0, y = 0; i < MAX_COLORS; i++)
  53. {
  54. colorRec[i].x = 2.0f + MARGIN_SIZE + x;
  55. colorRec[i].y = 22.0f + 256.0f + MARGIN_SIZE + y;
  56. colorRec[i].width = COLOR_SIZE*2.0f;
  57. colorRec[i].height = (float)COLOR_SIZE;
  58. if (i == (MAX_COLORS/2 - 1))
  59. {
  60. x = 0;
  61. y += COLOR_SIZE + MARGIN_SIZE;
  62. }
  63. else x += (COLOR_SIZE*2 + MARGIN_SIZE);
  64. }
  65. int activePattern = 0, activeCol = 0;
  66. float scale = 1.0f, rotation = 0.0f;
  67. SetTargetFPS(60);
  68. //---------------------------------------------------------------------------------------
  69. // Main game loop
  70. while (!WindowShouldClose()) // Detect window close button or ESC key
  71. {
  72. // Update
  73. //----------------------------------------------------------------------------------
  74. // Handle mouse
  75. if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
  76. {
  77. const Vector2 mouse = GetMousePosition();
  78. // Check which pattern was clicked and set it as the active pattern
  79. for (int i = 0; i < SIZEOF(recPattern); i++)
  80. {
  81. if (CheckCollisionPointRec(mouse, (Rectangle){ 2 + MARGIN_SIZE + recPattern[i].x, 40 + MARGIN_SIZE + recPattern[i].y, recPattern[i].width, recPattern[i].height }))
  82. {
  83. activePattern = i;
  84. break;
  85. }
  86. }
  87. // Check to see which color was clicked and set it as the active color
  88. for (int i = 0; i < MAX_COLORS; i++)
  89. {
  90. if (CheckCollisionPointRec(mouse, colorRec[i]))
  91. {
  92. activeCol = i;
  93. break;
  94. }
  95. }
  96. }
  97. // Handle keys: change scale
  98. if (IsKeyPressed(KEY_UP)) scale += 0.25f;
  99. if (IsKeyPressed(KEY_DOWN)) scale -= 0.25f;
  100. if (scale > 10.0f) scale = 10.0f;
  101. else if ( scale <= 0.0f) scale = 0.25f;
  102. // Handle keys: change rotation
  103. if (IsKeyPressed(KEY_LEFT)) rotation -= 25.0f;
  104. if (IsKeyPressed(KEY_RIGHT)) rotation += 25.0f;
  105. // Handle keys: reset
  106. if (IsKeyPressed(KEY_SPACE)) { rotation = 0.0f; scale = 1.0f; }
  107. //----------------------------------------------------------------------------------
  108. // Draw
  109. //----------------------------------------------------------------------------------
  110. BeginDrawing();
  111. ClearBackground(RAYWHITE);
  112. // Draw the tiled area
  113. DrawTextureTiled(texPattern, recPattern[activePattern], (Rectangle){(float)OPT_WIDTH+MARGIN_SIZE, (float)MARGIN_SIZE, GetScreenWidth() - OPT_WIDTH - 2.0f*MARGIN_SIZE, GetScreenHeight() - 2.0f*MARGIN_SIZE},
  114. (Vector2){0.0f, 0.0f}, rotation, scale, colors[activeCol]);
  115. // Draw options
  116. DrawRectangle(MARGIN_SIZE, MARGIN_SIZE, OPT_WIDTH - MARGIN_SIZE, GetScreenHeight() - 2*MARGIN_SIZE, ColorAlpha(LIGHTGRAY, 0.5f));
  117. DrawText("Select Pattern", 2 + MARGIN_SIZE, 30 + MARGIN_SIZE, 10, BLACK);
  118. DrawTexture(texPattern, 2 + MARGIN_SIZE, 40 + MARGIN_SIZE, BLACK);
  119. DrawRectangle(2 + MARGIN_SIZE + (int)recPattern[activePattern].x, 40 + MARGIN_SIZE + (int)recPattern[activePattern].y, (int)recPattern[activePattern].width, (int)recPattern[activePattern].height, ColorAlpha(DARKBLUE, 0.3f));
  120. DrawText("Select Color", 2+MARGIN_SIZE, 10+256+MARGIN_SIZE, 10, BLACK);
  121. for (int i = 0; i < MAX_COLORS; i++)
  122. {
  123. DrawRectangleRec(colorRec[i], colors[i]);
  124. if (activeCol == i) DrawRectangleLinesEx(colorRec[i], 3, ColorAlpha(WHITE, 0.5f));
  125. }
  126. DrawText("Scale (UP/DOWN to change)", 2 + MARGIN_SIZE, 80 + 256 + MARGIN_SIZE, 10, BLACK);
  127. DrawText(TextFormat("%.2fx", scale), 2 + MARGIN_SIZE, 92 + 256 + MARGIN_SIZE, 20, BLACK);
  128. DrawText("Rotation (LEFT/RIGHT to change)", 2 + MARGIN_SIZE, 122 + 256 + MARGIN_SIZE, 10, BLACK);
  129. DrawText(TextFormat("%.0f degrees", rotation), 2 + MARGIN_SIZE, 134 + 256 + MARGIN_SIZE, 20, BLACK);
  130. DrawText("Press [SPACE] to reset", 2 + MARGIN_SIZE, 164 + 256 + MARGIN_SIZE, 10, DARKBLUE);
  131. // Draw FPS
  132. DrawText(TextFormat("%i FPS", GetFPS()), 2 + MARGIN_SIZE, 2 + MARGIN_SIZE, 20, BLACK);
  133. EndDrawing();
  134. //----------------------------------------------------------------------------------
  135. }
  136. // De-Initialization
  137. //--------------------------------------------------------------------------------------
  138. UnloadTexture(texPattern); // Unload texture
  139. CloseWindow(); // Close window and OpenGL context
  140. //--------------------------------------------------------------------------------------
  141. return 0;
  142. }
  143. // Draw part of a texture (defined by a rectangle) with rotation and scale tiled into dest
  144. void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, float scale, Color tint)
  145. {
  146. if ((texture.id <= 0) || (scale <= 0.0f)) return; // Wanna see a infinite loop?!...just delete this line!
  147. if ((source.width == 0) || (source.height == 0)) return;
  148. int tileWidth = (int)(source.width*scale), tileHeight = (int)(source.height*scale);
  149. if ((dest.width < tileWidth) && (dest.height < tileHeight))
  150. {
  151. // Can fit only one tile
  152. DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)dest.width/tileWidth)*source.width, ((float)dest.height/tileHeight)*source.height},
  153. (Rectangle){dest.x, dest.y, dest.width, dest.height}, origin, rotation, tint);
  154. }
  155. else if (dest.width <= tileWidth)
  156. {
  157. // Tiled vertically (one column)
  158. int dy = 0;
  159. for (;dy+tileHeight < dest.height; dy += tileHeight)
  160. {
  161. DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)dest.width/tileWidth)*source.width, source.height}, (Rectangle){dest.x, dest.y + dy, dest.width, (float)tileHeight}, origin, rotation, tint);
  162. }
  163. // Fit last tile
  164. if (dy < dest.height)
  165. {
  166. DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)dest.width/tileWidth)*source.width, ((float)(dest.height - dy)/tileHeight)*source.height},
  167. (Rectangle){dest.x, dest.y + dy, dest.width, dest.height - dy}, origin, rotation, tint);
  168. }
  169. }
  170. else if (dest.height <= tileHeight)
  171. {
  172. // Tiled horizontally (one row)
  173. int dx = 0;
  174. for (;dx+tileWidth < dest.width; dx += tileWidth)
  175. {
  176. DrawTexturePro(texture, (Rectangle){source.x, source.y, source.width, ((float)dest.height/tileHeight)*source.height}, (Rectangle){dest.x + dx, dest.y, (float)tileWidth, dest.height}, origin, rotation, tint);
  177. }
  178. // Fit last tile
  179. if (dx < dest.width)
  180. {
  181. DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)(dest.width - dx)/tileWidth)*source.width, ((float)dest.height/tileHeight)*source.height},
  182. (Rectangle){dest.x + dx, dest.y, dest.width - dx, dest.height}, origin, rotation, tint);
  183. }
  184. }
  185. else
  186. {
  187. // Tiled both horizontally and vertically (rows and columns)
  188. int dx = 0;
  189. for (;dx+tileWidth < dest.width; dx += tileWidth)
  190. {
  191. int dy = 0;
  192. for (;dy+tileHeight < dest.height; dy += tileHeight)
  193. {
  194. DrawTexturePro(texture, source, (Rectangle){dest.x + dx, dest.y + dy, (float)tileWidth, (float)tileHeight}, origin, rotation, tint);
  195. }
  196. if (dy < dest.height)
  197. {
  198. DrawTexturePro(texture, (Rectangle){source.x, source.y, source.width, ((float)(dest.height - dy)/tileHeight)*source.height},
  199. (Rectangle){dest.x + dx, dest.y + dy, (float)tileWidth, dest.height - dy}, origin, rotation, tint);
  200. }
  201. }
  202. // Fit last column of tiles
  203. if (dx < dest.width)
  204. {
  205. int dy = 0;
  206. for (;dy+tileHeight < dest.height; dy += tileHeight)
  207. {
  208. DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)(dest.width - dx)/tileWidth)*source.width, source.height},
  209. (Rectangle){dest.x + dx, dest.y + dy, dest.width - dx, (float)tileHeight}, origin, rotation, tint);
  210. }
  211. // Draw final tile in the bottom right corner
  212. if (dy < dest.height)
  213. {
  214. DrawTexturePro(texture, (Rectangle){source.x, source.y, ((float)(dest.width - dx)/tileWidth)*source.width, ((float)(dest.height - dy)/tileHeight)*source.height},
  215. (Rectangle){dest.x + dx, dest.y + dy, dest.width - dx, dest.height - dy}, origin, rotation, tint);
  216. }
  217. }
  218. }
  219. }