Вы можете просто скопировать ветку «сохранить соотношение сторон» (при условии, что она работает) и просто перевернуть знак сравнения коэффициентов, т.е.:
if (ratiox > ratioy)
становится
if (ratiox <= ratioy)
Но я не уверен, что это на самом деле работает (вычисления отношения всегда меня раздражали - а у вас это сложно), и у меня нет Qt atm, поэтому я не могу попробовать. Но это должно сделать это. Обратите внимание, что изображение будет отцентрировано (не выровнено по левому краю, как на вашем изображении), но это можно довольно легко исправить.
EDIT
Вот исходный код, который работает в приложении GLUT (без QT, извините):
static void DrawObject(void)
{
int img_width = 1280;//_frame->width();
int img_height = 720;//_frame->height();
GLfloat offset_x = -1;
GLfloat offset_y = -1;
int p_viewport[4];
glGetIntegerv(GL_VIEWPORT, p_viewport); // don't have QT :'(
GLfloat gl_width = p_viewport[2];//width(); // GL context size
GLfloat gl_height = p_viewport[3];//height();
int n_mode = 0;
switch(n_mode) {
case 0: // KeepAspectRatioByExpanding
{
float ratioImg = float(img_width) / img_height;
float ratioScreen = gl_width / gl_height;
if(ratioImg < ratioScreen) {
gl_width = 2;
gl_height = 2 * ratioScreen / ratioImg;
} else {
gl_height = 2;
gl_width = 2 / ratioScreen * ratioImg;
}
// calculate image size
}
break;
case 1: // IgnoreAspectRatio
gl_width = 2;
gl_height = 2;
// OpenGL normalized coordinates are -1 to +1 .. hence width (or height) = +1 - (-1) = 2
break;
case 2: // KeepAspectRatio
{
float ratioImg = float(img_width) / img_height;
float ratioScreen = gl_width / gl_height;
if(ratioImg > ratioScreen) {
gl_width = 2;
gl_height = 2 * ratioScreen / ratioImg;
} else {
gl_height = 2;
gl_width = 2 / ratioScreen * ratioImg;
}
// calculate image size
offset_x = -1 + (2 - gl_width) * .5f;
offset_y = -1 + (2 - gl_height) * .5f;
// center on screen
}
break;
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
// just simple ortho view, no fancy transform ...
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2f(offset_x, offset_y);
glTexCoord2f(ImgWidth, 0);
glVertex2f(offset_x + gl_width, offset_y);
glTexCoord2f(ImgWidth, ImgHeight);
glVertex2f(offset_x + gl_width, offset_y + gl_height);
glTexCoord2f(0, ImgHeight);
glVertex2f(offset_x, offset_y + gl_height);
glEnd();
// draw a single quad
}
Это работает путем сравнения экранного формата изображения с изображения формата изображения. Вы фактически сравниваете отношение ширины изображения к ширине экрана с высотой изображения к высоте экрана. По крайней мере, это подозрительно, если не сказать неправильно.
Кроме того, нормализовано Координаты OpenGL (при условии простого ортогонального просмотра) находятся в диапазоне (-1, -1) для нижнего левого угла до (1, 1) для верхнего правого. Это означает, что нормализовано ширина и высота равны 2, а смещение равно (-1, -1). Остальная часть кода не требует пояснений. В случае, если текстура перевернута (я тестировал с родовой текстурой, не уверен, была ли она в вертикальном положении), просто измените координаты текстуры в соответствующем направлении (поменяйте местами 0 для ImgWidth (или height) и наоборот).
EDIT2
Использование пиксельных координат (без нормализованных координат OpenGL) еще проще. Вы можете использовать:
static void DrawObject(void)
{
int img_width = 1280;//_frame->width();
int img_height = 720;//_frame->height();
GLfloat offset_x = 0;
GLfloat offset_y = 0;
int p_viewport[4];
glGetIntegerv(GL_VIEWPORT, p_viewport);
GLfloat gl_width = p_viewport[2];//width(); // GL context size
GLfloat gl_height = p_viewport[3];//height();
int n_mode = 0;
switch(n_mode) {
case 0: // KeepAspectRatioByExpanding
{
float ratioImg = float(img_width) / img_height;
float ratioScreen = gl_width / gl_height;
if(ratioImg < ratioScreen)
gl_height = gl_width / ratioImg;
else
gl_width = gl_height * ratioImg;
// calculate image size
}
break;
case 1: // IgnoreAspectRatio
break;
case 2: // KeepAspectRatio
{
float ratioImg = float(img_width) / img_height;
float ratioScreen = gl_width / gl_height;
GLfloat orig_width = gl_width;
GLfloat orig_height = gl_height;
// remember those to be able to center the quad on screen
if(ratioImg > ratioScreen)
gl_height = gl_width / ratioImg;
else
gl_width = gl_height * ratioImg;
// calculate image size
offset_x = 0 + (orig_width - gl_width) * .5f;
offset_y = 0 + (orig_height - gl_height) * .5f;
// center on screen
}
break;
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(-1, -1, 0);
glScalef(2.0f / p_viewport[2], 2.0f / p_viewport[3], 1.0);
// just simple ortho view for vertex coordinate to pixel matching
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2f(offset_x, offset_y);
glTexCoord2f(img_width, 0);
glVertex2f(offset_x + gl_width, offset_y);
glTexCoord2f(img_width, img_height);
glVertex2f(offset_x + gl_width, offset_y + gl_height);
glTexCoord2f(0, img_height);
glVertex2f(offset_x, offset_y + gl_height);
glEnd();
// draw a single quad
}
Обратите внимание, что обе версии кода используют текстуры NPOT. Чтобы адаптировать код под ваш объект, нужно сделать что-то вроде этого:
void GLWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
qDebug() << "> GLWidget::paintEvent OpenGL:" << ((painter.paintEngine()->type() != QPaintEngine::OpenGL &&
painter.paintEngine()->type() != QPaintEngine::OpenGL2) ? "disabled" : "enabled");
QGLContext* context = const_cast<QGLContext *>(QGLContext::currentContext());
if (!context)
{
qDebug() << "> GLWidget::paintEvent !!! Unable to retrieve OGL context";
return;
}
context->makeCurrent();
painter.fillRect(QRectF(QPoint(0, 0), QSize(1280, 768)), Qt::black);
painter.beginNativePainting();
/* Initialize GL extensions */
GLenum err = glewInit();
if (err != GLEW_OK)
{
qDebug() << "> GLWidget::paintEvent !!! glewInit failed with: " << err;
return;
}
if (!GLEW_VERSION_2_1) // check that the machine supports the 2.1 API.
{
qDebug() << "> GLWidget::paintEvent !!! System doesn't support GLEW_VERSION_2_1";
return;
}
/* Setting up texture and transfering data to the GPU */
static GLuint texture = 0;
if (texture != 0)
{
context->deleteTexture(texture);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0,
GL_LUMINANCE, _frame->width(), _frame->height() + _frame->height() / 2, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, _frame->bits());
assert(glGetError() == GL_NO_ERROR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glClearColor(0.3, 0.3, 0.4, 1.0);
/* Initialize shaders and execute them */
_init_shaders();
int img_width = _frame->width();
int img_height = _frame->height();
GLfloat offset_x = 0;
GLfloat offset_y = 0;
GLfloat gl_width = width(); // GL context size
GLfloat gl_height = height();
qDebug() << "paint(): gl_width:" << gl_width << " gl_height:" << gl_height <<
" img:" << _frame->width() << "x" << _frame->height();
int fill_mode = 0;
switch(fill_mode) {
case 0: // KeepAspectRatioByExpanding
{
float ratioImg = float(img_width) / img_height;
float ratioScreen = gl_width / gl_height;
if(ratioImg < ratioScreen)
gl_height = gl_width / ratioImg;
else
gl_width = gl_height * ratioImg;
// calculate image size
}
break;
case 1: // IgnoreAspectRatio
break;
case 2: // KeepAspectRatio
{
float ratioImg = float(img_width) / img_height;
float ratioScreen = gl_width / gl_height;
GLfloat orig_width = gl_width;
GLfloat orig_height = gl_height;
// remember those to be able to center the quad on screen
if(ratioImg > ratioScreen)
gl_height = gl_width / ratioImg;
else
gl_width = gl_height * ratioImg;
// calculate image size
offset_x = 0 + (orig_width - gl_width) * .5f;
offset_y = 0 + (orig_height - gl_height) * .5f;
// center on screen
}
break;
}
glDisable(GL_CULL_FACE); // might cause problems if enabled
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2f(offset_x, offset_y);
glTexCoord2f(img_width, 0);
glVertex2f(offset_x + gl_width, offset_y);
glTexCoord2f(img_width, img_height);
glVertex2f(offset_x + gl_width, offset_y + gl_height);
glTexCoord2f(0, img_height);
glVertex2f(offset_x, offset_y + gl_height);
glEnd();
// draw a single quad
painter.endNativePainting();
}
Не могу гарантировать, что этот последний фрагмент кода не содержит ошибок, поскольку у меня нет QT. Но если есть какие-либо опечатки, исправить их будет довольно просто.