r1005: Increase the number of displayed digits for resample audio dialog box
[cinelerra_cv/mob.git] / guicast / vframe3d.C
blob1408696ff351508b95a438a322c2f42352e30eec
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;
35 int VFrame::get_window_id()
37         return texture ? texture->window_id : -1;
40 int VFrame::get_texture_id()
42         return texture ? texture->texture_id : -1;
45 int VFrame::get_texture_w()
47         return texture ? texture->texture_w : 0;
50 int VFrame::get_texture_h()
52         return texture ? texture->texture_h : 0;
56 int VFrame::get_texture_components()
58         return texture ? texture->texture_components : 0;
71 void VFrame::to_texture()
73 #ifdef HAVE_GL
75 // Must be here so user can create textures without copying data by setting
76 // opengl_state to TEXTURE.
77         BC_Texture::new_texture(&texture,
78                 get_w(),
79                 get_h(),
80                 get_color_model());
82 // Determine what to do based on state
83         switch(opengl_state)
84         {
85                 case VFrame::TEXTURE:
86                         return;
88                 case VFrame::SCREEN:
89                         if((get_w() % 4) || (get_h() % 4)) 
90                         {
91                                 printf("VFrame::to_texture w=%d h=%d\n", get_w(), get_h());
92                                 return;
93                         }
94                         if(pbuffer)
95                         {
96                                 enable_opengl();
97                                 screen_to_texture();
98                         }
99                         opengl_state = VFrame::TEXTURE;
100                         return;
101         }
103 //printf("VFrame::to_texture %d\n", texture_id);
105         switch(color_model)
106         {
107                 case BC_RGB888:
108                 case BC_YUV888:
109                         glTexSubImage2D(GL_TEXTURE_2D,
110                                 0,
111                                 0,
112                                 0,
113                                 get_w(),
114                                 get_h(),
115                                 GL_RGB,
116                                 GL_UNSIGNED_BYTE,
117                                 get_rows()[0]);
118                         break;
120                 case BC_RGBA8888:
121                 case BC_YUVA8888:
122                         glTexSubImage2D(GL_TEXTURE_2D,
123                                 0,
124                                 0,
125                                 0,
126                                 get_w(),
127                                 get_h(),
128                                 GL_RGBA,
129                                 GL_UNSIGNED_BYTE,
130                                 get_rows()[0]);
131                         break;
133                 case BC_RGB_FLOAT:
134                         glTexSubImage2D(GL_TEXTURE_2D,
135                                 0,
136                                 0,
137                                 0,
138                                 get_w(),
139                                 get_h(),
140                                 GL_RGB,
141                                 GL_FLOAT,
142                                 get_rows()[0]);
143                         break;
145                 case BC_RGBA_FLOAT:
146                         glTexSubImage2D(GL_TEXTURE_2D,
147                                 0,
148                                 0,
149                                 0,
150                                 get_w(),
151                                 get_h(),
152                                 GL_RGBA,
153                                 GL_FLOAT,
154                                 get_rows()[0]);
155                         break;
157                 default:
158                         fprintf(stderr, 
159                                 "VFrame::to_texture: unsupported color model %d.\n", 
160                                 color_model);
161                         break;
162         }
164         opengl_state = VFrame::TEXTURE;
165 #endif
168 void VFrame::to_ram()
170 #ifdef HAVE_GL
171         switch(opengl_state)
172         {
173 // Only pbuffer is supported since this is only called after the 
174 // overlay operation onto the pbuffer.
175                 case VFrame::SCREEN:
176                         if(pbuffer)
177                         {
178                                 enable_opengl();
179 printf("VFrame::to_ram %d %d\n", get_w(), get_h());
180                                 glReadPixels(0, 
181                                         0, 
182                                         get_w(), 
183                                         get_h(), 
184                                         GL_RGB,
185                                         GL_UNSIGNED_BYTE,
186                                         get_rows()[0]);
187                                 flip_vert();
188                         }
189                         opengl_state = VFrame::RAM;
190                         return;
191         }
192 #endif
195 void VFrame::create_pbuffer()
197 SET_TRACE
198         if(pbuffer && 
199                 pbuffer->window_id != BC_WindowBase::get_synchronous()->current_window->get_id())
200         {
201 SET_TRACE
202                 delete pbuffer;
203 SET_TRACE
204                 pbuffer = 0;
205         }
207         if((get_w() % 4) || (get_h() % 4))
208         {
209                 printf("VFrame::create_pbuffer w=%d h=%d\n", get_w(), get_h());
210                 return;
211         }
213 SET_TRACE
214         if(!pbuffer)
215         {
216                 pbuffer = new BC_PBuffer(get_w(), get_h());
217         }
218 SET_TRACE
221 void VFrame::enable_opengl()
223         create_pbuffer();
224         if(pbuffer)
225         {
226                 pbuffer->enable_opengl();
227         }
230 BC_PBuffer* VFrame::get_pbuffer()
232         return pbuffer;
236 void VFrame::screen_to_texture(int x, int y, int w, int h)
238 #ifdef HAVE_GL
239 // Create texture
240         BC_Texture::new_texture(&texture,
241                 get_w(),
242                 get_h(),
243                 get_color_model());
245         if(pbuffer)
246         {
247                 glEnable(GL_TEXTURE_2D);
249 // Read canvas into texture
250 // According to the man page, it must be GL_BACK for the onscreen buffer 
251 // and GL_FRONT for a single buffered PBuffer.  In reality it must be
252 // GL_BACK for a single buffered PBuffer if the PBuffer has alpha and using
253 // GL_FRONT captures the onscreen front buffer.
254 //              glReadBuffer(BC_WindowBase::get_synchronous()->is_pbuffer ? 
255 //                      GL_FRONT : GL_BACK);
256                 glReadBuffer(GL_BACK);
257                 glCopyTexSubImage2D(GL_TEXTURE_2D,
258                         0,
259                         0,
260                         0,
261                         x >= 0 ? x : 0,
262                         y >= 0 ? y : 0,
263                         w >= 0 ? w : get_w(),
264                         h >= 0 ? h : get_h());
265         }
266 #endif
269 void VFrame::draw_texture(float in_x1, 
270                 float in_y1,
271                 float in_x2,
272                 float in_y2,
273                 float out_x1,
274                 float out_y1,
275                 float out_x2,
276                 float out_y2,
277                 int flip_y)
279 #ifdef HAVE_GL
280         glBegin(GL_QUADS);
281         glNormal3f(0, 0, 1.0);
283         glTexCoord2f(in_x1 / get_texture_w(), in_y1 / get_texture_h());
284         glVertex3f(out_x1, flip_y ? -out_y1 : -out_y2, 0);
286         glTexCoord2f(in_x2 / get_texture_w(), in_y1 / get_texture_h());
287         glVertex3f(out_x2, flip_y ? -out_y1 : -out_y2, 0);
289         glTexCoord2f(in_x2 / get_texture_w(), in_y2 / get_texture_h());
290         glVertex3f(out_x2, flip_y ? -out_y2 : -out_y1, 0);
292         glTexCoord2f(in_x1 / get_texture_w(), in_y2 / get_texture_h());
293         glVertex3f(out_x1, flip_y ? -out_y2 : -out_y1, 0);
296         glEnd();
298 #endif
301 void VFrame::draw_texture(int flip_y)
303         draw_texture(0, 
304                 0,
305                 get_w(),
306                 get_h(),
307                 0,
308                 0,
309                 get_w(),
310                 get_h(),
311                 flip_y);
315 void VFrame::bind_texture(int texture_unit)
317 // Bind the texture
318         if(texture)
319         {
320                 texture->bind(texture_unit);
321         }
329 void VFrame::init_screen(int w, int h)
331 #ifdef HAVE_GL
332         glViewport(0, 0, w, h);
333         glMatrixMode(GL_PROJECTION);
334         glLoadIdentity();
335         float near = 1;
336         float far = 100;
337         float frustum_ratio = near / ((near + far) / 2);
338         float near_h = (float)h * 
339                 frustum_ratio;
340         float near_w = (float)w * 
341                 frustum_ratio;
342         glFrustum(-near_w / 2, 
343                 near_w / 2, 
344                 -near_h / 2, 
345                 near_h / 2, 
346                 near, 
347                 far);
348         glMatrixMode(GL_MODELVIEW);
349         glLoadIdentity();
350 // Shift down and right so 0,0 is the top left corner
351         glTranslatef(-w / 2, h / 2, 0.0);
352         glTranslatef(0.0, 0.0, -(far + near) / 2);
354         glDisable(GL_DEPTH_TEST);
355         glShadeModel(GL_SMOOTH);
356 // Default for direct copy playback
357         glDisable(GL_BLEND);
358         glDisable(GL_COLOR_MATERIAL);
359         glDisable(GL_CULL_FACE);
360         glEnable(GL_NORMALIZE);
361         glAlphaFunc(GL_GREATER, 0);
362         glDisable(GL_LIGHTING);
364         const GLfloat one[] = { 1, 1, 1, 1 };
365         const GLfloat zero[] = { 0, 0, 0, 0 };
366         const GLfloat light_position[] = { 0, 0, -1, 0 };
367         const GLfloat light_direction[] = { 0, 0, 1, 0 };
369 //      glEnable(GL_LIGHT0);
370 //      glLightfv(GL_LIGHT0, GL_AMBIENT, zero);
371 //      glLightfv(GL_LIGHT0, GL_DIFFUSE, one);
372 //      glLightfv(GL_LIGHT0, GL_SPECULAR, one);
373 //      glLighti(GL_LIGHT0, GL_SPOT_CUTOFF, 180);
374 //      glLightfv(GL_LIGHT0, GL_POSITION, light_position);
375 //      glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_direction);
376 //      glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
377 //      glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zero);
378         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, zero);
379         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, zero);
380         glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, zero);
381         glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, zero);
382         glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0);
383 #endif
386 void VFrame::init_screen()
388         init_screen(get_w(), get_h());
391 static int print_error(char *source, unsigned int object, int is_program)
393 #ifdef HAVE_GL
394     char string[BCTEXTLEN];
395         int len = 0;
396     if(is_program)
397                 glGetProgramInfoLog(object, BCTEXTLEN, &len, string);
398         else
399                 glGetShaderInfoLog(object, BCTEXTLEN, &len, string);
400         if(len > 0) printf("Playback3D::print_error:\n%s\n%s\n", source, string);
401         if(len > 0) return 1;
402         return 0;
403 #endif
410 unsigned int VFrame::make_shader(int x, ...)
412         unsigned int result = 0;
413 #ifdef HAVE_GL
414 // Construct single source file out of arguments
415         char *complete_program = 0;
416         int complete_size = 0;
417         int current_shader = 0;
419         va_list list;
420         va_start(list, x);
422         while(1)
423         {
424                 char *text = va_arg(list, char*);
425                 if(!text) break;
427 SET_TRACE
428 // Replace one occurrance in each source of main() with a unique id.
429                 char main_replacement[BCTEXTLEN];
430 SET_TRACE
431                 sprintf(main_replacement, "main%03d()", current_shader);
432 //printf("VFrame::make_shader %s %s\n", text, main_replacement);
433 SET_TRACE
434                 char *source_replacement = new char[strlen(text) + strlen(main_replacement) + 1];
435 SET_TRACE
436                 char *ptr = strstr(text, "main()");
437 SET_TRACE
439                 if(ptr)
440                 {
441                         memcpy(source_replacement, text, ptr - text);
442                         source_replacement[ptr - text] = 0;
443                         strcat(source_replacement, main_replacement);
444                         ptr += strlen("main()");
445                         strcat(source_replacement, ptr);
446                         current_shader++;
447                 }
448                 else
449                 {
450                         memcpy(source_replacement, text, strlen(text));
451                         source_replacement[strlen(text)] = 0;
452                 }
453 SET_TRACE
455                 if(!complete_program)
456                 {
457                         complete_size = strlen(source_replacement) + 1;
458                         complete_program = (char*)malloc(complete_size);
459                         strcpy(complete_program, source_replacement);
460                 }
461                 else
462                 {
463                         complete_size += strlen(source_replacement);
464                         complete_program = (char*)realloc(complete_program, complete_size);
465                         strcat(complete_program, source_replacement);
466                 }
468                 delete [] source_replacement;
469 SET_TRACE
470         }
472 // Add main() function which calls all the unique main replacements in order
473         char main_function[BCTEXTLEN];
474         sprintf(main_function, 
475                 "\n"
476                 "void main()\n"
477                 "{\n");
479         for(int i = 0; i < current_shader; i++)
480         {
481                 char main_replacement[BCTEXTLEN];
482                 sprintf(main_replacement, "\tmain%03d();\n", i);
483                 strcat(main_function, main_replacement);
484         }
486         strcat(main_function, "}\n");
487         if(!complete_program)
488         {
489                 complete_size = strlen(main_function) + 1;
490                 complete_program = (char*)malloc(complete_size);
491                 strcpy(complete_program, main_function);
492         }
493         else
494         {
495                 complete_size += strlen(main_function);
496                 complete_program = (char*)realloc(complete_program, complete_size);
497                 strcat(complete_program, main_function);
498         }
504         int got_it = 0;
505         result = BC_WindowBase::get_synchronous()->get_shader(complete_program, 
506                 &got_it);
508         if(!got_it)
509         {
510                 result = glCreateProgram();
512                 unsigned int shader;
513                 shader = glCreateShader(GL_FRAGMENT_SHADER);
514                 const GLchar *text_ptr = complete_program;
515                 glShaderSource(shader, 1, &text_ptr, NULL);
516                 glCompileShader(shader);
517                 int error = print_error(complete_program, shader, 0);
518                 glAttachShader(result, shader);
519                 glDeleteShader(shader);
521                 glLinkProgram(result);
522                 if(!error) error = print_error(complete_program, result, 1);
525 // printf("BC_WindowBase::make_shader: shader=%d window_id=%d\n", 
526 // result,
527 // BC_WindowBase::get_synchronous()->current_window->get_id());
528                 BC_WindowBase::get_synchronous()->put_shader(result, complete_program);
529         }
531 //printf("VFrame::make_shader\n%s\n", complete_program);
532         delete [] complete_program;
534 #endif
535         return result;
538 void VFrame::dump_shader(int shader_id)
540         BC_WindowBase::get_synchronous()->dump_shader(shader_id);
544 void VFrame::clear_pbuffer()
546 #ifdef HAVE_GL
547         if(cmodel_is_yuv(get_color_model()))
548                 glClearColor(0.0, 0.5, 0.5, 0.0);
549         else
550                 glClearColor(0.0, 0.0, 0.0, 0.0);
551         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
552 #endif