You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
11 KiB

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