/* * video_out_gl.c, X11/OpenGL interface * based on video_out_x11 by Aaron Holtzman, * and WS opengl window manager by Pontscho/Fresh! */ #include #include #include #include #include #include "config.h" #include "video_out.h" #include "video_out_internal.h" #include "sub.h" #ifdef HAVE_FREETYPE #include "font_load.h" #endif #include #ifdef GL_WIN32 #include #include #else #include #include #include #endif #include #ifdef GL_WIN32 #include "w32_common.h" #else #include "x11_common.h" #endif #include "aspect.h" #define NDEBUG //#undef NDEBUG // set to force an internal textureformat #undef TEXTUREFORMAT_ALWAYS //#define TEXTUREFORMAT_ALWAYS GL_RGB8 //#define TEXTUREFORMAT_ALWAYS GL_RGBA //#define TEXTUREFORMAT_ALWAYS GL_LUMINANCE8 // uncomment to activate gray-only yuv support //#define SUPPORT_YUV_ETC static vo_info_t info = { "X11 (OpenGL) - simpler version", "glsimple", "Reimar Doeffinger", "based on gl2 from Arpad Gereoffy & Sven Goethel" }; LIBVO_EXTERN (glsimple) #ifndef GL_WIN32 static GLXContext wsGLXContext; #endif static uint32_t img_format; static uint32_t img_width; static uint32_t img_height; static int int_pause; static int do_flip; static int useGL12; struct drawparams { // drawTextureDisplay uses these uint32_t dirtyXoff, dirtyYoff, dirtyWidth, dirtyHeight; unsigned char *ImageData; GLint gl_bitmap_format; GLint gl_bitmap_type; GLint rowlen; }; static struct drawparams maindparams; struct texparams { GLint gl_internal_format; uint32_t image_width; uint32_t image_height; GLfloat left, right, top, bottom; int bilinear; }; struct texture { // only setupTexture and removeTexture may modify these (except for initializing texCreated to 0) int texCreated; GLuint texobj; GLuint listobj; struct texparams internal; uint32_t texture_width; uint32_t texture_height; }; static struct texture maintex, osdtex, osdatex; static int r_sz, g_sz, b_sz, a_sz; static int gl_antialias = 0; static void removeTexture (struct texture *tex) { glDeleteTextures (1, &tex->texobj); glDeleteLists (tex->listobj, 1); tex->texCreated = 0; } static void setupTexture (struct texture *tex, struct texparams *params) { enum regenType { CREATE_TEX, CREATE_LIST, SET_BILIN, NOTHING }; enum regenType action = NOTHING; char *texInitData; int s; GLfloat xcov, ycov; if (params->bilinear != tex->internal.bilinear) action = SET_BILIN; if (tex->internal.image_width != params->image_width || tex->internal.image_height != params->image_height || tex->internal.left != params->left || tex->internal.right != params->right || tex->internal.top != params->top || tex->internal.bottom != params->bottom) action = CREATE_LIST; if (!tex->texCreated) { glGenTextures (1, &tex->texobj); tex->listobj = glGenLists (1); tex->texCreated = 1; #ifndef NDEBUG printf ("[glsimple] Created a texture\n"); #endif action = CREATE_TEX; } else if (tex->internal.gl_internal_format != params->gl_internal_format || params->image_width > tex->texture_width || params->image_height > tex->texture_height) action = CREATE_TEX; // initialize variables for texture tex->internal = *params; switch (action) { case CREATE_TEX: // find matching powers of two for texture size s = 1; while (s < tex->internal.image_width) s *= 2; tex->texture_width = s; s = 1; while (s < tex->internal.image_height) s *= 2; tex->texture_height = s; #ifndef NDEBUG printf ("[glsimple] Allocated texture of size %dx%d ...\n", tex->texture_width, tex->texture_height); #endif glBindTexture (GL_TEXTURE_2D, tex->texobj); if (useGL12) texInitData = NULL; else { texInitData = malloc (tex->texture_width * tex->texture_height); #ifndef NDEBUG memset (texInitData, 128, tex->texture_width * tex->texture_height); #endif } glTexImage2D (GL_TEXTURE_2D, 0, tex->internal.gl_internal_format, tex->texture_width, tex->texture_height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, texInitData); if (texInitData) free (texInitData); #ifndef NDEBUG printf ("glTexImage2D finished with %d\n", glGetError ()); if (glIsTexture (tex->texobj) == GL_FALSE) fprintf (stderr, "GLERROR ain't a texture (glGenText): texture=%d\n", tex->texobj); #endif // try to keep texture resident glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_PRIORITY, 1.0); // don't wrap around glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); case CREATE_LIST: #ifndef NDEBUG printf ("[glsimple] Creating list for texture %d ...\n", tex->texobj); #endif // area of texture actually used xcov = (GLfloat) tex->internal.image_width / (GLfloat) tex->texture_width; ycov = (GLfloat) tex->internal.image_height / (GLfloat) tex->texture_height; // compile list glNewList (tex->listobj, GL_COMPILE); glBindTexture (GL_TEXTURE_2D, tex->texobj); glBegin (GL_QUADS); glTexCoord2f (0, 0); glVertex2f (tex->internal.left, tex->internal.top); glTexCoord2f (0, ycov); glVertex2f (tex->internal.left, tex->internal.bottom); glTexCoord2f (xcov, ycov); glVertex2f (tex->internal.right, tex->internal.bottom); glTexCoord2f (xcov, 0); glVertex2f (tex->internal.right, tex->internal.top); glEnd (); glEndList (); case SET_BILIN: glBindTexture (GL_TEXTURE_2D, tex->texobj); tex->internal.bilinear %= 2; switch (tex->internal.bilinear) { case 0: glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); break; case 1: glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); break; default: printf ("[glsimple] unknown bilinear mode\n"); } case NOTHING: break; default: printf ("[glsimple] unknown action in setupTexture\n"); break; } } static void gl_set_antialias (int val) { gl_antialias = val; if (gl_antialias) { glShadeModel (GL_SMOOTH); glEnable (GL_POLYGON_SMOOTH); glEnable (GL_LINE_SMOOTH); glEnable (GL_POINT_SMOOTH); printf ("[glsimple] antialiasing on\n"); } else { glShadeModel (GL_FLAT); glDisable (GL_POLYGON_SMOOTH); glDisable (GL_LINE_SMOOTH); glDisable (GL_POINT_SMOOTH); printf ("[glsimple] antialiasing off\n"); } fflush (0); } static void drawTextureDisplay (struct texture *tex, struct drawparams *dparams) { if (dparams) { glBindTexture (GL_TEXTURE_2D, tex->texobj); glPixelStorei (GL_UNPACK_ROW_LENGTH, dparams->rowlen); glTexSubImage2D (GL_TEXTURE_2D, 0, dparams->dirtyXoff, dparams->dirtyYoff, dparams->dirtyWidth, dparams->dirtyHeight, dparams->gl_bitmap_format, dparams->gl_bitmap_type, dparams->ImageData); #ifndef NDEBUG fprintf (stdout, "[glsimple] glTexSubImage2D %d/%d - %d/%d\n", dparams->dirtyXoff, dparams->dirtyYoff, dparams->dirtyWidth, dparams->dirtyHeight); #endif } glCallList (tex->listobj); } static void resize (int width, int height) { struct texparams tparams = maintex.internal; #ifndef NDEBUG printf ("[glsimple] Resize: %dx%d\n", width, height); #endif if (vo_fs) { int w, h; aspect (&w, &h, A_ZOOM); panscan_calc (); tparams.left = (GLfloat) (width - w - vo_panscan_x) / (GLfloat) (2 * width); tparams.right = 1 - tparams.left; tparams.top = (GLfloat) (height - h - vo_panscan_y) / (GLfloat) (2 * height); tparams.bottom = 1 - tparams.top; } else { tparams.left = 0; tparams.right = 1; tparams.top = 0; tparams.bottom = 1; } if (do_flip) { int tmp = tparams.top; tparams.top = tparams.bottom; tparams.bottom = tparams.top; } setupTexture (&maintex, &tparams); glViewport (0, 0, width, height); glMatrixMode (GL_PROJECTION); glLoadIdentity (); glOrtho (0, 1, 1, 0, -1.0, 1.0); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); #ifdef HAVE_FREETYPE force_load_font = 1; #endif } static void draw_alpha_fnc (int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride) { struct drawparams dparams; struct texparams tparams; tparams.gl_internal_format = GL_ALPHA8; tparams.left = (GLfloat) x0 / (GLfloat) vo_dwidth; tparams.right = (GLfloat) (x0 + w) / (GLfloat) vo_dwidth; tparams.top = (GLfloat) y0 / (GLfloat) vo_dheight; tparams.bottom = (GLfloat) (y0 + h) / (GLfloat) vo_dheight; tparams.image_width = w; tparams.image_height = h; tparams.bilinear = 0; setupTexture (&osdatex, &tparams); tparams.gl_internal_format = GL_LUMINANCE8; setupTexture (&osdtex, &tparams); dparams.dirtyXoff = 0; dparams.dirtyYoff = 0; dparams.dirtyWidth = w; dparams.dirtyHeight = h; dparams.ImageData = srca; dparams.gl_bitmap_format = GL_ALPHA; dparams.gl_bitmap_type = GL_UNSIGNED_BYTE; dparams.rowlen = stride; glEnable (GL_BLEND); glBlendFunc (GL_ZERO, GL_SRC_ALPHA); drawTextureDisplay (&osdatex, &dparams); dparams.ImageData = src; dparams.gl_bitmap_format = GL_LUMINANCE; glBlendFunc (GL_ONE, GL_ONE); drawTextureDisplay (&osdtex, &dparams); glDisable (GL_BLEND); } #ifdef GL_WIN32 static int config_w32 (uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format) { PIXELFORMATDESCRIPTOR pfd; int pf; o_dwidth = d_width; o_dheight = d_height; vo_dwidth = d_width; vo_dheight = d_height; vo_fs = flags & VOFLAG_FULLSCREEN; vo_vm = flags & VOFLAG_MODESWITCHING; if (vo_config_count) destroyRenderingContext (); if (!createRenderingContext ()) return -1; pf = GetPixelFormat (vo_hdc); if (!DescribePixelFormat (vo_hdc, pf, sizeof pfd, &pfd)) { r_sz = g_sz = b_sz = a_sz = 0; } else { r_sz = pfd.cRedBits; g_sz = pfd.cGreenBits; b_sz = pfd.cBlueBits; a_sz = pfd.cAlphaBits; } return 0; } #else static int choose_glx_visual (Display * dpy, int scr, XVisualInfo * res_vi) { XVisualInfo template, *vi_list; int vi_num, i, best_i, best_weight; template.screen = scr; vi_list = XGetVisualInfo (dpy, VisualScreenMask, &template, &vi_num); if (!vi_list) return -1; best_weight = -1; best_i = -1; for (i = 0; i < vi_num; i++) { int val, res, w = 0; /* of course, the visual must support OpenGL rendering... */ res = glXGetConfig (dpy, vi_list + i, GLX_USE_GL, &val); if (res || val == False) continue; /* also it must be doublebuffered ... */ res = glXGetConfig (dpy, vi_list + i, GLX_DOUBLEBUFFER, &val); if (res || val == False) continue; /* furthermore it must be RGBA (not color indexed) ... */ res = glXGetConfig (dpy, vi_list + i, GLX_RGBA, &val); if (res || val == False) continue; /* prefer less depth buffer size, */ res = glXGetConfig (dpy, vi_list + i, GLX_DEPTH_SIZE, &val); if (res) continue; w += val * 2; /* stencil buffer size */ res = glXGetConfig (dpy, vi_list + i, GLX_STENCIL_SIZE, &val); if (res) continue; w += val * 2; /* and colorbuffer alpha size */ res = glXGetConfig (dpy, vi_list + i, GLX_ALPHA_SIZE, &val); if (res) continue; w += val; /* and finally, prefer DirectColor-ed visuals to allow color corrections */ if (vi_list[i].class != DirectColor) w += 100; if ((best_i == -1) || (w < best_weight)) { best_weight = w; best_i = i; } } if (best_i != -1) *res_vi = vi_list[best_i]; XFree (vi_list); return (best_i != -1) ? 0 : -1; } static uint32_t config_glx (uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format) { XSizeHints hint; XVisualInfo vinfo; XEvent xev; hint.x = 0; hint.y = 0; hint.width = d_width; hint.height = d_height; hint.flags = PPosition | PSize; // Create the window if (choose_glx_visual (mDisplay, mScreen, &vinfo) < 0) { printf ("[glsimple] no GLX support present\n"); return -1; } if (vo_window == None) { vo_window = vo_x11_create_smooth_window (mDisplay, RootWindow (mDisplay, mScreen), vinfo.visual, hint.x, hint.y, hint.width, hint.height, vinfo.depth, vo_x11_create_colormap (&vinfo)); XSelectInput (mDisplay, vo_window, StructureNotifyMask); /* Tell other applications about this window */ XSetStandardProperties (mDisplay, vo_window, title, title, None, NULL, 0, &hint); /* Map window. */ XMapWindow (mDisplay, vo_window); #ifdef HAVE_XINERAMA vo_x11_xinerama_move (mDisplay, vo_window); #endif XClearWindow (mDisplay, vo_window); vo_x11_sizehint (hint.x, hint.y, hint.width, hint.height, 0); if (flags & VOFLAG_FULLSCREEN) { vo_x11_fullscreen (); vo_dwidth = vo_screenwidth; vo_dheight = vo_screenheight; vo_fs = VO_TRUE; } /* Wait for map. */ do { XNextEvent (mDisplay, &xev); } while (xev.type != MapNotify || xev.xmap.event != vo_window); XSelectInput (mDisplay, vo_window, NoEventMask); } else if (!vo_fs) XMoveResizeWindow (mDisplay, vo_window, hint.x, hint.y, hint.width, hint.height); vo_x11_classhint (mDisplay, vo_window, "glsimple"); vo_hidecursor (mDisplay, vo_window); if (vo_config_count) glXDestroyContext (mDisplay, wsGLXContext); wsGLXContext = glXCreateContext (mDisplay, &vinfo, NULL, True); glXMakeCurrent (mDisplay, vo_window, wsGLXContext); XFlush (mDisplay); XSync (mDisplay, False); //XSelectInput(mDisplay, vo_window, StructureNotifyMask); // !!!! vo_x11_selectinput_witherr (mDisplay, vo_window, StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | ExposureMask); if (glXGetConfig (mDisplay, &vinfo, GLX_RED_SIZE, &r_sz) != 0) r_sz = 0; if (glXGetConfig (mDisplay, &vinfo, GLX_GREEN_SIZE, &g_sz) != 0) g_sz = 0; if (glXGetConfig (mDisplay, &vinfo, GLX_BLUE_SIZE, &b_sz) != 0) b_sz = 0; if (glXGetConfig (mDisplay, &vinfo, GLX_ALPHA_SIZE, &a_sz) != 0) a_sz = 0; return 0; } #endif struct gl_name_map_struct { GLint format; char* name; }; static const struct gl_name_map_struct gl_name_map[] = { // internal format {GL_R3_G3_B2, "GL_R3_G3_B2"}, {GL_RGB4, "GL_RGB4"}, {GL_RGB5, "GL_RGB5"}, {GL_RGB8, "GL_RGB8"}, {GL_RGB10, "GL_RGB10"}, {GL_RGB12, "GL_RGB12"}, {GL_RGB16, "GL_RGB16"}, {GL_RGBA2, "GL_RGBA2"}, {GL_RGBA4, "GL_RGBA4"}, {GL_RGB5_A1, "GL_RGB5_A1"}, {GL_RGBA8, "GL_RGBA8"}, {GL_RGB10_A2, "GL_RGB10_A2"}, {GL_RGBA12, "GL_RGBA12"}, {GL_RGBA16, "GL_RGBA16"}, {GL_LUMINANCE8, "GL_LUMINANCE8"}, // format {GL_RGB, "GL_RGB"}, {GL_RGBA, "GL_RGBA"}, {GL_RED, "GL_RED"}, {GL_GREEN, "GL_GREEN"}, {GL_BLUE, "GL_BLUE"}, {GL_ALPHA, "GL_ALPHA"}, {GL_LUMINANCE, "GL_LUMINANCE"}, {GL_LUMINANCE_ALPHA, "GL_LUMINANCE_ALPHA"}, {GL_COLOR_INDEX, "GL_COLOR_INDEX"}, // rest 1.2 only {GL_BGR, "GL_BGR"}, {GL_BGRA, "GL_BGRA"}, //type {GL_BYTE, "GL_BYTE"}, {GL_UNSIGNED_BYTE, "GL_UNSIGNED_BYTE"}, {GL_SHORT, "GL_SHORT"}, {GL_UNSIGNED_SHORT, "GL_UNSIGNED_SHORT"}, {GL_INT, "GL_INT"}, {GL_UNSIGNED_INT, "GL_UNSIGNED_INT"}, {GL_FLOAT, "GL_FLOAT"}, {GL_DOUBLE, "GL_DOUBLE"}, {GL_2_BYTES, "GL_2_BYTES"}, {GL_3_BYTES, "GL_3_BYTES"}, {GL_4_BYTES, "GL_4_BYTES"}, // rest 1.2 only {GL_UNSIGNED_BYTE_3_3_2, "GL_UNSIGNED_BYTE_3_3_2"}, {GL_UNSIGNED_BYTE_2_3_3_REV, "GL_UNSIGNED_BYTE_2_3_3_REV"}, {GL_UNSIGNED_SHORT_5_6_5, "GL_UNSIGNED_SHORT_5_6_5"}, {GL_UNSIGNED_SHORT_5_6_5_REV, "GL_UNSIGNED_SHORT_5_6_5_REV"}, {GL_UNSIGNED_SHORT_4_4_4_4, "GL_UNSIGNED_SHORT_4_4_4_4"}, {GL_UNSIGNED_SHORT_4_4_4_4_REV, "GL_UNSIGNED_SHORT_4_4_4_4_REV"}, {GL_UNSIGNED_SHORT_5_5_5_1, "GL_UNSIGNED_SHORT_5_5_5_1"}, {GL_UNSIGNED_SHORT_1_5_5_5_REV, "GL_UNSIGNED_SHORT_1_5_5_5_REV"}, {GL_UNSIGNED_INT_8_8_8_8, "GL_UNSIGNED_INT_8_8_8_8"}, {GL_UNSIGNED_INT_8_8_8_8_REV, "GL_UNSIGNED_INT_8_8_8_8_REV"}, {GL_UNSIGNED_INT_10_10_10_2, "GL_UNSIGNED_INT_10_10_10_2"}, {GL_UNSIGNED_INT_2_10_10_10_REV, "GL_UNSIGNED_INT_2_10_10_10_REV"}, {0, 0} }; static char *GLformat_string (GLint format) { int i = 0; while (gl_name_map[i].name) { if (gl_name_map[i].format == format) return gl_name_map[i].name; i++; } return "Unknown format!"; } static int isGL12 () { const GLubyte *glVersion = glGetString (GL_VERSION); if (!glVersion) return 0; return (glVersion[0] > '1' || (glVersion[0] == '1' && glVersion[2] >= '2')); } struct gl_internal_map_struct { int red_bits, green_bits, blue_bits, alpha_bits; GLint gl_internal_format; }; static const struct gl_internal_map_struct gl_internal_map[] = { {3, 3, 2, 0, GL_R3_G3_B2}, {4, 4, 4, 0, GL_RGB4}, {5, 5, 5, 0, GL_RGB5}, {8, 8, 8, 0, GL_RGB8}, {10, 10, 10, 0, GL_RGB10}, {2, 2, 2, 2, GL_RGBA2}, {4, 4, 4, 4, GL_RGBA4}, {5, 5, 5, 1, GL_RGB5_A1}, {8, 8, 8, 8, GL_RGBA8}, {10, 10, 10, 2, GL_RGB10_A2}, {0, 0, 0, 0, 0} }; static GLint match_gl_internal_format (int red_bits, int green_bits, int blue_bits, int alpha_bits) { #ifdef TEXTUREFORMAT_ALWAYS return TEXTUREFORMAT_ALWAYS; #else int i = 0; while (gl_internal_map[i].gl_internal_format) { if (gl_internal_map[i].red_bits == red_bits && gl_internal_map[i].green_bits == green_bits && gl_internal_map[i].blue_bits == blue_bits && gl_internal_map[i].alpha_bits == alpha_bits) return gl_internal_map[i].gl_internal_format; i++; } return GL_RGB; #endif } static void set_gl_bitmap_fmt (uint32_t format, struct drawparams *dparams) { switch (format) { case IMGFMT_RGB8: dparams->gl_bitmap_format = GL_RGB; dparams->gl_bitmap_type = GL_UNSIGNED_BYTE_2_3_3_REV; break; case IMGFMT_RGB15: dparams->gl_bitmap_format = GL_RGBA; dparams->gl_bitmap_type = GL_UNSIGNED_SHORT_1_5_5_5_REV; break; case IMGFMT_RGB16: dparams->gl_bitmap_format = GL_RGB; dparams->gl_bitmap_type = GL_UNSIGNED_SHORT_5_6_5_REV; break; case IMGFMT_RGB24: dparams->gl_bitmap_format = GL_RGB; dparams->gl_bitmap_type = GL_UNSIGNED_BYTE; break; case IMGFMT_RGB32: dparams->gl_bitmap_format = GL_RGBA; dparams->gl_bitmap_type = GL_UNSIGNED_BYTE; break; case IMGFMT_BGR8: dparams->gl_bitmap_format = GL_RGB; dparams->gl_bitmap_type = GL_UNSIGNED_BYTE_3_3_2; break; case IMGFMT_BGR15: dparams->gl_bitmap_format = GL_BGRA; dparams->gl_bitmap_type = GL_UNSIGNED_SHORT_1_5_5_5_REV; break; case IMGFMT_BGR16: dparams->gl_bitmap_format = GL_RGB; dparams->gl_bitmap_type = GL_UNSIGNED_SHORT_5_6_5; break; case IMGFMT_BGR24: dparams->gl_bitmap_format = GL_BGR; dparams->gl_bitmap_type = GL_UNSIGNED_BYTE; break; case IMGFMT_BGR32: dparams->gl_bitmap_format = GL_BGRA; dparams->gl_bitmap_type = GL_UNSIGNED_BYTE; break; #ifdef SUPPORT_YUV_ETC case IMGFMT_YVU9: case IMGFMT_IF09: case IMGFMT_YV12: case IMGFMT_I420: case IMGFMT_IYUV: case IMGFMT_CLPL: case IMGFMT_444P: case IMGFMT_422P: #endif case IMGFMT_Y800: case IMGFMT_Y8: dparams->gl_bitmap_format = GL_LUMINANCE; dparams->gl_bitmap_type = GL_UNSIGNED_BYTE; break; default: fprintf (stderr, "[glsimple] unsupported image format (%s)!\n", vo_format_name (img_format)); dparams->gl_bitmap_format = GL_RGBA; dparams->gl_bitmap_type = GL_UNSIGNED_BYTE; } } static void initGl (uint32_t width, uint32_t height) { struct texparams tparams; glDisable (GL_BLEND); glDisable (GL_DEPTH_TEST); glDepthMask (GL_FALSE); glDisable (GL_CULL_FACE); glPixelStorei (GL_UNPACK_ALIGNMENT, 1); glEnable (GL_TEXTURE_2D); gl_set_antialias (gl_antialias); tparams.gl_internal_format = match_gl_internal_format (r_sz, g_sz, b_sz, a_sz); tparams.image_width = width; tparams.image_height = height; tparams.left = 0; tparams.right = 1; tparams.top = 0; tparams.bottom = 1; tparams.bilinear = 1; removeTexture (&maintex); setupTexture (&maintex, &tparams); removeTexture (&osdtex); removeTexture (&osdatex); set_gl_bitmap_fmt (img_format, &maindparams); maindparams.rowlen = 0; printf ("[glsimple] Using image_format=%s, \n\tgl_bitmap_format=%s, gl_bitmap_type=%s, \n\trgb_size=(%d,%d,%d), a_sz=%d, \n\tgl_internal_format=%s\n", vo_format_name (img_format), GLformat_string (maindparams.gl_bitmap_format), GLformat_string (maindparams.gl_bitmap_type), r_sz, g_sz, b_sz, a_sz, GLformat_string (tparams.gl_internal_format)); glClearColor (0.0f, 0.0f, 0.0f, 0.0f); resize (vo_dwidth, vo_dheight); } /* connect to server, create and map window, * allocate colors and (shared) memory */ static uint32_t config (uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format) { img_width = width; img_height = height; img_format = format; int_pause = 0; do_flip = flags & VOFLAG_FLIPPING; panscan_init (); aspect_save_orig (width, height); aspect_save_prescale (d_width, d_height); aspect_save_screenres (vo_screenwidth, vo_screenheight); vo_dwidth = d_width; vo_dheight = d_height; #ifdef GL_WIN32 if (config_w32 (width, height, d_width, d_height, flags, title, format) == -1) #else if (config_glx (width, height, d_width, d_height, flags, title, format) == -1) #endif return -1; printf ("[glsimple] OpenGL Driver Information:\n"); printf ("\tvendor: %s,\n\trenderer %s,\n\tversion %s\n", glGetString (GL_VENDOR), glGetString (GL_RENDERER), glGetString (GL_VERSION)); sub_bg_alpha = 255; initGl (width, height); #ifndef GL_WIN32 saver_off (mDisplay); #endif return 0; } static int gl_handlekey (int key) { struct texparams tparams; if (key == 'a' || key == 'A') { gl_set_antialias (!gl_antialias); return 0; } else if (key == 'b' || key == 'B') { tparams = maintex.internal; tparams.bilinear++; setupTexture (&maintex, &tparams); return 0; } return 1; } #ifdef GL_WIN32 static void check_events (void) { int e = vo_w32_check_events (); if (e & VO_EVENT_RESIZE) resize (vo_dwidth, vo_dheight); if (e & VO_EVENT_EXPOSE && int_pause) flip_page (); } #else static void check_events (void) { XEvent Event; char buf[100]; KeySym keySym; int key; static XComposeStatus stat; int e; while (XPending (mDisplay)) { XNextEvent (mDisplay, &Event); if (Event.type == KeyPress) { XLookupString (&Event.xkey, buf, sizeof (buf), &keySym, &stat); key = (keySym & 0xff00) != 0 ? ((keySym & 0x00ff) + 256) : (keySym); if (gl_handlekey (key)) XPutBackEvent (mDisplay, &Event); break; } else { XPutBackEvent (mDisplay, &Event); break; } } e = vo_x11_check_events (mDisplay); if (e & VO_EVENT_RESIZE) resize (vo_dwidth, vo_dheight); if (e & VO_EVENT_EXPOSE && int_pause) flip_page (); } #endif static void draw_osd (void) { vo_draw_text (vo_dwidth, vo_dheight, draw_alpha_fnc); } static void flip_page (void) { glFinish (); // wait until rendering is finished #ifdef GL_WIN32 SwapBuffers (vo_hdc); #else glXSwapBuffers (mDisplay, vo_window); #endif } static uint32_t draw_slice (uint8_t * src[], int stride[], int w, int h, int x, int y) { maindparams.ImageData = (unsigned char *) src[0]; maindparams.dirtyXoff = x; maindparams.dirtyYoff = y; maindparams.dirtyWidth = w; maindparams.dirtyHeight = h; // clear display (gives trouble in fullscreen otherwise) glClear (GL_COLOR_BUFFER_BIT); drawTextureDisplay (&maintex, &maindparams); return 0; } static uint32_t draw_frame (uint8_t * src[]) { return draw_slice (src, 0, img_width, img_height, 0, 0);; } static uint32_t query_format (uint32_t format) { const uint32_t supported = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_FLIP; switch (format) { case IMGFMT_RGB8: case IMGFMT_BGR8: case IMGFMT_RGB15: case IMGFMT_BGR15: case IMGFMT_RGB16: case IMGFMT_BGR16: case IMGFMT_BGR24: case IMGFMT_BGR32: // not supported by OpenGL < 1.2 if (useGL12) return supported; else { #ifndef NDEBUG printf ("[glsimple] %s not supported due to OpenGL version < 1.2\n", vo_format_name (format)); #endif return 0; } #ifdef SUPPORT_YUV_ETC case IMGFMT_YVU9: case IMGFMT_IF09: case IMGFMT_YV12: case IMGFMT_I420: case IMGFMT_IYUV: case IMGFMT_CLPL: case IMGFMT_444P: case IMGFMT_422P: #endif case IMGFMT_Y800: case IMGFMT_Y8: case IMGFMT_RGB24: case IMGFMT_RGB32: return supported; } return 0; } static void uninit (void) { removeTexture (&maintex); removeTexture (&osdtex); removeTexture (&osdatex); if (!vo_config_count) return; #ifdef GL_WIN32 vo_w32_uninit (); #else vo_x11_uninit (); #endif } static uint32_t preinit (const char *arg) { useGL12 = 1; if (arg) { if (strcmp (arg, "gl11") == 0) useGL12 = 0; else { printf ("[glsimple] Unknown subdevice: %s\n", arg); return ENOSYS; } } if (!vo_init ()) return -1; // Can't open X11 return 0; } static uint32_t control (uint32_t request, void *data, ...) { switch (request) { case VOCTRL_PAUSE: return (int_pause = 1); case VOCTRL_RESUME: return (int_pause = 0); case VOCTRL_QUERY_FORMAT: return query_format (*((uint32_t *) data)); case VOCTRL_FULLSCREEN: #ifdef GL_WIN32 vo_w32_fullscreen (); initGl (img_width, img_height); #else vo_x11_fullscreen (); #endif return VO_TRUE; #ifndef GL_WIN32 case VOCTRL_SET_EQUALIZER: { va_list ap; int value; va_start (ap, data); value = va_arg (ap, int); va_end (ap); return vo_x11_set_equalizer (data, value); } case VOCTRL_GET_EQUALIZER: { va_list ap; int *value; va_start (ap, data); value = va_arg (ap, int *); va_end (ap); return vo_x11_get_equalizer (data, value); } #endif case VOCTRL_GET_PANSCAN: return VO_TRUE; case VOCTRL_SET_PANSCAN: resize (vo_dwidth, vo_dheight); return VO_TRUE; } return VO_NOTIMPL; }