graphics

experiments with opengl3.2/ogles3.3 on linux and win7
git clone http://frotz.net/git/graphics.git
Log | Files | Refs

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