You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
732 lines
18 KiB
732 lines
18 KiB
/*
|
|
*
|
|
* Copyright (C) 2002 George Staikos <staikos@kde.org>
|
|
* 2004 Dirk Ziegelmeier <dziegel@gmx.de>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public License
|
|
* along with this library; see the file COPYING.LIB. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "qvideostream.h"
|
|
#include <tqevent.h>
|
|
#include <tqimage.h>
|
|
#include <tqtimer.h>
|
|
|
|
#include <kdebug.h>
|
|
#include "kxv.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <X11/Xutil.h>
|
|
|
|
#ifdef HAVE_XSHM
|
|
extern "C" {
|
|
#include <sys/shm.h>
|
|
#include <X11/X.h>
|
|
#include <X11/Xlib.h>
|
|
#include <X11/extensions/XShm.h>
|
|
}
|
|
#endif
|
|
|
|
#ifdef HAVE_GL
|
|
class QVideoStreamGLWidget : public TQGLWidget
|
|
{
|
|
public:
|
|
QVideoStreamGLWidget(TQWidget* parent = 0, const char* name = 0);
|
|
virtual ~QVideoStreamGLWidget();
|
|
|
|
void setInputSize(const TQSize& sz);
|
|
void display(const unsigned char *const img, int x, int y, int sw, int sh);
|
|
|
|
private:
|
|
virtual void resizeGL(int w, int h);
|
|
void initializeGL();
|
|
|
|
virtual bool eventFilter( TQObject *o, TQEvent *e );
|
|
void calc(TQPoint& p, TQPoint& v);
|
|
|
|
|
|
TQSize _inputSize;
|
|
GLuint _tex;
|
|
int _tw, _th;
|
|
TQWidget* _w;
|
|
int _maxGL;
|
|
TQSize _sz;
|
|
bool _glfun;
|
|
TQPoint _ul, _ur, _ll, _lr;
|
|
TQPoint _vul, _vur, _vll, _vlr;
|
|
TQTimer* _glfunTimer;
|
|
};
|
|
#endif
|
|
|
|
class QVideoStreamPrivate
|
|
{
|
|
public:
|
|
QVideoStreamPrivate();
|
|
~QVideoStreamPrivate();
|
|
KXv *xvHandle;
|
|
KXvDevice *xvdev;
|
|
XImage *xim;
|
|
GC gc;
|
|
#ifdef HAVE_GL
|
|
QVideoStreamGLWidget* glwidget;
|
|
#endif
|
|
#ifdef HAVE_XSHM
|
|
XShmSegmentInfo shmh;
|
|
#endif
|
|
};
|
|
|
|
QVideoStreamPrivate::QVideoStreamPrivate()
|
|
{
|
|
xvHandle = 0;
|
|
xim = 0;
|
|
}
|
|
|
|
QVideoStreamPrivate::~QVideoStreamPrivate()
|
|
{
|
|
delete xvHandle;
|
|
}
|
|
|
|
QVideoStream::QVideoStream(TQWidget *widget, const char* name)
|
|
: TQObject(widget, name),
|
|
d(new QVideoStreamPrivate),
|
|
_w(widget),
|
|
_methods(METHOD_NONE),
|
|
_method(METHOD_NONE),
|
|
_format(FORMAT_NONE),
|
|
_init(false)
|
|
{
|
|
int dummy;
|
|
unsigned int dummy2;
|
|
findDisplayProperties(_xFormat, dummy, dummy2, dummy);
|
|
|
|
_methods = (VideoMethod)(_methods | METHOD_X11);
|
|
|
|
#ifdef HAVE_XSHM
|
|
if (XShmQueryExtension(_w->x11Display())) {
|
|
_methods = (VideoMethod)(_methods | METHOD_XSHM);
|
|
}
|
|
#endif
|
|
|
|
if (KXv::haveXv()) {
|
|
_methods = (VideoMethod)(_methods | METHOD_XV);
|
|
#ifdef HAVE_XSHM
|
|
_methods = (VideoMethod)(_methods | METHOD_XVSHM);
|
|
#endif
|
|
}
|
|
|
|
#ifdef HAVE_GL
|
|
if (TQGLFormat::hasOpenGL()) {
|
|
_methods = (VideoMethod)(_methods | METHOD_GL);
|
|
}
|
|
#endif
|
|
|
|
d->gc = XCreateGC(_w->x11Display(), _w->winId(), 0, NULL);
|
|
}
|
|
|
|
QVideoStream::~QVideoStream()
|
|
{
|
|
deInit();
|
|
XFreeGC(_w->x11Display(), d->gc);
|
|
delete d;
|
|
}
|
|
|
|
void QVideoStream::deInit()
|
|
{
|
|
if (!_init)
|
|
return;
|
|
|
|
_init = false;
|
|
_format = FORMAT_NONE;
|
|
|
|
Q_ASSERT(_methods & _method);
|
|
if (!(_methods & _method))
|
|
return;
|
|
|
|
switch (_method) {
|
|
case METHOD_XSHM:
|
|
#ifdef HAVE_XSHM
|
|
XShmDetach(_w->x11Display(), &(d->shmh));
|
|
XDestroyImage(d->xim);
|
|
d->xim = 0;
|
|
shmdt(d->shmh.shmaddr);
|
|
#endif
|
|
break;
|
|
case METHOD_X11:
|
|
delete[] d->xim->data;
|
|
d->xim->data = 0;
|
|
XDestroyImage(d->xim);
|
|
d->xim = 0;
|
|
break;
|
|
case METHOD_XVSHM:
|
|
case METHOD_XV:
|
|
delete d->xvHandle;
|
|
d->xvHandle = 0;
|
|
break;
|
|
case METHOD_GL:
|
|
#ifdef HAVE_GL
|
|
delete d->glwidget;
|
|
#endif
|
|
break;
|
|
default:
|
|
Q_ASSERT(0);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void QVideoStream::init()
|
|
{
|
|
Q_ASSERT(_methods & _method);
|
|
if (!(_methods & _method))
|
|
return;
|
|
|
|
switch (_method) {
|
|
case METHOD_XSHM:
|
|
{
|
|
#ifdef HAVE_XSHM
|
|
if ( !_inputSize.isValid() ) {
|
|
kdWarning() << "QVideoStream::init() (XSHM): Unable to initialize due to invalid input size." << endl;
|
|
return;
|
|
}
|
|
|
|
memset(&(d->shmh), 0, sizeof(XShmSegmentInfo));
|
|
d->xim = XShmCreateImage(_w->x11Display(),
|
|
(Visual*)_w->x11Visual(),
|
|
_w->x11Depth(),
|
|
ZPixmap, 0, &(d->shmh),
|
|
_inputSize.width(),
|
|
_inputSize.height());
|
|
d->shmh.shmid = shmget(IPC_PRIVATE,
|
|
d->xim->bytes_per_line*d->xim->height,
|
|
IPC_CREAT|0600);
|
|
d->shmh.shmaddr = (char *)shmat(d->shmh.shmid, 0, 0);
|
|
d->xim->data = (char*)d->shmh.shmaddr;
|
|
d->shmh.readOnly = False;
|
|
Status s = XShmAttach(_w->x11Display(), &(d->shmh));
|
|
if (s) {
|
|
XSync(_w->x11Display(), False);
|
|
shmctl(d->shmh.shmid, IPC_RMID, 0);
|
|
_format = _xFormat;
|
|
_init = true;
|
|
} else {
|
|
kdWarning() << "XShmAttach failed!" << endl;
|
|
XDestroyImage(d->xim);
|
|
d->xim = 0;
|
|
shmdt(d->shmh.shmaddr);
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
case METHOD_X11:
|
|
if ( !_inputSize.isValid() ) {
|
|
kdWarning() << "QVideoStream::init() (X11): Unable to initialize due to invalid input size." << endl;
|
|
return;
|
|
}
|
|
|
|
d->xim = XCreateImage(_w->x11Display(),
|
|
(Visual*)TQT_TQPAINTDEVICE(_w)->x11Visual(),
|
|
_w->x11Depth(),
|
|
ZPixmap, 0, 0,
|
|
_inputSize.width(),
|
|
_inputSize.height(),
|
|
32, 0);
|
|
|
|
d->xim->data = new char[d->xim->bytes_per_line*_inputSize.height()];
|
|
_format = _xFormat;
|
|
_init = true;
|
|
break;
|
|
case METHOD_XVSHM:
|
|
case METHOD_XV:
|
|
{
|
|
if (d->xvHandle)
|
|
delete d->xvHandle;
|
|
|
|
d->xvHandle = KXv::connect(_w->winId());
|
|
KXvDeviceList& xvdl(d->xvHandle->devices());
|
|
KXvDevice *xvdev = NULL;
|
|
|
|
for (xvdev = xvdl.first(); xvdev; xvdev = xvdl.next()) {
|
|
if (xvdev->isImageBackend() &&
|
|
xvdev->supportsWidget(_w)) {
|
|
d->xvdev = xvdev;
|
|
d->xvdev->useShm(_method == METHOD_XVSHM);
|
|
_format = FORMAT_YUYV;
|
|
_init = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!_init) {
|
|
delete d->xvHandle;
|
|
d->xvHandle = 0;
|
|
}
|
|
}
|
|
break;
|
|
case METHOD_GL:
|
|
#ifdef HAVE_GL
|
|
d->glwidget = new QVideoStreamGLWidget(_w, "QVideoStreamGLWidget");
|
|
d->glwidget->resize(_w->width(), _w->height());
|
|
d->glwidget->show();
|
|
_format = FORMAT_BGR24;
|
|
_init = true;
|
|
#endif
|
|
break;
|
|
default:
|
|
Q_ASSERT(0);
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool QVideoStream::haveMethod(VideoMethod method) const
|
|
{
|
|
return _methods & method;
|
|
}
|
|
|
|
QVideo::VideoMethod QVideoStream::method() const
|
|
{
|
|
return _method;
|
|
}
|
|
|
|
QVideo::VideoMethod QVideoStream::setMethod(VideoMethod method)
|
|
{
|
|
if (_methods & method) {
|
|
deInit();
|
|
_method = method;
|
|
init();
|
|
}
|
|
|
|
return _method;
|
|
}
|
|
|
|
TQSize QVideoStream::maxSize() const
|
|
{
|
|
return _size;
|
|
}
|
|
|
|
int QVideoStream::maxWidth() const
|
|
{
|
|
return _size.width();
|
|
}
|
|
|
|
int QVideoStream::maxHeight() const
|
|
{
|
|
return _size.height();
|
|
}
|
|
|
|
TQSize QVideoStream::size() const
|
|
{
|
|
return _size;
|
|
}
|
|
|
|
int QVideoStream::width() const
|
|
{
|
|
return _size.width();
|
|
}
|
|
|
|
int QVideoStream::height() const
|
|
{
|
|
return _size.height();
|
|
}
|
|
|
|
TQSize QVideoStream::setSize(const TQSize& sz)
|
|
{
|
|
_size = sz;
|
|
return _size;
|
|
}
|
|
|
|
int QVideoStream::setWidth(int width)
|
|
{
|
|
if (width < 0)
|
|
width = 0;
|
|
if (width > maxWidth())
|
|
width = maxWidth();
|
|
_size.setWidth(width);
|
|
return _size.width();
|
|
}
|
|
|
|
int QVideoStream::setHeight(int height)
|
|
{
|
|
if (height < 0)
|
|
height = 0;
|
|
if (height > maxHeight())
|
|
height = maxHeight();
|
|
_size.setHeight(height);
|
|
return _size.height();
|
|
}
|
|
|
|
TQSize QVideoStream::inputSize() const
|
|
{
|
|
return _inputSize;
|
|
}
|
|
|
|
int QVideoStream::inputWidth() const
|
|
{
|
|
return _inputSize.width();
|
|
}
|
|
|
|
int QVideoStream::inputHeight() const
|
|
{
|
|
return _inputSize.height();
|
|
}
|
|
|
|
TQSize QVideoStream::setInputSize(const TQSize& sz)
|
|
{
|
|
if (sz == _inputSize)
|
|
return _inputSize;
|
|
_inputSize = sz;
|
|
if (_method & (METHOD_XSHM | METHOD_X11)) {
|
|
deInit();
|
|
init();
|
|
}
|
|
#ifdef HAVE_GL
|
|
if (_method & METHOD_GL) {
|
|
d->glwidget->setInputSize(_inputSize);
|
|
}
|
|
#endif
|
|
return _inputSize;
|
|
}
|
|
|
|
int QVideoStream::setInputWidth(int width)
|
|
{
|
|
if (width == _inputSize.width())
|
|
return _inputSize.width();
|
|
_inputSize.setWidth(width);
|
|
if (_method & (METHOD_XSHM | METHOD_X11)) {
|
|
deInit();
|
|
init();
|
|
}
|
|
#ifdef HAVE_GL
|
|
if (_method & METHOD_GL) {
|
|
d->glwidget->setInputSize(_inputSize);
|
|
}
|
|
#endif
|
|
return _inputSize.width();
|
|
}
|
|
|
|
int QVideoStream::setInputHeight(int height)
|
|
{
|
|
if (height == _inputSize.height())
|
|
return _inputSize.height();
|
|
_inputSize.setHeight(height);
|
|
if (_method & (METHOD_XSHM | METHOD_X11)) {
|
|
deInit();
|
|
init();
|
|
}
|
|
#ifdef HAVE_GL
|
|
if (_method & METHOD_GL) {
|
|
d->glwidget->setInputSize(_inputSize);
|
|
}
|
|
#endif
|
|
return _inputSize.height();
|
|
}
|
|
|
|
bool QVideoStream::supportsFormat(VideoMethod method, ImageFormat format)
|
|
{
|
|
return (bool)(formatsForMethod(method) & format);
|
|
}
|
|
|
|
QVideo::ImageFormat QVideoStream::formatsForMethod(VideoMethod method)
|
|
{
|
|
switch(method) {
|
|
case METHOD_XSHM:
|
|
case METHOD_X11:
|
|
return _xFormat;
|
|
case METHOD_XV:
|
|
case METHOD_XVSHM:
|
|
return FORMAT_YUYV;
|
|
case METHOD_GL:
|
|
return FORMAT_BGR24;
|
|
default:
|
|
return FORMAT_NONE;
|
|
}
|
|
}
|
|
|
|
QVideo::ImageFormat QVideoStream::format() const
|
|
{
|
|
return _format;
|
|
}
|
|
|
|
bool QVideoStream::setFormat(ImageFormat format)
|
|
{
|
|
if(supportsFormat(_method, format)) {
|
|
_format = format;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
int QVideoStream::displayFrame(const unsigned char *const img)
|
|
{
|
|
return displayFrame(img, 0, 0, _inputSize.width(), _inputSize.height());
|
|
}
|
|
|
|
int QVideoStream::displayFrame(const unsigned char *const img, int x, int y, int sw, int sh)
|
|
{
|
|
Q_ASSERT(_init);
|
|
if (!_init)
|
|
return -1;
|
|
|
|
Q_ASSERT(_methods & _method);
|
|
if (!(_methods & _method))
|
|
return -1;
|
|
|
|
switch (_method) {
|
|
case METHOD_XV:
|
|
case METHOD_XVSHM:
|
|
return d->xvdev->displayImage(_w, img,
|
|
_inputSize.width(), _inputSize.height(), x, y, sw, sh,
|
|
_size.width(), _size.height());
|
|
break;
|
|
case METHOD_XSHM:
|
|
#ifdef HAVE_XSHM
|
|
memcpy(d->xim->data,img,d->xim->bytes_per_line*d->xim->height);
|
|
XShmPutImage(_w->x11Display(), _w->winId(), d->gc, d->xim,
|
|
x, y,
|
|
0, 0,
|
|
sw, sh,
|
|
0);
|
|
XSync(_w->x11Display(), False);
|
|
break;
|
|
#else
|
|
return -1;
|
|
#endif
|
|
case METHOD_X11:
|
|
memcpy(d->xim->data, img, d->xim->bytes_per_line*d->xim->height);
|
|
XPutImage(_w->x11Display(), _w->winId(), d->gc, d->xim,
|
|
x, y,
|
|
0, 0,
|
|
sw, sh);
|
|
XSync(_w->x11Display(), False);
|
|
break;
|
|
case METHOD_GL:
|
|
#ifdef HAVE_GL
|
|
d->glwidget->display(img, x, y, sw, sh);
|
|
#endif
|
|
break;
|
|
default:
|
|
Q_ASSERT(0);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
QVideoStream& QVideoStream::operator<<(const unsigned char *const img)
|
|
{
|
|
displayFrame(img);
|
|
return *this;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------
|
|
#ifdef HAVE_GL
|
|
|
|
QVideoStreamGLWidget::QVideoStreamGLWidget(TQWidget* parent, const char* name)
|
|
: TQGLWidget(TQGLFormat(TQGL::DoubleBuffer | TQGL::Rgba | TQGL::DirectRendering), parent, name),
|
|
_tex(0),
|
|
_w(parent),
|
|
_glfun(false)
|
|
{
|
|
kdDebug() << "QVideoStreamGLWidget::QVideoStreamGLWidget()" << endl;
|
|
|
|
connect(_w, TQT_SIGNAL(resized(int, int)),
|
|
this, TQT_SLOT(resize(int, int)));
|
|
|
|
topLevelWidget()->installEventFilter(this);
|
|
_glfunTimer = new TQTimer();
|
|
}
|
|
|
|
QVideoStreamGLWidget::~QVideoStreamGLWidget()
|
|
{
|
|
kdDebug() << "QVideoStreamGLWidget::~QVideoStreamGLWidget()" << endl;
|
|
delete _glfunTimer;
|
|
|
|
makeCurrent();
|
|
if(_tex != 0) {
|
|
glDeleteTextures(1, &_tex);
|
|
}
|
|
}
|
|
|
|
bool QVideoStreamGLWidget::eventFilter(TQObject*, TQEvent* e)
|
|
{
|
|
// For some reason, KeyPress does not work (yields 2), TQEvent::KeyPress is unknown... What the f...????
|
|
// I am too lazy to scan the header files for the reason.
|
|
if(e->type() == 6) {
|
|
TQKeyEvent* ke = TQT_TQKEYEVENT(e);
|
|
if(ke->key() == TQt::Key_Pause) {
|
|
_glfunTimer->start(500, true);
|
|
} else if (_glfunTimer->isActive() && (ke->key() == TQt::Key_Escape)) {
|
|
_glfun = !_glfun;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void QVideoStreamGLWidget::initializeGL()
|
|
{
|
|
kdDebug() << "QVideoStreamGLWidget::initializeGL()" << endl;
|
|
setAutoBufferSwap(false);
|
|
|
|
TQGLFormat f = format();
|
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &_maxGL);
|
|
kdDebug() << "OpenGL capabilities (* = required):" << endl;
|
|
kdDebug() << " Valid context*: " << isValid() << endl;
|
|
kdDebug() << " DoubleBuffer*: " << f.doubleBuffer() << endl;
|
|
kdDebug() << " Depth: " << f.depth() << endl;
|
|
kdDebug() << " RGBA*: " << f.rgba() << endl;
|
|
kdDebug() << " Alpha: " << f.alpha() << endl;
|
|
kdDebug() << " Accum: " << f.accum() << endl;
|
|
kdDebug() << " Stencil: " << f.stencil() << endl;
|
|
kdDebug() << " Stereo: " << f.stereo() << endl;
|
|
kdDebug() << " DirectRendering*: " << f.directRendering() << endl;
|
|
kdDebug() << " Overlay: " << f.hasOverlay() << endl;
|
|
kdDebug() << " Plane: " << f.plane() << endl;
|
|
kdDebug() << " MAX_TEXTURE_SIZE: " << _maxGL << endl;
|
|
|
|
qglClearColor(TQt::black);
|
|
glShadeModel(GL_FLAT);
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
|
|
_vul = TQPoint( 4, 10);
|
|
_vur = TQPoint(-8, 4);
|
|
_vll = TQPoint(10, -4);
|
|
_vlr = TQPoint(-8, -10);
|
|
}
|
|
|
|
void QVideoStreamGLWidget::resizeGL(int w, int h)
|
|
{
|
|
_sz = TQSize(w, h);
|
|
|
|
glViewport(0, 0, w, h);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glOrtho(0.0, w, 0.0, h, -1, 1);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
|
|
_ul = TQPoint(0, 0);
|
|
_ur = TQPoint(w, 0);
|
|
_ll = TQPoint(0, h);
|
|
_lr = TQPoint(w, h);
|
|
}
|
|
|
|
void QVideoStreamGLWidget::setInputSize(const TQSize& sz)
|
|
{
|
|
makeCurrent();
|
|
|
|
_inputSize = sz;
|
|
int iw = _inputSize.width();
|
|
int ih = _inputSize.height();
|
|
|
|
if ( (iw > _maxGL) || (ih > _maxGL) ) {
|
|
kdWarning() << "QVideoStreamGLWidget::setInputSize(): Texture too large! maxGL: " << _maxGL << endl;
|
|
return;
|
|
}
|
|
|
|
// textures have power-of-two x,y dimensions
|
|
int i;
|
|
for (i = 0; iw >= (1 << i); i++)
|
|
;
|
|
_tw = (1 << i);
|
|
for (i = 0; ih >= (1 << i); i++)
|
|
;
|
|
_th = (1 << i);
|
|
|
|
// Generate texture
|
|
if(_tex != 0) {
|
|
glDeleteTextures(1, &_tex);
|
|
}
|
|
glGenTextures(1, &_tex);
|
|
glBindTexture(GL_TEXTURE_2D, _tex);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
// Blank texture
|
|
char* dummy = new char[_tw*_th*4];
|
|
memset(dummy, 128, _tw*_th*4);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _tw, _th, 0,
|
|
GL_RGB, GL_UNSIGNED_BYTE, dummy);
|
|
delete[] dummy;
|
|
}
|
|
|
|
void QVideoStreamGLWidget::display(const unsigned char *const img, int x, int y, int sw, int sh)
|
|
{
|
|
makeCurrent();
|
|
|
|
// FIXME: Endianess - also support GL_RGB
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _inputSize.width(), _inputSize.height(),
|
|
GL_BGR, GL_UNSIGNED_BYTE, img);
|
|
|
|
// upper right coords
|
|
float ur_x = (float)(x + sw) / _tw;
|
|
float ur_y = (float)(y + sh) / _th;
|
|
|
|
// lower left coords
|
|
float ll_x = (float)(x) / _tw;
|
|
float ll_y = (float)(y) / _th;
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
|
glBindTexture(GL_TEXTURE_2D, _tex);
|
|
if (!_glfun) {
|
|
glBegin(GL_QUADS);
|
|
glTexCoord2f(ll_x, ur_y); glVertex2i(0, 0 );
|
|
glTexCoord2f(ll_x, ll_y); glVertex2i(0, _sz.height());
|
|
glTexCoord2f(ur_x, ll_y); glVertex2i(_sz.width(), _sz.height());
|
|
glTexCoord2f(ur_x, ur_y); glVertex2i(_sz.width(), 0 );
|
|
glEnd();
|
|
} else {
|
|
calc(_ul, _vul);
|
|
calc(_ur, _vur);
|
|
calc(_ll, _vll);
|
|
calc(_lr, _vlr);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
glBegin(GL_QUADS);
|
|
glTexCoord2f(0, y); glVertex2i(_ul.x(), _ul.y());
|
|
glTexCoord2f(0, 0); glVertex2i(_ll.x(), _ll.y());
|
|
glTexCoord2f(x, 0); glVertex2i(_lr.x(), _lr.y());
|
|
glTexCoord2f(x, y); glVertex2i(_ur.x(), _ur.y());
|
|
glEnd();
|
|
}
|
|
swapBuffers();
|
|
glDisable(GL_TEXTURE_2D);
|
|
}
|
|
|
|
void QVideoStreamGLWidget::calc(TQPoint& p, TQPoint& v)
|
|
{
|
|
p += v;
|
|
|
|
if(p.x() < 0) {
|
|
p.setX(-p.x());
|
|
v.setX(-v.x());
|
|
}
|
|
if(p.y() < 0) {
|
|
p.setY(-p.y());
|
|
v.setY(-v.y());
|
|
}
|
|
if(p.x() > _sz.width()) {
|
|
p.setX(_sz.width() - (p.x() - _sz.width()));
|
|
v.setX(-v.x());
|
|
}
|
|
if(p.y() > _sz.height()) {
|
|
p.setY(_sz.height() - (p.y() - _sz.height()));
|
|
v.setY(-v.y());
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#include "qvideostream.moc"
|