/* * Copyright © 2004 David Reveman * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation, and that the name of * David Reveman not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior permission. * David Reveman makes no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN * NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: David Reveman */ #ifdef HAVE_CONFIG_H # include "../config.h" #endif #include "glitzint.h" #include #include #include static glitz_extension_map gl_extensions[] = { { 0.0, "GL_ARB_texture_rectangle", GLITZ_FEATURE_TEXTURE_RECTANGLE_MASK }, { 0.0, "GL_EXT_texture_rectangle", GLITZ_FEATURE_TEXTURE_RECTANGLE_MASK }, { 0.0, "GL_NV_texture_rectangle", GLITZ_FEATURE_TEXTURE_RECTANGLE_MASK }, { 0.0, "GL_ARB_texture_non_power_of_two", GLITZ_FEATURE_TEXTURE_NON_POWER_OF_TWO_MASK }, { 0.0, "GL_ARB_texture_mirrored_repeat", GLITZ_FEATURE_TEXTURE_MIRRORED_REPEAT_MASK }, { 0.0, "GL_ARB_texture_border_clamp", GLITZ_FEATURE_TEXTURE_BORDER_CLAMP_MASK }, { 0.0, "GL_ARB_texture_env_combine", GLITZ_FEATURE_TEXTURE_ENV_COMBINE_MASK }, { 0.0, "GL_EXT_texture_env_combine", GLITZ_FEATURE_TEXTURE_ENV_COMBINE_MASK }, { 0.0, "GL_ARB_texture_env_dot3", GLITZ_FEATURE_TEXTURE_ENV_DOT3_MASK }, { 0.0, "GL_ARB_multisample", GLITZ_FEATURE_MULTISAMPLE_MASK }, { 0.0, "GL_NV_multisample_filter_hint", GLITZ_FEATURE_MULTISAMPLE_FILTER_HINT_MASK }, { 0.0, "GL_ARB_multitexture", GLITZ_FEATURE_MULTITEXTURE_MASK }, { 0.0, "GL_EXT_multi_draw_arrays", GLITZ_FEATURE_MULTI_DRAW_ARRAYS_MASK }, { 0.0, "GL_ARB_fragment_program", GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK }, { 0.0, "GL_ARB_vertex_buffer_object", GLITZ_FEATURE_VERTEX_BUFFER_OBJECT_MASK }, { 0.0, "GL_ARB_pixel_buffer_object", GLITZ_FEATURE_PIXEL_BUFFER_OBJECT_MASK }, { 0.0, "GL_EXT_pixel_buffer_object", GLITZ_FEATURE_PIXEL_BUFFER_OBJECT_MASK }, { 0.0, "GL_EXT_blend_color", GLITZ_FEATURE_BLEND_COLOR_MASK }, { 0.0, "GL_ARB_imaging", GLITZ_FEATURE_BLEND_COLOR_MASK }, { 0.0, "GL_APPLE_packed_pixels", GLITZ_FEATURE_PACKED_PIXELS_MASK }, { 0.0, "GL_EXT_framebuffer_object", GLITZ_FEATURE_FRAMEBUFFER_OBJECT_MASK }, { 0.0, NULL, 0 } }; static glitz_bool_t _glitz_extension_check (const char *extensions, const char *ext_name) { char *end; char *p = (char *) extensions; int ext_name_len = strlen (ext_name); if (! p) return 0; end = p + strlen (p); while (p < end) { int n = strcspn (p, " "); if ((ext_name_len == n) && (strncmp (ext_name, p, n) == 0)) { return 1; } p += (n + 1); } return 0; } unsigned long glitz_extensions_query (glitz_gl_float_t version, const char *extensions_string, glitz_extension_map *extensions_map) { unsigned long mask = 0; int i; for (i = 0; extensions_map[i].name; i++) if (((extensions_map[i].version > 1.0) && (version >= extensions_map[i].version)) || _glitz_extension_check (extensions_string, extensions_map[i].name)) mask |= extensions_map[i].mask; return mask; } static glitz_gl_float_t _glitz_gl_version_string_to_float (const char *gl_version_string) { glitz_gl_float_t version = 0.0f; int i; for (i = 0; isdigit (gl_version_string[i]); i++) version = version * 10.0f + (gl_version_string[i] - 48); if (gl_version_string[i++] != '.') return 0.0f; version = version * 10.0f + (gl_version_string[i] - 48); return (version + 0.1f) / 10.0f; } static glitz_status_t _glitz_query_gl_extensions (glitz_gl_proc_address_list_t *gl, glitz_gl_float_t *gl_version, unsigned long *feature_mask) { const char *gl_extensions_string; const char *gl_version_string; gl_version_string = (const char *) gl->get_string (GLITZ_GL_VERSION); if (!gl_version_string) return GLITZ_STATUS_NOT_SUPPORTED; *gl_version = _glitz_gl_version_string_to_float (gl_version_string); if (*gl_version < 1.2f) return GLITZ_STATUS_NOT_SUPPORTED; gl_extensions_string = (const char *) gl->get_string (GLITZ_GL_EXTENSIONS); *feature_mask = glitz_extensions_query (*gl_version, gl_extensions_string, gl_extensions); if ((*feature_mask & GLITZ_FEATURE_TEXTURE_ENV_COMBINE_MASK) && (*feature_mask & GLITZ_FEATURE_TEXTURE_ENV_DOT3_MASK)) { glitz_gl_int_t max_texture_units; gl->get_integer_v (GLITZ_GL_MAX_TEXTURE_UNITS, &max_texture_units); if (max_texture_units >= 3) *feature_mask |= GLITZ_FEATURE_PER_COMPONENT_RENDERING_MASK; } return GLITZ_STATUS_SUCCESS; } static void _glitz_gl_proc_address_lookup (glitz_backend_t *backend, glitz_get_proc_address_proc_t get_proc_address, void *closure) { if (backend->feature_mask & GLITZ_FEATURE_BLEND_COLOR_MASK) { if (backend->gl_version >= 1.4f) { backend->gl->blend_color = (glitz_gl_blend_color_t) get_proc_address ("glBlendColor", closure); } else { backend->gl->blend_color = (glitz_gl_blend_color_t) get_proc_address ("glBlendColorEXT", closure); } if (!backend->gl->blend_color) backend->feature_mask &= ~GLITZ_FEATURE_BLEND_COLOR_MASK; } if (backend->feature_mask & GLITZ_FEATURE_MULTITEXTURE_MASK) { if (backend->gl_version >= 1.3f) { backend->gl->active_texture = (glitz_gl_active_texture_t) get_proc_address ("glActiveTexture", closure); backend->gl->client_active_texture = (glitz_gl_client_active_texture_t) get_proc_address ("glClientActiveTexture", closure); } else { backend->gl->active_texture = (glitz_gl_active_texture_t) get_proc_address ("glActiveTextureARB", closure); backend->gl->client_active_texture = (glitz_gl_client_active_texture_t) get_proc_address ("glClientActiveTextureARB", closure); } if ((!backend->gl->active_texture) || (!backend->gl->client_active_texture)) { backend->feature_mask &= ~GLITZ_FEATURE_MULTITEXTURE_MASK; backend->feature_mask &= ~GLITZ_FEATURE_PER_COMPONENT_RENDERING_MASK; } } if (backend->feature_mask & GLITZ_FEATURE_MULTI_DRAW_ARRAYS_MASK) { backend->gl->multi_draw_arrays = (glitz_gl_multi_draw_arrays_t) get_proc_address ("glMultiDrawArraysEXT", closure); if (!backend->gl->multi_draw_arrays) backend->feature_mask &= ~GLITZ_FEATURE_MULTI_DRAW_ARRAYS_MASK; } if (backend->feature_mask & GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK) { backend->gl->gen_programs = (glitz_gl_gen_programs_t) get_proc_address ("glGenProgramsARB", closure); backend->gl->delete_programs = (glitz_gl_delete_programs_t) get_proc_address ("glDeleteProgramsARB", closure); backend->gl->program_string = (glitz_gl_program_string_t) get_proc_address ("glProgramStringARB", closure); backend->gl->bind_program = (glitz_gl_bind_program_t) get_proc_address ("glBindProgramARB", closure); backend->gl->program_local_param_4fv = (glitz_gl_program_local_param_4fv_t) get_proc_address ("glProgramLocalParameter4fvARB", closure); backend->gl->get_program_iv = (glitz_gl_get_program_iv_t) get_proc_address ("glGetProgramivARB", closure); if ((!backend->gl->gen_programs) || (!backend->gl->delete_programs) || (!backend->gl->program_string) || (!backend->gl->bind_program) || (!backend->gl->program_local_param_4fv)) backend->feature_mask &= ~GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK; } if ((backend->feature_mask & GLITZ_FEATURE_VERTEX_BUFFER_OBJECT_MASK) || (backend->feature_mask & GLITZ_FEATURE_PIXEL_BUFFER_OBJECT_MASK)) { if (backend->gl_version >= 1.5f) { backend->gl->gen_buffers = (glitz_gl_gen_buffers_t) get_proc_address ("glGenBuffers", closure); backend->gl->delete_buffers = (glitz_gl_delete_buffers_t) get_proc_address ("glDeleteBuffers", closure); backend->gl->bind_buffer = (glitz_gl_bind_buffer_t) get_proc_address ("glBindBuffer", closure); backend->gl->buffer_data = (glitz_gl_buffer_data_t) get_proc_address ("glBufferData", closure); backend->gl->buffer_sub_data = (glitz_gl_buffer_sub_data_t) get_proc_address ("glBufferSubData", closure); backend->gl->get_buffer_sub_data = (glitz_gl_get_buffer_sub_data_t) get_proc_address ("glGetBufferSubData", closure); backend->gl->map_buffer = (glitz_gl_map_buffer_t) get_proc_address ("glMapBuffer", closure); backend->gl->unmap_buffer = (glitz_gl_unmap_buffer_t) get_proc_address ("glUnmapBuffer", closure); } else { backend->gl->gen_buffers = (glitz_gl_gen_buffers_t) get_proc_address ("glGenBuffersARB", closure); backend->gl->delete_buffers = (glitz_gl_delete_buffers_t) get_proc_address ("glDeleteBuffersARB", closure); backend->gl->bind_buffer = (glitz_gl_bind_buffer_t) get_proc_address ("glBindBufferARB", closure); backend->gl->buffer_data = (glitz_gl_buffer_data_t) get_proc_address ("glBufferDataARB", closure); backend->gl->buffer_sub_data = (glitz_gl_buffer_sub_data_t) get_proc_address ("glBufferSubDataARB", closure); backend->gl->get_buffer_sub_data = (glitz_gl_get_buffer_sub_data_t) get_proc_address ("glGetBufferSubDataARB", closure); backend->gl->map_buffer = (glitz_gl_map_buffer_t) get_proc_address ("glMapBufferARB", closure); backend->gl->unmap_buffer = (glitz_gl_unmap_buffer_t) get_proc_address ("glUnmapBufferARB", closure); } if ((!backend->gl->gen_buffers) || (!backend->gl->delete_buffers) || (!backend->gl->bind_buffer) || (!backend->gl->buffer_data) || (!backend->gl->buffer_sub_data) || (!backend->gl->get_buffer_sub_data) || (!backend->gl->map_buffer) || (!backend->gl->unmap_buffer)) { backend->feature_mask &= ~GLITZ_FEATURE_VERTEX_BUFFER_OBJECT_MASK; backend->feature_mask &= ~GLITZ_FEATURE_PIXEL_BUFFER_OBJECT_MASK; } } if (backend->feature_mask & GLITZ_FEATURE_FRAMEBUFFER_OBJECT_MASK) { backend->gl->gen_framebuffers = (glitz_gl_gen_framebuffers_t) get_proc_address ("glGenFramebuffersEXT", closure); backend->gl->delete_framebuffers = (glitz_gl_delete_framebuffers_t) get_proc_address ("glDeleteFramebuffersEXT", closure); backend->gl->bind_framebuffer = (glitz_gl_bind_framebuffer_t) get_proc_address ("glBindFramebufferEXT", closure); backend->gl->framebuffer_renderbuffer = (glitz_gl_framebuffer_renderbuffer_t) get_proc_address ("glFramebufferRenderbufferEXT", closure); backend->gl->framebuffer_texture_2d = (glitz_gl_framebuffer_texture_2d_t) get_proc_address ("glFramebufferTexture2DEXT", closure); backend->gl->check_framebuffer_status = (glitz_gl_check_framebuffer_status_t) get_proc_address ("glCheckFramebufferStatusEXT", closure); backend->gl->gen_renderbuffers = (glitz_gl_gen_renderbuffers_t) get_proc_address ("glGenRenderbuffersEXT", closure); backend->gl->delete_renderbuffers = (glitz_gl_delete_renderbuffers_t) get_proc_address ("glDeleteRenderbuffersEXT", closure); backend->gl->bind_renderbuffer = (glitz_gl_bind_renderbuffer_t) get_proc_address ("glBindRenderbufferEXT", closure); backend->gl->renderbuffer_storage = (glitz_gl_renderbuffer_storage_t) get_proc_address ("glRenderbufferStorageEXT", closure); backend->gl->get_renderbuffer_parameter_iv = (glitz_gl_get_renderbuffer_parameter_iv_t) get_proc_address ("glGetRenderbufferParameterivEXT", closure); if ((!backend->gl->gen_framebuffers) || (!backend->gl->delete_framebuffers) || (!backend->gl->bind_framebuffer) || (!backend->gl->framebuffer_renderbuffer) || (!backend->gl->framebuffer_texture_2d) || (!backend->gl->check_framebuffer_status) || (!backend->gl->gen_renderbuffers) || (!backend->gl->delete_renderbuffers) || (!backend->gl->bind_renderbuffer) || (!backend->gl->renderbuffer_storage) || (!backend->gl->get_renderbuffer_parameter_iv)) backend->feature_mask &= ~GLITZ_FEATURE_FRAMEBUFFER_OBJECT_MASK; } } void glitz_backend_init (glitz_backend_t *backend, glitz_get_proc_address_proc_t get_proc_address, void *closure) { if (!_glitz_query_gl_extensions (backend->gl, &backend->gl_version, &backend->feature_mask)) { _glitz_gl_proc_address_lookup (backend, get_proc_address, closure); glitz_create_surface_formats (backend->gl, &backend->formats, &backend->texture_formats, &backend->n_formats, backend->feature_mask); _glitz_add_drawable_formats (backend->gl, backend->feature_mask, &backend->drawable_formats, &backend->n_drawable_formats); } backend->gl->get_integer_v (GLITZ_GL_MAX_VIEWPORT_DIMS, backend->max_viewport_dims); backend->gl->get_integer_v (GLITZ_GL_MAX_TEXTURE_SIZE, &backend->max_texture_2d_size); if (backend->feature_mask & GLITZ_FEATURE_TEXTURE_RECTANGLE_MASK) backend->gl->get_integer_v (GLITZ_GL_MAX_RECTANGLE_TEXTURE_SIZE, &backend->max_texture_rect_size); else backend->max_texture_rect_size = 0; } unsigned int glitz_uint_to_power_of_two (unsigned int x) { x |= (x >> 1); x |= (x >> 2); x |= (x >> 4); x |= (x >> 8); x |= (x >> 16); return (x + 1); } void glitz_set_raster_pos (glitz_gl_proc_address_list_t *gl, glitz_float_t x, glitz_float_t y) { gl->push_attrib (GLITZ_GL_TRANSFORM_BIT | GLITZ_GL_VIEWPORT_BIT); gl->matrix_mode (GLITZ_GL_PROJECTION); gl->push_matrix (); gl->load_identity (); gl->matrix_mode (GLITZ_GL_MODELVIEW); gl->push_matrix (); gl->load_identity (); gl->depth_range (0, 1); gl->viewport (-1, -1, 2, 2); gl->raster_pos_2f (0, 0); gl->bitmap (0, 0, 1, 1, x, y, NULL); gl->pop_matrix (); gl->matrix_mode (GLITZ_GL_PROJECTION); gl->pop_matrix (); gl->pop_attrib (); } void glitz_clamp_value (glitz_float_t *value, glitz_float_t min, glitz_float_t max) { if (*value < min) *value = min; else if (*value > max) *value = max; } void glitz_initiate_state (glitz_gl_proc_address_list_t *gl) { gl->hint (GLITZ_GL_PERSPECTIVE_CORRECTION_HINT, GLITZ_GL_FASTEST); gl->disable (GLITZ_GL_CULL_FACE); gl->depth_mask (GLITZ_GL_FALSE); gl->polygon_mode (GLITZ_GL_FRONT_AND_BACK, GLITZ_GL_FILL); gl->disable (GLITZ_GL_POLYGON_SMOOTH); gl->disable (GLITZ_GL_LINE_SMOOTH); gl->disable (GLITZ_GL_POINT_SMOOTH); gl->shade_model (GLITZ_GL_FLAT); gl->color_mask (GLITZ_GL_TRUE, GLITZ_GL_TRUE, GLITZ_GL_TRUE, GLITZ_GL_TRUE); gl->enable (GLITZ_GL_SCISSOR_TEST); gl->disable (GLITZ_GL_STENCIL_TEST); gl->enable_client_state (GLITZ_GL_VERTEX_ARRAY); gl->disable (GLITZ_GL_DEPTH_TEST); }