r854: Merge 2.1:
[cinelerra_cv/ct.git] / guicast / vframe3d.C
blobf9bbb7f38f6b3fbad12302ded76726fa26f7bbce
1 #define GL_GLEXT_PROTOTYPES
3 #include "bcpbuffer.h"
4 #include "bcresources.h"
5 #include "bcsignals.h"
6 #include "bcsynchronous.h"
7 #include "bctexture.h"
8 #include "bcwindowbase.h"
9 #include "vframe.h"
11 #if defined(HAVE_CONFIG_H)
12 #include "config.h"
13 #endif
15 #ifdef HAVE_GL
16 #include <GL/gl.h>
17 #include <GL/glext.h>
18 #endif
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
25 int VFrame::get_opengl_state()
27         return opengl_state;
30 void VFrame::set_opengl_state(int value)
32         opengl_state = value;
36 int VFrame::get_texture_id()
38         return texture ? texture->texture_id : -1;
41 int VFrame::get_texture_w()
43         return texture ? texture->texture_w : 0;
46 int VFrame::get_texture_h()
48         return texture ? texture->texture_h : 0;
62 void VFrame::to_texture()
64 #ifdef HAVE_GL
66 // Must be here so user can create textures without copying data by setting
67 // opengl_state to TEXTURE.
68         BC_Texture::new_texture(&texture,
69                 get_w(),
70                 get_h(),
71                 get_color_model());
73 // Determine what to do based on state
74         switch(opengl_state)
75         {
76                 case VFrame::TEXTURE:
77                         return;
79                 case VFrame::SCREEN:
80                         if((get_w() % 4) || (get_h() % 4)) 
81                         {
82                                 printf("VFrame::to_texture w=%d h=%d\n", get_w(), get_h());
83                                 return;
84                         }
85                         if(pbuffer)
86                         {
87                                 enable_opengl();
88                                 screen_to_texture();
89                         }
90                         opengl_state = VFrame::TEXTURE;
91                         return;
92         }
94 //printf("VFrame::to_texture %d\n", texture_id);
96         switch(color_model)
97         {
98                 case BC_RGB888:
99                 case BC_YUV888:
100                         glTexSubImage2D(GL_TEXTURE_2D,
101                                 0,
102                                 0,
103                                 0,
104                                 get_w(),
105                                 get_h(),
106                                 GL_RGB,
107                                 GL_UNSIGNED_BYTE,
108                                 get_rows()[0]);
109                         break;
111                 case BC_RGBA8888:
112                 case BC_YUVA8888:
113                         glTexSubImage2D(GL_TEXTURE_2D,
114                                 0,
115                                 0,
116                                 0,
117                                 get_w(),
118                                 get_h(),
119                                 GL_RGBA,
120                                 GL_UNSIGNED_BYTE,
121                                 get_rows()[0]);
122                         break;
124                 case BC_RGB_FLOAT:
125                         glTexSubImage2D(GL_TEXTURE_2D,
126                                 0,
127                                 0,
128                                 0,
129                                 get_w(),
130                                 get_h(),
131                                 GL_RGB,
132                                 GL_FLOAT,
133                                 get_rows()[0]);
134                         break;
136                 case BC_RGBA_FLOAT:
137                         glTexSubImage2D(GL_TEXTURE_2D,
138                                 0,
139                                 0,
140                                 0,
141                                 get_w(),
142                                 get_h(),
143                                 GL_RGBA,
144                                 GL_FLOAT,
145                                 get_rows()[0]);
146                         break;
148                 default:
149                         fprintf(stderr, 
150                                 "VFrame::to_texture: unsupported color model %d.\n", 
151                                 color_model);
152                         break;
153         }
155         opengl_state = VFrame::TEXTURE;
156 #endif
160 void VFrame::create_pbuffer()
162 SET_TRACE
163         if(pbuffer && 
164                 pbuffer->window_id != BC_WindowBase::get_synchronous()->current_window->get_id())
165         {
166 SET_TRACE
167                 delete pbuffer;
168 SET_TRACE
169                 pbuffer = 0;
170         }
172         if((get_w() % 4) || (get_h() % 4))
173         {
174                 printf("VFrame::create_pbuffer w=%d h=%d\n", get_w(), get_h());
175                 return;
176         }
178 SET_TRACE
179         if(!pbuffer)
180         {
181                 pbuffer = new BC_PBuffer(get_w(), get_h());
182         }
183 SET_TRACE
186 void VFrame::enable_opengl()
188         create_pbuffer();
189         if(pbuffer)
190         {
191                 pbuffer->enable_opengl();
192         }
197 void VFrame::screen_to_texture(int x, int y, int w, int h)
199 #ifdef HAVE_GL
200 // Create texture
201         BC_Texture::new_texture(&texture,
202                 get_w(),
203                 get_h(),
204                 get_color_model());
206         if(pbuffer)
207         {
208                 glEnable(GL_TEXTURE_2D);
210 // Read canvas into texture
211 // According to the man page, it must be GL_BACK for the onscreen buffer 
212 // and GL_FRONT for a single buffered PBuffer.  In reality it must be
213 // GL_BACK for a single buffered PBuffer if the PBuffer has alpha and using
214 // GL_FRONT captures the onscreen front buffer.
215 //              glReadBuffer(BC_WindowBase::get_synchronous()->is_pbuffer ? 
216 //                      GL_FRONT : GL_BACK);
217                 glReadBuffer(GL_BACK);
218                 glCopyTexSubImage2D(GL_TEXTURE_2D,
219                         0,
220                         0,
221                         0,
222                         x >= 0 ? x : 0,
223                         y >= 0 ? y : 0,
224                         w >= 0 ? w : get_w(),
225                         h >= 0 ? h : get_h());
226         }
227 #endif
230 void VFrame::draw_texture(float in_x1, 
231                 float in_y1,
232                 float in_x2,
233                 float in_y2,
234                 float out_x1,
235                 float out_y1,
236                 float out_x2,
237                 float out_y2,
238                 int flip_y)
240 #ifdef HAVE_GL
241         glBegin(GL_QUADS);
242         glNormal3f(0, 0, 1.0);
244         glTexCoord2f(in_x1 / get_texture_w(), in_y1 / get_texture_h());
245         glVertex3f(out_x1, flip_y ? -out_y1 : -out_y2, 0);
247         glTexCoord2f(in_x2 / get_texture_w(), in_y1 / get_texture_h());
248         glVertex3f(out_x2, flip_y ? -out_y1 : -out_y2, 0);
250         glTexCoord2f(in_x2 / get_texture_w(), in_y2 / get_texture_h());
251         glVertex3f(out_x2, flip_y ? -out_y2 : -out_y1, 0);
253         glTexCoord2f(in_x1 / get_texture_w(), in_y2 / get_texture_h());
254         glVertex3f(out_x1, flip_y ? -out_y2 : -out_y1, 0);
257         glEnd();
259 #endif
262 void VFrame::draw_texture(int flip_y)
264         draw_texture(0, 
265                 0,
266                 get_w(),
267                 get_h(),
268                 0,
269                 0,
270                 get_w(),
271                 get_h(),
272                 flip_y);
276 void VFrame::bind_texture(int texture_unit)
278 // Bind the texture
279         if(texture)
280         {
281                 texture->bind(texture_unit);
282         }
290 void VFrame::init_screen(int w, int h)
292 #ifdef HAVE_GL
293         glViewport(0, 0, w, h);
294         glMatrixMode(GL_PROJECTION);
295         glLoadIdentity();
296         float near = 1;
297         float far = 100;
298         float frustum_ratio = near / ((near + far) / 2);
299         float near_h = (float)h * 
300                 frustum_ratio;
301         float near_w = (float)w * 
302                 frustum_ratio;
303         glFrustum(-near_w / 2, 
304                 near_w / 2, 
305                 -near_h / 2, 
306                 near_h / 2, 
307                 near, 
308                 far);
309         glMatrixMode(GL_MODELVIEW);
310         glLoadIdentity();
311 // Shift down and right so 0,0 is the top left corner
312         glTranslatef(-w / 2, h / 2, 0.0);
313         glTranslatef(0.0, 0.0, -(far + near) / 2);
315         glDisable(GL_DEPTH_TEST);
316         glShadeModel(GL_SMOOTH);
317 // Default for direct copy playback
318         glDisable(GL_BLEND);
319         glDisable(GL_COLOR_MATERIAL);
320         glDisable(GL_CULL_FACE);
321         glEnable(GL_NORMALIZE);
322         glAlphaFunc(GL_GREATER, 0);
323         glDisable(GL_LIGHTING);
325         const GLfloat one[] = { 1, 1, 1, 1 };
326         const GLfloat zero[] = { 0, 0, 0, 0 };
327         const GLfloat light_position[] = { 0, 0, -1, 0 };
328         const GLfloat light_direction[] = { 0, 0, 1, 0 };
330 //      glEnable(GL_LIGHT0);
331 //      glLightfv(GL_LIGHT0, GL_AMBIENT, zero);
332 //      glLightfv(GL_LIGHT0, GL_DIFFUSE, one);
333 //      glLightfv(GL_LIGHT0, GL_SPECULAR, one);
334 //      glLighti(GL_LIGHT0, GL_SPOT_CUTOFF, 180);
335 //      glLightfv(GL_LIGHT0, GL_POSITION, light_position);
336 //      glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_direction);
337 //      glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
338 //      glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zero);
339         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, zero);
340         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, zero);
341         glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, zero);
342         glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, zero);
343         glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0);
344 #endif
347 void VFrame::init_screen()
349         init_screen(get_w(), get_h());
352 static int print_error(char *source, unsigned int object, int is_program)
354 #ifdef HAVE_GL
355     char string[BCTEXTLEN];
356         int len = 0;
357     if(is_program)
358                 glGetProgramInfoLog(object, BCTEXTLEN, &len, string);
359         else
360                 glGetShaderInfoLog(object, BCTEXTLEN, &len, string);
361         if(len > 0) printf("Playback3D::print_error:\n%s\n%s\n", source, string);
362         if(len > 0) return 1;
363         return 0;
364 #endif
371 unsigned int VFrame::make_shader(int x, ...)
373         unsigned int result = 0;
374 #ifdef HAVE_GL
375 // Construct single source file out of arguments
376         char *complete_program = 0;
377         int complete_size = 0;
378         int current_shader = 0;
380         va_list list;
381         va_start(list, x);
383         while(1)
384         {
385                 char *text = va_arg(list, char*);
386                 if(!text) break;
388 SET_TRACE
389 // Replace one occurrance in each source of main() with a unique id.
390                 char main_replacement[BCTEXTLEN];
391 SET_TRACE
392                 sprintf(main_replacement, "main%03d()", current_shader);
393 //printf("VFrame::make_shader %s %s\n", text, main_replacement);
394 SET_TRACE
395                 char *source_replacement = new char[strlen(text) + strlen(main_replacement) + 1];
396 SET_TRACE
397                 char *ptr = strstr(text, "main()");
398 SET_TRACE
400                 if(ptr)
401                 {
402                         memcpy(source_replacement, text, ptr - text);
403                         source_replacement[ptr - text] = 0;
404                         strcat(source_replacement, main_replacement);
405                         ptr += strlen("main()");
406                         strcat(source_replacement, ptr);
407                         current_shader++;
408                 }
409                 else
410                 {
411                         memcpy(source_replacement, text, strlen(text));
412                         source_replacement[strlen(text)] = 0;
413                 }
414 SET_TRACE
416                 if(!complete_program)
417                 {
418                         complete_size = strlen(source_replacement) + 1;
419                         complete_program = (char*)malloc(complete_size);
420                         strcpy(complete_program, source_replacement);
421                 }
422                 else
423                 {
424                         complete_size += strlen(source_replacement);
425                         complete_program = (char*)realloc(complete_program, complete_size);
426                         strcat(complete_program, source_replacement);
427                 }
429                 delete [] source_replacement;
430 SET_TRACE
431         }
433 // Add main() function which calls all the unique main replacements in order
434         char main_function[BCTEXTLEN];
435         sprintf(main_function, 
436                 "\n"
437                 "void main()\n"
438                 "{\n");
440         for(int i = 0; i < current_shader; i++)
441         {
442                 char main_replacement[BCTEXTLEN];
443                 sprintf(main_replacement, "\tmain%03d();\n", i);
444                 strcat(main_function, main_replacement);
445         }
447         strcat(main_function, "}\n");
448         if(!complete_program)
449         {
450                 complete_size = strlen(main_function) + 1;
451                 complete_program = (char*)malloc(complete_size);
452                 strcpy(complete_program, main_function);
453         }
454         else
455         {
456                 complete_size += strlen(main_function);
457                 complete_program = (char*)realloc(complete_program, complete_size);
458                 strcat(complete_program, main_function);
459         }
465         int got_it = 0;
466         result = BC_WindowBase::get_synchronous()->get_shader(complete_program, 
467                 &got_it);
469         if(!got_it)
470         {
471                 result = glCreateProgram();
473                 unsigned int shader;
474                 shader = glCreateShader(GL_FRAGMENT_SHADER);
475                 const GLchar *text_ptr = complete_program;
476                 glShaderSource(shader, 1, &text_ptr, NULL);
477                 glCompileShader(shader);
478                 int error = print_error(complete_program, shader, 0);
479                 glAttachShader(result, shader);
480                 glDeleteShader(shader);
482                 glLinkProgram(result);
483                 if(!error) error = print_error(complete_program, result, 1);
486 // printf("BC_WindowBase::make_shader: shader=%d window_id=%d\n", 
487 // result,
488 // BC_WindowBase::get_synchronous()->current_window->get_id());
489                 BC_WindowBase::get_synchronous()->put_shader(result, complete_program);
490         }
492 //printf("VFrame::make_shader\n%s\n", complete_program);
493         delete [] complete_program;
495 #endif
496         return result;
499 void VFrame::dump_shader(int shader_id)
501         BC_WindowBase::get_synchronous()->dump_shader(shader_id);
505 void VFrame::clear_pbuffer()
507 #ifdef HAVE_GL
508         if(cmodel_is_yuv(get_color_model()))
509                 glClearColor(0.0, 0.5, 0.5, 0.0);
510         else
511                 glClearColor(0.0, 0.0, 0.0, 0.0);
512         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
513 #endif