2 This file is part of the 3dengfx, realtime visualization system.
3 Copyright (c) 2004, 2005 John Tsiombikas <nuclear@siggraph.org>
5 3dengfx is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 3dengfx is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with 3dengfx; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 /* main 3dengfx state control, and low level OpenGL interaction
22 * Author: John Tsiombikas 2004
25 #include "3dengfx_config.h"
33 #include "fxwt/fxwt.hpp"
34 #include "fxwt/init.hpp"
35 #include "fxwt/gfx_library.h"
36 #include "3denginefx.hpp"
40 #include "gfx/3dgeom.hpp"
41 #include "gfxprog.hpp"
42 #include "gfx/image.h"
43 #include "common/config_parser.h"
44 #include "common/err_msg.h"
45 #include "dsys/dsys.hpp"
52 #ifdef SINGLE_PRECISION_MATH
53 #define GL_SCALAR_TYPE GL_FLOAT
55 #define GL_SCALAR_TYPE GL_DOUBLE
56 #endif // SINGLE_PRECISION_MATH
59 void (*load_matrix_gl)(const Matrix4x4 &mat);
62 #ifdef SINGLE_PRECISION_MATH
63 PFNGLLOADTRANSPOSEMATRIXFARBPROC glLoadTransposeMatrix;
65 PFNGLLOADTRANSPOSEMATRIXDARBPROC glLoadTransposeMatrix;
66 #endif // SINGLE_PRECISION_MATH
68 PFNGLACTIVETEXTUREARBPROC glActiveTexture;
69 PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTexture;
71 PFNGLBINDBUFFERARBPROC glBindBuffer;
72 PFNGLBUFFERDATAARBPROC glBufferData;
73 PFNGLDELETEBUFFERSARBPROC glDeleteBuffers;
74 PFNGLISBUFFERARBPROC glIsBuffer;
75 PFNGLMAPBUFFERARBPROC glMapBuffer;
76 PFNGLUNMAPBUFFERARBPROC glUnmapBuffer;
77 PFNGLGENBUFFERSARBPROC glGenBuffers;
79 // fragment/vertex program extensions
80 PFNGLBINDPROGRAMARBPROC glBindProgram;
81 PFNGLGENPROGRAMSARBPROC glGenPrograms;
82 PFNGLDELETEPROGRAMSARBPROC glDeletePrograms;
83 PFNGLPROGRAMSTRINGARBPROC glProgramString;
86 PFNGLPOINTPARAMETERFARBPROC glPointParameterf;
87 PFNGLPOINTPARAMETERFVARBPROC glPointParameterfv;
89 // --- OpenGL 2.0 Shading Language ---
92 PFNGLDELETEOBJECTARBPROC glDeleteObject;
93 PFNGLATTACHOBJECTARBPROC glAttachObject;
94 PFNGLDETACHOBJECTARBPROC glDetachObject;
95 PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameteriv;
96 PFNGLGETINFOLOGARBPROC glGetInfoLog;
99 PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObject;
100 PFNGLLINKPROGRAMARBPROC glLinkProgram;
101 PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObject;
104 PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObject;
105 PFNGLSHADERSOURCEARBPROC glShaderSource;
106 PFNGLCOMPILESHADERARBPROC glCompileShader;
109 PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocation;
110 PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniform;
111 PFNGLUNIFORM1IARBPROC glUniform1i;
112 PFNGLUNIFORM1FARBPROC glUniform1f;
113 PFNGLUNIFORM2FARBPROC glUniform2f;
114 PFNGLUNIFORM3FARBPROC glUniform3f;
115 PFNGLUNIFORM4FARBPROC glUniform4f;
116 PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fv;
117 PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fv;
120 using namespace glext;
122 static const char *gl_error_string[] = {
123 "GL_INVALID_ENUM", // 0x500
124 "GL_INVALID_VALUE", // 0x501
125 "GL_INVALID_OPERATION", // 0x502
126 "GL_STACK_OVERFLOW", // 0x503
127 "GL_STACK_UNDERFLOW", // 0x504
128 "GL_OUT_OF_MEMORY", // 0x505
129 "GL_NO_ERROR", // 0x0
130 "[INVALID ERROR NUMBER]"
133 ///////////////// local 3d engine state block ///////////////////
134 static bool gc_valid;
135 static GraphicsInitParameters gparams;
136 static Matrix4x4 tex_matrix[8];
137 static int coord_index[MAX_TEXTURES];
138 static PrimitiveType primitive_type;
139 static StencilOp stencil_fail, stencil_pass, stencil_pzfail;
140 static int stencil_ref;
141 static bool mipmapping = true;
142 static TextureDim ttype[8]; // the type of each texture bound to each texunit (1D/2D/3D/CUBE)
144 namespace engfx_state {
146 Matrix4x4 world_matrix;
147 Matrix4x4 view_matrix, inv_view_matrix;
148 const Camera *view_mat_camera;
149 Matrix4x4 proj_matrix;
150 const Light *bump_light;
154 using namespace engfx_state;
156 GraphicsInitParameters *load_graphics_context_config(const char *fname) {
157 static GraphicsInitParameters gip;
162 gip.stencil_bits = 8;
163 gip.dont_care_flags = 0;
165 if(load_config_file(fname) == -1) {
166 error("%s: could not load config file", __func__);
170 const ConfigOption *cfgopt;
171 while((cfgopt = get_next_option())) {
173 if(!strcmp(cfgopt->option, "fullscreen")) {
174 if(!strcmp(cfgopt->str_value, "true")) {
175 gip.fullscreen = true;
176 } else if(!strcmp(cfgopt->str_value, "false")) {
177 gip.fullscreen = false;
179 error("%s: error parsing config file %s", __func__, fname);
182 } else if(!strcmp(cfgopt->option, "resolution")) {
183 if(!strcmp(cfgopt->str_value, "dontcare")) {
186 gip.dont_care_flags |= DONT_CARE_SIZE;
188 if(!isdigit(cfgopt->str_value[0])) {
189 error("%s: error parsing config file %s", __func__, fname);
192 gip.x = atoi(cfgopt->str_value);
194 char *ptr = cfgopt->str_value;
195 while(*ptr && *ptr != 'x') ptr++;
196 if(!*ptr || !*(ptr+1) || !isdigit(*(ptr+1))) {
197 error("%s: error parsing config file %s", __func__, fname);
201 gip.y = atoi(ptr + 1);
203 } else if(!strcmp(cfgopt->option, "bpp")) {
204 if(cfgopt->flags & CFGOPT_INT) {
205 gip.bpp = cfgopt->int_value;
206 } else if(!strcmp(cfgopt->str_value, "dontcare")) {
208 gip.dont_care_flags |= DONT_CARE_BPP;
210 error("%s: error parsing config file %s", __func__, fname);
213 } else if(!strcmp(cfgopt->option, "zbuffer")) {
214 if(cfgopt->flags & CFGOPT_INT) {
215 gip.depth_bits = cfgopt->int_value;
216 } else if(!strcmp(cfgopt->str_value, "dontcare")) {
218 gip.dont_care_flags |= DONT_CARE_DEPTH;
220 error("%s: error parsing config file %s", __func__, fname);
223 } else if(!strcmp(cfgopt->option, "stencil")) {
224 if(cfgopt->flags & CFGOPT_INT) {
225 gip.stencil_bits = cfgopt->int_value;
226 } else if(!strcmp(cfgopt->str_value, "dontcare")) {
227 gip.stencil_bits = 8;
228 gip.dont_care_flags |= DONT_CARE_STENCIL;
230 error("%s: error parsing config file %s", __func__, fname);
236 destroy_config_parser();
241 /* ---- get_system_capabilities() ----
242 * Retrieves information on the graphics subsystem capabilities
243 * and returns a SysCaps structure describing them
245 SysCaps get_system_capabilities() {
246 static bool first_call = true;
253 // get extensions & vendor strings
254 const char *tmp_str = (const char*)glGetString(GL_EXTENSIONS);
256 error("%s: glGetString() failed, possibly no valid GL context", __func__);
259 char *ext_str = new char[strlen(tmp_str) + 1];
260 strcpy(ext_str, tmp_str);
262 char *cptr = ext_str;
264 if(*cptr == ' ') *cptr = '\n';
269 info("Supported extensions:\n-------------\n%s", ext_str);
272 info("Rendering System Information:");
274 const char *vendor = (const char*)glGetString(GL_VENDOR);
275 info(" Vendor: %s", vendor);
276 info("Renderer: %s", glGetString(GL_RENDERER));
277 info(" Version: %s", glGetString(GL_VERSION));
278 info("(note: the list of extensions is logged seperately at \"gl_ext.log\")");
280 // fill the SysCaps structure
282 sys_caps.multitex = (bool)strstr(ext_str, "GL_ARB_multitexture");
283 sys_caps.load_transpose = (bool)strstr(ext_str, "GL_ARB_transpose_matrix");
284 sys_caps.gen_mipmaps = (bool)strstr(ext_str, "GL_SGIS_generate_mipmap");
285 sys_caps.tex_combine_ops = (bool)strstr(ext_str, "GL_ARB_texture_env_combine");
286 sys_caps.bump_dot3 = (bool)strstr(ext_str, "GL_ARB_texture_env_dot3");
287 sys_caps.bump_env = (bool)strstr(ext_str, "GL_ATI_envmap_bumpmap");
288 sys_caps.vertex_buffers = (bool)strstr(ext_str, "GL_ARB_vertex_buffer_object");
289 sys_caps.depth_texture = (bool)strstr(ext_str, "GL_ARB_depth_texture");
290 sys_caps.shadow_mapping = (bool)strstr(ext_str, "GL_ARB_shadow");
291 sys_caps.point_sprites = (bool)strstr(ext_str, "GL_ARB_point_sprite");
292 sys_caps.point_params = (bool)strstr(ext_str, "GL_ARB_point_parameters");
293 glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &sys_caps.max_texture_units);
294 sys_caps.non_power_of_two_textures = (bool)strstr(ext_str, "GL_ARB_texture_non_power_of_two");
295 glGetIntegerv(GL_MAX_LIGHTS, &sys_caps.max_lights);
297 sys_caps.prog.asm_vertex = (bool)strstr(ext_str, "GL_ARB_vertex_program");
298 sys_caps.prog.asm_pixel = (bool)strstr(ext_str, "GL_ARB_fragment_program");
299 sys_caps.prog.glslang = (bool)strstr(ext_str, "GL_ARB_shading_language_100");
300 sys_caps.prog.shader_obj = (bool)strstr(ext_str, "GL_ARB_shader_objects");
301 sys_caps.prog.glsl_vertex = (bool)strstr(ext_str, "GL_ARB_vertex_shader");
302 sys_caps.prog.glsl_pixel = (bool)strstr(ext_str, "GL_ARB_fragment_shader");
306 // also log these things
307 info("-------------------");
308 info("System Capabilities");
309 info("-------------------");
310 info("Load transposed matrices: %s", sys_caps.load_transpose ? "yes" : "no");
311 info("Auto-generate mipmaps (SGIS): %s", sys_caps.gen_mipmaps ? "yes" : "no");
312 info("Custom texture combination operations: %s", sys_caps.tex_combine_ops ? "yes" : "no");
313 info("Diffuse bump mapping (dot3): %s", sys_caps.bump_dot3 ? "yes" : "no");
314 info("Specular bump mapping (env-bump): %s", sys_caps.bump_env ? "yes" : "no");
315 info("Video memory vertex/index buffers: %s", sys_caps.vertex_buffers ? "yes" : "no");
316 info("Depth texture: %s", sys_caps.depth_texture ? "yes" : "no");
317 info("Shadow mapping: %s", sys_caps.shadow_mapping ? "yes" : "no");
318 info("Programmable vertex processing (asm): %s", sys_caps.prog.asm_vertex ? "yes" : "no");
319 info("Programmable pixel processing (asm): %s", sys_caps.prog.asm_pixel ? "yes" : "no");
320 info("OpenGL 2.0 shading language: %s", sys_caps.prog.glslang ? "yes" : "no");
321 info("Programmable vertex processing (glsl): %s", sys_caps.prog.glsl_vertex ? "yes" : "no");
322 info("Programmable pixel processing (glsl): %s", sys_caps.prog.glsl_pixel ? "yes" : "no");
323 info("Point sprites: %s", sys_caps.point_sprites ? "yes" : "no");
324 info("Point parameters: %s", sys_caps.point_params ? "yes" : "no");
325 info("Non power of 2 textures: %s", sys_caps.non_power_of_two_textures ? "yes" : "no");
326 info("Texture units: %d", sys_caps.max_texture_units);
327 info("Max lights: %d", sys_caps.max_lights);
329 if(!sys_caps.point_sprites && !sys_caps.point_params) {
330 warning("no point sprites support, falling back to billboards which *may* degrade particle system performance");
336 const char *get_glerror_string(GLenum error) {
337 if(!error) return gl_error_string[0x506];
338 if(error < 0x500 || error > 0x505) error = 0x507;
339 return gl_error_string[error - 0x500];
342 /* load_matrix_transpose_arb() & load_matrix_transpose_manual()
343 * --------------------------------------------------------
344 * two functions to handle the transformation matrix loading
345 * to OpenGL by either transposing the Matrix4x4 data or using
346 * the transposed-loading extension (use through function pointer
347 * LoadMatrixGL which is set during initialization to the correct one)
349 void load_matrix_transpose_arb(const Matrix4x4 &mat) {
350 glLoadTransposeMatrix(mat.opengl_matrix());
353 void load_matrix_transpose_manual(const Matrix4x4 &mat) {
354 #ifdef SINGLE_PRECISION_MATH
355 glLoadMatrixf(mat.transposed().opengl_matrix());
357 glLoadMatrixd(mat.transposed().opengl_matrix());
358 #endif // SINGLE_PRECISION_MATH
362 //////////////// 3D Engine Initialization ////////////////
364 static const char *signame(int sig) {
367 return "segmentation fault (SIGSEGV)";
369 return "illegal instruction (SIGILL)";
371 return "termination signal (SIGTERM)";
373 return "floating point exception (SIGFPE)";
375 return "interrupt signal (SIGINT)";
379 return "can't happen";
382 static void signal_handler(int sig) {
383 error("It seems this is the end... caught %s, exiting...", signame(sig));
384 destroy_graphics_context();
388 /* ---- create_graphics_context() ----
389 * initializes the graphics subsystem according to the init parameters
391 bool create_graphics_context(const GraphicsInitParameters &gip) {
395 remove(get_log_filename());
397 if(!fxwt::init_graphics(&gparams)) {
401 signal(SIGSEGV, signal_handler);
402 signal(SIGILL, signal_handler);
403 signal(SIGTERM, signal_handler);
404 signal(SIGFPE, signal_handler);
405 signal(SIGINT, signal_handler);
407 #if GFX_LIBRARY == GTK
412 if(!start_gl()) return false;
420 * short graphics context creation
421 * creates a graphics context (windowed or fullscreen)
422 * given only the wanted resolution and a fullscreen flag.
424 bool create_graphics_context(int x, int y, bool fullscreen)
426 GraphicsInitParameters gip;
431 gip.fullscreen = fullscreen;
432 gip.stencil_bits = 8;
433 gip.dont_care_flags = DONT_CARE_DEPTH | DONT_CARE_STENCIL | DONT_CARE_BPP;
435 return create_graphics_context(gip);
438 /* OpenGL startup after initialization */
440 SysCaps sys_caps = get_system_capabilities();
442 glext::glActiveTexture = (PFNGLACTIVETEXTUREARBPROC)glGetProcAddress("glActiveTextureARB");
443 glext::glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREARBPROC)glGetProcAddress("glClientActiveTextureARB");
445 if(!glext::glActiveTexture || !glext::glClientActiveTexture) {
446 warning("No multitexturing support.");
447 sys_caps.multitex = false;
450 if(sys_caps.load_transpose) {
451 #ifdef SINGLE_PRECISION_MATH
452 glLoadTransposeMatrix = (PFNGLLOADTRANSPOSEMATRIXFARBPROC)glGetProcAddress("glLoadTransposeMatrixfARB");
454 glLoadTransposeMatrix = (PFNGLLOADTRANSPOSEMATRIXDARBPROC)glGetProcAddress("glLoadTransposeMatrixdARB");
455 #endif // SINGLE_PRECISION_MATH
457 load_matrix_gl = load_matrix_transpose_arb;
459 load_matrix_gl = load_matrix_transpose_manual;
462 if(sys_caps.vertex_buffers) {
463 glBindBuffer = (PFNGLBINDBUFFERARBPROC)glGetProcAddress("glBindBufferARB");
464 glBufferData = (PFNGLBUFFERDATAARBPROC)glGetProcAddress("glBufferDataARB");
465 glDeleteBuffers = (PFNGLDELETEBUFFERSARBPROC)glGetProcAddress("glDeleteBuffersARB");
466 glIsBuffer = (PFNGLISBUFFERARBPROC)glGetProcAddress("glIsBufferARB");
467 glMapBuffer = (PFNGLMAPBUFFERARBPROC)glGetProcAddress("glMapBufferARB");
468 glUnmapBuffer = (PFNGLUNMAPBUFFERARBPROC)glGetProcAddress("glUnmapBufferARB");
469 glGenBuffers = (PFNGLGENBUFFERSARBPROC)glGetProcAddress("glGenBuffersARB");
472 if(sys_caps.prog.asm_vertex || sys_caps.prog.asm_pixel) {
473 glBindProgram = (PFNGLBINDPROGRAMARBPROC)glGetProcAddress("glBindProgramARB");
474 glGenPrograms = (PFNGLGENPROGRAMSARBPROC)glGetProcAddress("glGenProgramsARB");
475 glDeletePrograms = (PFNGLDELETEPROGRAMSARBPROC)glGetProcAddress("glDeleteProgramsARB");
476 glProgramString = (PFNGLPROGRAMSTRINGARBPROC)glGetProcAddress("glProgramStringARB");
479 if(sys_caps.prog.shader_obj) {
480 glDeleteObject = (PFNGLDELETEOBJECTARBPROC)glGetProcAddress("glDeleteObjectARB");
481 glAttachObject = (PFNGLATTACHOBJECTARBPROC)glGetProcAddress("glAttachObjectARB");
482 glDetachObject = (PFNGLDETACHOBJECTARBPROC)glGetProcAddress("glDetachObjectARB");
483 glGetObjectParameteriv = (PFNGLGETOBJECTPARAMETERIVARBPROC)glGetProcAddress("glGetObjectParameterivARB");
484 glGetInfoLog = (PFNGLGETINFOLOGARBPROC)glGetProcAddress("glGetInfoLogARB");
486 glCreateProgramObject = (PFNGLCREATEPROGRAMOBJECTARBPROC)glGetProcAddress("glCreateProgramObjectARB");
487 glLinkProgram = (PFNGLLINKPROGRAMARBPROC)glGetProcAddress("glLinkProgramARB");
488 glUseProgramObject = (PFNGLUSEPROGRAMOBJECTARBPROC)glGetProcAddress("glUseProgramObjectARB");
490 glCreateShaderObject = (PFNGLCREATESHADEROBJECTARBPROC)glGetProcAddress("glCreateShaderObjectARB");
491 glShaderSource = (PFNGLSHADERSOURCEARBPROC)glGetProcAddress("glShaderSourceARB");
492 glCompileShader = (PFNGLCOMPILESHADERARBPROC)glGetProcAddress("glCompileShaderARB");
494 glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONARBPROC)glGetProcAddress("glGetUniformLocationARB");
495 glGetActiveUniform = (PFNGLGETACTIVEUNIFORMARBPROC)glGetProcAddress("glGetActiveUniformARB");
496 glUniform1i = (PFNGLUNIFORM1IARBPROC)glGetProcAddress("glUniform1iARB");
497 glUniform1f = (PFNGLUNIFORM1FARBPROC)glGetProcAddress("glUniform1fARB");
498 glUniform2f = (PFNGLUNIFORM2FARBPROC)glGetProcAddress("glUniform2fARB");
499 glUniform3f = (PFNGLUNIFORM3FARBPROC)glGetProcAddress("glUniform3fARB");
500 glUniform4f = (PFNGLUNIFORM4FARBPROC)glGetProcAddress("glUniform4fARB");
501 glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVARBPROC)glGetProcAddress("glUniformMatrix3fvARB");
502 glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVARBPROC)glGetProcAddress("glUniformMatrix4fvARB");
505 if(sys_caps.point_params) {
506 glext::glPointParameterf = (PFNGLPOINTPARAMETERFARBPROC)glGetProcAddress("glPointParameterfARB");
507 glext::glPointParameterfv = (PFNGLPOINTPARAMETERFVARBPROC)glGetProcAddress("glPointParameterfvARB");
509 if(!glext::glPointParameterfv) {
510 error("error loading glPointParameterfv");
513 if(!glext::glPointParameterf) {
514 error("error loading glPointParameterf");
521 set_default_states();
525 void destroy_graphics_context() {
526 static bool destroy_called_again = false;
528 if(destroy_called_again) {
529 warning("Multiple destroy_graphics_context() calls");
532 destroy_called_again = true;
536 if(!gc_valid) return;
538 info("3d engine shutting down...");
541 fxwt::destroy_graphics();
544 void set_default_states() {
545 set_primitive_type(TRIANGLE_LIST);
546 set_front_face(ORDER_CW);
547 set_backface_culling(true);
548 set_zbuffering(true);
550 set_auto_normalize(false);
552 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
553 glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
555 set_matrix(XFORM_WORLD, Matrix4x4());
556 set_matrix(XFORM_VIEW, Matrix4x4());
557 set_matrix(XFORM_PROJECTION, create_projection_matrix(quarter_pi, 1.333333f, 1.0f, 1000.0f));
559 memset(coord_index, 0, MAX_TEXTURES * sizeof(int));
561 for(int i=0; i<8; i++) {
565 if(sys_caps.point_params) {
566 glext::glPointParameterf(GL_POINT_SIZE_MIN_ARB, 1.0);
567 glext::glPointParameterf(GL_POINT_SIZE_MAX_ARB, 256.0);
569 float quadratic[] = {0.0f, 0.0f, 0.01f};
570 glext::glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION_ARB, quadratic);
574 const GraphicsInitParameters *get_graphics_init_parameters() {
578 void clear(const Color &color) {
579 glClearColor(color.r, color.g, color.b, color.a);
580 glClear(GL_COLOR_BUFFER_BIT);
583 void clear_zbuffer(scalar_t zval) {
585 glClear(GL_DEPTH_BUFFER_BIT);
588 void clear_stencil(unsigned char sval) {
589 glClearStencil(sval);
590 glClear(GL_STENCIL_BUFFER_BIT);
593 void clear_zbuffer_stencil(scalar_t zval, unsigned char sval) {
595 glClearStencil(sval);
596 glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
602 fxwt::swap_buffers();
605 void load_xform_matrices() {
606 for(int i=0; i<sys_caps.max_texture_units; i++) {
607 select_texture_unit(i);
608 glMatrixMode(GL_TEXTURE);
609 load_matrix_gl(tex_matrix[i]);
612 glMatrixMode(GL_PROJECTION);
613 load_matrix_gl(proj_matrix);
615 Matrix4x4 modelview = view_matrix * world_matrix;
616 glMatrixMode(GL_MODELVIEW);
617 load_matrix_gl(modelview);
620 #define BUFFER_OFFSET(i) ((char *)NULL + (i))
622 void draw(const VertexArray &varray) {
623 load_xform_matrices();
625 bool use_vbo = !varray.get_dynamic() && sys_caps.vertex_buffers;
627 glEnableClientState(GL_VERTEX_ARRAY);
628 glEnableClientState(GL_COLOR_ARRAY);
629 glEnableClientState(GL_NORMAL_ARRAY);
633 glBindBuffer(GL_ARRAY_BUFFER_ARB, varray.get_buffer_object());
634 glVertexPointer(3, GL_SCALAR_TYPE, sizeof(Vertex), (void*)((char*)&v.pos - (char*)&v));
635 glNormalPointer(GL_SCALAR_TYPE, sizeof(Vertex), (void*)((char*)&v.normal - (char*)&v));
636 glColorPointer(4, GL_SCALAR_TYPE, sizeof(Vertex), (void*)((char*)&v.color - (char*)&v));
638 for(int i=0; i<MAX_TEXTURES; i++) {
639 select_texture_unit(i);
640 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
642 int dim = ttype[i] == TEX_1D ? 1 : (ttype[i] == TEX_3D || ttype[i] == TEX_CUBE ? 3 : 2);
643 glTexCoordPointer(dim, GL_SCALAR_TYPE, sizeof(Vertex), (void*)((char*)&v.tex[coord_index[i]] - (char*)&v));
646 glBindBuffer(GL_ARRAY_BUFFER_ARB, 0);
648 glVertexPointer(3, GL_SCALAR_TYPE, sizeof(Vertex), &varray.get_data()->pos);
649 glNormalPointer(GL_SCALAR_TYPE, sizeof(Vertex), &varray.get_data()->normal);
650 glColorPointer(4, GL_SCALAR_TYPE, sizeof(Vertex), &varray.get_data()->color);
652 for(int i=0; i<MAX_TEXTURES; i++) {
653 select_texture_unit(i);
654 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
656 int dim = ttype[i] == TEX_1D ? 1 : (ttype[i] == TEX_3D || ttype[i] == TEX_CUBE ? 3 : 2);
657 glTexCoordPointer(dim, GL_SCALAR_TYPE, sizeof(Vertex), &varray.get_data()->tex[coord_index[i]]);
661 glDrawArrays(primitive_type, 0, varray.get_count());
663 glDisableClientState(GL_VERTEX_ARRAY);
664 glDisableClientState(GL_COLOR_ARRAY);
665 glDisableClientState(GL_NORMAL_ARRAY);
667 for(int i=0; i<MAX_TEXTURES; i++) {
668 select_texture_unit(i);
669 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
673 void draw(const VertexArray &varray, const IndexArray &iarray) {
674 load_xform_matrices();
676 bool use_vbo = !varray.get_dynamic() && sys_caps.vertex_buffers;
677 bool use_ibo = false;//!iarray.get_dynamic() && sys_caps.vertex_buffers;
679 glEnableClientState(GL_VERTEX_ARRAY);
680 glEnableClientState(GL_COLOR_ARRAY);
681 glEnableClientState(GL_NORMAL_ARRAY);
685 glBindBuffer(GL_ARRAY_BUFFER_ARB, varray.get_buffer_object());
686 glVertexPointer(3, GL_SCALAR_TYPE, sizeof(Vertex), (void*)((char*)&v.pos - (char*)&v));
687 glNormalPointer(GL_SCALAR_TYPE, sizeof(Vertex), (void*)((char*)&v.normal - (char*)&v));
688 glColorPointer(4, GL_SCALAR_TYPE, sizeof(Vertex), (void*)((char*)&v.color - (char*)&v));
690 for(int i=0; i<MAX_TEXTURES; i++) {
691 select_texture_unit(i);
692 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
694 int dim = ttype[i] == TEX_1D ? 1 : (ttype[i] == TEX_3D || ttype[i] == TEX_CUBE ? 3 : 2);
695 glTexCoordPointer(dim, GL_SCALAR_TYPE, sizeof(Vertex), (void*)((char*)&v.tex[coord_index[i]] - (char*)&v));
698 glBindBuffer(GL_ARRAY_BUFFER_ARB, 0);
700 glVertexPointer(3, GL_SCALAR_TYPE, sizeof(Vertex), &varray.get_data()->pos);
701 glNormalPointer(GL_SCALAR_TYPE, sizeof(Vertex), &varray.get_data()->normal);
702 glColorPointer(4, GL_SCALAR_TYPE, sizeof(Vertex), &varray.get_data()->color);
704 for(int i=0; i<MAX_TEXTURES; i++) {
705 select_texture_unit(i);
706 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
708 int dim = ttype[i] == TEX_1D ? 1 : (ttype[i] == TEX_3D || ttype[i] == TEX_CUBE ? 3 : 2);
709 glTexCoordPointer(dim, GL_SCALAR_TYPE, sizeof(Vertex), &varray.get_data()->tex[coord_index[i]]);
714 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, iarray.get_buffer_object());
715 glDrawElements(primitive_type, iarray.get_count(), GL_UNSIGNED_INT, 0);
716 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
718 glDrawElements(primitive_type, iarray.get_count(), GL_UNSIGNED_INT, iarray.get_data());
721 glDisableClientState(GL_VERTEX_ARRAY);
722 glDisableClientState(GL_COLOR_ARRAY);
723 glDisableClientState(GL_NORMAL_ARRAY);
725 for(int i=0; i<MAX_TEXTURES; i++) {
726 select_texture_unit(i);
727 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
732 /* draw_line(start_vertex, end_vertex, start_width, end_width)
733 * Draws a line as a cylindrically billboarded elongated quad.
735 void draw_line(const Vertex &v1, const Vertex &v2, scalar_t w1, scalar_t w2, const Color &col) {
736 if(w2 < 0.0) w2 = w1;
741 Vector3 cam_pos = Vector3(0,0,0).transformed(inv_view_matrix);
743 Vector3 vec = p2 - p1;
744 scalar_t len = vec.length();
747 basis.k = -(cam_pos - ((p2 + p1) / 2)).normalized();
749 basis.i = cross_product(basis.j, basis.k).normalized();
750 basis.k = cross_product(basis.i, basis.j).normalized();
752 world_matrix.set_translation(p1);
753 world_matrix = world_matrix * Matrix4x4(basis.create_rotation_matrix());
754 load_xform_matrices();
757 Vertex(Vector3(-w1, 0, 0), v1.tex[0].u, 0.0, col),
758 Vertex(Vector3(-w2, len, 0), v2.tex[0].u, 0.0, col),
759 Vertex(Vector3(w2, len, 0), v2.tex[0].u, 1.0, col),
760 Vertex(Vector3(w1, 0, 0), v1.tex[0].u, 1.0, col)
764 set_primitive_type(QUAD_LIST);
765 draw(VertexArray(quad, 4));
766 set_primitive_type(TRIANGLE_LIST);
770 void draw_point(const Vertex &pt, scalar_t size) {
774 Vector3 cam_pos = Vector3(0,0,0).transformed(inv_view_matrix);
777 basis.k = -(cam_pos - p).normalized();
778 basis.j = Vector3(0, 1, 0);
779 basis.i = cross_product(basis.j, basis.k);
780 basis.j = cross_product(basis.k, basis.i);
782 world_matrix.set_translation(p);
783 world_matrix = world_matrix * Matrix4x4(basis.create_rotation_matrix());
784 load_xform_matrices();
787 Vertex(Vector3(-size, -size, 0), 0.0, 0.0, pt.color),
788 Vertex(Vector3(-size, size, 0), 0.0, 1.0, pt.color),
789 Vertex(Vector3(size, size, 0), 1.0, 1.0, pt.color),
790 Vertex(Vector3(size, -size, 0), 1.0, 0.0, pt.color)
794 set_primitive_type(QUAD_LIST);
795 draw(VertexArray(quad, 4));
796 set_primitive_type(TRIANGLE_LIST);
802 void draw_scr_quad(const Vector2 &corner1, const Vector2 &corner2, const Color &color, bool reset_xform) {
804 glMatrixMode(GL_MODELVIEW);
809 glMatrixMode(GL_PROJECTION);
812 glOrtho(0.0, 1.0, 1.0, 0.0, 0.0, 1.0);
814 glDisable(GL_LIGHTING);
817 glColor4f(color.r, color.g, color.b, color.a);
818 glTexCoord2f(0.0f, 1.0f);
819 glVertex3f(corner1.x, corner1.y, -0.5);
820 glTexCoord2f(1.0f, 1.0f);
821 glVertex3f(corner2.x, corner1.y, -0.5);
822 glTexCoord2f(1.0f, 0.0f);
823 glVertex3f(corner2.x, corner2.y, -0.5);
824 glTexCoord2f(0.0f, 0.0f);
825 glVertex3f(corner1.x, corner2.y, -0.5);
828 glEnable(GL_LIGHTING);
833 glMatrixMode(GL_MODELVIEW);
838 int get_texture_unit_count() {
839 return sys_caps.max_texture_units;
842 //////////////////// render states /////////////////////
844 void set_primitive_type(PrimitiveType pt) {
848 void set_backface_culling(bool enable) {
850 glEnable(GL_CULL_FACE);
852 glDisable(GL_CULL_FACE);
856 void set_front_face(FaceOrder order) {
860 void set_auto_normalize(bool enable) {
862 glEnable(GL_NORMALIZE);
864 glDisable(GL_NORMALIZE);
868 void set_color_write(bool red, bool green, bool blue, bool alpha) {
869 glColorMask(red, green, blue, alpha);
872 void set_wireframe(bool enable) {
873 //set_primitive_type(enable ? LINE_LIST : TRIANGLE_LIST);
874 glPolygonMode(GL_FRONT_AND_BACK, enable ? GL_LINE : GL_FILL);
878 ///////////////// blending states ///////////////
880 void set_alpha_blending(bool enable) {
888 void set_blend_func(BlendingFactor src, BlendingFactor dest) {
889 glBlendFunc(src, dest);
892 ///////////////// zbuffer states ////////////////
894 void set_zbuffering(bool enable) {
896 glEnable(GL_DEPTH_TEST);
898 glDisable(GL_DEPTH_TEST);
902 void set_zwrite(bool enable) {
906 void set_zfunc(CmpFunc func) {
910 /////////////// stencil states //////////////////
911 void set_stencil_buffering(bool enable) {
913 glEnable(GL_STENCIL_TEST);
915 glDisable(GL_STENCIL_TEST);
919 void set_stencil_pass_op(StencilOp sop) {
921 glStencilOp(stencil_fail, stencil_pzfail, stencil_pass);
924 void set_stencil_fail_op(StencilOp sop) {
926 glStencilOp(stencil_fail, stencil_pzfail, stencil_pass);
929 void set_stencil_pass_zfail_op(StencilOp sop) {
930 stencil_pzfail = sop;
931 glStencilOp(stencil_fail, stencil_pzfail, stencil_pass);
934 void set_stencil_op(StencilOp fail, StencilOp spass_zfail, StencilOp pass) {
936 stencil_pzfail = spass_zfail;
938 glStencilOp(stencil_fail, stencil_pzfail, stencil_pass);
941 void set_stencil_func(CmpFunc func) {
942 glStencilFunc(func, stencil_ref, 0xffffffff);
945 void set_stencil_reference(unsigned int ref) {
949 ///////////// texture & material states //////////////
951 void set_point_sprites(bool enable) {
952 if(sys_caps.point_sprites) {
954 glEnable(GL_POINT_SPRITE_ARB);
956 glDisable(GL_POINT_SPRITE_ARB);
961 void set_texture_filtering(int tex_unit, TextureFilteringType tex_filter) {
967 min_filter = mipmapping ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST;
968 glTexParameteri(ttype[tex_unit], GL_TEXTURE_MIN_FILTER, min_filter);
969 glTexParameteri(ttype[tex_unit], GL_TEXTURE_MAG_FILTER, GL_NEAREST);
972 case BILINEAR_FILTERING:
973 min_filter = mipmapping ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR;
974 glTexParameteri(ttype[tex_unit], GL_TEXTURE_MIN_FILTER, min_filter);
975 glTexParameteri(ttype[tex_unit], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
978 case TRILINEAR_FILTERING:
980 min_filter = mipmapping ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR;
981 glTexParameteri(ttype[tex_unit], GL_TEXTURE_MIN_FILTER, min_filter);
982 glTexParameteri(ttype[tex_unit], GL_TEXTURE_MAG_FILTER, GL_LINEAR);
987 void set_texture_addressing(int tex_unit, TextureAddressing uaddr, TextureAddressing vaddr) {
988 glTexParameteri(ttype[tex_unit], GL_TEXTURE_WRAP_S, uaddr);
989 glTexParameteri(ttype[tex_unit], GL_TEXTURE_WRAP_T, vaddr);
992 void set_texture_border_color(int tex_unit, const Color &color) {
993 float col[] = {color.r, color.g, color.b, color.a};
994 glTexParameterfv(ttype[tex_unit], GL_TEXTURE_BORDER_COLOR, col);
997 void set_texture(int tex_unit, const Texture *tex) {
998 select_texture_unit(tex_unit);
999 glBindTexture(tex->get_type(), tex->tex_id);
1000 ttype[tex_unit] = tex->get_type();
1003 void set_mip_mapping(bool enable) {
1004 mipmapping = enable;
1007 void set_material(const Material &mat) {
1008 mat.set_glmaterial();
1011 void use_vertex_colors(bool enable) {
1013 glEnable(GL_COLOR_MATERIAL);
1015 glDisable(GL_COLOR_MATERIAL);
1020 void set_render_target(Texture *tex, CubeMapFace cube_map_face) {
1021 static std::stack<Texture*> rt_stack;
1022 static std::stack<CubeMapFace> face_stack;
1024 Texture *prev = rt_stack.empty() ? 0 : rt_stack.top();
1025 CubeMapFace prev_face = CUBE_MAP_PX; // just to get rid of the uninitialized var warning
1026 if(!face_stack.empty()) prev_face = face_stack.top();
1028 if(tex == prev) return;
1031 set_texture(0, prev);
1032 glCopyTexSubImage2D(prev->get_type() == TEX_CUBE ? prev_face : GL_TEXTURE_2D, 0, 0, 0, 0, 0, prev->width, prev->height);
1037 if(prev->get_type() == TEX_CUBE) {
1040 if(rt_stack.empty()) {
1041 set_viewport(0, 0, gparams.x, gparams.y);
1043 set_viewport(0, 0, rt_stack.top()->width, rt_stack.top()->height);
1047 if(tex->get_type() == TEX_CUBE) {
1048 set_viewport(0, 0, tex->width, tex->height);
1052 if(tex->get_type() == TEX_CUBE) face_stack.push(cube_map_face);
1056 void copy_texture(Texture *tex, bool full_screen) {
1059 int width = full_screen ? get_graphics_init_parameters()->x : tex->width;
1060 int height = full_screen ? get_graphics_init_parameters()->y : tex->height;
1062 set_texture(0, tex);
1063 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height);
1066 // multitexturing interface
1068 void select_texture_unit(int tex_unit) {
1069 if(sys_caps.multitex) {
1070 glext::glActiveTexture(GL_TEXTURE0 + tex_unit);
1071 glext::glClientActiveTexture(GL_TEXTURE0 + tex_unit);
1075 void enable_texture_unit(int tex_unit) {
1076 if(!tex_unit || (sys_caps.multitex && tex_unit < sys_caps.max_texture_units)) {
1077 select_texture_unit(tex_unit);
1078 glEnable(ttype[tex_unit]);
1082 void disable_texture_unit(int tex_unit) {
1083 if(!tex_unit || (sys_caps.multitex && tex_unit < sys_caps.max_texture_units)) {
1084 select_texture_unit(tex_unit);
1085 glDisable(ttype[tex_unit]);
1089 void set_texture_unit_color(int tex_unit, TextureBlendFunction op, TextureBlendArgument arg1, TextureBlendArgument arg2, TextureBlendArgument arg3) {
1091 select_texture_unit(tex_unit);
1092 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1093 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, op);
1094 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, arg1);
1095 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, arg2);
1096 if(arg3 != TARG_NONE) {
1097 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, arg3);
1101 void set_texture_unit_alpha(int tex_unit, TextureBlendFunction op, TextureBlendArgument arg1, TextureBlendArgument arg2, TextureBlendArgument arg3) {
1103 select_texture_unit(tex_unit);
1104 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
1105 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, op);
1106 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, arg1);
1107 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, arg2);
1108 if(arg3 != TARG_NONE) {
1109 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, arg3);
1113 void set_texture_coord_index(int tex_unit, int index) {
1114 coord_index[tex_unit] = index;
1117 void set_texture_constant(int tex_unit, const Color &col) {
1118 float color[] = {col.r, col.g, col.b, col.a};
1119 select_texture_unit(tex_unit);
1120 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
1123 //void set_texture_transform_state(int sttex_unitage, TexTransformState TexXForm);
1124 //void set_texture_coord_generator(int stage, TexGen tgen);
1126 void set_point_sprite_coords(int tex_unit, bool enable) {
1127 if(sys_caps.point_params) {
1128 select_texture_unit(tex_unit);
1129 glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, enable ? GL_TRUE : GL_FALSE);
1134 // programmable interface
1135 void set_gfx_program(GfxProg *prog) {
1136 if(!sys_caps.prog.glslang) return;
1140 if(!prog->linked) return;
1142 glUseProgramObject(prog->prog);
1144 // call any registered update handlers
1145 if(prog->update_handler) {
1146 prog->update_handler(prog);
1149 glUseProgramObject(0);
1154 void set_lighting(bool enable) {
1156 glEnable(GL_LIGHTING);
1158 glDisable(GL_LIGHTING);
1162 void set_ambient_light(const Color &ambient_color) {
1163 float col[] = {ambient_color.r, ambient_color.g, ambient_color.b, ambient_color.a};
1164 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col);
1167 void set_shading_mode(ShadeMode mode) {
1171 void set_bump_light(const Light *light) {
1175 // transformation matrices
1176 void set_matrix(TransformType xform_type, const Matrix4x4 &mat, int num) {
1177 switch(xform_type) {
1184 inv_view_matrix = view_matrix.inverse();
1185 view_mat_camera = 0;
1188 case XFORM_PROJECTION:
1193 tex_matrix[num] = mat;
1198 Matrix4x4 get_matrix(TransformType xform_type, int num) {
1199 switch(xform_type) {
1201 return world_matrix;
1207 return tex_matrix[num];
1209 case XFORM_PROJECTION:
1215 void set_viewport(unsigned int x, unsigned int y, unsigned int xsize, unsigned int ysize)
1217 glViewport(x, y, xsize, ysize);
1220 // normalized set_viewport()
1221 void set_viewport_norm(float x, float y, float xsize, float ysize)
1223 glViewport((int) (x * gparams.x), (int)(y * gparams.y),
1224 (int) (xsize * gparams.x), int (ysize * gparams.y));
1227 Matrix4x4 create_projection_matrix(scalar_t vfov, scalar_t aspect, scalar_t near_clip, scalar_t far_clip) {
1229 scalar_t f = 1.0f / (scalar_t)tan(vfov * 0.5f);
1230 scalar_t q = far_clip / (far_clip - near_clip);
1233 mat[0][0] = f / aspect;
1237 mat[2][3] = -q * near_clip;
1239 scalar_t f = 1.0f / (scalar_t)tan(vfov * 0.5f);
1242 mat[0][0] = f / aspect;
1244 mat[2][2] = (far_clip + near_clip) / (near_clip - far_clip);
1246 mat[2][3] = (2.0f * far_clip * near_clip) / (near_clip - far_clip);
1256 bool screen_capture(char *fname, enum image_file_format fmt) {
1258 static const char *suffix[] = {"png", "jpg", "tga", "oug1", "oug2"};
1262 uint32_t *pixels = new uint32_t[x * y];
1263 glReadPixels(0, 0, x, y, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
1266 static char fname_buf[50];
1268 sprintf(fname, "3dengfx_shot%04d.%s", scr_num++, suffix[fmt]);
1271 unsigned int flags = get_image_save_flags();
1272 set_image_save_flags(flags | IMG_SAVE_INVERT);
1273 int res = save_image(fname, pixels, x, y, fmt);
1274 set_image_save_flags(flags);