main.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. 
  2. #include <limits>
  3. #include "../../DFPSR/includeFramework.h"
  4. using namespace dsr;
  5. // Get the application folder when possible, falling back on current directory on systems not offering the feature.
  6. const String applicationFolder = file_getApplicationFolder();
  7. const String mediaFolder = file_combinePaths(applicationFolder, U"media");
  8. static BasicResourcePool pool(mediaFolder);
  9. // Global variables
  10. float distance = 4.0f;
  11. bool running = true;
  12. bool useOrthogonalCamera = false;
  13. bool useDepthBuffer = true;
  14. bool debugDrawnTriangles = false;
  15. bool debugOccluders = false;
  16. // The window handle
  17. Window window;
  18. int createCubePart(Model model, const FVector3D &min, const FVector3D &max) {
  19. // Add positions
  20. model_addPoint(model, FVector3D(min.x, min.y, min.z)); // 0: Left-down-near
  21. model_addPoint(model, FVector3D(min.x, min.y, max.z)); // 1: Left-down-far
  22. model_addPoint(model, FVector3D(min.x, max.y, min.z)); // 2: Left-up-near
  23. model_addPoint(model, FVector3D(min.x, max.y, max.z)); // 3: Left-up-far
  24. model_addPoint(model, FVector3D(max.x, min.y, min.z)); // 4: Right-down-near
  25. model_addPoint(model, FVector3D(max.x, min.y, max.z)); // 5: Right-down-far
  26. model_addPoint(model, FVector3D(max.x, max.y, min.z)); // 6: Right-up-near
  27. model_addPoint(model, FVector3D(max.x, max.y, max.z)); // 7: Right-up-far
  28. // Create a part for the polygons
  29. int part = model_addEmptyPart(model, U"cube");
  30. // Polygons using default texture coordinates on the 4 corners of the texture
  31. model_addQuad(model, part, 3, 2, 0, 1); // Left quad
  32. model_addQuad(model, part, 6, 7, 5, 4); // Right quad
  33. model_addQuad(model, part, 2, 6, 4, 0); // Front quad
  34. model_addQuad(model, part, 7, 3, 1, 5); // Back quad
  35. model_addQuad(model, part, 3, 7, 6, 2); // Top quad
  36. model_addQuad(model, part, 0, 4, 5, 1); // Bottom quad
  37. return part;
  38. }
  39. Model createCubeModel(const FVector3D &min, const FVector3D &max) {
  40. Model result = model_create();
  41. createCubePart(result, min, max);
  42. return result;
  43. }
  44. DSR_MAIN_CALLER(dsrMain)
  45. void dsrMain(List<String> args) {
  46. // Create a window
  47. window = window_create(U"David Piuva's Software Renderer - Cube example", 1600, 900);
  48. // Load an interface to the window
  49. window_loadInterfaceFromFile(window, file_combinePaths(mediaFolder, U"interface.lof"));
  50. // Tell the application to terminate when the window is closed
  51. window_setCloseEvent(window, []() {
  52. running = false;
  53. });
  54. // Get whole window key events
  55. window_setKeyboardEvent(window, [](const KeyboardEvent& event) {
  56. if (event.keyboardEventType == KeyboardEventType::KeyDown) {
  57. DsrKey key = event.dsrKey;
  58. if (key >= DsrKey_1 && key <= DsrKey_9) {
  59. window_setPixelScale(window, key - DsrKey_0);
  60. } else if (key == DsrKey_F11) {
  61. window_setFullScreen(window, !window_isFullScreen(window));
  62. } else if (key == DsrKey_Escape) {
  63. running = false;
  64. }
  65. }
  66. });
  67. // Get component handles
  68. Component mainPanel = window_findComponentByName(window, U"mainPanel", true);
  69. Component buttonA = window_findComponentByName(window, U"buttonA", true);
  70. Component buttonB = window_findComponentByName(window, U"buttonB", true);
  71. Component buttonC = window_findComponentByName(window, U"buttonC", true);
  72. Component buttonD = window_findComponentByName(window, U"buttonD", true);
  73. // Connect components with actions
  74. component_setMouseMoveEvent(mainPanel, [](const MouseEvent& event) {
  75. distance = event.position.y / (float)window_getCanvasHeight(window) * 20.0f + 0.01f;
  76. });
  77. component_setPressedEvent(buttonA, []() {
  78. useOrthogonalCamera = !useOrthogonalCamera;
  79. });
  80. component_setPressedEvent(buttonB, []() {
  81. useDepthBuffer = !useDepthBuffer;
  82. });
  83. component_setPressedEvent(buttonC, []() {
  84. debugOccluders = !debugOccluders;
  85. });
  86. component_setPressedEvent(buttonD, []() {
  87. debugDrawnTriangles = !debugDrawnTriangles;
  88. });
  89. // Create a cube model
  90. Model cubeModel = createCubeModel(FVector3D(-0.5f), FVector3D(0.5f));
  91. model_setDiffuseMapByName(cubeModel, 0, pool, "RGB");
  92. model_setFilter(cubeModel, Filter::Alpha);
  93. // Import models
  94. // TODO: Load write protected models from a resource pool
  95. Model crateModel = importFromContent_DMF1(string_load(file_combinePaths(mediaFolder, U"Model_Crate.dmf")), pool);
  96. Model barrelModel = importFromContent_DMF1(string_load(file_combinePaths(mediaFolder, U"Model_Barrel.dmf")), pool);
  97. Model testModel = importFromContent_DMF1(string_load(file_combinePaths(mediaFolder, U"Model_Test.dmf")), pool);
  98. // Create a renderer for multi-threading
  99. Renderer worker = renderer_create();
  100. while(running) {
  101. double startTime;
  102. window_executeEvents(window);
  103. // Request buffers after executing the events, to get newly allocated buffers after resize events
  104. auto colorBuffer = window_getCanvas(window);
  105. auto depthBuffer = window_getDepthBuffer(window);
  106. // Get target size
  107. int targetWidth = image_getWidth(colorBuffer);
  108. int targetHeight = image_getHeight(colorBuffer);
  109. // Paint the background color
  110. startTime = time_getSeconds();
  111. // TODO: Make a SIMD vectorized color fill for non-uniform bytes
  112. // Round the start location up to 16-bytes and the end location down to 16-bytes
  113. // Use regular assignments for the non-padding leftover pixels in sub-images
  114. image_fill(colorBuffer, ColorRgbaI32(160, 180, 200, 255));
  115. printText("Fill sky: ", (time_getSeconds() - startTime) * 1000.0, " ms\n");
  116. // Update the depth buffer
  117. startTime = time_getSeconds();
  118. // Clear the buffer
  119. if (useOrthogonalCamera) {
  120. image_fill(depthBuffer, std::numeric_limits<float>::infinity()); // Infinite depth
  121. } else {
  122. image_fill(depthBuffer, 0.0f); // Infinite reciprocal depth using zero
  123. }
  124. printText("Clear depth: ", (time_getSeconds() - startTime) * 1000.0, " ms\n");
  125. // Create a camera
  126. const double speed = 0.2f;
  127. double timer = time_getSeconds() * speed;
  128. FVector3D cameraPosition = FVector3D(sin(timer) * distance, 2, cos(timer) * distance);
  129. FMatrix3x3 cameraRotation = FMatrix3x3::makeAxisSystem(-cameraPosition, FVector3D(0.0f, 1.0f, 0.0f));
  130. Camera camera = useOrthogonalCamera ?
  131. Camera::createOrthogonal(Transform3D(cameraPosition, cameraRotation), targetWidth, targetHeight, 8.0f) :
  132. Camera::createPerspective(Transform3D(cameraPosition, cameraRotation), targetWidth, targetHeight);
  133. Transform3D testLocation(FVector3D(0.0f, -3.0f, 0.0f), FMatrix3x3(3.0f));
  134. Transform3D crateLocation(FVector3D(sin(timer * 0.36) * 0.21, sin(timer * 1.4) * 0.8, sin(timer * 0.43) * 0.17), FMatrix3x3(4.0f));
  135. Transform3D barrelLocation(FVector3D(sin(timer * 2.36) * 4.6, sin(timer * 3.45) * 4.6, sin(timer * 2.14 + 3.6) * 4.6), FMatrix3x3(4.0f));
  136. Transform3D cubeLocation(FVector3D(sin(timer * 4.37) * 2.6, sin(timer * 2.64) * 2.6, sin(timer * 3.34 + 2.7) * 2.6), FMatrix3x3());
  137. startTime = time_getSeconds();
  138. ImageF32 depth = useDepthBuffer ? depthBuffer : ImageF32();
  139. // Begin render batch
  140. renderer_begin(worker, colorBuffer, depth);
  141. // Occluders
  142. // An occluder box is placed inside of the crate where it will not be seen
  143. renderer_occludeFromBox(worker, FVector3D(-0.15f, -0.15f, -0.15f), FVector3D(0.15f, 0.15f, 0.15f), crateLocation, camera, debugOccluders);
  144. // Solid geometry
  145. renderer_giveTask(worker, crateModel, crateLocation, camera);
  146. renderer_giveTask(worker, barrelModel, barrelLocation, camera);
  147. renderer_giveTask(worker, testModel, testLocation, camera);
  148. // Use triangles as occluders
  149. // This simpler approach to occlusion is not nearly as efficient as full shapes, but without the added work of placing occluders
  150. //renderer_occludeFromExistingTriangles(worker);
  151. // Filtered geometry
  152. renderer_giveTask(worker, cubeModel, cubeLocation, camera);
  153. // Complete render batch
  154. renderer_end(worker, debugDrawnTriangles);
  155. printText("Draw world: ", (time_getSeconds() - startTime) * 1000.0, " ms\n");
  156. startTime = time_getSeconds();
  157. window_drawComponents(window);
  158. printText("Draw GUI: ", (time_getSeconds() - startTime) * 1000.0, " ms\n");
  159. window_showCanvas(window);
  160. }
  161. }