00001 #define GL_GLEXT_PROTOTYPES
00002
00003 #include "bcpbuffer.h"
00004 #include "bcresources.h"
00005 #include "bcsignals.h"
00006 #include "bcsynchronous.h"
00007 #include "bctexture.h"
00008 #include "bcwindowbase.h"
00009 #include "vframe.h"
00010
00011 #if defined(HAVE_CONFIG_H)
00012 #include "config.h"
00013 #endif
00014
00015 #ifdef HAVE_GL
00016 #include <GL/gl.h>
00017 #include <GL/glext.h>
00018 #endif
00019
00020 #include <stdarg.h>
00021 #include <stdio.h>
00022 #include <string.h>
00023 #include <unistd.h>
00024
00025 int VFrame::get_opengl_state()
00026 {
00027 return opengl_state;
00028 }
00029
00030 void VFrame::set_opengl_state(int value)
00031 {
00032 opengl_state = value;
00033 }
00034
00035 int VFrame::get_window_id()
00036 {
00037 return texture ? texture->window_id : -1;
00038 }
00039
00040 int VFrame::get_texture_id()
00041 {
00042 return texture ? texture->texture_id : -1;
00043 }
00044
00045 int VFrame::get_texture_w()
00046 {
00047 return texture ? texture->texture_w : 0;
00048 }
00049
00050 int VFrame::get_texture_h()
00051 {
00052 return texture ? texture->texture_h : 0;
00053 }
00054
00055
00056 int VFrame::get_texture_components()
00057 {
00058 return texture ? texture->texture_components : 0;
00059 }
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 void VFrame::to_texture()
00072 {
00073 #ifdef HAVE_GL
00074
00075
00076
00077 BC_Texture::new_texture(&texture,
00078 get_w(),
00079 get_h(),
00080 get_color_model());
00081
00082
00083 switch(opengl_state)
00084 {
00085 case VFrame::TEXTURE:
00086 return;
00087
00088 case VFrame::SCREEN:
00089 if((get_w() % 4) || (get_h() % 4))
00090 {
00091 printf("VFrame::to_texture w=%d h=%d\n", get_w(), get_h());
00092 return;
00093 }
00094 if(pbuffer)
00095 {
00096 enable_opengl();
00097 screen_to_texture();
00098 }
00099 opengl_state = VFrame::TEXTURE;
00100 return;
00101 }
00102
00103
00104
00105 switch(color_model)
00106 {
00107 case BC_RGB888:
00108 case BC_YUV888:
00109 glTexSubImage2D(GL_TEXTURE_2D,
00110 0,
00111 0,
00112 0,
00113 get_w(),
00114 get_h(),
00115 GL_RGB,
00116 GL_UNSIGNED_BYTE,
00117 get_rows()[0]);
00118 break;
00119
00120 case BC_RGBA8888:
00121 case BC_YUVA8888:
00122 glTexSubImage2D(GL_TEXTURE_2D,
00123 0,
00124 0,
00125 0,
00126 get_w(),
00127 get_h(),
00128 GL_RGBA,
00129 GL_UNSIGNED_BYTE,
00130 get_rows()[0]);
00131 break;
00132
00133 case BC_RGB_FLOAT:
00134 glTexSubImage2D(GL_TEXTURE_2D,
00135 0,
00136 0,
00137 0,
00138 get_w(),
00139 get_h(),
00140 GL_RGB,
00141 GL_FLOAT,
00142 get_rows()[0]);
00143 break;
00144
00145 case BC_RGBA_FLOAT:
00146 glTexSubImage2D(GL_TEXTURE_2D,
00147 0,
00148 0,
00149 0,
00150 get_w(),
00151 get_h(),
00152 GL_RGBA,
00153 GL_FLOAT,
00154 get_rows()[0]);
00155 break;
00156
00157 default:
00158 fprintf(stderr,
00159 "VFrame::to_texture: unsupported color model %d.\n",
00160 color_model);
00161 break;
00162 }
00163
00164 opengl_state = VFrame::TEXTURE;
00165 #endif
00166 }
00167
00168 void VFrame::to_ram()
00169 {
00170 #ifdef HAVE_GL
00171 switch(opengl_state)
00172 {
00173
00174
00175 case VFrame::SCREEN:
00176 if(pbuffer)
00177 {
00178 enable_opengl();
00179 printf("VFrame::to_ram %d %d\n", get_w(), get_h());
00180 glReadPixels(0,
00181 0,
00182 get_w(),
00183 get_h(),
00184 GL_RGB,
00185 GL_UNSIGNED_BYTE,
00186 get_rows()[0]);
00187 flip_vert();
00188 }
00189 opengl_state = VFrame::RAM;
00190 return;
00191 }
00192 #endif
00193 }
00194
00195 void VFrame::create_pbuffer()
00196 {
00197 SET_TRACE
00198 if(pbuffer &&
00199 pbuffer->window_id != BC_WindowBase::get_synchronous()->current_window->get_id())
00200 {
00201 SET_TRACE
00202 delete pbuffer;
00203 SET_TRACE
00204 pbuffer = 0;
00205 }
00206
00207 if((get_w() % 4) || (get_h() % 4))
00208 {
00209 printf("VFrame::create_pbuffer w=%d h=%d\n", get_w(), get_h());
00210 return;
00211 }
00212
00213 SET_TRACE
00214 if(!pbuffer)
00215 {
00216 pbuffer = new BC_PBuffer(get_w(), get_h());
00217 }
00218 SET_TRACE
00219 }
00220
00221 void VFrame::enable_opengl()
00222 {
00223 create_pbuffer();
00224 if(pbuffer)
00225 {
00226 pbuffer->enable_opengl();
00227 }
00228 }
00229
00230 BC_PBuffer* VFrame::get_pbuffer()
00231 {
00232 return pbuffer;
00233 }
00234
00235
00236 void VFrame::screen_to_texture(int x, int y, int w, int h)
00237 {
00238 #ifdef HAVE_GL
00239
00240 BC_Texture::new_texture(&texture,
00241 get_w(),
00242 get_h(),
00243 get_color_model());
00244
00245 if(pbuffer)
00246 {
00247 glEnable(GL_TEXTURE_2D);
00248
00249
00250
00251
00252
00253
00254
00255
00256 glReadBuffer(GL_BACK);
00257 glCopyTexSubImage2D(GL_TEXTURE_2D,
00258 0,
00259 0,
00260 0,
00261 x >= 0 ? x : 0,
00262 y >= 0 ? y : 0,
00263 w >= 0 ? w : get_w(),
00264 h >= 0 ? h : get_h());
00265 }
00266 #endif
00267 }
00268
00269 void VFrame::draw_texture(float in_x1,
00270 float in_y1,
00271 float in_x2,
00272 float in_y2,
00273 float out_x1,
00274 float out_y1,
00275 float out_x2,
00276 float out_y2,
00277 int flip_y)
00278 {
00279 #ifdef HAVE_GL
00280 glBegin(GL_QUADS);
00281 glNormal3f(0, 0, 1.0);
00282
00283 glTexCoord2f(in_x1 / get_texture_w(), in_y1 / get_texture_h());
00284 glVertex3f(out_x1, flip_y ? -out_y1 : -out_y2, 0);
00285
00286 glTexCoord2f(in_x2 / get_texture_w(), in_y1 / get_texture_h());
00287 glVertex3f(out_x2, flip_y ? -out_y1 : -out_y2, 0);
00288
00289 glTexCoord2f(in_x2 / get_texture_w(), in_y2 / get_texture_h());
00290 glVertex3f(out_x2, flip_y ? -out_y2 : -out_y1, 0);
00291
00292 glTexCoord2f(in_x1 / get_texture_w(), in_y2 / get_texture_h());
00293 glVertex3f(out_x1, flip_y ? -out_y2 : -out_y1, 0);
00294
00295
00296 glEnd();
00297
00298 #endif
00299 }
00300
00301 void VFrame::draw_texture(int flip_y)
00302 {
00303 draw_texture(0,
00304 0,
00305 get_w(),
00306 get_h(),
00307 0,
00308 0,
00309 get_w(),
00310 get_h(),
00311 flip_y);
00312 }
00313
00314
00315 void VFrame::bind_texture(int texture_unit)
00316 {
00317
00318 if(texture)
00319 {
00320 texture->bind(texture_unit);
00321 }
00322 }
00323
00324
00325
00326
00327
00328
00329 void VFrame::init_screen(int w, int h)
00330 {
00331 #ifdef HAVE_GL
00332 glViewport(0, 0, w, h);
00333 glMatrixMode(GL_PROJECTION);
00334 glLoadIdentity();
00335 float near = 1;
00336 float far = 100;
00337 float frustum_ratio = near / ((near + far) / 2);
00338 float near_h = (float)h *
00339 frustum_ratio;
00340 float near_w = (float)w *
00341 frustum_ratio;
00342 glFrustum(-near_w / 2,
00343 near_w / 2,
00344 -near_h / 2,
00345 near_h / 2,
00346 near,
00347 far);
00348 glMatrixMode(GL_MODELVIEW);
00349 glLoadIdentity();
00350
00351 glTranslatef(-w / 2, h / 2, 0.0);
00352 glTranslatef(0.0, 0.0, -(far + near) / 2);
00353
00354 glDisable(GL_DEPTH_TEST);
00355 glShadeModel(GL_SMOOTH);
00356
00357 glDisable(GL_BLEND);
00358 glDisable(GL_COLOR_MATERIAL);
00359 glDisable(GL_CULL_FACE);
00360 glEnable(GL_NORMALIZE);
00361 glAlphaFunc(GL_GREATER, 0);
00362 glDisable(GL_LIGHTING);
00363
00364 const GLfloat one[] = { 1, 1, 1, 1 };
00365 const GLfloat zero[] = { 0, 0, 0, 0 };
00366 const GLfloat light_position[] = { 0, 0, -1, 0 };
00367 const GLfloat light_direction[] = { 0, 0, 1, 0 };
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, zero);
00379 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, zero);
00380 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, zero);
00381 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, zero);
00382 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0);
00383 #endif
00384 }
00385
00386 void VFrame::init_screen()
00387 {
00388 init_screen(get_w(), get_h());
00389 }
00390
00391 static int print_error(char *source, unsigned int object, int is_program)
00392 {
00393 #ifdef HAVE_GL
00394 char string[BCTEXTLEN];
00395 int len = 0;
00396 if(is_program)
00397 glGetProgramInfoLog(object, BCTEXTLEN, &len, string);
00398 else
00399 glGetShaderInfoLog(object, BCTEXTLEN, &len, string);
00400 if(len > 0) printf("Playback3D::print_error:\n%s\n%s\n", source, string);
00401 if(len > 0) return 1;
00402 return 0;
00403 #endif
00404 }
00405
00406
00407
00408
00409
00410 unsigned int VFrame::make_shader(int x, ...)
00411 {
00412 unsigned int result = 0;
00413 #ifdef HAVE_GL
00414
00415 char *complete_program = 0;
00416 int complete_size = 0;
00417 int current_shader = 0;
00418
00419 va_list list;
00420 va_start(list, x);
00421
00422 while(1)
00423 {
00424 char *text = va_arg(list, char*);
00425 if(!text) break;
00426
00427 SET_TRACE
00428
00429 char main_replacement[BCTEXTLEN];
00430 SET_TRACE
00431 sprintf(main_replacement, "main%03d()", current_shader);
00432
00433 SET_TRACE
00434 char *source_replacement = new char[strlen(text) + strlen(main_replacement) + 1];
00435 SET_TRACE
00436 char *ptr = strstr(text, "main()");
00437 SET_TRACE
00438
00439 if(ptr)
00440 {
00441 memcpy(source_replacement, text, ptr - text);
00442 source_replacement[ptr - text] = 0;
00443 strcat(source_replacement, main_replacement);
00444 ptr += strlen("main()");
00445 strcat(source_replacement, ptr);
00446 current_shader++;
00447 }
00448 else
00449 {
00450 memcpy(source_replacement, text, strlen(text));
00451 source_replacement[strlen(text)] = 0;
00452 }
00453 SET_TRACE
00454
00455 if(!complete_program)
00456 {
00457 complete_size = strlen(source_replacement) + 1;
00458 complete_program = (char*)malloc(complete_size);
00459 strcpy(complete_program, source_replacement);
00460 }
00461 else
00462 {
00463 complete_size += strlen(source_replacement);
00464 complete_program = (char*)realloc(complete_program, complete_size);
00465 strcat(complete_program, source_replacement);
00466 }
00467
00468 delete [] source_replacement;
00469 SET_TRACE
00470 }
00471
00472
00473 char main_function[BCTEXTLEN];
00474 sprintf(main_function,
00475 "\n"
00476 "void main()\n"
00477 "{\n");
00478
00479 for(int i = 0; i < current_shader; i++)
00480 {
00481 char main_replacement[BCTEXTLEN];
00482 sprintf(main_replacement, "\tmain%03d();\n", i);
00483 strcat(main_function, main_replacement);
00484 }
00485
00486 strcat(main_function, "}\n");
00487 if(!complete_program)
00488 {
00489 complete_size = strlen(main_function) + 1;
00490 complete_program = (char*)malloc(complete_size);
00491 strcpy(complete_program, main_function);
00492 }
00493 else
00494 {
00495 complete_size += strlen(main_function);
00496 complete_program = (char*)realloc(complete_program, complete_size);
00497 strcat(complete_program, main_function);
00498 }
00499
00500
00501
00502
00503
00504 int got_it = 0;
00505 result = BC_WindowBase::get_synchronous()->get_shader(complete_program,
00506 &got_it);
00507
00508 if(!got_it)
00509 {
00510 result = glCreateProgram();
00511
00512 unsigned int shader;
00513 shader = glCreateShader(GL_FRAGMENT_SHADER);
00514 const GLchar *text_ptr = complete_program;
00515 glShaderSource(shader, 1, &text_ptr, NULL);
00516 glCompileShader(shader);
00517 int error = print_error(complete_program, shader, 0);
00518 glAttachShader(result, shader);
00519 glDeleteShader(shader);
00520
00521 glLinkProgram(result);
00522 if(!error) error = print_error(complete_program, result, 1);
00523
00524
00525
00526
00527
00528 BC_WindowBase::get_synchronous()->put_shader(result, complete_program);
00529 }
00530
00531
00532 delete [] complete_program;
00533
00534 #endif
00535 return result;
00536 }
00537
00538 void VFrame::dump_shader(int shader_id)
00539 {
00540 BC_WindowBase::get_synchronous()->dump_shader(shader_id);
00541 }
00542
00543
00544 void VFrame::clear_pbuffer()
00545 {
00546 #ifdef HAVE_GL
00547 if(cmodel_is_yuv(get_color_model()))
00548 glClearColor(0.0, 0.5, 0.5, 0.0);
00549 else
00550 glClearColor(0.0, 0.0, 0.0, 0.0);
00551 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00552 #endif
00553 }
00554