4 * Copyright (C) 2011 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #define GL_GLEXT_PROTOTYPES
24 #include "bcpbuffer.h"
25 #include "bcresources.h"
26 #include "bcsignals.h"
27 #include "bcsynchronous.h"
28 #include "bctexture.h"
29 #include "bcwindowbase.h"
32 #if defined(HAVE_CONFIG_H)
45 int VFrame::get_opengl_state()
50 void VFrame::set_opengl_state(int value)
55 int VFrame::get_window_id()
57 return texture ? texture->window_id : -1;
60 int VFrame::get_texture_id()
62 return texture ? texture->texture_id : -1;
65 int VFrame::get_texture_w()
67 return texture ? texture->texture_w : 0;
70 int VFrame::get_texture_h()
72 return texture ? texture->texture_h : 0;
76 int VFrame::get_texture_components()
78 return texture ? texture->texture_components : 0;
91 void VFrame::to_texture()
95 // Must be here so user can create textures without copying data by setting
96 // opengl_state to TEXTURE.
97 BC_Texture::new_texture(&texture, get_w(), get_h(), get_color_model());
99 // Determine what to do based on state
100 switch(opengl_state) {
101 case VFrame::TEXTURE:
105 if((get_w() % 4) || (get_h() % 4)) {
106 printf("VFrame::to_texture w=%d h=%d\n", get_w(), get_h());
113 opengl_state = VFrame::TEXTURE;
117 //printf("VFrame::to_texture %d\n", texture_id);
119 switch(color_model) {
122 type = GL_UNSIGNED_BYTE;
128 type = GL_UNSIGNED_BYTE;
144 "VFrame::to_texture: unsupported color model %d.\n",
149 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, get_w(), get_h(),
150 format, type, get_rows()[0]);
151 opengl_state = VFrame::TEXTURE;
155 void VFrame::create_pbuffer()
158 pbuffer->window_id != BC_WindowBase::get_synchronous()->current_window->get_id())
164 if((get_w() % 4) || (get_h() % 4))
166 printf("VFrame::create_pbuffer w=%d h=%d\n", get_w(), get_h());
172 pbuffer = new BC_PBuffer(get_w(), get_h());
176 void VFrame::enable_opengl()
181 pbuffer->enable_opengl();
185 BC_PBuffer* VFrame::get_pbuffer()
191 void VFrame::screen_to_texture(int x, int y, int w, int h)
195 BC_Texture::new_texture(&texture,
196 get_w(), get_h(), get_color_model());
199 glEnable(GL_TEXTURE_2D);
201 // Read canvas into texture, use back texture for DOUBLE_BUFFER
203 // According to the man page, it must be GL_BACK for the onscreen buffer
204 // and GL_FRONT for a single buffered PBuffer. In reality it must be
205 // GL_BACK for a single buffered PBuffer if the PBuffer has alpha and using
206 // GL_FRONT captures the onscreen front buffer.
207 // 10/11/2010 is now generating "illegal operation"
208 glReadBuffer(GL_BACK);
210 glReadBuffer(BC_WindowBase::get_synchronous()->is_pbuffer ?
213 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
214 x >= 0 ? x : 0, y >= 0 ? y : 0,
215 w >= 0 ? w : get_w(), h >= 0 ? h : get_h());
220 void VFrame::screen_to_ram()
224 glReadBuffer(GL_BACK);
225 int type = BC_CModels::is_float(color_model) ? GL_FLOAT : GL_UNSIGNED_BYTE;
226 int format = BC_CModels::has_alpha(color_model) ? GL_RGBA : GL_RGB;
227 glReadPixels(0, 0, get_w(), get_h(), format, type, get_rows()[0]);
228 opengl_state = VFrame::RAM;
232 void VFrame::draw_texture(float in_x1,
244 glNormal3f(0, 0, 1.0);
246 glTexCoord2f(in_x1 / get_texture_w(), in_y1 / get_texture_h());
247 glVertex3f(out_x1, flip_y ? -out_y1 : -out_y2, 0);
249 glTexCoord2f(in_x2 / get_texture_w(), in_y1 / get_texture_h());
250 glVertex3f(out_x2, flip_y ? -out_y1 : -out_y2, 0);
252 glTexCoord2f(in_x2 / get_texture_w(), in_y2 / get_texture_h());
253 glVertex3f(out_x2, flip_y ? -out_y2 : -out_y1, 0);
255 glTexCoord2f(in_x1 / get_texture_w(), in_y2 / get_texture_h());
256 glVertex3f(out_x1, flip_y ? -out_y2 : -out_y1, 0);
264 void VFrame::draw_texture(int flip_y)
278 void VFrame::bind_texture(int texture_unit)
283 texture->bind(texture_unit);
292 void VFrame::init_screen(int w, int h)
295 glViewport(0, 0, w, h);
296 glMatrixMode(GL_PROJECTION);
300 float frustum_ratio = near / ((near + far)/2);
301 float near_h = (float)h * frustum_ratio;
302 float near_w = (float)w * frustum_ratio;
303 glFrustum(-near_w/2, near_w/2, -near_h/2, near_h/2, near, far);
304 glMatrixMode(GL_MODELVIEW);
306 // Shift down and right so 0,0 is the top left corner
307 glTranslatef(-w/2, h/2, 0.0);
308 glTranslatef(0.0, 0.0, -(far + near) / 2);
310 glDisable(GL_DEPTH_TEST);
311 glShadeModel(GL_SMOOTH);
312 // Default for direct copy playback
314 glDisable(GL_COLOR_MATERIAL);
315 glDisable(GL_CULL_FACE);
316 glEnable(GL_NORMALIZE);
317 glAlphaFunc(GL_ALWAYS, 0);
318 glDisable(GL_ALPHA_TEST);
319 glDisable(GL_LIGHTING);
321 const GLfloat zero[] = { 0, 0, 0, 0 };
322 // const GLfloat one[] = { 1, 1, 1, 1 };
323 // const GLfloat light_position[] = { 0, 0, -1, 0 };
324 // const GLfloat light_direction[] = { 0, 0, 1, 0 };
326 // glEnable(GL_LIGHT0);
327 // glLightfv(GL_LIGHT0, GL_AMBIENT, zero);
328 // glLightfv(GL_LIGHT0, GL_DIFFUSE, one);
329 // glLightfv(GL_LIGHT0, GL_SPECULAR, one);
330 // glLighti(GL_LIGHT0, GL_SPOT_CUTOFF, 180);
331 // glLightfv(GL_LIGHT0, GL_POSITION, light_position);
332 // glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_direction);
333 // glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
334 // glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zero);
335 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, zero);
336 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, zero);
337 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, zero);
338 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, zero);
339 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0);
343 void VFrame::init_screen()
345 init_screen(get_w(), get_h());
348 static int print_error(char *source, unsigned int object, int is_program)
351 char string[BCTEXTLEN];
354 glGetProgramInfoLog(object, BCTEXTLEN, &len, string);
356 glGetShaderInfoLog(object, BCTEXTLEN, &len, string);
357 if(len > 0) printf("Playback3D::print_error:\n%s\n%s\n", source, string);
358 if(len > 0) return 1;
367 unsigned int VFrame::make_shader(int x, ...)
369 unsigned int result = 0;
371 // Construct single source file out of arguments
372 char *complete_program = 0;
373 int complete_size = 0;
374 int current_shader = 0;
381 char *text = va_arg(list, char*);
384 // Replace one occurrance in each source of main() with a unique id.
385 char main_replacement[BCTEXTLEN];
386 sprintf(main_replacement, "main%03d()", current_shader);
387 //printf("VFrame::make_shader %s %s\n", text, main_replacement);
388 char *source_replacement = new char[strlen(text) + strlen(main_replacement) + 1];
389 char *ptr = strstr(text, "main()");
393 memcpy(source_replacement, text, ptr - text);
394 source_replacement[ptr - text] = 0;
395 strcat(source_replacement, main_replacement);
396 ptr += strlen("main()");
397 strcat(source_replacement, ptr);
402 memcpy(source_replacement, text, strlen(text));
403 source_replacement[strlen(text)] = 0;
406 if(!complete_program)
408 complete_size = strlen(source_replacement) + 1;
409 complete_program = (char*)malloc(complete_size);
410 strcpy(complete_program, source_replacement);
414 complete_size += strlen(source_replacement);
415 complete_program = (char*)realloc(complete_program, complete_size);
416 strcat(complete_program, source_replacement);
419 delete [] source_replacement;
423 // Add main() function which calls all the unique main replacements in order
424 char main_function[BCTEXTLEN];
425 sprintf(main_function,
430 for(int i = 0; i < current_shader; i++)
432 char main_replacement[BCTEXTLEN];
433 sprintf(main_replacement, "\tmain%03d();\n", i);
434 strcat(main_function, main_replacement);
437 strcat(main_function, "}\n");
438 if(!complete_program)
440 complete_size = strlen(main_function) + 1;
441 complete_program = (char*)malloc(complete_size);
442 strcpy(complete_program, main_function);
446 complete_size += strlen(main_function);
447 complete_program = (char*)realloc(complete_program, complete_size);
448 strcat(complete_program, main_function);
456 result = BC_WindowBase::get_synchronous()->get_shader(complete_program,
461 result = glCreateProgram();
464 shader = glCreateShader(GL_FRAGMENT_SHADER);
465 const GLchar *text_ptr = complete_program;
466 glShaderSource(shader, 1, &text_ptr, NULL);
467 glCompileShader(shader);
468 int error = print_error(complete_program, shader, 0);
469 glAttachShader(result, shader);
470 glDeleteShader(shader);
472 glLinkProgram(result);
473 if(!error) error = print_error(complete_program, result, 1);
476 // printf("BC_WindowBase::make_shader: shader=%d window_id=%d\n",
478 // BC_WindowBase::get_synchronous()->current_window->get_id());
479 BC_WindowBase::get_synchronous()->put_shader(result, complete_program);
482 //printf("VFrame::make_shader\n%s\n", complete_program);
483 free(complete_program);
484 complete_program = NULL;
490 void VFrame::dump_shader(int shader_id)
492 BC_WindowBase::get_synchronous()->dump_shader(shader_id);
496 void VFrame::clear_pbuffer()
499 if(BC_CModels::is_yuv(get_color_model()))
500 glClearColor(0.0, 0.5, 0.5, 0.0);
502 glClearColor(0.0, 0.0, 0.0, 0.0);
503 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);