Commit 62b19673 authored by Romain Vimont's avatar Romain Vimont
Browse files

opengl: use TransformMatrix to apply OpenGL vflip

Uploading a picture_t to OpenGL flips it vertically.

To display the video in the correct orientation, the renderer reversed
the transformation: each vertex received as attribute texture
coordinates (x, 1-y) instead of (x, y), in order to flip the image
vertically.

This caused several problems.

Firstly, the renderer must be independent of the input picture storage.
Otherwise, when it will receive an input in the correct orientation, it
will wrongly apply a vertical flip.

Secondly, since the vflip was applied on the input coordinates, it
occurred before the orientation transform:

    OrientationMatrix * VFlipMatrix * input_coords  (semantically)

whereas the correct transformation is:

    VFlipMatrix * OrientationMatrix * input_coords

(for reasons explained in e329c4bb).

Since matrix multiplication is not commutative, it resulted in a
wrong orientation in some cases (for example if OrientationMatrix
contains a rotation by 90°).

(In fact, in pratice, this case still worked, because the initialization
of OrientationMatrix was also wrong, see the two previous commits).

To fix all these problems, initialize the texture coordinates in the
normal orientation in the renderer, and apply the vertical flip using
the TransformationMatrix in the sampler.

This also allows to simplify the Android interop, which can just provide
its own transform matrix without compensating for the vertical flip
that was applied in the renderer.
parent 2e1aa698
......@@ -137,37 +137,6 @@ Open(vlc_object_t *obj)
};
interop->ops = &ops;
/* The transform Matrix (uSTMatrix) given by the SurfaceTexture is not
* using the same origin than us. Ask the caller to rotate textures
* coordinates, via the vertex shader, by forcing an orientation. */
switch (interop->fmt.orientation)
{
case ORIENT_TOP_LEFT:
interop->fmt.orientation = ORIENT_BOTTOM_LEFT;
break;
case ORIENT_TOP_RIGHT:
interop->fmt.orientation = ORIENT_BOTTOM_RIGHT;
break;
case ORIENT_BOTTOM_LEFT:
interop->fmt.orientation = ORIENT_TOP_LEFT;
break;
case ORIENT_BOTTOM_RIGHT:
interop->fmt.orientation = ORIENT_TOP_RIGHT;
break;
case ORIENT_LEFT_TOP:
interop->fmt.orientation = ORIENT_RIGHT_TOP;
break;
case ORIENT_LEFT_BOTTOM:
interop->fmt.orientation = ORIENT_RIGHT_BOTTOM;
break;
case ORIENT_RIGHT_TOP:
interop->fmt.orientation = ORIENT_LEFT_TOP;
break;
case ORIENT_RIGHT_BOTTOM:
interop->fmt.orientation = ORIENT_LEFT_BOTTOM;
break;
}
int ret = opengl_interop_init(interop, GL_TEXTURE_EXTERNAL_OES,
VLC_CODEC_RGB32,
COLOR_SPACE_UNDEF);
......
......@@ -488,7 +488,8 @@ static int BuildSphere(GLfloat **vertexCoord, GLfloat **textureCoord, unsigned *
unsigned off2 = (lat * (nbLonBands + 1) + lon) * 2;
float u = (float)lon / nbLonBands;
float v = (float)lat / nbLatBands;
/* In OpenGL, the texture coordinates start at bottom left */
float v = 1.0f - (float)lat / nbLatBands;
(*textureCoord)[off2] = u;
(*textureCoord)[off2 + 1] = v;
}
......@@ -577,35 +578,35 @@ static int BuildCube(float padW, float padH,
float row[] = {0.f, 1.f/2, 1.0};
const GLfloat tex[] = {
col[1] + padW, row[1] + padH, // front
col[1] + padW, row[2] - padH,
col[2] - padW, row[1] + padH,
col[2] - padW, row[2] - padH,
col[3] - padW, row[1] + padH, // back
col[3] - padW, row[2] - padH,
col[2] + padW, row[1] + padH,
col[2] + padW, row[2] - padH,
col[2] - padW, row[0] + padH, // left
col[2] - padW, row[1] - padH,
col[1] + padW, row[1] - padH, // front
col[1] + padW, row[0] + padH,
col[1] + padW, row[1] - padH,
col[2] - padW, row[1] - padH,
col[2] - padW, row[0] + padH,
col[0] + padW, row[0] + padH, // right
col[0] + padW, row[1] - padH,
col[1] - padW, row[0] + padH,
col[1] - padW, row[1] - padH,
col[3] - padW, row[1] - padH, // back
col[3] - padW, row[0] + padH,
col[2] + padW, row[1] - padH,
col[2] + padW, row[0] + padH,
col[2] - padW, row[2] - padH, // left
col[2] - padW, row[1] + padH,
col[1] + padW, row[2] - padH,
col[1] + padW, row[1] + padH,
col[0] + padW, row[2] - padH, // bottom
col[0] + padW, row[2] - padH, // right
col[0] + padW, row[1] + padH,
col[1] - padW, row[2] - padH,
col[1] - padW, row[1] + padH,
col[2] + padW, row[0] + padH, // top
col[2] + padW, row[1] - padH,
col[3] - padW, row[0] + padH,
col[3] - padW, row[1] - padH,
col[0] + padW, row[0] + padH, // bottom
col[0] + padW, row[1] - padH,
col[1] - padW, row[0] + padH,
col[1] - padW, row[1] - padH,
col[2] + padW, row[2] - padH, // top
col[2] + padW, row[1] + padH,
col[3] - padW, row[2] - padH,
col[3] - padW, row[1] + padH,
};
memcpy(*textureCoord, tex,
......@@ -658,10 +659,10 @@ static int BuildRectangle(GLfloat **vertexCoord, GLfloat **textureCoord, unsigne
memcpy(*vertexCoord, coord, *nbVertices * 3 * sizeof(GLfloat));
static const GLfloat tex[] = {
0.0, 0.0,
0.0, 1.0,
1.0, 0.0,
0.0, 0.0,
1.0, 1.0,
1.0, 0.0,
};
memcpy(*textureCoord, tex, *nbVertices * 2 * sizeof(GLfloat));
......
......@@ -306,11 +306,31 @@ sampler_base_fetch_locations(struct vlc_gl_sampler *sampler, GLuint program)
static const GLfloat *
GetTransformMatrix(const struct vlc_gl_interop *interop)
{
/* In column-major order */
static const float MATRIX4_VFLIP[4*4] = {
1, 0, 0, 0,
0, -1, 0 , 0,
0, 0, 1, 0,
0, 1, 0, 1,
};
const GLfloat *tm = NULL;
if (interop->ops && interop->ops->get_transform_matrix)
tm = interop->ops->get_transform_matrix(interop);
if (!tm)
tm = MATRIX4_IDENTITY;
/*
* Due to the way texture coordinates are expressed, the interpretation
* of the video orientation is flipped vertically in the OpenGL world.
*
* For example, a video stored from top-left to bottom-right is
* considered in its natural orientation (ORIENT_NORMAL) in VLC, but
* flipped vertically (ORIENT_VFLIPPED) in OpenGL, since the origin of
* coordinates (0, 0) is at the bottom-right.
*
* Unless a specific matrix is specified by get_transform_matrix(),
* flip vertically by default.
*/
tm = MATRIX4_VFLIP;
return tm;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment