decal.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. #include <r3d/r3d.h>
  2. #include <raymath.h>
  3. #ifndef RESOURCES_PATH
  4. # define RESOURCES_PATH "./"
  5. #endif
  6. #define MAXDECALS 256
  7. static bool RayCubeIntersection(Ray ray, Vector3 cubePos, Vector3 cubeSize, Vector3* intersectionPoint, Vector3* normal);
  8. static void DrawTransformedCube(Matrix t, Color c);
  9. int main(void)
  10. {
  11. InitWindow(800, 450, "[r3d] - Decal example");
  12. SetTargetFPS(60);
  13. // Initialize R3D
  14. R3D_Init(GetScreenWidth(), GetScreenHeight(), 0);
  15. // Load decal texture
  16. Texture2D texture = LoadTexture(RESOURCES_PATH "decal.png");
  17. // Create wall material
  18. R3D_Material materialWalls = R3D_GetDefaultMaterial();
  19. materialWalls.albedo.color = DARKGRAY;
  20. // Create decal material
  21. R3D_Decal decal;
  22. decal.material = R3D_GetDefaultMaterial();
  23. decal.material.albedo.texture = texture;
  24. // Create room mesh and transforms
  25. float roomSize = 32.0f;
  26. R3D_Mesh meshPlane = R3D_GenMeshPlane(roomSize, roomSize, 1, 1);
  27. Matrix matRoom[6];
  28. matRoom[0] = MatrixMultiply(MatrixRotateZ(90.0f * DEG2RAD), MatrixTranslate(roomSize / 2.0f, 0.0f, 0.0f));
  29. matRoom[1] = MatrixMultiply(MatrixRotateZ(-90.0f * DEG2RAD), MatrixTranslate(-roomSize / 2.0f, 0.0f, 0.0f));
  30. matRoom[2] = MatrixMultiply(MatrixRotateX(90.0f * DEG2RAD), MatrixTranslate(0.0f, 0.0f, -roomSize / 2.0f));
  31. matRoom[3] = MatrixMultiply(MatrixRotateX(-90.0f * DEG2RAD), MatrixTranslate(0.0f, 0.0f, roomSize / 2.0f));
  32. matRoom[4] = MatrixMultiply(MatrixRotateX(180.0f * DEG2RAD), MatrixTranslate(0.0f, roomSize / 2.0f, 0.0f));
  33. matRoom[5] = MatrixTranslate(0.0f, -roomSize / 2.0f, 0.0f);
  34. // Setup light
  35. R3D_Light light = R3D_CreateLight(R3D_LIGHT_OMNI);
  36. R3D_SetLightEnergy(light, 2.0f);
  37. R3D_SetLightActive(light, true);
  38. // Setup camera
  39. Camera3D camera = (Camera3D) {
  40. .position = (Vector3) {0.0f, 0.0f, 0.0f},
  41. .target = (Vector3) {1.0f, 0.0f, 0.0f},
  42. .up = (Vector3) {0.0f, 1.0f, 0.0f},
  43. .fovy = 70,
  44. };
  45. DisableCursor();
  46. // Decal state
  47. Vector3 decalScale = {3.0f, 3.0f, 3.0f};
  48. Matrix targetDecalTransform = MatrixIdentity();
  49. Matrix decalTransforms[MAXDECALS];
  50. int decalCount = 0;
  51. int decalIndex = 0;
  52. Vector3 targetPosition = {0};
  53. // Main loop
  54. while (!WindowShouldClose())
  55. {
  56. float delta = GetFrameTime();
  57. UpdateCamera(&camera, CAMERA_FREE);
  58. // Compute ray from camera to target
  59. Ray hitRay = {camera.position, Vector3Normalize(Vector3Subtract(camera.target, camera.position))};
  60. Vector3 hitPoint = {0}, hitNormal = {0};
  61. if (RayCubeIntersection(hitRay, Vector3Zero(), (Vector3) { roomSize, roomSize, roomSize }, &hitPoint, &hitNormal)) {
  62. targetPosition = hitPoint;
  63. }
  64. // Compute decal transform
  65. Matrix translation = MatrixTranslate(targetPosition.x, targetPosition.y, targetPosition.z);
  66. Matrix scaling = MatrixScale(decalScale.x, decalScale.y, decalScale.z);
  67. Matrix rotation = MatrixIdentity();
  68. if (hitNormal.x == -1.0f) rotation = MatrixRotateXYZ((Vector3) { -90.0f * DEG2RAD, 180.0f * DEG2RAD, 90.0f * DEG2RAD });
  69. else if (hitNormal.x == 1.0f) rotation = MatrixRotateXYZ((Vector3) { -90.0f * DEG2RAD, 180.0f * DEG2RAD, -90.0f * DEG2RAD });
  70. else if (hitNormal.y == -1.0f) rotation = MatrixRotateY(180.0f * DEG2RAD);
  71. else if (hitNormal.y == 1.0f) rotation = MatrixRotateZ(180.0f * DEG2RAD);
  72. else if (hitNormal.z == -1.0f) rotation = MatrixRotateX(90.0f * DEG2RAD);
  73. else if (hitNormal.z == 1.0f) rotation = MatrixRotateXYZ((Vector3) { -90.0f * DEG2RAD, 180.0f * DEG2RAD, 0 });
  74. targetDecalTransform = MatrixMultiply(MatrixMultiply(scaling, rotation), translation);
  75. // Apply decal on mouse click
  76. if (IsMouseButtonPressed(0)) {
  77. decalTransforms[decalIndex] = targetDecalTransform;
  78. decalIndex = (decalIndex + 1) % MAXDECALS;
  79. if (decalCount < MAXDECALS) decalCount++;
  80. }
  81. // Draw scene
  82. BeginDrawing();
  83. ClearBackground(RAYWHITE);
  84. R3D_Begin(camera);
  85. for (int i = 0; i < 6; i++) {
  86. R3D_DrawMesh(&meshPlane, &materialWalls, matRoom[i]);
  87. }
  88. if (decalCount > 0) {
  89. R3D_DrawDecalInstanced(&decal, decalTransforms, decalCount);
  90. }
  91. R3D_DrawDecal(&decal, targetDecalTransform);
  92. R3D_End();
  93. BeginMode3D(camera);
  94. DrawTransformedCube(targetDecalTransform, WHITE);
  95. EndMode3D();
  96. DrawText("LEFT CLICK TO APPLY DECAL", 10, 10, 20, LIME);
  97. EndDrawing();
  98. }
  99. // Cleanup
  100. R3D_UnloadMesh(&meshPlane);
  101. R3D_Close();
  102. CloseWindow();
  103. return 0;
  104. }
  105. bool RayCubeIntersection(Ray ray, Vector3 cubePosition, Vector3 cubeSize, Vector3* intersectionPoint, Vector3* normal)
  106. {
  107. Vector3 halfSize = { cubeSize.x / 2, cubeSize.y / 2, cubeSize.z / 2 };
  108. Vector3 min = { cubePosition.x - halfSize.x, cubePosition.y - halfSize.y, cubePosition.z - halfSize.z };
  109. Vector3 max = { cubePosition.x + halfSize.x, cubePosition.y + halfSize.y, cubePosition.z + halfSize.z };
  110. float tMin = (min.x - ray.position.x) / ray.direction.x;
  111. float tMax = (max.x - ray.position.x) / ray.direction.x;
  112. if (tMin > tMax) { float temp = tMin; tMin = tMax; tMax = temp; }
  113. float tYMin = (min.y - ray.position.y) / ray.direction.y;
  114. float tYMax = (max.y - ray.position.y) / ray.direction.y;
  115. if (tYMin > tYMax) { float temp = tYMin; tYMin = tYMax; tYMax = temp; }
  116. if ((tMin > tYMax) || (tYMin > tMax)) return false;
  117. if (tYMin > tMin) tMin = tYMin;
  118. if (tYMax < tMax) tMax = tYMax;
  119. float tZMin = (min.z - ray.position.z) / ray.direction.z;
  120. float tZMax = (max.z - ray.position.z) / ray.direction.z;
  121. if (tZMin > tZMax) { float temp = tZMin; tZMin = tZMax; tZMax = temp; }
  122. if ((tMin > tZMax) || (tZMin > tMax)) return false;
  123. if (tZMin > tMin) tMin = tZMin;
  124. if (tZMax < tMax) tMax = tZMax;
  125. if (tMin < 0) {
  126. tMin = tMax;
  127. if (tMin < 0) return false;
  128. }
  129. *intersectionPoint = (Vector3){ ray.position.x + ray.direction.x * tMin,
  130. ray.position.y + ray.direction.y * tMin,
  131. ray.position.z + ray.direction.z * tMin };
  132. if (fabs(intersectionPoint->x - min.x) < 0.001f) normal->x = -1.0f; // Left face
  133. else if (fabs(intersectionPoint->x - max.x) < 0.001f) normal->x = 1.0f; // Right face
  134. if (fabs(intersectionPoint->y - min.y) < 0.001f) normal->y = -1.0f; // Bottom face
  135. else if (fabs(intersectionPoint->y - max.y) < 0.001f) normal->y = 1.0f; // Top face
  136. if (fabs(intersectionPoint->z - min.z) < 0.001f) normal->z = -1.0f; // Near face
  137. else if (fabs(intersectionPoint->z - max.z) < 0.001f) normal->z = 1.0f; // Far face
  138. return true;
  139. }
  140. void DrawTransformedCube(Matrix transform, Color color)
  141. {
  142. static Vector3 vertices[8] = {
  143. { -0.5f, -0.5f, -0.5f },
  144. { 0.5f, -0.5f, -0.5f },
  145. { 0.5f, 0.5f, -0.5f },
  146. { -0.5f, 0.5f, -0.5f },
  147. { -0.5f, -0.5f, 0.5f },
  148. { 0.5f, -0.5f, 0.5f },
  149. { 0.5f, 0.5f, 0.5f },
  150. { -0.5f, 0.5f, 0.5f },
  151. };
  152. Vector3 transformedVertices[8];
  153. for (int i = 0; i < 8; i++) {
  154. transformedVertices[i] = Vector3Transform(vertices[i], transform);
  155. }
  156. for (int i = 0; i < 4; i++) {
  157. DrawLine3D(transformedVertices[i], transformedVertices[(i + 1) % 4], color); // Bottom
  158. DrawLine3D(transformedVertices[i + 4], transformedVertices[(i + 1) % 4 + 4], color); // Top
  159. DrawLine3D(transformedVertices[i], transformedVertices[i + 4], color); // Sides
  160. }
  161. }