added a camera class and created a camera that I am not using yet :p
[vkrt] / src / main.cc
1 #include <stdio.h>
2
3 #define GLFW_INCLUDE_VULKAN
4 #include <GLFW/glfw3.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include <gmath/gmath.h>
9
10 /* extern "C": vulkan framework */
11 #include "vk.h"
12 #include "util.h"
13
14 /* C++ */
15 #include "camera.h"
16
17 /**************************/
18 /* static glfw callbacks */
19 /**************************/
20
21 static void
22 clb_key(GLFWwindow *win, int key, int scancode, int action, int mods);
23
24 static void
25 clb_reshape(GLFWwindow *win, int width, int height);
26
27 static void
28 clb_motion(GLFWwindow *win, double x, double y);
29
30 static void
31 clb_mouse(GLFWwindow *win, int button, int action, int mods);
32
33 /**************************/
34 /* static functions */
35 /**************************/
36
37 /* init, cleanup, display */
38
39 static bool
40 init();
41
42 static void
43 cleanup();
44
45 static void
46 display();
47
48 /* vulkan, glfw */
49
50 static bool
51 vk_init();
52
53 static void
54 vk_cleanup();
55
56 /**************************/
57 /* static variables */
58 /**************************/
59
60 static GLFWwindow *win;
61 static bool redraw_pending;
62 static bool move_camera;
63
64 /* camera */
65 static float cam_phi = 25;
66 static float cam_theta = 0;
67 static float cam_dist = 16;
68 static Vec3 cam_pos;
69
70 static float aspect;
71 static OrbitCamera *camera;
72
73 static bool vk_enable_layers = true;
74
75 static int win_w = 800;
76 static int win_h = 600;
77
78 static struct vk_ctx vk_core;
79 static VkSurfaceKHR vk_surf;
80 static struct vk_renderer vk_rnd;
81 static struct vk_swapchain vk_chain;
82 static struct vk_semaphores vk_sema;
83 static struct vk_attachment vk_depth_att;
84 static float vk_fb_color[4] = { 0.0, 0.0, 0.5, 1.0 };
85
86 /* make array later if many cmd buffers */
87 static VkCommandBuffer vk_cmd_buf;
88
89 /* empty for as long as we hardcode the vertices in the vertex shader */
90 static struct vk_vertex_info vk_vert_info;
91
92 int main(int argc, char** argv)
93 {
94     atexit(cleanup);
95
96     if (!glfwInit()) {
97         fprintf(stderr, "Failed to initialize GLFW.\n");
98         return 1;
99     }
100
101     if (!init()) {
102         return 1;
103     }
104
105     /* reshape window once just in case */
106
107     glfwGetWindowSize(win, &win_w, &win_h);
108     clb_reshape(win, win_w, win_h);
109
110     /* event loop */
111     redraw_pending = true;
112
113     while(!glfwWindowShouldClose(win)) {
114         glfwWaitEvents();
115         if (redraw_pending) {
116             redraw_pending = false;
117             display();
118         }
119     }
120
121 #if 0
122         while(!glfwWindowShouldClose(win)) {
123                 display();
124
125                 glfwSwapBuffers(win);
126                 glfwPollEvents();
127         }
128 #endif
129
130     return 0;
131 }
132
133 /* static functions */
134
135 static bool
136 vk_init()
137 {
138     char *vsdr = 0;
139     char *fsdr = 0;
140     int vsz, fsz;
141
142     if (glfwVulkanSupported() != GLFW_TRUE) {
143         fprintf(stderr, "Vulkan is not supported on this device.\n");
144         return false;
145     }
146
147     /* create window */
148
149     glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
150     win = glfwCreateWindow(win_w, win_h, "helloworld rt", 0, 0);
151
152     if (!win) {
153         fprintf(stderr, "Failed to create GLFW window\n");
154         return false;
155     }
156
157     glfwSetKeyCallback(win, clb_key);
158
159     /* initialize Vulkan context (instance) */
160
161     if (!vk_init_ctx_for_rendering(&vk_core, true, vk_enable_layers)) {
162         fprintf(stderr, "Failed to initialize Vulkan context.\n");
163         return false;
164     }
165
166     /* create (Xcb) surface */
167
168     glfwGetFramebufferSize(win, &win_h, &win_h);
169     if (glfwCreateWindowSurface(vk_core.inst, win, 0, &vk_surf)
170             != VK_SUCCESS) {
171         fprintf(stderr, "Failed to create XCB surface.\n");
172         return false;
173     }
174
175     /* create semaphores */
176     if (!vk_create_semaphores(&vk_core, false, &vk_sema)) {
177         fprintf(stderr, "No semaphores were created.\n");
178         goto fail;
179     }
180
181     /* create swapchain */
182     if (!vk_create_swapchain(&vk_core, win_w, win_h, false, vk_surf, 0, &vk_chain)) {
183         fprintf(stderr, "No swapchain was created.\n");
184         goto fail;
185     }
186
187     if (vk_chain.swapchain == VK_NULL_HANDLE) {
188         fprintf(stderr, "Invalid swapchain handle.\n");
189         goto fail;
190     }
191
192     /* create shaders */
193     vsdr = sdr_load("data/main.vert.spv", &vsz);
194     fsdr = sdr_load("data/main.frag.spv", &fsz);
195
196     /* create depth attachment (for the moment we are going to use this
197      * for all images */
198     if (!vk_fill_image_props(&vk_core,
199                              win_w, win_h, 1,
200                              1, 1, 1,
201                              VK_FORMAT_D32_SFLOAT_S8_UINT,
202                              VK_IMAGE_TILING_OPTIMAL,
203                              VK_IMAGE_LAYOUT_UNDEFINED,
204                              VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
205                              false, true, false,
206                              &vk_depth_att.props)) {
207         fprintf(stderr, "Unsupported depth image properties\n");
208         return false;
209     }
210     if (!vk_create_image(&vk_core, &vk_depth_att.props, &vk_depth_att.obj)) {
211         fprintf(stderr, "Failed to create depth attachment.\n");
212         goto fail;
213     }
214
215     /* create renderer */
216     if (!vk_create_renderer(&vk_core,
217                             vsdr, vsz, fsdr, fsz,
218                             win_w, win_h, 1,
219                             false, false,
220                             vk_chain.num_atts, vk_chain.atts, &vk_depth_att,
221                             &vk_vert_info, &vk_rnd)) {
222         goto fail;
223     }
224
225     /* create cmd buffer */
226     if ((vk_cmd_buf = vk_create_cmd_buffer(&vk_core)) == VK_NULL_HANDLE) {
227         fprintf(stderr, "Failed to create command buffer.\n");
228         goto fail;
229     }
230
231     /* record cmd buffer */
232     if (!vk_record_cmd_buffer(&vk_core, vk_cmd_buf,
233                               &vk_rnd, 0,
234                               4, vk_fb_color,
235                               vk_chain.num_atts + 1, 0,
236                               0, 0, win_w, win_h)) {
237         fprintf(stderr, "Failed to record command buffer.\n");
238         goto fail;
239     }
240
241     free(vsdr);
242     free(fsdr);
243
244     /* set GLFW callbacks */
245
246     glfwSetWindowSizeCallback(win, clb_reshape);
247
248     glfwSetCursorPosCallback(win, clb_motion);
249     glfwSetMouseButtonCallback(win, clb_mouse);
250
251     return true;
252
253 fail:
254     free(vsdr);
255     free(fsdr);
256
257     return false;
258 }
259
260 static bool
261 init()
262 {
263     if (!vk_init()) {
264         fprintf(stderr, "Failed to initialize Vulkan structs.\n");
265         return false;
266     }
267
268     camera = new OrbitCamera;
269     return true;
270 }
271
272 static void
273 cleanup()
274 {
275     vk_cleanup();
276 }
277
278 static void
279 display()
280 {
281     uint32_t img_idx;
282     VkSubmitInfo sinfo;
283     VkPipelineStageFlags wait_stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
284         VkPresentInfoKHR pinfo;
285
286     vkAcquireNextImageKHR(vk_core.dev, vk_chain.swapchain,
287                           UINT64_MAX, vk_sema.frame_ready, 0, &img_idx);
288
289     memset(&sinfo, 0, sizeof sinfo);
290     sinfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
291     sinfo.waitSemaphoreCount = 1;
292     sinfo.pWaitSemaphores = &vk_sema.frame_ready;
293     sinfo.pWaitDstStageMask = &wait_stages;
294     sinfo.commandBufferCount = 1;
295     sinfo.pCommandBuffers = &vk_cmd_buf;
296     sinfo.signalSemaphoreCount = 1;
297         sinfo.pSignalSemaphores = &vk_sema.frame_done;
298
299     if (vkQueueSubmit(vk_core.queue, 1, &sinfo, 0) != 0) {
300         fprintf(stderr, "Failed to submit draw commands.\n");
301         abort();
302     }
303
304     memset(&pinfo, 0, sizeof pinfo);
305     pinfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
306     pinfo.waitSemaphoreCount = 1;
307     pinfo.pWaitSemaphores = &vk_sema.frame_done;
308     pinfo.swapchainCount = 1;
309     pinfo.pSwapchains = &vk_chain.swapchain;
310     pinfo.pImageIndices = &img_idx;
311
312     vkQueuePresentKHR(vk_core.queue, &pinfo);
313 }
314
315 static void
316 vk_cleanup()
317 {
318     vkQueueWaitIdle(vk_core.queue);
319
320     if (vk_cmd_buf != VK_NULL_HANDLE) {
321         vkResetCommandBuffer(vk_cmd_buf, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
322     }
323
324     vk_destroy_image(&vk_core, &vk_depth_att.obj);
325     vk_destroy_semaphores(&vk_core, &vk_sema);
326     vk_destroy_renderer(&vk_core, &vk_rnd);
327
328     if (vk_chain.swapchain) {
329         vk_destroy_swapchain(&vk_core, &vk_chain);
330         vkDestroySurfaceKHR(vk_core.inst, vk_surf, 0);
331     }
332
333     glfwDestroyWindow(win);
334
335     if (!vk_enable_layers)
336         vkFreeCommandBuffers(vk_core.dev, vk_core.cmd_pool, 1, &vk_cmd_buf);
337
338     vk_cleanup_ctx(&vk_core, vk_enable_layers);
339
340     glfwTerminate();
341 }
342
343 /* glfw callbacks */
344
345 static void
346 clb_key(GLFWwindow *win, int key, int scancode,
347         int action, int mods)
348 {
349     if (action == GLFW_PRESS) {
350         switch(key) {
351         case GLFW_KEY_ESCAPE:
352             glfwSetWindowShouldClose(win, GLFW_TRUE);
353             return;
354         case ' ':
355             move_camera = !move_camera;
356             break;
357         default:
358             break;
359         }
360     }
361 }
362
363 static void
364 clb_reshape(GLFWwindow *win,
365             int width,
366             int height)
367 {
368 }
369
370 static double prev_x, prev_y;
371 static bool button[8];
372
373 static void
374 clb_motion(GLFWwindow *win,
375            double x,
376            double y)
377 {
378         double dx = x - prev_x;
379         double dy = y - prev_y;
380
381         prev_x = x;
382         prev_y = y;
383
384         if(button[0]) {
385                 cam_theta += dx * 0.5;
386                 cam_phi += dy * 0.5;
387
388                 if(cam_phi < 0)
389                         cam_phi = 0;
390                 if(cam_phi > 90)
391                         cam_phi = 90;
392         }
393
394         if(button[1]) {
395                 cam_dist += dy * 0.1;
396                 if(cam_dist < 0.0) {
397                         cam_dist = 0.0;
398                 }
399         }
400 }
401
402 static void
403 clb_mouse(GLFWwindow *win,
404           int button,
405           int action,
406           int mods)
407 {
408 }