add system build to autoconf/automake
[goodguy/history.git] / cinelerra-5.1 / guicast / vframe3d.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2011 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #define GL_GLEXT_PROTOTYPES
23
24 #include "bcpbuffer.h"
25 #include "bcresources.h"
26 #include "bcsignals.h"
27 #include "bcsynchronous.h"
28 #include "bctexture.h"
29 #include "bcwindowbase.h"
30 #include "vframe.h"
31
32 #ifdef HAVE_GL
33 #include <GL/gl.h>
34 #include <GL/glext.h>
35 #endif
36
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 int VFrame::get_opengl_state()
43 {
44         return opengl_state;
45 }
46
47 void VFrame::set_opengl_state(int value)
48 {
49         opengl_state = value;
50 }
51
52 int VFrame::get_window_id()
53 {
54         return texture ? texture->window_id : -1;
55 }
56
57 int VFrame::get_texture_id()
58 {
59         return texture ? texture->texture_id : -1;
60 }
61
62 int VFrame::get_texture_w()
63 {
64         return texture ? texture->texture_w : 0;
65 }
66
67 int VFrame::get_texture_h()
68 {
69         return texture ? texture->texture_h : 0;
70 }
71
72
73 int VFrame::get_texture_components()
74 {
75         return texture ? texture->texture_components : 0;
76 }
77
78
79
80
81
82
83
84
85
86
87
88 void VFrame::to_texture()
89 {
90 #ifdef HAVE_GL
91
92 // Must be here so user can create textures without copying data by setting
93 // opengl_state to TEXTURE.
94         BC_Texture::new_texture(&texture, get_w(), get_h(), get_color_model());
95
96 // Determine what to do based on state
97         switch(opengl_state) {
98         case VFrame::TEXTURE:
99                 return;
100
101         case VFrame::SCREEN:
102                 if((get_w() % 4) || (get_h() % 4)) {
103                         printf("VFrame::to_texture w=%d h=%d\n", get_w(), get_h());
104                         return;
105                 }
106                 if(pbuffer) {
107                         enable_opengl();
108                         screen_to_texture();
109                 }
110                 opengl_state = VFrame::TEXTURE;
111                 return;
112         }
113
114 //printf("VFrame::to_texture %d\n", texture_id);
115         GLenum type, format;
116         switch(color_model) {
117         case BC_RGB888:
118         case BC_YUV888:
119                 type = GL_UNSIGNED_BYTE;
120                 format = GL_RGB;
121                 break;
122
123         case BC_RGBA8888:
124         case BC_YUVA8888:
125                 type = GL_UNSIGNED_BYTE;
126                 format = GL_RGBA;
127                 break;
128
129         case BC_RGB_FLOAT:
130                 type = GL_FLOAT;
131                 format = GL_RGB;
132                 break;
133
134         case BC_RGBA_FLOAT:
135                 format = GL_RGBA;
136                 type = GL_FLOAT;
137                 break;
138
139         default:
140                 fprintf(stderr,
141                         "VFrame::to_texture: unsupported color model %d.\n",
142                         color_model);
143                 return;
144         }
145
146         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, get_w(), get_h(),
147                 format, type, get_rows()[0]);
148         opengl_state = VFrame::TEXTURE;
149 #endif
150 }
151
152 void VFrame::create_pbuffer()
153 {
154         if(pbuffer &&
155                 pbuffer->window_id != BC_WindowBase::get_synchronous()->current_window->get_id())
156         {
157                 delete pbuffer;
158                 pbuffer = 0;
159         }
160
161         if((get_w() % 4) || (get_h() % 4))
162         {
163                 printf("VFrame::create_pbuffer w=%d h=%d\n", get_w(), get_h());
164                 return;
165         }
166
167         if(!pbuffer)
168         {
169                 pbuffer = new BC_PBuffer(get_w(), get_h());
170         }
171 }
172
173 void VFrame::enable_opengl()
174 {
175         create_pbuffer();
176         if(pbuffer)
177         {
178                 pbuffer->enable_opengl();
179         }
180 }
181
182 BC_PBuffer* VFrame::get_pbuffer()
183 {
184         return pbuffer;
185 }
186
187
188 void VFrame::screen_to_texture(int x, int y, int w, int h)
189 {
190 #ifdef HAVE_GL
191 // Create texture
192         BC_Texture::new_texture(&texture,
193                 get_w(), get_h(), get_color_model());
194
195         if(pbuffer) {
196                 glEnable(GL_TEXTURE_2D);
197
198 // Read canvas into texture, use back texture for DOUBLE_BUFFER
199 #if 1
200 // According to the man page, it must be GL_BACK for the onscreen buffer
201 // and GL_FRONT for a single buffered PBuffer.  In reality it must be
202 // GL_BACK for a single buffered PBuffer if the PBuffer has alpha and using
203 // GL_FRONT captures the onscreen front buffer.
204 // 10/11/2010 is now generating "illegal operation"
205                 glReadBuffer(GL_BACK);
206 #else
207                 glReadBuffer(BC_WindowBase::get_synchronous()->is_pbuffer ?
208                         GL_FRONT : GL_BACK);
209 #endif
210                 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
211                         x >= 0 ? x : 0, y >= 0 ? y : 0,
212                         w >= 0 ? w : get_w(), h >= 0 ? h : get_h());
213         }
214 #endif
215 }
216
217 void VFrame::screen_to_ram()
218 {
219 #ifdef HAVE_GL
220         enable_opengl();
221         glReadBuffer(GL_BACK);
222         int type = BC_CModels::is_float(color_model) ? GL_FLOAT : GL_UNSIGNED_BYTE;
223         int format = BC_CModels::has_alpha(color_model) ? GL_RGBA : GL_RGB;
224         glReadPixels(0, 0, get_w(), get_h(), format, type, get_rows()[0]);
225         opengl_state = VFrame::RAM;
226 #endif
227 }
228
229 void VFrame::draw_texture(
230         float in_x1, float in_y1, float in_x2, float in_y2,
231         float out_x1, float out_y1, float out_x2, float out_y2,
232         int flip_y)
233 {
234 #ifdef HAVE_GL
235         in_x1 /= get_texture_w();  in_y1 /= get_texture_h();
236         in_x2 /= get_texture_w();  in_y2 /= get_texture_h();
237         float ot_y1 = flip_y ? -out_y1 : -out_y2;
238         float ot_y2 = flip_y ? -out_y2 : -out_y1;
239         texture->draw_texture(
240                 in_x1,in_y1,  in_x2,in_y2,
241                 out_x1,ot_y1, out_x2, ot_y2);
242 #endif
243 }
244
245 void VFrame::draw_texture(int flip_y)
246 {
247         draw_texture(0,0,  get_w(),get_h(),
248                 0,0, get_w(),get_h(), flip_y);
249 }
250
251
252 void VFrame::bind_texture(int texture_unit)
253 {
254 // Bind the texture
255         if(texture)
256         {
257                 texture->bind(texture_unit);
258         }
259 }
260
261
262
263
264
265
266 void VFrame::init_screen(int w, int h)
267 {
268 #ifdef HAVE_GL
269         glViewport(0, 0, w, h);
270         glMatrixMode(GL_PROJECTION);
271         glLoadIdentity();
272         float near = 1;
273         float far = 100;
274         float frustum_ratio = near / ((near + far)/2);
275         float near_h = (float)h * frustum_ratio;
276         float near_w = (float)w * frustum_ratio;
277         glFrustum(-near_w/2, near_w/2, -near_h/2, near_h/2, near, far);
278         glMatrixMode(GL_MODELVIEW);
279         glLoadIdentity();
280 // Shift down and right so 0,0 is the top left corner
281         glTranslatef(-w/2, h/2, 0.0);
282         glTranslatef(0.0, 0.0, -(far + near) / 2);
283
284         glDisable(GL_DEPTH_TEST);
285         glShadeModel(GL_SMOOTH);
286 // Default for direct copy playback
287         glDisable(GL_BLEND);
288         glDisable(GL_COLOR_MATERIAL);
289         glDisable(GL_CULL_FACE);
290         glEnable(GL_NORMALIZE);
291         glAlphaFunc(GL_ALWAYS, 0);
292         glDisable(GL_ALPHA_TEST);
293         glDisable(GL_LIGHTING);
294
295         const GLfloat zero[] = { 0, 0, 0, 0 };
296 //      const GLfloat one[] = { 1, 1, 1, 1 };
297 //      const GLfloat light_position[] = { 0, 0, -1, 0 };
298 //      const GLfloat light_direction[] = { 0, 0, 1, 0 };
299
300 //      glEnable(GL_LIGHT0);
301 //      glLightfv(GL_LIGHT0, GL_AMBIENT, zero);
302 //      glLightfv(GL_LIGHT0, GL_DIFFUSE, one);
303 //      glLightfv(GL_LIGHT0, GL_SPECULAR, one);
304 //      glLighti(GL_LIGHT0, GL_SPOT_CUTOFF, 180);
305 //      glLightfv(GL_LIGHT0, GL_POSITION, light_position);
306 //      glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_direction);
307 //      glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
308 //      glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zero);
309         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, zero);
310         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, zero);
311         glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, zero);
312         glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, zero);
313         glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0);
314 #endif
315 }
316
317 void VFrame::init_screen()
318 {
319         init_screen(get_w(), get_h());
320 }
321
322 static int print_error(char *source, unsigned int object, int is_program)
323 {
324 #ifdef HAVE_GL
325     char string[BCTEXTLEN];
326         int len = 0;
327     if(is_program)
328                 glGetProgramInfoLog(object, BCTEXTLEN, &len, string);
329         else
330                 glGetShaderInfoLog(object, BCTEXTLEN, &len, string);
331         if(len > 0) printf("Playback3D::print_error:\n%s\n%s\n", source, string);
332         if(len > 0) return 1;
333 #endif
334         return 0;
335 }
336
337
338
339
340
341 unsigned int VFrame::make_shader(int x, ...)
342 {
343         unsigned int result = 0;
344 #ifdef HAVE_GL
345 // Construct single source file out of arguments
346         char *complete_program = 0;
347         int complete_size = 0;
348         int current_shader = 0;
349
350         va_list list;
351         va_start(list, x);
352
353         while(1)
354         {
355                 char *text = va_arg(list, char*);
356                 if(!text) break;
357
358 // Replace one occurrance in each source of main() with a unique id.
359                 char main_replacement[BCTEXTLEN];
360                 sprintf(main_replacement, "main%03d()", current_shader);
361 //printf("VFrame::make_shader %s %s\n", text, main_replacement);
362                 char *source_replacement = new char[strlen(text) + strlen(main_replacement) + 1];
363                 char *ptr = strstr(text, "main()");
364
365                 if(ptr)
366                 {
367                         memcpy(source_replacement, text, ptr - text);
368                         source_replacement[ptr - text] = 0;
369                         strcat(source_replacement, main_replacement);
370                         ptr += strlen("main()");
371                         strcat(source_replacement, ptr);
372                         current_shader++;
373                 }
374                 else
375                 {
376                         memcpy(source_replacement, text, strlen(text));
377                         source_replacement[strlen(text)] = 0;
378                 }
379
380                 if(!complete_program)
381                 {
382                         complete_size = strlen(source_replacement) + 1;
383                         complete_program = (char*)malloc(complete_size);
384                         strcpy(complete_program, source_replacement);
385                 }
386                 else
387                 {
388                         complete_size += strlen(source_replacement);
389                         complete_program = (char*)realloc(complete_program, complete_size);
390                         strcat(complete_program, source_replacement);
391                 }
392
393                 delete [] source_replacement;
394         }
395         va_end(list);
396
397 // Add main() function which calls all the unique main replacements in order
398         char main_function[BCTEXTLEN];
399         sprintf(main_function,
400                 "\n"
401                 "void main()\n"
402                 "{\n");
403
404         for(int i = 0; i < current_shader; i++)
405         {
406                 char main_replacement[BCTEXTLEN];
407                 sprintf(main_replacement, "\tmain%03d();\n", i);
408                 strcat(main_function, main_replacement);
409         }
410
411         strcat(main_function, "}\n");
412         if(!complete_program)
413         {
414                 complete_size = strlen(main_function) + 1;
415                 complete_program = (char*)malloc(complete_size);
416                 strcpy(complete_program, main_function);
417         }
418         else
419         {
420                 complete_size += strlen(main_function);
421                 complete_program = (char*)realloc(complete_program, complete_size);
422                 strcat(complete_program, main_function);
423         }
424
425
426
427
428
429         int got_it = 0;
430         result = BC_WindowBase::get_synchronous()->get_shader(complete_program,
431                 &got_it);
432
433         if(!got_it)
434         {
435                 result = glCreateProgram();
436
437                 unsigned int shader;
438                 shader = glCreateShader(GL_FRAGMENT_SHADER);
439                 const GLchar *text_ptr = complete_program;
440                 glShaderSource(shader, 1, &text_ptr, NULL);
441                 glCompileShader(shader);
442                 int error = print_error(complete_program, shader, 0);
443                 glAttachShader(result, shader);
444                 glDeleteShader(shader);
445
446                 glLinkProgram(result);
447                 if(!error) error = print_error(complete_program, result, 1);
448
449
450 // printf("BC_WindowBase::make_shader: shader=%d window_id=%d\n",
451 // result,
452 // BC_WindowBase::get_synchronous()->current_window->get_id());
453                 BC_WindowBase::get_synchronous()->put_shader(result, complete_program);
454         }
455
456 //printf("VFrame::make_shader\n%s\n", complete_program);
457         free(complete_program);
458         complete_program = NULL;
459
460 #endif
461         return result;
462 }
463
464 void VFrame::dump_shader(int shader_id)
465 {
466         BC_WindowBase::get_synchronous()->dump_shader(shader_id);
467 }
468
469
470 void VFrame::clear_pbuffer()
471 {
472 #ifdef HAVE_GL
473         if(BC_CModels::is_yuv(get_color_model()))
474                 glClearColor(0.0, 0.5, 0.5, 0.0);
475         else
476                 glClearColor(0.0, 0.0, 0.0, 0.0);
477         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
478 #endif
479 }
480