]> gitweb.ps.run Git - subsurface_scattering/blob - src/main.cpp
ui changes
[subsurface_scattering] / src / main.cpp
1 #include <stdio.h>\r
2 #include <fstream>\r
3 \r
4 #include <GL/glew.h>\r
5 \r
6 #define GLM_ENABLE_EXPERIMENTAL\r
7 \r
8 #include <glm/glm.hpp>\r
9 #include <glm/gtx/rotate_vector.hpp>\r
10 #include <glm/gtc/matrix_transform.hpp>\r
11 #include <glm/gtc/type_ptr.hpp>\r
12 \r
13 #include <SFML/OpenGL.hpp>\r
14 #include <SFML/Graphics.hpp>\r
15 \r
16 #include <imgui.h>\r
17 #include <imgui-SFML.h>\r
18 \r
19 #include <assimp/Importer.hpp>\r
20 #include <assimp/postprocess.h>\r
21 #include <assimp/scene.h>\r
22 \r
23 struct model {\r
24   std::vector<float> vertices;\r
25   std::vector<GLuint> indices;\r
26 \r
27   void draw() {\r
28     if (VAO == 0) initVAO();\r
29     glBindVertexArray(VAO);\r
30     glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);\r
31     glBindVertexArray(0);\r
32   }\r
33 \r
34 private:\r
35   void initVAO() {\r
36     GLuint VBO;\r
37     glGenBuffers(1, &VBO);\r
38 \r
39     GLuint EBO;\r
40     glGenBuffers(1, &EBO);\r
41 \r
42     glGenVertexArrays(1, &VAO);\r
43 \r
44     glBindVertexArray(VAO);\r
45 \r
46     glBindBuffer(GL_ARRAY_BUFFER, VBO);\r
47     glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(),\r
48                 vertices.data(), GL_STATIC_DRAW);\r
49 \r
50     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);\r
51     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(),\r
52                 indices.data(), GL_STATIC_DRAW);\r
53 \r
54     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(0));\r
55     glEnableVertexAttribArray(0);\r
56     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 6, (void*)(sizeof(float) * 3));\r
57     glEnableVertexAttribArray(1);\r
58 \r
59     glBindVertexArray(0);\r
60   }\r
61   GLuint VAO = 0;\r
62 };\r
63 \r
64 \r
65 struct freecam {\r
66   glm::vec3 pos = glm::vec3(0, 0, -1);\r
67   glm::vec2 rot = glm::vec2(0, 0);\r
68 \r
69   void update(sf::Window &window) {\r
70     int mouseDeltaX = sf::Mouse::getPosition(window).x - window.getSize().x / 2;\r
71     int mouseDeltaY = sf::Mouse::getPosition(window).y - window.getSize().y / 2;\r
72 \r
73     rot.x += mouseDeltaX;\r
74     rot.y += mouseDeltaY;\r
75 \r
76     forward = glm::rotate(glm::vec3(0, 0, 1), rot.y / angleFactor, glm::vec3(1, 0, 0));\r
77     forward = glm::rotate(forward, -rot.x / angleFactor, glm::vec3(0, 1, 0));\r
78 \r
79     glm::vec3 left = glm::rotate(glm::vec3(0, 0, 1), -rot.x / angleFactor + glm::radians(90.0f), glm::vec3(0, 1, 0));\r
80 \r
81     if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::LShift))\r
82       moveFactor = 200;\r
83     else\r
84       moveFactor = 20;\r
85 \r
86     if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))\r
87       pos += forward / moveFactor;\r
88     if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))\r
89       pos -= forward / moveFactor;\r
90     if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))\r
91       pos += left / moveFactor;\r
92     if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))\r
93       pos -= left / moveFactor;\r
94 \r
95     limit();\r
96   }\r
97 \r
98   void limit() {\r
99     rot.x = fmod(rot.x, glm::radians(360.0f) * angleFactor);\r
100     rot.y = fmod(rot.y, glm::radians(360.0f) * angleFactor);\r
101   }\r
102 \r
103   glm::mat4 getViewMatrix() {\r
104     forward = glm::rotate(glm::vec3(0, 0, 1), rot.y / angleFactor, glm::vec3(1, 0, 0));\r
105     forward = glm::rotate(forward, -rot.x / angleFactor, glm::vec3(0, 1, 0));\r
106     glm::mat4 result = glm::lookAt(pos, pos + forward, up);\r
107     return result;\r
108   }\r
109 \r
110 private:\r
111   glm::vec3 forward = glm::vec3(0, 0, 1);\r
112   glm::vec3 up = glm::vec3(0, 1, 0);\r
113 \r
114   const float angleFactor = 200;\r
115   float moveFactor = 20;\r
116 };\r
117 \r
118 \r
119 struct arccam {\r
120   glm::vec2 rot = glm::vec2(0, 0);\r
121   float radius = 1;\r
122 \r
123   void update(sf::Window &window) {\r
124     int mouseDeltaX = sf::Mouse::getPosition(window).x - window.getSize().x / 2;\r
125     int mouseDeltaY = sf::Mouse::getPosition(window).y - window.getSize().y / 2;\r
126 \r
127     rot.x += mouseDeltaX;\r
128     rot.y += mouseDeltaY;\r
129 \r
130     limit(-89, 89);\r
131   }\r
132 \r
133   void limit(float minY, float maxY) {\r
134     float angleX = rot.x / angleFactor;\r
135     float angleY = rot.y / angleFactor;\r
136 \r
137     rot.x = fmod(rot.x, glm::radians(360.0f) * angleFactor);\r
138 \r
139     if (angleY > glm::radians(maxY))\r
140       rot.y = glm::radians(maxY) * angleFactor;\r
141     if (angleY < glm::radians(minY))\r
142       rot.y = glm::radians(minY) * angleFactor;\r
143   }\r
144 \r
145   glm::mat4 getViewMatrix() {\r
146     float angle = rot.y / angleFactor;\r
147   \r
148     float camY = sin(angle) * exp(radius);\r
149     float camZ = cos(angle) * exp(radius);\r
150     glm::mat4 result = glm::lookAt(glm::vec3(0.0, camY, camZ), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));\r
151     result = glm::rotate(result, rot.x / angleFactor, glm::vec3(0, 1, 0));\r
152 \r
153     return result;\r
154   }\r
155 \r
156 private:\r
157   const float angleFactor = 200;\r
158 };\r
159 \r
160 \r
161 std::string readFile(std::string filename) {\r
162   std::ifstream ifs(filename, std::ios::binary);\r
163   ifs.seekg(0, ifs.end);\r
164   long length = ifs.tellg();\r
165   ifs.seekg(0, ifs.beg);\r
166   char *buffer = (char*)malloc(length);\r
167   ifs.read(buffer, length);\r
168   ifs.close();\r
169   std::string result(buffer);\r
170   free(buffer);\r
171   return result;\r
172 }\r
173 \r
174 model loadModel(const std::string &filename) {\r
175   Assimp::Importer importer;\r
176 \r
177   const aiScene *scene = importer.ReadFile(\r
178       filename, aiProcess_CalcTangentSpace | aiProcess_Triangulate |\r
179                     aiProcess_SortByPType | aiProcess_GenSmoothNormals);\r
180 \r
181   model result;\r
182 \r
183   for (int i = 0; i < scene->mMeshes[0]->mNumVertices; i++) {\r
184     aiVector3D v = scene->mMeshes[0]->mVertices[i];\r
185     aiVector3D n = scene->mMeshes[0]->mNormals[i];\r
186     result.vertices.push_back(v.x);\r
187     result.vertices.push_back(v.y);\r
188     result.vertices.push_back(v.z);\r
189     result.vertices.push_back(n.x);\r
190     result.vertices.push_back(n.y);\r
191     result.vertices.push_back(n.z);\r
192   }\r
193 \r
194   for (int i = 0; i < scene->mMeshes[0]->mNumFaces; i++) {\r
195     aiFace f = scene->mMeshes[0]->mFaces[i];\r
196     for (int j = 0; j < f.mNumIndices; j++) {\r
197       result.indices.push_back(f.mIndices[j]);\r
198     }\r
199   }\r
200 \r
201   return result;\r
202 }\r
203 \r
204 GLuint compileShaders(const char *vertFilename, const char *fragFilename) {\r
205   GLuint vertShader = glCreateShader(GL_VERTEX_SHADER);\r
206   std::string vertSource = readFile(vertFilename);\r
207   const char *vertAddr = vertSource.c_str();\r
208   glShaderSource(vertShader, 1, &vertAddr, NULL);\r
209   glCompileShader(vertShader);\r
210 \r
211   int success;\r
212   char infoLog[512];\r
213   glGetShaderiv(vertShader, GL_COMPILE_STATUS, &success);\r
214   if (!success) {\r
215     glGetShaderInfoLog(vertShader, 512, NULL, infoLog);\r
216     printf("Error compiling vertex shader: %s\n", infoLog);\r
217   }\r
218 \r
219   GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);\r
220   std::string fragSource = readFile(fragFilename);\r
221   const char *fragAddr = fragSource.c_str();\r
222   glShaderSource(fragShader, 1, &fragAddr, NULL);\r
223   glCompileShader(fragShader);\r
224 \r
225   glGetShaderiv(fragShader, GL_COMPILE_STATUS, &success);\r
226   if (!success) {\r
227     glGetShaderInfoLog(fragShader, 512, NULL, infoLog);\r
228     printf("Error compiling fragment shader: %s\n", infoLog);\r
229   }\r
230 \r
231   // Link Shader Program\r
232 \r
233   GLuint shaderProgram = glCreateProgram();\r
234   glAttachShader(shaderProgram, vertShader);\r
235   glAttachShader(shaderProgram, fragShader);\r
236   glLinkProgram(shaderProgram);\r
237 \r
238   glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);\r
239   if (!success) {\r
240     glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);\r
241     printf("Error linking shader program: %s\n", infoLog);\r
242   }\r
243 \r
244   glDeleteShader(vertShader);\r
245   glDeleteShader(fragShader);\r
246 \r
247   return shaderProgram;\r
248 }\r
249 \r
250 \r
251 int main() {\r
252   // Window Setup\r
253 \r
254   sf::ContextSettings settings;\r
255   settings.depthBits = 24;\r
256   settings.antialiasingLevel = 0;\r
257   settings.majorVersion = 4;\r
258   settings.minorVersion = 6;\r
259 \r
260   sf::RenderWindow window(sf::VideoMode(1600, 900), "Subsurface Scattering",\r
261                     sf::Style::Default, settings);\r
262   window.setVerticalSyncEnabled(true);\r
263 \r
264   ImGui::SFML::Init(window);\r
265 \r
266   // Initialize GLEW\r
267 \r
268   if (glewInit() != GLEW_OK) {\r
269   }\r
270 \r
271   GLuint shaderProgram = compileShaders("shaders/vert.glsl", "shaders/frag.glsl");\r
272 \r
273   model m = loadModel("models/Isotrop-upperjaw.ply");\r
274 \r
275   arccam arcCam;\r
276   freecam freeCam;\r
277       \r
278   glm::vec3 lightPos(1.2f, 5.0f, 2.0f);\r
279 \r
280   // MVP\r
281 \r
282   glm::mat4 model = glm::scale(glm::mat4(1.0f), glm::vec3(0.01f, 0.01f, 0.01f));\r
283 \r
284   glm::mat4 view;\r
285 \r
286   glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)window.getSize().x / window.getSize().y, 0.001f, 1000.0f);\r
287 \r
288   struct {\r
289     bool wireframe = false;\r
290     bool freecam = false;\r
291   } options;\r
292 \r
293   sf::Clock deltaClock;\r
294 \r
295   bool prevMouse = false;\r
296 \r
297   bool running = true;\r
298   while (running) {\r
299     // Events\r
300 \r
301     sf::Event event;\r
302     while (window.pollEvent(event)) {\r
303       ImGui::SFML::ProcessEvent(event);\r
304 \r
305       if (event.type == sf::Event::EventType::Closed) {\r
306         running = false;\r
307       } else if (event.type == sf::Event::EventType::Resized) {\r
308         glViewport(0, 0, event.size.width, event.size.height);\r
309       } else if (event.type == sf::Event::EventType::KeyReleased) {\r
310         using keys = sf::Keyboard;\r
311         switch (event.key.code) {\r
312         case keys::Escape:\r
313           running = false;\r
314           break;\r
315         }\r
316       } else if (event.type == sf::Event::EventType::MouseWheelScrolled) {\r
317         if (! options.freecam) {\r
318           arcCam.radius -= event.mouseWheelScroll.delta / 5.0f;\r
319         }\r
320       }\r
321     }\r
322 \r
323     // Update\r
324 \r
325     if (sf::Mouse::isButtonPressed(sf::Mouse::Right)) {\r
326       window.setMouseCursorVisible(false);\r
327 \r
328       if (prevMouse) {\r
329         if (options.freecam)\r
330           freeCam.update(window);\r
331         else\r
332           arcCam.update(window);\r
333       }\r
334 \r
335 \r
336       sf::Mouse::setPosition(sf::Vector2i(\r
337           window.getSize().x / 2,\r
338           window.getSize().y / 2\r
339         ), window);  \r
340     } else {\r
341       window.setMouseCursorVisible(true);\r
342     }\r
343 \r
344     prevMouse = sf::Mouse::isButtonPressed(sf::Mouse::Right);\r
345 \r
346     // Render\r
347 \r
348     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\r
349 \r
350     glEnable(GL_DEPTH_TEST);\r
351 \r
352     if (options.wireframe)\r
353       glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);\r
354     else\r
355       glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\r
356 \r
357     glUseProgram(shaderProgram);\r
358     \r
359     if (options.freecam)\r
360       view = freeCam.getViewMatrix();\r
361     else\r
362       view = arcCam.getViewMatrix();\r
363     \r
364     glUniformMatrix4fv(\r
365       glGetUniformLocation(shaderProgram, "model"),\r
366       1, GL_FALSE, glm::value_ptr(model));\r
367     glUniformMatrix4fv(\r
368       glGetUniformLocation(shaderProgram, "view"),\r
369       1, GL_FALSE, glm::value_ptr(view));\r
370     glUniformMatrix4fv(\r
371       glGetUniformLocation(shaderProgram, "projection"),\r
372       1, GL_FALSE, glm::value_ptr(proj));\r
373 \r
374     glUniform3f(\r
375       glGetUniformLocation(shaderProgram, "objectColor"),\r
376       1.0f, 0.5f, 0.31f);\r
377     glUniform3f(\r
378       glGetUniformLocation(shaderProgram, "lightColor"),\r
379       1.0f, 1.0f, 1.0f);\r
380     glUniform3fv(\r
381       glGetUniformLocation(shaderProgram, "lightPos"),\r
382       1, glm::value_ptr(lightPos));\r
383 \r
384     m.draw();\r
385     \r
386     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\r
387 \r
388     ImGui::SFML::Update(window, deltaClock.restart());\r
389 \r
390     ImGui::Begin("Options");\r
391     ImGui::Checkbox("Wireframe", &options.wireframe);\r
392     ImGui::Checkbox("Free Cam", &options.freecam);\r
393     if (options.freecam) {\r
394       ImGui::LabelText("Position", "%f %f %f", freeCam.pos.x, freeCam.pos.y, freeCam.pos.z);\r
395       ImGui::LabelText("Rotation", "%f %f", freeCam.rot.x, freeCam.rot.y);\r
396       if (ImGui::Button("Reset")) {\r
397         freeCam.pos = glm::vec3(0, 0, -1);\r
398         freeCam.rot = glm::vec2(0);\r
399       }\r
400     } else {\r
401       ImGui::LabelText("Rotation", "%f %f", arcCam.rot.x, arcCam.rot.y);\r
402       ImGui::DragFloat("Radius", &arcCam.radius, 0.01f, -1.0f, 1.0f);\r
403       if (ImGui::Button("Reset")) {\r
404         arcCam.rot = glm::vec2(0);\r
405         arcCam.radius = 1;\r
406       }\r
407     }\r
408     ImGui::End();\r
409 \r
410     ImGui::SFML::Render(window);\r
411 \r
412     window.display();\r
413   }\r
414 \r
415   return 0;\r
416 }