first commit
This commit is contained in:
120
project/fm_viewer/fav/opengl/ConvolutionShader.cpp
Normal file
120
project/fm_viewer/fav/opengl/ConvolutionShader.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV (from 2016)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
#include "../ConvolutionShader.h"
|
||||
#include "../VideoShader_p.h"
|
||||
#if !(REMOVE_VIDEO_SHADER)
|
||||
namespace FAV {
|
||||
class ConvolutionShaderPrivate : public VideoShaderPrivate
|
||||
{
|
||||
public:
|
||||
ConvolutionShaderPrivate() : VideoShaderPrivate()
|
||||
, u_Kernel(-1)
|
||||
, radius(1)
|
||||
{
|
||||
kernel.resize((2*radius+1)*(2*radius+1));
|
||||
updateShaderCode();
|
||||
}
|
||||
void updateShaderCode() {
|
||||
const int ks = (2*radius+1)*(2*radius+1);
|
||||
header = QStringLiteral("uniform float u_Kernel[%1];").arg(ks).toUtf8();
|
||||
QString s = QStringLiteral("vec4 sample2d(sampler2D tex, vec2 pos, int p) { vec4 c = vec4(0.0);");
|
||||
const int kd = 2*radius+1;
|
||||
for (int i = 0; i < ks; ++i) {
|
||||
const int x = i % kd - radius;
|
||||
const int y = i / kd - radius;
|
||||
s += QStringLiteral("c += texture(tex, pos + u_texelSize[p]*vec2(%1.0,%2.0))*u_Kernel[%3];")
|
||||
.arg(x).arg(y).arg(i);
|
||||
}
|
||||
s += "c.a = texture(tex, pos).a;"
|
||||
"return c;}\n";
|
||||
sample_func = s.toUtf8();
|
||||
}
|
||||
|
||||
int u_Kernel;
|
||||
int radius;
|
||||
QVector<float> kernel;
|
||||
QByteArray header, sample_func;
|
||||
};
|
||||
|
||||
ConvolutionShader::ConvolutionShader()
|
||||
: VideoShader(*new ConvolutionShaderPrivate())
|
||||
{}
|
||||
|
||||
ConvolutionShader::ConvolutionShader(ConvolutionShaderPrivate &d)
|
||||
: VideoShader(d)
|
||||
{}
|
||||
|
||||
int ConvolutionShader::kernelRadius() const
|
||||
{
|
||||
return d_func().radius;
|
||||
}
|
||||
|
||||
void ConvolutionShader::setKernelRadius(int value)
|
||||
{
|
||||
DPTR_D(ConvolutionShader);
|
||||
if (d.radius == value)
|
||||
return;
|
||||
d.radius = value;
|
||||
d.kernel.resize(kernelSize());
|
||||
d.updateShaderCode();
|
||||
rebuildLater();
|
||||
}
|
||||
|
||||
int ConvolutionShader::kernelSize() const
|
||||
{
|
||||
return (2*kernelRadius() + 1)*(2*kernelRadius() + 1);
|
||||
}
|
||||
|
||||
const char* ConvolutionShader::userShaderHeader(QOpenGLShader::ShaderType t) const
|
||||
{
|
||||
if (t == QOpenGLShader::Vertex)
|
||||
return 0;
|
||||
return kernelUniformHeader().constData();
|
||||
}
|
||||
|
||||
const char* ConvolutionShader::userSample() const
|
||||
{
|
||||
return kernelSample().constData();
|
||||
}
|
||||
|
||||
bool ConvolutionShader::setUserUniformValues()
|
||||
{
|
||||
setKernelUniformValue();
|
||||
return true;
|
||||
}
|
||||
|
||||
const QByteArray& ConvolutionShader::kernelUniformHeader() const
|
||||
{
|
||||
return d_func().header;
|
||||
}
|
||||
|
||||
const QByteArray& ConvolutionShader::kernelSample() const
|
||||
{
|
||||
return d_func().sample_func;
|
||||
}
|
||||
|
||||
void ConvolutionShader::setKernelUniformValue()
|
||||
{
|
||||
program()->setUniformValueArray("u_Kernel", kernel(), kernelSize(), 1);
|
||||
}
|
||||
|
||||
} //namespace FAV
|
||||
#endif #if !(REMOVE_VIDEO_SHADER)
|
||||
546
project/fm_viewer/fav/opengl/Geometry.cpp
Normal file
546
project/fm_viewer/fav/opengl/Geometry.cpp
Normal file
@@ -0,0 +1,546 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2017 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV (from 2016)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
|
||||
#include "../Geometry.h"
|
||||
#include <QtDebug>
|
||||
#include <QtCore/qmath.h>
|
||||
|
||||
namespace FAV {
|
||||
|
||||
Attribute::Attribute(DataType type, int tupleSize, int offset, bool normalize)
|
||||
: m_normalize(normalize)
|
||||
, m_type(type)
|
||||
, m_tupleSize(tupleSize)
|
||||
, m_offset(offset)
|
||||
{}
|
||||
|
||||
Attribute::Attribute(const QByteArray& name, DataType type, int tupleSize, int offset, bool normalize)
|
||||
: m_normalize(normalize)
|
||||
, m_type(type)
|
||||
, m_tupleSize(tupleSize)
|
||||
, m_offset(offset)
|
||||
, m_name(name)
|
||||
{}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
QDebug operator<<(QDebug dbg, const Attribute &a) {
|
||||
dbg.nospace() << "attribute: " << a.name();
|
||||
dbg.nospace() << ", offset " << a.offset();
|
||||
dbg.nospace() << ", tupleSize " << a.tupleSize();
|
||||
dbg.nospace() << ", dataType " << a.type();
|
||||
dbg.nospace() << ", normalize " << a.normalize();
|
||||
return dbg.space();
|
||||
}
|
||||
#endif
|
||||
|
||||
Geometry::Geometry(int vertexCount, int indexCount, DataType indexType)
|
||||
: m_primitive(TriangleStrip)
|
||||
, m_itype(indexType)
|
||||
, m_vcount(vertexCount)
|
||||
, m_icount(indexCount)
|
||||
{}
|
||||
|
||||
int Geometry::indexDataSize() const
|
||||
{
|
||||
switch (indexType()) {
|
||||
case TypeU16: return indexCount()*2;
|
||||
case TypeU32: return indexCount()*4;
|
||||
default: return indexCount();
|
||||
}
|
||||
}
|
||||
|
||||
void Geometry::setIndexValue(int index, int value)
|
||||
{
|
||||
switch (indexType()) {
|
||||
case TypeU8: {
|
||||
quint8* d = (quint8*)m_idata.constData();
|
||||
*(d+index) = value;
|
||||
}
|
||||
break;
|
||||
case TypeU16: {
|
||||
quint16* d = (quint16*)m_idata.constData();
|
||||
*(d+index) = value;
|
||||
}
|
||||
break;
|
||||
case TypeU32: {
|
||||
quint32* d = (quint32*)m_idata.constData();
|
||||
*(d+index) = value;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Geometry::setIndexValue(int index, int v1, int v2, int v3)
|
||||
{
|
||||
// TODO: *(d + 3*index), *(d + 3*index + 1), *(d + 3*index + 2)
|
||||
switch (indexType()) {
|
||||
case TypeU8: {
|
||||
quint8* d = (quint8*)m_idata.constData();
|
||||
*(d+index++) = v1;
|
||||
*(d+index++) = v2;
|
||||
*(d+index++) = v2;
|
||||
}
|
||||
break;
|
||||
case TypeU16: {
|
||||
quint16* d = (quint16*)m_idata.constData();
|
||||
*(d+index++) = v1;
|
||||
*(d+index++) = v2;
|
||||
*(d+index++) = v3;
|
||||
}
|
||||
break;
|
||||
case TypeU32: {
|
||||
quint32* d = (quint32*)m_idata.constData();
|
||||
*(d+index++) = v1;
|
||||
*(d+index++) = v2;
|
||||
*(d+index++) = v3;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Geometry::dumpVertexData()
|
||||
{
|
||||
printf("vertex %p: ", m_vdata.constData());
|
||||
const int n = stride()/sizeof(float);
|
||||
for (int i = 0; i < m_vcount; ++i) {
|
||||
const float* f = (const float*)(m_vdata.constData()+i*stride());
|
||||
for (int j = 0; j < n; ++j) {
|
||||
printf("%f, ", *(f+j));
|
||||
}
|
||||
printf(";");
|
||||
}
|
||||
printf("\n");fflush(0);
|
||||
}
|
||||
|
||||
void Geometry::dumpIndexData()
|
||||
{
|
||||
switch (indexType()) {
|
||||
case TypeU8: {
|
||||
quint8* d = (quint8*)m_idata.constData();
|
||||
for (int i = 0; i < m_icount; ++i) printf("%u, ", *(d+i));
|
||||
}
|
||||
break;
|
||||
case TypeU16: {
|
||||
quint16* d = (quint16*)m_idata.constData();
|
||||
for (int i = 0; i < m_icount; ++i) printf("%u, ", *(d+i));
|
||||
}
|
||||
break;
|
||||
case TypeU32: {
|
||||
quint32* d = (quint32*)m_idata.constData();
|
||||
for (int i = 0; i < m_icount; ++i) printf("%u, ", *(d+i));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
printf("\n");fflush(0);
|
||||
}
|
||||
|
||||
void Geometry::allocate(int nbVertex, int nbIndex)
|
||||
{
|
||||
m_icount = nbIndex;
|
||||
m_vcount = nbVertex;
|
||||
m_vdata.resize(nbVertex*stride());
|
||||
memset(m_vdata.data(), 0, m_vdata.size());
|
||||
if (nbIndex <= 0) {
|
||||
m_idata.clear(); // required?
|
||||
return;
|
||||
}
|
||||
switch (indexType()) {
|
||||
case TypeU8:
|
||||
m_idata.resize(nbIndex*sizeof(quint8));
|
||||
break;
|
||||
case TypeU16:
|
||||
m_idata.resize(nbIndex*sizeof(quint16));
|
||||
break;
|
||||
case TypeU32:
|
||||
m_idata.resize(nbIndex*sizeof(quint32));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
memset((void*)m_idata.constData(), 0, m_idata.size());
|
||||
}
|
||||
|
||||
bool Geometry::compare(const Geometry *other) const
|
||||
{
|
||||
// this == other: attributes and stride can be different
|
||||
if (!other)
|
||||
return false;
|
||||
if (stride() != other->stride())
|
||||
return false;
|
||||
return attributes() == other->attributes();
|
||||
}
|
||||
|
||||
TexturedGeometry::TexturedGeometry()
|
||||
: Geometry()
|
||||
, nb_tex(0)
|
||||
, geo_rect(-1, 1, 2, -2) // (-1, -1, 2, 2) flip y
|
||||
{
|
||||
setVertexCount(4);
|
||||
a = QVector<Attribute>()
|
||||
<< Attribute(TypeF32, 2, 0)
|
||||
<< Attribute(TypeF32, 2, 2*sizeof(float))
|
||||
;
|
||||
setTextureCount(1);
|
||||
}
|
||||
|
||||
void TexturedGeometry::setTextureCount(int value)
|
||||
{
|
||||
if (value == nb_tex)
|
||||
return;
|
||||
texRect.resize(value);
|
||||
nb_tex = value;
|
||||
}
|
||||
|
||||
int TexturedGeometry::textureCount() const
|
||||
{
|
||||
return nb_tex;
|
||||
}
|
||||
|
||||
void TexturedGeometry::setPoint(int index, const QPointF &p, const QPointF &tp, int texIndex)
|
||||
{
|
||||
setGeometryPoint(index, p);
|
||||
setTexturePoint(index, tp, texIndex);
|
||||
}
|
||||
|
||||
void TexturedGeometry::setGeometryPoint(int index, const QPointF &p)
|
||||
{
|
||||
float *v = (float*)(m_vdata.constData() + index*stride());
|
||||
*v = p.x();
|
||||
*(v+1) = p.y();
|
||||
}
|
||||
|
||||
void TexturedGeometry::setTexturePoint(int index, const QPointF &tp, int texIndex)
|
||||
{
|
||||
float *v = (float*)(m_vdata.constData() + index*stride() + (texIndex+1)*2*sizeof(float));
|
||||
*v = tp.x();
|
||||
*(v+1) = tp.y();
|
||||
}
|
||||
|
||||
void TexturedGeometry::setRect(const QRectF &r, const QRectF &tr, int texIndex)
|
||||
{
|
||||
setPoint(0, r.topLeft(), tr.topLeft(), texIndex);
|
||||
setPoint(1, r.bottomLeft(), tr.bottomLeft(), texIndex);
|
||||
switch (primitive()) {
|
||||
case TriangleStrip:
|
||||
setPoint(2, r.topRight(), tr.topRight(), texIndex);
|
||||
setPoint(3, r.bottomRight(), tr.bottomRight(), texIndex);
|
||||
break;
|
||||
case TriangleFan:
|
||||
setPoint(3, r.topRight(), tr.topRight(), texIndex);
|
||||
setPoint(2, r.bottomRight(), tr.bottomRight(), texIndex);
|
||||
break;
|
||||
case Triangles:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TexturedGeometry::setGeometryRect(const QRectF &r)
|
||||
{
|
||||
geo_rect = r;
|
||||
}
|
||||
|
||||
void TexturedGeometry::setTextureRect(const QRectF &tr, int texIndex)
|
||||
{
|
||||
if (texRect.size() <= texIndex)
|
||||
texRect.resize(texIndex+1);
|
||||
texRect[texIndex] = tr;
|
||||
//qInfo() << "tr" << tr;
|
||||
}
|
||||
|
||||
const QVector<Attribute>& TexturedGeometry::attributes() const
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
void TexturedGeometry::create()
|
||||
{
|
||||
allocate(vertexCount());
|
||||
if (a.size()-1 < textureCount()) { // the first is position
|
||||
for (int i = a.size()-1; i < textureCount(); ++i)
|
||||
a << Attribute(TypeF32, 2, int((i+1)* 2*sizeof(float)));
|
||||
} else {
|
||||
a.resize(textureCount() + 1);
|
||||
}
|
||||
|
||||
setGeometryPoint(0, geo_rect.topLeft());
|
||||
setGeometryPoint(1, geo_rect.bottomLeft());
|
||||
switch (primitive()) {
|
||||
case TriangleStrip:
|
||||
setGeometryPoint(2, geo_rect.topRight());
|
||||
setGeometryPoint(3, geo_rect.bottomRight());
|
||||
break;
|
||||
case TriangleFan:
|
||||
setGeometryPoint(3, geo_rect.topRight());
|
||||
setGeometryPoint(2, geo_rect.bottomRight());
|
||||
break;
|
||||
case Triangles:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < texRect.size(); ++i) {
|
||||
const QRectF tr = texRect[i];
|
||||
setTexturePoint(0, tr.topLeft(), i);
|
||||
setTexturePoint(1, tr.bottomLeft(), i);
|
||||
switch (primitive()) {
|
||||
case TriangleStrip:
|
||||
setTexturePoint(2, tr.topRight(), i);
|
||||
setTexturePoint(3, tr.bottomRight(), i);
|
||||
break;
|
||||
case TriangleFan:
|
||||
setTexturePoint(3, tr.topRight(), i);
|
||||
setTexturePoint(2, tr.bottomRight(), i);
|
||||
break;
|
||||
case Triangles:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if (TOP_DOWN_360)
|
||||
#define HEMISPHERE_ONLY 1
|
||||
#define HEMISPHERE_TEST 1
|
||||
#define DRAW_DEBUG_GRAPH 0
|
||||
Sphere::Sphere()
|
||||
: TexturedGeometry()
|
||||
, r(1)
|
||||
{
|
||||
setPrimitive(Triangles);
|
||||
setResolution(64, 129);
|
||||
a = QVector<Attribute>()
|
||||
<< Attribute(TypeF32, 3, 0)
|
||||
<< Attribute(TypeF32, 2, 3*sizeof(float));
|
||||
}
|
||||
#else // DURLA 360
|
||||
Sphere::Sphere()
|
||||
: TexturedGeometry()
|
||||
, r(1)
|
||||
{
|
||||
setPrimitive(Triangles);
|
||||
setResolution(64, 64);
|
||||
//setResolution(128, 128);
|
||||
a = QVector<Attribute>()
|
||||
<< Attribute(TypeF32, 3, 0)
|
||||
<< Attribute(TypeF32, 2, 3*sizeof(float));
|
||||
}
|
||||
|
||||
#endif
|
||||
void Sphere::setResolution(int w, int h)
|
||||
{
|
||||
ru = w;
|
||||
rv = h;
|
||||
#if (HEMISPHERE_ONLY)
|
||||
setVertexCount((ru+1)*((rv/2)+1));
|
||||
#else
|
||||
setVertexCount((ru+1)*(rv+1));
|
||||
#endif
|
||||
}
|
||||
|
||||
void Sphere::setRadius(float value)
|
||||
{
|
||||
r = value;
|
||||
}
|
||||
|
||||
float Sphere::radius() const
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
#if (TOP_DOWN_360)
|
||||
void Sphere::create()
|
||||
{
|
||||
// RU = W, RV = H 가로세로 셀의 개수 * QUAD(2 triangle)
|
||||
allocate(vertexCount(), ru*rv*3*2); // quads * 2 triangles,
|
||||
if (a.size()-1 < nb_tex) { // the first is position
|
||||
for (int i = a.size()-1; i < nb_tex; ++i)
|
||||
a << Attribute(TypeF32, 2, 3*sizeof(float) + int(i* 2*sizeof(float)));
|
||||
} else {
|
||||
a.resize(nb_tex + 1);
|
||||
}
|
||||
|
||||
// TODO: use geo_rect?
|
||||
float *vd = (float*)m_vdata.constData();
|
||||
const float dTheta = M_PI*2.0/float(ru); // 경도 변환 각도 (360 / x)
|
||||
const float dPhi = M_PI/float(rv); // 위도 변환 각도 (180 / y)
|
||||
#if(HEMISPHERE_ONLY)
|
||||
// https://stackoverrun.com/ko/q/734419
|
||||
#if (DRAW_DEBUG_GRAPH)
|
||||
QString graph = "";
|
||||
#endif
|
||||
for (int lat = rv/2; lat < rv; ++lat) {
|
||||
|
||||
const float phi = M_PI_2 - float(lat+1)*dPhi; // 90 - 위도 * y
|
||||
float cosPhi = qCos(phi);
|
||||
const float sinPhi = qSin(phi);
|
||||
|
||||
// if(lat == rv-1) {
|
||||
// cosPhi = 0;
|
||||
// }
|
||||
|
||||
//const float v = 1.0f - float(lat)*dv; // flip y?
|
||||
for (int lon = 0; lon <= ru; ++lon) {
|
||||
const float theta = float(lon)*dTheta;
|
||||
const float cosTheta = qCos(theta);
|
||||
const float sinTheta = qSin(theta);
|
||||
#if (DRAW_DEBUG_GRAPH)
|
||||
int x = r*cosPhi*cosTheta * 1000.0; // X
|
||||
int y = r*sinPhi * 1000.0; // Z
|
||||
int z = r*cosPhi*sinTheta * 1000.0; // Y
|
||||
graph += QString().sprintf("%02d,%02d,%03d,%03d,%03d\n",lat,lon,x,y,z);
|
||||
#endif // DRAW_DEBUG_GRAPH
|
||||
|
||||
*vd++ = r*cosPhi*cosTheta*SPHERE_SCALE; // X = radius *
|
||||
*vd++ = r*sinPhi*SPHERE_SCALE; // Y(Z) 1~-1
|
||||
*vd++ = r*cosPhi*sinTheta*SPHERE_SCALE; // Z
|
||||
// texture
|
||||
for (int i = 0; i < nb_tex; ++i) {
|
||||
// GRID
|
||||
*vd++ = texRect[i].x()+texRect[i].width()/qreal(ru) * qreal(lon);
|
||||
*vd++ = texRect[i].y()+texRect[i].height()/qreal(rv/2) * qreal(lat-rv/2);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if (DRAW_DEBUG_GRAPH)
|
||||
QFile file("C:\\home\\temp\\sphere.csv");
|
||||
if(file.open(QIODevice::WriteOnly))
|
||||
{
|
||||
file.write("LAT,LON,X,Y,Z\n");
|
||||
file.write(graph.toUtf8());
|
||||
file.close();
|
||||
}
|
||||
qInfo() << graph;
|
||||
#endif
|
||||
// create index data
|
||||
if (m_icount > 0) {
|
||||
int idx = 0;
|
||||
for (int lat = 0; lat < rv/2; ++lat) {
|
||||
for (int lon = 0; lon < ru; ++lon) {
|
||||
const int ring = lat*(ru+1) + lon;
|
||||
const int ringNext = ring + ru+1;
|
||||
setIndexValue(idx, ring, ringNext, ring+1);
|
||||
setIndexValue(idx+3, ringNext, ringNext+1, ring+1);
|
||||
idx += 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_icount /= 2;
|
||||
#else // HEMISPHERE_ONLY --> FULL SPHERE
|
||||
for (int lat = 0; lat <= rv; ++lat) {
|
||||
const float phi = M_PI_2 - float(lat)*dPhi;
|
||||
const float cosPhi = qCos(phi);
|
||||
const float sinPhi = qSin(phi);
|
||||
//const float v = 1.0f - float(lat)*dv; // flip y?
|
||||
for (int lon = 0; lon <= ru; ++lon) {
|
||||
const float theta = float(lon)*dTheta;
|
||||
const float cosTheta = qCos(theta);
|
||||
const float sinTheta = qSin(theta);
|
||||
//const float u = float(lon) * du;
|
||||
*vd++ = r*cosPhi*cosTheta;//2.0*float(lon)/float(ru) -1.0;//
|
||||
*vd++ = r*sinPhi;//2.0*float(lat)/float(rv)-1.0;//
|
||||
*vd++ = r*cosPhi*sinTheta;
|
||||
// texture
|
||||
for (int i = 0; i < nb_tex; ++i) {
|
||||
*vd++ = texRect[i].x()+texRect[i].width()/float(ru) * float(lon);
|
||||
*vd++ = texRect[i].y()+texRect[i].height()/float(rv) * float(lat);
|
||||
}
|
||||
}
|
||||
}
|
||||
// create index data
|
||||
if (m_icount > 0) {
|
||||
int idx = 0;
|
||||
for (int lat = 0; lat < rv; ++lat) {
|
||||
for (int lon = 0; lon < ru; ++lon) {
|
||||
const int ring = lat*(ru+1) + lon;
|
||||
const int ringNext = ring + ru+1;
|
||||
setIndexValue(idx, ring, ringNext, ring+1);
|
||||
setIndexValue(idx+3, ringNext, ringNext+1, ring+1);
|
||||
idx += 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
#else // DUAL 360
|
||||
void Sphere::create()
|
||||
{
|
||||
allocate(vertexCount(), ru*rv*3*2); // quads * 2 triangles,
|
||||
if (a.size()-1 < nb_tex) { // the first is position
|
||||
for (int i = a.size()-1; i < nb_tex; ++i)
|
||||
a << Attribute(TypeF32, 2, 3*sizeof(float) + int(i* 2*sizeof(float)));
|
||||
} else {
|
||||
a.resize(nb_tex + 1);
|
||||
}
|
||||
|
||||
// TODO: use geo_rect?
|
||||
float *vd = (float*)m_vdata.constData();
|
||||
const float dTheta = M_PI*2.0/float(ru);
|
||||
const float dPhi = M_PI/float(rv);
|
||||
//const float du = 1.0f/float(ru);
|
||||
//const float dv = 1.0f/float(rv);
|
||||
for (int lat = 0; lat <= rv; ++lat) {
|
||||
const float phi = M_PI_2 - float(lat)*dPhi;
|
||||
const float cosPhi = qCos(phi);
|
||||
const float sinPhi = qSin(phi);
|
||||
//const float v = 1.0f - float(lat)*dv; // flip y?
|
||||
for (int lon = 0; lon <= ru; ++lon) {
|
||||
const float theta = float(lon)*dTheta;
|
||||
const float cosTheta = qCos(theta);
|
||||
const float sinTheta = qSin(theta);
|
||||
//const float u = float(lon) * du;
|
||||
*vd++ = r*cosPhi*cosTheta;//2.0*float(lon)/float(ru) -1.0;//
|
||||
*vd++ = r*sinPhi;//2.0*float(lat)/float(rv)-1.0;//
|
||||
*vd++ = r*cosPhi*sinTheta;
|
||||
for (int i = 0; i < nb_tex; ++i) {
|
||||
*vd++ = texRect[i].x()+texRect[i].width()/float(ru) * float(lon);
|
||||
*vd++ = texRect[i].y()+texRect[i].height()/float(rv) * float(lat);
|
||||
}
|
||||
}
|
||||
}
|
||||
// create index data
|
||||
if (m_icount > 0) {
|
||||
int idx = 0;
|
||||
for (int lat = 0; lat < rv; ++lat) {
|
||||
for (int lon = 0; lon < ru; ++lon) {
|
||||
const int ring = lat*(ru+1) + lon;
|
||||
const int ringNext = ring + ru+1;
|
||||
setIndexValue(idx, ring, ringNext, ring+1);
|
||||
setIndexValue(idx+3, ringNext, ringNext+1, ring+1);
|
||||
idx += 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // DURL 360
|
||||
|
||||
|
||||
} //namespace FAV
|
||||
303
project/fm_viewer/fav/opengl/GeometryRenderer.cpp
Normal file
303
project/fm_viewer/fav/opengl/GeometryRenderer.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2017 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV (from 2016)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
#include "../GeometryRenderer.h"
|
||||
#if !(REMOVE_GEOMETRY_RENDERER)
|
||||
#include "OpenGLHelper.h"
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
#define QGLF(f) QOpenGLContext::currentContext()->functions()->f
|
||||
#else
|
||||
#define QGLF(f) QGLFunctions(NULL).f
|
||||
#endif
|
||||
namespace FAV {
|
||||
|
||||
GeometryRenderer::GeometryRenderer()
|
||||
: g(NULL)
|
||||
, features_(kVBO|kIBO|kVAO|kMapBuffer)
|
||||
, vbo_size(0)
|
||||
, ibo_size(0)
|
||||
, ibo(QOpenGLBuffer::IndexBuffer)
|
||||
, stride(0)
|
||||
{
|
||||
static bool disable_ibo = qgetenv("QTAV_NO_IBO").toInt() > 0;
|
||||
setFeature(kIBO, !disable_ibo);
|
||||
static bool disable_vbo = qgetenv("QTAV_NO_VBO").toInt() > 0;
|
||||
setFeature(kVBO, !disable_vbo);
|
||||
static bool disable_vao = qgetenv("QTAV_NO_VAO").toInt() > 0;
|
||||
setFeature(kVAO, !disable_vao);
|
||||
}
|
||||
|
||||
void GeometryRenderer::setFeature(int f, bool on)
|
||||
{
|
||||
if (on)
|
||||
features_ |= f;
|
||||
else
|
||||
features_ ^= f;
|
||||
}
|
||||
|
||||
void GeometryRenderer::setFeatures(int value)
|
||||
{
|
||||
features_ = value;
|
||||
}
|
||||
|
||||
int GeometryRenderer::features() const
|
||||
{
|
||||
return features_;
|
||||
}
|
||||
|
||||
int GeometryRenderer::actualFeatures() const
|
||||
{
|
||||
int f = 0;
|
||||
if (vbo.isCreated())
|
||||
f |= kVBO;
|
||||
if (ibo.isCreated())
|
||||
f |= kIBO;
|
||||
#if QT_VAO
|
||||
if (vao.isCreated())
|
||||
f |= kVAO;
|
||||
#endif
|
||||
return f;
|
||||
}
|
||||
|
||||
bool GeometryRenderer::testFeatures(int value) const
|
||||
{
|
||||
return !!(features() & value);
|
||||
}
|
||||
|
||||
void GeometryRenderer::updateGeometry(Geometry *geo)
|
||||
{
|
||||
g = geo;
|
||||
if (!g) {
|
||||
ibo.destroy();
|
||||
vbo.destroy();
|
||||
#if QT_VAO
|
||||
vao.destroy();
|
||||
#endif
|
||||
vbo_size = 0;
|
||||
ibo_size = 0;
|
||||
return;
|
||||
}
|
||||
static int support_map = -1;
|
||||
if (support_map < 0) {
|
||||
static const char* ext[] = { "GL_OES_mapbuffer", NULL};
|
||||
if (OpenGLHelper::isOpenGLES()) {
|
||||
support_map = QOpenGLContext::currentContext()->format().majorVersion() > 2 ||
|
||||
OpenGLHelper::hasExtension(ext);
|
||||
} else {
|
||||
support_map = 1;
|
||||
}
|
||||
}
|
||||
if (testFeatures(kIBO) && !ibo.isCreated()) {
|
||||
if (g->indexCount() > 0) {
|
||||
//qDebug("creating IBO...");
|
||||
if (!ibo.create())
|
||||
qDebug("IBO create error");
|
||||
}
|
||||
}
|
||||
if (ibo.isCreated()) {
|
||||
ibo.bind();
|
||||
const int bs = g->indexDataSize();
|
||||
if (bs == ibo_size) {
|
||||
void * p = NULL;
|
||||
if (support_map && testFeatures(kMapBuffer))
|
||||
p = ibo.map(QOpenGLBuffer::WriteOnly);
|
||||
if (p) {
|
||||
memcpy(p, g->constIndexData(), bs);
|
||||
ibo.unmap();
|
||||
} else {
|
||||
ibo.write(0, g->constIndexData(), bs);
|
||||
}
|
||||
} else {
|
||||
ibo.allocate(g->indexData(), bs); // TODO: allocate NULL and then map or BufferSubData?
|
||||
ibo_size = bs;
|
||||
}
|
||||
ibo.release();
|
||||
}
|
||||
if (testFeatures(kVBO) && !vbo.isCreated())
|
||||
{
|
||||
#if (DEBUG_QT_VAO)
|
||||
qDebug("creating VBO...");
|
||||
#endif
|
||||
if (!vbo.create())
|
||||
{
|
||||
qWarning("VBO create error");
|
||||
}
|
||||
}
|
||||
if (vbo.isCreated()) {
|
||||
vbo.bind();
|
||||
const int bs = g->vertexCount()*g->stride();
|
||||
/* Notes from https://www.opengl.org/sdk/docs/man/html/glBufferSubData.xhtml
|
||||
When replacing the entire data store, consider using glBufferSubData rather than completely recreating the data store with glBufferData. This avoids the cost of reallocating the data store.
|
||||
*/
|
||||
if (bs == vbo_size) { // vbo.size() error 0x501 on rpi, and query gl value can be slow
|
||||
void* p = NULL;
|
||||
if (support_map && testFeatures(kMapBuffer))
|
||||
p = vbo.map(QOpenGLBuffer::WriteOnly);
|
||||
if (p) {
|
||||
memcpy(p, g->constVertexData(), bs);
|
||||
vbo.unmap();
|
||||
} else {
|
||||
vbo.write(0, g->constVertexData(), bs);
|
||||
vbo_size = bs;
|
||||
}
|
||||
} else {
|
||||
vbo.allocate(g->vertexData(), bs);
|
||||
}
|
||||
vbo.release();
|
||||
}
|
||||
#if QT_VAO
|
||||
if (stride == g->stride() && attrib == g->attributes())
|
||||
return;
|
||||
stride = g->stride();
|
||||
attrib = g->attributes();
|
||||
|
||||
if (testFeatures(kVAO) && !vao.isCreated())
|
||||
{
|
||||
#if (DEBUG_QT_VAO)
|
||||
qDebug("creating VAO...");
|
||||
#endif
|
||||
if (!vao.create())
|
||||
{
|
||||
#if (DEBUG_QT_VAO)
|
||||
qDebug("VAO create error");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if (DEBUG_QT_VAO)
|
||||
qDebug("vao updated");
|
||||
#endif
|
||||
if (vao.isCreated()) // can not use vao binder because it will create a vao if necessary
|
||||
{
|
||||
vao.bind();
|
||||
}
|
||||
// can set data before vao bind
|
||||
if (!vao.isCreated())
|
||||
{
|
||||
return;
|
||||
}
|
||||
qDebug("geometry attributes changed, rebind vao...");
|
||||
// call once is enough if no feature and no geometry attribute is changed
|
||||
if (vbo.isCreated())
|
||||
{
|
||||
vbo.bind();
|
||||
for (int an = 0; an < g->attributes().size(); ++an) {
|
||||
// FIXME: assume bind order is 0,1,2...
|
||||
const Attribute& a = g->attributes().at(an);
|
||||
QGLF(glVertexAttribPointer(an, a.tupleSize(), a.type(), a.normalize(), g->stride(), reinterpret_cast<const void *>(qptrdiff(a.offset())))); //TODO: in setActiveShader
|
||||
QGLF(glEnableVertexAttribArray(an));
|
||||
}
|
||||
vbo.release(); // unbind after vao unbind? http://www.zwqxin.com/archives/opengl/vao-and-vbo-stuff.html
|
||||
} // TODO: bind pointers if vbo is disabled
|
||||
// bind ibo to vao thus no bind is required later
|
||||
if (ibo.isCreated())// if not bind here, glDrawElements(...,NULL) crashes and must use ibo data ptr, why?
|
||||
ibo.bind();
|
||||
vao.release();
|
||||
if (ibo.isCreated())
|
||||
ibo.release();
|
||||
#endif
|
||||
#if (DEBUG_QT_VAO)
|
||||
qDebug("geometry updated");
|
||||
#endif
|
||||
}
|
||||
|
||||
void GeometryRenderer::bindBuffers()
|
||||
{
|
||||
bool bind_vbo = vbo.isCreated();
|
||||
bool bind_ibo = ibo.isCreated();
|
||||
bool setv_skip = false;
|
||||
#if QT_VAO
|
||||
if (vao.isCreated()) {
|
||||
vao.bind(); // vbo, ibo is ok now
|
||||
setv_skip = bind_vbo;
|
||||
bind_vbo = false;
|
||||
bind_ibo = false;
|
||||
}
|
||||
#endif
|
||||
//qDebug("bind ibo: %d vbo: %d; set v: %d", bind_ibo, bind_vbo, !setv_skip);
|
||||
if (bind_ibo)
|
||||
ibo.bind();
|
||||
// no vbo: set vertex attributes
|
||||
// has vbo, no vao: bind vbo & set vertex attributes
|
||||
// has vbo, has vao: skip
|
||||
if (setv_skip)
|
||||
return;
|
||||
if (!g)
|
||||
return;
|
||||
const char* vdata = static_cast<const char*>(g->vertexData());
|
||||
if (bind_vbo) {
|
||||
vbo.bind();
|
||||
vdata = NULL;
|
||||
}
|
||||
for (int an = 0; an < g->attributes().size(); ++an) {
|
||||
const Attribute& a = g->attributes().at(an);
|
||||
QGLF(glVertexAttribPointer(an, a.tupleSize(), a.type(), a.normalize(), g->stride(), vdata + a.offset()));
|
||||
QGLF(glEnableVertexAttribArray(an)); //TODO: in setActiveShader
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryRenderer::unbindBuffers()
|
||||
{
|
||||
bool unbind_vbo = vbo.isCreated();
|
||||
bool unbind_ibo = ibo.isCreated();
|
||||
bool unsetv_skip = false;
|
||||
#if QT_VAO
|
||||
if (vao.isCreated()) {
|
||||
vao.release();
|
||||
unsetv_skip = unbind_vbo;
|
||||
unbind_vbo = false;
|
||||
unbind_ibo = false;
|
||||
}
|
||||
#endif //QT_VAO
|
||||
//qDebug("unbind ibo: %d vbo: %d; unset v: %d", unbind_ibo, unbind_vbo, !unsetv_skip);
|
||||
if (unbind_ibo)
|
||||
ibo.release();
|
||||
// release vbo. qpainter is affected if vbo is bound
|
||||
if (unbind_vbo)
|
||||
vbo.release();
|
||||
// no vbo: disable vertex attributes
|
||||
// has vbo, no vao: unbind vbo & set vertex attributes
|
||||
// has vbo, has vao: skip
|
||||
if (unsetv_skip)
|
||||
return;
|
||||
if (!g)
|
||||
return;
|
||||
for (int an = 0; an < g->attributes().size(); ++an) {
|
||||
QGLF(glDisableVertexAttribArray(an));
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryRenderer::render()
|
||||
{
|
||||
if (!g)
|
||||
return;
|
||||
bindBuffers();
|
||||
if (g->indexCount() > 0) {
|
||||
DYGL(glDrawElements(g->primitive(), g->indexCount(), g->indexType(), ibo.isCreated() ? NULL : g->indexData())); // null: data in vao or ibo. not null: data in memory
|
||||
#if (MODEL_360)
|
||||
//DYGL(glDrawElements(GL_LINE_LOOP, g->indexCount(), g->indexType(), ibo.isCreated() ? NULL : g->indexData())); // null: data in vao or ibo. not null: data in memory
|
||||
#endif
|
||||
} else {
|
||||
DYGL(glDrawArrays(g->primitive(), 0, g->vertexCount()));
|
||||
//DYGL(glDrawArrays(GL_LINE_LOOP, 0, g->vertexCount()));
|
||||
}
|
||||
unbindBuffers();
|
||||
}
|
||||
} //namespace FAV
|
||||
#endif // #if !(REMOVE_GEOMETRY_RENDERER)
|
||||
773
project/fm_viewer/fav/opengl/OpenGLHelper.cpp
Normal file
773
project/fm_viewer/fav/opengl/OpenGLHelper.cpp
Normal file
@@ -0,0 +1,773 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
|
||||
#include "OpenGLHelper.h"
|
||||
#include <string.h> //strstr
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QRegExp>
|
||||
#include <QtGui/QMatrix4x4>
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
|
||||
#include <QtOpenGL/QGLFunctions>
|
||||
#endif
|
||||
#else
|
||||
#include <QtGui/QGuiApplication>
|
||||
#endif
|
||||
#ifdef QT_OPENGL_DYNAMIC
|
||||
#include <QtGui/QOpenGLFunctions_1_0>
|
||||
#endif
|
||||
#if QTAV_HAVE(EGL_CAPI) // && QTAV_HAVE(QT_EGL) //make sure no crash if no egl library
|
||||
#define EGL_CAPI_NS
|
||||
#include "capi/egl_api.h"
|
||||
#endif //QTAV_HAVE(EGL_CAPI)
|
||||
#include "../Logger.h"
|
||||
|
||||
#define BUG_GLES3_ANDROID 1 //FIXME: N7 android6 gles3 displays red images, only rgb32 is correct
|
||||
|
||||
namespace FAV {
|
||||
namespace OpenGLHelper {
|
||||
|
||||
// glGetTexParameteriv is supported by es2 does not support GL_TEXTURE_INTERNAL_FORMAT.
|
||||
/// 16bit (R16 e.g.) texture does not support >8bit a BE channel, fallback to 2 channel texture
|
||||
int depth16BitTexture()
|
||||
{
|
||||
static int depth = qgetenv("QTAV_TEXTURE16_DEPTH").toInt() == 8 ? 8 : 16;//8 ? 8 : 16;
|
||||
return depth;
|
||||
}
|
||||
|
||||
bool useDeprecatedFormats()
|
||||
{
|
||||
static bool v = qgetenv("QTAV_GL_DEPRECATED").toInt() == 1;
|
||||
return v;
|
||||
}
|
||||
|
||||
QString removeComments(const QString &code)
|
||||
{
|
||||
QString c(code);
|
||||
c.remove(QRegExp(QStringLiteral("(/\\*([^*]|(\\*+[^*/]))*\\*+/)|(//[^\r^\n]*)")));
|
||||
return c;
|
||||
}
|
||||
|
||||
/// current shader works fine for gles 2~3 only with commonShaderHeader(). It's mainly for desktop core profile
|
||||
|
||||
static QByteArray commonShaderHeader(QOpenGLShader::ShaderType type)
|
||||
{
|
||||
// TODO: check useDeprecatedFormats() or useDeprecated()?
|
||||
QByteArray h;
|
||||
if (isOpenGLES()) {
|
||||
h += "precision mediump int;\n"
|
||||
"precision mediump float;\n"
|
||||
;
|
||||
} else {
|
||||
h += "#define highp\n"
|
||||
"#define mediump\n"
|
||||
"#define lowp\n"
|
||||
;
|
||||
}
|
||||
if (type == QOpenGLShader::Fragment) {
|
||||
// >=1.30: texture(sampler2DRect,...). 'texture' is defined in header
|
||||
// we can't check GLSLVersion() here because it the actually version used can be defined by "#version"
|
||||
h += "#if __VERSION__ < 130\n"
|
||||
"#define texture texture2D\n"
|
||||
"#else\n"
|
||||
"#define texture2D texture\n"
|
||||
"#endif // < 130\n"
|
||||
;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
QByteArray compatibleShaderHeader(QOpenGLShader::ShaderType type)
|
||||
{
|
||||
#if BUG_GLES3_ANDROID
|
||||
if (isOpenGLES())
|
||||
return commonShaderHeader(type);
|
||||
#endif //BUG_GLES3_ANDROID
|
||||
QByteArray h;
|
||||
// #version directive must occur in a compilation unit before anything else, except for comments and white spaces. Default is 100 if not set
|
||||
h.append("#version ").append(QByteArray::number(GLSLVersion()));
|
||||
if (isOpenGLES() && QOpenGLContext::currentContext()->format().majorVersion() > 2)
|
||||
h += " es";
|
||||
h += "\n";
|
||||
h += commonShaderHeader(type);
|
||||
if (GLSLVersion() >= 130) { // gl(es) 3
|
||||
if (type == QOpenGLShader::Vertex) {
|
||||
h += "#define attribute in\n"
|
||||
"#define varying out\n"
|
||||
;
|
||||
} else if (type == QOpenGLShader::Fragment) {
|
||||
h += "#define varying in\n"
|
||||
"#define gl_FragColor out_color\n" //can not starts with 'gl_'
|
||||
"out vec4 gl_FragColor;\n"
|
||||
;
|
||||
}
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
int GLSLVersion()
|
||||
{
|
||||
static int v = -1;
|
||||
if (v >= 0)
|
||||
return v;
|
||||
if (!QOpenGLContext::currentContext()) {
|
||||
qWarning("%s: current context is null", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
const char* vs = (const char*)DYGL(glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
int major = 0, minor = 0;
|
||||
// es: "OpenGL ES GLSL ES 1.00 (ANGLE 2.1.99...)" can use ""%*[ a-zA-Z] %d.%d" in sscanf, desktop: "2.1"
|
||||
//QRegExp rx("(\\d+)\\.(\\d+)");
|
||||
if (strncmp(vs, "OpenGL ES GLSL ES ", 18) == 0)
|
||||
vs += 18;
|
||||
if (sscanf(vs, "%d.%d", &major, &minor) == 2) {
|
||||
v = major * 100 + minor;
|
||||
} else {
|
||||
qWarning("Failed to detect glsl version using GL_SHADING_LANGUAGE_VERSION!");
|
||||
v = 110;
|
||||
if (isOpenGLES())
|
||||
v = QOpenGLContext::currentContext()->format().majorVersion() >= 3 ? 300 : 100;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
bool isEGL()
|
||||
{
|
||||
static int is_egl = -1;
|
||||
if (is_egl >= 0)
|
||||
return !!is_egl;
|
||||
#ifdef Q_OS_IOS
|
||||
is_egl = 0;
|
||||
return false;
|
||||
#endif
|
||||
if (isOpenGLES()) { //TODO: ios has no egl
|
||||
is_egl = 1;
|
||||
return true;
|
||||
}
|
||||
// angle has no QTAV_HAVE(QT_EGL). TODO: no assert in capi, or check egl loaded
|
||||
#if QTAV_HAVE(EGL_CAPI) //&& QTAV_HAVE(QT_EGL) //make sure no crash if no egl library
|
||||
if (!egl::api().loaded()) { //load twice, here and ns func call
|
||||
is_egl = 0;
|
||||
return false;
|
||||
}
|
||||
if (eglGetCurrentDisplay() != EGL_NO_DISPLAY) { //egl can be loaded but glx is used
|
||||
is_egl = 1;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
if (QGuiApplication::platformName().contains(QLatin1String("egl"))) {
|
||||
is_egl = 1;
|
||||
return true;
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
|
||||
if (QGuiApplication::platformName().contains(QLatin1String("xcb"))) {
|
||||
is_egl = qgetenv("QT_XCB_GL_INTEGRATION") == "xcb_egl";
|
||||
qDebug("xcb_egl=%d", is_egl);
|
||||
return !!is_egl;
|
||||
}
|
||||
#endif //5.5.0
|
||||
#endif
|
||||
// we can use QOpenGLContext::currentContext()->nativeHandle().value<QEGLNativeContext>(). but gl context is required
|
||||
if (QOpenGLContext::currentContext())
|
||||
is_egl = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isOpenGLES()
|
||||
{
|
||||
#ifdef QT_OPENGL_DYNAMIC
|
||||
QOpenGLContext *ctx = QOpenGLContext::currentContext();
|
||||
if (ctx)
|
||||
return ctx->isOpenGLES();
|
||||
if (qstrcmp(qApp->metaObject()->className(), "QCoreApplication") == 0) // QGuiApplication is required by QOpenGLContext::openGLModuleType
|
||||
return false;
|
||||
// desktop openGLModuleType() can create es compatible context, so prefer QOpenGLContext::isOpenGLES().
|
||||
// qApp->testAttribute(Qt::AA_UseOpenGLES) is what user requested, but not the result can be different. reproduce: dygl set AA_ShareOpenGLContexts|AA_UseOpenGLES, fallback to desktop (why?)
|
||||
return QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL;
|
||||
#endif //QT_OPENGL_DYNAMIC
|
||||
#ifdef QT_OPENGL_ES_2
|
||||
return true;
|
||||
#endif //QT_OPENGL_ES_2
|
||||
#if defined(QT_OPENGL_ES_2_ANGLE_STATIC) || defined(QT_OPENGL_ES_2_ANGLE)
|
||||
return true;
|
||||
#endif //QT_OPENGL_ES_2_ANGLE_STATIC
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasExtensionEGL(const char *exts[])
|
||||
{
|
||||
#if !QTAV_HAVE(EGL_CAPI)
|
||||
Q_UNUSED(exts);
|
||||
#endif
|
||||
|
||||
if (!isEGL())
|
||||
return false;
|
||||
#if QTAV_HAVE(EGL_CAPI)
|
||||
static QList<QByteArray> supported;
|
||||
if (supported.isEmpty()) {
|
||||
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
eglInitialize(display, NULL, NULL);
|
||||
supported = QByteArray(eglQueryString(display, EGL_EXTENSIONS)).split(' ');
|
||||
}
|
||||
static bool print_exts = true;
|
||||
if (print_exts) {
|
||||
print_exts = false;
|
||||
qDebug() << "EGL extensions: " << supported;
|
||||
}
|
||||
for (int i = 0; exts[i]; ++i) {
|
||||
if (supported.contains(QByteArray(exts[i])))
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasExtension(const char *exts[])
|
||||
{
|
||||
const QOpenGLContext *ctx = QOpenGLContext::currentContext();
|
||||
if (!ctx) {
|
||||
qWarning("no gl context for hasExtension");
|
||||
return false;
|
||||
}
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
const char *ext = (const char*)glGetString(GL_EXTENSIONS);
|
||||
if (!ext)
|
||||
return false;
|
||||
#endif
|
||||
for (int i = 0; exts[i]; ++i) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
if (ctx->hasExtension(exts[i]))
|
||||
#else
|
||||
if (strstr(ext, exts[i]))
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isPBOSupported() {
|
||||
// check pbo support
|
||||
static bool support = false;
|
||||
static bool pbo_checked = false;
|
||||
if (pbo_checked)
|
||||
return support;
|
||||
const QOpenGLContext *ctx = QOpenGLContext::currentContext();
|
||||
Q_ASSERT(ctx);
|
||||
if (!ctx)
|
||||
return false;
|
||||
const char* exts[] = {
|
||||
"GL_ARB_pixel_buffer_object",
|
||||
"GL_EXT_pixel_buffer_object",
|
||||
"GL_NV_pixel_buffer_object", //OpenGL ES
|
||||
NULL
|
||||
};
|
||||
support = hasExtension(exts);
|
||||
if (QOpenGLContext::currentContext()->format().majorVersion() > 2)
|
||||
support = true;
|
||||
pbo_checked = true;
|
||||
return support;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GLint internal_format;
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
} gl_param_t;
|
||||
|
||||
// es formats: ALPHA, RGB, RGBA, LUMINANCE, LUMINANCE_ALPHA
|
||||
// es types: UNSIGNED_BYTE, UNSIGNED_SHORT_5_6_5, UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_5_5_5_1 (NO UNSIGNED_SHORT)
|
||||
/*!
|
||||
c: number of channels(components) in the plane
|
||||
b: componet size
|
||||
result is gl_param_compat[(c-1)+4*(b-1)]
|
||||
*/
|
||||
static const gl_param_t gl_param_compat[] = { // it's legacy
|
||||
{ GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE},
|
||||
{ GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE},
|
||||
{ GL_RGB, GL_RGB, GL_UNSIGNED_BYTE},
|
||||
{ GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE},
|
||||
{ GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE}, //2 x 8 fallback to ra
|
||||
{0,0,0},
|
||||
};
|
||||
static const gl_param_t gl_param_3r16[] = {
|
||||
{GL_R8, GL_RED, GL_UNSIGNED_BYTE}, // 1 x 8
|
||||
{GL_RG8, GL_RG, GL_UNSIGNED_BYTE}, // 2 x 8
|
||||
{GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE}, // 3 x 8
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // 4 x 8
|
||||
{GL_R16, GL_RED, GL_UNSIGNED_SHORT}, // 1 x 16
|
||||
{GL_RG16, GL_RG, GL_UNSIGNED_SHORT}, // 2 x 16
|
||||
{GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT}, // 3 x 16
|
||||
{GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT}, // 4 x 16
|
||||
{0,0,0},
|
||||
};
|
||||
static const gl_param_t gl_param_desktop_fallback[] = {
|
||||
{GL_RED, GL_RED, GL_UNSIGNED_BYTE}, // 1 x 8
|
||||
{GL_RG, GL_RG, GL_UNSIGNED_BYTE}, // 2 x 8
|
||||
{GL_RGB, GL_RGB, GL_UNSIGNED_BYTE}, // 3 x 8
|
||||
{GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}, // 4 x 8
|
||||
{GL_RG, GL_RG, GL_UNSIGNED_BYTE}, // 2 x 8
|
||||
{0,0,0},
|
||||
};
|
||||
static const gl_param_t gl_param_es3rg8[] = {
|
||||
{GL_R8, GL_RED, GL_UNSIGNED_BYTE}, // 1 x 8
|
||||
{GL_RG8, GL_RG, GL_UNSIGNED_BYTE}, // 2 x 8
|
||||
{GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE}, // 3 x 8
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // 4 x 8
|
||||
{GL_RG8, GL_RG, GL_UNSIGNED_BYTE}, // 2 x 8 fallback to rg
|
||||
{0,0,0},
|
||||
};
|
||||
//https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_rg.txt
|
||||
// supported by ANGLE+D3D11
|
||||
static const gl_param_t gl_param_es2rg[] = {
|
||||
{GL_RED, GL_RED, GL_UNSIGNED_BYTE}, // 1 x 8 //es2: GL_EXT_texture_rg. R8, RG8 are for render buffer
|
||||
{GL_RG, GL_RG, GL_UNSIGNED_BYTE}, // 2 x 8
|
||||
{GL_RGB, GL_RGB, GL_UNSIGNED_BYTE}, // 3 x 8
|
||||
{GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}, // 4 x 8
|
||||
{GL_RG, GL_RG, GL_UNSIGNED_BYTE}, // 2 x 8 fallback to rg
|
||||
{0,0,0},
|
||||
};
|
||||
|
||||
bool test_gl_param(const gl_param_t& gp, bool* has_16 = 0)
|
||||
{
|
||||
if (!QOpenGLContext::currentContext()) {
|
||||
qWarning("%s: current context is null", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
GLuint tex;
|
||||
DYGL(glGenTextures(1, &tex));
|
||||
DYGL(glBindTexture(GL_TEXTURE_2D, tex));
|
||||
while (DYGL(glGetError()) != GL_NO_ERROR) {}
|
||||
DYGL(glTexImage2D(GL_TEXTURE_2D, 0, gp.internal_format, 64, 64, 0, gp.format, gp.type, NULL));
|
||||
if (DYGL(glGetError()) != GL_NO_ERROR) {
|
||||
DYGL(glDeleteTextures(1, &tex));
|
||||
return false;
|
||||
}
|
||||
if (!gl().GetTexLevelParameteriv) {
|
||||
qDebug("Do not support glGetTexLevelParameteriv. test_gl_param returns false");
|
||||
DYGL(glDeleteTextures(1, &tex));
|
||||
return false;
|
||||
}
|
||||
GLint param = 0;
|
||||
//GL_PROXY_TEXTURE_2D and no glGenTextures?
|
||||
#ifndef GL_TEXTURE_INTERNAL_FORMAT //only in desktop
|
||||
#define GL_TEXTURE_INTERNAL_FORMAT 0x1003
|
||||
#endif
|
||||
gl().GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, ¶m);
|
||||
if (param != gp.internal_format) {
|
||||
qDebug("Do not support texture internal format: %#x (result %#x)", gp.internal_format, param);
|
||||
DYGL(glDeleteTextures(1, &tex));
|
||||
return false;
|
||||
}
|
||||
if (!has_16) {
|
||||
DYGL(glDeleteTextures(1, &tex));
|
||||
return true;
|
||||
}
|
||||
*has_16 = false;
|
||||
GLenum pname = 0;
|
||||
#ifndef GL_TEXTURE_RED_SIZE
|
||||
#define GL_TEXTURE_RED_SIZE 0x805C
|
||||
#endif
|
||||
#ifndef GL_TEXTURE_LUMINANCE_SIZE
|
||||
#define GL_TEXTURE_LUMINANCE_SIZE 0x8060
|
||||
#endif
|
||||
switch (gp.format) {
|
||||
case GL_RED: pname = GL_TEXTURE_RED_SIZE; break;
|
||||
case GL_LUMINANCE: pname = GL_TEXTURE_LUMINANCE_SIZE; break;
|
||||
}
|
||||
param = 0;
|
||||
if (pname)
|
||||
gl().GetTexLevelParameteriv(GL_TEXTURE_2D, 0, pname, ¶m);
|
||||
if (param) {
|
||||
qDebug("16 bit texture depth: %d.\n", (int)param);
|
||||
*has_16 = (int)param == 16;
|
||||
}
|
||||
DYGL(glDeleteTextures(1, &tex));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hasRG()
|
||||
{
|
||||
static int has_rg = -1;
|
||||
if (has_rg >= 0)
|
||||
return !!has_rg;
|
||||
qDebug("check gl3 rg: %#X", gl_param_3r16[1].internal_format);
|
||||
if (test_gl_param(gl_param_3r16[1])) {
|
||||
has_rg = 1;
|
||||
return true;
|
||||
}
|
||||
qDebug("check es3 rg: %#X", gl_param_es3rg8[1].internal_format);
|
||||
if (test_gl_param(gl_param_es3rg8[1])) {
|
||||
has_rg = 1;
|
||||
return true;
|
||||
}
|
||||
qDebug("check GL_EXT_texture_rg");
|
||||
static const char* ext[] = { "GL_EXT_texture_rg", 0}; //RED, RG, R8, RG8
|
||||
if (hasExtension(ext)) {
|
||||
qDebug("has extension GL_EXT_texture_rg");
|
||||
has_rg = 1;
|
||||
return true;
|
||||
}
|
||||
qDebug("check gl es>=3 rg");
|
||||
if (QOpenGLContext::currentContext())
|
||||
has_rg = isOpenGLES() && QOpenGLContext::currentContext()->format().majorVersion() > 2; // Mesa GLES3 does not support (from qt)
|
||||
return has_rg;
|
||||
}
|
||||
|
||||
static int has_16_tex = -1;
|
||||
static const gl_param_t* get_gl_param()
|
||||
{
|
||||
if (!QOpenGLContext::currentContext()) {
|
||||
qWarning("%s: current context is null", __FUNCTION__);
|
||||
return gl_param_compat;
|
||||
}
|
||||
static gl_param_t* gp = 0;
|
||||
if (gp)
|
||||
return gp;
|
||||
bool has_16 = false;
|
||||
// [4] is always available
|
||||
if (test_gl_param(gl_param_3r16[4], &has_16)) {
|
||||
if (has_16 && depth16BitTexture() == 16)
|
||||
gp = (gl_param_t*)gl_param_3r16;
|
||||
else
|
||||
gp = (gl_param_t*)gl_param_desktop_fallback;
|
||||
has_16_tex = has_16;
|
||||
if (!useDeprecatedFormats()) {
|
||||
qDebug("using gl_param_%s", gp == gl_param_3r16? "3r16" : "desktop_fallback");
|
||||
return gp;
|
||||
}
|
||||
} else if (test_gl_param(gl_param_es3rg8[4], &has_16)) { //3.0 will fail because no glGetTexLevelParameteriv
|
||||
gp = (gl_param_t*)gl_param_es3rg8;
|
||||
has_16_tex = has_16;
|
||||
if (!useDeprecatedFormats()) {
|
||||
qDebug("using gl_param_es3rg8");
|
||||
return gp;
|
||||
}
|
||||
} else if (isOpenGLES()) {
|
||||
if (QOpenGLContext::currentContext()->format().majorVersion() > 2)
|
||||
gp = (gl_param_t*)gl_param_es3rg8; //for 3.0
|
||||
else if (hasRG())
|
||||
gp = (gl_param_t*)gl_param_es2rg;
|
||||
has_16_tex = has_16;
|
||||
if (gp && !useDeprecatedFormats()) {
|
||||
qDebug("using gl_param_%s", gp == gl_param_es3rg8 ? "es3rg8" : "es2rg");
|
||||
return gp;
|
||||
}
|
||||
}
|
||||
qDebug("fallback to gl_param_compat");
|
||||
gp = (gl_param_t*)gl_param_compat;
|
||||
has_16_tex = false;
|
||||
return gp;
|
||||
}
|
||||
|
||||
bool has16BitTexture()
|
||||
{
|
||||
if (has_16_tex >= 0)
|
||||
return !!has_16_tex;
|
||||
if (!QOpenGLContext::currentContext()) {
|
||||
qWarning("%s: current context is null", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
get_gl_param();
|
||||
return !!has_16_tex;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
VideoFormat::PixelFormat pixfmt;
|
||||
quint8 channels[4];
|
||||
} reorder_t;
|
||||
// use with gl_param_compat
|
||||
static const reorder_t gl_channel_maps[] = {
|
||||
{ VideoFormat::Format_ARGB32, {1, 2, 3, 0}},
|
||||
{ VideoFormat::Format_ABGR32, {3, 2, 1, 0}}, // R->gl.?(a)->R
|
||||
{ VideoFormat::Format_BGR24, {2, 1, 0, 3}},
|
||||
{ VideoFormat::Format_BGR565, {2, 1, 0, 3}},
|
||||
{ VideoFormat::Format_BGRA32, {2, 1, 0, 3}},
|
||||
{ VideoFormat::Format_BGR32, {2, 1, 0, 3}},
|
||||
{ VideoFormat::Format_BGR48LE,{2, 1, 0, 3}},
|
||||
{ VideoFormat::Format_BGR48BE,{2, 1, 0, 3}},
|
||||
{ VideoFormat::Format_BGR48, {2, 1, 0, 3}},
|
||||
{ VideoFormat::Format_BGR555, {2, 1, 0, 3}},
|
||||
// TODO: rgb444le/be etc
|
||||
{ VideoFormat::Format_Invalid,{1, 2, 3}}
|
||||
};
|
||||
|
||||
static QMatrix4x4 channelMap(const VideoFormat& fmt)
|
||||
{
|
||||
if (fmt.isPlanar()) //currently only for planar
|
||||
return QMatrix4x4();
|
||||
switch (fmt.pixelFormat()) {
|
||||
case VideoFormat::Format_UYVY:
|
||||
return QMatrix4x4(0.0f, 0.5f, 0.0f, 0.5f,
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
case VideoFormat::Format_YUYV:
|
||||
return QMatrix4x4(0.5f, 0.0f, 0.5f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
case VideoFormat::Format_VYUY:
|
||||
return QMatrix4x4(0.0f, 0.5f, 0.0f, 0.5f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
case VideoFormat::Format_YVYU:
|
||||
return QMatrix4x4(0.5f, 0.0f, 0.5f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
case VideoFormat::Format_VYU:
|
||||
return QMatrix4x4(0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const quint8 *channels = NULL;//{ 0, 1, 2, 3};
|
||||
for (int i = 0; gl_channel_maps[i].pixfmt != VideoFormat::Format_Invalid; ++i) {
|
||||
if (gl_channel_maps[i].pixfmt == fmt.pixelFormat()) {
|
||||
channels = gl_channel_maps[i].channels;
|
||||
break;
|
||||
}
|
||||
}
|
||||
QMatrix4x4 m;
|
||||
if (!channels)
|
||||
return m;
|
||||
m.fill(0);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
m(i, channels[i]) = 1;
|
||||
}
|
||||
qDebug() << m;
|
||||
return m;
|
||||
}
|
||||
|
||||
//template<typename T, size_t N> Q_CONSTEXPR size_t array_size(const T (&)[N]) { return N;} //does not support local type if no c++11
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
|
||||
bool videoFormatToGL(const VideoFormat& fmt, GLint* internal_format, GLenum* data_format, GLenum* data_type, QMatrix4x4* mat)
|
||||
{
|
||||
typedef struct fmt_entry {
|
||||
VideoFormat::PixelFormat pixfmt;
|
||||
GLint internal_format;
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
} fmt_entry;
|
||||
static const fmt_entry pixfmt_to_gles[] = {
|
||||
{VideoFormat::Format_BGRA32, GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE }, //tested for angle
|
||||
{VideoFormat::Format_RGB32, GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE },
|
||||
{VideoFormat::Format_Invalid, 0, 0, 0}
|
||||
};
|
||||
Q_UNUSED(pixfmt_to_gles);
|
||||
static const fmt_entry pixfmt_to_desktop[] = {
|
||||
{VideoFormat::Format_BGRA32, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE }, //bgra bgra works on win but not macOS
|
||||
{VideoFormat::Format_RGB32, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE }, //FIXMEL endian check
|
||||
//{VideoFormat::Format_BGRA32, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, //{2,1,0,3}
|
||||
//{VideoFormat::Format_BGR24, GL_RGB, GL_BGR, GL_UNSIGNED_BYTE }, //{0,1,2,3}
|
||||
#ifdef GL_UNSIGNED_SHORT_5_6_5_REV
|
||||
{VideoFormat::Format_BGR565, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV}, // es error, use channel map
|
||||
#endif
|
||||
#ifdef GL_UNSIGNED_SHORT_1_5_5_5_REV
|
||||
{VideoFormat::Format_RGB555, GL_RGBA, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV},
|
||||
#endif
|
||||
#ifdef GL_UNSIGNED_SHORT_1_5_5_5_REV
|
||||
{VideoFormat::Format_BGR555, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV},
|
||||
#endif
|
||||
// TODO: BE formats not implemeted
|
||||
{VideoFormat::Format_RGB48, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT }, //TODO: they are not work for ANGLE, and rgb16 works on desktop gl, so remove these lines to use rgb16?
|
||||
{VideoFormat::Format_RGB48LE, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT },
|
||||
{VideoFormat::Format_RGB48BE, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT },
|
||||
{VideoFormat::Format_BGR48, GL_RGB, GL_BGR, GL_UNSIGNED_SHORT }, //RGB16?
|
||||
{VideoFormat::Format_BGR48LE, GL_RGB, GL_BGR, GL_UNSIGNED_SHORT },
|
||||
{VideoFormat::Format_BGR48BE, GL_RGB, GL_BGR, GL_UNSIGNED_SHORT },
|
||||
{VideoFormat::Format_RGBA64LE, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT },
|
||||
{VideoFormat::Format_RGBA64BE, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT },
|
||||
{VideoFormat::Format_BGRA64LE, GL_RGBA, GL_BGRA, GL_UNSIGNED_SHORT },
|
||||
{VideoFormat::Format_BGRA64BE, GL_RGBA, GL_BGRA, GL_UNSIGNED_SHORT },
|
||||
{VideoFormat::Format_Invalid, 0, 0, 0}
|
||||
};
|
||||
Q_UNUSED(pixfmt_to_desktop);
|
||||
const fmt_entry *pixfmt_gl_entry = pixfmt_to_desktop;
|
||||
if (OpenGLHelper::isOpenGLES())
|
||||
pixfmt_gl_entry = pixfmt_to_gles;
|
||||
// Very special formats, for which OpenGL happens to have direct support
|
||||
static const fmt_entry pixfmt_gl_base[] = {
|
||||
{VideoFormat::Format_RGBA32, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, // only tested for macOS, win, angle
|
||||
{VideoFormat::Format_RGB24, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE },
|
||||
{VideoFormat::Format_RGB565, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5},
|
||||
{VideoFormat::Format_BGR32, GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE }, //rgba(tested) or abgr, depending on endian
|
||||
};
|
||||
const VideoFormat::PixelFormat pixfmt = fmt.pixelFormat();
|
||||
// can not use array size because pixfmt_gl_entry is set on runtime
|
||||
for (const fmt_entry* e = pixfmt_gl_entry; e->pixfmt != VideoFormat::Format_Invalid; ++e) {
|
||||
if (e->pixfmt == pixfmt) {
|
||||
*internal_format = e->internal_format;
|
||||
*data_format = e->format;
|
||||
*data_type = e->type;
|
||||
if (mat)
|
||||
*mat = QMatrix4x4();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < ARRAY_SIZE(pixfmt_gl_base); ++i) {
|
||||
const fmt_entry& e = pixfmt_gl_base[i];
|
||||
if (e.pixfmt == pixfmt) {
|
||||
*internal_format = e.internal_format;
|
||||
*data_format = e.format;
|
||||
*data_type = e.type;
|
||||
if (mat)
|
||||
*mat = QMatrix4x4();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
static const fmt_entry pixfmt_to_gl_swizzele[] = {
|
||||
{VideoFormat::Format_VYU, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE },
|
||||
{VideoFormat::Format_UYVY, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE },
|
||||
{VideoFormat::Format_YUYV, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE },
|
||||
{VideoFormat::Format_VYUY, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE },
|
||||
{VideoFormat::Format_YVYU, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE },
|
||||
{VideoFormat::Format_BGR565, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, //swizzle
|
||||
{VideoFormat::Format_RGB555, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, //not working
|
||||
{VideoFormat::Format_BGR555, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, //not working
|
||||
};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(pixfmt_to_gl_swizzele); ++i) {
|
||||
const fmt_entry& e = pixfmt_to_gl_swizzele[i];
|
||||
if (e.pixfmt == pixfmt) {
|
||||
*internal_format = e.internal_format;
|
||||
*data_format = e.format;
|
||||
*data_type = e.type;
|
||||
if (mat)
|
||||
*mat = channelMap(fmt);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
GLint *i_f = internal_format;
|
||||
GLenum *d_f = data_format;
|
||||
GLenum *d_t = data_type;
|
||||
gl_param_t* gp = (gl_param_t*)get_gl_param();
|
||||
const int nb_planes = fmt.planeCount();
|
||||
if (gp == gl_param_3r16 && (
|
||||
//nb_planes == 2 || // nv12 UV plane is 16bit, but we use rg
|
||||
(OpenGLHelper::depth16BitTexture() == 16 && OpenGLHelper::has16BitTexture() && fmt.isBigEndian() && fmt.bitsPerComponent() > 8) // 16bit texture does not support be channel now
|
||||
)) {
|
||||
gp = (gl_param_t*)gl_param_desktop_fallback;
|
||||
qDebug("desktop_fallback for %s", nb_planes == 2 ? "bi-plane format" : "16bit big endian channel");
|
||||
}
|
||||
for (int p = 0; p < nb_planes; ++p) {
|
||||
// for packed rgb(swizzle required) and planar formats
|
||||
const int c = (fmt.channels(p)-1) + 4*((fmt.bitsPerComponent() + 7)/8 - 1);
|
||||
if (gp[c].format == 0)
|
||||
return false;
|
||||
const gl_param_t& f = gp[c];
|
||||
*(i_f++) = f.internal_format;
|
||||
*(d_f++) = f.format;
|
||||
*(d_t++) = f.type;
|
||||
}
|
||||
if (nb_planes > 2 && data_format[2] == GL_LUMINANCE && fmt.bytesPerPixel(1) == 1) { // QtAV uses the same shader for planar and semi-planar yuv format
|
||||
internal_format[2] = data_format[2] = GL_ALPHA;
|
||||
if (nb_planes == 4)
|
||||
internal_format[3] = data_format[3] = data_format[2]; // vec4(,,,A)
|
||||
}
|
||||
if (mat)
|
||||
*mat = channelMap(fmt);
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: format + datatype? internal format == format?
|
||||
//https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_format_BGRA8888.txt
|
||||
// TODO: special format size, or componentsize(dataType)*components(format)
|
||||
int bytesOfGLFormat(GLenum format, GLenum dataType) // TODO: rename bytesOfTexel
|
||||
{
|
||||
int component_size = 0;
|
||||
switch (dataType) {
|
||||
#ifdef GL_UNSIGNED_INT_8_8_8_8_REV
|
||||
case GL_UNSIGNED_INT_8_8_8_8_REV:
|
||||
return 4;
|
||||
#endif
|
||||
#ifdef GL_UNSIGNED_BYTE_3_3_2
|
||||
case GL_UNSIGNED_BYTE_3_3_2:
|
||||
return 1;
|
||||
#endif //GL_UNSIGNED_BYTE_3_3_2
|
||||
#ifdef GL_UNSIGNED_BYTE_2_3_3_REV
|
||||
case GL_UNSIGNED_BYTE_2_3_3_REV:
|
||||
return 1;
|
||||
#endif
|
||||
case GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
#ifdef GL_UNSIGNED_SHORT_1_5_5_5_REV
|
||||
case GL_UNSIGNED_SHORT_1_5_5_5_REV:
|
||||
#endif //GL_UNSIGNED_SHORT_1_5_5_5_REV
|
||||
#ifdef GL_UNSIGNED_SHORT_5_6_5_REV
|
||||
case GL_UNSIGNED_SHORT_5_6_5_REV:
|
||||
#endif //GL_UNSIGNED_SHORT_5_6_5_REV
|
||||
case GL_UNSIGNED_SHORT_5_6_5: // gles
|
||||
#ifdef GL_UNSIGNED_SHORT_4_4_4_4_REV
|
||||
case GL_UNSIGNED_SHORT_4_4_4_4_REV:
|
||||
#endif //GL_UNSIGNED_SHORT_4_4_4_4_REV
|
||||
case GL_UNSIGNED_SHORT_4_4_4_4:
|
||||
return 2;
|
||||
case GL_UNSIGNED_BYTE:
|
||||
component_size = 1;
|
||||
break;
|
||||
// mpv returns 2
|
||||
#ifdef GL_UNSIGNED_SHORT_8_8_APPLE
|
||||
case GL_UNSIGNED_SHORT_8_8_APPLE:
|
||||
case GL_UNSIGNED_SHORT_8_8_REV_APPLE:
|
||||
return 2;
|
||||
#endif
|
||||
case GL_UNSIGNED_SHORT:
|
||||
component_size = 2;
|
||||
break;
|
||||
}
|
||||
switch (format) {
|
||||
case GL_RED:
|
||||
case GL_LUMINANCE:
|
||||
case GL_ALPHA:
|
||||
return component_size;
|
||||
case GL_RG:
|
||||
case GL_LUMINANCE_ALPHA:
|
||||
return 2*component_size;
|
||||
#ifdef GL_YCBCR_422_APPLE
|
||||
case GL_YCBCR_422_APPLE:
|
||||
return 2;
|
||||
#endif
|
||||
#ifdef GL_RGB_422_APPLE
|
||||
case GL_RGB_422_APPLE:
|
||||
return 2;
|
||||
#endif
|
||||
#ifdef GL_BGR //ifndef GL_ES
|
||||
case GL_BGR:
|
||||
#endif
|
||||
case GL_RGB:
|
||||
return 3*component_size;
|
||||
#ifdef GL_BGRA //ifndef GL_ES
|
||||
case GL_BGRA:
|
||||
#endif
|
||||
case GL_RGBA:
|
||||
return 4*component_size;
|
||||
default:
|
||||
qWarning("bytesOfGLFormat - Unknown format %u", format);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace OpenGLHelper
|
||||
} //namespace FAV
|
||||
118
project/fm_viewer/fav/opengl/OpenGLHelper.h
Normal file
118
project/fm_viewer/fav/opengl/OpenGLHelper.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/******************************************************************************
|
||||
QtAV: Media play library based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef QTAV_OPENGLHELPER_H
|
||||
#define QTAV_OPENGLHELPER_H
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
#include "../VideoFormat.h"
|
||||
#include "gl_api.h"
|
||||
// for dynamicgl. qglfunctions before qt5.3 does not have portable gl functions
|
||||
#ifdef QT_OPENGL_DYNAMIC
|
||||
#define DYGL(glFunc) QOpenGLContext::currentContext()->functions()->glFunc
|
||||
#else
|
||||
#define DYGL(glFunc) glFunc
|
||||
#endif
|
||||
|
||||
#define EGL_ENSURE(x, ...) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
EGLint err = eglGetError(); \
|
||||
qWarning("EGL error@%d<<%s. " #x ": %#x %s", __LINE__, __FILE__, err, eglQueryString(eglGetCurrentDisplay(), err)); \
|
||||
return __VA_ARGS__; \
|
||||
} \
|
||||
} while(0)
|
||||
#define EGL_WARN(x, ...) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
EGLint err = eglGetError(); \
|
||||
qWarning("EGL error@%d<<%s. " #x ": %#x %s", __LINE__, __FILE__, err, eglQueryString(eglGetCurrentDisplay(), err)); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define WGL_ENSURE(x, ...) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
qWarning() << "WGL error " << __FILE__ << "@" << __LINE__ << " " << #x << ": " << qt_error_string(GetLastError()); \
|
||||
return __VA_ARGS__; \
|
||||
} \
|
||||
} while(0)
|
||||
#define WGL_WARN(x, ...) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
qWarning() << "WGL error " << __FILE__ << "@" << __LINE__ << " " << #x << ": " << qt_error_string(GetLastError()); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QMatrix4x4;
|
||||
QT_END_NAMESPACE
|
||||
namespace FAV {
|
||||
namespace OpenGLHelper {
|
||||
QString removeComments(const QString& code);
|
||||
QByteArray compatibleShaderHeader(QOpenGLShader::ShaderType type);
|
||||
int GLSLVersion();
|
||||
bool isEGL();
|
||||
bool isOpenGLES();
|
||||
/*!
|
||||
* \brief hasExtensionEGL
|
||||
* Test if any of the given extensions is supported
|
||||
* \param exts Ends with NULL
|
||||
* \return true if one of extension is supported
|
||||
*/
|
||||
bool hasExtensionEGL(const char* exts[]);
|
||||
bool hasRG();
|
||||
bool has16BitTexture();
|
||||
// set by user (environment var "QTAV_TEXTURE16_DEPTH=8 or 16", default now is 8)
|
||||
int depth16BitTexture();
|
||||
// set by user (environment var "QTAV_GL_DEPRECATED=1")
|
||||
bool useDeprecatedFormats();
|
||||
/*!
|
||||
* \brief hasExtension
|
||||
* Test if any of the given extensions is supported. Current OpenGL context must be valid.
|
||||
* \param exts Ends with NULL
|
||||
* \return true if one of extension is supported
|
||||
*/
|
||||
bool hasExtension(const char* exts[]);
|
||||
bool isPBOSupported();
|
||||
/*!
|
||||
* \brief videoFormatToGL
|
||||
* \param fmt
|
||||
* \param internal_format an array with size fmt.planeCount()
|
||||
* \param data_format an array with size fmt.planeCount()
|
||||
* \param data_type an array with size fmt.planeCount()
|
||||
* \param mat channel reorder matrix used in glsl
|
||||
* \return false if fmt is not supported
|
||||
*/
|
||||
bool videoFormatToGL(const VideoFormat& fmt, GLint* internal_format, GLenum* data_format, GLenum* data_type, QMatrix4x4* mat = NULL);
|
||||
int bytesOfGLFormat(GLenum format, GLenum dataType = GL_UNSIGNED_BYTE);
|
||||
} //namespace OpenGLHelper
|
||||
} //namespace FAV
|
||||
#else
|
||||
namespace FAV {
|
||||
namespace OpenGLHelper {
|
||||
#define DYGL(f) f
|
||||
inline bool isOpenGLES() {return false;}
|
||||
} //namespace OpenGLHelper
|
||||
} //namespace FAV
|
||||
#endif //QT_NO_OPENGL
|
||||
#endif // QTAV_OPENGLHELPER_H
|
||||
300
project/fm_viewer/fav/opengl/OpenGLTypes.cpp
Normal file
300
project/fm_viewer/fav/opengl/OpenGLTypes.cpp
Normal file
@@ -0,0 +1,300 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV (from 2016)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
#include "../OpenGLTypes.h"
|
||||
#include "OpenGLHelper.h"
|
||||
#include <QtCore/QRegExp>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVariant>
|
||||
#include "../Logger.h"
|
||||
namespace FAV {
|
||||
struct uniform_type_name {
|
||||
QByteArray name;
|
||||
Uniform::Type type;
|
||||
} uniform_type_names[] ={
|
||||
{"sample2D", Uniform::Sampler},
|
||||
{"bool", Uniform::Bool},
|
||||
{"int", Uniform::Int},
|
||||
{"uint", Uniform::Int},
|
||||
{"float", Uniform::Float},
|
||||
{"vec2", Uniform::Vec2},
|
||||
{"vec3", Uniform::Vec3},
|
||||
{"vec4", Uniform::Vec4},
|
||||
{"mat2", Uniform::Mat2},
|
||||
{"mat3", Uniform::Mat3},
|
||||
{"mat4", Uniform::Mat4},
|
||||
{"bvec2", Uniform::BVec2},
|
||||
{"bvec3", Uniform::BVec3},
|
||||
{"bvec4", Uniform::BVec4},
|
||||
{"ivec2", Uniform::IVec2},
|
||||
{"ivec3", Uniform::IVec3},
|
||||
{"ivec4", Uniform::IVec4},
|
||||
{"uvec2", Uniform::UVec2},
|
||||
{"uvec3", Uniform::UVec3},
|
||||
{"uvec4", Uniform::UVec4},
|
||||
{"mat2x2", Uniform::Mat2},
|
||||
{"mat3x3", Uniform::Mat3},
|
||||
{"mat4x4", Uniform::Mat4},
|
||||
{"dmat2", Uniform::DMat2},
|
||||
{"dmat3", Uniform::DMat3},
|
||||
{"dmat4", Uniform::DMat4},
|
||||
};
|
||||
|
||||
static Uniform::Type UniformTypeFromName(const QByteArray& name)
|
||||
{
|
||||
for (const uniform_type_name* un = uniform_type_names; un < uniform_type_names + sizeof(uniform_type_names)/sizeof(uniform_type_names[0]); ++un) {
|
||||
if (un->name == name)
|
||||
return un->type;
|
||||
}
|
||||
return Uniform::Unknown;
|
||||
}
|
||||
|
||||
static QByteArray UniformTypeToName(Uniform::Type ut)
|
||||
{
|
||||
for (const uniform_type_name* un = uniform_type_names; un < uniform_type_names + sizeof(uniform_type_names)/sizeof(uniform_type_names[0]); ++un) {
|
||||
if (un->type == ut)
|
||||
return un->name;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
Uniform::Uniform(Type tp, int count)
|
||||
: dirty(true)
|
||||
, location(-1)
|
||||
, tuple_size(1)
|
||||
, array_size(1)
|
||||
, t(tp)
|
||||
{
|
||||
setType(tp, count);
|
||||
}
|
||||
|
||||
Uniform& Uniform::setType(Type tp, int count)
|
||||
{
|
||||
t = tp;
|
||||
array_size = count;
|
||||
if (isVec()) {
|
||||
tuple_size = (t >> (V+1)) & ((1<<3) - 1);
|
||||
} else if (isMat()) {
|
||||
tuple_size = (t >> (M+1)) & ((1<<3) - 1);
|
||||
tuple_size *= tuple_size;
|
||||
}
|
||||
int element_size = sizeof(float);
|
||||
if (isInt() || isUInt() || isBool()) {
|
||||
element_size = sizeof(int);
|
||||
}
|
||||
data = QVector<int>(element_size/sizeof(int)*tupleSize()*arraySize());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T> bool set_uniform_value(QVector<int>& dst, const T* v, int count)
|
||||
{
|
||||
Q_ASSERT(sizeof(T)*count <= sizeof(int)*dst.size() && "set_uniform_value: Bad type or array size");
|
||||
// why not dst.constData()?
|
||||
const QVector<int> old(dst);
|
||||
memcpy((char*)dst.data(), (const char*)v, count*sizeof(T));
|
||||
return old != dst;
|
||||
}
|
||||
|
||||
template<> bool set_uniform_value<bool>(QVector<int>& dst, const bool* v, int count)
|
||||
{
|
||||
const QVector<int> old(dst);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
dst[i] = *(v + i);
|
||||
}
|
||||
return old != dst;
|
||||
}
|
||||
|
||||
void Uniform::set(const float &v, int count)
|
||||
{
|
||||
if (count <= 0)
|
||||
count = tupleSize()*arraySize();
|
||||
dirty = set_uniform_value(data, &v, count);
|
||||
}
|
||||
|
||||
void Uniform::set(const int &v, int count)
|
||||
{
|
||||
if (count <= 0)
|
||||
count = tupleSize()*arraySize();
|
||||
dirty = set_uniform_value(data, &v, count);
|
||||
|
||||
}
|
||||
|
||||
void Uniform::set(const unsigned &v, int count)
|
||||
{
|
||||
if (count <= 0)
|
||||
count = tupleSize()*arraySize();
|
||||
dirty = set_uniform_value(data, &v, count);
|
||||
}
|
||||
|
||||
|
||||
void Uniform::set(const float *v, int count)
|
||||
{
|
||||
if (count <= 0)
|
||||
count = tupleSize()*arraySize();
|
||||
dirty = set_uniform_value(data, v, count);
|
||||
}
|
||||
|
||||
void Uniform::set(const int *v, int count)
|
||||
{
|
||||
if (count <= 0)
|
||||
count = tupleSize()*arraySize();
|
||||
dirty = set_uniform_value(data, v, count);
|
||||
}
|
||||
|
||||
void Uniform::set(const unsigned *v, int count)
|
||||
{
|
||||
if (count <= 0)
|
||||
count = tupleSize()*arraySize();
|
||||
dirty = set_uniform_value(data, v, count);
|
||||
}
|
||||
|
||||
void Uniform::set(const QVariant &v)
|
||||
{
|
||||
if (tupleSize() > 1 || arraySize() > 1) {
|
||||
if (isFloat()) { //TODO: what if QVector<qreal> but uniform is float?
|
||||
set(v.value<QVector<float> >().data());
|
||||
} else if (isInt() || isBool()) {
|
||||
set(v.value<QVector<int> >().data());
|
||||
} else if (isUInt()) {
|
||||
set(v.value<QVector<unsigned> >().data());
|
||||
} else if (type() == Uniform::Sampler) {
|
||||
|
||||
}
|
||||
} else {
|
||||
if (isFloat()) {
|
||||
set(v.toFloat());
|
||||
} else if (isInt() || isBool()) {
|
||||
set(v.toInt());
|
||||
} else if (isUInt()) {
|
||||
set(v.toUInt());
|
||||
} else if (type() == Uniform::Sampler) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Uniform::setGL()
|
||||
{
|
||||
if (location < 0) {
|
||||
return false;
|
||||
}
|
||||
switch (type()) {
|
||||
case Uniform::Bool:
|
||||
case Uniform::Int:
|
||||
gl().Uniform1iv(location, arraySize(), address<int>());
|
||||
break;
|
||||
case Uniform::Float:
|
||||
gl().Uniform1fv(location, arraySize(), address<float>());
|
||||
break;
|
||||
case Uniform::Vec2:
|
||||
gl().Uniform2fv(location, arraySize(), address<float>());
|
||||
break;
|
||||
case Uniform::Vec3:
|
||||
gl().Uniform3fv(location, arraySize(), address<float>());
|
||||
break;
|
||||
case Uniform::Vec4:
|
||||
gl().Uniform4fv(location, arraySize(), address<float>());
|
||||
break;
|
||||
case Uniform::Mat2:
|
||||
gl().UniformMatrix2fv(location, arraySize(), GL_FALSE, address<float>());
|
||||
break;
|
||||
case Uniform::Mat3:
|
||||
gl().UniformMatrix3fv(location, arraySize(), GL_FALSE, address<float>());
|
||||
break;
|
||||
case Uniform::Mat4:
|
||||
gl().UniformMatrix4fv(location, arraySize(), GL_FALSE, address<float>());
|
||||
break;
|
||||
case Uniform::IVec2:
|
||||
gl().Uniform2iv(location, arraySize(), address<int>());
|
||||
break;
|
||||
case Uniform::IVec3:
|
||||
gl().Uniform3iv(location, arraySize(), address<int>());
|
||||
break;
|
||||
case Uniform::IVec4:
|
||||
gl().Uniform4iv(location, arraySize(), address<int>());
|
||||
break;
|
||||
default:
|
||||
qDebug() << *this;
|
||||
qWarning("Unsupported uniform type in Qt. You should use 'VideoShader::setUserUniformValues()' to call glUniformXXX or directly call glUniformXXX instead");
|
||||
return false;
|
||||
}
|
||||
dirty = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
Q_AV_EXPORT QDebug operator<<(QDebug dbg, const Uniform &u)
|
||||
{
|
||||
dbg.nospace() << "uniform " << UniformTypeToName(u.type()) << " " << u.name.constData();
|
||||
if (u.arraySize() > 1) {
|
||||
dbg.nospace() << "[" << u.arraySize() << "]";
|
||||
}
|
||||
dbg.nospace() << ", dirty: " << u.dirty;
|
||||
dbg.nospace() << ", location: " << u.location << ", " << "tupleSize: " << u.tupleSize() << ", ";
|
||||
if (u.isBool() || u.isInt()) {
|
||||
dbg.nospace() << "value: " << u.value<int>();
|
||||
} else if (u.isUInt()) {
|
||||
dbg.nospace() << "value: " << u.value<unsigned>();
|
||||
} else if (u.isDouble()) {
|
||||
dbg.nospace() << "value: " << u.value<double>();
|
||||
} else {
|
||||
dbg.nospace() << "value: " << u.value<float>();
|
||||
}
|
||||
return dbg.space();
|
||||
}
|
||||
|
||||
Q_AV_EXPORT QDebug operator<<(QDebug dbg, Uniform::Type ut);
|
||||
#endif
|
||||
|
||||
QVector<Uniform> ParseUniforms(const QByteArray &text, GLuint programId = 0)
|
||||
{
|
||||
QVector<Uniform> uniforms;
|
||||
const QString code = OpenGLHelper::removeComments(QString(text));
|
||||
const QStringList lines = code.split(';');
|
||||
// TODO: highp lowp etc.
|
||||
const QString exp(QStringLiteral("\\s*uniform\\s+([\\w\\d]+)\\s+([\\w\\d]+)\\s*"));
|
||||
const QString exp_array = exp + QStringLiteral("\\[(\\d+)\\]\\s*");
|
||||
foreach (QString line, lines) {
|
||||
line = line.trimmed();
|
||||
if (!line.startsWith(QStringLiteral("uniform ")))
|
||||
continue;
|
||||
QRegExp rx(exp_array);
|
||||
if (rx.indexIn(line) < 0) {
|
||||
rx = QRegExp(exp);
|
||||
if (rx.indexIn(line) < 0)
|
||||
continue;
|
||||
}
|
||||
Uniform u;
|
||||
const QStringList x = rx.capturedTexts();
|
||||
//qDebug() << x;
|
||||
u.name = x.at(2).toUtf8();
|
||||
int array_size = 1;
|
||||
if (x.size() > 3)
|
||||
array_size = x[3].toInt();
|
||||
const QByteArray t(x[1].toLatin1());
|
||||
u.setType(UniformTypeFromName(t), array_size);
|
||||
if (programId > 0)
|
||||
u.location = gl().GetUniformLocation(programId, u.name.constData());
|
||||
uniforms.append(u);
|
||||
}
|
||||
qDebug() << uniforms;
|
||||
return uniforms;
|
||||
}
|
||||
} //namespace FAV
|
||||
2105
project/fm_viewer/fav/opengl/OpenGLVideo.cpp
Normal file
2105
project/fm_viewer/fav/opengl/OpenGLVideo.cpp
Normal file
File diff suppressed because it is too large
Load Diff
65
project/fm_viewer/fav/opengl/ShaderManager.cpp
Normal file
65
project/fm_viewer/fav/opengl/ShaderManager.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#include "ShaderManager.h"
|
||||
#if !(REMOVE_SHADER_MANAGER)
|
||||
|
||||
#include "../VideoShader.h"
|
||||
|
||||
|
||||
namespace FAV {
|
||||
class ShaderManager::Private
|
||||
{
|
||||
public:
|
||||
~Private() {
|
||||
// TODO: thread safe required?
|
||||
qDeleteAll(shader_cache.values());
|
||||
shader_cache.clear();
|
||||
}
|
||||
|
||||
QHash<qint32, VideoShader*> shader_cache;
|
||||
};
|
||||
|
||||
ShaderManager::ShaderManager(QObject *parent) :
|
||||
QObject(parent)
|
||||
, d(new Private())
|
||||
{
|
||||
#if (MODEL_360)
|
||||
dualMode = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
ShaderManager::~ShaderManager()
|
||||
{
|
||||
delete d;
|
||||
d = 0;
|
||||
}
|
||||
|
||||
VideoShader* ShaderManager::prepareMaterial(VideoMaterial *material, qint32 materialType)
|
||||
{
|
||||
|
||||
#if (MODEL_360)
|
||||
qint32 type = materialType != -1 ? materialType : material->type();
|
||||
if(dualMode == 1)
|
||||
{
|
||||
type = 9999;
|
||||
}
|
||||
#else
|
||||
const qint32 type = materialType != -1 ? materialType : material->type();
|
||||
#endif
|
||||
VideoShader *shader = d->shader_cache.value(type, 0);
|
||||
if (shader)
|
||||
{
|
||||
return shader;
|
||||
}
|
||||
#if (DEBUG_SHADER_MANAGER)
|
||||
qDebug() << QString("[ShaderManager] cache a new shader material type(%1): %2").arg(type).arg(VideoMaterial::typeName(type));
|
||||
#endif
|
||||
shader = material->createShader();
|
||||
#if (MODEL_360)
|
||||
shader->dualMode = dualMode;
|
||||
#endif
|
||||
shader->initialize();
|
||||
d->shader_cache[type] = shader;
|
||||
return shader;
|
||||
}
|
||||
} //namespace FAV
|
||||
#endif //#if !(REMOVE_VIDEO_SHADER)
|
||||
|
||||
57
project/fm_viewer/fav/opengl/ShaderManager.h
Normal file
57
project/fm_viewer/fav/opengl/ShaderManager.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV (from 2014)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef QTAV_SHADERMANAGER_H
|
||||
#define QTAV_SHADERMANAGER_H
|
||||
|
||||
#define REMOVE_SHADER_MANAGER 0
|
||||
#if !(REMOVE_SHADER_MANAGER)
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#define DEBUG_SHADER_MANAGER 0
|
||||
|
||||
namespace FAV {
|
||||
class VideoShader;
|
||||
class VideoMaterial;
|
||||
/*!
|
||||
* \brief The ShaderManager class
|
||||
* Cache VideoShader and shader programes for different video material type.
|
||||
* TODO: ShaderManager does not change for a given vo, so we can expose VideoRenderer.shaderManager() to set custom shader. It's better than VideoRenderer.opengl() because OpenGLVideo exposes too many apis that may confuse user.
|
||||
*/
|
||||
class ShaderManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ShaderManager(QObject *parent = 0);
|
||||
~ShaderManager();
|
||||
VideoShader* prepareMaterial(VideoMaterial *material, qint32 materialType = -1);
|
||||
// void setCacheSize(int value);
|
||||
#if (MODEL_360)
|
||||
int dualMode;
|
||||
#endif
|
||||
private:
|
||||
class Private;
|
||||
Private* d;
|
||||
};
|
||||
} //namespace FAV
|
||||
#endif // QTAV_SHADERMANAGER_H
|
||||
#endif // #if !(REMOVE_SHADER_MANAGER)
|
||||
207
project/fm_viewer/fav/opengl/SubImagesGeometry.cpp
Normal file
207
project/fm_viewer/fav/opengl/SubImagesGeometry.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV (from 2016)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
#include "SubImagesGeometry.h"
|
||||
#if !(DO_NOT_USE_SUBTITLE)
|
||||
#include "../Logger.h"
|
||||
|
||||
namespace FAV {
|
||||
#define U8COLOR 0
|
||||
static const int kMaxTexWidth = 4096; //FIXME: glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
|
||||
// if texture1d, we can directly copy ASS_Image.bitmap without line by line copy, i.e. tiled, and upload only once
|
||||
|
||||
|
||||
typedef struct {
|
||||
float x, y; // depends on target rect
|
||||
float tx, ty; // depends on texture size and rects layout
|
||||
#if U8COLOR
|
||||
union {
|
||||
quint8 r, g, b, a; //to be normalized
|
||||
quint32 rgba;
|
||||
};
|
||||
#else
|
||||
float r, g, b, a;
|
||||
#endif
|
||||
} VertexData;
|
||||
|
||||
static VertexData* SetUnnormalizedVertexData(VertexData* v, int tx, int ty, int tw, int th, quint32 color, bool useIndecies)
|
||||
{
|
||||
#if U8COLOR
|
||||
union {
|
||||
quint8 r, g, b, a;
|
||||
quint32 rgba;
|
||||
};
|
||||
r = color >> 24;
|
||||
g = (color >> 16) & 0xff;
|
||||
b = (color >> 8) & 0xff;
|
||||
a = 255 - (color & 0xff);
|
||||
#else
|
||||
float r, g, b, a;
|
||||
r = (float)(color >> 24)/255.0;
|
||||
g = (float)((color >> 16) & 0xff)/255.0;
|
||||
b = (float)((color >> 8) & 0xff)/255.0;
|
||||
a = (float)(255 - (color & 0xff))/255.0;
|
||||
#endif
|
||||
// normalize later
|
||||
v[0].tx = tx;
|
||||
v[0].ty = ty;
|
||||
v[1].tx = tx;
|
||||
v[1].ty = ty + th;
|
||||
v[2].tx = tx + tw;
|
||||
v[2].ty = ty;
|
||||
v[3].tx = tx + tw;
|
||||
v[3].ty = ty + th;
|
||||
#if U8COLOR
|
||||
v[0].rgba = rgba;
|
||||
v[1].rgba = rgba;
|
||||
v[2].rgba = rgba;
|
||||
v[3].rgba = rgba;
|
||||
#else
|
||||
#define SETC(x) x.r = r; x.g=g; x.b=b; x.a=a;
|
||||
SETC(v[0]);
|
||||
SETC(v[1]);
|
||||
SETC(v[2]);
|
||||
SETC(v[3]);
|
||||
#endif
|
||||
if (!useIndecies) {
|
||||
v[4] = v[1];
|
||||
v[5] = v[2];
|
||||
return v + 6;
|
||||
}
|
||||
return v + 4;
|
||||
}
|
||||
|
||||
static VertexData* SetVertexPositionAndNormalize(VertexData* v, float x, float y, float w, float h, float texW, float texH, bool useIndecies)
|
||||
{
|
||||
v[0].x = x;
|
||||
v[0].y = y;
|
||||
v[1].x = x;
|
||||
v[1].y = y + h;
|
||||
v[2].x = x + w;
|
||||
v[2].y = y;
|
||||
v[3].x = x + w;
|
||||
v[3].y = y + h;
|
||||
v[0].tx /= texW;
|
||||
v[0].ty /= texH;
|
||||
v[1].tx /= texW;
|
||||
v[1].ty /= texH;
|
||||
v[2].tx /= texW;
|
||||
v[2].ty /= texH;
|
||||
v[3].tx /= texW;
|
||||
v[3].ty /= texH;
|
||||
//qDebug("%f,%f<=%f,%f; %u,%u,%u,%u", v[3].x, v[3].y, v[3].tx, v[3].ty, v[3].r, v[3].g, v[3].b, v[3].a);
|
||||
if (!useIndecies) {
|
||||
v[4] = v[1];
|
||||
v[5] = v[2];
|
||||
return v + 6;
|
||||
}
|
||||
return v + 4;
|
||||
}
|
||||
|
||||
SubImagesGeometry::SubImagesGeometry()
|
||||
: Geometry()
|
||||
, m_normalized(false)
|
||||
, m_w(0)
|
||||
, m_h(0)
|
||||
{
|
||||
setPrimitive(Geometry::Triangles);
|
||||
m_attributes << Attribute(TypeF32, 2)
|
||||
<< Attribute(TypeF32, 2, 2*sizeof(float))
|
||||
#if U8COLOR
|
||||
<< Attribute(TypeU8, 4, 4*sizeof(float), true);
|
||||
#else
|
||||
<< Attribute(TypeF32, 4, 4*sizeof(float));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SubImagesGeometry::setSubImages(const SubImageSet &images)
|
||||
{
|
||||
// TODO: operator ==
|
||||
if (m_images == images)
|
||||
return false;
|
||||
m_images = images;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SubImagesGeometry::generateVertexData(const QRect &rect, bool useIndecies, int maxWidth)
|
||||
{
|
||||
if (maxWidth < 0)
|
||||
maxWidth = kMaxTexWidth;
|
||||
if (useIndecies)
|
||||
allocate(4*m_images.images.size(), 6*m_images.images.size());
|
||||
else
|
||||
allocate(6*m_images.images.size());
|
||||
qDebug("images: %d/%d, %dx%d", m_images.isValid(), m_images.images.size(), m_images.width(), m_images.height());
|
||||
m_rects_upload.clear();
|
||||
m_w = m_h = 0;
|
||||
m_normalized = false;
|
||||
if (!m_images.isValid())
|
||||
return false;
|
||||
|
||||
int W = 0, H = 0;
|
||||
int x = 0, h = 0;
|
||||
VertexData* vd = (VertexData*)vertexData();
|
||||
int index = 0;
|
||||
foreach (const SubImage& i, m_images.images) {
|
||||
if (x + i.stride > maxWidth && maxWidth > 0) {
|
||||
W = qMax(W, x);
|
||||
H += h;
|
||||
x = 0;
|
||||
h = 0;
|
||||
}
|
||||
// we use w instead of stride even if we must upload stride. when maping texture coordinates and view port coordinates, we can use the visual rects instead of stride, i.e. the geometry vertices are (x, y, w, h), not (x, y, stride, h)
|
||||
m_rects_upload.append(QRect(x, H, i.stride, i.h));
|
||||
vd = SetUnnormalizedVertexData(vd, x, H, i.w, i.h, i.color, useIndecies);
|
||||
if (useIndecies) { // TODO: set only once because it never changes, use IBO
|
||||
const int v0 = index*4/6;
|
||||
setIndexValue(index, v0, v0+1, v0+2);
|
||||
setIndexValue(index+3, v0+1, v0+2, v0+3);
|
||||
index += 6;
|
||||
}
|
||||
x += i.w;
|
||||
h = qMax(h, i.h);
|
||||
}
|
||||
W = qMax(W, x);
|
||||
H += h;
|
||||
m_w = W;
|
||||
m_h = H;
|
||||
//qDebug("sub texture %dx%d", m_w, m_h);
|
||||
|
||||
const float dx0 = rect.x();
|
||||
const float dy0 = rect.y();
|
||||
const float sx = float(rect.width())/float(m_images.width());
|
||||
const float sy = float(rect.height())/float(m_images.height());
|
||||
vd = (VertexData*)vertexData();
|
||||
foreach (const SubImage& i, m_images.images) {
|
||||
//qDebug() << rect;
|
||||
//qDebug("i: %d,%d", i.x, i.y);
|
||||
vd = SetVertexPositionAndNormalize(vd, dx0 + float(i.x)*sx, dy0 + float(i.y)*sy, i.w*sx, i.h*sy, m_w, m_h, useIndecies);
|
||||
m_normalized = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int SubImagesGeometry::stride() const
|
||||
{
|
||||
return sizeof(VertexData);
|
||||
}
|
||||
|
||||
} //namespace FAV
|
||||
#endif // #if !(DO_NOT_USE_SUBTITLE)
|
||||
58
project/fm_viewer/fav/opengl/SubImagesGeometry.h
Normal file
58
project/fm_viewer/fav/opengl/SubImagesGeometry.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2017 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV (from 2016)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
#ifndef QTAV_SUBIMAGESGEOMETRY_H
|
||||
#define QTAV_SUBIMAGESGEOMETRY_H
|
||||
#include "../Geometry.h"
|
||||
#include "../SubImage.h"
|
||||
|
||||
#if !(DO_NOT_USE_SUBTITLE)
|
||||
|
||||
namespace FAV {
|
||||
class SubImagesGeometry : public Geometry {
|
||||
public:
|
||||
SubImagesGeometry();
|
||||
bool setSubImages(const SubImageSet& images);
|
||||
/*!
|
||||
* \brief generateVertexData
|
||||
* \param rect rect render to. If it's viewport rect, and fit video aspect ratio, ass images created from video frame size needs a scale transform is required when rendering
|
||||
* \param useIndecies
|
||||
* \param maxWidth
|
||||
* \return false if current SubImageSet is invalid
|
||||
*/
|
||||
bool generateVertexData(const QRect& rect, bool useIndecies = false, int maxWidth = -1);
|
||||
// available after generateVertexData is called
|
||||
int width() { return m_w;}
|
||||
int height() { return m_h;}
|
||||
int stride() const Q_DECL_OVERRIDE;
|
||||
const QVector<Attribute>& attributes() const Q_DECL_OVERRIDE { return m_attributes;}
|
||||
const SubImageSet& images() const { return m_images; }
|
||||
const QVector<QRect>& uploadRects() const { return m_rects_upload;}
|
||||
private:
|
||||
using Geometry::allocate;
|
||||
bool m_normalized;
|
||||
int m_w, m_h;
|
||||
QVector<Attribute> m_attributes;
|
||||
SubImageSet m_images; // for texture upload parameters
|
||||
QVector<QRect> m_rects_upload;
|
||||
};
|
||||
} //namespace FAV
|
||||
#endif //QTAV_SUBIMAGESGEOMETRY_H
|
||||
#endif // #if !(DO_NOT_USE_SUBTITLE)
|
||||
141
project/fm_viewer/fav/opengl/SubImagesRenderer.cpp
Normal file
141
project/fm_viewer/fav/opengl/SubImagesRenderer.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2017 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV (from 2016)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
|
||||
#include "SubImagesRenderer.h"
|
||||
#if !(REMOVE_SUBIMAGE_RENDERER)
|
||||
#include "SubImagesGeometry.h"
|
||||
#include "../GeometryRenderer.h"
|
||||
|
||||
namespace FAV {
|
||||
|
||||
#define GLSL(x) #x "\n"
|
||||
|
||||
static const char kVert[] = GLSL(
|
||||
attribute vec4 a_Position;
|
||||
attribute vec2 a_TexCoords;
|
||||
attribute vec4 a_Color;
|
||||
uniform mat4 u_Matrix;
|
||||
varying vec2 v_TexCoords;
|
||||
varying vec4 v_Color;
|
||||
void main() {
|
||||
gl_Position = u_Matrix * a_Position;
|
||||
v_TexCoords = a_TexCoords;
|
||||
v_Color = a_Color;
|
||||
});
|
||||
|
||||
static const char kFrag[] = GLSL(
|
||||
uniform sampler2D u_Texture;
|
||||
varying vec2 v_TexCoords;
|
||||
varying vec4 v_Color;
|
||||
void main() {
|
||||
gl_FragColor.rgb = v_Color.rgb;
|
||||
gl_FragColor.a = v_Color.a*texture2D(u_Texture, v_TexCoords).r;
|
||||
}
|
||||
);
|
||||
|
||||
SubImagesRenderer::SubImagesRenderer()
|
||||
: m_geometry(new SubImagesGeometry())
|
||||
, m_renderer(new GeometryRenderer())
|
||||
, m_tex(0)
|
||||
{}
|
||||
|
||||
SubImagesRenderer::~SubImagesRenderer()
|
||||
{
|
||||
delete m_geometry;
|
||||
delete m_renderer;
|
||||
}
|
||||
|
||||
void SubImagesRenderer::render(const SubImageSet &ass, const QRect &target, const QMatrix4x4 &transform)
|
||||
{
|
||||
if (m_geometry->setSubImages(ass) || m_rect != target) {
|
||||
m_rect = target;
|
||||
if (!m_geometry->generateVertexData(m_rect, true))
|
||||
return;
|
||||
uploadTexture(m_geometry);
|
||||
m_renderer->updateGeometry(m_geometry);
|
||||
}
|
||||
if (!m_program.isLinked()) {
|
||||
m_program.removeAllShaders();
|
||||
QByteArray vs(kVert);
|
||||
vs.prepend(OpenGLHelper::compatibleShaderHeader(QOpenGLShader::Vertex));
|
||||
m_program.addShaderFromSourceCode(QOpenGLShader::Vertex, vs);
|
||||
QByteArray fs(kFrag);
|
||||
fs.prepend(OpenGLHelper::compatibleShaderHeader(QOpenGLShader::Fragment));
|
||||
m_program.addShaderFromSourceCode(QOpenGLShader::Fragment, fs);
|
||||
// TODO: foreach geometry.attributes
|
||||
m_program.bindAttributeLocation("a_Position", 0);
|
||||
m_program.bindAttributeLocation("a_TexCoords", 1);
|
||||
m_program.bindAttributeLocation("a_Color", 2);
|
||||
if (!m_program.link())
|
||||
qWarning() << m_program.log();
|
||||
}
|
||||
m_program.bind();
|
||||
gl().ActiveTexture(GL_TEXTURE0);
|
||||
DYGL(glBindTexture(GL_TEXTURE_2D, m_tex));
|
||||
m_program.setUniformValue("u_Texture", 0);
|
||||
m_program.setUniformValue("u_Matrix", transform*m_mat);
|
||||
DYGL(glEnable(GL_BLEND));
|
||||
if (m_geometry->images().format() == SubImageSet::ASS)
|
||||
gl().BlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
else
|
||||
gl().BlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
m_renderer->render();
|
||||
|
||||
DYGL(glDisable(GL_BLEND));
|
||||
}
|
||||
|
||||
void SubImagesRenderer::setProjectionMatrixToRect(const QRectF &v)
|
||||
{
|
||||
m_mat.setToIdentity();
|
||||
m_mat.ortho(v);
|
||||
}
|
||||
|
||||
void SubImagesRenderer::uploadTexture(SubImagesGeometry *g)
|
||||
{
|
||||
if (!m_tex) {
|
||||
DYGL(glGenTextures(1, &m_tex)); //TODO: delete
|
||||
}
|
||||
GLint internal_fmt;
|
||||
GLenum data_type;
|
||||
GLenum fmt;
|
||||
if (g->images().format() == SubImageSet::ASS)
|
||||
OpenGLHelper::videoFormatToGL(VideoFormat(VideoFormat::Format_Y8), &internal_fmt, &fmt, &data_type);
|
||||
else //rgb32
|
||||
OpenGLHelper::videoFormatToGL(VideoFormat(VideoFormat::Format_ARGB32), &internal_fmt, &fmt, &data_type);
|
||||
DYGL(glBindTexture(GL_TEXTURE_2D, m_tex));
|
||||
DYGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
DYGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
DYGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
||||
DYGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
||||
DYGL(glTexImage2D(GL_TEXTURE_2D, 0, internal_fmt, g->width(), g->height(), 0, fmt, data_type, NULL));
|
||||
//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
for (int i = 0; i < g->uploadRects().size(); ++i) {
|
||||
const QRect& r = g->uploadRects().at(i);
|
||||
const SubImage& sub = g->images().images.at(i);
|
||||
DYGL(glTexSubImage2D(GL_TEXTURE_2D, 0, r.x(), r.y(), r.width(), r.height(), fmt, data_type, sub.data.constData()));
|
||||
}
|
||||
//glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||
DYGL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
}
|
||||
|
||||
} //namespace FAV
|
||||
#endif //#if !(REMOVE_OEPNGL_SHADER)
|
||||
77
project/fm_viewer/fav/opengl/SubImagesRenderer.h
Normal file
77
project/fm_viewer/fav/opengl/SubImagesRenderer.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV (from 2016)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
#ifndef QTAV_SUBIMAGESRENDERER_H
|
||||
#define QTAV_SUBIMAGESRENDERER_H
|
||||
|
||||
#define REMOVE_SUBIMAGE_RENDERER 1
|
||||
#if !(REMOVE_SUBIMAGE_RENDERER)
|
||||
|
||||
#include <QtGui/QMatrix4x4>
|
||||
#include <../SubImage.h>
|
||||
#include <../OpenGLTypes.h>
|
||||
#include "OpenGLHelper.h"
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
#include <QtGui/QOpenGLShaderProgram>
|
||||
#include <QtGui/QOpenGLShader>
|
||||
#else
|
||||
#include <QtOpenGL/QGLShaderProgram>
|
||||
#include <QtOpenGL/QGLShader>
|
||||
#undef QOpenGLShaderProgram
|
||||
#undef QOpenGLShader
|
||||
#define QOpenGLShaderProgram QGLShaderProgram
|
||||
#define QOpenGLShader QGLShader
|
||||
#endif
|
||||
|
||||
namespace FAV {
|
||||
class SubImagesGeometry;
|
||||
class GeometryRenderer;
|
||||
class SubImagesRenderer
|
||||
{
|
||||
public:
|
||||
SubImagesRenderer();
|
||||
~SubImagesRenderer();
|
||||
/*!
|
||||
* \brief render
|
||||
* \param ass
|
||||
* \param target
|
||||
* \param transform additional transform, e.g. aspect ratio
|
||||
*/
|
||||
void render(const SubImageSet& ass, const QRect& target, const QMatrix4x4& transform = QMatrix4x4());
|
||||
/*!
|
||||
* \brief setProjectionMatrixToRect
|
||||
* the rect will be viewport
|
||||
*/
|
||||
void setProjectionMatrixToRect(const QRectF& v);
|
||||
|
||||
private:
|
||||
void uploadTexture(SubImagesGeometry* g);
|
||||
|
||||
SubImagesGeometry *m_geometry;
|
||||
GeometryRenderer *m_renderer;
|
||||
QMatrix4x4 m_mat;
|
||||
QRect m_rect;
|
||||
|
||||
GLuint m_tex;
|
||||
QOpenGLShaderProgram m_program;
|
||||
};
|
||||
} //namespace FAV
|
||||
#endif // QTAV_SUBIMAGESRENDERER_H
|
||||
#endif // #if !(REMOVE_SUBIMAGE_RENDERER)
|
||||
1298
project/fm_viewer/fav/opengl/VideoShader.cpp
Normal file
1298
project/fm_viewer/fav/opengl/VideoShader.cpp
Normal file
File diff suppressed because it is too large
Load Diff
204
project/fm_viewer/fav/opengl/VideoShaderObject.cpp
Normal file
204
project/fm_viewer/fav/opengl/VideoShaderObject.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV (from 2016)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
#include "../VideoShaderObject.h"
|
||||
#if !(REMOVE_VIDEO_SHADER)
|
||||
#include "../VideoShader_p.h"
|
||||
#include <QtCore/QEvent>
|
||||
#include <QtCore/QMetaProperty>
|
||||
#include <QtCore/QSignalMapper>
|
||||
|
||||
namespace FAV {
|
||||
|
||||
class VideoShaderObjectPrivate : public VideoShaderPrivate
|
||||
{
|
||||
public:
|
||||
~VideoShaderObjectPrivate() {
|
||||
qDeleteAll(sigMap[VertexShader]);
|
||||
qDeleteAll(sigMap[FragmentShader]);
|
||||
sigMap[VertexShader].clear();
|
||||
sigMap[FragmentShader].clear();
|
||||
}
|
||||
|
||||
QVector<QSignalMapper*> sigMap[ShaderTypeCount];
|
||||
};
|
||||
|
||||
VideoShaderObject::VideoShaderObject(QObject *parent)
|
||||
: QObject(parent)
|
||||
, VideoShader(*new VideoShaderObjectPrivate())
|
||||
{}
|
||||
|
||||
VideoShaderObject::VideoShaderObject(VideoShaderObjectPrivate &d, QObject *parent)
|
||||
: QObject(parent)
|
||||
, VideoShader(d)
|
||||
{}
|
||||
|
||||
bool VideoShaderObject::event(QEvent *event)
|
||||
{
|
||||
DPTR_D(VideoShaderObject);
|
||||
if (event->type() != QEvent::DynamicPropertyChange)
|
||||
return QObject::event(event);
|
||||
QDynamicPropertyChangeEvent *e = static_cast<QDynamicPropertyChangeEvent*>(event);
|
||||
for (int shaderType = VertexShader; shaderType < ShaderTypeCount; ++shaderType) {
|
||||
QVector<Uniform> &uniforms = d.user_uniforms[shaderType];
|
||||
for (int i = 0; i < uniforms.size(); ++i) {
|
||||
if (uniforms.at(i).name == e->propertyName()) {
|
||||
propertyChanged(i|(shaderType<<16));
|
||||
}
|
||||
}
|
||||
}
|
||||
return QObject::event(event);
|
||||
}
|
||||
|
||||
void VideoShaderObject::propertyChanged(int id)
|
||||
{
|
||||
DPTR_D(VideoShaderObject);
|
||||
const int st = id>>16;
|
||||
const int idx = id&0xffff;
|
||||
Uniform &u = d.user_uniforms[st][idx];
|
||||
const QVariant v = property(u.name.constData());
|
||||
u.set(v);
|
||||
//if (u.dirty) update();
|
||||
}
|
||||
|
||||
void VideoShaderObject::programReady()
|
||||
{
|
||||
DPTR_D(VideoShaderObject);
|
||||
// find property name. if has property, bind to property
|
||||
for (int st = VertexShader; st < ShaderTypeCount; ++st) {
|
||||
qDeleteAll(d.sigMap[st]);
|
||||
d.sigMap[st].clear();
|
||||
const QVector<Uniform> &uniforms = d.user_uniforms[st];
|
||||
for (int i = 0; i < uniforms.size(); ++i) {
|
||||
const Uniform& u = uniforms[i];
|
||||
const int idx = metaObject()->indexOfProperty(u.name.constData());
|
||||
if (idx < 0) {
|
||||
qDebug("VideoShaderObject has no meta property '%s'. Setting initial value from dynamic property", u.name.constData());
|
||||
const_cast<Uniform&>(u).set(property(u.name.constData()));
|
||||
continue;
|
||||
}
|
||||
QMetaProperty mp = metaObject()->property(idx);
|
||||
if (!mp.hasNotifySignal()) {
|
||||
qWarning("VideoShaderObject property '%s' has no signal", mp.name());
|
||||
continue;
|
||||
}
|
||||
QMetaMethod mm = mp.notifySignal();
|
||||
QSignalMapper *mapper = new QSignalMapper();
|
||||
mapper->setMapping(this, i|(st<<16));
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
|
||||
connect(this, mm, mapper, mapper->metaObject()->method(mapper->metaObject()->indexOfSlot("map()")));
|
||||
#else
|
||||
|
||||
#endif
|
||||
connect(mapper, SIGNAL(mapped(int)), this, SLOT(propertyChanged(int)));
|
||||
d.sigMap[st].append(mapper);
|
||||
qDebug() << "set uniform property: " << u.name << property(u.name.constData());
|
||||
propertyChanged(i|(st<<16)); // set the initial value
|
||||
}
|
||||
}
|
||||
//ready();
|
||||
}
|
||||
|
||||
class DynamicShaderObjectPrivate : public VideoShaderObjectPrivate {
|
||||
public:
|
||||
QString header;
|
||||
QString sampleFunc;
|
||||
QString pp;
|
||||
};
|
||||
|
||||
DynamicShaderObject::DynamicShaderObject(QObject *parent)
|
||||
: VideoShaderObject(*new DynamicShaderObjectPrivate(), parent)
|
||||
{}
|
||||
|
||||
DynamicShaderObject::DynamicShaderObject(DynamicShaderObjectPrivate &d, QObject *parent)
|
||||
: VideoShaderObject(d, parent)
|
||||
{}
|
||||
|
||||
QString DynamicShaderObject::header() const
|
||||
{
|
||||
return d_func().header;
|
||||
}
|
||||
|
||||
void DynamicShaderObject::setHeader(const QString &text)
|
||||
{
|
||||
DPTR_D(DynamicShaderObject);
|
||||
if (d.header == text)
|
||||
return;
|
||||
d.header = text;
|
||||
Q_EMIT headerChanged();
|
||||
rebuildLater();
|
||||
}
|
||||
|
||||
|
||||
QString DynamicShaderObject::sample() const
|
||||
{
|
||||
return d_func().sampleFunc;
|
||||
}
|
||||
|
||||
void DynamicShaderObject::setSample(const QString &text)
|
||||
{
|
||||
DPTR_D(DynamicShaderObject);
|
||||
if (d.sampleFunc == text)
|
||||
return;
|
||||
d.sampleFunc = text;
|
||||
Q_EMIT sampleChanged();
|
||||
rebuildLater();
|
||||
}
|
||||
|
||||
QString DynamicShaderObject::postProcess() const
|
||||
{
|
||||
return d_func().pp;
|
||||
}
|
||||
|
||||
void DynamicShaderObject::setPostProcess(const QString &text)
|
||||
{
|
||||
DPTR_D(DynamicShaderObject);
|
||||
if (d.pp == text)
|
||||
return;
|
||||
d.pp = text;
|
||||
Q_EMIT postProcessChanged();
|
||||
rebuildLater();
|
||||
}
|
||||
|
||||
const char* DynamicShaderObject::userShaderHeader(QOpenGLShader::ShaderType st) const
|
||||
{
|
||||
if (st == QOpenGLShader::Vertex)
|
||||
return 0;
|
||||
if (d_func().header.isEmpty())
|
||||
return 0;
|
||||
return d_func().header.toUtf8().constData();
|
||||
}
|
||||
|
||||
const char* DynamicShaderObject::userSample() const
|
||||
{
|
||||
if (d_func().sampleFunc.isEmpty())
|
||||
return 0;
|
||||
return d_func().sampleFunc.toUtf8().constData();
|
||||
}
|
||||
|
||||
const char* DynamicShaderObject::userPostProcess() const
|
||||
{
|
||||
if (d_func().pp.isEmpty())
|
||||
return 0;
|
||||
return d_func().pp.toUtf8().constData();
|
||||
}
|
||||
|
||||
} //namespace FAV
|
||||
#endif // #if !(REMOVE_VIDEO_SHADER)
|
||||
179
project/fm_viewer/fav/opengl/gl_api.cpp
Normal file
179
project/fm_viewer/fav/opengl/gl_api.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
/******************************************************************************
|
||||
QtAV: Media play library based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV (from 2016)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
#include "gl_api.h"
|
||||
#include "OpenGLHelper.h"
|
||||
|
||||
namespace FAV {
|
||||
typedef void *(*GetProcAddress_t)(const char *);
|
||||
static GetProcAddress_t sGetProcAddress;
|
||||
|
||||
void* GetProcAddress_Qt(const char *name)
|
||||
{
|
||||
if (!QOpenGLContext::currentContext())
|
||||
return 0;
|
||||
void* p = (void*)QOpenGLContext::currentContext()->getProcAddress(QByteArray((const char*)name));
|
||||
if (!p) {
|
||||
#if defined(Q_OS_WIN) && defined(QT_OPENGL_DYNAMIC)
|
||||
HMODULE handle = (HMODULE)QOpenGLContext::openGLModuleHandle();
|
||||
if (handle)
|
||||
p = (void*)GetProcAddress(handle, name);
|
||||
#endif
|
||||
}
|
||||
//fallback to QOpenGLFunctions_1_0?
|
||||
return p;
|
||||
}
|
||||
|
||||
static void* GetProcAddressWithExt(GetProcAddress_t get, const char *name)
|
||||
{
|
||||
void* fp = get(name);
|
||||
if (fp)
|
||||
return fp;
|
||||
static const char *ext[] = {
|
||||
"ARB", "OES", "EXT", "ANGLE", "NV" //TODO: MESA, INTEL?
|
||||
#ifdef __APPLE__
|
||||
, "APPLE"
|
||||
#endif
|
||||
, NULL
|
||||
};
|
||||
char f[512];
|
||||
memcpy(f, name, strlen(name));
|
||||
char* const p = f + strlen(name);
|
||||
for (int i = 0; ext[i]; ++i) {
|
||||
memcpy(p, ext[i], sizeof(ext[i]) + 1); //copy trail '\0'
|
||||
fp = get(f);
|
||||
if (fp) {
|
||||
printf("extension resolved: %s", f);
|
||||
return fp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void* GetProcAddressDefault(const char *name)
|
||||
{
|
||||
return GetProcAddressWithExt(GetProcAddress_Qt, name);
|
||||
}
|
||||
|
||||
#ifdef QT_OPENGL_DYNAMIC
|
||||
#define GETPROCADDRESS_RESOLVE
|
||||
// GL_RESOLVE_ES_X_X will link to lib or use getProcAddress
|
||||
#define GL_RESOLVE_ES_2_0(name) GL_RESOLVE(name)
|
||||
#define GL_RESOLVE_ES_3_0(name) GL_RESOLVE(name)
|
||||
#define GL_RESOLVE_ES_3_1(name) GL_RESOLVE(name)
|
||||
#else
|
||||
#ifdef GL_ES_VERSION_2_0
|
||||
#define GL_RESOLVE_ES_2_0(name) GL_RESOLVE(name)
|
||||
#define GL_RESOLVE_ES_3_0(name) GL_RESOLVE_EXT(name)
|
||||
#define GL_RESOLVE_ES_3_1(name) GL_RESOLVE_EXT(name)
|
||||
#elif GL_ES_VERSION_3_0
|
||||
#define GL_RESOLVE_ES_2_0(name) GL_RESOLVE(name)
|
||||
#define GL_RESOLVE_ES_3_0(name) GL_RESOLVE(name)
|
||||
#define GL_RESOLVE_ES_3_1(name) GL_RESOLVE_NONE(name) //gl3ext is empty
|
||||
#elif GL_ES_VERSION_3_1
|
||||
#define GL_RESOLVE_ES_2_0(name) GL_RESOLVE(name)
|
||||
#define GL_RESOLVE_ES_3_0(name) GL_RESOLVE(name)
|
||||
#define GL_RESOLVE_ES_3_1(name) GL_RESOLVE(name)
|
||||
#else
|
||||
#define GETPROCADDRESS_RESOLVE
|
||||
// GL_RESOLVE_ES_X_X will link to lib or use getProcAddress
|
||||
#define GL_RESOLVE_ES_2_0(name) GL_RESOLVE(name)
|
||||
#define GL_RESOLVE_ES_3_0(name) GL_RESOLVE(name)
|
||||
#define GL_RESOLVE_ES_3_1(name) GL_RESOLVE(name)
|
||||
#endif
|
||||
#endif //QT_OPENGL_DYNAMIC
|
||||
|
||||
|
||||
#define GL_RESOLVE_NONE(name) do { name = NULL;}while(0)
|
||||
#define GL_RESOLVE_EXT(name) do {\
|
||||
void** fp = (void**)(&name); \
|
||||
*fp = GetProcAddressDefault("gl" # name); \
|
||||
} while(0)
|
||||
#ifdef GETPROCADDRESS_RESOLVE
|
||||
#define GL_RESOLVE(name) GL_RESOLVE_EXT(name)
|
||||
#else
|
||||
#define GL_RESOLVE(name) do {\
|
||||
name = ::gl##name; \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
#define WGL_RESOLVE(name) do {\
|
||||
void** fp = (void**)(&name); \
|
||||
*fp = sGetProcAddress("wgl" # name); \
|
||||
} while(0)
|
||||
|
||||
void api::resolve()
|
||||
{
|
||||
//memset(g, 0, sizeof(g));
|
||||
sGetProcAddress = GetProcAddressDefault;
|
||||
GL_RESOLVE(GetString);
|
||||
GL_RESOLVE(GetError);
|
||||
GL_RESOLVE(ActiveTexture);
|
||||
GL_RESOLVE(BindFramebuffer);
|
||||
GL_RESOLVE(GetUniformLocation);
|
||||
GL_RESOLVE(Uniform1f);
|
||||
GL_RESOLVE(Uniform2f);
|
||||
GL_RESOLVE(Uniform3f);
|
||||
GL_RESOLVE(Uniform4f);
|
||||
GL_RESOLVE(Uniform1fv);
|
||||
GL_RESOLVE(Uniform2fv);
|
||||
GL_RESOLVE(Uniform3fv);
|
||||
GL_RESOLVE(Uniform4fv);
|
||||
GL_RESOLVE(Uniform1iv);
|
||||
GL_RESOLVE(Uniform2iv);
|
||||
GL_RESOLVE(Uniform3iv);
|
||||
GL_RESOLVE(Uniform4iv);
|
||||
GL_RESOLVE(UniformMatrix2fv);
|
||||
GL_RESOLVE(UniformMatrix3fv);
|
||||
GL_RESOLVE(UniformMatrix4fv);
|
||||
GL_RESOLVE(BlendFuncSeparate);
|
||||
|
||||
GL_RESOLVE_ES_3_1(GetTexLevelParameteriv);
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
if (!OpenGLHelper::isOpenGLES()) {
|
||||
static const char* ext[] = {
|
||||
"WGL_NV_DX_interop2",
|
||||
"WGL_NV_DX_interop",
|
||||
NULL,
|
||||
};
|
||||
if (OpenGLHelper::hasExtension(ext)) { // TODO: use wgl getprocaddress function (for qt4)
|
||||
qDebug("resolving WGL_NV_DX_interop...");
|
||||
WGL_RESOLVE(DXSetResourceShareHandleNV);
|
||||
WGL_RESOLVE(DXOpenDeviceNV);
|
||||
WGL_RESOLVE(DXCloseDeviceNV);
|
||||
WGL_RESOLVE(DXRegisterObjectNV);
|
||||
WGL_RESOLVE(DXUnregisterObjectNV);
|
||||
WGL_RESOLVE(DXObjectAccessNV);
|
||||
WGL_RESOLVE(DXLockObjectsNV);
|
||||
WGL_RESOLVE(DXUnlockObjectsNV);
|
||||
}
|
||||
}
|
||||
#endif //Q_OS_WIN32
|
||||
}
|
||||
|
||||
api& gl() {
|
||||
static api g;
|
||||
if (!sGetProcAddress) {
|
||||
g.resolve();
|
||||
}
|
||||
return g;
|
||||
}
|
||||
} //namespace FAV
|
||||
170
project/fm_viewer/fav/opengl/gl_api.h
Normal file
170
project/fm_viewer/fav/opengl/gl_api.h
Normal file
@@ -0,0 +1,170 @@
|
||||
/******************************************************************************
|
||||
QtAV: Media play library based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV (from 2016)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
#ifndef QTAV_GL_API_H
|
||||
#define QTAV_GL_API_H
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
#include <qglobal.h>
|
||||
# if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
#include <QtGui/QOpenGLBuffer>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QtGui/QOpenGLFunctions>
|
||||
#include <QtGui/QOpenGLShaderProgram>
|
||||
# elif defined(QT_OPENGL_LIB)
|
||||
# if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
|
||||
#include <QtOpenGL/QGLFunctions>
|
||||
# endif //4.8
|
||||
#include <QtOpenGL/QGLBuffer>
|
||||
#include <QtOpenGL/QGLContext>
|
||||
#include <QtOpenGL/QGLShaderProgram>
|
||||
#define QOpenGLShaderProgram QGLShaderProgram
|
||||
typedef QGLBuffer QOpenGLBuffer;
|
||||
#define QOpenGLContext QGLContext
|
||||
#define QOpenGLShaderProgram QGLShaderProgram
|
||||
#define QOpenGLShader QGLShader
|
||||
#define QOpenGLFunctions QGLFunctions
|
||||
#define initializeOpenGLFunctions() initializeGLFunctions()
|
||||
#include <qgl.h>
|
||||
# else //used by vaapi even qtopengl module is disabled
|
||||
# if defined(QT_OPENGL_ES_2)
|
||||
# if defined(Q_OS_MAC) // iOS
|
||||
#include <OpenGLES/ES2/gl.h>
|
||||
#include <OpenGLES/ES2/glext.h>
|
||||
# else // "uncontrolled" ES2 platforms
|
||||
#include <GLES2/gl2.h>
|
||||
# endif // Q_OS_MAC
|
||||
# else // non-ES2 platforms
|
||||
# if defined(Q_OS_MAC)
|
||||
#include <OpenGL/gl.h>
|
||||
# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
|
||||
#include <OpenGL/gl3.h>
|
||||
# endif
|
||||
#include <OpenGL/glext.h>
|
||||
# else
|
||||
#include <GL/gl.h>
|
||||
# endif // Q_OS_MAC
|
||||
# endif // QT_OPENGL_ES_2
|
||||
# endif
|
||||
|
||||
#ifndef GL_APIENTRY
|
||||
#ifdef Q_OS_WIN
|
||||
#define GL_APIENTRY __stdcall
|
||||
#else
|
||||
#define GL_APIENTRY
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef GL_TEXTURE_RECTANGLE
|
||||
#define GL_TEXTURE_RECTANGLE 0x84F5
|
||||
#endif
|
||||
|
||||
//GL_BGRA is available in OpenGL >= 1.2
|
||||
#ifndef GL_BGRA
|
||||
#define GL_BGRA 0x80E1
|
||||
#endif
|
||||
#ifndef GL_BGR
|
||||
#define GL_BGR 0x80E0
|
||||
#endif
|
||||
#ifndef GL_RED
|
||||
#define GL_RED 0x1903
|
||||
#endif
|
||||
#ifndef GL_RG
|
||||
#define GL_RG 0x8227
|
||||
#endif
|
||||
#ifndef GL_R8
|
||||
#define GL_R8 0x8229
|
||||
#endif
|
||||
#ifndef GL_R16
|
||||
#define GL_R16 0x822A
|
||||
#endif
|
||||
#ifndef GL_RG8
|
||||
#define GL_RG8 0x822B
|
||||
#endif
|
||||
#ifndef GL_RG16
|
||||
#define GL_RG16 0x822C
|
||||
#endif
|
||||
#ifndef GL_RGB8
|
||||
#define GL_RGB8 0x8051
|
||||
#endif
|
||||
#ifndef GL_RGB16
|
||||
#define GL_RGB16 0x8054
|
||||
#endif
|
||||
#ifndef GL_RGBA8
|
||||
#define GL_RGBA8 0x8058
|
||||
#endif
|
||||
#ifndef GL_RGBA16
|
||||
#define GL_RGBA16 0x805B
|
||||
#endif
|
||||
|
||||
namespace FAV {
|
||||
typedef char GLchar; // for qt4 mingw
|
||||
struct api;
|
||||
api& gl();
|
||||
struct api {
|
||||
void resolve();
|
||||
// TODO: static, so gl::GetString
|
||||
const GLubyte *(GL_APIENTRY *GetString)(GLenum);
|
||||
GLenum (GL_APIENTRY *GetError)(void);
|
||||
void (GL_APIENTRY *ActiveTexture)(GLenum);
|
||||
void (GL_APIENTRY *BindFramebuffer)(GLenum target, GLuint framebuffer);
|
||||
GLint (GL_APIENTRY *GetUniformLocation)(GLuint, const GLchar *);
|
||||
void (GL_APIENTRY *Uniform1f)(GLint, GLfloat);
|
||||
void (GL_APIENTRY *Uniform2f)(GLint, GLfloat, GLfloat);
|
||||
void (GL_APIENTRY *Uniform3f)(GLint, GLfloat, GLfloat, GLfloat);
|
||||
void (GL_APIENTRY *Uniform4f)(GLint, GLfloat, GLfloat, GLfloat, GLfloat);
|
||||
void (GL_APIENTRY *Uniform1fv)(GLint location, GLsizei count, const GLfloat *value);
|
||||
void (GL_APIENTRY *Uniform2fv)(GLint location, GLsizei count, const GLfloat *value);
|
||||
void (GL_APIENTRY *Uniform3fv)(GLint location, GLsizei count, const GLfloat *value);
|
||||
void (GL_APIENTRY *Uniform4fv)(GLint location, GLsizei count, const GLfloat *value);
|
||||
void (GL_APIENTRY *Uniform1iv)(GLint location, GLsizei count, const GLint *value);
|
||||
void (GL_APIENTRY *Uniform2iv)(GLint location, GLsizei count, const GLint *value);
|
||||
void (GL_APIENTRY *Uniform3iv)(GLint location, GLsizei count, const GLint *value);
|
||||
void (GL_APIENTRY *Uniform4iv)(GLint location, GLsizei count, const GLint *value);
|
||||
void (GL_APIENTRY *UniformMatrix2fv)(GLint, GLsizei, GLboolean, const GLfloat *);
|
||||
void (GL_APIENTRY *UniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat *);
|
||||
void (GL_APIENTRY *UniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
|
||||
void (GL_APIENTRY *BlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
|
||||
|
||||
// Before using the following members, check null ptr first because they are not valid everywhere
|
||||
// ES3.1
|
||||
void (GL_APIENTRY *GetTexLevelParameteriv)(GLenum, GLint, GLenum, GLint *);
|
||||
|
||||
#if defined(Q_OS_WIN32)
|
||||
//#include <GL/wglext.h> //not found in vs2013
|
||||
//https://www.opengl.org/registry/specs/NV/DX_interop.txt
|
||||
#ifndef WGL_ACCESS_READ_ONLY_NV
|
||||
#define WGL_ACCESS_READ_ONLY_NV 0x00000000
|
||||
#define WGL_ACCESS_READ_WRITE_NV 0x00000001
|
||||
#define WGL_ACCESS_WRITE_DISCARD_NV 0x00000002
|
||||
#endif
|
||||
BOOL (WINAPI* DXSetResourceShareHandleNV)(void *dxObject, HANDLE shareHandle);
|
||||
HANDLE (WINAPI* DXOpenDeviceNV)(void *dxDevice);
|
||||
BOOL (WINAPI* DXCloseDeviceNV)(HANDLE hDevice);
|
||||
HANDLE (WINAPI* DXRegisterObjectNV)(HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access);
|
||||
BOOL (WINAPI* DXUnregisterObjectNV)(HANDLE hDevice, HANDLE hObject);
|
||||
BOOL (WINAPI* DXObjectAccessNV)(HANDLE hObject, GLenum access);
|
||||
BOOL (WINAPI* DXLockObjectsNV)(HANDLE hDevice, GLint count, HANDLE *hObjects);
|
||||
BOOL (WINAPI* DXUnlockObjectsNV)(HANDLE hDevice, GLint count, HANDLE *hObjects);
|
||||
#endif
|
||||
};
|
||||
} //namespace FAV
|
||||
#endif //QT_NO_OPENGL
|
||||
#endif //QTAV_GL_API_H
|
||||
Reference in New Issue
Block a user