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"
42 int VFrame::get_opengl_state()
47 void VFrame::set_opengl_state(int value)
52 int VFrame::get_window_id()
54 return texture ? texture->window_id : -1;
57 int VFrame::get_texture_id()
59 return texture ? texture->texture_id : -1;
62 int VFrame::get_texture_w()
64 return texture ? texture->texture_w : 0;
67 int VFrame::get_texture_h()
69 return texture ? texture->texture_h : 0;
73 int VFrame::get_texture_components()
75 return texture ? texture->texture_components : 0;
88 void VFrame::to_texture()
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());
96 // Determine what to do based on state
97 switch(opengl_state) {
102 if((get_w() % 4) || (get_h() % 4)) {
103 printf("VFrame::to_texture w=%d h=%d\n", get_w(), get_h());
110 opengl_state = VFrame::TEXTURE;
114 //printf("VFrame::to_texture %d\n", texture_id);
116 switch(color_model) {
119 type = GL_UNSIGNED_BYTE;
125 type = GL_UNSIGNED_BYTE;
141 "VFrame::to_texture: unsupported color model %d.\n",
146 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, get_w(), get_h(),
147 format, type, get_rows()[0]);
148 opengl_state = VFrame::TEXTURE;
152 void VFrame::create_pbuffer()
155 pbuffer->window_id != BC_WindowBase::get_synchronous()->current_window->get_id())
161 if((get_w() % 4) || (get_h() % 4))
163 printf("VFrame::create_pbuffer w=%d h=%d\n", get_w(), get_h());
169 pbuffer = new BC_PBuffer(get_w(), get_h());
173 void VFrame::enable_opengl()
178 pbuffer->enable_opengl();
182 BC_PBuffer* VFrame::get_pbuffer()
188 void VFrame::screen_to_texture(int x, int y, int w, int h)
192 BC_Texture::new_texture(&texture,
193 get_w(), get_h(), get_color_model());
196 glEnable(GL_TEXTURE_2D);
198 // Read canvas into texture, use back texture for DOUBLE_BUFFER
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);
207 glReadBuffer(BC_WindowBase::get_synchronous()->is_pbuffer ?
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());
217 void VFrame::screen_to_ram()
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;
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,
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);
245 void VFrame::draw_texture(int flip_y)
247 draw_texture(0,0, get_w(),get_h(),
248 0,0, get_w(),get_h(), flip_y);
252 void VFrame::bind_texture(int texture_unit)
257 texture->bind(texture_unit);
266 void VFrame::init_screen(int w, int h)
269 glViewport(0, 0, w, h);
270 glMatrixMode(GL_PROJECTION);
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);
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);
284 glDisable(GL_DEPTH_TEST);
285 glShadeModel(GL_SMOOTH);
286 // Default for direct copy playback
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);
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 };
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);
317 void VFrame::init_screen()
319 init_screen(get_w(), get_h());
322 static int print_error(char *source, unsigned int object, int is_program)
325 char string[BCTEXTLEN];
328 glGetProgramInfoLog(object, BCTEXTLEN, &len, string);
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;
340 // make_shader(0, frag1, .., fragn, 0);
341 // or make_shader(fragments);
343 unsigned int VFrame::make_shader(const char **fragments, ...)
345 unsigned int result = 0;
347 // Construct single source file out of arguments
353 va_list list; va_start(list, fragments);
354 while( va_arg(list, char*) != 0 ) ++nb_frags;
357 const char *frags[nb_frags], *text = 0;
359 va_list list; va_start(list, fragments);
360 for( int i=0; i<nb_frags; ++i ) frags[i] = va_arg(list, char*);
365 while( (text = *fragments++) ) {
366 char src[strlen(text) + BCSTRLEN + 1];
367 const char *tp = strstr(text, "main()");
369 // Replace main() with a mainxxx()
370 char mainxxx[BCSTRLEN], *sp = src;
371 sprintf(mainxxx, "main%03d()", nb_mains++);
373 memcpy(sp, text, n); sp += n;
375 memcpy(sp, mainxxx, n); sp += n;
376 tp += strlen("main()");
381 char *new_program = !program ? cstrdup(text) :
382 cstrcat(2, program, text);
383 delete [] program; program = new_program;
386 // Add main() which calls mainxxx() in order
387 char main_program[BCTEXTLEN], *cp = main_program;
388 cp += sprintf(cp, "\nvoid main() {\n");
389 for( int i=0; i < nb_mains; ++i )
390 cp += sprintf(cp, "\tmain%03d();\n", i);
391 cp += sprintf(cp, "}\n");
392 cp = !program ? cstrdup(main_program) :
393 cstrcat(2, program, main_program);
394 delete [] program; program = cp;
397 result = BC_WindowBase::get_synchronous()->get_shader(program, &got_it);
399 result = glCreateProgram();
400 unsigned int shader = glCreateShader(GL_FRAGMENT_SHADER);
401 const GLchar *text_ptr = program;
402 glShaderSource(shader, 1, &text_ptr, NULL);
403 glCompileShader(shader);
404 int error = print_error(program, shader, 0);
405 glAttachShader(result, shader);
406 glDeleteShader(shader);
407 glLinkProgram(result);
409 error = print_error(program, result, 1);
410 //printf("BC_WindowBase::make_shader: shader=%d window_id=%d\n", result,
411 // BC_WindowBase::get_synchronous()->current_window->get_id());
412 BC_WindowBase::get_synchronous()->put_shader(result, program);
415 //printf("VFrame::make_shader\n%s\n", program);
421 void VFrame::dump_shader(int shader_id)
423 BC_WindowBase::get_synchronous()->dump_shader(shader_id);
427 void VFrame::clear_pbuffer()
430 float gbuv = BC_CModels::is_yuv(get_color_model()) ? 0.5 : 0;
431 glClearColor(0.0, gbuv, gbuv, 0.0);
432 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);