/* platform.c * * Platform * * Notes: assumes multisampling is always enabled * */ #include #include #include #include #include #include #include "event.h" #include "gldraw.h" #include "gltools.h" #include "luatools.h" #include "platform.h" #include "sdltools.h" #include "window.h" /* few light arrays */ const GLfloat fNoLight[] = { 0.0f, 0.0f, 0.0f, 1.0f }; const GLfloat fLowLight[] = { 0.25f, 0.25f, 0.25f, 1.0f }; const GLfloat fMedLight[] = { 0.50f, 0.50f, 0.50f, 1.0f }; const GLfloat fShinyLight[] = { 0.70f, 0.70f, 0.70f, 1.0f }; const GLfloat fBrightLight[] = { 1.0f, 1.0f, 1.0f, 1.0f }; /* light values and coordinates */ const GLfloat lightPos[] = { -10.f, 5.0f, 5.0f, 1.0f }; /* variables that should be already defined and declared for us by main program */ extern unsigned int xres_w; extern unsigned int yres_w; extern unsigned int bpp_w; extern unsigned int af_w; extern const char *window_caption; extern const char *window_icon_path; extern const unsigned int sdl_video_flags; extern unsigned int maxfps_w; void platform_init(struct platform *p) { if (!p) { fprintf(stderr, "platform: failed to initialize, parameter = NULL\n"); exit(-1); } int ret; /* Lua */ /* create new lua state */ p->L = luaL_newstate(); /* load lua libraries */ luaL_openlibs(p->L); /* initialize SDL, GLEW, and OpenGL */ load_config(p); p->screen = setup_sdl(); setup_glew(); setup_opengl(); /* add a simple timer / callback function */ p->timer_id = SDL_AddTimer(5000, sdlTimerCallback, &(p->camera)); /* apply a custom cursor */ p->my_cursor = sdlInitCursor(arrow); SDL_SetCursor(p->my_cursor); /* set the camera to <0,0,0> */ glframe_reset(&p->camera); /* setup and init the event handler */ struct event_vtbl event_tbl; memset(&event_tbl, 0, sizeof(event_tbl)); event_tbl.keydown = event_keydown; ret = event_handler_init(p, &event_tbl); if (ret == -1) { fprintf(stderr, "platform: failed to init event handler\n"); exit(-1); } /* init client */ p->client_init(p->c); } /* it's a good idea to destroy things in reverse order */ void platform_destroy(struct platform *p) { /* destroy client */ p->client_destroy(p->c); SDL_FreeSurface(p->screen); lua_close(p->L); } /* load Lua config file from the disk */ int load_config(struct platform *p) { if (!p) return -1; if ((luaLoadConfig(p->L, "config.lua") | luaFillTablePlatform(p->L, &p->config_table)) != -1) { /* print what was loaded from config.lua to stdout */ luaPrintTablePlatform(&p->config_table); /* override any globals that config.lua redefines */ if (p->config_table.xres) xres_w = p->config_table.xres; if (p->config_table.yres) yres_w = p->config_table.yres; if (p->config_table.bpp) bpp_w = p->config_table.bpp; if (p->config_table.af) af_w = p->config_table.af; if (p->config_table.name) window_caption = p->config_table.name; if (p->config_table.icon) window_icon_path = p->config_table.icon; if (p->config_table.maxfps) maxfps_w = p->config_table.maxfps; } return 0; } void setup_opengl(void) { /* setup fog */ glEnable(GL_FOG); glFogfv(GL_FOG_COLOR, fLowLight); /* set fog color to match background */ glFogf(GL_FOG_START, 4.0f); glFogf(GL_FOG_END, 20.0f); glFogi(GL_FOG_MODE, GL_LINEAR); /* fog equation */ glEnable(GL_DEPTH_TEST); /* hidden surface removal, aka Z-buffer */ glFrontFace(GL_CCW); /* counter clock-wise polygons face out */ glEnable(GL_CULL_FACE); /* do not calculate inside of a pyramid */ /* enable lighting, primitives now need to define color properties */ glEnable(GL_LIGHTING); /* global illumination, ambient RGBA intensity of the entire scene */ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fLowLight); /* setup and enable light 0 */ glLightfv(GL_LIGHT0, GL_AMBIENT, fMedLight); glLightfv(GL_LIGHT0, GL_DIFFUSE, fShinyLight); glLightfv(GL_LIGHT0, GL_SPECULAR, fBrightLight); glLightfv(GL_LIGHT0, GL_POSITION, lightPos); glEnable(GL_LIGHT0); /* set material properties to follow all glColor values */ /* all primitives specified after the glMaterial call are affected by the * last values set, until another call to glMaterial is made */ glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); /* enable color tracking, should be called after glColorMaterial */ glEnable(GL_COLOR_MATERIAL); /* set globally, sets specular reflection to a white color, * this call follows all subsequent primitives */ glMaterialfv(GL_FRONT, GL_SPECULAR, fBrightLight); /* default (0), by increasing this value you reduce the size and increase * the focus of the specular highlight, causing a shiny spot to appear */ glMateriali(GL_FRONT, GL_SHININESS, 64); if (glIsEnabled(GL_MULTISAMPLE) == GL_FALSE) { fprintf(stderr, "OpenGL error: multisampling cannot be enabled!\n"); exit(-1); } /* multisampling for polygons, conflicts with *polygon* anti-aliasing */ /* enabled by default, that's what man page says, hmmm! */ glEnable(GL_MULTISAMPLE); /* turn off AA forever, it enables blending globally, so depth test goes out * of the window, blended objects should be rendered in back to front order, * also, following lines are ignored by OpenGL if multisampling is enabled */ #if 0 /* turn on anti aliasing for points and lines */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_POINT_SMOOTH); glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); glEnable(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); #endif #if 0 /* screws up snowman, this has been replaced by superior multisampling */ glEnable(GL_POLYGON_SMOOTH); glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); #endif /* we will keep the blending function and hints though */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); /* anisotropic filtering */ if (gltQueryExtension("GL_EXT_texture_filter_anisotropic") == GL_TRUE) { GLint af_amount; glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &af_amount); printf("platform: anisotropic filtering is supported, with max amount " "of: %d\n", af_amount); if (af_amount < af_w) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, af_amount); else glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, af_w); /* see what value was set */ glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &af_amount); printf("platform: set anisotropic filtering to %d\n", af_amount); } else printf("platform: anisotropic filtering is not supported\n"); /* texture compression */ if (gltQueryExtension("GL_ARB_texture_compression") == GL_TRUE) { printf("platform: host gfx device supports texture compression\n"); /* ToDo */ } /* how OpenGL combines the colors from texels with the color of the underlying * geometry is controlled by the texture environment mode */ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); /* once texture is loaded and enabled, it will applied to every primitive * that specifies coordinates, ORLY? */ glEnable(GL_TEXTURE_2D); /* specular highlights for textured items */ glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); /* glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_COLOR_SINGLE); */ /* only if lighting is disabled */ /* glEnable(GL_COLOR_SUM); */ /* draw fragments that pass this test, fragments with lower than 0.2f * alpha are discarded, this is just for the kicks */ glAlphaFunc(GL_GREATER, 0.2f); glEnable(GL_ALPHA_TEST); /* gray background */ glClearColor(0.5f, 0.5f, 0.5f, 1.0f); } SDL_Surface *setup_sdl_video(int w, int h, int bpp, unsigned int flags) { SDL_Surface *srfc; if (!bpp) { const SDL_VideoInfo* info = NULL; /* get some video information. */ info = SDL_GetVideoInfo(); if (!info) { fprintf( stderr, "SDL: video query failed: %s\n", SDL_GetError()); exit(-1); } bpp = info->vfmt->BitsPerPixel; printf("SDL: bpp was not specified, chose %d bits\n", bpp); } if (!flags) flags = SDL_OPENGL | SDL_RESIZABLE; if ((srfc = SDL_SetVideoMode(w, h, bpp, flags)) == NULL) { fprintf(stderr, "SDL: unable to set video mode: %s\n", SDL_GetError()); exit(-1); } return srfc; } SDL_Surface *setup_sdl(void) { SDL_Surface *screen; const SDL_VideoInfo* info = NULL; if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) == -1) { fprintf(stderr, "SDL: unable to init, %s\n", SDL_GetError()); exit(-1); } atexit(SDL_Quit); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_WM_SetCaption(window_caption, NULL); SDL_WM_SetIcon(IMG_Load(window_icon_path), NULL); /* set video mode */ screen = setup_sdl_video(xres_w, yres_w, bpp_w, sdl_video_flags); /* get some video information. */ info = SDL_GetVideoInfo(); if (!info) { fprintf( stderr, "SDL: video query failed: %s\n", SDL_GetError()); exit(-1); } int bpp = info->vfmt->BitsPerPixel; printf("SDL: applied %d bits per pixel\n", bpp); /* query opengl attributes after SetVideoMode call */ int fb_red_comp; int fb_green_comp; int fb_blue_comp; int fb_alpha_comp; int double_buff; int depth_sz; SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &fb_red_comp); SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &fb_green_comp); SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &fb_blue_comp); SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &fb_alpha_comp); SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &double_buff); SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &depth_sz); printf("SDL: framebuffer; size of components, red: %d bits, green: %d bits, " "blue: %d bits, alpha: %d bits\n" "SDL: double-buffering: %s, depth buffer size: %d bits\n", fb_red_comp, fb_green_comp, fb_blue_comp, fb_alpha_comp, double_buff ? "enabled" : "disabled", depth_sz); SDL_EnableUNICODE(1); /* SDL doesn't trigger off a ResizeEvent at startup, but as we need this * for OpenGL, we do this ourselves */ SDL_Event resizeEvent; resizeEvent.type = SDL_VIDEORESIZE; resizeEvent.resize.w = xres_w; resizeEvent.resize.h = yres_w; SDL_PushEvent(&resizeEvent); /* save the surf pointer in platform */ return screen; } void setup_glew(void) { /* initalize glew */ GLenum glewerr = glewInit(); if (GLEW_OK != glewerr) { fprintf(stderr, "GLEW error: %s\n", glewGetErrorString(glewerr)); exit(-1); } else fprintf(stdout, "GLEW: using version %s\n", glewGetString(GLEW_VERSION)); /* display OpenGL version */ GLint major; GLint minor; glGetIntegerv(GL_MAJOR_VERSION, &major); glGetIntegerv(GL_MINOR_VERSION, &minor); fprintf(stdout, "GLEW: initialized OpenGL %d.%d\n", major, minor); }