Mercurial > mplayer.hg
comparison libvo/gl_common.c @ 16488:3191dcb27a12
hardware color-space conversion for vo_gl and vo_gl2
author | reimar |
---|---|
date | Wed, 14 Sep 2005 22:08:04 +0000 |
parents | 01d27e023ae4 |
children | cbd0ee58633b |
comparison
equal
deleted
inserted
replaced
16487:bafefab46f12 | 16488:3191dcb27a12 |
---|---|
1 /** | |
2 * Common OpenGL routines. | |
3 * Copyleft (C) Reimar Döffinger <Reimar.Doeffinger@stud.uni-karlsruhe.de>, 2005 | |
4 * Licensend under the GNU GPL v2. | |
5 * Special thanks go to the xine team and Matthias Hopf, whose video_out_opengl.c | |
6 * gave me lots of good ideas. | |
7 */ | |
1 #include <stdlib.h> | 8 #include <stdlib.h> |
9 #include <stdio.h> | |
2 #include <string.h> | 10 #include <string.h> |
11 #include <math.h> | |
3 #include "gl_common.h" | 12 #include "gl_common.h" |
4 | 13 |
5 void (APIENTRY *GenBuffers)(GLsizei, GLuint *); | 14 void (APIENTRY *GenBuffers)(GLsizei, GLuint *); |
6 void (APIENTRY *DeleteBuffers)(GLsizei, const GLuint *); | 15 void (APIENTRY *DeleteBuffers)(GLsizei, const GLuint *); |
7 void (APIENTRY *BindBuffer)(GLenum, GLuint); | 16 void (APIENTRY *BindBuffer)(GLenum, GLuint); |
16 GLenum, GLenum, GLboolean, GLboolean, | 25 GLenum, GLenum, GLboolean, GLboolean, |
17 GLboolean); | 26 GLboolean); |
18 void (APIENTRY *ActiveTexture)(GLenum); | 27 void (APIENTRY *ActiveTexture)(GLenum); |
19 void (APIENTRY *BindTexture)(GLenum, GLuint); | 28 void (APIENTRY *BindTexture)(GLenum, GLuint); |
20 void (APIENTRY *MultiTexCoord2f)(GLenum, GLfloat, GLfloat); | 29 void (APIENTRY *MultiTexCoord2f)(GLenum, GLfloat, GLfloat); |
30 void (APIENTRY *GenPrograms)(GLsizei, GLuint *); | |
31 void (APIENTRY *DeletePrograms)(GLsizei, const GLuint *); | |
21 void (APIENTRY *BindProgram)(GLenum, GLuint); | 32 void (APIENTRY *BindProgram)(GLenum, GLuint); |
22 void (APIENTRY *ProgramString)(GLenum, GLenum, GLsizei, const GLvoid *); | 33 void (APIENTRY *ProgramString)(GLenum, GLenum, GLsizei, const GLvoid *); |
23 void (APIENTRY *ProgramEnvParameter4f)(GLenum, GLuint, GLfloat, GLfloat, | 34 void (APIENTRY *ProgramEnvParameter4f)(GLenum, GLuint, GLfloat, GLfloat, |
24 GLfloat, GLfloat); | 35 GLfloat, GLfloat); |
25 int (APIENTRY *SwapInterval)(int); | 36 int (APIENTRY *SwapInterval)(int); |
247 if (!BindTexture) | 258 if (!BindTexture) |
248 BindTexture = getProcAddress("glBindTextureARB"); | 259 BindTexture = getProcAddress("glBindTextureARB"); |
249 MultiTexCoord2f = getProcAddress("glMultiTexCoord2f"); | 260 MultiTexCoord2f = getProcAddress("glMultiTexCoord2f"); |
250 if (!MultiTexCoord2f) | 261 if (!MultiTexCoord2f) |
251 MultiTexCoord2f = getProcAddress("glMultiTexCoord2fARB"); | 262 MultiTexCoord2f = getProcAddress("glMultiTexCoord2fARB"); |
263 GenPrograms = getProcAddress("glGenPrograms"); | |
264 if (!GenPrograms) | |
265 GenPrograms = getProcAddress("glGenProgramsARB"); | |
266 if (!GenPrograms) | |
267 GenPrograms = getProcAddress("glGenProgramsNV"); | |
268 DeletePrograms = getProcAddress("glDeletePrograms"); | |
269 if (!DeletePrograms) | |
270 DeletePrograms = getProcAddress("glDeleteProgramsARB"); | |
271 if (!DeletePrograms) | |
272 DeletePrograms = getProcAddress("glDeleteProgramsNV"); | |
252 BindProgram = getProcAddress("glBindProgram"); | 273 BindProgram = getProcAddress("glBindProgram"); |
253 if (!BindProgram) | 274 if (!BindProgram) |
254 BindProgram = getProcAddress("glBindProgramARB"); | 275 BindProgram = getProcAddress("glBindProgramARB"); |
255 if (!BindProgram) | 276 if (!BindProgram) |
256 BindProgram = getProcAddress("glBindProgramNV"); | 277 BindProgram = getProcAddress("glBindProgramNV"); |
372 if (y < y_max) | 393 if (y < y_max) |
373 glTexSubImage2D(target, 0, x, y, w, y_max - y, format, type, data); | 394 glTexSubImage2D(target, 0, x, y, w, y_max - y, format, type, data); |
374 } | 395 } |
375 | 396 |
376 /** | 397 /** |
398 * \brief Setup register combiners for YUV to RGB conversion. | |
399 * \param uvcos used for saturation and hue adjustment | |
400 * \param uvsin used for saturation and hue adjustment | |
401 */ | |
402 static void glSetupYUVCombiners(float uvcos, float uvsin) { | |
403 GLfloat ucoef[4]; | |
404 GLfloat vcoef[4]; | |
405 GLint i; | |
406 glGetIntegerv(GL_MAX_GENERAL_COMBINERS_NV, &i); | |
407 if (i < 2) | |
408 mp_msg(MSGT_VO, MSGL_ERR, | |
409 "[gl] 2 general combiners needed for YUV combiner support (found %i)\n", i); | |
410 glGetIntegerv (GL_MAX_TEXTURE_UNITS, &i); | |
411 if (i < 3) | |
412 mp_msg(MSGT_VO, MSGL_ERR, | |
413 "[gl] 3 texture units needed for YUV combiner support (found %i)\n", i); | |
414 if (!CombinerInput || !CombinerOutput || | |
415 !CombinerParameterfv || !CombinerParameteri) { | |
416 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Combiner functions missing!\n"); | |
417 return; | |
418 } | |
419 ucoef[0] = 0 * uvcos + 1.403 * uvsin; | |
420 vcoef[0] = 0 * uvsin + 1.403 * uvcos; | |
421 ucoef[1] = -0.344 * uvcos + -0.714 * uvsin; | |
422 vcoef[1] = -0.344 * uvsin + -0.714 * uvcos; | |
423 ucoef[2] = 1.770 * uvcos + 0 * uvsin; | |
424 vcoef[2] = 1.770 * uvsin + 0 * uvcos; | |
425 ucoef[3] = 0; | |
426 vcoef[3] = 0; | |
427 // Coefficients (probably) must be in [0, 1] range, whereas they originally | |
428 // are in [-2, 2] range, so here comes the trick: | |
429 // First put them in the [-0.5, 0.5] range, then add 0.5. | |
430 // This can be undone with the HALF_BIAS and SCALE_BY_FOUR arguments | |
431 // for CombinerInput and CombinerOutput | |
432 for (i = 0; i < 4; i++) { | |
433 ucoef[i] = ucoef[i] * 0.25 + 0.5; | |
434 vcoef[i] = vcoef[i] * 0.25 + 0.5; | |
435 } | |
436 CombinerParameterfv(GL_CONSTANT_COLOR0_NV, ucoef); | |
437 CombinerParameterfv(GL_CONSTANT_COLOR1_NV, vcoef); | |
438 | |
439 // UV first, like this green component cannot overflow | |
440 CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, | |
441 GL_TEXTURE1, GL_HALF_BIAS_NORMAL_NV, GL_RGB); | |
442 CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, | |
443 GL_CONSTANT_COLOR0_NV, GL_HALF_BIAS_NORMAL_NV, GL_RGB); | |
444 CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, | |
445 GL_TEXTURE2, GL_HALF_BIAS_NORMAL_NV, GL_RGB); | |
446 CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, | |
447 GL_CONSTANT_COLOR1_NV, GL_HALF_BIAS_NORMAL_NV, GL_RGB); | |
448 CombinerOutput(GL_COMBINER0_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV, | |
449 GL_SPARE0_NV, GL_SCALE_BY_FOUR_NV, GL_NONE, GL_FALSE, | |
450 GL_FALSE, GL_FALSE); | |
451 | |
452 // stage 2 | |
453 CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV, GL_SPARE0_NV, | |
454 GL_SIGNED_IDENTITY_NV, GL_RGB); | |
455 CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV, GL_ZERO, | |
456 GL_UNSIGNED_INVERT_NV, GL_RGB); | |
457 CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_C_NV, | |
458 GL_TEXTURE0, GL_SIGNED_IDENTITY_NV, GL_RGB); | |
459 CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_D_NV, GL_ZERO, | |
460 GL_UNSIGNED_INVERT_NV, GL_RGB); | |
461 CombinerOutput(GL_COMBINER1_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV, | |
462 GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, | |
463 GL_FALSE, GL_FALSE); | |
464 | |
465 // leave final combiner stage in default mode | |
466 CombinerParameteri(GL_NUM_GENERAL_COMBINERS_NV, 2); | |
467 } | |
468 | |
469 static const char *yuv_prog_template = | |
470 "!!ARBfp1.0\n" | |
471 "TEMP res, y, u, v;" | |
472 "TEX y, fragment.texcoord[0], texture[0], 2D;" | |
473 "MAD res, y, {%.4f, %.4f, %.4f}, {%.4f, %.4f, %.4f};" | |
474 "TEX u, fragment.texcoord[1], texture[1], 2D;" | |
475 "MAD res, u, {%.4f, %.4f, %.4f}, res;" | |
476 "TEX v, fragment.texcoord[2], texture[2], 2D;" | |
477 "MAD result.color, v, {%.4f, %.4f, %.4f}, res;" | |
478 "END"; | |
479 | |
480 static const char *yuv_pow_prog_template = | |
481 "!!ARBfp1.0\n" | |
482 "TEMP res, y, u, v;" | |
483 "TEX y, fragment.texcoord[0], texture[0], 2D;" | |
484 "MAD res, y, {%.4f, %.4f, %.4f}, {%.4f, %.4f, %.4f};" | |
485 "TEX u, fragment.texcoord[1], texture[1], 2D;" | |
486 "MAD res, u, {%.4f, %.4f, %.4f}, res;" | |
487 "TEX v, fragment.texcoord[2], texture[2], 2D;" | |
488 "MAD_SAT res, v, {%.4f, %.4f, %.4f}, res;" | |
489 "POW result.color.r, res.r, %.4f.r;" | |
490 "POW result.color.g, res.g, %.4f.g;" | |
491 "POW result.color.b, res.b, %.4f.b;" | |
492 "END"; | |
493 | |
494 static const char *yuv_lookup_prog_template = | |
495 "!!ARBfp1.0\n" | |
496 "TEMP res, y, u, v;" | |
497 "TEX y, fragment.texcoord[0], texture[0], 2D;" | |
498 "MAD res, y, {%.4f, %.4f, %.4f, 0}, {%.4f, %.4f, %.4f, 0};" | |
499 "TEX u, fragment.texcoord[1], texture[1], 2D;" | |
500 "MAD res, u, {%.4f, %.4f, %.4f, 0}, res;" | |
501 "TEX v, fragment.texcoord[2], texture[2], 2D;" | |
502 "MAD res, v, {%.4f, %.4f, %.4f, 0}, res;" | |
503 "ADD res.a, res.a, 0.125;" | |
504 "TEX result.color.r, res.raaa, texture[3], 2D;" | |
505 "ADD res.a, res.a, 0.25;" | |
506 "TEX result.color.g, res.gaaa, texture[3], 2D;" | |
507 "ADD res.a, res.a, 0.25;" | |
508 "TEX result.color.b, res.baaa, texture[3], 2D;" | |
509 "END"; | |
510 | |
511 /** | |
512 * \brief setup a fragment program that will do YUV->RGB conversion | |
513 * \param brightness brightness adjustment offset | |
514 * \param contrast contrast adjustment factor | |
515 * \param uvcos used for saturation and hue adjustment | |
516 * \param uvsin used for saturation and hue adjustment | |
517 * \param lookup use fragment program that uses texture unit 4 to | |
518 * do additional conversion via lookup. | |
519 */ | |
520 static void glSetupYUVFragprog(float brightness, float contrast, | |
521 float uvcos, float uvsin, float rgamma, | |
522 float ggamma, float bgamma, int type) { | |
523 char yuv_prog[1000]; | |
524 const char *prog_template = yuv_prog_template; | |
525 int lookup = 0; | |
526 GLint i; | |
527 // this is the conversion matrix, with y, u, v factors | |
528 // for red, green, blue and the constant offsets | |
529 float ry, ru, rv, rc; | |
530 float gy, gu, gv, gc; | |
531 float by, bu, bv, bc; | |
532 switch (type) { | |
533 case YUV_CONVERSION_FRAGMENT_POW: | |
534 prog_template = yuv_pow_prog_template; | |
535 break; | |
536 case YUV_CONVERSION_FRAGMENT_LOOKUP: | |
537 prog_template = yuv_lookup_prog_template; | |
538 lookup = 1; | |
539 break; | |
540 } | |
541 glGetIntegerv (GL_MAX_TEXTURE_UNITS, &i); | |
542 if (i < 3) | |
543 mp_msg(MSGT_VO, MSGL_ERR, | |
544 "[gl] 3 texture units needed for YUV fragment support (found %i)\n", i); | |
545 if (lookup && i < 4) | |
546 mp_msg(MSGT_VO, MSGL_ERR, | |
547 "[gl] 4 texture units needed for YUV fragment support with lookup (found %i)\n", i); | |
548 if (!ProgramString) { | |
549 mp_msg(MSGT_VO, MSGL_FATAL, "[gl] ProgramString function missing!\n"); | |
550 return; | |
551 } | |
552 ry = 1.164 * contrast; | |
553 gy = 1.164 * contrast; | |
554 by = 1.164 * contrast; | |
555 ru = 0 * uvcos + 1.596 * uvsin; | |
556 rv = 0 * uvsin + 1.596 * uvcos; | |
557 gu = -0.391 * uvcos + -0.813 * uvsin; | |
558 gv = -0.391 * uvsin + -0.813 * uvcos; | |
559 bu = 2.018 * uvcos + 0 * uvsin; | |
560 bv = 2.018 * uvsin + 0 * uvcos; | |
561 rc = (-16 * ry + (-128) * ru + (-128) * rv) / 255.0 + brightness; | |
562 gc = (-16 * gy + (-128) * gu + (-128) * gv) / 255.0 + brightness; | |
563 bc = (-16 * by + (-128) * bu + (-128) * bv) / 255.0 + brightness; | |
564 rgamma = 1.0 / rgamma; | |
565 ggamma = 1.0 / ggamma; | |
566 bgamma = 1.0 / bgamma; | |
567 snprintf(yuv_prog, 1000, prog_template, ry, gy, by, rc, gc, bc, ru, gu, bu, | |
568 rv, gv, bv, rgamma, bgamma, bgamma); | |
569 ProgramString(GL_FRAGMENT_PROGRAM, GL_PROGRAM_FORMAT_ASCII, | |
570 strlen(yuv_prog), yuv_prog); | |
571 glGetIntegerv(GL_PROGRAM_ERROR_POSITION, &i); | |
572 if (i != -1) | |
573 mp_msg(MSGT_VO, MSGL_ERR, | |
574 "[gl] Error compiling fragment program, make sure your card supports\n" | |
575 "GL_ARB_fragment_program (use glxinfo to check).%.10s\n", &yuv_prog[i]); | |
576 } | |
577 | |
578 /** | |
579 * \brief little helper function to create a lookup table for gamma | |
580 * \param map buffer to create map into | |
581 * \param size size of buffer | |
582 * \param gamma gamma value | |
583 */ | |
584 static void gen_gamma_map(unsigned char *map, int size, float gamma) { | |
585 int i; | |
586 gamma = 1.0 / gamma; | |
587 for (i = 0; i < size; i++) { | |
588 float tmp = (float)i / (size - 1.0); | |
589 tmp = pow(tmp, gamma); | |
590 if (tmp > 1.0) tmp = 1.0; | |
591 if (tmp < 0.0) tmp = 0.0; | |
592 map[i] = 255 * tmp; | |
593 } | |
594 } | |
595 | |
596 //! resolution of texture for gamma lookup table | |
597 #define LOOKUP_RES 512 | |
598 | |
599 /** | |
600 * \brief setup YUV->RGB conversion | |
601 * \param brightness brightness adjustment offset | |
602 * \param contrast contrast adjustment factor | |
603 * \param hue hue adjustment angle | |
604 * \param saturation saturation adjustment factor | |
605 * \param rgamma gamma value for red channel | |
606 * \param ggamma gamma value for green channel | |
607 * \param bgamma gamma value for blue channel | |
608 * \param type YUV conversion type | |
609 */ | |
610 void glSetupYUVConversion(int type, float brightness, float contrast, | |
611 float hue, float saturation, | |
612 float rgamma, float ggamma, float bgamma) { | |
613 float uvcos = saturation * cos(hue); | |
614 float uvsin = saturation * sin(hue); | |
615 switch (type) { | |
616 case YUV_CONVERSION_COMBINERS: | |
617 glSetupYUVCombiners(uvcos, uvsin); | |
618 break; | |
619 case YUV_CONVERSION_FRAGMENT_LOOKUP: | |
620 { | |
621 unsigned char lookup_data[4 * LOOKUP_RES]; | |
622 gen_gamma_map(lookup_data, LOOKUP_RES, rgamma); | |
623 gen_gamma_map(&lookup_data[LOOKUP_RES], LOOKUP_RES, ggamma); | |
624 gen_gamma_map(&lookup_data[2 * LOOKUP_RES], LOOKUP_RES, bgamma); | |
625 ActiveTexture(GL_TEXTURE3); | |
626 glCreateClearTex(GL_TEXTURE_2D, GL_LUMINANCE8, GL_LINEAR, | |
627 LOOKUP_RES, 4, 0); | |
628 glUploadTex(GL_TEXTURE_2D, GL_LUMINANCE, GL_UNSIGNED_BYTE, lookup_data, | |
629 LOOKUP_RES, 0, 0, LOOKUP_RES, 4, 0); | |
630 ActiveTexture(GL_TEXTURE0); | |
631 } | |
632 case YUV_CONVERSION_FRAGMENT: | |
633 case YUV_CONVERSION_FRAGMENT_POW: | |
634 glSetupYUVFragprog(brightness, contrast, uvcos, uvsin, | |
635 rgamma, ggamma, bgamma, type); | |
636 break; | |
637 } | |
638 } | |
639 | |
640 /** | |
641 * \brief enable the specified YUV conversion | |
642 * \param target texture target for Y, U and V textures (e.g. GL_TEXTURE_2D) | |
643 * \param type type of YUV conversion | |
644 */ | |
645 void inline glEnableYUVConversion(GLenum target, int type) { | |
646 if (type <= 0) return; | |
647 ActiveTexture(GL_TEXTURE1); | |
648 glEnable(target); | |
649 ActiveTexture(GL_TEXTURE2); | |
650 glEnable(target); | |
651 switch (type) { | |
652 case YUV_CONVERSION_COMBINERS: | |
653 glEnable(GL_REGISTER_COMBINERS_NV); | |
654 break; | |
655 case YUV_CONVERSION_FRAGMENT_LOOKUP: | |
656 ActiveTexture(GL_TEXTURE3); | |
657 glEnable(GL_TEXTURE_2D); | |
658 case YUV_CONVERSION_FRAGMENT_POW: | |
659 case YUV_CONVERSION_FRAGMENT: | |
660 glEnable(GL_FRAGMENT_PROGRAM); | |
661 break; | |
662 } | |
663 ActiveTexture(GL_TEXTURE0); | |
664 } | |
665 | |
666 /** | |
667 * \brief disable the specified YUV conversion | |
668 * \param target texture target for Y, U and V textures (e.g. GL_TEXTURE_2D) | |
669 * \param type type of YUV conversion | |
670 */ | |
671 void inline glDisableYUVConversion(GLenum target, int type) { | |
672 if (type <= 0) return; | |
673 ActiveTexture(GL_TEXTURE1); | |
674 glDisable(target); | |
675 ActiveTexture(GL_TEXTURE2); | |
676 glDisable(target); | |
677 switch (type) { | |
678 case YUV_CONVERSION_COMBINERS: | |
679 glDisable(GL_REGISTER_COMBINERS_NV); | |
680 break; | |
681 case YUV_CONVERSION_FRAGMENT_LOOKUP: | |
682 ActiveTexture(GL_TEXTURE3); | |
683 glDisable(GL_TEXTURE_2D); | |
684 case YUV_CONVERSION_FRAGMENT_POW: | |
685 case YUV_CONVERSION_FRAGMENT: | |
686 glDisable(GL_FRAGMENT_PROGRAM); | |
687 break; | |
688 } | |
689 ActiveTexture(GL_TEXTURE0); | |
690 } | |
691 | |
692 /** | |
377 * \brief draw a texture part at given 2D coordinates | 693 * \brief draw a texture part at given 2D coordinates |
378 * \param x screen top coordinate | 694 * \param x screen top coordinate |
379 * \param y screen left coordinate | 695 * \param y screen left coordinate |
380 * \param w screen width coordinate | 696 * \param w screen width coordinate |
381 * \param h screen height coordinate | 697 * \param h screen height coordinate |
384 * \param tw texture part width in pixels | 700 * \param tw texture part width in pixels |
385 * \param th texture part height in pixels | 701 * \param th texture part height in pixels |
386 * \param sx width of texture in pixels | 702 * \param sx width of texture in pixels |
387 * \param sy height of texture in pixels | 703 * \param sy height of texture in pixels |
388 * \param rect_tex whether this texture uses texture_rectangle extension | 704 * \param rect_tex whether this texture uses texture_rectangle extension |
705 * \param is_yv12 if set, also draw the textures from units 1 and 2 | |
389 */ | 706 */ |
390 void glDrawTex(GLfloat x, GLfloat y, GLfloat w, GLfloat h, | 707 void glDrawTex(GLfloat x, GLfloat y, GLfloat w, GLfloat h, |
391 GLfloat tx, GLfloat ty, GLfloat tw, GLfloat th, | 708 GLfloat tx, GLfloat ty, GLfloat tw, GLfloat th, |
392 int sx, int sy, int rect_tex) { | 709 int sx, int sy, int rect_tex, int is_yv12) { |
710 GLfloat tx2 = tx / 2, ty2 = ty / 2, tw2 = tw / 2, th2 = th / 2; | |
393 if (!rect_tex) { | 711 if (!rect_tex) { |
394 tx /= sx; ty /= sy; tw /= sx; th /= sy; | 712 tx /= sx; ty /= sy; tw /= sx; th /= sy; |
713 tx2 = tx, ty2 = ty, tw2 = tw, th2 = th; | |
395 } | 714 } |
396 glBegin(GL_QUADS); | 715 glBegin(GL_QUADS); |
397 glTexCoord2f(tx, ty); | 716 glTexCoord2f(tx, ty); |
717 if (is_yv12) { | |
718 MultiTexCoord2f(GL_TEXTURE1, tx2, ty2); | |
719 MultiTexCoord2f(GL_TEXTURE2, tx2, ty2); | |
720 } | |
398 glVertex2f(x, y); | 721 glVertex2f(x, y); |
399 glTexCoord2f(tx, ty + th); | 722 glTexCoord2f(tx, ty + th); |
723 if (is_yv12) { | |
724 MultiTexCoord2f(GL_TEXTURE1, tx2, ty2 + th2); | |
725 MultiTexCoord2f(GL_TEXTURE2, tx2, ty2 + th2); | |
726 } | |
400 glVertex2f(x, y + h); | 727 glVertex2f(x, y + h); |
401 glTexCoord2f(tx + tw, ty + th); | 728 glTexCoord2f(tx + tw, ty + th); |
729 if (is_yv12) { | |
730 MultiTexCoord2f(GL_TEXTURE1, tx2 + tw2, ty2 + th2); | |
731 MultiTexCoord2f(GL_TEXTURE2, tx2 + tw2, ty2 + th2); | |
732 } | |
402 glVertex2f(x + w, y + h); | 733 glVertex2f(x + w, y + h); |
403 glTexCoord2f(tx + tw, ty); | 734 glTexCoord2f(tx + tw, ty); |
735 if (is_yv12) { | |
736 MultiTexCoord2f(GL_TEXTURE1, tx2 + tw2, ty2); | |
737 MultiTexCoord2f(GL_TEXTURE2, tx2 + tw2, ty2); | |
738 } | |
404 glVertex2f(x + w, y); | 739 glVertex2f(x + w, y); |
405 glEnd(); | 740 glEnd(); |
406 } | 741 } |
407 | 742 |
408 #ifdef GL_WIN32 | 743 #ifdef GL_WIN32 |