#define PGL_PREFIX_TYPES #define PORTABLEGL_IMPLEMENTATION #include #define STB_IMAGE_IMPLEMENTATION #include #include #include #include #include #include #include #define SDL_MAIN_HANDLED #include using namespace glm; struct My_Uniforms { mat4 model; mat4 view; mat4 projection; GLuint tex; }; void setup_context(); void cleanup(); bool handle_events(); unsigned int loadTexture(const char *path); void depthview_vs(float* vs_output, pgl_vec4* vertex_attribs, Shader_Builtins* builtins, void* uniforms); void depthview_fs(float* fs_input, Shader_Builtins* builtins, void* uniforms); // settings unsigned int scr_width = 640; unsigned int scr_height = 480; // camera Camera camera(vec3(0.0f, 0.0f, 3.0f)); // timing float deltaTime = 0.0f; float lastFrame = 0.0f; SDL_Window* window; SDL_Renderer* ren; SDL_Texture* tex; pix_t* bbufpix; glContext the_Context; My_Uniforms uniforms; int main() { // SDL2 and PortableGL: initialize and configure // ------------------------------ setup_context(); // tell SDL to capture our mouse SDL_SetRelativeMouseMode(SDL_TRUE); // configure global opengl state // ----------------------------- glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); // Create our shader programs and set uniform pointer for each // ----------------------------------------------------------- GLenum smooth[] = { PGL_SMOOTH2 }; GLuint shader = pglCreateProgram(depthview_vs, depthview_fs, 2, smooth, GL_FALSE); glUseProgram(shader); pglSetUniform(&uniforms); // set up vertex data (and buffer(s)) and configure vertex attributes // ------------------------------------------------------------------ float cubeVertices[] = { // positions // texture Coords -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f }; float planeVertices[] = { // positions // texture Coords (note we set these higher than 1 (together with GL_REPEAT as texture wrapping mode). this will cause the floor texture to repeat) 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, -5.0f, -0.5f, 5.0f, 0.0f, 0.0f, -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, 5.0f, -0.5f, 5.0f, 2.0f, 0.0f, -5.0f, -0.5f, -5.0f, 0.0f, 2.0f, 5.0f, -0.5f, -5.0f, 2.0f, 2.0f }; // cube VAO unsigned int cubeVAO, cubeVBO; glGenVertexArrays(1, &cubeVAO); glGenBuffers(1, &cubeVBO); glBindVertexArray(cubeVAO); glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 0); glEnableVertexAttribArray(1); pglVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 3 * sizeof(float)); glBindVertexArray(0); // plane VAO unsigned int planeVAO, planeVBO; glGenVertexArrays(1, &planeVAO); glGenBuffers(1, &planeVBO); glBindVertexArray(planeVAO); glBindBuffer(GL_ARRAY_BUFFER, planeVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), &planeVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 0); glEnableVertexAttribArray(1); pglVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), 3 * sizeof(float)); glBindVertexArray(0); // load textures // ------------- unsigned int cubeTexture = loadTexture(FileSystem::getPath("resources/textures/marble.jpg").c_str()); unsigned int floorTexture = loadTexture(FileSystem::getPath("resources/textures/metal.png").c_str()); // render loop // ----------- while (true) { // per-frame time logic // -------------------- int currentFrame = SDL_GetTicks(); deltaTime = (currentFrame - lastFrame)/1000.0f; lastFrame = currentFrame; // input // ----- if (handle_events()) break; // render // ------ glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); mat4 model = mat4(1.0f); uniforms.view = camera.GetViewMatrix(); uniforms.projection = perspective(radians(camera.Zoom), (float)scr_width / (float)scr_height, 0.1f, 100.0f); // cubes glBindVertexArray(cubeVAO); uniforms.tex = cubeTexture; uniforms.model = translate(model, vec3(-1.0f, 0.0f, -1.0f)); glDrawArrays(GL_TRIANGLES, 0, 36); model = mat4(1.0f); uniforms.model = translate(model, vec3(2.0f, 0.0f, 0.0f)); glDrawArrays(GL_TRIANGLES, 0, 36); // floor glBindVertexArray(planeVAO); uniforms.tex = floorTexture; uniforms.model = mat4(1.0f); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); // SDL2: blit texture (ie latest rendered frame) to screen // ------------------------------------------------------------------------------- SDL_UpdateTexture(tex, NULL, bbufpix, scr_width * sizeof(pix_t)); SDL_RenderCopy(ren, tex, NULL, NULL); SDL_RenderPresent(ren); } // optional: de-allocate all resources once they've outlived their purpose: // ------------------------------------------------------------------------ glDeleteVertexArrays(1, &cubeVAO); glDeleteVertexArrays(1, &planeVAO); glDeleteBuffers(1, &cubeVBO); glDeleteBuffers(1, &planeVBO); // SDL and PortableGL cleanup // ------------------------------------------------------------------ cleanup(); return 0; } // process all input: Poll for events reacting to ones we care about // --------------------------------------------------------------------------------------------------------- bool handle_events() { SDL_Event event; SDL_Scancode sc; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: return true; case SDL_KEYDOWN: sc = event.key.keysym.scancode; switch (sc) { case SDL_SCANCODE_ESCAPE: return true; /* case SDL_SCANCODE_W: camera.ProcessKeyboard(FORWARD, deltaTime); break; case SDL_SCANCODE_S: camera.ProcessKeyboard(BACKWARD, deltaTime); break; case SDL_SCANCODE_A: camera.ProcessKeyboard(LEFT, deltaTime); break; case SDL_SCANCODE_D: camera.ProcessKeyboard(RIGHT, deltaTime); break; */ default: ; } break; //sdl_keydown case SDL_WINDOWEVENT: switch (event.window.event) { case SDL_WINDOWEVENT_RESIZED: scr_width = event.window.data1; scr_height = event.window.data2; pglResizeFramebuffer(scr_width, scr_height); bbufpix = (pix_t*)pglGetBackBuffer(); glViewport(0, 0, scr_width, scr_height); SDL_DestroyTexture(tex); tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, scr_width, scr_height); break; } break; case SDL_MOUSEMOTION: { float dx = event.motion.xrel; float dy = -event.motion.yrel; // reversed since y coordinates go from bottom to top camera.ProcessMouseMovement(dx, dy); } break; case SDL_MOUSEWHEEL: camera.ProcessMouseScroll(event.wheel.y); break; } } const Uint8 *state = SDL_GetKeyboardState(NULL); if (state[SDL_SCANCODE_W]) { camera.ProcessKeyboard(FORWARD, deltaTime); } if (state[SDL_SCANCODE_S]) { camera.ProcessKeyboard(BACKWARD, deltaTime); } if (state[SDL_SCANCODE_A]) { camera.ProcessKeyboard(LEFT, deltaTime); } if (state[SDL_SCANCODE_D]) { camera.ProcessKeyboard(RIGHT, deltaTime); } return false; } /* // glfw: whenever the window size changed (by OS or user resize) this callback function executes // --------------------------------------------------------------------------------------------- void framebuffer_size_callback(GLFWwindow* window, int width, int height) { // make sure the viewport matches the new window dimensions; note that width and // height will be significantly larger than specified on retina displays. glViewport(0, 0, width, height); } */ void setup_context() { // Initialize SDL2 and create window SDL_SetMainReady(); if (SDL_Init(SDL_INIT_VIDEO)) { std::cout << "SDL_Init error: " << SDL_GetError() << "\n"; exit(0); } window = SDL_CreateWindow("LearnPortablGL", 100, 100, scr_width, scr_height, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); if (!window) { std::cerr << "Failed to create window\n"; SDL_Quit(); exit(0); } // Create Software Renderer and texture ren = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE); tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, scr_width, scr_height); // Initialize and set PGL context if (!init_glContext(&the_Context, &bbufpix, scr_width, scr_height)) { puts("Failed to initialize glContext"); exit(0); } set_glContext(&the_Context); } void depthview_vs(float* vs_output, pgl_vec4* vertex_attribs, Shader_Builtins* builtins, void* uniforms) { My_Uniforms* u = (My_Uniforms*)uniforms; mat4 model = u->model; mat4 view = u->view; mat4 projection = u->projection; vec4 aPos = ((vec4*)vertex_attribs)[0]; *(vec4*)&builtins->gl_Position = projection * view * model * aPos; } float near = 0.1f; float far = 100.0f; inline float LinearizeDepth(float depth) { float z = depth * 2.0f - 1.0f; // back to NDC return (2.0f * near * far) / (far + near - z * (far - near)); } void depthview_fs(float* fs_input, Shader_Builtins* builtins, void* uniforms) { // could also use builtins->gl_FragDepth float depth = LinearizeDepth(builtins->gl_FragCoord.z) / far; //divide by far to get depth in range [0,1] for visualization purposes *(vec4*)&builtins->gl_FragColor = vec4(depth, depth, depth, 1.0f); } void cleanup() { free_glContext(&the_Context); SDL_DestroyTexture(tex); SDL_DestroyRenderer(ren); SDL_DestroyWindow(window); SDL_Quit(); } // utility function for loading a 2D texture from file // --------------------------------------------------- unsigned int loadTexture(char const * path) { unsigned int textureID; glGenTextures(1, &textureID); int width, height, nrComponents; unsigned char *data = stbi_load(path, &width, &height, &nrComponents, STBI_rgb_alpha); if (data) { GLenum format; /* if (nrComponents == 1) format = GL_RED; else if (nrComponents == 3) format = GL_RGB; else if (nrComponents == 4) format = GL_RGBA; */ format = GL_RGBA; glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); stbi_image_free(data); } else { std::cout << "Texture failed to load at path: " << path << std::endl; stbi_image_free(data); } return textureID; }