decal.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. #include "./common.h"
  2. #define MAXDECALS 256
  3. /* === Resources === */
  4. static R3D_Mesh meshPlane;
  5. static R3D_Material materialWalls = { 0 };
  6. static Texture2D texture = { 0 };
  7. static R3D_Decal decal = { 0 };
  8. static Camera3D camera = { 0 };
  9. static R3D_Light light = { 0 };
  10. /* === Data === */
  11. float roomSize = 32.0f;
  12. Matrix matRoom[6];
  13. Vector3 decalScale = { 3.0f, 3.0f, 3.0f };
  14. Matrix targetDecalTransform = { 0 };
  15. Matrix decalTransforms[MAXDECALS];
  16. int decalCount = 0;
  17. int decalIndex = 0;
  18. Vector3 targetPosition = { 0 };
  19. /* === Helper Functions === */
  20. static bool RayCubeIntersection(Ray ray, Vector3 cubePosition, Vector3 cubeSize, Vector3* intersectionPoint, Vector3* normal) {
  21. Vector3 halfSize = { cubeSize.x / 2, cubeSize.y / 2, cubeSize.z / 2 };
  22. Vector3 min = { cubePosition.x - halfSize.x, cubePosition.y - halfSize.y, cubePosition.z - halfSize.z };
  23. Vector3 max = { cubePosition.x + halfSize.x, cubePosition.y + halfSize.y, cubePosition.z + halfSize.z };
  24. float tMin = (min.x - ray.position.x) / ray.direction.x;
  25. float tMax = (max.x - ray.position.x) / ray.direction.x;
  26. if (tMin > tMax) { float temp = tMin; tMin = tMax; tMax = temp; }
  27. float tYMin = (min.y - ray.position.y) / ray.direction.y;
  28. float tYMax = (max.y - ray.position.y) / ray.direction.y;
  29. if (tYMin > tYMax) { float temp = tYMin; tYMin = tYMax; tYMax = temp; }
  30. if ((tMin > tYMax) || (tYMin > tMax)) return false;
  31. if (tYMin > tMin) tMin = tYMin;
  32. if (tYMax < tMax) tMax = tYMax;
  33. float tZMin = (min.z - ray.position.z) / ray.direction.z;
  34. float tZMax = (max.z - ray.position.z) / ray.direction.z;
  35. if (tZMin > tZMax) { float temp = tZMin; tZMin = tZMax; tZMax = temp; }
  36. if ((tMin > tZMax) || (tZMin > tMax)) return false;
  37. if (tZMin > tMin) tMin = tZMin;
  38. if (tZMax < tMax) tMax = tZMax;
  39. if (tMin < 0) {
  40. tMin = tMax;
  41. if (tMin < 0) return false;
  42. }
  43. *intersectionPoint = (Vector3){ ray.position.x + ray.direction.x * tMin,
  44. ray.position.y + ray.direction.y * tMin,
  45. ray.position.z + ray.direction.z * tMin };
  46. if (fabs(intersectionPoint->x - min.x) < 0.001f) normal->x = -1.0f; // Left face
  47. else if (fabs(intersectionPoint->x - max.x) < 0.001f) normal->x = 1.0f; // Right face
  48. if (fabs(intersectionPoint->y - min.y) < 0.001f) normal->y = -1.0f; // Bottom face
  49. else if (fabs(intersectionPoint->y - max.y) < 0.001f) normal->y = 1.0f; // Top face
  50. if (fabs(intersectionPoint->z - min.z) < 0.001f) normal->z = -1.0f; // Near face
  51. else if (fabs(intersectionPoint->z - max.z) < 0.001f) normal->z = 1.0f; // Far face
  52. return true;
  53. }
  54. static void DrawTransformedCube(Matrix transform, Color color) {
  55. static Vector3 vertices[8] = {
  56. { -0.5f, -0.5f, -0.5f },
  57. { 0.5f, -0.5f, -0.5f },
  58. { 0.5f, 0.5f, -0.5f },
  59. { -0.5f, 0.5f, -0.5f },
  60. { -0.5f, -0.5f, 0.5f },
  61. { 0.5f, -0.5f, 0.5f },
  62. { 0.5f, 0.5f, 0.5f },
  63. { -0.5f, 0.5f, 0.5f },
  64. };
  65. Vector3 transformedVertices[8];
  66. for (int i = 0; i < 8; i++) {
  67. transformedVertices[i] = Vector3Transform(vertices[i], transform);
  68. }
  69. for (int i = 0; i < 4; i++) {
  70. DrawLine3D(transformedVertices[i], transformedVertices[(i + 1) % 4], color); // Bottom
  71. DrawLine3D(transformedVertices[i + 4], transformedVertices[(i + 1) % 4 + 4], color); // Top
  72. DrawLine3D(transformedVertices[i], transformedVertices[i + 4], color); // Sides
  73. }
  74. }
  75. /* === Example === */
  76. const char* Init(void)
  77. {
  78. /* --- Initialize R3D with its internal resolution --- */
  79. R3D_Init(GetScreenWidth(), GetScreenHeight(), 0);
  80. SetTargetFPS(60);
  81. /* --- Load textures --- */
  82. texture = LoadTexture(RESOURCES_PATH "decal.png");
  83. /* --- Create materials --- */
  84. materialWalls = R3D_GetDefaultMaterial();
  85. materialWalls.albedo.color = DARKGRAY;
  86. decal.material = R3D_GetDefaultMaterial();
  87. decal.material.albedo.texture = texture;
  88. decal.material.blendMode = R3D_BLEND_ALPHA;
  89. /* --- Create a plane along with the transformation matrices to place them to represent a room --- */
  90. meshPlane = R3D_GenMeshPlane(roomSize, roomSize, 1, 1);
  91. matRoom[0] = MatrixMultiply(MatrixRotateZ(90.0f * DEG2RAD), MatrixTranslate(roomSize / 2.0f, 0.0f, 0.0f));
  92. matRoom[1] = MatrixMultiply(MatrixRotateZ(-90.0f * DEG2RAD), MatrixTranslate(-roomSize / 2.0f, 0.0f, 0.0f));
  93. matRoom[2] = MatrixMultiply(MatrixRotateX(90.0f * DEG2RAD), MatrixTranslate(0.0f, 0.0f, -roomSize / 2.0f));
  94. matRoom[3] = MatrixMultiply(MatrixRotateX(-90.0f * DEG2RAD), MatrixTranslate(0.0f, 0.0f, roomSize / 2.0f));
  95. matRoom[4] = MatrixMultiply(MatrixRotateX(180.0f * DEG2RAD), MatrixTranslate(0.0f, roomSize / 2.0f, 0.0f));
  96. matRoom[5] = MatrixTranslate(0.0f, -roomSize / 2.0f, 0.0f);
  97. /* --- Setup the scene lighting --- */
  98. light = R3D_CreateLight(R3D_LIGHT_OMNI);
  99. R3D_SetLightEnergy(light, 2.0f);
  100. R3D_SetLightActive(light, true);
  101. /* --- Setup the camera --- */
  102. camera = (Camera3D){
  103. .position = (Vector3) { 0.0f, 0.0f, 0.0f },
  104. .target = (Vector3) { roomSize / 2.0f, 0.0f, 0.0f },
  105. .up = (Vector3) { 0.0f, 1.0f, 0.0f },
  106. .fovy = 70,
  107. };
  108. DisableCursor();
  109. return "[r3d] - Decal example";
  110. }
  111. void Update(float delta)
  112. {
  113. UpdateCamera(&camera, CAMERA_FREE);
  114. /* --- Find intersection point of camera target on cube --- */
  115. Ray hitRay = {
  116. .position = camera.position,
  117. .direction = Vector3Normalize(Vector3Subtract(camera.target, camera.position))
  118. };
  119. Vector3 hitPoint = { 0 };
  120. Vector3 hitNormal = { 0 };
  121. if (RayCubeIntersection(hitRay, Vector3Zero(), (Vector3) { roomSize, roomSize, roomSize }, &hitPoint, &hitNormal)) {
  122. targetPosition = hitPoint;
  123. }
  124. /* --- Create transformation matrix at intersection point --- */
  125. Matrix translation = MatrixTranslate(targetPosition.x, targetPosition.y, targetPosition.z);
  126. Matrix scaling = MatrixScale(decalScale.x, decalScale.y, decalScale.z);
  127. Matrix rotation = MatrixIdentity();
  128. if (hitNormal.x == -1.0f)
  129. rotation = MatrixRotateXYZ((Vector3) { -90.0f * DEG2RAD, 180.0f * DEG2RAD, 90.0f * DEG2RAD });
  130. else if (hitNormal.x == 1.0f)
  131. rotation = MatrixRotateXYZ((Vector3) { -90.0f * DEG2RAD, 180.0f * DEG2RAD, -90.0f * DEG2RAD });
  132. else if (hitNormal.y == -1.0f)
  133. rotation = MatrixRotateY(180.0f * DEG2RAD);
  134. else if (hitNormal.y == 1.0f)
  135. rotation = MatrixRotateZ(180.0f * DEG2RAD);
  136. else if (hitNormal.z == -1.0f)
  137. rotation = MatrixRotateX(90.0f * DEG2RAD);
  138. else if (hitNormal.z == 1.0f)
  139. rotation = MatrixRotateXYZ((Vector3) { -90.0f * DEG2RAD, 180.0f * DEG2RAD, 0 });
  140. targetDecalTransform = MatrixMultiply(MatrixMultiply(scaling, rotation), translation);
  141. /* --- Input --- */
  142. if (IsMouseButtonPressed(0)) {
  143. decalTransforms[decalIndex] = targetDecalTransform;
  144. decalIndex++;
  145. if (decalIndex >= MAXDECALS) decalIndex = 0;
  146. if (decalCount < MAXDECALS) decalCount++;
  147. }
  148. }
  149. void Draw(void)
  150. {
  151. R3D_Begin(camera);
  152. /* --- Draw the faces of our "room" --- */
  153. for (int i = 0; i < 6; i++) {
  154. R3D_DrawMesh(&meshPlane, &materialWalls, matRoom[i]);
  155. }
  156. /* --- Draw applied decals --- */
  157. if (decalCount > 0) {
  158. R3D_DrawDecalInstanced(&decal, decalTransforms, decalCount);
  159. }
  160. /* --- Draw targeting decal --- */
  161. R3D_DrawDecal(&decal, targetDecalTransform);
  162. R3D_End();
  163. /* --- Show decal projection box --- */
  164. BeginMode3D(camera);
  165. DrawTransformedCube(targetDecalTransform, WHITE);
  166. EndMode3D();
  167. DrawText("LEFT CLICK TO APPLY DECAL", 10, 10, 20, LIME);
  168. }
  169. void Close(void)
  170. {
  171. R3D_UnloadMesh(&meshPlane);
  172. R3D_Close();
  173. }