Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

Render.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /*!
  2. * \file src/Render.cpp
  3. * \brief World Renderer
  4. *
  5. * \author Mongoose
  6. * \author xythobuz
  7. */
  8. #include <fstream>
  9. #include <sstream>
  10. #include "global.h"
  11. #include "BoundingBox.h"
  12. #include "BoundingSphere.h"
  13. #include "Camera.h"
  14. #include "Log.h"
  15. #include "Menu.h"
  16. #include "Selector.h"
  17. #include "StaticMesh.h"
  18. #include "World.h"
  19. #include "system/Shader.h"
  20. #include "system/Window.h"
  21. #include "Render.h"
  22. #include <glm/gtc/matrix_transform.hpp>
  23. #include <glbinding/gl/gl.h>
  24. #include "imgui/imgui.h"
  25. #include "stb/stb_image_write.h"
  26. RenderMode Render::mode = RenderMode::LoadScreen;
  27. std::vector<RoomRenderList> Render::roomList;
  28. bool Render::displayViewFrustum = false;
  29. bool Render::displayVisibilityCheck = false;
  30. void Render::display() {
  31. gl::glClear(gl::GL_COLOR_BUFFER_BIT | gl::GL_DEPTH_BUFFER_BIT);
  32. if (mode == RenderMode::LoadScreen) {
  33. ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f));
  34. ImGui::SetNextWindowSize(ImVec2(Window::getSize().x, Window::getSize().y));
  35. ImGui::Begin("SplashWindow", nullptr, ImGuiWindowFlags_NoTitleBar
  36. | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove
  37. | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse
  38. | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings);
  39. auto bm = TextureManager::getBufferManager(TEXTURE_SPLASH, TextureStorage::SYSTEM);
  40. ImGui::Image(bm, ImVec2(Window::getSize().x, Window::getSize().y));
  41. ImGui::End();
  42. return;
  43. }
  44. if (mode == RenderMode::Wireframe) {
  45. gl::glPolygonMode(gl::GL_FRONT_AND_BACK, gl::GL_LINE);
  46. } else {
  47. gl::glPolygonMode(gl::GL_FRONT_AND_BACK, gl::GL_FILL);
  48. }
  49. bool updated = Camera::update();
  50. glm::mat4 projection = Camera::getProjectionMatrix();
  51. glm::mat4 view = Camera::getViewMatrix();
  52. glm::mat4 VP = projection * view;
  53. if (updated || displayVisibilityCheck) {
  54. clearRoomList();
  55. buildRoomList(VP);
  56. }
  57. for (int r = roomList.size() - 1; r >= 0; r--) {
  58. auto& rl = roomList.at(r);
  59. //! \fixme TODO scissor to portal in screenspace to fix 4D rendering
  60. //gl::glEnable(gl::GL_SCISSOR_TEST);
  61. //gl::glScissor(rl.portalPos.x, rl.portalPos.y, rl.portalSize.x, rl.portalSize.y);
  62. //ImGui::Text("%.2f %.2f", rl.portalPos.x, rl.portalPos.y);
  63. //ImGui::Text("%.2f %.2f", rl.portalSize.x, rl.portalSize.y);
  64. //ImGui::Text("--");
  65. rl.room->display(VP);
  66. for (int i = 0; i < World::sizeEntity(); i++) {
  67. auto& e = World::getEntity(i);
  68. if (rl.room->getIndex() == e.getRoom()) {
  69. e.display(VP);
  70. }
  71. }
  72. //gl::glDisable(gl::GL_SCISSOR_TEST);
  73. }
  74. if (displayViewFrustum)
  75. Camera::displayFrustum(VP);
  76. Selector::displaySelection();
  77. BoundingBox::display();
  78. BoundingSphere::display();
  79. if (mode == RenderMode::Wireframe) {
  80. gl::glPolygonMode(gl::GL_FRONT_AND_BACK, gl::GL_FILL);
  81. }
  82. }
  83. void Render::buildRoomList(glm::mat4 VP, int room, glm::vec2 min, glm::vec2 max) {
  84. glm::vec2 halfSize = glm::vec2(Window::getSize()) / 2.0f;
  85. glm::vec2 pos = (min * halfSize) + halfSize;
  86. glm::vec2 size = (max * halfSize) + halfSize - pos;
  87. if (room < -1) {
  88. // Check if the camera currently is in a room...
  89. for (int i = 0; i < World::sizeRoom(); i++) {
  90. if (World::getRoom(i).getBoundingBox().inBox(Camera::getPosition())) {
  91. buildRoomList(VP, i);
  92. return;
  93. }
  94. }
  95. buildRoomList(VP, -1);
  96. } else if (room == -1) {
  97. // Check visibility for all rooms!
  98. for (int i = 0; i < World::sizeRoom(); i++) {
  99. if (Camera::boxInFrustum(World::getRoom(i).getBoundingBox())) {
  100. roomList.emplace_back(&World::getRoom(i), pos, size);
  101. }
  102. }
  103. } else {
  104. roomList.emplace_back(&World::getRoom(room), pos, size);
  105. if (displayVisibilityCheck) {
  106. // Display the visibility test for the portal to this room
  107. BoundingBox debugBox(glm::vec3(min, 0.0f), glm::vec3(max, 0.0f));
  108. debugBox.display(glm::mat4(1.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(0.0f, 1.0f, 0.0f));
  109. }
  110. // Check all portals leading from this room to somewhere else
  111. for (int i = 0; i < World::getRoom(room).sizePortals(); i++) {
  112. auto& portal = World::getRoom(room).getPortal(i);
  113. auto& r = World::getRoom(portal.getAdjoiningRoom());
  114. // Calculate the 2D screen-space bounding box of this portal
  115. glm::vec4 newMin, newMax;
  116. for (int c = 0; c < 4; c++) {
  117. glm::vec3 port = portal.getVertex(c);
  118. glm::vec4 vert = VP * glm::vec4(port, 1.0f);
  119. if (c == 0) {
  120. newMin = vert;
  121. newMax = vert;
  122. } else {
  123. if (vert.x < newMin.x)
  124. newMin.x = vert.x;
  125. if (vert.y < newMin.y)
  126. newMin.y = vert.y;
  127. if (vert.z < newMin.z)
  128. newMin.z = vert.z;
  129. if (vert.w < newMin.w)
  130. newMin.w = vert.w;
  131. if (vert.x > newMax.x)
  132. newMax.x = vert.x;
  133. if (vert.y > newMax.y)
  134. newMax.y = vert.y;
  135. if (vert.z > newMax.z)
  136. newMax.z = vert.z;
  137. if (vert.w > newMax.w)
  138. newMax.w = vert.w;
  139. }
  140. }
  141. // Check if the portal lies behind the player
  142. if (!((newMin.z <= newMin.w) && (newMin.z >= -newMin.w)
  143. && (newMax.z <= newMax.w) && (newMax.z >= -newMax.w))) {
  144. continue;
  145. }
  146. //! \fixme Need to check portal normal, only render if it points in our direction
  147. //if (!normalFacingUs) {
  148. // continue;
  149. //}
  150. // Check if the portal intersects the portal leading into this room
  151. if (!((min.x < (newMax.x / newMax.w)) && (max.x > (newMin.x / newMin.w))
  152. && (min.y < (newMax.y / newMax.w)) && (max.y > (newMin.y / newMin.w)))) {
  153. continue;
  154. }
  155. // Check if the connected room is in our view frustum (could be visible)
  156. if (!Camera::boxInFrustum(r.getBoundingBox())) {
  157. //continue;
  158. }
  159. // Check if this room is already in the list...
  160. bool found = false;
  161. for (int n = 0; n < roomList.size(); n++) {
  162. if (roomList.at(n).room == &r) {
  163. found = true;
  164. break;
  165. }
  166. }
  167. // ...only render it if it is not
  168. if (!found) {
  169. buildRoomList(VP, portal.getAdjoiningRoom(), glm::vec2(newMin) / newMin.w,
  170. glm::vec2(newMax) / newMax.w);
  171. }
  172. }
  173. }
  174. }
  175. void Render::screenShot(const char* filenameBase) {
  176. orAssert(filenameBase != nullptr);
  177. int w = Window::getSize().x;
  178. int h = Window::getSize().y;
  179. int sz = w * h;
  180. unsigned char* image = new unsigned char[sz * 3];
  181. gl::glReadPixels(0, 0, w, h, gl::GL_RGB, gl::GL_UNSIGNED_BYTE, image);
  182. unsigned char* buffer = new unsigned char[sz * 3];
  183. for (int x = 0; x < w; x++) {
  184. for (int y = 0; y < h; y++) {
  185. buffer[3 * (x + (y * w))] = image[3 * (x + ((h - y - 1) * w))];
  186. buffer[(3 * (x + (y * w))) + 1] = image[(3 * (x + ((h - y - 1) * w))) + 1];
  187. buffer[(3 * (x + (y * w))) + 2] = image[(3 * (x + ((h - y - 1) * w))) + 2];
  188. }
  189. }
  190. // Don't overwrite files
  191. static int count = 0;
  192. bool done = false;
  193. std::string f;
  194. while (!done) {
  195. std::ostringstream filename;
  196. filename << filenameBase << "-" << count++ << ".png";
  197. f = filename.str();
  198. std::ifstream fs(f);
  199. done = !fs.good();
  200. fs.close();
  201. }
  202. if (!stbi_write_png(f.c_str(), w, h, 3, buffer, 0)) {
  203. Log::get(LOG_ERROR) << "Error saving image \"" << f << "\"!" << Log::endl;
  204. }
  205. delete [] image;
  206. delete [] buffer;
  207. }
  208. static const int modeStringCount = 4;
  209. static const char* modeStrings[modeStringCount] = {
  210. "Splash", "Texture", "Wireframe", "Solid"
  211. };
  212. void Render::displayUI() {
  213. if (ImGui::CollapsingHeader("Render Settings##render")) {
  214. int item = 0;
  215. if (mode == RenderMode::Texture)
  216. item = 1;
  217. else if (mode == RenderMode::Wireframe)
  218. item = 2;
  219. else if (mode == RenderMode::Solid)
  220. item = 3;
  221. if (ImGui::Combo("Render Mode##render", &item, modeStrings, modeStringCount)) {
  222. if (item == 0)
  223. mode = RenderMode::LoadScreen;
  224. else if (item == 1)
  225. mode = RenderMode::Texture;
  226. else if (item == 2)
  227. mode = RenderMode::Wireframe;
  228. else if (item == 3)
  229. mode = RenderMode::Solid;
  230. }
  231. ImGui::Separator();
  232. ImGui::Text("Camera:");
  233. bool updateViewFrustum = Camera::getUpdateViewFrustum();
  234. if (ImGui::Checkbox("Update Frustum##camera", &updateViewFrustum)) {
  235. Camera::setUpdateViewFrustum(updateViewFrustum);
  236. }
  237. ImGui::SameLine();
  238. ImGui::Checkbox("Show Frustum##camera", &displayViewFrustum);
  239. ImGui::SameLine();
  240. bool keepInRoom = Camera::getKeepInRoom();
  241. if (ImGui::Checkbox("Keep in Room##camera", &keepInRoom)) {
  242. Camera::setKeepInRoom(keepInRoom);
  243. }
  244. glm::vec3 camPos = Camera::getPosition();
  245. if (ImGui::SliderFloat3("Position##camera", &camPos.x, -100000, 100000)) {
  246. Camera::setPosition(camPos);
  247. }
  248. ImGui::Separator();
  249. ImGui::Text("Bounding Boxes:");
  250. bool showBoundingBox = Room::getShowBoundingBox();
  251. if (ImGui::Checkbox("Rooms##bbox", &showBoundingBox)) {
  252. Room::setShowBoundingBox(showBoundingBox);
  253. }
  254. ImGui::SameLine();
  255. bool showBoundingBox2 = StaticMesh::getShowBoundingBox();
  256. if (ImGui::Checkbox("StaticMeshes##bbox", &showBoundingBox2)) {
  257. StaticMesh::setShowBoundingBox(showBoundingBox2);
  258. }
  259. ImGui::SameLine();
  260. bool showBoundingBox3 = Portal::getShowBoundingBox();
  261. if (ImGui::Checkbox("Portals##bbox", &showBoundingBox3)) {
  262. Portal::setShowBoundingBox(showBoundingBox3);
  263. }
  264. ImGui::SameLine();
  265. ImGui::Checkbox("VisChecks##bbox", &displayVisibilityCheck);
  266. ImGui::Separator();
  267. ImGui::Text("Renderable Objects:");
  268. ImGui::Text("Room: ");
  269. ImGui::SameLine();
  270. bool showRoomGeometry = Room::getShowRoomGeometry();
  271. if (ImGui::Checkbox("Geometry##renderroom", &showRoomGeometry)) {
  272. Room::setShowRoomGeometry(showRoomGeometry);
  273. }
  274. ImGui::SameLine();
  275. bool showRoomModels = Room::getShowRoomModels();
  276. if (ImGui::Checkbox("Models##renderroom", &showRoomModels)) {
  277. Room::setShowRoomModels(showRoomModels);
  278. }
  279. ImGui::SameLine();
  280. bool showRoomSprites = Room::getShowRoomSprites();
  281. if (ImGui::Checkbox("Sprites##renderroom", &showRoomSprites)) {
  282. Room::setShowRoomSprites(showRoomSprites);
  283. }
  284. ImGui::Text("Entity: ");
  285. ImGui::SameLine();
  286. bool showEntitySprites = Entity::getShowEntitySprites();
  287. if (ImGui::Checkbox("Sprites##renderentity", &showEntitySprites)) {
  288. Entity::setShowEntitySprites(showEntitySprites);
  289. }
  290. ImGui::SameLine();
  291. bool showEntityMeshes = Entity::getShowEntityMeshes();
  292. if (ImGui::Checkbox("Meshes##renderentity", &showEntityMeshes)) {
  293. Entity::setShowEntityMeshes(showEntityMeshes);
  294. }
  295. ImGui::SameLine();
  296. bool showEntityModels = Entity::getShowEntityModels();
  297. if (ImGui::Checkbox("Models##renderentity", &showEntityModels)) {
  298. Entity::setShowEntityModels(showEntityModels);
  299. }
  300. ImGui::Separator();
  301. if (ImGui::Button("New Splash##render")) {
  302. TextureManager::initializeSplash();
  303. }
  304. ImGui::SameLine();
  305. if (ImGui::Button("New Menu##render")) {
  306. Menu::initialize();
  307. }
  308. }
  309. }