1//======================================================================== 2// Multisample anti-aliasing test 3// Copyright (c) Camilla Löwy <elmindreda@glfw.org> 4// 5// This software is provided 'as-is', without any express or implied 6// warranty. In no event will the authors be held liable for any damages 7// arising from the use of this software. 8// 9// Permission is granted to anyone to use this software for any purpose, 10// including commercial applications, and to alter it and redistribute it 11// freely, subject to the following restrictions: 12// 13// 1. The origin of this software must not be misrepresented; you must not 14// claim that you wrote the original software. If you use this software 15// in a product, an acknowledgment in the product documentation would 16// be appreciated but is not required. 17// 18// 2. Altered source versions must be plainly marked as such, and must not 19// be misrepresented as being the original software. 20// 21// 3. This notice may not be removed or altered from any source 22// distribution. 23// 24//======================================================================== 25// 26// This test renders two high contrast, slowly rotating quads, one aliased 27// and one (hopefully) anti-aliased, thus allowing for visual verification 28// of whether MSAA is indeed enabled 29// 30//======================================================================== 31 32#define GLAD_GL_IMPLEMENTATION 33#include <glad/gl.h> 34#define GLFW_INCLUDE_NONE 35#include <GLFW/glfw3.h> 36 37#if defined(_MSC_VER) 38 // Make MS math.h define M_PI 39 #define _USE_MATH_DEFINES 40#endif 41 42#include "linmath.h" 43 44#include <stdio.h> 45#include <stdlib.h> 46 47#include "getopt.h" 48 49static const vec2 vertices[4] = 50{ 51 { -0.6f, -0.6f }, 52 { 0.6f, -0.6f }, 53 { 0.6f, 0.6f }, 54 { -0.6f, 0.6f } 55}; 56 57static const char* vertex_shader_text = 58"#version 110\n" 59"uniform mat4 MVP;\n" 60"attribute vec2 vPos;\n" 61"void main()\n" 62"{\n" 63" gl_Position = MVP * vec4(vPos, 0.0, 1.0);\n" 64"}\n"; 65 66static const char* fragment_shader_text = 67"#version 110\n" 68"void main()\n" 69"{\n" 70" gl_FragColor = vec4(1.0);\n" 71"}\n"; 72 73static void error_callback(int error, const char* description) 74{ 75 fprintf(stderr, "Error: %s\n", description); 76} 77 78static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) 79{ 80 if (action != GLFW_PRESS) 81 return; 82 83 switch (key) 84 { 85 case GLFW_KEY_SPACE: 86 glfwSetTime(0.0); 87 break; 88 case GLFW_KEY_ESCAPE: 89 glfwSetWindowShouldClose(window, GLFW_TRUE); 90 break; 91 } 92} 93 94static void usage(void) 95{ 96 printf("Usage: msaa [-h] [-s SAMPLES]\n"); 97} 98 99int main(int argc, char** argv) 100{ 101 int ch, samples = 4; 102 GLFWwindow* window; 103 GLuint vertex_buffer, vertex_shader, fragment_shader, program; 104 GLint mvp_location, vpos_location; 105 106 while ((ch = getopt(argc, argv, "hs:")) != -1) 107 { 108 switch (ch) 109 { 110 case 'h': 111 usage(); 112 exit(EXIT_SUCCESS); 113 case 's': 114 samples = atoi(optarg); 115 break; 116 default: 117 usage(); 118 exit(EXIT_FAILURE); 119 } 120 } 121 122 glfwSetErrorCallback(error_callback); 123 124 if (!glfwInit()) 125 exit(EXIT_FAILURE); 126 127 if (samples) 128 printf("Requesting MSAA with %i samples\n", samples); 129 else 130 printf("Requesting that MSAA not be available\n"); 131 132 glfwWindowHint(GLFW_SAMPLES, samples); 133 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); 134 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); 135 136 window = glfwCreateWindow(800, 400, "Aliasing Detector", NULL, NULL); 137 if (!window) 138 { 139 glfwTerminate(); 140 exit(EXIT_FAILURE); 141 } 142 143 glfwSetKeyCallback(window, key_callback); 144 145 glfwMakeContextCurrent(window); 146 gladLoadGL(glfwGetProcAddress); 147 glfwSwapInterval(1); 148 149 glGetIntegerv(GL_SAMPLES, &samples); 150 if (samples) 151 printf("Context reports MSAA is available with %i samples\n", samples); 152 else 153 printf("Context reports MSAA is unavailable\n"); 154 155 glGenBuffers(1, &vertex_buffer); 156 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); 157 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 158 159 vertex_shader = glCreateShader(GL_VERTEX_SHADER); 160 glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL); 161 glCompileShader(vertex_shader); 162 163 fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); 164 glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL); 165 glCompileShader(fragment_shader); 166 167 program = glCreateProgram(); 168 glAttachShader(program, vertex_shader); 169 glAttachShader(program, fragment_shader); 170 glLinkProgram(program); 171 172 mvp_location = glGetUniformLocation(program, "MVP"); 173 vpos_location = glGetAttribLocation(program, "vPos"); 174 175 glEnableVertexAttribArray(vpos_location); 176 glVertexAttribPointer(vpos_location, 2, GL_FLOAT, GL_FALSE, 177 sizeof(vertices[0]), (void*) 0); 178 179 while (!glfwWindowShouldClose(window)) 180 { 181 float ratio; 182 int width, height; 183 mat4x4 m, p, mvp; 184 const double angle = glfwGetTime() * M_PI / 180.0; 185 186 glfwGetFramebufferSize(window, &width, &height); 187 ratio = width / (float) height; 188 189 glViewport(0, 0, width, height); 190 glClear(GL_COLOR_BUFFER_BIT); 191 192 glUseProgram(program); 193 194 mat4x4_ortho(p, -ratio, ratio, -1.f, 1.f, 0.f, 1.f); 195 196 mat4x4_translate(m, -1.f, 0.f, 0.f); 197 mat4x4_rotate_Z(m, m, (float) angle); 198 mat4x4_mul(mvp, p, m); 199 200 glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) mvp); 201 glDisable(GL_MULTISAMPLE); 202 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 203 204 mat4x4_translate(m, 1.f, 0.f, 0.f); 205 mat4x4_rotate_Z(m, m, (float) angle); 206 mat4x4_mul(mvp, p, m); 207 208 glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) mvp); 209 glEnable(GL_MULTISAMPLE); 210 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 211 212 glfwSwapBuffers(window); 213 glfwPollEvents(); 214 } 215 216 glfwDestroyWindow(window); 217 218 glfwTerminate(); 219 exit(EXIT_SUCCESS); 220} 221 222