glapp.cc (7714B)
1 /* Copyright 2013 Brian Swetland <swetland@frotz.net> 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <time.h> 19 20 /* flag opengl.h to include the extension table */ 21 #define GLXTN 22 23 #include "app.h" 24 #include "util.h" 25 26 static void gl_map_functions(void) { 27 int n; 28 for (n = 0; n < sizeof(fntb)/sizeof(fntb[0]); n++) { 29 *fntb[n].func = SDL_GL_GetProcAddress(fntb[n].name); 30 if (!(*fntb[n].func)) 31 die("cannot find func '%s'", fntb[n].name); 32 } 33 } 34 35 static void quit(void) { 36 SDL_Quit(); 37 exit(0); 38 } 39 40 void App::handleEvents(void) { 41 unsigned code; 42 SDL_Event ev; 43 44 while (SDL_PollEvent(&ev)) { 45 switch (ev.type) { 46 case SDL_WINDOWEVENT: 47 switch (ev.window.event) { 48 case SDL_WINDOWEVENT_RESIZED: 49 width = ev.window.data1; 50 height = ev.window.data2; 51 glViewport(0, 0, width, height); 52 onResize(); 53 } 54 break; 55 case SDL_KEYDOWN: 56 code = ev.key.keysym.scancode; 57 keystate[code >> 5] |= (1 << (code & 0x1F)); 58 if (code == SDL_SCANCODE_ESCAPE) 59 quit(); 60 onKeyDown(code); 61 break; 62 case SDL_KEYUP: 63 code = ev.key.keysym.scancode; 64 keystate[code >> 5] &= ~(1 << (code & 0x1F)); 65 onKeyUp(code); 66 break; 67 case SDL_QUIT: 68 quit(); 69 } 70 } 71 } 72 73 void App::setOptions(int argc, char **argv) { 74 char *x; 75 argc--; 76 argv++; 77 while (argc--) { 78 if (!strcmp("-nosync", argv[0])) { 79 _vsync = 0; 80 } else if (!strcmp("-fullscreen", argv[0])) { 81 _fullscreen = 1; 82 } else if (!strcmp("-fs", argv[0])) { 83 _fullscreen = 1; 84 } else if (isdigit(argv[0][0]) && (x = strchr(argv[0],'x'))) { 85 width = atoi(argv[0]); 86 height = atoi(x + 1); 87 } else { 88 printx("unknown argument '%s'\n",argv[0]); 89 } 90 argv++; 91 } 92 } 93 94 static void dump_gl_params(void) { 95 #define GGI(name) { int n = -1; glGetIntegerv(GL_##name, &n); printx(#name ": %d\n", n); } 96 97 GGI(MAX_TEXTURE_SIZE); 98 GGI(MAX_3D_TEXTURE_SIZE); 99 GGI(MAX_RECTANGLE_TEXTURE_SIZE); 100 GGI(MAX_CUBE_MAP_TEXTURE_SIZE); 101 GGI(MAX_ARRAY_TEXTURE_LAYERS); 102 103 GGI(MAX_ELEMENTS_INDICES); 104 GGI(MAX_ELEMENTS_VERTICES); 105 GGI(MAX_DRAW_BUFFERS); 106 GGI(MAX_RENDERBUFFER_SIZE); 107 108 GGI(MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS); 109 GGI(MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS); 110 GGI(MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS); 111 GGI(MAX_COMBINED_UNIFORM_BLOCKS); 112 GGI(MAX_COMBINED_TEXTURE_IMAGE_UNITS); 113 114 GGI(MAX_VERTEX_ATTRIBS); 115 GGI(MAX_VERTEX_OUTPUT_COMPONENTS); 116 GGI(MAX_VERTEX_UNIFORM_BLOCKS); 117 GGI(MAX_VERTEX_UNIFORM_COMPONENTS); 118 GGI(MAX_VERTEX_TEXTURE_IMAGE_UNITS); 119 120 GGI(MAX_GEOMETRY_INPUT_COMPONENTS); 121 GGI(MAX_GEOMETRY_OUTPUT_COMPONENTS); 122 GGI(MAX_GEOMETRY_UNIFORM_BLOCKS); 123 GGI(MAX_GEOMETRY_UNIFORM_COMPONENTS); 124 GGI(MAX_GEOMETRY_TEXTURE_IMAGE_UNITS); 125 126 GGI(MAX_VARYING_COMPONENTS); 127 GGI(MAX_VARYING_FLOATS); 128 GGI(MAX_FRAGMENT_INPUT_COMPONENTS); 129 GGI(MAX_FRAGMENT_UNIFORM_BLOCKS); 130 GGI(MAX_FRAGMENT_UNIFORM_COMPONENTS); 131 GGI(MAX_TEXTURE_IMAGE_UNITS); 132 133 GGI(MAX_UNIFORM_BUFFER_BINDINGS); 134 GGI(MAX_UNIFORM_BLOCK_SIZE); 135 GGI(UNIFORM_BUFFER_OFFSET_ALIGNMENT); 136 137 GGI(NUM_EXTENSIONS); 138 } 139 140 static const char *dbg_source(GLenum n) { 141 switch (n) { 142 case GL_DEBUG_SOURCE_API_ARB: return "api"; 143 case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: return "compiler"; 144 case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: return "winsys"; 145 case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: return "3rdpty"; 146 case GL_DEBUG_SOURCE_APPLICATION_ARB: return "app"; 147 case GL_DEBUG_SOURCE_OTHER_ARB: return "other"; 148 default: return "unknown"; 149 } 150 } 151 static const char *dbg_type(GLenum n) { 152 switch (n) { 153 case GL_DEBUG_TYPE_ERROR_ARB: return "error"; 154 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: return "undef"; 155 case GL_DEBUG_TYPE_PERFORMANCE_ARB: return "perf"; 156 case GL_DEBUG_TYPE_PORTABILITY_ARB: return "portability"; 157 case GL_DEBUG_TYPE_OTHER_ARB: return "other"; 158 default: return "unknown"; 159 } 160 } 161 static const char *dbg_severity(GLenum n) { 162 switch (n) { 163 case GL_DEBUG_SEVERITY_HIGH_ARB: return "high"; 164 case GL_DEBUG_SEVERITY_MEDIUM_ARB: return "medium"; 165 case GL_DEBUG_SEVERITY_LOW_ARB: return "low"; 166 default: return "unknown"; 167 } 168 } 169 static void APIENTRY dbg_callback(GLenum source, GLenum type, GLuint id, GLenum severity, 170 GLsizei length, const GLchar *message, GLvoid *cookie) { 171 #if VERBOSE 172 error("%s: %s: %x: %s: %s", 173 dbg_source(source), dbg_type(type), id, 174 dbg_severity(severity), message); 175 #else 176 error("GL: %s", message); 177 #endif 178 } 179 180 void App::fullscreen(int yes) { 181 if (yes) { 182 SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN); 183 _fullscreen = 1; 184 } else { 185 SDL_SetWindowFullscreen(win, 0); 186 _fullscreen = 0; 187 } 188 } 189 190 int App::start(void) { 191 memset(keystate, 0, sizeof(keystate)); 192 193 if (SDL_Init(SDL_INIT_VIDEO)) 194 die("sdl video init failed"); 195 196 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); 197 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); 198 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); 199 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); 200 201 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); 202 SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32); 203 204 /* enable vsync */ 205 //SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, _vsync); 206 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, _vsync); 207 208 unsigned flags = SDL_WINDOW_OPENGL; 209 if (_fullscreen) 210 flags |= SDL_WINDOW_FULLSCREEN; 211 //flags |= SDL_WINDOW_RESIZABLE; 212 213 win = SDL_CreateWindow("Application", 214 SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 215 width, height, flags); 216 217 SDL_GetWindowSize(win, &width, &height); 218 printx("Window is %d x %d.\n", width, height); 219 220 int minor = 3; 221 while (minor > 0) { 222 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 223 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor); 224 glcontext = SDL_GL_CreateContext(win); 225 if (glcontext) 226 break; 227 minor--; 228 } 229 if (!glcontext) { 230 printx("cannot obtain OpenGL 3.1+ context\n"); 231 exit(1); 232 } else { 233 printx("using OpenGL 3.%d\n", minor); 234 /* todo: verify extension availability */ 235 } 236 237 gl_map_functions(); 238 239 { // TODO: filter or disable in release mode 240 PFNGLDEBUGMESSAGECALLBACKARBPROC fn; 241 fn = (PFNGLDEBUGMESSAGECALLBACKARBPROC) 242 SDL_GL_GetProcAddress("glDebugMessageCallbackARB"); 243 if (fn) { 244 fn(dbg_callback, NULL); 245 glEnable(GL_DEBUG_OUTPUT); 246 // glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); 247 } else { 248 printx("warning: no glDebugMessageCallbackARB()\n"); 249 } 250 } 251 252 printx("Vender: %s\n", glGetString(GL_VENDOR)); 253 printx("Renderer: %s\n", glGetString(GL_RENDERER)); 254 printx("GL Version: %s\n", glGetString(GL_VERSION)); 255 printx("GLSL Version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION)); 256 257 dump_gl_params(); 258 259 SDL_GL_SetSwapInterval(_vsync); 260 261 if (init()) 262 return -1; 263 264 time_t t0, t1; 265 unsigned count; 266 t0 = t1 = time(NULL); 267 count = 0; 268 269 for (;;) { 270 handleEvents(); 271 272 unsigned b = SDL_GetRelativeMouseState(&mouseDX, &mouseDY); 273 mouseBTN = (b & 1) | ((b & 2) << 1) | ((b & 4) >> 1); 274 275 render(); 276 277 if (_vsync) { 278 SDL_GL_SwapWindow(win); 279 } else { 280 glFlush(); 281 } 282 count++; 283 t1 = time(NULL); 284 if (t0 != t1) { 285 fps = count; 286 count = 0; 287 t0 = t1; 288 } 289 } 290 return -1; 291 } 292 293 App::App() : width(800), height(600), _vsync(1), _fullscreen(0) { 294 } 295 296 App::~App() { 297 } 298 299 void init_io(void); 300 301 int main(int argc, char **argv) { 302 init_io(); 303 return App::__main(argc, argv); 304 } 305 306 int App::__main(int argc, char **argv) { 307 App *app = createApp(); 308 app->setOptions(argc, argv); 309 app->start(); 310 app->release(); 311 return 0; 312 } 313